配套笔记:Agent 架构如何设计 · PE与PEV架构 · 如何防止幻觉
本文用图说话,把 V1(过度设计)与 V2(重构后)的架构差异可视化,便于面试白板讲解。
一、V1:过度设计的 PE 状态机(翻车现场)
链路:Planner → Executor → Gatekeeper → Verifier → Composer
5 个 LLM 节点 + 全量状态传递,看起来职责清晰,实则是"用编排复杂性掩盖推理能力不足"。
flowchart TD
U1([用户输入诊断请求]) --> Planner
subgraph LLM["LLM 节点(均消耗推理)"]
Planner["Planner<br/>宏观规划排查路径"]
Executor["Executor<br/>调用工具执行"]
Gatekeeper["Gatekeeper<br/>(LLM) 参数校验"]
Verifier["Verifier<br/>(LLM) 结果审查"]
Composer["Composer<br/>(LLM) 总结报告"]
end
Planner -->|"规划路径(猜)"| Executor
Executor -->|"结果踢回重规划"| Planner
Executor --> Gatekeeper
Gatekeeper -->|"通过"| Verifier
Verifier -.->|"打回:结论不行"| Executor
Verifier -->|"通过"| Composer
Composer --> R1([诊断报告])
%% 翻车点标注
Planner -.- x1["❌ 宏观规划 vs 微观试探错位<br/>踢皮球割裂推理连贯性"]
Verifier -.- x2["❌ LLM 审查 LLM<br/>死循环 + 双重幻觉"]
Executor -.- x3["❌ 1000 行脏日志全量塞入<br/>上下文腐烂 → 过度输出"]
Gatekeeper -.- x4["❌ 确定性逻辑做成 LLM 节点<br/>浪费一次推理 + 不可靠"]
classDef llm fill:#fce4ec,stroke:#c2185b,stroke-width:1px
classDef bad fill:#fff3e0,stroke:#e65100,stroke-width:1px,stroke-dasharray:4 3
class Planner,Executor,Gatekeeper,Verifier,Composer llm
class x1,x2,x3,x4 bad
三大致命弊端:
- 踢皮球:诊断是数据驱动的"走一步看一步",PE 强行前置宏观 Plan,Planner 要么瞎猜路径,要么 Executor 出结果就踢回重规划。
- 死循环 + 双重幻觉:LLM 审 LLM,Verifier 打回 Executor 改了还打回,Token 烧穿;Verifier 自己也产生"审查幻觉"。
- 上下文断裂/膨胀:全量传 → 上下文爆炸;摘要传 → 丢失关键线索。
二、V2:单 ReAct Agent + 强 Harness + 分层 Verify(重构后)
核心思想:把推理还给 ReAct,把校验还给代码。
flowchart TD
U2([用户输入诊断请求]) --> Router{"命中已知 SOP?"}
Router -->|"是(80% 高频)"| Highway["🛣️ Highway 流水线<br/>专家固化 SOP = 离线 Plan<br/>固定 PE,不走推理"]
Highway --> Sec["秒级出结果"]
Router -->|"否(长尾复杂)"| Agent["🧠 单 ReAct DiagnosisAgent<br/>While 循环:感知-决策-行动-反馈<br/>边查边想,过程流式输出"]
subgraph Harness["Harness 代码层(0 LLM)"]
direction TB
RTK["① 工具层 RTK 清洗<br/>1000 行日志 → 只留 ERROR±5 行<br/>DB 记录 → 聚合为指标"]
Schema["② JSON Schema 契约<br/>thought≤50字 / 格式校验<br/>不合格直接打回"]
Assert["③ 物理门禁<br/>evidence_id 真实存在?<br/>raw_path 文件存在?"]
end
Tools[("工具集<br/>查日志 / 指标 / Trace / DB")]
Agent <-->|调用 + 清洗后返回| RTK
RTK --> Tools
Agent -->|每步输出| Schema
Schema -.->|不合格打回| Agent
Agent -->|"结构化草稿报告"| Assert
Assert -.->|失败:假证据/格式错| Agent
Assert -->|成功:写入暂存区<br/>状态 PENDING| UI["前端过渡态<br/>'正在安全校验…'"]
UI -.->|后台异步触发| Verifier2["🔍 独立 Verifier Agent<br/>隔离上下文(仅看证据+草稿)<br/>语义校验:时间线对齐?"]
Verifier2 -->|输出置信度分数| Push{"基于置信度<br/>WebSocket 二次推送"}
Push -->|">=0.7 高置信"| R2["推送强诊断结论"]
Push -->|"0.4~0.7 中置信"| R3["结论 + '建议人工复核'"]
Push -->|"<0.4 低置信"| R4["只推原始日志/时间线<br/>不编结论"]
Push -->|"异步 >8s 未返回"| R5["降级:推草稿 + 超时提示"]
classDef react fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
classDef code fill:#e8f5e9,stroke:#2e7d32,stroke-width:1px
classDef async fill:#fff8e1,stroke:#f9a825,stroke-width:1px,stroke-dasharray:5 3
classDef highway fill:#f3e5f5,stroke:#8e24aa,stroke-width:1px
class Agent react
class RTK,Schema,Assert code
class Verifier2,Push,UI async
class Highway highway
三、V1 → V2 的降维对照表
| 维度 | V1(过度设计) | V2(重构后) | 核心动作 |
|---|---|---|---|
| 主推理 | Planner + Executor 拆成 2 个 LLM 节点 | 单 ReAct DiagnosisAgent |
合并 |
| 总结 | 独立 Composer 节点 | ReAct 终点直接输出结构化报告 | 砍掉 |
| 参数校验 | LLM Gatekeeper 节点 | 代码层 JSON Schema Linter(0 LLM) | 下沉为代码 |
| 数据清洗 | 没有 | 工具层 RTK 机制 | 新增代码层 |
| 结果审查 | 主链路同步 Verifier(LLM)→ 死循环 | 物理验真(代码同步) + 语义校验(异步 Agent) | 分层 + 脱链 |
| 高频场景 | 全走 ReAct | Highway 流水线旁路 | 旁路 PE |
| 防幻觉 | 靠"多加监工" | 上下文干净 + 契约 + 物理门禁 + 负反馈 | 治源 |
四、单 Agent vs 多 Agent 选型决策图
终极拷问的答案:不要为"拆"而拆,看任务拓扑 + 两条硬指标。
flowchart TD
Start([要不要引入多 Agent / Graph?]) --> Q1{"任务拓扑?"}
Q1 -->|"线性深挖<br/>前一步决定后一步查什么"| Single["✅ 单 Agent + 强 Harness<br/>拆了会丢上下文连贯性"]
Q1 -->|"扇出汇聚<br/>子任务互不依赖可并行"| Q2{"单 Agent 还撑得住?"}
Q2 -->|"工具 ≤10 且上下文可压"| Single2["✅ 仍用单 Agent"]
Q2 -->|"工具 >10 或上下文物理爆炸"| Multi["✅ Supervisor 多 Agent<br/>子 Agent 并行跑<br/>各自消化原始数据,只传结论摘要"]
Single --> CheckHard{"需要状态外化 / 可中断恢复?"}
Single2 --> CheckHard
CheckHard -->|"否"| NoGraph["✅ 普通 While 循环即可<br/>不需要 Graph 框架"]
CheckHard -->|"是(跑到一半存档/等人审)"| Graph["⚠️ 才引入 LangGraph<br/>仅为 状态外化 + 断点续跑"]
classDef keep fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px
classDef warn fill:#fff3e0,stroke:#e65100,stroke-width:1px
class Single,Single2,NoGraph keep
class Multi warn
class Graph warn
两条硬性触发线(触发其一才演进多 Agent):
- 单 Agent 工具数 > 10,工具选择准确率断崖式下降。
- 即便 RTK 清洗 + 文件卸载,上下文仍物理装不下。
五、防幻觉"四层防线"因果链(数据面细节)
flowchart LR
Input[("工具原始返回<br/>1000 行脏日志 / 大表")] --> L1
L1["防线1<br/>RTK 清洗<br/>切断脏数据输入<br/>只留 ERROR±5 / 聚合指标"]
L1 -->|干净数据| Brain["🧠 Agent 推理"]
Brain -->|每步输出| L2["防线2<br/>JSON Schema 契约<br/>锁死输出格式<br/>超50字/格式错直接打回(0 LLM)"]
L2 -.->|不合格| Brain
Brain -->|最终报告| L3["防线3<br/>物理门禁<br/>evidence_id 查会话历史<br/>raw_path 查文件系统<br/>绝不靠 LLM 验真"]
L3 -.->|不合法| Brain
L3 -->|通过| L4["防线4<br/>交叉验证(异步)<br/>日志结论 vs 指标结论<br/>日志时间线 vs Trace时间线<br/>需≥2独立证据支持"]
L4 -->|不一致| Low["低置信度报告<br/>不强行缝合"]
L4 -->|一致| High["高置信度结论"]
Bonus["附加:闭环负反馈<br/>配置回滚先 Dry-run<br/>真报错喂回当 Observation<br/>打破真空自圆其说"]
Brain -.->|有副作用动作| Bonus
Bonus -.->|物理阻力| Brain
classDef defense fill:#e8f5e9,stroke:#2e7d32,stroke-width:1px
classDef brain fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
class L1,L2,L3,L4,Bonus defense
class Brain brain
六、一句话方法论(面试收尾)
把推理还给 ReAct,把校验还给代码,把上下文洗干净。
成熟的 Agent 架构,标志不是组件多丰富、Graph 多复杂,而是把模型能力接入可交付的工程运行时——用 While 循环驱动大脑,用 Harness 代码锁住手脚。