AmigaОбучение ИИ
Модуль 5 · Подключаем клиент · урок 12 из 14

Определяем промпты

9 мин чтения▶ есть видеоверсия

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

Первый промпт

Добавьте в docs_server.py:

python
@mcp.prompt(title="Выжимка документа")
def summarize(name: DocName) -> str:
    """Сделать короткую выжимку документа проекта."""
    return (
        f"Прочитай документ {name} с помощью инструмента read_doc и сделай "
        "выжимку: три-пять предложений, только факты, без оценок."
    )

Декоратор @mcp.prompt() регистрирует функцию как промпт. Как и у инструментов, имя берётся из функции, описание из docstring, аргументы из сигнатуры. title — человекочитаемое имя для интерфейса: в списке промптов хост покажет «Выжимка документа», а вызывать будет по имени summarize.

Мы переиспользовали тип DocName из урока про инструменты: аргумент name получит то же описание «Имя файла, например brief.md». Оно попадёт в метаданные аргумента, и хост сможет показать его как подсказку в форме.

Функция возвращает строку — SDK превратит её в одно сообщение от пользователя. Это то, что получит модель, когда человек выберет промпт и введёт имя документа.

Что делает промпт хорошим

Посмотрите на текст ещё раз. Он не просто просит «сделай выжимку» — он говорит, каким инструментом взять документ и в каком формате ответить. Это и есть смысл промптов на сервере: автор сервера знает, как правильно им пользоваться, и упаковывает это знание.

Пользователь, набирая запрос руками, мог бы написать «выжимку брифа» — и модель, возможно, попросила бы текст, или прочитала бы не тот документ, или выдала бы абзац с оценками. Промпт убирает эту вариативность. Три вещи, которые стоит закладывать в каждый промпт:

  • какие инструменты и ресурсы использовать — по именам, как они называются на сервере;
  • формат результата — длина, структура, что включать и что нет;
  • ограничения — «ничего не выдумывай», «не меняй документ», «спроси, если данных не хватает».

Второй промпт: аргументы и список сообщений

python
from mcp.server.mcpserver.prompts.base import UserMessage


@mcp.prompt(title="Документ в тезисы")
def to_theses(
    name: DocName,
    audience: Annotated[str, Field(description="Для кого тезисы")] = "команда разработки",
) -> list[UserMessage]:
    """Переписать документ в формате тезисов для заданной аудитории."""
    return [
        UserMessage(
            f"Прочитай документ {name} инструментом read_doc и перепиши его "
            f"в виде тезисов для аудитории «{audience}». Один тезис — одна "
            "строка, не больше десяти строк. Ничего не выдумывай."
        )
    ]

Здесь два новых момента.

Необязательный аргумент. У audience есть значение по умолчанию, поэтому в метаданных промпта он будет помечен как необязательный. Хост покажет его как поле, которое можно не заполнять. Аргумент без значения по умолчанию — обязательный, и если клиент его не передаст, SDK вернёт ошибку до вызова функции.

Список сообщений. Вместо строки функция возвращает list[UserMessage]. Это позволяет собрать целый диалог: несколько сообщений пользователя, ответы ассистента (AssistantMessage из того же модуля). Так делают промпты с примерами: «вот документ — вот как должны выглядеть тезисы — а теперь сделай так же для этого документа». Для одного сообщения разницы между строкой и списком нет; мы показали список, чтобы вы знали, что он есть.

Содержимым сообщения может быть не только текст: UserMessage принимает картинку, аудио или встроенный ресурс. Промпт мог бы сразу приложить содержимое документа как ресурс, вместо того чтобы просить модель вызвать read_doc. Мы выбрали инструмент, потому что так промпт работает и с документами, которые появятся после запуска сервера.

Все аргументы — строки

В протоколе аргументы промпта передаются как строки: prompts/get получает словарь «имя → строка». SDK приведёт "3" к int, если вы объявите такой тип, но полагаться на сложные типы в промптах не стоит — хосты показывают аргументы как текстовые поля. Держите аргументы простыми: имена, короткие фразы, числа.

Проверяем

Дополните check.py:

python
        for prompt in (await client.list_prompts()).prompts:
            args = [(a.name, "обязательный" if a.required else "необязательный") for a in prompt.arguments or []]
            print("промпт:", prompt.name, "—", prompt.title, args)

        got = await client.get_prompt("summarize", {"name": "brief.md"})
        for message in got.messages:
            print(message.role, ":", message.content.text)

        got = await client.get_prompt("to_theses", {"name": "risks.md", "audience": "заказчик"})
        print(got.messages[0].content.text)

list_prompts вернёт имена, заголовки и аргументы с флагом required. get_prompt вернёт объект с полем messages; у каждого сообщения есть role и content, у текстового содержимого — text. Именно эти сообщения клиент отправит модели в следующем уроке.

