EdgeOne Makers 从入门到精通
附录

§26 联网搜索与自定义工具

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 参数与返回值

我调的时候最常改的是 maxResultssite,一个控数量、一个控范围。

参数 类型 必填 默认 说明
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 编程客户端里。