上下文管理
“上下文”是一个含义过载的术语。您可能关心两大类上下文
- 您的代码可用的本地上下文:这是工具函数运行、回调(如
on_handoff)、生命周期钩子等时您可能需要的数据和依赖项。 - LLM 可用的上下文:这是 LLM 在生成响应时看到的数据。
本地上下文
这通过 RunContextWrapper 类和其中的 context 属性来表示。其工作方式如下:
- 您可以创建任何您想要的 Python 对象。一种常见模式是使用 dataclass 或 Pydantic 对象。
- 您将该对象传递给各种运行方法(例如
Runner.run(..., **context=whatever**))。 - 您的所有工具调用、生命周期钩子等都将传递一个包装器对象,
RunContextWrapper[T],其中T表示您的上下文对象类型,您可以通过wrapper.context访问它。
最重要的一点是:对于给定的 agent 运行,所有 agent、工具函数、生命周期等都必须使用相同类型的上下文。
您可以使用上下文来处理以下事项:
- 运行的上下文数据(例如,用户名/uid 或其他用户信息)
- 依赖项(例如,logger 对象、数据获取器等)
- 辅助函数
注意
上下文对象不发送给 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标记 agent,以便类型检查器可以捕获错误(例如,如果我们尝试传递接受不同上下文类型的工具)。 - 上下文传递给
run函数。 - agent 正确调用该工具并获取年龄。
高级:ToolContext
在某些情况下,您可能希望访问有关正在执行的工具的额外元数据——例如,其名称、调用 ID 或原始参数字符串。
为此,您可以使用 ToolContext 类,它扩展了 RunContextWrapper。
from typing import Annotated
from pydantic import BaseModel, Field
from agents import Agent, Runner, function_tool
from agents.tool_context import ToolContext
class WeatherContext(BaseModel):
user_id: str
class Weather(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_tool
def get_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})")
return Weather(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– 传递给工具的原始参数字符串
在执行期间需要工具级别元数据时,使用 ToolContext。
对于 agent 和工具之间的常规上下文共享,RunContextWrapper 仍然足够。
Agent/LLM 上下文
当调用 LLM 时,它能看到的数据仅来自对话历史记录。这意味着,如果您想让 LLM 可以使用一些新数据,则必须以使其在历史记录中可用方式来完成。有几种方法可以做到这一点
- 您可以将其添加到 Agent 的
instructions中。这也被称为“系统提示”或“开发者消息”。系统提示可以是静态字符串,也可以是接收上下文并输出字符串的动态函数。这是一种常见策略,用于始终有用的信息(例如,用户名或当前日期)。 - 将其添加到调用
Runner.run函数时的input中。这类似于instructions策略,但允许您拥有位于 命令链 中较低位置的消息。 - 通过函数工具公开它。这对于按需上下文很有用——LLM 决定何时需要一些数据,并且可以调用该工具来获取该数据。
- 使用检索或网络搜索。这些是能够从文件或数据库(检索)或从网络(网络搜索)中获取相关数据的特殊工具。这对于将响应置于相关的上下文数据中很有用。