Model API Research · Merged Edition · 2026-10-25

Model API 三种协议
能力、细节与 Harness 选型

一份合并版报告:先用五层框架讲清 Chat Completions、Responses、Anthropic Messages 的能力差异,再用同一条任务走完三次 trace;最后把 DSH × pi-ai 的数据流、核心对象、同类框架与选型依据合并进来。

3 种协议 5 层能力 1 条任务 3 次 trace DSH × pi-ai 深潜 2026-10 快照
Protocol 01

Chat Completions

兼容层与最大公约数。简单、生态最广,但没有 reasoning 连续性、hosted tools 和 server state。

Protocol 02

Responses

OpenAI 的 agent runtime。Items、hosted tools、server state、encrypted reasoning;Codex 的唯一协议。

Protocol 03

Anthropic Messages

Claude 的强类型 agent 协议。Content blocks、signed thinking、cache_control;Claude Code 的唯一协议。

资料与代码快照:2026-10-25(Asia/Shanghai) 合并内容:协议能力 / 细节 trace / harness / DSH×pi-ai
01 / Background

为什么会有三种协议?

不是三家厂商随意发明三套 JSON,而是 agent 的需求把“聊天 API”推向了“agent runtime”。Chat Completions 解决的是“给模型一段消息、拿回一段文本”;Responses 和 Messages 解决的是“让模型连续地思考、调工具、保持状态、被审计”。

2023

Chat Completions 成为通用 RPC

messages 数组 + function calling + SSE delta。简单、无状态,迅速成为事实标准,几乎所有模型和网关都兼容它。

2023–2024

Anthropic Messages 强化类型

顶层 system、content blocks、tool_use/tool_result、stop_reason。Claude Code 后来把这套协议变成 coding agent 的事实接口。

2025

Responses 把 agent 原语做进协议

Items、previous_response_id、hosted tools、encrypted reasoning、semantic SSE。OpenAI 明确建议新项目用 Responses,Codex 随后只支持 Responses。

2026

协议墙与多模型适配并存

Codex 只认 Responses,Claude Code 只认 Messages;第三方 harness 转向 provider-native + OpenAI-compatible 兜底;Gemini Interactions GA。

一句话理解三种协议

Chat Completions 是 RPC,Responses 是 OpenAI 的 agent runtime,Messages 是 Claude 的 agent runtime。前者把“模型动作”压回 message;后两者把 tool call、reasoning、state、hosted tools 做成一等公民。这个分层决定了它们的能力上限,而不只是字段命名不同。

三条演化线

Line A

通用化

Chat Completions 被 OpenAI、Anthropic、Gemini 以及无数网关实现。它的价值是“谁都能接”,代价是只能表达所有模型的最小公倍数。

Line B

Agent 化

工具循环变长、reasoning 需要跨请求保持、hosted tools 出现、上下文需要压缩。Responses 和 Messages 各自把这些需求写进 wire format。

Line C

厂商化

OpenAI 的 Codex 只支持 Responses,Anthropic 的 Claude Code 只支持 Messages。协议不再是中立标准,而是 harness 与模型生态的绑定面。

背景判断基于 2026-10-25 的官方文档:OpenAI 的 Migrate to Responses 明确“Chat Completions 仍支持,但新项目推荐 Responses”;Claude Code 的 gateway 文档只列 Anthropic Messages / Bedrock InvokeModel / Vertex rawPredict 三种格式。

02 / At a glance

一张表看懂三种协议

先看结构差异,再看能力差异。表中“Chat”指 OpenAI Chat Completions;“Resp”指 OpenAI Responses;“Msg”指 Anthropic Messages。所有结论以 2026-10 的官方文档为准。

Chat Completions Responses Messages
三种协议的结构与能力对照(coding-agent 视角)
维度Chat CompletionsResponsesMessages
定位通用聊天 RPC / 兼容层OpenAI agent runtimeClaude 强类型 agent 协议
端点/v1/chat/completions/v1/responses/v1/messages
请求模型messages[],role 扁平input 为 string 或 Item[]messages[] + 顶层 system,content blocks
工具调用assistant tool_calls → role:"tool"function_call Item → function_call_output Itemtool_use block → tool_result block
终止信号finish_reason(tool_calls / stop)output 含 function_call;statusstop_reason(tool_use / end_turn / pause_turn)
状态无状态,客户端重发全部历史可选 server state(previous_response_id / Conversations)无状态,客户端重发;beta compaction
Reasoning无正式 round-tripencrypted reasoning Itemsthinking block + signature
流式统一 chunk delta + [DONE]语义化 response.* 事件命名 SSE:message_start / content_block_* / message_stop
缓存隐式;GPT-5.6+ 可显式 breakpoint隐式 + 显式 breakpoint / keycache_control 自动或最多 4 个显式 breakpoint
内置工具无 hosted tools最丰富:search / file / code / computer / MCP / shell 等丰富:web / code / computer / editor / MCP connector 等
结构化输出response_formattext.formatoutput_config.format
多模态图片 / 音频 / 文件图片 / 文件(音频按模型核实)图片 / PDF / 文档
长任务无background + WebSocket流式 + pause_turn;无 background
兼容性事实标准,几乎人人支持OpenAI/Codex 系 + 部分网关Claude 系 + 网关 + 自托管
版本策略稳定但 agent 能力冻结;新项目不推荐快速演进;部分能力按模型/账号灰度anthropic-version + beta headers;2026-10-21 有破坏性变更
最大风险能力上限低,前沿 OpenAI 模型工具循环受限OpenAI 绑定强,默认存储/复杂度高前缀/thinking 约束硬,beta 多,版本变更快
关键不是“字段多少”,而是“谁能表达 reasoning 状态”

Chat Completions 不能把模型上一轮的 thinking 原样带回;Responses 可以带 encrypted reasoning item;Messages 可以带签名 thinking block。对短对话影响不大,对长时程 coding agent 是质量分水岭。

03 / Capability, from surface to depth

能力差异:从“长什么样”到“能做什么”

能力差异不是一个表能讲完的。按五层看:L1 表面形状、L2 控制流、L3 状态、L4 质量、L5 系统。越往下,越接近真正的选型。

L1

表面:消息、Item、Block

这是最容易看到的一层,也是最多人停的一层。三种协议都能“发一条消息、拿回一段文本”,但它们的“基本单位”不同:Chat 是 message,Responses 是 Item,Messages 是 content block。

L1:请求/响应/模型动作的单位
维度Chat CompletionsResponsesMessages
请求单位messages[],role 扁平input:string 或 Item[]messages[] + 顶层 system,content blocks
响应单位choices[].messageoutput: Item[]content: Block[]
模型动作assistant message 里的 tool_calls单独的 function_call Item单独的 tool_use block
状态表达历史全在 messages 里Items + 可选 response idmessages + thinking signature
L1 只能让你写出 demo

看懂字段不代表能写 agent。真正的差异在下一层:工具循环由谁驱动、终止信号是什么、结果放在哪里。

L2

控制流:谁驱动工具循环

三种协议都是“模型发起调用 → 客户端执行 → 结果回传 → 模型继续”,但每一步的载体和终止信号不同。写错终止条件,就会死循环或提前结束。

