Table of Contents

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 check result.IsSuccess for 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:

  1. Loads a language model capable of tool calling.
  2. Creates an agent with two built-in tools: Calculator and DateTime.
  3. Sends a prompt and receives a result where the agent autonomously calls tools as needed.
  4. 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

Share