Сэмплирование
В 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() сигнализирует серверу о завершении сэмплирования.
Когда настраивать сэмплирование клиента
Рассмотрите пользовательскую логику сэмплирования, когда:
- Нужно интегрировать проприетарные или локальные модели
- Требуется точный контроль стоимости или задержки
- Нужна фильтрация или аудит запросов
- Требуются детерминированные или политически-управляемые ответы
Обучение на примерах
Полный рабочий пример доступен здесь.