Blog

The Age of Emergent AI โ€” the six levels of Agentic Governance Maturity, from Prompt to Swarm.
Multi-Agent Systems in Production

The Age of Emergent AI

Classical software engineering is a century-long campaign to eliminate unpredictability. We write f(x) = y, test it, and expect the same output every time. Agentic software inverts that premise. At its core sits a large language model that does not compute answers so much as sample them from a probability distribution over tokens โ€” P(w_t | context). Any single run is one draw from that distribution. Emergent Engineering is the discipline of building deterministic frameworks โ€” context, harnesses, policies, and observability โ€” around that stochastic core so that reliable, governable behavior emerges from it.

The most useful mental model is a maturity ladder. Each level adds a new capability, and โ€” this is the part teams miss โ€” each new capability introduces a new class of failure that the previous level’s tooling cannot contain. You mature by adding the governance mechanism that tames the new failure. This post walks the six levels of Agentic Governance Maturity, and for each one it does two things: critiques the level’s shortcomings, and lays out exactly how to build the next level. The interactive portal below lets you explore each level, run a policy decision, and watch a swarm’s entropy live.

The shift: from control to containment

Three eras, side by side. In classical software the author holds absolute control: explicit logic, deterministic output, f(x) = y. In machine learning we surrender the exact function and approximate it from data โ€” fฬ‚(x) โ‰ˆ y โ€” trading authorial control for pattern-matching at scale. In emergent AI even the approximation is probabilistic: the model emits a distribution over next tokens and we sample it.

The engineering consequence is the whole game: you cannot unit-test your way to a guarantee when the unit is stochastic. So you stop trying to make the core deterministic and instead govern it. You engineer the boundary around the model โ€” what it can see, what it can do, and what it is forbidden from doing โ€” with the rigor classical software reserved for the logic itself. Determinism doesn’t disappear; it relocates to the boundary. The six levels below are six successively stronger boundaries.

The Agentic Governance Maturity model

Progress in agentic systems is less about larger models than about the sophistication of the governance we build around them. Six levels trace that path. Each introduces a distinct engineering challenge, a control mechanism, a set of shortcomings, and a concrete path to the next level.

LevelCapability it addsGovernance mechanismNew failure classYou’ve outgrown it whenโ€ฆ
1. PromptingShape behavior with wordsInstruction & few-shot contractsDrift, injection, hallucinationโ€ฆyou’re pasting data in by hand
2. ContextGround in fresh, private dataRetrieval & state hydration (RAG)Retrieval miss, context dilutionโ€ฆit can only tell you, not do
3. HarnessTake real actionsTyped, sandboxed tool use (MCP)Unsafe/unvalidated side-effectsโ€ฆone goal needs many dependent calls
4. SequentialChain dependent stepsOrchestration graph + state fabricPartial failure, state corruptionโ€ฆa fixed plan can’t adapt mid-run
5. Autonomous LoopDecide its own next stepDeontic policy engineRunaway autonomy, irreversible actsโ€ฆcoordinating many agents is the bottleneck
6. Collaborative SwarmCollective problem-solvingBlackboard + entropy governanceNon-convergence, cascade, collusionโ€”

Level 1 โ€” Prompting: carving a persona out of latent space

A pretrained model is a superposition of every persona, register, and reasoning style in its training data. Prompting is the act of collapsing that superposition toward one region with declarative language: a role (“you are an SRE telemetry sentinel”), an output contract (a JSON schema), a handful of exemplars, and explicit negative constraints (“never mutate production”). The governance mechanism here is the instruction contract itself.

Shortcomings. Everything lives in one editable text field, and that is the whole problem. Instructions drift as the conversation grows and the original system prompt slides out of the model’s effective attention. A later user turn can override an earlier rule โ€” classic prompt injection โ€” because to the model, instructions and data are the same tokens. With no grounding, the model fills gaps by inventing plausible facts. And structurally it is blind and handless: it cannot reach fresh or private data, cannot act, and remembers nothing beyond the window. At Level 1 your rules are suggestions, not walls.

Reaching Level 2. Stop feeding the model facts by hand and build a retrieval layer that does it automatically. Concretely: index your private and live data (chunk it semantically, embed it, store the vectors); insert a retrieve โ†’ assemble โ†’ generate step so every request first pulls the most relevant context and injects it into the prompt with citations; and add a memory tier so state survives across turns. The moment the model reasons over data it fetched rather than data you pasted, you are at Level 2.

Level 2 โ€” Context: grounding a frozen model in a live world

A model’s weights are frozen at training time and generic to the whole internet. Level 2 injects the specific, current state it needs at inference time โ€” the essence of Retrieval-Augmented Generation and, more broadly, dynamic state hydration. Because the context window is finite and every token costs latency and money, this level is really an information-retrieval problem wearing an LLM hat: chunking strategy, hybrid dense + lexical (BM25) retrieval, a cross-encoder reranker, and explicit context assembly.

Shortcomings. Retrieval is now a dependency, and it fails quietly. Low recall silently omits the one document that mattered, and you never see the omission. Context dilution โ€” the “lost in the middle” effect โ€” buries the key fact among filler so the model ignores it. A stale index confidently grounds the model in yesterday’s truth. A poisoned document becomes an injection vector that survives into the prompt. And the ceiling remains hard: context makes the model an authoritative observer, but it is still read-only. It can tell you exactly which pod to restart; it cannot restart it.

Reaching Level 3. Give the model hands โ€” but typed ones. Define a small set of tools as strict schemas (JSON Schema / Pydantic, or expose them over MCP), then build a harness that stands between the model and every side effect: it parses the proposed call, validates the arguments, authorizes the identity, executes in a sandbox, and returns a structured result. Start with read-only tools to prove the loop, then add mutating tools one at a time behind role-based access control. When the model can act and the harness is what makes that safe, you are at Level 3.

Level 3 โ€” Harness Engineering: where stochastic meets deterministic

This is the most important level and the one teams most often skip. A model that can act emits a string claiming to be a tool call; the harness is the typed, sandboxed layer that parses it, refuses anything that fails validation, executes the rest inside strict boundaries, and feeds a structured result back. Protocols like MCP standardize the wire format, but the harness is where you re-impose determinism on a probabilistic caller โ€” three responsibilities, always in this order:

class AegisHarness:
def __init__(self):
self.allowed = ["staging", "read-only"]
def execute_tool(self, call_json):
# 1. SCHEMA VALIDATION โ€” is this a well-formed, typed call?
call = ToolCall.model_validate_json(call_json) # reject malformed args
# 2. RBAC ENFORCEMENT โ€” is this identity permitted this namespace?
if call.namespace not in self.allowed:
return {"status": "blocked", "reason": "RBAC: namespace not permitted"}
# 3. SANDBOXED EXECUTION โ€” run with least privilege, timeouts, idempotency
return sandbox.run(call, timeout_s=30, idempotency_key=call.id)

The discipline in one line: the model proposes; the harness disposes. Its toolkit is strict argument schemas, tool-layer RBAC, least-privilege sandboxing, idempotency keys, and structured errors the model can recover from.

Shortcomings. The harness makes a single action safe, but it has no memory of the last action or intent for the next. It cannot express “do A, then B only if A succeeded, and roll back both if C fails.” Push a multi-step goal through a bare harness and you get brittleness: the model re-plans from scratch on every turn, loses track of what it already did, repeats or contradicts earlier steps, and leaves the system half-changed when one call fails. A validated action is necessary but it is not a workflow.

Reaching Level 4. Lift control flow out of application code and into an explicit orchestrator. Model the task as a state graph (a DAG) with a typed state object passed between nodes; let the model produce the plan while a graph engine (LangGraph-style) executes it. Add checkpointing so a long run can resume, parallel fan-out/fan-in for independent branches, and saga-style compensation so a mid-run failure can undo prior steps. When a durable, recoverable graph โ€” not your if/else โ€” drives the sequence, you are at Level 4.

Level 4 โ€” Loop Engineering : Sequential: orchestrating stateful, branching work

Level 4 chains individual tool calls into a multi-step workflow. The model produces a plan and an orchestrator executes it as a stateful graph, holding intermediate results in a “state fabric,” running independent branches in parallel, and joining them back together. The unit of reasoning is no longer a single call but a transaction that spans several โ€” and that is exactly what changes the failure surface.

Shortcomings. You have inherited every hard problem of distributed systems, now driven by a stochastic planner. Partial failure is the signature bug: step 3 of 5 throws and the system is left half-mutated. Parallel branches race on shared state. Context is lost across a hand-off, so a later node reasons on stale intermediate results. And more subtly, the plan itself is fixed at authoring time: a hand-drawn graph can only handle the paths you anticipated, so the instant reality diverges from the diagram, the workflow is stuck. Better prompts do not fix any of this; idempotency, transactions, and compensation do.

Reaching Level 5. Hand the planning to the agent and wrap it in governance. Replace the fixed graph with a closed perceive โ†’ decide โ†’ act โ†’ observe loop (ReAct or plan-execute) that chooses its own next action and reacts to results โ€” then bound it: explicit termination conditions, hard iteration and token budgets, and reflection between steps. Critically, stand up an out-of-band policy engine that evaluates every proposed action before it runs, plus human-in-the-loop gates on irreversible operations. When the agent decides the plan and a policy engine โ€” not the prompt โ€” governs it, you are at Level 5.

Level 5 โ€” Autonomy Engineering with the Autonomous Loop: policy engineering for self-directed agents

At Level 5 the agent enters a continuous cycle, choosing its own next action until a goal or termination condition is met. The per-step validation from the harness is necessary but no longer sufficient; you need standing rules about what ought to happen. That is policy engineering, and its logic is deontic: Permissions, Prohibitions, and Obligations, evaluated out of band by a policy engine before any action runs.

# Out-of-band deontic policy โ€” evaluated by the engine, NOT the model.
# PROHIBITION (F): no production mutation during the Friday change-freeze.
deny[action] {
action.verb == "patch"
action.target == "production"
time.weekday == "Friday"
}
# OBLIGATION (O): any allowed prod change must emit a health-check after.
require_healthcheck[action] { action.target == "production" }

The essential move is to keep policy outside the model. A rule in the system prompt is a suggestion the model can be argued out of or injected past; a rule in a separate engine is a wall. The agent may correctly reason that patching the database fixes the incident โ€” and still be blocked because it’s Friday. The reasoning is real; the policy is what makes it governable. (Try the simulator in the portal above: set the namespace to production, check “Is Friday,” and watch the prohibition roll it back.)

Shortcomings. A single governed agent is still a single agent โ€” a bottleneck and a single point of failure. It has one perspective, so it is prone to confident, unchallenged mistakes; nothing in the loop plays devil’s advocate. Its policy engine keeps it safe but does not make it smarter, and complex problems that need parallel specialists โ€” one to detect, one to fix, one to attack the fix โ€” do not fit inside one linear loop. Scale it by simply running more copies and they collide, because there is no protocol for them to coordinate.

Reaching Level 6. Decompose the one agent into specialized roles and replace central orchestration with decentralized coordination. Give them a shared blackboard where they publish observations and bid on tasks (a contract-net market), and add explicitly adversarial roles โ€” a critic, an adversary โ€” so the group challenges its own conclusions instead of amplifying them. Then change what you observe: with no central trace, instrument aggregate signals (entropy, consensus stability) and wire an autonomy governor that throttles the swarm when those signals go out of bounds. When useful behavior comes from the interaction rather than any one agent, you are at Level 6.

Level 6 โ€” Collaborative Swarm: emergence engineering

At the top level there is no central orchestrator to inspect. Multiple specialized agents โ€” say a Sentinel that detects symptoms, a Mutator that proposes fixes, and an Adversary that stress-tests them โ€” interact through a shared medium, and the useful behavior is authored in none of them. It is a property of the interaction. You stop programming steps and start engineering the conditions and boundaries under which good behavior emerges. Because there is no trace to read, you measure the system’s physics: agentic entropy (HA), how disordered the collective’s decisions are, and consensus stability, how reliably it converges.

Shortcomings. Emergence cuts both ways โ€” the same interactions that solve problems no single agent could also produce failures no single agent intended. Swarms oscillate and fail to converge; they slide into echo-chamber groupthink when the adversarial roles are too weak; a fault in one agent can cascade through the shared blackboard; and agents can settle into emergent collusion that no one designed and no trace explains. Debugging is genuinely hard, because there is no linear story to replay โ€” only aggregate signals to interpret.

Beyond Level 6. There is no Level 7 โ€” the frontier is tighter governance of emergence itself. The governing move is the “systemic chill-out” policy: when entropy crosses a safe threshold, the observability harness automatically scales down the swarm’s autonomy until order returns. From here the work is better entropy and consensus metrics, formal convergence guarantees, and federation across swarms. We do not merely watch emergence; we engineer its limits. That is the enduring role of the human operator in the age of emergent AI โ€” not to author every action, but to set the physical boundaries within which useful behavior is allowed to emerge.

Practitioner takeaways

  • Locate yourself on the ladder before you optimize. Most teams over-invest in prompt cleverness (Level 1) and under-invest in the harness (Level 3) that actually makes agents safe to ship. Effort should follow the failure class you’re actually hitting.
  • Don’t climb a level until you’ve contained the one below. Each level’s failure class is only tolerable because the previous level’s governance mechanism is solid. An autonomous loop on top of an unvalidated harness is an outage generator.
  • Determinism belongs at the boundary, not the core. Stop fighting the model’s stochasticity; spend that budget on retrieval quality, schema validation, RBAC, sandboxing, and policy.
  • Keep policy out of the model. Prohibitions and obligations enforced by an out-of-band engine survive prompt injection and model drift. Rules “in the system prompt” do not.
  • Instrument for emergence before you need it. Entropy and consensus metrics are cheap to add early and impossible to reconstruct after an incident.

Agentic governance is not a rejection of software rigor โ€” it is that rigor, relocated. We moved it from the logic to the boundary, one level at a time. The core became probabilistic; our discipline did not.

Architecture Pattern

Multiโ€‘Source RAG โ€” Ten Patterns with ADK


Pattern 1 โ€” Multiโ€‘Source Retrieval & Synthesis Orchestration

Pattern type: Architecture / Evaluation

Context / Background
Real questions often require complementary evidence scattered across multiple documents (narrative chapters, meeting segments). Systems must retrieve from diverse sources and synthesize longโ€‘form answers.

Problem
Singleโ€‘source or factoid QA hides failure modes: low retrieval diversity, missing complementary evidence, and weak longโ€‘form synthesis.

Forces

  • Recall vs. context budget
  • Complementary vs. overlapping evidence
  • Latency/cost vs. quality (reranking, longer prompts)
  • Abstractive coherence vs. extractive faithfulness

Solution (overview)
Split the pipeline into (A) multiโ€‘source retrieval (dense + reranker) and (B) a dedicated synthesis step run by a reasoning model. Evaluate with MSRSโ€‘style tasks that require multiโ€‘doc integration.

Solution โ€” Ten Steps

  1. Build a unified corpus with docโ€‘level and segmentโ€‘level metadata.
  2. Chunk to ~800โ€“1200 tokens; store both chunk and doc embeddings.
  3. Use domainโ€‘appropriate dense embeddings (story vs. meeting).
  4. Retrieve topโ€‘K chunks per query; ensure source diversity (distinct docs).
  5. Rerank chunks (pairwise or crossโ€‘encoder) to select complementary evidence.
  6. Deโ€‘duplicate and expand to full passages; enforce perโ€‘doc quotas.
  7. Construct a synthesis prompt with citations and perโ€‘doc keypoints.
  8. Run a reasoning LLM for longโ€‘form synthesis; keep chainโ€‘ofโ€‘thought internal.
  9. Postโ€‘validate with factuality checks against retrieved snippets.
  10. Score with ROUGEโ€‘1/2, BERTScore, and an LLMโ€‘based rubric (Gโ€‘Evalโ€‘style).

Implementation (ADKโ€‘style, Python skeleton)

# Pseudocode 
from google.adk.agents import Agent
from google.adk.memory import InMemoryMemoryService
from google.adk.runtime import Orchestrator

retriever = DenseRetriever(index="story_or_meet.index", k=12)
reranker = VertexAIReranker(model="text-multilingual-rerank@latest")

class MultiSourceRAGAgent(Agent):
    def handle(self, query: str):
        initial = retriever.search(query, k=24)              # highโ€‘recall set
        reranked = reranker.rerank(query, initial)
        diverse = enforce_doc_diversity(reranked, per_doc_max=3, top_k=8)
        prompt = build_synthesis_prompt(query, diverse)
        return self.call_reasoning_llm(prompt, model="gemini-2.5-pro")

orchestrator = Orchestrator(root=MultiSourceRAGAgent(), memory=InMemoryMemoryService())

Resulting Consequences

  • Exposes and reduces retrieval diversity gaps.
  • Stable quality across narrative and meeting domains.
    โˆ’ Slightly higher latency due to reranking and reasoning LLM step.

Related Patterns: #2 Decontextualization, #5 Reasoningโ€‘Model Synthesis, #8 Domainโ€‘specific Retriever Pairing.


Pattern 2 โ€” Query Decontextualization Gate

Pattern type: Data / Preโ€‘processing

Context / Background
Legacy datasets contain queries that implicitly rely on hidden context (e.g., โ€œWhatโ€™s the plot?โ€). This confuses retrieval and penalizes the wrong stage.

