Skip to content

Messages API

Anthropic 最底层的 HTTP 接口,所有官方 SDK 和 Agent SDK 都是它上面搭出来的。

Messages API 是 Anthropic 面向开发者最基础的一层。上一节讲的 Agent SDK 也好,官方的 @anthropic-ai/sdk 也好,Claude 桌面客户端也好,最终都会拆成一条条 POST /v1/messages 请求发到 Anthropic 的服务器。搞清楚这层协议本身,你能诊断任何一层上面出的问题。

绝大多数业务里你不会直接手写 HTTP 请求,而是用官方 SDK,但理解底层协议非常有价值:一是排错时能看懂 API 报错和 SDK 抛出的异常到底对应哪个字段;二是做自研 agent 框架、做批量数据处理时能精细控制每个字段的开销;三是切换到 Bedrock、Vertex 之类的托管入口时,接口签名和字段基本一致,学一次到处能用。

一个最简单的请求长什么样

端点固定:

POST https://api.anthropic.com/v1/messages

三个必填的 header:

x-api-key: sk-ant-xxxxx
anthropic-version: 2023-06-01
content-type: application/json

anthropic-version 是 API 的版本号,不是 SDK 版本,历史值一直是 2023-06-01,除非官方明确通知,都用这个即可。

请求体最小结构:

json
{
  "model": "claude-sonnet-5",
  "max_tokens": 1024,
  "messages": [
    {"role": "user", "content": "用一句话解释 CAP 定理"}
  ]
}

用 curl 走一遍:

bash
curl https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-sonnet-5",
    "max_tokens": 1024,
    "messages": [
      {"role": "user", "content": "用一句话解释 CAP 定理"}
    ]
  }'

返回大概是这样:

json
{
  "id": "msg_01ABC...",
  "type": "message",
  "role": "assistant",
  "model": "claude-sonnet-5",
  "content": [
    {"type": "text", "text": "CAP 定理是说……"}
  ],
  "stop_reason": "end_turn",
  "usage": {"input_tokens": 15, "output_tokens": 42}
}

注意 content数组而不是字符串。原因是响应里可能同时出现文本块和 tool_use 块,用数组统一表示。

请求体的核心字段

字段说明
model模型 ID,见下节表格
messages对话数组,每项 {role, content},role 是 userassistant
max_tokens本次生成允许的最大 token 数,必填
system系统提示词,独立于 messages 传
temperature采样温度,0 到 1,默认 1
top_p / top_k采样截断参数,通常保持默认
stop_sequences遇到就停下的字符串列表
stream是否走流式,默认 false
tools工具定义数组,用于 tool use
tool_choice强制工具选择策略

当前模型 ID

写这一节时 Anthropic 官方在售的主要模型 ID:

  • claude-opus-4-8:最新一代 Opus,最强推理,最贵。适合复杂 agent 决策、深度代码理解、多步推理。
  • claude-opus-4-7:上一代 Opus,仍在维护,价格略低。已有代码里如果钉死这个版本,可以继续用,但新项目直接上 4-8。
  • claude-sonnet-5:Sonnet 系列旗舰,日常首选的性价比档。写代码、写文档、做一般 agent 循环,这一档最平衡。
  • claude-haiku-4-5-20251001:Haiku 系列小模型,快而便宜,适合分类、抽取、批处理、大规模离线任务。
  • claude-fable-5:Fable 系列,面向创意写作和角色扮演场景,比 Sonnet 在长文本连贯性上更强。

模型 ID 通常带日期后缀作为不变引用,也可以用不带日期的别名跟随最新版本。生产环境建议钉死带日期的 ID,避免升级破坏行为。原型阶段可以用别名图省事。

还有一个隐藏字段叫 metadata,可以传一个 user_id 字符串,Anthropic 后台用于滥用检测。做多租户服务时建议每次都带上,一是合规,二是出问题时排查更快。

多轮对话

messages 数组本身承载完整对话历史。要多轮,你自己把之前的 assistant 回复也塞回去:

json
{
  "model": "claude-sonnet-5",
  "max_tokens": 1024,
  "system": "你是一个精通分布式系统的中文助教。",
  "messages": [
    {"role": "user", "content": "什么是 CAP?"},
    {"role": "assistant", "content": "CAP 定理指的是……"},
    {"role": "user", "content": "那 PACELC 呢?"}
  ]
}

服务器不保存对话状态,每次请求你都要把上下文整个发过去。这也是为什么 prompt caching(下面会讲)对多轮场景很关键。

流式返回

stream 置为 true,服务器就以 SSE(Server-Sent Events)方式一段段推 token:

json
{
  "model": "claude-sonnet-5",
  "max_tokens": 1024,
  "stream": true,
  "messages": [{"role": "user", "content": "写一个 fizzbuzz"}]
}

响应体是一串 event:data: 的 SSE 事件流,常见事件有 message_startcontent_block_startcontent_block_deltacontent_block_stopmessage_deltamessage_stop。SDK 会替你把这堆事件重新组装成一个 stream 对象,业务代码里几乎都用 SDK 而不是自己解析 SSE。

流式的意义有两层:一是用户体验层面,边生成边渲染,用户不用干等一分钟才看到第一个字;二是资源层面,如果你只需要开头一段就够了,可以中途中断连接,省下后续 token 费用。做聊天类产品几乎必须走流式,做批处理离线任务反倒可以不用。

Tool use 循环

要让 Claude 调你的函数,两步:请求里带 tools,响应里如果是 tool_use 就把结果作为 tool_result 发回去。

请求:

