Interview prep
PatternContext and knowledge

Context Isolation

Isolamento de Contexto

Context Isolation is an AI design pattern for LLM apps and agents, in the Context and knowledge group. Run subtasks in separate contexts and bring back only the result.

Element
19/70
Level
Advanced
Read
8 min
Updated
On this page 18
  1. 01Intent
  2. 02Problem
  3. 03Solution
  4. 04Structure
  5. 05Pseudocode
  6. 06Real-world scenarios
  7. 07Applicability
  8. 08When not to use
  9. 09How to implement
  10. 10Variations
  11. 11Cost, latency, and failure modes
  12. 12How to evaluate
  13. 13In production
  14. 14Security
  15. 15Pros and cons
  16. 16Relations
  17. 17Code
  18. 18Check your understanding
  19. ··Quick answers

Intent

Run subtasks in separate contexts and bring back only the result. It is for systems where the material read, the intermediate reasoning, or one step’s instructions would get in the way of the others if they shared a context.

In one sentence
Separate rooms in a newsroom: the reporters do not work at the editor’s desk, and only the finished story crosses the door.

Problem

Sofia maintains an automated pull request reviewer. To review well, it needs to read the diff, the touched files, related tests, and the file’s commit history. All of that went into the same context as the review.

Two effects appeared. The first was predictable: the context passed 100,000 tokens on medium PRs, and reviews became expensive and slow. The second was less obvious: the reviewer began commenting on code that was not in the diff. It had read the whole file and pointed out old problems that were not the PR’s concern. Useful comments got lost among the out-of-scope ones.

Summarizing the material did not help. The reviewer did need to look at files and tests, but only to answer specific questions (“does this function have tests?”, “who else calls this method?”), not to carry everything while writing the review.

This is a sibling of Context Rot, with a difference: the heavy material should never have entered the writing context. Compacting afterwards cleans what already leaked in. Isolating keeps it out.

The question this pattern answers: how does one step use a lot of material without that material contaminating the rest of the work?

Solution

Give each subtask its own context, created from scratch, with only what it needs: a self-contained instruction, the read tools, and, when needed, a piece of the material. When the subtask ends, the context is thrown away. Only a short result in an agreed format comes back.

The main context never sees the raw material. It sees questions and answers: “does apply_discount have tests?” and “yes, in tests/test_pricing.py, lines 40 to 88, covering zero discount and discount larger than the total”.

Isolation is the principle; Subagent Delegation is the most common way to apply it, but it also applies to simple calls with no loop and to the steps of a workflow.

Worked example

Sofia’s PR changes only pricing.py. The reviewer needs to know whether apply_discount has a test, not the whole test file on the desk.

The main context sends a self-contained question:

Question: does apply_discount in src/pricing.py, changed in this PR, have tests?
Scope: answer only about coverage of this function. Ignore old failures in other functions.
Format: { "answer": string, "evidence": [{ "path": string, "lines": string }] }

The isolated context reads what it needs and returns:

{
  "answer": "Yes. tests/test_pricing.py covers zero discount and discount larger than the total. I did not see a negative-discount case.",
  "evidence": [{ "path": "tests/test_pricing.py", "lines": "40-88" }]
}

The main context gets about 80 words and cites the lines. The thousands of tokens in the test file died in the isolated context.

An illustrative account. Without isolation, a medium PR carries a diff (3,000 tokens) plus three files (45,000) on each of 8 turns: about 384,000 input tokens. With isolation, the main context keeps the diff and the short answers (say 8,000 per turn, 64,000 total) and the isolated contexts pay for the read once. Total cost may even rise if there are many questions. What drops, and that is the point, is the context that writes the review, and with it the out-of-scope comments.

The instruction has to carry the constraints. The isolated context did not see the diff. If the question omits “ignore old failures”, it reports the test that has been missing for two years.

Check +20 XP on first tryThe reviewer comments on old code that is not in the diff, because whole files landed in the review context. Which change attacks the cause?

Structure

flowchart TD
  M(["1. Main context: review"]):::llm --> Q1["2. Self-contained question"]:::tool
  Q1 --> C1(["3. Isolated context A"]):::llm
  C1 --> F[("4. Files, tests, history")]:::store
  C1 -->|"5. short answer"| M
  M --> Q2["2. Another question"]:::tool
  Q2 --> C2(["3. Isolated context B"]):::llm
  C2 --> F
  C2 -->|"5. short answer"| M
  M --> OUT(["6. Focused result"]):::io
  1. The main context owns the goal (reviewing the diff) and decides what it needs to know.
  2. Each need becomes a self-contained question that does not depend on the main context’s history.
  3. A fresh context is created to answer it.
  4. That context reads whatever it needs, as much as it needs.
  5. A short answer with evidence comes back; the isolated context is discarded.
  6. The main context finishes the job with a small, focused context.

Pseudocode

schema Answer { answer: string, evidence: list[{ path: string, lines: string }] }

