12.2 Tavily API 集成

Tavily 服务介绍

Tavily 是专为 AI Agent 和 LLM 应用设计的搜索引擎 API。与传统搜索引擎不同,Tavily 针对 AI 应用场景进行了优化。

核心特性

特性 描述
AI 优化 返回格式直接适合 LLM 处理
答案摘要 内置 AI 生成的答案摘要
结构化数据 JSON 格式,易于解析
深度搜索 可选的内容提取功能
主题过滤 支持按主题分类搜索

与传统搜索 API 的区别

1
2
3
4
5
6
7
8
9
10
11
传统搜索 API (如 Bing):
├── 返回 HTML/JSON
├── 需要自己提取内容
├── 需要总结处理
└── 成本较高

Tavily API:
├── 返回结构化 JSON
├── 内置答案摘要
├── 直接可用
└── 成本较低

API 注册与配置

获取 API Key

  1. 访问官网https://tavily.com

  2. 注册账户

    • 点击 “Sign Up”
    • 使用 Google/GitHub 账户或邮箱注册
    • 验证邮箱
  3. 获取 API Key

    • 登录后进入 Dashboard
    • 在 API Keys 部分创建新 Key
    • API Key 格式:tvly-xxxxxxxxxxxxxxxxxxxxx

免费额度

计划 价格 搜索次数/月
Free $0 1,000 次
Growth $5/月 5,000 次
Standard $20/月 25,000 次

配置 API Key

方式 1:环境变量

1
2
3
4
5
# .env 文件
TAVILY_API_KEY=tvly-xxxxxxxxxxxxxxxxxxxxx

# 或直接导出
export TAVILY_API_KEY=tvly-xxxxxxxxxxxxxxxxxxxxx

方式 2:config.json

1
2
3
4
5
6
7
8
{
"search": {
"provider": "tavily",
"apiKey": "tvly-xxxxxxxxxxxxxxxxxxxxx",
"maxResults": 5,
"searchDepth": "basic"
}
}

方式 3:代码中直接使用

1
2
3
import { createTavilyClient } from "./search/tavily-client.js";

const client = createTavilyClient("tvly-xxxxxxxxxxxxxxxxxxxxx");

SDK 集成

安装依赖

1
npm install @tavily/core

类型定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// src/search/types.ts

/**
* 搜索选项
*/
export interface SearchOptions {
/** 搜索查询关键词或问题 */
query: string;
/** 返回结果数量 (默认 5,最多 10) */
maxResults?: number;
/** 搜索深度 (basic: 快速, advanced: 深度) */
searchDepth?: 'basic' | 'advanced';
/** 搜索时间范围(天数) */
days?: number;
/** 搜索主题 */
topic?: string;
/** 是否包含 AI 答案摘要 */
includeAnswer?: boolean;
/** 是否包含原始内容 */
includeRawContent?: boolean;
/** 是否包含图像 */
includeImages?: boolean;
}

/**
* 搜索结果项
*/
export interface SearchResultItem {
/** 结果标题 */
title: string;
/** 结果 URL */
url: string;
/** 内容片段 */
content: string;
/** 相关性评分 */
score: number;
/** 发布日期 */
publishedDate?: string;
}

/**
* Tavily API 响应
*/
export interface TavilyResponse {
/** AI 生成的答案摘要 */
answer: string;
/** 搜索查询 */
query: string;
/** 搜索结果列表 */
results: SearchResultItem[];
/** 图像结果 */
images?: Array<{
url: string;
description: string;
}>;
}

客户端实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// src/search/tavily-client.ts

import { tavily } from '@tavily/core';
import type { SearchOptions, TavilyResponse, ISearchService } from './types.js';

/**
* Tavily 搜索客户端
*/
export class TavilyClient implements ISearchService {
private client: ReturnType<typeof tavily> | null = null;
private apiKey: string;
private available: boolean = true;

/**
* 创建 Tavily 客户端
* @param apiKey Tavily API Key
*/
constructor(apiKey: string) {
this.apiKey = apiKey;

// 验证 API Key
if (!apiKey || apiKey.trim() === '' || apiKey.startsWith('your-')) {
console.warn('[Tavily] API Key 未配置或无效');
this.available = false;
return;
}

// 初始化客户端
try {
this.client = tavily({ apiKey: this.apiKey });
console.log('[Tavily] 客户端初始化成功');
} catch (error) {
console.error('[Tavily] 客户端初始化失败:', error);
this.available = false;
}
}

/**
* 检查服务是否可用
*/
isAvailable(): boolean {
return this.available;
}

/**
* 执行搜索
* @param options 搜索选项
* @returns 搜索结果
*/
async search(options: SearchOptions): Promise<TavilyResponse> {
if (!this.available || !this.client) {
throw new Error('Tavily 服务不可用');
}

console.log(`\n[Tavily] 搜索: "${options.query}"`);
console.log(` 深度: ${options.searchDepth || 'basic'}`);
console.log(` 结果数: ${options.maxResults || 5}`);

// 调用 Tavily API
const response = await this.client.search(options.query, {
maxResults: options.maxResults || 5,
searchDepth: options.searchDepth || 'basic',
includeAnswer: options.includeAnswer !== false,
includeRawContent: options.includeRawContent ? 'markdown' : false,
includeImages: options.includeImages || false,
days: options.days,
topic: options.topic,
});

// 转换结果格式
const result: TavilyResponse = {
answer: response.answer || '',
query: options.query,
results: (response.results || []).map((item) => ({
title: item.title || '',
url: item.url || '',
content: item.content || '',
score: item.score || 0,
publishedDate: item.publishedDate,
})),
};

console.log(`[Tavily] 搜索完成,找到 ${result.results.length} 个结果\n`);

return result;
}
}

