Name: Towards AI Legal Name: Towards AI, Inc. Description: Towards AI is the world's leading artificial intelligence (AI) and technology publication. Read by thought-leaders and decision-makers around the world. Phone Number: +1-650-246-9381 Email: pub@towardsai.net
228 Park Avenue South New York, NY 10003 United States
Website: Publisher: https://towardsai.net/#publisher Diversity Policy: https://towardsai.net/about Ethics Policy: https://towardsai.net/about Masthead: https://towardsai.net/about
Name: Towards AI Legal Name: Towards AI, Inc. Description: Towards AI is the world's leading artificial intelligence (AI) and technology publication. Founders: Roberto Iriondo, , Job Title: Co-founder and Advisor Works for: Towards AI, Inc. Follow Roberto: X, LinkedIn, GitHub, Google Scholar, Towards AI Profile, Medium, ML@CMU, FreeCodeCamp, Crunchbase, Bloomberg, Roberto Iriondo, Generative AI Lab, Generative AI Lab VeloxTrend Ultrarix Capital Partners Denis Piffaretti, Job Title: Co-founder Works for: Towards AI, Inc. Louie Peters, Job Title: Co-founder Works for: Towards AI, Inc. Louis-François Bouchard, Job Title: Co-founder Works for: Towards AI, Inc. Cover:
Towards AI Cover
Logo:
Towards AI Logo
Areas Served: Worldwide Alternate Name: Towards AI, Inc. Alternate Name: Towards AI Co. Alternate Name: towards ai Alternate Name: towardsai Alternate Name: towards.ai Alternate Name: tai Alternate Name: toward ai Alternate Name: toward.ai Alternate Name: Towards AI, Inc. Alternate Name: towardsai.net Alternate Name: pub.towardsai.net
5 stars – based on 497 reviews

Frequently Used, Contextual References

TODO: Remember to copy unique IDs whenever it needs used. i.e., URL: 304b2e42315e

Resources

Free: 6-day Agentic AI Engineering Email Guide.
Learnings from Towards AI's hands-on work with real clients.
Beyond Bigger Context Windows: 10 Context Engineering Patterns Every LLM Engineer Should Know
Latest   Machine Learning

Beyond Bigger Context Windows: 10 Context Engineering Patterns Every LLM Engineer Should Know

Last Updated on July 6, 2026 by Editorial Team

Author(s): Arpit Baranwal

Originally published on Towards AI.

Beyond Bigger Context Windows: 10 Context Engineering Patterns Every LLM Engineer Should Know

Large context windows are impressive, but they haven’t eliminated the need for context engineering. In production AI systems, deciding what not to send to the model is often more important than increasing the number of tokens it can process.

Beyond Bigger Context Windows: 10 Context Engineering Patterns Every LLM Engineer Should Know
Figure 1: Context optimization is a loop: retrieve, compress, rank, and assemble only the useful evidence.

Introduction

When frontier models began offering very large context windows, many people predicted that Retrieval-Augmented Generation would become less important. If a model can read an entire codebase, documentation library, or book in one prompt, why bother with retrieval?
In practice, the opposite happened. Teams building production AI systems still spend significant engineering effort deciding which information reaches the model. Larger context windows increase capacity, but they do not automatically improve reasoning, reduce latency, or lower cost.
The problem has shifted
from : How do we fit information into the prompt?
to: What information actually deserves the model’s attention?
This discipline is increasingly called context engineering.

Why Bigger Context Windows Are Not Enough

Consider a technical assistant helping engineers troubleshoot industrial equipment. The available information might include manuals, maintenance logs, sensor histories, support tickets, internal engineering documents, and regulatory standards. Even if an LLM could technically process all of it, that does not mean it should. In practice, indiscriminate ingestion introduces several real operational penalties:

  • Higher inference cost
  • Increased latency
  • More irrelevant information competing for attention
  • Greater risk of conflicting or stale information
  • Reduced reasoning efficiency
  • Every additional token consumes computation

Every additional token consumes computation. More importantly, every irrelevant token competes for the model’s attention. Good context engineering is therefore not about maximizing context. It is about maximizing signal while minimizing noise.

