dsh-web-search-byok
让 DeepSeek Harness (DSH) 的 web_search 走你自己的 API 网关,而不是官方搜索通道与官方余额。
A DSH web-search provider that routes web_search through your own API gateway (BYOK — bring your own key), supporting the Anthropic Messages web_search tool and the OpenAI Responses web_search tool.
为什么
DSH 内置的搜索 provider 直连官方接口,每次 web_search 都会产生一次官方模型调用并扣官方余额。若你已经在用自建网关、订阅型渠道或第三方兼容网关,这笔开销和网络路径都是多余的。
本插件注册一个新的搜索 provider(id:byok),把搜索请求转发到你配置的网关,由网关侧执行原生服务端搜索,再把结果映射回 DSH 的搜索契约。插件本身不含任何厂商端点、模型名和密钥,全部由配置提供。
特性
- 两种协议:
anthropic(Anthropic Messages + 原生web_search_20250305服务端工具)、openai-responses(OpenAI Responses +web_search工具)。 - 零厂商绑定:端点、模型、密钥名、提示词、上限、超时全部可配;代码里没有硬编码的服务商。
- 密钥不落盘:优先从 DSH credentials 服务读取,取不到再退回同名环境变量;密钥不进日志、不进仓库。
- 配置热生效:配置字段声明为 volatile,改完下一次搜索即按新配置执行(无需重启)。
- 可离线验证:协议解析层是纯函数,
node --test用 mock fetch 覆盖全部解析分支,不联网、不需要真实密钥。 - 图形化设置:插件页里打开本插件那一行的「配置」,字段改动保存即生效(volatile),不必手改 YAML。
安装
DSH 插件以 profile 的依赖形式加载,统一用 pnpm 管理(<profile> 形如 desktop / web)。
从 npm 安装(推荐)
dsh plugin --profile <profile> add dsh-web-search-byok
或在 profile 目录直接:
cd ~/.dsh/profiles/<profile>
pnpm add dsh-web-search-byok
新版本刚发布时,pnpm 的供应链策略(
minimumReleaseAge)可能要求显式放行;按 pnpm 提示把该版本加进 profile 的pnpm-workspace.yaml的minimumReleaseAgeExclude即可,或等过了最小发布年龄再装。
从源码安装(开发用)
# 1. 取源码
git clone https://github.com/elliotsu1107/dsh-web-search-byok.git
# 2. 安装插件自身依赖(只有 @deepseek-ai/schemastery 一个)
cd dsh-web-search-byok
pnpm install
# 3.(可选)放到 profile 的 plugins 目录,或记住克隆路径
cp -r . ~/.dsh/profiles/<profile>/plugins/dsh-web-search-byok/
# 4. 在 profile 目录安装本地依赖
cd ~/.dsh/profiles/<profile>
pnpm add "dsh-web-search-byok@link:./plugins/dsh-web-search-byok"
第 2 步不能省:DSH 按插件的真实路径解析裸模块名。若插件目录是跨盘 junction/软链而目标目录没有
node_modules,就会出现「启动时没能加载/failed to import: Cannot find package」。详见 docs/02-安装与配置.md §六。
通用步骤
编辑 profile 的 package.json,把插件加进 bundle 列表:
{
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"@deepseek-ai/dsh-web-app",
"dsh-web-search-byok"
]
}
}
}
再编辑 profile 的 cordis.patch.yml(示例见下一节),保存后重启 DSH 生效。
npm 包:
dsh-web-search-byok(当前0.2.0,MIT)。
配置
profile 的 cordis.patch.yml 追加以下内容:
# 1) 插件本体
- id: web-search-byok
name: dsh-web-search-byok
config:
protocol: anthropic # anthropic | openai-responses
baseURL: https://gateway.example.com/v1
model: your-model-id # 需要该模型/网关支持服务端 web_search 工具
apiKeyEnv: WEB_SEARCH_API_KEY # 密钥名,不是密钥本身
# 2) 把 ctx.web 的搜索切到本 provider
- id: web
name: '@deepseek-ai/dsh-web'
config:
searchProvider: byok
fetchProvider: http # web_fetch 仍走本地直连,不经网关
# 3)(可选)关掉官方搜索通道,避免任何一次搜索回落到官方余额
- id: web-search-deepseek
name: '@deepseek-ai/dsh-web-search-deepseek'
disabled: true
- id: web-deepseek-api
name: '@deepseek-ai/dsh-web-deepseek-api'
disabled: true
密钥按 apiKeyEnv 指定的名字保存:优先从 DSH 的 credentials 服务读取,读不到再读同名环境变量。不要把密钥写进 cordis.patch.yml。
配置字段
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
protocol |
string | anthropic |
网关协议:anthropic / openai-responses |
baseURL |
string | 空 | 网关基地址,插件拼 /messages 或 /responses;只接受 http(s),不得内嵌账号密码、查询串、锚点 |
model |
string | 空 | 执行服务端搜索的模型 id |
apiKeyEnv |
string | WEB_SEARCH_API_KEY |
密钥名(credentials 服务 → 环境变量) |
promptTemplate |
string | Perform a web search for the query: |
拼在搜索词前的提示词 |
maxTokens |
number | 4096 |
anthropic 协议单次输出上限 |
maxUses |
number | 3 |
anthropic 协议单次请求允许的最大搜索次数 |
timeoutMs |
number | 60000 |
单次搜索超时(毫秒) |
sessionHeader |
string | 空 | 网关若要求会话头(缺少会 400),填头名;插件按进程生成 UUID 填入 |
headers |
object | {} |
额外请求头,键值均为字符串 |
baseURL 与 model 必填;protocol 非法、baseURL 不合法、sessionHeader 不是合法头名时,会在第一次搜索时给出 WEB_PROVIDER_CONFIG 明确报错。
设置界面
0.2.0 起自带图形化设置页(浏览器半侧 lib/client.js):
侧栏 插件 → 已安装 → dsh-web-search-byok → 行 web-search-byok 的「配置」
- 可改
protocol(下拉)、baseURL/model/apiKeyEnv/sessionHeader/promptTemplate、timeoutMs/maxTokens/maxUses、headers(JSON); - 保存后写入 profile 的
cordis.patch.yml用户层,volatile 热更新立即生效,不用重启; - 密钥字段只填名字(凭据引用),真实密钥仍由 DSH 凭据域或环境变量提供;
- 清空某个字段再保存 =
unset,恢复组合默认值。
细节与排错(含「未提供配置命名空间」)见 docs/02-安装与配置.md §九。
两种协议
| 项 | anthropic |
openai-responses |
|---|---|---|
| 端点 | POST {baseURL}/messages |
POST {baseURL}/responses |
| 鉴权 | x-api-key 与 Authorization: Bearer 同时发送 |
Authorization: Bearer |
| 搜索工具 | {"type":"web_search_20250305","name":"web_search","max_uses":N} |
{"type":"web_search"} |
| 结果来源 | web_search_tool_result 块 + 文本块 citations |
url_citation 注解 |
| 额外参数 | maxTokens / maxUses / promptTemplate |
promptTemplate |
统一返回 DSH 的搜索契约:{ sources: [{ url, title?, snippet?, publishedAt? }], content?, truncated: false },并按 URL 去重。
开发与测试
pnpm install # 安装唯一运行时依赖 @deepseek-ai/schemastery
node --test test/ # 协议解析 + 配置解析 + 入口装配 + 客户端 bundle 契约,28 项,全部离线
node --check lib/provider.js && node --check lib/settings.js && node --check lib/index.js
不访问网络、不需要真实密钥:测试用 mock fetch 与固定响应。test/entry.test.mjs 会真实 import 插件入口,因此缺依赖会在这里直接失败,而不是等重启 DSH 才发现。详细设计见 docs/01-设计说明.md,安装排错见 docs/02-安装与配置.md。
隐私与安全
- 仓库内不含任何密钥、令牌、账号、本机路径、私有网关地址与个人邮箱;提交身份使用 GitHub noreply 地址。
- 密钥只从 credentials 服务或环境变量读取,仅在内存中使用,不写盘、不打日志。
- 搜索请求只发往你配置的
baseURL;redirect: 'error'防止被重定向到其他主机。 - 提交前自查见 docs/03-隐私与发布检查.md。
许可
MIT,见 LICENSE。
English
A BYOK web-search provider for DeepSeek Harness. It registers a byok search provider on DSH's ctx.web seam and forwards searches to an API gateway you configure, using either the Anthropic Messages protocol with the native server-side web_search_20250305 tool, or the OpenAI Responses protocol with the web_search tool. No vendor endpoints, model ids or keys are hardcoded; the API key is resolved from DSH credentials or an environment variable and never persisted. Install by cloning this repository and linking it as a local dependency of your DSH profile, then select searchProvider: byok in the profile's cordis.patch.yml and restart DSH. MIT licensed.
No comments yet. Be the first to write one.