Intent Classifier#
The Intent Classifier is a single orchestration node that performs three roles in one LLM call: intent classification, meta response generation, and depth routing. It is the entry point for every query in the AI-Q workflow.
Location: src/aiq_agent/agents/chat_researcher/nodes/intent_classifier.py
Purpose#
Rather than using separate classifiers for intent and depth, the Intent Classifier combines all routing decisions into a single LLM invocation. This minimizes latency for the common case (meta queries get an instant response) and avoids an extra round-trip for research queries.
The classifier outputs structured JSON with:
Intent –
metaorresearchMeta response – a direct reply when intent is
metaDepth decision –
shallowordeepwhen intent isresearch
Internal Flow#
SystemMessage + trimmed history] D --> E[Invoke LLM with timeout] E -->|success| F[Extract JSON from response] E -->|timeout| G[Return timeout error message] E -->|API unavailable| H[Return unavailability message] F --> I{intent == meta?} I -->|yes| J[Set user_intent = meta
Add AIMessage to messages] I -->|no| K[Set user_intent = research
Set depth_decision = shallow or deep] J --> L[Return state update] K --> L G --> L H --> L style A fill:#e1f5fe style L fill:#e8f5e9 style E fill:#fff3e0
State Model#
The Intent Classifier reads from and writes to ChatResearcherState:
Inputs read:
Field |
Usage |
|---|---|
|
Conversation history; the last message is the current query |
|
Optional user info injected into the prompt for personalization |
|
Used to build the tools info list shown to the LLM |
Outputs written:
Field |
Type |
Condition |
|---|---|---|
|
|
Always |
|
Appended |
When intent is |
|
|
When intent is |
IntentResult#
class IntentResult(BaseModel):
"""
Result of intent classification.
Attributes:
intent: Classified intent - either 'meta' (greetings, chit-chat, capabilities)
or 'research' (queries requiring data lookup and sources).
raw: Optional raw classification response from the LLM.
"""
intent: Literal["meta", "research"]
raw: dict[str, Any] | None = None
DepthDecision#
class DepthDecision(BaseModel):
"""
Result of depth/complexity assessment for a research query.
Attributes:
decision: Routing decision - 'shallow' for quick lookups or 'deep' for comprehensive research.
raw_reasoning: Optional reasoning text from the LLM explaining the decision.
"""
decision: Literal["shallow", "deep"]
raw_reasoning: str | None = None
Configuration#
Configured through IntentClassifierConfig (NeMo Agent Toolkit type name: intent_classifier):
Parameter |
Type |
Default |
Description |
|---|---|---|---|
|
|
required |
LLM to use for classification |
|
|
|
Tool references; their names and descriptions are shown to the LLM so it can assess query complexity |
|
|
|
Enable verbose logging using |
|
|
|
Timeout in seconds for the LLM call |
Example YAML:
functions:
intent_classifier:
_type: intent_classifier
llm: nemotron_llm
tools:
- web_search_tool
verbose: true
llm_timeout: 90
Prompt Template#
The classifier uses intent_classification.j2 located in
src/aiq_agent/agents/chat_researcher/prompts/.
Template variables:
Variable |
Source |
|---|---|
|
Content of the last user message |
|
Current date and time string |
|
User info dict (name, email) or empty |
|
List of |
The prompt instructs the LLM to respond with a JSON object containing
intent, meta_response (when meta), and research_depth (when research).
Error Handling#
The classifier handles two failure modes gracefully:
LLM API unavailable (404, model not found): Returns a user-friendly message asking to check the API key and model configuration.
Timeout (asyncio timeout, 504 gateway): Returns a timeout message. The timeout is configurable through
llm_timeout(default 90 seconds).
In both cases, the error message is returned as an AIMessage so the
orchestrator routes to END and the user sees the error.
Example I/O#
Meta query:
Input: "Hello! What can you do?"
Output: user_intent = IntentResult(intent="meta")
messages += [AIMessage("Hi! I'm a research assistant...")]
-> routes to END
Research query (shallow):
Input: "What is CUDA?"
Output: user_intent = IntentResult(intent="research")
depth_decision = DepthDecision(decision="shallow")
-> routes to shallow_research
Research query (deep):
Input: "Compare the economic impacts of renewable energy adoption across G7 nations"
Output: user_intent = IntentResult(intent="research")
depth_decision = DepthDecision(decision="deep")
-> routes to clarifier