跳转至

网络搜索和读取网页的维护记录:Sonar Pro Search 和 DeepSeek Search、Fetch

这是网络搜索和读取网页背后的维护记录。用的时候不用看,出问题或者要改做法时再看。

2026-10-01 先接的是 DeepSeek 原生搜索。2026-10-02 用户指定 Perplexity 的 Sonar Pro Search 为默认,DeepSeek 改作备选。2026-10-18 DeepSeek 开放官方接口,备选换成官方 Search,另接 Fetch 读网页。

Sonar Pro Search

接口从哪来

  • 模型是用户指定的,页面是 openrouter.ai/perplexity/sonar-pro-search3。它就是 OpenRouter 上的普通 chat 模型,用 /api/v1/chat/completions,没有特殊端点。
  • 元数据从中转的 GET /api/v1/models/perplexity/sonar-pro-search/endpoints 查:
    • 模型说明写的是「只在 OpenRouter API 上提供」的 Pro Search 模式,Perplexity 最强的 agentic 搜索。
    • 上下文 200k,最多输出 8000 token。
    • 输入每百万 token 3 美元,输出 15 美元,另有一项 web_search 0.018。
    • 支持 web_search_options、structured_outputs、reasoning。
    • 上游延迟近 30 分钟 p50 是 8.1 秒,p90 是 19 秒,p99 是 29 秒。
  • OpenRouter 上 Perplexity 还有 sonar、sonar-pro、sonar-reasoning-pro、sonar-deep-research,web_search 一项都是 0.005。
  • 返回格式和 search_context_size 是经 Context7 查 OpenRouter 文档仓库(openrouterteam/docs)的 web search 指南看到的:来源以 url_citation 注解返回;web_search_options.search_context_size 决定原生搜索模型取多少上下文。

实测

2026-10-02 经海外中转实测,查询词沿用 2026-10-01 测 DeepSeek 原生搜索时的两个,直接写在用户消息里,不加前缀:

请求 耗时 结果
「Caddy 2.11 release notes」 19.8 秒 200,693 个输出 token,0.0281 美元;15 条来源,回答分 2.11.1 的改动、安全修复、2.11.2 三节,带 CVE 编号
「2026 国庆 高速免费 时间」 6.0 秒 200,146 个输出 token,0.0200 美元;15 条来源,第一条是新华社;回答是 10 月 1 日到 7 日,还提到中秋不免费
中文那条再跑一次 4.9 秒 0.0205 美元,回答一样
中文那条加 search_context_size: "low" 7.5 秒 0.0163 美元,回答一样
中文那条加 search_context_size: "high" 4.9 秒 0.0249 美元,回答一样
OpenAI Python SDK 3.22.1,base_url 填 …/api/v1,英文那条 20.6 秒 15 条来源,message.annotations 直接能读
  • 回答里的角标 [n] 对应 annotations 里的第 n 条:核对了中文那次的 [1]、[5]、[13],指向的文章都对得上。
  • url_citation 只有 url、title、start_index、end_index 四个字段,两个 index 都是 0。OpenRouter 文档 Responses API 的例子里注解带 content 摘录,这里没有。
  • 两次都是 15 条来源。中文那次有好几条是同一篇新浪文章带不同的追踪参数。
  • 响应里 reasoning 是空的,reasoning_tokens 是 0;顶层没有 Perplexity 官方 API 的 citations、search_results 字段。
  • 输入 token 只算用户消息本身,8 个。扣掉输出 token 的钱,每次搜索的费用:low 约 0.014 美元,默认约 0.018,high 约 0.022。
  • 响应头里有 X-Generation-Id。

DeepSeek Search 和 Fetch

接口从哪来

DeepSeek 2026-10-17 开放了官方的 Search 和 Fetch 接口1,2026-10-18 接进来:Search 换掉网络搜索里原来的备选,Fetch 单开一篇读取网页。

  • 原来的备选取自 DeepSeek Harness 的 web-search-deepseek 插件2:往 Anthropic 兼容端点发一次挂 web_search_20250305 工具的 Messages 调用,每搜一次就是一次完整的模型调用,2026-10-01 实测 4.7 秒、输入 token 两千到八千多。官方接口不过模型,0.5 秒出结果
  • 两个接口都是 /v1/tools/ 下的普通 JSON POST,鉴权跟模型接口一样用 Bearer。中转对所有路径原样转发,Caddy 没改
  • 指南说 snippet 通常 100 到 200 字符、summary 600 到 800 字符,实测对不上,见下面的表
  • 指南还提到 DeepSeek Harness、Claude Code、Codex 调 DeepSeek API 时,服务端工具调用会用到这两个接口,2026-11-01 起按次收费。原来那条挂 web_search 工具的路应该就是这个,我们已经不走

