type
Post
status
Invisible
date
Mar 31, 2026
slug
claude-code-source-walkthrough
summary
cc源码阅读
tags
开发
category
技术分享
titleIcon
password
icon
insider
🫗
开源社区又添一位大将(bushi)
对比codex的上下文压缩
工具调用
 
 

破局之道四:超越 Schema 的 Tool Use Examples

大模型调用工具经常“翻车”的另一个隐形杀手,在于复杂的格式歧义。
  • Schema 的天然局限:JSON Schema 在约束数据类型(如 due_date 为 string)方面表现优秀,但在定义“业务用法”上无能为力。模型无从得知 due_date 究竟需要 "2024-11-06" 还是 "Nov 6, 2024",也不知道某个 id 到底应该是一个纯数字还是加上 "USR-" 前缀[1]。
  • 在定义中融入示例(Few-shot prompting):Anthropic 给出了一个非常实用的设定——在工具定义中加上 input_examples。通过几组具备代表性的(如必填项怎么传、边缘情况怎么传)实际入参示例,为模型提供隐式的 Few-shot 学习。内部测试数据显示,这种方法能将面对复杂参数结构时的准确率从 72% 显著提升至 90%[1]。

总结:心智模型的认知跃迁 (Mindset Shift)

寻找到正确的 Harness 架构,关键并不在于代码的堆砌,而是要完成以下核心的认知转换:
  1. 重新定义 Context 的作用:Context 是极其昂贵的、用来理解意图和编排计划的逻辑推理工作区(Workspace for Reasoning),绝不是用来存储海量账单的临时数据库。所有枯燥的机械计算和数据处理,应当全数剥离并下放至代码沙盒中去完成[1]。
  1. 顺应模型的原生天赋:无论是 Claude、OpenAI 还是现代开源大模型,其预训练语料中都包含了海量的代码(如 Python 和 TypeScript)。相比于写一大堆 System Prompt 强逼模型去遵循深层嵌套且容易出错的 JSON Schema,直接让模型调用 Python 函数显然更契合它们的“原生程序员”直觉[1]。
  1. 寻找最简单的可行解(Layer Features Strategically)
    1. 系统架构的设计需要遵循“做减法”的原则,仅当模型能力存在特定瓶颈时才增加对口的复杂性[1]:
      • 遇到工具定义本身导致的上下文膨胀 ➔ 引入 Tool Search Tool[1]。
      • 遇到庞大中间结果流转导致的幻觉和超高延迟 ➔ 引入 Programmatic Tool Calling[1]。
      • 遇到频繁的参数类型与格式化崩溃 ➔ 引入 Tool Use Examples[1]。
当这些特性被恰如其分地整合在一起,我们便能拥有一个能够从容处理长周期、复杂分析任务的生产级别 AI Agent。
 

传统工具调用(Traditional Tool Calling)的上下文膨胀危机与工具搜索方案

