从function calling到skill:让AI Agent真正具备联网搜索能力

发布时间:2026/9/12 14:34:11
从function calling到skill:让AI Agent真正具备联网搜索能力 最近开源社区里冒出个挺有意思的项目一个叫 web-access 的 skill刚开源没两天GitHub 上就斩获了 1.7K Star。如果你平时玩 AI Agent大概率已经刷到过这个名字。它做的事听起来简单——让 AI 真正具备访问网页、检索实时信息的能力——但做过 Agent 开发的人都知道这件事远比想象中麻烦。先说一个我自己的经历。之前搭了个带工具的 AI 助手本地知识库、文档问答都挺好可一旦问它“今天有什么值得关注的 AI 新闻”“某软件最新版本是多少”它要么翻出训练数据里的旧消息要么直接回复“我无法实时访问互联网”。那种“什么都懂但断网”的感觉就像请了个读了万卷书但没出门的应届生靠谱又无力。web-access 这类 skill 的出现就是把“出门”的能力补上了。这篇文章我会从为什么需要它、它的核心机制是什么、怎么装到自己的 Agent 里、踩过哪些坑这几个维度完整过一遍。1. 这个 skill 到底解决了什么问题1.1 大模型的知识截止日期与实时信息鸿沟大模型不是数据库它的知识来自训练时见过的语料所以天然有一个“知识截止日期”。训练完之后任何新发生的事它都不知道除非你给它额外的检索工具。以前大家习惯把这种能力打包成 function calling预先定义好“搜索新闻”“查询天气”这些工具函数模型在需要时按参数调用。但 function calling 有个问题工具是硬编码的每加一个能力就要改代码、重新部署。更重要的是工具的输出往往是结构化 JSON不一定适合直接作为模型回答的上下文。对于“搜索一下然后读正文再总结”这种复合任务靠几个固定函数拼起来非常别扭。web-access 走的完全是另一条路它把“上网”这个能力打包成一个可插拔的 skillAgent 运行时根据任务描述自动判断是否需要调用。不是新增一个函数而是给 Agent 塞了一整套“怎么去搜索、怎么抓页面、怎么提炼信息、怎么把内容喂回对话”的完整流程。这种方式天然适合 Agent 的“思考-行动-观察”循环也方便社区快速复用。1.2 从 function calling 到 skillAgent 能力外挂的进化先统一一下认知这里说的 skill指的是 AI Agent 生态里的一种可复用能力包。它的形态通常是一个文件夹里面有一个描述文件类似 SKILL.md加若干脚本放在 Agent 客户端的 skills 目录下。Agent 启动时会扫描这些目录把技能描述加载进系统提示词。当对话中出现匹配的任务时模型会主动调用对应脚本再把结果纳入回答参考。这跟传统插件的核心区别在于skill 的描述本身是由模型来理解和触发的而不是靠人工写死“当用户输入 XX 时执行 XX 函数”。等于你是在给 Agent 提供一份“能力说明书”具体什么时候用、怎么组合Agent 自己决定。现在市面上的 skill 五花八门有处理文档的、有做数据可视化的、有管理日程的。web-access 在这套生态里属于“基础设施型”技能因为它几乎是所有 Agent 共同的刚需。可以说没有联网能力的 Agent 只能跑训练数据里的老场景一旦接上 web-access才真正算一个敢接实时任务的助理。1.3 为什么 web-access 能火得这么快一个开源项目刚发布就拿到 1.7K Star通常至少踩中了三个点痛点痛、门槛低、时机对。痛点痛上面已经说了“模型回答过期信息”是所有 Agent 应用的硬伤。门槛低是这类 skill 的设计哲学——不需要你在代码层面做基础设施下载目录、配一个 API key、重启 Agent完事。时机对是因为现在正好是 Agent 生态的爆发期各种 Agent 客户端都在完善 skills 机制大家都需要这种“插上就能用”的联网能力。适用人群其实很宽研究 Agent 开发的工程师可以拿它做能力基座用开源 Agent 做个人助理的用户装上之后体验立马上一个台阶哪怕只是好奇 AI 应用怎么玩的路人照着教程装一遍也能明显感觉到“AI 能查实时信息了”跟“AI 只会瞎编”的差别。2. 核心机制与技术细节拆解2.1 一条完整的“AI 上网”工作链路web-access 并不是一个单独的函数而是一条完整链路。用户在对话里提出问题后Agent 先判断“这个问题是否需要实时信息”如果需要就调用 skill 里的搜索脚本把自然语言问题转换成适合搜索引擎的查询词拉回一批结果摘要。摘要显示在 Agent 的上下文里后模型再判断哪条链接值得点进去细看于是调用抓取脚本读取页面正文清洗后放进上下文最终综合生成回答。这整个过程里最关键的是两个决策点第一个是把用户的模糊问题改写成有效的搜索关键词第二个是根据摘要决定要不要继续深入阅读。大部分的 skill 体验差就差在这两步处理得不好。好的做法是给 skill 定义清晰的输入输出约定。比如搜索脚本返回结构化字段title、url、published_date、snippet抓取脚本返回 Markdown 格式的正文这样模型读起来不费劲也方便后续继续追问。我见过一些实现粗糙的联网插件直接把浏览器抓回来的整个 HTML 塞给模型效果必然稀烂——因为 HTML 里掺杂的噪音比你想象的多得多。2.2 搜索引擎 API 与直接抓取两条腿走路的取舍现在主流的 web-access 实现通常会同时支持两种联网方式走搜索引擎 API 和直接抓取指定 URL。前者解决“我不知道信息在哪帮我找一下”的场景后者解决“我明确知道你给我这个链接去读里面的内容”的场景。两者各有各的适用场景我整理了一个对比表联网方式优点缺点典型场景搜索引擎 API结果干净、结构化、无需处理反爬需要 API key可能产生费用部分站点不出现在搜索结果里实时新闻、竞品信息、热点事件、资料查找直接抓取 URL不受搜索引擎索引限制可以读指定页面全文容易遇到反爬、页面结构复杂时清洗困难用户给链接要求总结、抓取官方文档、读取特定公告浏览器渲染抓取能拿到 JS 动态渲染后的内容重、慢、资源消耗大数据看板、SPA 站点、登录后可见内容所以 web-access 类 skill 普遍的做法是“两条腿走路”搜索用 API阅读用抓取脚本。如果遇到普通抓取拿不到内容的动态页面再考虑降级到 Playwright 这类无头浏览器方案。别一开始就上浏览器渲染太重了90% 的页面用 requests 加一个好看的 User-Agent 就能解决。2.3 真正难的地方是内容清洗与 token 控制很多第一次做联网 Agent 的人会犯同一个错觉得联网把内容拿回来就行却忽略了“模型上下文窗口是有限的”。一个普通网页的正文少说几千字多则上万字要是连同导航、广告、评论区一起塞进去一次对话很快就把上下文撑爆且噪音会严重干扰模型判断。所以内容清洗是整个 skill 里最核心的工程点。常见的做法是引入正文抽取库比如解析 HTML 或提取正文文本它会根据标签密度、文本长度、段落结构等因素自动识别正文区域。我实际用下来它对绝大多数文章类页面抽取效果很好但对表格、代码块、论坛帖子的处理不太稳定需要额外适配。抽取完成之后还要做截断策略。我习惯按照“单条内容不超过 1500 字”的标准来截取优先保留标题、发布时间、开头部分和包含关键词的段落。这样既保住核心信息又给对话上下文留出足够空间。token 估算有个粗经验中文一个汉字差不多占 1 到 2 个 token一篇 1500 字的正文直接消耗两三千 token如果一次性给模型塞十篇上下文就快满了。所以 web-access 的设计一定要“克制”能只读摘要就不读正文能只读一段就不读全篇。2.4 容易被忽略的请求安全细节还有一个不需要经常出现、但一出现就是事故的问题请求安全。给 Agent 加联网能力本质上就是给模型发了一张“任意请求”的通行证。如果不做任何限制模型在抓取用户提供的链接时理论上可以请求内网地址引发 SSRF 漏洞服务端请求伪造也可能在无意识中访问大量非预期站点。我建议无论在哪个项目里使用 web-access 类能力都至少做三件事限制协议只允许 HTTP/HTTPS对抓取 URL 做基础校验拒绝解析到内网 IP 地址设置请求超时和最大响应体大小。这些限制能挡住 99% 的意外风险。虽然多数人只是自用但安全习惯应该在第一天就建立而不是等出了问题再补。3. 实操部署与接入把 web-access 装进你的 Agent3.1 目录结构与 SKILL.md 的正确写法目前主流支持 skills 机制的 Agent 客户端通常都会约定一个固定的技能目录。拿常见的配置来说你需要把 web-access 文件夹放到客户端的 skills 目录下例如用户目录下的隐藏配置文件夹里的 skills 文件夹这个 web-access 文件夹一般包含三样东西能力描述文件、脚本目录和依赖清单。目录结构大致是这样的web-access/ ├── SKILL.md ├── scripts/ │ ├── search.py │ └── fetch.py └── requirements.txt其中 SKILL.md 是灵魂它告诉 Agent 这个技能能做什么、什么时候该调用、怎么传参数。写法上开头通常是一段 YAML 格式的元信息用来定义名称和描述。描述部分特别重要因为模型就是靠这段文字来判断“现在这个任务应不应该激活该技能”。我见过不少 skill 没被触发成功问题就出在描述写得过于宽泛比如只写了“联网搜索”结果模型把很多不需要联网的问题也硬塞过来了。一个相对合理的描述字段应该明确说清楚“当用户需要查询实时信息、访问指定网页、获取最新动态时使用”同时补一句“不适合回答常识性或不需要联网的问题”。这样模型在遇到“11 等于几”时就不会浪费 token 去调搜索。3.2 环境变量与搜索 API 配置搜索 API 的选型上目前社区常用的有 Tavily、Brave Search、SerpAPI 等。Tavily 是专为 Agent 场景设计的返回值结构对 LLM 友好Brave Search 月免费额度相对充足适合个人玩耍SerpAPI 更像通用搜索接口灵活度更高。个人自用的话我建议先用 Tavily免费档足够日常测试它的返回字段天然带摘要和发布时间省去你不少解析工作。安装好依赖后需要把 API key 写入环境变量。以 Linux/macOS 为例在配置文件中加入一行即可export TAVILY_API_KEY你的key搜索脚本实现其实不复杂核心就是通过 HTTP 请求把查询词发给搜索 API再解析结果。我给出一个极简可用的参考实现import os import requests def search(query: str, max_results: int 5) - list[dict]: api_key os.environ.get(TAVILY_API_KEY) resp requests.post( https://api.tavily.com/search, json{ api_key: api_key, query: query, max_results: max_results, search_depth: basic, include_answer: False, }, timeout15, ) resp.raise_for_status() return resp.json().get(results, [])这个实现把返回结果做成列表每项包含标题、链接、摘要和发布时间Agent 拿到后就可以直接阅读理解并决定下一步动作。3.3 一行行跑通验证 skill 是否可用装完别急着一上来就对接 Agent先用命令行单独验证两个脚本能不能跑。经验告诉我90% 的“skill 没生效”问题其实是脚本本身在环境里就跑不通而 Agent 客户端只负责调用错误信息被吞了。验证搜索脚本直接执行python scripts/search.py 2025年AI Agent发展趋势正常情况会打印出一串 JSON包含 top 结果。如果报错优先检查环境变量是否真的被读到了以及网络能否访问搜索 API。验证抓取脚本随便拿一个你常读的博客链接测试。抓取脚本的核心是请求页面并抽取正文一个简单的版本长这样import requests from trafilatura import extract def fetch(url: str) - str: headers {User-Agent: Mozilla/5.0 (compatible; WebAccessSkill/1.0)} resp requests.get(url, headersheaders, timeout20) resp.raise_for_status() body extract(resp.text, output_formatmarkdown, include_linksFalse) return body[:2000] or 未提取到正文内容这里设置了 User-Agent 伪装成普通浏览器避免一部分基础反爬输出格式指定为 Markdown方便模型阅读。截断到 2000 字是为了保护上下文。两个脚本都跑通之后再把整个文件夹接入 Agent重启会话测试一个真实问题比如“帮我查一下昨天发布的某某模型有哪些新特性”。这时候你观察 Agent 的思考过程应该能看到它先搜索、再阅读、最后总结的几个阶段。如果它直接给出了答案却没触发 skill大概率是描述写得不对或者目录路径不对回去检查这两处。4. 调优与扩展从“能联网”到“好用地联网”4.1 搜索参数与时效性控制装上只代表“能联网”距离“好用”还差一步那就是参数调校。先说时效性控制。搜索引擎 API 一般支持按时间范围过滤比如只搜最近一天、最近一周的数据。如果 Agent 做的是新闻监测类任务这个参数非常关键否则它可能给你翻出半年前的内容。以 Tavily 为例可以在请求参数里加上时间范围字段表示只返回最近三天的结果。另外控制返回数量也很重要。我自己的习惯是默认返回 5 条只有在明确需要更多参考信息时才调到 8 到 10 条。返回太多摘要模型反而容易纠结返回太少可能错过关键信息。5 条是个不错的平衡点。4.2 多轮检索与结果缓存第二个优化方向是让 Agent 具备“检索-阅读-再检索”的循环能力。第一次搜索返回的摘要往往比较简略模型需要点进一两个高价值链接读全文读完之后如果发现线索不足还可以继续发起新搜索。这个能力不需要额外写复杂代码关键是在 SKILL.md 里给足提示告诉模型“一次搜索可能不够如果信息不完整可以结合多个来源交叉验证”。缓存是另一个容易忽略的点。同样一个查询词如果每次对话都要重新请求搜索引擎和抓取页面既浪费时间和 API 额度也容易触发限流。我建议在脚本里加一个简单的磁盘缓存以查询词加时间窗口为 key命中缓存就直接返回之前的结果。我可以分享一个小技巧缓存时间按场景区分热点新闻缓存几分钟长期有效的知识类问题缓存一整天。4.3 动手写一个最小可用的替代版如果不想依赖外部项目或者想彻底搞懂 web-access 的底层逻辑完全可以用几十行 Python 写一个“乞丐版”的联网技能。思路很简单搜索部分直接拼一个搜索引擎的 URL用 requests 抓取搜索结果页正文部分用 BeautifulSoup 解析 HTML按照标题标签和段落标签粗筛正文。下面是一个缩水版正文提取的核心片段import requests from bs4 import BeautifulSoup def naive_fetch(url: str) - str: resp requests.get(url, headers{User-Agent: Mozilla/5.0}, timeout15) soup BeautifulSoup(resp.text, html.parser) for tag in soup([script, style, nav, footer, aside]): tag.decompose() paragraphs soup.find_all(p) text \n.join(p.get_text(stripTrue) for p in paragraphs) return text[:2000] or 未提取到正文内容这个版本能应付不少简单页面但它有两个致命缺陷一是很多正规站点的正文并非都装载 p 标签里二是面对动态渲染页面时完全无能为力。所以它最大的价值是教学真要稳定商用还是直接采用现成方案更省心。5. 常见问题与排查技巧实录5.1 高频问题速查表我整理了实际部署中容易遇到的问题按“现象-原因-解法”的格式列在下面现象可能原因解决思路Agent 始终不触发 skillSKILL.md 描述过于宽泛或路径不对检查技能目录位置重写描述给出明确的触发条件搜索结果为空API key 失效或查询词质量差先单独跑脚本验证 key再改写成更具体的查询词抓取页面返回空内容页面是 JS 动态渲染或反爬拦截换 User-Agent必要时用无头浏览器渲染单次对话 token 迅速耗尽抓取内容没有截断或一次读了太多文章限制单篇长度控制同时阅读的链接数量频繁收到 429 限流没有做缓存或请求频率太高加磁盘/内存缓存设置合理超时和重试中文页面乱码编码识别失败在请求时显式指定页面编码或按响应头处理5.2 我自己踩过的三个坑第一个坑是我最开始图省事让 Agent 每轮对话都把搜索到的五篇全文一起塞进上下文结果模型开始说胡话因为上下文窗口被塞满了。后来改成先看摘要再挑两篇精读效果立刻正常了。所以说联网能力的工程质量不是看“能不能拿到网页”而是看“能不能用最少的信息回答好问题”。第二个坑是遇到某新闻类站点requests 抓回来的内容只有一堆空的 div 标签。这类站点用前端框架渲染正文在初始 HTML 里根本不存在。后来对这类域名做了单独处理匹配到才启用浏览器渲染脚本。我提醒一句不要对所有站点都启用无头浏览器耗时和资源开销是普通请求的十几倍只对黑名单域名用就好。第三个坑是 SSRF 隐患。测试时我给了 Agent 一个内网管理系统的链接它居然真的去请求了还返回了错误详情。虽然本地环境无所谓但如果在跑自动化流程的服务器上这就是个实打实的安全漏洞。后来我在抓取脚本里加了一步 IP 解析校验检测到内网地址就直接拒绝并提示换链接。5.3 给 skill 加日志和埋点最后一条建议也是很多人忽略的给 skill 加上日志和埋点。不要只在出问题的时候才去调试而是在每个关键步骤都输出一行结构化日志记录搜索关键词、搜索结果数量、抓取 URL、耗时、实际消耗 token 等。这么做的好处非常明显。第一你可以复盘 Agent 某次错误回答的全过程看到底是没搜到、搜错还是读错了第二你可以统计高频查询词反哺 Agent 的提示词优化第三消耗埋点能让你精确评估 API 费用避免月底收到账单才发现额度超了。我现在习惯把所有请求日志放到一个独立目录按天切分线上和本地都能快速检索。别小看这一步的日志价值Agent 应用调试比传统后端难得多因为“为什么模型会那样判断”往往不是一个堆栈能解释清楚的而日志至少能还原它的行动路径。从接入 web-access 到现在我最明显的体感是再也不用跟 AI 说“帮我去查个东西”然后听它道歉式地回复“我无法访问实时内容”了。它搜索到的内容会附上来源链接回答也能跟着最新情况走这种升级对于拿 Agent 当生产力工具的人来说是质变级的体验。最后一个小建议装好之后别急着让它处理复杂任务先丢几个你每天都会手动搜的问题去测一边测一边看日志打磨。联网类 skill 的调优是个持续过程但你每多调优一轮Agent 的可用性就上一个台阶。