コンテキスト管理
コンテキストは多義的な用語です。主に関心を持つべきコンテキストには、次の 2 つの大きなクラスがあります。
- コード内でローカルに利用可能なコンテキスト:これは、ツール関数の実行時や
on_handoff
のようなコールバック、ライフサイクルフックなどで必要となるデータや依存関係です。 - LLM に利用可能なコンテキスト:これは、LLM がレスポンスを生成する際に参照できるデータです。
ローカルコンテキスト
これは RunContextWrapper
クラスおよびその中の context
プロパティによって表現されます。仕組みは以下の通りです。
- 任意の Python オブジェクトを作成します。一般的なパターンとしては、dataclass や Pydantic オブジェクトを使います。
- そのオブジェクトを各種 run メソッド(例:
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)!
return f"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 に新しいデータを利用させたい場合は、そのデータを履歴に含める必要があります。これを実現する方法はいくつかあります。
- エージェントの
instructions
に追加する。この方法は「システムプロンプト」や「開発者メッセージ」とも呼ばれます。システムプロンプトは静的な文字列でも、コンテキストを受け取って文字列を出力する動的な関数でも構いません。たとえば、ユーザー名や現在の日付など、常に有用な情報に適しています。 Runner.run
関数を呼び出す際にinput
に追加する。この方法はinstructions
と似ていますが、chain of command の下位メッセージとして追加できます。- 関数ツールを通じて公開する。この方法は オンデマンド のコンテキストに適しています。LLM が必要なタイミングでツールを呼び出し、データを取得できます。
- リトリーバルや Web 検索を利用する。これらはファイルやデータベース(リトリーバル)、または Web(Web 検索)から関連データを取得できる特別なツールです。関連するコンテキストデータに基づいたレスポンスを「グラウンディング」するのに役立ちます。