← Back to home@ThzxxArt

dsh-search-tools

为 DeepSeek Harness 提供可插拔的网页搜索与正文抓取:支持 SearXNG 搜索、Readability 正文提取,全部在 Web 设置页完成配置。

Stars
1
Language
TypeScript
Created
Oct 22, 2026
Updated
Oct 25, 2026

Introduction

dsh-search-tools

简体中文 · English

Listed on dsh-plugin.org npm CI license

为 DeepSeek Harness(DSH)提供 adapter-first 的网页搜索与正文抓取。所有配置都在 DSH Web GUI 的 设置 → 搜索工具 完成,不要求用户手改 YAML。

仓库版本:0.1.9(2026-10-24)。 本版为 Local Direct 增加 Brave Search 与 360 Search 两个可选 HTML 引擎,并把执行模型改为每引擎独立 worker:一个慢引擎不会吞掉另一个引擎的成功结果。默认引擎仍是 DuckDuckGo + Bing;解析、去重、RRF 融合、域名多样性和缓存都在本地完成,不需要 SearXNG、API key、Reader、浏览器或第三方聚合服务。查询会直接发往启用的公网搜索引擎,但不会经过 SearXNG/Reader;不执行页面 JavaScript。默认搜索仍是 searxng,稳定 provider id 和工具 schema 不变。详细边界见 Local Direct 搜索配置 与 v0.1.9 发布清单。


目录


它解决什么问题

DSH 自带 web_search 和 web_fetch,但默认后端不一定适合每个人:有人已经有自己的 SearXNG,有人需要把搜索请求走代理,有人希望抓取结果直接是干净的正文,而不是整页 HTML。

dsh-search-tools 把“搜索/抓取后端”从 DSH 核心中解耦出来:

  • 用户可以在 Web 设置页选择后端、填写实例、测试连接;
  • 插件向 DSH 注册稳定 provider id,切换后端不会改变 DSH 的 web.searchProvider;
  • 新增后端只需要注册 adapter,设置页按 manifest 自动渲染,不需要改页面代码;
  • 额外提供 web_research:一次调用完成“搜索 + 抓取前 N 条正文”,适合需要页面内容而非只拿链接的模型回合。

它不做这些事:不提供公共搜索 API,不绕过目标站点的登录/付费墙,也不替代 DSH 的权限与沙箱模型。渲染能力取决于抓取 adapter:readable-http 不执行页面 JavaScript;可选的 wire-http 在本地做浏览器级 HTTP/TLS 指纹和 PDF 文本提取,但同样不执行页面 JavaScript;可选的 jina-reader 会把公网 URL 交给 Reader 服务做浏览器渲染(自托管时留在本机),三者都不登录、不绕过付费墙、不破解验证码。

界面预览

