☰
Claude code课程:工具的使用-3.利用工具强制生成 JSON 与 TaoToken 统一 Key 通道
2026/10/9 2:26:31 网站建设 项目流程

1. 为什么 Claude Code 工具调用里要强制 JSON 输出

在 Claude Code 课程的工具使用章节里,前两节我们让模型调用计算器、查询天气,模型返回的是tool_use块,里面input字段天然就是结构化对象。但很多同学在练习时会遇到一个尴尬场景:直接让模型“返回 JSON”,结果拿到一段带解释文字、带 Markdown 代码围栏、甚至字段名拼错的字符串,还得写正则去抠。这就是本节要解决的问题——利用工具定义(tool schema)来强制模型输出合法 JSON。

核心思路其实很朴素:模型一旦决定“调用工具”,它就必须按照你给的input_schema来填参数。我们并不真的去执行这个工具函数,只把tool_use.input取出来当结果用。这相当于给模型套了一个格式模具,它以为自己在调工具,实际上我们在做结构化抽取。

这个技巧适合谁?适合正在做 Claude Code 课程练习的同学、需要从非结构化文本里抽实体/做情感分析/做分类的开发者,以及想把模型输出直接喂给下游程序(数据库、前端表格、自动化流程)的工程同学。关键词就是 Claude code、工具使用、JSON 结构化输出。

我试过在同一个 prompt 里既要求“返回 JSON”又给工具定义,结果模型有时会走纯文本路线,格式飘忽。后来统一改成“只允许用工具”,配合tool_choice参数,稳定性立刻上来了。下面我会把工具定义 JSON 片段、强制参数配置、以及用 curl 验证返回结构的完整动作都写清楚,你可以直接复制到课程练习里跑。

在进入配置之前,先说明一个工程上的现实问题:课程示例里模型调用是直连的,但真实练习中你往往要同时接多个工具、多个模型,Key 管理会很乱。所以本节会结合 TaoToken 的统一 Key/API 通道来做,让 Claude Code 的工具调用请求走一个稳定的入口,避免在多个 Key 之间来回切换。

2. TaoToken 统一 Key 通道的前置准备与接入文档

要把上面的强制 JSON 技巧跑通,第一步是让请求能稳定发出去。Claude Code 课程里的示例代码用的是 Anthropic SDK,默认读环境变量里的 Key。如果你同时练多个模型、多个工具,每个都配一套 Key,很容易在切换时把 A 的 Key 填到 B 的 base_url 上,报 401 还找不到原因。TaoToken 在这里的作用就是提供统一的 Key 和 API 通道,把模型对话、coding plan、控制台、API Keys 管理收敛到一个入口。

你需要先拿到两样东西:一个可用的 API Key,以及统一的 Base URL。Base URL 用https://taotoken.net/api,注意这个地址不带任何查询参数,直接作为 SDK 的base_url或 curl 的请求前缀。Key 则在控制台的 API Keys 页面创建,创建后复制保存,后面所有配置都复用它。

具体入口我列一下,方便你按需跳转:模型对话入口在 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite ,可以用来先在网页上验证模型是否正常响应;API Keys 管理在 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite ,创建和吊销 Key 都在这里;接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite ,里面有各语言 SDK 的 base_url 填法;如果你后面要做长期编码或 Agent,可以看 coding plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite 。

环境变量配置建议这样写,Linux/macOS 用 export,Windows PowerShell 用$env::

export ANTHROPIC_BASE_URL="https://taotoken.net/api" export ANTHROPIC_API_KEY="你的Key"

注意这里变量名用的是 Anthropic SDK 认的ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY,这样课程里的Anthropic()客户端不用改代码就能读到。如果你用的是 OpenAI 兼容风格的调用,变量名换成OPENAI_BASE_URL和OPENAI_API_KEY,值里的 base_url 同样填https://taotoken.net/api。

这里有个容易踩的坑:base_url 末尾不要自己加/v1或/messages,SDK 会自己拼路径。我见过有同学写成https://taotoken.net/api/v1,结果请求打到/api/v1/v1/messages,直接 404。统一用https://taotoken.net/api就好。

配好之后,先别急着写工具定义,用一条最简单的请求确认通道是通的。这一步能帮你把“Key 问题”和“工具 schema 问题”分开排查,后面出错时心里有底。确认通了再进入下一节的工具定义和强制 JSON 配置。

3. 可复制的工具定义 JSON 与强制输出配置

