AI Agent联网搜索优化:Yandex搜索与Ollama智能提取的工程实践
1. 项目概述与核心价值最近在折腾AI Agent发现一个挺头疼的问题想让Agent去网上查点资料结果它要么给你返回一堆只有标题和摘要的搜索结果信息量太少要么就是一股脑把整个网页的HTML都塞进上下文直接就把宝贵的Token预算给撑爆了。这就像让一个助手去图书馆它要么只给你看目录要么把整本书都搬过来两种体验都挺糟糕的。直到我遇到了这个组合技能包——yandex-search-webscraper-skill它用一种相当巧妙的方式在“信息广度”和“处理效率”之间找到了一个绝佳的平衡点。这个项目本质上是一对为OpenClaw Agent设计的技能Skill。一个是**yandex-search/负责调用Yandex搜索API帮你从海量信息中快速定位目标。更妙的是它带一个--scrape参数可以联动第二个技能web-scraper/**后者能通过本地运行的轻量级Ollama模型智能地从网页中提取出结构化的核心内容标题、正文、链接等生成一份高度精简的JSON。这套组合拳打下来最终送入Agent上下文的Token数量相比直接抓取原始网页能减少10到40倍。对于任何需要让AI进行联网搜索并深度处理信息的场景比如市场调研、竞品分析、新闻摘要或者技术研究这都是一套能极大提升效率和效果的工具。2. 架构设计与核心思路拆解2.1 为什么是“搜索智能抽取”的组合传统的Agent联网方案通常面临两难选择。方案A仅使用搜索引擎API返回的片段Snippet。优点是极其省Token速度快。缺点是信息严重不全一个复杂的答案可能分布在多个段落片段根本覆盖不到导致Agent基于片面信息做出错误判断。方案B使用类似web_fetch的函数直接抓取完整HTML。优点是信息完整。缺点是灾难性的——一个普通新闻页可能产生5000到30000个Token瞬间耗尽上下文窗口且其中90%是导航栏、广告、侧边栏等噪音对核心任务毫无帮助。yandex-search-webscraper-skill选择的是一条折中但更聪明的路“精准定位 智能提纯”。精准定位Yandex Search首先利用成熟的搜索引擎Yandex完成“大海捞针”的工作。它根据你的查询从全网找到最相关的几十个网页链接和简短摘要。这一步成本极低速度快。智能提纯Web Scraper对于筛选出的关键链接比如前3个不直接塞入原始HTML而是启动一个本地的小模型richardyoung/schematron-3b让它像一个人一样去“阅读”网页并按照预设的格式标题、正文、链接列表等提取出核心信息输出为结构化的JSON。这个设计的精妙之处在于它将计算密集型、需要“理解力”的任务从杂乱HTML中提取语义卸载给了专门优化过的小模型而这个小模型在本地运行无需网络往返且输出极其紧凑。最终你既获得了近乎完整的内容信息又只付出了极小的Token代价。2.2 技术栈选型背后的考量运行时 (Bun)项目选择Bun而非Node.js主要看中其启动速度、内置的测试运行器以及更现代化的API设计。对于需要频繁启动脚本的Agent工具链来说更快的启动时间意味着更低的延迟。不过如果你习惯用Node理论上稍作修改主要是包导入和脚本执行方式也能跑起来。搜索API (Yandex)选择Yandex Search API可能出于几个考虑。一是它对俄语及东欧区域内容有更好的覆盖项目演示也用了俄语网站。二是其API可能在某些区域有更好的可用性或性价比。当然这个架构是解耦的核心思想可以迁移到Google、Bing等任何搜索API上。抽取模型 (Ollama schematron-3b)这是项目的灵魂。Ollama提供了极其简便的本地大模型运行方案一条命令就能拉取和运行模型避免了复杂的服务部署。schematron-3b模型选择这个3B参数量的模型是关键。更大的模型如7B、13B虽然能力可能更强但推理速度慢资源占用高。而3B的模型在保证足够的内容抽取和结构化能力这是一个定义相对明确的任务的前提下实现了速度与精度的最佳平衡。Q4_K_M这个量化版本进一步降低了内存需求使得它可以在消费级硬件上流畅运行。注意schematron-3b是一个专门为网页内容抽取和结构化任务微调的模型。不要用它去做通用的聊天或创作它的强项就是理解HTML并提取指定字段。用对了场景才能发挥最大价值。3. 环境准备与详细配置指南3.1 基础环境搭建假设你已经在本地机器上可以是开发机也可以是运行Agent的服务器让我们一步步把环境搭起来。第一步安装Bun如果你的系统还没有Bun按照官方文档安装是最稳妥的。通常一条curl命令就能搞定。安装后在终端输入bun --version确认安装成功。第二步安装并配置Ollama前往Ollama官网下载并安装对应你操作系统的版本。安装完成后启动Ollama服务通常安装后会自动运行或作为一个后台服务。拉取项目指定的模型。打开终端执行ollama pull richardyoung/schematron-3b:Q4_K_M这会下载大约2GB左右的模型文件。确保你的网络通畅且磁盘有足够空间。第三步获取项目代码你可以通过Git克隆仓库或者直接下载ZIP包解压。git clone https://github.com/qwexs/yandex-search-webscraper-skill.git cd yandex-search-webscraper-skill3.2 Yandex Search API 密钥配置这是整个配置中相对繁琐但必须的一步因为你需要一个Yandex Cloud的账号。注册与登录访问Yandex Cloud官网用邮箱注册一个账号。完成必要的验证步骤。创建服务账号Yandex Cloud使用服务账号来管理API权限这是一种安全的最佳实践。# 安装并配置Yandex Cloud CLI (yc)然后用它创建服务账号 yc iam service-account create --name search-bot这行命令创建了一个名为search-bot的服务账号。绑定权限你需要给这个服务账号授权允许它使用搜索API。首先你需要知道你的folder-id在Yandex Cloud控制台可以找到。# 为服务账号添加搜索API用户角色 yc resource-manager folder add-access-binding 你的folder-id \ --role search-api.webSearch.user --service-account-name search-bot将你的folder-id替换成你实际的文件夹ID。创建API密钥最后为这个服务账号创建一个静态密钥这就是我们代码里要用的apiKey。yc iam api-key create --service-account-name search-bot执行成功后命令行会输出一长串的密钥字符串类似AQVN...。务必立即复制并妥善保存因为它只显示一次。写入配置文件回到项目目录的yandex-search/文件夹下。cd yandex-search cp config.example.json config.json然后编辑config.json文件填入你刚才获取的apiKey和你的folderId。{ apiKey: 你复制的AQVN...密钥, folderId: 你的folder-id, region: auto }实操心得在配置ycCLI时如果遇到权限问题确保你用的是正确的账户并且该账户对目标文件夹有admin或editor权限。另外API密钥是最高机密千万不要提交到Git仓库。项目提供的.example文件就是防止你误操作的最佳实践。4. 核心技能使用详解与实战环境配置妥当后我们就可以开始体验这两个技能是如何协同工作的了。建议从简单的开始逐步深入。4.1 独立使用 Web Scraper这个技能可以单独使用用来快速解析任何你感兴趣的网页并获取其结构化摘要。基本用法# 进入web-scraper目录执行脚本 cd web-scraper bun scripts/scrape.js --url https://example.com运行后终端会输出一个格式化的JSON对象包含了从该网页提取出的title、main_content、links、images等字段。main_content字段就是经过清洗和提取后的核心正文去除了广告、导航等噪音。高级参数--prompt如果你对默认的提取指令不满意可以用这个参数传入自定义的Prompt给Ollama模型。例如你只想提取文章中的代码片段可以尝试--prompt “Extract only code examples from the page.”。但这需要你对模型的能力和Prompt工程有一定了解。--compact输出压缩后的JSON单行方便管道传递给其他工具处理。--no-retry默认情况下如果提取失败如网络超时、模型错误脚本会重试一次。加上这个参数则禁用重试。实战示例解析一篇技术博客假设我们想快速了解一篇关于Rust新特性的长博客。bun scripts/scrape.js --url https://blog.rust-lang.org/2024/01/01/some-new-feature.html --compact rust_blog_summary.json这条命令将结果压缩后保存到了rust_blog_summary.json文件。打开文件你会看到一篇可能长达数千字的文章被浓缩成了几百个Token的核心内容摘要非常适合直接喂给AI进行下一步分析或总结。4.2 独立使用 Yandex Search这个技能负责搜索它有两个主要脚本search.js和更智能的smart-search.js。search.js基础搜索cd yandex-search # 基础搜索返回10条文本格式结果 bun search.js “如何学习Bun运行时” # 返回5条结果并以JSON格式输出 bun search.js “Bun vs Node.js” --limit5 --formatjson # 指定搜索区域为土耳其并将结果保存到文件 bun search.js “最新科技新闻” --regiontr --outputresults.jsonsearch.js提供了最直接的API调用方式。--region参数很重要ru针对俄语区com针对国际tr针对土耳其ua针对乌克兰auto则会根据查询词自动判断西里尔字母用ru拉丁字母用com。smart-search.js智能搜索推荐这个脚本是search.js的增强版它最大的特点是自动处理区域并且集成了--scrape功能。# 智能搜索自动判断区域 bun smart-search.js “Python异步编程最佳实践” # 智能搜索并提取前3条结果的完整内容 bun smart-search.js “React Server Components 深度解析” --scrape --scrape-top3当你使用--scrape时会发生以下事情smart-search.js调用Yandex API进行搜索得到URL列表和摘要。对于排名前N--scrape-top指定默认3的结果它会依次调用web-scraper技能。web-scraper抓取该URL的HTML用Ollama模型提取结构化内容。最终返回给你的结果里前几条就不再是简短的摘要而是包含了_scraped字段的丰富对象里面是完整的、结构化的页面内容。4.3 组合技能实战一个完整的研究流程假设你是一名开发者想研究“2024年前端状态管理库的新趋势”。步骤1进行初步广度搜索bun smart-search.js “2024 frontend state management trends” --limit15 --formatjson initial_results.json这一步先获取15条相关的文章、博客链接看看大家都在讨论什么。打开initial_results.json快速浏览标题和摘要筛选出3-5篇看起来最权威、最新的文章。步骤2深度提取核心内容假设你挑中了其中3篇。# 你可以手动对这三篇分别使用web-scraper bun ../web-scraper/scripts/scrape.js --url “https://link-to-article-1.com” article1.json bun ../web-scraper/scripts/scrape.js --url “https://link-to-article-2.com” article2.json bun ../web-scraper/scripts/scrape.js --url “https://link-to-article-3.com” article3.json或者更高效的方式是直接用智能搜索的整合功能# 用一个更精确的查询词直接让smart-search去抓取前3的结果 bun smart-search.js “Zustand vs Redux Toolkit 2024 comparison” --scrape --scrape-top3 --formatjson deep_dive.json步骤3将结果喂给AI Agent现在你有了deep_dive.json文件里面包含了三篇文章的精华内容总Token数可能只有一两千。你可以轻松地将这个JSON文件的内容作为上下文发送给你的OpenClaw Agent或其他AI助手并给出指令“基于以下三篇关于2024年前端状态管理的文章内容为我总结当前主要的趋势、技术选型建议以及社区热议的焦点。”这样一来你的Agent就能基于高质量、高信息密度的材料生成一份非常有洞察力的报告而整个过程几乎都是自动化的。5. 内部工作机制深度解析理解了怎么用我们再来深入看看它内部是怎么跑的。这能帮助你在出问题时进行排查甚至进行定制化修改。5.1 智能搜索 (smart-search.js) 的工作流当你执行bun smart-search.js “query” --scrape --scrape-top3时一个完整的调用链被激活参数解析与配置加载脚本首先解析命令行参数并加载config.json中的API密钥。区域判断根据查询字符串自动判断区域西里尔字母→ru拉丁字母→com。调用搜索API使用yandex-search/search.js模块向Yandex Search API发送HTTP请求。请求中包含了你的查询词、区域、所需结果数量(limit)等参数。接收并解析搜索结果API返回JSON格式的搜索结果包含每个结果的title、url、snippet等。判断是否需要抓取如果--scrape标志存在则进入抓取流程。并发抓取对于前N--scrape-top个结果脚本会并行地为每个URL调用web-scraper/scripts/scrape.js。这是性能优化的关键避免了顺序抓取带来的漫长等待。整合结果每个scrape.js调用返回该页面的结构化JSON。smart-search.js将这些JSON作为_scraped字段合并到对应的搜索结果对象中。格式化输出根据--format参数将最终整合后的数据以纯文本、JSON或Markdown格式输出到终端或文件。5.2 网页抓取器 (web-scraper) 的提取管道scrape.js脚本本身也是一个协调者它内部的工作流程更精细获取原始HTML调用fetch-html.js模块。这个模块使用HTTP库如Bun内置的fetch或node-fetch去请求目标URL。字符编码探测与解码这是一个关键且易被忽视的步骤。互联网上的网页编码五花八门UTF-8, GBK, windows-1251等。fetch-html.js会尝试从HTTP响应头Content-Type或HTML的meta charset标签中探测编码并正确地将二进制流解码为字符串。如果探测失败它可能会尝试一些常见的编码进行回退确保乱码不会传递给下游。语义化内容定位解码后的完整HTML字符串会先经过一个预处理步骤。fetch-html.js会尝试用一组语义化选择器去定位页面的“主内容区”。它优先寻找article,main,#content,.post-body,#mw-content-text维基百科专用等标签或ID/Class。如果找到它会提取这个区域内的HTML而不是整个文档。这步操作在内容送入模型之前完成直接过滤掉了大量噪音是降低后续处理负载和提升模型精度的关键。构造Prompt并调用Ollama提取出的或完整的HTML片段连同预先定义好的系统提示词System Prompt被一起发送给本地运行的Ollama API。这个系统提示词大致是“你是一个专业的网页内容提取器。请从提供的HTML中提取以下结构化信息标题(title)、描述(description)、正文(main_content)、链接(links)、图片(images)、元数据(metadata)。以JSON格式输出。”模型推理与JSON解析Ollama服务启动schematron-3b模型进行推理。模型“理解”HTML结构并生成符合要求的JSON字符串。extract.js模块接收这个字符串并尝试用JSON.parse()解析它。错误处理与重试如果解析失败模型可能输出格式不规范的JSON或者HTTP请求超时默认配置下脚本会重试一次。这提高了在偶尔网络波动或模型抽风时的鲁棒性。5.3 关键模块fetch-html.js的智慧这个模块值得单独拿出来说。它的“语义化选择器”策略是基于对大量网站结构的经验总结。例如article 绝大多数博客、新闻网站用这个标签包裹正文。main HTML5的主内容区域标签。#mw-content-text 维基百科项目的特定ID。.post-content,.entry-content WordPress等CMS常见的正文类名。这种启发式方法虽然不完美有些网站结构怪异但能覆盖绝大部分主流网站在准确性和通用性上取得了很好的平衡。如果它找不到这些语义化标签才会回退到使用整个body的内容。你可以根据自己常抓取的网站类型修改这个模块中的选择器数组以优化提取效果。6. 常见问题、故障排查与性能调优在实际使用中你可能会遇到一些问题。这里记录了一些常见坑点和解决思路。6.1 搜索相关问题问题现象可能原因排查与解决搜索返回403 Forbidden或认证错误1. API密钥无效或过期。2. 服务账号没有正确的search-api.webSearch.user角色。3.folderId填写错误。1. 检查config.json中的apiKey和folderId是否与Yandex Cloud控制台中的一致。2. 在Yandex Cloud控制台进入对应文件夹的“访问绑定”页面确认你的服务账号已被分配该角色。3. 尝试用yc iam api-key list命令列出密钥确认状态。搜索结果很少或质量差1. 区域(region)设置不当。2. 查询词不准确或太宽泛。1. 尝试明确指定--regioncom国际或--regionru俄语区。2. 优化你的搜索关键词使用更具体、更专业的术语。smart-search.js区域判断错误查询词混合了不同语言字符。auto模式基于简单规则。如果查询词是“Python编程”它会用com如果是“Python программирование”它会用ru。对于混合词建议手动指定--region。6.2 抓取与模型相关问题问题现象可能原因排查与解决scrape.js返回空JSON或错误1. 目标网站无法访问或屏蔽爬虫。2. Ollama服务未运行或模型未加载。3. HTML编码探测失败导致乱码。4. 模型提取失败。1. 先用浏览器或curl命令测试URL是否能正常访问。2. 运行ollama list确认schematron-3b模型状态为“已下载”。运行ollama serve确保服务在运行。3. 查看fetch-html.js的中间输出可能需要临时添加日志看原始HTML是否正确。4. 尝试使用--no-retry并查看原始错误信息。抓取速度很慢1. 目标网站响应慢。2. 模型推理速度慢。3. 网络问题。1. 这是外部因素无法控制。2.schematron-3b:Q4_K_M在CPU上运行可能较慢。考虑使用性能更强的CPU或尝试支持GPU推理的Ollama版本如果你有NVIDIA显卡。3. 检查本地网络。提取的内容不准确如包含了侧边栏1. 目标网站结构特殊语义选择器未命中。2. 模型在理解复杂页面时出现偏差。1. 这是当前方法的局限性。你可以修改fetch-html.js为你常抓取的特定网站添加自定义选择器。2. 尝试使用--prompt参数提供更精确的提取指令例如“只提取class为‘article-body’的div内的文本”。Error: connect ECONNREFUSEDOllama API服务默认端口11434未启动。确保Ollama服务正在运行。在终端执行ollama serve并保持该窗口打开或将其配置为系统后台服务。6.3 性能调优建议调整并发数smart-search.js在--scrape模式下是并发抓取的。如果同时抓取太多页面比如--scrape-top10可能会对本地网络和Ollama造成较大压力导致部分请求超时。建议根据你的硬件情况将--scrape-top设置在3-5之间平衡速度与稳定性。模型量化与硬件Q4_K_M是精度和速度的平衡选择。如果你追求极速且可以接受轻微的质量损失可以尝试拉取更低精度的版本如Q2_K。反之如果质量至上且硬件足够可以尝试非量化或更高精度的版本。使用GPU运行会显著加速推理。缓存策略如果你需要反复分析同一批URL可以考虑在scrape.js外层添加一个简单的缓存层比如将URL的MD5哈希作为键将提取的JSON保存到本地文件。下次请求相同URL时直接读取缓存避免重复的网络请求和模型推理。超时设置当前脚本的超时设置可能对某些慢速网站不友好。你可以修改fetch-html.js中的fetch请求以及调用Ollama API时的超时参数以适应你的网络环境。7. 集成到OpenClaw Agent与其他扩展思路7.1 作为OpenClaw Skill运行这个项目的首要设计目标就是作为OpenClaw Agent的技能。集成方式通常是将这两个技能目录放入你的OpenClaw项目的技能文件夹中并在Agent的配置中声明它们。在你的OpenClaw Agent的配置文件中你可能会添加如下技能引用skills: - name: yandex_search path: ./skills/yandex-search-webscraper-skill/yandex-search description: “使用Yandex进行网络搜索并可选择抓取完整页面内容。” - name: web_scraper path: ./skills/yandex-search-webscraper-skill/web-scraper description: “使用本地Ollama模型从网页中提取结构化内容。”之后你的Agent在运行时就可以根据计划或用户指令动态调用yandex_search技能进行搜索并在需要时链式调用web_scraper技能对结果进行深度解析。这赋予了Agent强大的实时信息获取与理解能力。7.2 扩展与定制化方向这个项目提供了一个优秀的框架你可以在此基础上进行多种扩展更换搜索引擎如果你更习惯用Google或Bing可以仿照yandex-search/目录的结构创建一个google-search/模块。核心是替换掉调用Yandex API的代码改为调用其他搜索引擎的API并适配其返回的数据格式。定制提取模型如果你对schematron-3b的提取效果在某些领域如学术论文、电商页面不满意可以用你自己的数据微调一个类似的小模型。Ollama支持导入自定义模型你只需要替换模型名称即可。增加提取字段默认提取的字段title, main_content等可能不够用。你可以修改web-scraper中发送给模型的系统提示词要求它提取更多信息比如作者、发布日期、产品价格、评分等并相应调整后续处理JSON的代码。构建自动化管道你可以将此技能作为更大自动化流程的一部分。例如定期搜索某个主题抓取新文章自动生成摘要报告并发送到你的笔记软件如Notion、Obsidian。这只需要用Bun写一个简单的调度脚本将这几个步骤串联起来。这套工具的核心思想——用大模型哪怕是小型专用模型对原始信息进行“提纯”后再送入工作流——非常具有启发性。它不仅仅适用于AI Agent任何需要从互联网获取并处理信息的自动化场景都可以借鉴这种模式在信息完整性和处理成本之间找到最优解。