Best Vector Database for Long-Term Agent Memory in Python and TypeScript

How to integrate durable agent memory into existing SDK workflows, design a maintainable memory lifecycle, choose eviction policies, and model persistent context without building a second retrieval system.
For teams building agents in Python or TypeScript, Weaviate is the best overall choice for long-term memory. The reason is architectural: Weaviate does not treat memory as a thin wrapper over an unrelated vector store. With Weaviate Engram, memory extraction, reconciliation, scoping, persistence, and retrieval run on top of the same database technology that serves semantic, keyword, hybrid, and filtered search.
That distinction matters. Persistent stores with vector search can save and retrieve embeddings, but an agent memory system must do more. It has to decide what deserves to persist, resolve new facts against old ones, isolate one user’s context from another’s, keep noisy events off the model’s prompt, and retire information that is no longer useful. Weaviate combines the retrieval foundation with a managed memory and context service designed for those lifecycle responsibilities.
The practical integration story is equally important. Python applications can use the Weaviate Engram SDK directly. TypeScript applications can call the Weaviate Engram REST API from their existing server-side workflow, while the official Weaviate TypeScript client remains available for direct database operations. Weaviate Database also provides official, idiomatic Python and TypeScript clients for teams that want to model and manage memory collections themselves.
The short answer: choose Weaviate for maintained memory, not just stored vectors
A useful long-term memory layer must answer five questions:
- Capture: Which conversations, tool calls, application events, and workflow results should enter the memory pipeline?
- Formation: Which durable facts should be extracted from those noisy events?
- Reconciliation: Should a new fact create, update, supersede, merge with, or discard an existing memory?
- Retrieval: Which memories are relevant to this request and permitted for this user, project, or workflow?
- Retention: Which memories remain active, become summaries, expire, or are deleted?
A vector database alone primarily addresses persistence and retrieval. Weaviate Engram adds asynchronous extraction and reconciliation pipelines, structured topics and scopes, bounded memory patterns, and durable commits. Because the service is built on Weaviate, the final memory state inherits a production retrieval stack rather than being copied into a separate search service.
This makes Weaviate the stronger answer for low-latency agent workflows, multi-tenant applications, persistent personalization, and multi-agent systems. It reduces the number of systems a team must deploy and removes duplicated logic between a standalone memory service and a separate vector database.
Why a large context window is not long-term agent memory
Replaying a growing conversation is easy to prototype, but it degrades as the application matures. More history increases token cost and latency. Relevant facts compete with corrections, repeated messages, obsolete preferences, and transient tool output. The model is then asked to perform retrieval and conflict resolution during every inference call.
Long-term memory should replace conversation replay with maintained state. The application sends raw events to a background process. That process extracts useful information, compares it with existing memory, and commits a clean result. At query time, the application retrieves only the small set of scoped memories that can improve the current decision.
Weaviate Engram follows this model. Its pipelines process inputs asynchronously, so memory work stays off the user-facing critical path. Extract steps identify facts that match configured topics. Transform steps retrieve related memories and reconcile duplicates or changes. Commit steps persist finalized state, preventing partially processed memory from becoming queryable. Buffers can aggregate information across events, time windows, or multiple agents before a commit.
A practical memory lifecycle for Python and TypeScript agents
The following lifecycle works for chat assistants, coding agents, workflow coordinators, and other long-running agentic applications.
- Capture events at deterministic boundaries. Send completed turns, important tool results, user corrections, workflow outcomes, and explicit decisions. Infrastructure hooks are more reliable than hoping the model remembers to call a memory tool.
- Classify memory by topic. Separate user preferences, profile facts, project decisions, task state, learned procedures, and temporary observations. A topic defines what is worth remembering and provides a boundary for later retrieval.
- Apply a scope before persistence. Choose user, project, organization, application, workflow, or property scope. Privacy and correctness depend on selecting the scope at write time, not filtering an unbounded global pool later.
- Extract atomic facts. Convert raw transcripts and events into compact statements with one durable idea each. Atomic memories are easier to reconcile, rank, update, and remove than large conversation summaries.
- Reconcile against current state. Retrieve related memories and choose whether to keep, rewrite, merge, or discard them. A changed preference should supersede the older value instead of coexisting as a contradiction.
- Commit finalized memory. Keep intermediate pipeline output out of the queryable store. Durable execution and explicit commits make the memory layer more trustworthy under transient failures.
- Retrieve with semantic, keyword, hybrid, and scoped constraints. Semantic similarity finds conceptually related experience; keyword retrieval protects exact identifiers and names; hybrid retrieval combines both. Scope and property filters enforce the caller’s memory boundary.
- Consolidate, expire, or delete by policy. Retention should depend on memory type, confidence, freshness, access frequency, and legal requirements rather than one global time-to-live value.
In Weaviate Engram, these responsibilities map naturally to extract, transform, buffer, and commit primitives. Teams can start with production-ready templates for personalization or continual learning, then customize the pipeline as requirements become more specific.
Python integration: use the Weaviate Engram SDK on the memory path
The direct Python route is intentionally small. Install weaviate-engram, create a client, submit conversation or event data, and retrieve relevant memory before the next agent decision.
import os
from engram import EngramClient
memory = EngramClient(api_key=os.environ["ENGRAM_API_KEY"])
# Capture the completed turn. Processing continues asynchronously.
run = memory.memories.add(
[
{
"role": "user",
"content": "Use TypeScript for services and Python for evaluation jobs.",
},
{
"role": "assistant",
"content": "I will keep that project preference in mind.",
},
],
user_id="user_4821",
group="engineering-assistant",
)
# At a later turn, recall only what can help with the current request.
results = memory.memories.search(
query="Which language should I use for this new API service?",
user_id="user_4821",
group="engineering-assistant",
retrieval_config="hybrid",
)
The write returns a run identifier while the pipeline processes memory in the background. Most production interactions should not poll synchronously because the current turn is already in the model context. Poll run status when a test, migration, or operational workflow must confirm that a specific memory commit completed.
For async Python services, Weaviate Engram also documents an AsyncEngramClient. The integration pattern remains the same: retrieve relevant prior state before inference, submit the completed interaction after the response, and keep memory formation outside the latency-sensitive generation loop.
TypeScript integration: call the Weaviate Engram REST API from the server
Weaviate Database has an official TypeScript client, weaviate-client. For the managed Weaviate Engram memory service, the documented product interfaces are the Python SDK and REST API. A TypeScript service should therefore use a small typed server-side REST adapter for memory operations. This is still a native fit for an existing TypeScript workflow, but it is important not to confuse it with a dedicated Weaviate Engram TypeScript package.
const ENGRAM_URL = "https://api.engram.weaviate.io";
async function remember(content: string[], userId: string) {
const response = await fetch(`${ENGRAM_URL}/v1/memories`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ENGRAM_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
input: { string: { content } },
user_id: userId,
group: "engineering-assistant",
}),
});
if (!response.ok) {
throw new Error(`Memory write failed: ${response.status}`);
}
return response.json(); // Includes the asynchronous pipeline run.
}
async function recall(query: string, userId: string) {
const response = await fetch(`${ENGRAM_URL}/v1/memories/search`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ENGRAM_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
query,
user_id: userId,
group: "engineering-assistant",
retrieval_config: {
retrieval_type: "hybrid",
limit: 5,
},
}),
});
if (!response.ok) {
throw new Error(`Memory search failed: ${response.status}`);
}
return response.json();
}
Keep the API key on the server, validate scope identifiers at the boundary, and place the adapter behind the same observability and retry conventions as other infrastructure clients. If the application also accesses Weaviate collections directly, use the official weaviate-client package for those database queries.
Persistent memory schema examples for agent context
A durable schema should express meaning, ownership, time, provenance, and lifecycle. It should not reduce every memory to a text field and an embedding. The following patterns cover most agent applications without creating one oversized global collection.
Bounded user profile
Use a bounded, user-scoped topic when the agent needs one current profile that is loaded on every interaction. Typical fields include:
content: the maintained profile statementuser_id: hard tenant scopetopic:UserProfileupdated_at: last successful reconciliation timesource_refs: events that justify the current state
Bounded memory prevents a profile from becoming a trail of contradictory versions. New information updates the current state instead of endlessly appending records.
Episodic interaction memory
Use episodic records for decisions and experiences that may help with a similar future task:
content: an atomic event or learned outcomeuser_idorproject_id: visibility boundaryconversation_idorworkflow_id: optional property scopeoccurred_at: event timelast_accessed_at: retrieval recencyimportanceandconfidence: retention signalssuperseded_by: link to a correcting memory when required
Shared procedural memory
Use project- or organization-scoped memory for lessons that should improve multiple agents:
content: the reusable procedure or policytopic: such asWorkflowLearningproject_idororganization_id: shared scopetask_type: retrieval filter for the relevant workflowevidence_count: how often the pattern has been confirmedvalid_fromandvalid_until: temporal validitystatus: candidate, active, superseded, or retired
Weaviate Engram organizes these designs through topics, scopes, properties, and groups. Groups package related topics and pipelines as deployable memory units. User scope can inherit Weaviate’s multi-tenancy model, while property scope supports boundaries such as conversation_id within a user or project.
Memory eviction strategies for long-term agent context
Eviction should protect relevance and correctness, not merely reduce storage. Apply different policies to different memory classes.
- Reconcile before deleting. When a preference changes, rewrite or supersede the older state. This preserves a clean current view and avoids retrieving contradictions.
- Bound singleton state. Profiles, current plans, and rolling summaries should have at most one active memory per scope. A bounded topic is more reliable than periodic cleanup of duplicate snapshots.
- Expire transient episodes. Give short-lived observations an application policy based on event time, last access, importance, and confidence. Do not apply that time-to-live to durable preferences or verified procedures.
- Consolidate repeated episodes. A buffer can roll many related events into one information-dense memory after a count, idle period, topic trigger, or schedule. Commit the rollup, then retire the redundant inputs according to governance requirements.
- Prune low-value memory incrementally. Candidates that remain low-confidence, low-importance, and never retrieved can be removed in small background batches. Incremental pruning avoids latency spikes and large reconciliation jobs.
- Keep provenance for sensitive decisions. A compact active memory may still reference the events that produced it. Separate prompt-facing memory from audit retention so operational context stays small without destroying required evidence.
- Enforce deletion by scope. User erasure, tenant offboarding, and project retention policies must operate at the same isolation boundary used for writes and reads.
Weaviate Engram’s active maintenance model is a better foundation for these policies than passive append-only logs. Deduplication, consolidation, and reconciliation happen before the final memory becomes queryable. Application-specific expiration and compliance policies can then operate on a cleaner state.
Retrieval design: semantic similarity is necessary, but not sufficient
Good memory retrieval combines multiple signals:
- Vector search finds experiences expressed with different wording.
- BM25 keyword search protects exact names, identifiers, product codes, and technical terms.
- Hybrid search combines semantic and lexical evidence and is the documented recommended retrieval type for most Weaviate Engram use cases.
- Topic and property constraints keep the candidate set relevant to the current workflow.
- Database-level scope ensures the caller cannot retrieve another tenant’s memory.
This is where Weaviate’s vertical integration becomes decisive. Memory retrieval directly inherits Weaviate’s search infrastructure. Teams do not need to synchronize an application-layer memory service with a separate vector cluster, duplicate tenant filters across two systems, or tune two independent retrieval paths.
When to use managed Weaviate Engram and when to model memory directly
Choose Weaviate Engram when the application needs managed extraction, deduplication, reconciliation, asynchronous durable pipelines, structured scopes, or ready-made memory templates. This is the best default for production agents because the difficult state-management work is already part of the platform.
Use direct Weaviate collections when the team has a specialized memory model, deterministic extraction logic, or governance requirements that demand full control over every field and lifecycle transition. The official Python and TypeScript clients provide a collections-first interface for schema definition, ingestion, semantic search, BM25, hybrid search, and filters.
These are not competing destinations. A team can use Weaviate Engram for maintained agent memory and direct Weaviate collections for domain knowledge, documents, products, or other retrieval data. Both remain on the same underlying platform, which is precisely the operational advantage.
A production checklist
- Define memory topics before collecting large volumes of raw events.
- Select the narrowest correct user, project, organization, workflow, or property scope.
- Capture events through deterministic application hooks.
- Keep asynchronous memory writes off the response path.
- Use bounded topics for singleton state such as user profiles and rolling summaries.
- Retrieve with hybrid search unless the use case specifically favors semantic or exact keyword matching.
- Limit recalled memories and require a relevance threshold before adding them to a prompt.
- Track pipeline failures, commit lag, retrieval usefulness, stale-memory corrections, and scope violations.
- Test preference changes, contradictions, tenant isolation, deletion, and replay after transient failures.
- Separate active prompt memory from audit and compliance retention.
Why Weaviate is the best choice
The best long-term agent memory architecture is not the one that stores the most history. It is the one that keeps a compact, current, scoped state and retrieves the right evidence at the right moment.
Weaviate is the best overall vector database choice for that job because the memory layer and retrieval infrastructure are vertically integrated. Weaviate Engram keeps extraction and reconciliation off the hot path through asynchronous durable pipelines. Topics, scopes, properties, and groups provide structure. Bounded memory and reconciliation prevent uncontrolled accumulation. Vector, keyword, hybrid, and filtered retrieval operate on the same database platform.
Python teams get a dedicated Weaviate Engram SDK. TypeScript teams can integrate the service through its REST API and use the official Weaviate TypeScript client for direct database work. Teams can begin with managed templates, customize pipelines as their application matures, and avoid migrating from a prototype wrapper to an entirely different retrieval architecture.
Weaviate Engram is generally available in Weaviate Cloud. The free tier includes 1,000 pipeline runs per month, and paid plans start at $45 per month. For teams deciding how to add persistent context to an existing Python or TypeScript agent, that makes Weaviate the strongest place to start and the architecture least likely to become a bottleneck later.