Files
metona-ai-desktop/docs/Agent网络工具通用设计-v2.md
T
thzxx 656c6b7af1 feat: 升级至 v0.3.4 — 接入 Xiaomi MiMo Provider + 文档全量校准
新增 MiMo (小米) LLM Provider 适配器,支持 mimo-v2.5-pro 和 mimo-v2.5 两个文本模型,复用 OpenAI 兼容 SSE 流式解析,支持 Thinking 模式和 Function Calling。同步校准全量 docs 文档与 README 使其与实际代码一致。

主要变更:
- 新增 mimo.adapter.ts 适配器(SSE + thinking.type + max_completion_tokens)
- 修复 thinking 逻辑 bug:禁用思考时未传 temperature/top_p
- 补全 sse-stream.ts 的 MiMo 缓存字段映射(prompt_tokens_details.cached_tokens)
- 补全 sse-stream.ts 的 finish_reason 映射(repetition_truncation)
- 注册 MiMo 适配器到 adapters/index.ts、main.ts 工厂
- handlers.ts 添加 mimo.contextWindow 热重载触发
- database.service.ts seed 添加 mimo 默认配置
- SettingsModal/OnboardingWizard/Header 添加 MiMo Provider UI
- constants.ts PROVIDER_LABELS 添加 mimo
- .env.example 添加 MIMO_API_KEY/MIMO_BASE_URL
- 反向修改 4 个 docs HTML 设计文档(工具数量/版本日期/适配器列表/数据库表)
- 反向修改 Agent网络工具通用设计-v2.md 附录 B 文件索引
- 完全重写 README.md(v0.3.4、27 工具、4 适配器、9 表)
2026-07-15 22:28:09 +08:00

44 KiB
Raw Blame History

Agent 网络工具通用设计(增强版)

本文档描述 Agent 网络工具链的整体设计与优化方案,涵盖 SearXNG 元搜索配置、web_search 搜索、web_fetch 抓取、browser 浏览器控制四个核心模块。文档聚焦架构、配置与接口,不绑定具体编程语言与框架实现,并给出各环节可引入的成熟第三方库建议。

目录

  1. SearXNG 配置设计
  2. web_search 搜索设计
  3. web_fetch 抓取设计
  4. browser 浏览器设计
  5. 第三方库选型指南
  6. 优化增强路线图

1. SearXNG 配置设计

1.1 架构概览

SearXNG 是开源元搜索引擎,支持 70+ 搜索引擎聚合,不追踪用户、不记录隐私。本设计将 SearXNG 作为可选替代方案:启用后通过 SearXNG 的 JSON 或 HTML API 进行搜索;关闭时回退到内置四引擎 HTML 解析方案(Bing + 百度 + 搜狗 + 360 搜索)。

整体分为三层。UI 层负责配置模态框的交互与表单同步;数据层负责通过本地数据库读写配置项,键值对形式持久化;执行层位于主进程,在搜索请求到来时读取配置,决定走 SearXNG 通道还是内置引擎通道,并完成参数拼装、认证注入、请求发送与结果解析。

