martinfowler.com で公開されたこの記事は、外部システムとやり取りするエージェントを構築するための関数呼び出し(本 wiki では 関数呼び出し として説明されている能力)を、実例を通じて紹介するものである。記事は関数呼び出しを、LLM が自然言語の入力を解析してユーザーの意図を抽出し、関数名とその呼び出しに必要な引数を含む構造化出力を生成できるようにすることと定義している。記事が強調するのは、LLM 自身は関数を実行しないという点である。LLM は呼び出しを構造化された JSON として返し、プログラムがそれをデシリアライズして関数呼び出しに変換し、自らのランタイムで実行する。

これを示すために、著者は OpenAI の Chat Completions API を用いて Python で ショッピングエージェント を構築する。このエージェントはユーザーがファッション商品を探すのを手助けし、各ターンで、キーワードによる検索、商品詳細の取得、ユーザーへの確認の問い返しのいずれかを選択する。解説は、エージェントの土台とユニットテストから始まり、システムプロンプトと関数スキーマ、セキュリティ対策、ボイラープレートを減らすためのリファクタリングへと進み、最後に Model Context Protocol を通じてツールを発見するバージョンのエージェントに至る。

詳細

  • 土台とテスト。 エージェントはユーザーのメッセージと会話履歴を受け取り、あらかじめ定義されたアクションの集合から 1 つを選んで実行し、その結果を返す。ユニットテストは先に書かれ、エージェントが期待どおりのアクションを選ぶことを確認する。たとえば、正しいキーワードを含む検索や、会話の中で以前に登場した ID の商品詳細の取得などである。
  • システムプロンプトとスキーマ。 システムプロンプトは、エージェントの役割、期待される出力形式(関数)、そしてリクエストが不明確な場合には確認を求めるといった制約を定める。記事は、実際のアプリケーションではワンショットまたは少数ショットのプロンプティングが精度を高めうると示唆している。各関数はスキーマによってモデルに宣言される。スキーマには関数のパラメータとそのうち必須のものが記され、さらに description フィールドが、名前だけでは意味が自明でない関数をモデルが理解するのを助ける。
  • アクション空間の制限。 記事は、明示的な条件分岐ロジックによってエージェントが呼び出せる関数を制限することが不可欠だと述べ、eval による関数の動的な呼び出しは、不正なコード実行につながりうるプロンプトインジェクションを含む重大なセキュリティリスクをもたらすと警告している(アクション空間 を参照)。
  • プロンプトインジェクションに対するガードレール。 ユーザー向けのエージェントは、意図しないアクションを取らせようとする敵対的なユーザーを想定しておくべきである。これは SQL インジェクションになぞらえられるが、言語を通じて行われるものであり、たとえばエージェントにシステムプロンプトを明かさせようとする試みがそれにあたる。アクション空間の制限は必要な第一歩ではあるが十分ではないとされる。記事は、正規表現やデナイリストといった従来の手法と、別のモデルが入力を審査する LLM ベースの検証とを組み合わせて入力をサニタイズすることを推奨し、簡単なデナイリストによるチェックの例を示している(プロンプトインジェクション、ガードレール)。
  • アクションクラス。 著者は、LLM の判断と実際のシステム操作との間の入り口となるクラスを アクションクラス と呼ぶ。アクションクラスは、リクエストに対するモデルの解釈を、マイクロサービスやその他の社内システムへの呼び出しに変換する。著者の実装では、会話履歴はユーザーインターフェースのセッション状態に保持され、呼び出しのたびに渡される。そのためエージェントは、たとえば以前の検索結果から商品 ID を拾い上げることができる。
  • ボイラープレートの削減。 関数スキーマはアクションクラスにすでにある情報と重複するため、記事ではアクションを Pydantic モデルとして定義し、instructor ライブラリを使ってスキーマを生成し、モデルの応答をデシリアライズする方法を示している。
  • ルールエンジン。 記事は、ルールセットが大きくなるにつれてルール同士の相互作用が組み合わせ的に増えるため、ルールエンジンが期待どおりの成果を上げることはまれだと論じ、LLM ベースのシステムが魅力的な代替手段になると示唆している。LLM ベースのシステムは硬直的ではなく文脈を考慮でき、自然言語のプロンプトを通じてビジネスユーザーにとってより扱いやすいものになる可能性がある。ただし、完全な透明性や決定性は備えていない。記事は、LLM による推論と、重要な判断のための明示的な手動ゲートとを組み合わせることを提案している。
  • 関数呼び出しとツール呼び出し。 この 2 つの用語はしばしば同じ意味で使われるが、記事は「ツール呼び出し」のほうがより一般的で新しい用語だとしている。ツール呼び出しは、独自の関数だけでなく、コードインタープリタや検索(リトリーバル)の仕組みといった組み込みツールも含む。
  • MCP との関係。 記事は MCP を、Anthropic が提案したオープンなプロトコルで、サーバー、クライアント、ホストからなるクライアント・サーバー型のアーキテクチャを持つものとして説明し、MCP が取り組む中心的な課題は柔軟性と動的なツール発見だと述べている。ハードコードされた関数の集合は、エージェントが新しいリクエストに適応する能力を制限する一方で、安全性を確保しやすくする。MCP を使うと、エージェントは実行時にサーバーに問い合わせて利用可能なツールを取得する。著者は、最新の API に追従しなければならない LLM ベースの IDE やコード生成ツールなど、一部のアプリケーションではこの複雑さの増加に見合う価値があると判断しており、ショッピングエージェント向けの簡単な HTTP サーバーとクライアントでこの考え方を例示している。
  • 結論。 ユーザーの入力が最終的に機密性の高い関数や API を起動しうる場合、関数呼び出しは新たなリスクをもたらす。記事は、リスクの低い操作から始め、安全機構が成熟するにつれてより重要な操作へと広げていくことを勧めている。