function isolated(question, tools, budget):
    # 3. fresh context: nothing from the main history enters here
    ctx = new_context(system=READER_PROMPT, messages=[question])
    result = run_agent(ctx, tools=tools, budget=budget, output=Answer)    # 4
    trace.span("isolated", question, tokens=ctx.tokens)
    return result                                                         # 5. ctx is discarded

function review(diff):
    state.messages = [diff]
    while budget.check():
        reply = llm_with_tools(REVIEW_PROMPT, [ask_codebase], state)      # 1
        if reply.is_final:
            return reply.text                                             # 6
        for call in reply.tool_calls:                                     # 2
            answer = isolated(call.args.question, READ_TOOLS, budget.share(10))
            state.add(tool_result(call, answer))

Real-world scenarios

  • Coding agent. Repository exploration runs in isolated contexts. The main agent receives files and lines, not the contents of dozens of files.
  • Deep research with citations. Each sub-question is researched in its own context. The pages read die there; sourced claims come back.
  • Automated PR reviewer. The review looks only at the diff; questions about the rest of the code are answered in isolated contexts.

Applicability

  • One step needs to read a lot of material and use little of it.
  • The material read distracts or contaminates the main step’s reasoning.
  • Parts of the work need different instructions or tools that should not mix.
  • Untrusted content must be read far from the context that holds tools.

When not to use

  • The material is small and all relevant. Reading it directly is simpler and cheaper.
  • The main step must reason over all the material at once (comparing two versions of a contract clause by clause).
  • The only problem is a growing conversation history. Context Compaction solves it without creating new contexts.
Check +20 XP on first tryYou need to compare two versions of a contract, clause by clause. A colleague wants to isolate each clause in a subagent. What do you do?

How to implement

  1. Find in the traces the material that enters the main context and gets used only once.
  2. Define the questions the main context needs answered about that material.
  3. Create a tool that takes the question and runs in a fresh context, with read tools.
  4. Define the answer format, with evidence.
  5. Make sure in code that the isolated context does not receive the main history.
  6. Give the isolated context a budget, charged against the total.
  7. Compare in the eval: quality, tokens in the main context, and total cost.

Common traps

  • Passing the history ‘to help’. If the isolated call sees the whole review, you did not isolate. The question has to be self-contained.
  • An answer with no evidence. The main context starts repeating invented claims. Reject empty evidence in code.
  • A vague question. “Look at the tests” returns an essay. “Does function X in this PR have a test? Ignore the rest” returns a fact.
  • A budget only on the main context. The isolated while True is Unbounded Loop in the next room. The cap applies to the tree.

Variations

  • Simple isolated call. No loop: one question and one piece of material, in one call. Useful when you already know what to read.
  • Isolated subagent. With a loop and tools, for exploring. That is Subagent Delegation.
  • Isolation for security. The isolated context reads untrusted content and returns structured data. That is the Dual LLM.
  • Workflow steps. Each step in a chain receives only the fields it needs, not the full output of earlier steps.

Cost, latency, and failure modes

Aspect What happens How it shows up in the trace
Calls One or more per isolated question child isolated spans
Total cost May rise, because isolated contexts reread material sum of tokens across isolated spans
Main cost Drops sharply, because the context stays small stable input tokens on the main context
Latency Independent questions can run in parallel overlapping isolated spans
Failure: incomplete question The isolated context misses a constraint the main context knew a correct answer to the wrong question
Failure: answer without evidence The main context trusts an invented claim empty evidence field

How to evaluate

  • Final result quality with and without isolation.
  • Tokens in the main context over the task.
  • Out-of-scope comments (in the reviewer’s case), which should drop.
  • Accuracy of isolated answers on questions with known answers.
{ "diff": "fixtures/pr-512.diff", "expected_comments": 2, "max_out_of_scope_comments": 0 }

Measure both costs. A team that watches only the total bill sometimes undoes the pattern, without seeing that the missing out-of-scope comments were worth more.

In production

  • One span per isolated context, with the question, tokens, and answer.
  • A dashboard of main-context tokens versus isolated-context tokens.
  • A sample of evidence-free isolated answers for review.
  • An alert if the main context starts sending its own history as a tool argument.

Security

Isolated contexts are the right place to read untrusted content. Give them read tools only, and treat their answer as data in the main context.

Greshake et al. (2023) documented indirect prompt injection: hidden instructions in a page or an email the model reads. If that page shares a context with side-effect tools, hostile text becomes an order. Isolating the read does not replace the gate on the tools, but it cuts the most common channel.

Pros and cons

Pros Cons
A small, focused main context Total cost may rise
Material read does not contaminate the reasoning The question must be self-contained
Parts get their own instructions and tools More spans to debug
Hostile content is read far from side-effect tools A short answer may lose useful detail

Relations

Code

The tabs expose an ask_codebase tool that answers questions in a fresh context, without the review’s history. Python and TypeScript clear the message list by hand. LangChain does the same with a create_agent that receives only the question: the reviewer’s history never enters the dict.

Python. Use this when the review runs in Python and isolated reading is a regular function.

