Blog/开发者工具/

Tavily 搜索 API | SandBase

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

深色电影质感画面:Tavily 搜索结果、抓取的网页正文与一张站点地图经由同一条 API 管道汇入 Agent 内核

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/searchquery
抓取特定网页的正文tavily/extracturls
发现一个站点的结构tavily/mapurl

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 上的 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
  }
}

响应结构因端点而异——请检查一次真实响应,并逐端点确定精确的字段路径。

某个 Tavily 端点的 SandBase API 参考,展示带厂商前缀的 URL 和响应结构 端点 API 参考是每个参数名和响应路径的事实来源。

串起 search → extract

因为每个端点共享同一套鉴权和一致的 output 信封,Agent 可以把一个 RAG 检索步串起来,而不用为每个面单独写特例:

  1. 按 query 搜索。 用一个 query 调用 tavily/search;读 output.results,每条带一个 url 和一个 score,外加一个合成的 answer。
  2. 抽取正文。 用你想保留的 urls 调用 tavily/extract 拿每个网页的 raw_content。
  3. 或映射站点。 用一个 url 调用 tavily/map 在定向抽取前发现一个站点的结构。

每一步都返回相同的 { id, status, model, output } 结构,所以你的 Agent 只需按 status 分支一次,并在每一步复用同一段读 JSON 的代码。

SandBase Tavily 端点列表,展示 search、extract 和 map 端点 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。准备好后: