Building an AI Agent in .NET with Inferable
In this tutorial, we'll build a simple AI agent that manages inventory operations using .NET and Inferable. Our agent will handle stock checks, process orders, and manage inventory - all through natural language commands.
Prerequisites
Before we begin, make sure you have:
- .NET 7.0 or later installed
- Basic familiarity with C#
- Inferable CLI installed (
npm install -g @inferablehq/inferable
)
Authenticate with Inferable
inf auth login
Setting Up the Project
First, let's create a new .NET project with the Inferable SDK:
inf bootstrap dotnet
This will guide you through creating a new .NET project with the Inferable SDK installed. Let's remove the example code since we'll be starting fresh:
rm Program.cs
Creating Our Inventory System
Let's start by defining our inventory models and a simple in-memory store:
using System.Collections.Concurrent;
namespace InventoryAgent.Models;
public class Item
{
public string Id { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public decimal Price { get; set; }
public int Quantity { get; set; }
}
public class Store
{
private readonly ConcurrentDictionary<string, Item> _items = new();
public void Initialize()
{
var items = new[]
{
new Item { Id = "LIGHT-1", Name = "Lightsaber", Price = 199.99m, Quantity = 5 },
new Item { Id = "DROID-1", Name = "Astromech Droid", Price = 2499.99m, Quantity = 2 },
new Item { Id = "FORCE-1", Name = "Force Crystal", Price = 99.99m, Quantity = 10 }
};
foreach (var item in items)
{
_items.TryAdd(item.Id, item);
}
}
public Item? GetItem(string itemId)
{
_items.TryGetValue(itemId, out var item);
return item;
}
public bool UpdateItem(string itemId, Func<Item, Item> updateFn)
{
return _items.TryUpdate(
itemId,
oldValue => updateFn(oldValue),
item => true);
}
}
Implementing Inventory Functions
Now, let's create our input models and functions:
namespace InventoryAgent.Models;
public class CheckStockInput
{
public string ItemId { get; set; } = string.Empty;
}
public class OrderInput
{
public string ItemId { get; set; } = string.Empty;
public int Quantity { get; set; }
}
public class InventoryService
{
private readonly Store _store;
public InventoryService(Store store)
{
_store = store;
}
public async Task<Item?> CheckStock(CheckStockInput input)
{
var item = _store.GetItem(input.ItemId);
if (item == null)
{
throw new Exception($"Item not found: {input.ItemId}");
}
return item;
}
public async Task<Item?> ProcessOrder(OrderInput input)
{
var item = _store.GetItem(input.ItemId);
if (item == null)
{
throw new Exception($"Item not found: {input.ItemId}");
}
if (item.Quantity < input.Quantity)
{
throw new Exception(
$"Insufficient stock: requested {input.Quantity}, available {item.Quantity}");
}
var success = _store.UpdateItem(input.ItemId, current =>
{
current.Quantity -= input.Quantity;
return current;
});
if (!success)
{
throw new Exception("Failed to update inventory");
}
return _store.GetItem(input.ItemId);
}
}
Creating the Inferable Agent
Now let's connect our inventory system to Inferable:
using Inferable;
using InventoryAgent.Models;
var store = new Store();
store.Initialize();
var service = new InventoryService(store);
var options = new InferableOptions
{
ApiSecret = Environment.GetEnvironmentVariable("INFERABLE_API_SECRET")
};
var client = new InferableClient(options);
// Register our inventory service
var inventoryService = client.Default;
// Register the CheckStock function
await inventoryService.RegisterFunction(new FunctionRegistration<CheckStockInput>
{
Name = "checkStock",
Description = "Check the current stock level of an item",
Function = async (input) => await service.CheckStock(input)
});
// Register the ProcessOrder function
await inventoryService.RegisterFunction(new FunctionRegistration<OrderInput>
{
Name = "processOrder",
Description = "Process an order for an item",
Function = async (input) => await service.ProcessOrder(input)
});
// Start the service
await inventoryService.Start();
// Keep the application running
await Task.Delay(-1);
Using our multi-agent system
To run the agent, use the inf app
command from within the project directory:
inf app
With our agent running, we can interact with it through natural language. Here are some example interactions:
-
Checking stock:
"How many lightsabers do we have in stock?"
-
Processing an order:
"Place an order for 2 Astromech Droids"
The agent will:
- Understand the natural language request
- Map it to the appropriate function
- Extract required parameters
- Execute the function
- Return results in a user-friendly format
How It Works
Inferable orchestrates the interaction by:
- Using LLMs to parse natural language input
- Mapping requests to registered functions
- Validating inputs using .NET type information
- Executing functions in your .NET service
- Formatting responses for users
The agent can handle complex queries and multi-step operations. For example, it will automatically check stock levels before processing orders.
Security and Control
A key benefit of this implementation is that all inventory operations run on your own machine. Inferable never has direct access to your data - it only orchestrates function calls based on natural language input.
C#-Specific Features
The .NET implementation takes advantage of several C#-specific features:
- Uses
ConcurrentDictionary
for thread-safe operations - Leverages C#'s async/await pattern
- Uses nullable reference types for better type safety
- Takes advantage of .NET's built-in dependency injection patterns
Next Steps
You can extend this basic agent in several ways:
- Add Entity Framework for persistent storage
- Implement CQRS pattern for operations
- Add approval workflows using
requiredApproval
configuration - Integrate with real inventory systems
- Add data masking for sensitive information using the
masked()
decorator
Conclusion
We've built a simple but powerful AI agent that manages inventory operations through natural language. The Inferable .NET SDK made it easy to connect our C# code to an AI interface while maintaining full control over our business logic and data.