Capture pipeline for AI interactions: from conversation to auditable knowledge
How to design the event schema, partitioning, retention, and indexing needed to turn prompts, retrieved context, and human edits into a reusable knowledge asset.
Every generative AI system in production generates a valuable byproduct that is usually discarded: the complete record of each interaction — the prompt, the retrieved context, the model's output, the subsequent human edit, and the cost of the call. Without a carefully designed capture pipeline, that material gets lost in unstructured logs or simply never exists. This article details the engineering required to turn these interactions into an auditable, reusable asset.
Why structured capture, not just logging
Traditional logging records text for debugging. Capturing AI interactions is a different discipline: it builds a structured trail that serves three distinct consumers — auditability (what the model said and why), product improvement (which responses were edited, and how), and knowledge reuse (the same question shouldn't cost a full generation twice).
That requires schema decisions, not just "dump everything into a log table."
Event schema
An interaction event should capture, at minimum:
interaction_id uuid
session_id uuid
timestamp datetime (UTC)
actor_id string (user or service)
model_name string
model_version string
prompt_template_id string
prompt_rendered text
retrieved_context[] array<{source_id, chunk_id, score, doc_version}>
completion_raw text
completion_final text -- after human edit, if any
edited_by string | null
edit_diff text | null
tokens_input int
tokens_output int
cost_usd decimal
latency_ms int
feedback_signal enum(accepted, edited, rejected, none)Two fields deserve special attention. ${'retrieved_context[]'} must reference the exact document version used — not just the source ID — because documents get updated and you need to know which version generated which answer. And ${'completion_final'} versus ${'completion_raw'} is what lets you actually measure how much humans trust or correct the model.
Partitioning and volume
Production-scale AI interactions generate high, growing volume. Partitioning by ${'timestamp'} (daily or monthly) combined with ${'tenant_id'} in multi-tenant setups is the starting point. Avoid using ${'model_name'} as the primary partition key — model versions change frequently, and you'll query by time period far more often than by model.
For high volumes, write in a columnar format (Parquet or equivalent) into a data lake, with a streaming layer (Kafka, Kinesis) absorbing write peaks before batch consolidation. This keeps the capture pipeline from becoming an application latency bottleneck — capture should be asynchronous and never block the response to the user.
Retention and PII
Retention of AI interactions is not a standalone technical decision — it's a compliance decision. Recommended practices:
| Layer | Typical retention | Note |
|---|---|---|
| Raw log (full prompt + output) | 30–90 days | Subject to personal data policy |
| Aggregated metadata (cost, latency, edit rate) | 1–2 years | No PII, safe for long-term analysis |
| Anonymized samples for training/evaluation | Indefinite, with consent | Requires explicit anonymization pipeline |
PII must be handled at the pipeline's entry point, not as a later filter. A detection step (rules + NER model) should run before persistence, masking or tokenizing sensitive fields, with a separate mapping table under stricter access control than the rest of the pipeline. Never rely on "we'll anonymize later" — raw PII replicated across a data lake is a liability, not an asset.
Indexing for knowledge reuse
The end goal isn't just to store history — it's to let past interactions feed the retrieval system. That means:
- Indexing ${'
completion_final'} (the human-validated version) as a candidate for new knowledge content, with provenance metadata pointing back to the original interaction. - Grouping interactions by ${'
prompt_template_id'} to spot recurring question patterns that justify creating a canonical document instead of relying on repeated generation. - Exposing edit rate by topic as a quality signal — topics with high edit rates indicate insufficient or stale retrieved context and should trigger a review of the knowledge base.
That last point closes the loop: capture isn't just for auditing the past — it's for improving the next retrieval.
Common mistakes
- Storing only the final output, without the retrieved context — makes it impossible to know why the model answered the way it did.
- Not versioning source documents, which makes ${'
retrieved_context'} useless for audits six months later. - Treating cost as a separate infrastructure metric instead of a field on the event itself — makes it hard to attribute cost to a use case or user.
- Applying uniform retention to data of different natures (raw vs. aggregated), causing unnecessary exposure or loss of useful signal.
What to do on Monday
- 1.Define the minimum interaction event schema and implement asynchronous capture before any other model improvement.
- 2.Audit whether your ${'
retrieved_context'} references document version — if not, fix it before accumulating more untraceable history. - 3.Establish per-layer retention policy (raw, aggregated, anonymized) with legal/compliance before scaling volume.
- 4.Pick one concrete use case for the reuse loop: identify the ${'
prompt_template_id'} with the highest edit rate and treat it as priority content backlog.
Further reading
Executive track:
- The forgotten asset: turning AI interactions into auditable knowledge — the business view of this same topic.
