Anthropic Messages 协议
Anthropic Messages 协议
Section titled “Anthropic Messages 协议”anthropic_messages/v1/messagessrc/protocol/anthropic/messages/wiresrc/provider/anthropic_messagessrc/ingress/anthropic_messagessrc/translation/anthropic_messagesopenai_responses当前运行时已支持 anthropic_messages -> anthropic_messages 透传。完整 wire model 已在协议层建模,协议转换和 provider 兼容处理仍应保持显式、可测试。
Anthropic Messages 请求主体是 MessageCreateParamsBase:
struct MessageCreateParamsBase { max_tokens: u32, messages: Vec<MessageParam>, model: String, stream: Option<bool>, system: Option<SystemPrompt>, tools: Option<Vec<ToolUnion>>, tool_choice: Option<ToolChoice>, thinking: Option<ThinkingConfigParam>, temperature: Option<Number>, top_k: Option<u32>, top_p: Option<Number>, stop_sequences: Option<Vec<String>>, ...}运行时 ingress 目前只要求 body 是 JSON 且包含非空 model,然后保留原始 body:
struct PreparedAnthropicMessagesRequest { body: Vec<u8>, model: String,}当前 wire request body 直接由 MessageCreateParamsBase 表示;不再额外保留薄封装 projection 类型。
Anthropic 的 system 不在 messages 数组里,而是单独字段:
enum SystemPrompt { Text(String), Blocks(Vec<TypedTextBlockParam>),}消息由 MessageParam 表示:
struct MessageParam { content: MessageParamContent, role: Role,}
enum MessageParamContent { Text(String), Blocks(Vec<ContentBlockParam>),}ContentBlockParam 是请求侧 block union,包含文本、图片、文档、搜索结果、思考块、工具调用、工具结果、server tool 相关结果等。
Anthropic 非流式响应由 Message 表示:
struct Message { id: String, content: Vec<ContentBlock>, model: String, role: Role, type: MessageType, stop_reason: Option<StopReason>, stop_sequence: Option<String>, usage: Usage, ...}响应内容是 ContentBlock:
enum ContentBlock { Text(TextBlock), Thinking(ThinkingBlock), RedactedThinking(RedactedThinkingBlock), ToolUse(ToolUseBlock), ServerToolUse(ServerToolUseBlock), WebSearchToolResult(WebSearchToolResultBlock), WebFetchToolResult(WebFetchToolResultBlock), CodeExecutionToolResult(CodeExecutionToolResultBlock), BashCodeExecutionToolResult(BashCodeExecutionToolResultBlock), TextEditorCodeExecutionToolResult(TextEditorCodeExecutionToolResultBlock), ToolSearchToolResult(ToolSearchToolResultBlock), ContainerUpload(ContainerUploadBlock),}这里的重点是 Anthropic 把模型输出组织为 content blocks,而不是 OpenAI Responses 的 output items 或 Chat Completions 的单个 assistant message。
用户端工具调用
Section titled “用户端工具调用”Anthropic 的用户端工具定义是 custom Tool:
struct Tool { name: String, description: Option<String>, input_schema: InputSchema, strict: Option<bool>, cache_control: Option<CacheControlEphemeral>, ...}模型请求客户端执行工具时,响应内容里出现 ContentBlock::ToolUse:
struct ToolUseBlock { id: String, caller: ToolCaller, input: Value, name: String,}客户端执行后,在下一轮请求里用 ContentBlockParam::ToolResult 回填:
struct ToolResultBlockParam { tool_use_id: String, content: Option<ToolResultContentParam>, is_error: Option<bool>, cache_control: Option<CacheControlEphemeral>,}关联字段是 tool_use_id,它对应上一轮 ToolUseBlock.id。is_error 用于表达客户端工具执行失败。
tool_choice 控制模型工具选择:
enum ToolChoice { Auto(ToolChoiceAuto), Any(ToolChoiceAny), Tool(ToolChoiceTool), None(ToolChoiceNone),}Auto、Any、Tool 支持 disable_parallel_tool_use,用于限制并行工具调用。
服务端工具调用
Section titled “服务端工具调用”Anthropic 的协议模型显式区分 server tools。请求侧 ToolUnion 可以包含自定义工具和多种服务端工具,例如:
bash_20250124code_execution_20250522code_execution_20250825code_execution_20260120memory_20250818text_editor_*web_search_*web_fetch_*tool_search_*
服务端工具调用在响应内容中表现为 ServerToolUseBlock:
struct ServerToolUseBlock { id: String, caller: ToolCaller, input: Value, name: ServerToolName,}服务端工具结果通过专门的 result block 返回:
struct ServerToolResultBlock { id: String, caller: ToolCaller, input: Value, name: ServerToolName, content: ServerToolResultContent, error: Option<ToolErrorBlock>, type: String,}ServerToolName 覆盖 web、code execution、bash、text editor、tool search 等服务端能力。
ToolCaller 表示是谁触发了这个工具:
enum ToolCaller { Direct(DirectCaller), CodeExecution20250825(ServerToolCaller), CodeExecution20260120(ServerToolCaller20260120),}这允许协议表达“直接由模型调用”和“由某个 code execution 工具继续调用其他 server tool”的区别。
SSE 流式
Section titled “SSE 流式”Anthropic Messages 流事件由 MessageStreamEvent 表示:
enum MessageStreamEvent { Ping(PingEvent), MessageStart(MessageStartEvent), MessageDelta(MessageDeltaEvent), MessageStop(MessageStopEvent), ContentBlockStart(ContentBlockStartEvent), ContentBlockDelta(ContentBlockDeltaEvent), ContentBlockStop(ContentBlockStopEvent),}典型事件顺序:
message_startcontent_block_startcontent_block_delta*content_block_stopmessage_deltamessage_stopping 是保活事件,不改变消息内容。
内容增量由 ContentBlockDelta 表示:
enum ContentBlockDelta { TextDelta(TextDelta), InputJsonDelta(InputJsonDelta), CitationsDelta(CitationsDelta), ThinkingDelta(ThinkingDelta), SignatureDelta(SignatureDelta),}文本流使用 TextDelta.text。工具输入流通常使用 InputJsonDelta.partial_json,客户端需要按 content block index 聚合 partial JSON。思考内容使用 ThinkingDelta,签名使用 SignatureDelta。
block 通过 index 关联:
ContentBlockStartEvent.index:开始一个 content block。ContentBlockDeltaEvent.index:给对应 block 增量追加内容。ContentBlockStopEvent.index:该 block 结束。
消息级结束由 MessageStopEvent 表示;MessageDeltaEvent 携带 stop_reason、stop_sequence 和增量 usage。
content blocks、并行与串行
Section titled “content blocks、并行与串行”Anthropic Messages 的输出单元是 assistant 消息中的 content[] 数组。与 Responses 的顶层 output[] 不同,Anthropic 把所有输出内容(文本、思考、工具调用、服务端工具调用)都嵌套在一个 Message.content[] 里。
同一个“并行读取两个文件”的工具调用,在 Anthropic 中表现为一个 assistant 消息里的多个 tool_use block:
{ "role": "assistant", "content": [ {"type": "tool_use", "id": "tu_1", "name": "read_file", "input": {"path": "src/main.rs"}}, {"type": "tool_use", "id": "tu_2", "name": "read_file", "input": {"path": "Cargo.toml"}} ]}对应的工具结果在下一个 user 消息中以 tool_result block 回填,同样可以包含多个 result block:
{ "role": "user", "content": [ {"type": "tool_result", "tool_use_id": "tu_1", "content": "fn main() {...}"}, {"type": "tool_result", "tool_use_id": "tu_2", "content": "[package]\nname = ..."} ]}Anthropic 通过 tool_choice 中的 disable_parallel_tool_use 字段控制是否允许并行工具调用:
{"type": "auto", "disable_parallel_tool_use": true}当设为 true 时,模型每次只会产出一个 tool_use block。省略或设为 false 时,模型可以在单个 assistant 消息中产出多个 tool_use block。
OpenAI 协议的对应字段是请求级 parallel_tool_calls: false。proxai 在 openai_responses -> anthropic_messages 转换时,将 parallel_tool_calls: false 映射为 tool_choice.disable_parallel_tool_use: true。
严格邻接约束
Section titled “严格邻接约束”Anthropic 要求工具调用和工具结果严格相邻:
- assistant 消息包含一个或多个
tool_useblock。 - 紧接着的 user 消息必须包含对应的
tool_resultblock(每个tool_use_id恰好匹配一个 result)。 - 中间不能插入其他 role 的消息。
部分 provider(如 MiniMax M3)严格执行此约束,对拆分或交错的工具轮次会返回 tool call result does not follow tool call (2013) 错误。proxai 在翻译时保持相邻 tool_use / tool_result 的聚合,避免拆散并行工具调用。
流式中的并行工具参数
Section titled “流式中的并行工具参数”SSE 流式时,多个并行 tool_use 的 input_json_delta 事件可以交错到达,通过 ContentBlockStartEvent.index 和 ContentBlockDeltaEvent.index 区分属于哪个 block:
index=0 input_json_delta {"path":index=1 input_json_delta {"path":index=0 input_json_delta "src/main.rs"}index=1 input_json_delta "Cargo.toml"}这与 Responses 通过 item_id + output_index 区分并行 item 的方式类似,但 Anthropic 使用的是消息内 content block 的数组 index。
关于 Anthropic 与其他协议在流式标识模型、事件粒度、以及跨协议翻译时如何生成缺失的 item_id / index,详见 协议转换 的 ## Streaming identifier model and parallel assembly 章节。
完整交互示例
Section titled “完整交互示例”完整的多轮 SSE 示例已经拆到独立页面,避免协议概览页过长。
proxai 当前处理方式
Section titled “proxai 当前处理方式”anthropic_messages -> anthropic_messages 当前是透传:
- ingress 校验 JSON 和非空
model。 - translation 构造
ProviderRequest::AnthropicMessages,保留原始 body。 - provider 直接转发到上游。
- 非流式响应原样返回并可 capture。
- SSE 响应保留原始 bytes 和 headers;
AnthropicSseObserver使用SseEventScanner扫描事件,将MessageStreamEvent归纳到AnthropicResponseState,并记录 completed/closed/error 日志。AnthropicCompatibleprovider 会先经过 provider-local SSE normalization。
当前 Anthropic observer 不重组语义流,也不注入工具参数超时诊断。协议层的 MessageStreamEvent 主要用于 provider response 观察、摘要和跨协议翻译。