mcpField
B
baml

baml

github.com/ouachitalabs開発256 回インストール39 週間前に更新
リポジトリ

baml について

BAML は、構造化された型付き出力を扱う LLM アプリ向けの DSL とクイックリファレンスです。Python、TypeScript、Go、Ruby 用のクライアントコードを生成し、構文やテスト、コマンドラインの使い方も説明します。

主な機能

  1. 01型付き構造化出力スキーマ
  2. 024 言語向けクライアント生成
  3. 03Jinja ベースのプロンプトテンプレート
  4. 04スキーマに沿った柔軟な解析
  5. 05テストとコマンドライン操作

活用シーン

  1. 01LLM による構造化データ抽出
  2. 02入力の列挙型分類
  3. 03マルチターン対話やマルチモーダル処理の構築
  4. 04BAML 関数のテスト

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/ouachitalabs/skills --skill baml

インストール後、Claude Code で/bamlを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

examples/
chat.baml
classification.baml
extraction.baml
multimodal.baml
usage.py

詳細

BAML クイックリファレンス

BAML(Boundary AI Markup Language)は、構造化された型安全な出力を使用する LLM アプリケーションを構築するための DSL です。Python、TypeScript、Go、Ruby 用のクライアントコードを生成します。

BAML の仕組み

  • baml_src/ 内のすべての .baml ファイルは、互いにグローバルにアクセスできます
  • baml-cli generate でクライアントを生成します
  • 生成された baml_client/ には、インポートして呼び出せる型安全な関数が含まれています
  • BAML の型は、Python では Pydantic モデル、TypeScript では型、Go では構造体、Ruby では Sorbet の型になります

基本構文

型
// Primitives
string, int, float, bool, null

// Composite
Type?           // optional (nullable)
Type[]          // array
Type1 | Type2   // union
map<K, V>       // dictionary

// Literals
"spam" | "ham"  // literal string union

// Multimodal
image, audio, video, pdf
クラス

構造化データの形を定義します。フィールド名と型の間にコロンは付けません。

class Resume {
    name string
    email string?                           // optional
    skills string[]                         // array
    experience Experience[]                 // nested type
    seniority SeniorityLevel               // enum
}

class Experience {
    company string
    role string @description("Job title")   // hint for the LLM
    years int @alias("duration_years")      // JSON key mapping
}
列挙型

値の固定セットです。分類タスクに最適です。

enum SeniorityLevel {
    JUNIOR @description("0-2 years experience")
    MID @description("2-5 years experience")
    SENIOR @description("5+ years experience")
}

enum Category {
    SPAM
    HAM
    UNKNOWN @skip  // excluded from prompts
}
関数

LLM とのやり取りを定義します。関数名は大文字で始める必要があります。

function ExtractResume(resume_text: string) -> Resume {
    client "openai/gpt-4o"
    prompt #"
        Extract structured information from this resume.

        {{ ctx.output_format }}

        Resume:
        ---
        {{ resume_text }}
        ---
    "#
}
クライアント

LLM プロバイダーを設定します。2 つのスタイルがあります。

// Shorthand (uses env vars automatically)
client "openai/gpt-4o"
client "anthropic/claude-sonnet-4-20250514"

// Named client (full control)
client<llm> GPT4 {
    provider openai
    options {
        model "gpt-4o"
        api_key env.OPENAI_API_KEY
        temperature 0.0
    }
}

// Fallback chain
client<llm> Resilient {
    provider fallback
    options {
        clients [GPT4, Claude, GPT4Mini]
    }
}
ジェネレーター

コード生成を設定します。

generator target {
    output_type "python/pydantic"  // or "typescript", "go", "ruby/sorbet"
    output_dir "../"
    default_client_mode "sync"     // or "async"
    version "0.203.1"
}

複数の言語で、複数の場所に対するコード生成を設定できます。 たとえば、それぞれの BAML クライアントでバックエンドとフロントエンドの型を揃えたい場合があります。 その場合は、generator ブロックを 2 つ初期化します。


重要な 2 つの概念

1. {{ ctx.output_format }}

この Jinja マクロはすべてのプロンプトに含める必要があります。戻り値の型スキーマを出力することで、LLM に生成すべき構造を知らせます。

function ClassifyEmail(email: string) -> Category {
    client GPT4
    prompt #"
        Classify this email.

        {{ ctx.output_format }}

        Email: {{ email }}
    "#
}

