把 pi-coding-agent 的 DeepSeek provider 从传统的 openai-completions(/chat/completions)切换到 DeepSeek 原生支持的 OpenAI Responses API(/v1/responses)的完整记录,环境为 Termux (Android) + pi-coding-agent 0.83.0,作者「糖醋鱼的小破站」于 2026-08-02 实测。
背景
DeepSeek 现已原生支持 OpenAI Responses API 格式(端点 /v1/responses)。修改前,pi 内置目录(pi-ai/dist/providers/data/deepseek.json)把 DeepSeek 模型注册为 openai-completions + baseUrl: https://api.deepseek.com,即走传统 /chat/completions 格式,未使用 Responses API。
Responses API 的优势(实测)
- reasoning 是一等公民:chat completions 下 DeepSeek 思考内容走非标准扩展字段
reasoning_content,pi 需thinkingFormat: "deepseek"等特判;responses 下 reasoning 是标准结构化 item(type: "reasoning"),流式事件response.reasoning_text.delta,标准解析器直接处理。实测 thinking 实时流入 pi 的 thinking 槽位,usage.output_tokens_details.reasoning_tokens正常统计。 - 工具调用更规范:工具调用是独立结构化 item(
function_call/function_call_output),通过call_id关联;response.function_call_arguments.delta支持边生成边解析(实测一次调用收到 13 个参数增量事件),多轮工具循环比 chat completions 的强耦合顺序更不容易出错。 - 显式缓存控制:
prompt_cache_key/prompt_cache_retention可显式控制上下文缓存;实测 pi 在PI_CACHE_RETENTION=long下发送prompt_cache_retention: "24h"被 DeepSeek 接受,端到端测试第 2 轮cacheRead: 384命中缓存。 - 输入为结构化 item 数组:多轮对话中 assistant 的 reasoning 与 message 可独立回传,角色/顺序约束比 chat completions 宽松。
- 标准统一、面向未来:OpenAI 新一代主推接口,新特性(web_search、结构化输出、文件搜索)会优先在 Responses API 提供。
- 官方 SDK 生态:
client.responses.create()原生支持,pi 直接复用 openai 包,无需自定义 HTTP 封装。
已知差异(相对 OpenAI)
include: ["reasoning.encrypted_content"]被忽略:DeepSeek 返回明文reasoning_text(对 pi 无影响,明文解析更简单)。- 未验证/可能暂不支持 OpenAI 专属能力:web_search 工具、结构化输出(json_schema)、文件搜索等,后续需等 DeepSeek 补齐或通过兼容层实现。
端点可用性验证(curl 直测)
GET /v1/models:返回deepseek-v4-flash、deepseek-v4-pro。- 非流式
POST /v1/responses:HTTP 200,标准 Responses 结构,reasoningitem +messageitem 齐全。 - 模拟 pi 客户端完整参数全部通过:
stream: true、store: false、prompt_cache_key、prompt_cache_retention: "24h"、max_output_tokens: 384000、temperature、reasoning: {effort, summary}、system/developerrole、工具调用流式。 - SSE 事件序列为标准 Responses 协议:
response.created→response.in_progress→response.output_item.added(reasoning)→response.reasoning_text.delta→ … →response.completed。
pi 侧关键代码调研
- API 分发(
pi-ai/dist/compat.js):openai-completions→/chat/completions,openai-responses→/v1/responses;openai-responses原先只分配给 openai / azure-openai-responses / openai-codex。 - 客户端行为(
dist/api/openai-responses.js):baseURL +/v1/responses;发送stream、store、缓存参数、max_output_tokens、tools、reasoning、include:["reasoning.encrypted_content"];sessionAffinityFormat 默认 “openai” → 发送session_id与x-client-request-id头。 - reasoning 明文解析(
dist/api/openai-responses-shared.js):response.reasoning_text.delta追加到 thinking block;response.output_item.done(reasoning item)序列化存入block.thinkingSignature用于多轮回放。 - 多轮 reasoning 回放要求(关键兼容点):DeepSeek 要求上一轮 assistant 消息的
reasoning_text必须原样回传,否则 400(The reasoning_text in the thinking mode must be passed back to the API.)。pi 通过 thinkingSignature 满足,但前提是回放的 assistant 消息带provider/api/model字段(isSameModel 判断为 true)——测试脚本最初漏传这些字段导致 400。
配置修改(models.json)
关键发现(dist/core/provider-composer.js):
applyModelsJson对内置模型只应用baseUrl与compat,provider级api不会作用于内置模型。applyModelOverride(modelOverrides)不含api字段,无法通过它改 api。- 因此必须用
models数组按 id 重定义内置模型(同名 id 替换内置模型),并在模型级设置api: "openai-responses"。
最终 ~/.pi/agent/models.json:
{
"providers": {
"deepseek": {
"baseUrl": "https://api.deepseek.com",
"api": "openai-responses",
"compat": {
"supportsLongCacheRetention": true,
"sendSessionAffinityHeaders": true
},
"models": [
{
"id": "deepseek-v4-flash",
"name": "DeepSeek V4 Flash",
"api": "openai-responses",
"reasoning": true,
"input": ["text"],
"cost": { "input": 0.14, "output": 0.28, "cacheRead": 0.0028, "cacheWrite": 0 },
"contextWindow": 1000000,
"maxTokens": 384000,
"thinkingLevelMap": { "minimal": null, "low": null, "medium": null, "high": "high", "max": "max" },
"compat": {
"supportsDeveloperRole": false,
"supportsLongCacheRetention": true
}
},
{
"id": "deepseek-v4-pro",
"name": "DeepSeek V4 Pro",
"api": "openai-responses",
"reasoning": true,
"input": ["text"],
"cost": { "input": 0.435, "output": 0.87, "cacheRead": 0.003625, "cacheWrite": 0 },
"contextWindow": 1000000,
"maxTokens": 384000,
"thinkingLevelMap": { "minimal": null, "low": null, "medium": null, "high": "high", "max": "max" },
"compat": {
"supportsDeveloperRole": false,
"supportsLongCacheRetention": true
}
}
]
}
}
}
注意点:supportsDeveloperRole: false 让 pi 发 system role(与内置目录一致);保留原 cost / contextWindow / maxTokens / thinkingLevelMap 避免重定义丢失信息;schema 对 api 无枚举限制,openai-responses 合法。
验证与端到端实测
pi --list-models正确列出 deepseek-v4-flash / deepseek-v4-pro(1M / 384K)。- 用 ModelRuntime 解析确认模型
api: "openai-responses"。 - 端到端测试(pi 真实客户端 + 工具循环):“What is 17 times 23? Use the calculator tool, then give the final number.”
- 第 1 轮:
stopReason: toolUse,工具调用 calculator{"a":17,"b":23},cacheRead: 384。 - 第 2 轮(回传 reasoning + 工具结果):
stopReason: stop,最终答案 391。 - 结论:工具调用 / 流式输出 / thinking / usage 统计全部正常;
cacheRead: 384证明 Responses API 下上下文缓存生效;多轮 reasoning 回传满足 400 校验。
- 第 1 轮:
生效方式与回退
- 生效:pi 启动时读 models.json;编辑后重新打开 /model 选模型或重启 pi。正在运行的会话仍用旧配置,新会话/新请求走 Responses API。
- 回退:把 models.json 中的
"api": "openai-responses"改回"openai-completions"(或删除 models 数组,仅保留原 compat),重启 pi 即可。
涉及文件
| 文件 | 说明 |
|---|---|
~/.pi/agent/models.json |
修改的配置文件(provider 覆盖) |
~/.pi/agent/auth.json |
DeepSeek API key(未改动) |
~/.pi/agent/settings.json |
默认 provider/model/thinking 设置(未改动) |
pi-ai/dist/providers/data/deepseek.json |
pi 内置 DeepSeek 目录(只读参考) |
pi-ai/dist/api/openai-responses.js |
Responses 客户端实现(只读参考) |
pi-ai/dist/api/openai-responses-shared.js |
流解析/消息转换(只读参考) |
pi-ai/dist/core/provider-composer.js |
pi 配置合并逻辑(只读参考) |
原文:Pi agent 接入 DeepSeek OpenAI Responses API 完整记录(公众号「糖醋鱼的小破站」)