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

21 阅读7分钟

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[&#34;环境变量<br/>USE_RESPONSES_API<br/>AGENT_OS_GATEWAY_USE_RESPONSES_API&#34;]
        YAML[&#34;config.yaml<br/>gateway.use_responses_api&#34;]
        Cfg[&#34;CliConfig<br/>apps/gliding_code/src/config.rs&#34;]
        S[&#34;Settings<br/>src/config/settings.rs<br/>GatewaySettings.use_responses_api&#34;]
        ENV --> Cfg
        YAML --> S
        Cfg -->|&#34;构造 GatewaySettings&#34;| S
    end

    subgraph GW[&#34;统一网关 UnifiedGateway<br/>src/gateway/unified_gateway.rs&#34;]
        R[&#34;RwLock use_responses_api<br/>+ set_use_responses_api()&#34;]
        BR[&#34;should_use_responses_api(model)&#34;]
        CAP[&#34;is_responses_capable_model(model)<br/>deepseek-v4-flash*&#34;]
        BR --> CAP

        subgraph NonStream[&#34;非流式路径&#34;]
            N1[&#34;chat / chat_with_model / chat_with_params&#34;]
            N2[&#34;build_responses_body<br/>messages → instructions + input items&#34;]
            N3[&#34;send_responses_request<br/>→ send_with_retry(指数退避重试)&#34;]
            N4[&#34;parse_responses_response<br/>output items → ChatCompletionResponse&#34;]
        end

        subgraph Stream[&#34;流式路径&#34;]
            S1[&#34;stream_chat_with_params&#34;]
            S2[&#34;build_responses_body(stream: true)&#34;]
            S3[&#34;send_stream_request<br/>Accept: text/event-stream&#34;]
        end
    end

    subgraph SSE[&#34;流式事件解析 src/llm/sse.rs&#34;]
        P1[&#34;SseParser::push → parse_frame&#34;]
        P2{&#34;type 前缀 == response.* ?&#34;}
        P3[&#34;parse_responses_api_event<br/>response.* → StreamEvent&#34;]
        P4[&#34;parse_openai_stream_event<br/>chat completions 事件&#34;]
        P1 --> P2
        P2 -->|是| P3
        P2 -->|否| P4
    end

    subgraph ACC[&#34;流式聚合 src/llm/stream_types.rs&#34;]
        A1[&#34;StreamAccumulator::process_event&#34;]
        A2[&#34;StreamResponse<br/>thought / content / tool_calls / usage&#34;]
        A1 --> A2
    end

    subgraph Downstream[&#34;下游消费方(无感知)&#34;]
        D1[&#34;Agent Runner / SA&#34;]
        D2[&#34;Tool Executor&#34;]
        D3[&#34;Gliding Code TUI&#34;]
        D4[&#34;stream_processor.rs MessageStream&#34;]
    end

    R --> BR
    BR -->|&#34;开启 且 模型为 v4-flash&#34;| N2
    BR -->|&#34;开启 且 模型为 v4-flash&#34;| S2
    BR -->|&#34;关闭 或 非 v4-flash&#34;| CC[&#34;/v1/chat/completions 原有路径&#34;]
    N2 --> N3 --> N4
    S2 --> S3
    S3 -->|&#34;HTTP body 流&#34;| 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.rsGatewaySettings.use_responses_apifalse(程序化默认)/ true(CLI 默认)是否启用 Responses API 路由
config.yamlgateway.use_responses_apitrueYAML 配置入口
apps/gliding_code/src/config.rsUSE_RESPONSES_APItrue环境变量,1 / true 视为开启
同上(兼容)AGENT_OS_GATEWAY_USE_RESPONSES_API兼容别名
unified_gateway.rsset_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_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
第一条非空 systeminstructions(顶层字段)
其余 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

flowchart LR
    RAW[&#34;POST /v1/responses 响应<br/>{ id, output[], usage }&#34;]
    RAW --> M{遍历 output items}
    M -->|&#34;type == message&#34;| T[&#34;content[] 各 block 的 text<br/>拼接为 content&#34;]
    M -->|&#34;type == reasoning&#34;| R[&#34;content[] 的 reasoning_text<br/>拼接为 reasoning_content&#34;]
    M -->|&#34;type == function_call&#34;| F[&#34;call_id/name/arguments<br/>→ ResponseToolCall{function}&#34;]
    M -->|&#34;type == custom_tool_call&#34;| C[&#34;id/name/input<br/>→ ResponseToolCall{custom}&#34;]
    T --> RESP
    R --> RESP
    F --> RESP
    C --> RESP
    RESP[&#34;ChatCompletionResponse<br/>choices[0].message{content, reasoning_content, tool_calls}<br/>finish_reason: stop | tool_calls<br/>usage{input_tokens→prompt_tokens, output_tokens→completion_tokens}&#34;]

关键点: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.createdMessageStart { id, model }记录 message_id / model
response.output_item.added(function_call / custom_tool_call)ContentBlockStart { ToolUse{id, name} }工具块开始
response.output_text.deltaContentBlockDelta { TextDelta }正文增量
response.reasoning_text.deltaContentBlockDelta { ThinkingDelta }推理内容(TUI 中以思考步骤呈现)
response.function_call_arguments.deltaContentBlockDelta { ToolCallDelta{arguments} }工具参数增量
response.custom_tool_call_input.deltaContentBlockDelta { ToolCallDelta{arguments} }自定义工具参数增量
response.completedMessageDelta { finish_reason }completed+有工具调用 → tool_calls;否则 → stop;附 usage
response.incompleteMessageDelta { finish_reason: "length" }输出截断
response.failedMessageDelta { finish_reason: "error" }失败

5.2 流式终止语义

flowchart TD
    START[&#34;流开始&#34;] --> CREATED[&#34;response.created&#34;]
    CREATED --> LOOP[&#34;增量事件循环<br/>output_text / reasoning_text / function_call_arguments delta&#34;]
    LOOP --> TERM{&#34;终止事件&#34;}
    TERM -->|&#34;response.completed&#34;| C1{&#34;output 含 function_call?&#34;}
    C1 -->|是| R1[&#34;finish_reason = tool_calls&#34;]
    C1 -->|否| R2[&#34;finish_reason = stop&#34;]
    TERM -->|&#34;response.incomplete&#34;| R3[&#34;finish_reason = length&#34;]
    TERM -->|&#34;response.failed&#34;| R4[&#34;finish_reason = error&#34;]
    R1 --> END[&#34;MessageStream::next_event 返回 None<br/>collect_all / collect_with_callback 完成&#34;]
    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[&#34;应用层&#34;]
        TUI[&#34;Gliding Code TUI<br/>/model deepseek-v4-flash&#34;]
        AR[&#34;Agent Runner / SA 编排&#34;]
        TE[&#34;Tool Executor&#34;]
    end

    subgraph GW2[&#34;UnifiedGateway&#34;]
        CHAT[&#34;chat_with_params(非流式)&#34;]
        STREAM[&#34;stream_chat_with_params(流式)&#34;]
    end

    subgraph Proto[&#34;协议层&#34;]
        RP[&#34;/v1/responses&#34;]
        CC[&#34;/v1/chat/completions&#34;]
    end

    subgraph Conv[&#34;转换层&#34;]
        BODY[&#34;build_responses_body&#34;]
        PARSER[&#34;parse_responses_response&#34;]
        SSEP[&#34;parse_responses_api_event&#34;]
    end

    subgraph Core[&#34;核心层&#34;]
        RETRY[&#34;send_with_retry&#34;]
        MSTREAM[&#34;MessageStream + StreamAccumulator&#34;]
    end

    subgraph DL[&#34;DeepSeek API&#34;]
        D1[&#34;deepseek-v4-flash<br/>Responses API 原生&#34;]
        D2[&#34;deepseek-v4-pro<br/>Chat Completions&#34;]
    end

    TUI --> AR
    AR --> CHAT
    AR --> STREAM
    TE --> CHAT
    CHAT -->|&#34;v4-flash 且开启&#34;| BODY --> RP --> RETRY --> PARSER
    STREAM -->|&#34;v4-flash 且开启&#34;| BODY --> RP --> MSTREAM --> SSEP
    CHAT -->|&#34;其他模型&#34;| CC --> RETRY
    STREAM -->|&#34;其他模型&#34;| 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_messagesunified_gateway.rsmessages → instructions + input items 转换
test_responses_api_text_streamsse.rs文本流全链路(created + delta + completed)聚合正确
test_responses_api_no_done_terminatorsse.rs不依赖 [DONE],completed 即终止
test_responses_api_reasoning_deltasse.rs推理增量 → thinking 聚合
test_responses_api_tool_call_streamsse.rsfunction_call_arguments.delta → 工具调用聚合
test_responses_api_custom_tool_call_deltasse.rs自定义工具参数增量解析
test_responses_api_incomplete_sets_lengthsse.rsresponse.incompletefinish_reason: length
test_responses_api_failed_sets_errorsse.rsresponse.failedfinish_reason: error
test_responses_api_live_non_streaming / _streaming / _tool_callunified_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+678Responses API 非流式/流式接入、消息与响应转换、重试重构、运行时开关、测试
src/llm/sse.rs+323parse_responses_api_event 语义事件解析、流式测试
src/config/settings.rs+5GatewaySettings.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结构体字段适配