Context Engineering as an Optimization Problem

Useful Context = Relevant Information — Noise — Redundancy + Structure

The objective is not to provide the model with everything you know. The objective is to provide exactly what it needs to solve the current task. This design philosophy underpins modern RAG systems, long-running assistants, and agentic AI architectures.

Pattern 1: Semantic Chunking

Figure 2: Semantic chunking preserves meaning by splitting documents at natural boundaries.

Many RAG systems split documents into fixed-size chunks, such as 500 or 1,000 tokens. Although simple, this can separate related ideas or merge unrelated topics.
A better strategy is semantic chunking: split by headings, sections, paragraphs, functions, API definitions or code blocks.
Each chunk should represent a complete concept rather than an arbitrary number of tokens. This improves retrieval quality because embeddings represent coherent ideas instead of fragmented text.

The following is simplified pseudocode showing the chunking:

from langchain.text_splitter import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=100,
separators=["\n## ", "\n### ", "\n\n", "."]
)
chunks = splitter.split_text(document)

Pattern 2: Hierarchical Retrieval

Figure 3: Hierarchical retrieval narrows search from corpus to document, section, and paragraph.

Instead of searching every paragraph individually, production systems often retrieve information in multiple stages.
A system may first identify relevant documents, then relevant sections, and finally the paragraphs most useful for the current question.
This reduces search complexity while improving retrieval precision, especially in large enterprise knowledge bases.

The following is simplified pseudocode showing the retrieval flow:

docs = retrieve_documents(query, top_k=20)

sections = retrieve_sections(
query,
documents=docs,
top_k=5
)

paragraphs = retrieve_paragraphs(
query,
sections=sections,
top_k=8
)
answer = llm(paragraphs)

Pattern 3: Context Compression

Figure 4: Compression converts long retrieved passages into short task-specific evidence.

Retrieval often returns more information than necessary. An intermediate compression step extracts only what matters for the current query. Compression can include key sentence extraction, bullet-point summaries, table generation, equation extraction or code snippet isolation. The model receives the essential evidence without unnecessary detail.

from langchain_openai import ChatOpenAI
from langchain.retrievers.document_compressors import LLMChainExtractor

# Initialize the LLM

llm = ChatOpenAI(model="gpt-4.1")
# Create the compressor
compressor = LLMChainExtractor.from_llm(llm)

# Compress retrieved documents based on the user query
compressed_docs = compressor.compress_documents(
documents=retrieved_docs,
query=user_query
)

# Generate the final response
response = llm.invoke(
f""" Context: {compressed_docs} Question: {user_query} """ )

Pattern 4: Sliding Conversation Memory

Figure 5: Sliding memory keeps recent turns verbatim and summarizes older history.

Long-running assistants cannot retain every previous message indefinitely. A practical approach is to keep the last few turns unchanged while summarizing older discussion into goals, constraints, decisions and unresolved questions. This maintains continuity while keeping prompts compact.

from langchain_openai import ChatOpenAI
from langchain.memory import ConversationSummaryBufferMemory

llm = ChatOpenAI(model="gpt-4.1")

memory = ConversationSummaryBufferMemory(
llm=llm,
max_token_limit=1000
)

# Save each interaction
memory.save_context(
{"input": user_query},
{"output": assistant_response}
)

# Returns:
# • Summary of older messages
# • Most recent conversation turns
context = memory.load_memory_variables({})["history"]

response = llm.invoke(
f""" Context: {context} User: {user_query} """
)

Pattern 5: Query Expansion and Metadata Filtering

Figure 6: Query expansion improves recall, while metadata filtering narrows the search space.

Users rarely phrase questions using exactly the same terminology found in documentation. For example, battery degradation may need to expand into capacity fade, cycle aging, calendar aging, state of health and lithium-ion aging.
Metadata filtering then narrows the search by project, product version, department, author, date, language or security level.

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4.1")

# Step 1: Expand the user query
expanded_queries = llm.invoke(
f"""
Generate 3 alternative search queries for this user question.
Keep them short and technical. Question: {user_query}"""

).content.split("\n")

# Step 2: Search only inside the relevant metadata scope
all_results = []