Problem
Ambiguous queries inflate difficulty and degrade retrieval precision; synthesis quality becomes noisy.

Forces

  • Ambiguity vs. realism
  • Rewrite effort vs. evaluation clarity
  • Risk of query drift

Solution (overview)
Rewrite queries into standalone forms before retrieval; add a light classifier that routes โ€œunderspecifiedโ€ queries through a decontextualization step.

Solution โ€” Ten Steps

  1. Define decontextualization rubric (who/what/when/where).
  2. Fineโ€‘tune or prompt an LLM to rewrite underspecified queries.
  3. Detect underspecification with a small classifier (BERT/SFT) or rules.
  4. Preserve original intent via entity and constraint extraction.
  5. Add provenance tags (original vs. rewritten) for auditability.
  6. Reโ€‘run retrieval on rewritten queries; keep both result sets for ablation.
  7. Penalize rewrites that materially change the ask (edit distance + entity diff).
  8. Log retrieval deltas (P@K/R@K/NDCG) and downstream score deltas.
  9. If deltas regress, fall back to humanโ€‘approved rewrite templates.
  10. Report decontextualization coverage and gains in eval dashboards.

Implementation (ADKโ€‘style, microโ€‘agent)

class DecontextualizeAgent(Agent):
    def handle(self, query: str) -> str:
        if is_underspecified(query):
            return rewrite_query(query, model="gemini-2.5-flash")
        return query

Resulting Consequences

  • Higher retrieval precision/recall; cleaner attribution.
    โˆ’ Small risk of intent drift (mitigated by entity constraints).

Related Patterns: #1 Orchestration, #6 Oracleโ€‘Gap Diagnostic.


Pattern 3 โ€” Retriever Diversity & Kโ€‘Target Tuning

Pattern type: Retrieval Engineering

Context / Background
MSRS domains differ in optimal K and chunking. Narratives need more complementary slices; meetings benefit from concise, timestamped segments.

Problem
Fixed K and naรฏve chunking reduce complementary coverage or flood the context with redundancy.

Forces

  • Chunk size vs. semantic cohesion
  • K vs. latency and context window
  • Docโ€‘level vs. segmentโ€‘level granularity

Solution (overview)
Tune chunk size (~1K tokens), choose K to match average oracle set per domain, and enforce crossโ€‘doc diversity with perโ€‘doc caps before synthesis.

Solution โ€” Ten Steps

  1. Profile oracle set sizes per domain (e.g., Kโ‰ˆ8 story, Kโ‰ˆ3 meet).
  2. Chunk at 800โ€“1200 tokens; store title/speaker metadata.
  3. Use meanโ€‘pooled embeddings over tokens; persist docโ€‘level vectors.
  4. Retrieve k_hi for recall (e.g., 24).
  5. Rerank to k_mid (e.g., 10) with crossโ€‘encoder or Vertex Reranker.
  6. Enforce perโ€‘doc cap (e.g., โ‰ค3 from any doc).
  7. Expand to full passages if needed (keep citations tight).
  8. Run ablations over {k_hi, k_mid, per_doc_cap}.
  9. Track retrieval metrics alongside generation (linked runs).
  10. Ship tuned defaults per domain config.

Implementation (selection helper)

def select_diverse(chunks, per_doc_max=3, top_k=8):
    out, seen = [], {}
    for c in chunks:
        d = c.meta["doc_id"]
        if seen.get(d, 0) < per_doc_max:
            out.append(c); seen[d] = seen.get(d, 0) + 1
        if len(out) == top_k: break
    return out

Resulting Consequences

  • Better complementary coverage; lower redundancy.
    โˆ’ Requires domain profiling and stored metadata discipline.

Related Patterns: #8 Domainโ€‘specific Pairing, #4 Longโ€‘Context Guardrail.


Pattern 4 โ€” Longโ€‘Context Guardrail vs. Selective Retrieval

Pattern type: Architecture

Context / Background
Temptation: โ€œjust stuffโ€ the entire corpus into a longโ€‘context model. In meetings, this often exceeds limits or degrades synthesis quality versus a strong retriever.

Problem
Truncation, noise injection, and cost explode in longโ€‘contextโ€‘only setups.

Forces

  • Context window vs. corpus size
  • Latency/cost vs. precision
  • Summarization sensitivity to irrelevant passages

