New to Exa? Try the Coding Agent Quickstart
to get started in under a minute.
Pydantic AI is a Python agent framework from the team behind Pydantic. Its harness ships an official Exa integration as two composable capabilities:
ExaSearch: web research tools backed by the Exa Search API:web_search(top results with their most relevant excerpts, plus an optional synthesized text summary),get_page(full-page retrieval for a specific URL), and opt-indeep_search(a synthesized, cited answer in one call).ExaAgent: delegates long-running research to the Exa Agent API as deferred tool calls.
See the full reference from Pydantic here.
Read Pydantic's article about building a Research Agent with Exa
A walkthrough of three copy-paste research agents built on Pydantic AI and Exa.
Get Started
1
Pre-requisites and installation
Install the harness with the Exa extra and set your
EXA_API_KEY environment variable.Bash
Get your Exa API key
2
Add ExaSearch to an agent
Pass
ExaSearch to an Agent via the capabilities parameter. Authentication comes from EXA_API_KEY by default.Python
ExaSearch contributes two tools to the agent:web_search returns short excerpts (Exa highlights) rather than full page text, so surveying several sources stays cheap; the agent then reads a chosen page with get_page. A URL or question that returns no content, a rate limit, or a transient failure surfaces to the model as a ModelRetry so the run can recover; authentication failures (401/403) propagate as configuration errors.3
Enable deep search (optional)
deep_search runs Exa’s multi-step deep search (type='deep'): Exa expands the question into multiple queries, searches, and returns an answer grounded in citations in one tool call. It invests more time and search depth than web_search, so it is off by default. Enable it explicitly:Python
deep_search as an escalation from web_search, not a replacement.Configuration
Every field ofExaSearch with its default:
Python
include_domains and exclude_domains apply to web_search and deep_search, and are mutually exclusive. Out-of-range limits and setting both domain lists raise at construction.
Text summary
Settext_summary to have every web_search call also request a synthesized plain-text summary of the results. Pass True for an unconstrained summary, or a string describing the desired format:
Python
Summary: line.
Structured citations
Every tool returns aToolReturn: return_value carries the readable text the model sees (including the Sources: blocks), and metadata carries the sources as structured ExaSource records ({'url': ..., 'title': ...}) under the 'sources' key. Metadata is never sent to the model, so rendering citations needs no text parsing:
Python
Custom client
The default client isexa_py.AsyncExa, configured from EXA_API_KEY. Pass any object satisfying the ExaClient protocol to configure authentication or the base URL explicitly, or to substitute a fake in tests:
Python
Exa agent runs
The Exa Agent API runs open-ended research tasks asynchronously. TheExaAgent capability maps that lifecycle onto Pydantic AI’s deferred tool calls: its exa_agent tool creates the run and defers, carrying the Exa run ID in the deferred call’s metadata.
Python
execution='inline') the capability resolves its own deferred calls within the agent run by polling the Exa run to completion, so the tool behaves like a regular (if slow) tool. With execution='external' the calls bubble up as DeferredToolRequests output for the host application to resolve out of band.
Every field of ExaAgent with its default:
Python
Agent spec (YAML/JSON)
Both capabilities work with Pydantic AI’s agent spec, so you can declare them in a config file instead of Python:agent.yaml
Python
custom_capability_types so the spec loader knows how to instantiate the capabilities. Spec-loaded instances always build the default client from EXA_API_KEY.
Next
- Search API - Semantic search with highlights, summaries, and deep search
- Agent API - Open-ended asynchronous research runs
- MCP Setup - Exa’s hosted MCP server
- SDKs - Python and JavaScript SDK docs