3 ポイント 投稿者 GN⁺ 2025-05-28 | 1件のコメント | WhatsAppで共有
  • LLM 0.26 は、CLI と Python ライブラリで OpenAI、Anthropic、Gemini、Ollama のローカルモデルに、Python 関数で作ったツールを接続できるようにした大規模リリース
  • ツールはプラグインとしてインストールして --tool/-T name_of_tool で呼び出せるほか、--functions一時的な Python 関数 をコマンドラインから直接渡して使うことも可能
  • 組み込みツール llm_versionllm_time に加え、simpleeval、QuickJS、SQLite、Datasette のプラグインが提供され、モデルは失敗した呼び出しのあとにスキーマ照会や別の式で 再試行 できる
  • Python API の新しい model.chain() はツール呼び出し要求を検出して実行し、その結果を再びモデルへ渡し、同期関数と asyncio ツールの両方をサポート
  • 複数ベンダーのツール利用・関数呼び出し方式が収束してきたことで実装が可能になり、次の課題はプラグイン拡張、より多くのモデルプラグイン対応、Model Context Protocol クライアント対応

LLM 0.26 のツール実行サポート

  • LLM 0.26 は、プロジェクト開始以来最大の機能として ツールサポート を追加
  • LLM CLIPython ライブラリ で、OpenAI、Anthropic、Gemini、Ollama のローカルモデルに Python 関数 として表現できるツールへのアクセス権を与えられる
  • 新しい ツールプラグイン をインストールすると、現在使っているモデルに新機能を追加できる
  • 中核となる使い方は 4 つ
    • プラグインツールをインストールし、--tool/-T name_of_tool で読み込む
    • --functions オプションで Python 関数コード をコマンドラインに直接渡す
    • Python API でも tools=[locals] のような形でツールを渡せる
    • ツールは非同期・同期の両コンテキストで動作する

CLI でツールを実行する

  • 最新の LLM は uv tool install llm でインストールでき、既存のインストールは uv tool upgrade llm でアップグレードできる
  • OpenAI の利用例では、llm keys set openai で API キーを設定したあと、次のように実行する
llm --tool llm_version "What version?" --td
  • llm_version は LLM に含まれるシンプルなデモツールで、--tool llm_version はそのツールをモデルに公開する
  • --tool は複数回指定でき、短縮オプション -T も使える
  • --td--tools-debug の略で、ツール呼び出しと応答情報 を出力して内部動作を確認できる
  • デフォルトモデルは通常 gpt-4o-mini だが、例では llm models default gpt-4.1-minigpt-4.1-mini をデフォルトに変更している
  • -m オプションで別のモデルを指定でき、o4-mini と組み込みの llm_time ツールを一緒に実行する例もある
llm --tool llm_time "What time is it?" --td -m o4-mini
  • llm_time ツールの応答には utc_timeutc_time_isolocal_timezonelocal_timetimezone_offsetis_dst などのフィールドが含まれる

複数モデルとプラグインでの動作

  • ツールをサポートするモデルプラグインでも、同じコマンドパターンを使える
  • Anthropic Claude Sonnet 4 の例では次の流れを使う
    • llm install llm-anthropic -U
    • llm keys set anthropic
    • llm --tool llm_version "What version?" --td -m claude-4-sonnet
  • Google Gemini 2.5 Flash の例では次の流れを使う
    • llm install llm-gemini -U
    • llm keys set gemini
    • llm --tool llm_version "What version?" --td -m gemini-2.5-flash-preview-05-20
  • Ollama で動かす qwen3:4b でもシンプルなツールを実行できる
    • qwen3:4b は 2.6GB サイズの小型モデル
    • ollama pull qwen3:4b
    • llm install 'llm-ollama>=0.11a0'
    • llm --tool llm_version "What version?" --td -m qwen3:4b

数学、JavaScript、SQLite、Datasette のツールプラグイン

  • LLM が苦手な大きな数の掛け算のような作業は、ツール呼び出しで補える
  • llm-tools-simpleeval は、Daniel Fairhead の simpleeval ライブラリを公開する
    • simpleeval は “Simple Safe Sandboxed Extensible Expression Evaluator for Python” ライブラリ
    • シンプルな Python 式を実行するための十分に堅牢なサンドボックスを提供する
  • 計算例は次のように実行する
