""" 用户反馈学习服务 — 采集反馈信号,自动调整 Agent 策略 """ from __future__ import annotations import logging from typing import Any, Dict, List, Optional from collections import Counter, defaultdict from sqlalchemy import func, desc from sqlalchemy.orm import Session from app.core.database import SessionLocal from app.models.feedback_record import FeedbackRecord from app.models.agent_execution_log import AgentExecutionLog logger = logging.getLogger(__name__) class FeedbackLearner: """从用户反馈中学习,自动调整 Agent 策略""" def record_feedback( self, user_id: str, signal_type: str, *, execution_log_id: Optional[str] = None, agent_name: Optional[str] = None, task_id: Optional[str] = None, original_output: Optional[str] = None, user_correction: Optional[str] = None, feedback_context: Optional[Dict[str, Any]] = None, ) -> Optional[str]: """记录一条用户反馈。""" db: Optional[Session] = None try: db = SessionLocal() severity = 0.5 if signal_type == "reject_approval": severity = 0.9 elif signal_type == "thumbs_down": severity = 0.7 elif signal_type == "manual_edit": severity = 0.6 elif signal_type == "retry_command": severity = 0.4 entry = FeedbackRecord( user_id=user_id, signal_type=signal_type, severity=severity, execution_log_id=execution_log_id, agent_name=agent_name, task_id=task_id, original_output=original_output[:5000] if original_output else None, user_correction=user_correction[:5000] if user_correction else None, feedback_context=feedback_context, ) db.add(entry) db.commit() db.refresh(entry) # 标记相关执行日志的反馈 if execution_log_id: exec_log = db.query(AgentExecutionLog).filter( AgentExecutionLog.id == execution_log_id ).first() if exec_log: exec_log.user_rating = 1 if signal_type in ("thumbs_down", "reject_approval") else 3 exec_log.user_feedback = signal_type db.commit() return str(entry.id) except Exception as e: logger.error("记录反馈失败: %s", e) if db: try: db.rollback() except Exception: pass return None finally: if db: try: db.close() except Exception: pass def analyze_feedback_patterns(self, agent_name: Optional[str] = None, days: int = 7) -> Dict[str, Any]: """分析反馈模式,识别需要调整的策略。""" db: Optional[Session] = None try: db = SessionLocal() from datetime import datetime, timedelta since = datetime.now() - timedelta(days=days) q = db.query(FeedbackRecord).filter(FeedbackRecord.created_at >= since) if agent_name: q = q.filter(FeedbackRecord.agent_name == agent_name) records = q.all() if not records: return {"total_feedback": 0, "message": "近期无反馈"} # 统计信号类型 signal_dist = Counter(r.signal_type for r in records) # 按 Agent 分组 by_agent = defaultdict(lambda: {"total": 0, "negative": 0, "patterns": []}) for r in records: name = r.agent_name or "unknown" by_agent[name]["total"] += 1 if r.signal_type in ("thumbs_down", "reject_approval"): by_agent[name]["negative"] += 1 # 生成策略建议 strategy_advice = [] total = len(records) negative_rate = (signal_dist.get("thumbs_down", 0) + signal_dist.get("reject_approval", 0)) / total if total > 0 else 0 if negative_rate > 0.3: strategy_advice.append({ "type": "adjust_temperature", "reason": f"负面反馈率 {negative_rate:.1%},建议降低 temperature", "action": "temperature -= 0.1", }) if signal_dist.get("retry_command", 0) / total > 0.2 if total > 0 else False: strategy_advice.append({ "type": "enhance_prompt", "reason": "用户频繁要求重试,输出可能不够精准", "action": "在 system prompt 中增加更具体的输出要求", }) if signal_dist.get("manual_edit", 0) / total > 0.2 if total > 0 else False: strategy_advice.append({ "type": "suggest_review", "reason": "输出频繁被手动修改,建议开启 self_review", "action": "开启输出质量自检", }) # 推荐有问题的 Agent problematic_agents = [ {"agent": name, "negative_rate": round(data["negative"] / data["total"], 2)} for name, data in by_agent.items() if data["total"] >= 3 and data["negative"] / data["total"] > 0.3 ] return { "total_feedback": total, "period_days": days, "signal_distribution": dict(signal_dist), "overall_negative_rate": round(negative_rate, 3), "problematic_agents": problematic_agents, "strategy_advice": strategy_advice, } except Exception as e: logger.error("分析反馈模式失败: %s", e) return {"error": str(e)} finally: if db: try: db.close() except Exception: pass def generate_negative_examples(self, agent_name: str, limit: int = 5) -> List[Dict[str, Any]]: """为 Agent 生成反例(用于更新 system prompt)。""" db: Optional[Session] = None try: db = SessionLocal() records = ( db.query(FeedbackRecord) .filter( FeedbackRecord.agent_name == agent_name, FeedbackRecord.original_output.isnot(None), FeedbackRecord.user_correction.isnot(None), FeedbackRecord.signal_type.in_(["thumbs_down", "manual_edit"]), ) .order_by(desc(FeedbackRecord.created_at)) .limit(limit) .all() ) examples = [] for r in records: examples.append({ "original": (r.original_output or "")[:500], "corrected": (r.user_correction or "")[:500], "signal": r.signal_type, }) return examples except Exception as e: logger.error("生成反例失败: %s", e) return [] finally: if db: try: db.close() except Exception: pass feedback_learner = FeedbackLearner()