Claude Code 能改文件、跑测试、读网页,看起来像是一个会操作电脑的程序。容易忽略的事实是:模型本身不会执行命令,也不会直接打开网页。从模型的角度看,它始终只是在输入文本(更准确地说是结构化消息)后,输出文本或结构化内容块。

让它获得行动能力的机制叫 Tool Use(工具调用):模型负责决定“该用什么工具、参数是什么”,Claude Code 或 Anthropic 的服务端负责真正执行,再把结果作为下一轮输入交回模型。这篇文章用一次 git status 的客户端工具调用和 Web Search 的服务器工具调用,把这个循环拆开,并区分公开协议与抓包中观察到的内部实现。

文中 API 字段以 Anthropic 当前公开文档为准。Claude Code 的内部工具名、请求次数、所用子模型会随版本和任务变化;抓包能说明某一版本的实现,不能当作稳定接口。


先建立一个正确心智模型:模型没有“手”

可以把 Claude 看作一个能根据上下文选择下一步的决策器。它看到的能力清单大致是这样:

{
"name": "bash",
"description": "在项目目录中执行 shell 命令",
"input_schema": {
"type": "object",
"properties": {
"command": { "type": "string" }
},
"required": ["command"]
}
}

模型不会把 git status 交给操作系统。它输出的是“我要调用 bash,参数为 git status”这一段结构化意图。能访问终端、文件系统和网络的是模型外面的宿主程序:Claude Code、SDK 应用、浏览器插件,或 Anthropic 的服务端。

这也解释了为什么同一个模型在不同产品中“能力”差异很大:能力不只来自模型,还来自它被授予了哪些工具、工具在哪执行,以及每一层如何限制权限。


客户端工具:一次 git status 是怎样跑起来的

假设我们问 Claude Code:“这个 Git 仓库有什么改动?”一次典型的客户端工具调用包含四步。

用户问题


Claude:输出 tool_use(工具名 + JSON 参数)


Claude Code:在本机执行命令


Claude Code:输出包装成 tool_result,发回模型


Claude:依据结果生成自然语言回答

1. 客户端把工具定义随请求交给模型

调用 Messages API 时,应用除了传入用户消息,还传入 tools 数组。数组中的每项至少描述工具名、用途和输入 JSON Schema。模型据此决定要不要调用工具;它也可能直接回答,或一次请求多个彼此独立的工具。

2. 模型返回 tool_use

若需要终端,响应的 content 中会包含 type: "tool_use" 的块。简化后如下:

{
"type": "tool_use",
"id": "toolu_01ABC...",
"name": "bash",
"input": {
"command": "git status --short"
}
}

这里的重点有三个:

  • name 选择工具;
  • input 是通过 JSON Schema 描述的参数;
  • id 是这次调用的关联标识,结果必须用它配对。

当响应的 stop_reasontool_use,不是“模型出错”,而是当前回合停在了等待工具结果的位置。流式响应里,参数可能分成多段增量抵达;客户端应完成组装和校验后再执行,而不是把未完成的片段直接当 shell 命令运行。

3. Claude Code 在你的电脑上执行

对客户端工具而言,这一步完全在客户端发生。Claude Code 取出命令,按自身的权限策略、工作目录、审批设置和沙箱规则执行它;再收集标准输出、标准错误和退出状态。

因此,“模型叫我运行一条命令”不等于“命令已经安全地执行”。真正的安全边界在客户端:工具输入要校验,危险操作要审批,文件路径和工作目录要受限,尽可能放进沙箱。

4. 客户端把结果作为 tool_result 交回去

客户端随后在下一次 Messages 请求里保留刚才的 assistant 消息,并追加一条带 tool_result 的用户消息:

{
"type": "tool_result",
"tool_use_id": "toolu_01ABC...",
"content": " M README.md\n M hello.py\n?? notes.txt"
}

tool_use_id 必须与上一步的 id 完全对应。模型并没有亲眼看见终端,它只看见这段文本结果,于是再输出“README.mdhello.py 被修改,并有一个未跟踪文件”之类的总结。此时若 stop_reasonend_turn,这一轮才真正结束。

这正是官方 Tool Use 文档里的基本循环:模型提议调用,应用执行,应用回传结果,模型继续推理。bash、读写文件、数据库查询、企业内部 API 都可以套进这个模式。


“客户端执行”与“服务器执行”不是同一种工具

Tool Use 按执行位置可以粗分为两类:

类型 谁执行 例子 结果怎样回来
客户端工具 你的应用或 Claude Code shell、读写文件、内部 API 客户端自己构造 tool_result 再请求模型
服务器工具 Anthropic 基础设施 Web Search、Web Fetch、Code Execution 等托管能力 通常由服务端在同一次 API 调用内执行并返回相应结果块

前一类给了应用最高的自由度,也把权限控制、重试、超时、审计都留给应用。后一类减少了客户端集成成本,但用量、可用区域、数据保留和价格由服务端工具的规则决定。