L2:一次工具循环的三步
环节Chat CompletionsResponsesMessages
模型发起assistant tool_calls[];finish_reason:"tool_calls"function_call Item;call_id 关联tool_use block;stop_reason:"tool_use"
执行客户端客户端函数 + 可选 hosted tools客户端函数 + 可选 server tools
回传role:"tool" + tool_call_idfunction_call_output Item + call_iduser message 里的 tool_result block + tool_use_id
继续/终止finish_reason != "tool_calls"output 里不再出现 function_call;statusstop_reason != "tool_use";end_turn

关键差异:Chat 把“调用”和“结果”压进 message,循环最简单;Responses 把模型动作拆成 Item,能表达 hosted tools 和 reasoning;Messages 把 assistant turn 拆成 block,要求整个 turn 原样回传,thinking 不能被丢掉。

失败模式:Chat 把 finish_reason 当文本结束、Responses 把 output[0] 当文本、Messages 只回传 tool_result 而丢掉 thinking —— 三种都会让循环“看起来能跑,实际不对”。

L3

状态:历史到底归谁

这是从“能跑”到“能长跑”的分水岭。状态归属决定了你能不能压缩、分支、重写历史、做 ZDR,也决定了缓存和 reasoning 连续性。

L3:状态所有权与可编辑性
维度Chat CompletionsResponsesMessages
默认状态客户端服务端(可 store:false)客户端
续接方式重发全部 messagesprevious_response_id / Conversations / 手工回放重发全部 messages
历史编辑完全可控stateful 模式受限;stateless 可控可控,但 preserved thinking 要求 append-only
ZDR/驻留最容易需显式 store:false + 加密 reasoning最容易
failover最容易,但丢 reasoning需回放 Item;reasoning 不可跨 provider需处理 thinking 签名,跨 provider 不可用

非显然的判断:server state 不是“更先进”,而是“把复杂度从客户端搬到服务端”。它简化回放、提高缓存,但带来 retention/ZDR/数据驻留/历史不可编辑的约束。客户端状态更可控,但压缩、分支、重写历史的代码要自己写。

L4

质量:reasoning、cache、stream

这一层开始解释“为什么同样模型,换协议效果会变”。决定性因素是 reasoning 能否跨轮回传、缓存能否稳定命中、流式事件是否足以驱动工具进度。

L4.1 Reasoning round-trip

协议Reasoning 载体回传要求典型失败
Chat无正式载体(仅 usage 计数)无多轮后推理不连续;新 OpenAI 模型工具调用受限
Responsesreasoning Item,含 encrypted_content / summary与 function_call 一起回传;不要漏、不要改工具循环质量下降;与手工回放混用导致上下文重复
Messagesthinking block + signature工具回合内完整原样回传;跨回合建议全部回传修改/重排 400;prefix 变化导致 preserved thinking 失效
Chat 的 reasoning 要分两层看

OpenAI Chat Completions 核心只支持 reasoning 模型与 reasoning_effort:reasoning token 会产生、会计费,但不会作为内容返回,也没有跨轮状态回传;reasoning summary 只在 Responses 里提供。OpenAI-compatible 厂商(DeepSeek、OpenRouter、vLLM 等)常在 Chat 形状上增加 reasoning_content / reasoning_details 扩展,这才让 Chat 能“看到”推理内容;但字段名、流式 delta、是否必须回传都因厂商而异,不是 OpenAI 标准。

为什么这是胜负手:reasoning 是 provider-scoped、model-family-scoped 的不透明状态。它不能翻译成另一家的字段,也不能在 fallback 时复用。短对话看不出来,长工具循环会暴露质量差距。

L4.2 缓存与 prefix

协议机制控制粒度典型 TTL
Chat隐式;GPT-5.6+ 支持显式 breakpointprompt_cache_key / prompt_cache_options30m(新模型);旧模型 in_memory/24h
Responses隐式 + 显式 breakpointprompt_cache_key / prompt_cache_options30m/12h(模型相关)
Messages自动或 block 级 cache_control最多 4 个显式 breakpoint5m/1h

非显然的判断:缓存不是“省钱技巧”,而是“历史不可变”的约束。你一旦用显式缓存,就必须保证 tools/system/thinking 配置稳定、历史 append-only;否则命中率会掉,甚至 prefix 失效。

L4.3 流式语义

协议事件模型文本工具参数Reasoning
Chat统一 chunkdelta.contenttool_calls[].function.arguments 片段无
Responses语义 response.* 事件response.output_text.deltaresponse.function_call_arguments.deltareasoning_summary_text.delta
Messages命名 block 事件text_deltainput_json_deltathinking_delta + signature_delta

非显然的判断:流式不是 UI 细节。语义事件决定你能不能做工具进度、reasoning 展示、断线恢复;chunk 最好写,但信息最少。

L5

系统:hosted tools、长任务、可移植

最后一层是架构:协议不仅是“怎么调模型”,还决定你能不能把 search/code/computer/MCP 交给厂商、能不能做后台任务、能不能跨 provider 迁移。

能力Chat CompletionsResponsesMessages
Hosted tools无最丰富:search/file/code/computer/MCP/shell丰富:web/code/computer/editor/MCP connector
后台/长任务无background + WebSocket流式 + pause_turn;无 background
可移植性最高较低(OpenAI 绑定)中等(Claude 生态强)
治理边界harness 自己provider 可代跑工具,信任边界外移provider 可代跑 server tools
能力总结:不是打分,而是“默认强项”
能力ChatResponsesMessages
Reasoning 连续性弱强强
工具循环保真中强强
状态/长任务弱强中
缓存控制中强强
Hosted tools弱强强
可移植性强弱中
实现复杂度低高高
04 / Detail, one task three traces

细节差异:同一条任务,三种 trace

抽象讨论容易失真。这里用一个最小任务把三种协议各跑一遍:用户说“读一下 a.py”,模型调用 read_file,工具返回内容,模型继续回答。重点看每一步的载体、终止信号和状态。

Chat Completionsmessages
{
  "model": "gpt-...",
  "messages": [
    { "role": "user",
      "content": "Read a.py" }
  ],
  "tools": [{
    "type": "function",
    "function": {
      "name": "read_file",
      "parameters": { "type": "object" }
    }
  }]
}
ResponsesItems
{
  "model": "gpt-...",
  "input": [
    { "role": "user",
      "content": "Read a.py" }
  ],
  "tools": [{
    "type": "function",
    "name": "read_file",
    "parameters": { "type": "object" }
  }]
}
Messagesblocks
{
  "model": "claude-...",
  "max_tokens": 1024,
  "system": "You are a coding agent.",
  "messages": [{
    "role": "user",
    "content": "Read a.py"
  }],
  "tools": [{
    "name": "read_file",
    "input_schema": { "type": "object" }
  }]
}

Step 1:模型怎么发起工具调用

同一步,三种协议的字段与流事件完全不同
协议完整响应里的调用终止信号流式事件
Chatchoices[0].message.tool_calls[0]:{id, function:{name, arguments}}finish_reason:"tool_calls"delta.tool_calls[].function.arguments 片段
Responsesoutput[] 中的 function_call:{call_id, name, arguments}output 中出现 function_callresponse.function_call_arguments.delta
Messagescontent[] 中的 tool_use:{id, name, input}stop_reason:"tool_use"input_json_delta(partial JSON)

