コンテキスト管理
コンテキストは多義的な用語です。考慮すべき主なコンテキストは 2 つあります。
- コードからローカルに利用できるコンテキスト: これは、ツール関数の実行時、
on_handoffのようなコールバック、ライフサイクルフックなどで必要になる可能性のあるデータや依存関係です。 - LLM に利用できるコンテキスト: これは、応答生成時に LLM が参照できるデータです。
ローカルコンテキスト
これは RunContextWrapper クラスと、その中の context プロパティによって表現されます。仕組みは次のとおりです。
- 任意の Python オブジェクトを作成します。一般的なパターンとしては、dataclass や Pydantic オブジェクトを使います。
- そのオブジェクトを各種の実行メソッドに渡します(例:
Runner.run(..., **context=whatever**))。 - すべてのツール呼び出しやライフサイクルフックなどには、
RunContextWrapper[T]というラッパーオブジェクトが渡されます。ここでTはコンテキストオブジェクトの型で、wrapper.contextからアクセスできます。
最も重要な点は次のとおりです。あるエージェント実行において、すべてのエージェント、ツール関数、ライフサイクルなどは同じコンテキストの「型」を使用する必要があります。
コンテキストは次のような用途に使えます。
- 実行のためのコンテキストデータ(例: ユーザー名/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())
- これはコンテキストオブジェクトです。ここでは dataclass を使っていますが、任意の型を使えます。
- これはツールです。
RunContextWrapper[UserInfo]を受け取ることがわかります。ツールの実装はコンテキストから読み取ります。 - 型チェッカーが誤りを検出できるように、エージェントをジェネリックの
UserInfoでマークします(たとえば、別のコンテキスト型を受け取るツールを渡そうとした場合など)。 - コンテキストは
run関数に渡されます。 - エージェントはツールを正しく呼び出し、年齢を取得します。
エージェント/LLM コンテキスト
LLM が呼び出されるとき、LLM が参照できる 唯一 のデータは会話履歴にあるものだけです。つまり、新しいデータを LLM に利用させたい場合は、そのデータを履歴に含める必要があります。方法はいくつかあります。
- エージェントの
instructionsに追加します。これは「システムプロンプト」や「開発者メッセージ」とも呼ばれます。システムプロンプトは静的な文字列でも、コンテキストを受け取って文字列を出力する動的関数でもかまいません。これは常に有用な情報(たとえばユーザー名や現在の日付)に一般的な戦術です。 Runner.runを呼ぶときにinputに追加します。これはinstructionsの戦術に似ていますが、指示の階層の下位にメッセージを配置できます。- 関数ツールを通じて公開します。これは オンデマンド のコンテキストに有用です。LLM が必要に応じてデータが必要だと判断し、ツールを呼び出してそのデータを取得できます。
- リトリーバル(retrieval)や Web 検索を使用します。これらは、ファイルやデータベース(リトリーバル)または Web(Web 検索)から関連データを取得できる特別なツールです。これは、関連するコンテキストデータに基づいて応答をグラウンディングするのに役立ちます。