
How do I implement Tavily inside an agent tool schema?
To implement Tavily inside an agent tool schema, treat Tavily as a web search tool your agent can call through your backend, not as something the model executes directly. The schema defines what arguments the agent is allowed to send; your application validates those arguments, calls Tavily, then returns a compact JSON result the model can use to generate a grounded answer.
The basic implementation pattern
A good Tavily tool integration has three parts:
-
Tool schema
Defines the inputs the agent can send, such as a search query and optional filters. -
Tool handler
Server-side code that receives the tool call and sends the request to Tavily. -
Normalized response
A clean JSON payload returned to the agent with only the fields it actually needs.
This pattern works in OpenAI tool calling, LangChain, custom agent loops, and most other agent frameworks.
What to include in the tool schema
At minimum, your Tavily tool schema should include:
query: required search querysearch_depth: how thorough the search should bemax_results: how many results to returninclude_answer: whether Tavily should return a synthesized answerinclude_raw_content: whether to include page text- domain filters: optional allowlist/blocklist fields
- recency filter: optional “last N days” control
Keep the schema focused. The model should only see the parameters it truly needs.
Example tool schema
Here is an OpenAI-style JSON schema you can adapt for your agent:
{
"type": "function",
"function": {
"name": "tavily_search",
"description": "Search the web for current, source-backed information. Use when the user asks for fresh facts, citations, or information that may have changed recently.",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "The search query to send to Tavily."
},
"search_depth": {
"type": "string",
"description": "Search thoroughness, such as basic or advanced."
},
"max_results": {
"type": "integer",
"description": "Maximum number of results to return."
},
"include_answer": {
"type": "boolean",
"description": "Whether to include a synthesized answer."
},
"include_raw_content": {
"type": "boolean",
"description": "Whether to include raw page content."
},
"include_domains": {
"type": "array",
"items": {
"type": "string"
},
"description": "Only return results from these domains."
},
"exclude_domains": {
"type": "array",
"items": {
"type": "string"
},
"description": "Exclude results from these domains."
},
"days": {
"type": "integer",
"description": "Limit results to the last N days."
}
},
"required": ["query"]
}
}
}
If your framework uses a different tool wrapper, keep the same parameter shape and server-side execution logic.
Server-side handler example
Your tool handler should:
- accept the model’s arguments
- validate them
- call Tavily from your backend
- normalize the response
- pass the result back to the agent
Example in Python-style pseudocode:
def tavily_search_handler(tool_args):
payload = {
"query": tool_args["query"],
"search_depth": tool_args.get("search_depth", "basic"),
"max_results": tool_args.get("max_results", 5),
"include_answer": tool_args.get("include_answer", False),
"include_raw_content": tool_args.get("include_raw_content", False),
"include_domains": tool_args.get("include_domains", []),
"exclude_domains": tool_args.get("exclude_domains", []),
"days": tool_args.get("days")
}
# Call Tavily here using your SDK or HTTP client.
raw_response = call_tavily_api(payload)
normalized = {
"query": raw_response.get("query", tool_args["query"]),
"answer": raw_response.get("answer"),
"sources": [
{
"title": r.get("title"),
"url": r.get("url"),
"snippet": r.get("content"),
"score": r.get("score")
}
for r in raw_response.get("results", [])
]
}
return normalized
Why normalize the response?
A normalized result is easier for the agent to use. It also keeps your context window smaller and reduces noise. In most cases, the agent only needs:
- the final answer, if available
- a handful of source snippets
- URLs for citations
How the agent loop should work
A standard Tavily-enabled agent flow looks like this:
- The user asks a question.
- The model decides whether it needs live web search.
- The model emits a tool call with Tavily arguments.
- Your backend receives the call and validates the input.
- Your backend calls Tavily.
- Your backend returns the result to the model.
- The model produces the final response using the search data.
This separation is important: the model requests the search, but your server performs it.
Best practices for a clean Tavily integration
1. Keep the API key out of the schema
Never put TAVILY_API_KEY in the tool definition. Store it server-side in environment variables or your secret manager.
2. Use Tavily only when freshness matters
Tavily is ideal for:
- current events
- product changes
- pricing
- documentation that may have changed
- citation-backed answers
If the model can answer confidently from its own knowledge, you may not need a tool call.
3. Return concise, structured output
Avoid returning full raw pages unless your use case truly needs them. Large, unfiltered content makes the agent slower and less reliable.
4. Add domain constraints when appropriate
If your workflow requires trusted sources, use domain allowlists or blocklists to keep the search focused.
5. Validate all tool inputs
Do not trust the model to send perfect arguments. Validate types, ranges, and allowed values before calling Tavily.
6. Feed the model source-friendly data
If you want strong citations, return:
- page title
- URL
- short snippet
- optional relevance score
That gives the model enough structure to cite sources cleanly.
Common mistakes to avoid
- Exposing the API key to the model
- Letting the model call Tavily directly
- Returning too much raw content
- Skipping input validation
- Using search when a direct answer is enough
- Not mapping Tavily results into a stable JSON format
A simple rule of thumb
If your agent framework supports JSON-schema-style tools, Tavily should be implemented as:
Tool schema → backend handler → Tavily API call → normalized JSON → model response
That is the cleanest and most reliable pattern.
When to use include_answer versus results only
Use include_answer when you want a fast synthesized response from the search layer.
Use results only when:
- you need the model to reason over multiple sources
- you want custom citations
- you want the agent to compare sources before answering
A strong default is to return both:
- the synthesized answer
- a short list of result sources
Final recommendation
If you are implementing Tavily inside an agent tool schema, define a small, explicit schema centered on query, keep all credentials server-side, normalize Tavily’s response before passing it back to the agent, and only expose the parameters your workflow actually needs. That approach gives you a robust Tavily-powered agent that is easier to maintain, easier to debug, and better at producing accurate, source-backed answers.