import anthropic
from pydantic import BaseModel

client = anthropic.Anthropic()


class Evidence(BaseModel):
    path: str
    lines: str


class Answer(BaseModel):
    answer: str
    evidence: list[Evidence]


READER = "You answer one question about the repository using only the read tools. Be brief and cite file and lines."


def ask_codebase(question: str, max_steps: int = 10) -> Answer:
    messages = [{"role": "user", "content": question}]  # 3. nothing from the review enters here
    for _ in range(max_steps):
        reply = client.messages.create(
            model="claude-haiku-4-5", max_tokens=4000, system=READER,
            tools=READ_TOOLS, messages=messages,
        )
        if reply.stop_reason != "tool_use":
            break
        messages.append({"role": "assistant", "content": reply.content})
        messages.append({"role": "user", "content": run_tools(reply)})  # 4
    messages.append({"role": "user", "content": "Answer now in the requested format."})
    return client.messages.parse(  # 5. only the short answer leaves
        model="claude-haiku-4-5", max_tokens=1000, system=READER,
        messages=messages, output_format=Answer,
    ).parsed_output


ASK_TOOL = {
    "name": "ask_codebase",
    "description": "Answers a question about code outside the diff (tests, callers, history). "
                   "The question must be self-contained. Returns a short answer with file and lines.",
    "input_schema": {"type": "object", "properties": {"question": {"type": "string"}}, "required": ["question"]},
}

What you gained: the review never carries whole files, and reading uses a cheap model. What you lost: each question rereads what it needs; for many questions about the same files, consider caching.

TypeScript. Use this when the review runs on the SDK runner and isolated reading is a typed tool.

import Anthropic from "@anthropic-ai/sdk";
import { betaZodTool } from "@anthropic-ai/sdk/helpers/beta/zod";
import { z } from "zod";

const client = new Anthropic();

const READER =
  "You answer one question about the repository using only the read tools. " +
  'Finish with JSON {"answer": string, "evidence": [{"path": string, "lines": string}]}.';

export const askCodebase = betaZodTool({
  name: "ask_codebase",
  description:
    "Answers a question about code outside the diff (tests, callers, history). " +
    "The question must be self-contained. Returns a short answer with file and lines.",
  inputSchema: z.object({ question: z.string() }),
  run: async ({ question }) => {
    // 3. a new runner = a new context, without the review's history
    const final = await client.beta.messages.toolRunner({
      model: "claude-haiku-4-5",
      max_tokens: 4000,
      system: READER,
      tools: READ_TOOLS,
      messages: [{ role: "user", content: question }],
      max_iterations: 10,
    });
    return final.content.find((b) => b.type === "text")?.text ?? "{}"; // 5
  },
});

// review: tools: [askCodebase]; the diff is the only large thing in the main context

What you gained: isolation is structural, since each tool call creates its own runner. What you lost: the answer arrives as text; validate the JSON before trusting it.

Python + LangChain. Use this when the isolated reader is a create_agent and its call receives only the question.

from langchain.agents import create_agent
from langchain.tools import tool
from pydantic import BaseModel


class Evidence(BaseModel):
    path: str
    lines: str


class Answer(BaseModel):
    answer: str
    evidence: list[Evidence]


# 3. this agent does not receive the review's messages
reader = create_agent(
    "anthropic:claude-haiku-4-5",
    tools=READ_TOOLS,
    system_prompt="You answer one question about the repository using only the read tools. "
                  "Be brief and cite file and lines.",
    response_format=Answer,
)


@tool
def ask_codebase(question: str) -> str:
    """Answer a question about code outside the diff. The question must stand alone."""
    out = reader.invoke(
        {"messages": [{"role": "user", "content": question}]},  # only the question
        {"recursion_limit": 20},
    )
    return out["structured_response"].model_dump_json()  # 5

READ_TOOLS are the read tools. The main reviewer receives ask_codebase and does not receive READ_TOOLS. The other ways to write that loop are on ReAct Loop.

What you gained: the review history has nowhere to enter, because the call does not receive it. What you lost: recursion_limit counts steps, not money.

Check your understanding

Check +20 XP on first tryThe main agent passes the whole review history into the isolated call, 'for extra context'. What does that do to the pattern?

Check +20 XP on first tryAfter isolation, total cost went up because isolated contexts reread the same files. Which reading is right?

Check +20 XP on first tryThe subagent was asked 'does apply_discount have tests?' without the constraint to ignore old issues outside the diff. It reports a test that has been missing for two years. What is the diagnosis?

Quick answers

What is Context Isolation?

Context Isolation is an AI design pattern for LLM apps and agents, in the Context and knowledge group. Run subtasks in separate contexts and bring back only the result.

Which smells does the Context Isolation pattern help cure?

Context Rot, Mega Agent, and Shared Scratchpad.

Where does Context Isolation show up in practice?

In the real-world scenarios Coding agent, Deep research with citations, and Automated PR reviewer.

Go further

Relations

Refactorings that lead here 1
Search