细节:Chat 的 arguments 是 JSON 字符串,Responses 也是字符串,Messages 的 input 是对象;但流式时三者都可能只给出 partial JSON。不要在第一个 delta 就解析。

Step 2:工具结果怎么回传

协议回传消息关联键注意
Chat新增 {"role":"tool","tool_call_id":"call_1","content":"..."}tool_call_id一条 tool message 对应一个调用
Responses新增 {"type":"function_call_output","call_id":"call_1","output":"..."}call_idreasoning Item 要一起回传
Messagesuser message 里加 {"type":"tool_result","tool_use_id":"toolu_1","content":"..."}tool_use_idassistant 的 thinking + tool_use 原样保留

Step 3:模型继续与终止

协议继续生成最终响应状态变化
Chat追加 tool message 后再次请求choices[0].message.contentfinish_reason:"stop"
Responsesprevious_response_id 或回放完整 Item 历史output[] 里的 message / output_textstatus:"completed"
Messages把 assistant content + tool_result 回传content[] 里的 textstop_reason:"end_turn"

把三次 trace 对齐

步骤ChatResponsesMessages
模型动作message.tool_callsfunction_call Itemtool_use block
工具结果role:"tool"function_call_output Itemtool_result block
终止信号finish_reasonstatus / outputstop_reason
Reasoning没有reasoning Itemthinking block + signature
历史编辑完全可控stateful 受限 / stateless 可控append-only 最稳

翻译会丢什么

翻译通常能保留通常丢失/降级
Chat → Responses文本、工具调用/结果、大部分 schemasigned/encrypted reasoning、hosted tools、server state、语义事件
Responses → Chat文本、函数调用reasoning Item、built-in tools、previous_response_id、compaction
Messages → Responses文本、工具调用/结果thinking signature、cache_control、server tools、beta 字段
任意 → Chat文本、函数调用reasoning 状态、缓存控制、hosted tools、长任务语义
最重要的回归测试

不要只测“最终文本对不对”。至少测:工具调用 ID 是否稳定、partial JSON 是否能拼完整、thinking/reasoning 是否原样回传、终止事件是否识别、缓存 prefix 是否被意外改写、失败后重试是否重复执行工具。

05 / Tradeoffs, judgments only

取舍:五个判断

这一节只留判断,不重复事实;完整 harness/版本事实在附录 A 和 B。真正难的不是“知道字段”,而是知道在什么约束下放弃什么。

判断 01

先选模型 / harness,再选协议

协议不是自由变量。Codex 只能 Responses、Claude Code 只能 Messages;选错 harness,协议就固定了。反过来,选模型路线也会排除一批 harness。

行动:先列“必须支持的模型 + 必须用的 harness”,再看协议;不要先画一个“统一协议”架构。

判断 02

Chat 是兼容层,不是 agent protocol

Chat 适合简单聊天、分类、RAG、旧应用、自托管入口。对“推理模型 + 长工具循环”,它的能力上限已经被 OpenAI 自己的新模型限制封死。

行动:把 Chat 放在边界,不要放在 agent 核心;需要 agent 时优先 Responses/Messages。

判断 03

State 是产品/合规决策

server state 简化回放、提升缓存,但带来 retention/ZDR/数据驻留/历史不可编辑。client state 更可控,但要自己写压缩、分支、回写。

行动:先问“历史能不能编辑/删除/驻留”,再决定 state 归属;不要默认 server state。

判断 04

Reasoning / cache 是移植成本

跨协议翻译能保留文本和工具调用,但很难保留 signed/encrypted reasoning、cache 前缀和 hosted tools。短对话看不出,长任务会暴露。

行动:网关优先 native passthrough;翻译只用于非推理/短对话;fallback 不要把 reasoning 当可复用状态。

判断 05

网关要原生,不是“统一成 Chat”

同时服务 Codex + Claude Code 的网关,必须原生提供 /v1/responses 和 /v1/messages;只做 Chat 翻译会同时丢两端的能力。

行动:入口按客户端协议分流,出口按 provider native;把“是否翻译”作为可观测字段。

条件 → 选择(快速判断)
你的约束优先选择避免
OpenAI 前沿模型 + 长工具循环ResponsesChat 作为主协议
Claude 生态 + thinking/cacheMessagesChat 翻译层接 Claude Code
多 provider、简单聊天/RAGChat 兼容层用 Chat 统一所有 agent
同时服务 Codex + Claude Code原生 Responses + Messages 双入口只做 Chat 网关
ZDR / 历史可编辑客户端状态 / store:false默认 server state
长上下文/成本敏感支持 prefix cache 且 append-only每轮重写 system/tools
选型公式

选择 = 模型路线 × harness 协议墙 × 工作负载 × 合规/成本。四个约束里先排除不可选项,再在剩下的里选“保真度最高、翻译最少”的方案。

06 / Harness, three rules

Harness:三条规则

完整 20 行 harness 事实表在附录 A。正文只留三条规则、架构分类和“为什么”,避免把“事实”当“分析”。

Rule 01 · OpenAI

Codex 是 Responses 墙

wire_api 只接受 "responses";只实现 Chat Completions 的网关无法服务 Codex。这不是“偏好”,是硬约束。

wire_api = "responses"
Rule 02 · Anthropic

Claude Code 是 Messages 墙

Claude Code / Agent SDK 只接受 Anthropic Messages、Bedrock InvokeModel、Vertex rawPredict;没有 OpenAI 格式模式。

ANTHROPIC_BASE_URL → /v1/messages
Rule 03

同时服务 Codex 和 Claude Code 的网关,必须原生提供 /v1/responses 和 /v1/messages。只做 Chat 翻译,Codex 直接 404,Claude Code 拿不到完整 thinking/cache 语义。

三种 harness 架构

默认协议不是随机的:架构决定默认值
架构代表默认协议代价
厂商自有Codex、Claude Code、Gemini CLI、Antigravity自家 native(Responses / Messages / generateContent)协议墙、模型锁定
多 provider nativeCline、OpenCode、Kilo、Zed、Crush、Goose按 provider native;自定义端点 Chat适配代码多;Gemini Interactions 支持薄
Chat-normalizingAider、OpenHands、SWE-agent(LiteLLM)harness 入口 Chatreasoning/cache/hosted tools 受翻译层限制
provider-neutralDSHDeepSeek route Messages;其他 provider 经 pi-ai nativeadapter 多;依赖 pi-ai

为什么默认值差异这么大

  • 厂商自有 harness 服务自家模型:Codex/Claude Code/Gemini CLI 的默认值是 dogfooding,也是协议墙的来源。
  • 抽象层决定默认值:AI SDK 系更容易跟上 Responses/Interactions;LiteLLM 系天然以 Chat 为内部形状;DSH 选择 provider-neutral + native adapter。
  • 订阅 OAuth 是隐形协议通道:ChatGPT/Codex、Claude、Copilot 的订阅后端往往走 Responses/Messages 的私有变体。
  • OpenAI-compatible 是最低成本扩展:大量 harness 把它当兜底,代价是 reasoning/hosted tools/state 受限。
07 / DeepSeek Harness × pi-ai

DSH × pi-ai:provider-neutral 与原生 adapter