llm install llm-tools-simpleeval
llm -T simple_eval 'Calculate 1234 * 4346 / 32414 and square root it' --td
  • 実行例では、モデルはまず 1234 * 4346 / 32414 を計算して 165.45208860368976 を得て、sqrt(...) が定義されていないため失敗したあと、** 0.5 に変えて 12.862818066181678 を得ている
  • 公開されているツールプラグインは 4 つ
    • llm-tools-simpleeval: 数学のような単純な式をサポート
    • llm-tools-quickjs: サンドボックス化された QuickJS JavaScript インタープリタへのアクセスを提供し、呼び出し間で環境が維持されるため変数や関数を再利用できる
    • llm-tools-sqlite: ローカル SQLite データベースへの読み取り専用 SQL クエリアクセスを提供
    • llm-tools-datasette: リモートの Datasette インスタンスで SQL クエリを実行

Datasette ツールボックスとエラー後の再試行

  • Datasette プラグインは、内部に複数のツールを持つ ツールボックス の形で動作する
    • ツールボックスはコンストラクタで構成できるプラグイン
  • 使用例は次のとおり
llm install llm-tools-datasette
llm -T 'Datasette("https://datasette.io/content";)' --td "What has the most stars?"
  • Datasette("https://datasette.io/content";) は、プラグインで使う Datasette インスタンスの URL を渡している
  • この例は、Datasette の Web サイトを動かしている content database を対象にしている
  • モデルは 3 回の呼び出しを行う
    • 最初は SELECT name, stars FROM repos ORDER BY stars DESC LIMIT 1 を推測したが、stars カラムが存在せず失敗した
    • エラーを受け取ったあと、Datasette_schema() ツールでデータベーススキーマを照会した
    • スキーマをもとに正しいクエリを組み立てて実行した
  • 最終応答によると、スター数が最も多いリポジトリは datasette で、10,020 stars を持っている

--functions で一時ツールを作る

  • --functions オプションは、プラグインより構造化の弱い 一時ツール の使い方を提供する
  • Python コードブロックをコマンドラインに直接渡すと、その中で定義した関数がモデルの使えるツールになる
  • ブログ検索ツールの例では、httpx で検索ページを呼び出し、HTML をそのままモデルに返す
llm --functions '
import httpx

def search_blog(q):
    "Search Simon Willison blog"
    return httpx.get("https://simonwillison.net/search/";, params={"q": q}).content
' --td 'Three features of sqlite-utils' -s 'use Simon search'
  • 実装は検索ページの HTML をそのまま返す方式だが、実際に動作する
  • GPT-4.1 系列は 100万トークン を処理できるため、荒い HTML でも扱えるとみなしている
  • モデルが自分で答えず、提供された検索ツールを使うようにするには、システムプロンプトに use Simon search を追加する必要がある
  • より良い検索ツールには、さらに詳細な指示と検索結果の関連スニペットが必要になる
  • 例の結果では、sqlite-utils の機能として CLI と Python ライブラリの統合、alter=True によるカラム自動追加、プラグインサポートが挙げられている

Python API のツールサポート

  • LLM は CLI ツールであると同時に Python ライブラリでもあり、0.26 では Python API にも ツールサポート が追加された
  • 例では、"strawberry" の中にある r の数を、関数ツールで数える問題を解いている
import llm

def count_char_in_text(char: str, text: str) -> int:
    "How many times does char appear in text?"
    return text.count(char)

model = llm.get_model("gpt-4.1-mini")
chain_response = model.chain(
    "Rs in strawberry?",
    tools=[count_char_in_text],
    after_call=print
)
for chunk in chain_response:
    print(chunk, end="", flush=True)
  • after_call=print は、先ほどの --td オプションのように ツール呼び出しを確認 する方法
  • 新しい model.chain() メソッドは model.prompt() に似ているが、返されたツール呼び出し要求を検出して実行し、その結果とともに再度モデルを呼び出す
  • model.chain() は最終回答を返す前に複数の応答を実行できる
  • chain_response を反復処理すると、複数の応答にまたがって返されるトークンをストリーミング出力できる
  • 例の結果では、count_char_in_text ツールが char='r'text='strawberry' で呼び出され、結果 3 をもとに strawberry には r が 3 つあると答える
  • Python ライブラリは asyncio もサポートしており、ツールは async def 関数にもできる
  • モデルが複数の非同期ツールを一度に要求した場合、ライブラリは asyncio.gather() で同時実行する
  • ツールボックスもサポートされており、tools=[Datasette("https://datasette.io/content";)]chain() に渡すと、CLI の --tool 'Datasette(...)' と同じ効果になる

