DeepSeek Responses API 接入说明
Commit :
4391ba3--- update Responses API support日期 : 2026-08-04
范围 :
src/gateway/unified_gateway.rs、src/llm/sse.rs、src/config/settings.rs、apps/gliding_code/src/config.rs、config.yaml及测试适配
1. 背景
DeepSeek 官方推出 Responses API (POST /v1/responses)作为新一代接口,相比 Chat Completions 具备语义化的流式事件(response.*)、显式的工具调用往返结构、原生推理内容(reasoning)输出等能力。截至 2026-08-04,该接口仅支持 deepseek-v4-flash 模型 (deepseek-v4-pro 预计 2026 年 8 月初启用)。
本次修改为 Gliding Horse 接入 Responses API,同时保持对 Chat Completions 的完全兼容:
deepseek-v4-flash请求默认路由到/v1/responses;- 其余模型(含
deepseek-v4-pro)自动回退到/v1/chat/completions; - 下游调用方(Agent Runner、工具执行器、TUI 等)无感知 ------两种协议在网关层统一收敛为内部
ChatCompletionResponse/StreamEvent词汇表。
2. 整体架构
flowchart TB subgraph Config"配置层" ENV"环境变量\
USE_RESPONSES_API\
AGENT_OS_GATEWAY_USE_RESPONSES_API" YAML"config.yaml\
gateway.use_responses_api" Cfg"CliConfig\
apps/gliding_code/src/config.rs" S"Settings\
src/config/settings.rs\
GatewaySettings.use_responses_api" ENV --> Cfg YAML --> S Cfg -->|"构造 GatewaySettings"| S end subgraph GW"统一网关 UnifiedGateway\
src/gateway/unified_gateway.rs" R"RwLock\<bool\> use_responses_api\
+ set_use_responses_api()" BR"should_use_responses_api(model)" CAP"is_responses_capable_model(model)\
deepseek-v4-flash\*" BR --> CAP subgraph NonStream"非流式路径" N1"chat / chat_with_model / chat_with_params" N2"build_responses_body\
messages → instructions + input items" N3"send_responses_request\
→ send_with_retry(指数退避重试)" N4"parse_responses_response\
output items → ChatCompletionResponse" end subgraph Stream"流式路径" S1"stream_chat_with_params" S2"build_responses_body(stream: true)" S3"send_stream_request\
Accept: text/event-stream" end end subgraph SSE"流式事件解析 src/llm/sse.rs" P1"SseParser::push → parse_frame" P2{"type 前缀 == response.* ?"} P3"parse_responses_api_event\
response.\* → StreamEvent" P4"parse_openai_stream_event\
chat completions 事件" P1 --> P2 P2 -->|是| P3 P2 -->|否| P4 end subgraph ACC"流式聚合 src/llm/stream_types.rs" A1"StreamAccumulator::process_event" A2"StreamResponse\
thought / content / tool_calls / usage" A1 --> A2 end subgraph Downstream"下游消费方(无感知)" D1"Agent Runner / SA" D2"Tool Executor" D3"Gliding Code TUI" D4"stream_processor.rs MessageStream" end R --> BR BR -->|"开启 且 模型为 v4-flash"| N2 BR -->|"开启 且 模型为 v4-flash"| S2 BR -->|"关闭 或 非 v4-flash"| CC"/v1/chat/completions 原有路径" N2 --> N3 --> N4 S2 --> S3 S3 -->|"HTTP body 流"| P1 P3 --> A1 P4 --> A1 N4 --> D1 N4 --> D2 A2 --> D3 A2 --> D4 D4 --> D3
设计要点 :Responses API 是网关内部的一条协议适配分支,所有 Responses 特有的结构(input items、semantic events)都在网关 / SSE 解析层完成转换,业务层看到的数据形状与 Chat Completions 完全一致。
3. 配置与开关
3.1 配置项
| 位置 | 字段 / 变量 | 默认值 | 说明 |
|---|---|---|---|
src/config/settings.rs |
GatewaySettings.use_responses_api |
false(程序化默认)/ true(CLI 默认) |
是否启用 Responses API 路由 |
config.yaml |
gateway.use_responses_api |
true |
YAML 配置入口 |
apps/gliding_code/src/config.rs |
USE_RESPONSES_API |
true |
环境变量,1 / true 视为开启 |
| 同上(兼容) | AGENT_OS_GATEWAY_USE_RESPONSES_API |
--- | 兼容别名 |
unified_gateway.rs |
set_use_responses_api(&self, enabled: bool) |
--- | 运行时动态切换 |
yaml
# config.yaml 示例
gateway:
base_url: "https://api.deepseek.com"
api_key: "sk-..."
timeout_seconds: 300
max_retries: 3
retry_base_ms: 500
# deepseek-v4-flash 走 Responses API (/v1/responses),deepseek-v4-pro 继续走 chat completions
use_responses_api: true
model_mapping:
planning: "deepseek-v4-pro"
execution: "deepseek-v4-flash"
sh
# 环境变量方式
export USE_RESPONSES_API=1 # 显式开启
export USE_RESPONSES_API=0 # 强制走 chat completions
3.2 模型能力判定
rust
/// 仅 deepseek-v4-flash 支持 Responses API;
/// deepseek-v4-pro 在 DeepSeek 启用前继续使用 chat completions。
fn is_responses_capable_model(model: &str) -> bool {
let m = model.to_lowercase();
m == "deepseek-v4-flash" || m.starts_with("deepseek-v4-flash-")
}
fn should_use_responses_api(&self, model: &str) -> bool {
*self.use_responses_api.read().unwrap() && Self::is_responses_capable_model(model)
}
即使
use_responses_api为true,非deepseek-v4-flash模型也绝不会被路由到/v1/responses------这是硬性安全边界,防止对尚不支持该接口的模型产生 400 错误。
4. 非流式请求(chat / chat_with_model / chat_with_params)
sequenceDiagram participant Caller as 调用方 participant GW as UnifiedGateway participant API as DeepSeek /v1/responses Caller->>GW: chat_with_params(model, messages, temperature, max_tokens, tools, tool_choice) GW->>GW: should_use_responses_api(model)? alt 是(v4-flash 且开关开启) GW->>GW: build_responses_body() Note over GW: system → instructions<br/>user/assistant → input items<br/>tool_calls → function_call<br/>tool 消息 → function_call_output GW->>API: POST {base}/v1/responses API-->>GW: { id, output\[\], usage{} } GW->>GW: parse_responses_response() Note over GW: message→text<br/>reasoning→reasoning_content<br/>function_call/custom_tool_call→tool_calls<br/>usage 归一化 GW-->>Caller: ChatCompletionResponse(形状与 chat completions 一致) else 否(其他模型或开关关闭) GW-->>Caller: 走 /v1/chat/completions 原有逻辑 end
4.1 消息转换:responses_input_items
| Chat Completions 消息 | Responses API input item |
|---|---|
第一条非空 system |
instructions(顶层字段) |
其余 system / developer / user |
{type: message, role, content:[{type: input_text, text}]} |
assistant(无工具调用) |
{type: message, role: assistant, content:[{type: output_text, text}]} |
assistant(有工具调用) |
message item + 每个调用一个 {type: function_call, call_id, name, arguments} |
tool |
{type: function_call_output, call_id, output} |
4.2 工具定义转换:convert_responses_tools
Chat Completions 将函数定义嵌套在 function 键下,Responses API 要求扁平结构:
jsonc
// chat completions(入参)
{ "type": "function", "function": { "name": "get_weather", "description": "...", "parameters": {...} } }
// responses(转换后)
{ "type": "function", "name": "get_weather", "description": "...", "parameters": {...} }
非函数工具(web_search、自定义工具)原样透传。
4.3 响应解析:parse_responses_response
flowchart LR RAW"POST /v1/responses 响应\
{ id, output\[, usage }"] RAW --> M{遍历 output items} M -->|"type == message"| T"content\[ 各 block 的 text<br/>拼接为 content"] M -->|"type == reasoning"| R"content\[ 的 reasoning_text<br/>拼接为 reasoning_content"] M -->|"type == function_call"| F"call_id/name/arguments\
→ ResponseToolCall{function}" M -->|"type == custom_tool_call"| C"id/name/input\
→ ResponseToolCall{custom}" T --> RESP R --> RESP F --> RESP C --> RESP RESP"ChatCompletionResponse\
choices\[0.message{content, reasoning_content, tool_calls}<br/>finish_reason: stop | tool_calls<br/>usage{input_tokens→prompt_tokens, output_tokens→completion_tokens}"]
关键点 :Responses API 的 usage 字段是 input_tokens / output_tokens,而 Chat Completions 是 prompt_tokens / completion_tokens------解析层完成归一化,下游统计与计费展示无需改动。
4.4 重试与错误处理:send_with_retry
两种协议共享同一重试骨架(重构自原有逻辑):
- 指数退避:
retry_base_ms * 2^(attempt-1); - 4xx 客户端错误立即终止(不重试),并将请求体前 8K 字符嵌入错误信息便于 TUI 直接排查;
- 5xx / 网络错误按
max_retries重试; - 解析失败(JSON 无效 / 结构不符)也会重试并记录响应长度日志。
5. 流式请求(stream_chat_with_params)
sequenceDiagram participant Caller as 调用方 participant GW as UnifiedGateway participant MS as MessageStream participant SP as StreamingProcessor / SseParser participant ACC as StreamAccumulator participant API as DeepSeek /v1/responses (stream) Caller->>GW: stream_chat_with_params(...) GW->>GW: build_responses_body(stream: true) GW->>API: POST {base}/v1/responses(Accept: text/event-stream) API-->>MS: HTTP chunk 流 MS->>SP: push_chunk(bytes) SP->>SP: parse_frame → 识别 response.* 前缀 SP->>ACC: StreamEvent 事件流 ACC->>ACC: process_event 聚合 MS-->>Caller: collect_with_callback / collect_all → StreamResponse
5.1 事件映射:parse_responses_api_event
Responses API 流由语义事件 组成(type: "response.*"),且没有 data: [DONE] 终止帧------终止由 response.completed / response.incomplete / response.failed 承担。parse_frame 通过 type 前缀分流到 Responses 解析器:
| Responses API 事件 | 内部 StreamEvent | 备注 |
|---|---|---|
response.created |
MessageStart { id, model } |
记录 message_id / model |
response.output_item.added(function_call / custom_tool_call) |
ContentBlockStart { ToolUse{id, name} } |
工具块开始 |
response.output_text.delta |
ContentBlockDelta { TextDelta } |
正文增量 |
response.reasoning_text.delta |
ContentBlockDelta { ThinkingDelta } |
推理内容(TUI 中以思考步骤呈现) |
response.function_call_arguments.delta |
ContentBlockDelta { ToolCallDelta{arguments} } |
工具参数增量 |
response.custom_tool_call_input.delta |
ContentBlockDelta { ToolCallDelta{arguments} } |
自定义工具参数增量 |
response.completed |
MessageDelta { finish_reason } |
completed+有工具调用 → tool_calls;否则 → stop;附 usage |
response.incomplete |
MessageDelta { finish_reason: "length" } |
输出截断 |
response.failed |
MessageDelta { finish_reason: "error" } |
失败 |
5.2 流式终止语义
flowchart TD START"流开始" --> CREATED"response.created" CREATED --> LOOP"增量事件循环\
output_text / reasoning_text / function_call_arguments delta" LOOP --> TERM{"终止事件"} TERM -->|"response.completed"| C1{"output 含 function_call?"} C1 -->|是| R1"finish_reason = tool_calls" C1 -->|否| R2"finish_reason = stop" TERM -->|"response.incomplete"| R3"finish_reason = length" TERM -->|"response.failed"| R4"finish_reason = error" R1 --> END"MessageStream::next_event 返回 None\
collect_all / collect_with_callback 完成" R2 --> END R3 --> END R4 --> END
5.3 与 Chat Completions 流式路径的关系
SseParser/MessageStream/StreamAccumulator完全复用;- 差异仅在
parse_frame内部:response.*前缀走新解析器,其余走原有parse_openai_stream_event; [DONE]帧仍被兼容处理(parse_frame中payload == "[DONE]"返回None),因此两种协议可在同一代码路径内共存。
6. 调用链全景
flowchart TB subgraph App"应用层" TUI"Gliding Code TUI\
/model deepseek-v4-flash" AR"Agent Runner / SA 编排" TE"Tool Executor" end subgraph GW2"UnifiedGateway" CHAT"chat_with_params(非流式)" STREAM"stream_chat_with_params(流式)" end subgraph Proto"协议层" RP"/v1/responses" CC"/v1/chat/completions" end subgraph Conv"转换层" BODY"build_responses_body" PARSER"parse_responses_response" SSEP"parse_responses_api_event" end subgraph Core"核心层" RETRY"send_with_retry" MSTREAM"MessageStream + StreamAccumulator" end subgraph DL"DeepSeek API" D1"deepseek-v4-flash\
Responses API 原生" D2"deepseek-v4-pro\
Chat Completions" end TUI --> AR AR --> CHAT AR --> STREAM TE --> CHAT CHAT -->|"v4-flash 且开启"| BODY --> RP --> RETRY --> PARSER STREAM -->|"v4-flash 且开启"| BODY --> RP --> MSTREAM --> SSEP CHAT -->|"其他模型"| CC --> RETRY STREAM -->|"其他模型"| CC --> MSTREAM RETRY --> D1 RETRY --> D2 MSTREAM --> D1 MSTREAM --> D2
7. 配置与使用示例
7.1 完整启用配置
sh
# 1) API Key
export DEEPSEEK_API_KEY="sk-..."
# 2) 显式启用 Responses API(v4-flash 默认已开启,可省略)
export USE_RESPONSES_API=1
# 3) 运行 Gliding Code,默认模型 deepseek-v4-flash 即走 /v1/responses
./glidingcode "设计一个知识图谱的 schema"
# 4) 切换到 v4-pro(自动回退 chat completions)
./glidingcode --model deepseek-v4-pro "分析这段代码的时间复杂度"
7.2 运行时动态切换(编程接口)
rust
// 任意时刻可切换,无需重建网关
gateway.set_use_responses_api(false); // 强制全部模型走 chat completions
gateway.set_use_responses_api(true); // 恢复 v4-flash 走 responses
7.3 观察点
| 现象 | 说明 |
|---|---|
日志出现 LLM API call successful |
非流式调用完成(含 usage) |
流式正常结束、无 [DONE] 依赖 |
说明 response.completed 终止事件被正确解析 |
| TUI 中出现可展开的思考步骤 | response.reasoning_text.delta → ThinkingDelta → thinking 聚合 |
| 工具调用正常往返 | function_call items / function_call_arguments.delta 转换正确 |
| 4xx 错误附 8K 请求体预览 | 便于直接定位请求构造问题 |
8. 测试覆盖
新增 / 适配的测试(cargo test --lib,全量 1193 项通过):
| 测试 | 位置 | 验证点 |
|---|---|---|
test_build_responses_body_converts_messages |
unified_gateway.rs |
messages → instructions + input items 转换 |
test_responses_api_text_stream |
sse.rs |
文本流全链路(created + delta + completed)聚合正确 |
test_responses_api_no_done_terminator |
sse.rs |
不依赖 [DONE],completed 即终止 |
test_responses_api_reasoning_delta |
sse.rs |
推理增量 → thinking 聚合 |
test_responses_api_tool_call_stream |
sse.rs |
function_call_arguments.delta → 工具调用聚合 |
test_responses_api_custom_tool_call_delta |
sse.rs |
自定义工具参数增量解析 |
test_responses_api_incomplete_sets_length |
sse.rs |
response.incomplete → finish_reason: length |
test_responses_api_failed_sets_error |
sse.rs |
response.failed → finish_reason: error |
test_responses_api_live_non_streaming / _streaming / _tool_call |
unified_gateway.rs |
真实 API 端到端(无 DEEPSEEK_API_KEY 时自动跳过) |
各模块 use_responses_api: false 适配 |
4 处测试结构体 | 新字段向后兼容 |
9. 边界与限制
- 模型支持面 :Responses API 目前仅
deepseek-v4-flash;deepseek-v4-pro在官方启用前自动走 chat completions(is_responses_capable_model硬性判定)。 - 温度等参数 :思考模式下
temperature等参数不生效(DeepSeek 文档说明,兼容性静默忽略,不报错);网关仍透传参数,由 API 侧处理。 - 无降级重试 :若
/v1/responses返回 4xx(如参数不合法),不会自动降级到 chat completions------这是有意设计,避免掩盖请求构造错误;可通过set_use_responses_api(false)手动回退。 - 流式终止 :Responses 流没有
[DONE];若服务端异常断流且无终止事件,MessageStream依赖底层 HTTP 流结束(None)自然终止。 - usage 归一化 :
input_tokens/output_tokens→prompt_tokens/completion_tokens的映射在解析层完成,计费展示沿用原有逻辑。
10. 文件变更清单
| 文件 | 变更 | 说明 |
|---|---|---|
src/gateway/unified_gateway.rs |
+678 | Responses API 非流式/流式接入、消息与响应转换、重试重构、运行时开关、测试 |
src/llm/sse.rs |
+323 | parse_responses_api_event 语义事件解析、流式测试 |
src/config/settings.rs |
+5 | GatewaySettings.use_responses_api 字段 |
apps/gliding_code/src/config.rs |
+8 | 环境变量读取(USE_RESPONSES_API / 兼容别名),默认开启 |
config.yaml |
+2 | 配置项与注释 |
src/core/agent_runner/tests.rs |
+1 | 结构体字段适配 |
src/core/sa/tests.rs |
+1 | 结构体字段适配 |
src/skill_graph/skill_creator.rs |
+4 | 结构体字段适配 |
src/tools/tool_executor/tests.rs |
+1 | 结构体字段适配 |
src/worker/agent_os_worker.rs |
+2 | 结构体字段适配 |