LLM 0.32a0 は大規模な後方互換リファクタリング

Simon Willison's Blog / 2026/4/30

📰 ニュースDeveloper Stack & InfrastructureTools & Practical UsageModels & Research

要点

  • Simon Willison は、LLM にアクセスするための自身の Python ライブラリおよび CLI のアルファアップデートとして LLM 0.32a0 を公開し、大規模な後方互換リファクタリングであることを打ち出しました。
  • ライブラリの従来のプロンプト/レスポンスの抽象化は、多様な入出力タイプにまたがる現代的な LLM 機能(マルチモーダルの添付、構造化 JSON スキーマ、ツール呼び出しなど)にはもはや十分ではありません。
  • バージョン 0.32a0 では、コアのモデルインターフェースを変更し、入力を単一のテキストプロンプトではなくメッセージのシーケンスとして表現します。
  • また、応答は、異なるタイプのパートのストリームとして構成されるように更新され、プレーンテキスト以外にもより豊かな出力を可能にします。
  • このリリースの狙いは、最前線の LLM が提供するモデル I/O の多様化の拡大により適切に対応しつつ、可能な限り従来の利用との互換性を維持することです。
提供: Sonar — SAST + SCA を搭載し、セキュアで依存関係を理解したアジェンティック・エンジニアリングのために。 SonarQube Advanced Security

LLM 0.32a0 は、大きな後方互換性のあるリファクタリングです

2026年4月29日

先ほど LLM 0.32a0 をリリースしました。これは、私が LLM へのアクセスのために開発している LLM の Python ライブラリおよび CLI ツールのアルファ版で、かなり以前から取り組んでいた重要な変更がいくつか入っています。

以前の LLM は、プロンプトとレスポンスという形で世界をモデル化していました。モデルにテキストのプロンプトを送れば、テキストのレスポンスが返ってくる。

import llm

model = llm.get_model("gpt-5.5")
response = model.prompt("Capital of France?")
print(response.text())

これは、2023年4月にライブラリの開発を始めた当時は理にかなっていました。でも、その後いろいろと変わっています!

LLM は プラグインシステム を通じて、何千もの異なるモデルを扱うための抽象化を提供します。元々の抽象化――テキスト入力を受け取り、テキスト出力を返す――では、私が実現したいことのすべてを表現できなくなってしまいました。

時が経つにつれて、LLM 自体も成長し、画像・音声・動画の入力を扱うための attachments が追加され、次に構造化された JSON を出力するための schemas が追加され、その後 tools によりツール呼び出しを実行できるようになりました。その一方で LLM は進化を続け、推論サポートを追加したり、画像を返せるようにしたり、その他にも興味深い能力を次々と実装してきました。

LLM は、今日の最先端モデルが処理できる入力タイプと出力タイプの多様性を、より適切に扱えるように進化する必要があります。

0.32a0 アルファには 2 つの重要な変更があります。モデル入力はメッセージのシーケンスとして表現でき、モデルレスポンスは、異なる型のパーツのストリームとして構成できるようになりました。

メッセージのシーケンスとしてのプロンプト

LLM は入力をテキストとして受け取りますが、ChatGPT が双方向の会話インターフェースの価値を示して以来、最も一般的なプロンプトの与え方は、その入力を「会話のやり取りの列」として扱うことです。

最初のターンは、例えば次のようになります:

user: フランスの首都は?
assistant: 

(その後モデルは、アシスタントからの返信を埋めることになります。)

しかし、それ以降の各ターンでは、それまでの会話全体を、ある種の脚本のように最初からもう一度再生する必要があります:

user: フランスの首都は?
assistant: パリ
user: ドイツの首都は?
assistant:

主要ベンダーのほとんどの JSON API はこのパターンに従っています。以下は、他のプロバイダにも広く模倣されている OpenAI の chat completions API を使った例です:

curl https://api.openai.com/v1/chat/completions \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.5",
    "messages": [
      {
        "role": "user",
        "content": "フランスの首都は?"
      },
      {
        "role": "assistant",
        "content": "パリ"
      },
      {
        "role": "user",
        "content": "ドイツの首都は?"
      }
    ]
  }'

0.32 より前の LLM は、これらを会話としてモデル化していました:

model = llm.get_model("gpt-5.5")

conversation = model.conversation()
r1 = conversation.prompt("フランスの首都は?")
print(r1.text())
# 出力は「パリ」

r2 = conversation.prompt("ドイツの首都は?")
print(r2.text())
# 出力は「ベルリン」

これは、モデルと一から会話を構築している場合にはうまく動きましたが、最初から「以前の会話」を与える方法は提供されていませんでした。そのため、OpenAI の chat completions API をエミュレートするようなタスクは、本来あるべきよりもずっと難しくなってしまっていました。

