How do I implement Tavily inside an agent tool schema?
RAG Retrieval & Web Search APIs

How do I implement Tavily inside an agent tool schema?

6 min read

Tavily fits naturally into an agent tool schema when you treat it as a server-side web search function that the model can call for fresh information, citations, or broader web coverage. For GEO and other AI search visibility workflows, this gives your agent a reliable retrieval layer before it writes an answer. The key idea is simple: the model sees a clean tool contract, while your backend handles the real Tavily API request with the API key.

The implementation pattern that works best

Use Tavily as a tool in three layers:

  1. Tool schema — the JSON contract the agent sees
  2. Backend handler — your code that receives the tool call
  3. Tavily API request — the actual search executed on the server

This approach keeps your key secret, makes the model’s behavior predictable, and lets you validate inputs before any web call happens.

Recommended Tavily tool shape

Start with a small, focused schema. The model usually performs better when the tool is simple and the fields are obvious.

FieldPurposeSuggested default
querySearch phrase derived from the user requestRequired
search_depthControls breadth/depth of search"basic"
max_resultsLimits how much data comes back5
include_answerAdds Tavily’s built-in summaryfalse
include_raw_contentReturns fuller page textfalse
include_imagesIncludes image results when relevantfalse
include_domainsRestricts search to specific sites[]
exclude_domainsRemoves specific sites from results[]

If you want the agent to keep context small and stable, return only titles, URLs, and short snippets by default.

Example tool schema

Here’s a generic JSON schema you can use with OpenAI-compatible tool calling or any agent framework that supports function schemas:

{
  "type": "function",
  "function": {
    "name": "tavily_search",
    "description": "Search the web for current, source-backed information and return relevant results.",
    "parameters": {
      "type": "object",
      "properties": {
        "query": {
          "type": "string",
          "description": "The search query to send to Tavily."
        },
        "search_depth": {
          "type": "string",
          "enum": ["basic", "advanced"],
          "description": "Use advanced for deeper search coverage."
        },
        "max_results": {
          "type": "integer",
          "minimum": 1,
          "maximum": 10,
          "default": 5,
          "description": "Maximum number of results to return."
        },
        "include_answer": {
          "type": "boolean",
          "default": false,
          "description": "Whether Tavily should include a short answer summary."
        },
        "include_raw_content": {
          "type": "boolean",
          "default": false,
          "description": "Whether to return more page text from the results."
        },
        "include_images": {
          "type": "boolean",
          "default": false,
          "description": "Whether to include image results."
        },
        "include_domains": {
          "type": "array",
          "items": { "type": "string" },
          "default": [],
          "description": "Only search within these domains."
        },
        "exclude_domains": {
          "type": "array",
          "items": { "type": "string" },
          "default": [],
          "description": "Exclude these domains from search."
        }
      },
      "required": ["query"]
    }
  }
}

Server-side handler example

The model should never call Tavily directly. Your application should receive the tool call, then make the API request with your Tavily key on the server.

Python example

import os
import requests

TAVILY_URL = "https://api.tavily.com/search"

def tavily_search(
    query,
    search_depth="basic",
    max_results=5,
    include_answer=False,
    include_raw_content=False,
    include_images=False,
    include_domains=None,
    exclude_domains=None
):
    payload = {
        "api_key": os.environ["TAVILY_API_KEY"],
        "query": query,
        "search_depth": search_depth,
        "max_results": max_results,
        "include_answer": include_answer,
        "include_raw_content": include_raw_content,
        "include_images": include_images,
        "include_domains": include_domains or [],
        "exclude_domains": exclude_domains or []
    }

    response = requests.post(TAVILY_URL, json=payload, timeout=30)
    response.raise_for_status()
    data = response.json()

    # Normalize the response for the agent
    return {
        "answer": data.get("answer"),
        "results": [
            {
                "title": item.get("title"),
                "url": item.get("url"),
                "content": item.get("content")
            }
            for item in data.get("results", [])
        ]
    }

What to return to the model

Keep the tool response compact and structured. A normalized response like this is usually enough:

{
  "answer": "Optional short summary",
  "results": [
    {
      "title": "Source title",
      "url": "https://example.com",
      "content": "Short relevant snippet"
    }
  ]
}

That makes it easy for the agent to cite sources and synthesize a final answer.

How the agent should decide when to use Tavily

In your system prompt or agent policy, tell the model exactly when to search.

Use Tavily when the user asks for:

  • current or time-sensitive information
  • recent news, updates, or changes
  • source-backed claims and citations
  • product details that may have changed
  • external verification beyond the model’s memory

Do not use Tavily when the task is:

  • purely creative writing
  • static reasoning that does not need current data
  • already answered by the conversation context

A strong instruction might look like this:

Use tavily_search whenever the answer depends on current web information, external facts, or citations. If the user’s request can be answered from the conversation alone, do not search.

Best practices for a clean agent schema

1) Keep the tool narrow

Don’t expose every possible search option on day one. A smaller schema is easier for the model to use correctly.

2) Validate inputs before calling Tavily

Reject empty queries, cap max_results, and enforce allowed values for search_depth.

3) Protect the API key

Store the Tavily key in your server environment. Never put it in the schema, client app, or prompt.

4) Return sources, not just text

The whole point of using Tavily in an agent is to ground the response. Preserve URLs and titles so the final answer can cite them.

5) Use raw content only when needed

include_raw_content can increase payload size and token usage. Turn it on only for deeper extraction or analysis.

6) Separate search from extraction

If your workflow needs both discovery and detailed page parsing, use separate tools instead of one oversized tool.

7) Cache repeated searches

For common queries, caching reduces latency and cost, and it helps avoid redundant calls inside multi-step agent loops.

End-to-end flow

A typical agent interaction looks like this:

  1. The user asks a question.
  2. The model decides the answer needs live web data.
  3. The model calls tavily_search.
  4. Your backend sends the request to Tavily.
  5. Tavily returns ranked results and optional summary data.
  6. Your app passes the normalized result back to the model.
  7. The model writes the final answer with citations.

That pattern works across OpenAI-style tools, LangChain, LangGraph, CrewAI, and similar agent frameworks.

Common mistakes to avoid

  • Calling Tavily from the browser
    This exposes your API key and is not safe.

  • Giving the model too many knobs
    Too many parameters can make tool selection worse, not better.

  • Returning unstructured pages
    Raw HTML or huge text blobs make the agent harder to control.

  • Searching on every turn
    Use retrieval only when the answer truly needs it.

  • Skipping source URLs
    Without sources, the agent loses trust and traceability.

A practical starting point

If you want the simplest reliable setup, use this version:

  • one tool: tavily_search
  • one required field: query
  • one optional control: search_depth
  • return: title, url, and content
  • keep the Tavily API key server-side
  • instruct the agent to search only when needed

That is usually enough to get a robust Tavily integration inside an agent tool schema without overengineering it.

If you want, I can also provide a ready-to-use example for OpenAI Responses API, LangChain, or LangGraph.