Knowledge Graphs for AI Agents
Track 4 โ€” Serving & Architecture

M10 ยท The Hybrid Context Stack

Module 11 of 14
โฑ Estimated time: 45 minutes ๐Ÿ“‹ Prerequisites: M02 (RAG limits), M04 (structural graphs), M07 (OKF bundles), M09 (serving) ๐ŸŽš Level: Advanced

Learning Objectives

SKILL LEVEL: ADVANCED

  • Assign each context layer its owned territory: structural graph = what the code is; OKF = what engineers know; vector RAG = the unstructured remainder.
  • Apply the two failure triggers โ€” multi-hop reasoning failure and tribal-knowledge sprawl โ€” to decide which layer (if any) a system needs next.
  • Trace one query through the three-stage pipeline (narrative orientation โ†’ structural traversal โ†’ semantic search) and account for its token budget.
  • Build a router that classifies queries as canonical, structural, or exploratory, and dispatches them to the right layer with fallbacks.
  • Cite the production evidence โ€” the ERPNext case study โ€” and explain why accuracy gains are a better signal than token-reduction multiples.

Three Layers, Not Three Competitors

The viral framing of 2026 โ€” "Graphify kills RAG," "OKF kills vector databases" โ€” is backwards, and you have spent nine modules accumulating the evidence to see why. Graphify's own benchmarks (M04) showed it tying dense vector RAG on QA accuracy and slightly losing on recall. OKF's own spec (M06) ships no search layer at all. Neither of these things is trying to replace retrieval. They are specialized layers that sit alongside a vector index, each justified only by a specific failure mode.

BEFORE: Think about how you'd research an unfamiliar city before moving there. You'd use the street map to understand how districts connect. You'd read a local's guide for the things no map shows โ€” which neighborhoods are quiet, why the old town floods in spring. And you'd search the city's newspaper archive for anything else that comes up.

PAIN: Now imagine being told to choose ONE. Navigate with only the newspaper archive and you'll piece together street layouts from decade-old traffic reports. Use only the map and you'll never learn the flood story. Each source answers a class of question the others structurally cannot.

MAPPING: The structural graph is the street map โ€” precise, verifiable connections. The OKF bundle is the local's guide โ€” curated, narrative, explains why. Vector RAG is the newspaper archive โ€” vast, unstructured, searchable by theme. The 2026 architecture question was never "which one wins?" It is "which layer owns which context?"

A hybrid context stack is an agent architecture in which three retrieval mechanisms coexist, each owning a distinct knowledge class: (1) a vector RAG index over unstructured text โ€” docs, tickets, Slack threads, the long tail; (2) a structural graph โ€” deterministic, AST-extracted call graphs, class hierarchies, imports and exports; (3) a narrative layer (OKF) โ€” curated Markdown concepts capturing architecture, schemas, playbooks, and intent. In one sentence: Graphify extracts what the code is, OKF curates what engineers know, and vector RAG searches the unstructured remainder.

Animation ยท THREE_LAYER_STACK โ€” one agent, three feeds
๐Ÿค– AI coding agent
context assembly
๐Ÿ”Ž VECTOR RAG
docs ยท tickets ยท Slack
long-tail text
๐Ÿ—บ STRUCTURAL
AST call graphs
imports ยท hierarchies
๐Ÿ“š OKF NARRATIVE
architecture ยท schemas
playbooks ยท intent
Press play: three questions, three different layers answering.

The capability breakdown

Vector RAGStructural graphOKF narrative
OwnsUnstructured long tailWhat the code ISWhat engineers KNOW
RetrievalProbabilistic (nearest-neighbor)Deterministic (edge traversal)Deterministic (exact file)
Best question"Themes in churn interviews?""What calls verify_token?""Why does billing route through a webhook?"
Fails atMulti-hop structure, canonical truthBusiness intent, the whyUncurated bulk, thematic search
Ingest costEmbedding + re-indexingZero-LLM AST parseCuration labor (M08's pipeline)
โš ๏ธ Common Misconceptions

"The graph replaces my vector index." โ€” On head-to-head QA accuracy, graph retrieval tied dense RAG (76% vs 76% on LongMemEval-S) and slightly lost on recall. Its wins are determinism and ingest cost, not retrieval quality. Evaluate it as a RAG replacement and you'll maintain graphs for problems you don't have.

"OKF is a smarter RAG." โ€” OKF has no retrieval at all. It's a format. At scale something must still search it โ€” often the same retrieval machinery RAG already provides, now pointed at something worth retrieving from.

"More layers = better agent." โ€” Every layer is maintenance: hooks, lint, freshness gates (M11). A layer with no failure mode justifying it is pure overhead.

Failure-Driven Adoption: The Two Triggers

Here is the discipline that separates architecture from hype-chasing: you add a layer when โ€” and only when โ€” you have observed a concrete failure mode that layer addresses. Not because a benchmark impressed you, not because a launch post went viral, and not because of vague dissatisfaction with your current RAG setup.

That last one deserves numbers. Industry surveys found that 72% of enterprise RAG deployments underdelivered or failed outright in year one โ€” but the dominant causes were poor chunking strategies, outdated vector indices, and inappropriate embedding models, not the absence of a graph. Adding a knowledge graph to a flawed retrieval pipeline gives you a flawed retrieval pipeline with higher operational overhead. Fix the pipeline first; as Atlan's guidance puts it: "RAG first, graph when depth becomes a bottleneck."

Animation ยท DECISION_TREE โ€” symptom before tool
Does your coding agent underperform?
sifting multi-file code
dependencies & calls
loss of tribal context
across team silos
Multi-Hop Reasoning Failure
Knowledge Sprawl Failure
TRIGGER โ†’ add a structural graph
(AST edges: Graphify / CodeGraph)
TRIGGER โ†’ add Google OKF
(curated narrative spec)
Press play to walk both diagnostic branches.

Trigger 1 โ€” multi-hop reasoning failures โ†’ add the structural graph

This failure appears when an answer requires linking facts across multiple files that are never co-located in one text chunk. The symptom sounds like: your agent cannot answer "What breaks in the API layer if I alter the schema in db/migrations/04_users.sql?" It retrieves the migration file (keyword-rich, semantically close) but misses the foreign-key references, interface implementations, and cross-file calls that make up the actual answer.

Why can't better prompting fix it? Because vector RAG embeds text blocks independently. The relationship between the migration and the API handler was never captured in vector space โ€” there is nothing for a better prompt or a bigger context window to recover. M02 called this the structural blind spot; the fix is the layer whose entire job is relationships: the AST graph you built in Track 2.

Trigger 2 โ€” tribal-knowledge sprawl โ†’ add OKF

This failure appears when critical institutional context is fragmented across Slack channels, outdated wikis, and unwritten developer memory. The symptom is subtler and nastier: the agent generates syntactically valid code that violates internal architectural guidelines, calls deprecated internal APIs, or ignores domain-specific business logic. Nothing crashes. Reviews catch it โ€” sometimes.

Why can't the structural graph fix it? Because AST parsers inspect source code, and business intent isn't in the source. No parse of webhooks.py reveals that the team decided (ADR-001) never to make billing settlement block on notifications. That knowledge lives in prose โ€” which is exactly what OKF's concept files are for, in a shape agents reliably parse.

โœ… Why It Matters

The triggers keep you honest in both directions. orderflow's 15 files will never produce a multi-hop failure a single context window can't absorb โ€” so a structural graph there is ceremony (below the ~500-file floor from M04). A 3,000-file monorepo with three teams and a rotating on-call absolutely will โ€” and there the graph pays for itself weekly. Same tool, opposite verdicts, decided by observed failure, not fashion.

The Staged Query Pipeline

When a system has earned all three layers, how do they compose at query time? Not as alternatives the agent picks between at random โ€” as stages, ordered from cheapest-and-most-curated to broadest-and-noisiest. Follow one real query through: "What breaks if I modify UserService.py?"

Animation ยท STAGED_PIPELINE โ€” one query, three stages, a running meter
"What breaks if I modify UserService.py?"
STAGE 1 ยท OKF progressive disclosure โ€” read module narrative & owner specs (~2K tokens)
STAGE 2 ยท Graph traversal โ€” walk calls / imports / inherits edges (zero LLM cost)
STAGE 3 ยท Vector / sparse search โ€” Slack incidents, issues, PR comments (only the remainder)
tokens: 0
Press play to run the query through the stack.

Walk the stages in prose, because the ordering logic is the lesson:

  1. Stage 1 โ€” narrative orientation (~2K tokens). The agent reads the OKF catalog's entry for the target: what UserService is, who owns it, which modules relate. This is progressive disclosure from M09 โ€” a curated 2K-token orientation instead of a 50-file exploration. Output: the specific nodes worth investigating.
  2. Stage 2 โ€” structural traversal (zero LLM cost). With targets identified, the agent queries the graph: callers, implementers, transitive dependents. Deterministic answers from the M09 server; the LLM spends nothing acquiring them and everything reasoning about them.
  3. Stage 3 โ€” the unstructured remainder. Whatever the curated layers can't answer โ€” "did we have an incident last time someone touched this?" โ€” goes to vector/sparse search over Slack logs, GitHub issues, PR comments. RAG does what RAG is actually for: the long tail.
๐Ÿ”Ž What Just Happened?

Each stage narrows the next stage's work. The narrative layer told us where to look; the graph told us exactly what's connected; search only had to cover what neither curated layer could know. Reverse the order and stage 3 runs first over everything โ€” which is the M00 exploration problem all over again, with extra infrastructure.

The Router Pattern

The staged pipeline suits deep investigations. But plenty of agent traffic is single questions, and those deserve a cheaper dispatch: a router that classifies each query and sends it straight to the layer that owns it. A canonical question โ€” "What is the SLA for Severity-1 incidents?" โ€” routes to a deterministic OKF read. A structural one โ€” "who calls this?" โ€” routes to the graph server. An exploratory one โ€” "what are common themes in churn interviews?" โ€” falls back to vector search.

Let's build the skeleton, in three chunks. Chunk 1 โ€” classification. What: decide the query class. Why: the class determines cost and failure characteristics โ€” a canonical query answered probabilistically is how the stale-WAU disaster of M02 happened. Gotcha: keyword rules look naive but are transparent and debuggable; teams often run rules first with an LLM-classifier fallback, not the reverse.

router.py โ€” classify
STRUCTURAL_CUES = ("who calls", "what calls", "depends on", "call graph",
                   "imports", "blast radius", "what breaks", "cycle")
CANONICAL_CUES  = ("definition of", "canonical", "sla", "policy",
                   "runbook", "how do we compute", "what is our")

def classify(query: str) -> str:
    q = query.lower()
    if any(cue in q for cue in STRUCTURAL_CUES):
        return "structural"
    if any(cue in q for cue in CANONICAL_CUES):
        return "canonical"
    return "exploratory"          # default: the broad, noisy layer
router.mjs โ€” classify
const STRUCTURAL_CUES = ["who calls", "what calls", "depends on", "call graph",
                         "imports", "blast radius", "what breaks", "cycle"];
const CANONICAL_CUES  = ["definition of", "canonical", "sla", "policy",
                         "runbook", "how do we compute", "what is our"];

function classify(query) {
  const q = query.toLowerCase();
  if (STRUCTURAL_CUES.some(c => q.includes(c))) return "structural";
  if (CANONICAL_CUES.some(c => q.includes(c)))  return "canonical";
  return "exploratory";          // default: the broad, noisy layer
}

Chunk 2 โ€” dispatch with fallbacks. What: send each class to its layer, and fall through when a layer misses. Why: the M09 server returns a graceful miss ("not in graph โ€” try grep") precisely so a router can catch it and degrade to search instead of failing. Gotcha: log every route decision โ€” when the router misroutes (it will), the log is how you tune the cues.

router.py โ€” dispatch
import logging
log = logging.getLogger("router")

def route(query: str) -> dict:
    kind = classify(query)
    log.info("route=%s query=%r", kind, query)
    try:
        if kind == "structural":
            answer = graph_query(query)          # M09 MCP tools
            if "error" in answer:                # graceful miss -> degrade
                log.warning("graph miss, falling back to search")
                return {"layer": "vector", "answer": vector_search(query)}
            return {"layer": "graph", "answer": answer}
        if kind == "canonical":
            return {"layer": "okf", "answer": read_concept(query)}  # exact file
        return {"layer": "vector", "answer": vector_search(query)}
    except Exception as exc:
        log.error("layer failed: %s โ€” degrading to vector search", exc)
        return {"layer": "vector", "answer": vector_search(query)}
router.mjs โ€” dispatch
async function route(query) {
  const kind = classify(query);
  console.error(`route=${kind} query=${JSON.stringify(query)}`);
  try {
    if (kind === "structural") {
      const answer = await graphQuery(query);      // M09 MCP tools
      if (answer.error) {                          // graceful miss -> degrade
        console.error("graph miss, falling back to search");
        return { layer: "vector", answer: await vectorSearch(query) };
      }
      return { layer: "graph", answer };
    }
    if (kind === "canonical")
      return { layer: "okf", answer: await readConcept(query) };  // exact file
    return { layer: "vector", answer: await vectorSearch(query) };
  } catch (exc) {
    console.error(`layer failed: ${exc} โ€” degrading to vector search`);
    return { layer: "vector", answer: await vectorSearch(query) };
  }
}

Chunk 3 โ€” what the leaf functions are. Nothing new: graph_query wraps the M09 MCP tools; read_concept is a python-frontmatter read of the matching bundle file (M06); vector_search is whatever retrieval you already had. The router adds no storage of its own โ€” it is pure traffic control over layers you built in earlier modules.

๐Ÿ”Ž What Just Happened?

You turned three independent layers into one system with ~40 lines of dispatch. Note the asymmetry of the fallbacks: everything degrades toward vector search (broad, probabilistic, always available) and never toward OKF (exact answers only โ€” a fuzzy fallback pretending to be canonical is precisely the M02 disaster).

The Evidence

Does the assembled stack actually help? Two data points frame the answer โ€” one for the upside, one for the cost of not having it.

The ERPNext case study

The best production-shaped benchmark in the corpus ran on ERPNext, an open-source enterprise repository of over 1,000,000 lines of Python and JavaScript โ€” real scale, not a 52-file demo. Evaluations used Claude Opus 4.8, capped at 14 turns per task:

  • Baseline agent (vector RAG / grep exploration): 70.8% key-fact coverage.
  • Graphify + OKF hybrid pipeline: 82.0% key-fact coverage, averaging ~140,000 tokens per query session.

Sit with what an 11.2-percentage-point improvement means on a million-line codebase: roughly one in nine facts the baseline agent missed or got wrong, the hybrid agent got right. Missed facts are wrong refactors, broken callers, violated conventions. That accuracy delta is a far more reliable indicator of production value than any synthetic token-reduction multiple โ€” token savings tell you the agent was cheaper; fact coverage tells you it was right.

The cost of retrieval-only

On the other side of the ledger: research into legal-domain RAG systems โ€” a field with high-stakes, multi-document questions much like large codebases โ€” found standard retrieval tools hallucinate in 17% to 33% of complex queries, because retrieval alone fails to model multi-document logic. That is the gap the structural and narrative layers exist to close: not making search better, but removing whole question classes from search's jurisdiction.

๐Ÿ’ฐ The Honesty Rule, applied

Notice which number this module leads with: an accuracy gain measured on a 1M-LOC repo with a stated model and turn cap โ€” not a 71.5ร— token multiple from a favorable 52-file corpus. When you evaluate this architecture for your own team, replicate the ERPNext shape: your repo, a fixed task set, fact-coverage scoring, before and after. M04 taught you why: token multiples are corpus-topology-dependent; correctness deltas are what your users experience.

The Decision Matrix

Locate your codebase's shape and your observed failure mode; the cell tells you what to add next. (No observed failure โ†’ the answer is always "nothing yet.")

EnvironmentMulti-hop failures observedTribal-knowledge failures observedNo concrete failures yet
Monolith (<500 files)Usually fits in context โ€” verify before adding a graph (below the payoff floor)Add a small OKF bundle; curation cost is low at this sizeRAG-only is fine; fix chunking first
MicroservicesAdd the structural graph โ€” cross-service call chains are exactly what chunks never co-locateAdd OKF โ€” ownership boundaries and contracts are narrative knowledgeKeep RAG; add contract concepts opportunistically
Monorepo (1000s of files)Structural graph, with M11's freshness ops from day oneOKF with lint + governance (type drift arrives with team count)Instrument agent failures first; adopt from data

The matrix encodes this module's whole argument: the environment sets the cost of each layer, the failure mode sets the value, and you adopt when value exceeds cost โ€” never on hype.

Walk it, step by step

One question sent to each layer in turn, including the layers that answer it badly. The routing rule at the end is what the whole module is for.

MCP vs RAG vs OKF: One Metric, Three Roles

A final source of confusion to dissolve: MCP, RAG, and OKF get name-dropped together so often that they blur. They occupy different positions in the timeline of a question. OKF is knowledge written down in advance. MCP is the live connection to systems at question time. RAG is on-the-spot retrieval over what nobody curated.

orderflow's WAU metric shows all three in one story. The definition of weekly active users โ€” 7-day window, completed orders, testers excluded โ€” lives in an OKF concept file, written once, versioned in git (M06). When an agent must compute this week's WAU, the definition doesn't run queries: the agent calls a database tool over MCP to execute the SQL against the live warehouse. And when someone asks "have we ever debated changing the WAU window?" โ€” that discussion lives in old Slack threads and PR comments, which is RAG's territory.

One more composition worth knowing: OKF bundles can themselves be RAG targets. Once a bundle grows past what an agent browses by hand, a search layer indexes it โ€” and clean, structured Markdown with explicit links is far better material to index than PDFs chopped into arbitrary chunks. The honest picture isn't "OKF instead of RAG"; it's "RAG, pointed at something worth retrieving from."

You can now assign any piece of knowledge to its layer and any question to its route. Time to prove it on ten real queries.

Hands-On: Route 10 Queries

What you'll do: act as the router. For each orderflow query, pick the layer that should own it. Immediate feedback per pick โ€” this exercise is embedded (no lab folder). Time: 15 min.

Q1. "Who calls verify_token, directly and transitively?"

Structural graph
Vector RAG
OKF bundle

Q2. "What is the canonical definition of weekly active users?"

Vector RAG
OKF bundle
Structural graph

Q3. "What were the recurring complaints in last quarter's support tickets?"

Vector RAG
OKF bundle
Structural graph

Q4. "What breaks if orders_fact gains a column?"

Structural graph
OKF bundle
Vector RAG

Q5. "Why is the event bus in-process instead of a broker?"

OKF bundle
Structural graph
Vector RAG

Q6. "Is there a dependency cycle anywhere in services/?"

Structural graph
Vector RAG
OKF bundle

Q7. "What's our runbook for rotating the payments signing key?"

OKF bundle
Vector RAG
Structural graph

Q8. "Did anyone discuss rate-limiting webhooks before? What was decided?"

Vector RAG
OKF bundle
Structural graph

Q9. "Which functions does advance_order reach in two hops?"

Structural graph
Vector RAG
OKF bundle

Q10. "Summarize how our architecture docs describe the notifications service."

OKF bundle
Vector RAG
Structural graph
โœ… Checkpoint

8+ correct: you route like the architecture intends. The pattern to internalize โ€” structure โ†’ graph, canon โ†’ bundle, everything undocumented โ†’ search โ€” plus one refinement: deep investigations (Q4) legitimately use stages in sequence, not a single layer.

Knowledge Check

1. What is the correct one-sentence division of labor across the three layers?

RAG extracts code, the graph searches text, OKF stores embeddings
The graph extracts what the code is, OKF curates what engineers know, RAG searches the unstructured remainder
All three answer the same questions with different accuracy
OKF replaces both once the bundle is complete

2. Your agent writes syntactically valid code that keeps using a deprecated internal API. Which trigger fired, and what do you add?

Multi-hop reasoning failure โ†’ add a structural graph
Tribal-knowledge sprawl โ†’ add OKF
Bad chunking โ†’ fix the RAG pipeline
No failure observed โ†’ add nothing

3. Why does the staged pipeline put OKF orientation BEFORE graph traversal?

The bundle is more accurate than the graph
Cheap narrative orientation identifies the targets, so the structural stage traverses from the right nodes
Graph queries are too expensive to run first
MCP servers must warm up before answering

4. In the ERPNext study, why is the 70.8% โ†’ 82.0% key-fact result a better adoption signal than a 71.5ร— token multiple?

Fact coverage measures correctness at production scale; token multiples are corpus-topology-dependent cost figures
The hybrid used almost no tokens
Percentages are always more trustworthy than multiples
The ERPNext corpus was smaller and easier

5. In the router, why do all failures degrade toward vector search and never toward OKF?

Vector search is faster than reading a concept file
A probabilistic fallback pretending to be canonical is the M02 disaster; degrading to an honestly-fuzzy layer is safe
OKF bundles can't handle the load
The graph never returns misses

6. "72% of enterprise RAG deployments underdelivered in year one." What does this module conclude from that?

RAG is obsolete; replace it with graphs
Fix the retrieval pipeline first; add a graph only when a depth failure is actually observed
The surveys are wrong
Adding OKF fixes failing RAG

Module Summary

Layers, not competitors

Graph = what the code is. OKF = what engineers know. RAG = the unstructured remainder. Graph retrieval TIED dense RAG on accuracy โ€” its wins are determinism and ingest cost.

Failure-driven adoption

Multi-hop failures โ†’ structural graph. Tribal-knowledge sprawl โ†’ OKF. No observed failure โ†’ add nothing. 72% of RAG failures are pipeline quality, not missing graphs.

The staged pipeline

OKF orientation (~2K tokens) โ†’ graph traversal (zero LLM cost) โ†’ vector search for the remainder. Each stage narrows the next.

The evidence

ERPNext, 1M+ LOC: 70.8% โ†’ 82.0% key-fact coverage (~140K tokens/session). Accuracy deltas beat token multiples as adoption signals. Retrieval-only hallucinates 17โ€“33% on complex multi-document queries.

What we built on orderflow: a router dispatching canonical โ†’ bundle, structural โ†’ graph server, exploratory โ†’ search โ€” with all failures degrading toward the honestly-probabilistic layer.

Next module preview: the stack works โ€” on the day you built it. M11 is about every day after: silent hook failures, artifact desync, the scale wall, and the observability that separates a production system from a demo that hasn't failed yet.

References

  • "Graphify, OKF, or Both? Beyond RAG for Codebases" โ€” the three-layer framing and decision matrix (Towards AI, Jul 2026)
  • Graphify BENCHMARKS.md โ€” LongMemEval-S / LOCOMO head-to-head results
  • Atlan โ€” "Knowledge Graphs vs RAG" (2026): "RAG first, graph when depth becomes a bottleneck"
  • Prism Labs โ€” "Beyond Vector Embeddings in 2026" (chunk co-location)
  • ERPNext hybrid-pipeline evaluation (1M+ LOC case study)
  • Course modules: M02 (RAG limits), M06โ€“M08 (OKF), M09 (serving)