跳到主要内容

dsh-tinyfish

已验证

@viztor/dsh-tinyfish · v0.12.1 · MIT · Web 界面

TinyFish-backed search and fetch providers for the DeepSeek Harness web capability seam (ctx.web) — $0 SERP and page extraction, direct or via Monid.

安装

dsh plugin add @viztor/dsh-tinyfish

用 dsh --profile default --dump-config 确认 layer 已生效 —— 参见安装指南。

源码

标签

作者

说明文档

English | 简体中文 | 日本語

TinyFish logo

dsh-tinyfish

为 DeepSeek Harness 提供免费的网页搜索与抓取。
让你的 agent 连上实时网络——每次调用只要 $0。

npm downloads ci license


你的 agent 早就学会了推理,现在给它一点可供推理的“材料”:实时搜索结果与干净的页面正文,直连 harness 自带的 web_search 与 web_fetch 工具。由 TinyFish 驱动——两个端点都免费,你主机上的网络链路从此不再按次计费。

之前 之后
每次搜索调用都要计费 $0,永久免费
抓回来的页面是 HTML,转换得磕磕绊绊 干净的 Markdown,来自浏览器级提取器,开箱即用
换提供方就要重装 改配置文件的两个单词即可,不用重装
每个提供方要么接受你的原样查询,要么什么都不接受 常驻默认值——域名、语言、时效、日期上下界、缓存 TTL、选择器

📊 方案对比

适用场景 解决方案 费用
在原生工具里免费搜索与抓取 dsh-tinyfish,任一通道 $0——直连通道用 TinyFish 密钥,Monid 通道用平台密钥;两种载荷完全一致
官方默认 deepseek-official + http 搜索按次计费;抓回的 HTML 还要再付一道 turndown 转换
需要提供方特有的 SERP 细节(地理、流量、排名)或批量查询 经 monid_run 调用的 Monid SERP 镜像 每次约 $0.002–$0.18,随提供方而定——只在任务真需要这些细节时用
fetch 读不了的页面(重 JS、需登录、要交互) CLI 里的 tinyfish agent / browser 按量计费($0.016/step,$0.002/min)——只在抓取落空后果断升级

🚀 快速上手

方法一:从 Web 界面直接安装(推荐)

DeepSeek Harness 支持直接在 Web 界面安装插件,全程不用碰终端:

  1. 打开 DSH Web,在侧边栏选择 Plugins(插件)。
  2. 点击 Add plugin(添加插件)。
  3. 输入包名 dsh-tinyfish(或 @viztor/dsh-tinyfish)——这是自由输入框,不是仓库搜索。
  4. 点击 Install(安装)——DSH 会从 npm 拉取软件包,并加载它声明的 bundle 补丁。live profile(官方 Web profile 挂载了 HMR)会立即生效;否则 DSH 会提示下次启动时生效。
  5. 在该 Plugins 页面打开 Tinyfish 卡片:选择通道(direct 或 monid),填入密钥——两个都填也行——然后点击 Save(保存)!
  6. 安装到此结束——bundle 已把两条网络链路都指向 TinyFish。若想另行选择,参见选择提供方。
  7. 问 agent 一个时效性问题;会返回实时来源。结果本身不会标明提供方——失败信息会,并会写出 tinyfish。

方法二:终端 / Profile 的 package.json

适用于无头环境、服务器或纳入版本管理的 dotfiles:

cd ~/.dsh/profiles/web
npm install dsh-tinyfish   # or: npm install @viztor/dsh-tinyfish — same thing

认准一个名字装一次。两个 tarball 打包的是同一份构建产物、读取同一份设置(提供方注册为 tinyfish,配置挂在行 id dsh-tinyfish 下,凭证共用同一对引用)——所以之后改名不丢任何东西,但两个都挂会把 bundle 加载两遍。带 scope 的 tarball 其 manifest 与补丁的 name 不同,好让 loader 在 scope 下解析它。dsh-tinyfish 是 DSH 约定用的名字,本文档也用它。

📦 改从 GitHub Packages 安装

每次发版都会把 @viztor/dsh-tinyfish 镜像到 GitHub Packages——npmjs.org 连不上时的第二来源,也是仓库侧边栏的数据来源。只有带作用域的名字会镜像:GitHub 按所有者作用域把软件包关联到仓库。与 npmjs 不同,GitHub Packages 连公开包也要认证:未认证的请求会 404,且不告诉你这个包是否存在。用带有 read:packages 权限的 token:

# project-local .npmrc is better than global for a token
@viztor:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=ghp_xxx

之后 npm install @viztor/dsh-tinyfish 就会从镜像解析。除非 npmjs 宕机,一律优先用它:不用 token,也不用额外配置。

挂载它——加进该 profile 的 package.json,然后重启 DSH:

{
  "dependencies": { "dsh-tinyfish": "^0.11.0" },
  "dsh": {
    "profile": {
      "bundles": [
        "@deepseek-ai/dsh-base",
        "@deepseek-ai/dsh-web-app",
        "dsh-tinyfish",
      ],
    },
  },
}

经 package.json 安装的 bundle 在启动时解析,所以这里要重启 DSH——只重载补丁加载不了它们。

配一把密钥——从下面的通道里选一个存好,然后问 agent 一个时效性问题(who won the last Formula 1 race?)。能返回实时来源,就证明该行已校验通过、凭证已解析;结果本身不会标明提供方,所以请到 profile 补丁里确认指向(searchProvider / fetchProvider)——或者故意触发一次失败,错误信息里会写出 tinyfish。

选择提供方

默认 bundle 会把两条网络链路都指向 TinyFish,所以全新安装不用改任何补丁就能跑。它通过设置网络 seam 的 searchProvider / fetchProvider 实现,按行 id 匹配。插件只有这一条路:dsh-web 在构造时一次性解析这两个字段,没有给提供方可“自荐”的 API。

若想另行选择,在 profile 的 cordis.patch.yml 里覆盖,它在每个 bundle 补丁之后生效,因此优先级最高:

- id: web
  config:
    searchProvider: deepseek-official
    fetchProvider: http

搜索和抓取是两个独立字段,所以搜索走 TinyFish、抓取留在官方 http 提供方可以,反过来也行。插件保持挂载、静默待命。主机也可以改设 DSH_WEB_SEARCH_PROVIDER / DSH_WEB_FETCH_PROVIDER——它们喂给同一对字段,两边都设时以配置文件为准,因此在官方 profile 上始终是基础补丁胜出。

🔑 双通道,一个插件

特性 直连 (默认) 经 Monid
背后是什么 TinyFish 官方 API 同样的 TinyFish 端点,经你的 Monid 钱包转发
需要什么 tinyfish.ai 的免费密钥 app.monid.ai 的平台密钥
最快配法 tinyfish auth login monid keys add
花费 $0 $0

默认是 direct,因为包名就叫 TinyFish——全新安装索取的正是名字里那个凭证。更想用 Monid(你的 Monid MCP 挂载可能已经有一把平台密钥)?在 profile 补丁里钉死:

- id: dsh-tinyfish
  config:
    channel: monid

两把密钥可以并存——存一个永远不会覆盖另一个,切换通道也不丢任何东西。

⚙️ 插件卡片

Plugins → Tinyfish(插件 → Tinyfish)。GUI 里能改的东西都在这里:TinyFish 是否回答搜索与抓取、通道选择、密钥、搜索排序依据和尝试次数。改动先暂存、一起保存;你输入的密钥由 harness 保管,绝不写入 profile。

两个密钥框同时摆在页面上,各自标明所鉴权的服务;Monid 框的提示里写着它的引用,Direct 框的引用则印在它下方那行说明里——于是可以在 Direct 选中时配 Monid 密钥,不用来回切换也能看清两个密钥各是否存在。

这一行只管 TinyFish 的行为,不管选中它。bundle 已经把 searchProvider/fetchProvider 指向 tinyfish,所以全新安装无需改补丁就在 Web 路径上——想用别的,就在你自己的补丁层里覆盖这两个字段。参见选择提供方。

📖 完整配置参考

全都住在同一行 dsh-tinyfish 里。该行带校验,越界值会被带着报错信息拒绝,而不是悄悄钳制。

键 默认值 含义
channel direct monid 或 direct
apiKey (未设置) 两个通道通用的字面凭证;优先用引用
apiKeyEnv TINYFISH_API_KEY direct 的凭证引用或环境变量
monidKeyEnv MONID_API_KEY monid 的凭证引用或环境变量
purpose (未设置) 随每次搜索与抓取发送的目标说明;TinyFish 据此排序;最多 2000 个字符
attempts 3 瞬时失败或搜索落空时的总尝试次数(1–5);3 即最多重试 2 次
filters.domainType (未设置) web | news | research_paper——仅补丁文件
filters.language / .location (未设置) 地域定向——仅补丁文件
filters.includeDomains / .excludeDomains (未设置) 逗号分隔——仅补丁文件
filters.recencyMinutes (未设置) 按分钟计的时效窗口(1–5256000);上游与 .afterDate 互斥——仅补丁文件
filters.afterDate (未设置) 日期下界,YYYY-MM-DD;不适用于 research_paper——仅补丁文件
filters.pubYearMin (未设置) 发表年份下界(0–9999),仅 research_paper——仅补丁文件
fetchOptions.ttl (未设置) 缓存容忍秒数;0 强制实时抓取,不设则接受任何缓存——仅补丁文件
fetchOptions.perUrlTimeoutMs (未设置) 单 URL 耗时上限,毫秒(1–110000)——仅补丁文件
fetchOptions.excludeSelectors (未设置) 提取前剔除的 CSS 选择器,逗号分隔(1–20 个 × 每个 ≤1000 字符);直接下载 PDF/CSV 时会被拒绝——仅补丁文件
monidBase / searchBase / fetchBase 上游默认 端点覆盖,给测试环境用
search / fetch true 是否提供该种类;false 不注销注册,只报告不可用

关掉一个报的是“不可用”而非“缺失”——harness 分得清这两者,只有后者意味着“安装坏了”。但“不可用”也不会悄悄 fallback:如果 searchProvider/fetchProvider 还写着 TinyFish,调用会失败。想用另一个提供方,就把对应工具指向它。

- id: dsh-tinyfish
  config:
    search: true
    fetch: false # TinyFish stays registered but unavailable for fetch; point fetchProvider elsewhere to use another fetch

Manifest 元数据,而非配置

manifest 里还带着 dsh.compatibility:显式声明的 Node 与 DSH 范围,外加每个发版的实测结论——compatible、incompatible 或 unknown——供目录核验各 DSH 版本。

**DSH 本体从不读它。**harness 里没有任何代码读 dsh.compatibility,dshReleases 映射也全无引用,所以这些字段改变不了插件的加载、注册与行为。DSH 自己的兼容机制是另一回事:loader 检查的是 peerDependencies,豁免记录在 profile 的 compatibility.json 里。这些字段的存在,是让列表页能如实写清“哪些已被验证”,这里的结论也的确是实测而非期望:0.2.0-rc.2 是本仓库每次构建与测试所跑的版本,0.2.0-rc.1 虽在 peer 范围内但从未实际跑过,0.1.7-rc.2 则低于下限。0.2.0-rc.1 以同样方式验证过(把五个 harness devDependencies 全部钉到该版本并跑门禁);0.2.1-alpha.1 记为 incompatible,因为 peer 范围并不接受它 —— semver 只在范围本身带有同一 major.minor.patch 的预发布版本时才放行预发布版,因此 loader 在该 alpha 主机上会拒绝加载本插件。

过滤器与抓取选项写在补丁文件里

filters 与 fetchOptions 是嵌套对象,而设置表单一个字段只对应一个扁平键——所以搜索与抓取调优留在运维层面:

- id: dsh-tinyfish
  config:
    channel: monid
    filters:
      domainType: research_paper
      language: zh
      includeDomains: arxiv.org,openreview.net
      pubYearMin: 2023
    fetchOptions:
      ttl: 0 # force a live fetch instead of accepting a cached page
      excludeSelectors: nav, .cookie-banner

