mcpField
G
guidance

guidance

github.com/orchestra-researchエージェントワークフロー14.1k956 回インストール19 週間前に更新
リポジトリ

guidance について

Guidanceは、LLM生成ワークフローを構築する開発者向けのPythonライブラリです。正規表現、選択肢、文法で出力を制約し、再利用可能な関数や制御フローも提供します。

主な機能

  1. 01正規表現と文法による制約
  2. 02選択肢の制約
  3. 03トークンヒーリング
  4. 04Python形式のチャット用コンテキストマネージャー
  5. 05再利用可能な生成関数

活用シーン

  1. 01有効なJSONやXMLの生成
  2. 02日付、メール、ID形式の制約
  3. 03複数段階の生成ワークフロー構築
  4. 04テキストの固定カテゴリ分類

インストール

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

$npx skills add https://github.com/orchestra-research/ai-research-skills --skill guidance

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

同梱ファイル

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

references/
backends.md
constraints.md
examples.md

詳細

Guidance: 制約付き LLM 生成

このスキルを使うタイミング

Guidance は次のような場合に使用します:

  • 正規表現や文法で LLM の出力構文を制御 したいとき
  • 有効な JSON/XML/コード の生成を保証したいとき
  • 従来のプロンプト手法と比べて レイテンシーを削減 したいとき
  • 日付、メールアドレス、ID などの 構造化されたフォーマットを強制 したいとき
  • Python らしい制御フローで 複数ステップのワークフロー を構築したいとき
  • 文法的な制約によって 無効な出力を防止 したいとき

GitHub スター数: 18,000+ | 開発元: Microsoft Research

インストール

# Base installation
pip install guidance

# With specific backends
pip install guidance[transformers]  # Hugging Face models
pip install guidance[llama_cpp]     # llama.cpp models

クイックスタート

基本例: 構造化生成
from guidance import models, gen

# Load model (supports OpenAI, Transformers, llama.cpp)
lm = models.OpenAI("gpt-4")

# Generate with constraints
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

# Configure Claude
lm = models.Anthropic("claude-sonnet-4-5-20250929")

# Use context managers for chat format
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")

# System message
with system():
    lm += "You are a JSON generation expert."

# User message
with user():
    lm += "Generate a person object with name and age."

# Assistant response
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")

# Constrain to valid email format
lm += "Email: " + gen("email", regex=r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}")

# Constrain to date format (YYYY-MM-DD)
lm += "Date: " + gen("date", regex=r"\d{4}-\d{2}-\d{2}")

# Constrain to phone number
lm += "Phone: " + gen("phone", regex=r"\d{3}-\d{3}-\d{4}")

print(lm["email"])  # Guaranteed valid email
print(lm["date"])   # Guaranteed YYYY-MM-DD format

仕組み:

  • 正規表現はトークンレベルの文法に変換されます
  • 生成中に無効なトークンがフィルタリングされます
  • モデルは一致する出力しか生成できません
選択肢の制約
from guidance import models, gen, select

lm = models.Anthropic("claude-sonnet-4-5-20250929")

# Constrain to specific choices
lm += "Sentiment: " + select(["positive", "negative", "neutral"], name="sentiment")

# Multiple-choice selection
lm += "Best answer: " + select(
    ["A) Paris", "B) London", "C) Berlin", "D) Madrid"],
    name="answer"
)

print(lm["sentiment"])  # One of: positive, negative, neutral
print(lm["answer"])     # One of: A, B, C, or D
3. トークンヒーリング

Guidance は、プロンプトと生成部分の間のトークン境界を自動的に「ヒール(修復)」します。

問題: トークン化によって不自然な境界が生じます。

# Without token healing
prompt = "The capital of France is "
# Last token: " is "
# First generated token might be " Par" (with leading space)
# Result: "The capital of France is  Paris" (double space!)

解決策: Guidance は 1 トークン分戻って再生成します。

from guidance import models, gen

lm = models.Anthropic("claude-sonnet-4-5-20250929")

# Token healing enabled by default
lm += "The capital of France is " + gen("capital", max_tokens=5)
# Result: "The capital of France is Paris" (correct spacing)

利点:

  • 自然なテキスト境界
  • 不自然な空白の問題がない
  • モデルの性能向上(自然なトークン列を参照できる)
4. 文法ベースの生成

文脈自由文法を使って複雑な構造を定義します。

from guidance import models, gen

lm = models.Anthropic("claude-sonnet-4-5-20250929")

# JSON grammar (simplified)
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>
}
"""

# Generate valid JSON
lm += gen("person", grammar=json_grammar)

print(lm["person"])  # Guaranteed valid JSON structure

ユースケース:

  • 複雑な構造化出力
  • 入れ子になったデータ構造
  • プログラミング言語の構文
  • ドメイン固有言語
5. Guidance 関数

@guidance デコレーターを使って、再利用可能な生成パターンを作成します。

from guidance import guidance, gen, models

@guidance
def generate_person(lm):
    """Generate a person with name and age."""
    lm += "Name: " + gen("name", max_tokens=20, stop="\n")
    lm += "\nAge: " + gen("age", regex=r"[0-9]+", max_tokens=3)
    return lm

# Use the function
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 agent with tool use."""
    lm += f"Question: {question}\n\n"

    for i in range(max_rounds):
        # Thought
        lm += f"Thought {i+1}: " + gen("thought", stop="\n")

        # Action
        lm += "\nAction: " + select(list(tools.keys()), name="action")

        # Execute tool
        tool_result = tools[lm["action"]]()
        lm += f"\nObservation: {tool_result}\n\n"

        # Check if done
        lm += "Done? " + select(["Yes", "No"], name="done")
        if lm["done"] == "Yes":
            break

    # Final answer
    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"  # Or set ANTHROPIC_API_KEY env var
)
OpenAI
lm = models.OpenAI(
    model="gpt-4o-mini",
    api_key="your-api-key"  # Or set OPENAI_API_KEY env var
)
ローカルモデル(Transformers)
from guidance.models import Transformers