这一节是全文的核心,给你可以直接复制的工具定义片段和强制参数配置。我们以情感分析为例,工具名print_sentiment_scores,input_schema用标准 JSON Schema 描述三个必填的数值字段。

{ "name": "print_sentiment_scores", "description": "Prints the sentiment scores of a given text.", "input_schema": { "type": "object", "properties": { "positive_score": { "type": "number", "description": "The positive sentiment score, ranging from 0.0 to 1.0." }, "negative_score": { "type": "number", "description": "The negative sentiment score, ranging from 0.0 to 1.0." }, "neutral_score": { "type": "number", "description": "The neutral sentiment score, ranging from 0.0 to 1.0." } }, "required": ["positive_score", "negative_score", "neutral_score"] } }

关键点在于required数组,它保证模型必须填全三个字段,不会漏。description写得越明确,模型填值的语义越准,比如这里限定 0.0 到 1.0,模型就不会给你返回 0 到 100 的分数。

接下来是强制参数配置。光靠 prompt 里写“只使用这个工具”有时会失效,正确做法是用tool_choice参数锁死:

{ "tool_choice": { "type": "tool", "name": "print_sentiment_scores" } }

这个配置告诉模型:你必须通过调用print_sentiment_scores来响应,不允许走纯文本。把它和上面的 tools 数组一起放进请求体。完整的请求体结构(以 Anthropic Messages API 为例)长这样:

{ "model": "claude-3-sonnet-20240229", "max_tokens": 4096, "tools": [ 上面那个工具定义 ], "tool_choice": { "type": "tool", "name": "print_sentiment_scores" }, "messages": [ { "role": "user", "content": "<text>I'm a HUGE hater of pickles.</text> Only use the print_sentiment_scores tool." } ] }

如果你用 Python SDK,代码是这样:

from anthropic import Anthropic import json client = Anthropic() tools = [ /* 上面的工具定义 */ ] response = client.messages.create( model="claude-3-sonnet-20240229", max_tokens=4096, tools=tools, tool_choice={"type": "tool", "name": "print_sentiment_scores"}, messages=[{"role": "user", "content": "<text>I'm a HUGE hater of pickles.</text> Only use the print_sentiment_scores tool."}] ) for content in response.content: if content.type == "tool_use" and content.name == "print_sentiment_scores": print(json.dumps(content.input, indent=2)) break

这里content.input就是模型填好的结构化对象,直接json.dumps就是合法 JSON,不需要任何正则清洗。这就是“强制 JSON”的全部秘密。

再给一个实体抽取的工具定义,字段是数组嵌套对象,用来演示复杂结构:

{ "name": "print_entities", "description": "Prints extract named entities.", "input_schema": { "type": "object", "properties": { "entities": { "type": "array", "items": { "type": "object", "properties": { "name": {"type": "string", "description": "The extracted entity name."}, "type": {"type": "string", "description": "The entity type (e.g., PERSON, ORGANIZATION, LOCATION)."}, "context": {"type": "string", "description": "The context in which the entity appears in the text."} }, "required": ["name", "type", "context"] } } }, "required": ["entities"] } }

注意items里也写了required,这样数组里每个对象都保证有 name/type/context 三个字段,下游解析时不用做空值判断。这套 schema 写法在 Claude Code 课程练习里可以直接复用,换成翻译、分类、摘要任务,只改字段名和 description 即可。

4. 用 curl 验证返回结构是否合法

配置写好了,怎么确认返回的真是合法 JSON?最直接的办法是用 curl 发一条请求,把响应存下来,再用jq校验结构。这一步在课程练习里特别重要,因为 SDK 有时会把错误吞掉,curl 能看到原始 HTTP 状态和响应体。

先发请求,把响应写到文件:

curl -s https://taotoken.net/api/v1/messages \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "content-type: application/json" \ -d '{ "model": "claude-3-sonnet-20240229", "max_tokens": 4096, "tools": [{ "name": "print_sentiment_scores", "description": "Prints the sentiment scores of a given text.", "input_schema": { "type": "object", "properties": { "positive_score": {"type": "number"}, "negative_score": {"type": "number"}, "neutral_score": {"type": "number"} }, "required": ["positive_score", "negative_score", "neutral_score"] } }], "tool_choice": {"type": "tool", "name": "print_sentiment_scores"}, "messages": [{"role": "user", "content": "<text>I hate pickles.</text> Only use the print_sentiment_scores tool."}] }' > resp.json

拿到resp.json后,先看stop_reason是不是tool_use,这代表模型确实走了工具调用:

