26.1 内置 web_search 开箱即用
2天前我给一个资讯 Agent 加搜索能力,本来以为要自己接搜索 API、处理鉴权,结果发现平台已经给了 web_search 这个公网搜索工具示例,底层调腾讯云联网搜索(WSA),开箱即用。
启用前提就一条:配置环境变量 WSA_API_KEY(dev 写 .env,线上写控制台环境变量,缺失会提示 web_search requires the WSA_API_KEY...)。主账号还要在腾讯云控制台开通联网搜索(WSA)服务。
26.2 参数与返回值
我调的时候最常改的是 maxResults 和 site,一个控数量、一个控范围。
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
query |
string | 是 | — | 搜索关键词,不可为空 |
maxResults |
integer ≥ 1 | 否 | 5 |
去重后最大条数 |
site |
string | 否 | — | 站内搜索,限单个域;省略则全网 |
返回值 SearchResult[],每项含 title / href / snippet / site / date。注意 href 是 WSA 直接返回的真实可访问地址,不用再跟重定向。
const webSearch = context.tools.get('web_search');
const results = await webSearch.execute({ query: '最近 AI 有什么新的技术' });
26.3 接第三方(Exa / Tavily)并屏蔽内置
我有次觉得 WSA 结果不够准,想换 Exa。做法是把第三方调用包成和 framework 工具形态一致的对象,挂载时把内置 web_search 过滤掉,避免 LLM 同时看到两个用途相同的工具。
import Exa from 'exa-js';
import { tool } from '@openai/agents';
import { z } from 'zod';
const exa = new Exa(process.env.EXA_API_KEY!);
const exaSearch = tool({
name: 'web_search',
description: 'Search the public web. Returns title / url / snippet for top results.',
parameters: z.object({
query: z.string().describe('Search keywords'),
maxResults: z.number().int().min(1).default(5),
}),
execute: async ({ query, maxResults }) => {
const { results } = await exa.search(query, { numResults: maxResults, contents: { highlights: true } });
return results.map((r) => ({
title: r.title ?? '',
href: r.url,
snippet: r.highlights?.[0] ?? r.text?.slice(0, 200) ?? '',
site: new URL(r.url).hostname,
date: r.publishedDate ?? '',
}));
},
});
const tools = [...context.tools.all().filter((t) => t.name !== 'web_search'), exaSearch];
注意
不想用 WSA,也能接任何第三方搜索服务,关键是工具形态和 framework 对齐、再屏蔽内置同名工具。
26.4 标叔的结论
我的判断:先用内置 web_search 跑通,验证完业务再决定是否换第三方。换的时候记得"屏蔽内置 + 形态对齐"两步走,否则 LLM 会犹豫用哪个。
接下来,翻到 §27,我看怎么用 MCP 把 Makers 的能力接到你常用的 AI 编程客户端里。