Skip to content

feat(deepseek): support Responses web search - #1015

Merged
AAswordman merged 8 commits into
AAswordman:developmentfrom
nailuoGG:feat/deepseek-responses-server-tools
Aug 27, 2026
Merged

AAswordman merged 8 commits into
AAswordman:developmentfrom
nailuoGG:feat/deepseek-responses-server-tools

Conversation

@nailuoGG

@nailuoGG nailuoGG commented Aug 22, 2026 •

Copy link
Copy Markdown
Contributor

变更说明 / Description

为 DeepSeek 增加由 API 端点驱动的 Responses API 支持,并接入服务端 web_search。现有 /chat/completions 配置继续使用 Chat Completions;只有将端点切换为 /responses 后才会进入 Responses 协议。

本 PR 保留 Responses 无状态多轮请求所需的 web_search_call 和函数工具调用结构,并将服务端已执行的工具记录与 Operit 本地工具的权限、执行链路分离。

改动范围 / Scope

已包含 / Included

  • DeepSeek API 端点决定协议:/chat/completions 使用 Chat Completions,/responses 使用 Responses API。
  • 增加 DeepSeek Responses 服务端搜索开关;关闭时不声明 web_search。
  • 在现有客户端函数工具之外追加 {"type":"web_search"},保持 tool_choice=auto。
  • 解析 Responses 流中的终态事件、reasoning、引用与 web_search_call,并保存、恢复多轮历史所需的原始 output item。
  • 保留函数调用 ID 和原始顺序,避免后续 Responses 请求中出现 No tool output found for tool call。
  • 将服务端工具调用显示为只读记录,使用云端图标与本地工具区分,不进入 AITool、权限确认或本地执行链路。
  • Android 支持搜索期间的“正在搜索”状态,并可查看完成后的服务端调用详情。
  • Web Chat 支持完成后的 web_search 只读记录,严格处理 action.query 和 action.queries,点击记录可查看完整 raw JSON。
  • 408 和 429 保留既有重试与多 Key 轮换行为,其他确定性 4xx 仍立即失败。
  • 增加端点路由、旧配置兼容、Responses payload、工具历史、流事件和展示 metadata 的回归测试代码,并补充协议文档。

未包含与待跟进 / Out of scope and follow-ups

  • 不包含“只允许服务端搜索”模式。当前 tool_choice=auto,模型可在服务端 web_search 与 Operit 本地工具之间自主选择,也可在同一轮混合使用。
  • Web Chat 尚未转发 SERVER_TOOL_STARTED / SERVER_TOOL_COMPLETED 旁路事件;搜索期间显示通用“正在接收回复”,完成后才显示服务端工具记录。
  • 服务端搜索开关目前跟随 Responses provider 配置;使用同一配置的辅助功能请求还需要单独限定到正常 CHAT 调用。
  • 不主动请求 web_search_call.action.sources,不包含完整搜索来源面板或独立引用面板。
  • 不包含 Gradle wrapper、构建工具链或其他与功能无关的变更。

兼容性与风险 / Compatibility and risks

  • 已发布的 DeepSeek /chat/completions 配置继续使用原协议;新增配置字段有默认值,不要求迁移旧数据。
  • 只有显式使用 /responses 端点时才进入 Responses 请求路径,服务端搜索仍可通过开关关闭。
  • web_search_call 以隐藏 metadata 保存,仅用于 Responses 历史恢复和经过校验的只读展示;复制消息与非 Responses 请求会移除该 metadata。
  • 服务端工具记录不会转换为客户端 <tool>,不会绕过本地工具权限。
  • DeepSeek web_search 可能以 SSRF_BLOCKED 拒绝部分公开域名;该策略由模型服务端控制,Operit 仅保留并展示服务端结果。

关联 Issue / Related issues

Closes #877

Fixes #989

Related: #948, #797, #946

验证 / Verification

已通过 / Passed

  • git diff --check upstream/development...HEAD
  • npm --prefix web-chat run typecheck
  • npm run build:webchat
  • mise exec java@21.0.2 -- ./gradlew assembleDebug --stacktrace --no-daemon(BUILD SUCCESSFUL)
  • Web Chat 生产构建产物已包含 openai:responses_web_search、action.queries 解析和服务端工具详情弹窗。

Vite 构建仅报告现有的 500 kB chunk 大小警告,构建成功。Android Debug APK 构建仅报告现有的资源值覆盖与 SDK XML 版本警告,构建成功。

已运行但被上游问题阻断 / Run but blocked upstream

  • mise exec java@21.0.2 -- ./gradlew :app:testDebugUnitTest --stacktrace --no-daemon 已运行,但在 :app:compileDebugUnitTestKotlin 阶段失败,测试用例尚未开始执行。
  • 编译错误位于 ThinkingQualityMappingTest.kt 第 19、35、61 行:测试仍传入 Int,当前实现已要求字符串选项 ID。相关实现与测试文件在本分支和 upstream/development 完全一致,且不在本 PR diff 中,因此判定为上游已有回归,本 PR 未混入无关修复。
  • GitHub 已为最新提交创建 PR Check run #32720130880,但 fork 工作流停在 action_required,尚未启动任何 job;当前身份无上游仓库管理员权限,无法代为批准。

