【Agent Harness】流马(Gliding Horse)DeepSeek Responses API 接入介绍

DeepSeek Responses API 接入说明

Commit : 4391ba3 --- update Responses API support

日期 : 2026-08-04

范围 : src/gateway/unified_gateway.rssrc/llm/sse.rssrc/config/settings.rsapps/gliding_code/src/config.rsconfig.yaml 及测试适配


1. 背景

DeepSeek 官方推出 Responses APIPOST /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_apitrue,非 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_framepayload == "[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.incompletefinish_reason: length
test_responses_api_failed_sets_error sse.rs response.failedfinish_reason: error
test_responses_api_live_non_streaming / _streaming / _tool_call unified_gateway.rs 真实 API 端到端(无 DEEPSEEK_API_KEY 时自动跳过)
各模块 use_responses_api: false 适配 4 处测试结构体 新字段向后兼容

9. 边界与限制

  1. 模型支持面 :Responses API 目前仅 deepseek-v4-flashdeepseek-v4-pro 在官方启用前自动走 chat completions(is_responses_capable_model 硬性判定)。
  2. 温度等参数 :思考模式下 temperature 等参数不生效(DeepSeek 文档说明,兼容性静默忽略,不报错);网关仍透传参数,由 API 侧处理。
  3. 无降级重试 :若 /v1/responses 返回 4xx(如参数不合法),不会自动降级到 chat completions------这是有意设计,避免掩盖请求构造错误;可通过 set_use_responses_api(false) 手动回退。
  4. 流式终止 :Responses 流没有 [DONE];若服务端异常断流且无终止事件,MessageStream 依赖底层 HTTP 流结束(None)自然终止。
  5. usage 归一化input_tokens/output_tokensprompt_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 结构体字段适配
相关推荐
暗黑小白6 小时前
LLM 业务级可观测
大模型·ai agent
大龄码农有梦想6 小时前
AI Agent 目前最大的瓶颈是什么?
人工智能·机器学习·ai agent·智能体·ai工作流·智能体平台
SomeB1oody7 小时前
【RustyML入门】2.0. 经典机器学习
开发语言·后端·机器学习·rust·教程
暗黑小白7 小时前
脱敏引擎工程化
后端·ai agent
Embedded-Xin7 小时前
Rust学习——Cargo工具
linux·学习·架构·rust·嵌入式
龙仔7258 小时前
RustDesk 完整笔记
运维·笔记·rust·远程工具·rustdesk
An_s9 小时前
rust(pdfium)底层开发实现wasm包给vue3调用
开发语言·rust·wasm
deepseek2311 小时前
GPT-5.6 Luna 降价 80%:从 24% 到 90% 的缓存命中率,OpenAI 的价格战打在了工程层
大模型·openai·ai agent
对象存储与RustFS12 小时前
为什么越来越多的企业选择RustFS作为对象存储?
后端·rust·开源