for query in expanded_queries:
results = vector_db.similarity_search(
query=query,
k=5,
filter={
"department": "Battery",
"document_type": "technical_report",
"year": 2025
}
)
all_results.extend(results)

# Step 3: Pass filtered, expanded results to the LLM
context = "\n\n".join(doc.page_content for doc in all_results)

response = llm.invoke(f""" Context: {context} Question: {user_query} """)

Pattern 6: Retrieval Re-ranking

Figure 7: Re-ranking turns broad candidate retrieval into high-precision context selection.

Vector search is fast, but embedding similarity is not always the same as task relevance. Modern systems often retrieve a larger candidate set using embeddings, then apply a cross-encoder or LLM-based re-ranker.
This often improves answer quality more than simply increasing the number of retrieved chunks.

Write on Medium

The following is simplified pseudocode showing the retrieval re-ranking:

docs = vector_db.search(query, top_k=20)

ranked = reranker.rank(query, docs)

context = ranked[:5]

Pattern 7: Structured Agent Memory

Figure 8: Structured memory stores agent state as fields instead of raw chat history.

Agentic systems often fail because they repeatedly rediscover information or carry too much irrelevant history.
Instead of storing raw conversation logs, maintain compact structured state: goal, constraints, completed work, intermediate results and next action.
This is smaller, easier to inspect, and better aligned with multi-step reasoning.

from dataclasses import dataclass, field
from typing import List


@dataclass
class AgentMemory:
goal: str
constraints: List[str] = field(default_factory=list)
completed_tasks: List[str] = field(default_factory=list)
intermediate_results: List[str] = field(default_factory=list)
next_action: str = ""


memory = AgentMemory(
goal="Write a Medium article on context engineering",
constraints=[
"Keep examples practical",
"Use simple architecture diagrams",
"Avoid overly academic language"
]
)

# Agent completes a step
memory.completed_tasks.append("Drafted introduction")
memory.intermediate_results.append(
"Main thesis: bigger context windows do not remove the need for context engineering."
)
memory.next_action = "Write the section on structured agent memory"

# Build compact context for the next LLM call
prompt = f""" Agent State: Goal: {memory.goal}
Constraints: {memory.constraints}
Completed Tasks: {memory.completed_tasks}
Intermediate Results: {memory.intermediate_results}
Next Action: {memory.next_action} """


response = llm.invoke(prompt)

Pattern 8: Dynamic Prompt Assembly

Figure 9: Dynamic prompt assembly adds only the modules needed for the current task.

A production system should not rely on one massive static prompt.
Instead, prompts are assembled from modules: system instructions, user query, retrieved documents, tool outputs, user preferences, examples and agent memory.
We include each module only when it applies, which keeps the prompt lean and the system easier to maintain.

def build_prompt(
user_query,
retrieved_docs=None,
tool_outputs=None,
user_preferences=None,
examples=None,
agent_memory=None
):
prompt_parts = []

# Always included
prompt_parts.append(""" You are a helpful AI assistant.
Answer clearly and use only reliable information. """
)

# Optional modules
if user_preferences:
prompt_parts.append(f""" User Preferences: {user_preferences} """)

if agent_memory:
prompt_parts.append(f""" Agent Memory: {agent_memory} """)

if retrieved_docs:
prompt_parts.append(f""" Retrieved Documents: {retrieved_docs} """)

if tool_outputs:
prompt_parts.append(f""" Tool Outputs: {tool_outputs} """)

if examples:
prompt_parts.append(f""" Examples: {examples} """)

# Current task
prompt_parts.append(f""" User Query: {user_query} """)

return "\n".join(prompt_parts)


prompt = build_prompt(
user_query="Explain context compression",
retrieved_docs=retrieved_context,
user_preferences="Prefer short examples with Python code",
agent_memory="Previous section discussed structured memory"
)

response = llm.invoke(prompt)

Pattern 9: Tool-First Context
Sometimes the best context is no context at all.
Instead of injecting thousands of tokens from a database, spreadsheet, or log file, let the model call a tool: SQL, calculator, search, knowledge graph, API, or code execution environment.
Only the result of the tool call needs to enter the prompt. This reduces token use and usually improves factual accuracy.

