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
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 --
metaorresearch - Meta response -- a direct reply when intent is
meta - Depth decision --
shallowordeepwhen intent isresearch
graph TD
A[Receive ChatResearcherState] --> B[Extract latest user query]
B --> C[Render intent_classification.j2]
C --> D[Build message list:<br/>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<br/>Add AIMessage to messages]
I -->|no| K[Set user_intent = research<br/>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
The Intent Classifier reads from and writes to ChatResearcherState:
Inputs read:
| Field | Usage |
|---|---|
messages |
Conversation history; the last message is the current query |
user_info |
Optional user info injected into the prompt for personalization |
data_sources |
Used to build the tools info list shown to the LLM |
Outputs written:
| Field | Type | Condition |
|---|---|---|
user_intent |
IntentResult(intent="meta" or "research") |
Always |
messages |
Appended AIMessage with meta response |
When intent is meta |
depth_decision |
DepthDecision(decision="shallow" or "deep") |
When intent is research |
:language: python
:pyobject: IntentResult
:caption: IntentResult model
:language: python
:pyobject: DepthDecision
:caption: DepthDecision model
Configured through IntentClassifierConfig (NeMo Agent Toolkit type name: intent_classifier):
| Parameter | Type | Default | Description |
|---|---|---|---|
llm |
LLMRef |
required | LLM to use for classification |
tools |
list[FunctionRef | FunctionGroupRef] |
[] |
Tool references; their names and descriptions are shown to the LLM so it can assess query complexity |
verbose |
bool |
false |
Enable verbose logging using VerboseTraceCallback |
llm_timeout |
float |
90 |
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: 90The classifier uses intent_classification.j2 located in
src/aiq_agent/agents/chat_researcher/prompts/.
Template variables:
| Variable | Source |
|---|---|
query |
Content of the last user message |
current_datetime |
Current date and time string |
user_info |
User info dict (name, email) or empty |
tools |
List of {name, description} dicts for available tools |
The prompt instructs the LLM to respond with a JSON object containing
intent, meta_response (when meta), and research_depth (when research).
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.
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