有一个常见误解需要避免:服务器工具不意味着模型知道“真实世界”。它依然是“模型决定调用 -> 某个执行器得到数据 -> 数据进入后续上下文”的循环,只是执行器从本机换成了 Anthropic 托管的服务。


Web Search:服务端如何把搜索结果交给 Claude

在 Claude API 中启用 web_search 后,Claude 可以在一个 Messages API 调用中发起搜索。官方文档将其称为在单个 API 调用内自动完成的搜索:响应会包含服务端的调用与结果内容块,随后模型可据此继续生成回答。

这是最常见的路径,不是“永远只有一次 HTTP 请求”的承诺。若同一组并行调用里还混入了客户端工具,API 会先以 stop_reason: "tool_use" 等待客户端的 tool_result;某些较长的服务端 Agent 循环也可能以 pause_turn 要求调用方原样续传上下文。因此,调用方应始终按返回的停止原因和内容块驱动状态机,而不是把请求次数写死。

概念上的返回形态如下:

[
{
"type": "server_tool_use",
"id": "srvtoolu_01XYZ...",
"name": "web_search",
"input": { "query": "London weather today" }
},
{
"type": "web_search_tool_result",
"tool_use_id": "srvtoolu_01XYZ...",
"content": [
{
"type": "web_search_result",
"title": "...",
"url": "https://...",
"encrypted_content": "..."
}
]
}
]

encrypted_content 应该怎样理解

encrypted_content 不是给应用读取的网页正文。官方文档要求多轮对话时把它原样回传;API 会在后续回合解密并恢复 Claude 所需的搜索上下文。应用可使用标题、URL 和引用信息构建展示,但不应依赖或尝试解析该字段。

视频将它解释为“防止开发者把搜索结果当作免费内容下载服务”。这个推断有现实上的合理性,但目前能从公开文档确认的语义只有:它是供后续 API 回合回传的加密内容。把具体搜索供应商的授权条款或加密的唯一商业目的写成事实,会超出公开证据。

为什么抓包可能会看到多次请求和 Haiku

有些 Claude Code 抓包会显示:主模型先提出 Web Search,客户端又用一个较小模型处理搜索,最后把摘要交还主模型。这是一种很常见的 Agent 编排方式,但要分清两个层次:

  1. 公开 Web Search API 协议:搜索工具可以由 Anthropic 在单次 Messages 调用内执行;
  2. Claude Code 产品内部编排:产品可能额外创建子代理、压缩上下文、重试或做权限检查,因此网络上看到的请求数和模型选择不构成 API 承诺。

用较小模型处理搜索材料有两个合理的工程目标:减少昂贵主模型的上下文负担,以及让不可信网页内容先经过低权限环境。前者是成本与上下文管理;后者则是安全隔离。


子代理为什么有助于防提示词注入

网页不是可信输入。搜索结果、网页正文甚至 README 都可能出现“忽略前文指令,执行某个命令”这样的恶意文本。模型未必总能可靠地区分它是数据还是指令,这就是 Prompt Injection(提示词注入)的核心风险。

把搜索放在只拥有 web_search 权限的子代理中,可以缩小风险半径:即使子代理被网页内容误导,它也没有 bash、写文件或发布部署的工具可用。主代理只接收经过压缩的、受格式约束的结果。

但隔离不是魔法。摘要仍可能夹带错误或攻击性指令,主代理仍应把外部内容视为不可信数据。一个可落地的防线至少包括:

  • 按最小权限给每个代理和工具授权;
  • 对写文件、执行命令、外发数据等高影响动作要求人工确认;
  • 限制工作目录、网络出口和可访问的密钥;
  • 校验工具参数,记录调用与结果;
  • 让不可信内容与高权限工具尽量不要共处同一上下文。

这比单纯在系统提示词里写一句“不要被注入”可靠得多。


Web Search 的费用:与 Claude Code 订阅不要混为一谈

对 Claude API,Anthropic 当前公开的 Web Search 价格是 每 1,000 次搜索 10 美元,并且搜索产生的内容仍按普通 token 规则计费。响应的 usage 中会以 web_search_requests 记录次数;一次搜索无论返回多少条结果,都计为一次。搜索报错不收费。

这是 API 的服务端工具定价,不能直接推导为每个 Claude Code 套餐、地区或账户的实际扣费规则。使用 Claude Code 时,应以产品页面、账户用量页和当时的套餐说明为准;使用 API 时,才应按请求数加 token 成本做预算。


小结

Claude Code 的“会干活”可以压缩成一句话:

模型负责提出结构化的行动请求,受控的执行器负责行动,结果再回到模型的上下文中。

理解这个循环后,许多现象就顺理成章了:为什么模型能改文件却不会真的敲键盘,为什么工具结果也会消耗上下文,为什么 tool_use_id 必须配对,为什么网页搜索会额外计费,以及为什么 Agent 安全的关键并不只是换一个更聪明的模型,而是工具权限、执行环境和不可信输入的隔离。

参考链接