Tavily 搜索 API | SandBase
用一个 REST API 运行 Tavily 网页搜索、网页正文抓取和站点结构映射。无需单独 SDK——一个 SandBase 密钥,为 Agent 和 RAG 工作流而生。

Tavily 是一个为 LLM 和 Agent 而建的搜索 API——它返回的不是给人看的一页链接,而是带内容和一个可选合成答案的排名结果,让模型能把输出锚定在真实来源上。它还能抽取网页正文、映射站点结构。这让它成为检索增强生成(RAG)和研究型 Agent 的常见构件。可要自己接,仍意味着再管一个 API 客户端和它的鉴权。
SandBase 的 Tavily 搜索 API 把这些收进一套约定。它通过普通 REST 运行 Tavily 的搜索、抽取和映射能力——一个 SandBase API 密钥,不需要单独的 SDK。端点 API 参考是每个参数和响应信封的权威来源;下面的字段名来自我实际跑的调用(测试于 2026-09-27,UTC),仅供观测——并非文档保证——请以真实响应为准核对,因为负载会随时间变化。想上手?获取 SandBase API 密钥,然后浏览 Tavily 端点。
先说结论
- 三个端点覆盖整个循环:
search(找 + 可选答案)、extract(抓网页正文)、map(发现站点结构)。- 每次调用都是
POST /v1/api/tavily/<path>——只传该端点的参数,无 SDK,一个SANDBASE_API_KEY。- 信封可能不同:参考记录的是
outputs[0].data,但在我的调用里负载常出现在一个顶层output对象下——两种结构都读。- 为 RAG 和 Agent 而生:search 返回结果加一个合成的
answer;extract 和 map 接urls/url。
关于这个端点响应结构的说明
SandBase 端点通常返回一个 outputs 数组,其首个元素在 data 下承载负载;Tavily 参考记录的是这个 outputs[0].data 结构。而在我自己的调用里,负载常出现在单个顶层 output 对象下(search 是 results 加一个 answer,extract 和 map 是 results)。因为信封可能不同,写代码时两种结构都读:优先读顶层 output,再回退到 outputs[0].data。动手前请以你所调用端点的线上参考核对确切信封。
你需要哪个 Tavily 端点?
| 你的需求 | 端点 | 输入 |
|---|---|---|
| 找相关网页,带一个可选答案 | tavily/search | query |
| 抓取特定网页的正文 | tavily/extract | urls |
| 发现一个站点的结构 | tavily/map | url |
SandBase vs. 直接用 Tavily API
| 你的情况 | 用 |
|---|---|
| 想在众多 provider 间用一个密钥、一套约定 | SandBase Tavily API(本文) |
| 需要 Tavily 特有功能或直接计费 | Tavily 自己的 API 和控制台 |
SandBase 在 Tavily 的能力之上提供一层统一的 Model API;当你需要厂商特有控制或直接契约时,用 Tavily 自己的 API。
Tavily API 能取到什么
- 搜索 —
tavily/search接一个query,返回排名results(每条带url、title、content、score)加一个合成的answer。 - 抽取 —
tavily/extract接urls,返回每个网页的raw_content,并用一个failed_results列表列出抓取失败的。 - 映射 —
tavily/map接一个url,在results下返回发现的站点结构,带一个base_url。
动手前请以每个端点的线上 API 参考为准核对参数;可用性因端点而异。
SandBase 上的 Tavily API 页面——带标签的概览和端点列表,每个端点都标了路径。
快速上手:第一次调用
SandBase 暴露不止一个 API 面。目录里可能显示 /apis/v1/... 下的 GET 路径;本文使用每个端点 API 参考上标注的带厂商前缀的 Model API 路径。不要擅自改动 HTTP 方法或 URL——以你所选端点的参考为准。
运行一次搜索:
import os
import requests
resp = requests.post(
"https://api.sandbase.ai/v1/api/tavily/search",
headers={
"Authorization": f"Bearer {os.environ['SANDBASE_API_KEY']}",
"Content-Type": "application/json",
},
json={"query": "best practices for RAG systems"},
)
resp.raise_for_status()
body = resp.json()
if body.get("status") != "completed":
error = body.get("error", {})
raise RuntimeError(error.get("message", "Tavily 请求未完成"))
# 信封可能不同:优先读顶层 output,否则回退到文档的 outputs[0].data。
output = body.get("output")
if output is None and body.get("outputs"):
output = body["outputs"][0].get("data", {})
output = output or {}
for r in output.get("results", [])[:5]:
print(r.get("score"), r.get("title"), "-", r.get("url"))
print("answer:", output.get("answer"))
curl -X POST https://api.sandbase.ai/v1/api/tavily/search \
-H "Authorization: Bearer $SANDBASE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "best practices for RAG systems"}'
响应带一个 id、一个 status、model 名称。参考记录负载在 outputs[0].data 下;在我的调用里它常出现在一个顶层 output 对象下——所以两种结构都读。failed 或 timeout 的运行则带 error,所以先按 status 分支判断。下面的块是示意性的、并非文档保证——我那次搜索调用的一次抓取(搜索 run id a37e8e9d-b389-479d-ae8c-7822d5fe8629,测试于 2026-09-27,UTC);参考的业务负载示例是刻意留空的,所以请把这些字段名当作仅供观测,并对照真实响应核对:
{
"id": "a37e8e9d-b389-479d-ae8c-7822d5fe8629",
"model": "tavily/search",
"status": "completed",
"output": {
"query": "…",
"answer": "…",
"results": [ { "title": "…", "url": "…", "content": "…", "score": 0.0 } ],
"response_time": 0.0
}
}
响应结构因端点而异——请检查一次真实响应,并逐端点确定精确的字段路径。
端点 API 参考是每个参数名和响应路径的事实来源。
串起 search → extract
因为每个端点共享同一套鉴权和一致的 output 信封,Agent 可以把一个 RAG 检索步串起来,而不用为每个面单独写特例:
- 按 query 搜索。 用一个
query调用tavily/search;读output.results,每条带一个url和一个score,外加一个合成的answer。 - 抽取正文。 用你想保留的
urls调用tavily/extract拿每个网页的raw_content。 - 或映射站点。 用一个
url调用tavily/map在定向抽取前发现一个站点的结构。
每一步都返回相同的 { id, status, model, output } 结构,所以你的 Agent 只需按 status 分支一次,并在每一步复用同一段读 JSON 的代码。
Tavily 端点列表的一角。
常见用例
Tavily 搜索 API 做 RAG 检索
用一个 query 运行 tavily/search 拿到带内容和一个合成答案的排名结果,再把靠前的 URL 传给 tavily/extract 取全文。输入:一个 query,再 URL。输出:结果加一个答案,再网页正文。端点:search、extract。
Tavily 抽取 API 做文本抽取
把一组网页 URL 传给 tavily/extract,一次调用抓它们的 raw_content,并用一个 failed_results 列表列出没抓到的。输入:urls。输出:抽取的正文。端点:extract。
Tavily 映射 API 做站点发现
用一个 url 调用 tavily/map 发现一个站点的结构——在跨文档站定向抽取前很有用。输入:一个 url。输出:发现的站点结构。端点:map。
为什么放在 API 层来做
通过一层统一 API 来读 Tavily,意味着你的代码依赖的是有名字的 JSON 字段和单个响应信封,而不是又一个厂商 SDK。鉴权是一个密钥,而且因为每个端点都返回相同的 { id, status, model, output } 结构,重试、日志和错误处理都可以收进一个你写一次、处处复用的辅助函数里。换一个 query、换一组 URL,代码路径完全一样——这正是让一个 RAG 或研究型 Agent 可组合的关键。你的时间花在”检索到的来源对你的任务意味着什么”上,而不是花在把 SDK 粘一起。当你需要的不止这些读取时,在线上列表里查到合适的端点,并在接入前确认它的参数。
局限与边界
- 信封可能不同。 参考记录的是
outputs[0].data;在我的调用里负载常出现在一个顶层output对象下。两种结构都读(优先output,回退outputs[0].data)并按status分支。 extract接urls;map接一个url。 传每个端点各自记录的参数。- 字段仅供观测。 参考保证的是信封;把
results、answer、raw_content、failed_results当作观测到的、以真实响应核对。 - 速率与量级。 把响应当作尽力而为的读取;作为客户端侧的韧性措施,遇到 HTTP 429 等瞬时错误时按退避策略重试。
- 以线上参考核对端点。 可用性和字段可能变化;在依赖某个具体端点前先确认。
常见问题
我需要单独的 Tavily API 密钥或 SDK 吗?
不需要。你用自己的 SANDBASE_API_KEY 向 SandBase 鉴权,通过普通 REST 调用 Tavily 端点——你这边不需要单独的 SDK。
为什么这个面返回 output 而不是 outputs?
参考记录负载在 outputs[0].data 下;在我的调用里它常出现在一个顶层 output 对象下,里面是端点的负载。因为信封可能不同,两种结构都读(优先 output,回退 outputs[0].data),并以线上参考核对。
search 和 extract 有什么区别?
search 按 query 找相关网页、返回结果加一个合成答案;extract 抓你已有的一组 URL 的全文。常见的 RAG 模式是先 search、再 extract 靠前的 URL。
我能用它做 RAG 吗?
能。search → extract 是天然的 RAG 检索步:按 query 找网页、抓它们的正文、喂给你的模型。search 给出的合成 answer 覆盖你想直接要有据回答的场景。
从一次搜索开始
创建一个 SandBase API 密钥,用一个 query 调用 search,在串进 extract 或 map 之前先检查 output。准备好后: