アウトラインズを用いた構造化言語モデル生成
LLM の構造化出力生成における確実性を高めるオープンソースライブラリ「outlines」の導入と、その推論レベルでの動作原理が解説されている。
キーポイント
構造化出力生成の課題解決
従来のプロンプトエンジニアリングや確率に依存する手法では難しかった JSON などの構造化データ生成において、outlines ライブラリが決定論的な certainty を導入し、ハルシネーションを防止する。
推論レベルでのトークンマスク機能
生成後にテキストを修正するのではなく、推論段階で文法的に不正なトークンを事前にマスキング(除外)することで、出力フォーマット違反を物理的に不可能にする仕組みを持つ。
多肢選択分類の実装例
カスタマーサポートの感情分析など、限られた選択肢から正確に 1 つを選ぶタスクにおいて、generate.choice() 関数を用いて事前定義されたリテラルやクラスを選択させる実装が可能である。
Transformers との統合
Hugging Face の AutoModel や Tokenizer を活用してモデルをロードし、outlines オブジェクトでラップすることで、既存の LLM パイプラインに容易に組み込んで使用できる。
出力制約の強制メカニズム
outlines ライブラリは、モデルとトークナイザーをラップして内部で有限状態機械(FSM)を構築し、指定された Python タイプや Pydantic モデルに基づいて生成結果を厳密に制限します。
構造化データの生成対応
Literal 型による単純な選択肢の制約に加え、Pydantic モデルを使用して JSON オブジェクトのような複雑な構造を持つデータ生成も可能になります。
構造化されたJSON生成の信頼性向上
Outlinesライブラリを使用することで、LLMが生成するJSONに不要な文字や構文エラーが含まれるリスクを排除し、パーサーが即座に処理可能な純粋なJSONストリングスを保証できます。
影響分析・編集コメントを表示
影響分析
この記事は、LLM を実務で活用する際最大のボトルネックであった「構造化データの生成不安定さ」に対する解決策を提示しており、開発現場における信頼性の向上に直結する重要な技術動向です。決定論的な制御を導入することで、LLM の出力をより予測可能かつ安全なものにし、自動化パイプラインの構築を加速させる可能性があります。
編集コメント
LLM の出力制御において「確率」から「決定論」へパラダイムシフトを起こすツールとして注目すべき技術です。実務でのデータ抽出や API 連携における信頼性向上に即座に貢献できるため、開発者にとっての必須知識と言えます。

