山东大学项目实训个人记录4
1. Scoring Agent:综合四维评分
目标:让模型一次性给出语法、任务完成度、连贯衔接、词汇四个维度的分数和详细理由。
实现:在AgentRuntime中新增scoring_agent方法,复用已有的ReportSchema。
系统提示词明确要求:
你是 IELTS 写作总评分 agent。你只能返回一个 JSON 对象,不要输出 markdown,不要解释。 JSON 结构必须包含 grammar_accuracy、task_response、coherence_cohesion、lexical_resource, 每个维度都必须是 {"score": number, "reasonBullets":["..."]},每项提供 3 条简洁中文理由。调用deepseek.generate_structured,直接得到一份完整的四维报告。
技术点:由于我们已经为ReportDimension定义了丰富的字段别名(reasonBullets可接受feedback、reasons、bullets),即使 LLM 偶尔使用其他命名,Pydantic 也能正确映射。
2. Tutor Agent:生成建议与亮点
目标:输出逐句修改建议(含错误类型、原文定位、解释、改写)以及作文亮点和学习路径。
实现:tutor_agent方法返回TutorResponse
系统提示词做了非常详细的约束:
errorType只能使用grammar、task_response、coherence、lexical四个稳定键。suggestions必须包含sourceText、explanation、revision、revisedSentence及位置索引。highlights.type限advanced_vocabulary、cohesive_device、clear_position、supporting_example。所有解释和建议必须为中文。
亮点定位修正:LLM 返回的positionStart/End经常与原文有偏移。在normalize_suggestions函数中对每个建议进行二次匹配——用sourceText在原文中模糊查找,重新计算准确位置,确保前端高亮准确。
3. 完整顺序调度链
本周先将四个 Agent 串起来:
language_agent() → discourse_agent() → scoring_agent() → tutor_agent()
每次调用后,将上一步的结果暂存于状态变量,最后汇总。这样一旦某个 Agent 失败,可以清晰地定位问题。
4. JSON 修复机制
痛点:即使我们使用了 DeepSeek 的response_format={"type": "json_object"},模型偶尔还是会输出以下非法内容:
在 JSON 前后添加解释文字,如
"Sure, here is the result: {...}"JSON 内部包含
//注释使用单引号而非双引号
字段名末尾多了一个逗号
解决方案:在DeepSeekClient._extract_json中加入修复逻辑:
先用
json.loads尝试直接解析。若失败,用正则
r"\{.*\}"提取第一个完整花括号块(忽略前后文本)。再尝试解析提取出的字符串。
若仍失败,抛出异常(由上层降级为 Mock)。
同时,Pydantic 模型中的model_validator对reasonBullets做类型兜底:如果 LLM 返回的是字符串(比如用序号分隔的几条理由),自动按换行或句号拆分成列表。
效果:几乎不再出现因为格式问题导致整个评估任务崩溃的情况
感悟:大模型输出不可控通过“强约束 Prompt + 宽松解析 + 降级 Mock”三层防御能让系统在生产环境中保持鲁棒。下一步是实现并行调度。