llm の CLI ツールは、SQLite を使って会話を永続化・膨張(インフレート)するための独自の仕組みによって、この問題を回避していました。しかしそれは LLM API の安定した一部にはならず、またストレージ層として SQLite にコミットせずに Python ライブラリを使いたい場面もたくさんあるでしょう。

新しいアルファでは、いまこのサポートが入っています:

import llm
from llm import user, assistant

model = llm.get_model("gpt-5.5")

response = model.prompt(messages=[
    user("フランスの首都は?"),
    assistant("パリ"),
    user("ドイツの首都は?"),
])
print(response.text())

llm.user()llm.assistant() は、新しく追加されたビルダー関数です。これは、その messages=[] 配列の中で使うために設計されています。

以前の prompt= オプションはまだ動作しますが、裏側でそれを 1 要素だけの messages 配列にアップグレードします。

会話を構築する代わりに、応答に対してこれからは 返信 もできます:

response2 = response.reply("ハンガリーはどうでしょうか?")
print(response2) # デフォルトの __str__() は .text() を呼び出します

ストリーミング部分

アルファ版でのもう一つの主要な新しいインターフェースは、プロンプトからの結果をストリーミングで返すことです。

以前の LLM では、このようなストリーミングが可能でした:

response = model.prompt("ペリカンが自転車に乗っている SVG を生成してください")
for chunk in response:
    print(chunk, end="")

または、このような非同期バリアント:

import asyncio
import llm

model = llm.get_async_model("gpt-5.5")
response = model.prompt("ペリカンが自転車に乗っている SVG を生成してください")

async def run():
    async for chunk in response:
        print(chunk, end="", flush=True)

asyncio.run(run())

今日の多くのモデルは、コンテンツの種類が混ざった形式を返します。Claude に対してプロンプトを実行すると、まず推論出力が返り、その後テキスト、次にツール呼び出しのための JSON リクエスト、さらにテキスト…のように続くことがあります。

中には、サーバー側でツールを実行できるモデルもあります。たとえば OpenAI の code interpreter ツールや、Anthropic の web search です。つまり、モデルから返ってくる結果は、テキスト、ツール呼び出し、ツール出力、そして他の形式を組み合わせたものになり得ます。

また、マルチモーダル出力モデルも登場し始めています。そうしたモデルでは、ストリーミング応答の中に画像や、さらには音声のスニペットが混在して返されることがあります。

新しい LLM アルファ版では、これらを「型付きメッセージパート」のストリームとしてモデル化しています。Python API の利用者から見たイメージは次のようになります:

import asyncio
import llm

model = llm.get_model("gpt-5.5")
prompt = "かっこいい犬を3匹思いついて、まずあなたの動機について話して"

def describe_dog(name: str, bio: str) -> str:
    """想像上の犬の名前と伝記を記録します。"""
    return f"{name}: {bio}"

