Simon WillisonがリリースしたLLM 0.32a0を読んで、自分が書いてきたコードのいくつかが「惜しい設計だったな」と感じた。
今まで会話履歴を扱うとき、LLMライブラリの`conversation()`オブジェクトを使うしかなかった。これが微妙で、「既存の会話ログを途中から流し込む」という処理が書きにくかった。
OpenAIのchat completions APIはもともと`messages`配列でやり取りする設計だ。それをLLMライブラリのconversationに変換するラッパーを自前で書いてた人、結構いると思う。自分もそのひとりだった。
0.32a0ではこれが解消されて、こう書けるようになった。
`llm.user()`と`llm.assistant()`というビルダー関数が新しく追加されていて、これを使って配列を組み立てるだけでいい。既存の`prompt=`オプションも引き続き使えるから、古いコードが壊れるわけじゃない。後方互換性を保ちつつ新しいインターフェースを足してる設計は素直に好き。
もうひとつ気になったのがストリーミングの変更だ。今のモデルってテキストだけ返すわけじゃない。Claudeでいえば、推論(reasoning)の出力があって、テキストがあって、そのあとツール呼び出しのJSONが来る、という流れがある。
今まではストリームを`for chunk in response`でひとつの文字列の塊として受け取ってた。でもこれだと「今ここで流れてるのはreasoningなのかテキストなのかツール呼び出しなのか」が区別できない。
0.32a0では、ストリームを型付きのパーツとして受け取れるようになっている。これはUIを作るときに地味に効いてくる。reasoning部分をグレーアウトで表示したい、ツール呼び出し中はスピナーを出したい、そういう細かい制御がやっと素直に書ける。
自分が今作ってる個人開発のチャットUIは、reasoning部分を折りたたむ実装を無理やり文字列パースで書いてた。これが一番「あー、ライブラリ側で型として持ってほしかったやつだ」と思った瞬間だった。
0.32a0はまだアルファ版だ。本番には使えないにしても、設計の方向性を把握しておくだけで次のコードの書き方が変わる。
とくに`response.reply("How about Hungary?")`みたいなシンプルなチェーンができるようになったのは、スクリプトレベルでの用途に効く。会話管理のためにSQLiteをわざわざ使いたくない場面ってあるし、その逃げ道が用意された感じがする。
自分は来週、個人開発のチャットUIでストリーミングパーツの受け取り方を0.32a0の設計に寄せて書き直してみるつもりだ。まだalphaだからライブラリ自体は使わず、構造だけ真似る形で。
messagesに直接渡せるようになった何が嬉しいか
今まで会話履歴を扱うとき、LLMライブラリの`conversation()`オブジェクトを使うしかなかった。これが微妙で、「既存の会話ログを途中から流し込む」という処理が書きにくかった。
OpenAIのchat completions APIはもともと`messages`配列でやり取りする設計だ。それをLLMライブラリのconversationに変換するラッパーを自前で書いてた人、結構いると思う。自分もそのひとりだった。
0.32a0ではこれが解消されて、こう書けるようになった。
import llm
from llm import user, assistant
model = llm.get_model("gpt-5.5")
response = model.prompt(
messages=[
user("Capital of France?"),
assistant("Paris"),
user("Germany?"),
]
)
print(response.text())`llm.user()`と`llm.assistant()`というビルダー関数が新しく追加されていて、これを使って配列を組み立てるだけでいい。既存の`prompt=`オプションも引き続き使えるから、古いコードが壊れるわけじゃない。後方互換性を保ちつつ新しいインターフェースを足してる設計は素直に好き。
「ストリームをパーツとして受け取る」発想の転換
もうひとつ気になったのがストリーミングの変更だ。今のモデルってテキストだけ返すわけじゃない。Claudeでいえば、推論(reasoning)の出力があって、テキストがあって、そのあとツール呼び出しのJSONが来る、という流れがある。
今まではストリームを`for chunk in response`でひとつの文字列の塊として受け取ってた。でもこれだと「今ここで流れてるのはreasoningなのかテキストなのかツール呼び出しなのか」が区別できない。
0.32a0では、ストリームを型付きのパーツとして受け取れるようになっている。これはUIを作るときに地味に効いてくる。reasoning部分をグレーアウトで表示したい、ツール呼び出し中はスピナーを出したい、そういう細かい制御がやっと素直に書ける。
自分が今作ってる個人開発のチャットUIは、reasoning部分を折りたたむ実装を無理やり文字列パースで書いてた。これが一番「あー、ライブラリ側で型として持ってほしかったやつだ」と思った瞬間だった。
alphaだけど試す価値はあると思う
0.32a0はまだアルファ版だ。本番には使えないにしても、設計の方向性を把握しておくだけで次のコードの書き方が変わる。
とくに`response.reply("How about Hungary?")`みたいなシンプルなチェーンができるようになったのは、スクリプトレベルでの用途に効く。会話管理のためにSQLiteをわざわざ使いたくない場面ってあるし、その逃げ道が用意された感じがする。
自分は来週、個人開発のチャットUIでストリーミングパーツの受け取り方を0.32a0の設計に寄せて書き直してみるつもりだ。まだalphaだからライブラリ自体は使わず、構造だけ真似る形で。