Agent Engineering 课程阅读
首页/课程七 · 智能体前沿/反思进研究回路:从「重写报告」到「修正结论」

在 GitHub 查看原文

本页目录

Lesson 05 — 反思进研究回路:从「重写报告」到「修正结论」

本课目标:把 L04 的 Reflexion 机制接进 research-assistant,把现有 reviewer 从单通道(只改文字)升级为双通道(文字重写 + 事实修正),让 Agent 发现新旧信息冲突时能定向补研并在报告中写修正说明。

学完你能回答:「你的 Agent 怎么修正错误结论?」——不只改错字,还改错误认知。


0. 起点:现有 reviewer 的局限

research-assistant 现有的 reviewer(阶段 2)只做一件事:评估报告的文字质量——结构完不完整、表述专不专业。不合格就让 writer 重写。

现有 reviewer(单通道):
  report 不合格 → "结构不完整" → writer 重写(改文字)

  🚫 不能做:发现"结论过时"→ 重新研究
  🚫 不能做:发现"新旧信息冲突"→ 判断采信谁

问题:硬任务要求"发现新信息与旧结论冲突时要修正并说明为什么"。现有 reviewer 根本不碰事实——它只看报告写得好不好,不看报告里的结论对不对。

本课升级为双通道:文字通道(现状保留)+ 事实通道(新增)。


1. 双通道 reviewer

                    ┌─────────── reviewer ───────────┐
                    │                                 │
     report ───────▶│  事实通道(新增)                │
                    │  新 findings vs 记忆旧结论       │
                    │  冲突? ──是──▶ re_research      │──▶ research_team(定向补研)
                    │    │ 否                          │
                    │    ▼                             │
                    │  文字通道(现有)                │
                    │  结构/表述合格?                 │
                    │  不合格 ─▶ rework                │──▶ writer(重写)
                    │    │ 合格                         │
                    │    ▼                             │
                    │  pass                            │──▶ END
                    └─────────────────────────────────┘
通道 检测什么 不通过时 路由到 防死循环
事实通道(L05 新增) 新 findings 与记忆旧结论冲突 生成定向补研问题 research_team re_research_count >= max_re_research
文字通道(阶段 2) 报告结构/表述质量 带 feedback writer rewrite_count >= max_rewrites

事实通道优先

为什么事实通道优先于文字通道?因为事实错了文字再漂亮也没用。先修正认知(补研),再修文字(重写)。如果先重写文字,writer 可能基于错误结论写出"漂亮的错误报告"。

与硬任务的关系

硬任务要求"发现新信息与旧结论冲突时修正并说明为什么"。这条要求完全由事实通道实现: 1. reviewer 检测到新 findings 与记忆旧结论冲突 2. 生成定向补研问题("验证 X 到底对不对") 3. 路由回 research_team 用补研问题做子题 4. 补研结果回流,writer 在报告中写"修正说明"(旧结论/新证据/为何采信新的)


2. 冲突检测:check_conflicts

核心逻辑

def check_conflicts(findings, mem_store, llm):
    for finding in findings:
        # 1. recall 旧记忆
        old = mem_store.recall(finding)
        # 2. LLM judge:一致 / 冲突 / 无关
        verdict = llm.judge(finding, old)
        if verdict == "冲突":
            conflicts.append(finding)
            # 3. 生成定向补研问题
            queries.append(llm.generate_question(finding, old))
    return {"conflicts": conflicts, "queries": queries}

LLM judge 的判断标准

给 LLM 新发现和旧结论,让它判断三者之一: - 一致:新发现支持旧结论(无冲突) - 冲突:新发现与旧结论矛盾(需要修正) - 无关:新发现和旧结论讲的是不同方面(无冲突)

降级路径

无 LLM 时用关键词检测:finding 含"修正""实际上""并非""错误"等冲突信号词 → 疑似冲突。粗糙但能跑(教学演示用,生产必须用 LLM judge)。


3. 流派对比

问题:Agent 发现结论可能过时/错误时,怎么修正?

流派 做法 取舍
① 不修正(现状) reviewer 只看文字,不管事实 ✅ 简单;🚫 结论过时也不改
② 全量重查 每次都从头重新研究 ✅ 一定最新;🚫 成本高、无增量
③ 冲突触发定向补研(本课选它) 只在检测到冲突时补研冲突点 ✅ 精准、成本低;🚫 依赖冲突检测质量
④ 定时刷新 定期重新研究所有主题 ✅ 系统性;🚫 僵化、不响应实时冲突

