前言¶
DeepSeek Harness(dsh)把联网搜索做成可替换的能力,而不是写死在智能体循环里。模型侧始终调用同一套 web_search / web_fetch,真正去网上查资料的是 ctx.web 上注册的搜索提供方。官方仓库里已经有 @deepseek-ai/dsh-web-search-exa:它走 Exa 的 POST /search REST 接口,但没有 API 密钥时提供方直接不可用。
很多本地试用、临时排查、不想先去申请密钥的场景,会卡在这一步。社区维护者 TonyDua 做了 @tonydua/dsh-web-search-exa(仓库名 dsh-web-search-exa):无密钥时走 Exa 托管的匿名 MCP,配了 EXA_API_KEY 再自动切回 REST。本文按插件目录页、GitHub README / package.json、DeepSeek Harness 官方文档和 Exa MCP 说明交叉核对后整理。
DeepSeek Harness 的核心理念是「一切皆插件」。文中用到的 DSH 插件库 是独立社区站点,与 DeepSeek / 幻方没有官方从属关系,不要把它当成官方应用商店。
这是什么¶
dsh-web-search-exa 是一款 DeepSeek Harness 工具与能力插件,由 TonyDua 维护,许可证 MIT,主要语言 JavaScript,要求 Node.js 18 及以上。GitHub 仓库为 TonyDua/dsh-web-search-exa,npm 包名 @tonydua/dsh-web-search-exa。目录页与 GitHub 在本文核对时均显示 6 颗星;仓库创建于 2026-08-14,目录收录日期同日。
它解决的问题很具体:给 ctx.web 注册一个 Exa 搜索提供方,让已有的模型工具、提示词区和结果卡片不用改,就能用上网页搜索。它不是官方包的替代品,而是官方包的零配置变体——官方实现只走带密钥的 REST;本包补上匿名 MCP 兜底,带密钥时的 REST 行为与官方路径一致。
仓库 package.json 当前版本为 0.1.3。npm 页面在本文检索时列出的最新发布仍是 0.1.2。0.1.3 的变更是:bundle 补丁不再重复定义官方已经占用的 web 行,避免 dsh plugin add 后出现 duplicate loader entry id: web 启动失败。从 GitHub 安装会拿到含该修复的源码。
核心功能¶
默认免密钥,走匿名 MCP¶
未配置 apiKey 或环境变量 EXA_API_KEY 时,搜索走 Exa 托管 MCP:https://mcp.exa.ai/mcp,JSON-RPC 2.0 调用 web_search_exa,请求里不带凭据。来源标识放在 x-exa-source: dsh-anything 头里。
Exa 自己的 MCP 页面写明:连接 https://mcp.exa.ai/mcp 不需要 API 密钥。匿名调用有限流;HTTP 429 会以 WEB_PROVIDER_ERROR 返回,并提示去配置密钥。
配了密钥自动切 REST¶
设置了 EXA_API_KEY(或配置里的字面量 apiKey)之后,提供方改走 https://api.exa.ai/search(POST /search,Authorization: Bearer)。仓库说明这条路径额度更高,对模型侧的工具行为没有额外改动。REST 检索模式 searchType 默认为 auto,也可设为 keyword 或 neural。
即插即用,不改模型工具¶
它只向 ctx.web 注册 WebSearchProvider,不拥有 ctx.web 这个键,也不自己注册面向模型的工具。工具名、参数、提示词和结果卡片仍由 @deepseek-ai/dsh-tool-web 负责。返回结果会规范成 seam 的 WebSearchSource:url、title、snippet、publishedAt;maxResults 由 seam 在返回路径上截断。
DeepSeek Harness 文档对选择规则写得很清楚:没有配置提供方 id、且当时只有一个可用搜索提供方时,seam 会自动选中它。无密钥时官方 DeepSeek 搜索提供方不可用,因此本插件可以在零配置下被自动选中。
可与官方 Exa 包共存¶
默认 provider id 是 exa,Cordis 插件名是 web-search-exa,和官方 @deepseek-ai/dsh-web-search-exa 相同。seam 遇到重复 id 会抛 WEB_DUPLICATE_PROVIDER,两个包直接装进同一个 profile 会在启动时报错,没有静默覆盖。本包可用 providerId 改成例如 exa-anon,再在 web 配置里显式选择。
主要配置项¶
| 配置键 | 默认值 | 含义 |
|---|---|---|
providerId |
exa |
注册到 ctx.web 的提供方 id;与官方包共存时才需要改 |
apiKey |
未设置 | Exa 密钥字面值;为空则走匿名 MCP |
apiKeyEnv |
EXA_API_KEY |
未写字面 apiKey 时读取的环境变量名 |
apiURL |
https://api.exa.ai/search |
带密钥时的 REST 端点 |
mcpURL |
https://mcp.exa.ai/mcp |
匿名 MCP 端点 |
searchType |
auto |
REST 检索模式:auto / keyword / neural |
numResults |
未设置 | 请求未带 maxResults 时的默认条数 |
highlightsPerResult |
1 |
REST 路径每个结果请求的高亮句子数 |
apiKey 标记了 role('secret'),不会出现在 describe() 响应里。
安装与启用¶
插件目录页给出的安装命令如下,在 DeepSeek Harness 终端中运行:
dsh plugin add github:TonyDua/dsh-web-search-exa
如需可复现安装,按目录页说明固定 commit 哈希:
dsh plugin add github:TonyDua/dsh-web-search-exa#commit
把 #commit 换成实际提交哈希。仓库 README 还提供了按 web profile、从 npm 安装的写法(v0.1.3 起带 dsh.bundle manifest,bundle 补丁会插入提供方行):
dsh plugin --profile web add @tonydua/dsh-web-search-exa
装完后重启 dsh web。目录页写明:插件以当前 dsh 进程的权限运行,安装时可能执行代码;安装前应检查源代码仓库和许可证。
典型用法¶
无密钥、只装这一个搜索提供方时,重启后一般不用再改配置:官方 DeepSeek 搜索不可用,seam 会自动选中本插件。模型继续用原来的 web_search 即可。搜索结果仍由 dsh-tool-web 渲染成来源、摘要、日期卡片,和 DeepSeek 搜索的展示方式相同。
已经配置了密钥、希望明确走 Exa 时,在 $DSH_HOME/profiles/web/cordis.patch.yml 里选中提供方(该文件在 bundle 补丁之后应用):
- id: web
name: '@deepseek-ai/dsh-web'
config:
searchProvider: exa
也可以不改文件,用环境变量在运行时指定:
export DSH_WEB_SEARCH_PROVIDER=exa
本地开发目录可以按 README 直接指向检出路径:
dsh plugin --profile web add ../plugins/dsh-web-search-exa
若要和官方 @deepseek-ai/dsh-web-search-exa 装在同一个 profile,必须改 id。官方包的 id 固定为 exa,给本包一个不同值,例如 exa-anon:
- insert:
- id: web-search-exa
name: '@tonydua/dsh-web-search-exa'
config:
providerId: exa-anon
- id: web
name: '@deepseek-ai/dsh-web'
config:
searchProvider: exa-anon
对应的环境变量是 $DSH_WEB_SEARCH_PROVIDER=exa-anon。更省事的做法是:每个 profile 只装其中一个包,沿用默认 id。
当前版本没有 Web 设置页里的可编辑卡片。Settings → Plugins 清单里会出现 web-search-exa(@tonydua/dsh-web-search-exa),服务端也注册了 web-search-exa 配置段,但没有客户端卡片绑定它。内置的 “Web search” 卡片改的是官方 web-search-deepseek 命名空间,和本插件无关。改配置请编辑 cordis.patch.yml 或环境变量,然后重启 dsh web。README 写明下一版本计划补 UI 卡片,本文不把它当作已经交付的功能。
适用场景与注意事项¶
适合这些情况:
- 本地试用 DeepSeek Harness 的网页搜索,暂时不想申请 Exa 密钥
- 已经在用
web_search,只想换搜索后端,不想动工具和提示词 - 需要和官方 Exa 包对比,或在同一套 profile 里用
providerId显式切换
使用前注意:
- 匿名 MCP 有限流。 频繁搜索遇到 429 时,按仓库说明配置
EXA_API_KEY或apiKey,提供方会切到 REST。Exa 托管 MCP 是 Exa 的官方产品,免费匿名可用,但额度由对方控制。 - 本插件只提供搜索,不提供抓取。
web_fetch仍走独立的 fetch 提供方(官方文档里是dsh-web-fetch-http这一路),不要指望它顺带读完整网页。 - 不要无改动地双装官方包和本包。 默认 id 冲突会直接导致启动失败。
- 当前没有设置 UI。 改
searchType、mcpURL、providerId等只能走补丁文件或环境变量。 - 运行时单例。 README 说明
@deepseek-ai/dsh-tools必须在一个 profile 里解析成同一份物理实例。本插件不依赖它;若其它第三方插件把它装成嵌套普通依赖,agent 循环可能在搜索提供方被调用前就报Cannot read properties of undefined (reading 'prepare')。应先修那个插件的依赖声明。 - 权限与许可证。 插件以当前 dsh 进程权限运行。安装前阅读仓库源码和 MIT 许可证。DeepSeek Harness 本身仍处于开发者预览,官方 README 写明会有破坏兼容性的变更。
- 选型。 已有
EXA_API_KEY、希望跟官方实现走:用@deepseek-ai/dsh-web-search-exa。要零配置试用:用本包。
匿名 MCP 的接入方式,仓库 README 写明参考了 can1357/oh-my-pi 以及 @oh-my-pi/exa:有密钥走 REST、无密钥走 mcp.exa.ai/mcp。
小结¶
dsh-web-search-exa 把 Exa 接到 DeepSeek Harness 的 ctx.web 上:没密钥时用官方托管的匿名 MCP,有密钥时自动升到 REST,模型侧的 web_search 不用改。它是社区维护的零配置变体,不是官方包,也不是 DeepSeek 官方商店里的「认证插件」。
目录页:https://deepseek-harness-plugin.com/zh-CN/plugins/dsh-web-search-exa/
GitHub:https://github.com/TonyDua/dsh-web-search-exa