Why this matters
A coding assistant, a support bot, and a document Q&A tool all use LLMs but need radically different context. Dynamic context assembly routes requests through different assembly pipelines based on intent classification.
Core concepts
Intent classification as a routing signal
from enum import Enum
class RequestIntent(str, Enum):
CODE_GENERATION = "code_generation"
CODE_DEBUGGING = "code_debugging"
DOCUMENT_QA = "document_qa"
GENERAL_CHAT = "general_chat"
DATA_ANALYSIS = "data_analysis"
SYSTEM_DESIGN = "system_design"
async def classify_intent(user_message: str, client) -> RequestIntent:
prompt = (
"Classify this request into one of these categories:
"
"- code_generation, code_debugging, document_qa, "
"general_chat, data_analysis, system_design
"
f"Request: {user_message}
"
"Reply with only the category name, nothing else."
)
response = await client.messages.create(
model="claude-3-haiku-20240307",
max_tokens=20,
messages=[{"role": "user", "content": prompt}],
)
raw = response.content[0].text.strip().lower()
try:
return RequestIntent(raw)
except ValueError:
return RequestIntent.GENERAL_CHAT
Context recipes by intent
from dataclasses import dataclass
@dataclass
class ContextRecipe:
fetch_retrieval: bool
fetch_code_context: bool
history_turns: int
retrieval_doc_limit: int
INTENT_RECIPES: dict[RequestIntent, ContextRecipe] = {
RequestIntent.CODE_GENERATION: ContextRecipe(
fetch_retrieval=False, fetch_code_context=True, history_turns=10, retrieval_doc_limit=0,
),
RequestIntent.CODE_DEBUGGING: ContextRecipe(
fetch_retrieval=True, fetch_code_context=True, history_turns=15, retrieval_doc_limit=3,
),
RequestIntent.DOCUMENT_QA: ContextRecipe(
fetch_retrieval=True, fetch_code_context=False, history_turns=5, retrieval_doc_limit=8,
),
RequestIntent.GENERAL_CHAT: ContextRecipe(
fetch_retrieval=False, fetch_code_context=False, history_turns=20, retrieval_doc_limit=0,
),
}
Feature flags for A/B testing
import hashlib
from dataclasses import dataclass
@dataclass
class ContextFlags:
enable_retrieval: bool = True
enable_history_summarization: bool = True
retrieval_chunk_limit: int = 5
def load_context_flags(user_id: str, feature_store: dict) -> ContextFlags:
user_hash = int(hashlib.md5(user_id.encode()).hexdigest(), 16) % 100
return ContextFlags(
enable_history_summarization=user_hash < 50,
**feature_store.get("global_overrides", {}),
)
Code: ContextRouter
from dataclasses import dataclass
@dataclass
class ContextRouter:
client: object
memory_manager: MemoryManager
vector_store: object
feature_store: dict
async def route(self, user_message: str, session_id: str, system_prompt: str) -> list[dict]:
await self.memory_manager.load_session(session_id)
intent = await classify_intent(user_message, self.client)
recipe = INTENT_RECIPES.get(intent, INTENT_RECIPES[RequestIntent.GENERAL_CHAT])
flags = load_context_flags(self.memory_manager.user_id, self.feature_store)
retrieved_docs = None
if recipe.fetch_retrieval and flags.enable_retrieval:
try:
hits = await self.vector_store.search(
user_message, limit=min(recipe.retrieval_doc_limit, flags.retrieval_chunk_limit)
)
retrieved_docs = [hit["content"] for hit in hits]
except Exception:
retrieved_docs = None
return await self.memory_manager.assemble_context(
system_prompt=system_prompt,
user_input=user_message,
retrieved_docs=retrieved_docs,
)
Common mistakes
Classifying intent with an expensive model. Use a fast, cheap model. Target under 200ms latency.
One giant assembly function. Separate recipes make each intent's requirements explicit and testable.
No fallback when classification fails. Always have a safe default recipe.
Not logging the classified intent. Log intent and recipe for every request.
Try it yourself
- Add a
SYSTEM_DESIGNrecipe. What context components would be most useful? - Implement keyword-matching intent classification. Compare its accuracy to the LLM version.
- Design an A/B test for retrieval chunk count. What metric would you track?