计费、限速、错误码以下面存档的指南为准。只有拿到结果才收钱:

只有返回 HTTP 200 且产生结果的请求才会计费(Search 的 results 必须非空,Fetch 必须返回网页正文)。请求失败、搜索无结果或超时不计费。

实测 Fetch 取不到的页面都返回 404,照这句不收钱;没去对账单。

DeepSeek《网页搜索与抓取》指南原文(2026-10-18 抓取,HTML 转成 Markdown,只把站内链接补成绝对地址)
# 网页搜索与抓取

Search 接口和 Fetch 接口为 Agent 与 RAG 应用提供实时网页内容:

* **Search 接口**按 query 搜索网页,返回结构化结果。该接口由 DeepSeek 自研搜索引擎提供支持。
* **Fetch 接口**抓取单个网页,以 Markdown 文本返回页面内容。

两者都是原始 JSON API,使用与 DeepSeek API 相同的 Bearer 鉴权。

Base URL 为 `https://api.deepseek.com`:

| API | Endpoint |
| --- | --- |
| Search | `POST https://api.deepseek.com/v1/tools/search` |
| Fetch | `POST https://api.deepseek.com/v1/tools/fetch` |

完整的请求与响应 Schema 请参考 [Search API Reference](https://api-docs.deepseek.com/zh-cn/api/search) 和 [Fetch API Reference](https://api-docs.deepseek.com/zh-cn/api/fetch)。

---

## 鉴权

在请求头中携带 API Key 和 JSON 内容类型:

| 请求头 | 必填 | 值 |
| --- | --- | --- |
| `Authorization` | 是 | `Bearer <DeepSeek API Key>` |
| `Content-Type` | 是 | `application/json` |

---

## Search 接口

### 请求

```bash
curl https://api.deepseek.com/v1/tools/search \
  -H "Authorization: Bearer <DeepSeek API Key>" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "DeepSeek V4 模型 发布",
    "count": 5,
    "need_content": true
  }'
```

```python
import requests

response = requests.post(
    "https://api.deepseek.com/v1/tools/search",
    headers={
        "Authorization": "Bearer <DeepSeek API Key>",
    },
    json={
        "query": "DeepSeek V4 模型 发布",
        "count": 5,
        "need_content": True,
    },
)
response.raise_for_status()

for result in response.json()["results"]:
    print(result["title"], result["url"])
    print(result["summary"])
```

请求字段:

| 字段 | 类型 | 必填 | 默认值 | 说明 |
| --- | --- | --- | --- | --- |
| `query` | string | 是 | - | 搜索词,1~128 个 Unicode 字符,不能全为空白,支持下方列出的搜索语法。 |
| `count` | integer | 否 | `10` | 返回条数,1~50。 |
| `ori_question` | string | 否 | - | 触发搜索的用户原始问题,1~128 个字符,有助于更好地理解搜索意图,传 `null` 视为未提供。 |
| `localization` | string | 否 | `""` | 用于优先返回本地化搜索结果的 IP 地址。 |
| `need_content` | boolean | 否 | `false` | 是否在 `content` 中返回网页正文,为 `false` 时 `content` 恒为空字符串。 |

请求体中的未知字段会被忽略。

### 搜索语法

`query` 中的搜索语法会原样传递给搜索服务。下表中的示例将操作符与搜索词组合使用;你可以在一个 query 中组合多个操作符。

| 操作符 | 示例 | 说明 |
| --- | --- | --- |
| `site:` | `DeepSeek site:github.com` | 将结果限制在指定站点,指定多个时用空格分隔并通过 `OR` 连接,例如 `DeepSeek site:github.com OR site:huggingface.co`。 |
| `-site:` | `DeepSeek -site:example.com` | 排除指定站点,指定多个时用空格分隔。 |
| `-` | `DeepSeek -广告` | 排除包含指定关键词的网页,指定多个时用空格分隔。 |
| `-"..."` | `DeepSeek -"release notes"` | 排除包含指定短语的网页,短语内可以包含空格,指定多个时用空格分隔。 |
| `"..."` | `DeepSeek "精确短语"` | 精确匹配指定短语,指定多个时用空格分隔。 |
| `lang:` | `DeepSeek lang:zh,en` | 将结果限制在指定语言,多种语言用逗号分隔,例如 `lang:zh,en`。 |
| `after:` | `DeepSeek after:2025` 或 `DeepSeek after:2025-01-01` | 将结果限制在指定日期之后发布的网页。 |
| `before:` | `DeepSeek before:2026` 或 `DeepSeek before:2026-06-01` | 将结果限制在指定日期之前发布的网页。 |

例如:

```json
{
  "query": "DeepSeek 模型 site:github.com OR site:huggingface.co lang:zh after:2025",
  "count": 10
}
```

### 响应

请求成功时返回 HTTP 200 与 `results` 数组。搜索正常结束但没有匹配结果时,返回空数组。

```json
{
  "results": [
    {
      "rerank_score": 2.4,
      "title": "DeepSeek V4 模型发布",
      "url": "https://example.com/deepseek-v4",
      "snippet": "DeepSeek V4 已上线,支持工具调用与长上下文。",
      "summary": "DeepSeek 发布了 V4 模型。此次发布改进了工具调用与长上下文能力,适合 Agent 工作流。",
      "content": "DeepSeek V4 现已正式上线……",
      "site_name": "Example News",
      "site_icon": "https://example.com/favicon.ico",
      "date": "2026-06-01T00:00:00+00:00",
      "authority": 3
    }
  ]
}
```

`results` 中每一项包含以下字段:

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `rerank_score` | number | 排序分数,0~3 分,综合考虑相关性、权威性、时效性等维度,大于等于 1.5 分为优质结果。 |
| `title` | string | 标题。 |
| `url` | string | 结果链接。 |
| `snippet` | string | 短摘要,与 query 相关,通常为 100~200 字符,适用于前端展现。 |
| `summary` | string | 长摘要,与 query 相关,通常为 600~800 字符,适用于给模型阅读。 |
| `content` | string | 网页正文,`need_content` 为 `false` 或正文缺失时为空字符串。 |
| `site_name` | string 或 null | 站点名称,缺失时为 `null`。 |
| `site_icon` | string 或 null | 站点图标 URL,缺失时为 `null`。 |
| `date` | string 或 null | 发布时间,统一为 UTC 的 RFC 3339 格式,未知时为 `null`。 |
| `authority` | integer | 网页权威性,0~4(`-1` 表示未知),大于等于 3 为极权威结果。 |

---

## Fetch 接口

### 请求

```bash
curl https://api.deepseek.com/v1/tools/fetch \
  -H "Authorization: Bearer <DeepSeek API Key>" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/article"
  }'
```

```python
import requests

response = requests.post(
    "https://api.deepseek.com/v1/tools/fetch",
    headers={
        "Authorization": "Bearer <DeepSeek API Key>",
    },
    json={"url": "https://example.com/article"},
)
response.raise_for_status()

page = response.json()
print(page["title"])
print(page["content"])
```

请求字段:

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `url` | string | 是 | 要抓取的网页地址,长度不超过 8192,必须为含 host 的 HTTP/HTTPS URL,且不能携带用户名或密码。 |

### 响应

```json
{
  "title": "Example article",
  "content": "# Example article\n\nArticle content."
}
```

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `title` | string | 页面标题,缺失时为空字符串。 |
| `content` | string | 抓取后的 Markdown 正文。 |

Fetch 的结果受目标站点的可用性和访问策略影响。

---

## 错误

错误响应使用 OpenAI 兼容的错误格式,`param` 字段恒为 `null`。

```json
{
  "error": {
    "message": "'count' must be between 1 and 50",
    "type": "invalid_request_error",
    "param": null,
    "code": "invalid_request_error"
  }
}
```

| HTTP 状态码 | 说明 |
| --- | --- |
| 400 | 请求头或请求体不合法,包括 JSON 格式错误或字段值无效。 |
| 401 | API Key 缺失或无效。 |
| 402 | 账号余额不足。 |
| 403 | Fetch 请求被安全策略拒绝。 |
| 404 | Fetch 未能获取可用的网页内容,例如 URL 不可用、被站点策略拦截、目标站点返回错误、内容类型不受支持或页面没有可提取的 Markdown 正文。 |
| 408 | 读取请求体超时。 |
| 413 | 请求体超过大小限制。 |
| 429 | 超过 Search 或 Fetch 的 QPS 限制。 |
| 500 | 服务器内部错误。 |
| 504 | 下游请求超时。 |

Search 和 Fetch 都是只读请求。遇到 HTTP 408、429 或 5xx 错误时,请等待后重试。遇到 HTTP 402 时,请先充值再重试。对于其它 4xx 错误,如不修改请求,请勿重试。

---

## 计费

Search 和 Fetch 按请求次数计费,不按 token 或返回结果条数计费:

| API | 计费单位 | 价格 |
| --- | --- | --- |
| Search | 每 1,000 次成功请求 | 5元 |
| Fetch | 每 1,000 次成功请求 | 5元 |

只有返回 HTTP 200 且产生结果的请求才会计费(Search 的 `results` 必须非空,Fetch 必须返回网页正文)。请求失败、搜索无结果或超时不计费。`count` 只控制返回的结果条数,不影响单次请求的价格。

请注意,当前用户在 DeepSeek Harness/Claude Code/Codex 中使用 DeepSeek API 时,已经会通过 Server 端工具调用访问到 Search/Fetch 接口,这部分 Search/Fetch 接口调用目前未计费,并将于北京时间 2026 年 11 月 1 日 00:00 起按次收取调用费用。

---

## 限速

对每个账号,Search 和 Fetch 分别独立限速,互不占用额度:

| API | QPS 限制 |
| --- | --- |
| Search | 5 |
| Fetch | 5 |

QPS(每秒请求数)限制按账号粒度计算,与使用哪个 API Key 无关,并与模型并发限制相互独立。超过账号级 QPS 限制的请求会收到 HTTP 429 错误码。除了账号级限制,Fetch 还针对目标域名有 QPS 限制,超过该限制也会收到 HTTP 429 错误码。

实测

2026-10-18 经国内中转实测,前两个查询沿用 Sonar 那次的:

请求 耗时 结果
Search「Caddy 2.11 release notes」 0.70 秒 10 条,rerank_score 1.93 到 2.15,authority 都是 3;summary 1043 到 3813 字符,有一条 snippet 3137 字符
Search「2026 国庆 高速免费 时间」 0.50 秒 10 条,前两条是光明网同一篇,一条 URL 带 #1;summary 96 到 714 字;第一条答案对:10 月 1 日 0 时到 7 日 24 时
中文那条加 count: 5、need_content: true 0.50 秒 content 406 到 2450 字
Search「caddy release site:github.com after:2026-01-01」 0.54 秒 5 条全是 github.com,日期都在 2026 年
Search「高速免费」count: 3,加和不加 ori_question 0.57 秒 两次返回的 3 条一模一样
Search「国庆 高速免费 site:mp.weixin.qq.com」 0.39 秒 0 条;另一个查询要 20 条,也没有一条公众号
Search query 全是空格 0.22 秒 400,'query' must not be empty
Fetch 光明网新闻 6.3 秒 2049 字,正文全,末尾混进一行统计代码
同一个 URL 再取 0.25 秒 有缓存
Fetch GitHub 的 release 页 10.9 秒 4131 字符,开头带「Skip to content」和导航菜单的标题
Fetch uv 文档的 Running scripts 8.1 秒 6329 字符,链接 0 个,代码块大多整块丢掉,行内代码前后的空格被吃掉
Fetch DeepSeek 这篇指南 0.26 秒 6402 字,表格和代码块都压成了纯文本;这么快大概是别人取过
Fetch 知乎问题页、arXiv 的 PDF 0.2 到 0.3 秒 404,not_found_error
Fetch 不存在的页面 3.8 秒 404,not_found_error
  • Search 的 URL 片段不止 #1,还见过 #2、#none、#comment#1。标题常常重复成「标题 - 标题」
  • date 几乎都是 T16:00:00+00:00,即北京时间零点,只有日期精度
  • Fetch 的 content 标点全带反斜杠转义,去掉之后是普通 Markdown

没做的

  • Sonar 和 DeepSeek Search 没拿同一批问题比过准确率。
  • Sonar 的 web_search_options 里只试了 search_context_size,别的选项(比如限定域名、地区)没试。sonar、sonar-pro 这些更便宜的 Perplexity 模型没试。
  • 海外机的 SSH 公钥还没装回去,OpenRouter 的中转配置没同步进 assets/gateway/。
  • DeepSeek Search 的 localization 没试。
  • Fetch 没拿真实的公众号文章试,也没试要跑 JS 才出内容的页面。
  • 两个接口的 429 没撞到过,限速只照指南写。

  1. DeepSeek 网页搜索与抓取指南,以及 Search、Fetch 的 API Reference,2026-10-18 读。 ↩

  2. deepseek-harness web-search-deepseek 插件,钉 639ed01(0.2.0-rc.2),2026-10-01 读。 ↩