lm = Transformers(
    "microsoft/Phi-4-mini-instruct",
    device="cuda"  # Or "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)  # Valid JSON guaranteed
パターン 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):
    """Generate answer with step-by-step reasoning."""
    lm += f"Question: {question}\n\n"

    # Generate multiple reasoning steps
    for i in range(3):
        lm += f"Step {i+1}: " + gen(f"step_{i+1}", stop="\n", max_tokens=100) + "\n"

    # Final answer
    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 agent with tool use."""
    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):
        # Thought
        lm += f"Thought: " + gen("thought", stop="\n") + "\n"

        # Action selection
        lm += "Action: " + select(["calculator", "search", "answer"], name="action")

        if lm["action"] == "answer":
            lm += "\nFinal Answer: " + gen("answer", max_tokens=100)
            break

        # Action input
        lm += "\nAction Input: " + gen("action_input", stop="\n") + "\n"

        # Execute tool
        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):
    """Extract structured entities from text."""
    lm += f"Text: {text}\n\n"

    # Extract person
    lm += "Person: " + gen("person", stop="\n", max_tokens=30) + "\n"

    # Extract organization
    lm += "Organization: " + gen("organization", stop="\n", max_tokens=30) + "\n"

    # Extract date
    lm += "Date: " + gen("date", regex=r"\d{4}-\d{2}-\d{2}", max_tokens=10) + "\n"

    # Extract location
    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. 形式の検証には正規表現を使う
# ✅ Good: Regex ensures valid format
lm += "Email: " + gen("email", regex=r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}")

# ❌ Bad: Free generation may produce invalid emails
lm += "Email: " + gen("email", max_tokens=50)
2. 固定カテゴリには select() を使う
# ✅ Good: Guaranteed valid category
lm += "Status: " + select(["pending", "approved", "rejected"], name="status")

# ❌ Bad: May generate typos or invalid values
lm += "Status: " + gen("status", max_tokens=20)
3. トークンヒーリングを活用する
# Token healing is enabled by default
# No special action needed - just concatenate naturally
lm += "The capital is " + gen("capital")  # Automatic healing
4. stop シーケンスを使う
# ✅ Good: Stop at newline for single-line outputs
lm += "Name: " + gen("name", stop="\n")

# ❌ Bad: May generate multiple lines
lm += "Name: " + gen("name", max_tokens=50)
5. 再利用可能な関数を作成する
# ✅ Good: Reusable pattern
@guidance
def generate_person(lm):
    lm += "Name: " + gen("name", stop="\n")
    lm += "\nAge: " + gen("age", regex=r"[0-9]+")
    return lm

# Use multiple times
lm = generate_person(lm)
lm += "\n\n"
lm = generate_person(lm)
6. 制約のバランスを取る
# ✅ Good: Reasonable constraints
lm += gen("name", regex=r"[A-Za-z ]+", max_tokens=30)

# ❌ Too strict: May fail or be very slow
lm += gen("name", regex=r"^(John|Jane)$", max_tokens=10)

代替手段との比較

機能GuidanceInstructorOutlinesLMQL
正規表現の制約✅ あり❌ なし✅ あり✅ あり
文法のサポート✅ CFG❌ なし✅ CFG✅ CFG
Pydantic による検証❌ なし✅ あり✅ あり❌ なし
トークンヒーリング✅ あり❌ なし✅ あり❌ なし
ローカルモデル✅ あり⚠️ 限定的✅ あり✅ あり
API モデル✅ あり✅ あり⚠️ 限定的✅ あり
Python らしい構文✅ あり✅ あり✅ あり❌ SQL 風
学習コスト低低中高

Guidance を選ぶべき場合:

  • 正規表現や文法による制約が必要な場合
  • トークンヒーリングを使いたい場合
  • 制御フローを含む複雑なワークフローを構築する場合
  • ローカルモデル(Transformers、llama.cpp)を使用する場合
  • Python らしい構文を好む場合

代替手段を選ぶべき場合:

  • Instructor: 自動リトライを伴う Pydantic による検証が必要な場合
  • Outlines: JSON スキーマによる検証が必要な場合
  • LMQL: 宣言的なクエリ構文を好む場合

パフォーマンス特性

レイテンシの削減:

  • 制約付き出力の場合、従来のプロンプティングより30〜50%高速
  • トークンヒーリングにより、不要な再生成が減少
  • 文法制約により、無効なトークンの生成を防止

メモリ使用量:

  • 制約なしの生成と比べてオーバーヘッドは最小限
  • 文法のコンパイル結果は初回使用後にキャッシュ
  • 推論時に効率的なトークンフィルタリングを実行

トークン効率:

  • 無効な出力によるトークンの無駄を防止
  • リトライループが不要
  • 有効な出力への直接的な経路

リソース

関連項目

  • references/constraints.md - 包括的な正規表現と文法パターン
  • references/backends.md - バックエンド固有の設定
  • references/examples.md - 本番環境で使える例

コメント