guidance
Guidanceを使用することで、正規表現やグラマーによってLLMの出力を制御し、有効なJSON/XML/コード生成を保証できます。構造化フォーマットの強制と複数ステップのワークフロー構築が可能です。Microsoft Researchが開発した制約付き生成フレームワークにより、LLMの出力を確実にコントロールします。
description の原文を見る
Control LLM output with regex and grammars, guarantee valid JSON/XML/code generation, enforce structured formats, and build multi-step workflows with Guidance - Microsoft Research's constrained generation framework
SKILL.md 本文
Guidance: 制約付きLLM生成
このスキルをいつ使うか
以下の場合にGuidanceを使用してください:
- 正規表現または文法でLLM出力を制御したい
- 有効なJSON/XML/コード生成を保証したい
- 従来のプロンプト手法と比べてレイテンシを削減したい
- 構造化フォーマット(日付、メール、IDなど)を強制したい
- Pythonの制御フローを使用してマルチステップワークフローを構築したい
- 文法的制約を通じて無効な出力を防ぎたい
GitHubスター: 18,000+ | 提供元: Microsoft Research
インストール
# 基本インストール
pip install guidance
# 特定のバックエンドを指定
pip install guidance[transformers] # Hugging Faceモデル
pip install guidance[llama_cpp] # llama.cppモデル
クイックスタート
基本例: 構造化生成
from guidance import models, gen
# モデルを読み込み(OpenAI、Transformers、llama.cppに対応)
lm = models.OpenAI("gpt-4")
# 制約付きで生成
result = lm + "The capital of France is " + gen("capital", max_tokens=5)
print(result["capital"]) # "Paris"
Anthropic Claudeを使用
from guidance import models, gen, system, user, assistant
# Claudeを設定
lm = models.Anthropic("claude-sonnet-4-5-20250929")
# チャット形式でコンテキストマネージャを使用
with system():
lm += "You are a helpful assistant."
with user():
lm += "What is the capital of France?"
with assistant():
lm += gen(max_tokens=20)
コア概念
1. コンテキストマネージャ
GuidanceはチャットスタイルのインタラクションのためにPythonのコンテキストマネージャを使用します。
from guidance import system, user, assistant, gen
lm = models.Anthropic("claude-sonnet-4-5-20250929")
# システムメッセージ
with system():
lm += "You are a JSON generation expert."
# ユーザーメッセージ
with user():
lm += "Generate a person object with name and age."
# アシスタント応答
with assistant():
lm += gen("response", max_tokens=100)
print(lm["response"])
メリット:
- 自然なチャットフロー
- 明確なロール分離
- 読みやすく保守しやすい
2. 制約付き生成
Guidanceは、正規表現または文法を使用して、出力が指定されたパターンと一致することを確保します。
正規表現制約
from guidance import models, gen
lm = models.Anthropic("claude-sonnet-4-5-20250929")
# 有効なメール形式に制約
lm += "Email: " + gen("email", regex=r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}")
# 日付形式に制約(YYYY-MM-DD)
lm += "Date: " + gen("date", regex=r"\d{4}-\d{2}-\d{2}")
# 電話番号に制約
lm += "Phone: " + gen("phone", regex=r"\d{3}-\d{3}-\d{4}")
print(lm["email"]) # 有効なメール形式が保証される
print(lm["date"]) # YYYY-MM-DD形式が保証される
仕組み:
- 正規表現はトークンレベルで文法に変換される
- 生成中に無効なトークンがフィルタリングされる
- モデルはマッチングする出力のみを生成できる
選択制約
from guidance import models, gen, select
lm = models.Anthropic("claude-sonnet-4-5-20250929")
# 特定の選択肢に制約
lm += "Sentiment: " + select(["positive", "negative", "neutral"], name="sentiment")
# 複数選択肢の選択
lm += "Best answer: " + select(
["A) Paris", "B) London", "C) Berlin", "D) Madrid"],
name="answer"
)
print(lm["sentiment"]) # 以下のいずれか: positive, negative, neutral
print(lm["answer"]) # 以下のいずれか: A, B, C, D
3. トークンヒーリング
Guidanceはプロンプトと生成の間のトークン境界を自動的に「修復」します。
問題: トークン化により不自然な境界が生じます。
# トークンヒーリングなし
prompt = "The capital of France is "
# 最後のトークン: " is "
# 最初に生成されるトークンは " Par"(先頭にスペース)かもしれません
# 結果: "The capital of France is Paris"(スペースが2つ!)
ソリューション: Guidanceは1トークン戻って再生成します。
from guidance import models, gen
lm = models.Anthropic("claude-sonnet-4-5-20250929")
# トークンヒーリングはデフォルトで有効
lm += "The capital of France is " + gen("capital", max_tokens=5)
# 結果: "The capital of France is Paris"(スペースが正しい)
メリット:
- 自然なテキスト境界
- 不自然なスペースの問題なし
- より良いモデルパフォーマンス(自然なトークンシーケンスを認識)
4. 文法ベースの生成
文脈自由文法を使用して複雑な構造を定義します。
from guidance import models, gen
lm = models.Anthropic("claude-sonnet-4-5-20250929")
# JSON文法(簡略版)
json_grammar = """
{
"name": <gen name regex="[A-Za-z ]+" max_tokens=20>,
"age": <gen age regex="[0-9]+" max_tokens=3>,
"email": <gen email regex="[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}" max_tokens=50>
}
"""
# 有効なJSONを生成
lm += gen("person", grammar=json_grammar)
print(lm["person"]) # 有効なJSON構造が保証される
ユースケース:
- 複雑な構造化出力
- ネストされたデータ構造
- プログラミング言語の構文
- ドメイン固有言語
5. Guidance関数
@guidanceデコレータで再利用可能な生成パターンを作成します。
from guidance import guidance, gen, models
@guidance
def generate_person(lm):
"""名前と年齢を持つ人を生成します."""
lm += "Name: " + gen("name", max_tokens=20, stop="\n")
lm += "\nAge: " + gen("age", regex=r"[0-9]+", max_tokens=3)
return lm
# 関数を使用
lm = models.Anthropic("claude-sonnet-4-5-20250929")
lm = generate_person(lm)
print(lm["name"])
print(lm["age"])
ステートフル関数:
@guidance(stateless=False)
def react_agent(lm, question, tools, max_rounds=5):
"""ツール使用を伴うReActエージェント."""
lm += f"Question: {question}\n\n"
for i in range(max_rounds):
# 思考
lm += f"Thought {i+1}: " + gen("thought", stop="\n")
# 動作
lm += "\nAction: " + select(list(tools.keys()), name="action")
# ツール実行
tool_result = tools[lm["action"]]()
lm += f"\nObservation: {tool_result}\n\n"
# 完了確認
lm += "Done? " + select(["Yes", "No"], name="done")
if lm["done"] == "Yes":
break
# 最終的な回答
lm += "\nFinal Answer: " + gen("answer", max_tokens=100)
return lm
バックエンド設定
Anthropic Claude
from guidance import models
lm = models.Anthropic(
model="claude-sonnet-4-5-20250929",
api_key="your-api-key" # または ANTHROPIC_API_KEY 環境変数を設定
)
OpenAI
lm = models.OpenAI(
model="gpt-4o-mini",
api_key="your-api-key" # または OPENAI_API_KEY 環境変数を設定
)
ローカルモデル(Transformers)
from guidance.models import Transformers
lm = Transformers(
"microsoft/Phi-4-mini-instruct",
device="cuda" # または "cpu"
)
ローカルモデル(llama.cpp)
from guidance.models import LlamaCpp
lm = LlamaCpp(
model_path="/path/to/model.gguf",
n_ctx=4096,
n_gpu_layers=35
)
一般的なパターン
パターン1: JSON生成
from guidance import models, gen, system, user, assistant
lm = models.Anthropic("claude-sonnet-4-5-20250929")
with system():
lm += "You generate valid JSON."
with user():
lm += "Generate a user profile with name, age, and email."
with assistant():
lm += """{
"name": """ + gen("name", regex=r'"[A-Za-z ]+"', max_tokens=30) + """,
"age": """ + gen("age", regex=r"[0-9]+", max_tokens=3) + """,
"email": """ + gen("email", regex=r'"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"', max_tokens=50) + """
}"""
print(lm) # 有効なJSONが保証される
パターン2: 分類
from guidance import models, gen, select
lm = models.Anthropic("claude-sonnet-4-5-20250929")
text = "This product is amazing! I love it."
lm += f"Text: {text}\n"
lm += "Sentiment: " + select(["positive", "negative", "neutral"], name="sentiment")
lm += "\nConfidence: " + gen("confidence", regex=r"[0-9]+", max_tokens=3) + "%"
print(f"Sentiment: {lm['sentiment']}")
print(f"Confidence: {lm['confidence']}%")
パターン3: マルチステップ推論
from guidance import models, gen, guidance
@guidance
def chain_of_thought(lm, question):
"""段階的な推論を伴う回答を生成します."""
lm += f"Question: {question}\n\n"
# 複数の推論ステップを生成
for i in range(3):
lm += f"Step {i+1}: " + gen(f"step_{i+1}", stop="\n", max_tokens=100) + "\n"
# 最終的な回答
lm += "\nTherefore, the answer is: " + gen("answer", max_tokens=50)
return lm
lm = models.Anthropic("claude-sonnet-4-5-20250929")
lm = chain_of_thought(lm, "What is 15% of 200?")
print(lm["answer"])
パターン4: ReActエージェント
from guidance import models, gen, select, guidance
@guidance(stateless=False)
def react_agent(lm, question):
"""ツール使用を伴うReActエージェント."""
tools = {
"calculator": lambda expr: eval(expr),
"search": lambda query: f"Search results for: {query}",
}
lm += f"Question: {question}\n\n"
for round in range(5):
# 思考
lm += f"Thought: " + gen("thought", stop="\n") + "\n"
# 動作選択
lm += "Action: " + select(["calculator", "search", "answer"], name="action")
if lm["action"] == "answer":
lm += "\nFinal Answer: " + gen("answer", max_tokens=100)
break
# 動作入力
lm += "\nAction Input: " + gen("action_input", stop="\n") + "\n"
# ツール実行
if lm["action"] in tools:
result = tools[lm["action"]](lm["action_input"])
lm += f"Observation: {result}\n\n"
return lm
lm = models.Anthropic("claude-sonnet-4-5-20250929")
lm = react_agent(lm, "What is 25 * 4 + 10?")
print(lm["answer"])
パターン5: データ抽出
from guidance import models, gen, guidance
@guidance
def extract_entities(lm, text):
"""テキストから構造化エンティティを抽出します."""
lm += f"Text: {text}\n\n"
# 人物を抽出
lm += "Person: " + gen("person", stop="\n", max_tokens=30) + "\n"
# 組織を抽出
lm += "Organization: " + gen("organization", stop="\n", max_tokens=30) + "\n"
# 日付を抽出
lm += "Date: " + gen("date", regex=r"\d{4}-\d{2}-\d{2}", max_tokens=10) + "\n"
# 場所を抽出
lm += "Location: " + gen("location", stop="\n", max_tokens=30) + "\n"
return lm
text = "Tim Cook announced at Apple Park on 2024-09-15 in Cupertino."
lm = models.Anthropic("claude-sonnet-4-5-20250929")
lm = extract_entities(lm, text)
print(f"Person: {lm['person']}")
print(f"Organization: {lm['organization']}")
print(f"Date: {lm['date']}")
print(f"Location: {lm['location']}")
ベストプラクティス
1. フォーマット検証に正規表現を使用する
# ✅ 良い: 正規表現は有効なフォーマットを保証
lm += "Email: " + gen("email", regex=r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}")
# ❌ 悪い: 自由生成では無効なメールが生成される可能性がある
lm += "Email: " + gen("email", max_tokens=50)
2. 固定カテゴリにselect()を使用する
# ✅ 良い: 有効なカテゴリが保証される
lm += "Status: " + select(["pending", "approved", "rejected"], name="status")
# ❌ 悪い: タイプミスや無効な値が生成される可能性がある
lm += "Status: " + gen("status", max_tokens=20)
3. トークンヒーリングを活用する
# トークンヒーリングはデフォルトで有効
# 特別なアクションは不要 - 自然に連結するだけ
lm += "The capital is " + gen("capital") # 自動修復
4. ストップシーケンスを使用する
# ✅ 良い: 改行で停止(1行出力用)
lm += "Name: " + gen("name", stop="\n")
# ❌ 悪い: 複数行が生成される可能性がある
lm += "Name: " + gen("name", max_tokens=50)
5. 再利用可能な関数を作成する
# ✅ 良い: 再利用可能なパターン
@guidance
def generate_person(lm):
lm += "Name: " + gen("name", stop="\n")
lm += "\nAge: " + gen("age", regex=r"[0-9]+")
return lm
# 複数回使用
lm = generate_person(lm)
lm += "\n\n"
lm = generate_person(lm)
6. 制約のバランスを取る
# ✅ 良い: 適切な制約
lm += gen("name", regex=r"[A-Za-z ]+", max_tokens=30)
# ❌ 厳しすぎる: 失敗するか非常に遅い可能性がある
lm += gen("name", regex=r"^(John|Jane)$", max_tokens=10)
代替手段との比較
| 機能 | Guidance | Instructor | Outlines | LMQL |
|---|---|---|---|---|
| 正規表現制約 | ✅ はい | ❌ いいえ | ✅ はい | ✅ はい |
| 文法サポート | ✅ CFG | ❌ いいえ | ✅ CFG | ✅ CFG |
| Pydantic検証 | ❌ いいえ | ✅ はい | ✅ はい | ❌ いいえ |
| トークンヒーリング | ✅ はい | ❌ いいえ | ✅ はい | ❌ いいえ |
| ローカルモデル | ✅ はい | ⚠️ 限定的 | ✅ はい | ✅ はい |
| APIモデル | ✅ はい | ✅ はい | ⚠️ 限定的 | ✅ はい |
| Pythonシンタックス | ✅ はい | ✅ はい | ✅ はい | ❌ SQLのような |
| 学習曲線 | 低 | 低 | 中 | 高 |
Guidanceを選ぶべき場合:
- 正規表現/文法制約が必要
- トークンヒーリングが必要
- 制御フローを使用して複雑なワークフローを構築している
- ローカルモデルを使用している(Transformers、llama.cpp)
- Pythonシンタックスを好む
代替手段を選ぶべき場合:
- Instructor: Pydantic検証と自動リトライが必要
- Outlines: JSONスキーマ検証が必要
- LMQL: 宣言的クエリシンタックスを好む
パフォーマンス特性
レイテンシ削減:
- 制約付き出力では従来のプロンプト手法より30〜50%高速
- トークンヒーリングは不必要な再生成を削減
- 文法制約は無効なトークン生成を防止
メモリ使用量:
- 制約なし生成と比べて最小限のオーバーヘッド
- 文法コンパイルは最初の使用後にキャッシュされる
- 推論時のトークンフィルタリングが効率的
トークン効率:
- 無効な出力でトークンが浪費されない
- リトライループが不要
- 有効な出力への直接パス
リソース
- ドキュメント: https://guidance.readthedocs.io
- GitHub: https://github.com/guidance-ai/guidance (18k以上のスター)
- ノートブック: https://github.com/guidance-ai/guidance/tree/main/notebooks
- Discord: コミュニティサポートあり
関連項目
references/constraints.md- 包括的な正規表現と文法パターンreferences/backends.md- バックエンド固有の設定references/examples.md- 本番環境対応例
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- AlexiosBluffMara
- ライセンス
- MIT
- 最終更新
- 2026/5/12
Source: https://github.com/AlexiosBluffMara/mercury / ライセンス: MIT