跳至正文
Wener Notes

MaaS Spec Messages

约 12 分钟阅读

目标

  • 梳理 MaaS 需要适配的 message / item / content block / part 类型。
  • 明确各协议的 role、type、基础结构和跨协议映射边界。
  • 避免把 provider 的中间状态错误地压平成纯文本,尤其是 tool call、tool result、reasoning/thought、citation、multimodal content。

Canonical Model

MaaS 内部建议把“对话消息”和“协议输出 item”分开建模:

TypeScript
type MaasRole =
  | 'system'
  | 'developer'
  | 'user'
  | 'assistant'
  | 'tool'
  | 'function'
  | 'model';

type MaasMessage = {
  id?: string;
  role: MaasRole;
  type?: string;          // provider item/message type,例如 message/function_call/thought
  content?: MaasContentPart[] | string;
  name?: string;          // function/tool name, legacy function role name
  status?: 'in_progress' | 'completed' | 'incomplete';
  phase?: 'commentary' | 'final_answer';
  toolCalls?: MaasToolCall[];
  toolCallId?: string;    // tool/function result references a call
  provider?: 'openai' | 'anthropic' | 'google' | string;
  providerRaw?: unknown;
};

type MaasContentPart =
  | MaasTextPart
  | MaasImagePart
  | MaasAudioPart
  | MaasFilePart
  | MaasToolCallPart
  | MaasToolResultPart
  | MaasReasoningPart
  | MaasRefusalPart
  | MaasCitationPart
  | MaasCodePart
  | MaasUnknownPart;

Canonical Part Types

Canonical type说明OpenAIAnthropicGoogle
text普通文本输入/输出input_text, output_text, chat texttexttext
refusal拒答文本refusal通常是普通 text 或 stop/error 语义safety/block metadata 或文本
image图片输入/输出input_image, chat image_urlimageinline_data, file_data
audio音频输入/输出chat input_audio, realtime/audio output通常通过 file/document 或专用能力inline_data, live audio chunks
file / document文件、PDF、文档input_filedocumentfile_data, inline_data
tool_call模型请求调用工具function_call, chat tool_calls[]tool_use, server_tool_use, mcp_tool_usefunctionCall, Interactions function_call
tool_result工具调用结果function_call_output, chat role=tooltool_result, mcp_tool_resultfunctionResponse, Interactions function_result / function_response
reasoning / thought推理/思考状态reasoningthinking, redacted_thinkingthought / thought signatures
code代码执行请求或结果code interpreter itemscode execution server tool blocksexecutableCode, codeExecutionResult
citation / annotation引用、搜索结果、定位信息annotations on output_textcitations/search result blocksgrounding metadata / citations
unknown保留未知 provider 扩展原样保存原样保存原样保存

不变量

  • 不要把未知 type 丢弃;放入 providerRaw 或 unknown part。
  • 不要把多个不同 tool call 合并为一个 tool call;只能合并同一调用的 streaming delta。
  • 手动管理上下文时,应保留 provider 要求回传的中间 item:OpenAI reasoning、Google thought/signature/function_call、Anthropic thinking/redacted_thinking/tool_use 等。
  • Tool result 必须引用对应 tool call ID;字段名因协议不同而不同。

OpenAI Responses API

Input Shape

input 可以是字符串,也可以是 input item 列表。

json
{
  "model": "gpt-5.4",
  "input": [
    {
      "type": "message",
      "role": "developer",
      "content": [{ "type": "input_text", "text": "You are concise." }]
    },
    {
      "type": "message",
      "role": "user",
      "content": [
        { "type": "input_text", "text": "Describe this image" },
        { "type": "input_image", "image_url": "data:image/png;base64,...", "detail": "auto" }
      ]
    }
  ]
}

Input Message Roles

Role说明
developer开发者/应用指令;优先级高于 user
system系统指令;部分新模型更推荐 developer
user终端用户输入
assistant之前模型输出;手动管理上下文时可回放