実装の背景とツール利用パターン

  • ツール利用パターンは、2022 年 10 月に最初に公開された ReAcT paper を見て以来追ってきた方式
  • 基本パターンはシンプル
    • モデルに、利用可能なツールがあることを知らせる
    • モデルが JSON、XML、tool_name(arguments) のような特殊構文でツール動作を要求して停止する
    • コードがその出力をパースして要求されたツールを実行する
    • 実行結果を含めた新しいプロンプトをモデルへ送る
  • この方式は現在ほぼ すべてのモデル で動作する
  • 多くのモデルはツール利用のために別途学習されており、Berkeley Function-Calling Leaderboard のようなリーダーボードもある
  • OpenAI、Anthropic、Google、Mistral、Meta は API にツール利用または関数呼び出し機能を含めている
  • ローカルモデル側でも、Ollama は昨年 ツールサポート を追加し、llama.cpp サーバーにも含まれている
  • LLM は 2025 年 2 月に スキーマサポート を先にリリースしており、これをツールサポートへ向けた段階として活用した
  • 複数モデルで動く抽象化レイヤーの設計が課題だったが、ベンダー各社の方式が明確に収束してきた今、実装可能になった
  • PyCon US の Building software on top of Large Language Models ワークショップがアルファ実装の仕上げのきっかけとなり、チュートリアルの tools section も提供されている

エージェントと今後の計画

  • “agents” という用語には依然として抵抗感があるが、LLM の世界では tools in a loop へと収束しており、LLM 0.26 もその形に近い
  • エージェントを作りたいなら、LLM 0.26 は良い出発点になり得る
  • 次の作業は LLM tools v2 milestone に 13 件の issue として整理されている
    • 主に、ツール実行ログ表示の改善と、今回のリリースを妨げなかった小さな issue
    • 追加の issue は tools label にある
  • プラグインの可能性が最も期待される領域
    • llm-plugin-tools の cookiecutter テンプレートを自分でも使っている
    • 関連チュートリアルを作る予定
  • より多くのモデルプラグインにツールサポートを追加する作業も残っている
  • Model Context Protocol サポートも計画に含まれている
    • MCP は、モデルがツールにアクセスするための標準方式として急速に台頭している
    • 2 週間前までは主要ベンダー API で直接サポートされていなかったが、直近 8 日の間に OpenAI、Anthropic、Mistral に追加された
    • LLM が MCP クライアントとして動作し、人々が作成する MCP サーバーを LLM の追加ツールソースとして簡単に使えるようにすることが目標