json
{
  "model": "claude-sonnet-5",
  "max_tokens": 1024,
  "tools": [
    {
      "name": "get_weather",
      "description": "查询指定城市的天气",
      "input_schema": {
        "type": "object",
        "properties": {"city": {"type": "string"}},
        "required": ["city"]
      }
    }
  ],
  "messages": [{"role": "user", "content": "北京今天天气怎么样?"}]
}

响应里 stop_reasontool_usecontent 数组里出现一个 tool_use 块:

json
{
  "content": [
    {"type": "tool_use", "id": "toolu_01ABC", "name": "get_weather", "input": {"city": "北京"}}
  ],
  "stop_reason": "tool_use"
}

你的代码去执行 get_weather,把结果作为下一轮的 user 消息传回:

json
{
  "role": "user",
  "content": [
    {"type": "tool_result", "tool_use_id": "toolu_01ABC", "content": "晴 26 度"}
  ]
}

循环直到 stop_reason 变成 end_turn。Agent SDK 帮你封装的正是这套循环。

如果一次响应里带了多个 tool_use 块(并行工具调用),你就要把每个都执行完,把结果拼成一个 user message 里的多个 tool_result 块一起发回去,而不是分成多轮。这里踩过坑的人不少:只回填一个 tool_use_id,另一个悬空,Claude 就会一直等那个不存在的结果。

Prompt caching

对于长 system prompt、大段 CLAUDE.md、多轮对话历史这种大量重复输入的场景,用 prompt caching 能省钱也能提速。原理是 Anthropic 服务端把打了缓存标记的那段内容前缀哈希后缓存下来,下次请求命中就跳过重新处理。

在需要缓存的内容块尾部打一个 cache_control 标记:

json
{
  "system": [
    {
      "type": "text",
      "text": "很长的系统提示词,加上一大段项目背景……",
      "cache_control": {"type": "ephemeral"}
    }
  ],
  "messages": [{"role": "user", "content": "开始吧"}]
}

首次调用照常收费并写入缓存,后续 5 分钟内命中的部分按 10% 计费。ephemeral 是当前唯一的缓存类型。命中判断是基于前缀严格匹配,所以缓存块之前的所有内容改一个字都会失效——把稳定不变的内容放在 messages 数组最前面,动态部分放在后面。

Token 计数

估算 token 数不用扔进 messages 里试,专门的端点:

POST https://api.anthropic.com/v1/messages/count_tokens

请求体和 /messages 一样但不会真的生成,返回一个 input_tokens 数字。做长文本预算控制时很好用。比如你要往 system prompt 塞一大堆项目文档,先 count 一下确认没超上下文窗口,再真正发生成请求,能省掉 400 错误的返工。

TypeScript 官方 SDK 示例

日常调用一般不直接写 fetch,用 @anthropic-ai/sdk 封装好的客户端:

bash
npm install @anthropic-ai/sdk
ts
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

const response = await client.messages.create({
  model: "claude-sonnet-5",
  max_tokens: 1024,
  system: "你是一个中文技术助手。",
  messages: [{ role: "user", content: "解释一下什么是 CAP 定理" }],
});

console.log(response.content[0]);

ANTHROPIC_API_KEY 环境变量会被 SDK 自动读到。流式改成 client.messages.stream({...}) 拿到一个可迭代的 stream 对象。

Python 端等价写法用 anthropic 包:

python
import anthropic

client = anthropic.Anthropic()

response = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    system="你是一个中文技术助手。",
    messages=[{"role": "user", "content": "解释一下什么是 CAP 定理"}],
)

print(response.content[0].text)

流式版本用 with client.messages.stream(...) as stream: 上下文管理器包起来,然后 for text in stream.text_stream: 拿到 delta。

缓存的另一个好处是首字节延迟。命中缓存的部分服务端处理时间几乎为零,Time-to-first-token 会明显低于全新请求。做交互式产品时用户能感知到这个差别。

错误码和限流

跟其它 REST 服务一样,Messages API 用标准 HTTP 状态码告诉你出了什么问题。几个高频的:

  • 400:请求体有问题,通常是字段类型错、max_tokens 缺失、模型 ID 拼错。
  • 401x-api-key 无效或者没传。
  • 403:key 没有对应模型的权限(比如免费额度不含 Opus)。
  • 429:触发速率限制。响应头里会带 retry-after 告诉你几秒后再试。
  • 500 / 529:服务端过载或临时故障,直接指数退避重试。

速率限制分两个维度:每分钟请求数(RPM)和每分钟 token 数(TPM)。生产系统一定要在客户端做退避和排队,否则一次流量峰值就能把整条链路打瘫。

直接用 REST vs 用官方 SDK

除非你在做嵌入式、需要自己实现 SSE 解析或者跑在非主流语言里,日常业务都建议走官方 SDK。SDK 帮你处理:

  • 自动带上 anthropic-version 头,跟着新版本升级
  • SSE 流式解析、重连、超时
  • Retry with exponential backoff
  • 类型提示,编辑器自动补全
  • 特殊参数(比如 tool_choice、metadata)的字段命名和类型

自己撸 REST 通常只在 debug 一个诡异行为或者写最小可复现代码时才会用。

API 和 Agent SDK 怎么选

一句话总结:只调一次拿文本,用 Messages API;要跑工具循环,用 Agent SDK。Agent SDK 里的 tool 循环本身就是若干次 Messages API 调用的编排,自己写不是不行,就是重复造轮子。

再具体一点,什么时候必须回到 Messages API 层:需要精细控制每一次调用的模型和 max_tokens、需要把响应喂给非 Claude 的下游模型、需要把 API 调用嵌进已有的自研 agent 框架里。除了这些,Agent SDK 更省事。

本教程为社区中文学习整理,非官方发布。Claude Code 属于 Anthropic。