┌─────────────────────────────────────────────────────┐
│                    UI 层(Renderer                   │
│  配置模态框 / 表单控件 / 状态指示                      │
├─────────────────────────────────────────────────────┤
│              数据层(SQLite / LocalStorage           │
│  键值对持久化 / 运行时缓存 / 配置校验                  │
├─────────────────────────────────────────────────────┤
│              执行层(Main Process                    │
│  参数拼装 → 认证注入 → API 调用 → 结果解析             │
│  双模式切换:SearXNG / 内置四引擎                     │
└─────────────────────────────────────────────────────┘

1.2 配置项定义

SearXNG 相关配置共 12 项,各配置项的默认值与含义如下:

配置项 类型 默认值 说明
enabled boolean false 是否启用 SearXNG
url string '' SearXNG 实例根地址(不含 /search 路径)
engines string '' 引擎列表,逗号分隔,留空则使用实例默认引擎
language string 'zh-CN' 搜索语言
safesearch number 1 安全搜索级别(0=关闭,1=中等,2=严格)
time_range string '' 时间范围过滤(day/week/month/year
max_results number 0 单次最大结果数,0 表示使用默认
auth_key string '' 认证密钥,内容随认证类型不同而不同
auth_type string 'bearer' 认证类型(bearer 或 basic
format string 'json' 返回格式(json 或 html
fetch_count number 0 自动抓取条数,0 表示由 AI 决定
fetch_mode string 'sequential' 抓取类型(sequential 顺序或 random 随机)

1.3 持久化存储

配置通过本地数据库以键值对形式持久化。写入时逐项调用 saveSetting(key, value),读取时通过 getSetting(key, default) 回填到运行时缓存。对应的存储键名汇总如下:

存储键名 对应配置项 默认值
searxng_enabled enabled false
searxng_url url ''
searxng_engines engines ''
searxng_language language 'zh-CN'
searxng_safesearch safesearch 1
searxng_time_range time_range ''
searxng_max_results max_results 0
searxng_auth_key auth_key ''
searxng_auth_type auth_type 'bearer'
searxng_format format 'json'
fetch_count fetch_count 0
fetch_mode fetch_mode 'sequential'

1.4 UI 模态框

配置界面以模态框形式呈现,包含以下交互控件。启用开关为实时保存,切换即写入数据库;其余字段在点击保存按钮时统一校验并落库。URL 字段需通过非空校验与 http/https 格式校验。

  • 启用开关:实时切换 SearXNG 启用状态,立即持久化
  • API 地址:实例根地址,必填,需为 http/https 格式
  • 搜索引擎:逗号分隔的引擎名称,留空使用实例默认
  • 语言选择:下拉项含 zh-CN / zh-TW / en / ja / ko / 自动检测
  • 安全搜索:下拉项含 0 关闭 / 1 中等 / 2 严格
  • 时间范围:下拉项含 不限 / 一天 / 一周 / 一月 / 一年
  • 结果数量:数字输入,0 表示使用默认
  • 返回格式:下拉项含 JSON 结构化解析 / HTML 原始网页
  • 自动抓取条数:数字输入,范围 18
  • 抓取类型:下拉项含 顺序抓取 / 随机抓取
  • 认证设置:认证类型(bearer / basic)+ 认证密钥(密码型输入框)
  • 保存按钮:校验后批量持久化全部字段
  • 连接测试按钮(增强):一键验证 URL 可达性与认证有效性

工具栏入口按钮上设状态指示圆点:启用时为绿色,未启用时为灰色;模态框内同时显示文字状态徽章(已启用 / 未启用)。

1.5 SearXNG 认证方式详解

SearXNG 实例可配置鉴权,本设计支持两种认证类型,由 auth_type 配置项决定,认证密钥统一存放在 auth_key 中。两种方式的核心区别在于请求头的构造方式与密钥的填写格式。

Bearer Token 认证(auth_type = 'bearer',默认值)

当认证类型为 bearer 时,系统在 HTTP 请求头中添加:

Authorization: Bearer <auth_key>

密钥原样放入 token 位置,不做任何编码转换。auth_key 应直接填写 SearXNG 实例签发的访问令牌本身。

适用场景

  • SearXNG 实例通过反向代理(如 Nginx/Caddy)签发的固定令牌鉴权
  • JWTJSON Web Token)格式的令牌
  • OAuth2 Bearer Token
  • 任何基于 Token 的简单鉴权方案

安全要求:建议配合 HTTPS 使用,防止令牌在网络传输中被截获。

Basic 认证(auth_type = 'basic'

当认证类型为 basic 时,系统将 auth_key 整体进行 Base64 编码,再在请求头中添加:

Authorization: Basic <Base64(auth_key)>

auth_key 应填写 用户名:密码 格式的明文字符串,由系统负责编码。

适用场景

  • SearXNG 实例配置了 HTTP Basic Auth 的场景
  • Nginx/Caddy 反向代理的 auth_basic 指令保护
  • 任何标准用户名密码鉴权网关

安全要求:必须配合 HTTPS 使用。Basic Auth 以 Base64 编码传输凭据(非加密),明文网络可还原。

两种方式对比

维度 Bearer Basic
请求头格式 Authorization: Bearer <token> Authorization: Basic <Base64>
密钥填写内容 令牌原值 用户名:密码 明文串
是否编码 否,原样透传 是,整体 Base64 编码
适用场景 令牌/JWT/OAuth2 鉴权 用户名密码鉴权
安全要求 建议 HTTPS 必须 HTTPS
凭据可复用性 高(无状态令牌) 低(每次携带凭据)
撤销方式 令牌失效/黑名单 修改密码

无论哪种方式,仅当 auth_key 非空时才会注入 Authorization 头;auth_key 为空则视为匿名访问,不附加任何认证信息。认证逻辑对 JSON 与 HTML 两种返回格式均生效。

1.6 主进程搜索调用流程

搜索请求到达主进程后,执行层按以下步骤处理:

  1. 读取配置:从数据库加载全部 SearXNG 相关配置项
  2. 构建参数
    • 查询词、引擎列表、语言、安全搜索级别拼入查询串
    • 时间范围优先使用调用方传入值,缺省时回退到配置项默认值
    • 最大结果数取配置项与入参的较大有效值
  3. 认证注入:根据 auth_type 构造对应的 Authorization 请求头
  4. 发送请求:向 <url>/search?<参数> 发起 HTTP GET 请求
  5. 解析结果
    • JSON 模式:结构化解析每条结果的标题、URL、摘要、来源引擎
    • HTML 模式:转为纯文本交由 AI 自行分析
  6. 统计引擎状态:记录各引擎命中条数与异常原因

1.7 双模式切换逻辑

在统一的搜索入口处,通过读取 searxng_enabled 判断走哪条通道:

  • SearXNG 启用时
    • 自动抓取条数从面板配置读取,取配置项与默认下限的较大值,限制在最大抓取上限内
    • 抓取类型为顺序或随机
    • 日志标记来源为 [SearXNG]
  • 未启用时
    • 走内置四引擎并行搜索通道
    • 日志标记来源为 [内置]

2. web_search 搜索设计

2.1 架构概览

web_search 是搜索工具的总入口,内部根据 SearXNG 开关分流到两条通道。SearXNG 通道走元搜索 API;内置通道则并行调度四个搜索引擎,经合并去重、可达性预检、智能排序、摘要增强与缓存后输出结果。无论哪条通道,最终都会进入自动抓取阶段,对前 N 条结果抓取完整内容。

web_search 入口
    ├── searxng_enabled?
    │   ├── 是 → SearXNG API 搜索
    │   └── 否 → 内置四引擎并行搜索
    │              ├── Bing (权重90)
    │              ├── 百度 (权重80)
    │              ├── 搜狗 (权重75)
    │              └── 360搜索 (权重75)
    │         → Promise.allSettled 并行容错
    │         → 合并去重(URL 标准化)
    │         → 可达性预检(并发5)
    │         → 智能排序(可达性+权重+摘要质量)
    │         → 摘要自动增强(web_fetch top3
    │         → LRU 缓存(5分钟TTL)
    └── 自动抓取前N条完整内容
        → 相关性过滤 → 逐条抓取 → 失败随机补充

2.2 函数参数

web_search 接受以下参数:

参数 类型 默认值 说明
query string 必填 搜索关键词
max_results number 30 最大结果数,上限 30
time_range string 时间过滤(day/week/month/year 等,支持中英文别名)
enhance_snippets boolean true 是否自动增强过短摘要
fetch_top number 5 自动抓取前 N 条完整内容,范围 3–8

2.3 内置四引擎并行搜索

内置通道调度四个搜索引擎,每个引擎带有权重,用于后续排序。四个引擎并行执行,采用容错并发模型,任一引擎失败不影响其余引擎。

引擎 权重 请求地址 特殊处理
Bing 90 bing.com/search 支持 freshness 参数映射时间范围
百度 80 baidu.com/s data-url 属性提取真实 URL
搜狗 75 sogou.com/web 过滤 sogou.com 自身链接
360 搜索 75 so.com/s 过滤 so.com 自身链接

时间范围参数映射规则:

用户输入 Bing 参数 说明
day / 1d / 一天 Day 最近一天
week / 1w / 一周 Week 最近一周
month / 1m / 一月 Month 最近一月

2.4 搜索引擎 HTML 解析

每个引擎返回的是 HTML 页面,需要专门的解析器从中提取标题、URL、摘要三要素。四个解析器的提取策略各有差异,但整体思路一致:先以块级结构切分结果条目,再从条目内提取标题链接与摘要文本,最后过滤掉引擎自身的导航类链接。

  • Bing 解析:按 <li class="b_algo"> 块切分,从锚点提取标题与 URL,从 <p>.b_caption 提取描述
  • 百度解析:按 <div class="result"> 块切分,标题取自 <h3 class="t"> 锚点,真实 URL 取自 data-url 属性,摘要取自 .c-abstract.content-right_*
  • 搜狗解析:按 .vrwrap.rb 块切分,摘要取自多个候选区域(.star-wiki / .space-txt / .str_info),过滤 sogou.com 自身链接
  • 360 搜索解析:按 .res-list.result 块切分,摘要取自 .res-desc / .res-rich / .res-summary / <dd>,过滤 so.com 自身链接

[增强建议] 各引擎解析器可迁移至基于 CSS 选择器的 DOM 解析方案(如 Cheerio),替代当前的正则匹配,提升鲁棒性与维护性。详见第 5 章「第三方库选型指南」。

2.5 智能排序算法

合并去重后,对结果计算综合评分并排序。评分由三部分加权构成:


\text{score} = \underbrace{\frac{\text{weight}}{100} \times 50}_{\text{引擎权重 50\%}} + \underbrace{\text{可达性加分}}_{\text{可达 +30 / 不可达 -20}} + \underbrace{\frac{\min(\text{snippetLen}, 100)}{100} \times 20}_{\text{摘要质量 20%(上限100字符)}}

最终按评分降序排列。

2.6 URL 可达性预检

为剔除死链,排序前对候选结果做可达性预检。采用并发批次控制策略:

  • 并发数:每批 5 个 URL
  • 超时:每个请求 3 秒
  • 判断标准:仅判断响应是否成功(HTTP 2xx),不读取正文
  • 结果回填:写入结果的 reachable 字段(true / false

2.7 摘要自动增强

enhance_snippets 开启时,对排序前列中摘要过短(< 30 字符)且可达的结果,调用 web_fetch 补充抓取其正文,取前 200 字符替换原摘要。该增强最多对前 3 条执行,避免过度请求。增强后的结果打上 _enhanced: true 标记。

2.8 自动抓取完整内容

搜索完成后,对前 N 条结果自动抓取完整正文,供 AI 综合分析。完整流程:

  1. 相关性过滤:从查询词中提取中文双字/三字片段与英文单词,在标题与摘要中匹配计分,得分上限 100,得分为 0 的结果直接过滤
  2. 构建抓取列表
    • sequential 模式:按相关性降序取前 N 条
    • random 模式:Fisher-Yates 洗牌后取 N 条
  3. 逐条抓取:调用 web_fetch,失败时从剩余未抓取结果中随机选 1 条补充重试
  4. 结果存入_fetched 数组 + _fetched_count 计数

2.9 LRU 搜索缓存

为降低重复查询的开销,搜索结果带 LRU 缓存。

参数
最大容量 200 条
过期时间 5 分钟(300,000ms
缓存键 查询词(归一化后)
淘汰策略 最早写入淘汰
命中时行为 校验时效,过期删除并返回未命中

[增强建议] 可替换为成熟的 lru-cache 库,支持 TTL、大小限制、统计指标等开箱能力。详见第 5 章。

2.10 响应格式

web_search 返回结构化结果,主要字段如下:

{
  "success": true,
  "query": "搜索关键词",
  "results": [
    {
      "title": "标题",
      "url": "https://...",
      "snippet": "摘要文本",
      "engine": "bing",
      "weight": 90,
      "reachable": true,
      "_score": 68.5,
      "_enhanced": false
    }
  ],
  "total": 15,
  "formatted": "人类可读文本汇总",
  "structured": [...],
  "from_cache": false,
  "engine_stats": { "bing": "8 条", "百度": "5 条" },
  "_mode": "builtin | searxng",
  "_fetched": [{ "url", "title", "content" }],
  "_fetched_count": 5
}

3. web_fetch 抓取设计

3.1 架构概览

web_fetch 采用三阶段回退策略,确保最大概率获取网页内容:

Phase 1: HTTP 抓取
├── UA 轮换池(5种)+ Accept-Language 轮换池(3种)
├── 指数退避重试(2s→4s→6s + jitter ±60%
├── 反爬请求头(Sec-Fetch-* / DNT / Referer 等)
├── 流式读取(10MB 上限)
└── 拦截检测(10 种特征模式)
    ↓ 失败/被拦截/内容过短
Phase 2: SPA 自动升级
└── HTML 内容 < 200 字符 → 升级浏览器渲染
    ↓ 失败
Phase 3: 浏览器回退
├── 打开隐藏窗口 → 等待 2.5s JS 渲染
├── 提取页面正文 → 关闭窗口
└── LRU 缓存(100 条, 10 分钟 TTL

3.2 函数参数

web_fetch 接受以下参数:

参数 类型 默认值 说明
url string 必填 目标 URL,仅支持 http/https
max_chars number 最大字符数,0 表示不截断
extract_mode string 提取模式
mobile_ua boolean 是否使用移动端 UA
retry boolean true 是否启用重试

3.3 反爬请求头

为规避基础反爬,HTTP 抓取阶段采用请求头轮换策略。

UA 轮换池(5 种):覆盖桌面 Chrome、Edge、Safari、Firefox 与移动端 Chrome,模拟主流浏览器指纹。

Accept-Language 轮换池(3 种):中英混合、中文优先、英文优先三种语言偏好。

每次重试按尝试序号取模轮换 UA 与语言,同时附带完整的反爬请求头集合:

请求头 用途
User-Agent 轮换池取模 浏览器指纹伪装
Accept text/html,application/xhtml+xml,... 声明接受内容类型
Accept-Language 轮换池取模 语言偏好伪装
Accept-Encoding gzip, deflate, br 声明压缩格式
Cache-Control no-cache 禁止缓存
DNT 1 Do Not Track
Referer 目标站点根地址 来源页伪装
Sec-Fetch-Dest document 导航目标声明
Sec-Fetch-Mode navigate 请求模式声明
Sec-Fetch-Site none 来源站点声明
Sec-Fetch-User ?1 用户触发声明
Pragma no-cache HTTP/1.0 兼容

[增强建议] 可引入 got-scraping 库,其内置了更完善的浏览器指纹模拟、Cookie Jar 管理、HTTP/2 支持与代理集成能力,详见第 5 章。

3.4 重试配置

参数
最大重试次数 3 次(Phase 1 内部)
基础退避间隔 2s → 4s → 6s
Jitter 范围 基础延迟 × [0%, +60%] 随机
直接跳过重试的状态码 403 / 503 / 429 / 502
可重试状态码 5xx(除上述外)

3.5 HTML 转文本引擎

抓取到的 HTML 需转为纯文本。处理流水线:

  1. 移除噪声标签及内容script、style、noscript、nav、header、footer、aside、iframe、svg
  2. 移除 HTML 注释
  3. 块级标签转行p、div、h1-h6、li、tr、blockquote、section、article、pre、br、hr → \n
  4. 表格单元制表符td、th → \t
  5. 移除剩余标签
  6. 解码 HTML 实体30+ 命名实体(&nbsp;&lt;&amp;&hellip;&mdash; 等)+ 全部数字实体(&#123;&#x1F;
  7. 清理空白:合并连续空白、清理首尾空行

[增强建议] 可引入 @mozilla/readability 作为前置步骤,先提取文章主体内容再做文本转换,大幅减少导航/广告/侧边栏等噪声;或使用 turndown 将 HTML 转 Markdown 保留结构。详见第 5 章。

3.6 拦截页面检测

维护一组拦截特征模式,命中任一特征即判定为拦截页,触发浏览器回退:

特征模式 对应防护
Just a moment... / Cloudflare 标题 Cloudflare JS Challenge
Attention Required! Cloudflare 托管挑战
challenge-platform Cloudflare 平台标识
.cf-challenge- 类名 Cloudflare Challenge 页面
Access Denied 标题 WAF 拒绝
403 Forbidden 标题 HTTP 403 拦截
请启用 JavaScript JS 强制检测
Please enable JavaScript JS 强制检测(英文)
Checking your browser 浏览器环境检测
DDoS protection DDoS 防护页
正文长度 < 80 字符 空白/空壳页面

3.7 内容过短自动升级

对于成功返回但正文过短(< 200 字符)的页面——通常是 SPA 单页应用或空壳页面,其有效内容依赖 JS 渲染——自动升级到浏览器渲染通道。若渲染成功则用渲染结果替换,方法标记为 browser

3.8 浏览器回退实现

浏览器回退通道的完整流程:

  1. 查缓存:LRU 缓存(100 条,10 分钟 TTL),命中则截断返回
  2. 打开窗口:隐藏 BrowserWindow 加载目标 URL
  3. 等待渲染:2.5秒让 SPA/动态内容完成 JS 渲染
  4. 提取正文:移除非内容标签后取 innerText
  5. 关闭窗口:确保资源释放
  6. 写缓存:正文 ≥ 100 字符时写入缓存

异常保障:任何步骤出错均确保调用关闭函数,避免窗口泄漏。

3.9 触发浏览器回退的条件

条件 说明 Phase 1 → Phase 3
HTTP 403/503/429/502 反爬/限流/拦截信号 直接跳转
拦截特征匹配 Cloudflare/验证码/JS 要求等 直接跳转
内容 < 200 字符 SPA 或空壳页面 经 Phase 2 升级
请求超时 超过 HTTP 超时阈值 直接跳转
所有重试均失败 网络不可达等 直接跳转

3.10 流式读取与大文件保护

参数
硬上限 10 MB
无 Content-Length 时 流式读取,累计字节数
超限处理 中止下载,返回错误
有 Content-Length 时 预判是否超限

3.11 超时封装

HTTP 抓取通过带超时的封装发起请求:创建 AbortController,设定超时定时器,超时即中止请求。该封装同时被搜索阶段的可达性预检复用。


4. browser 浏览器设计

4.1 架构概览

browser 模块基于隐藏浏览器窗口实现,提供完整的网页加载、截图、JS 执行、内容提取与交互操作能力。整个模块封装为单例窗口,包含 9 个核心函数。

函数 职责 关键参数
browserOpen 打开 URL url, waitSelector
browserScreenshot 截图 fullPage, selector(视口/元素/全页三模式)
browserEvaluate 执行 JS js(任意代码)
browserExtract 提取内容 selector, maxChars
browserClick 点击元素 selector, wait
browserType 输入文本 selector, text, clear, submit
browserScroll 滚动页面 direction, selector
browserWait 等待条件 selector, timeMs
browserClose 关闭窗口

窗口默认参数1280×800、不可见(show:false)、上下文隔离、沙箱模式、页面加载超时 30s。

4.2 核心状态管理

维度 设计决策
实例模式 单例懒加载,首次调用时创建
销毁方式 browserClose() 显式销毁
应用退出 统一调用 browserClose() 清理
就绪检查 操作前校验窗口存在且已加载页面
安全配置 禁用 Node.js 集成、上下文隔离、沙箱、允许跨域(截图需要)

4.3 打开 URL

  • 若已有窗口加载了不同 URL → 先关闭重建,避免历史状态干扰
  • 加载目标 URL30 秒超时
  • 可选等待指定 CSS 选择器出现(轮询 300ms,最长 10s)
  • 返回页面标题与实际 URL

4.4 截图

三种模式:

模式 触发条件 输出
元素截图 指定 selector 该元素矩形区域 PNGBase64
全页截图 fullPage=true 完整滚动尺寸 PNGBase64
视口截图 默认 当前可见区域 PNGBase64

4.5 执行 JavaScript

接收任意 JS 在页面上下文中执行。字符串原样返回,其余类型序列化为格式化 JSON。独立超时控制。

4.6 提取页面内容

  • 克隆目标根节点,移除 script/style/iframe/svg 后取 innerText
  • 支持 CSS 选择器限定提取区域
  • 默认上限 15000 字符
  • 同时提取最多 50 个有效链接(http 开头 + 有可见文本)

4.7 点击元素

可选等待元素出现 → 滚动到视口中央 → 触发点击 → 等待 500ms。元素不存在则报错。

4.8 输入文本

聚焦 → clear 决定清空/追加 → 赋值 → 触发 input + change 事件(兼容 React/Vue)→ submit 决定是否提交(form.submit 或 Enter 键)。输入后等 300ms(提交等 1000ms)。

4.9 滚动页面

  • 指定 selector → scrollIntoView 到中央
  • 方向滚动:down(+500px) / up(-500px) / top(回顶) / bottom(到底)

4.10 等待条件

  • 选择器等待:轮询 300ms,默认 10s(可由 timeMs 覆盖)
  • 定时等待:按 timeMs 固定延迟,默认 1s

4.11 关闭浏览器

销毁单例窗口并置空引用。幂等操作——窗口已销毁时为空操作。

4.12 工具调度映射

所有 browser 函数通过统一工具执行通道调度:

调用名 映射函数 入参
browser_open browserOpen url, wait_selector
browser_screenshot browserScreenshot full_page, selector
browser_evaluate browserEvaluate js
browser_extract browserExtract selector, max_chars
browser_click browserClick selector, wait
browser_type browserType selector, text, clear, submit
browser_scroll browserScroll direction, selector
browser_wait browserWait selector, time_ms
browser_close browserClose

4.13 浏览器与 web_fetch 的协作关系

web_fetch 三阶段回退:
  Phase 1 (HTTP) 失败
    ├─ 403/503/429/502? → browserFallback(url)
    ├─ Cloudflare 拦截?   → browserFallback(url)
    ├─ 内容 < 200 字符?   → browserFallback(url) [经 Phase 2]
    ├─ 超时?              → browserFallback(url)
    └─ 所有重试失败?       → browserFallback(url)

browserFallback:
  browserOpen(url) → 等待 2.5s → browserExtract() → browserClose()
  结果进入 LRU 缓存 (100条, 10分钟TTL)

4.14 超时配置汇总

工具 默认超时 最大超时 说明
web_search 3,000ms/引擎 300,000ms 每引擎独立超时
web_fetch 20,000ms 600,000ms HTTP 抓取超时
browser_extract 10,000ms 300,000ms 页面提取超时
browser_evaluate 8,000ms JS 执行超时
browser_screenshot 60,000ms 截图超时
browser_open 30,000ms 页面加载超时

5. 第三方库选型指南

本章针对工具链各环节,给出经过筛选的成熟第三方库推荐,涵盖 HTTP 客户端、HTML 解析、文章提取、浏览器反检测、缓存、URL 处理等领域。所有推荐库均为 npm 生态中活跃维护、广泛使用的项目。

5.1 HTTP 客户端层

当前实现使用原生 fetch + 手动请求头构造。以下库可在对应层面提供增强:

got-scraping 重点推荐)

维度 详情
包名 got-scraping
定位 专为网页抓取设计的 HTTP 客户端,基于 got 封装
核心优势 内置浏览器指纹轮换、Cookie Jar 自动管理、HTTP/2 支持、代理集成、流式处理
指纹模拟 自动轮换 Header Order、TLS 指纹、HTTP/2 SETTINGS 帧,比手动构造请求头更难被识别
代理支持 原生支持 HTTP/SOCKS5 代理,可配置代理轮换
Cookie 管理 自动 Cookie Jar,跨请求保持会话状态
重试机制 内置指数退避重试,可自定义重试条件
适用环节 替代 web_fetch Phase 1 的原生 fetch,显著降低被反爬识别的概率
替代方案 axios(通用 HTTP 客户端)、undiciNode.js 原生 HTTP/1.1 客户端)

为什么选 got-scraping 而非 axios/got

axios 是通用 HTTP 客户端,不具备抓取专用能力;got 是底层 HTTP 库,功能强大但需自行组装抓取特性;got-scrapinggot 之上专门为抓取场景做了封装,开箱即用的指纹模拟、Cookie 管理与代理支持正好覆盖 web_fetch Phase 1 的全部需求。

axios(备选)

维度 详情
包名 axios
定位 最流行的 Node.js/Browser 通用 HTTP 客户端
核心优势 拦截器机制、请求/响应转换、取消令牌、CSRF 保护、JSON 自动处理
周边生态 axios-retry(自动重试)、cache-interceptor(缓存拦截器)
适用环节 如不需要抓取专用特性而偏向通用性,可作为基础 HTTP 层
注意事项 不自带指纹模拟,需手动构造请求头;2025 年曾发生供应链攻击事件,锁定版本

5.2 HTML 解析层

当前实现使用正则表达式解析搜索引擎 HTML 结果。以下库可提供更健壮的 DOM 级解析能力:

cheerio 重点推荐)

维度 详情
包名 cheerio
定位 服务端 jQuery 核心子集实现,轻量快速 DOM 解析
核心优势 jQuery 风格 API$('.b_algo'))、极快速度(约比 jsdom 快 8 倍)、零依赖、API 熟悉度高
适用环节 替代四引擎解析器中的正则匹配,改用 CSS 选择器精确提取标题/URL/摘要
示例场景 $('li.b_algo').each((i, el) => { const $el = $(el); ... })
版本注意 Cheerio v1(最新版)API 有变化,需参考新版文档

jsdom(特定场景备选)

维度 详情
包名 jsdom
定位 纯 JavaScript 实现的完整 DOM 环境
核心优势 完整 DOM APIquerySelector/getComputedStyle 等)、脚本执行、兼容依赖 DOM 的库
适用环节 需要 DOM 兼容性的复杂解析场景(如运行依赖 DOM 的第三方提取脚本)
权衡 比 cheerio 慢且重量大,一般场景 cheerio 已足够

parse5(底层备选)

维度 详情
包名 parse5
定位 WHATWG HTML Living Standard 合规的 HTML 解析/序列化工具集
核心优势 严格符合 HTML5 规范、可处理畸形 HTML、提供 serialize 功能
适用环节 需要规范合规 HTML 解析的底层场景;或作为 cheerio/jsdom 的底层解析引擎

5.3 文章内容提取层

当前 htmlToText 函数做简单的标签移除与文本提取。以下库可大幅提升文章类页面的提取质量:

@mozilla/readability 重点推荐)

维度 详情
包名 @mozilla/readability
定位 Mozilla Firefox Reader View 的算法移植,自动提取文章主体内容
核心优势 基于 Mozilla 成熟算法,自动识别文章正文区、剥离导航/广告/评论/侧边栏噪声
输入要求 需配合 jsdom 提供 DOM 环境
输出 { title, content, textContent, length }
适用环节 web_fetch 抓取后作为 htmlToText 的前置步骤:先 readability 提取主体,再转文本
效果预期 对新闻/博客/百科/论坛帖子类页面效果极佳,可直接替代手动噪声标签列表
依赖 需搭配 jsdom 使用
同类项目 node-readability(封装了 request + @mozilla/readability 的老项目,已不太活跃)
注意事项 对非文章类页面(如搜索结果页、列表页、数据仪表盘)可能误提取或返回空

turndownHTML → Markdown

维度 详情
包名 turndown
定位 HTML 到 Markdown 的转换器
核心优势 保留文档结构(标题层级、表格、列表、代码块、链接),输出格式友好
适用环节 当需要保留 HTML 结构而非纯文本时,作为 htmlToText 的替代或补充
使用方式 TurndownService().turndown(htmlString) → Markdown 文本

5.4 浏览器反检测层

当前 browser 模块使用 Electron 原生 BrowserWindow,无额外反检测措施。以下插件可显著降低被网站识别为自动化脚本的概率:

puppeteer-extra-plugin-stealth 重点推荐)

维度 详情
包名 puppeteer-extra-plugin-stealth
定位 Puppeteer 反检测插件,隐藏无头浏览器自动化痕迹
核心优势 18 种独立的反检测技术模块,系统性覆盖所有主要检测维度
检测维度覆盖 见下方详细列表
架构设计 微内核 + 插件化,每种技术封装为独立模块,可单独启停
依赖关系 需配合 puppeteer-extra 使用
适用环节 browser 模块的 BrowserWindow 创建时注入 stealth 脚本,或在 browser 回退通道中使用 puppeteer-extra 替代原生 BrowserWindow

18 种反检测技术模块清单

# 模块名 解决的检测点
1 navigator.webdriver 移除 webdriver=true 标志
2 chrome.runtime 模拟 chrome.runtime 对象
3 chrome.loadTimes 模拟已废弃但仍被检测的 API
4 chrome.csi 模拟 Chrome CSI 对象
5 iframe.contentWindow 修复 iframe contentWindow 检测
6 media.codecs 补全媒体编解码器支持列表
7 navigator.plugins 模拟浏览器插件信息
8 navigator.languages 修正语言设置
9 navigator.platform 修正平台标识
10 navigator.hardwareConcurrency 模拟真实的 CPU 核心数
11 webgl.vendor 伪装 WebGL 渲染厂商/型号
12 window.outerdimensions 修正窗口尺寸关系
13 sourceurl 移除源码 URL 泄露
14 user-agent-override 同步 navigator.userAgent 与请求头
15 permissions 修正 Permissions API 行为
16 runtime.enable 修复 chrome.runtime.enable
17 eof 修复 EOF 检测
18 preload 修复脚本 preload 检测

集成建议:由于本项目基于 Electron(非独立 Puppeteer),有两种集成路径:(A) 将 stealth 插件的各模块 JS 脚本提取出来,通过 webContents.executeJavaScript 在 BrowserWindow 加载时注入;(B) 在 browser 回退通道中使用 puppeteer-extra + stealth 替代原生 BrowserWindow。路径 A 更轻量,路径 B 更彻底。

5.5 缓存层

当前使用手写 Map 实现 LRU 缓存。以下库提供更完善的能力:

lru-cache 推荐)

维度 详情
包名 lru-cache
定位 高性能 LRU 缓存实现,支持 TTL、大小限制、统计
核心优势 TTL 自动过期、 maxSize 按 count 或 byte 限制、hit/miss/stale 统计、异步 dispose 回调
适用环节 替代搜索缓存(200 条/5min)和浏览器回退缓存(100 条/10min)的手写实现
API 示例 new LRUMax({ max: 200, ttl: 300_000 })

cacheable(备选)

维度 详情
包名 cacheable
定位 支持多后端(内存/Redis/文件)的统一缓存抽象
核心优势 可无缝切换存储后端,适合未来分布式部署需求
适用环节 如果未来需要跨进程共享缓存(如主进程 + 多个渲染进程)

5.6 URL 处理层

当前 URL 去重依赖简单标准化。以下库可提供更强的 URL 归一化能力:

normalize-url(推荐)

维度 详情
包名 normalize-url
定位 URL 归一化工具
核心优势 自动去除追踪参数(utm_*)、统一协议/路径/查询串/片段格式、强制小写、去除默认端口
适用环节 搜索结果合并去重阶段的 URL 标准化,减少因 URL 变体导致的重复结果

5.7 SearXNG 客户端层

当前 SearXNG 调用通过手动拼接 URL 参数 + fetch 发送。以下方案可考虑:

手动封装(当前方案,合理)

SearXNG API 本身非常简单(GET /search?q=...&format=json),手动拼接完全够用。不建议引入额外的客户端库增加复杂度。如未来需要更多功能(如实例健康检查、引擎状态查询),可考虑封装一个轻量内部模块即可。

5.8 库选型总览

环节 当前方案 推荐替代 核心收益 引入成本
HTTP 抓取 原生 fetch + 手动请求头 got-scraping 指纹模拟、Cookie管理、HTTP/2、代理 中(替换 fetch 调用)
HTML 解析(搜索引擎) 正则匹配 cheerio CSS选择器、DOM遍历、鲁棒性 中(重写4个解析器)
文章内容提取 标签移除 + 纯文本 @mozilla/readability 自动识别正文、剥离噪声 中(需jsdom依赖)
HTML → 结构化文本 自定义 htmlToText turndown(可选) 保留Markdown结构 低(新增转换通道)
浏览器反检测 puppeteer-extra-plugin-stealth 18种反检测、绕过Cloudflare 高(需适配Electron
缓存 手写 Map LRU lru-cache TTL、统计、dispose回调 低(替换数据结构)
URL 归一化 简单标准化 normalize-url 去追踪参数、统一格式 低(替换标准化函数)

6. 优化增强路线图

本章按优先级排列可执行的优化项,每项标注预期收益、复杂度与依赖关系。

6.1 P0 — 高优先级(立即可做)

6.1.1 引入 lru-cache 替换手写缓存

  • 改动范围:搜索缓存 + 浏览器回退缓存
  • 工作量:小(约 2-3 小时)
  • 收益:消除手写 LRU 的边界 bug 风险,获得 TTL 精确过期与统计指标
  • 依赖:安装 lru-cache

6.1.2 引入 cheerio 重写四引擎解析器

  • 改动范围Bing/百度/搜狗/360 四个 HTML 解析函数
  • 工作量:中(约 1-2 天)
  • 收益:正则 → CSS 选择器,解析鲁棒性大幅提升,应对搜索引擎 HTML 变更的成本降低
  • 依赖:安装 cheerio

6.1.3 引入 normalize-url 强化去重

  • 改动范围:搜索结果合并去重的 URL 标准化步骤
  • 工作量:小(约 1-2 小时)
  • 收益:减少因 utm_* 参数、尾部斜杠、协议差异导致的重复结果
  • 依赖:安装 normalize-url

6.2 P1 — 中优先级(短期规划)

6.2.1 引入 got-scraping 替换 web_fetch Phase 1

  • 改动范围web_fetch 的 HTTP 抓取阶段
  • 工作量:中(约 2-3 天)
  • 收益:内置指纹轮换、Cookie Jar、HTTP/2、代理支持,被反爬识别概率显著降低
  • 风险got-scraping 基于 got,需确认与 Electron 进程的兼容性;必要时可用 got 核心自行封装
  • 依赖:安装 got-scraping

6.2.2 引入 @mozilla/readability 提升文章提取质量

  • 改动范围web_fetch 的 HTML 转文本流程,新增 readability 前置步骤
  • 工作量:中(约 1-2 天)
  • 收益:新闻/博客/百科类页面的提取质量质的飞跃,噪声自动剥离
  • 注意事项:需处理非文章页面的 fallbackreadability 返回空时回退到原有 htmlToText)
  • 依赖:安装 @mozilla/readability + jsdom

6.2.3 UI 增加「连接测试」按钮

  • 改动范围SearXNG 配置模态框
  • 工作量:小(约 半天)
  • 收益:用户保存配置前可一键验证 URL 可达性与认证有效性,降低配置错误率
  • 实现要点:向 ${url}/search?q=test&format=json 发送带认证头的测试请求,展示响应状态与耗时

6.3 P2 — 中低优先级(中期规划)

6.3.1 集成 stealth 反检测

  • 改动范围browser 模块的 BrowserWindow 创建 / browser 回退通道
  • 工作量:大(约 3-5 天)
  • 收益:绕过 Cloudflare 等反爬检测的概率大幅提升,减少浏览器回退触发频率
  • 推荐路径:提取 stealth 插件的 JS 脚本,通过 webContents.executeJavaScript 注入 BrowserWindow
  • 依赖:分析 puppeteer-extra-plugin-stealth 源码,提取各 evasions 模块

6.3.2 引入 turndown 新增 Markdown 输出模式

  • 改动范围web_fetch / browserExtract 的内容输出
  • 工作量:小(约 1 天)
  • 收益:AI 收到的网页内容保留结构(标题层级、表格、列表、代码块),提升理解质量
  • 实现要点:新增 format: 'markdown' 参数选项,默认保持现有纯文本行为不变

6.3.3 代理支持

  • 改动范围web_fetch HTTP 抓取阶段 + SearXNG 调用
  • 工作量:中(约 2-3 天)
  • 收益:企业网络环境下可通过代理访问外网;高频抓取时可轮换 IP 降低封禁风险
  • 实现要点:配置项新增 proxy_url / proxy_listgot-scraping 原生支持代理

6.4 P3 — 低优先级(长期规划)

6.4.1 分布式缓存后端

  • 前提P0 缓存改造完成
  • 方向:使用 cacheable 或类似方案,支持 Redis / SQLite / 文件后端
  • 收益:多实例部署时缓存共享,避免重复抓取

6.4.2 搜索引擎解析器热更新

  • 方向:将四引擎解析规则外部化为配置文件或脚本,支持不重启生效
  • 收益:搜索引擎 HTML 结构变更时无需发版,运维可快速响应

6.4.3 抓取速率自适应限速

  • 方向:根据目标站点的响应时间与错误率动态调整请求间隔
  • 收益:尊重目标站点,减少被封禁概率,体现负责任的抓取行为

附录 A:工具联动模式

四种模块在实际任务中的典型协作流程:

标准搜索流程

web_search(query) → 分析结果 → web_fetch(topN URLs) → 综合回答

浏览器交互流程

browser_open(url) → browser_wait(selector) → browser_extract()
→ browser_screenshot() → browser_click() / browser_type() → browser_close()

自动降级流程

web_fetch(url) → [HTTP失败] → browser_open(url) → browser_extract() → browser_close()

SearXNG + 自动抓取流程

web_search(query) → [SearXNG模式] → JSON结果 → 相关性过滤
→ applyAutoFetch(topN) → 逐条web_fetch() → 带全文的回答

附录 B:关键文件索引(原始实现参考)

文件 说明
electron/harness/tools/built-in/browser.ts 浏览器控制核心(9 个 action 路由)
electron/harness/tools/built-in/browser-window-manager.ts 浏览器窗口状态管理 + 页面操作(单例 + 隔离会话)
electron/harness/tools/built-in/web-search.ts web_search 工具(SearXNG / 内置四引擎双模式)
electron/harness/tools/built-in/web-fetch.ts web_fetch 工具(三阶段回退抓取)
electron/harness/tools/built-in/network-utils.ts 网络工具函数(LRU 缓存、UA 轮换、反爬请求头、拦截检测、HTML 转文本、SearXNG 认证)
electron/harness/tools/built-in/http-request.ts HTTP/REST API 请求工具
electron/harness/tools/built-in/file-guard.ts 文件保护(工作空间边界 + MEMORY.md 保护)
electron/harness/tools/registry.ts 工具注册表 + PolicyEngine 策略引擎 + truncateResult
electron/harness/sandbox/permissions.ts PolicyEngine(三级权限 + 频率限制 + 通配符策略)
electron/harness/agent-loop/engine.ts Agent Loop 引擎(ReAct 状态机 + 工具超时配置)
electron/ipc/handlers.ts IPC 通道处理(50+ 通道,含 searxng:testConnection
electron/main.ts 应用生命周期(启动流程 + browserClose on quit
src/components/settings/SettingsModal.tsx 设置面板(含 SearXNG 配置 Tab
src/stores/agent-store.ts Agent 状态管理(Zustand
src/hooks/useAgentStream.ts 流式事件监听 Hook

附录 C:第三方库速查表

库名 版本建议 npm 周下载量级 许可证 引入优先级
got-scraping 最新稳定版 ~500K+/周 MIT P1
cheerio v1.x ~10M+/周 MIT P0
@mozilla/readability 最新版 ~2M+/周 Apache-2.0 P1
jsdom 最新版 ~5M+/周 MIT P1readability 依赖)
turndown v7.x ~2M+/周 MIT P2
puppeteer-extra-plugin-stealth 最新版 ~500K+/周 MIT P2
puppeteer-extra 最新版 ~1M+/周 MIT P2stealth 依赖)
lru-cache v10.x ~20M+/周 ISC P0
normalize-url 最新版 ~5M+/周 MIT P0
axios ^1.7.x(锁定安全版本) ~30M+/周 MIT 备选