最新资讯
dev.to 部署 Underdog Bark 3.0 Pro:逐字转写、自定义后端与分块设置 dev.to 为艰难对话构建 AI:五个 Agent、一条安全正则与一位盲评监督者 techcrunch.com Palo Alto Networks 洽谈以 5 亿美元收购 AI Agent 安全初创公司 Clutch theinformation.com 黄仁勋被要求就涉华间谍指控向国会作简报 www.infoq.com Edera 推出 Object Capability Bounded Authority,试图将凭证与 AI Agent 工作负载隔离 wechat 这波杀疯了!旗舰级模型不限量、1个月视频额度免费领 bloomberg.com AI 抛售蔓延至信用市场,软银领跌亚洲美元债 dev.to 如何在专用 GPU 服务器上用 OpenAI 兼容 API 部署 LLM dev.to 审计 153 份 Claude Code 与 Codex 会话记录:User-Agent 与 URL 中的邮箱泄露 dev.to 你的 Agent Harness 应具备的 17 项能力 dev.to 离线 AI 记忆中 0.8 余弦阈值为何失效 dev.to Kimi K3.1 Pro 开放权重:自托管 2.8T 模型前的开发者清单
多元动态
登录 注册
智能体 dev.to · @Thomas Tartrau

Claude 的 JSON 工具调用与程序化工具调用对比

原文 我的收藏

文章比较使用 Claude API 构建 Agent 时连接工具的三种方式,关注其对性能、成本和代码复杂度的影响。传统工具调用采用循环模式:模型请求工具、服务器执行并回传结果、模型再推理并请求下一个工具,每次迭代都是一次完整往返;工具数量增长后问题凸显,例如查询 20 名员工的费用需要 20 次往返,且中间结果不断堆积进上下文。据 Anthropic 的测量,在多服务器配置下,仅工具定义就可能消耗超过 134,000 token。

AI推荐理由 对比 Claude API 中 JSON 工具调用与程序化工具调用等三种方式,指出传统循环式调用随工具数量增长产生大量往返与上下文膨胀,并引用 Anthropic 测量称多服务器场景下工具定义本身可占用逾 134,000 token,对构建 Agent 的开发者有直接工程参考;但正文在第一种方案处截断,缺少完整对比数据。

74

正文

