Назад к articles
article

Как мы используем Ollama в проектах на .NET

Зачем использовать Ollama

В наши дни ИИ используется во многих приложениях. И ваше следующее приложение тоже могут потребовать его добавления. Существует много провайдеров, предоставляющих API для использования ИИ, такие как ChatGPT, DeepSeek или Gemini. Но некоторые приложения могут иметь особенности, не позволяющие использовать такие API.

Некоторые из причин:

  1. Приложение может использовать ИИ для обработки персональных данных. Может быть очень опасно или даже запрещено законом - отправлять такие данные провайдеру.
  2. У приложения могут быть высокие требования к доступности, а значит нельзя полагаться на сторонние API, которые периодически лежат.
  3. Клиент может располагаться в стране, где ИИ провайдеры не работают из-за экспортных ограничений. На самом деле, список причин можно расписывать и дальше.

Но главное, в таких случаях остается возможность использования локально развернутых моделей. Это могуть быть модели обученные с нуля, или переобученные чьи-то. Но оба этих варианта занимают немало времени, что критично при разработке MVP. Мы предпочитаем использовать Open Source LLM модели для проверки гипотез. Это позволяет получить результат за короткий промежуток времени. На дальнейших этапах, если MVP доказывает свою полезность, моедли в приложении уже могут быть заменены на специфичные, специально обученные под определенную задачу.

Ollama - это проект, предоставляющий универсальное API для использования разных модейлей из кода. Такой API позволяет менять используемую модель за несколько секунд, ничего не переписывая.

Нативное использование API Ollama

Когда приложение Ollama запущено (на порту 11434 по умолчанию) через него можно делать API запросы к моделям. Для получения ответа нужно просто вызвать адрес POST /api/generate с телом запроса:

{
    "model": "qwen2.5vl:3b",
    "prompt": "What you see on photo?",
    "stream": false,
    "images": ["base64Image"],
    "format": {
        "properties": {
            "Tags": {
                "items": {
                    "type": ["string"]
                },
                "type": ["array"]
            }
        },
        "type": ["object"]
    }
}

Самые часто исползуемые свойства здесь:

  1. Model: модель, которая будет использована. Первый вызов модели, начнет ее загрузку на диск, поэтому ответ может занять долгое время. Также, Ollama обычно загружает вызыванную модель в память GPU и хранит ее там 5 миинут по умолчанию. Это означает, что второй и последующие вызовы будут намного быстрее, чем первый, так как модель уже находится в памяти видеокарты.
  2. Prompt: ваш вопрос к ИИ.
  3. Format: структурированный вывод. Это поле позволяет возвращать ответ модели в строго заданном формате. Здесь вы определяете DTO, которое будет возвращаться из модели.
  4. Images: закодированные в base64 байты изображения. Используется только с моделями, которые подеерживают обработку изображений. Информация об этом обычно есть в описании модели. Несмотря на то, что поле является массивом закодированных изображений, все модели, что мы использовали, работали только с одним изображением.

Пример ответа на подобный запрос:

{
  "model": "qwen2.5vl:3b",
  "data": {
    "Tags": ["Empty room", "No furniture", "Unfinished walls", "No design solutions", "No color scheme"]
  }
}

Адаптер от Laraue

Прямеое использование API имеет недостатки, замедляющие разработку. Маой главной проблемой вляется описание стуктурированного вывода для запросов. Здесь очень просто допустить ошибку, поэтому мы сделали строго типизированный адаптер, который сам генерирует схему на основе C# класса.

Nuget latest version
Downloads latest version
Github Laraue.Core.Ollama

Для использования библиотеки, нужно выполнить три шага.

Зарегистрировать адаптер в контейнере:

services.AddHttpClient<IOllamaPredictor, OllamaPredictor>((serviceProvider, client) =>
{
    client.BaseAddress = new Uri("http://localhost:11434/"); // Или ваш адрес ollama
});

Далее необходимо описать класс, в который будет десериализоваться ответ от модели:

public record PredictionResult
{
    public required string[] Tags { get; set; }
}

Теперь можно вызывать Ollama из кода:

var imageBytes = File.ReadAllBytes("C://my-image.jpg");
var base64EncodedImage = Convert.ToBase64String(imageBytes);
var predictionResult = await ollamaPredictor.PredictAsync<PredictionResult>(
    model: "gemma3:12b",
    prompt: "Return info about objects on the picture",
    base64EncodedImage,
    ct);

На этом все. Схема выходного объекта генерируется автоматически. Процесс сериализации и десериализации скрыт в адаптере. Любые изменения DTO объекта не приводят к ручному переписыванию схемы.

Реальное использование

Использование адаптера можно найти в проекте real estate. Здесь Ollama используется для оценки уровня ремонта в квартирах.