这一章是合并进来的 DSH 深潜。先纠正一个常见画法:DSH 的 LLM 流不是“HTTP Chat/Responses/Messages 进来”,也不是“adapter = DeepSeek Messages / pi-ai”。正确结构是:agent loop → dsh-llm → adapter 选择 → 两条分支。

Branch A · 官方 route

dsh-llm-deepseek

直连 DeepSeek Messages(https://api.deepseek.com/anthropic + /v1/messages);默认 route deepseek-official / deepseek-account。baseURL 也可指向 Messages-compatible 网关。

Branch B · 三方 provider

dsh-llm-pi-ai

通过 pi-ai catalog 接三方 provider 的 native protocol(OpenAI Responses / Anthropic Messages / Google generateContent 等);自定义 route 只开 3 种协议。

下面 §7.1–§7.7 以 dsh-llm-pi-ai 为主线;dsh-llm-deepseek 共享同一个 dsh-llm seam 和 StreamChunk 契约,但不经过 toPiContext / toStreamChunks。

7.1 / Relationship

Pi、pi-ai、DSH:谁是谁

先把最常见的误解拆掉:dsh-llm-pi-ai 不是 Pi harness,也不是“DSH 内置了 Pi”。它只是 DSH 的一个 adapter,把 pi-ai 这个多 provider LLM 库接进 DSH 的 dsh-llm seam。

Pi harness @earendil-works/pi-coding-agent
独立 coding agent harness:CLI、工具、TUI、扩展、skills、agent core。
使用
→
pi-ai @earendil-works/pi-ai
多 provider LLM 库:provider 目录、认证/OAuth、模型元数据、协议适配、流事件。
←
包装
DSH @deepseek-ai/dsh
独立 coding harness:自己的 agent loop、工具、session、Web/CLI、审批、重试。
Pi

harness 本体

Pi 是 Earendil Works 的 minimal/extensible coding agent;monorepo 里还有 pi-agent-core、pi-tui、pi-durable 等。

pi-ai

模型层

不是 harness,也不是网关;它是被 Pi 和 DSH 共同复用的 provider/LLM 库。

DSH

另一个 harness

DSH 只依赖 pi-ai,不依赖 pi-coding-agent/pi-agent-core;Pi 的 CLI/TUI/工具不会进入 DSH。

一句话

Pi 和 DSH 是并列的 harness;它们共享 pi-ai 这个模型层,但不是 fork,也不是同一个运行时。 dsh-llm-pi-ai 是 DSH 侧的 adapter,负责把 pi-ai 的 Context / AssistantMessageEvent / Model 转成 DSH 的 GenerateOptions / StreamChunk / ReplayEnvelope。

证据:DSH 的 packages/llm/llm-pi-ai/package.json 只声明 @earendil-works/pi-ai,没有 pi-coding-agent 或 pi-agent-core;其 description 明确写的是 “design-verification twin of dsh-llm-deepseek”。

7.2 / Data flow

一次请求的数据交互流程

DSH 的请求不是“把 messages 直接丢给 pi-ai”。中间有 provider-neutral 预处理、能力校验、凭据解析、图片投影、Context 转换、事件回译和 replay 存储。

先分清两条 adapter 分支

DSH 的 dsh-llm 后面不是只有一个 adapter:dsh-llm-deepseek 直连 DeepSeek Messages(默认 route:deepseek-official / deepseek-account);dsh-llm-pi-ai 通过 pi-ai catalog 接三方 provider(OpenAI / Anthropic / Google / …)。本章 §7.2–§7.4 以 dsh-llm-pi-ai 为主线,DeepSeek 直连分支在同一个 seam 下走另一套 adapter。

1. Agent loop从 session 构造 GenerateOptions,deep-freeze
2. LlmRuntime选 adapter、冻结本次调用、投影 file/image/tool update
3. Adapter解析 snapshot、model、capabilities、credential
4. toPiContextDSH Message → pi-ai Context
5. streamSimplepi-ai provider → 原生 wire
6. toStreamChunksAssistantMessageEvent → StreamChunk
7. BlockAssembler拼 content blocks,记录 assistant message
8. ReplayreplayState 存进 source,下一轮恢复签名/ID

图中的 5–8 步是 dsh-llm-pi-ai 的路径;dsh-llm-deepseek 走 DeepSeek Messages,不经过 toPiContext/toStreamChunks,但共享同一个 dsh-llm seam 和 StreamChunk 契约。

7.2.1 入口:GenerateOptions

Agent loop 从 session 里取出历史,构造“模型将看到的精确输入”。DSH 的 GenerateOptions 同时包含请求身份、消息、工具和采样控制:

interface GenerateOptions {
  provider: string
  model: string
  reasoningEffort?: ReasoningEffortId
  messages: RequestMessage[]       // system / developer / user / assistant / tool
  system?: string                  // one-shot 调用
  tools?: ToolSchema[]
  toolHistory?: ToolHistory
  temperature?: number
  maxTokens?: number
  stop?: string[]
  sessionId?: SessionId
  purpose?: 'compaction' | 'session-title'
  signal?: AbortSignal
}

messages 里的内容块是 DSH 的 canonical ContentBlock:text、reasoning、image、file、tool-call、tool-addition、tool-removal。这份输入会被 deep-freeze,adapter 只读。

7.2.2 LlmRuntime:provider-neutral 预处理

在进入 adapter 前,LlmRuntime.adapterStream() 做四类统一处理:

  • 文件投影:file block 永远不直接发给 provider,转成带路径/大小的文本句柄;
  • 图片投影:不支持图片的模型,图片变成文本占位符;支持图片的模型才进入 attachment 解析;
  • 工具更新投影:按模型的 toolUpdate 能力选择 in-history / addition-only / 完整列表;
  • Replay 隔离:如果历史 assistant 的 source.provider 不是当前 adapter 拥有的 provider,就剥掉 replayState,避免跨 adapter 使用 provider 签名。

这一步是 DSH 的“provider-neutral 边界”:所有 provider 看到的输入先被规范化,但 reasoning/cache 等 provider 语义不被强行翻译。

7.2.3 PiAiAdapter:解析 snapshot、模型、凭据

每个请求会取当前 profiles 的不可变 snapshot(profiles + pi-ai Models collection)。配置变更会构建新 snapshot,不会修改飞行中的请求;这样 prepareCall() 冻结的配置能一直保持到 dispatch。

// 简化自 adapter.ts
const profile = snapshot.profiles.get(options.provider)
const model = snapshot.models.getModel(options.provider, options.model)
const reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning)
const apiKey = await this.config.resolveApiKey(options.provider, profile)
const events = snapshot.models.streamSimple(model, context, {
  apiKey,
  reasoning,
  ...options.temperature !== undefined ? { temperature: options.temperature } : {},
  ...options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {},
  ...options.sessionId !== undefined ? { sessionId: String(options.sessionId) } : {},
  signal: watchdog.signal,
  headers,
  maxRetries: 0, // 重试归 DSH
})

凭据解析是“fail loud”的:如果 profile 明确写了 apiKeyEnv,解析不到就抛 MISSING_CREDENTIAL,不会让 pi-ai 去捡一个不相关的 OPENAI_API_KEY。只有完全没配凭据的 route 才交给 pi-ai 的 provider-native ambient auth / OAuth store。

