【Agent Harness】流马(Gliding Horse)DeepSeek Responses API 接入介绍
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. 整体架构
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) |
— | 运行时动态切换 |
# 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"
# 环境变量方式
export USE_RESPONSES_API=1 # 显式开启
export USE_RESPONSES_API=0 # 强制走 chat completions
3.2 模型能力判定
/// 仅 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)
user/assistant → input items
tool_calls → function_call
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
reasoning→reasoning_content
function_call/custom_tool_call→tool_calls
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 要求扁平结构:
// 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
{ id, output[], usage }"] RAW --> M{遍历 output items} M -->|"type == message"| T["content[] 各 block 的 text
拼接为 content"] M -->|"type == reasoning"| R["content[] 的 reasoning_text
拼接为 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}
finish_reason: stop | tool_calls
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)
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 流式终止语义
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. 调用链全景
/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 完整启用配置
# 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 运行时动态切换(编程接口)
// 任意时刻可切换,无需重建网关
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 | 结构体字段适配 |
原文地址: https://www.cveoy.top/t/topic/qHgc 著作权归作者所有。请勿转载和采集!