快速结论:当 LLM 在工具调用参数里”自作主张”生成了本应由 InjectedToolCallId 注入的 tool call ID 时,LangChain 会把这个伪造值透传给工具函数,而不是用真实的 ToolCall.id 覆盖它,导致工具拿到的执行上下文 ID 错误。优先排查工具的 args_schema 是否显式包含了该注入参数,以及 LangChain 版本是否已包含修复补丁。
适用环境:LangChain(langchain_core,涉及 langchain_core/tools/base.py 的注入逻辑)。Issue 中未提供操作系统、Python、CUDA、显卡或第三方依赖版本信息。
最快修复方案:暂无确认的一步修复方案。原 Issue 由 PR #32766 修复,但评论补充表明使用自定义 args_schema 时问题仍会复现,修复并不完整。
注意事项:不要依赖”把注入参数写进 docstring / schema”来规避问题,因为这反而更容易诱导 LLM 生成该参数。升级 LangChain 后仍需按下方验证方法自行确认覆盖逻辑是否生效,尤其在自定义 schema 场景下。
问题场景
使用 LangChain 的 @tool 装饰器或 StructuredTool.from_function 定义一个工具函数,函数签名中包含一个用 Annotated[str, InjectedToolCallId] 标注的参数(例如 tool_call_id)。这类参数本应由 LangChain 从 ToolCall.id 自动注入,而不是由模型生成。
当模型在生成的 tool call 参数里包含了这个字段(常见诱因是它出现在 docstring 或工具描述中),或者调用方手动构造了冲突参数时,工具函数会收到模型伪造的 ID,而不是顶层真实的 ToolCall.id。
报错原文
AssertionError: assert 'fake_llm_id' == 'real_id_456'
- real_id_456 (expected: real tool call ID)
+ fake_llm_id (actual: LLM-generated fake ID)
# 评论补充的自定义 schema 对比输出:
custom_schema=False, received_id=real_id, message_id=real_id
custom_schema=True, received_id=conflicting_id, message_id=real_id
原因分析
最可能的原因是 langchain_core/tools/base.py 中注入逻辑的条件判断有缺陷。原 Issue 指出的问题代码(约第 660 行)大致如下:
for k, v in get_all_basemodel_annotations(input_args).items():
if (
_is_injected_arg_type(v, injected_type=InjectedToolCallId)
and k not in tool_input # ❌ 仅在参数缺失时才注入
):
tool_input[k] = ...
由于判断条件是 k not in tool_input,只要 LLM 已经生成了该参数,真实值就不会被注入,InjectedToolCallId 的覆盖语义被绕过。
评论进一步指出:原 Issue 由 PR #32766 修复,但当使用自定义 args_schema(且该 schema 不含 tool_call_id)时,冲突 ID 仍会被传入工具函数。此时工具函数内部拿到 conflicting_id,而返回的 ToolMessage 却标记为 real_id,两者不一致——这可能说明自定义 schema 路径未复用同一套覆盖逻辑。
环境排查
- 确认 LangChain /
langchain_core版本,核对是否已包含 PR #32766 的修复;若为旧版本,先升级再复测。 - 确认工具定义方式:使用
@tool自动生成 schema,还是通过StructuredTool.from_function传入自定义args_schema。 - 确认自定义
args_schema(若使用)是否显式包含tool_call_id等注入参数字段。 - 确认工具 docstring / 描述中是否提到该注入参数,因为这可能诱导 LLM 生成该字段。
- 确认调用方传入的是完整
ToolCall字典(含顶层id),而非只传 args。
解决步骤
- 先升级到包含 PR #32766 的 LangChain 版本,复测原始的”LLM 生成参数”场景是否已修复。
- 若你使用的是自定义
args_schema,单独构造冲突参数的对比用例复测。可参考评论中的最小复现:同一函数分别用自动生成 schema 和自定义PublicArgsschema 调用,比较received_id与message_id是否一致。 - 若自定义 schema 仍复现,检查
args_schema是否暴露了注入参数字段。可优先尝试从对外 schema 中移除该字段,让注入逻辑走自动路径(此处理为规避思路,未在 Issue 中验证为通用修复)。 - 若问题依旧,按评论建议的方向跟进:在 Issue 下补充自定义 schema 的复现,或新开 Issue 并关联 #32729 与 #32766,以便维护者确认该覆盖规则是否应扩展到自定义 schema 场景。
- 在等待上游修复期间,可在工具函数内部自行校验:当收到的 ID 与预期不符时,从外部上下文传入真实 ID,而不是直接采信参数值。
验证方法
用评论中的脚本自测:分别以 custom_schema=False 和 custom_schema=True 调用工具,传入顶层 id="real_id" 与参数内 tool_call_id="conflicting_id"。期望两种情况下 received_id 均为 real_id,且 received_id 与 message_id 一致。若 custom_schema=True 时 received_id 仍为 conflicting_id,说明问题未解决。
参考来源
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)