Перейти к основному содержимому

Сэмплирование

В MCP именно клиент отвечает за выполнение запросов на сэмплирование LLM, инициируемых серверами. В отличие от традиционных архитектур, клиент:

  • Владеет доступом к модели и ключами API
  • Применяет локальные политики (стоимость, конфиденциальность, ограничения скорости)
  • Является посредником во всём взаимодействии с языковыми моделями

Серверы никогда не общаются с LLM напрямую — они только запрашивают сэмплирование.

Важная концептуальная модель

  • Сервер запрашивает сэмплирование
  • Клиент выполняет сэмплирование
  • Клиент принимает решение:
    • какую модель использовать
    • поддерживаются ли инструменты
    • как обрабатываются запросы
  • Клиент возвращает структурированные результаты серверу

Конфигурация клиента

Поддержка сэмплирования должна быть явно включена на клиенте:

let mut client = Client::new()
.with_options(|opt| opt
.with_sampling(|s| s.with_tools()));
  • with_sampling() включает поддержку сэмплирования
  • with_tools() разрешает вызовы инструментов в процессе сэмплирования

Обработчик сэмплирования

Для поддержки сэмплирования клиент должен определить обработчик, помеченный атрибутным макросом #[sampling]. Этот обработчик получает объект CreateMessageRequestParams и возвращает CreateMessageResult.

use neva::prelude::*;

#[sampling]
async fn sampling_handler(params: CreateMessageRequestParams) -> CreateMessageResult {
println!("Received sampling request: {:?}", params);

// Здесь логика сэмплирования на стороне клиента
}

Обработчик вызывается каждый раз, когда сервер вызывает Context::sample().

Анализ запросов на сэмплирование

Входящий CreateMessageRequestParams содержит:

  • Сообщения запроса
  • Системный запрос
  • Предпочтения модели
  • Метаданные инструментов
  • Предыдущие результаты инструментов (для многошагового сэмплирования)

Доступ к текстовым запросам

let prompts: Vec<&TextContent> = params.text().collect();

Включает все накопленные текстовые сообщения пользователя и ассистента.

Определение запросов на использование инструментов

Клиент может проверить, разрешает ли или ожидает ли сервер использование инструментов через tool_choice:

if params.tool_choice.is_some_and(|c| !c.is_none()) {
// Модели разрешено или требуется вызвать инструменты
}

Это позволяет клиенту решить, производить ли вызовы инструментов или конечный текст.

Использование инструментов

Если инструменты включены, клиент может ответить запросом на вызов инструмента вместо обычного текста.

CreateMessageResult::assistant()
.with_model("gpt-5")
.use_tools([
("get_weather", ("city", "London"))
])
примечание
  • Выполнение инструментов всегда осуществляется сервером
  • Клиент только возвращает намерение вызвать инструменты
  • Аргументы инструментов должны соответствовать схеме инструмента

Обработка результатов инструментов

После выполнения инструментов сервером он отправит повторный запрос на сэмплирование, содержащий результаты инструментов.

Эти результаты доступны через:

let results: Vec<&ToolResult> = params.results().collect();

На этом этапе клиент обычно должен:

  • Интерпретировать выходные данные инструментов
  • Сформировать финальный ответ ассистента
  • Завершить шаг сэмплирования

Формирование финальных ответов

Для возврата обычного сообщения ассистента и завершения цикла сэмплирования:

CreateMessageResult::assistant()
.with_model("gpt-5")
.with_content("Final response text")
.end_turn()

Вызов end_turn() сигнализирует серверу о завершении сэмплирования.

Когда настраивать сэмплирование клиента

Рассмотрите пользовательскую логику сэмплирования, когда:

  • Нужно интегрировать проприетарные или локальные модели
  • Требуется точный контроль стоимости или задержки
  • Нужна фильтрация или аудит запросов
  • Требуются детерминированные или политически-управляемые ответы

Обучение на примерах

Полный рабочий пример доступен здесь.