OpenAI Responses 的 assistant message 还可能带 phase:

phase说明
commentary中间评论/过程消息
final_answer最终回答

对 Codex/GPT-5.3+ 一类模型,后续请求回放 assistant messages 时应保留 phase。

Input Content Types

Type基本字段说明
input_texttext文本输入
input_imageimage_url 或 file_id, detail图片输入
input_filefile_id / file_url / file_data / filename, detail文件输入

Output Item Types

Responses API 的 output[] 不是单一 assistant message;它是 item 列表。

Type关键字段说明
messageid, role=assistant, content[], status, phaseassistant 文本/refusal 输出
function_callid, call_id, name, arguments, status模型请求调用函数;结果引用 call_id
function_call_outputid, call_id, output, status函数结果;通常作为下一轮 input item
reasoningid, summary[], content[], encrypted_content, statusreasoning 模型中间项;手动上下文管理时需要保留
compactionid, encrypted_contentresponses compact API 生成的压缩项
tool_search_callid, call_id, arguments, execution, statustool search 调用
tool_search_outputtools[]tool search 加载出的工具定义
computer_callid, call_id, action, statuscomputer use 动作调用
computer_call_outputcall_id, output fieldscomputer use 动作结果
file_search_callid, query/result fieldsfile search 工具调用
web_search_callid, action/status fieldsweb search 工具调用
image_generation_callid, result, status图像生成工具调用
code_interpreter_callid, code/container/output fieldscode interpreter 工具调用
mcp_call / mcp_list_toolsMCP fieldsremote MCP 工具相关 item
additional_toolstool definitions模型请求追加/加载工具定义的扩展项

Output Message Content Types

Type基本字段说明
output_texttext, annotations[], logprobs?assistant 文本输出
refusalrefusal拒答内容

output_text.annotations[] 常见类型包括:

Annotation type说明
file_citation文件引用
url_citationURL 引用
container_file_citationcontainer file 引用
file_path生成/引用的文件路径

Responses Streaming 聚合

Event family聚合键说明
response.output_item.addedoutput_index, item id创建 output item
response.output_text.deltaitem_id / output_index / content index合并文本 delta
response.function_call_arguments.deltaitem_id / output_index合并 function arguments 字符串
response.function_call_arguments.doneitem_id / output_index得到完整 function call

MaaS 规则:同一 output item 的 delta 合并为一个 item;不同 output_index 不合并。

OpenAI Chat Completions

Message Roles

Role说明content 类型
developer新模型优先使用的开发者指令;替代部分 system 用法string 或 text parts
system系统指令,旧模型/兼容接口常用string 或 text parts
user用户输入string 或 parts: text, image_url, input_audio 等
assistant模型输出string/parts、tool_calls[]、refusal、audio 等
tooltool resulttext content + tool_call_id
functionlegacy function resultname + content;已被 tool 取代

Content Part Types

RolePart type基本字段说明
developer / systemtexttext指令文本
usertexttext用户文本
userimage_urlimage_url.url, detail?图片输入
userinput_audioinput_audio.data, format音频输入
assistanttexttextassistant 文本 part
assistantrefusalrefusal拒答 part
tooltexttext工具结果文本;Chat Completions tool message 只支持文本 part

Assistant Tool Calls

json
{
  "role": "assistant",
  "content": null,
  "tool_calls": [
    {
      "id": "call_...",
      "type": "function",
      "function": {
        "name": "get_weather",
        "arguments": "{\"location\":\"Paris\"}"
      }
    }
  ]
}

Result:

json
{
  "role": "tool",
  "tool_call_id": "call_...",
  "content": "{\"temperature\":25}"
}
  • finish_reason=tool_calls 表示模型调用了工具。
  • Streaming 时按 choices[].delta.tool_calls[].index 聚合同一 tool call;function.arguments 是字符串片段。
  • 多个 tool result 不应合成一个 role=tool message,因为每条 tool message 只有一个 tool_call_id。

Anthropic Messages API