证据 / Evidence

  • Android 端点选择、搜索开关、搜索状态与服务端调用记录:#issuecomment-5379170879
  • Web Chat 完成后的服务端工具记录和详情展示:#issuecomment-5394234660
  • 2026-08-24 运行日志确认 DeepSeek Responses 请求成功执行服务端 web_search,返回 web_search_call 和批量 action.queries;同一轮也可继续调用 Operit 本地工具。

检查清单 / Checklist

  • 目标分支为 development。
  • 已记录协议边界、已知限制和未运行项。
  • 已提供 Android 和 Web Chat 界面证据。
  • Web Chat 类型检查与生产构建通过。
  • Android Debug APK 构建通过。
  • Android JVM 测试命令已运行,但被 upstream/development 的既有测试源码编译回归阻断。
  • PR Check 已创建但等待上游管理员批准运行,当前尚无 job 结果。

@nailuoGG

Copy link
Copy Markdown
Contributor Author
image image image image

@nailuoGG

nailuoGG commented Aug 22, 2026 •

Copy link
Copy Markdown
Contributor Author

成本收益:

本PR的主要收益是借助支持DeepSeek的 responses api能够支持服务端工具调用,例如web_search,可以简化搜索工具的配置。

看过了关联的几个issue后发现在当前时间节点的收益不算特别强。#948

并且已经有多个方案能够支持DeepSeek的 response api 或者 web_search 能力

姑且停留在draft一段时间。看看后续DeepSeek的接口支持是否有变化,有更强的动力去推进这件事情

AAswordman

This comment was marked as duplicate.

@AAswordman AAswordman left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

整体思路和方向没有问题:通过端点选择 Responses/Chat 协议、保留服务端 web_search 的历史结构,并将服务端工具调用与本地工具执行路径分离,这个设计方向是合理的。后续继续补齐实现细节和验证证据即可。

@nailuoGG
nailuoGG force-pushed the feat/deepseek-responses-server-tools branch 2 times, most recently from 28f8d18 to 2c13bc3 Compare August 24, 2026 07:02
@nailuoGG
nailuoGG marked this pull request as ready for review August 24, 2026 07:08
@nailuoGG
nailuoGG marked this pull request as draft August 24, 2026 07:23
@nailuoGG

Copy link
Copy Markdown
Contributor Author

添加Web 页面验证证据
image
image
image

@nailuoGG
nailuoGG marked this pull request as ready for review August 24, 2026 10:56
Use the saved endpoint as the single protocol selector so released Chat
Completions configurations keep their behavior and the runtime protocol
cannot disagree with the address shown to the user.

Enable optional server-side web search only for Responses requests. Preserve
web_search_call output items for DeepSeek's stateless multi-turn history and
retain function call IDs so client tool outputs remain paired across turns.
Server-side tools have already been executed by the model provider. They must
be visible to users without entering Operit's local tool permission,
authorization, or execution pipeline.

Render validated web_search_call metadata as dedicated read-only records on
Android and Web Chat. Keep local tool behavior unchanged and hide malformed
or internal protocol metadata from normal message rendering.
Protect the protocol boundaries introduced by DeepSeek Responses: endpoint
routing, released-config defaults, optional search declaration, output-item
replay, and hidden metadata removal from copied content.

Cover function call ID retention and call/output ordering so parallel tool
results remain bound to the correct Responses calls while older records
without call IDs keep their released behavior.
Record the compatibility contract across endpoint routing, optional search,
stream events, stateless history replay, and the boundary between client tool
execution and read-only server tool records.

Keep the implementation sequence and verification notes available to future
contributors so later provider and UI changes preserve the same protocol and
userspace behavior.
Failing every 4xx immediately prevents repeated invalid requests, but it also
disables the existing retry and key-rotation behavior needed for temporary
request timeouts and rate limits.

Keep deterministic client errors terminal while classifying 408 and 429 as
retriable. Preserve their HTTP status on the exception so the existing delay,
retry limit, and multi-key rate-limit handling continue to apply.
DeepSeek Responses rejects client-tool continuations when the preceding reasoning_text item is not returned. The adapter only persisted OpenAI encrypted reasoning metadata, so DeepSeek tool rounds lost the stateless reasoning history required by the API.

- Thread provider identity through streaming and non-streaming Responses parsing.
- Preserve DeepSeek reasoning item IDs and plaintext content in hidden metadata.
- Replay reasoning before assistant messages, function calls, and tool outputs.
- Remove duplicate rendered thinking content after successful replay.
- Preserve the existing OpenAI encrypted reasoning metadata contract.
- Add regression tests and protocol documentation.

Validation:
- 46 CI Python tests passed.
- Repository hygiene, Markdown links, localization, and WebChat typecheck passed on a clean latest-development merge candidate.
- OpenAIResponsesPayloadAdapterTest passed with JDK 21.
- assembleDebug passed with JDK 21.
- :app:testDebugUnitTest ran 1212 tests with 6 failures; latest development reproduced the same 6 failures in the corresponding 23-test baseline set.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants