跟着 Qwen Code 的延迟工具桥走两次调用
以下是逻辑摘要,不是复制源码。它限定在普通 function-declaration 模式中一个仍隐藏的 deferred 目标;已预加载、visibleTools、CodeModeOnly 等情况另走分支。
text
setTools(): ToolRegistry.getFunctionDeclarations() → 初始模型声明
hidden deferred 目标不在声明列表;tool_search 与 tool_call 留在列表
请求一:tool_search(query)
检索已注册且隐藏的 deferred 工具 → 返回 <functions>{schema}</functions>
不调用目标;不因此 reveal 目标
请求二:tool_call({ name, arguments })
CoreToolScheduler → resolveDeferredToolCall → 检查目标与上下文
wrapper 改写为真实工具名/参数 → 后续按真实目标调度ToolRegistry.getFunctionDeclarations()默认排除仍隐藏的 deferred 工具;client.setTools()用过滤后的声明集更新模型可见工具。声明过滤 · setToolsToolSearchTool自身保持可见;关键词查询只遍历隐藏 deferred 候选,select:则可精确重看可见工具。处理返回的是 schema 文本。源码的returnSchemas()没有调用revealDeferredTool或执行目标;tool_search的返回文本也不等于模型函数声明刷新。工具构造 · 候选 · 返回resolveDeferredToolCall()校验tool_callwrapper、规范目标名、拒绝桥自身嵌套、要求目标仍是隐藏 deferred,并检查子 Agent 排除规则和声明能力。桥缺半边时也拒绝。它返回的是目标工具对象与参数,不是自己执行目标。解析CoreToolScheduler在调度前调用解析器,再用目标工具名替换 wrapper;它也检查该 Agent 的目标工具 allowlist/blocklist。因此tool_call包装并不是绕开目标权限的捷径。调度改写 · 调度入口
注意:schema 在 tool_search 的回复里可读,与目标出现在模型原生工具声明中是两种不同的可见性。本文没有量化节约多少 token,也没有实测模型是否稳定遵循“先搜索再调用”;不把源码注释里的设计意图当成效果指标。
在线预览稿:书稿仍在校稿,系统篇以文内固定源码版本为准;静态阅读不等于运行验收。