Message Roles

Role说明
user用户输入,也承载 client tool 的 tool_result blocks
assistantClaude 输出,包含文本、thinking、tool_use 等 blocks
system通常是 top-level system;新文档也支持 mid-conversation role=system,位置受限

Mid-conversation system message 约束:

  • 必须紧跟 user turn,或紧跟以 server tool use 结束的 assistant turn。
  • 不能插在 assistant tool_use 与对应 user tool_result 中间。
  • 不要放不可信内容;tool output / retrieved content 应放在 tool_result。

Content Block Types

Block typeRole基本字段说明
textuser/assistant/systemtext文本
imageusersource图片输入;source 可为 base64/url/file
documentuser/tool_resultsource, title?, context?文档/PDF/文本文件
tool_useassistantid, name, inputclient-executed tool call
tool_resultusertool_use_id, content?, is_error?client tool result
server_tool_useassistantid, name, input/tool-specific fieldsserver-executed tool call
server tool result blockassistanttool-specific fields例如 web/code/search 结果;由 Anthropic server 产生
thinkingassistantthinking, signature?extended thinking block;继续对话时不能改
redacted_thinkingassistantencrypted/redacted fieldsredacted thinking;继续对话时不能改
mcp_tool_useassistantid, server_name, name, inputMCP connector 工具调用
mcp_tool_resultassistant/user-like MCP flowtool_use_id, content, is_error?MCP connector 工具结果
search_resultnested in contentsource/title/url/content可嵌在 tool result / search content 中

Tool Result Placement

Anthropic tool-use contract:

  1. assistant 返回 stop_reason=tool_use 和一个或多个 tool_use blocks。
  2. 下一条 message 必须是 role=user,并包含每个 tool_use.id 对应的 tool_result.tool_use_id。
  3. tool_result blocks 必须在 user content[] 最前面;普通 text 只能放在所有 tool results 后面。
  4. 并行工具结果应放在一个 user message 的多个 tool_result blocks 中,不要拆成多轮 user messages。

示例:

json
[
  {
    "role": "assistant",
    "content": [
      { "type": "tool_use", "id": "toolu_01", "name": "get_weather", "input": { "location": "SF" } },
      { "type": "tool_use", "id": "toolu_02", "name": "get_time", "input": { "timezone": "America/Los_Angeles" } }
    ]
  },
  {
    "role": "user",
    "content": [
      { "type": "tool_result", "tool_use_id": "toolu_01", "content": "SF: 20C" },
      { "type": "tool_result", "tool_use_id": "toolu_02", "content": "14:30" }
    ]
  }
]

Google Gemini generateContent API

Content Shape

contents[] 是多轮内容数组:

json
{
  "contents": [
    {
      "role": "user",
      "parts": [{ "text": "What is in this image?" }]
    },
    {
      "role": "model",
      "parts": [{ "text": "A cat." }]
    }
  ],
  "system_instruction": {
    "parts": [{ "text": "You are concise." }]
  }
}

Roles

Role说明
user用户输入、function response 等客户端提供内容
model模型输出、function call、thought 等模型生成内容

system_instruction 是独立字段,不是普通 contents[].role=system。

Part Types

Google Part 是 oneof 风格,常见字段如下:

Part field说明MaaS canonical
text文本text
inline_data / inlineDatainline bytes + MIME typeimage / audio / file
file_data / fileData文件 URI + MIME typefile / image / audio
function_call / functionCall模型请求调用函数tool_call
function_response / functionResponse函数结果tool_result
executable_code / executableCodecode execution 请求code
code_execution_result / codeExecutionResultcode execution 结果code / tool_result
thought fields / signaturethinking/tool context continuationreasoning / provider metadata

注意:如果模型使用 thinking 或 tools,Google 文档要求保留并原样回传模型生成的 steps/parts,例如 thought、function_call 及其 signatures。

Google Interactions API

新版 Interactions API 把一次交互拆成 input/steps。

Input / Step Types

