К ленте · Россия

РоссияНовостьМодели

FAIRouter вышел на NuGet. Выбираем языковую модель под задачу в несколько строк на C#

Ранее мы рассказывали о FAIRouter , нашей библиотеке для маршрутизации запросов. Коротко напомню, что она делает. Есть несколько языковых моделей, у них разные цены, скорость и сильные...

Ранее мы рассказывали о FAIRouter, нашей библиотеке для маршрутизации запросов. Коротко напомню, что она делает. Есть несколько языковых моделей, у них разные цены, скорость и сильные стороны. FAIRouter сам выбирает модель под задачу, проверяет готовый ответ и учится на отзывах. Общая схема работы показана на рисунке 1.

Версия на C# теперь опубликована на NuGet, поэтому собирать ее из исходников больше не нужно. В этой статье покажу, как поставить пакет и что с ним можно делать. Все примеры ниже были собраны на пакете версии 0.1.0.

Установка

Понадобится.NET 10. Создадим консольный проект и подключим пакет:

dotnet new console -f net10.0 -n RouterDemo
cd RouterDemo
dotnet add package FAI.Router

Также нужен ключ поставщика моделей. В примерах будем использовать OpenRouter, ключ положим в переменную среды:

$env:OPENROUTER_API_KEY = "ваш ключ"

Первый запрос

Заменим содержимое Program.cs следующим кодом:

using FAI.Router;

FaiRouter router = await FaiRouter.FromOpenRouterAsync(
 apiKey: Environment.GetEnvironmentVariable("OPENROUTER_API_KEY")!,
 modelIds:
 [
 "google/gemini-2.5-flash",
 "openai/gpt-4.1-mini",
 "anthropic/claude-haiku-4.5"
 ],
 databasePath: "fai-router.db");

RouterAnswer answer = await router.AskAsync(
 "Напиши обзор методов кластеризации на 1500 знаков");

Console.WriteLine($"{answer.Winner.Name}: {answer.Score}");
Console.WriteLine(answer.Text);
Console.WriteLine(answer.Critic);

Здесь modelIds задает список кандидатов, а в файле fai-router.db хранятся веса и журнал ходов. Если файла нет, он будет создан. В ответе нас интересуют четыре поля:

  • Winner показывает, какая модель была выбрана;
  • Text содержит ответ модели;
  • Score содержит оценку судьи от 0 до 1;
  • Critic показывает, чем ответ отличается от заказа, по пунктам.

Судья проверяет ответ автоматически. Например, если в задании было четыре раздела и таблица, а в ответе один раздел без таблицы, это будет видно в Critic.

Список моделей можно вообще не задавать. Тогда выбор идет среди 54 популярных моделей из комплекта пакета:

FaiRouter router = await FaiRouter.FromOpenRouterAsync(
 apiKey: Environment.GetEnvironmentVariable("OPENROUTER_API_KEY")!,
 databasePath: "fai-router.db");

Обучение на отзывах

Самое интересное начинается, когда маршрутизатор получает отзывы. Отзыв задается числом от 0 до 1, где 1 означает отличный ответ, а 0.2 слабый:

router.Feedback(answer.RoundId!.Value, score: 1.0);
router.Train(epochs: 10);
router.Save();

После этого веса сохраняются в базе, и на похожих задачах маршрутизатор учитывает полученный опыт. Отзывы можно накапливать и обучать маршрутизатор реже, например один раз в день. Стоит учитывать, что в журнале хранятся тексты запросов.

Что важнее, цена или качество

В библиотеке есть три готовых профиля: Quality, Balance и Price. По умолчанию используется Balance. Профиль можно менять на каждом запросе:

RouterAnswer cheap = await router.AskAsync(
 prompt, weights: RouteWeights.Price);

RouterAnswer strong = await router.AskAsync(
 prompt, weights: RouteWeights.Quality);

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