Откройте инспектор: во вкладке Prompts появятся оба промпта, у второго — два поля, одно с пометкой «необязательный». Заполните и посмотрите сгенерированное сообщение. Это самый быстрый способ проверить, что текст промпта собирается так, как вы задумали.

Как это выглядит в Claude Code

Когда сервер подключён к Claude Code, его промпты становятся командами: /mcp__project-docs__summarize brief.md. Хост вызовет prompts/get, получит сообщения и отправит их модели как начало разговора. Пользователю не нужно помнить, как правильно попросить выжимку, — он выбирает команду из списка.

Попробуйте сами

10–15 мин на рабочем месте
  1. Добавьте промпт compare(first, second), который просит сравнить два документа и найти противоречия. Проверьте в инспекторе, что оба аргумента обязательные.
  2. Перепишите to_theses так, чтобы он возвращал три сообщения: просьбу, пример ответа ассистента (AssistantMessage) на учебном документе и финальную просьбу. Сравните, как изменится результат в клиенте после следующего урока.
  3. Для сервиса из своей работы напишите два промпта в виде текста с аргументами. Проверьте по списку из раздела «Что делает промпт хорошим»: инструменты названы, формат задан, ограничения есть.

Коротко

  • @mcp.prompt(title=...) регистрирует промпт; имя из функции, описание из docstring, аргументы из сигнатуры.
  • Аргумент со значением по умолчанию — необязательный; описания задаются через Annotated[..., Field(description=...)].
  • Возврат str — одно сообщение пользователя; list[UserMessage | AssistantMessage] — диалог с примерами.
  • Хороший промпт называет инструменты сервера по именам, задаёт формат ответа и ограничения.
  • Аргументы передаются строками; держите их простыми.
  • В Claude Code промпты становятся командами /mcp__сервер__промпт.

Видеоверсия

Сценарий озвучки · 437 слов, ≈ 3 мин

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

Первый — выжимка документа. Декоратор «промпт» с заголовком «Выжимка документа» — это человекочитаемое имя для интерфейса. Имя функции, описание из докстринга, аргументы из сигнатуры — всё как у инструментов. Единственный аргумент — имя документа, и мы переиспользуем для него тот же тип с описанием, что и у инструментов. Функция возвращает строку, и SDK превращает её в одно сообщение от пользователя.

Посмотрите на текст промпта. Он не просто просит сделать выжимку — он говорит, каким инструментом взять документ и в каком формате ответить: три-пять предложений, только факты, без оценок. В этом и смысл промптов на сервере: автор знает, как правильно пользоваться сервером, и упаковывает это знание. Пользователь, набирая запрос руками, мог бы получить не тот документ или абзац с оценками. Промпт убирает эту вариативность. Три вещи, которые стоит закладывать в каждый промпт: какие инструменты и ресурсы использовать, по именам; формат результата; и ограничения — «ничего не выдумывай», «не меняй документ».

Второй промпт — документ в тезисы для заданной аудитории. Здесь два новых момента. Первый: у аргумента «аудитория» есть значение по умолчанию, поэтому он необязательный. Хост покажет его как поле, которое можно не заполнять. Аргумент без значения по умолчанию обязателен, и без него SDK вернёт ошибку до вызова функции. Второй момент: функция возвращает не строку, а список сообщений. Это позволяет собрать целый диалог — несколько сообщений пользователя и ответы ассистента. Так делают промпты с примерами: вот документ, вот как должны выглядеть тезисы, а теперь сделай так же для другого. Содержимым сообщения может быть не только текст, но и картинка или встроенный ресурс.

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

Проверяем из клиента: печатаем список промптов с аргументами и флагом обязательности, запрашиваем промпт «выжимка» с именем документа и смотрим сообщение. Потом «тезисы» с аудиторией «заказчик». Открываем инспектор: во вкладке промптов оба на месте, у второго два поля, одно помечено необязательным. Заполняем — видим готовое сообщение.

Когда сервер подключён к Claude Code, промпты становятся командами через слеш с именем сервера и промпта. Пользователю не нужно помнить, как правильно попросить выжимку, — он выбирает команду из списка.

Задания для самостоятельной работы: добавьте промпт «сравнить два документа» с двумя обязательными аргументами и проверьте в инспекторе, что оба помечены обязательными. Перепишите промпт с тезисами так, чтобы он возвращал диалог с примером ответа ассистента. И для сервиса из своей работы напишите два промпта текстом, проверив их по трём пунктам: инструменты названы, формат задан, ограничения есть.

В следующем уроке научим наш собственный клиент делать то же самое: показывать промпты как команды и запускать разговор с готового сообщения.

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