以下截图使用 demo 数据(https://searxng.example.com,无真实凭据):

搜索工具概览

搜索后端与实例卡

Fetch 正文 reader

Jina Reader 抓取配置

功能一览

能力说明
稳定的搜索/抓取 providerdsh-search-tools、dsh-search-tools-fetch 永不随后端变化
内置搜索 adapterSearXNG:多实例、顺序/轮询、故障转移、JSON/HTML、GET/POST、Bearer/Basic、代理、缓存、分页、域名过滤
本地直连搜索 adapter(可选)Local Direct:本机直接查询 DuckDuckGo + Bing HTML 首页,可选 Brave Search / 360;本地解析/去重/RRF 融合/域名多样性/缓存;不需要服务、Key、Reader 或浏览器,不执行 JS
内置抓取 adapterReadability HTTP:复用 DSH 安全 HTTP,Readability 提取正文,失败可回退原文
本地强抓取 adapter(可选)Wire HTTP:impit 本地浏览器级 TLS/HTTP2 指纹、逐跳公网出口 pinning、Readability、PDF 文本;不需要 Reader/Key/浏览器/容器,不执行 JS
可选渲染抓取 adapterJina Reader:浏览器渲染、PDF/Office、CSS 选择器、iframe/Shadow DOM、代理选项;目标必须是公网地址,Reader 可托管或自托管
研究工具web_research:搜索、按并发抓取前 N 页、按页/总预算截断、返回来源与正文
Web 设置页概览、搜索、抓取、研究、诊断五个页签;Connection / Search behavior 子页、实例卡、内联测试、正文 reader、预算条、字段级错误、诊断、缓存清理、键盘保存
凭据隔离搜索 token 写入 DSH credentials,不落 YAML、不进日志、不出现在诊断文本
接管与恢复可选让内置 web_search / web_fetch 使用本插件;关闭时恢复之前的 provider
外部 adapter通过 ctx.searchTools 注册新后端;设置页自动渲染 manifest 字段

工作原理

DSH ctx.web
  searchProvider = "dsh-search-tools"         (稳定)
  fetchProvider  = "dsh-search-tools-fetch"   (稳定)
        │
        ▼
  SearchDispatcher / FetchDispatcher
        │ 读取 config.search.adapter / config.fetch.adapter
        ▼
  ctx.searchTools(adapter 注册表)
    ├── searxng         内置搜索 adapter(默认)
    ├── local-direct    内置搜索 adapter(本机直连 DDG + Bing)
    ├── readable-http   内置抓取 adapter(默认,DSH 安全 HTTP)
    ├── wire-http       内置抓取 adapter(可选,本地浏览器级 HTTP + PDF)
    ├── jina-reader     内置抓取 adapter(可选,Reader 渲染)
    └── 未来由独立包注册的 adapter

关键设计:

  1. provider id 稳定,adapter 可换。 加一个后端不会改 web.searchProvider,也不会要求 DSH 重启后重新注册 provider。
  2. 配置按 section 开放。 search.adapters 和 fetch.adapters 是开放字典,adapter 自己拥有默认值与校验逻辑;核心 schema 不需要为每个后端加字段。
  3. manifest 驱动设置页。 Host 路由把 adapter manifest 发给浏览器,页面按 fields 通用渲染。新增 adapter 不需要改 React 代码。
  4. 配置在调用时解析。 Dispatcher 每次按当前配置选择 adapter;切换后不需要重新注册 provider。

架构细节见 docs/architecture.md。

环境要求

项目要求
DSH>=0.2.1-rc.2 <0.3.0(当前按 0.2.1-rc.2 验证)
Node.js`^22.19.0
搜索后端Local Direct(不需要部署,直接查 DDG/Bing)或一个可访问的 SearXNG 实例;也可暂时保持 DSH 默认搜索
抓取后端公网 http(s) 页面;readable-http 由 DSH SSRF 防护拦截内网,wire-http 在本地逐跳 pin 公网地址,jina-reader 在发出前做公网目标守卫
Reader(可选)r.jina.ai 的 API key,或一个可访问的自托管 Jina Reader 端点;不配置时继续用 readable-http 或 wire-http
浏览器DSH Web GUI(设置页只在 Web 端注册)

DSH 本身仍是 preview 软件,接口可能变化。插件把 peer 范围锁在已验证的 0.2.1-rc.2 线,升级 DSH 前请先看 CHANGELOG。

安装与升级

方式一:Web UI(推荐)

  1. 打开 DSH Web GUI。

  2. 进入 插件(Plugins)。

  3. 点击 添加插件(Add plugin)。

  4. 输入包名:

    dsh-search-tools
    
  5. 安装完成后启用这个 bundle。

  6. 打开 设置 → 搜索工具。

设置页出现,说明 Host 与浏览器两半都已加载。

方式二:CLI

dsh plugin --profile <profile> add dsh-search-tools

<profile> 换成实际 profile 名。安装后启动该 profile:

dsh --profile <profile>

方式三:离线 tarball

从 GitHub Releases 下载最新可用的 dsh-search-tools-<version>.tgz,然后:

dsh plugin --profile <profile> add ./dsh-search-tools-<version>.tgz

发布资产与 npm 产物字节一致,适合内网或无法访问 npm 的环境。

升级

DSH 插件目前不支持自动更新。升级步骤:

  1. 先在 设置 → 搜索工具 → 概览 关闭搜索/抓取接管(如果已开启)。
  2. 在 插件 页卸载旧版本。
  3. 重新添加 dsh-search-tools 或新的 tarball。
  4. 重新启用,检查设置页配置是否保留(配置在 profile 的 YAML patch 中,通常不会因重装丢失)。
  5. 重新测试搜索与抓取。

CLI 对应:

dsh plugin --profile <profile> remove dsh-search-tools
dsh plugin --profile <profile> add dsh-search-tools

不要在接管仍开启时直接卸载。内置 web_search 会指向一个不存在的 provider,直到你重装插件或手动恢复 web.searchProvider。

安装后检查

  • 设置 → 搜索工具 能看到五个页签。
  • 诊断 里能看到版本号、配置文件路径、抓取/研究运行状态和缓存统计。
  • 如果模型工具已启用,会话里应能看到 web_research。
  • 搜索测试通过后,才建议开启搜索接管。

快速开始

1. 准备搜索来源

有两条零代码路径:

  • Local Direct(推荐先试):不需要准备任何服务。它在本机直接请求 DuckDuckGo 和 Bing 的公开 HTML 结果页,解析和融合都在本机完成。可额外启用 Brave Search 或 360;Brave 内部使用 Firefox HTTP 指纹,其他引擎遵循 profile 设置。查询会离开本机发往启用的引擎;首次使用请确认所在网络能访问它们。
  • SearXNG:需要一个可访问的 SearXNG 实例。实例地址是 http(s) 绝对 URL,例如 https://searx.example.com;JSON API 需要 search.formats 包含 json,HTML-only 也可以;有认证时准备 Bearer token 或 username:password;有限流时准备多个实例或代理。插件会自动去掉末尾 /search、query 和 hash,实例 URL 里不能带用户名/密码。

2. 在设置页配置

  1. 打开 设置 → 搜索工具 → 搜索。
  2. 在 后端 选择 Local Direct 或 SearXNG。
  3. Local Direct:勾选 DuckDuckGo / Bing / Brave Search / 360 搜索 中至少一个,按需选市场、安全搜索、结果数;不需要实例或密钥。点 测试搜索引擎 可检查可达性。
  4. SearXNG:点击 添加实例,填写实例地址;备注名可选;按需设置引擎、分类、语言、安全搜索、分页、结果数、超时;需要认证时选择 Bearer / Basic 并保存密钥。
  5. 点击 测试,确认返回结构化来源;Local Direct 还会显示可达引擎。
  6. 点击 保存并应用。

3. 配置抓取(可选)

  1. 打开 抓取 页签。
  2. 先保持 Readability HTTP,用默认值测试一个公网页面,例如 https://example.com。
  3. 如果目标站点是 SPA、PDF/Office,或静态 HTTP 抓不到正文,改选 Jina Reader:
    • 托管服务填 https://r.jina.ai/,在 Jina API key 保存密钥;
    • 自托管填 http://127.0.0.1:3000/(仅 loopback 允许明文 HTTP)或 HTTPS 反代地址;
    • 需要动态内容时把 Fetch engine 设为 browser;需要新鲜内容时打开 Bypass Reader cache。
  4. 保存前看 form 顶部的数据边界 warning;测试 通过后保存并应用。
  5. web_fetch 工具默认 30 秒;把 Reader 超时调到 30 秒以上时,必须同时调高 DSH tool-web.fetchTimeoutMs,否则会先收到 TOOL_TIMEOUT。

4. 开启接管(可选)

在 概览:

  • 接管内置搜索:让 DSH 的 web_search 使用本插件的搜索 provider。开启前会先用当前配置跑一次搜索测试,失败则不会接管。
  • 接管内置抓取:让 DSH 的 web_fetch 使用本插件的抓取 provider。

接管状态会写入 DSH 的 web.searchProvider / web.fetchProvider。关闭时插件会恢复之前记录的 provider(activation.previousSearchProvider / previousFetchProvider)。

如果只想用 web_research,不一定要开启接管。web_research 调用的是当前 DSH 的搜索/抓取 provider;不接管时就使用 DSH 默认后端。

5. 使用模型工具

模型会话中可以直接使用:

  • web_search:DSH 内置工具,接管后走本插件;
  • web_fetch:DSH 内置工具,接管后走本插件;
  • web_research:本插件注册的研究工具,不依赖接管,但会使用当前 provider。

web_research 示例参数:

{
  "query": "DeepSeek Harness release notes",
  "max_results": 8,
  "fetch_top": 3,
  "max_chars": 12000
}

返回内容包含 sources、fetched 和 truncated;会话卡片会显示来源数、成功抓取数、抓取详情和截断标记。

设置页说明

概览(Overview)

  • 当前搜索 provider / 抓取 provider;
  • 接管状态与快捷开关;
  • 搜索后端是否可用、搜索来源数(SearXNG 实例或 Local Direct 引擎)、缓存条数;
  • 快速搜索测试与抓取预览;
  • 没有来源时的引导卡片。

搜索(Search)

  • 卡片式 adapter picker:显示 adapter 描述、capabilities、配置状态;
  • SearXNG 实例编辑器:添加、删除、上移、下移、启用/停用、单实例测试;
  • Local Direct 引擎多选、市场、安全搜索、每站结果数;不需要实例;
  • 测试搜索引擎:使用固定探测词,不写缓存,直接列出可达引擎,无实例也能用;
  • 由 manifest 自动渲染的字段;
  • 内联测试:显示耗时、来源标题/链接/摘要、Search notes(例如单个引擎被限流或解析为空);
  • 校验错误会定位到具体字段,搜索草稿的错误不会阻塞抓取测试。

抓取(Fetch)

  • 抓取 adapter 选择与字段;
  • 输入公网 URL 做一次抓取预览;
  • 选择 wire-http 时显示本地边界 notice、浏览器指纹/超时/PDF 字段;它不需要 Key,也不执行页面 JavaScript;
  • 选择 jina-reader 时显示数据边界 warning、API key 和浏览器/Reader 选项;readable-http 仍保留原有字段;
  • 显示状态码、内容类型、字符数、截断标记和正文预览;
  • 内网地址会被 readable-http 的 SSRF 防护或 jina-reader 的公网目标守卫拒绝,这是预期行为。

研究(Research)

  • 启用/关闭 web_research;
  • 默认结果数、最大抓取条数、默认抓取条数、单页/总字符预算、并发、超时;
  • 模型看到的工具提示 预览:描述、参数名、默认值与范围都来自当前草稿;可一键复制;
  • 关闭 web_research 后,保存后模型将看不到这个工具。

诊断(Diagnostics)

  • 配置文件路径;
  • 搜索后端、抓取后端、研究工具的真实运行状态(fetch.available / research.registered);
  • 缓存条数与命中/未命中统计;
  • 清空缓存;
  • 最近错误(环形缓冲);
  • 复制诊断信息(已脱敏)与清空错误;
  • 当前版本。

键盘与状态

  • Cmd/Ctrl+S:保存并应用当前草稿(仅在配置有效且有未保存更改时)。
  • 页签支持 ← / → / Home / End。
  • 保存状态、测试结果、诊断操作都通过 aria-live 播报。
  • 配置被更高层覆盖时页面只读;配置在别处修改时提示冲突,需重新加载。

配置参考

配置存放位置

配置通过 DSH 原生 settings 服务写入当前 profile 的 YAML patch:

$DSH_HOME/profiles/<profile>/cordis.patch.yml

结构大致如下:

- id: dsh-search-tools
  name: dsh-search-tools
  config:
    search:
      adapter: searxng
      adapters:
        searxng:
          enabled: true
          instances:
            - url: https://searx.example.com
              enabled: true
              label: primary
          engines: []
          categories: [general]
          language: all
          safesearch: 1
          pages: 1
          maxResults: 10
          strategy: ordered
          method: GET
          format: auto
          auth:
            type: none
          requestTimeoutMs: 12000
          deadlineMs: 45000
          retries: 1
          cacheTtlMs: 300000
          cacheMaxEntries: 200
          userAgent: dsh-search-tools/0.1.9 (+https://github.com/ThzxxArt/dsh-search-tools)
          proxy: ""
          includeDomains: []
          excludeDomains: []
        local-direct:
          enabled: true
          engines: [duckduckgo, bing]
          market: auto
          safeSearch: moderate
          maxResults: 10
          maxPerHost: 2
          profile: chrome
          requestTimeoutMs: 8000
          deadlineMs: 15000
          retries: 1
          minIntervalMs: 1000
          cacheTtlMs: 300000
          cacheMaxEntries: 200
          maxResponseBytes: 2000000
          proxy: ""
          includeDomains: []
          excludeDomains: []
    fetch:
      adapter: readable-http
      adapters:
        readable-http:
          enabled: true
          readability: true
          minArticleChars: 200
          maxArticleChars: 200000
          maxResponseBytes: 5000000
          maxBodyChars: 2000000
          timeoutMs: 20000
          maxRedirects: 5
          userAgent: dsh-search-tools/0.1.9 (+https://github.com/ThzxxArt/dsh-search-tools)
          failOpen: true
        wire-http:
          enabled: true
          profile: chrome
          timeoutMs: 25000
          maxRedirects: 5
          locale: ""
          maxResponseBytes: 5000000
          readability: true
          minArticleChars: 200
          maxArticleChars: 200000
          failOpen: true
          pdf: true
          maxPdfPages: 10
          maxBodyChars: 2000000
        jina-reader:
          enabled: true
          endpoint: https://r.jina.ai/
          engine: auto
          responseMode: markdown
          timeoutMs: 25000
          maxResponseBytes: 5000000
          maxBodyChars: 200000
          waitForSelector: ""
          targetSelector: ""
          removeSelector: ""
          includeIframes: false
          includeShadowDom: false
          noCache: false
          respectRobots: true
          retainImages: none
          retainLinks: all
          upstreamProxy: none
          locale: ""
          userAgent: ""
    research:
      enabled: true
      maxResults: 8
      maxFetch: 8
      defaultFetchTop: 3
      maxCharsPerPage: 12000
      maxTotalChars: 40000
      concurrency: 3
      timeoutMs: 120000
    activation:
      previousSearchProvider: ""
      previousFetchProvider: ""

不要手改这个文件来配置插件。 设置页会处理校验、section 级 diff、密钥隔离和冲突检测。手改容易写坏 YAML,也可能被更高层 overlay 覆盖。

密钥不进入 YAML。插件通过 DSH credentials 读取:

凭据引用用途格式
SEARXNG_TOKENBearer 认证token 原文
SEARXNG_BASIC_AUTHBasic 认证username:password
JINA_API_KEYJina Reader Bearer 认证(可选)token 原文;自托管无认证时留空

设置页的密钥字段是 write-only:只显示“已配置/未配置”和来源,不回显值。测试使用已保存的密钥;未保存的输入不会发送。

SearXNG 搜索配置

字段默认范围/取值说明
enabledtrueboolean关闭后该 adapter 不可用
instances[]列表实例按顺序尝试;每项有 url、enabled、label
engines[]逗号分隔留空使用实例默认引擎;例如 google, bing
categories["general"]逗号分隔留空不发送该参数,使用实例默认;通常 general
languageall字符串例如 zh-CN、en-US
safesearch10 / 1 / 2安全搜索等级
timeRange空day / week / month / year时间范围
pages11–3并发请求的分页数,结果合并去重
maxResults101–20每次搜索最多返回条数
strategyorderedordered / round-robin多实例顺序优先或轮询
methodGETGET / POSTSearXNG 请求方法
formatautoauto / json / htmlauto 先 JSON 后 HTML
auth.typenonenone / bearer / basic认证方式
requestTimeoutMs120001000–120000单次 HTTP 请求超时
deadlineMs450001000–300000整次搜索总预算,不能小于单次超时
retries10–5每个实例的重试次数,只重试可重试错误
cacheTtlMs3000000–86400000搜索结果缓存 TTL;0 关闭
cacheMaxEntries2000–10000缓存最大条数;0 关闭
userAgent带版本号非空、无换行请求 UA
proxy空http(s) URL代理;不能包含用户名/密码
includeDomains[]域名列表只保留匹配域名,支持子域名
excludeDomains[]域名列表排除匹配域名,支持子域名

行为说明:

  • 多实例故障转移:一个实例失败会尝试下一个;全部失败才报错。
  • 重试与预算:单实例重试受 retries 和 deadlineMs 共同约束;预算耗尽后不再尝试新实例。429/5xx 的 Retry-After(秒或 HTTP 日期)优先于指数退避,且同样不超过剩余 deadline。
  • host 校验:搜索/抓取 dispatcher 在 live 配置、页面草稿、probe 和 preview 前调用 adapter 的 validate();非法数字、枚举、数组或跨字段配置返回 SEARCH_CONFIG_INVALID / FETCH_CONFIG_INVALID,不会静默 clamp。
  • 预览与 probe:Search 测试预览使用当前草稿的 maxResults;搜索 probe 使用 requestTimeoutMs 和配置的 GET / POST 方法。
  • JSON / HTML:auto 先请求 JSON;遇到 403/415/406 或 JSON 解析失败时,同实例再请求一次 HTML。401 仍按认证失败处理,不会误判成格式问题。
  • Search notes:SearXNG 的 unresponsive_engines 会被保留为提示。看到 0 条结果时先看这里,可能是引擎被限流/CAPTCHA,而不是查询真的没有结果。
  • 缓存键:包含查询、实例列表、引擎、分类、语言、安全搜索、时间范围、分页、策略、方法、格式、认证类型、代理、UA 和域名过滤;修改这些会自然失效。凭据轮换不会自动改键,建议清空缓存。
  • 域名过滤:在结果进入 sources 前过滤,支持 example.com 匹配 www.example.com。
  • 分页部分成功:一页失败不会丢弃其他成功页;失败页写入 notes,全部失败才报错。

Local Direct 搜索配置

本地边界: Select Local Direct 后,查询由 Host 进程直接发往启用的固定公开 HTML 端点(默认 html.duckduckgo.com、www.bing.com;可选 search.brave.com、www.so.com);解析、去重、RRF 融合、域名多样性和缓存都在本机完成。不需要 SearXNG、API key、Reader、浏览器、Docker 或第三方聚合服务。查询会离开本机;它不执行页面 JavaScript,不登录、不绕过付费墙或验证码。引擎 HTML 结构变化可能导致解析为空,此时会显式报错或写入 notes,不会静默 fallback 到 SearXNG。

字段默认范围/取值说明
enabledtrueboolean关闭后该 adapter 不可用
engines["duckduckgo","bing"]duckduckgo / bing / brave / so360,至少一个启用的公开 HTML 引擎;结果在本地融合。Brave 由 Firefox HTTP 指纹请求;360 面向中文市场
marketautoauto / us-en / cn-zh / gb-en / jp-ja / de-de / fr-fr传给 DDG kl 和 Bing setlang/cc 的市场
safeSearchmoderateoff / moderate / strict映射到 DDG kp、Bing adlt 和 Brave safeSearch
maxResults101–20融合后返回条数上限
maxPerHost21–5同一 hostname 最多保留条数,避免单站刷满
profilechromechrome / firefoxImpit TLS/HTTP2 指纹;不是浏览器
requestTimeoutMs80001000–30000单个引擎请求超时
deadlineMs150001000–60000整次搜索总预算,不能小于单次超时
retries10–2失败引擎的重试轮数
minIntervalMs10000–10000每个引擎的最小请求间隔,避免并发搜索打爆引擎
cacheTtlMs3000000–86400000完整成功结果的缓存 TTL;0 关闭
cacheMaxEntries2000–1000缓存条数
maxResponseBytes200000065536–10485760单引擎 HTML 上限;超限该引擎失败
proxy空http(s) URL可选代理;不能包含用户名/密码
includeDomains[]域名列表只保留匹配域名,支持子域名
excludeDomains[]域名列表排除匹配域名,支持子域名

行为与失败语义:

  • 固定 origin,无用户可控 URL。 引擎 URL 由代码构造,只有查询、市场、安全搜索等参数变化;配置里没有自定义 endpoint。测试固定 origin,防止把 adapter 变成开放代理。
  • 不跟随重定向。 Impit 使用 followRedirects:false + redirect:'manual';3xx 视为该引擎失败,不会跟随到未知 host。
  • 无 Cookie / Authorization / JS。 每次搜索新建一个 Impit worker;不发送登录态,不执行页面脚本;worker 在成功、失败、abort、deadline 后都会终止。
  • 本地 RRF。 每个引擎按排名贡献 1/(60+rank+1);同 URL 合并更长标题/摘要;再按 hostname 多样性截断。查询词不参与第二阶段 LLM 重排。
  • 部分成功。 一个引擎失败时返回另一个引擎的结果,并在 notes 写明失败引擎与原因;全部失败抛 LOCAL_DIRECT_ALL_FAILED,不会自动 fallback 到 SearXNG/Jina。若 200 页面的结果全部被 includeDomains/excludeDomains 过滤掉,该引擎仍算成功(空结果 + note),不会误报全部失败。
  • 缓存只写完整成功。 只有所有启用引擎都成功、没有失败 note、且至少有结果时才写缓存;部分成功/空结果不缓存,下一次会重试失败引擎。
  • 探测。 Search 页的 测试搜索引擎 使用固定查询 dsh-search-tools probe,不写缓存;返回可达引擎列表。
  • 不解析广告。 DDG 的 result--ad 和 Bing 的 li.b_ad(即使同时带 b_algo)广告项会被丢弃;DDG uddg 和 Bing ck/a?u=a1... 的跳转链接在本地解包为真实结果 URL。
  • 引擎可用性不是 SLA。 每个引擎都可能限流、返回 202/403 或改版;这是公开 HTML 路径的固有风险。出现空结果时先看 notes 和 测试搜索引擎,必要时切回 SearXNG。

Readability HTTP 抓取配置

字段默认范围说明
enabledtrueboolean关闭后该抓取 adapter 不可用
readabilitytrueboolean是否用 Readability 提取正文
minArticleChars2000–100000低于此长度不视为文章正文
maxArticleChars2000001000–5000000提取后正文的文本最大字符数,不是 HTML 长度;不能小于 minArticleChars,也不能大于 maxBodyChars
maxResponseBytes50000001024–50000000响应体最大字节数
maxBodyChars20000001024–20000000解码后最大字符数,不能小于正文下限
timeoutMs200001000–120000抓取超时
maxRedirects50–10最大重定向次数
userAgent带版本号非空、无换行请求 UA
failOpentrueboolean正文提取失败时回退到原始内容

readable-http 的行为:

  • 复用 DSH 的安全 HTTP provider,目标是阻止 SSRF 和访问内网地址;
  • 只处理 http(s) URL;
  • 只解析文本/HTML;PDF、图片、二进制不会变成正文;
  • 不执行 JavaScript,因此纯前端渲染页面可能抓不到实际内容;
  • maxArticleChars 限制的是提取后的正文文本,不是原始 HTML;truncated 由提取器返回,短正文配长 HTML 不会再误报;
  • 需要截断 HTML 时按块级节点处理;无法安全截断时退回纯文本,保证不会返回半截标签;
  • Readability 失败且 failOpen=true 时返回原始文本/HTML,而不是让整个抓取失败;
  • readable-http 的 /probe 会真实发起一次抓取并返回 HTTP 状态/内容类型。

Wire HTTP 抓取配置

本地边界: wire-http 在本地通过 loopback 出口守卫抓取,不把目标 URL 发给第三方 Reader,也不需要 API key、浏览器、Docker 或系统库。它使用 impit 的 Chrome/Firefox TLS/HTTP2 指纹;不执行页面 JavaScript,所以 SPA 仍应使用 jina-reader。它不会登录、绕过付费墙或破解验证码。

字段默认范围/取值说明
enabledtrueboolean关闭后该 adapter 不可用
profilechromechrome / firefox浏览器 TLS/HTTP2 指纹;不是浏览器引擎
timeoutMs250001000–180000worker 与出口守卫的硬超时;默认低于 DSH web_fetch 的 30 秒工具超时
maxRedirects50–10每一跳重定向都重新经过公网出口守卫
locale空BCP 47可选 Accept-Language,例如 zh-CN
maxResponseBytes50000001024–50000000原始响应字节上限;超限显式失败
readabilitytrueboolean用 Readability 提取 HTML 正文;关闭时返回原始 HTML
minArticleChars2000–100000正文最小字符数
maxArticleChars2000001000–5000000提取后正文文本上限;不能小于下限,也不能大于 maxBodyChars
failOpentrueboolean提取失败时回退原始 HTML;关闭时返回 WIRE_UNREADABLE
pdftrueboolean本地 PDF 文本提取
maxPdfPages101–20只读前 N 页;超过上限标记 truncated
maxBodyChars20000001024–20000000解码后字符上限,HTML/文本/PDF 共用

行为与失败语义:

  • 初始目标先解析并校验,随后每一跳由本地出口代理重新解析;任何 DNS 答案包含私网/loopback/link-local/CGNAT/ULA/IPv4-mapped/6to4/Teredo/已知 NAT64 前缀(64:ff9b::/96、64:ff9b:1::/48)都会被拒绝;网络专用 NAT64 前缀无法在通用运行时中穷举,仍被文档标为残余边界;
  • 只允许 http(s)、80/443,不允许 URL 凭据;代理连接到已验证的 IP,不会再次解析主机名;
  • impit 运行在单次请求 worker 中,成功、失败、取消或超时都会终止 worker;原生 client 不会跨请求残留;
  • 响应按 Content-Type/magic 分流:PDF → 本地 PDF.js 文本;HTML → Readability;文本/JSON → 直接文本;二进制 → WIRE_UNSUPPORTED_CONTENT;
  • 2xx 空 body 返回 WIRE_EMPTY_BODY;4xx/5xx 的空 body 保留状态码;PDF 无文本层返回 WIRE_PDF_UNREADABLE,损坏 PDF 返回 WIRE_PDF_INVALID;
  • 不自动 fallback 到 Jina 或 readable-http,避免把被本地守卫拒绝的 URL 静默发给第三方;
  • 不需要 JINA_API_KEY;设置页不显示 secret 字段。

Jina Reader 抓取配置

数据边界: jina-reader 不是 readable-http 的替代默认值。托管 https://r.jina.ai/ 时,目标 URL 会发给 Jina;只有自托管 Reader 才把页面留在本机。Reader 可能缓存页面,需要新鲜内容时打开 noCache。它不会登录、绕过付费墙或破解验证码。

字段默认范围/取值说明
enabledtrueboolean关闭后该 adapter 不可用
endpointhttps://r.jina.ai/http(s) URL托管服务或自托管 Reader;远程必须 HTTPS,http 仅允许 loopback
engineautoauto / browser / curlbrowser 强制无头浏览器;curl 使用轻量 HTTP,适合静态页
responseModemarkdownmarkdown / html / texthtml 会映射为 body.kind=html,交给本地 Readability
timeoutMs250002000–180000本地硬超时;发给 Reader 的 X-Timeout 会少 1 秒作为等待预算,最小值 2000 保证它仍短于本地截止。超过 30000 还需调高 DSH tool-web.fetchTimeoutMs
maxResponseBytes50000001024–50000000Reader 返回的 JSON 包体上限;超限返回 JINA_RESPONSE_TOO_LARGE
maxBodyChars2000001024–20000000按响应模式截断 data.content / data.html / data.text,并置 truncated=true
waitForSelector空CSS 选择器等元素出现后再提取
targetSelector空CSS 选择器只提取匹配内容
removeSelector空CSS 选择器提取前移除导航/广告等
includeIframesfalsebooleanX-With-Iframe: true
includeShadowDomfalsebooleanX-With-Shadow-Dom: true
noCachefalsebooleanX-No-Cache: true,要求实时抓取
respectRobotstruebooleanX-Robots-Txt: dsh-search-tools
retainImagesnonenone / all默认移除图片,省 token
retainLinksallnone / all是否保留链接
upstreamProxynonenone / autoauto 需要 Reader 支持且通常需要 API key
locale空BCP 47例如 zh-CN;控制 Reader 浏览器 locale
userAgent空字符串作为 X-User-Agent 发给目标页;空则 Reader 默认

行为与错误:

  • 请求固定为 POST <endpoint>/,Content-Type: application/x-www-form-urlencoded,body 为 url=<目标>;Accept: application/json,并带 X-Respond-With、X-Timeout 等头。Markdown 请求 markdown;HTML/text 请求 <mode>,content,因为 Jina 把目标站错误warning 放在 content 分支。
  • 目标 URL 在发出前经过公网目标守卫:只允许 http(s)、禁止 URL 内凭据、拒绝 loopback/私有/链路本地地址及 IPv4-compatible 等过渡地址,并要求 DNS 解析结果全部为公网地址。错误码为 JINA_INVALID_TARGET / JINA_TARGET_BLOCKED / JINA_TARGET_UNRESOLVED。
  • 401/403 → JINA_AUTH;429 → JINA_RATE_LIMIT(有 Retry-After 时带 retryAfterMs,最多 1 小时);5xx/其他 → JINA_HTTP;网络失败 → JINA_NETWORK;超时 → JINA_TIMEOUT;非法 JSON/缺少当前模式的字段(data.content、data.html 或 data.text)→ JINA_BAD_RESPONSE(若目标状态已是非 2xx,则返回空正文并保留状态码);超限 → JINA_RESPONSE_TOO_LARGE。
  • Reader 返回的目标页 404/5xx 优先从 data.warning 恢复,其次读官方 data.httpStatus;HTML/text 不再附加 content companion,直接依赖这两个官方字段。可选的 data.statusCode 作为自托管兼容字段最后兜底,且 warning/httpStatus 优先;只有三者都缺失时才无法恢复目标状态。
  • 残余风险: Reader 服务端会重新解析目标 DNS,并可能跟随目标页重定向/浏览器跳转;本插件无法像 HttpFetchProvider 那样 pin 住连接,所以这是 best-effort 守卫,不是 DSH 级别的 SSRF 保证。自托管时请限制 Reader 容器的网络出口。
  • HTML 模式的 maxBodyChars 截断优先落在完整标签边界,但仍可能留下不完整文档;需要 token 预算时优先用 Markdown/text。
  • 自托管: Jina Reader 开源版可运行在本机/内网;把 endpoint 设为 http://127.0.0.1:3000/(或 HTTPS 反代)。托管 Jina 的 API key 只发给你配置的 endpoint,并保存在 DSH credentials。

web_research 配置

字段默认范围说明
enabledtrueboolean关闭后模型看不到该工具
maxResults81–20返回来源数上限,也是 max_results 的上界
maxFetch81–10抓取页数上限,也是 fetch_top 的上界
defaultFetchTop30–10模型未指定 fetch_top 时的默认抓取数;不能大于 maxFetch
maxCharsPerPage120001000–200000单页字符上限,也是 max_chars 的上界
maxTotalChars400001000–500000所有页面合计字符预算;不能小于单页上限
concurrency31–8并发抓取数
timeoutMs1200005000–600000工具超时预算

web_research 会把模型参数夹到这些边界内,并按 maxTotalChars 在多个页面之间分配剩余预算。defaultFetchTop > maxFetch 或 maxCharsPerPage > maxTotalChars 会在执行前返回 RESEARCH_CONFIG_INVALID。某个页面抓取失败不会让整次调用失败;失败页会带 error 字段,卡片仍会显示来源和成功抓取数。

超时字段说明: timeoutMs 同时进入工具注册的声明超时和 runResearch 的内部 signal;到点后搜索/抓取会被取消并返回 WEB_RESEARCH_TIMEOUT,不再只是提示词里的展示值。

接管配置

接管不是必选项。

配置作用
web.searchProvider = dsh-search-tools内置 web_search 使用本插件搜索 provider
web.fetchProvider = dsh-search-tools-fetch内置 web_fetch 使用本插件抓取 provider
activation.previousSearchProvider开启接管前记录的搜索 provider,关闭时恢复
activation.previousFetchProvider开启接管前记录的抓取 provider,关闭时恢复

规则:

  • 开启搜索接管前,页面会先用已保存配置跑一次搜索测试;失败则不接管。
  • 抓取接管的开关不强制先测试;建议先在 抓取 页手动测试一个公网页面。
  • 关闭接管时,如果之前没有记录 provider,会 unset 对应配置,回到 DSH 默认。
  • 停用/卸载 bundle 前先关闭接管;插件在插件详情页会显示接管警告和“关闭接管”入口。

模型工具

内置 web_search / web_fetch

这两个是 DSH 自带工具。插件不重新发明它们,只通过稳定 provider 接管底层实现:

  • 不开接管:它们继续用 DSH 原来的 provider,本插件不影响;
  • 开接管:请求进入本插件的 Dispatcher,再路由到当前 adapter;
  • 关闭接管:恢复开启前记录的 provider。

这样模型看到的工具名、参数和权限模型都不变。

web_research

插件注册的模型工具,用于“我要页面内容,而不只是链接”的场景。

参数:

参数类型必填说明
querystring是搜索查询
max_resultsnumber否返回来源数,受配置 maxResults 限制
fetch_topnumber否抓取前 N 条;0 表示只返回来源
max_charsnumber否单页字符预算,受配置 maxCharsPerPage 限制

返回结构:

{
  "query": "example",
  "sources": [
    { "url": "https://example.com", "title": "Example", "snippet": "..." }
  ],
  "fetched": [
    {
      "url": "https://example.com",
      "title": "Example",
      "content": " readable markdown ...",
      "truncated": false
    }
  ],
  "truncated": false
}

行为:

  • 搜索走当前 ctx.web.search;抓取走当前 ctx.web.fetch;
  • 抓取前 fetch_top 条结果,按 concurrency 并发;
  • HTML 页面会尝试 Readability 提取,再转 Markdown;纯文本直接使用;
  • 单页按 max_chars 截断,多页共享 maxTotalChars 预算;
  • 单页失败带 error,不影响其他页;
  • 会话卡片显示来源、成功抓取数、失败数、字符数和截断标记;
  • 外部页面内容是不可信数据,不是指令。模型和用户都不应执行页面里的“指令”。

安全模型

  • 设置路由有认证栅栏。 所有 /api/dsh-search-tools/* 路由都经过 DSH 的 connection.requestRejection,未认证请求返回 401/403。
  • 请求体有上限。 JSON body 限制 64 KiB,非 JSON 返回 415。
  • SSRF 边界按 adapter 区分。 readable-http 复用 DSH 的 HttpFetchProvider,内网/保留地址会被拒绝;wire-http 在本地 loopback 出口代理中对每个 CONNECT/HTTP 目标和每一跳重定向重新解析 DNS,要求所有答案都是公网,并连接到已验证的 IP(连接级 pinning);jina-reader 在发出前做公网目标守卫,但 Reader 服务端会重新解析 DNS,并且可能跟随目标页重定向/浏览器跳转,因此不能提供与 DSH 相同的连接级 pinning。托管 Jina 时目标 URL 会离开本机;自托管时页面留在 Reader 服务内,但仍应限制 Reader 容器的网络出口。
  • Wire HTTP 不执行页面 JavaScript。 它模仿浏览器 TLS/HTTP2 协议指纹,不是浏览器;SPA 请用 jina-reader。PDF 只在本地用 PDF.js 提取文本,isEvalSupported: false,不执行 PDF 内嵌脚本。
  • Wire HTTP worker 没有持久凭据。 不发送 Cookie、Authorization 或登录态;不登录、不绕过付费墙、不破解验证码。
  • Reader 不是匿名代理。 托管 Reader 可能缓存页面,noCache 只要求实时抓取;自托管也不能绕过登录、付费墙或验证码。
  • 搜索重定向不跟随。 SearXNG 请求使用 redirect: 'error',认证头不会跟随跨源重定向。Local Direct 使用 followRedirects:false + redirect:'manual',3xx 直接视为该引擎失败。
  • 搜索出口按 adapter 区分。 searxng 把查询发给用户配置的实例(可私有/loopback);local-direct 只把查询发给启用的固定公网 origin(默认 DuckDuckGo/Bing,可选 Brave/360),没有用户可控 endpoint,不发送 Cookie/Authorization,也不执行 JS。web_research 的抓取阶段仍只接受公网页面;搜索结果中的本地/私有 URL 不会被 fetch adapter 读取。
  • 凭据不落 YAML。 Bearer/Basic/Jina API key 写入 DSH credentials;YAML 只保存非敏感配置。诊断文本会脱敏,不包含 token。
  • 代理不带凭据。 proxy 必须是 http(s) URL,且不能包含用户名/密码,避免把代理凭据写进配置。
  • 错误信息有限。 实例/目标主机名可能出现在诊断中,但查询字符串和凭据会被去掉。
  • 无遥测。 插件不向作者发送使用数据;SearXNG 搜索请求只发往你配置的实例,Local Direct 请求只发往启用的固定公网引擎,jina-reader 请求只发往你配置的 Reader endpoint(托管 Jina 时该 endpoint 是第三方)。Local Direct 的查询文本会到这些引擎,不会发给本站或其他聚合服务。

安全边界仍然取决于 DSH 本身和你的部署。不要把设置页暴露在不可信网络;不要在共享 profile 中把密钥当公共配置。

适配器开发

外部 adapter contract 在 0.1.x 标记为实验性。接口可能在小版本中调整;依赖它时请锁定 dsh-search-tools 版本并做集成测试。

一个 adapter 包大致做三件事:

  1. 依赖 ctx.searchTools 服务;
  2. 提供 manifest(设置页渲染用)和 runtime(实际搜索/抓取);
  3. 用 ctx.effect 注册,确保卸载时自动清理。
import type { Context } from '@deepseek-ai/cordis'

export const inject = ['searchTools']

export function apply(ctx: Context): void {
  ctx.effect(
    () => ctx.searchTools.registerSearchAdapter(myAdapter),
    'my-search-adapter',
  )
}

myAdapter 的结构:

const myAdapter = {
  manifest: {
    kind: 'search',
    id: 'my-search',
    label: { en: 'My Search', zh: '我的搜索' },
    description: { en: '...', zh: '...' },
    defaults: { endpoint: 'https://search.example.com' },
    capabilities: ['json', 'probe'],
    groups: [
      { id: 'connection', label: { en: 'Connection', zh: '连接' } },
      { id: 'advanced', label: { en: 'Advanced', zh: '高级' }, advanced: true },
    ],
    fields: [
      { kind: 'text', key: 'endpoint', label: { en: 'Endpoint', zh: '地址' }, group: 'connection' },
      { kind: 'number', key: 'timeoutMs', label: { en: 'Timeout', zh: '超时' }, group: 'advanced', unit: 'ms' },
    ],
  },
  validate(rawConfig) {
    return { ok: true, issues: [] }
  },
  create(ctx, getConfig) {
    return {
      available: () => true,
      async search(request, signal) {
        return { sources: [], truncated: false }
      },
    }
  },
}

约定:

  • 搜索 adapter 的 id 必须唯一;kind 必须是 search 或 fetch。
  • 配置存在 config.search.adapters.<id>(或 fetch.adapters.<id>),adapter 自己 normalize/validate。
  • fields 支持 text、url、password、number、boolean、select、tags、checkboxes、instances;可选 group、advanced、unit 只影响展示,不改变配置结构。checkboxes 声明固定 options,用 default 给出多选默认值。
  • groups 可选;不声明时页面渲染单个 Configuration 分组。字段的 group 不存在时回退到第一个分组,advanced: true 的字段自动进入折叠区。
  • 需要密钥时用 secretRefs 声明引用,值走 DSH credentials,不要写进 manifest defaults;secret 也可声明 group / advanced。
  • 新增 adapter 不需要改设置页代码;页面按 manifest 渲染,声明 groups 后自动获得分组与折叠。
  • v0.1.x 不支持 adapter 自带完全自定义的设置 UI;如有需要,可以未来注册自己的 settings.section,但那就不再是统一页面的一部分。
  • 外部 adapter 的本地化目前以 manifest 的 label / description 原文为准;内置 adapter 由插件字典提供中英文。

ctx.effect 返回 disposer;不要在 apply 外保存全局注册状态。重复注册同一 id 会被拒绝。

本地开发

pnpm install --frozen-lockfile --registry=https://registry.npmjs.org
pnpm typecheck
pnpm test
pnpm build
pnpm release

pnpm build 产出:

lib/index.js        Host 半侧
lib/wire-worker.js  wire-http 单次请求 worker
lib/client.js       浏览器 lazy-CJS factory
lib/types/**        TypeScript 声明

测试与检查:

命令内容
pnpm typecheckTypeScript 类型检查
pnpm testVitest:Host 单测、设置页/研究卡片组件测试、pipeline、publint 策略
pnpm coverage同上 + V8 覆盖率门禁;statements / branches / functions / lines 均不得低于 85%
pnpm buildHost、浏览器、类型声明
pnpm pack:checkbuild + pnpm pack --dry-run + publint
pnpm releasetypecheck + coverage + pack:check

CI 在 Ubuntu/Windows × Node 22/24 上跑 typecheck、coverage、build、pack dry-run、publint。publint 只忽略 lib/client.js 的 FILE_INVALID_FORMAT:DSH 把它当浏览器 CJS 工厂加载,不是 Node ESM 入口;其他诊断仍然失败。

项目结构

src/core/                 adapter 类型、注册表、稳定 dispatcher、诊断
src/search/adapters/      SearXNG + Local Direct adapter(manifest/schema/parser/fusion/worker)
src/fetch/adapters/       Readability HTTP / Wire HTTP / Jina Reader adapters
src/research/             web_research pipeline、prompt、render、tool
src/host/                 认证的设置路由
src/client/               设置 → 搜索工具 + 研究卡片
src/shared/               config、校验、diff、URL、公网目标守卫、限制
tests/                    Host 单测 + 设置页/研究卡片组件测试
docs/                     架构、设计、M0 验收、发布清单

为什么用 linkedom 而不是 jsdom

Readability 运行在 Host 内。jsdom 的 tr46 依赖会调用 createRequire(...).resolve.paths,而 DSH 的 profile resolution hook 没有实现它;linkedom 更小,也能在 Host 内工作。jsdom 只作为组件测试的 dev 依赖。

发布流程

发布前确认:

  • package.json 版本是 0.1.9;
  • CHANGELOG.md 有对应条目;
  • pnpm release 全绿;
  • 工作区干净;
  • npm 认证可用,或仓库配置了 NPM_TOKEN secret。

本地检查:

pnpm install --frozen-lockfile --registry=https://registry.npmjs.org
pnpm release
pnpm pack --pack-destination dist

打 tag 并推送:

git tag -a v0.1.9 -m "dsh-search-tools v0.1.9"
git push origin main --follow-tags

推送 v* tag 会触发 .github/workflows/release.yml:

  1. 在 Ubuntu/Windows × Node 22/24 上先跑完整验证矩阵(含 check:package);
  2. 校验 tag 名与 package.json 版本一致,且 tag commit 在 main 上;
  3. 重复 pnpm release;
  4. 检查该版本是否已发布,已存在则跳过;
  5. 用 NPM_TOKEN 发布到 npm(provenance);
  6. 把 tarball 附加到 GitHub Release,并使用 docs/release-v<version>.md 作为发布说明。

手动发布(不产生 provenance;正式发布走 tag workflow):

npm publish --access public

发布后做一次全新 profile 冒烟:安装、启用、分别用 local-direct 和 searxng 做搜索测试、分别用 readable-http、wire-http 和 jina-reader 做抓取测试、一次 web_research 调用。详细清单见 v0.1.9 发布清单。

故障排查

现象可能原因处理
设置页没有“搜索工具”bundle 未启用;DSH 版本不匹配;客户端加载失败在插件页启用;确认 DSH 在 >=0.2.1-rc.2 <0.3.0;看浏览器控制台/插件日志
搜索测试 401/403实例需要认证;凭据未保存;Basic 格式不是 username:password在认证字段选择正确类型,保存密钥后重试;确认 Source: env 是否符合预期
搜索测试 429实例/引擎限流降低频率、换实例或引擎、增加缓存 TTL,或改用其他后端
Local Direct 全部失败网络无法访问引擎;引擎返回 202/403/429;解析为空点 测试搜索引擎 看可达性;换网络/代理;稍后重试;必要时切回 SearXNG
Local Direct 结果偏少只启用了单引擎;每站上限;引擎只返回首页多启用一个引擎;提高 maxPerHost/maxResults;看 Search notes
返回 0 条但测试“成功”SearXNG 默认引擎被限流/CAPTCHA看 Search notes;指定 engines(例如 bing)或换实例
JSON 解析失败实例未启用 JSON 格式在 SearXNG 的 search.formats 加 json;或把格式设为 html
web_research is disabled研究工具关闭设置 → 研究 → 启用 web_research 并保存
研究只返回来源、不抓正文fetch_top=0;抓取失败;目标页面不可读提高 fetch_top;看抓取详情的 error;手动在抓取页测试 URL
内网 URL 抓取失败readable-http 的 DSH SSRF 防护;jina-reader 的公网目标守卫预期行为;不要尝试绕过
Jina 抓取返回 401/403API key 未配置/无效;匿名 IP 被限流在设置页保存 JINA_API_KEY;或改用自托管 Reader
Jina 抓取返回 429Reader 限流稍后重试、降低频率、配置 key/配额,或改回 readable-http
Jina 超时Reader 浏览器渲染慢;DSH web_fetch 30 秒工具超时先到降低 timeoutMs 到 25 秒内,或调高 DSH tool-web.fetchTimeoutMs
接管后内置搜索报错bundle 被停用/卸载但接管仍指向插件重新启用插件,或关闭接管;设置页/插件详情页有恢复入口
配置保存冲突配置在别处被修改;更高层覆盖点 重新加载;检查 profile 的 cordis.patch.yml 和更高层 overlay
配置只读被更高层配置覆盖页面顶部会说明;到覆盖层修改,或移除覆盖
实例 URL 重复规范化后相同去掉重复实例;URL 会去掉末尾 /search、query、hash
代理配置报错不是 http(s),或包含用户名/密码改成无凭据的 http(s)://host:port
缓存结果不更新TTL 未到在诊断页清空缓存,或等 TTL 过期
安装后没有 web_research研究工具关闭;模型未刷新工具列表启用并保存;开新会话或重新加载页面
npm 安装失败registry/网络/peer 不匹配检查 DSH 版本、Node 版本、npm registry;用 tarball 离线安装

诊断顺序建议:

  1. 看 设置 → 诊断 → 最近错误;
  2. 看 Search notes(引擎级错误);
  3. 用 测试 复现,不要只看模型回合;
  4. 确认是否开启了接管,以及当前 provider 是哪一个;
  5. 最后再查 DSH 日志和实例日志。

已知限制

  • 内置两个搜索 adapter 和三个抓取 adapter。 搜索默认仍是 searxng;local-direct 是零部署的本地直连后端,默认查询 DuckDuckGo/Bing,并可选用 Brave Search / 360 公开 HTML,不执行 JS,也不保证引擎永不改版/限流。抓取默认 readable-http;wire-http 是本地浏览器级 HTTP + PDF 后端;jina-reader 是可选 Reader 后端。0.1.x 不附带 Google/Exa 等需要 API key 的商业搜索后端;Brave/360 走公开 HTML 页面,不需要 API key。
  • 没有自动更新。 升级需要卸载再安装。
  • 外部 adapter contract 是实验性的。 0.1.x 可能调整;生产集成请锁版本。
  • 浏览器渲染只属于 jina-reader。 readable-http 和 wire-http 都不执行 JS;wire-http 强化的是 TLS/HTTP2 指纹、出口 pinning 和 PDF,不是浏览器引擎。Jina 需要公网 Reader(托管或自托管),且不处理登录态、付费墙或验证码。SPA 能渲染不等于能登录。
  • readable-http 只处理文本/HTML。 PDF、图片、音视频不会转成正文;wire-http 可本地提取 PDF 文本;需要 Office/浏览器渲染时用 jina-reader。Jina 的 PDF/Office 转换取决于 Reader 服务能力。
  • web_research 不是爬虫。 只抓前 N 条结果,不做站点遍历、去重图谱或深度抓取。
  • 研究提示词预览可复制。 工具描述保持英文,与模型实际看到的内容一致;预览数值跟随当前草稿。
  • 接管是全局 provider 切换。 它会影响该 DSH profile 中所有使用 ctx.web 的调用,不只本插件。
  • 缓存是进程内内存。 重启后丢失;多进程不共享。
  • DSH preview 兼容范围窄。 当前锁在 0.2.1-rc.2 线,升级 DSH 前先跑回归。

许可证与第三方组件

本项目使用 MIT 许可证,见 LICENSE。

第三方组件与许可证说明见 THIRD_PARTY_NOTICES.md。主要运行时依赖包括 @mozilla/readability、linkedom、cheerio、turndown、@joplin/turndown-plugin-gfm、undici、lru-cache、normalize-url、ipaddr.js、impit(Apache-2.0,平台原生二进制)和 pdfjs-dist(Apache-2.0)。jina-reader 只调用用户配置的 Reader 服务,不打包 Jina 的代码;自托管 Reader 的许可证与运行要求由 Reader 项目提供。wire-http 不打包浏览器、Reader 或 Jina 代码。


如果这个插件对你有帮助,欢迎在 GitHub 提 issue 或 discussion。安全问题请不要公开贴 token、实例密码或完整配置。