はじめに
通常、LLM(大規模言語モデル)に対して JSON オブジェクトのような整った構造化データを求める際、巧妙なプロンプトの工夫と「ちょっとした運」の両方が必要になります。そうでないと、期待通りの完璧な構造で出力を得るのは難しいものです。
しかし、その常識を覆す新しいオープンソースライブラリoutlinesが登場しました。このライブラリは、LLM が構造化データ生成において陥りがちなハルシネーション(幻覚)といった典型的な問題を解決するために設計されています。具体的には、出力生成プロセスに「決定論的な確実性」をもたらすことで、より信頼性の高い構造化データの生成を可能にします。
この記事では、outlinesがどのようなことができるのかを実践的な Python の例とともに解説していきます。
使用事例 1:感情分析における多肢選択分類
必ず JSON 形式で返してください。translation フィールドのみ。他のフィールドは一切追加しないこと — 余計なフィールドを書こうとして本文がトークン上限で打ち切られる事故を防ぐため:
構造化言語モデル生成における Outlines の活用(その2/5)
最初のユースケースに深く入る前に、みなさんは「Outlines はどうやって機能し、構造化されたモデル出力の正しさをどのように保証するのか」と疑問に思っているかもしれません。推論段階では、生成されたテキストを後から修正しようとするのではなく、生成プロセスそのものの中で「文法的に不正なトークン」をマスク(除外)します。これにより、特定の出力形式で求められるルールを破ることが事実上不可能になります。
まず、顧客サポートチケットの分析パイプラインを構築する例を見てみましょう。ここでは、限られた承認済みリストから正確に1 つだけの選択肢を選出する必要があります。これは分類問題とほぼ同じであり、generate.choice() 関数がこれを実現します。この関数は、対象となるモデルに対して事前に定義されたリテラルやクラスの中から 1 つを選択させるように強制します。
その前に、事前学習済み大規模言語モデル(LLM)を読み込むために、Outlines を transformers ライブラリと共にインストールしておきましょう:
pip install outlines[transformers]
以下のコードでは、outlines.from_transformers() を使用して、Hugging Face の自動クラスを介して事前学習済みモデルとそのトークナイザーを読み込んでいます。さらに素晴らしいのは、これら両方が Outlines オブジェクトにラップされており、後でモデルに対して「具体的に何を取得すべきか」を指示できるようになっている点です。
推論段階では、レビューの分類を依頼するユーザープロンプトだけでなく、モデルが従うべき出力制約を含む Literal オブジェクトも同時に渡します:
import outlines
from transformers import AutoTokenizer, AutoModelForCausalLM
from typing import Literal
1. 標準的な Transformer ベースのモデルを用いたバックエンドの読み込み
まず、microsoft/Phi-3-mini-4k-instruct というモデル名を指定します。
model_name = "microsoft/Phi-3-mini-4k-instruct"ここからは outlines の from_transformers() 関数を使って、モデルとトークナイザーを読み込みます。これにより、後続の処理で型制約を効率的に適用できるようになります。
# outlines を使用して、transformers からモデルを読み込む
model = outlines.from_transformers(
AutoModelForCausalLM.from_pretrained(model_name),
AutoTokenizer.from_pretrained(model_name)
)2. モデルを直接呼び出し、許可された文字列を型制約として渡す
次に、このモデルに対して具体的なタスクを実行します。ここでは、顧客レビューの感情分析を行い、結果が「Positive(肯定的)」「Negative(否定的)」「Neutral(中立)」のいずれかになるよう制限をかけます。
sentiment = model(
"Classify the sentiment of this customer review: 'I've been waiting two weeks for my delivery and it's still missing.'",
Literal["Positive", "Negative", "Neutral"]
)
print(sentiment)出力結果は以下のようになります。
Negative注意: ここで定義した Literal は Python の組み込み型モジュールの一部であり、outlines 独自の機能ではありません。しかし、このライブラリをそのまま使うことで、モデルの制御が保証されます。具体的には、モデルとトークナイザーが一つのオブジェクトにラップされ、標準的な Python の型制約を強制します。その内部では有限状態機械(FSM)が構築されており、出力可能な選択肢を指定されたものだけに制限する仕組みになっています。
# 使用例 2: JSON オブジェクトの生成
この例では、まず Pydantic を用いて、架空のキャラクター(名前、説明、年齢を持つ)を表す JSON オブジェクトの構造を定義します。その後、先ほどラップした outlines モデルを使用し、生成される出力が指定された JSON 構造に厳密に従うように制御します。
from pydantic import BaseModel必ず JSON 形式で返してください。translation フィールドのみ。他のフィールドは一切追加しないこと — 余計なフィールドを書こうとして本文がトークン上限で打ち切られる事故を防ぐため:
{"translation": "リライト全文"}
1. 目的の JSON 構造に対応する Pydantic モデルを定義する
class Character(BaseModel):
name: str
description: str
age: int
必ず JSON 形式で返してください。translation フィールドのみ。他のフィールドは一切追加しないこと — 余計なフィールドを書こうとして本文がトークン上限で打ち切られる事故を防ぐため:
2. Pydantic モデルに準拠した JSON 出力を生成するために outlines でラップされたモデルを使用する
json_output = model(
"架空のキャラクター『Anya』を記述する JSON オブジェクトを生成してください。",
Character,
max_new_tokens=200
)
必ず JSON 形式で返してください。出力されるのは translation フィールドのみです。他のフィールドは一切追加しないでください。余計なフィールドを追加しようとして本文がトークン上限に達し、出力が途中で打ち切られてしまう事故を防ぐためです。
出力結果を確認します。
必ず JSON 形式で返してください。translation フィールドのみを含めてください。他のフィールドは一切追加しないでください。余計なフィールドを記述しようとして本文がトークン上限に達し、途中で切れてしまう事故を防ぐためです。
リライト全文
3 つ目の例も JSON 関連ですが、前回のケースとは文脈が少し異なります。データベース更新のために厳密な定義された JSON ペイロードが必要となる API を構築していると想像してください。
標準的な大規模言語モデル(LLM)にこの出力を求めると、JSON パーサーをクラッシュさせる可能性のある、邪魔な末尾のコンマなどが付随する結果になりがちです。
Outlines を使うと、Pydantic ベースのカスタムクラスオブジェクトを用いて、再度 JSON ペイロードのスキーマを定義できます。
from pydantic import BaseModel
from typing import Literal
import json
class ServerHealth(BaseModel):
service_name: str
uptime_seconds: int
status: Literal["OK", "DEGRADED", "DOWN"]
1. Outlines は、必ず有効な JSON 文字列として生成されることを保証します
raw_json_string = model(
"メインの認証データベースの現在のステータスを報告してください。",
ServerHealth,
max_new_tokens=50
)
print(type(raw_json_string)) # 出力結果:
2. 整形して表示
parsed_json = json.loads(raw_json_string)
print(json.dumps(parsed_json, indent=2))
Output:
{
"service_name": "auth_db_status",
"uptime_seconds": 1623456789,
"status": "OK"
}
おわりに
LLM は人間との会話で「らしく」聞こえるために、構文を破ったり、事実と異なる情報を生成(ハルシネーション)したりするように訓練されています。そのため、クリーンな JSON オブジェクトのような信頼性の高い構造化データを出力させるのは、一筋縄ではいかないと感じることもあるでしょう。
Outlines は、この課題に対する解決策として登場したオープンソースライブラリです。LLM の出力生成プロセスに「決定論的な確実性」をもたらすことで、より高品質で信頼性の高い構造化データの生成を可能にします。本記事では、この興味深いツールを活用する初心者向けの、シンプルながら有用な 3 つのユースケースをご紹介しました。
Iván Palomares Carrascosa は、AI、機械学習、ディープラーニング、LLM の分野でリーダーシップを発揮し、ライターやスピーカー、アドバイザーとしても活躍しています。彼は、実社会において AI を効果的に活用する方法を他者に指導・支援する活動を行っています。
原文を表示

