Your First AI Agent
An AI agent is more than a chatbot. It is an LLM that can reason about a task, decide which tools to call, interpret the results, and produce a final answer. LM-Kit.NET provides a fluent builder API that makes it straightforward to create agents with built-in or custom tools, all running locally on your hardware.
This guide walks you through creating, configuring, and running your first agent.
TL;DR
using LMKit.Model;
using LMKit.Agents;
using LMKit.Agents.Tools.BuiltIn;
using LM model = LM.LoadFromModelID("qwen3:4b");
var agent = Agent.CreateBuilder(model)
.WithPersona("helpful-assistant")
.WithInstruction("You are a helpful assistant. Use tools when needed.")
.WithTools(tools =>
{
tools.Register(BuiltInTools.CalcArithmetic);
tools.Register(BuiltInTools.DateTimeNow);
})
.WithMaxIterations(5)
.Build();
var result = await agent.RunAsync("What is 15% of $2,340?");
Console.WriteLine(result.Content);
- Use
Agent.CreateBuilder(model)to configure persona, instructions, and tools. - Register built-in tools (
Calculator,DateTime,WebSearch,PdfSplit,Ocr, etc.) or implement custom ones. - Call
agent.RunAsync(prompt)and checkresult.IsSuccessfor the final answer.
Prerequisites
| Requirement | Details |
|---|---|
| LM-Kit.NET | Installed via NuGet (LM-Kit.NET package) |
| .NET | .NET 8.0 or later |
| VRAM | 4+ GB recommended (a model like qwen3:4b fits in ~3 GB) |
| Completed | Understanding Model Loading and Caching and Estimating Memory and Context Size |
What You Will Build
A console application that:
- Loads a language model capable of tool calling.
- Creates an agent with two built-in tools:
CalculatorandDateTime. - Sends a prompt and receives a result where the agent autonomously calls tools as needed.
- Runs an interactive loop so you can keep asking questions.
Step 1: Load a Model
Choose a model that supports tool calling. Models such as qwen3:4b, gemma3:4b, and gemma3:12b all have strong tool-calling capabilities.
using System.Text;
using LMKit.Model;
Console.InputEncoding = Encoding.UTF8;
Console.OutputEncoding = Encoding.UTF8;
// Optional: set your license key
// LMKit.Licensing.LicenseManager.SetLicenseKey("");
using LM model = LM.LoadFromModelID("qwen3:4b",
loadingProgress: p =>
{
Console.Write($"\rLoading model: {p * 100:F0}% ");
return true;
});
Console.WriteLine($"\nModel loaded: {model.Name}");
Console.WriteLine($"Tool calling support: {model.HasToolCalls}");
Step 2: Build the Agent
Use the Agent.CreateBuilder() fluent API to configure the agent's persona, instructions, tools, and iteration limit.
using LMKit.Agents;
using LMKit.Agents.Tools.BuiltIn;
var agent = Agent.CreateBuilder(model)
.WithPersona("helpful-assistant")
.WithInstruction("You are a helpful assistant with access to a calculator and date/time information. Use your tools when a question requires computation or current date/time data.")
.WithTools(tools =>
{
tools.Register(BuiltInTools.CalcArithmetic);
tools.Register(BuiltInTools.DateTimeNow);
})
.WithMaxIterations(5)
.Build();
Builder Methods Explained
| Method | Purpose |
|---|---|
WithPersona(string) |
A short name or role for the agent (e.g., "helpful-assistant", "financial-analyst"). |
WithInstruction(string) |
A detailed system prompt that guides the agent's behavior. |
WithTools(Action<ToolRegistry>) |
Registers one or more tools the agent can call during execution. |
WithMaxIterations(int) |
Caps the number of reasoning/tool-calling cycles to prevent infinite loops. |
Build() |
Finalizes configuration and returns the Agent instance. |
Step 3: Run the Agent
The simplest way to execute an agent is the RunAsync method, which returns an AgentExecutionResult.
var result = await agent.RunAsync("What is 15% of $2,340?");
if (result.IsSuccess)
{
Console.WriteLine(result.Content);
}
else if (result.IsFailed)
{
Console.WriteLine($"Error: {result.Error?.Message}");
}
else if (result.IsCancelled)
{
Console.WriteLine("Execution was cancelled.");
}
Understanding AgentExecutionResult
| Property | Type | Description |
|---|---|---|
Content |
string |
The final text response from the agent. |
IsSuccess |
bool |
true when execution completed without errors. |
IsFailed |
bool |
true when an exception occurred during execution. |
IsCancelled |
bool |
true when execution was cancelled via a CancellationToken. |
Error |
Exception |
The exception that caused the failure (only when IsFailed is true). |
ToolCalls |
IReadOnlyList<ToolCallResult> |
A record of every tool invocation the agent made. |
Duration |
TimeSpan |
Total wall-clock time for the execution. |
InferenceCount |
int |
Number of LLM inference calls made during execution. |
Step 4: Add an Interactive Loop
Wrap the execution in a loop so you can have a continuous conversation with the agent.
Console.WriteLine("\nAgent ready. Type a question, or 'quit' to exit.\n");
while (true)
{
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write("You: ");
Console.ResetColor();
string input = Console.ReadLine()?.Trim();
if (string.IsNullOrEmpty(input))
continue;
if (input.Equals("quit", StringComparison.OrdinalIgnoreCase))
break;
var result = await agent.RunAsync(input);
if (result.IsSuccess)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"Agent: {result.Content}");
Console.ResetColor();
// Show tool usage summary
if (result.ToolCalls.Count > 0)
{
Console.ForegroundColor = ConsoleColor.DarkGray;
Console.WriteLine($" [{result.ToolCalls.Count} tool call(s), {result.Duration.TotalSeconds:F1}s, {result.InferenceCount} inference(s)]");
Console.ResetColor();
}
}
else
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"Error: {result.Error?.Message}");
Console.ResetColor();
}
Console.WriteLine();
}
Complete Example
Here is the full program combining all the steps above:
using System.Text;
using LMKit.Model;
using LMKit.Agents;
using LMKit.Agents.Tools.BuiltIn;
// Optional: set your license key
// LMKit.Licensing.LicenseManager.SetLicenseKey("");
Console.InputEncoding = Encoding.UTF8;
Console.OutputEncoding = Encoding.UTF8;
// Step 1: Load the model
Console.WriteLine("Loading model...");
using LM model = LM.LoadFromModelID("qwen3:4b",
loadingProgress: p =>
{
Console.Write($"\rLoading model: {p * 100:F0}% ");
return true;
});
Console.WriteLine($"\nModel loaded: {model.Name}");
// Step 2: Build the agent
var agent = Agent.CreateBuilder(model)
.WithPersona("helpful-assistant")
.WithInstruction("You are a helpful assistant with access to a calculator and date/time information. Use your tools when a question requires computation or current date/time data.")
.WithTools(tools =>
{
tools.Register(BuiltInTools.CalcArithmetic);
tools.Register(BuiltInTools.DateTimeNow);
})
.WithMaxIterations(5)
.Build();
Console.WriteLine("Agent ready. Type a question, or 'quit' to exit.\n");
// Step 3: Interactive loop
while (true)
{
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write("You: ");
Console.ResetColor();
string input = Console.ReadLine()?.Trim();
if (string.IsNullOrEmpty(input))
continue;
if (input.Equals("quit", StringComparison.OrdinalIgnoreCase))
break;
var result = await agent.RunAsync(input);
if (result.IsSuccess)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"Agent: {result.Content}");
Console.ResetColor();
if (result.ToolCalls.Count > 0)
{
Console.ForegroundColor = ConsoleColor.DarkGray;
Console.WriteLine($" [{result.ToolCalls.Count} tool call(s), {result.Duration.TotalSeconds:F1}s, {result.InferenceCount} inference(s)]");
Console.ResetColor();
}
}
else
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"Error: {result.Error?.Message}");
Console.ResetColor();
}
Console.WriteLine();
}
Console.WriteLine("Goodbye!");
Example Conversation
Loading model...
Loading model: 100%
Model loaded: Qwen3-4B-Instruct
Agent ready. Type a question, or 'quit' to exit.
You: What is 15% of $2,340?
Agent: 15% of $2,340 is $351.00.
[1 tool call(s), 2.3s, 2 inference(s)]
You: What day of the week is it today?
Agent: Today is Thursday, February 6, 2026.
[1 tool call(s), 1.1s, 2 inference(s)]
You: If I invest $5,000 at 4.5% annual interest, how much will I have after 3 years with compound interest?
Agent: With compound interest at 4.5% annually over 3 years, $5,000 would grow to approximately $5,706.82.
[1 tool call(s), 3.4s, 2 inference(s)]
You: quit
Goodbye!
Available Built-In Tools
LM-Kit.NET ships with a library of ready-to-use tools organized by category. Here are some commonly used ones:
| Tool | Category | Description |
|---|---|---|
BuiltInTools.CalcArithmetic |
Numeric | Arithmetic, percentages, and mathematical expressions. |
BuiltInTools.DateTimeNow |
Utility | Current date, time, time zones, and date calculations. |
BuiltInTools.WebSearch |
Net | Web search via DuckDuckGo (no API key required). |
BuiltInTools.HttpGet, HttpPost, ... |
Net | Individual HTTP method tools (register the HTTP method tools you need). |
BuiltInTools.FileSystemRead, FileSystemList, ... |
IO | Individual file system tools (tools.AddFileSystemTools() registers all). |
BuiltInTools.RegexMatch |
Text | Regular expression matching and extraction. |
BuiltInTools.PdfSplit |
Document | Split PDFs by page ranges into separate files. |
BuiltInTools.PdfToImage |
Document | Render PDF pages as JPEG, PNG, or BMP images. |
BuiltInTools.PdfUnlock |
Document | Remove password protection from a PDF. |
BuiltInTools.DocumentTextExtract |
Document | Extract text from PDF, DOCX, XLSX, PPTX, EML, MBOX, HTML. |
BuiltInTools.OcrRecognize |
Document | OCR using Tesseract with 34 language support. |
Register any combination of tools to match your use case:
var agent = Agent.CreateBuilder(model)
.WithPersona("research-assistant")
.WithInstruction("You are a research assistant that can search the web and perform calculations.")
.WithTools(tools =>
{
tools.Register(BuiltInTools.WebSearch);
tools.Register(BuiltInTools.CalcArithmetic);
tools.Register(BuiltInTools.DateTimeNow);
})
.WithMaxIterations(10)
.Build();
Inspecting Tool Calls
After execution, the ToolCalls property lets you see exactly which tools the agent invoked and what results they returned.
var result = await agent.RunAsync("What is the square root of 144?");
if (result.IsSuccess)
{
Console.WriteLine(result.Content);
foreach (var call in result.ToolCalls)
{
Console.WriteLine($" Tool: {call.ToolName}");
Console.WriteLine($" Args: {call.Arguments}");
Console.WriteLine($" Result: {call.Result}");
Console.WriteLine($" Status: {call.ResultType}");
}
}
This is valuable for debugging, auditing, and understanding how the agent reaches its conclusions.
Troubleshooting
| Problem | Solution |
|---|---|
| Agent does not call tools | Verify that the model supports tool calling (model.HasToolCalls). Try a model like qwen3:4b or gemma3:12b. |
| Agent loops without producing an answer | Increase WithMaxIterations() or switch to a more capable model. |
| Out-of-memory during execution | Use a smaller model, reduce GPU layer count, or free other resources. |
result.IsFailed is true |
Check result.Error for the exception details. Common causes include model incompatibility or cancellation. |
Next Steps
- Create an AI Agent with Tools (How-To): implement custom tools with the
IToolinterface. - Equip an Agent with Built-In Tools (How-To): explore the growing catalog of built-in tools across all categories.
- Process PDFs and Images with Built-In Document Tools (How-To): build agents that split PDFs, run OCR, and preprocess scanned images.
- Build a Function-Calling Agent (How-To): advanced function-calling patterns with JSON schemas.
- Build a Multi-Agent Workflow (How-To): orchestrate multiple agents with pipeline, parallel, and supervisor patterns.
- Research Assistant Demo: see a full ReAct agent with web search in action.
- Document Processing Agent Demo: see an agent using Document tools for PDF and image processing.
- Tool Calling Assistant Demo: explore custom tool implementations for weather, currency, and unit conversion.
- Build Dynamic Prompts with Templates (How-To): use
PromptTemplateto build agent instructions dynamically from runtime data. - Build a RAG Pipeline (How-To): ground your agent in a private knowledge base with retrieval-augmented generation.