7.2.4 toPiContext:DSH Message → pi-ai Context

toPiContext() 把 DSH 的 role/content 结构翻译成 pi-ai 的 Context:

  • 请求级 system + 开头连续的 system 历史 → Context.systemPrompt;
  • 其余 system / developer / assistant / tool / user → pi-ai messages;
  • tool-call → pi-ai toolCall(arguments 从 DSH 的原始 JSON 字符串解析成对象);
  • tool → pi-ai toolResult,toolName 从前一条 assistant 的 tool call 建立 id→name 映射补上;
  • developer 的 tool-addition/tool-removal → pi-ai system 的 toolsAdded/toolsRemoved(或模型不支持时降级);
  • 图片 → pi-ai ImageContent;文件永远只以文本句柄出现。

7.2.5 pi-ai provider:原生 wire

models.streamSimple() 是 pi-ai 的统一简化入口。它内部按模型的 api 选择协议实现:anthropic-messages、openai-responses、openai-completions、google-generative-ai、bedrock-converse-stream 等。协议差异由 pi-ai 的 provider 层处理,DSH 只看到统一的 AssistantMessageEvent。

7.2.6 toStreamChunks:事件回译

// 简化映射
text_start      → { type: 'block-start', blockType: 'text' }
text_delta      → { type: 'text-delta', text }
thinking_start  → { type: 'block-start', blockType: 'reasoning' }
thinking_delta  → { type: 'reasoning-delta', text }
toolcall_start  → { type: 'block-start', blockType: 'tool-call' }
toolcall_delta  → { type: 'tool-call-delta', argumentsDelta }
toolcall_end    → { type: 'block-end', block: { type:'tool-call', arguments: JSON.stringify(...) } }
done            → { type: 'usage' } + { type: 'finish', replayState }
error           → { type: 'usage' } + { type: 'finish', reason: error/aborted }

这里有一个重要方向差异:pi-ai 的 tool arguments 是已解析对象,DSH 的 tool-call 保留原始 JSON 字符串。所以 toolcall_end 会重新 JSON.stringify;参数非法时 DSH 会报 MALFORMED_RESPONSE(除非是 length 截断)。

7.2.7 回到 DSH:BlockAssembler 与 Replay

BlockAssembler 把 StreamChunk 拼成 DSH 的 content blocks;finish.replayState 被存进 assistant message 的 source.replayState。下一次请求只有在同一个 adapter 实例同时拥有历史 provider 和目标 provider 时,才会把 replay state 传给 adapter;否则剥离并降级为 provider-neutral 历史。

7.3 / Objects

核心数据对象

DSH 和 pi-ai 各有一套完整的类型系统。理解 adapter 的关键,是看清两边的对象如何一一对应,以及哪些字段是“语义损失点”。

DSH

Provider-neutral 词汇

GenerateOptions

provider / model / messages / system / tools / toolHistory / reasoningEffort / temperature / maxTokens / stop / sessionId / purpose / signal

Message + ContentBlock

role: system / developer / user / assistant / tool;block: text / reasoning / image / file / tool-call / tool-addition / tool-removal

StreamChunk

block-start / text-delta / reasoning-delta / tool-call-delta / block-end / usage / finish

ReplayEnvelope

response + blocks:adapter-private 的原生回放元数据,DSH 只存不解释

pi-ai

Provider 原生词汇

Context

systemPrompt / messages / tools

Message

user / assistant / toolResult / system

AssistantMessage

content: text / thinking / toolCall;usage、stopReason、responseId、responseModel、providerThinkingLevel、签名

AssistantMessageEvent

start / text_* / thinking_* / toolcall_* / done / error

Model + Models

provider/id/api/baseUrl/reasoning/input/contextWindow/maxTokens/thinkingLevelMap/compat;Models 提供 streamSimple()

对象映射表

DSH ↔ pi-ai 的对象对应关系
DSHpi-ai转换要点
GenerateOptionsContext + SimpleStreamOptions消息进 Context,采样/凭据/传输进 options
Message / ContentBlockContext.messages / ContentBlockrole 和 block 语义基本对齐,但 toolResult 需要补 name
ToolSchemaToolname/description/parameters 直接映射
StreamChunkAssistantMessageEvent事件一一对应,但 tool arguments 类型不同
TokenUsageUsagepi-ai 把 reasoning 折进 output;cache 只在非零时出现
FinishReasonAssistantMessage.stopReasonstop/toolUse/length/error/aborted 映射;deferred → error
ReplayEnvelopeAssistantMessage 原生字段只保存 responseId / signatures / thoughtSignature / namespace
LlmResolvedModelInfoModelcontextWindow、input、reasoning、thinkingLevelMap、compat

最容易踩的四个转换点

Arguments

原始 JSON 字符串 vs parsed object

DSH 保留模型产出的 raw JSON string;pi-ai 的 toolCall.arguments 是 parsed object。adapter 在 toolcall_end 重新 stringify。非法 JSON 在 DSH 侧是 MALFORMED_RESPONSE。

Tool name

toolResult 需要 toolName

DSH 的 tool 消息只有 toolCallId;pi-ai 的 toolResult 需要 toolName。adapter 从前一条 assistant 的 tool call 建立 id→name 映射补上。

Error

cause 被压平,只能文本分类

pi-ai 把底层 Error 压平成 error.message,丢掉 cause。DSH 的 stream.ts 里有 XXX(pi-ai upstream) 注释,承认只能正则识别 AUTH / RATE_LIMIT / TIMEOUT / TRANSPORT。

Perf

tool 参数流式解析 O(n²)

DSH 对 pi-ai 打 patch,去掉每个 delta 对整个累计 JSON 的重复解析;否则多 MB 参数流会卡事件循环。这是库级集成的真实代价。

7.4 / Replay

Replay:保留 provider 原生签名

DSH 的 durable 内容(text / reasoning / tool-call)是 source of truth;pi-ai 的 replay metadata 只负责恢复“原生保真度”,不是重新存一份 assistant message。

1. pi-ai done拿到完整 AssistantMessage + usage + stopReason
2. toPiReplayState提取 responseId / responseModel / thinking signatures / thoughtSignature
3. DSH 存储写进 assistant.source.replayState
4. 下一轮toPiAssistant 校验并恢复原生 AssistantMessage

Replay envelope 有两半:

  • response:api、provider、model、responseId、responseModel、providerThinkingLevel、stopReason;
  • blocks:逐块的 textSignature、thinkingSignature、redacted、toolCall.thoughtSignature、namespace。
关键设计

如果 replay state 缺失、版本不匹配、provider/model 不匹配或 block 数量/类型不一致,DSH 会把它降级成 provider-neutral 历史,并记 warning,而不是让请求失败。这样既保住了“能跑”,又尽量保住“原生签名”。

这也解释了 DSH 为什么不把“所有 provider 都归一化成 Chat Completions”:一旦归一化,thinking signature / responseId / thoughtSignature 就没有地方存,长时程工具循环的质量会下降。

7.5 / Why pi-ai

DSH 选 pi-ai 的因素

这一节把“仓库明说的”与“我基于代码结构的推断”分开。前者可以在 DSH 的 README、Agent Note、源码注释里找到;后者是工程判断,不是官方声明。

