baml について
BAML は、構造化された型付き出力を扱う LLM アプリ向けの DSL とクイックリファレンスです。Python、TypeScript、Go、Ruby 用のクライアントコードを生成し、構文やテスト、コマンドラインの使い方も説明します。
主な機能
- 01型付き構造化出力スキーマ
- 024 言語向けクライアント生成
- 03Jinja ベースのプロンプトテンプレート
- 04スキーマに沿った柔軟な解析
- 05テストとコマンドライン操作
活用シーン
- 01LLM による構造化データ抽出
- 02入力の列挙型分類
- 03マルチターン対話やマルチモーダル処理の構築
- 04BAML 関数のテスト
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ ouachitalabs/ skills --skill bamlインストール後、Claude Code で/bamlを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
examples/chat.bamlclassification.bamlextraction.bamlmultimodal.bamlusage.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
- Installation: https://docs.boundaryml.com/guide/installation-language/python.md
- TypeScript setup: https://docs.boundaryml.com/guide/installation-language/typescript.md
- Go setup: https://docs.boundaryml.com/guide/installation-language/go.md
Language Reference
- Complete syntax: https://docs.boundaryml.com/ref/overview.md
- Type system: https://docs.boundaryml.com/ref/baml/types.md
- Classes: https://docs.boundaryml.com/ref/baml/class.md
- Enums: https://docs.boundaryml.com/ref/baml/enum.md
- Functions: https://docs.boundaryml.com/ref/baml/function.md
- Generator: https://docs.boundaryml.com/ref/baml/generator.md
LLM Providers
- OpenAI: https://docs.boundaryml.com/ref/llm-client-providers/open-ai.md
- OpenAI-compatible (Ollama, vLLM, etc.): https://docs.boundaryml.com/ref/llm-client-providers/openai-generic.md
- Fallback strategy: https://docs.boundaryml.com/ref/llm-client-strategies/fallback.md
- Round-robin strategy: https://docs.boundaryml.com/ref/llm-client-strategies/round-robin.md
Prompt Engineering
- Reducing hallucinations: https://docs.boundaryml.com/examples/prompt-engineering/reducing-hallucinations.md
- Classification patterns: https://docs.boundaryml.com/examples/prompt-engineering/classification.md
Advanced
- Streaming: https://docs.boundaryml.com/guide/baml-basics/streaming.md
- Dynamic types: https://docs.boundaryml.com/guide/baml-advanced/dynamic-types.md
Testing
- Writing tests: https://docs.boundaryml.com/ref/baml/test.md