RouterAnswer enough = await router.AskAsync(prompt, bar: 0.7);
Console.WriteLine(enough.Reached);

Поле Reached показывает, дотянул ли кто‑то до планки. Планка начинает работать, когда накопится хотя бы три отзыва человека.

Диалог вместо одного запроса

В AskAsync можно передать диалог целиком. Задание распознается по последней реплике пользователя, а модель видит всю историю:

using AI.LLM.Core.Models.Common.Messages;

LLMMessage[] dialog =
[
 new(LLMMessage.UserRole, "Что такое кластеризация?"),
 new(LLMMessage.AssistantRole, "Это разбиение объектов на группы."),
 new(LLMMessage.UserRole, "Теперь объясни это школьнику")
];

RouterAnswer replied = await router.AskAsync(dialog);

Другие поставщики

Пакет работает не только с OpenRouter. Всего есть три способа подключения:

Метод

Куда подключается

FromOpenRouterAsync

OpenRouter

FromFractalRouterAsync

FractalRouter

FromOpenAiCompatibleAsync

любой сервер с протоколом OpenAI chat completions

Последний вариант подойдет и для своей модели. Цену такой модели нужно указать самому:

FaiRouter local = await FaiRouter.FromOpenAiCompatibleAsync(
 baseUrl: "http://localhost:8000/v1",
 apiKey: "local",
 modelIds: ["my-model"],
 prices: new Dictionary<string, Price>
 {
 ["my-model"] = new Price(0, 0)
 },
 judgeModel: "my-model");

Судья работает через того же поставщика, по умолчанию на модели openai/gpt-4o-mini. Если на вашем сервере такой модели нет, укажите другую в параметре judgeModel, как в примере выше.

Не только модели

Выбирать можно не только модели, но и инструменты с агентами. Для этого в конструктор передаются свои кандидаты и функция, которая их запускает. Рассмотрим пример с двумя вариантами поиска:

using AI.LLM.Core.Models.Common.Messages;
using AI.LLM.Services.LLM;
using FAI.Router;
using FAI.Router.LLM;
using FAI.Router.RoutedElements;

BaseRoutedElement deepSearch = new()
{
 Name = "deep-search",
 DPMTInp = 5,
 DPMTOutp = 20,
 TPS = 30
};

BaseRoutedElement fastSearch = new()
{
 Name = "fast-search",
 DPMTInp = 1,
 DPMTOutp = 2,
 TPS = 200
};

LLMBase judge = new OpenAiCompatibleLlm(
 Providers.OpenRouter,
 "ваш ключ",
 "openai/gpt-4o-mini");

FaiRouter tools = new(
 [deepSearch, fastSearch],
 (candidate, messages, token) =>
 RunSearchAsync(candidate.Name!, messages, token),
 "tools.db",
 llm: judge);

Здесь DPMTInp и DPMTOutp задают цену за миллион токенов, а TPS скорость в токенах в секунду. Для инструмента эти числа условные, важно только их соотношение. Функцию RunSearchAsync вы пишете сами, она запускает нужный поиск и возвращает текст. Такие кандидаты стартуют со случайными весами, поэтому первое время им нужны ваши отзывы.

Итоги

Таким образом, чтобы попробовать FAIRouter, достаточно одной команды dotnet add package FAI.Router и нескольких строк кода. Пакет распространяется под лицензией Apache-2.0, исходный код и подробная документация опубликованы на GitHub, а замечания и вопросы можно оставить в разделе issues.

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

Источник: Хабр · статьиПубликуется с разрешения правообладателя, подтверждённого редакцией.Оригинал: FAIRouter вышел на NuGet. Выбираем языковую модель под задачу в несколько строк на C# ↗

Есть кому отправить?

Скопируется постоянная ссылка на этот материал.

Комментарии

Обсуждайте статью, отвечайте и оценивайте комментарии. Вход — через ваш Яндекс ID.

Загружаем обсуждение…