P1解析失败恢复:从误报模型不可用到可恢复澄清链路

这篇记录一次真实联调中的 P1 修复:同一个用户问题,本应触发澄清,却被错误归因为“模型不可用”。

STAR 复盘

S(Situation)背景

在 2026-03-05 的真实联调中,知识库工具链路已经打通,但出现了错误路由:

  • 用户输入:帮我查知识库
  • 实际事件:llm_request -> react_plan(parseStatus=schema_validation_failed) -> final(模型不可用)
  • 预期事件:clarification_needed(提示用户补充检索主题)

触发条件很典型:

  • LLM 输出了 action=CALL_TOOL,但缺失 tool_calls
  • 现有 PlanOutput 约束要求 CALL_TOOL 必须有 tool_calls
  • 校验失败后被统一兜底到“模型不可用”,导致故障分类错误

T(Task)任务

目标不是修一个 case,而是做一套可复用的编排健壮性改造:

  1. parser 失败时可恢复,不再一刀切到“模型不可用”。
  2. CALL_TOOL 与澄清语义冲突做统一仲裁,优先澄清。
  3. 在事件里区分 planner_parse_failedllm_unavailable
  4. 用真实联调验证,并纳入典型 case 集。

A(Action)行动

A1. 编排层改造

  1. 新增 parse 失败恢复入口(app/langgraph/decoders.py
  • 新增 recover_plan_from_parse_failure(...)
  • 尝试从原始文本提取 JSON payload
  • 自动修复结构(如从 tool_name/arguments 补齐 tool_calls
  • 若仍不满足 schema,但存在澄清语义,降级为 CLARIFY
  • 只有最后才走 RESPOND 兜底

恢复动作标签:

  • repair_payload_shape
  • downgrade_to_clarify
  1. 新增动作冲突仲裁(app/langgraph/decoders.py
  • normalize_plan_with_tools(...) 增加通用规则:
  • action=CALL_TOOL 且存在非空 clarification_question 时,改写为 CLARIFY
  • 输出冲突码:planner_conflict:call_tool_with_clarification

这条规则基于状态与 schema,不依赖 query 文本硬编码。

  1. plan 节点接入失败分级(app/langgraph/nodes/plan.py
  • PlanParseError 不再直接套模型不可用兜底
  • 接入 recover_plan_from_parse_failure(...)
  • react_plan 事件补充:
  • failureClass
  • recoveryActions

同时区分两类用户文案:

  • parse 失败:当前请求解析失败,请换个说法或补充信息后重试。
  • 模型不可用:保留原不可用文案

A2. 测试增强

  • tests/test_plan_parser.py
  • test_recover_plan_from_parse_failure_downgrades_to_clarify
  • tests/test_plan_schema.py
  • test_normalize_plan_with_tools_prefers_clarify_when_planner_outputs_both
  • tests/test_orchestrator_langgraph.py
  • 更新 parse fallback 断言:应为 planner_parse_failed,且文案为“解析失败”

A3. 真实联调与脚本

  • 新增典型用例:典型case.md 的 Case 10
  • 更新批量脚本:scripts/run_typical_cases.sh
  • 将 macOS 不兼容 timeout 改为 curl --max-time

R(Result)结果

R1. 自动化测试

  • pytest -q tests/test_plan_parser.py tests/test_plan_schema.py tests/test_orchestrator_langgraph.py:25 passed
  • pytest -q:53 passed

R2. 真实联调证据(Case 10)

关键日志信号(来自 logs/typical-cases/case10_p1_parse_recovery_clarify/sse.log):

  • react_plan.action=CLARIFY
  • parseStatus=recovered_parse_failure_clarify
  • failureClass=planner_parse_failed
  • recoveryActions=["downgrade_to_clarify"]
  • 下游发出 clarification_needed
  • 全链路未出现“模型不可用”误报

结论:P1 的核心误路由已被修复。

R3. 全量 Case 1~10 观察摘要

通过项:

  • Case1/8:问候直答正常,未误触发工具
  • Case4:知识库命中时,tool_call + tool_result 成对出现
  • Case6:缺参触发澄清
  • Case9:澄清文案已脱敏(未泄漏内部参数细节)
  • Case10:P1 恢复路径按预期生效

待后续跟进:

  • 观察到部分会话存在 conversation_started 重复发射迹象(P2)
  • Case3 在当前数据环境无匹配,转澄清,属于数据映射问题
  • Case7 未触发上游异常,需故障注入复测异常分支

关键证据清单

  • 测试汇总:pytest 结果(53 passed)
  • 典型 case:Case 10 明确验证 schema_validation_failed -> CLARIFY 恢复
  • SSE 事件:failureClassrecoveryActions 可观测,便于后续排障

核心代码文件清单

  • app/langgraph/decoders.py
  • app/langgraph/nodes/plan.py
  • tests/test_plan_parser.py
  • tests/test_plan_schema.py
  • tests/test_orchestrator_langgraph.py
  • 典型case.md
  • scripts/run_typical_cases.sh

脱敏说明

本文仅保留必要技术细节,以下信息均已脱敏处理:

  • 网关鉴权头(如 token、签名)
  • 内网地址、端口、私有域名
  • 可能关联租户或业务身份的标识

若需要演示联调命令,请使用示例占位符:https://example.com127.0.0.1<TOKEN>


P1解析失败恢复:从误报模型不可用到可恢复澄清链路
https://willfordzhan.github.io/2026/03/05/p1/
作者
詹文杰
发布于
2026年3月5日
许可协议