Type方向基本字段说明
user_inputclient -> modelcontent string 或 content blocks用户输入 step
thoughtmodel -> client/historycontent?, signature?模型思考;Gemini 3+ stateless 回放要保留 signature
function_callmodel -> clientid, name, arguments, signature?custom function call;id 用于结果关联
function_resultclient -> modelname, call_id, result[]function call 执行结果;examples 使用此名
function_responseclient/model contextid/call_id, result, signature?tool-combination 文档也称 result step 为 function_response
built-in tool stepsmodel/servertool-specific args/results, signature?google_search/maps/url_context/file_search 等 built-in tool 上下文
model text/content stepmodel -> clientcontent[] / text fields最终或中间模型输出

Stateful vs Stateless

Mode规则
Stateful使用 previous_interaction_id,server 自动处理 id 与 signature
Stateless客户端自己维护 history;必须把模型生成 steps 原样放回下一轮 input,包括 thought、function_call、built-in tool steps、signature

Function result 示例:

json
{
  "type": "function_result",
  "name": "set_light_values",
  "call_id": "fc_...",
  "result": [{ "type": "text", "text": "{\"brightness\":25}" }]
}

Tool Choice

Value说明
auto默认;模型自行决定是否调用工具
any必须调用函数
none禁止函数调用
validatedPreview;保证 schema adherence;tool context circulation 默认用 validated
allowed_tools限制可调用工具集合

Google Live API

Live API 是双向流,message/event 类型与 generateContent 不同。

DirectionMessage family说明
client -> serversetup建立模型、工具、音频等配置
client -> serverclientContent发送 turns;turns 是 {role, parts},可带 turnComplete
client -> serverrealtimeInput实时音频/视频/activity 输入
client -> servertoolResponse客户端工具结果
server -> clientserverContent模型内容、转录、turnComplete、interrupted 等
server -> clienttoolCall模型请求客户端执行工具
server -> clienttoolCallCancellation工具调用取消
server -> clientsetupComplete / errors会话状态

MaaS 如果只做非实时 Chat/Responses 兼容,可以先不把 Live event 压成普通 message;保留为 stream event 更安全。

Cross-Protocol Mapping

Roles

CanonicalOpenAI ResponsesOpenAI ChatAnthropicGoogle generateContentGoogle Interactions
systemsystemsystemtop-level system 或 mid-conversation role=systemsystem_instructionrequest-level config
developerdeveloperdeveloper无直接等价,通常映射到 system无直接等价request-level instruction/config
useruseruseruseruseruser_input
assistantassistant output messageassistantassistantmodelmodel output/content steps
toolfunction_call_output itemrole=tooluser message with tool_result blocksfunctionResponse partfunction_result step
functionlegacy onlyrole=function legacy无无无

Text / Multimodal

CanonicalOpenAI ResponsesOpenAI ChatAnthropicGoogle
text inputinput_texttext part/stringtext block/stringtext part / user_input.content
text outputoutput_textassistant content/text deltatext blocktext part / model content step
image inputinput_imageimage_urlimageinline_data / file_data
audio inputaudio-specific input or chat input_audioinput_audiofile/document style unless model-specificinline_data / Live realtime input
file/documentinput_filelimited by model/APIdocumentfile_data / inline_data

Tool Calls

CanonicalOpenAI ResponsesOpenAI ChatAnthropicGoogle
call IDfunction_call.call_idtool_calls[].idtool_use.idfunctionCall.id or Interactions function_call.id
provider item IDfunction_call.idsame as call ID or message idsame as call ID/block idstep/part id
call namenamefunction.namenamename
argumentsJSON string argumentsJSON string function.argumentsobject inputobject args / arguments
result referencefunction_call_output.call_idtool_call_idtool_result.tool_use_idfunctionResponse.name/id or Interactions call_id
parallel result packagingmultiple output itemsmultiple role=tool messagesone user message, multiple tool_result blocksmultiple parts/steps

MaaS Implementation Notes

