"Haven't we seen this before?" is the highest-value question in triage, and the answer usually lives in a postmortem nobody re-reads.
Tier: Core · Hands-on time: ~60 minutes
This playbook builds retrieval-augmented lookup over your incident history: embed past postmortems and incident summaries, retrieve the most similar at triage time with recency and relevance ranking, and inject them into your triage/investigation prompts (pb-14/pb-15). Commercial equivalents exist — PagerDuty's SRE Agent "learns from past incidents" via shared agent memory, incident.io leans on its Catalog — but a pgvector table and fifty lines of Python teach you exactly what those products do and where similarity search misleads.
Not worth it below ~20 documents — grep and a well-named postmortem folder outperform embeddings at that scale.
pgvector/pgvector:pg16), or any vector store you already run.Normalize the corpus into retrieval units. Chunk each postmortem into sections (summary, timeline, root cause, action items) rather than fixed windows — a hit on "root cause" text is far more diagnostic than a hit in a timeline. Store one row per section: (incident_id, section, text, embedding vector, date, services text[], severity).
Embed and index. Batch-embed sections; create the pgvector index (ivfflat/hnsw, cosine distance). Sanity-check dimensionality and that re-embedding the same text yields distance ~0 — a cheap catch for pipeline bugs.
Retrieve with a composite score, not raw similarity. At query time, embed the new incident's triage summary (alert text + suspected service) and rank with similarity blended with recency decay and a service-match boost — in SQL or in Python:
SELECT incident_id, section, text,
(1 - (embedding <=> $1)) * exp(-extract(days from now()-date)/365.0)
* (CASE WHEN services && $2 THEN 1.3 ELSE 1.0 END) AS score
FROM incident_chunks ORDER BY score DESC LIMIT 8;
Recency matters because your stack changes: a 3-year-old incident about a decommissioned system is similarity-bait.
Present retrieval as candidates, then let the LLM compare — with citations. Deduplicate to the top 3 incidents and prompt:
Current incident: <triage summary>. Candidate past incidents: <retrieved
sections with incident IDs>. For each candidate, state: SAME failure mode /
SAME symptom, DIFFERENT cause / UNRELATED — quoting the retrieved text that
justifies the judgment. If a past incident matches, list what fixed it then,
citing its action-item text. Do not use knowledge beyond these excerpts.
The SAME-symptom/DIFFERENT-cause distinction is the entire game — surface-similar incidents with different causes are how retrieval misleads responders.
Wire it into triage and keep it fed. Add the top match (with its incident ID and match rationale) to your pb-14 bundle as === SIMILAR PAST INCIDENTS ===. Add an ingest step to your postmortem pipeline so every new (verified) postmortem is embedded on merge — a memory that stops learning decays into a museum.
Embed the verified postmortem, never the raw incident channel — you want institutional memory built from gated facts (pb-19), not from mid-incident speculation that later proved wrong.
nomic-embed-text-class models) and keep pgvector inside the client boundary. Retrieval quality with good local embedding models is entirely adequate for this corpus size.A shared "learnings" index across clients feels like knowledge management and reads, in an audit, like data commingling. Isolate first, generalize learnings by hand into sanitized pattern docs.