经典 ReAct Agent Loop 改造
LangGraph 图结构重设计、NoSQL 会话读写、确认流图拓扑、SSE payload 补丁等 11 个子问题
1. 背景
旧行为:工具执行完后直接到 response 透传,工具结果直接展示给用户,无 LLM 再加工。
问题:用户看到的是 [工具成功] list_plans\n{...} 而非自然语言总结;与经典 Agent Loop 语义不符(工具结果应回到 LLM 生成最终回答)。
目标:改为经典 ReAct 模式——工具执行结果追加进 messages 后,必须再经 intent_recognition 调用 LLM,由 LLM 决定继续调工具、结束对话或进入「待确认写库」路径。
2. 图结构
- 入口:默认
intent_recognition;confirm=true时入口为confirm_recovery。 - 边:
confirm_recovery→execute_tools;intent_recognition→ 条件边 →persistence|execute_tools|response;persistence→response仅这一条出边(不得再连intent_recognition,否则会同轮并行、绕过 App 确认);execute_tools→stage_mutating_pending|intent_recognition;stage_mutating_pending→persistence;response→END。
3. 执行流程简图
intent_recognition ─┬─ chat / error ──► response ─► END
│
├─ execute_confirmed ─► execute_tools ─┬─► stage_mutating_pending ─► persistence ─► response ─► END
│ └─► intent_recognition (ReAct 闭环)
│
├─ tool_call_staged_reads ─► execute_tools (同上)
│
└─ tool_call / mixed:需确认且 pending 非空 ─► persistence ─► response ─► END
4. 关键路由逻辑
route_after_intent(intent_recognition 出发):
| 条件 | 目标 |
|---|---|
_loop_after_tools 且 pending_tool_calls 非空 | execute_tools |
_loop_after_tools 且 pending 为空 | response |
intent == "execute_confirmed" | execute_tools |
intent == "tool_call_staged_reads" | execute_tools |
needs_confirmation 且 pending_tool_calls 非空 | persistence |
intent in ("chat","error") | response |
route_after_execute_tools(execute_tools 出发):
| 条件 | 目标 |
|---|---|
staged_mutating_calls 非空 | stage_mutating_pending |
| 否则 | intent_recognition(经典 ReAct) |
5. 确认机制与 ReAct 的衔接
- 提案轮:
intent_recognition→persistence(waiting_confirmation+pending_tool_calls入文档库)→response→ 本轮结束。 - 确认轮:新请求
confirm=true→confirm_recovery→execute_tools→intent_recognition→ 继续循环或response。
6. 实际踩坑记录
6.1 未确认即执行写库(同轮偷跑)
根因:persistence 曾同时有出边至 response 与 intent_recognition,同一 superstep 内两后继均可被调度。并行的 intent_recognition_node 读库看到 waiting_confirmation 后将 pending_tool_calls 直接映射为 execute_confirmed,绕过用户确认。
采纳:去掉 persistence → intent_recognition 单边;移除 intent 内「读 DB waiting_confirmation 即自动 execute_confirmed」的分支。
6.2 App 不展示「确认执行」
根因:旧版 persistence_node 合并回图状态时将 needs_confirmation 设为 false,本意是防 intent 误判,结果连 App 依赖的快照标志一并关掉。
采纳:persistence_node 返回更新为 needs_confirmation: True(仍清空 pending_tool_calls,避免重复进 persistence)。
6.3 计划标题整句入库
根因:模型把整句用户话填进 plan_title,原 enrich_create_plan_calls_from_messages 在已有 plan_title 时不再改写。
采纳:在 execute_tools 调用工具前对 create_plan 做 normalize_plan_title_for_create。
7. 小结
经典循环:工具结果 → intent_recognition(LLM)→ 再决策,而非工具后直接 response。
拓扑约束:persistence 只连 response,保证待确认写库不会在同一 send-message 内被并行 intent 偷跑执行。
先读后写:stage_mutating_pending → persistence → response,写操作仍在用户确认后执行。