在构建 AI 智能体的早期阶段,开发者通常习惯于将所有可能用到的工具定义(Tool definitions)在一开始就全部加载到系统提示词(System prompt)中。视频指出,当你在系统内集成了大量的工具和模型上下文协议(MCP, Model Context Protocol)服务器时,这种做法会带来灾难性的后果。
  • 上下文膨胀的直观展现:
    • 作者在视频中展示了一个集成在自定义 Python 和 React 应用中的智能体后台(使用 Langfuse 进行追踪)。仅仅是对智能体说了一句简单的“Hello”,系统在没有任何实质性交互的情况下,就已经消耗了 13,000 个 Token。通过后台的生成追踪(Generation trace)可以发现,系统一次性将 60 个不同的工具加载到了上下文(Context)中。这些工具主要来自于两个 MCP 服务器:Playwright MCP 和 GitHub MCP。这种“全量预加载”(Front-loading)的方法不仅消耗了惊人的 Token 数量,而且当系统规模扩展时,AI 智能体会在庞大的工具库中迷失,极难为当前任务挑选出正确的工具(Wrong Tool 问题)。
  • Anthropic 的解决方案:工具搜索工具(Tool Search Tool):
    • 为了解决这个问题,Anthropic 提出了一种动态发现机制。其核心逻辑是:不要预先加载所有工具,而是推迟加载(Defer the loading),让智能体自己去搜索所需的工具。
    • 步骤 1:工具注册中心(Tool Registry): 所有的工具都被集中存放在一个注册中心里,初始状态下它们并不在模型的上下文中。
    • 步骤 2:暴露搜索接口: 智能体唯一默认拥有的工具是“Tool Search Tool”。当用户提出需求时,智能体首先调用这个搜索工具,通过输入名称或关键字(Keyword)来检索可能需要的工具。
    • 步骤 3:动态加载(Dynamic Loading): 当智能体通过搜索找到了对应的工具(例如 GitHub 的 list_commits 工具),系统才会将这个特定工具的完整架构(Full Schema)加载到当前的对话上下文中。
  • 实际效果演示:
    • 作者在视频中将 MCP 服务器的加载模式标记为“延迟加载”(Deferred loading)并重启服务。再次对智能体说“Hello”时,Token 消耗量直接下降到了 6,300 个。此时加载到上下文中的工具仅有 12 个,而第 12 个正是“Tool Search Tool”。随后,作者要求智能体获取某个私有 GitHub 项目的最新提交记录(Latest commit)。智能体首先执行了工具搜索,找到了 list_commits 工具,将其加载,并成功返回了包含 Commit ID 和提交信息的正确结果。此后,当作者继续追问“给我倒数第二个提交记录”时,由于 list_commits 已经在上下文中,智能体无需再次搜索,直接调用该工具即可。这种模式极大地保持了上下文的整洁性,为后续的复杂推理留出了空间。

编程式工具调用(Programmatic Tool Calling):终结中间结果的无效堆积

除了工具定义带来的膨胀,传统的工具调用还面临着另一个巨大挑战:中间结果(Intermediate Results)导致的数据堵塞。当智能体需要执行批量数据处理或多步骤查询时,传统的“单次 API 调用 - 返回结果 - 再次调用”模式显得极其低效。
  • 业务场景:Q3 差旅预算合规性检查(Q3 Travel Budget Compliance Check):
    • 视频引用了 Anthropic 官方文章中的一个经典商业任务:“找出哪些团队成员超出了他们的 Q3 差旅预算?”系统提供了三个工具:get_team_members(获取团队成员名单)、get_expenses(获取特定用户的报销费用)和 get_budget_by_level(获取特定职级的预算限制)。
  • 传统方法的灾难性表现:
    • 如果使用传统的工具调用模式,智能体的执行逻辑如下:
      1. 调用 get_team_members 获取所有成员(假设有 20 人)。
      1. 针对这 20 个人中的每一个,调用 get_expenses。这需要进行 20 次独立的工具调用(Tool calls)。
      1. 获取每个人的预算限制。
      1. 在上下文中手动计算每个人的总费用,并与预算进行比对。
      作者使用 OpenRouter 上的 Claude Haiku 模型测试了这种传统方法。后台的追踪记录(Traces)显示,模型进行了整整 56 次工具调用(56 tool calls),经历了 6 轮(Rounds)的来回交互,总共消耗了 76,000 个提示词令牌(76,000 prompt tokens)。在这个过程中,数十条包含机票、酒店、餐饮明细的原始 JSON 数据被塞进了上下文窗口。更糟糕的是,经过如此庞大的计算,模型最终未能提供全面准确的答案(遗漏了超支 1,700 美元的 Marcus Johnson)。
  • 编程式工具调用的革命性突破:
    • 为了展示编程式调用的威力,作者切换到了一个全新的开源模型:Qwen 3.5 27B(270 亿参数模型)。在编程式调用中,智能体不再试图亲自处理每一条数据,而是转变成了一个编写脚本的程序员。
    • 代码生成(Code Generation): 智能体理解任务后,直接生成一段包含 for 循环、变量、数据转换和错误处理的 Python 代码。例如,在代码中遍历所有团队成员,调用获取费用的函数,求和,并使用 if 条件判断是否超支。
    • 迭代与自我修复(Iteration and Self-Correction): 在实际演示中,Qwen 3.5 首次生成的代码在执行时报错了。这是因为模型在没有看到实际数据前,并不知道工具返回的精确 JSON 结构。然而,智能体能够读取错误追溯(Traceback),理解错误原因(例如遇到了未知的数据结构),然后自动修改 Python 脚本并再次执行。经过几次自我迭代,脚本成功运行。
    • 惊人的效率对比: Qwen 3.5 最终准确找出了所有 4 位超支的员工(Sarah Chen, Marcus Johnson, Alex Nguyen, Emily Rodriguez)及精确的超支金额。而这一切仅仅花费了 4 次工具调用(4 tool calls)和 45,000 个令牌(45,000 tokens)。相比传统方法,大幅降低了成本,且由于数据处理全部在 Python 脚本的内存中完成,对话上下文完全没有被冗长的中间报销明细所污染。