Category 列挙型の場合、次のように出力されます。

Answer with any of the categories:
SPAM
HAM

クラスの場合は、フィールドの説明を含む JSON スキーマを出力します。

2. スキーマ整合型パーサー(SAP)

BAML のパーサーは、意図的に寛容な設計になっています。LLM 出力によくある問題を自動的に修正します。

  • 文字列を囲む引用符の欠落
  • 末尾のカンマ
  • JSON 内のコメント
  • 不完全なシーケンス
  • エスケープされていない文字

そのため、厳密な JSON パースや関数呼び出しと比べて、精度が 87~93%向上します。


プロンプト構文(Jinja)

BAML のプロンプトでは、Jinja テンプレートを使用します。

prompt #"
    {# Comments don't appear in output #}

    {{ _.role("system") }}
    You are a helpful assistant.

    {{ _.role("user") }}
    {% for msg in messages %}
        {{ msg.content }}
    {% endfor %}

    {% if verbose %}
        Be detailed in your response.
    {% endif %}

    {{ ctx.output_format }}
"#

主な構文:

  • {{ variable }} - 値を埋め込みます
  • {% for item in list %}...{% endfor %} - ループ
  • {% if cond %}...{% endif %} - 条件分岐
  • {{ _.role("system"|"user"|"assistant") }} - メッセージのロールを設定します
  • {{ value|filter }} - フィルターを適用します(例:|upper、|length、|join(","))

BAML 関数の呼び出し

Python
from baml_client import b
from baml_client.types import Resume

# Sync
resume = b.ExtractResume(resume_text)
print(resume.name, resume.skills)

# Async
from baml_client.async_client import b
resume = await b.ExtractResume(resume_text)

# Streaming
stream = b.stream.ExtractResume(resume_text)
for partial in stream:
    print(partial)  # partial Resume object
final = stream.get_final_response()
TypeScript
import { b } from './baml_client'

// Async (default)
const resume = await b.ExtractResume(resumeText)
console.log(resume.name, resume.skills)

// Streaming
const stream = b.stream.ExtractResume(resumeText)
for await (const partial of stream) {
    console.log(partial)
}
const final = await stream.getFinalResponse()
Go
import b "example.com/myproject/baml_client"

resume, err := b.ExtractResume(ctx, resumeText, nil)
if err != nil {
    log.Fatal(err)
}
fmt.Println(resume.Name, resume.Skills)

テスト

BAML ファイル内で直接テストを定義します。

test SimpleExtraction {
    functions [ExtractResume]
    args {
        resume_text "John Doe, Software Engineer at Acme Corp for 5 years"
    }
    @@assert({{ this.name == "John Doe" }})
}

テストを実行します。

baml-cli test                    # run all
baml-cli test -i "ExtractResume" # filter by function
baml-cli test --parallel 5       # parallel execution

属性リファレンス

フィールドレベル:

  • @alias("name") - JSON 出力内のフィールド名を変更します
  • @description("...") - LLM にコンテキストを追加します
  • @skip - プロンプトから除外します(列挙型のみ)

ブロックレベル:

  • @@dynamic - クラス/列挙型の実行時の変更を許可します

検証:

  • @check(expr, name) - ソフト検証(結果を返し、失敗してもエラーになりません)
  • @assert(expr, name) - ハード検証(失敗時に例外をスローします)

ストリーミング:

  • @@stream.done - オブジェクトは完成したときにのみ表示されます
  • @stream.not_null - 親のストリーミングが始まる前に、フィールドに値が必要です
  • @stream.with_state - 完了状態のメタデータを含めます

CLI コマンド

baml-cli init          # initialize new project
baml-cli generate      # generate client code
baml-cli dev           # dev server with hot reload
baml-cli test          # run tests
baml-cli serve         # start REST API server (port 2024)
baml-cli fmt           # format BAML files

よくあるパターン

完全に動作するサンプルについては、examples/ ディレクトリを参照してください。

  • extraction.baml - 構造化データの抽出
  • classification.baml - 列挙型ベースの分類
  • chat.baml - メッセージ履歴を使った複数ターンのチャット
  • multimodal.baml - 画像/音声/PDF 入力
  • usage.py - Python での呼び出しパターン

Further Resources

Getting Started

Language Reference

LLM Providers

Prompt Engineering

Advanced

Testing

コメント