AI Agent 的 Web Search 功能实现详解
整理于 2026/07/01。涵盖:实现原理、搜索 API 选型、Google 官方 API、主流 agent(Codex / Claude Code / Gemini CLI / OpenCode 等)的搜索来源对照。
一、核心模型:Tool Use(工具调用)
LLM 本身不会"上网",它只做两件事:理解问题、决定要不要搜。真正的搜索由外部代码执行。流程是:
用户提问
→ LLM 判断:"这个问题需要最新信息,我该调 search 工具"
→ LLM 输出结构化 tool_call: {name: "web_search", args: {query: "..."}}
→ Agent 运行时拦截 tool_call,执行真正的 HTTP 搜索
→ 把搜索结果作为 tool_result 喂回 LLM
→ LLM 基于结果生成最终回答(可能再触发下一轮搜索)
这就是 ReAct(Reason + Act)模式:思考 → 行动 → 观察 → 再思考,循环直到 LLM 觉得够了。
二、搜索这一步具体怎么做
web_search 工具内部通常走以下几种实现之一:
| 方式 | 做法 | 代表 |
|---|---|---|
| 搜索 API | 调用现成搜索服务的 API,返回结构化 JSON | Tavily、Brave Search API、Serper、Bing API、Google Custom Search |
| 官方内置工具 | 平台直接提供托管搜索 | OpenAI 的 web_search、Anthropic 的 WebSearch tool、Gemini Grounding |
| 自己抓网页 | 拿到 URL 后用 HTTP 客户端 + HTML 解析(甚至 headless 浏览器)抓正文 | requests + BeautifulSoup / Playwright |
| MCP server | 通过 Model Context Protocol 暴露一个搜索服务给 agent | modelcontextprotocol/servers 里的 search/fetch server |
返回给 LLM 的内容一般是清洗后的纯文本片段(不是原始 HTML),否则 token 浪费严重且模型容易迷失。
三、Agent 运行时怎么编排
无论用 LangChain / LangGraph / 自写 loop,骨架都一样:
messages = [{"role": "user", "content": query}]
while True:
resp = llm.chat(messages, tools=[web_search_tool_schema])
if not resp.tool_calls:
break # 模型不再要工具 → 给最终答案
for call in resp.tool_calls:
result = run_tool(call) # 真正发 HTTP 请求搜索
messages.append(tool_result(call.id, result))
关键点:工具的 schema(参数定义)要描述清楚,模型才知道该怎么调;搜索 query 由模型自己生成,所以"会不会搜"很大程度取决于模型能力。
四、工程上常见的增强
- query 改写:先让 LLM 把用户口语化问题改写成搜索引擎友好的关键词,甚至拆成多个子查询并行搜。
- 结果去重 + rerank:搜回来几十条,先用 embedding 或关键词打分筛 top-K 再喂模型。
- 正文抽取:用 readability / trafilatura 把网页正文从导航、广告里抠出来。
- 多轮 / 迭代搜索:第一轮结果不够,模型自己决定换关键词再搜(这就是 agent 区别于"单次 RAG"的地方)。
- 引用回链:把每条结果的 URL 保留,最终回答时附上来源。
- 缓存 + 限流:搜索 API 要钱,重复 query 要缓存。
五、搜索 API 选型
5.1 Google 有官方 API 吗?有,但不"纯粹"
Google 官方提供的是 Google Custom Search JSON API(基于 Programmable Search Engine,原名 CSE)。它和你在 google.com 上搜的不完全一样:
- 需要先在 cse.google.com 建一个"自定义搜索引擎",配置成搜索整个 web 或指定站点。
- 然后用 API key + CSE ID 调
https://www.googleapis.com/customsearch/v1。 - 返回 JSON(标题、摘要、URL、缩略图等)。
几个坑:
1. 它不是 google.com 那个完整搜索,索引范围受 CSE 配置限制(虽然能设成"整个 web",但结果质量和排序跟 google.com 有差距)。
2. 默认每天上限 10,000 次,再高要申请提额。
3. 返回的是摘要 snippet,不包含网页全文。要全文还得自己 fetch URL + 抽正文。
免费吗?半免费:
- 每天前 100 次免费(无需开 billing,太平洋时间午夜重置)。
- 超过部分 $5 / 1000 次。
- 严格说是"有免费额度,不是完全免费"。个人测试和小 demo 完全够用。
5.2 主流搜索 API 横向对比
| 服务 | 免费额度 | 超额价格 | 数据来源 | 适合 |
|---|---|---|---|---|
| Google Custom Search API | 100 次/天 | $5 / 1k | Google(受 CSE 限制) | 要"官方 Google 结果" |
| Tavily | ~1000 次/月 | ~$30/月起,约 4k 次 | 自有爬虫 + LLM 清洗 | 给 AI agent 用,开箱即用,返回已清洗的正文 |
| Brave Search API | ~2000 次/月 | ~$5/月起 | 独立索引(非 Google) | 隐私导向、免费额度大方 |
| Serper.dev | 一次性 2500 次(非每月) | ~$50/月 ≈ 50k 次 | 抓 Google SERP | 想要 google.com 质量但懒得配 CSE |
| DuckDuckGo | 完全免费 | — | 自有 + Bing | 免费但有速率限制、结果一般 |
| Bing Web Search API | 1000 次/月 | $3 / 1k | Microsoft Bing | 微软生态、稳定 |
| SearXNG(自建) | 0 成本 | — | 元搜索聚合 | 自己部署,无限免费 |
5.3 给 AI agent 用,到底选哪个?
关键区别在于 API 返回的是"链接列表"还是"已处理好的正文":
- 传统型(Google CSE、Brave、Serper、Bing):只给标题 + 摘要 + URL。你拿到后还得自己 fetch 网页、抽取正文、切分喂给 LLM。工程量大。
- AI 优化型(Tavily、Exa、Jina Reader):直接返回清洗后的正文/答案片段,甚至帮你做了 rerank。这是现在 AI agent 的主流选择,省一大堆后处理。
实际推荐:
- 想最快跑起来 → Tavily(LangChain/LangGraph 有现成封装,几行代码)。
- 想要 Google 原生结果质量 → Serper(抓 google.com SERP,比官方 CSE 更接近真实 google.com)。
- 不想花钱、能接受折腾 → 自建 SearXNG,或用 DuckDuckGo(注意容易被限流)。
- 走 MCP 生态 → 用现成的 search MCP server,agent 端不用写代码。
5.4 调用示例(Google Custom Search)
import requests
API_KEY = "你的_key"
CSE_ID = "你的搜索引擎id"
r = requests.get("https://www.googleapis.com/customsearch/v1", params={
"key": API_KEY,
"cx": CSE_ID,
"q": "AI agent web search implementation",
})
for item in r.json().get("items", []):
print(item["title"], "→", item["link"])
print(" ", item.get("snippet"))
拿到 link 后,再用 trafilatura / BeautifulSoup 抓正文喂给 LLM 即可。
六、主流 Agent 的搜索来源对照
核心结论:主流厂商自家的 agent 基本不用第三方搜索 API(Tavily/Brave 那种),而是用自家平台 API 内置的服务端 web search 工具。第三方搜索 API 更多出现在"自己搭 agent"的场景(LangChain 生态、自建 bot、模型无关 agent)。
| Agent | 搜索实现 | 用谁的数据 |
|---|---|---|
| OpenAI Codex CLI | OpenAI Responses API 的内置 web_search 工具 |
OpenAI 服务端搜索(非公开具体供应商,整合多家) |
| Claude Code | Anthropic API 的内置 WebSearch 工具 |
Anthropic 服务端搜索 |
| Gemini CLI | Gemini API 的 Grounding with Google Search | 真正的 Google Search |
| ChatGPT 网页版 | OpenAI 内置 web search(Bing + 自建索引) | OpenAI 服务端 |
| OpenCode(开源) | 不绑定,可配置任意 provider;多走 MCP | 用户自己接(Tavily / Brave / Serper / MCP server) |
| Cline / Continue / Goose | 通过 MCP server 或自定义工具 | 用户自己接,常见 Tavily / Brave / DuckDuckGo |
6.1 内置型 vs 第三方可配置型
1. 厂商内置型(Codex / Claude Code / Gemini CLI)
搜索在服务端完成,agent 端几乎不写代码:
agent 发 tool_call: web_search("xxx")
→ 请求打到 OpenAI/Anthropic/Google 的 API
→ 服务端执行搜索、抓网页、清洗、rerank
→ 直接返回处理好的结果片段进对话
- 优点:零配置、结果已为 LLM 优化、有引用、计费走 API 账单。
- 缺点:要付平台 API 钱(web search 通常按次额外计费,如 OpenAI web_search $30/1k 次、Anthropic $10/1k 次)、不可控供应商。
Codex CLI 具体是怎么做的:它本身是开源 CLI(TypeScript/Rust),但 web search 不是自己实现的——它把 web_search 作为一个 built-in tool 传给 Responses API,真正的搜索在 OpenAI 服务器上跑,结果回流进对话。CLI 本地只负责沙箱、文件、shell 这些本地工具。
Gemini CLI 最特殊:因为 Google 自己就是搜索引擎,它的 grounding 直接用 真正的 Google Search,质量和覆盖面是所有 agent 里最接近 google.com 的。
2. 第三方/可配置型(OpenCode / Cline / Goose / 自建 agent)
这类不绑定单一厂商,搜索靠外接工具,两条主流路径:
- 直接调搜索 API:在工具函数里
requests.get(tavily/brave/serper),自己处理结果。 - 走 MCP server:装一个 search MCP server(如
@modelcontextprotocol/server-brave-search、Tavily MCP),agent 自动发现并调用。这是 2025 年后开源 agent 的事实标准,换搜索源只换 MCP server,agent 代码不动。
OpenCode 这类"模型无关"agent 必须走这条路——因为它要支持你接任何 LLM(Deepseek/Kimi/Qwen/OpenAI/Anthropic),没有"自家服务端搜索"可用,只能外接。
6.2 为什么厂商 agent 不用 Tavily 这类?
- 体验闭环:搜索 → 抓正文 → rerank → 引用,全在服务端一次搞定,agent 端零代码。
- 数据/质量可控:自己掌控索引和排序(OpenAI 自建+Bing、Google 用自家、Anthropic 自建)。
- 商业化:搜索调用单独计费,是 API 收入的一部分。
- 延迟和成本:服务端可以做缓存、批处理,比客户端逐次调第三方便宜。
七、自己搭 Agent 怎么选
- 已经全用 OpenAI/Anthropic API → 直接开它们内置的
web_search工具,最省事。 - 要换模型、要可控、要省 API 钱 → Tavily(AI 优化)或 Brave(免费额度大)+ MCP server,开源 agent 直接插。
- 要 google.com 级结果 → Gemini CLI 的 grounding,或 Serper(抓 google SERP)。
八、一句话总结
web search = 一个被 LLM 通过 tool calling 驱动的外部 HTTP 搜索函数,外加 query 改写、正文抽取、rerank、多轮迭代等工程增强。 模型从不直接联网,它只是"指挥"联网这件事。
Codex / Claude Code / Gemini CLI 这类"官方 agent"用自家 API 内置的服务端搜索;OpenCode / Cline / Goose 这类"模型无关 agent"靠外接搜索 API 或 MCP server。 第三方搜索 API 的主战场是后者。