核心系统架构与安全隔离:沙盒(Sandbox)与工具桥接(Tool Bridge)机制

让 LLM 自己编写代码并运行,听起来极具风险。如果智能体生成的代码包含恶意指令,或者不小心删除了系统文件怎么办?视频详细解析了如何利用沙盒与工具桥接技术来构建一个“生产级别”(Production-grade)的安全执行环境。
  • 轻量级 LLM 沙盒(LLM Sandbox):
    • 作者介绍了一个名为 lm-sandbox 的开源项目。这是一个轻量级的便携式沙盒环境,专门为 LLM 生成的代码设计,支持 Docker 或 Podman。
    • 隔离执行(Isolated Execution): 当 FastAPI 后端接收到 LLM 生成的代码时,它会瞬间启动一个 Docker 沙盒容器(Container)。这段 Python 代码只在这个与宿主机(Host system)完全隔离的环境中执行。
    • 网络隔离(Network Isolation): 出于安全考虑,这个沙盒容器被剥夺了所有的互联网访问权限(No internet access)。它不能随意向外发送 HTTP 请求,也不能直接连接公司的生产数据库。为了进一步提高安全性,作者建议使用 G-Visor,因为传统的 Docker 容器仍然共享宿主机的内核,而 G-Visor 提供了更深层次的隔离。
  • 创新的工具桥接机制(Tool Bridge):
    • 既然沙盒没有网络权限,那 Python 脚本内部如何调用 get_expenses 这种需要查询外部系统的函数呢?这就需要“工具桥接”机制。
    • 存根函数(Stubs): 系统会将 MCP 中定义的工具转换为 Python 的存根函数(Auto-generated Python functions),并注入到沙盒中。对于沙盒里的代码来说,调用这些工具就像调用普通的 Python 库一样自然。
    • 请求路由与认证: 当脚本执行到调用工具的代码时,存根函数会将请求连同一个会话 ID(Session ID)发送回宿主机的 FastAPI 后端(这是沙盒唯一被允许通信的通道)。
    • 后端代理执行: FastAPI 后端接收到请求后,通过 Session ID 验证身份,然后代替沙盒去请求外部的数据库或 MCP 服务器,获取到结果后,再把数据穿透回沙盒中。这样一来,核心凭证(API Credentials)和密钥永远留在安全的后端,沙盒本身完全是个“瞎子”,只能被动接收处理需要的数据。
  • Cloudflare 研究的印证: 视频引用了 Cloudflare 的最新研究,证明了 LLM 相比于拼凑复杂的 JSON MCP 调用,它们在处理标准编程语言(如 TypeScript 或 Vanilla Python)时表现得更加出色。将 MCP Schema 转换为代码环境下的存根,实际上迎合了 LLM 预训练数据的分布优势(大量的开源代码),从而提升了整体表现。

高效工具设计(Efficient Tool Design)与按需分层策略