When building an application with the Claude API, connecting tools is the first step toward a functional agent. The model can call functions, query databases, send messages. But how you wire those tools drastically changes performance, cost, and code complexity. In 2026, the Claude API offers three distinct approaches. This article compares them with code, numbers, and practical experience from using all three. The problem: round trips Traditional tool calling works in a loop: the model requests a tool, your server executes it, sends back the result, the model reasons over the result, requests another tool, and so on. Each iteration is a full round trip with the model. The problem becomes concrete as the number of tools grows. Checking expenses for 20 employees? 20 round trips. Every intermediate result piles into the context. According to Anthropic's measurements, tool definitions alone can consume over 134,000 tokens before any conversation in a multi-server setup. Approach 1: JSON schema + manual loop This is the original approach. You define each tool with a JSON schema, send the request to the API, parse the tool_use response, execute the tool, and send back the result. client = anthropic.Anthropic() tools = [{ "name": "query_database", "description": "Execute a SQL query. Returns rows as JSON.", "input_schema": { "type": "object", "properties": { "sql": {"type": "string", "description": "SQL query"} }, "required": ["sql"] } }] messages = [{"role": "user", "content": "What's the revenue by region?"}] while True: response = client.messages.create( model="claude-sonnet-5", max_tokens=4096, tools=tools, messages=messages, ) if response.stop_reason == "end_turn": break for block in response.content: if block.type == "tool_use": result = execute_sql(block.input["sql"]) messages.append({"role": "assistant", "content": response.content}) messages.append({ "role": "user", "content": [{ "type": "tool_result", "tool_use_id": block.id, "content": json.dumps(result) }] }) Enter fullscreen mode Exit fullscreen mode The while True loop is the critical part. You handle the request/response cycle, parse tool_use blocks, accumulate messages, and manage error cases yourself. Pros: full control over every step. You can log, filter results, inject business logic between calls. Cons: lots of boilerplate. Every tool result passes through the model, even if it's just an intermediate value. With 10 tool calls, that's 10 full inference passes. Approach 2: Tool Runner SDK The Tool Runner is a helper in the official Anthropic SDKs (Python, TypeScript, Go, Java, C#, PHP, Ruby). It automates the agentic loop: tool definition, execution, conversation state management, and type validation. In Python, the @beta_tool decorator generates the JSON schema from type hints and the docstring: from anthropic import Anthropic, beta_tool client = Anthropic() @beta_tool def query_database(sql: str) -> str: """Execute a SQL query on the sales database. Args: sql: SQL query to execute """ rows = db.execute(sql) return json.dumps(rows) runner = client.beta.messages.tool_runner( model="claude-sonnet-5", max_tokens=4096, tools=[query_database], messages=[{"role": "user", "content": "What's the revenue by region?"}], ) for message in runner: print(message) Enter fullscreen mode Exit fullscreen mode In TypeScript, two options: betaZodTool with Zod validation (recommended), or betaTool with a plain JSON schema: const client = new Anthropic(); const queryDatabase = betaZodTool({ name: "query_database", description: "Execute a SQL query on the sales database", inputSchema: z.object({ sql: z.string().describe("SQL query to execute"), }), run: async (input) => { const rows = await db.execute(input.sql); return JSON.stringify(rows); }, }); const result = await client.beta.messages.toolRunner({ model: "claude-sonnet-5", max_tokens: 4096, tools: [queryDatabase], messages: [{ role: "user", content: "What's the revenue by region?" }], }); Enter fullscreen mode Exit fullscreen mode The Tool Runner handles the loop automatically: when Claude requests a tool, the runner executes it and sends back the result. No more while True, no manual tool_use block parsing. Pros: less code, type safety with Zod or Python type hints, built-in error handling. Cons: same execution model as the manual approach under the hood. Each tool call is still a round trip with the model. The gain is in DX, not performance. Approach 3: programmatic tool calling Programmatic tool calling changes the execution model. Instead of requesting one tool at a time through the API, Claude writes Python code that calls your tools directly inside a code execution container. Intermediate results stay in the container and only enter the model's context when Claude explicitly sends them. To enable this approach, you need two things: include the code_execution tool in the request, and add allowed_callers to the tools Claude can call from code: client = anthropic.Anthropic() response = client.messages.create( model="claude-sonnet-5", max_tokens=4096, messages=[{ "role": "user", "content": "Compare revenue across the West, East, and Central regions" }], tools=[ {"type": "code_execution_20260120", "name": "code_execution"}, { "name": "query_database", "description": "Execute a SQL query. Returns rows as JSON.", "input_schema": { "type": "object", "properties": { "sql": {"type": "string", "description": "SQL query"} }, "required": ["sql"] }, "allowed_callers": ["code_execution_20260120"] } ], ) Enter fullscreen mode Exit fullscreen mode Claude then generates a Python script that calls query_database in a loop or in parallel via asyncio.gather, filters the results, and only sends back the summary: results = {} for region in ["West", "East", "Central"]: rows = json.loads(await query_database({ "sql": f"SELECT SUM(revenue) as total FROM sales WHERE region = '{region}'" })) results[region] = rows[0]["total"] best = max(results, key=results.get) print(f"Highest revenue region: {best} ({results[best]} USD)") print(f"Details: {json.dumps(results)}") Enter fullscreen mode Exit fullscreen mode Instead of 3 model round trips, a single inference produced the code, and all 3 tool calls execute inside the container. The model only receives the final print() output. Tools are exposed as async Python functions. The allowed_callers field controls who can call each tool: Value Behavior ["direct"] Standard API call (default) ["code_execution_20260120"] Call only from code execution ["direct", "code_execution_20260120"] Both modes Anthropic recommends choosing a single mode per tool to avoid ambiguity. Pros: massive token and latency reduction. BrowseComp and DeepSearchQA benchmarks show +11% performance and -24% input tokens. On complex research tasks, average usage drops from 43,588 to 27,297 tokens, a 37% reduction. Cons: requires the code_execution tool (beta). Containers have a limited lifetime (~5 minutes idle). Not available on Amazon Bedrock or Google Cloud. The field is not a security boundary: allowed_callers guides Claude but does not strictly block direct calls. Comparison Criterion JSON + loop Tool Runner SDK Programmatic Inferences per N tools N N 1 + returns Intermediate tokens In context In context In container Code complexity High Low Medium Per-step control Full Limited Via generated code Latency N x inference N x inference 1 inference + exec Type safety Manual Zod / type hints N/A (generated code) Availability GA, all clouds Beta, all clouds Beta, direct API When to use what JSON + manual loop when you need fine-grained control between each tool call. For example: a workflow with human validation between steps, detailed logging, or conditional business logic. It's also the only option if you target Bedrock or Google Cloud without the Tool Runner. Tool Runner SDK for most use cases. The code is cleaner, type validation is automatic, and the behavior is identical to the manual loop under the hood. This is the approach I use by default in my TypeScript and Python projects. Programmatic tool calling when the number of tool calls per request is high or intermediate results are large. The typical example: aggregating data from 20 sources, filtering, and only returning the summary. It's also the most efficient approach for research tasks where Claude needs to explore and sort before concluding. You can combine approaches. A tool marked ["direct"] will be called through the standard loop, while another marked ["code_execution_20260120"] will be orchestrated by the code. In the same project. In practice In CodeRift, I use the Tool Runner for review agents: each agent has 2-3 tools (read a file, search symbols, post a comment) and the number of calls is predictable. The Tool Runner eliminates boilerplate without sacrificing visibility. For data exploration tasks in my IronFlow workflows, programmatic tool calling would be the right choice: an agent scanning 50 GitLab projects, filtering open MRs, and aggregating stats. The heavy lifting happens in the container, and only the summary enters the context. The manual JSON approach stays for cases where the Tool Runner isn't available (unsupported SDK, or integration with a third-party framework that manages its own loop). The choice isn't permanent. Start with the Tool Runner, migrate to programmatic when the token bill justifies it.

来源报道 · 1 篇 · 以下链接均前往原始媒体

← 返回精选动态 原文

更多内容