1件のコメント

 
GN⁺ 2025-05-28
Hacker Newsの意見
  • このツールのために書いたストリーミングMarkdownレンダラーも見る価値があります: https://github.com/day50-dev/Streamdown
    背景は https://github.com/simonw/llm/issues/12 にあり、Simonのllmの上に作ったtmuxツールを含む https://github.com/day50-dev/llmehelp も毎日使っています

    • llmの上に作ったものをもう1つ忘れていましたが、ZSHプラグインとしてzleを使い、キー1つで英語をシェルコマンドに変換してくれます: https://github.com/day50-dev/Zummoner
      今日も$ git find out if abcdefg is a descendent of hijklmnopのような形で使いましたし、別コメントのfor i in $(seq 1 6); do printf "%${i}sh${i}\n\n-----\n" | tr " " "#"; done | pv -bqL 30も、元はもっと自然言語に近い入力でした
      ctrl-x xを押すとバッファがOpenRouterに送られ、1秒もかからず正しい構文に置き換わります
    • ライブラリは本当に良さそうで、プラグインがツールのコンテンツ表示方法を引き受けられるフックがあるとよさそうです
      Issueを立ててあります: https://github.com/simonw/llm/issues/1112
      設計案をいくつか入れましたが、まだ完全にしっくり来ているわけではないのでフィードバックが欲しいです
    • ストリーミングLLM出力をすばやく表示するために、いくつかの言語でストリーミングMarkdownレンダラーを自作したことがあるので、自分だけではないと分かってうれしいです
    • 興味深いので確認するつもりです。今はllmbatシンタックスハイライトを一緒に使っています
  • これは自分の足を撃つリスクを大きく高めます
    ドキュメント https://llm.datasette.io/en/stable/tools.html はプロンプトインジェクションに警告していますが、よりありそうなシナリオは自分で被害を出すことだと思います
    たとえば証券口座へのアクセス権をツールに与えて取引を自動化すると、プロンプトインジェクションがなくても、ボットが愚かな取引をしないよう止める仕組みがありません

    • その通りで、本当にリスクは大きくなります
      LLMにツールを接続し始めると、特にそのツール呼び出しが認証済みで、代わりに行動までできる場合、物事が悪い方向に進む経路が多すぎます
      MCP界隈はいまこれを超高速で経験していて、昨日のGitHub MCPの件もその例です: https://news.ycombinator.com/item?id=44097390
      ドキュメントには大きな警告を入れましたし、初期のツールプラグインも被害を与えられないものだけを出すよう慎重にしました。なのでQuickJSサンドボックスとSQLiteプラグインも読み取り専用です
    • llmを証券口座に接続するなら、愚かなのはボットではなく、それを接続した人です
    • サンドボックス化が鍵になるでしょう
      macOSではそれほど難しくありませんが、今は使いやすい良いツールが不足しています。Claude Codeはユーザー体験を改善するためにSeatbeltを少しずつ使い始めています
    • 自分の足を撃つ議論は要点を外していると思います
      自分に害を与える可能性はあり、おそらくそうなることもありますが、可能性を評価しないこともリスクです。一般の人は自分の足を撃つ可能性を過小評価し、技術者は新しい可能性を学ばないリスクを過小評価しがちです
      1年前にもLLMに自分のノートPCでローカルコマンドを実行させていましたし、ある程度危険だとは見ていますが、有害なことは起きませんでした。find out where I am and what weather it is going to beのようなプロンプトでrm -rf /を実行する可能性はあるとしても、非常に低いです
      ただし、LLMがどう判断するか分からないまま株式取引を任せるのは、私の基準では危険すぎます
    • どんなツールでも誤用される可能性があります
  • Warpターミナルのターミナルベースのエージェントというアイデアは気に入っていますが、Cursorのように「良いプロンプトとLLM呼び出しはこちらで面倒を見るので、信じてお金を払ってください」というモデルはあまり好きではありません
    そこでシェルの腕不足を補ってくれるシンプルなCLIベースのターミナルエージェントを探していて、ターミナルツールとllmの組み合わせは軽量な解決策として良さそうに見えます
    大きな自爆リスクはよく分かっているので、他のエージェントのようにツール呼び出しごとに権限を尋ねる方式が可能なのか気になります。たとえば「llmrm -rf ./*を呼び出そうとしています。確認するにはYを押してください」のような形なら、LLMがターミナルで暴走するのをある程度防げます

    • ターミナルがなぜあちこちで広告を出し、複数のプロジェクトをスポンサーしているのか不思議でしたが、完全無料ではないことが今分かりました
    • それは--full-autoを渡していないときのcodex CLIのデフォルト動作なのでは、という気がします
  • llmを使っている人なら Gtk-llm-chat も見る価値があります
    llmコマンドラインツールとデスクトップに統合され、トレイアイコンと見栄えの良いチャットウィンドウを提供します
    最近3.0.0をリリースし、3大デスクトップOS向けのパッケージを提供しています

    • 通常のチャット以外には、どんな用途で使っているのか気になります
  • このリリースは、既存クライアントの制約なしにLLMの潜在能力を開く中核的な構成要素だと思います
    0.26アルファが出た後、MCPサーバーとやり取りするプラグインを作ろうとしましたが、かなり難しかったです。今のところ接続してツールを動的に取得して使うところまではできましたが、まだパラメーターの受け渡しはできていません

    • 今朝、MCPで簡単なプラグインデモを作れるか試してみましたが、かなり手強かったです
      公式のmcp Pythonライブラリは、asyncioを実行し、サーバーに接続してから利用可能なツールを検査するという流れを強く前提にしています
  • llm CLIのタブ補完用zsh/omzプラグインを、ほぼバイブコーディングで保守しているのですが、新機能のリリース速度が速くて追いつくのが大変です
    それでも llm -f README.md -f llm.plugin.zsh -f completions/_llm -f [https://simonwillison.net/2025/May/27/llm-tools/](<https://simonwillison.net/2025/May/27/llm-tools/>;) "implement tab completions for the new tool plugins feature" くらいで90%は解決します
    リポジトリは https://github.com/eliyastein/llm-zsh-plugin で、できるだけ多くのオプションやフラグを入れようとして少し雑然としているので、フィードバックがほしいです

    • これがSFではなく、単に今のコーディングのやり方だというのは少し驚きです
      未来の世代は、私たちがアセンブリプログラマーを見て「どうやって仕事をしていたんだろう?」と思うように、私たちがどうやって仕事を成し遂げていたのか不思議に思うでしょう
  • Claude Codeがツールをどう認識して使っているのか気になっていました
    LLMにツールとその使い方を教えることはでき、実行ラッパーがそれを管理することもできますが、Claude Codeはラッパーが使うツール呼び出しAPIについてかなり具体的な期待を持っていて、事後学習やファインチューニングで強く補強されているのだろうと見ていました
    なので、Claudeを使うサードパーティ製のツール呼び出しフレームワークは、Anthropic自身のフレームワークより不利なのか気になります
    それとは別に、GitHub MCPの「攻撃」記事で述べられていたように、LLMは認証情報の全権限まで使うようだまされる可能性があります。GitHubのように細かな認証情報があり、私たちの会社もそうなので、ラッパーがLLMに渡す細分化された認証情報を生成するプロトコルを誰かが試してくれるとよいと思います
    アプリケーションにはより強い認証情報を与え、下位のLLMには特定のタスクやリソースについて「権限要求」を行うよう学習させる構成を想像しています。ユーザーが許可すれば、フレームワークがサービスからスコープを限定した認証情報を取得し、ツール呼び出しに使わせるという方式です

    • その認証情報の方式は、今でもLLMのツール対応で可能です
      「追加の認証情報を要求する」ツールを公開し、呼び出されたらユーザーに尋ねる、かなり凝ったツール構成が必要です
      ツールは認証情報を保持し、実際のトークンをLLMに絶対渡してはならず、代わりに creds1 のような記号を渡して、以後のリクエストでは creds1 で呼び出すよう伝えることができます
  • この論文を見たことがあるか気になります。見た目どおり重要なら、この指標はすべてのシステムカードに入るべきではないかと思います
    128Kトークン以上のコンテキストをサポートすると主張する人気LLM 12個を評価したところ、短いコンテキストではうまくいくものの、コンテキスト長が伸びるほど性能が大きく低下したそうです。32Kでは10モデルが短い長さのベースラインの50%を下回り、例外的に性能のよいGPT-4oも99.3%から69.7%に下がったそうです
    https://arxiv.org/abs/2502.05167

    • この論文は見ていませんでしたが、本当に興味深いです
      最近のneedle in a haystackテストではGemini 2.5 ProとGemini 2.5 Flashが他のモデルを大きく引き離していると認識しているので、それらのモデルでも試してみるとよさそうです
  • 先週、0.26a0で独自データに基づく顧客向けチャットボットのデモを作りました
    自分で書く必要があった主要な要素は、システムプロンプト、外部データを取得するツール、計算を実行するツールで、このライブラリのおかげで中核機能は非常に簡単に作れました
    デモで労力の大半は配管作業に費やしました。会話が維持され、接続問題でブラウザを再読み込みしても自然に更新され、新しいチャットセッションを開始できる、見栄えのよいWeb UIを作る作業です
    after_call=print は知りませんでしたが、ブログ記事を読んで知ることができてよかったです

  • Simonのツールを毎日使っています
    パイプとローカルのOllama・リモートモデル間の簡単な切り替えのおかげで、とても作業しやすいです