Skip to main content
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-in deep_search (a synthesized, cited answer in one call).
  • ExaAgent: delegates long-running research to the Exa Agent API as deferred tool calls.
A capability bundles the tools, per-tool output budgets, and short research guidance in the system prompt, so you don’t have to wire a search API to a page fetcher and prompt the agent to research methodically yourself.
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
When enabled, the capability’s instructions tell the model to treat deep_search as an escalation from web_search, not a replacement.

Configuration

Every field of ExaSearch 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

Set text_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
The tool’s return shape is unchanged: when Exa returns a summary it is prepended as a Summary: line.

Structured citations

Every tool returns a ToolReturn: 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 is exa_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. The ExaAgent 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
By default (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
Pass 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
Last modified on July 21, 2026