jq '.stop_reason' resp.json

预期输出"tool_use"。然后提取tool_use块里的input字段,校验它是不是合法 JSON 且字段齐全:

jq '.content[] | select(.type=="tool_use") | .input' resp.json

预期输出类似:

{ "positive_score": 0.0, "negative_score": 0.791, "neutral_score": 0.209 }

再用jq做一次字段存在性断言,确保三个字段都在且是数字:

jq -e '.content[] | select(.type=="tool_use") | .input | has("positive_score") and has("negative_score") and has("neutral_score")' resp.json

返回true就说明结构合法。如果返回false或报错,说明模型没按 schema 填,需要检查tool_choice是否生效、required是否写全。

实测下来,加上tool_choice后,stop_reason稳定是tool_use,input字段直接就是干净的对象。你可以把这段 curl 校验写进 CI,每次改 schema 后跑一遍,防止字段名写错导致下游解析失败。对于实体抽取那种嵌套数组,校验命令改成:

jq -e '.content[] | select(.type=="tool_use") | .input.entities | length > 0' resp.json

确认数组非空且每个元素都有 name/type/context,就说明复杂结构也稳了。

5. 本篇常见报错排查:401、local proxy failed、reading choices、OAuth

练习过程中最容易卡住的不是 schema 本身,而是请求发不出去或响应解析不了。下面按真实报错逐条排查。

401 Unauthorized:最常见。先确认ANTHROPIC_API_KEY环境变量在当前终端里真的生效,用echo $ANTHROPIC_API_KEY看有没有值。如果值对但还报 401,检查 base_url 是不是写成了带/v1的地址,导致请求路径重复。还有一种情况是 Key 复制时带了空格或换行,重新从 API Keys 页面复制一次。如果用的是 Claude Code 客户端,检查~/.claude/settings.json里的配置是否和终端环境变量冲突。

local proxy failed / connection refused:这类报错通常是本地网络层的问题,不是 Key 的问题。先确认ANTHROPIC_BASE_URL填的是https://taotoken.net/api,没有多余端口。如果你本地跑着什么转发工具,先关掉再试。用curl -v https://taotoken.net/api/v1/messages看 TCP 连接是否建立,如果卡在连接阶段,说明是网络出口问题,换网络环境重试。

reading 'choices' of undefined:这个报错一般出现在用 OpenAI 兼容 SDK 调 Anthropic 风格接口时,响应结构对不上。Anthropic 的响应是content数组,OpenAI 是choices数组。如果你用 OpenAI SDK,base_url 要填https://taotoken.net/api,但请求路径和响应解析要按对应风格来。混用会导致 SDK 去读不存在的choices字段。解决办法是统一 SDK 和接口风格,别一边用 Anthropic SDK 一边按 OpenAI 的字段名解析。

OAuth / authentication_error:如果你在 Claude Code 客户端里看到 OAuth 相关报错,通常是客户端走了交互式登录流程,而你想用 API Key 直连。检查客户端配置里是否强制走了 OAuth,改成 API Key 模式,把 Key 填到对应字段。如果同时出现auth.json相关提示,检查~/.claude/auth.json或项目下的配置文件,确保里面没有残留的旧 token 覆盖了环境变量。

排查顺序建议:先 curl 确认通道通,再看stop_reason,最后校验input结构。把这三步分开,401 和 schema 问题就不会混在一起。每次改完配置,用第 4 节的 jq 命令跑一遍,比肉眼检查靠谱得多。

6. 把强制 JSON 接入你的 Claude Code 工作流

到这里,工具定义、强制参数、curl 校验、报错排查都齐了。最后说下怎么把它变成日常可用的工作流。你可以把情感分析、实体抽取、翻译这几个工具定义存成一个tools.json,在 Python 里json.load进来复用,改任务时只换tool_choice的 name 和 prompt 里的文本。

对于需要长期跑编码或 Agent 任务的场景,建议把 Key 和 base_url 统一走 TaoToken 的 coding plan 通道,这样多个工具、多个模型共用一套凭证,切换时不用改代码。模型对话入口可以用来快速验证某个 schema 是否被模型正确理解,接入文档里有各语言 SDK 的完整示例,API Keys 页面负责日常的 Key 轮换。

如果你在课程练习里要交作业,把 curl 校验那段一起附上,评审一眼就能看出你的输出是结构化且可验证的。这套方法不依赖特定模型版本,换模型时只要 schema 不变,tool_choice依然生效,下游解析代码一行都不用动。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询