Skip to main content
Glama
README.md
# deepseek-search

> 把 **DeepSeek 官方自研搜索引擎**(Search / Fetch API)封装成 **零依赖**的 SDK、命令行工具和 MCP 服务器,
> 让 Agent、RAG 与脚本可以直接检索实时网页、抓取网页正文。

- 官方接口文档:[网页搜索与抓取](https://api-docs.deepseek.com/zh-cn/guides/search/)
- 端点:`POST /v1/tools/search`、`POST /v1/tools/fetch`(Base URL `https://api.deepseek.com`)
- 特性:零第三方依赖、Node ≥ 18.17、原生 `fetch`、指数退避重试、本地参数校验、DSH / Claude Desktop / Cursor / Codex 通用 MCP

| 入口 | 适合场景 |
|---|---|
| `dseek` CLI | 终端查询、脚本集成、快速验证 Key |
| `dseek-mcp` MCP 服务器 | 给 DeepSeek Harness、Claude Desktop、Cursor、Codex 等挂上 `deepseek_search` / `deepseek_fetch` 工具 |
| `DeepSeekSearch` SDK | 在自己的 Node 程序里做检索增强 |

> 本项目是非官方社区实现,仅调用 DeepSeek 公开 API,不修改、不重发任何官方服务。

---

## 1. 快速开始

```bash
git clone https://github.com/fengyuan19990207-max/deepseek-search.git
cd deepseek-search

# 只需一个 DeepSeek API Key(https://platform.deepseek.com/api_keys)
export DEEPSEEK_API_KEY=sk-xxxxxxxx        # Windows PowerShell: $env:DEEPSEEK_API_KEY='sk-xxxxxxxx'

node bin/dseek.mjs search "DeepSeek 自研搜索引擎" --count 3
```

无需 `npm install`:仓库没有运行时依赖。

可选:把 CLI 装到全局

```bash
npm install -g .
dseek search "site:github.com mcp server" -n 5
```

### API Key 从哪里读

按优先级自动查找,只在本进程内使用,不会打印或写回:

1. `--api-key` 参数
2. 环境变量 `DEEPSEEK_API_KEY`
3. `$DSH_HOME/credentials.json` 中的 `DEEPSEEK_API_KEY` 字段
4. `$DSH_HOME/.env` 中的 `DEEPSEEK_API_KEY=...`
5. 当前目录 `.env`
6. `~/.deepseek-search.json` 中的 `apiKey` 字段

---

## 2. 命令行

```bash
# 基本搜索
dseek search "DeepSeek V4 模型 发布" -n 5

# 只要标题和链接(不要分数/日期/摘要)
dseek search "本地部署 大模型" --no-meta

# 带上网页正文(need_content=true,返回更慢)
dseek search "RAG 检索增强 最佳实践" -n 3 --content

# 搜索语法:限定站点、语言、时间
dseek search "mcp server" --site github.com --site huggingface.co --lang en --after 2025

# 排除站点与关键词
dseek search "显卡评测" --exclude-site zhihu.com --exclude 广告

# 原始 JSON(便于 jq 等工具处理)
dseek search "Rust 异步运行时" -n 5 --json

# 抓取网页正文(Markdown)
dseek fetch https://api-docs.deepseek.com/zh-cn/guides/search/ --max-chars 2000
```

真实输出示例:

```text
$ dseek search "DeepSeek 自研搜索引擎" --count 3
1. [更新日志 | DeepSeek API Docs](https://api-docs.deepseek.com/zh-cn/updates/)
   score 2.38 ★ · authority 3 ★ · DeepSeek
   Search / Fetch API 已上线,使用自研搜索引擎,支持网页搜索与抓取……

2. [DeepSeek API支持网页搜索与抓取 每千次请求5元](https://app.qudong.com/article/526513.html)
   score 2.37 ★ · authority 3 ★ · 2026-10-17 16:00:00 · 驱动中国
   DeepSeek发布公告,其API现已支持网页搜索与抓取,按请求次数计费……

# 3 条结果 · 349ms
```

退出码:`0` 成功、`1` 请求失败、`2` 参数/用法错误。

### 支持的搜索语法

`query` 里的操作符原样交给搜索服务,可组合使用:

| 操作符 | 示例 | 说明 |
|---|---|---|
| `site:` | `DeepSeek site:github.com` | 限定站点;多个用空格 + `OR` |
| `-site:` | `DeepSeek -site:example.com` | 排除站点 |
| `-` | `DeepSeek -广告` | 排除包含关键词的网页 |
| `-"..."` | `DeepSeek -"release notes"` | 排除包含短语的网页 |
| `"..."` | `DeepSeek "精确短语"` | 精确匹配短语 |
| `lang:` | `DeepSeek lang:zh,en` | 限定语言 |
| `after:` | `DeepSeek after:2025-01-01` | 只保留该日期之后发布 |
| `before:` | `DeepSeek before:2026-06-01` | 只保留该日期之前发布 |

CLI 侧对应参数:`--site`(可重复)、`--exclude-site`、`--exclude`、`--lang`、`--after`、`--before`。

---

## 3. MCP 服务器(给 Agent 挂搜索引擎)

`bin/mcp-server.mjs` 是一个 **stdio 传输、零依赖、单文件**的 MCP 服务器,暴露两个工具:

| 工具 | 作用 |
|---|---|
| `deepseek_search` | 检索实时网页,返回标题、URL、摘要、可选正文、发布时间、权威性、相关度分数 |
| `deepseek_fetch` | 抓取单个网页,返回 Markdown 正文 |

### 3.1 DeepSeek Harness(DSH)

把下面这段追加到 `$DSH_HOME/profiles/<profile>/cordis.patch.yml`(profile 通常是 `desktop`),
把 `<NODE>`、`<REPO>`、`<DSH_HOME>` 换成实际路径,保存即热加载:

```yaml
- insert:
    - id: mcp-deepseek-search
      name: '@deepseek-ai/dsh-mcp-client'
      config:
        serverName: deepseek
        transport: stdio
        command: '<NODE>/node.exe'
        args:
          - '<REPO>/bin/mcp-server.mjs'
        env:
          DSH_HOME: '<DSH_HOME>'      # 让服务器从 credentials.json 自动取 Key
          # DEEPSEEK_API_KEY: 'sk-...'  # 也可以显式给
        toolCallTimeoutMs: 120000
        failOnStartupError: false
```

加载成功后,模型侧会多出 `mcp__deepseek__deepseek_search` 与 `mcp__deepseek__deepseek_fetch`。
本仓库已在 DSH 中实测:写入配置后工具热加载生效,无需重启。

参考片段见 [`examples/dsh-cordis.patch.yml`](examples/dsh-cordis.patch.yml)。

### 3.2 Claude Desktop

`claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "deepseek": {
      "command": "node",
      "args": ["/绝对路径/deepseek-search/bin/mcp-server.mjs"],
      "env": { "DEEPSEEK_API_KEY": "sk-..." }
    }
  }
}
```

### 3.3 Cursor / 其他 MCP 客户端

`~/.cursor/mcp.json`:

```json
{
  "mcpServers": {
    "deepseek": {
      "command": "node",
      "args": ["/绝对路径/deepseek-search/bin/mcp-server.mjs"],
      "env": { "DEEPSEEK_API_KEY": "sk-..." }
    }
  }
}
```

### 3.4 Codex CLI

`~/.codex/config.toml`:

```toml
[mcp_servers.deepseek]
command = "node"
args = ["/绝对路径/deepseek-search/bin/mcp-server.mjs"]

[mcp_servers.deepseek.env]
DEEPSEEK_API_KEY = "sk-..."
```

### 3.5 手动验证 MCP 服务器

```bash
printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"t","version":"1"}}}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' \
  | node bin/mcp-server.mjs
```

诊断日志只写 stderr,stdout 只输出协议消息,不会污染 MCP 通道。

---

## 4. SDK 用法

```js
import { DeepSeekSearch, formatResultsMarkdown } from 'deepseek-search';

const client = new DeepSeekSearch();               // Key 自动发现

const { results, meta } = await client.search({
  query: 'DeepSeek 自研搜索引擎 lang:zh after:2026',
  count: 5,
  needContent: false,        // true 时才返回网页正文
  oriQuestion: 'DeepSeek 什么时候上线了搜索 API?',
});

console.log(formatResultsMarkdown(results, { summaryChars: 200 }));
console.log(meta);           // { count, elapsedMs, attempts }

const page = await client.fetch({ url: results[0].url });
console.log(page.title, page.content.length);
```

也提供一次性函数:`search(query, options)`、`fetchPage(url, options)`。

自定义行为:

```js
const client = new DeepSeekSearch({
  apiKey: 'sk-...',
  baseURL: 'https://api.deepseek.com',   // 或自建代理
  timeoutMs: 30_000,
  maxAttempts: 3,        // 408/429/5xx 才重试,指数退避 + 抖动
  retryDelayMs: 500,
  signal: undefined,     // 支持 AbortSignal
});
```

---

## 5. 响应字段

`deepseek_search` 每条结果:

| 字段 | 类型 | 说明 |
|---|---|---|
| `rerank_score` | number | 综合相关性分数 0~3,**≥ 1.5 为优质** |
| `title` | string | 标题 |
| `url` | string | 链接 |
| `snippet` | string | 短摘要(100~200 字符),适合前端展示 |
| `summary` | string | 长摘要(600~800 字符),适合给模型读 |
| `content` | string | 网页正文,`need_content=false` 时为空 |
| `site_name` | string \| null | 站点名 |
| `site_icon` | string \| null | 站点图标 URL |
| `date` | string \| null | 发布时间(UTC,RFC 3339) |
| `authority` | integer | 权威性 0~4(`-1` 未知),**≥ 3 为极权威** |

`deepseek_fetch` 返回 `{ title, content }`,`content` 为 Markdown。

---

## 6. 错误、限速与计费

| HTTP | 含义 | 本库行为 |
|---|---|---|
| 400 | 请求不合法 | 抛错,不重试 |
| 401 | Key 缺失或无效 | 抛错,不重试 |
| 402 | 账户余额不足 | 抛错,不重试 |
| 403 | Fetch 被安全策略拒绝 | 抛错,不重试 |
| 404 | Fetch 拿不到可用正文 | 抛错,不重试 |
| 408 / 429 / 5xx | 超时、超过 QPS、服务端错误 | **指数退避自动重试**(默认 3 次) |

- 限速:Search 与 Fetch **各自 5 QPS**(账号级,与 Key 无关),Fetch 另有按域名的限制。
- 计费:按**成功请求次数**,每 1,000 次 5 元;失败、空结果、超时不收费;`count` 不影响价格。
- 说明:在 DeepSeek Harness / Claude Code / Codex 中经 Server 端工具调用触发的 Search / Fetch 目前未计费,
  自北京时间 2026-11-01 00:00 起按次收费。

---

## 7. 目录结构

```text
deepseek-search/
├── bin/
│   ├── dseek.mjs           # CLI
│   └── mcp-server.mjs      # 零依赖 MCP 服务器(stdio)
├── src/
│   ├── client.mjs          # /v1/tools/search、/v1/tools/fetch 客户端
│   ├── format.mjs          # Markdown / 文本 / JSON 渲染
│   └── index.mjs           # 统一出口
├── test/
│   ├── client.test.mjs     # 客户端与格式化单测(本地 Mock API)
│   ├── mcp-server.test.mjs # MCP 端到端(spawn 子进程 + Mock API)
│   ├── cli.test.mjs        # CLI 参数解析、搜索语法拼接、退出码
│   └── helpers.mjs         # Mock DeepSeek API
├── examples/
│   ├── search.mjs
│   └── dsh-cordis.patch.yml
└── .github/workflows/ci.yml
```

## 8. 开发与测试

```bash
node --test test/client.test.mjs test/mcp-server.test.mjs test/cli.test.mjs   # 29 个用例:客户端、格式化、CLI、MCP 端到端,全部离线
node ./bin/dseek.mjs --version
```

CI 在 Ubuntu / Windows 上覆盖 Node 18/20/22/24。

## 9. 相关链接

- [网页搜索与抓取(官方指南)](https://api-docs.deepseek.com/zh-cn/guides/search/)
- [Search API 参考](https://api-docs.deepseek.com/zh-cn/api/search/)
- [Fetch API 参考](https://api-docs.deepseek.com/zh-cn/api/fetch/)
- [DeepSeek 平台 / API Key](https://platform.deepseek.com/api_keys)

## License

[MIT](LICENSE)