随着 MCP 协议的普及,单个服务器可能包含数十个工具。如果不加节制,系统很容易崩溃。视频最后总结了一套关于如何设计和组织工具的策略方法论。
  • 避免过度提供工具:
    • Anthropic 的文章提到,GitHub MCP 曾经包含 35 个工具,仅这些定义就占用了 26,000 个 Token(不过后续版本已优化至 4,000 个 Token)。如果接入 5 个类似 JIRA、Slack 这样的重型服务器,还没开始对话,55,000 个 Token 就已经消失了。这也是为什么必须依赖 Tool Search 工具的原因。
  • 工具使用示例(Tool Use Examples)的威力:
    • 传统的 JSON Schema 擅长定义数据结构(如字符串、整数),但在表达“使用模式”(Usage patterns)时却无能为力。例如,如果一个 API 需要一个 due_date(截止日期)的字符串,模型怎么知道是该输出 "2024-11-06" 还是 "Nov 6, 2024"?
    • 在定义中嵌入示例: 解决方案是在工具定义中直接提供请求样例(Input examples)。通过向模型展示具体的调用模板,内部测试表明,这能将复杂参数处理的准确率从 72% 大幅跃升至 90%(improved accuracy from 72% to 90%)。这相当于一种隐式的少样本提示(Few-shot prompting)。
  • 策略分层(Layer features strategically):
    • 作者建议不要盲目叠加所有功能,而是根据系统的最大瓶颈(Biggest bottleneck)来分层使用:
      1. 遇到工具定义导致的上下文膨胀(Context bloat from tool definitions): 引入 工具搜索工具(Tool Search Tool)
      1. 遇到庞大中间结果污染上下文(Large intermediate results polluting context): 引入 编程式工具调用(Programmatic Tool Calling),利用代码脚本替代对话历史来处理数据。
      1. 遇到参数错误或格式畸形的调用(Parameter errors and malformed calls): 引入 工具使用示例(Tool Use Examples)
  • 减少成本与提高模型表现

4. 框架 & 心智模型(Framework & Mindset)

框架:智能体架构的“按需与隔离”执行框架(The "On-Demand & Isolated" Execution Framework for AI Agents)

从视频内容中,我们可以抽象出一套为现代 AI 智能体设计的“按需与隔离”执行框架。这套框架彻底推翻了早期智能体“大而全”的设计思路,转而走向了模块化、精细化和高度安全的架构范式。这套框架可以被清晰地拆解为以下三个核心步骤:
  • 第一阶段:能力工具的延迟加载与动态发现(Deferred Loading & Dynamic Discovery)
    • 在构建智能体时,我们必须摒弃将所有能力清单提前硬编码到系统提示词中的习惯。相反,系统应该维持一个极简的初始上下文,仅保留一个“索引工具”(即 Tool Search Tool)。所有的业务能力(如查询数据库、读取 GitHub 提交、发送邮件)都被静态存储在外部的工具注册表中。当且仅当智能体在理解用户意图后,判定需要某项能力时,它才会通过搜索动作将对应的工具 Schema 动态拉取到对话上下文中。这种“按需加载”的架构不仅极大节省了 Token 成本,更重要的是它避免了 LLM 在面对海量工具时产生的注意力分散和“工具选择幻觉”。
  • 第二阶段:控制流向代码环境的转移(Shifting Control Flow to Code Environments)
    • 这是该框架中最具颠覆性的一环。传统架构下,业务的逻辑循环(如遍历列表、条件过滤)是由 LLM 通过一轮又一轮的自然语言对话(Chat turns)来驱动的。在本框架中,LLM 不再作为执行器,而是作为“编译器”。遇到涉及多步逻辑或大量中间数据的任务时,系统强制要求智能体生成一段 Python 或 TypeScript 脚本。数据查询、清洗、计算(如遍历 20 个员工的报销单并进行求和比对)统统交给脚本底层的解释器(Python Runner)去执行。这样一来,高达数万 Token 的中间数据(如报销明细、机票账单)只在脚本内存中流转,最终只有几百个 Token 的总结报告(Script Result)会被返回给 LLM。这本质上是将繁重的数据处理工作从昂贵的“神经上下文”转移到了廉价且精准的“传统计算内存”中。
  • 第三阶段:零信任隔离与穿透通信(Zero-Trust Isolation & Penetrative Communication)
    • 随着代码生成成为核心驱动力,安全成为必须解决的命题。该框架引入了基于 Docker 和 G-Visor 的零信任沙盒机制。LLM 生成的代码被视为“不可信负载”,必须在无外网权限、系统资源受限的隔离容器中运行。为了让这段被隔离的代码仍能发挥业务价值,框架设计了“工具桥接”(Tool Bridge)机制。代码中对外部系统(如财务数据库)的调用请求,会被截获并转换为带有 Session ID 的 HTTP 内部请求,发送回高度信任的宿主机后端(Backend Server)。由后端代理完成敏感操作后再将纯净的数据结果回传给沙盒。这种机制完美实现了“代码逻辑运算权限”与“敏感数据获取权限”的物理级解耦,是构建企业级智能体不可或缺的基础设施。