7.5.1 仓库/代码明确说到的

Twin adapter

“design-verification twin”

DSH 同时有 dsh-llm-deepseek(直连 fetch)和 dsh-llm-pi-ai(库实现)。两套不同内部实现跑同一个 StreamChunk 契约,用来验证“provider-neutral”不是只适配了 DeepSeek 的假抽象。

Catalog + auth

provider 目录、OAuth、模型元数据

catalog route 继承 pi-ai 的 endpoint、protocol、model catalog;OAuth 登录、credential store、环境变量发现都不需要 DSH 自己为每个 provider 重写。

Narrow protocols

自定义 route 只开 3 种协议

openai-completions / openai-responses / anthropic-messages。Bedrock/Vertex/Azure/Codex 的认证流程无法用“key + baseURL + models”完整表达,所以走各自 catalog provider。

Bundle

narrow runtime imports

dormant 的 dsh-llm-pi-ai 不 import pi-ai aggregate entry,避免把 TypeBox 和数百个模块带进每次启动;协议实现走 api/*.lazy。

Retry

重试归 DSH

pi-ai 调用设 maxRetries: 0;DSH 的 dsh-llm-retry 在 agent step 边界重试。adapter 一次调用就是一次 SDK attempt。

Cache

system reminder fallback

pi-ai 对不支持 mid-conversation system 的模型会把后续 system 拼到初始 prompt,破坏 prefix cache;DSH 改成 <system-reminder> user 消息,保留原生 system 的模型则不动。

Patch

流式 tool 参数性能

DSH 仓库对 pi-ai 的流式 tool-call 参数解析打 patch,去掉每个 delta 的整段 JSON 重复解析(O(n²))。

Replay

durable content 权威

DSH 只存 pi-ai 的原生签名/ID,不存完整 assistant message;跨 adapter 剥离 replay,失效时降级而不是失败。

7.5.2 我的推断(未在仓库中直接写死)

  1. TS/Node 同栈、in-process:DSH 是 TS 插件系统;pi-ai 是 TS 库,可以直接进进程,不需要像 LiteLLM 那样额外跑 Python 服务。对桌面/CLI/本地优先的 harness,这是决定性因素。
  2. 覆盖成本:要自己接 OpenAI、Anthropic、Google、Bedrock、Vertex、OpenRouter、Groq、Cerebras、xAI、Copilot 等几十家 provider,认证/OAuth/模型目录/流事件都要维护;pi-ai 已经把这些做成 catalog。
  3. 原生协议保真:DSH 的差异化是“provider-neutral 但不丢 provider 语义”;pi-ai 保留 native protocol 和 provider metadata,比 Chat 归一化网关更贴合 DSH 的 replay 设计。
  4. 插件化快照语义:DSH 的 prepareCall() 要冻结一次调用的 adapter generation;pi-ai 的 Models collection 可以整体替换,adapter 用不可变 snapshot 包住,正好匹配。
  5. 不需要网关能力:DSH 不需要中心化 key、LB、guardrails、团队配额;这些是 LiteLLM/Portkey/Bifrost 的强项,但对本地 harness 是额外服务。DSH 自己已经有 credential seam、retry、session、审批。
  6. 生态/许可证:pi-ai 是 MIT,Pi harness 自己 dogfood;DSH 可以读源码、打小 patch,不需要引入商业网关。

7.5.3 代价与风险

Dependency

上游 + patch 维护

pi-ai 升级要重新验证 patch、错误文本分类、provider 行为;DSH 的 patch 是集成成本的一部分。

Error

错误 cause 丢失

pi-ai 把底层 Error 压平成 message,DSH 只能靠正则识别 401/429/5xx/timeout;provider 改文案就会误分类。

Scope

不是网关

没有 load balancing、fallback、central quota、guardrails;DSH 只做单次调用,路由/重试在更上层。

Drift

catalog 漂移

pi-ai 的模型目录/协议支持变化会影响 DSH 的模型选择;DSH 用 patch/版本 pin 控制。

7.6 / Frameworks

同类框架:pi-ai 在哪个位置

pi-ai 既不是 LiteLLM Proxy,也不是 OpenRouter,更不是 LangChain。先把“库 / 网关 / 托管 / agent 框架”分开,再比较会清楚很多。

7.6.1 四类形态

先分类,再比较:不同形态解决的问题不同
类别代表形态适合
进程内多 provider 库pi-ai、Vercel AI SDK、LiteLLM SDK、aisuite、any-llm代码依赖,直接调用 provider嵌入 harness/应用,低延迟,自己控制运行时
自托管 HTTP 网关LiteLLM Proxy、Portkey、Bifrost、TensorZero独立服务,统一 API团队级 key/配额/路由/观测/guardrails
托管网关OpenRouter、Vercel AI Gateway、Cloudflare AI GatewaySaaS 代理快速接大量模型,免运维
Agent 框架LangChain、LlamaIndex、Pydantic AI、Mastra编排/agent 抽象构建应用逻辑,不是模型传输层
DSH 要的是第一类

DSH 是本地优先的 coding harness,自己的治理边界在 credential / session / approval / retry 层;它不需要再套一个中心网关。pi-ai 作为 in-process 库,正好补“多 provider 接入”,又不和 DSH 的运行时抢职责。

7.6.2 横向对比

代表性框架对比(2026-10;部分数字为厂商自述,具体以官方为准)
框架形态/语言协议策略优点代价/限制DSH 匹配
pi-aiTS 库每个 provider 走 native protocol;统一 Context / eventprovider 目录全、OAuth/认证/模型元数据、类型好、可嵌进程、MIT不是网关;无路由/LB/guardrails;错误 cause 丢失;需维护 patch最匹配
LiteLLMPython SDK + Proxy(新版 Rust core)主要 OpenAI 格式,支持 native passthrough100+ provider、成本追踪、路由/fallback、guardrails、企业功能独立 Python 服务;翻译层可能丢 reasoning/cache;运维复杂服务端可选
Vercel AI SDKTS 库provider packages 走 native API;统一 LanguageModel / stream partsUI/agent 生态强、provider 多、TS 类型好、Apache-2.0更偏应用/UI;默认 Vercel AI Gateway;不是 provider catalog/auth 库可选替代
OpenRouter托管网关主 API 是 OpenAI Chat;另有 Anthropic Messages / Responses(stateless)400+ 模型、路由/fallback、免运维、统一账单托管、额外网络跳、数据合规、无本地/离线可当 route
Portkey自托管/托管网关(MIT)OpenAI-compatible,1600+ 模型guardrails、缓存、路由、观测、企业部署独立服务;翻译层;不是 TS 库团队网关
BifrostGo 网关(Apache-2.0)OpenAI-compatible,10k+ 模型高性能(<200µs)、failover、语义缓存、MCP独立服务;Go 运维;翻译层团队网关
TensorZeroRust 网关 + LLMOps(Apache-2.0)OpenAI-compatible观测/评估/优化/实验一体化偏 LLMOps 平台;独立服务团队实验
aisuitePython 轻量库(MIT)统一 Chat Completions + Agents简单、易学、provider 覆盖功能少、无 gateway/路由;PythonPython 应用
any-llmPython 库(Apache-2.0)单一接口轻量、provider 覆盖、Mozilla 生态无 gateway/路由;PythonPython 应用
LangChain / LlamaIndexPython/TS 编排框架各自 model wrapper生态、RAG/agent 组件不是 wire-level 传输层;抽象重不是同类

7.6.3 三个关键对比

pi-ai vs LiteLLM

pi-ai:TS 库,嵌进程;provider catalog / auth / model metadata / 原生流事件;无服务、无网关治理。

LiteLLM:Python SDK + Proxy;统一网关、路由、成本、guardrails、企业治理;以 OpenAI 格式为主,支持 native passthrough。

选择:本地/桌面 harness → pi-ai;团队统一入口/配额/审计 → LiteLLM。

pi-ai vs Vercel AI SDK

两者都是 TS 进程内库。AI SDK 更上层,偏应用/UI/agent,默认 Vercel AI Gateway,provider 包很多;pi-ai 更底层,重点是 provider catalog、认证/OAuth、模型元数据、原生流事件。

选择:DSH 已有自己的 agent loop/UI/session,pi-ai 的边界更窄、更贴合 dsh-llm;如果是 Next.js 应用,AI SDK 更顺手。

pi-ai vs OpenRouter / Portkey / Bifrost

这些是网关/服务,不是库:多一跳网络、多一套运维、可能翻译协议;适合团队统一治理,不适合本地优先的 DSH 内核。

选择:DSH 可以把它们当成一个自定义 OpenAI-compatible route,但不会把它们嵌进进程。

pi-ai vs aisuite / any-llm

这两者都是 Python 轻量统一接口,适合 Python 应用快速接多家 provider;但没有 DSH 需要的 TS 类型、provider catalog、OAuth、原生 replay 元数据和进程内插件语义。

选择:Python 应用 → aisuite/any-llm;TS harness → pi-ai/AI SDK。

7.6.4 决策矩阵

按需求选形态:没有“最好”,只有“边界匹配”
需求首选次选不要选
本地/桌面 coding harness,TS,进程内pi-aiVercel AI SDKLiteLLM Proxy / OpenRouter
团队统一 key、配额、审计、路由LiteLLM Proxy / PortkeyBifrostpi-ai(没有治理层)
快速接 400+ 模型、免运维OpenRouterVercel AI Gateway自建 provider 适配
Python 应用快速统一接口LiteLLM SDK / aisuiteany-llmpi-ai(TS)
LLM 实验/评估/优化TensorZeroLiteLLM + 自建观测纯库
Next.js/React AI 应用Vercel AI SDKAI Gatewaypi-ai(缺少 UI 层)
7.7 / Conclusion

DSH × pi-ai 的结论

  1. DSH 的 pi-ai adapter 是“模型接入层”,不是 Pi harness,也不是网关。它把 pi-ai 的 provider/catalog/auth/native stream 接进 DSH 的 dsh-llm,DSH 自己保留 agent loop、工具、session、审批、重试。
  2. 数据流是“双向翻译 + 原生保真”:DSH Message → pi-ai Context → provider wire → pi-ai events → DSH StreamChunk;assistant 的原生签名/ID 通过 ReplayEnvelope 存回 DSH,下一轮再恢复。
  3. 选 pi-ai 的核心因素:TS 同栈、in-process、provider 覆盖、OAuth/模型目录、原生协议保真、MIT、可打 patch;以及“twin adapter”用两套实现验证 provider-neutral 契约。
  4. 不选 LiteLLM/OpenRouter/Portkey/Bifrost 的核心原因:它们是网关/服务,不是库;对本地优先的 DSH 来说多一跳、多一套运维,而且 Chat 归一化会丢 reasoning/cache 语义。
  5. 代价:上游依赖/patch、错误 cause 丢失导致文本分类、catalog 漂移、没有网关级路由/LB;这些由 DSH 自己的 retry/credential/session 层补位。
选型的一句话

要“把模型接进自己的 harness”——选 pi-ai/AI SDK;要“把模型接给整个团队”——选 LiteLLM/Portkey/Bifrost;要“最快接最多模型”——选 OpenRouter;要“做 agent 应用”——选 AI SDK/LangChain。DSH 属于第一种。

来源

版本提示:DSH 仍是开发预览;本文按当前安装的 @deepseek-ai/dsh 0.2.1-rc.2 与 @earendil-works/pi-ai 1.4.0 的包文档/代码核对。框架对比中的“模型数量/性能”含厂商自述,生产前请按锁定版本复核。

08 / Decision

决策树与场景配方

把前面的分析压缩成可执行的判断。先按“模型路线 / harness 协议墙 / 工作负载”分流,再看合规和成本。

If · simple
只做聊天、分类、RAG、批处理
→ Chat Completions。生态最广、代理最简单;不要为“未来 agent 化”提前引入 Responses/Messages 的复杂度。
If · OpenAI-first
写/选 OpenAI 系 coding agent
→ Responses。Codex 只能 Responses;自研要 hosted tools/server state/长任务也选 Responses。只有简单 tool loop 且能接受新模型限制时才考虑 Chat。
If · Claude-first
写/选 Claude 系 coding agent
→ Messages。Claude Code/Agent SDK 只认 Messages;thinking 连续性、cache_control、企业网关都围绕它。
If · Gemini-first
写/选 Gemini 系 coding agent
→ Interactions(新项目/托管 agent/background)或 generateContent(batch/explicit caching/旧集成)。
If · multi-model
多模型统一接入
→ 能 native passthrough 就按上游协议分流;只能一个入口时,Chat 作为兼容层,但接受 reasoning/tools/state 的损失;不要强行用 Chat 统一 agent。
If · gateway
同时服务 Codex + Claude Code
→ 网关必须原生提供 /v1/responses 和 /v1/messages;只做 Chat 翻译服务不了两堵协议墙。
If · local
本地/开源模型
→ 默认 Chat;想跑 Codex 就让本地服务提供 /v1/responses;想跑 Claude Code 就提供 /v1/messages;注意本地实现多为 stateless/兼容子集。
If · compliance
ZDR / 数据驻留优先
→ 优先 stateless Chat/Messages;用 Responses/Interactions 时显式 store:false + 加密 reasoning,或自托管网关;不要把 server state 当默认。
If · DSH
使用或扩展 DeepSeek Harness
→ DeepSeek 官方 route 是 Messages;接 OpenAI/Anthropic/Google 走 pi-ai;Gemini Interactions 当前无路径;DeepSeek Responses 需自定义 route 且为 stateless。
If · cost
长上下文/成本敏感
→ 选支持 prefix cache 且能保持 append-only 的协议;Messages 的显式缓存最强,Responses 的 state/cache 更省心;Chat 的自动缓存适合简单场景。

迁移与落地清单

Migrate

Chat → Responses

  • 端点换 /v1/responses;读 output: Item[],不要读 choices[0]。
  • response_format → text.format;工具定义扁平化为 {type:"function", name, parameters, strict}。
  • 工具结果从 role:"tool" 改为 function_call_output Item,tool_call_id → call_id。
  • 流式从 chunk 改为 response.* 语义事件。
  • 决定 state:手工回放 / previous_response_id / Conversations;ZDR 用 store:false 并保留 encrypted reasoning。
Migrate

新增第二个协议

  • 定义内部 AgentEvent/ToolCall/ToolResult/ReasoningState,但保留原始 opaque payload。
  • 每个协议写 adapter:encodeRequest、decodeStreamEvent、stateMode、capabilities。
  • 历史只追加、不重排;thinking/reasoning/thought 原样存、原样传。
  • 建 golden transcripts:同一任务在各协议下比较工具调用、reasoning、终止条件。
  • 网关做 capability detection:不支持 previous_response_id 就不接受 stateful 请求;不支持 cache_control 就明确降级。
09 / Appendix

附录:事实、术语与来源

正文只留判断,事实放这里。包括完整 harness 表、版本事实、Gemini Interactions、术语和来源。

A. Coding harness 事实表

2026-10 快照;闭源产品协议不可观测,表中标注了证据边界。此表是事实,不是选型建议。

代表性 coding harness 的默认/硬性协议(2026-10 快照;闭源产品协议不可观测,标注证据边界)
Harness默认 / 硬性协议其他协议与说明选择要点
厂商自有 harness
OpenAI Codex CLIResponses only内置 OpenAI/Ollama/LM Studio 也只能走 Responses 端点(推断;本地服务需提供 /v1/responses)协议墙;Chat-only 网关不可用
Claude Code / Agent SDKMessages onlyBedrock InvokeModel、Vertex rawPredict、Foundry/AWS;无 OpenAI 格式协议墙;网关必须原生 Messages
Gemini CLIgenerateContentGemini API / Vertex / Code Assist;无 OpenAI 兼容、无 Interactions;2026-06 起免费/Google One 层由 Antigravity CLI 接替Google 自有栈;旧版参考
Antigravity CLIGoogle 托管后端Gemini + 通过 Google 提供的 partner Claude;无 BYOK base URL账号锁定;不是通用 BYO 网关客户端
GitHub Copilot CLIGitHub 托管BYOK:openai(Chat,默认)、azure、anthropic(Messages);有 COPILOT_PROVIDER_WIRE_API托管默认 + 有限 BYOK
Cursor / Amp / Warp厂商后端BYOK 仅部分 provider;wire protocol 不公开闭源,协议不可观测
多模型 harness / 网关客户端
ClineOpenAI→Resp Anthropic→Msg Google→GenOpenAI-compatible(Chat)、Bedrock/Vertex/Ollama、Codex/Claude 订阅provider-native + 兼容端点
Kilo Code未知端点默认 Chat显式 Provider API:Chat / Responses / Messages;Gemini 走 Google AI把协议做成显式选项
OpenCodeOpenAI→RespAI SDK + Models.dev:Responses/Chat、Messages、Gemini、Google Interactions;自定义 baseURLAI SDK 抽象,默认随 provider
Continue多数 ChatOpenAI Responses 只对 o-series/GPT-5+ 做“minimal draft”;Anthropic Messages;Gemini generateContent兼容优先,Responses 部分支持
GooseOpenAI Chat Anthropic Msg Gemini GenChatGPT/Codex 订阅走 Responses;Bedrock/Vertex/Azure/LiteLLM/兼容端点Rust provider crates 按厂商实现
Crush按 provider 类型provider 类型:openai(可 Responses;ChatGPT OAuth 走 Responses)/ openai-compat(Chat)/ anthropic(Messages)/ google(Gen)“openai”和“openai-compat”明确区分
Zed Agent自定义默认 openai_chatper-model protocol:anthropic / openai_responses / openai_chat / google少数四协议都可选的编辑器
Aider / OpenHands / SWE-agentharness 侧 Chat通过 LiteLLM 出站到 Messages/generateContent;自定义端点默认 ChatLiteLLM 翻译,能力取决于翻译层
Factory Droidopenai→Resp anthropic→Msg generic→Chat还有 bedrock-converse;provider 类型显式闭源但公开协议映射
DeepSeek Harness (DSH)DeepSeek route→Messages其他 provider 经 pi-ai 按 catalog native;自定义 route 仅 3 种;无 Interactionsprovider-neutral + native adapter
Agent SDK / 框架
OpenAI Agents SDKResponsesChat 通过 OpenAIChatCompletionsModel / set_default_openai_api("chat_completions")Responses 优先;Chat 能力受限
Claude Agent SDKMessagesBedrock/Vertex/Foundry 变体;ANTHROPIC_BASE_URL 可接网关包装 Claude Code 运行时
Google ADKgenerateContentInteractions 通过 use_interactions_api=True opt-in;Claude/OpenAI/LiteLLM 连接器默认 Gen,Interactions 可选
Vercel AI SDKOpenAI→Resp Anthropic→Msg Google→Genopenai.chat、google.interactions、OpenAI-compatible(Chat)统一抽象,默认随 provider/SDK 版本

B. 2026-10 版本事实

事件事实影响
Anthropic API 2026-10-21移除 temperature/top_p/top_k;SDK 默认改用 Bearer;API 仍接受 x-api-key;Foundry SDK 例外旧 SDK/harness 可能不兼容;锁定 anthropic-version
Gemini Interactions2026-06 GA;Google 新能力优先在 Interactions;generateContent legacy 但继续支持Gemini-first 新项目优先 Interactions;第三方 harness 支持仍薄
Codex wire APIwire_api 只接受 "responses";当前版本不再支持 "chat"Chat-only 网关无法服务 Codex
DSH0.2.1-rc.2;dsh-llm-deepseek 走 Messages;dsh-llm-pi-ai 依赖 pi-ai ^1.1.0(当前 1.4.0)开发预览;协议/包版本变化快

C. Gemini Interactions:第四种协议

Google 在 2026-06 将 Interactions GA,并明确新模型/agentic 能力优先在 Interactions 上线;generateContent 转为 legacy 但继续支持。它用 Interaction + typed steps(thought、function_call、function_result、model_output),默认 server state(previous_interaction_id),支持 background 和托管 agent。

当前第三方 harness 对 Interactions 的支持仍薄:AI SDK、ADK(opt-in)、OpenCode 是少数先行者;Gemini CLI、Cline、Kilo、Continue、Goose、Crush、DSH 等仍以 generateContent 为主。

D. 术语表

展开术语表

Wire protocol:模型 API 的 HTTP/JSON/SSE 形状;本文比较的对象。

Harness:驱动模型、执行工具、管理上下文的 agent 运行时(CLI/IDE/SDK)。

Hosted tools:由模型厂商在服务端执行的内置工具(web search、code execution 等)。

Opaque reasoning:加密/签名的 reasoning 状态;客户端不可读,但必须原样回传。

Native passthrough:网关不翻译,直接把客户端协议转发到同协议上游。

OpenAI-compatible:通常只意味着 /chat/completions 兼容,不等于 Responses 兼容。

MCP:Model Context Protocol,工具/上下文接入协议,不是模型 API 协议。

ACP:Agent Client Protocol,agent 与编辑器/harness 之间的协议,不是模型 API 协议。

ReplayEnvelope:DSH 存储的 adapter-private 原生回放元数据;内容仍是 durable message。

E. 主要来源

版本提示

资料与代码快照为 2026-10-25。Anthropic API 刚在 2026-10-21 做了破坏性变更;Codex、Claude Code、harness 和 DSH 版本也在快速变化。生产落地请锁定 SDK/API 版本,并建立自己的协议回归测试。