The dynamic expert agent

1 min read
On trails:AGCTXstep 11/11

Two ideas close this trail, and they combine. Hyper-personalization: the agent knows the user’s preferences and history. The dynamic expert agent: a router classifier identifies the user’s intent, then dynamically assembles the context and tools that intent needs.

Personalization

Personalization is the stateful context from the anatomy of contextAnatomy of contextFive kinds of context, told apart by where they come from and how long they live.Opens in a new tab made visible: facts about this user, kept in a long-term store and pulled in when relevant. LangChain describes semantic memory as the kind used to personalize an application by remembering facts from past interactions, and a profile as one continuously updated record. The catch: a profile that keeps growing becomes error-prone to update. See agent memoryAgent memoryWhat an agent remembers: the thread it is in, and what it keeps across threads.Opens in a new tab.

The expert

A user message goes to a router that classifies the intent. Each intent maps to an expert bundle: its own prompt, its own tools and the user's preferences. Only the chosen bundle reaches the model. User message Router classify intent billing expert its prompt + tools + user preferences tech expert its prompt + tools + user preferences more experts
Only the chosen bundle reaches the model.

The router makes one small decision, which expert. What follows is assembly: that expert’s own prompt, only its tools (see scopingContext scopingShow the model only what it needs for this step, tools included.Opens in a new tab) and the user’s stored preferences. It is the context assemblerThe context assemblerThe step that builds the prompt from scratch on every loop.Opens in a new tab with the choice of ingredients made per question. Experts are plain configuration, so adding one is adding an entry.

Python
from typing import Literalfrom pydantic import BaseModelfrom langchain.agents import create_agentfrom langgraph.graph import MessagesStatefrom langgraph.runtime import Runtime class Intent(BaseModel):    name: Literal["billing", "tech"] router = llm.with_structured_output(Intent) EXPERTS = {    "billing": {"prompt": "You are a billing specialist.", "tools": [lookup_invoice, issue_refund]},    "tech": {"prompt": "You are a technical support engineer.", "tools": [search_docs, run_diagnostics]},} def expert(state: MessagesState, runtime: Runtime) -> dict:    question = state["messages"][-1].content    intent = router.invoke(question).name                       # 1. classify the intent    prefs = runtime.store.search((runtime.context.user_id, "preferences"), limit=5)  # 2. who is asking    agent = create_agent(                                       # 3. build only what this needs        llm,        tools=EXPERTS[intent]["tools"],        system_prompt=f"{EXPERTS[intent]['prompt']}\nUser preferences: {[p.value for p in prefs]}",    )    return agent.invoke({"messages": state["messages"]})

The catch

Anthropic’s routing workflow exists to separate concerns, so that each kind of input gets a specialised prompt. The cost is the router itself: a wrong classification sends the question to an expert without the tools it needs. The router needs its own test cases (see agent evaluationAgent evaluationTest the flow an agent took and what it left behind, against the goal and the guardrails.Opens in a new tab) and a fallback. When each expert is a full agent in its own right, this becomes the router patternRouter patternA manager that only decides which specialist handles the request.Opens in a new tab.


Sources