心智模型:从“JSON 填空者”到“全栈程序员”的认知跃迁(Mindset Shift: From "JSON Filler" to "Full-Stack Developer")

理解这期视频的核心,不仅仅是掌握几项新技术,更要求开发者和架构师在对待大型语言模型(LLMs)时,完成一次深刻的“心智模型”转变。
  • 重构对 LLM 最佳优势的认知:顺应其代码原生性
    • 在过去的一两年里,我们习惯于将大模型视为一个高级的“JSON 格式化引擎”。我们花费大量时间编写详尽的系统提示词,要求模型必须严格遵循某种深层嵌套的 JSON 结构来调用 API。然而,Cloudflare 的研究和本视频的实践揭示了一个关键事实:LLMs 的训练语料中包含了海量的开源代码(如 Python、TypeScript)。相较于拼凑生硬的 JSON Schema,它们在编写包含业务逻辑的控制流(Control Flow)和原生函数调用时,表现得更加游刃有余。因此,开发者的心智应当从“如何强制模型输出符合规范的 JSON”转变为“如何为模型提供一套清晰好用的 Python SDK 存根(Stubs)”。当你把工具伪装成原生的编程函数库时,模型就能发挥出其作为“原生程序员”的巨大潜力。
  • 重新定义上下文的作用:Context 是推理空间,不是数据库
    • 传统工具调用失败的根本原因在于对“上下文窗口”(Context Window)的滥用。我们常常错误地将 LLM 的上下文当成了用来存储中间数据的临时数据库。将几十个人的原始报销单数据全部塞进对话历史,不仅会迅速耗尽 Token 限额,还会因为“大海捞针”效应(Needle in a haystack)导致模型逻辑混乱、产生幻觉(例如漏掉超支的 Marcus Johnson)。新的心智模型要求我们将上下文视为极度稀缺的“逻辑推理工作区”(Workspace for Reasoning)。任何纯粹的数据堆砌和机械计算都应该被剥离出去(通过代码沙盒)。我们要保护上下文的纯洁性,让 LLM 专注于理解意图、制定计划、编写代码以及总结最终结果。
  • 拥抱“容错与迭代”的执行闭环(Embracing the Error-and-Iterate Loop)
    • 在使用基于 JSON 的离散 API 调用时,一旦模型输出格式错误或者传递了错误的参数,整个调用链条往往会面临硬性崩溃(Fatal Crash),只能依赖重新撰写 Prompt。而在“编程式工具调用”的心智中,我们需要建立一种“允许失败,自我修复”的宽容系统。像 Qwen 3.5 这样的模型第一次写出的代码往往是不完美的(比如错误估计了数据库返回的 JSON 嵌套层级),但这并不可怕。系统设计者应当将代码运行产生的 Traceback 报错信息原封不动地反馈给模型。模型具备极强的代码 Debug 能力,它能够通过阅读错误日志,理解数据的真实形态,进而自动修改代码并重试。这就要求开发者不再追求单次调用的“One-shot”完美率,而是致力于打造一个能够支撑智能体在沙盒中自主进行“尝试 - 报错 - 修正 - 成功”闭环的鲁棒性环境。
 
 
 
Chrome extension recommendation (1)English Subsite at top-right
Loading...
2024-2026CamelliaV.

CamelliaV | Java;前端;AI;ACGN;