Responses API

百科 · 模型与对话 · 另一套信封

两套协议都出自 OpenAI,DeepSeek 是照着接的。

Chat Completions 定于 2023 年。再早的 Completions 只收一整段 prompt。换成对话以后,请求走 POST /chat/completions,用 messages 按 role 分开谁说的话。这套后来成了各家对齐的格式,DeepSeek 也实现了它,所以前面几篇的 curl 都打在这条路径上:messages 进去,choices 出来。

Responses 定于 2025 年,给要调用工具、连续行动的程序用。OpenAI 把它做成 Chat Completions 的下一代原语,并把 Assistants API 里的工具能力收进同一次请求:input 进去,output 里按条目返回。DeepSeek 为了让 Codex 这类已经说 Responses 的客户端能换 base_url,在 POST https://api.deepseek.com/responses 上按这套格式接了进来。

问的可以还是「你是谁」。下面只看报文差在哪。

一次调用

curl https://api.deepseek.com/responses \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $DEEPSEEK_API_KEY" \
  -d '{
    "model": "deepseek-flash",
    "instructions": "你是一个助手",
    "input": "你是谁",
    "stream": false
  }'

input 和 instructions 至少要有一个。instructions 会被插成第一条 system 消息,干的是 System prompt 那件事。前面几篇的 deepseek-chat 用在 /chat/completions;这条路径的示例模型是 deepseek-flash。

回来的是一条 response,不是 chat completion:

{
  "id": "resp_8f2a",
  "object": "response",
  "status": "completed",
  "model": "deepseek-flash",
  "store": false,
  "output": [
    {
      "type": "message",
      "role": "assistant",
      "content": [
        {
          "type": "output_text",
          "text": "我是 DeepSeek,由深度求索开发的智能助手。"
        }
      ]
    }
  ]
}

翻译成人话:

  • 没有 choices。话在 output 里,这一条的 type 是 message
  • 正文在 content[].text,type 为 output_text。官方 SDK 会把这些文字收成 output_text
  • status 为 completed,相当于那边的 finish_reason: stop
  • output 是列表。普通回答是一条 message;思考过程若有,是另一条 reasoning;伸手则是一条 function_call

多轮仍要自己贴

DeepSeek 这份 Responses 是无状态的。previous_response_id、conversation、store 都不生效,响应里 store 固定为 false。下一轮还是把已经说过的条目放进 input:

{
  "model": "deepseek-flash",
  "input": [
    {"role": "user", "content": "你以后称呼自己为小K"},
    {"role": "assistant", "content": "好的,我以后称呼自己为小K!"},
    {"role": "user", "content": "你是谁"}
  ]
}

这和 Messages 是同一件事,只是字段叫 input。OpenAI 自己的 Responses 可以用 previous_response_id 让服务端续上一条。接到 DeepSeek 时,这个字段会被忽略。

工具换了条目

Tool 里的清单套在 tools[].function 下,点名挂在 message.tool_calls,观察是 role: tool。Responses 把这三样摊成条目。

清单:

{
  "type": "function",
  "name": "get_weekday",
  "description": "按给定时区返回当前日期和星期几",
  "parameters": {
    "type": "object",
    "properties": {
      "timezone": {"type": "string", "description": "IANA 时区,例如 Asia/Shanghai"}
    },
    "required": ["timezone"]
  }
}

模型点名时,output 里多一条:

{
  "type": "function_call",
  "call_id": "call_8f2a",
  "name": "get_weekday",
  "arguments": "{\"timezone\":\"Asia/Shanghai\"}"
}

运行时读完时钟,下一次 input 里接上:

{
  "type": "function_call_output",
  "call_id": "call_8f2a",
  "output": "2026-10-08 星期四"
}

arguments 仍是 JSON 字符串。call_id 要对上,对不上这条观察就挂空。循环还是 Agent loop 那一圈:执行,写回,再请求。DeepSeek 这里只认 function 这种工具;web_search 一类内置工具会被忽略。

流也不用 [DONE]

stream: true 时,每条 SSE 都写 event,名字是协议规定的。正文增量、工具参数、结束各是一种事件。没有 data: [DONE]。事件表见 Responses SSE。

总结

  • /chat/completions 用 messages 和 choices;/responses 用 input、instructions 和 output 条目
  • DeepSeek 的 Responses 仍无状态。多轮自己把条目贴进 input
  • 工具是 function_call 配 function_call_output,用 call_id 对上
  • 流以 response.completed 结束,没有 [DONE]

参见