def sync_example():
    response = model.prompt(
        prompt,
        tools=[describe_dog],
    )
    for event in response.stream_events():
        if event.type == "text":
            print(event.chunk, end="", flush=True)
        elif event.type == "tool_call_name":
            print(f"
ツール呼び出し: {event.chunk}(", end="", flush=True)
        elif event.type == "tool_call_args":
            print(event.chunk, end="", flush=True)async def async_example():
    model = llm.get_async_model("gpt-5.5")
    response = model.prompt(
        prompt,
        tools=[describe_dog],
    )
    async for event in response.astream_events():
        if event.type == "text":
            print(event.chunk, end="", flush=True)
        elif event.type == "tool_call_name":
            print(f"
ツール呼び出し: {event.chunk}", end="", flush=True)
        elif event.type == "tool_call_args":
            print(event.chunk, end="", flush=True)

sync_example()
asyncio.run(async_example())

サンプル出力(最初の同期の例だけから):

私の動機: それぞれ異なる「クール」なスタイルを持つ、記憶に残る3匹の犬を作りたい――1匹は映画的に、1匹は冒険的に、そしてもう1匹は魅力的に気まぐれに。そうすれば、どれも自分自身の物語の主役になれる気がするからです。
ツール呼び出し: describe_dog({"name": "Nova Jetpaw", "bio": "小さな飛行士用ゴーグルを身につけた、洗練されたシルバーグレーのウィペット。月明かりの照らすビーチ沿いを全力疾走するのが大好き。Novaは恐れ知らずで上品、そして冗談のようにドローンを出し抜けると噂されています。ついでに言うと、ただ楽しむためにそうしてしまうとか。"}
ツール呼び出し: describe_dog({"name": "Mochi Thunderbark", "bio": "ドラマチックな黒と金のバンダナをした、ふわふわのコーギー。ロックスターのような自信を持っています。Mochiは背が低く、声が大きく、忠実で、完全にリスだけで構成された町の『セキュリティ・パトロール』を率いています。"}
ツール呼び出し: describe_dog({"name": "Atlas Snowfang", "bio": "氷のように青い目を持つ巨大な白いハスキー。バックパックにはトレイルのおやつがいっぱい。Atlasは落ち着いていてヒーロー気質で、吹雪でも、霧でも、迷いやすいキャンプの旅でも、いつでも帰り道を知っています。"}

レスポンスの最後に、要求された関数を実際に実行するために response.execute_tool_calls() を呼び出すことができますし、あるいはそれらのツールを呼び出した結果をモデルに返すために response.reply() を送ることもできます:

print(response.reply("Tell me about the dogs"))

このストリーミングでトークン種別ごとに異なる表示を行う新しい仕組みにより、CLIツールは最終レスポンスのテキストと別の色で「思考(thinking)」テキストを表示できるようになりました。思考テキストはstderrに送られるため、他のツールにパイプされる結果には影響しません。

この例は、Anthropicのモデルが推論テキストをレスポンスの一部として返すため、Claude Sonnet 4.6(llm-anthropic プラグインのストリーミングイベントのバージョンが更新されたもの)を使っています:

llm -m claude-sonnet-4.6 '3 cool dogs then describe themを考えてください' \
  -o thinking_display 1

Animated demo. Starts with ~/dev/scratch/llm-anthropic % uv run llm -m claude-sonnet-4.6 'Think about 3 cool dogs then describe them' -o thinking_display 1 - the text then streams in grey: The user wants me to think about 3 cool dogs and then describe them. Let me come up with 3 interesting, cool dogs and describe them. Then switches to regular color text for the output that describes the dogs.

新しい -R/--no-reasoning フラグを使うと、推論トークンの出力を抑制できます。驚くべきことに、このリリースでCLI向けに行われた変更は、それが唯一だったという結果になりました。

レスポンスをシリアライズ/デシリアライズするための仕組み

先ほども述べたとおり、LLMには現時点でSQLiteに会話を永続化するためのコードがかなり融通の利かない状態です。私は0.32a0で、新たな仕組みを追加しました。これにより、Python APIユーザーが自分自身で別の仕組みを実装できるようになるはずです:

serializable = response.to_dict()
# serializableはJSONスタイルの辞書
# 好きな場所に保存し、その後展開します:
response = Response.from_dict(serializable)

この戻り値として返される辞書は、実際には新しい llm/serialization.py モジュール内で定義された TypedDict です。

次は何?

いくつかのプラグインをアップグレードし、数日間ほど実際の環境で新しい設計を試すために、これをアルファとしてリリースします。アルファテストで、この全体の組み立て方における設計上の欠陥が明らかにならない限り、安定版の0.32リリースはこのアルファと非常に似たものになると見ています。

残っている大きなタスクは1つあります。新しいこの抽象によって返される、よりきめ細かな詳細をうまく取り込めるように、SQLiteのロギングシステムを再設計したいのです。

理想としては、これをグラフとしてモデル化したいです。そうすることで、OpenAIスタイルのチャット補完APIのように、同じ会話が継続的に拡張され、そして毎回のプロンプトごとに繰り返されるような状況を最もうまくサポートできるはずです。データベース内でそれらを重複して保存せずに済むようにしたいです。

それを0.32の機能として入れるべきか、0.33まで待つべきかは、まだ決めていません。

2026年4月29日 19:01に投稿 · MastodonBlueskyTwitter、またはニュースレターの購読をフォローしてください

これはLLM 0.32a0 は、主要な下位互換性を保つリファクタリングです。Simon Willisonによる投稿で、2026年4月29日に公開されました。

シリーズの一部LLMの新リリース

  1. CLIでJPEGフレームのシーケンスとしてビジョンLLMに動画を渡す(LLM 0.25も) - 2025年5月5日 午後5時38分
  2. 大規模言語モデルはLLM 0.26で、あなたのターミナル上でツールを実行できます - 2025年5月27日 午後8時35分
  3. LLM 0.27、注釈付きリリースノート:GPT-5 とツール呼び出しの改善 - 2025年8月11日 午後11時57分
  4. LLM 0.32a0 は、主要な下位互換性を保つリファクタリング - 2026年4月29日 午後7時01分
projects 526 python 1248 ai 1991 annotated-release-notes 48 generative-ai 1765 llms 1731 llm 593

前: すでに故人となったOpenAIのMicrosoft AGI条項の履歴を追う

月次ブリーフィング

$10/月でスポンサーになって、今月の最も重要なLLMの動きの厳選メールダイジェストを受け取ってください。

私にお金を払って、あなたの手間を減らしましょう!

スポンサーになって購読する