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,而是做一套可复用的编排健壮性改造:
- parser 失败时可恢复,不再一刀切到“模型不可用”。
- 对
CALL_TOOL与澄清语义冲突做统一仲裁,优先澄清。 - 在事件里区分
planner_parse_failed与llm_unavailable。 - 用真实联调验证,并纳入典型 case 集。
A(Action)行动
A1. 编排层改造
- 新增 parse 失败恢复入口(
app/langgraph/decoders.py)
- 新增
recover_plan_from_parse_failure(...) - 尝试从原始文本提取 JSON payload
- 自动修复结构(如从
tool_name/arguments补齐tool_calls) - 若仍不满足 schema,但存在澄清语义,降级为
CLARIFY - 只有最后才走
RESPOND兜底
恢复动作标签:
repair_payload_shapedowngrade_to_clarify
- 新增动作冲突仲裁(
app/langgraph/decoders.py)
- 在
normalize_plan_with_tools(...)增加通用规则: - 当
action=CALL_TOOL且存在非空clarification_question时,改写为CLARIFY - 输出冲突码:
planner_conflict:call_tool_with_clarification
这条规则基于状态与 schema,不依赖 query 文本硬编码。
- plan 节点接入失败分级(
app/langgraph/nodes/plan.py)
PlanParseError不再直接套模型不可用兜底- 接入
recover_plan_from_parse_failure(...) react_plan事件补充:failureClassrecoveryActions
同时区分两类用户文案:
- parse 失败:
当前请求解析失败,请换个说法或补充信息后重试。 - 模型不可用:保留原不可用文案
A2. 测试增强
tests/test_plan_parser.pytest_recover_plan_from_parse_failure_downgrades_to_clarifytests/test_plan_schema.pytest_normalize_plan_with_tools_prefers_clarify_when_planner_outputs_bothtests/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 passedpytest -q:53 passed
R2. 真实联调证据(Case 10)
关键日志信号(来自 logs/typical-cases/case10_p1_parse_recovery_clarify/sse.log):
react_plan.action=CLARIFYparseStatus=recovered_parse_failure_clarifyfailureClass=planner_parse_failedrecoveryActions=["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 事件:
failureClass与recoveryActions可观测,便于后续排障
核心代码文件清单
app/langgraph/decoders.pyapp/langgraph/nodes/plan.pytests/test_plan_parser.pytests/test_plan_schema.pytests/test_orchestrator_langgraph.py典型case.mdscripts/run_typical_cases.sh
脱敏说明
本文仅保留必要技术细节,以下信息均已脱敏处理:
- 网关鉴权头(如 token、签名)
- 内网地址、端口、私有域名
- 可能关联租户或业务身份的标识
若需要演示联调命令,请使用示例占位符:https://example.com、127.0.0.1、<TOKEN>。
P1解析失败恢复:从误报模型不可用到可恢复澄清链路
https://willfordzhan.github.io/2026/03/05/p1/