跳至内容

上下文管理

上下文(Context)是一个被过度使用的术语。主要有两类您可能关心的上下文:

  1. 代码本地可用的上下文:这是在工具函数运行时、在类似on_handoff的回调期间、生命周期钩子等情况下,您可能需要的数据和依赖项。
  2. LLM可访问的上下文:这是LLM生成响应时能看到的数据。

本地上下文

这通过RunContextWrapper类和其中的context属性来表示。其工作原理如下:

  1. 您可以创建任何想要的Python对象。常见的模式是使用数据类或Pydantic对象。
  2. 您将该对象传递给各种运行方法(例如 Runner.run(..., **context=whatever**))
  3. 您的所有工具调用、生命周期钩子等都将传递一个包装对象RunContextWrapper[T],其中T代表您可以通过wrapper.context访问的上下文对象类型。

需要了解的最重要事项是:对于给定的代理运行,每个代理、工具函数、生命周期等都必须使用相同类型的上下文。

您可以将上下文用于以下用途:

  • 运行时的上下文数据(例如用户名/用户ID或其他用户相关信息)
  • 依赖项(例如日志记录器对象、数据获取器等)
  • 辅助函数

注意

上下文对象不会发送给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())
  1. 这是上下文对象。我们在这里使用了数据类,但您可以使用任何类型。
  2. 这是一个工具。您可以看到它接收一个RunContextWrapper[UserInfo]。该工具实现从上下文中读取数据。
  3. 我们使用通用的UserInfo标记代理,这样类型检查器就能捕获错误(例如,如果我们尝试传递一个需要不同上下文类型的工具)。
  4. 上下文被传递给run函数。
  5. 代理正确调用工具并获取年龄。

代理/LLM上下文

当调用LLM时,唯一它能访问的数据来自对话历史记录。这意味着如果您想让LLM获取一些新数据,必须以某种方式将这些数据放入历史记录中。有几种方法可以实现这一点:

  1. 您可以将其添加到Agent的instructions中。这也被称为"系统提示"或"开发者消息"。系统提示可以是静态字符串,也可以是接收上下文并输出字符串的动态函数。这是处理始终有用信息(例如用户名或当前日期)的常用策略。
  2. 在调用Runner.run函数时将其添加到input中。这与instructions策略类似,但允许您在命令链中设置优先级较低的消息。
  3. 通过函数工具公开它。这对于按需获取上下文非常有用 - LLM可以决定何时需要某些数据,并可以调用工具来获取该数据。
  4. 使用检索或网络搜索功能。这些是特殊工具,能够从文件或数据库(检索)或从网络(网络搜索)获取相关数据。这对于将响应"锚定"在相关上下文数据中非常有用。