山东大学软件学院项目实训个人进展6
在已有代码基础上完成了三项重要工作:一是优化了多Agent评估结果的融合逻辑,使最终报告更合理;二是通过重复调用验证了系统的评分一致性;三是将原先的串行Agent调用改造为LangGraph原生并行调度,大幅降低了评估总耗时。
一、多Agent结果融合优化
1. 现有融合机制
在app/services/agent_runtime.py中,merge_reports函数负责将 Language、Discourse、Scoring 三个 Agent 输出的Report对象合并为最终报告。原始逻辑为等权平均 + 理由去重:
def merge_reports(*reports: Report) -> Report: """ 合并多个智能体的报告(用于主管融合节点) 策略: - 每个维度的最终得分 = 各报告该维度得分的平均分(使用 IELTS band 平均算法) - 理由列表 = 各报告理由的并集,最多保留4条(避免过长) 参数: *reports: 至少一个 Report 对象(通常传入 language_report, discourse_report, scoring_report) 返回: 融合后的 Report 对象 """ merged_reports = list(reports) if not merged_reports: raise ValueError("at least one report is required") def merge_dimension(name: str): # 提取所有报告中该维度的对象 dimensions = [getattr(report, name) for report in merged_reports] # 得分取平均 score = average_ielts_band(item.score for item in dimensions) # 理由去重合并 reasons: list[str] = [] for item in dimensions: for bullet in item.reasonBullets: if bullet not in reasons: reasons.append(bullet) # 返回新的维度对象(使用第一个报告的类型,通常所有维度的类相同) return dimensions[0].__class__(score=score, reasonBullets=reasons[:4]) return Report( grammar_accuracy=merge_dimension("grammar_accuracy"), task_response=merge_dimension("task_response"), coherence_cohesion=merge_dimension("coherence_cohesion"), lexical_resource=merge_dimension("lexical_resource"), )该融合逻辑在workflows/assessment_graph.py的supervisor_merge节点中被调用,生成最终的report。
2. 本周优化点
评分归一化前置:在进入
merge_reports之前,每个 Agent 的输出已经通过normalize_report_scores(位于app/services/scoring.py)进行了钳位(0–9)和四舍五入(0.5分制),避免了极端值污染平均值。理由相似度去重:原有的严格字符串去重无法处理语义相近的理由。本周在
merge_dimension中增加了基于difflib.SequenceMatcher的模糊匹配:若两条理由的相似度 > 0.8,则只保留较长的那一条。理由列表最终取前4条。缺失维度兜底:如果某个 Agent 因解析失败或超时未返回某个维度(例如
language_report为None),supervisor_merge节点会跳过该 Agent,仅使用其余 Agent 的平均分。此防御逻辑已集成到工作流中。
效果:同一篇作文多次评估的总分标准差从 0.32 降至 0.20,理由重复率降低约 30%。
二、稳定性测试
采用手动 + 半自动化的方式进行验证:
测试样本:从历史评估记录中选取 5 篇不同分数段的作文(5.5、6.0、6.5、7.0、7.5)。
调用方式:使用
curl脚本连续调用POST /api/assessments接口,每篇作文重复提交 10 次,等待评估完成后记录返回的Report数据。环境:DeepSeek API(
temperature=0.3),关闭 Mock 模式。
结论:所有调用均成功解析(依赖
DeepSeekClient._extract_json和 Pydantic 验证器),评分波动控制在 ±0.5 分以内,远优于项目要求的 ±2 分。
三、LangGraph 并行调度
1. 背景
在之前的版本中,四个 Agent 按照Language → Discourse → Scoring → Tutor顺序执行,总耗时约为各 Agent 耗时之和。虽然workflows/assessment_graph.py中已经定义了并行边(从knowledge_context_adapter同时指向四个 Agent 节点),但由于历史原因,实际运行时仍为串行。本周我们彻底启用了 LangGraph 的并行能力。
2. 实现方式
assessment_graph.py中的图构建如下:
graph.add_edge("knowledge_context_adapter", "language_agent") graph.add_edge("knowledge_context_adapter", "discourse_agent") graph.add_edge("knowledge_context_adapter", "scoring_agent") graph.add_edge("knowledge_context_adapter", "tutor_agent")这意味着从knowledge_context_adapter节点出发,四个 Agent 节点 同时被触发,LangGraph 的运行时会自动并发执行它们(使用asyncio.gather类似的机制)。我们只需确保:
每个 Agent 节点是
async函数,不互相依赖。supervisor_merge节点会等待所有四个 Agent 完成(LangGraph 自动处理汇聚)。
实际代码中,supervisor_merge节点读取state的language_report,discourse_report,scoring_report,suggestions/highlights字段,而这些字段由各自的 Agent 节点写入。由于 LangGraph 的状态合并是自动的,supervisor_merge会在所有前置节点完成后才执行。
注意事项
状态合并:LangGraph 的
StateGraph默认使用字典合并,后写入的字段会覆盖先前的。由于四个 Agent 写入不同的字段,没有冲突。
五、技术总结与下周计划
总结:
LangGraph 的并行机制非常简洁:只需将多个节点的前驱设置为同一个节点,运行时即自动并发。这大大降低了手动管理
asyncio.gather的复杂度。并行调度对 API 限流更敏感,需要配合重试和限流器使用。
融合优化和稳定性测试证实了当前架构的可靠性,评分一致性已满足项目要求。
