在 AI Agent 中集成 Bing 网络搜索:@agent-infra/bing-search 类型安全客户端完全指南
@agent-infra/bing-search 是 GitHub Trending 精选开源仓库 UI-TARS-desktop(其开源多模态 AI Agent 技术栈的 monorepo 汇聚了 agent-infra、agent-tars、tarko 等多个面向 Agent 的工程包)中位于 packages/agent-infra/search/bing-search 的一个轻量级 TypeScript 客户端,用于对接微软 Bing Search API。本文面向需要在 Agent 应用中接入实时网络检索能力的开发者,围绕该包的配置项、调用 API、响应结构与环境变量约定展开完整讲解,并结合仓库源码剖析其底层实现(默认 Base URL、认证请求头注入、fetch 参数拼接逻辑等)。读完本文,你将掌握如何用最少的外部依赖,为 LLM Agent、RAG 管线或浏览器操作型 Agent 快速接入 Bing Web Search,并在统一搜索抽象中同时编排多种搜索服务。
一、包定位:agent-infra 搜索体系中的一员
@agent-infra/bing-search 归属于仓库内的 packages/agent-infra/search 目录,该目录下并列了多个搜索实现:
bing-search:本文主角,微软 Bing Search API 的零依赖 TypeScript 客户端;duckduckgo-search:DuckDuckGo 搜索适配;browser-search:浏览器引擎搜索适配(含 benchmark 与多引擎示例);search:上层统一搜索抽象包,将不同搜索服务封装为统一的SearchProvider入口。
从 packages/agent-infra/search/search/src/index.ts 可以看出,@agent-infra/search 会直接复用本包导出的 BingSearchClient、BingSearchConfig 与 BingSearchOptions,并在 provider === SearchProvider.BingSearch 分支下创建客户端实例执行搜索。因此,理解 bing-search 的配置与类型约定,也是深入使用统一搜索层的基础。
包本身被定位为 面向 AI 应用 的搜索能力组件:Agent 在执行需要事实查证、时效信息获取或 Web 内容抓取的任务时,可以把 search() 的返回结果作为上下文喂给大模型,或用于构建带引用的 RAG 答案。
二、核心特性
根据 README 与 package.json,该包的设计目标可归纳为四点:
- Type-safe(类型安全):覆盖
BingSearchOptions、BingSearchResponse、WebPage、Image、Video等完整类型定义,编译期即可校验查询参数与响应字段(见 api-client.ts); - Configurable(高度可配置):Base URL、API Key、自定义请求头、日志器均可按需注入,并支持环境变量覆盖;
- Minimal(极简):运行时零外部依赖——生产依赖仅声明了工作区内的
@agent-infra/logger(见 package.json),网络请求直接使用 Node.js/浏览器内置的fetch; - Developer-friendly(开发者友好):Promise 风格异步 API,仅需
new BingSearchClient(...)+await client.search(...)两步即可完成一次搜索。
三、安装
在任意 Node.js 项目中安装即可(仅该单一 npm 包,无需连带安装其他 agent-infra 包):
npm install @agent-infra/bing-search
# 或
yarn add @agent-infra/bing-search
# 或
pnpm add @agent-infra/bing-search
若要在本仓库 monorepo 内直接调试源码,也可在 packages/agent-infra/search/bing-search 目录执行 pnpm install 后运行测试或示例。包构建采用 @rslib/core,同时产出 ESM 与 CJS 双格式并生成 d.ts 类型声明(见 rslib.config.ts),因此无论项目的模块体系是 import 还是 require 均能使用。
四、快速开始
4.1 基础搜索
最典型用法是显式传入 API Key,然后调用 search():
import { BingSearchClient } from '@agent-infra/bing-search';
const client = new BingSearchClient({
apiKey: 'YOUR_API_KEY',
});
const results = await client.search({
q: 'climate change',
count: 5,
});
console.log(results.webPages?.value);
q 为必填查询词,count 表示希望返回的结果条数。返回的 results.webPages.value 是结构化网页结果数组,每一项包含标题 name、链接 url、摘要 snippet 等字段,适合直接注入 LLM 上下文。
4.2 通过环境变量注入密钥(推荐)
为避免把密钥硬编码进代码,包在 getBingSearchConfig()(src/config.ts)中内置了环境变量兜底逻辑,支持两个变量:
BING_SEARCH_API_KEY:Bing API 订阅密钥;BING_SEARCH_API_BASE_URL:自定义 API 地址(如自建代理网关时)。
// 在你的环境变量中设置:
// BING_SEARCH_API_KEY=your-api-key
import { BingSearchClient } from '@agent-infra/bing-search';
const client = new BingSearchClient();
const results = await client.search({ q: 'renewable energy' });
console.log(results.webPages?.value);
注意:不传任何配置直接 new BingSearchClient() 也是合法的——此时 apiKey 会回落到环境变量,若两者皆为空则 apiKey 为空字符串,请求会因缺少 Ocp-Apim-Subscription-Key 请求头而返回 401。因此生产环境务必确保密钥已注入。
4.3 配置优先级规则
从 src/config.ts 第 35~52 行的实现可以看到如下优先级(高 → 低):
- 构造时传入的
options.apiKey/options.baseUrl; - 环境变量
BING_SEARCH_API_KEY/BING_SEARCH_API_BASE_URL; - 内置默认值(Base URL 为
https://api.bing.microsoft.com/v7.0)。
请求头合并逻辑为:先注入认证头 Ocp-Apim-Subscription-Key: <apiKey>,再用 options.headers 做展开覆盖,因此你可以用自定义 headers 追加额外的请求头或覆盖默认头。
4.4 获取预配置单例
包在模块底部额外导出了默认单例:
import { bingSearchClient } from '@agent-infra/bing-search';
const results = await bingSearchClient.search({ q: 'latest AI news', count: 3 });
该单例在模块加载时以默认配置(即纯环境变量驱动)初始化(见 api-client.ts),适合配置统一、直接复用全局实例的场景。
五、接入自定义日志器
搜索客户端在 search() 前后会输出结构化日志。默认使用 defaultLogger(来自 @agent-infra/logger 的静默 BaseLogger 实例),若要观测请求参数与客户端配置,可注入带前缀的 ConsoleLogger:
import { ConsoleLogger } from '@agent-infra/logger';
import { BingSearchClient } from '@agent-infra/bing-search';
const logger = new ConsoleLogger('[BingSearch]');
const client = new BingSearchClient({
apiKey: 'YOUR_API_KEY',
logger,
});
const results = await client.search({ q: 'machine learning' });
从源码(api-client.ts)看,客户端构造时会打印一次 client config,每次 search() 会打印 search params,便于调试传入的真实参数。
Logger 接口定义于 packages/agent-infra/logger/src/types.ts,提供 log/info/warn/error/debug/success 等方法,并支持通过 spawn(subPrefix) 派生子日志器。你也可以实现该接口传入自定义日志器(如接入 Electron 主进程日志、远端日志上报等)。
六、客户端配置与 Search 方法 API
6.1 new BingSearchClient(config?)
constructor(config?: Partial<BingSearchConfig>)
BingSearchConfig 字段(定义见 src/config.ts):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
baseUrl |
string |
否 | API 基础地址,默认 https://api.bing.microsoft.com/v7.0,可通过环境变量 BING_SEARCH_API_BASE_URL 覆盖 |
apiKey |
string |
否 | Bing API 订阅密钥,可通过环境变量 BING_SEARCH_API_KEY 覆盖 |
headers |
Record<string, string> |
否 | 自定义请求头,会与自动注入的认证头合并(同名覆盖) |
logger |
Logger |
否 | 日志器,默认使用 @agent-infra/logger 的 defaultLogger |
6.2 await client.search(params)
async search(params: BingSearchOptions): Promise<BingSearchResponse>
BingSearchOptions 字段(定义见 api-client.ts):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
q |
string |
是 | 搜索查询词(query) |
count |
number |
否 | 单次返回的结果条数,用于控制上下文长度 |
offset |
number |
否 | 结果偏移量,配合 count 实现分页拉取 |
mkt |
string |
否 | 市场代码,如 en-US,用于限定返回结果的区域与语言偏好 |
safeSearch |
'Off' | 'Moderate' | 'Strict' |
否 | 成人内容过滤等级(关闭 / 中等 / 严格),面向 Agent 场景建议 Strict 或 Moderate |
[key: string] |
any |
否 | 索引签名,允许透传 Bing Search API 支持的其他查询参数(如 freshness、responseFilter、textDecorations 等) |
补充说明:得益于
[key: string]: any的透传设计,新增 Bing API 参数无需等待本包发版即可直接使用;q、count、safeSearch等命名含义遵循 Bing Web Search API 约定。实际调用前建议到 Bing 开发者后台确认当前订阅套餐支持的接口版本与参数。
七、响应类型结构
search() 返回 BingSearchResponse(完整定义见 api-client.ts),为一次 HTTP 响应反序列化后的对象。除顶层 _type、queryContext.originalQuery(回显原始查询词)外,主要按类型分组:
7.1 Web 网页结果 webPages
webPages?: {
value: WebPage[];
totalEstimatedMatches?: number; // 估算匹配总数
someResultsRemoved?: boolean;
webSearchUrl?: string;
}
其中单个 WebPage 的字段包括:
name:网页标题;url:网页地址;snippet:文本摘要(Agent 场景中最常用的上下文片段);dateLastCrawled?:Bing 最近一次抓取该页的时间;displayUrl?、id?、siteName?、language?、thumbnailUrl?;isFamilyFriendly?、isNavigational?、noCache?等布尔标记。
7.2 图片与视频结果 images / videos
当查询与图片/视频高度相关时,Bing 也会返回对应分组:
Image:含contentUrl、thumbnailUrl、hostPageUrl、encodingFormat、width/height、thumbnail尺寸等;Video:含name、description、contentUrl、duration、viewCount?、creator?、publisher?、embedHtml、allowHttpsEmbed等。
7.3 排序信息 rankingResponse
rankingResponse.mainline.items 提供回答类型与结果索引的排序结构,可用于判断不同分组在结果页中的展示顺序。
实践建议:Agent 做问答引用时,通常优先取 results.webPages?.value,按序拼接 name + snippet + url 作为带来源的上下文;图片/视频类任务再按需消费 images、videos 分组。
八、底层实现与错误处理(源码级)
search() 的实现非常直白(api-client.ts):
- 用
URLSearchParams遍历params,跳过值为undefined的键,把其余参数追加为查询字符串; - 发起
GET ${baseUrl}?${queryParams},携带已合并的请求头(含Ocp-Apim-Subscription-Key认证头); - 网络层使用原生
fetch,不依赖 axios 等第三方 HTTP 库——这是包"零运行时依赖"的关键; - 若
response.ok === false(HTTP 非 2xx),抛出Bing search failed: <status> <statusText>错误并继续抛出;非网络类异常会先console.error再上抛,交由调用方处理。
因此在调用侧应当用 try/catch 包裹,典型处理如下:
try {
const results = await client.search({ q: 'UI-TARS', count: 5 });
console.log(`Found ${results.webPages?.value.length || 0} results`);
} catch (error) {
console.error('Search failed:', error);
// 401:API Key 缺失/无效;429:触发限流;500:Bing 服务端异常
}
九、可运行的完整示例
仓库在 examples/default.ts 中给出了一个可直接运行的最小示例,它同时演示了 环境变量取密钥 + 自定义 Logger + 结果打印 三种能力的组合:
import { ConsoleLogger } from '@agent-infra/logger';
import { BingSearchClient } from '../src';
async function runExample() {
const logger = new ConsoleLogger('[BingSearch]');
try {
const client = new BingSearchClient({
baseUrl: process.env.BING_SEARCH_API_BASE_URL,
apiKey: process.env.BING_SEARCH_API_KEY,
logger,
});
const results = await client.search({
q: 'UI-TARS',
count: 5,
});
console.log(JSON.stringify(results.webPages, null, 2));
console.log(`Found ${results.webPages?.value.length || 0} results`);
} catch (error) {
console.error('Search with options failed:', error);
}
}
if (require.main === module) {
runExample().catch(console.error);
}
运行前设置好环境变量即可:
export BING_SEARCH_API_KEY=your-api-key
# 可选:export BING_SEARCH_API_BASE_URL=https://api.bing.microsoft.com/v7.0
cd packages/agent-infra/search/bing-search
npx ts-node examples/default.ts
你也可以在 packages/agent-infra/search/search/examples/default.ts 中查看本包被 @agent-infra/search 统一搜索层编排调用的多引擎示例(multi-engine.ts),了解多搜索源并发/兜底的使用形态。
十、适用场景与边界
- 适合:LLM 应用的事实核查与联网检索、RAG 系统补充实时信息、Agent 的"搜索→摘要→引用"链路、作为统一搜索抽象中的一个 provider。
- 需要注意:客户端仅负责把 Bing Search API 的响应 JSON 原样返回并做类型标注,不内置请求缓存、限流排队或重试退避,高并发或长链路任务建议在业务层自行封装;API Key 走 Azure/微软配额计费,请按需控制
count与请求频率。 - 许可:包遵循 Apache License 2.0(版权归 ByteDance, Inc. 及其关联方所有,见 README),二次分发与商业使用请遵守对应条款。
结语
@agent-infra/bing-search 以"类型安全 + 零运行时依赖 + Promise API"三个简单承诺,把 Bing Web Search 能力压缩成一个可在任意 Agent/Node 应用中两行接好的模块;配合 BING_SEARCH_API_KEY 环境变量、可注入的 Logger,以及可由 @agent-infra/search 统一编排的 provider 设计,它为多模态 Agent 技术栈提供了一条低摩擦的联网检索路径。如需深挖实现,可直接阅读 src/config.ts 与 src/api-client.ts 两份核心源码。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00