- Published on
Building an AI-Powered .NET API with Ollama and Microsoft.Extensions.AI
Table of Contents
Introduction
The integration of AI capabilities into .NET applications has become more accessible with Microsoft's release of the Microsoft.Extensions.AI package. This tutorial demonstrates how to build an intelligent API that leverages Ollama's Large Language Models (LLMs) and implements custom function calling.
Prerequisites
Before starting, ensure you have:
- .NET 9.0 SDK installed
- Ollama installed and running locally
- Basic understanding of .NET Web APIs
- A code editor (Visual Studio or VS Code recommended)
Understanding the Components
Ollama
Ollama is an open-source platform that simplifies running and managing Large Language Models locally. It supports various models including:
- Llama 3
- Mistral
- Gemma
- Code Llama
- And many more
Key benefits:
- Local execution for privacy
- OpenAI-compatible API
- Low resource requirements
- Active community and updates
Microsoft.Extensions.AI
This new framework provides:
- Unified abstractions for AI services
- Seamless integration with .NET dependency injection
- Support for multiple AI providers
- Built-in function calling capabilities
Getting Started
First, create a new .Net API project using the following command:
dotnet new web -n OllamaWithExtensionAndFunctionCalling
Next, install the required packages:
dotnet add package Microsoft.Extensions.AI --prerelease
dotnet add package Microsoft.Extensions.AI.Ollama --prerelease
dotnet add package Scalar.AspNetCore
dotnet add package Microsoft.AspNetCore.OpenApi
At the time of writing this post, the Microsoft.Extensions.AI package is in preview, so you need to add the --prerelease
flag to install the package. please check the latest version of the package before installing.
Project Setup in Detail
Let's break down the implementation into smaller, manageable steps:
1. Basic API Structure
// Initial Program.cs setup
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// Configure base routes
app.MapGet("/", () => "Hello from AI-powered API!");
2. Ollama Integration
// Configuration setup
var ollamaEndpoint = builder.Configuration["AI__Ollama__Endpoint"] ?? "http://localhost:11434";
var chatModel = builder.Configuration["AI__Ollama__ChatModel"] ?? "llama3.2";
// Create and configure Ollama client
IChatClient client = new OllamaChatClient(ollamaEndpoint, modelId: chatModel)
.AsBuilder()
.UseFunctionInvocation()
.Build();
3. Implementing AI Functions
[Description("Gets the weather")]
string GetWeather() => Random.Shared.NextDouble() > 0.5 ? "It's sunny" : "It's raining";
[Description("Gets the location")]
string GetLocation() => "Vienna, Austria";
[Description("Gets the weather and location")]
string GetWeatherAndLocation() => $"{GetWeather()} in {GetLocation()}";
var chatOptions = new ChatOptions
{
Tools =
[
AIFunctionFactory.Create(GetWeather),
AIFunctionFactory.Create(GetLocation),
AIFunctionFactory.Create(GetWeatherAndLocation)
]
};
Next, add the following code to the Program.cs
file:
using System.ComponentModel;
using Microsoft.Extensions.AI;
using Scalar.AspNetCore;
var builder = WebApplication.CreateBuilder(args);
var ollamaEndpoint = builder.Configuration["AI__Ollama__Endpoint"] ?? "http://localhost:11434";
var chatModel = builder.Configuration["AI__Ollama__ChatModel"] ?? "llama3.2";
IChatClient client = new OllamaChatClient(ollamaEndpoint, modelId: chatModel)
.AsBuilder()
.UseFunctionInvocation()
.Build();
[Description("Gets the weather")]
string GetWeather() => Random.Shared.NextDouble() > 0.5 ? "It's sunny" : "It's raining";
[Description("Gets the location")]
string GetLocation() => "Vienna, Austria";
[Description("Gets the weather and location")]
string GetWeatherAndLocation() => $"{GetWeather()} in {GetLocation()}";
var chatOptions = new ChatOptions
{
Tools =
[
AIFunctionFactory.Create(GetWeather),
AIFunctionFactory.Create(GetLocation),
AIFunctionFactory.Create(GetWeatherAndLocation)
]
};
builder.Services.AddChatClient(client);
builder.Services.AddOpenApi();
var app = builder.Build();
app.MapOpenApi().CacheOutput();
app.MapScalarApiReference();
app.MapGet("/", () => Results.Redirect("/scalar/v1")).ExcludeFromDescription();
app.MapPost(
"/chat",
async (IChatClient client, string message) =>
await client.CompleteAsync(message, chatOptions, cancellationToken: default)
);
app.Run();
In the above code, we first create a new WebApplication
using the WebApplication.CreateBuilder
method. Next, we read the Ollama endpoint and chat model from the configuration. We then create a new OllamaChatClient
instance and configure it to use function invocation.
Next, we define three functions: GetWeather
, GetLocation
, and GetWeatherAndLocation
. These functions are used to demonstrate how to call a function from the Ollama AI extension.
We then create a new ChatOptions
instance and add the three functions to the Tools
property using the AIFunctionFactory.Create
method.
Finally, we add the OllamaChatClient
and OpenApi
services to the service collection and configure the API routes. The /chat
endpoint is used to handle chat requests, and the CompleteAsync
method is called with the message and chat options.
I'm reading the Ollama endpoint and chat model from the configuration. You can set these values in the appsettings.json
file:
{
"AI": {
"Ollama": {
"Endpoint": "http://localhost:11434",
"ChatModel": "llama3.2"
}
}
}
if they are not available in the configuration, the default values will be used.
Advanced Usage
Error Handling
Add robust error handling to your chat endpoint:
app.MapPost("/chat", async (IChatClient client, ChatRequest request) =>
{
try
{
var response = await client.CompleteAsync(
request.Message,
chatOptions,
cancellationToken: default);
return Results.Ok(new { response });
}
catch (Exception ex)
{
return Results.Problem(
title: "Chat completion failed",
detail: ex.Message);
}
});
Performance Optimization
Consider adding caching for frequent queries:
builder.Services.AddOutputCache(options =>
{
options.AddBasePolicy(builder =>
builder.Cache()
.Expire(TimeSpan.FromMinutes(5)));
});
Testing the Implementation
Here are some example queries to test your API:
# Basic weather query
curl -X POST "http://localhost:5000/chat?message=Where am I? and how is the weather?"
# Combined query
curl -X POST "http://localhost:5000/chat?message=Give me a weather report and location?"
Best Practices and Tips
Model Selection: Choose the appropriate Ollama model based on your needs:
- Llama3 for general purpose
- CodeLlama for code-related tasks
- Mistral for balanced performance
Performance Optimization:
- Implement request caching
- Use appropriate model sizes
- Consider batch processing for multiple requests
Security Considerations:
- Validate all inputs
- Implement rate limiting
- Use appropriate authentication
Troubleshooting
Common issues and solutions:
Ollama Connection Failed
- Verify Ollama is running
- Check endpoint configuration
- Ensure firewall permissions
Model Loading Issues
- Confirm model is downloaded
- Check available system resources
- Verify model name spelling
GitHub Repository
You can find the complete source code for this project on GitHub: OllamaWithExtensionAndFunctionCalling. Feel free to fork and experiment with the code.
Conclusion
This implementation demonstrates the power of combining .NET's new AI extensions with Ollama's capabilities. The resulting API can understand natural language queries and execute appropriate functions, making it a valuable addition to any AI-powered application.
Additional Resources
Related Posts
Modern API Documentation in .NET with Scalar and OpenAPI
Learn how to implement beautiful API documentation using Scalar and OpenAPI in .NET 9.0
Ollama Semantic Kernel Connector With C#: Console App & API Guide
In this post, we will learn how to use the Ollama Semantic Kernel Connector with C#.
ABP-Powered Web App with Inertia.js, React, and Vite
Building a web application with ABP Framework, Inertia.js, React, and Vite.