Agentic Context Engineering: The Multi-Source Query Problem

~13 min read

The book's concrete motivating example — a single query spanning Linear, Calendar, Gmail, and Slack — shows exactly why naive RAG breaks down, and introduces the 3-layer agentic solution.

The previous subtopic ended on this course's claim that no real-world workflow looks like a single static source. This subtopic covers the concrete example this course uses to make that claim undeniable, and the alternative architecture it proposes in response.

This course's motivating query: 'What's blocking the Chicago office project, and when's our next meeting about it?' Answering this single query requires searching across sources like Linear (for blockers), Calendar (for meetings), Gmail (for emails), and Slack (for discussions). No naive RAG setup can handle this! Sit with why this specific example breaks the manual pipeline from the previous subtopic: it's not just that the answer spans multiple documents (ordinary RAG handles that fine via top-k retrieval) — it's that the answer spans multiple SYSTEMS with entirely different data shapes (a project tracker's task/blocker records, a calendar's event records, an inbox's email threads, a chat app's message history), each needing different handling before it can even be usefully embedded, let alone combined into one coherent answer.

This course's proposed solution reframes the problem entirely: to actually solve this problem, you'd need to think of it as building an Agentic context retrieval system with three critical layers. The word 'agentic' here is doing real work — rather than one fixed embed-then-retrieve pipeline applied uniformly, an agentic system makes DYNAMIC decisions at query time: which sources are even relevant to THIS particular query, how to search each one appropriately given its distinct shape, and how to combine the results coherently — decisions a static pipeline never has to make because it only ever has one source to consider.

The three layers (detailed fully as Infrastructure Requirements in the final subtopic of this topic) are named directly by this course: Ingestion layer (getting different-shaped source data in, correctly, and kept fresh), Retrieval layer (figuring out what the query really needs and searching the right sources the right way), and Generation layer (producing a response the user can actually trust and verify). This course is candid about the cost of this: that's months of engineering before your first query works. It's definitely a tough problem to solve — a direct, honest acknowledgment that 'agentic' here is not a small tweak on top of manual RAG, but a substantially larger engineering undertaking, justified specifically by the genuine difficulty of the multi-source problem it solves.

💻 Code example

# Modeling the CORE difference: a manual pipeline has ONE fixed source
# to search; an agentic system must DECIDE, per query, which of several
# differently-shaped sources are relevant and how to search each.

SOURCES = {
    "linear": {"kind": "project_tracker", "relevant_for": ["blocker", "blocking", "task", "issue"]},
    "calendar": {"kind": "events", "relevant_for": ["meeting", "when", "schedule"]},
    "gmail": {"kind": "email_threads", "relevant_for": ["email", "sent", "replied", "project"]},
    "slack": {"kind": "chat_messages", "relevant_for": ["discussed", "mentioned", "channel", "office"]},
}

def agentic_source_selection(query: str, sources: dict) -> list[str]:
    """The AGENTIC decision a manual pipeline never has to make:
    which of several differently-shaped sources does THIS query need?"""
    query_lower = query.lower()
    selected = []
    for name, info in sources.items():
        if any(keyword in query_lower for keyword in info["relevant_for"]):
            selected.append(name)
    return selected

def search_source(source_name: str, kind: str, query: str) -> str:
    """Each source needs DIFFERENT search handling given its distinct shape --
    a project tracker isn't searched the same way as a calendar."""
    return f"[{kind} search in {source_name} for: {query!r}]"

query = "What's blocking the Chicago office project, and when's our next meeting about it?"
selected_sources = agentic_source_selection(query, SOURCES)
print(f"Query requires sources: {selected_sources}")

for source_name in selected_sources:
    result = search_source(source_name, SOURCES[source_name]["kind"], query)
    print(" ", result)
# A manual RAG pipeline (previous subtopic) has no equivalent decision --
# it only ever has ONE vector store to search, regardless of the query

💬 Deep Dive with AI

Key points

  • The book's motivating example: 'What's blocking the Chicago office project, and when's our next meeting?' requires Linear, Calendar, Gmail, AND Slack — no naive RAG setup can handle this
  • The hard part isn't that the answer spans multiple documents (ordinary RAG handles that) — it's that it spans multiple SYSTEMS with entirely different data shapes
  • The book's solution: build an Agentic context retrieval system with three critical layers, making dynamic per-query decisions rather than using one fixed pipeline
  • The three named layers are Ingestion (getting differently-shaped sources in and fresh), Retrieval (searching the right sources the right way), and Generation (a trustworthy, verifiable response)
  • The book is candid this is a substantial undertaking — 'months of engineering before your first query works' — not a small tweak on manual RAG