Leon 开源个人助理中的 Tiny Web Crawler 技能:有界网页抓取与证据驱动的信息检索实战指南
发布时间:2026/10/1 16:57:46来源:尧图网络
人工智能AI Agent交互助手本地部署大模型工具调用AI 技能【免费下载链接】leon Leon is your open-source personal assistant.项目地址https://gitcode.com/gh_mirrors/le/leon点击查看免费下载导读本文围绕 Leon 开源个人助理GitHub 加速计划镜像gh_mirrors/le/leon内置的tiny-web-crawlerAgent 技能展开系统讲解它如何从一个或多个起始 URL 出发抓取网页、抽取可读文本、在页面内搜索关键词并沿相关链接有界爬取直到命中目标信息或到达资源上限。读完本文你将掌握crawl-web.mjs与fetch-page.mjs两个脚本的全部命令行参数与默认限制、渐进式抓取的内部实现、链接打分与提前停止机制以及如何遵循证据规则和输出规范让 Leon 在真实问答中给出可追溯、可验证的答案。一、技能定位Agent Skill 在 Leon 中的角色Leon 将技能分为两类原生技能Native Skill位于skills/native/skill/通过skill.jsonlocales/ action 入口实现具体动作和 Agent 技能Agent Skill位于skills/agent/skill/SKILL.md。根据 AGENTS.md 的定义Agent 技能由三部分组成发现前置元数据discovery frontmatter供服务器发现与加载简洁的工作流指令指导 Leon 已有的 Agent 主循环如何调用工具可选的支撑脚本放在scripts/目录承担实际的执行逻辑。tiny-web-crawler正是这份约定中明确点名的参照范例Followtiny-web-crawler它的定位是引导 Leon 的现有 Agent 循环和工具调用而不是重新实现一套独立的 Agent 循环。因此它的目录结构非常紧凑skills/agent/tiny-web-crawler/ ├── SKILL.md # 技能指令与工作流 └── scripts/ ├── fetch-page.mjs # 单页抓取 └── crawl-web.mjs # 有界多页爬取SKILL.md的 frontmatter 声明了技能的元数据name: tiny-web-crawlerdescription一句话概括其能力边界——从一个或多个起始页面开始爬取获取可读内容在页面内搜索跟进相关链接在找到所需信息或达到有界上限时停止版本1.0.0作者为 Leon 的创建者 Louis Grenard。这段description会被服务器端读取用于技能发现与意图匹配。前端元数据如何被服务器解析从源码结构看服务器通过 skill-domain-helper.ts 中定义的AGENT_SKILL_FILENAME SKILL.md常量来定位 Agent 技能文档并解析其 frontmatterparseAgentSkillFrontmatter见 skill-domain-helper.ts它会校验首行必须是---边界符提取name与description字段并对 name 应用模式与长度校验、对 description 应用非空与最大长度校验。这意味着技能文档的 frontmatter 质量直接决定技能能否被 Leon 正确识别和按语义触发。二、两个脚本的分工与运行方式技能文档明确要求使用捆绑脚本完成实际抓取二者分工互补脚本用途适用场景scripts/fetch-page.mjs抓取单个页面抽取紧凑可读文本、链接与查询片段单页检视对某个有希望的页面做深入检查scripts/crawl-web.mjs从一个或多个起始 URL 出发跟进相关链接在限制内或命中强匹配时停止需要跨多页寻找目标信息的有界爬取使用 node 运行与运行时 shim两个脚本均以#!/usr/bin/env node开头通过node执行。技能文档特别说明Leon 的 shell 工具会注入运行时 shim因此这里的node在可用时会解析到 Leon 托管的 Node.js 二进制只有当托管二进制缺失时才回退到PATH中的系统 node。文档同时提醒不要手工拼接$LEON_HOME/bin/node/...或/bin/node/...路径——路径解析由 Leon 运行时统一处理手工拼接会破坏版本隔离。基本调用示例直接照搬技能文档并可用node scripts/crawl-web.mjs --url https://example.com --query target phrase --max-pages 8 --max-depth 2脚本输出均为 JSON直接打印到 stdout方便 Agent 或 LLM 解析后续处理。三、crawl-web.mjs有界多页爬取的完整实现crawl-web.mjs是整个技能的执行引擎。它内置两个硬性前置校验源码 crawl-web.mjs--url/--urls与--query必须同时提供缺一即报错——错误信息甚至明确提示先用网页搜索再把有希望的 URL 传进来说明该技能设计为与 Leon 的搜索工具链配合使用而非自建搜索入口。命令行参数总览参数默认值说明--url url/--start-url url无可重复传入单个起始 URL可多次出现--urls u1,u2,...无逗号分隔的多个起始 URL自动 trim 并过滤空值--query phrase无必填目标查询短语用于页面打分、链接筛选与片段提取--max-pages n8最多抓取页数--max-depth n2从起始页算起允许跟进的最大链接深度--same-domain-limit n5同一域名最多抓取页数--max-search-queries n3最大搜索查询数保留在输出 limits 中参数解析逻辑见 crawl-web.mjs所有数值型参数通过Number()转换非法值不会导致崩溃。内部抓取流程优先级队列 链接打分核心循环源码 crawl-web.mjs是一个按链接相关度排序的 BFS 优先队列关键机制如下入队与排序每个待抓取项携带depth、来源页via、链接文本linkText和linkScore每次循环前队列按linkScore降序排序保证最相关的链接优先被抓取。去重与域名配额visited集合记录已访问 URLURL 会去掉 hash 片段后归一化perDomainCounts按 hostname 计数超过sameDomainLimit的域名直接跳过防止单个站点耗尽预算。链接打分scoreLink源码 crawl-web.mjs查询短语先被分词按非字母数字切分、过滤长度小于 2 的词元然后链接的url text命中任一词元4 分链接的上下文文本context即链接前后约 800 字符命中1 分与当前来源页同域名且已有得分额外 2 分鼓励站内权威页优先。提前停止shouldStopEarly源码 crawl-web.mjs当页面请求成功、存在 snippets、页面score 8常量STRONG_MATCH_SCORE并且已达到最大深度或当前页没有更相关的链接可跟进时立即终止爬取——这对应技能文档找到强匹配就尽早停下优于广撒网的设计原则。停止原因循环结束时stopReason取三值之一——limit_reached达到页数上限、strong_match_found命中强匹配提前停止、queue_exhausted队列自然耗尽。输出结构crawl-web.mjs的输出 JSON 包含{ query: target phrase, limits: { maxPages: 8, maxDepth: 2, sameDomainLimit: 5, maxSearchQueries: 3 }, stopReason: strong_match_found, pagesChecked: 4, pages: [ { url: ..., status: 200, ok: true, title: ..., depth: 0, via: null, linkText: , score: 9, textLength: 12345, chunk: { offset: 0, chars: 6000, hasMore: true, nextOffset: 6000 }, rawTruncated: false, snippets: [...], error: null } ], matches: [ /* 仅包含有 snippets 命中的页面摘要 */ ] }pages数组记录每个访问页的摘要标题、状态、深度、来源、得分、文本长度、片段、是否截断matches只收录有查询片段命中的页面方便 Agent 直接聚焦候选答案页。每次抓取实际是通过spawnSync以 summary 模式调用fetch-page.mjs默认--max-text-chars 6000、--max-links 150见 crawl-web.mjs因此二者输出口径一致。四、fetch-page.mjs单页抓取与渐进式读取fetch-page.mjs负责单页的抓取、清洗与结构化输出是crawl-web.mjs的底层单元也可独立用于单页检视。命令行参数总览参数默认值说明--url url无必填目标页面 URL缺失时直接抛错Missing --url--query phrase空用于片段提取与打分不传则snippets为空数组、score为 0--mode summary\|fullsummaryfull时结果始终携带完整text字段--include-text boolfalse为true时返回完整文本text否则只返回textPreview--offset n0从文本第 n 个字符处开始切片用于分段读取长文--timeout-ms n15000请求超时毫秒数--max-raw-chars n500000原始 HTML 最大读取字符数流式读取超出即截断并置rawTruncated--max-text-chars n8000可读文本单次最大返回字符数--max-links n150最多抽取链接数参数解析与默认值定义见 fetch-page.mjs 与 fetch-page.mjs。所有数值参数经getPositiveInteger校验非法值回退到默认值。页面抓取与内容清洗管线请求阶段源码 fetch-page.mjs使用AbortController实现超时中断fetch时redirect: follow跟随重定向最终 URL 以响应后的实际地址为准携带固定USER_AGENT现代 Chrome 桌面 UA见 fetch-page.mjs与accept头提升页面兼容性原始响应体通过流式读取达到maxRawChars即截断并await reader.cancel()避免超大页面耗尽内存。清洗阶段源码 fetch-page.mjs先剥离噪声块标签script、style、noscript、svg、canvas、iframe、form、select、button、nav、footer、asideREMOVED_BLOCK_TAGS——导航、页脚、表单等非正文内容被整体移除再移除 HTML 注释将p/div/section/article/header/footer/main/li/tr/h1-h6等块级结束标签替换为换行保留段落结构随后剥掉剩余标签最后做 HTML 实体解码nbsp;、amp;、quot;、#39;、lt;、gt;、十进制/十六进制字符引用并归一化空白。内容类型判断通过content-type头或正文中是否出现html、body、a特征来判定 HTML非 HTML如纯文本、JSON则按原文本直接归一化处理。渐进式抓取机制Progressive Fetching这是技能文档强调的核心特性——默认只返回紧凑输出按需再取全文textPreview可读文本前 1500 字符DEFAULT_TEXT_PREVIEW_CHARS的短预览snippets查询词元在文本中的命中片段每个词元取命中位置前后各 180 字符去重后最多 8 条源码 fetch-page.mjslinks归一化后的链接列表去掉 hash、只保留 http/https、按 URL 去重合并文本与上下文每条包含url、text≤180 字符、context≤600 字符链接前后各约 800 字符的周边文本chunk.hasMore/chunk.nextOffset指示当前文本切片是否已读完、下一段从哪个字符偏移继续。对应技能文档中的深查用法node scripts/fetch-page.mjs --url https://example.com/docs --query key phrase \ --include-text --offset 8000 --max-text-chars 8000当预览、标题或链接表明某页高度相关时才用--include-text --offset n --max-text-chars n逐段读取全文避免一次性消耗过多 token。输出 JSON 结构{ ok: true, status: 200, url: https://example.com/, contentType: text/html, title: Example Domain, mode: summary, rawTruncated: false, textLength: 1200, chunk: { offset: 0, chars: 1200, hasMore: false, nextOffset: null }, score: 2, snippets: [...], links: [ { url: ..., text: ..., context: ... } ], textPreview: ... }抓取失败时输出{ ok: false, error: 错误信息 }并设置退出码 1源码 fetch-page.mjs。五、默认限制资源有界原则技能文档明确给出默认限制除非用户另行指定限制项默认值对应参数最大抓取页数8--max-pages从起始页起最大链接深度2--max-depth同一域名最多页数5--same-domain-limit技能文档的指导原则是倾向提前停止而非广泛爬取Prefer stopping early over crawling broadly。这套有界设计在源码中体现为三重保险页数上限pages.length maxPages、域名配额perDomainCounts和强匹配提前退出shouldStopEarly。当达到上限仍未找到答案时Agent 应如实汇报已检查的内容与未解决的疑点而不是无限制扩大爬取范围。六、技能工作流九步标准化流程SKILL.md给出了 Agent 执行时的完整工作流整理如下澄清目标仅当请求的信息或起始点存在歧义时才向用户澄清目标尊重用户起点用户提供了 URL 时从该 URL 开始主流程使用scripts/crawl-web.mjs抓取页面、在内容中搜索、跟进相关链接单页深查对某个有希望的页面使用scripts/fetch-page.mjs做一次性或深入检视渐进读取先做紧凑抓取预览、片段、链接仅当片段/标题/链接显示页面可能相关时再读取完整或后续文本块页内精确检索在已抓取内容中搜索确切的名称、短语、日期、数字、标题或邻近同义词访问去重记录已访问 URL不重复访问同一页面及时收尾一旦找到带足够上下文的目标信息立即停止如实汇报若到达限制仍未找到报告已检查的内容与尚未解决的部分。这条流程与代码实现一一对应第 5 步对应fetch-page.mjs的textPreview/snippets/chunk.nextOffset渐进机制第 7 步对应crawl-web.mjs的visited集合第 8 步对应shouldStopEarly强匹配提前停止。七、链接选择策略什么值得跟技能文档给出了清晰的链接优先级指引Agent 应优先跟进满足以下条件的链接文本、URL、标题、周边文本或页面结构中提到目标实体实体、话题、产品、人物、组织、日期或标识符与目标相关时命中以下语义词docs、documentation、reference、API、pricing、changelog、release、support、help、FAQ、blog、news、about、contact、terms、policy、source、repository、issue、discussion站内权威页优先于第三方综述canonical 内部页优先。同时应避开明显无关的链接、重复链接、导航噪音、广告、跟踪链接、仅登录页、宽泛的分类页——除非它们是当前唯一可行的路径。源码层的印证scoreLink中url text命中 4 分、上下文命中 1 分、同域名 2 分的打分体系正是把链接文本/URL/周边上下文提及目标与站内权威优先这两条策略机械化为可排序的数值供优先队列自动择优。八、证据规则回答的可追溯性底线SKILL.md对信息的使用方式提出了严格要求防止 Agent 在缺乏证据时给出误导性回答引用来源回答时必须引用实际使用过的页面一手优先优先引用一手来源而非二手综述区分事实与推断明确区分直接找到的事实与基于邻近证据的推断不越界声明若只找到邻近或部分证据不得声称已找到该信息冲突处理当来源相互冲突时如实说明并在有发布时间/更新日期时对比日期引述克制引述原文要短大部分内容用转述paraphrase。这些规则与crawl-web.mjs的输出设计是配套的matches数组只收录有片段命中的页面pages保留每个页面的完整状态与得分正是为了让 Agent 能逐页回溯、精确指明决定性来源 URL。九、输出规范先答后注技能文档规定的回答格式是先直接给出答案Answer directly first附上简明来源说明concise source notes有用时列出已检查的页面给出决定性来源 URLdecisive source URL说明仍存在的不确定性remaining uncertainty若目标未找到明确说明并总结已检查的最相关位置。这种先结论、后证据、留不确定性的输出结构既符合 LLM 直接作答的体验又保留了可核验的追溯路径。十、技能边界与实战建议综合文档与源码使用该技能时有几点值得注意它是编排层而非执行层按照 AGENTS.md 的约定Agent 技能只负责指导 Leon 的 Agent 循环和工具调用不要在此基础上再搭建第二个 Agent 循环或原生动作清单与搜索工具配合crawl-web.mjs要求先有候选 URL其报错信息明确建议先用 web search 再传 URL因此典型链路是搜索定位 → crawl-web 有界爬取 → fetch-page 深查命中页预算意识默认 8 页 / 深度 2 / 同域 5 页是为了控制成本与延迟实战中建议先小预算试探命中迹象明显后再放宽--max-pages等参数长文分段读取利用chunk.nextOffset循环推进配合--offset与--max-text-chars可无损读取超过单次上限的长文档。结语tiny-web-crawler是 Leon Agent 技能体系的一个小而完整的范本SKILL.md用九步工作流、默认限制、渐进抓取、链接选择、证据规则与输出规范定义了怎么爬、爬多少、何时停、怎么答crawl-web.mjs与fetch-page.mjs则以优先队列打分、域名配额、强匹配提前停止和流式截断等机制把策略落成可运行的代码。理解这个技能既能直接上手有界网页检索任务也能作为在 Leon 中编写其他 Agent 技能带 frontmatter 的SKILL.mdscripts/支撑脚本的参照模板——正如 AGENTS.md 所言它就是 Leon 官方指定的 Agent 技能范例。赞分享人工智能AI Agent交互助手本地部署大模型工具调用AI 技能【免费下载链接】leon Leon is your open-source personal assistant.项目地址https://gitcode.com/gh_mirrors/le/leon点击查看免费下载相关推荐SwiftSoup数据提取实战从网页中抓取结构化信息的终极指南SwiftSoup数据提取实战从网页中抓取结构化信息的终极指南 想要快速从网页中提取结构化数据SwiftSoup是您的完美解决方案 这个纯Swift网页爬虫后端Polar 前端重渲染优化实战用 Memoized Components 配合 Early Return 消除不必要的昂贵计算Polar 前端重渲染优化实战用 Memoized Components 配合 Early Return 消除不必要的昂贵计算 本文基于仓库内置的 Verce网页爬虫后端AI 应用Automa数据抓取实战从网页提取信息的完整教程Automa数据抓取实战从网页提取信息的完整教程 Automa是一款强大的浏览器自动化工具专门用于网页数据抓取和工作流程自动化。本文将为您详细介绍如何使用ARPA工作流自动化浏览器控制网页爬虫上一篇自建 CouchDB 服务器完整指南为 Obsidian Self-hosted LiveSync 搭建私有同步后端下一篇RIOT 内核同步原语深度解析Mutex 数据结构、加解锁流程与优先级继承创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网