/**
* 创建 Tavily 客户端实例
*/
export function createTavilyClient(apiKey?: string): TavilyClient {
const key = apiKey || process.env.TAVILY_API_KEY || '';
return new TavilyClient(key);
}

API 调用示例

基础搜索

1
2
3
4
5
6
7
8
9
10
11
12
13
import { createTavilyClient } from './search/tavily-client.js';

const client = createTavilyClient();

// 执行搜索
const result = await client.search({
query: 'React 19 新特性',
maxResults: 5,
searchDepth: 'basic',
});

console.log(result.answer);
console.log(result.results);

深度搜索

1
2
3
4
5
6
const result = await client.search({
query: 'TypeScript 高级类型',
maxResults: 5,
searchDepth: 'advanced', // 包含正文内容提取
includeRawContent: true,
});

新闻搜索

1
2
3
4
5
6
const result = await client.search({
query: 'AI 最新进展',
topic: 'news', // 新闻主题
days: 3, // 最近 3 天
maxResults: 10,
});

财经搜索

1
2
3
4
5
const result = await client.search({
query: '比特币价格分析',
topic: 'finance',
maxResults: 5,
});

响应格式解析

完整响应示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"answer": "React 19 引入了多个新特性,包括服务器组件(Server Components)的稳定版本、新的 Actions API、改进的表单处理、以及更好的并发渲染支持...",
"query": "React 19 新特性",
"results": [
{
"title": "React 19 发布公告",
"url": "https://react.dev/blog/2024/12/19/react-19",
"content": "React 19 正式发布,引入了服务器组件、Actions 等...",
"score": 0.95,
"publishedDate": "2024-12-19"
},
{
"title": "React 19 新特性详解",
"url": "https://dev.to/react-19-features",
"content": "详细介绍 React 19 的所有新功能...",
"score": 0.87,
"publishedDate": "2024-12-20"
}
]
}

字段说明

字段 类型 描述
answer string AI 生成的答案摘要
query string 原始搜索查询
results array 搜索结果列表
results[].title string 结果标题
results[].url string 结果链接
results[].content string 内容摘要
results[].score number 相关性评分 (0-1)
results[].publishedDate string 发布日期(可选)

错误处理

常见错误类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 1. API Key 无效
if (!apiKey || apiKey.startsWith('your-')) {
throw new Error('Tavily API Key 未配置或无效');
}

// 2. 服务不可用
if (!this.client) {
throw new Error('Tavily 服务初始化失败');
}

// 3. API 调用失败
try {
const result = await this.client.search(options);
} catch (error) {
if (error.response?.status === 401) {
throw new Error('API Key 无效或已过期');
}
if (error.response?.status === 429) {
throw new Error('API 请求次数超限');
}
throw new Error(`搜索失败: ${error.message}`);
}

优雅降级

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 安全搜索包装器
*/
async function safeSearch(
client: TavilyClient,
query: string
): Promise<TavilyResponse | null> {
try {
if (!client.isAvailable()) {
console.warn('搜索服务不可用,跳过搜索');
return null;
}
return await client.search({ query });
} catch (error) {
console.error(`搜索失败: ${error.message}`);
return null;
}
}

性能优化

请求参数优化

1
2
3
4
5
6
7
8
9
10
11
12
13
// 快速搜索(默认)
{
searchDepth: 'basic', // 只返回标题和摘要
maxResults: 5, // 限制结果数量
includeImages: false, // 不包含图像
}

// 深度搜索(需要详细信息时)
{
searchDepth: 'advanced', // 包含正文内容
maxResults: 10,
includeRawContent: true, // 返回完整内容
}

响应时间对比

search_depth 响应时间 数据量
basic ~2-3 秒 标题+摘要
advanced ~5-10 秒 包含正文

小结

本节介绍了 Tavily API 的集成:

  • Tavily 服务特性和优势
  • API 注册和配置
  • SDK 集成方法
  • API 调用示例
  • 响应格式解析
  • 错误处理和性能优化

导航

上一篇: 12.1 搜索能力的重要性

下一篇: 12.3 搜索工具实现