Solution (overview)
Adopt a guardrail: default to selective retrieval; allow longโ€‘context only when the corpus fits comfortably and shows nonโ€‘inferior performance in canary runs.

Solution โ€” Ten Steps

  1. Compute perโ€‘query corpus token count; preflight against window.
  2. Run canary evals: Longโ€‘Context vs. Strongโ€‘Retriever vs. Oracle.
  3. If LC โ‰ค SR โˆ’ delta on Gโ€‘Eval, route to SR; else allow LC.
  4. For meetings, always SR unless corpus < 60% of window.
  5. Prefer reasoning LLM for synthesis even under LC.
  6. Trim boilerplate (agenda, greetings) via regex/learned filters.
  7. Collapse repetitive turns with speakerโ€‘aware summarizers preโ€‘retrieval.
  8. Cache LC summaries; refresh on corpus change.
  9. Monitor window overflows; fail closed to SR.
  10. Periodically reโ€‘test thresholds as models evolve.

Implementation (routing sketch)

if tokens(corpus) < 0.6 * CONTEXT_LIMIT and lc_performs_ok():
    mode = "long_context"
else:
    mode = "selective_retrieval"

Resulting Consequences

  • Prevents silent truncation losses; lowers costs.
    โˆ’ Requires periodic A/B checks as LLMs change.

Related Patterns: #1 Orchestration, #6 Oracleโ€‘Gap Diagnostic.


Pattern 5 โ€” Reasoningโ€‘Model Synthesis Step

Pattern type: Generation

Context / Background
Even with oracle (gold) docs, nonโ€‘reasoning LLMs miss major/minor details in multiโ€‘doc synthesis.

Problem
Underโ€‘integration of evidence; shallow abstractions.

Forces

  • Coherence vs. coverage
  • Abstractive style vs. lexicalโ€‘overlap metrics

Solution (overview)
Use a reasoning LLM for the synthesis step with a scaffold that enumerates perโ€‘doc keypoints and forces crossโ€‘document linkage.

Solution โ€” Ten Steps

  1. Convert retrieved chunks โ†’ perโ€‘doc bullets (autoโ€‘salience).
  2. Require model to cite docโ€‘ids inline (e.g., [D3]).
  3. Ask for contrasts and agreements across docs.
  4. Add a checklist of required elements (entities, events, outcomes).
  5. Enforce sectioned output (Summary / Evidence / Gaps).
  6. Use low temperature; enable reasoning mode.
  7. Set generous max tokens (โ‰ฅ reference 95th percentile).
  8. Run selfโ€‘critique pass with evidenceโ€‘grounded rubric.
  9. Optionally compress to executive digest.
  10. Capture structured citations for audit.

Implementation (prompt scaffold, sketch)

SYNTH_PROMPT = f"""
You are a synthesis model. Given query Q and passages P[i] with doc_id,
write a coherent longโ€‘form answer that integrates complementary info.
- Enumerate keypoints per doc.
- Link points across docs (agreements/contrasts).
- Cite like [D{{doc_id}}].
- Sections: Summary, Evidence, Open Questions.
Q: {{query}}
P: {{passages}}
"""

Resulting Consequences

  • Higher Gโ€‘Eval (coherence/coverage) even if ROUGEโ€‘2/BERTScore move modestly.
    โˆ’ Slightly longer latency.

Related Patterns: #1, #3, #6.


Pattern 6 โ€” Oracleโ€‘Gap Diagnostic Harness

Pattern type: Evaluation / Diagnostics

Context / Background
We need to attribute failures to retrieval vs. generation.

Problem
Pipeline confounding hides which component to improve.

Forces

  • Retriever diversity vs. generator capability
  • Metric sensitivity (IR vs. summarization)

Solution (overview)
Run three controlled conditions per query: Oracle (gold docs), Strong Retriever, Longโ€‘Context. Compare ROUGEโ€‘1/2, BERTScore, and Gโ€‘Evalโ€‘style rubric; add smallโ€‘scale human error tags.

Solution โ€” Ten Steps

  1. Build eval dataset with query, gold summary, oracle docโ€‘ids.
  2. Implement runners for the three modes.
  3. Log IR metrics (P@K/R@K/NDCG/MAP) for SR.
  4. Compute ROUGEโ€‘1/2/L and BERTScore F1.
  5. Run LLMโ€‘asโ€‘Judge with a fixed rubric (coverage, coherence, grounding).
  6. Sample 40 outputs for human error taxonomy (missing major/minor, hallucination, vagueness).
  7. Attribute gap: if Oracle โ‰ซ SR โ†’ fix retrieval; if Oracle low โ†’ fix synthesis.
  8. Report perโ€‘domain breakdown (story vs. meeting).
  9. Store run manifests for repro.
  10. Alert when regressions exceed thresholds.

Implementation (runner sketch)

for mode in ["oracle", "strong_retriever", "long_context"]:
    preds = run_mode(mode, dataset)
    scores[mode] = compute_scores(preds, refs)
report = compare(scores)

Resulting Consequences

  • Clear, actionable attribution of errors.
    โˆ’ Requires curation of oracle doc sets.

Related Patterns: #4 Guardrail, #9 Contamination Safeguard.


Pattern 7 โ€” Multiโ€‘Document Necessity Enforcement (Dataset Construction)

Pattern type: Data / Benchmarking

Context / Background
Benchmarks are often solvable from a single doc, defeating the point of multiโ€‘source RAG.

Problem
Systems โ€œcheatโ€ by relying on one document; evaluation underโ€‘stresses retrieval diversity and synthesis.

Forces

  • Realism vs. construction cost
  • Complementary vs. redundant evidence

Solution (overview)
During dataset construction, ensure that answering the query requires at least two complementary documents; validate necessity by ablating each doc and observing score drops.

Solution โ€” Ten Steps

  1. Start from longโ€‘context, queryโ€‘focused MDS sources.
  2. Segment into documents; map queries to needed docs.
  3. Mark complementary roles (plot, setting; agenda, decision).
  4. Create oracle doc sets โ‰ฅ2 docs per item.
  5. Verify necessity via leaveโ€‘oneโ€‘out ablations.
  6. Remove items solvable from a single doc.
  7. Humanโ€‘validate a sample per batch.
  8. Publish docโ€‘id mappings for reproducibility.
  9. Provide retrieval baselines.
  10. Version datasets with changelogs.

Implementation
A small script computes ฮ”score when removing each doc; keep items with ฮ”score significant.

Resulting Consequences

  • Realistic pressure on retrieval and synthesis.
    โˆ’ Higher curation effort.

Related Patterns: #1, #6.


Pattern 8 โ€” Domainโ€‘Specific Retriever + Reranker Pairing

Pattern type: Retrieval Engineering

Context / Background
Narrative prose and meetings differ in structure, vocabulary, and evidence distribution.

Problem
Oneโ€‘size retriever fails crossโ€‘domain; BM25 can look โ€œgoodโ€ on IR metrics but underperform on generation for meetings.

Forces

  • Dense vs. sparse retrieval
  • Dialogue structure (speaker, timestamp) vs. prose
  • Reranker choice and depth

Solution (overview)
Choose perโ€‘domain stacks (e.g., geminiโ€‘embedding for STORY; NVโ€‘Embedโ€‘v2 + reranker for MEET). Use reranking depth tuned to domain.

Solution โ€” Ten Steps

  1. Benchmark multiple dense models per domain.
  2. Keep BM25 as fallback for rare keywords.
  3. Train/choose a reranker aligned to domain style.
  4. Tune k_hi/k_mid per domain.
  5. Enforce doc diversity caps.
  6. Use speaker/timestamp fields in meeting retrieval.
  7. Penalize boilerplate turns in meetings during rerank.
  8. Maintain separate indices per domain.
  9. Log crossโ€‘domain comparisons.
  10. Reโ€‘validate quarterly as models update.

Implementation (config separation)

story:
  embed_model: gemini-embedding
  k_hi: 24
  k_mid: 10
  reranker: vertexai_rerank
meet:
  embed_model: nv-embed-v2
  k_hi: 18
  k_mid: 6
  reranker: vertexai_rerank

Resulting Consequences

  • Higher synthesis quality with stable retrieval.
    โˆ’ Slightly increased ops overhead (two stacks).

Related Patterns: #3 Tuning, #4 Guardrail.


Pattern 9 โ€” Dataโ€‘Contamination & Leakage Safeguard

Pattern type: Evaluation Hygiene

Context / Background
Pretraining leakage can inflate scores and mask weaknesses.

Problem
Contaminated corpora compromise credibility and comparability.

Forces

  • Detectability vs. cost
  • Model updates over time
  • Reproducibility

Solution (overview)
Run contamination checks, report multiple retrieval settings (Oracle, SR, LC), and maintain contamination manifests.