from langchain_openai import ChatOpenAI
from langchain_community.utilities import SQLDatabase
from langchain.chains import create_sql_query_chain

# Connect to the database
db = SQLDatabase.from_uri("sqlite:///company.db")

llm = ChatOpenAI(model="gpt-4.1")

# Create a tool that converts natural language to SQL
sql_chain = create_sql_query_chain(llm, db)

# User question
user_query = "What were the top 5 selling products in Q1 2025?"

# Execute the SQL query
sql_query = sql_chain.invoke({"question": user_query})
result = db.run(sql_query)

# Only the query result is sent to the LLM
response = llm.invoke(f""" Question: {user_query} SQL Result: {result}
Answer the question based only on the SQL result. """
)

Pattern 10: Context Isolation in Multi-Agent Systems

A common mistake in multi-agent systems is giving every agent access to every piece of information. A better design separates context by responsibility: planner, researcher, coder, reviewer and final response generator.
This reduces distraction, lowers cost and creates clearer responsibility boundaries.

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4.1")

# Planner Agent
plan = llm.invoke(""" Task: Write a blog on context engineering.
Create an outline only. """
).content

# Research Agent
research = llm.invoke(f""" Outline: {plan}
Find supporting references and key technical concepts. """
).content

# Writer Agent
draft = llm.invoke(f""" Outline: {plan} Research Notes: {research}
Write the first draft. """
).content

# Reviewer Agent
review = llm.invoke(f""" Review the following draft for:
- Technical accuracy
- Grammar
- Readability
Draft: {draft} """
).content

# Final Response Generator
final_article = llm.invoke(f""" Original Draft: {draft}
Reviewer Feedback: {review} Produce the final polished article. """
)

Choosing the Right Strategy

No strategy is free each comes with a cost worth knowing before you commit to it.

Practical Implementation Checklist

  • Define a context budget before building the prompt.
  • Retrieve more candidates than you send to the model.
  • Re-rank retrieved chunks before final prompt construction.
  • Compress long evidence into query-specific summaries.
  • Remove duplicated or overlapping chunks.
  • Keep recent turns in full; summarize the rest.
  • Store agent state as structured fields.
  • Use tools instead of injecting raw databases or large files.
  • Isolate context between agents in multi-agent workflows.
  • Log which context was used so failures can be debugged.

Final Thoughts

As language models continue to expand their context windows, the temptation will always be to send more information. The best AI systems usually do the opposite. They retrieve less, compress more, organize information intelligently, and provide the model with only what is necessary to solve the current problem.

None of this comes free. Every pattern in this piece trades one cost , latency, complexity or the risk of dropping something relevant and for another benefit: precision, efficiency, or scale. The real skill isn’t memorizing these patterns; it’s knowing which cost your system can least afford, and designing around that constraint.

Context engineering is therefore not just a workaround for context limits. It is a core discipline for building efficient, reliable, and production-ready LLM applications. The future of LLM applications will not be shaped only by models with the largest context windows. It will be shaped by systems that know exactly how to use the context they already have.

Further Reading

Join thousands of data leaders on the AI newsletter. Join over 80,000 subscribers and keep up to date with the latest developments in AI. From research to projects and ideas. If you are building an AI startup, an AI-related product, or a service, we invite you to consider becoming a sponsor.

Published via Towards AI


Towards AI Academy

We Build Enterprise-Grade AI. We'll Teach You to Master It Too.

15 engineers. 100,000+ students. Towards AI Academy teaches what actually survives production.

Start free — no commitment:

6-Day Agentic AI Engineering Email Guide — one practical lesson per day

Agents Architecture Cheatsheet — 3 years of architecture decisions in 6 pages

Our courses:

AI Engineering Certification — 90+ lessons from project selection to deployed product. The most comprehensive practical LLM course out there.

Agent Engineering Course — Hands on with production agent architectures, memory, routing, and eval frameworks — built from real enterprise engagements.

AI for Work — Understand, evaluate, and apply AI for complex work tasks.

Note: Article content contains the views of the contributing authors and not Towards AI.