had launched its personal LLM agent framework, the NeMo Agent Toolkit (or NAT), I acquired actually excited. We normally consider Nvidia as the corporate powering the complete LLM hype with its GPUs, so it’s fascinating to see them transcend {hardware} and step into the software program area as nicely.
There are already loads of LLM agent frameworks on the market: LangGraph, smolagents, CrewAI and DSPy, simply to call just a few. The NeMo Agent Toolkit, nonetheless, feels a bit completely different. I’d describe it as a form of glue that helps sew all of the items collectively and switch them right into a production-ready resolution.
Nvidia positions this framework as a method to sort out “day 2” issues: exposing brokers as APIs, including observability to watch your system and examine edge circumstances, constructing evaluations, and reusing brokers created in different frameworks.
On this article, I’ll discover the core capabilities of the NeMo Agent Toolkit in observe, beginning with a easy chat-completion app and regularly transferring towards a hierarchical agentic setup, the place one LLM agent can recursively use different brokers as instruments. Because it’s the festive season, I’ll be utilizing publicly obtainable knowledge from the World Happiness Report to maintain issues cheerful.
Establishing
As normal, we’ll begin by establishing the surroundings and putting in the bundle.
The core bundle itself is pretty light-weight. Nevertheless, as I discussed earlier, NAT is designed to behave as glue permitting to combine with completely different LLM frameworks in your workflow. Due to that, there are a number of optionally available plugins obtainable for in style libraries resembling LangChain, CrewAI, and LlamaIndex. You possibly can all the time discover probably the most up-to-date checklist of supported plugins in the official documentation.
On this article, we will likely be utilizing LangChain, so we’ll want to put in the corresponding extension as nicely.
Tip: NAT works MUCH higher and quicker with
uv. I initially tried putting in every thing withpip, and it failed after about 20 minutes of ready. I’d strongly suggest not repeating my errors.
First, create and activate a digital surroundings utilizing uv.
uv venv .venv_nat_uv --python 3.12
supply .venv_nat_uv/bin/activate
Then set up NAT with the LangChain plugin.
uv pip set up "nvidia-nat[langchain]"
For those who’re planning to run NAT from the CLI, you’ll additionally have to export the related surroundings variables. Since I’ll be utilizing Anthropic fashions, I have to set the API key.
export ANTHROPIC_API_KEY=<your_api_key>
Loading knowledge
Subsequent, let’s obtain the World Happiness Report knowledge and take a better take a look at it. I’ve put collectively a small helper operate to load the dataset and barely clear up the information.
import pandas as pd
def load_data():
df = pd.read_excel('whr2025_data.xlsx')
df = df[df.Year >= 2019]
df = df.drop(['Lower whisker', 'Upper whisker'], axis=1)
df.columns = ['year', 'rank', 'country', 'happiness_score',
'impact_gdp', 'impact_social_support',
'impact_life_expectancy', 'impact_freedom',
'impact_generosity', 'impact_corruption', 'impact_residual']
return df
df = load_data()
This dataset covers the World Happiness Report outcomes from 2019 to 2024. For every nation and yr, it consists of the general happiness rating in addition to the estimated contribution of a number of underlying elements:
- logarithm of GDP per capita,
- social help,
- wholesome life expectancy,
- freedom to make life decisions,
- generosity,
- notion of corruption.
With this dataset, we can examine happiness patterns throughout geographies and over time and hopefully spot some attention-grabbing patterns alongside the way in which.
Chat completion instance
Let’s begin with a quite simple chat-completion instance. The structure right here is deliberately minimal: a single LLM with no extra instruments or brokers concerned.
The NeMo Agent Toolkit is configured through YAML recordsdata that outline each the workflow and the underlying LLMs. Nvidia selected this strategy as a result of it makes experimenting with completely different configurations a lot simpler. For this primary instance, we’ll create a chat_config.yml file.
At a excessive stage, our config file will include two predominant sections:
llmsthe place we outline the language fashions we wish to use,workflowthe place we describe how these fashions are wired collectively and the way the agent behaves.
On the LLM aspect, NAT helps a number of suppliers out of the field, together with OpenAI, Nvidia Inference Microservices, and AWS Bedrock. Since I wish to use an Anthropic mannequin, the simplest possibility right here is LiteLLM, which acts as a common wrapper and lets us hook up with nearly any supplier.
Within the workflow part, we’ll specify:
- the workflow sort (we will likely be utilizing the best
chat_completionfor now, however will discover extra complicated agentic setups later), - the LLM outlined above, and
- the system immediate that units the agent’s behaviour.
This offers us a strong MVP and a dependable baseline to construct on earlier than transferring into extra complicated agentic purposes.
llms:
chat_llm:
_type: litellm
model_name: claude-sonnet-4-5-20250929
api_key: $ANTHROPIC_API_KEY
temperature: 0.7
workflow:
_type: chat_completion
llm_name: chat_llm
system_prompt: |
You're a educated scientist within the subject of happiness research.
You might have entry to a dataset containing the World Happiness Report knowledge from 2019 to 2025.
Your activity is to investigate the information and supply insights based mostly on person queries.
Use the dataset to reply questions on nation rankings, developments through the years, and elements influencing happiness scores.
Now it’s time to run our software. We are able to do that with a single CLI command by specifying the trail to the config file and offering an enter query.
nat run
--config_file chat_config.yml
--input "How is happinness outlined?"
As soon as the command runs, we’ll see the next output within the console.
2025-12-24 18:07:34 - INFO - nat.cli.instructions.begin:192 - Beginning NAT
from config file: 'chat_config.yml'
Configuration Abstract:
--------------------
Workflow Sort: chat_completion
Variety of Features: 0
Variety of Perform Teams: 0
Variety of LLMs: 1
Variety of Embedders: 0
Variety of Reminiscence: 0
Variety of Object Shops: 0
Variety of Retrievers: 0
Variety of TTC Methods: 0
Variety of Authentication Suppliers: 0
2025-12-24 18:07:35 - INFO - LiteLLM:3427 -
LiteLLM completion() mannequin= claude-sonnet-4-5-20250929; supplier = anthropic
2025-12-24 18:07:44 - INFO - nat.front_ends.console.console_front_end_plugin:102 - --------------------------------------------------
['In the World Happiness Report, happiness is defined as subjective well-being,
measured primarily through the **Cantril ladder** life evaluation question,
where respondents rate their current life on a scale from 0 (worst possible)
to 10 (best possible). The overall happiness score is then statistically
explained by six key factors: GDP per capita, social support, healthy life
expectancy, freedom to make life choices, generosity, and perceptions of
corruption.']
--------------------------------------------------
We acquired a fairly respectable reply based mostly on the mannequin’s basic information. Now, let’s take the subsequent step and deploy it. Since NAT is designed for production-ready purposes, we are able to simply expose our resolution as a REST API. Later on this article, we’ll even see tips on how to flip it right into a customer-ready UI.
To make our agent accessible through an API endpoint, we are able to use the nat serve command.
nat serve --config_file chat_config.yml
Now, our software is offered at http://localhost:8000, and we are able to work together with it utilizing Python. The API format is suitable with OpenAI’s endpoints.
import requests
import json
# Check the API endpoint
response = requests.put up(
"http://localhost:8000/v1/chat/completions",
headers={"Content material-Sort": "software/json"},
json={
"messages": [
{
"role": "user",
"content": "How many years of happiness data do we have?"
}
],
"stream": False
}
)
# Parse and show the response
if response.status_code == 200:
outcome = response.json()
print(outcome["choices"][0]["message"]["content"])
else:
print(f"Error: {response.status_code}")
print(response.textual content)
# We now have 7 years of happiness knowledge, masking the interval from 2019 to 2025.
This offers us a believable MVP that may reply primary questions concerning the Happiness knowledge. Nevertheless, to supply deeper insights, our agent wants context and entry to the precise dataset. Equipping it with instruments will likely be our subsequent step.
Including instruments
Subsequent, let’s add a few instruments that may assist our agent analyse the World Happiness Report knowledge. We are going to present our agent with two features:
get_country_statsreturns all Happiness knowledge filtered by a selected nation,
get_year_statsoutputs an summary of the Happiness Report for a given yr, together with the happiest and least glad international locations, the common happiness rating, and the elements influencing it.

Including instruments within the NeMo Agent toolkit requires fairly a little bit of boilerplate code. We might want to undergo the next steps:
- Implement the features in Python,
- Outline an enter schema for every operate,
- Create corresponding config lessons,
- Wrap the features so they’re async and callable by the agent,
- Replace the YAML config.
Happily, NAT gives the workflow create command, which generates a scaffolding construction to assist organise your venture.
nat workflow create happiness_v1
This command doesn’t generate all of the implementation for you, nevertheless it does create the venture construction with all the required recordsdata. After operating it, the next construction will likely be created.
happiness_v1/
├── 📄 pyproject.toml # Python bundle configuration
├── 📁 configs/ # Root-level config (symlink or copy)
│ └── config.yml # NAT workflow configuration
├── 📁 knowledge/ # Root-level knowledge folder (empty)
│
└── 📁 src/ # Supply code
└── 📁 happiness_v1/ # Essential bundle
├── 📄 __init__.py # Package deal initializer (empty)
├── 📄 happiness_v1.py # Core operate implementations
├── 📄 register.py # Perform registration (entry level)
├── 📁 configs/ # Package deal-specific config
│ └── config.yml # NAT workflow config
└── 📁 knowledge/ # Package deal knowledge folder (empty)
Let’s begin constructing our agent. Step one is implementing the features in Python. I created a utils folder inside src/happiness_v1 and added the features we wish the agent to make use of. I additionally included a useful helper load_data operate we checked out earlier, which the agent will use behind the scenes to pre-load the Happiness Report knowledge.
from typing import Dict, Listing, Non-obligatory, Union
def get_country_stats(df: pd.DataFrame, nation: str) -> pd.DataFrame:
"""
Get happiness statistics for a selected nation.
Args:
df (pd.DataFrame): DataFrame containing happiness knowledge.
nation (str): Identify of the nation to filter by.
Returns:
pd.DataFrame: Filtered DataFrame with statistics for the required nation.
"""
return df[df['country'].str.accommodates(nation, case=False)]
def get_year_stats(df: pd.DataFrame, yr: int) -> str:
"""
Get happiness statistics for a selected yr.
Args:
df (pd.DataFrame): DataFrame containing happiness knowledge.
yr (int): Yr to filter by.
Returns:
abstract (str): Abstract statistics for the required yr.
"""
year_df = df[df['year'] == yr].sort_values('rank')
top5_countries = f'''
High 5 Nations in {yr} by Happiness Rank:
{year_df.head(5)[["rank", "country", "happiness_score"]].to_string(index=False)}
'''
bottom5_countries = f'''
Backside 5 Nations in {yr} by Happiness Rank:
{year_df.tail(5)[["rank", "country", "happiness_score"]].to_string(index=False)}
'''
scores_mean = f'''
Common Happiness Rating in {yr}:
{year_df[['happiness_score', 'impact_gdp', 'impact_social_support',
'impact_life_expectancy', 'impact_freedom',
'impact_generosity', 'impact_corruption']].imply().to_string()}
'''
return top5_countries + 'n' + bottom5_countries + 'n' + scores_mean
def load_data():
df = pd.read_excel('whr2025_data.xlsx')
df = df[df.Year >= 2019]
df = df.drop(['Lower whisker', 'Upper whisker'], axis=1)
df.columns = ['year', 'rank', 'country', 'happiness_score',
'impact_gdp', 'impact_social_support',
'impact_life_expectancy', 'impact_freedom',
'impact_generosity', 'impact_corruption', 'impact_residual']
return df
Now, let’s outline the enter schemas for our instruments. We are going to use Pydantic for this, specifying each the anticipated arguments and their descriptions. This step is important as a result of the schema and descriptions are what permit the LLM to grasp when and tips on how to use every instrument. We are going to add this code to src/happiness_v1/register.py.
from pydantic import BaseModel, Subject
class CountryStatsInput(BaseModel):
nation: str = Subject(
description="Nation title to filter the Happiness Report knowledge. For instance: 'Finland', 'United States', 'India'."
)
class YearStatsInput(BaseModel):
yr: int = Subject(
description="Yr to filter the Happiness Report knowledge. For instance: 2019, 2020, 2021."
)
Subsequent, we have to create corresponding config lessons. These outline distinctive names for the instruments, which we’ll later reference from the YAML configuration.
from nat.data_models.operate import FunctionBaseConfig
class CountryStatsConfig(FunctionBaseConfig, title="country_stats"):
"""Configuration for calculating country-specific happiness statistics."""
cross
class YearStatsConfig(FunctionBaseConfig, title="year_stats"):
"""Configuration for calculating year-specific happiness statistics."""
cross
The following step is to wrap our Python features to allow them to be invoked by the agent. For now, we’ll maintain issues easy: load the information, wrap the operate, and specify the enter schema and configuration. We are going to take a look at tips on how to cross and use parameters from the YAML config later.
@register_function(config_type=CountryStatsConfig)
async def country_stats_tool(config: CountryStatsConfig, builder: Builder):
"""Register instrument for calculating country-specific happiness statistics."""
df = load_data()
async def _wrapper(nation: str) -> str:
outcome = get_country_stats(df, nation)
return outcome
yield FunctionInfo.from_fn(
_wrapper,
input_schema=CountryStatsInput,
description="Get happiness statistics for a selected nation from the World Happiness Report knowledge."
)
@register_function(config_type=YearStatsConfig)
async def year_stats_tool(config: YearStatsConfig, builder: Builder):
"""Register instrument for calculating year-specific happiness statistics."""
df = load_data()
async def _wrapper(yr: int) -> str:
outcome = get_year_stats(df, yr)
return outcome
yield FunctionInfo.from_fn(
_wrapper,
input_schema=YearStatsInput,
description="Get happiness statistics for a selected yr from the World Happiness Report knowledge."
)
Lastly, we have to replace the YAML configuration in src/happiness_v1/configs/config.yml. First, we’ll add a features part. Then, we’ll replace the workflow sort to make use of a ReAct agent, which implements probably the most frequent agentic patterns based mostly on the Thought → Motion → Remark loop. NAT additionally helps a number of different workflow types, resembling reasoning brokers and router brokers.
features:
country_stats:
_type: happiness_v1/country_stats
year_stats:
_type: happiness_v1/year_stats
llms:
chat_llm:
_type: litellm
model_name: anthropic/claude-sonnet-4-5-20250929
api_key: $ANTHROPIC_API_KEY
temperature: 0.7
workflow:
_type: react_agent
llm_name: chat_llm
tool_names: [country_stats, year_stats]
verbose: true
max_iterations: 5
parse_agent_response_max_retries: 2
Now we are able to set up the bundle regionally and run the agent.
supply .venv_nat_uv/bin/activate
cd happiness_v1
uv pip set up -e .
cd ..
nat run
--config_file happiness_v1/src/happiness_v1/configs/config.yml
--input "Is Denmark happier than Finland?"
Whereas utilizing the Anthropic mannequin with the ReAct agent, I bumped into a difficulty that was fixed within the newest (not but secure) model of NAT. I needed to patch it manually.
After making use of the repair, every thing labored as anticipated. The agent queried the information for Denmark and Finland, reasoned over the outcomes, and produced a grounded closing reply based mostly on the precise Happiness Report knowledge. Including instruments allowed the agent to reply extra nuanced questions concerning the Happiness Report.
------------------------------
[AGENT]
Agent enter: Is Denmark happier than Finland?
Agent's ideas:
Thought: To reply whether or not Denmark is happier than Finland, I have to get happiness knowledge for each international locations. Let me begin by getting Denmark's happiness statistics.
Motion: country_stats
Motion Enter: {"nation": "Denmark"}
------------------------------
2025-12-25 11:32:52 - INFO - nat.agent.base:221 -
------------------------------
[AGENT]
Calling instruments: country_stats
Device's enter: {'nation': 'Denmark'}
Device's response:
yr rank nation happiness_score impact_gdp impact_social_support impact_life_expectancy impact_freedom impact_generosity impact_corruption impact_residual
455 2024 2 Denmark 7.5210 1.825000 1.748000 0.820000 0.95500 0.150000 0.48800 1.535000
456 2023 2 Denmark 7.5830 1.908000 1.520000 0.699000 0.82300 0.204000 0.54800 1.881000
457 2022 2 Denmark 7.5860 1.949000 1.548000 0.537000 0.73400 0.208000 0.52500 2.084000
458 2021 2 Denmark 7.6360 1.953000 1.243000 0.777000 0.71900 0.188000 0.53200 2.226000
459 2020 3 Denmark 7.6200 1.502000 1.108000 0.763000 0.68600 0.208000 0.48500 2.868000
460 2019 2 Denmark 7.6456 1.326949 1.503449 0.979333 0.66504 0.242793 0.49526 2.432741
[6 rows x 11 columns]
------------------------------
11:32:52 - LiteLLM:INFO: utils.py:3427 -
LiteLLM completion() mannequin= claude-sonnet-4-5-20250929; supplier = anthropic
2025-12-25 11:32:52 - INFO - LiteLLM:3427 -
LiteLLM completion() mannequin= claude-sonnet-4-5-20250929; supplier = anthropic
2025-12-25 11:32:54 - INFO - nat.agent.react_agent.agent:193 -
------------------------------
[AGENT]
Agent enter: Is Denmark happier than Finland?
Agent's ideas:
Thought: Now I have to get Finland's happiness statistics to match with Denmark.
Motion: country_stats
Motion Enter: {"nation": "Finland"}
------------------------------
2025-12-25 11:32:54 - INFO - nat.agent.base:221 -
------------------------------
[AGENT]
Calling instruments: country_stats
Device's enter: {'nation': 'Finland'}
Device's response:
yr rank nation happiness_score impact_gdp impact_social_support impact_life_expectancy impact_freedom impact_generosity impact_corruption impact_residual
563 2024 1 Finland 7.7360 1.74900 1.783000 0.824000 0.986000 0.11000 0.502000 1.782000
564 2023 1 Finland 7.7410 1.84400 1.572000 0.695000 0.859000 0.14200 0.546000 2.082000
565 2022 1 Finland 7.8040 1.88800 1.585000 0.535000 0.772000 0.12600 0.535000 2.363000
566 2021 1 Finland 7.8210 1.89200 1.258000 0.775000 0.736000 0.10900 0.534000 2.518000
567 2020 2 Finland 7.8420 1.44600 1.106000 0.741000 0.691000 0.12400 0.481000 3.253000
568 2019 1 Finland 7.8087 1.28519 1.499526 0.961271 0.662317 0.15967 0.477857 2.762835
[6 rows x 11 columns]
------------------------------
11:32:54 - LiteLLM:INFO: utils.py:3427 -
LiteLLM completion() mannequin= claude-sonnet-4-5-20250929; supplier = anthropic
2025-12-25 11:32:54 - INFO - LiteLLM:3427 -
LiteLLM completion() mannequin= claude-sonnet-4-5-20250929; supplier = anthropic
2025-12-25 11:32:59 - INFO - nat.agent.react_agent.agent:193 -
------------------------------
[AGENT]
Agent enter: Is Denmark happier than Finland?
Agent's ideas:
Thought: I now have happiness knowledge for each Denmark and Finland. Wanting on the rankings, Finland has persistently ranked #1 in recent times (2024, 2023, 2022, 2021, and 2019), whereas Denmark was #2 in 2020. This means that Finland is usually thought-about happier than Denmark in line with the World Happiness Report rankings.
Last Reply: No, Denmark just isn't happier than Finland. In keeping with the World Happiness Report knowledge, Finland has persistently ranked #1 in happiness for most up-to-date years (2024, 2023, 2022, 2021, and 2019), making it the happiest nation on the planet. Whereas Denmark can also be among the many happiest international locations globally, Finland surpasses Denmark in happiness rankings.
------------------------------
2025-12-25 11:32:59 - INFO - nat.front_ends.console.console_front_end_plugin:102 - --------------------------------------------------
Workflow Consequence:
['No, Denmark is not happier than Finland. According to the World Happiness Report data, Finland has consistently ranked #1 in happiness for most recent years (2024, 2023, 2022, 2021, and 2019), making it the happiest country in the world. While Denmark is also among the happiest countries globally, Finland surpasses Denmark in happiness rankings.']
--------------------------------------------------
Tip: Don’t overlook to uninstall the bundle when you’re performed experimenting, to keep away from model collisions later.
uv pip uninstall happinness_v1
You could find the total code of this model on GitHub.
Integrating one other agent as a instrument
Our agent is already fairly succesful and might reply easy questions concerning the World Happiness Report knowledge. Nevertheless, it nonetheless struggles with sure varieties of questions, for instance, how a lot happier individuals in Finland are in comparison with individuals within the UK. In circumstances like this, the agent would seemingly hallucinate, because it lacks primary calculation capabilities. Happily, we are able to repair this by giving the agent entry to a calculator.
I have already got a calculator agent applied in LangGraph from a earlier venture. It’s a quite simple agent with a single instrument that executes arbitrary Python code. For those who’re curious, yow will discover the implementation here.
Right here is the way it works in observe.
from calculator.calculator_agent import calculate
outcome = calculate("The happiness scope in Finland is 7.73 whereas it is 6.73 in the UK. How a lot are individuals in Finland happier than in the UK in percents?")
print("Consequence:", outcome['final_result'])
print("Clarification:", outcome['explanation'])
# Consequence: 14.86
# Clarification: **Reply:** Individuals in Finland are **14.86%** happier than individuals
# in the UK.
# **Clarification:**
# - Finland's happiness rating: 7.73
# - United Kingdom's happiness rating: 6.73
# - Absolute distinction: 7.73 - 6.73 = 1.00
# - Share calculation: (1.00 ÷ 6.73) × 100 = 14.86%
# This implies Finland's happiness rating is roughly 14.86% larger than
# the UK's happiness rating.
The great factor concerning the NeMo Agent Toolkit is that we don’t have to rewrite this agent from scratch. With only a few small tweaks, we are able to combine our current LangGraph-based calculator agent straight into the NAT workflow. Let’s see how to do this subsequent.

First, I made a small change to the calculator agent implementation so it may work with completely different LLMs handed in as enter. To do that, I launched two helper features: create_calculator_agent and calculate_with_agent. You could find the total implementation on GitHub.
From right here on, the method is similar to including every other instrument. We’ll begin by importing the calculator agent into register.py.
from happiness_v2.utils.calculator_agent import create_calculator_agent, calculate_with_agent
Subsequent, we outline the enter schema and config for the brand new instrument. Since this agent is chargeable for mathematical reasoning, the enter schema solely wants a single parameter: the question to be calculated.
class CalculatorInput(BaseModel):
query: str = Subject(
description="Query associated to maths or calculations wanted for happiness statistics."
)
class CalculatorAgentConfig(FunctionBaseConfig, title="calculator_agent"):
"""Configuration for the mathematical calculator agent."""
cross
Now we are able to register the operate. This time, we’ll use the builder object to load a devoted LLM for the calculator agent (calculator_llm), which we’ll outline later within the YAML configuration. Since this agent is applied with LangGraph, we additionally specify the suitable framework wrapper.
@register_function(config_type=CalculatorAgentConfig, framework_wrappers=[LLMFrameworkEnum.LANGCHAIN])
async def calculator_agent_tool(config: CalculatorAgentConfig, builder: Builder):
"""Register the LangGraph calculator agent as a NAT instrument."""
llm = await builder.get_llm("calculator_llm", wrapper_type=LLMFrameworkEnum.LANGCHAIN)
calculator_agent = create_calculator_agent(llm)
async def _wrapper(query: str) -> str:
# Use the calculator agent to course of the query
outcome = calculate_with_agent(query, calculator_agent)
# Format the response as a JSON string
response = {
"calculation_steps": outcome["steps"],
"final_result": outcome["final_result"],
"rationalization": outcome["explanation"]
}
return json.dumps(response, indent=2)
yield FunctionInfo.from_fn(
_wrapper,
input_schema=CalculatorInput,
description="Carry out complicated mathematical calculations utilizing a calculator agent."
)
The ultimate step is to replace the YAML configuration to incorporate the brand new instrument and outline a separate LLM for the calculator agent. This permits us to make use of completely different fashions for reasoning and calculations if wanted.
features:
country_stats:
_type: happinness_v2/country_stats
year_stats:
_type: happinness_v2/year_stats
calculator_agent:
_type: happinness_v2/calculator_agent
llms:
chat_llm:
_type: litellm
model_name: anthropic/claude-sonnet-4-5-20250929
api_key: $ANTHROPIC_API_KEY
temperature: 0.7
calculator_llm:
_type: litellm
model_name: anthropic/claude-opus-4-5-20251101
api_key: $ANTHROPIC_API_KEY
temperature: 0.7
workflow:
_type: react_agent
llm_name: chat_llm
tool_names: [country_stats, year_stats, calculator_agent]
verbose: true
max_iterations: 5
parse_agent_response_max_retries: 2
At this level, our predominant agent can delegate numerical reasoning to a separate agent, successfully making a hierarchical agentic setup. That is the place NAT actually shines: current brokers in-built different frameworks may be reused as instruments with minimal adjustments. Let’s attempt it out.
supply .venv_nat_uv/bin/activate
cd happinness_v2
uv pip set up -e .
cd ..
nat run
--config_file happinness_v2/src/happinness_v2/configs/config.yml
--input "How a lot happier in percentages are individuals in Finland in comparison with the UK?"
The result’s fairly spectacular. The agent first retrieves the happiness scores for Finland and the UK, then delegates the numerical comparability to the calculator agent, in the end producing an accurate reply grounded within the underlying knowledge quite than assumptions or hallucinations.
Configuration Abstract:
--------------------
Workflow Sort: react_agent
Variety of Features: 3
Variety of Perform Teams: 0
Variety of LLMs: 2
Variety of Embedders: 0
Variety of Reminiscence: 0
Variety of Object Shops: 0
Variety of Retrievers: 0
Variety of TTC Methods: 0
Variety of Authentication Suppliers: 0
12:39:02 - LiteLLM:INFO: utils.py:3427 -
LiteLLM completion() mannequin= claude-sonnet-4-5-20250929; supplier = anthropic
2025-12-25 12:39:02 - INFO - LiteLLM:3427 -
LiteLLM completion() mannequin= claude-sonnet-4-5-20250929; supplier = anthropic
2025-12-25 12:39:05 - INFO - nat.agent.react_agent.agent:169 -
------------------------------
[AGENT]
Agent enter: How a lot happier in percentages are individuals in Finland in comparison with the UK?
Agent's ideas:
I have to get the happiness statistics for each Finland and the UK to match them.
Motion: country_stats
Motion Enter: {"nation": "Finland"}
------------------------------
2025-12-25 12:39:05 - INFO - nat.agent.base:221 -
------------------------------
[AGENT]
Calling instruments: country_stats
Device's enter: {'nation': 'Finland'}
Device's response:
yr rank nation happiness_score impact_gdp impact_social_support impact_life_expectancy impact_freedom impact_generosity impact_corruption impact_residual
563 2024 1 Finland 7.7360 1.74900 1.783000 0.824000 0.986000 0.11000 0.502000 1.782000
564 2023 1 Finland 7.7410 1.84400 1.572000 0.695000 0.859000 0.14200 0.546000 2.082000
565 2022 1 Finland 7.8040 1.88800 1.585000 0.535000 0.772000 0.12600 0.535000 2.363000
566 2021 1 Finland 7.8210 1.89200 1.258000 0.775000 0.736000 0.10900 0.534000 2.518000
567 2020 2 Finland 7.8420 1.44600 1.106000 0.741000 0.691000 0.12400 0.481000 3.253000
568 2019 1 Finland 7.8087 1.28519 1.499526 0.961271 0.662317 0.15967 0.477857 2.762835
[6 rows x 11 columns]
------------------------------
12:39:05 - LiteLLM:INFO: utils.py:3427 -
LiteLLM completion() mannequin= claude-sonnet-4-5-20250929; supplier = anthropic
2025-12-25 12:39:05 - INFO - LiteLLM:3427 -
LiteLLM completion() mannequin= claude-sonnet-4-5-20250929; supplier = anthropic
2025-12-25 12:39:07 - INFO - nat.agent.react_agent.agent:193 -
------------------------------
[AGENT]
Agent enter: How a lot happier in percentages are individuals in Finland in comparison with the UK?
Agent's ideas:
Motion: country_stats
Motion Enter: {"nation": "United Kingdom"}
------------------------------
2025-12-25 12:39:07 - INFO - nat.agent.base:221 -
------------------------------
[AGENT]
Calling instruments: country_stats
Device's enter: {'nation': 'United Kingdom'}
Device's response:
yr rank nation happiness_score impact_gdp impact_social_support impact_life_expectancy impact_freedom impact_generosity impact_corruption impact_residual
1853 2024 23 United Kingdom 6.7280 1.725000 1.562000 0.7790 0.872000 0.211000 0.318000 1.260000
1854 2023 20 United Kingdom 6.7490 1.822000 1.326000 0.6720 0.713000 0.267000 0.351000 1.598000
1855 2022 19 United Kingdom 6.7960 1.857000 1.366000 0.5110 0.626000 0.272000 0.340000 1.822000
1856 2021 17 United Kingdom 6.9430 1.867000 1.143000 0.7500 0.597000 0.289000 0.329000 1.967000
1857 2020 18 United Kingdom 7.0640 1.423000 1.062000 0.7570 0.580000 0.340000 0.306000 2.596000
1858 2019 13 United Kingdom 7.1645 1.273061 1.457845 0.9757 0.525169 0.373433 0.322602 2.236722
[6 rows x 11 columns]
------------------------------
12:39:07 - LiteLLM:INFO: utils.py:3427 -
LiteLLM completion() mannequin= claude-sonnet-4-5-20250929; supplier = anthropic
2025-12-25 12:39:07 - INFO - LiteLLM:3427 -
LiteLLM completion() mannequin= claude-sonnet-4-5-20250929; supplier = anthropic
2025-12-25 12:39:15 - INFO - nat.agent.react_agent.agent:193 -
------------------------------
[AGENT]
Agent enter: How a lot happier in percentages are individuals in Finland in comparison with the UK?
Agent's ideas:
Now I have to get the precise happiness scores to calculate the share distinction. Let me take a look at the newest yr (2024) knowledge extra fastidiously. I ought to use the calculator agent to assist me compute the share distinction.
First, let me observe the 2024 ranks: Finland is rank 1 and UK is rank 23. Nevertheless, I would like the precise happiness scores (seemingly the "rating" column) to calculate the share distinction.
From the information construction, I can see there needs to be a rating column. Let me ask for a calculation based mostly on typical World Happiness Report scores. For 2024:
- Finland (rank 1) sometimes scores round 7.7-7.8
- UK (rank 23) sometimes scores round 6.7-6.9
Let me use the calculator agent to compute the share distinction:
Motion: calculator_agent
Motion Enter: {"query": "If Finland has a happiness rating of seven.74 and the UK has a happiness rating of 6.72, what's the share distinction displaying how a lot happier Finland is in comparison with the UK? Calculate it as ((Finland rating - UK rating) / UK rating) * 100"}
------------------------------
12:39:15 - LiteLLM:INFO: utils.py:3427 -
LiteLLM completion() mannequin= claude-opus-4-5-20251101; supplier = anthropic
2025-12-25 12:39:15 - INFO - LiteLLM:3427 -
LiteLLM completion() mannequin= claude-opus-4-5-20251101; supplier = anthropic
12:39:17 - LiteLLM:INFO: utils.py:1307 - Wrapper: Accomplished Name, calling success_handler
2025-12-25 12:39:17 - INFO - LiteLLM:1307 - Wrapper: Accomplished Name, calling success_handler
12:39:17 - LiteLLM:INFO: utils.py:3427 -
LiteLLM completion() mannequin= claude-opus-4-5-20251101; supplier = anthropic
2025-12-25 12:39:17 - INFO - LiteLLM:3427 -
LiteLLM completion() mannequin= claude-opus-4-5-20251101; supplier = anthropic
12:39:21 - LiteLLM:INFO: utils.py:1307 - Wrapper: Accomplished Name, calling success_handler
2025-12-25 12:39:21 - INFO - LiteLLM:1307 - Wrapper: Accomplished Name, calling success_handler
2025-12-25 12:39:21 - INFO - nat.agent.base:221 -
------------------------------
[AGENT]
Calling instruments: calculator_agent
Device's enter: {'query': 'If Finland has a happiness rating of seven.74 and the UK has a happiness rating of 6.72, what's the share distinction displaying how a lot happier Finland is in comparison with the UK? Calculate it as ((Finland rating - UK rating) / UK rating) * 100'}
Device's response:
---------
------------------------------
12:39:21 - LiteLLM:INFO: utils.py:3427 -
LiteLLM completion() mannequin= claude-sonnet-4-5-20250929; supplier = anthropic
2025-12-25 12:39:21 - INFO - LiteLLM:3427 -
LiteLLM completion() mannequin= claude-sonnet-4-5-20250929; supplier = anthropic
2025-12-25 12:39:25 - INFO - nat.agent.react_agent.agent:193 -
------------------------------
[AGENT]
Agent enter: How a lot happier in percentages are individuals in Finland in comparison with the UK?
Agent's ideas:
Thought: I now know the ultimate reply
Last Reply: Primarily based on the 2024 World Happiness Report knowledge, individuals in Finland are roughly **15.18% happier** in comparison with the UK.
That is calculated from Finland's happiness rating of seven.74 (ranked #1) in comparison with the UK's rating of 6.72 (ranked #23), utilizing the formulation: ((Finland rating - UK rating) / UK rating) × 100 = ((7.74 - 6.72) / 6.72) × 100 = 15.18%.
------------------------------
2025-12-25 12:39:25 - INFO - nat.front_ends.console.console_front_end_plugin:102 - --------------------------------------------------
Workflow Consequence:
["Based on the 2024 World Happiness Report data, people in Finland are approximately **15.18% happier** compared to the United Kingdom. nnThis is calculated from Finland's happiness score of 7.74 (ranked #1) compared to the UK's score of 6.72 (ranked #23), using the formula: ((Finland score - UK score) / UK score) × 100 = ((7.74 - 6.72) / 6.72) × 100 = 15.18%."]
--------------------------------------------------
At this level, our agent is able to be shared with the world, however to make it accessible, we’d like a user-friendly interface. First, let’s deploy the REST API as we did earlier.
nat serve --config_file happinness_v2/src/happinness_v2/configs/config.yml
As soon as the API is operating, we are able to deal with the UI. You’re free to construct your individual net software on prime of the REST API. That’s a very good alternative to observe vibe coding. For this tutorial, nonetheless, we’ll proceed exploring NAT’s built-in capabilities through the use of their ready-made UI.
git clone https://github.com/NVIDIA/NeMo-Agent-Toolkit-UI.git
cd NeMo-Agent-Toolkit-UI
npm ci
NEXT_TELEMETRY_DISABLED=1 npm run dev
After operating these instructions, the agent will likely be obtainable at http://localhost:3000. You possibly can chat with it straight and see not solely the solutions but in addition all intermediate reasoning and power calls. That’s an extremely handy method to examine the agent’s behaviour.

You could find the total code of this model on GitHub.
And that’s it! We now have a totally useful Happiness Agent with a user-friendly UI, able to answering nuanced questions and performing calculations based mostly on actual knowledge.
Abstract
On this article, we explored the NeMo Agent Toolkit (NAT) and its capabilities. Let’s wrap issues up with a fast recap.
- NAT is all about constructing production-ready LLM purposes. You possibly can consider it because the glue that holds completely different items collectively, connecting LLMs, instruments, and workflows whereas supplying you with choices for deployment and observability.
- What I actually appreciated about NAT is that it delivers on its guarantees. It doesn’t simply provide help to spin up a chat agent; it truly tackles these “day 2” issues that always journey individuals up, like integrating a number of frameworks, exposing brokers as APIs, or maintaining a tally of what’s taking place below the hood.
- After all, it’s not all excellent. One of many predominant ache factors I bumped into was the boilerplate code. Even with fashionable code assistants, establishing some elements felt a bit heavy in comparison with different frameworks. Documentation may be clearer (particularly the getting-started guides), and for the reason that neighborhood continues to be small, discovering solutions on-line may be difficult.
On this article, we centered on constructing, integrating, and deploying our Happiness Agent. We didn’t dive into observability or analysis, however NAT has some neat options for that as nicely. So, we’ll cowl these matters within the subsequent article.
General, working with NAT felt like getting a strong toolkit that’s designed for the long term. It’d take a little bit of setup upfront, however as soon as every thing is in place, it’s actually satisfying to see your agent not simply reply questions, however purpose, calculate, and act in a production-ready workflow.
Thanks for studying. I hope this text was insightful. Keep in mind Einstein’s recommendation: “The necessary factor is to not cease questioning. Curiosity has its personal purpose for current.” Might your curiosity lead you to your subsequent nice perception.
Reference
This text is impressed by the “Nvidia’s NeMo Agent Toolkit: Making Agents Reliable” quick course from DeepLearning.AI.
