BAML превращает хаос промпт-инжиниринга в стройный код

01 Jun, 2026

Знакомая ситуация? Вы пишете очередной сервис на базе LLM, и ваш код начинает тонуть в бесконечных f-строках, конкатенациях и сложных JSON-шаблонах. Каждый новый промпт — это боль: его сложно читать, поддерживать и, что самое главное, тестировать. А когда модель возвращает кривой JSON или просто отказывается следовать инструкциям, начинается отладка методом пристального взгляда.

Сегодня я хочу рассказать о проекте, который предлагает элегантное решение этой проблемы. Встречайте BAML (Basically a Made-up Language) — специализированный язык, который превращает промпт-инжиниринг из искусства в настоящую инженерную дисциплину.

Что такое BAML и зачем он нужен?

Если коротко, BAML — это язык для описания взаимодействия с большими языковыми моделями. Вместо того чтобы хранить промпты в строковых переменных внутри Python или TypeScript кода, вы выносите их в отдельные .baml файлы.

Основная идея BAML проста и гениальна: промпт — это функция. У этой функции есть типизированные входные параметры и, что самое важное, типизированный возвращаемый результат.

Вы описываете логику взаимодействия с LLM на BAML, а специальный компилятор (написанный на Rust, так что все очень быстро) генерирует для вас нативный, полностью типизированный клиент для вашего основного языка: Python, TypeScript, Ruby, Go и других.

Реклама

В итоге ваш основной код становится чистым. Вы просто вызываете сгенерированную функцию, как любую другую, а вся магия работы с LLM остается под капотом.

Ключевые возможности, которые цепляют

Давайте разберемся, что делает BAML таким привлекательным для разработчика.

1. Промпты как функции: прощайте, f-строки!

Забудьте о "супе" из строк. В BAML вы описываете функцию, ее аргументы и возвращаемый тип данных. Это сразу делает код на порядок читаемее и проще в поддержке.

Вот как выглядит определение функции-агента в BAML:

// Определяем классы для входных и выходных данных
class Message {
    role string
    content string
}

class ReplyTool {
  response string
}

class StopTool {
  action "stop" @description(#"
    когда стоит закончить диалог
  "#)
}

// А вот и сама функция
function ChatAgent(message: Message[], tone: "happy" | "sad") -> StopTool | ReplyTool {
    // Указываем, какую модель использовать
    client "openai/gpt-4o-mini"

    // А здесь сам промпт с использованием шаблонизатора Jinja
    prompt #"
        Be a {{ tone }} bot.

        {{ ctx.output_format }}

        {% for m in message %}
        {{ _.role(m.role) }}
        {{ m.content }}
        {% endfor %}
    "#
}

После этого в Python вы можете вызвать эту функцию так, будто она всегда там была:

from baml_client import b
from baml_client.types import Message, StopTool

# ... (код для инициализации диалога)

tool = b.ChatAgent(messages, "happy")
if isinstance(tool, StopTool):
    print("Goodbye!")
else:
    # Все поля типизированы и доступны через автодополнение
    print(tool.response)

2. Итерации со скоростью света прямо в VSCode

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

BAML решает эту проблему с помощью нативного расширения для VSCode (скоро и для JetBrains/Neovim). Оно предоставляет "песочницу" (Playground) прямо в редакторе.

Вы можете менять промпт, задавать разные входные параметры и мгновенно видеть результат, включая сырой запрос к API модели.

Визуализация запроса в VSCode

Авторы утверждают, что это ускоряет итерации в 10, а то и в 240 раз. Вместо того чтобы тестировать 10 идей за 20 минут, вы можете протестировать 240. Звучит как магия, но это просто хороший инструментарий.

Параллельное тестирование кейсов

3. Надежный tool-calling для любой модели

Что если вы хотите использовать модель, которая не поддерживает нативное "вызывание инструментов" (tool-calling)? Или поддерживает, но криво? BAML и тут приходит на помощь с алгоритмом SAP (schema-aligned parsing).

Эта технология позволяет BAML "добывать" структурированные данные даже из неидеальных ответов модели, например, когда JSON обернут в Markdown или ему предшествует какой-то текст. Это означает, что вы можете получать надежные типизированные результаты даже с моделями, которые вышли "вчера" и еще не обзавелись всеми нужными фичами.

4. Гибкое управление моделями

BAML позволяет легко переключаться между сотнями моделей от разных провайдеров (OpenAI, Anthropic, Gemini, Azure и любые OpenAI-совместимые). Хотите заменить gpt-4o-mini на o3-mini? Просто поменяйте одну строчку в .baml файле.

function Extract() -> Resume {
 client openai/gpt-4o-mini
 client openai/o3-mini
  prompt #"
    ....
  "#
}

Более того, BAML поддерживает продвинутые стратегии:

  • Политики повторных запросов (Retries): Автоматически повторить запрос, если модель упала или вернула некорректный ответ.
  • Резервные модели (Fallbacks): Если GPT-4 не справился, автоматически попробовать Anthropic Claude 3.
  • Ротация моделей (Round-robin): Распределять нагрузку между несколькими моделями.

Пример настройки Fallback и Retry

5. Удобная работа со стримингом

Создание "печатающих" UI, как в ChatGPT, может быть непростой задачей. BAML значительно ее упрощает, генерируя утилиты и хуки (например, для React/Next.js), которые позволяют легко работать с потоковыми ответами. Причем стриминг тоже полностью типизирован!

Пример стриминга для генератора рецептов

Зачем вообще создавать новый язык?

Авторы проекта приводят отличную аналогию. Когда-то давно мы писали веб-страницы так:

def home():
    return "<button onclick=\"() => alert(\\\"hello!\\\")\">Click</button>"

Это было неудобно, нечитаемо и вело к ошибкам. Потом появились шаблонизаторы, а затем и фреймворки вроде React с JSX, которые позволили описывать интерфейс декларативно и структурированно:

function Home() {
  return <button onClick={() => setCount(prev => prev + 1)}>
          {count} clicks!
         </button>
}

BAML делает для промпт-инжиниринга то же самое, что JSX сделал для веба. Он дает структуру, типизацию и инструменты там, где раньше был хаос из склеенных строк.

Выводы: кому стоит попробовать BAML?

BAML — это не просто очередной шаблонизатор. Это полноценный фреймворк, который привносит лучшие инженерные практики в мир разработки AI-приложений.

Кому особенно зайдет BAML:

  • Командам, работающим над сложными AI-агентами и workflow. Когда у вас десятки промптов, поддерживать их в виде строк становится невозможно.
  • Разработчикам, ценящим типизацию и надежность. Гарантия того, что модель вернет данные в нужном формате, дорогого стоит.
  • Всем, кто хочет ускорить цикл разработки. Интеграция с IDE — это настоящая killer-фича, которая экономит уйму времени.
  • Тем, кто строит мультимодальные системы. BAML позволяет легко переключаться между разными провайдерами и моделями, не переписывая код.

Проект полностью опенсорсный (Apache 2), работает локально без отправки ваших данных куда-либо (кроме прямых запросов к LLM, которые вы сами настроите) и активно развивается. Если вы чувствуете, что "промпты в строках" — это путь в никуда, обязательно загляните на GitHub BoundaryML/baml и попробуйте его в своем следующем проекте.