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

Промпты

Model Context Protocol (MCP) предоставляет стандартизированный способ для серверов предоставлять клиентам шаблоны промптов. Промпты позволяют серверам передавать структурированные сообщения и инструкции для взаимодействия с языковыми моделями. Клиенты могут получать список доступных промптов, извлекать их содержимое и передавать аргументы для их настройки.

В главе Основы мы научились объявлять простой промпт:

#[prompt(descr = "Generates a user message requesting a hello world code generation.")]
async fn hello_world_code(lang: String) -> PromptMessage {
PromptMessage::user()
.with(format!("Write a hello-world function on {lang}"))
}

Того же результата можно добиться без использования процедурного макроса:

use neva::prelude::*;

async fn hello_world_code(lang: String) -> PromptMessage {
PromptMessage::user()
.with(format!("Write a hello-world function on {lang}"))
}

#[tokio::main]
async fn main() {
let mut mcp_server = App::new()
.with_options(|opt| opt
.with_stdio()
.with_name("Sample MCP Server")
.with_version("1.0.0"));

mcp_server
.map_prompt("hello_world_code", hello_world_code)
.with_description("Generates a user message requesting a hello world code generation.");

mcp_server.run().await;
}

В примере выше имя промпта должно быть задано явно. При использовании атрибутного макроса #[prompt] имя промпта автоматически выводится из имени функции.

Все остальные параметры промпта, доступные в атрибутном макросе, можно настроить с помощью методов with_* (например, with_description()).

Метод map_prompt() регистрирует обработчик промпта под указанным именем и возвращает изменяемую ссылку на зарегистрированный промпт.

Входные аргументы

Для промпта можно явно задать входные аргументы. Если аргументы не указаны, Neva автоматически генерирует их на основе сигнатуры функции-обработчика.

Для переопределения сгенерированной схемы укажите её в виде JSON-строки:

#[prompt(
descr = "Generates a user message requesting a hello world code generation.",
args = r#"[
{
"name": "lang",
"description": "A language to use",
"required": true
}
]"#
)]
async fn hello_world_code(lang: String) -> PromptMessage {
PromptMessage::user()
.with(format!("Write a hello-world function on {lang}"))
}

MCP-контекст

В более сложных сценариях — например, когда промпту нужен доступ к ресурсам, объявленным на том же MCP-сервере, — можно внедрить Context в обработчик промпта:

#[prompt(descr = "Generates a user message requesting a translate a text using the glossary.")]
async fn translate_with_glossary(ctx: Context, text: String) -> PromptMessage {
let glossary = ctx.resource("res://glossary").await?;
let resource = result.contents
.into_iter()
.next()
.expect("No resource contents");

PromptMessage::user()
.with(format!("Translate using this glossary:\n{glossary}\n\nText: {text}"))
}

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

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