Solution โ€” Ten Steps

  1. Hash and timestamp corpora; store digests.
  2. Use webโ€‘scale overlap detectors for known model pretrains when available.
  3. Reโ€‘run eval on release model updates.
  4. Publish both SR and Oracle results.
  5. Record prompts and seeds for LLMโ€‘asโ€‘judge.
  6. Keep outโ€‘ofโ€‘domain canaries.
  7. Maintain frozen โ€œleaderboardโ€ snapshots.
  8. Track drift across time.
  9. Share contamination notes with peers.
  10. Automate checks in CI.

Implementation
Simple overlap heuristics (URL/domain matches, nโ€‘gram hashes) + manual spot checks.

Resulting Consequences

  • Trustworthy comparisons; easier peer review.
    โˆ’ Extra upfront work.

Related Patterns: #6 Diagnostic, #10 Scalable Construction.


Pattern 10 โ€” Scalable Benchmark Construction Loop

Pattern type: Process / Dataset Ops

Context / Background
Constructing multiโ€‘source tasks by hand is costly. MSRS shows a scalable way to bootstrap from existing longโ€‘context MDS datasets.

Problem
Quality vs. throughput tradeโ€‘off; human validation budget.

Forces

  • Automation vs. manual quality
  • Coverage vs. necessity constraints

Solution (overview)
Bootstrap from longโ€‘context, queryโ€‘focused datasets; enforce multiโ€‘doc necessity; apply decontextualization; validate at scale with spot checks.

Solution โ€” Ten Steps

  1. Pick base datasets (e.g., stories, meetings).
  2. Segment into documents; map queries to segments.
  3. Generate/clean decontextualized queries.
  4. Build oracle sets (โ‰ฅ2 docs).
  5. Index with dense embeddings.
  6. Calibrate K targets per domain.
  7. Create SR/LC/Oracle runners.
  8. Score with ROUGE/BERTScore/Gโ€‘Eval rubric.
  9. Humanโ€‘validate samples and error taxonomy.
  10. Release code/data with versioning.

Implementation
Provide scripts for segmentation, indexing, oracle mapping, and eval.

Resulting Consequences

  • Sustainable benchmark evolution; transferable to new domains.
    โˆ’ Ongoing maintenance of mappings and oracles.

ADKโ€‘Style Evaluation Harness (reproduces SR vs. LC vs. Oracle)

Inputs: queries.jsonl (id, query), oracle.jsonl (id, doc_ids[]), refs.jsonl (id, summary), index/ (FAISS/Vertex, plus metadata), corpus/ (text).

Modes

  • oracle: load oracle docs; pass to reasoning synthesizer.
  • strong_retriever: dense โ†’ rerank โ†’ diverse select.
  • long_context: pack entire corpus (guardrailed) or queryโ€‘scoped subcorpus.

Metrics

  • IR: P@K, R@K, NDCG, MAP (for SR mode)
  • Generation: ROUGEโ€‘1/2/L, BERTScore F1
  • LLMโ€‘asโ€‘Judge rubric (coverage, coherence, grounding) โ†’ 0โ€“100

Runner (skeleton)

from rag_eval import rouge, bertscore, geval

def run(mode, batch):
    if mode == "oracle":
        ctx = pull_oracle(batch)
    elif mode == "strong_retriever":
        ctx = retrieve_and_rerank(batch)
    elif mode == "long_context":
        ctx = pack_long_context(batch)
    return synthesize(ctx, model="gemini-2.5-pro")

scores = {}
for mode in ["oracle","strong_retriever","long_context"]:
    preds = run(mode, dataset)
    scores[mode] = {
        **rouge(preds, refs),
        **bertscore(preds, refs),
        "geval": geval(preds, refs, judge="gemini-2.5-pro")
    }
compare_and_report(scores)

Human Error Taxonomy (lightweight)
Sample 40 items and annotate: (a) missing many major details, (b) missing many minor details, (c) hallucination, (d) query misunderstanding, (e) vagueness.


ADK Components & Swappables

  • Embedding: gemini-embedding (story), nv-embed-v2 (meeting).
  • Reranking: Vertex AI Ranking API, LangChain Vertex Reranker wrapper.
  • Reasoning LLM: gemini-2.5-pro / gemini-2.5-flash for faster ablations.
  • Memory: InMemoryMemoryService for local runs; Memory Bank for persistence.
  • Orchestration: Root agent routes through #2 gate โ†’ #3 tuned retrieval โ†’ #5 synthesis.