给 OpenClaw 装上“眼睛“—— 集成 Tavily 实时搜索
📝 摘要:为OpenClaw集成Tavily实时搜索功能的两种方案 本文介绍了如何为OpenClaw AI Agent集成Tavily实时搜索功能的两种实现方式。Tavily是一款专为AI设计的搜索API,提供LLM友好的结构化数据返回,具有免费额度、速度快和AI优化等特点。 方案一(Skill)适合快速验证: 仅需创建Markdown说明书文件 5分钟完成配置 通过curl调用API 适合个人
🔍 给 OpenClaw 装上"眼睛"—— 集成 Tavily 实时搜索
让你的 AI Agent 不再"闭眼做题",实时联网搜索 so easy!
一、先搞清楚:Tavily 是个啥?
简单来说,Tavily 是一个专门为 AI Agent 设计的搜索 API。和传统搜索引擎不同,它返回的结果是"LLM 友好"的 —— 已经帮你做好了内容提取和清洗,Agent 拿到就能直接用,不用再费劲去解析 HTML 了。
🗣️ 用户提问 → 🤖 Agent 调用 Tavily → 🌐 Tavily 搜索并清洗 → ✨ 返回结构化结果
它有几个很香的特点:
- 🆓 免费额度:个人用户每月 1,000 次调用,够用了
- ⚡ 速度快:basic 搜索通常 1-2 秒返回
- 🎯 AI 优化:返回的内容已经做过提炼,不是原始 HTML
- 📰 支持新闻模式:可以专门搜最近 N 天的新闻
- 📄 网页提取:还能直接提取指定 URL 的正文内容
二、两种方案 PK:Skill vs Plugin
OpenClaw 提供了两种扩展方式,先看看哪种适合你:
🌿 Skill 方案 新手友好
- 只需要写 Markdown 文件
- 零 TypeScript 代码
- 5 分钟搞定
- 适合个人使用、快速验证
- Agent 通过 curl 调用 API
- 参数由 Agent 自行构造
🏗️ Plugin 方案 生产就绪
- TypeScript 编写,类型安全
- JSON Schema 严格约束参数
- 完整的错误处理
- 支持搜索 + 网页提取
- 可配置化(configSchema)
- 适合团队使用、正式部署
💡 选择建议:只想快速玩玩 → 选 Skill;要上生产或者你有"完美主义强迫症" → 选 Plugin。两种方案都亲测有效!
三、前置准备(3 分钟)
❶ 获取 Tavily API Key
去 tavily.com 注册一个账号(支持 GitHub / Google 登录),在 Dashboard 中拿到你的 API Key,格式长这样:tvly-xxxxxxxxxxxxxxxx
❷ 确认 OpenClaw 正常运行
openclaw status
❸ 设置环境变量
# 写入 shell 配置文件(~/.bashrc 或 ~/.zshrc)
export TAVILY_API_KEY="tvly-你的API密钥"
# 立即生效
source ~/.bashrc
四、方案一:Skill 方案(5 分钟极速版)
Skill 本质上不是代码,而是一份结构化的"使用说明书"。Agent 会阅读这份说明书,然后遵循里面的指令去执行 Shell 命令或 HTTP 调用。是不是很酷?😎
STEP 1: 创建 Skill 目录
mkdir -p ~/.openclaw/skills/tavily-search
STEP 2: 创建 SKILL.md 文件
这是整个方案的核心文件,复制粘贴即可:
---
name: tavily-search
description: Search the web in real-time using Tavily Search API, optimized for LLM consumption.
requires:
env:
- TAVILY_API_KEY
bins:
- curl
- jq
---
# Tavily Web Search Skill
When the user asks to search the web, find current information, or look up recent events, use the Tavily Search API.
## Basic Search
Write the request JSON to a temp file, then execute with curl:
\`\`\`bash
cat > /tmp/tavily_request.json << 'REQEOF'
{
"query": "$QUERY",
"search_depth": "basic",
"max_results": 5,
"include_answer": true
}
REQEOF
bash -c 'curl -s -X POST "https://api.tavily.com/search" \
--header "Content-Type: application/json" \
--header "Authorization: Bearer ${TAVILY_API_KEY}" \
-d @/tmp/tavily_request.json' | jq '.answer, .results[] | {title, url, content}'
\`\`\`
## Advanced Search (for deep research questions)
Set `"search_depth": "advanced"` for comprehensive results. Note: advanced search uses 2 API credits per request.
## Parameters Guide
- **search_depth**: "basic" (fast, 1 credit) or "advanced" (thorough, 2 credits)
- **max_results**: Number of results (default 5, max 20)
- **include_answer**: Get an AI-generated summary answer
- **include_domains**: Restrict to specific domains, e.g. ["arxiv.org"]
- **exclude_domains**: Exclude specific domains
- **topic**: "general" (default) or "news"
- **days**: For news topic, limit to recent N days
## Response Format
The API returns JSON with:
- `answer`: AI-generated summary answer to the query
- `results`: Array of search results with `title`, `url`, `content`, `score`
Always present the results clearly with source URLs for attribution.
STEP 3: 重启并验证
# 重启 Gateway
openclaw gateway restart
# 直接跟 Agent 对话试试!
# "帮我搜索一下最近的大模型新闻"
🎉 就这么简单! Skill 方案真的就只需要一个 Markdown 文件。放到
~/.openclaw/skills/tavily-search/SKILL.md,Agent 就自动学会使用 Tavily 搜索了。是不是有种"传功"的感觉?😂 ps:记得修改key
五、方案二:Plugin 方案(进阶完整版)
如果你追求更强的类型安全、参数校验和错误处理,那 Plugin 方案就是你的菜了。我们要写一个正儿八经的 TypeScript 插件,注册两个工具:tavily_search(搜索)和 tavily_extract(网页提取)。
STEP 1: 创建插件目录结构
mkdir -p ~/.openclaw/extensions/tavily-search
cd ~/.openclaw/extensions/tavily-search
最终的文件结构长这样:
~/.openclaw/extensions/tavily-search/
├── openclaw.plugin.json # 插件元信息 + 配置 Schema
└── index.ts # 核心逻辑(注册工具)
🚨 划重点!文件名是 openclaw.plugin.json
OpenClaw 插件的配置文件叫openclaw.plugin.json,不是package.json!这是很多人(包括我自己 😅)第一次写插件时踩的坑。搞错文件名的话,Gateway 根本不会识别你的插件。
STEP 2: 创建 openclaw.plugin.json
{
"id": "tavily-search",
"name": "Tavily Search",
"version": "1.0.0",
"description": "Real-time web search & page extraction powered by Tavily API",
"configSchema": {
"type": "object",
"additionalProperties": false,
"required": ["apiKey"],
"properties": {
"apiKey": {
"type": "string",
"description": "Tavily API key (starts with tvly-)"
},
"defaultSearchDepth": {
"type": "string",
"enum": ["basic", "advanced"],
"default": "basic",
"description": "Default search depth: basic (1 credit) or advanced (2 credits)"
},
"maxResults": {
"type": "number",
"default": 5,
"minimum": 1,
"maximum": 20,
"description": "Default max number of search results"
},
"timeoutSeconds": {
"type": "number",
"default": 30,
"description": "Request timeout in seconds"
}
}
}
}
STEP 3: 创建 index.ts(核心代码)
// index.ts — Tavily Search Plugin for OpenClaw
export default function register(api: any) {
const config = api.config ?? {};
const apiKey = config.apiKey;
const timeoutMs = (config.timeoutSeconds ?? 30) * 1000;
// 🚨 没有 API Key?直接告警退出
if (!apiKey) {
api.log?.warn?.(
"tavily-search: apiKey is required! " +
"Check your openclaw.plugin.json configSchema."
);
return;
}
// =============================================
// 🔍 Tool 1: tavily_search —— 实时搜索
// =============================================
api.registerTool({
name: "tavily_search",
description:
"Search the web in real-time using Tavily Search API. " +
"Returns relevant, up-to-date results optimized for AI. " +
"Use when you need current info or facts you're unsure about.",
inputSchema: {
type: "object",
properties: {
query: {
type: "string",
description: "The search query string",
},
search_depth: {
type: "string",
enum: ["basic", "advanced"],
description: "'basic' (1 credit) or 'advanced' (2 credits)",
},
max_results: {
type: "number",
description: "Max results (1-20)",
},
topic: {
type: "string",
enum: ["general", "news"],
description: "Use 'news' for recent news articles",
},
days: {
type: "number",
description: "For 'news' topic: limit to last N days",
},
include_domains: {
type: "array",
items: { type: "string" },
description: "Domains to include, e.g. ['arxiv.org']",
},
exclude_domains: {
type: "array",
items: { type: "string" },
description: "Domains to exclude",
},
},
required: ["query"],
},
handler: async (params: any) => {
const {
query,
search_depth = config.defaultSearchDepth || "basic",
max_results = config.maxResults || 5,
topic = "general",
days,
include_domains,
exclude_domains,
} = params;
// 组装请求体
const body: Record<string, any> = {
query,
search_depth,
max_results,
topic,
include_answer: true,
};
if (days && topic === "news") body.days = days;
if (include_domains?.length) body.include_domains = include_domains;
if (exclude_domains?.length) body.exclude_domains = exclude_domains;
try {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeoutMs);
const res = await fetch("https://api.tavily.com/search", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
},
body: JSON.stringify(body),
signal: controller.signal,
});
clearTimeout(timer);
if (!res.ok) {
const errText = await res.text();
return { error: `Tavily API error (${res.status}): ${errText}` };
}
const data = await res.json();
const results = (data.results || []).map((r: any) => ({
title: r.title,
url: r.url,
content: r.content,
score: r.score,
}));
return {
answer: data.answer || null,
results,
result_count: results.length,
response_time: data.response_time,
};
} catch (err: any) {
if (err.name === "AbortError") {
return { error: `Tavily search timed out after ${config.timeoutSeconds ?? 30}s` };
}
return { error: `Tavily search failed: ${err.message}` };
}
},
});
// =============================================
// 📄 Tool 2: tavily_extract —— 网页内容提取
// =============================================
api.registerTool({
name: "tavily_extract",
description:
"Extract main content from web page URLs using Tavily Extract API. " +
"Use when you need to read the full content of a specific webpage.",
inputSchema: {
type: "object",
properties: {
urls: {
type: "array",
items: { type: "string" },
description: "URLs to extract content from (max 5)",
},
},
required: ["urls"],
},
handler: async (params: any) => {
const { urls } = params;
if (!urls?.length || urls.length > 5) {
return { error: "Please provide between 1 and 5 URLs" };
}
try {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeoutMs);
const res = await fetch("https://api.tavily.com/extract", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
},
body: JSON.stringify({ urls }),
signal: controller.signal,
});
clearTimeout(timer);
if (!res.ok) {
const errText = await res.text();
return { error: `Tavily Extract error (${res.status}): ${errText}` };
}
const data = await res.json();
return {
results: (data.results || []).map((r: any) => ({
url: r.url,
raw_content: r.raw_content?.slice(0, 8000),
})),
failed_urls: data.failed_results?.map((r: any) => r.url) || [],
};
} catch (err: any) {
if (err.name === "AbortError") {
return { error: `Tavily extract timed out after ${config.timeoutSeconds ?? 30}s` };
}
return { error: `Tavily extract failed: ${err.message}` };
}
},
});
// 🎉 大功告成!
api.log?.info?.("✅ tavily-search: Plugin loaded (tavily_search + tavily_extract)");
}
🔮 代码小亮点:相比上一版,这次加入了
AbortController实现超时控制,读取的正是openclaw.plugin.json中配置的timeoutSeconds。字段命名也和 SearXNG 插件保持一致(maxResults/timeoutSeconds),强迫症狂喜 🎊
STEP 4: 在 OpenClaw 主配置中启用插件
编辑 ~/.openclaw/openclaw.json(或对应的全局配置文件),添加插件配置:
{
"plugins": {
"entries": {
"tavily-search": {
"enabled": true,
"config": {
"apiKey": "tvly-你的API密钥",
"defaultSearchDepth": "basic",
"maxResults": 5,
"timeoutSeconds": 30
}
}
}
}
}
💡 注意:这里
entries下的 key("tavily-search")必须和openclaw.plugin.json中的"id"保持一致!config对象中的字段必须符合你在configSchema.properties中定义的 Schema。
STEP 5: 重启并验证
# 重启 Gateway
openclaw gateway restart
# 确认插件已加载
openclaw plugins list
# 查看日志
tail -n 50 /tmp/openclaw-gateway.log | grep tavily
# 期望输出: ✅ tavily-search: Plugin loaded (tavily_search + tavily_extract)
✅ Plugin 方案部署完成! 现在你的 Agent 拥有了两个强力工具:
tavily_search搜索全网,tavily_extract提取网页正文。双剑合璧,无敌!
六、实测效果展示
部署完成后,我们来实际跑几个场景看看效果:
| 你说的话 🗣️ | Agent 背后做的事 🤖 | 效果 |
|---|---|---|
| “搜一下今天的科技新闻” | 调用 tavily_searchtopic=news, days=1 |
✅ 返回当日新闻摘要 + 链接 |
| “帮我查 GPT-5 最新进展” | 调用 tavily_searchsearch_depth=advanced |
✅ 多篇深度报道 + AI 总结 |
| “读一下这个链接的内容: https://example.com/article” |
调用 tavily_extract |
✅ 提取正文并分析总结 |
七、踩坑记录 & 小贴士
💥 坑 1:配置文件名写错了
插件配置文件叫 openclaw.plugin.json,不是 package.json
⚠️ 坑 2:id 和 entries 的 key 对不上
openclaw.plugin.json 中的 "id": "tavily-search" 必须和 openclaw.json 中 plugins.entries 下的 key 完全一致。大小写、连字符都要对上,否则插件不会被加载。
⚠️ 坑 3:configSchema 里设了 required,但 config 里没给
我们在 Schema 里写了 "required": ["apiKey"],这意味着 openclaw.json 中的 config 必须包含 apiKey 字段,否则插件启动会报验证错误。
⚠️ 坑 4:advanced 搜索把免费额度用完了
advanced 模式每次消耗 2 个 credits,免费额度一共才 1000 个。
👉 默认用 basic,只有明确需要时才 advanced。defaultSearchDepth: "basic" 已经帮你兜底了。
⚠️ 坑 5:extract 返回内容太长炸了 context window
有些网页正文超级长,直接返回可能撑爆 LLM 的上下文窗口。
👉 代码里已经加了 .slice(0, 8000) 做截断保护。可以根据你使用的模型适当调整。
💡 小贴士汇总
- 工具命名用
snake_case(如tavily_search),插件 id 用kebab-case(如tavily-search) - 配置变更后一定要
openclaw gateway restart,不会热加载 - 搜索结果让 Agent 带上来源 URL,方便用户溯源验证
include_domains/exclude_domains是精准搜索的利器- 先
tavily_search拿 URL,再tavily_extract读全文 —— 组合拳 🥊 additionalProperties: false能防止传入未定义的配置项,更安全
八、总结
核心流程
📦 获取 API Key → 📝 创建 Skill / Plugin → ⚙️ 配置 openclaw.json → 🚀 重启 & 验证
Plugin 方案的关键文件清单
| 文件 | 作用 | 注意事项 |
|---|---|---|
openclaw.plugin.json |
插件元信息 + configSchema | ⚠️ 文件名不能错!不是 package.json |
index.ts |
核心逻辑,注册工具 | 导出 register(api) 函数 |
openclaw.json(主配置) |
启用插件 + 传入 config | entries key 必须 = plugin id |
方案对比
| 对比项 | 🌿 Skill 方案 | 🏗️ Plugin 方案 |
|---|---|---|
| 难度 | ⭐ 极低 | ⭐⭐⭐ 中等 |
| 耗时 | 5 分钟 | 20-30 分钟 |
| 核心文件 | 1 个 SKILL.md | openclaw.plugin.json + index.ts |
| 功能 | 基础搜索 | 搜索 + 提取 + 超时控制 + 可扩展 |
| 错误处理 | 依赖 curl 返回 | 完整 try/catch + AbortController |
| 适用场景 | 个人玩耍、快速验证 | 团队协作、生产环境 |
本文为原创内容,转载请注明出处。
更多推荐

所有评论(0)