JayLi52
dsh-web-search-doubao
Doubao (feedcoop global_search) web search provider plugin for DeepSeek Harness (dsh), registers into the ctx.web capability seam
- Stars
- 0
- Language
- JavaScript
- Created
- Aug 15, 2026
- Updated
- Aug 15, 2026
Introduction
dsh-web-search-doubao
中文 | English
DeepSeek Harness(dsh)的豆包联网搜索插件:把字节跳动 feedcoop global_search API 接入 ctx.web 能力接缝,替换内置搜索提供方。
这是一个树外 bundle 插件(out-of-tree bundle):向 ctx.web 注册一个 WebSearchProvider(id: doubao),自带 cordis.patch.yml 层——装入 profile 后自动挂载并自动把搜索选择切到 doubao。零运行时依赖,不修改任何 harness 源码。
安装
在 harness 仓库根目录(源码运行用 pnpm dsh ...,安装版用 dsh ...):
dsh plugin --profile web add github:JayLi52/dsh-web-search-doubao
安装会:把包链接进 profile、把它的 bundle 层加入 dsh.profile.bundles、挂载提供方、切换 searchProvider: doubao。装完即用,无需手改配置。
配置 token
只需提供 feedcoop Bearer token,推荐环境变量方式——在 $DSH_HOME/.env(Windows 默认 C:\Users\<你>\.dsh\.env)写一行:
DOUBAO_SEARCH_API_KEY=<你的-token>
然后重启一次 dsh web(环境变量在启动时加载)。之后改 token 以外的配置都走 profile patch 热重载,不用再重启。
也可以在 profile 的 cordis.patch.yml 里内联(覆盖环境变量):
- id: web-search-doubao
name: dsh-web-search-doubao
config:
apiKey: <你的-token>
验证组合结果:
dsh --profile web --dump-config | grep -A3 web-search-doubao
在 Web UI 新会话里让模型联网搜索(web_search 工具)即走豆包。想切回内置搜索,在 profile 的 cordis.patch.yml 加:
- id: web
name: '@deepseek-ai/dsh-web'
config:
searchProvider: deepseek-official
(profile patch 晚于 bundle 层应用,后写者赢。)
配置项
| 字段 | 默认值 | 说明 |
|---|---|---|
apiKey | '' | Bearer token;为空时回退读取 $<apiKeyEnv>。两者皆空 → 提供方不可用 |
apiKeyEnv | DOUBAO_SEARCH_API_KEY | 存放 token 的环境变量名 |
baseURL | https://open.feedcoopapi.com | API 基址 |
docCount | 10 | 请求未带 maxResults 时的默认 DocCount |
maxSnippetLength | 300 | 每条结果摘要长度上限 |
映射规则
feedcoop Result.Documents[] → 接缝 WebSearchSource:Url→url(缺失丢弃)、Title→title、Snippet[] 中 Type==='text' 的 Text 换行拼接→snippet、DocumentInfo.PublishTime→publishedAt。maxResults 截断由接缝负责;图片类 Snippet 忽略。feedcoop 的错误信封(HTTP 200 + ResponseMetadata.Error,如 invalid_api_key)会被抛成显式错误,不会静默成"无结果"。
排障
| 症状 | 原因与处理 |
|---|---|
工具调用报 unknown tool "",模型只剩 thinking 死循环 | 不是本插件的问题:harness 的 llm-deepseek 适配器对"续包带空串 id/name"的流(DashScope 兼容模式等 OpenAI 兼容端点)有解析 bug,会把工具名覆盖成空串。修复见 deepseek-harness packages/llm/llm-deepseek/src/translate.ts(仅当非空才覆盖)。用 DeepSeek 官方端点不受影响 |
Doubao API error: invalid_api_key | token 错或未设置;检查 $DSH_HOME/.env 或 patch 里的 apiKey,改 env 需重启 |
WEB_PROVIDER_CONFIGURED_UNAVAILABLE | 选了 doubao 但 available() 为 false——即没配 token |
WEB_PROVIDER_AMBIGUOUS | 多个可用提供方且没配 searchProvider;显式指定 id |
改了 cordis.patch.yml 没生效 | patch 是热重载的;若整层解析失败会保留旧树并打日志,检查 YAML 是否为顶层数组 |
自证路由(A/B)
怀疑搜索没走豆包时,用 --patch 覆盖层投毒 key 跑一次性任务:错 key 必报 invalid_api_key(或空结果),真 key 正常——两次唯一变量是 doubao 的 key,即可证明路由。
# wrong-key-test.yml
- id: web-search-doubao
name: dsh-web-search-doubao
config:
apiKey: sk-invalid-for-ab-test-0000000000
dsh --profile headless --patch ./wrong-key-test.yml "用 web_search 搜 海淀必去景点"
分享给别人
profile 目录本身不可移植(package.json 里是本机 link: 绝对路径;key 与模型配置按设计不在 profile 内)。分享"配方":把本仓库链接发给对方,执行:
# 1. 装插件(自动挂载 + 自动切换搜索),并在 $DSH_HOME/.env 自备 token
dsh plugin --profile web add github:JayLi52/dsh-web-search-doubao
# 2.(可选)开 Claude Code 委托:先让包可解析
# npm 安装版:dsh plugin --profile web add @deepseek-ai/dsh-subagent-claude-code
# 源码运行版:harness 仓库 apps/cli/package.json 加
# "@deepseek-ai/dsh-subagent-claude-code": "workspace:^" 后 pnpm install
# 再在 ~/.dsh/profiles/web/cordis.patch.yml 追加:
# - insert:
# - id: subagent-claude-code
# name: '@deepseek-ai/dsh-subagent-claude-code'
# 3.(可选)跳过 ~/.agents 共享技能注入:启动环境设 DSH_AGENTS_HOME=<空目录>
模型 key(DEEPSEEK_API_KEY 或 Models 页配置)由对方自备。
English
A DeepSeek Harness web
capability seam (ctx.web) search provider backed by the Doubao / ByteDance
feedcoop global_search API. Out-of-tree bundle plugin: registers a
WebSearchProvider (id doubao) and ships a cordis.patch.yml layer that
mounts it and switches the seam's search selection to doubao on install.
Zero runtime dependencies; no harness source changes.
Install
dsh plugin --profile web add github:JayLi52/dsh-web-search-doubao
Token
Set DOUBAO_SEARCH_API_KEY=<token> in $DSH_HOME/.env and restart once, or
inline it via the profile patch (config.apiKey on the web-search-doubao
row). Verify with dsh --profile web --dump-config. To switch back to the
shipped provider, override searchProvider: deepseek-official on the web
row in the profile patch (later layers win).
Config fields
| Field | Default | Meaning |
|---|---|---|
apiKey | '' | Bearer token; falls back to $<apiKeyEnv>. Empty → unavailable. |
apiKeyEnv | DOUBAO_SEARCH_API_KEY | Env var holding the token. |
baseURL | https://open.feedcoopapi.com | Endpoint base. |
docCount | 10 | Default DocCount without maxResults. |
maxSnippetLength | 300 | MaxSnippetLength per request. |
Mapping & errors
Documents[] maps to WebSearchSource (url/title/snippet/publishedAt);
text-type snippet parts joined with newlines; image parts ignored; the seam
owns maxResults truncation. feedcoop error envelopes (HTTP 200 +
ResponseMetadata.Error, e.g. invalid_api_key) are thrown as explicit
errors, never silently mapped to "no results".
Troubleshooting
unknown tool ""with endless thinking: not this plugin — the harnessllm-deepseekadapter overwrites parsed tool-call name/id with the empty strings that OpenAI-compatible endpoints (e.g. DashScope) send on continuation chunks. Fix: only overwrite when non-empty, inpackages/llm/llm-deepseek/src/translate.ts. The official DeepSeek endpoint is unaffected.invalid_api_key: wrong/missing token; env changes need a restart.WEB_PROVIDER_CONFIGURED_UNAVAILABLE:doubaoselected but no token set.WEB_PROVIDER_AMBIGUOUS: several usable providers, nosearchProviderset.