Parse Rules

  • OpenAI Responses:
    • Treat top-level output[] item type as message/item type.
    • For message.content[], treat nested type as content part type.
    • function_call.call_id is the canonical tool call ID; keep id as provider item ID.
  • OpenAI Chat:
    • Treat messages[].role as message role.
    • Treat content[] part type as content part type.
    • Treat assistant.tool_calls[] as tool call parts even though they are not in content.
  • Anthropic:
    • Treat messages[].content[] blocks as first-class parts.
    • Preserve thinking / redacted_thinking unchanged when replaying.
    • Validate tool_result placement before sending.
  • Google:
    • For generateContent, parse contents[].parts[] oneof fields into parts.
    • For Interactions, parse each input[] / steps[] element by type.
    • Preserve signature and model-generated steps in stateless mode.

Serialization Rules

  • Do not serialize tool results as plain user text unless the target protocol has no tool-result primitive.
  • When converting OpenAI Chat -> Anthropic, merge consecutive role=tool messages that answer the same assistant tool_calls[] into one Anthropic user.content[] with multiple tool_result blocks.
  • When converting Anthropic -> OpenAI Chat, split one Anthropic user message containing multiple tool_result blocks into multiple role=tool messages.
  • When converting Responses -> Chat, map function_call.call_id to Chat tool_calls[].id; map function_call_output.call_id to tool_call_id.
  • When converting Google Interactions stateless history, never drop thought or signature fields even if MaaS does not expose them to callers.

Unknown / Future Types

Provider schemas change frequently. MaaS should:

  • keep providerRaw for every unrecognized item/block/part;
  • log unknown type counters by provider/model;
  • fail closed only when the unknown type affects required continuation semantics, e.g. a tool call/result or signed thought step;
  • otherwise pass through or expose as unknown part.

References

  • skills/openai-sdk-python/references/responses/input_tokens/count.md
  • skills/openai-sdk-python/references/chat.md
  • skills/openai-docs/references/guides/function-calling.md
  • skills/anthropic-docs/references/build-with-claude/working-with-messages.md
  • skills/anthropic-docs/references/build-with-claude/mid-conversation-system-messages.md
  • skills/anthropic-docs/references/agents-and-tools/tool-use/handle-tool-calls.md
  • skills/anthropic-docs/references/agents-and-tools/tool-use/troubleshooting-tool-use.md
  • skills/google-ai-docs/references/text-generation.md
  • skills/google-ai-docs/references/function-calling.md
  • skills/google-ai-docs/references/tool-combination.md
  • skills/google-ai-docs/references/live-guide.md

关联信息

反向链接、本文链接的其他页面和外部资料。

站内链接

  • MaaS Prompt Cache
    笔记 · cache.md

    | 模型 / 场景 | 最小缓存 Token 数 | · | Claude Opus 4.5 | 4096 | · | Claude Opus 4.1, 4 | 1024 | · | Claude Sonnet 4.5, 4, 3.7 | 1024 |

  • MaaS SSE
    笔记 · sse.md

    第一个 chunk 通常只有 ,没有内容。 · 后续 chunk 通常有 ,没有 。 · 最后的 chunk 里 和 可能分开出现。 · 第一个 chunk 和最后一个 chunk 通常不应该包含正常 content。 · 有些供应商为了紧凑,会在第一个 chunk 包含内容。

  • MaaS Tool Call
    笔记 · tool-call.md

    Tool call / function calling 是模型请求外部能力的通用机制。 · MaaS 网关需要处理不同厂商的 tool schema、tool choice、tool result role、tool call id 和 streaming chunk 差异。

  • MaaS Usage
    笔记 · usage.md

    MaaS Usage 用于描述模型请求的资源消耗与计费统计。不同 Provider 的字段命名、cache 口径、reasoning 口径和 streaming 返回时机不同,设计统一统计时应同时保留: · 原始 Provider usage:用于供应商账单核对和协议排障。

最近更新commit 6e3fe3e编辑