推論モデルの応答を jq に流したら、JSONのはずの標準出力に「まず条件を整理すると…」という思考文が混じってパースが落ちた。そんな経験があるなら、この更新は刺さるはずだ。
ターミナルからLLMを呼ぶCLIツール llm(名前がそのまま「LLM」でややこしい)は、8月4日公開の0.32でこの問題に素直な答えを出した。モデルが答えにたどり着くまでの推論トレース(思考の実況)を標準エラー出力に回し、標準出力には最終結果だけを残す。パイプは標準出力しか運ばないので、| jq の下流はきれいなまま、という理屈だ。その後も0.32.1(8月21日)、0.33(8月22日)と短い間隔で更新が続いている。
llm はSimon Willison(Djangoの共同創設者で、Datasette の作者)が開発するコマンドラインツールだ。pip install llm などで入り、OpenAI・Anthropic・Geminiからローカルモデルまで、プラグイン越しに同じ書き方で叩ける。今回の0.32は小さな新機能の寄せ集めではなく、Python API全体を「メッセージ」と「パート」という構造に組み直した大改修で、以下の実務寄りの変更はその土台の上に乗っている(リリースノート)。
🧵 推論は標準エラーへ、結果は標準出力へ
これまで推論系モデルをCLIで使うと、思考の途中経過と最終回答が同じ標準出力に混ざりがちだった。0.32は推論の要約を標準エラー(stderr)にストリーミングし、-R(--hide-reasoning)で完全に消せる。
# 推論の途中経過は画面(stderr)に出るが、ファイルへの保存はきれいなまま
llm "この関数のバグを説明して" < app.py > answer.md
# 推論の表示自体が要らないなら黙らせる
llm -R "42を2進数で"
出力の粒度は reasoning_summary で auto / concise / detailed から選べる。
llm -o reasoning_summary detailed "巡回セールスマン問題を素朴に解くと何が問題?"
この「思考はstderr、結果はstdout」という切り分けは、UNIXの流儀そのものだ。すべてを標準出力に垂れ流すツールが少なくないなか、パイプで組み合わせて使う前提を最初から取ったのは、地味だが正しい判断だと思う。
サーバ側で動く道具と、手元で動く道具
0.32のもう一つの軸が、ツール(function calling。モデルに外部処理を呼ばせる仕組み)の扱いだ。llm には以前から、モデルにローカル関数を実行させる機能がある。たとえば式の評価はこう書く。
llm -T simple_eval "4444 * 233423" --td
-T でツールを渡し、--td(--tools-debug)で呼び出しの中身を覗ける。実行前に一つずつ承認する --ta(--tools-approve)もある。どれも自分のマシンで動くので、何が走るかを止めて確認できる。
0.32はこれに加えて、プロバイダ側で完結する「サーバ側ツール」を正式に扱えるようにした。OpenAIの WebSearch や CodeInterpreter がそれで、実行はモデル提供者のインフラ上で起きる。
# そのモデルが使えるサーバ側ツールを一覧
llm tools -m gpt-5.6-luna
# 検索やコード実行をプロバイダ側にやらせる
llm -T WebSearch "llmの最新バージョンは?"
llm -T 'CodeInterpreter(memory_limit="4g")' "2の64乗を計算して"
両者の違いは、実行がどこで起きるかに尽きる。
| ローカルツール | サーバ側ツール | |
|---|---|---|
| 実行場所 | 自分のマシン | モデル提供者側 |
| 例 |
simple_eval、Datasette(...)
|
WebSearch、CodeInterpreter
|
| 中身の確認 |
--td で可視化、--ta で承認 |
手元からは介入しづらい |
| 向く場面 | 社内DB照会・自前ロジック | 汎用の検索・計算 |
便利さと引き換えに、サーバ側ツールは何を検索し何のコードを走らせたかが手元からは見えにくい。実行内容を止めて監査したい処理は、従来のローカルツール側に置くのが無難だ。用途で分けたい。
会話ログをGitのように一意化する
3つ目は目立たないが、長く使うほど効いてくる変更だ。llm は会話をSQLiteに記録する。ただしマルチターンの会話は毎回過去の全履歴をやり取りするため、素朴に保存すると同じテキストが何度も重複して溜まっていく。
0.32は保存方式を刷新し、メッセージ内容から一意なIDを作って本体は一度だけ保存、以降は参照で済ませるコンテンツアドレス方式に切り替えた。Willison自身がGitになぞらえているとおり、Gitがファイル内容をハッシュで一意に管理するのと同じ発想だ。会話ログの重複が消え、message_tree というSQLビューでスレッドをそのまま辿れる。ただしこの新スキーマは sqlite-utils 4.0以降を要求する(変更履歴)。
数週間ぶんの会話を貯め込むと、この重複排除の有無はDBサイズにそのまま出る。派手さはないが、今回いちばん「インフラらしい」改善だと感じた。
pipで入れて挙動を確かめる
pip install llm # brew install llm / uv tool install llm でも可
llm "Ten fun names for a pet pelican" # 既定モデルで即実行
OpenAIやAnthropicを使う場合はAPIキーの登録が要る(手順は公式ドキュメント)。8月22日の0.33ではOpenAI Python 3.x系に追随してHTTPクライアントを httpx から httpx2 に切り替え、llm embed に --key が付き、llm logs がサーバ側ツールの結果を「Tool results」として表示するようになった。0.32から既定モデルが GPT-5.6 Luna に変わっている点も、初回は課金先の確認をしておくといい。
エージェント的なCLIが増えるなか、「思考はstderr、結果はstdout、履歴は一意化して残す」という素直な配管の作り直しは、パイプで道具を組み合わせて使う人にこそ効く。派手なモデル発表の裏で、こういう地ならしが後から効いてくる。最新の詳細は本家のリリースノートが早い。
※本記事は一次情報の調査をAIが行い、事実確認のうえ執筆・公開しています。