Dakera vs pgvector: you already run Postgres, so here is what you would still write
pgvector turns Postgres into a vector store, and for vectors that belong next to relational data it is hard to beat. Agent memory asks for more than nearest-neighbour search. This page puts the SQL and application code for hybrid search, reranking and decay beside the Dakera call that does the same.
Reviewed October 2026
When pgvector is exactly right
pgvector is an open-source Postgres extension under the PostgreSQL licence. It stores vectors with the rest of your data and supports exact and approximate search with HNSW and IVFFlat indexes, plus half-precision, binary and sparse vector types and six distance operators. Because it lives in Postgres you get ACID transactions, joins and point-in-time recovery, and it comes preinstalled with many hosted Postgres providers. If your embeddings describe rows you already keep in Postgres, adding a column is the simplest design.
What you would still write
For agent memory, the vector index is the first of several pieces. pgvector's own documentation points to Postgres full-text search and Reciprocal Rank Fusion for hybrid retrieval; the rest is your code.
| Capability | pgvector + your code | Dakera |
|---|---|---|
| Embedding model | Your service | On-device |
| Hybrid retrieval and fusiontsvector, GIN index, RRF query | Your SQL | Yes |
| Cross-encoder reranking | Your service | Yes |
| Decay, TTL and expiry | Your SQL and a job | Yes |
| Deduplication and consolidation | Your code | Yes |
| Entity extraction and graph | Your pipeline | Yes |
| Agents, sessions, scoped keys | Your schema and roles | Yes |
| MCP tools and a memory dashboard | Your build | Yes |
Write path: schema, insert, decay
The pgvector schema is valid, ordinary Postgres. Decay becomes a scheduled DELETE that you own and tune.
CREATE EXTENSION vector;
CREATE TABLE memories (
id bigserial PRIMARY KEY,
agent_id text NOT NULL,
content text NOT NULL,
importance real DEFAULT 0.5,
created_at timestamptz DEFAULT now(),
embedding vector(1024),
tsv tsvector GENERATED ALWAYS AS
(to_tsvector('english', content))
STORED
);
CREATE INDEX ON memories USING hnsw
(embedding vector_cosine_ops);
CREATE INDEX ON memories USING gin (tsv);
INSERT INTO memories (agent_id, content,
importance, embedding)
VALUES ($1, $2, $3, $4);
-- decay: a job you schedule yourself
DELETE FROM memories
WHERE importance * exp(-extract(epoch
FROM now() - created_at) / 604800.0)
< 0.01;from dakera import DakeraClient
client = DakeraClient(
"http://localhost:3000", api_key=KEY)
client.store_memory(
agent_id="support",
content="Maria prefers email",
importance=0.8,
)
# decay is server-side configuration
client.decay_update_config(
strategy="exponential",
half_life_hours=168,
min_importance=0.01,
)Dakera supports six decay curves (exponential, linear, step, power-law, logarithmic, flat) and spaced-repetition TTL extension. See the Python SDK.
Read path: hybrid search, rerank, decay
Left: a reciprocal-rank-fusion query over vector and full-text results, weighted by importance and age, then a cross-encoder run in your application. Right: the call that does it.
WITH v AS (
SELECT id, row_number() OVER (
ORDER BY embedding <=> $1) AS r
FROM memories WHERE agent_id = $2
ORDER BY embedding <=> $1 LIMIT 50),
k AS (
SELECT id, row_number() OVER (
ORDER BY ts_rank_cd(tsv, q) DESC) AS r
FROM memories,
websearch_to_tsquery('english', $3) q
WHERE agent_id = $2 AND tsv @@ q
ORDER BY ts_rank_cd(tsv, q) DESC
LIMIT 50)
SELECT m.id, m.content,
(COALESCE(1.0 / (60 + v.r), 0)
+ COALESCE(1.0 / (60 + k.r), 0))
* m.importance
* exp(-extract(epoch FROM now()
- m.created_at) / 604800.0) AS score
FROM memories m
LEFT JOIN v USING (id)
LEFT JOIN k USING (id)
WHERE v.id IS NOT NULL OR k.id IS NOT NULL
ORDER BY score DESC LIMIT 20;
# then, in your application:
rows = conn.execute(SQL, params).fetchall()
pairs = [(query, r[1]) for r in rows]
scores = reranker.predict(pairs)
top = sorted(zip(scores, rows),
key=lambda x: -x[0])[:10]response = client.recall(
agent_id="support",
query="How do we contact Maria?",
top_k=10,
)
for m in response.memories:
print(m.content, m.score)
# BM25 + HNSW, RRF fusion, cross-encoder
# rerank and decay-aware scoring all ran
# in that one call, on-device.The SQL assumes your application computes the query embedding and passes it as $1. Reranker weights, decay constants and the language configuration are yours to choose and maintain.
What v0.12.0 adds for Postgres teams
- Multilingual: the SQL above uses one text search configuration,
'english', and you pick another per language. Dakera embeds with bge-m3 across 100+ languages in one space and takes a per-requestlang. See Multilingual. - Multimodal: file attachments, on-device speech to text and visual recall over document pages. See Multimodal.
- Debuggable ranking:
rerank_reportin every response, plus a Recall lab in the dashboard that shows why each memory ranked where it did. - Operations: encrypted, compressed backups,
/health/ready, anddakera downgradeto roll back to v0.11.108.
When to choose pgvector, and when Dakera
Choose pgvector if
- Your vectors belong next to relational rows, with joins and transactions between them.
- Postgres is already your operational database, and you do not want another datastore.
- Your host or managed Postgres already offers it, with the backups and failover you rely on.
- You want to write and tune the ranking SQL yourself.
Choose Dakera if
- You want memory behaviour (decay, consolidation, sessions, graph) without building it in SQL.
- Retrieval needs a reranker, and you would rather not host one.
- You need multilingual or multimodal memory behind one API.
- You want MCP tools, SDKs in four languages and a dashboard out of the box.
Prefer managed? Dakera Cloud is coming. Join the waitlist.
Frequently asked questions
Can pgvector do hybrid search?
Yes. Combine vector distance with Postgres full-text search and fuse the ranks, as in the query above. You write and maintain that query, along with the reranking and decay around it.
Does Dakera use Postgres?
No. Dakera is a single self-hosted binary with its own storage, so there is no database to provision beside it.
How do I move memories out of Postgres?
Select the content, importance and timestamps, start Dakera with the Quickstart command and send them through the batch memory endpoint. Dakera embeds on-device, so the stored vectors stay behind.
How should I read the LoCoMo figure?
Dakera reports Recall@20: whether the answer is among the top 20 retrieved memories, with no LLM in the retrieval path. It measures memory retrieval, so this page does not set it against a vector extension.
Run Dakera on your own infrastructure.
One binary with its models baked in and no per-call fees. Start it with one Docker command and see it for yourself.
Prefer managed hosting? Join the Dakera Cloud waitlist →