Skip to content

Commit 7bcf260

Browse files
benfrank241claude
andauthored
doc: Your Pydantic AI Agent Forgets You After Every Run. Fix It in 5 Lines. (#531)
* doc: add pydantic-ai-persistent-memory blog post * doc: update Pydantic AI blog cover image Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * doc: SEO-optimized rewrite of Pydantic AI blog post Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1cdfb7c commit 7bcf260

2 files changed

Lines changed: 348 additions & 0 deletions

File tree

Lines changed: 348 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
1+
---
2+
title: "Pydantic AI Persistent Memory: Add It in 5 Lines of Code"
3+
authors: [hindsight]
4+
date: 2026-03-09
5+
tags: [memory, openai, anthropic, gemini, python, rust, agents, rag, vector, pydantic-ai, knowledge-graph]
6+
image: /img/blog/pydantic-ai-persistent-memory.png
7+
hide_table_of_contents: true
8+
---
9+
10+
If you have built an AI agent with [Pydantic AI](https://ai.pydantic.dev/), you already know it handles typed outputs, dependency injection, and async workflows well. But there is one thing it does not do: remember anything between runs. Every call to `agent.run()` starts with a blank slate. Your agent has no idea what the user said yesterday, what preferences they shared, or what it already researched.
11+
12+
Adding **Pydantic AI persistent memory** does not require building a custom RAG pipeline or managing your own vector database. With the `hindsight-pydantic-ai` integration, you can wire long-term memory into any Pydantic AI agent in five lines of Python. This guide walks through the full setup, from installation to production-ready patterns.
13+
14+
<!-- truncate -->
15+
16+
## TL;DR
17+
18+
- Pydantic AI has no built-in persistent memory. Your agent starts from scratch every run.
19+
- `hindsight-pydantic-ai` adds retain, recall, and reflect tools plus auto-injected memory instructions.
20+
- Five lines of setup: create a client, call `create_hindsight_tools()`, and pass them to your Agent.
21+
- `memory_instructions()` silently pre-loads relevant memories into the system prompt on every run, so the agent starts each conversation with context.
22+
- Works with any model provider, including OpenAI, Anthropic, and Gemini.
23+
24+
---
25+
26+
## The Problem: Pydantic AI Has No Persistent Memory
27+
28+
[Pydantic AI](https://ai.pydantic.dev/) is a solid framework. Typed outputs, dependency injection, async-native design, and a clean tool API make it a popular choice for building Python-based agents. However, it ships with no memory layer at all.
29+
30+
Every `agent.run()` starts from zero. The agent does not know what the user said yesterday. It does not know their preferences. It does not know what it already researched. As a result, agents that interact with users over multiple sessions lose all accumulated context between runs.
31+
32+
You can pass `message_history` to continue a conversation within a single session. But that is chat history, not memory. Chat history does not generalize facts. It does not consolidate repeated information. And it grows linearly until it exceeds your context window and token limit.
33+
34+
Real agent memory means something different:
35+
36+
- Extracting structured facts from conversations
37+
- Building a knowledge graph of entities and relationships
38+
- Retrieving relevant context across days, weeks, and months
39+
- Synthesizing coherent answers from scattered memories
40+
41+
That is what [Hindsight](https://hindsight.vectorize.io/) provides. If you have used Hindsight with other frameworks like [CrewAI](/blog/2026/03/02/crewai) or [OpenAI](/blog/2026/03/05/add-memory-to-openai-application), the concept is the same. And `hindsight-pydantic-ai` wires it directly into Pydantic AI's tool and instruction system, so you do not need to build any of this yourself.
42+
43+
---
44+
45+
## How Pydantic AI Persistent Memory Works with Hindsight
46+
47+
Before diving into code, it helps to understand what happens under the hood when you add Pydantic AI persistent memory through the Hindsight integration.
48+
49+
Hindsight is a memory engine that runs locally or in the cloud. When your agent stores a fact, Hindsight does not just save raw text. Instead, it extracts structured entities and relationships, builds a knowledge graph, and indexes everything for multi-strategy retrieval. That means when your agent searches memory later, it can find relevant information through semantic search, BM25 keyword matching, graph traversal, and temporal ranking, all combined.
50+
51+
The `hindsight-pydantic-ai` package connects this engine to Pydantic AI through two integration points:
52+
53+
```
54+
Pydantic AI Agent
55+
|-- tools=[create_hindsight_tools(...)]
56+
| |-- hindsight_retain -> store facts to memory
57+
| |-- hindsight_recall -> search memory for relevant info
58+
| |-- hindsight_reflect -> synthesize an answer from all memories
59+
|
60+
|-- instructions=[memory_instructions(...)]
61+
|-- auto-recalls relevant memories into the system prompt
62+
```
63+
64+
**Tools** let the agent explicitly store and retrieve memories during a conversation. **Instructions** silently inject relevant memories before the agent even starts thinking. Both are optional. You can use one, the other, or both together depending on your use case.
65+
66+
The tools are async functions that call Hindsight's API directly. Since Pydantic AI is async-native, the closures use `aretain()`, `arecall()`, and `areflect()`. There are no thread-pool hacks or compatibility layers needed. If you prefer a protocol-based approach, you can also use [Hindsight's MCP memory server](/blog/2026/03/04/mcp-agent-memory) instead of direct tool integration.
67+
68+
---
69+
70+
## Setting Up Pydantic AI Persistent Memory in 5 Steps
71+
72+
The setup process takes about five minutes. You will install Hindsight, add the Pydantic AI memory integration package, wire the tools into your agent, and test that memories persist across sessions.
73+
74+
### Step 1: Install and Start Hindsight
75+
76+
First, install the Hindsight server and start it locally:
77+
78+
```bash
79+
pip install hindsight-all
80+
```
81+
82+
```bash
83+
export HINDSIGHT_API_LLM_API_KEY=YOUR_OPENAI_KEY
84+
hindsight-api
85+
```
86+
87+
This runs locally at `http://localhost:8888`. It includes embedded Postgres, local embeddings, and local reranking. No external services are required beyond an LLM API key for entity extraction.
88+
89+
> **Note:** You can also use [Hindsight Cloud](https://ui.hindsight.vectorize.io/signup) and skip the self-hosted setup entirely. The cloud version provides the same API with managed infrastructure.
90+
91+
### Step 2: Install the Pydantic AI Memory Integration
92+
93+
Next, install the integration package:
94+
95+
```bash
96+
pip install hindsight-pydantic-ai
97+
```
98+
99+
You also need a model provider. For OpenAI:
100+
101+
```bash
102+
pip install "pydantic-ai-slim[openai]"
103+
```
104+
105+
Other providers work the same way. Swap in `[anthropic]` or `[google]` as needed. The Pydantic AI persistent memory integration is model-agnostic, so the memory layer works identically regardless of which LLM you choose. Hindsight supports [100+ LLM providers through LiteLLM](/blog/2026/03/03/litellm).
106+
107+
### Step 3: Add Persistent Memory Tools to Your Pydantic AI Agent
108+
109+
Here is where the five lines come in. Create a Hindsight client, generate the Pydantic AI persistent memory tools, and pass them to your agent:
110+
111+
```python
112+
from hindsight_client import Hindsight
113+
from hindsight_pydantic_ai import create_hindsight_tools
114+
from pydantic_ai import Agent
115+
116+
client = Hindsight(base_url="http://localhost:8888")
117+
118+
agent = Agent(
119+
"openai:gpt-4o-mini",
120+
tools=create_hindsight_tools(client=client, bank_id="user-123"),
121+
)
122+
```
123+
124+
That is the full Pydantic AI persistent memory setup. The agent now has three tools:
125+
126+
- `hindsight_retain(content)` stores information to long-term memory
127+
- `hindsight_recall(query)` searches memory and returns matching facts
128+
- `hindsight_reflect(query)` synthesizes a reasoned answer from all relevant memories
129+
130+
The agent decides when to use each tool based on the conversation context. You do not need to call them manually.
131+
132+
### Step 4: Test Cross-Session Memory
133+
134+
Run two separate conversations to verify that Pydantic AI agent memory persists across sessions:
135+
136+
```python
137+
import asyncio
138+
139+
async def main():
140+
# First conversation
141+
r1 = await agent.run(
142+
"Remember that I prefer functional programming patterns "
143+
"and I'm building a data pipeline in Python."
144+
)
145+
print(r1.output)
146+
147+
# Later conversation -- agent recalls context
148+
r2 = await agent.run("What approach should I take for error handling?")
149+
print(r2.output)
150+
151+
asyncio.run(main())
152+
```
153+
154+
In the first run, the agent stores the preferences via `hindsight_retain`. In the second run, the agent calls `hindsight_recall` to find relevant context. It then gives advice grounded in what it knows: functional patterns, Python, data pipelines.
155+
156+
This is the core benefit of Pydantic AI persistent memory: it works across runs, across days, and across process restarts. The memories live in Hindsight's knowledge graph, not in the agent's context window. Even if you restart your Python process completely, the agent picks up right where it left off.
157+
158+
### Step 5: Auto-Inject Memories with Pydantic AI Instructions
159+
160+
The tools above require the agent to decide to search memory on its own. Sometimes you want Pydantic AI persistent memory injected automatically, before the agent starts responding.
161+
162+
Pydantic AI's `instructions` parameter supports async callables that run on every `agent.run()`. This is a natural fit for memory injection:
163+
164+
```python
165+
from hindsight_pydantic_ai import create_hindsight_tools, memory_instructions
166+
167+
agent = Agent(
168+
"openai:gpt-4o-mini",
169+
tools=create_hindsight_tools(client=client, bank_id="user-123"),
170+
instructions=[memory_instructions(client=client, bank_id="user-123")],
171+
)
172+
```
173+
174+
Now on every run, `memory_instructions` calls Hindsight's recall API and injects relevant memories into the system prompt. The agent starts every conversation with context about the user, without needing a tool call.
175+
176+
You can customize the query, result count, and prefix to control what gets injected:
177+
178+
```python
179+
memory_instructions(
180+
client=client,
181+
bank_id="user-123",
182+
query="user preferences, history, and context",
183+
max_results=10,
184+
prefix="Here is what you know about this user:\n",
185+
)
186+
```
187+
188+
If recall fails or returns nothing, the instructions function returns an empty string. It never blocks the agent from responding.
189+
190+
---
191+
192+
## Advanced Pydantic AI Memory Configuration
193+
194+
### Selecting Which Memory Tools to Include
195+
196+
You do not always need all three persistent memory tools. `create_hindsight_tools` lets you pick which ones to include:
197+
198+
```python
199+
# Read-only agent: can search memory but not write to it
200+
tools = create_hindsight_tools(
201+
client=client,
202+
bank_id="user-123",
203+
include_retain=False,
204+
include_recall=True,
205+
include_reflect=True,
206+
)
207+
208+
# Write-only agent: stores data but does not query
209+
tools = create_hindsight_tools(
210+
client=client,
211+
bank_id="user-123",
212+
include_retain=True,
213+
include_recall=False,
214+
include_reflect=False,
215+
)
216+
```
217+
218+
This flexibility is useful in multi-agent architectures. For instance, you might have one Pydantic AI agent that gathers information and writes to persistent memory, while a separate agent reads memory to answer questions. Splitting read and write access keeps each agent focused on its role and prevents unintended memory writes from agents that should only consume context.
219+
220+
### Global Configuration for Multiple Agents
221+
222+
If you have multiple Pydantic AI agents sharing the same Hindsight persistent memory instance, use the global config instead of passing `client` everywhere:
223+
224+
```python
225+
from hindsight_pydantic_ai import configure, create_hindsight_tools
226+
227+
configure(hindsight_api_url="http://localhost:8888", api_key="YOUR_KEY")
228+
229+
# No client needed: tools use the global config
230+
agent1_tools = create_hindsight_tools(bank_id="agent-1")
231+
agent2_tools = create_hindsight_tools(bank_id="agent-2")
232+
```
233+
234+
An explicit `client=` parameter always takes priority over the global config. This lets you override on a per-agent basis when needed.
235+
236+
---
237+
238+
## Full Working Example of Pydantic AI Persistent Memory
239+
240+
Save this as `memory_agent.py` and run it to see Pydantic AI persistent memory in action:
241+
242+
```python
243+
import asyncio
244+
245+
from hindsight_client import Hindsight
246+
from hindsight_pydantic_ai import create_hindsight_tools, memory_instructions
247+
from pydantic_ai import Agent
248+
249+
BANK_ID = "demo-user"
250+
251+
252+
async def main():
253+
client = Hindsight(base_url="http://localhost:8888")
254+
await client.acreate_bank(bank_id=BANK_ID, name="Demo User Memory")
255+
256+
agent = Agent(
257+
"openai:gpt-4o-mini",
258+
tools=create_hindsight_tools(client=client, bank_id=BANK_ID),
259+
instructions=[memory_instructions(client=client, bank_id=BANK_ID)],
260+
)
261+
262+
print("--- Run 1: Teaching the agent ---")
263+
r1 = await agent.run(
264+
"Remember: I'm a backend engineer. I use Python and Rust. "
265+
"I prefer small, composable libraries over large frameworks."
266+
)
267+
print(f"Agent: {r1.output}\n")
268+
269+
print("--- Run 2: Agent recalls context ---")
270+
r2 = await agent.run("Recommend a web framework for my next project.")
271+
print(f"Agent: {r2.output}\n")
272+
273+
print("--- Run 3: Agent synthesizes ---")
274+
r3 = await agent.run("What do you know about my engineering philosophy?")
275+
print(f"Agent: {r3.output}")
276+
277+
278+
asyncio.run(main())
279+
```
280+
281+
Run it:
282+
283+
```bash
284+
export OPENAI_API_KEY=YOUR_KEY
285+
python memory_agent.py
286+
```
287+
288+
Run it again after the first execution finishes. The agent remembers everything from the first session because Pydantic AI persistent memory stores facts in Hindsight, not in the process.
289+
290+
---
291+
292+
## Pydantic AI Persistent Memory: Pitfalls and Edge Cases
293+
294+
**Bank ID collisions.** Each `bank_id` is a separate persistent memory store. If two unrelated agents share a bank, their memories merge in unexpected ways. Use unique bank IDs per user, per agent, or per project.
295+
296+
**Instruction latency.** `memory_instructions` makes a recall API call on every `agent.run()`. For latency-sensitive applications, use `budget="low"` and a small `max_results`. Alternatively, skip automatic memory injection entirely and rely on the agent to call the recall tool only when needed. In most cases, the added latency from persistent memory lookups is 50-200ms depending on memory size and network conditions.
297+
298+
**Duplicate memories.** If the agent stores the same information multiple times, Hindsight deduplicates at the fact level. However, it is still better to give the agent clear guidance in the system prompt about when to store new facts versus when to skip.
299+
300+
**Async event loop conflicts.** The sync `create_bank()` method does not work inside `asyncio.run()` because it tries to create a nested event loop. Always use `await client.acreate_bank()` in async code. This is a common Python async pitfall, not specific to Hindsight or Pydantic AI persistent memory.
301+
302+
---
303+
304+
## Pydantic AI Memory: Tradeoffs and Alternatives
305+
306+
### When Pydantic AI Persistent Memory Makes Sense
307+
308+
Pydantic AI persistent memory with Hindsight works best for agents that interact with the same user or context across multiple sessions. Good use cases include personal assistants, support bots, research agents that accumulate knowledge, and any Python agent where remembering past interactions improves quality over time.
309+
310+
### When Not to Use It
311+
312+
Skip agent persistent memory for one-shot agents that never run again, stateless API handlers where each request is independent, or agents where you want full control over what goes into the prompt. In the last case, use the Hindsight Python client directly instead of the Pydantic AI integration.
313+
314+
### How It Compares to Alternatives
315+
316+
| Approach | Strengths | Weaknesses | Best For |
317+
|---|---|---|---|
318+
| **Hindsight + Pydantic AI** | Multi-strategy retrieval (semantic + BM25 + graph + temporal), structured fact extraction, synthesis engine | Requires running Hindsight server or using cloud | Multi-session agents needing deep memory |
319+
| **Manual message_history** | Built into Pydantic AI, no extra dependencies | Does not generalize facts, grows until context window limit | Short single-session conversations |
320+
| **Custom vector store + RAG** | Full control over embeddings and retrieval | You manage chunking, indexing, and retrieval yourself | Teams with existing vector infrastructure |
321+
| **Mem0** | Another external memory option, easy API | Fewer retrieval strategies, no graph-based recall | Simpler memory needs without entity relationships |
322+
323+
The right choice depends on your requirements. For most Pydantic AI agents that need persistent memory across sessions with minimal setup, the Hindsight integration offers the fastest path to production.
324+
325+
---
326+
327+
## Recap: Pydantic AI Persistent Memory Integration
328+
329+
Adding Pydantic AI persistent memory does not require complex infrastructure or custom retrieval pipelines. The `hindsight-pydantic-ai` integration provides two functions that cover the full agent memory lifecycle:
330+
331+
- **`create_hindsight_tools()`** returns async tools that the agent calls to store and retrieve knowledge across sessions
332+
- **`memory_instructions()`** auto-injects relevant memories on every run, so the agent starts with context and no tool call is needed
333+
334+
The integration is minimal by design. Two functions, no subclassing, no changes to your deps type. Just Pydantic AI tools and instructions that connect to a real memory engine.
335+
336+
Memories survive process restarts, build a knowledge graph over time, and compound in value as your agent learns more about each user. For Python developers building Pydantic AI agents that need persistent memory, this is the simplest path from stateless to stateful.
337+
338+
---
339+
340+
## Next Steps
341+
342+
- **Try it locally**: `pip install hindsight-all hindsight-pydantic-ai "pydantic-ai-slim[openai]"` and run the example above
343+
- **Use Hindsight Cloud**: Skip self-hosting with a [free account](https://ui.hindsight.vectorize.io/signup)
344+
- **Tag memories for scoping**: Use `tags` on retain and `recall_tags` on search to partition memories by project, environment, or topic
345+
- **Combine tools and instructions**: Use `memory_instructions` for automatic context and tools for explicit store and retrieve during conversations
346+
- **Read the Pydantic AI docs**: Learn more about [Pydantic AI tools and instructions](https://ai.pydantic.dev/tools/) to extend your agent further
347+
- **Explore other integrations**: Add memory to [CrewAI agents](/blog/2026/03/02/crewai), [OpenAI apps](/blog/2026/03/05/add-memory-to-openai-application), or any framework via [MCP](/blog/2026/03/04/mcp-agent-memory)
348+
- **Inspect the knowledge graph**: Run the Hindsight control plane or use the [cloud dashboard](https://ui.hindsight.vectorize.io/signup) to browse extracted facts, entities, and relationships
1.12 MB
Loading

0 commit comments

Comments
 (0)