**
# Introduction
Usually, when asking an LLM — abbreviation for "Large Language Model" — for a neat, structured output like JSON objects, for instance, a mix of careful prompt crafting with a "pinch" of luck is required. Otherwise, it might be tricky to get the model to obtain the perfectly structured output you are expecting. Or so it was, until a novel open-source library came onto the scene: outlines**.
This library is designed to prevent typical issues experienced by LLMs in these specific output-oriented use cases, such as hallucinations. More precisely, it introduces a degree of deterministic certainty into the output generation process.
Let's uncover what outlines allows us to do through this illustrative article, in which we will show some practical examples in Python!
# Use Case 1: Multiple-Choice Classification for Sentiment Analysis
**
Before fully diving into the first use case, you might be wondering. How does outlines work and how does it guarantee correctness in structured model outputs? At the inference level, it masks out "syntactically illegal" tokens during generation instead of attempting to fix poor text once generated. This makes it virtually impossible to break the rules underlying the specific output format sought.
Let's see a first example in which we are building an analysis pipeline for customer support tickets, and we want *exactly* one option from a limited, approved list of possible options. This is pretty much like a classification problem, and generate.choice() is the function that helps us mimic it, by forcing the model at hand to choose one of the predefined literals or classes.
But first, let's install it alongside the transformers to load pre-trained LLMs:
pip install outlines[transformers]The following code uses outlines.from_transformers() to load a pre-trained model aided by Hugging Face's auto classes for a model and its associated tokenizer. But the icing on the cake is: they are both wrapped in an outlines object that will later help tell the model what exactly to obtain. At the inference stage, we pass not only the user prompt asking to classify a review, but also a Literal object that contains the output constraints the model should limit to:
import outlines
from transformers import AutoTokenizer, AutoModelForCausalLM
from typing import Literal
# 1. Loading the backend using standard Transformer-based models
model_name = "microsoft/Phi-3-mini-4k-instruct"
# We use outlines to load the model with its from_transformers() function
model = outlines.from_transformers(
AutoModelForCausalLM.from_pretrained(model_name),
AutoTokenizer.from_pretrained(model_name)
)
# 2. Calling the model directly, passing our approved strings as type constraints
sentiment = model(
"Classify the sentiment of this customer review: 'I've been waiting two weeks for my delivery and it's still missing.'",
Literal["Positive", "Negative", "Neutral"]
)
print(sentiment)Output:
NegativeA word of warning here: although the literal we defined is part of Python's built-in typing module, rather than outlines, our out-of-the-box library still assumes model control here: both the model and tokenizer are wrapped into an object that enforces standard Python types, building a finite state machine under the hood that limits the output to the options provided only.
# Use Case 2: JSON Object Generation
This example first defines a Pydantic object that defines the desired structure for a JSON object describing a fictional character with a name, description, and age. It then uses our previously wrapped outlines model, passing the character object to ensure the output generated strictly follows this structure for the JSON object requested:
from pydantic import BaseModel
# 1. Define a Pydantic model for the desired JSON structure
class Character(BaseModel):
name: str
description: str
age: int
# 2. Using the outlines-wrapped model to generate a JSON output conforming to the Pydantic model
json_output = model(
"Generate a JSON object describing a fictional character named 'Anya'.",
Character,
max_new_tokens=200
)
print(json_output)Output:
{ "name": "Anya", "description": "Anya is a young, adventurous woman with a passion for exploring new places and meeting new people. She has long, curly hair and bright green eyes that sparkle with curiosity. Anya is always eager to learn and loves to share her knowledge with others. She is kind-hearted and always willing to lend a helping hand to those in need. Anya's favorite hobbies include hiking, reading, and playing the guitar. She is a free spirit who values freedom and independence above all else." ,"age": 25 }# Use Case 3: Pure JSON Generation for REST APIs
This third example, also JSON-related, is similar to the previous one but in a slightly different context. Imagine you are building an API backed requiring a well-defined JSON payload for updating a database. Asking a standard LLM to get this output will more often than not yield to annoying, trailing characters like commas that are likely to crash a JSON parser.
With outlines, we define our JSON payload schema once again with a Pydantic-based custom class object.
from pydantic import BaseModel
from typing import Literal
import json
class ServerHealth(BaseModel):
service_name: str
uptime_seconds: int
status: Literal["OK", "DEGRADED", "DOWN"]
# 1. Outlines should produce a raw string guaranteed to be valid JSON
raw_json_string = model(
"Report the current status of the main Auth database.",
ServerHealth,
max_new_tokens=50
)
print(type(raw_json_string)) # This will just print:
# 2. Pretty-printing
parsed_json = json.loads(raw_json_string)
print(json.dumps(parsed_json, indent=2))Output:
{
"service_name": "auth_db_status",
"uptime_seconds": 1623456789,
"status": "OK"
}# Closing Remarks
Since LLMs are trained to be chat-lovers capable of breaking syntax or hallucinating to "sound like humans" in their conversations with us, getting them to produce reliable, structured outputs like clean JSON objects can feel like a bit of a pain. Outlines a new, open-source library that introduces deterministic certainty into LLMs' output generation process for better, more reliable generation of structured outputs. This article showed three simple yet useful use cases for beginners with this interesting tool.
Iván Palomares Carrascosa** is a leader, writer, speaker, and adviser in AI, machine learning, deep learning & LLMs. He trains and guides others in harnessing AI in the real world.
関連記事
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み