コンテンツにスキップ

コンテキスト管理

コンテキストという用語は多義的です。重要になるコンテキストには主に 2 つのクラスがあります。

  1. コードでローカルに利用できるコンテキスト: ツール関数の実行時、on_handoff のようなコールバック、ライフサイクルフックなどで必要になるデータや依存関係です。
  2. LLM に提供されるコンテキスト: 応答を生成する際に LLM が参照できるデータです。

ローカルコンテキスト

これは RunContextWrapper クラスと、その中の context プロパティで表現されます。仕組みは次のとおりです。

  1. 任意の Python オブジェクトを作成します。よくあるパターンとしては dataclass や Pydantic オブジェクトを使います。
  2. そのオブジェクトを各種実行メソッドに渡します(例: Runner.run(..., **context=whatever**))。
  3. すべてのツール呼び出しやライフサイクルフックなどには、ラッパーオブジェクト RunContextWrapper[T] が渡されます。ここで T はコンテキストオブジェクトの型を表し、wrapper.context からアクセスできます。

最も 重要 な注意点: 特定のエージェント実行において、すべてのエージェント、ツール関数、ライフサイクル等は同じ種類(type)のコンテキストを使用しなければなりません。

コンテキストは次のような用途に使えます。

  • 実行のための文脈データ(例: ユーザー名 / uid や、ユーザーに関するその他の情報)
  • 依存関係(例: ロガーオブジェクト、データフェッチャーなど)
  • ヘルパー関数

注意

コンテキストオブジェクトは LLM に送信される わけではありません。これはあくまでローカルなオブジェクトであり、読み書きやメソッド呼び出しが可能です。

import asyncio
from dataclasses import dataclass

from agents import Agent, RunContextWrapper, Runner, function_tool

@dataclass
class UserInfo:  # (1)!
    name: str
    uid: int

@function_tool
async def fetch_user_age(wrapper: RunContextWrapper[UserInfo]) -> str:  # (2)!
    """Fetch the age of the user. Call this function to get user's age information."""
    return f"The user {wrapper.context.name} is 47 years old"

async def main():
    user_info = UserInfo(name="John", uid=123)

    agent = Agent[UserInfo](  # (3)!
        name="Assistant",
        tools=[fetch_user_age],
    )

    result = await Runner.run(  # (4)!
        starting_agent=agent,
        input="What is the age of the user?",
        context=user_info,
    )

    print(result.final_output)  # (5)!
    # The user John is 47 years old.

if __name__ == "__main__":
    asyncio.run(main())
  1. これがコンテキストオブジェクトです。ここでは dataclass を使っていますが、任意の型を使用できます。
  2. これはツールです。RunContextWrapper[UserInfo] を受け取り、ツールの実装はコンテキストから読み取ります。
  3. 型チェッカーがエラーを検出できるよう、エージェントにジェネリックの UserInfo を付与します(例えば、異なるコンテキスト型を受け取るツールを渡そうとした場合など)。
  4. run 関数にコンテキストを渡します。
  5. エージェントはツールを正しく呼び出し、年齢を取得します。

エージェント / LLM コンテキスト

LLM が呼び出されると、LLM が参照できるデータは会話履歴のものに 限られます。つまり、LLM に新しいデータを利用可能にしたい場合は、その履歴で参照できる形で提供する必要があります。いくつか方法があります。

  1. エージェントの instructions に追加します。これは「システムプロンプト」または「開発者メッセージ」とも呼ばれます。システムプロンプトは静的な文字列でも、コンテキストを受け取って文字列を出力する動的な関数でも構いません。常に有用な情報(例: ユーザー名や現在の日付)に適した一般的な戦術です。
  2. Runner.run 関数を呼ぶ際の input に追加します。これは instructions の戦術に似ていますが、chain of command 上でより下位のメッセージとして扱えます。
  3. 関数ツールを通じて公開します。これはオンデマンドのコンテキストに有用です。LLM が必要なときにデータを要求し、ツールを呼び出してそのデータを取得できます。
  4. リトリーバル(retrieval)や Web 検索を使用します。これらは、ファイルやデータベース(リトリーバル)または Web(Web 検索)から関連データを取得できる特別なツールです。関連する文脈データに基づいて応答を「グラウンディング」するのに役立ちます。