快速结论:当你在 LangChain 的 create_agent 流程中让工具调用产生过一次无效调用(invalid tool call,例如参数被截断)后,修复合成的 ToolMessage 会变成一个没有对应 tool_use 的孤儿 tool_result,从而让 Anthropic Messages API 在之后每次请求都返回 400。优先排查 _patch_invalid_tool_calls 生成的 tool_result 是否都有匹配的 tool_use。
适用环境:Issue 已确认:LangChain(langchain 1.4.2,langchain-anthropic 1.7.4,master 80b740905);使用 create_agent 与 ChatAnthropic 的 Anthropic 系列线程;复现基于 langchain + langchain-anthropic,可离线运行,无需 API Key。
最快修复方案:暂无确认的一步修复方案。Issue 中给出的首选修复方向是:在 _patch_invalid_tool_calls 中,把每个带 id 的 invalid tool call 提升为同一条 AIMessage 上的常规 tool_call(params 重新解析为 JSON,失败时回退为 {}),使 provider 序列化时始终存在对应的 tool_use 父块。该方案有对应 PR #40854,但截至整理时尚未合并。
注意事项:该修复方向尚未合并进发行版,需要自行跟踪 PR 状态;无 id 的 invalid tool call 不提升(避免生成 provider 无法接受的 id-less tool_call);已经处于损坏状态的持久化线程,需要依靠修复后重新回写状态来“自愈”。
问题场景
用户在使用 LangChain 的 create_agent 构建 Anthropic 系列(langchain-anthropic)Agent 时,一旦工具调用出现无效调用(例如模型返回被截断的 JSON 参数),之后的模型调用就会报 400。因为修复逻辑 _patch_invalid_tool_calls 会为无效调用补一条合成的 ToolMessage,但不会同步修改原 AIMessage;而 Anthropic 序列化器只根据 tool_calls 生成 tool_use,会完全丢弃 invalid_tool_calls,于是这条合成的 ToolMessage 就变成了没有匹配 tool_use 的孤儿 tool_result。由于修复结果会被写回 state,一次无效调用就会让该线程之后每次请求都失败。
报错原文
patched sequence: ['HumanMessage', 'AIMessage', 'ToolMessage', 'HumanMessage']
tool_use ids in payload: []
tool_result ids in payload: ['toolu_01ABC']
orphaned tool_result ids: ['toolu_01ABC']
The Anthropic Messages API rejects this payload with a 400
anthropic.BadRequestError: Error code: 400 - invalid_request_error:
...
原因分析
根本原因在 libs/langchain_v1/langchain/agents/factory.py 的 _patch_invalid_tool_calls:它为每个未应答的 invalid_tool_call 追加一条合成的错误 ToolMessage,但保留原 AIMessage 不变。不同 provider 的序列化器对该字段的处理不一致:langchain-openai 会为无效调用生成 tool_calls 条目,而 langchain-anthropic 只从 tool_calls 构建 tool_use 块,直接丢弃 invalid_tool_calls。于是合成的 ToolMessage 序列化出的 tool_result 在 payload 中找不到父级 tool_use,被 Anthropic Messages API 以 400 拒绝。
环境排查
- 确认
langchain版本(Issue 复现为 1.4.2)以及langchain-anthropic版本(Issue 复现为 1.7.4)。 - 确认是否使用
create_agent并接入了langchain-anthropic的模型(Issue 复现使用ChatAnthropic)。 - 确认历史消息中是否存在
invalid_tool_calls(AIMessage 层)。 - 确认该线程是否已经被“修复结果写回 state”,即一次无效调用后是否持续失败。
解决步骤
- 先用 Issue 提供的复现脚本确认问题:构造一条带
invalid_tool_calls的AIMessage,调用_patch_invalid_tool_calls,再调用ChatAnthropic._get_request_payload,检查返回 payload 中tool_result的tool_use_id是否能在tool_use的id列表中找到。 - 若确认存在孤儿
tool_result,可优先尝试修复方向:在_patch_invalid_tool_calls中,把每个带 id 的 invalid tool call 提升为同一AIMessage上的常规tool_call。做法是用model_copy(update={"tool_calls": [...], "invalid_tool_calls": [...]})重写消息,保留 content、usage metadata 和 response metadata;参数优先按 JSON 重新解析,失败或结果非 dict 时回退为{}。 - 无 id 的 invalid tool call 不提升(现有逻辑本就不为其生成
ToolMessage),避免生成 provider 不接受的 id-lesstool_call。 - 已经被旧修复损坏的持久化线程,同样走上述提升逻辑,使修复后的消息与 state 不同并回写,从而在下次模型调用时自愈。
- OpenAI 风格 provider 不受影响,其 id 原本就会序列化,现在只是改走常规
tool_calls路径。 - 跟踪对应 PR(#40854)是否合并;若尚未合并,注意该方案属于“可优先尝试”,不是发行版已验证的一步修复。
验证方法
重新运行 Issue 中的复现脚本,确认输出的 orphaned tool_result ids 为空列表,即 payload 中每个 tool_result.tool_use_id 都能找到匹配的 tool_use.id,并且结构断言不再为 ["toolu_01ABC"]。若使用 PR 中的回归测试,可运行 pytest tests/unit_tests/agents/test_invalid_tool_calls.py,其中包含“每个 tool_result id 都有父级 tool_call”的不变量测试以及持久化损坏线程自愈测试。
参考来源
AI 工具推荐
想把多个 AI 模型放在一个入口?
GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。
推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。
这个方案解决了吗?
可以继续搜索完整报错,或查看同一工具的其他排查指南。


![[Refactor/Chore] eslint error for node/panel components in CustomNode renderer](https://www.chat-gpts.plus/wp-content/uploads/2026/09/42468-e039c8cf-768x403.jpg)