选 ③ 的理由:硬任务的核心是"增量"——不是每次全查,是在有冲突时精准补。这和 L01 的记忆系统天然配合:有记忆才知道新旧冲突(没记忆就全是"新的",无所谓冲突)。成本可控:只在冲突时补研,不是每次都补。


4. 定向补研:research_team 的升级

research_team 节点升级:检测到 re_research_queries 时,用它们做子题(而非重新 split)。

async def research_team(state):
    re_queries = state.get("re_research_queries", [])
    if re_queries:
        # 定向补研:用冲突生成的补研问题作为子题
        sub_result = await research_subgraph.ainvoke({
            "topic": topic,
            "subtopics": re_queries,  # 直接用补研问题
            ...
        })
        return {"findings": sub_result["findings"]}  # 追加到现有 findings
    # 正常研究
    ...

关键设计:findings 是追加不是覆盖

findings 字段用 operator.add reducer,补研结果会追加到现有 findings,不覆盖。这样 writer 能看到"原始发现 + 补研发现",在报告中写修正说明。

writer 的修正说明

writer 检测到 conflicts 字段时,prompt 加修正说明要求:

📝 修正说明(请在报告中附「修正说明」部分,说明旧结论/新证据/为何采信新的):
  - 新发现「MCP 基于 JSON-RPC」与旧结论「MCP 基于 gRPC」冲突

5. 防死循环

双通道各有计数器: - 文字通道:rewrite_count >= max_rewrites(默认 3)→ 强制 pass - 事实通道:re_research_count >= max_re_research(默认 2)→ 强制 pass

两个都超限时强制通过(不能再重写也不能再补研)。这保证了系统最终会结束,不会无限循环。

review_route 的三路路由

def review_route(state):
    decision = state["review_decision"]
    if decision == "pass":
        return END
    if decision == "re_research" and re_research_count <= max_re_research:
        return "research_team"  # 事实冲突 → 补研
    if decision == "rework" and rewrite_count < max_rewrites:
        return "writer"  # 文字不合格 → 重写
    return END  # 超限 → 结束

6. 落地清单

改了哪些文件

文件 改动 说明
src/research_assistant/state.py conflicts/re_research_count/re_research_queries 双通道事实修正的 State 字段
src/research_assistant/config.py max_re_research 补研次数上限(防死循环)
src/research_assistant/nodes.py reviewer 升级双通道 + check_conflicts + review_route 三路 事实通道检测冲突→定向补研
src/research_assistant/nodes.py research_team 支持补研子题 冲突时用补研问题做子题
src/research_assistant/nodes.py writer 加修正说明 prompt 冲突时报告附修正说明
src/research_assistant/graph.py 条件边升级三路 pass/rework/re_research
src/research_assistant/service.py _initial_state 加新字段
tests/test_nodes.py +6 个测试 双通道路由 + 冲突检测

如何验证

cd portfolio-projects/research-assistant

# 1. 全量测试(56 原有 + 6 新增 = 62 全绿)
.venv/Scripts/python.exe -m pytest tests/ -q
# 预期:62 passed

# 2. 演示冲突检测
cd ../../frontier-lessons/05_reflection_research
PYTHONIOENCODING=utf-8 ../../.venv/Scripts/python.exe code.py
# 预期:新发现与旧结论冲突 → 检测到 → 生成补研问题

# 3. 真实跑(需 ENABLE_MEMORY=true + API key)
# 构造一条与记忆旧结论冲突的假搜索结果,跑硬任务
# 报告里应出现「修正说明」(旧结论/新证据/为何采信新的)

7. 本课在两条主线上的位置

  • 评估主线:本课引入了"冲突检测准确率"和"修正有效性"两个可量化点——冲突检测对不对(误报/漏报)、修正后报告质量是否提升。L08 的 TrajectoryEvaluator 会把它们纳入轨迹指标。
  • 上下文工程主线:双通道 reviewer 是上下文工程的判断层——reviewer 要同时处理"报告文本"(当前上下文)和"记忆旧结论"(外部存储调回),判断一致性。这是 L01-L04 机制的协同:记忆提供旧结论、Reflexion 提供反思框架、双通道把反思落到具体的事实修正。

🎯 面试话术

「我的 reviewer 有双通道:文字通道管报告质量(不合格→重写),事实通道管结论正确性(新旧冲突→定向补研)。冲突检测用 LLM judge 判断新发现和记忆旧结论是一致/冲突/无关,冲突时生成补研问题回到 research_team 验证,writer 在报告里写修正说明——旧结论/新证据/为何采信新的。防死循环靠两个计数器:重写和补研各有上限。Agent 不只改错字,还改错误认知。」