コンテキスト管理
コンテキストは多義的な用語です。ここでは主に次の 2 つのコンテキストがあります。
- コードからローカルで利用できるコンテキスト: ツール関数の実行時、
on_handoffのようなコールバック、ライフサイクルフックなどで必要になるデータや依存関係です。 - LLM に利用できるコンテキスト: 応答を生成する際に LLM が参照できるデータです。
ローカルコンテキスト
これはRunContextWrapper クラスと、その内部のcontext プロパティで表現されます。仕組みは次のとおりです。
- 任意の Python オブジェクトを作成します。一般的には dataclass や Pydantic オブジェクトを使います。
- そのオブジェクトを各種 run メソッドに渡します(例:
Runner.run(..., **context=whatever**))。 - すべてのツール呼び出しやライフサイクルフックなどにはラッパーオブジェクト
RunContextWrapper[T]が渡されます。ここでTはあなたのコンテキストオブジェクトの型で、wrapper.contextからアクセスできます。
最も重要 な点: 特定のエージェント実行において、エージェント、ツール関数、ライフサイクルなどはすべて同じ型のコンテキストを使う必要があります。
コンテキストは次のような用途に使えます:
- 実行のための状況データ(例: ユーザー名 / uid など、ユーザーに関する情報)
- 依存関係(例: logger オブジェクト、データフェッチャーなど)
- ヘルパー関数
注意
コンテキストオブジェクトは LLM には送信されません。これは純粋にローカルなオブジェクトであり、読み書きやメソッド呼び出しが可能です。
importasynciofromdataclassesimportdataclassfromagentsimportAgent,RunContextWrapper,Runner,function_tool@dataclassclassUserInfo:# (1)!name:struid:int@function_toolasyncdeffetch_user_age(wrapper:RunContextWrapper[UserInfo])->str:# (2)!"""Fetch the age of the user. Call this function to get user's age information."""returnf"The user{wrapper.context.name} is 47 years old"asyncdefmain():user_info=UserInfo(name="John",uid=123)agent=Agent[UserInfo](# (3)!name="Assistant",tools=[fetch_user_age],)result=awaitRunner.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関数に渡されます。 - エージェントはツールを正しく呼び出し、年齢を取得します。
上級:ToolContext
実行中のツールに関する追加メタデータ(名前、呼び出し ID、raw な引数文字列など)にアクセスしたい場合があります。
そのためには、RunContextWrapper を拡張したToolContext クラスを使用できます。
fromtypingimportAnnotatedfrompydanticimportBaseModel,FieldfromagentsimportAgent,Runner,function_toolfromagents.tool_contextimportToolContextclassWeatherContext(BaseModel):user_id:strclassWeather(BaseModel):city:str=Field(description="The city name")temperature_range:str=Field(description="The temperature range in Celsius")conditions:str=Field(description="The weather conditions")@function_tooldefget_weather(ctx:ToolContext[WeatherContext],city:Annotated[str,"The city to get the weather for"])->Weather:print(f"[debug] Tool context: (name:{ctx.tool_name}, call_id:{ctx.tool_call_id}, args:{ctx.tool_arguments})")returnWeather(city=city,temperature_range="14-20C",conditions="Sunny with wind.")agent=Agent(name="Weather Agent",instructions="You are a helpful agent that can tell the weather of a given city.",tools=[get_weather],)ToolContext はRunContextWrapper と同じ.context プロパティに加えて、
現在のツール呼び出しに特有の次のフィールドを提供します:
tool_name– 呼び出されるツールの名前tool_call_id– このツール呼び出しの一意な識別子tool_arguments– ツールに渡された raw な引数文字列
実行中にツールレベルのメタデータが必要な場合はToolContext を使用してください。
エージェントとツール間での一般的なコンテキスト共有には、RunContextWrapper で十分です。
エージェント / LLM コンテキスト
LLM が呼び出されると、参照できるのは会話履歴のデータのみです。したがって、LLM に新しいデータを利用可能にしたい場合は、その履歴で参照できる形にする必要があります。方法はいくつかあります:
- エージェントの
instructionsに追加します。これは「システムプロンプト」または「開発者メッセージ」とも呼ばれます。システムプロンプトは固定文字列でも、コンテキストを受け取って文字列を出力する動的関数でも構いません。常に有用な情報(例: ユーザー名や現在の日付)に適した一般的な手法です。 Runner.runを呼び出すときのinputに追加します。これはinstructionsの手法に似ていますが、chain of command の下位にメッセージを配置できます。- 関数ツールで公開します。これはオンデマンドのコンテキストに有用で、LLM が必要に応じてデータを取得するためにツールを呼び出せます。
- リトリーバルまたは Web 検索を使用します。これらはファイルやデータベース(リトリーバル)または Web(Web 検索)から関連データを取得できる特別なツールです。これは応答を関連する状況データに「グラウンディング」するのに有用です。