MiniMax 搜索接入指南
August 21, 2026 · View on GitHub
让 DSH(以及经桥接器的钉钉会话)的
web_search使用 MiniMax「coding_plan/search」 真实网页搜索, 替代随 DSH 内置但 key 失效的 DeepSeek 官方搜索(deepseek-official/dspark无效 key)。 本文是已验证生效的一键指南(2026-08 本机完成)。
一、原理速览
MiniMax 搜索是纯 HTTP API,无需 MCP / 子进程:
POST https://api.minimaxi.com/v1/coding_plan/search (国内 minimaxi.com)
POST https://api.minimax.io/v1/coding_plan/search (国际 minimax.io)
Headers: Authorization: Bearer <MINIMAX_API_KEY>
Body: { "q": "查询词" }
响应: { organic: [{title, link, snippet, date}], related_searches: [...] }
接入动作三件套(都在 DSH 宿主侧):
| # | 文件(仓库 deepseek-harness-plugin) | 作用 |
|---|---|---|
| 1 | plugins/minimax-search/minimax-search.mjs | 插件源码(仓库唯一真相源)→ 脚手架同步到宿主 |
| 2 | 宿主 ~/.dsh/profiles/web/cordis.patch.yml | 停用内置 DeepSeek + 把 web.searchProvider 指向 minimax + 插入插件行 |
| 3 | key 配置(三选一) | 新逻辑默认走 ctx.credentials(界面可写/轮换不重启);兼容 ~/.dsh/.env 的 MINIMAX_API_KEY 与 patch 里字面 config.apiKey |
2026-08-21 适配(dsh 0.1.1-rc.2):凭据解析已对齐官方
dsh-web-search-deepseek的新逻辑—— 优先级config.apiKey(字面)>ctx.credentials.resolve(apiKeyEnv)> launchEnvironment 快照, 并接入@deepseek-ai/dsh-web的WebError(WEB_PROVIDER_ERROR/WEB_ABORTED)。
二、前置条件
- 一台装了 DSH 并跑着
dsh web的机器(profile 为web)。 - MiniMax API key(
sk-开头,MiniMax 开放平台 / tokenPlan 套餐)——放~/.zshrc或便于导出即可,最终会进~/.dsh/.env。 - 能访问
api.minimaxi.com(国内)或api.minimax.io(国际)。
三、接入步骤
第 1 步:确认 key 可用(快速验证)
# 从 .zshrc 提取(不打印明文)
KEY=$(grep -m1 '^export MINIMAX_API_KEY=' ~/.zshrc | sed 's/^export MINIMAX_API_KEY=//; s/["'"'"']//g')
echo "key 长度: ${#KEY}, 前缀: ${KEY:0:4}"
# 验证 API
curl -s -X POST 'https://api.minimaxi.com/v1/coding_plan/search' \
-H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
-d '{"q":"测试"}' | python3 -c "import json,sys; d=json.load(sys.stdin); print('organic 条数:', len(d.get('organic',[])))"
期望:organic 条数: >=1。(否则 key 无效或区域不对,换 api.minimax.io。)
第 2 步:用脚手架安装插件(仓库 → 宿主)
插件源码在本仓库 plugins/minimax-search/minimax-search.mjs,仓库是唯一真相源。
用脚手架脚本同步到 DSH 宿主(不需要手动写宿主文件):
cd deepseek-harness-plugin # 本仓库根目录
npm run install:plugins # 同步 plugins/ → ~/.dsh/profiles/web/plugins/
# 若要装到别的 profile:DSH_PROFILE=tui npm run install:plugins
预期输出:
✅ 安装插件 [minimax-search] → /Users/.../.dsh/profiles/web/plugins/ (minimax-search.mjs)
已完成:共安装 1 个文件。
之后每次改
plugins/minimax-search/里的源码,重跑一次npm run install:plugins即可。 脚手架脚本见 scripts/install-plugins.mjs。
要点(如需手写/看懂插件):
- 导出
{ name, inject: ['web'], apply(ctx, config) }(同步 apply)。 apply里调用ctx.web.registerSearchProvider(new MiniMaxSearchProvider({...}))。- 凭据解析优先级
config.apiKey(字面)>ctx.credentials.resolve(apiKeyEnv)> launchEnvironment 快照;resolveApiKey()每次调用实时解析,credentials 缺席自动降级(零配置可用)。 - 错误走
@deepseek-ai/dsh-web的WebError(WEB_PROVIDER_ERROR/WEB_ABORTED),与官方 provider 同构。 - 绝不使用
process.env:宿主插件环境没有process(会抛 ReferenceError)。 fetch是全局可用(与内置dsh-web-search-deepseek同款用法)。- 官方 seam 包经宿主锚点(
~/.dsh/profiles)惰性解析(createRequire),解析不到自动降级为纯 fetch + 环境变量的旧行为。
第 3 步:配置宿主 patch
编辑 ~/.dsh/profiles/web/cordis.patch.yml:
# 1) 停用内置 DeepSeek 搜索(key 失效,会一直报 ****park is invalid)
- id: web-search-deepseek
disabled: true
# 2) 把 web 的搜索选择指向我们的 minimax provider(关键!)
- id: web
config:
searchProvider: minimax
# 3) 插入我们的插件
- insert:
- id: minimax-search
name: ./plugins/minimax-search.mjs
⚠️ 为什么必须改
web.searchProvider:dsh-basebundle 默认把web.searchProvider配成deepseek-official。 只注册 minimax 不够,选择规则会因「已配置 id」永远选 DeepSeek。必须覆盖为minimax。
第 4 步:配置 API key(三选一,按推荐排序)
方式 A(新逻辑,推荐):写入 DSH 凭据服务 ~/.dsh/.credentials.yaml
DSH 0.1.1 起提供 ctx.credentials 凭据服务(dsh-base bundle 内置 dsh-credentials-local)。
把 key 存成凭据引用 MINIMAX_API_KEY,插件每次操作经 ctx.credentials.resolve() 实时解析——
改配置界面即可轮换、无需重启 DSH、不进任何配置文件:
# 写入凭据(source 层:local;同名进程环境会遮蔽它,见 dsh-credentials 文档)
# 官方 web 界面「Models」页写 DeepSeek key 走的就是这个通道;
# 手动命令行写入可参考官方 dsh-credentials-local 的写接口,或继续用方式 B。
方式 B(兼容,零配置):~/.dsh/.env(DSH 启动 loadLayeredEnv 会读它并注入 launchEnvironment 快照)
KEY=$(grep -m1 '^export MINIMAX_API_KEY=' ~/.zshrc | sed 's/^export MINIMAX_API_KEY=//; s/["'"'"']//g')
echo "MINIMAX_API_KEY=$KEY" > ~/.dsh/.env
chmod 600 ~/.dsh/.env
方式 C(最高优先级):patch 里字面 config.apiKey
- id: minimax-search
name: ./plugins/minimax-search/minimax-search.mjs
config:
apiKey: sk-xxxx # 字面量最高优先级(覆盖 credentials / 环境变量)
apiKeyEnv: MINIMAX_API_KEY # 可选:改凭据引用名(默认 MINIMAX_API_KEY)
第 5 步:生效与验证
- patch 修改后 DSH 的 HMR 会自动重载,通常无需重启。
- 若 HMR 未生效(改插件文件本身时),重启 DSH:
kill <3080 监听 pid> && cd <harness 项目> && dsh web。 - 在任意 DSH 会话里调用
web_search工具,应返回真实结果 + 来源链接:
输入: web_search("react 最新版本")
输出: 9 条真实结果(标题/URL/摘要),不再是 "Authentication Fails ... invalid"
四、坑与排错
| 现象 | 原因 | 解决 |
|---|---|---|
报 ****park is invalid | 选到内置 DeepSeek(web.searchProvider 仍为 deepseek-official) | 换成 minimax,且 web-search-deepseek 可 disabled: true |
报 no usable web provider / WEB_PROVIDER_UNAVAILABLE | minimax available() 为 false(key 没读到) | 检查 ~/.dsh/.env 或 ctx.credentials 有 key;插件 resolveApiKey 会实时解析 |
报 multiple usable ... AMBIGUOUS | 配了多个可用 provider 且未显式选 | 在 web.config.searchProvider 里指定一个 |
| 插件不加载(lsof 看不到插件文件) | patch 未生效 / 需重启 | 确认 patch YAML 合法;重启 DSH |
宿主插件里 process is not defined | 宿主环境无 process | 改用 launchEnvironmentOf(ctx) 读 env / key |
报 WEB_ABORTED | 搜索被取消/超时(正常) | 无需处理;工具层会按取消处理 |
五、回滚
恢复 DSH 内置 DeepSeek 搜索(或换回原状):
# 1) 删掉宿主 patch 里的 minimax 相关条目
# (web-search-deepseek disabled、web.searchProvider、insert)
# 2) 或直接备份还原 cordis.patch.yml
cp ~/.dsh/profiles/web/cordis.patch.yml ~/.dsh/profiles/web/cordis.patch.yml.bak # 改前先备份
# 3) 想把插件文件也从宿主移除(仓库源码保留,不删)
rm ~/.dsh/profiles/web/plugins/minimax-search.mjs
建议:改宿主 patch 前先备份一份
cordis.patch.yml。 仓库plugins/minimax-search/是源码;宿主是安装产物。回滚只在宿主侧操作即可,不动仓库源码。
附录 A:插件源码模板
当前实现见仓库 plugins/minimax-search/minimax-search.mjs(唯一真相源,本附录为要点摘要;
用 npm run install:plugins 同步到宿主,勿手写宿主副本)。核心结构:
import { createRequire } from 'node:module'
import { join } from 'node:path'
import { homedir } from 'node:os'
// 宿主锚点解析官方 seam 包(~/.dsh/profiles 可触达全局 dsh 的 node_modules);
// 解析失败返回 null → 调用方降级,插件永远可加载。
function loadHostModule(name) {
try {
const req = createRequire(join(homedir(), '.dsh', 'profiles', '__probe__.cjs'))
return req(name)
} catch { return null }
}
export class MiniMaxSearchProvider {
constructor({ id = 'minimax', resolveApiKey, resolveApiKeySync, env, WebErrorMod } = {}) {
this.id = id
this._resolveApiKey = resolveApiKey // 每次操作实时解析(异步)
this._resolveApiKeySync = resolveApiKeySync // 同步快照(available() 用)
this._WebError = WebErrorMod || loadHostModule('@deepseek-ai/dsh-web')?.WebError || null
}
available() {
if (this._resolveApiKeySync) { const k = this._resolveApiKeySync(); if (k) return true }
return this._resolveApiKey !== undefined // 有异步解析器视为可用(运行时再判,与官方一致)
}
async search(request, signal) {
// ... fetch coding_plan/search;错误抛 WebError(WEB_PROVIDER_ERROR / WEB_ABORTED),
// 无 WebError 时降级 Error + err.code(行为等价)
}
}
export const name = 'minimax-search'
export const inject = ['web']
export function apply(ctx, config) {
const apiKeyEnv = config?.apiKeyEnv || 'MINIMAX_API_KEY'
const literalApiKey = config?.apiKey || ''
const provider = new MiniMaxSearchProvider({
id: 'minimax',
resolveApiKey: async () => {
// 1) 字面 key 2) ctx.credentials.resolve(apiKeyEnv) 3) launchEnvironment 快照
if (literalApiKey) return literalApiKey
const credentials = ctx.get?.('credentials')
if (credentials) {
const resolved = await credentials.resolve(apiKeyEnv)
if (resolved?.value) return resolved.value
}
const env = ctx.get?.('launchEnvironment')
return env?.get?.(apiKeyEnv)?.value || ''
},
resolveApiKeySync: () => {
if (literalApiKey) return literalApiKey
return ctx.get?.('launchEnvironment')?.get?.(apiKeyEnv)?.value || ''
},
})
ctx.web.registerSearchProvider(provider)
}
提示:
config里可选配apiKey(字面量,最高优先级)与apiKeyEnv(凭据引用名,默认MINIMAX_API_KEY)。 区域切换可把 endpoint 抽成MINIMAX_API_HOST驱动(见docs/DSH-NOTES.md)。