两个分组永远有解析结果:没设就是空分组,不给请求加任何东西;不可用的成员退化为未设置,绝不发往上游。三条上游注意事项按文档行为原样透出,不做强制:

  • recencyMinutes 与 afterDate 在 TinyFish API 里互斥;一行里两个都写就两个都发。
  • excludeSelectors 对直接下载的 PDF/CSV 无效,带上它会答 selector_unsupported。
  • 上游会按 domainType 交叉核验每个日期边界:recencyMinutes 与 afterDate 不接受 research_paper,pubYearMin 只属于它,配错任一一对都会让整个搜索被拒绝。

凭证从哪里来

每次调用现解析——轮换密钥下次搜索即生效,不用重启。先命中先生效:

  1. 行里的 apiKey 字面量(写在配置里的秘密;优先用 2–3)
  2. 凭证服务——apiKeyEnv(直连)或 monidKeyEnv(Monid),从设置界面保存
  3. 启动环境(DSH 启动前 export 的)
  4. 实时环境——先读配置的引用名(apiKeyEnv / monidKeyEnv,可以是你自己的变量名),再读 MONID_API_KEY / MONID_MCP_TOKEN / TINYFISH_API_KEY(任一 Monid 变量都覆盖 monid 通道)
  5. 各通道的 CLI 存储(monid keys add / tinyfish auth login)

凭证服务挂了就落到下一个来源,而不是让搜索失败。

端点从哪里来

行配置优先,其次环境变量,最后内置默认——测试环境不用改补丁就能换向:

设置项 环境变量
monidBase TINYFISH_MONID_BASE_URL
searchBase TINYFISH_SEARCH_BASE_URL
fetchBase TINYFISH_FETCH_BASE_URL
🔍 值得了解的行为
  • **404 是结果,不是错误。**单个 URL 抓取失败会带着状态码回来,因为那是模型需要的资源状态。
  • **publishedAt 诚实。**TinyFish 报的是人类日期("Apr 30, 2026"、"1 year ago")。能解析的转成 ISO-8601,解析不了的直接丢掉,绝不编造。只有不含时刻、也不带时区的日期按 UTC 读,所以同一页面在全球报的是同一天;带时刻的值按原样解析。
  • **空搜索会重试。**上游大约三跑空一——对合法查询也可能什么都不回;在认定之前,会一直重试到用尽尝试预算(attempts,总尝试次数)。
  • **被拦的 run 是终态。**若 Monid 工作区控制拦停一次运行,错误里会写原因并附充值链接。永不重试。
  • **关闭意味着“不可用”,不是“没了”。**关掉的种类保持注册、只是谢绝。若 profile 还把对应工具钉在 Tinyfish 上,调用会大声失败,而不会悄悄改道——想用别的提供方就把工具指向它。什么都没钉时,退出的 Tinyfish 只管让路:自动选择用剩下的人选,关掉其中一种正是把“多提供方歧义”收敛到唯一候选的办法。
  • **“不可用”三种成因、一种面孔。**seam 只看到一个布尔值,所以“开关关了”“没凭证”“base URL 写错”在下游读起来一模一样。卡片分得清——去看卡片上的开关和密钥徽标,端点覆盖则在行里或环境里看。
  • **purpose 是每次请求的一句话。**seam 的请求没有目标槽位——搜索只有 {query},抓取只有 {url}——不动 harness 就不可能有按调用的目标。配置里的那句话会逐字跟随每次搜索与抓取:常驻偏置,而非按任务指令。

TinyFish 的 agent 与 browser 界面没有暴露:按量计费、走钱包,既不是搜索也不是抓取。页面真需要开浏览器时,直接用 tinyfish CLI。

🛠 开发

工具链是 Vite+:vp pack 用 tsdown 构建,vp test 跑 Vitest,vp lint / vp fmt 即 Oxlint 与 Oxfmt,且是类型感知的。Lint 与格式配置住在 vite.config.ts 里——Vite+ 会忽略独立配置文件。

pnpm install
pnpm test               # hermetic — no network, no credential
pnpm run check          # format + lint + types
pnpm run release:gate   # build, then the full gate incl. the package checks
pnpm run test:live      # the real APIs, still $0, needs credentials

需要 DSH ^0.2.0-rc.1(0.2.0-rc.1 及之后、0.3.0 之前)与 Node 24+。完整流程与不变量:AGENTS.md。参与贡献:CONTRIBUTING.md。

许可证

MIT