openai-agents-python 上下文管理实战本地上下文RunContextWrapper/ToolContext与 LLM 上下文注入全解析【免费下载链接】openai-agents-pythonA lightweight, powerful framework for multi-agent workflows项目地址: https://gitcode.com/GitHub_Trending/op/openai-agents-python本文是 openai-agents-python 框架中「上下文管理」的完整技术指南。围绕 docs/ja/context.md英文原版见 docs/context.md系统讲解两大类上下文一类是代码本地可用的上下文通过RunContextWrapper与ToolContext传递的数据与依赖另一类是LLM 可见的上下文如何把新数据注入对话历史供模型参考。读完本文你将掌握如何在工具函数、on_handoff回调、生命周期钩子中读写上下文、用上下文做能力可见性capability visibility控制、在嵌套Agent.as_tool()场景下共享状态以及四种把数据喂给 LLM 的标准姿势。两种上下文先分清「谁在看」在 openai-agents-python 中“上下文context”是一个被重度重载overloaded的术语。梳理整个框架你需要关心的上下文只有两大类代码本地可用的上下文工具函数执行时、on_handoff等回调内、生命周期钩子lifecycle hooks中所需要的数据与依赖。例如用户信息、日志器对象、数据抓取器。LLM 可用的上下文模型生成响应时能够引用到的数据也就是最终出现在对话历史conversation history里的内容。前者是你的 Python 代码在运行时直接持有的对象后者是模型在推理时能看到的文本。二者互不重叠本地上下文对象永远不会被发送给 LLM。本文先讲本地上下文再讲如何把数据送入 LLM 视野。本地上下文RunContextWrapper与context属性本地上下文由RunContextWrapper类及其内部的context属性表示。它的工作方式只有三步创建任意 Python 对象作为上下文。常见做法是用 dataclass 或 Pydantic 对象任意类型都行。把该对象通过各类运行方法传入例如Runner.run(..., contextwhatever)。所有工具调用、生命周期钩子等都会收到一个包装对象RunContextWrapper[T]其中T是上下文对象的类型对象本体通过wrapper.context访问。从源码看Runner.run的签名是async def run(..., context: TContext | None None)上下文类型由泛型TContext承载定义于 run_context.py。框架内部会在执行链中把用户传入的对象包装进RunContextWrapper再分发给各个环节。上下文能装什么官方文档明确推荐的用途有三类运行相关的上下文数据例如用户名、UID 以及其他用户信息依赖Dependencies例如 logger 对象、数据抓取器data fetchers等辅助函数Helper functions可以放进上下文对象里在工具中直接调用。最重要的一条规则同一次运行必须使用同类型上下文最需要注意的一点针对某一次 Agent 运行的所有Agent、工具函数、生命周期处理等必须使用同一种类型的上下文。这一约束的工程价值在于类型安全。结合 tool.py 可以看到FunctionTool.is_enabled的签名是Callable[[RunContextWrapper[Any], AgentBase], MaybeAwaitable[bool]]如果你在同一个 Agent 上混用接收不同上下文类型的工具类型检查器如 mypy/pyright会在编译期报错从根源上避免运行时AttributeError。危险提示上下文不会发给 LLM!!! danger 注意 上下文对象是不会被发送给 LLM的。它纯粹是一个本地对象你可以读取它的值、写入新值、调用它的方法。这一点也是 run_context.py 的 docstring 所强调的上下文是把依赖和数据传递给你写的代码工具函数、回调、钩子等的通道而不是喂给模型的通道。单次运行内的状态共享语义在一次运行内部所有派生出来的 wrapper共享同一个底层应用上下文、批准状态approval state与用量追踪usage tracking。从 run_context.py 的_share_tool_state_with可以看到派生 wrapper 会直接共享_approvals与_tool_invocations字典引用这意味着子运行中的批准/拒绝决定和调用记账会立即反映到父运行。特别地嵌套的Agent.as_tool()运行可能会附带一个不同的tool_input结构化输入见下文但默认情况下不会为你的应用状态创建独立副本。也就是说你在嵌套运行里对wrapper.context的修改会影响到外层——这一点在多 Agent 协作场景中务必留意。用本地上下文控制能力可见性Capability Visibility当函数工具function tools、MCP 工具和 handoff交接依赖同一个请求策略时正确的做法是把策略的输入值或辅助函数放到你的应用上下文application context上而不是为每个功能单独维护一份能力列表。SDK 的各个接口都通过各自的回调向代码暴露当前运行上下文SDK 接口回调签名中的上下文源码位置FunctionTool.is_enabled接收RunContextWrapper外加AgentBasetool.pyHandoff.is_enabled接收RunContextWrapper外加AgentBasehandoffs/init.pyMCP 的tool_filter接收ToolFilterContext其run_context属性包含当前的RunContextWrappermcp/util.py在 mcp/util.py 中ToolFilterContext被定义为包含run_context当前运行上下文、agent请求工具列表的 Agent和server_nameMCP 服务器名三个字段的 dataclass即ToolFilterCallable Callable[[ToolFilterContext, MCPTool], MaybeAwaitable[bool]]。必须理解的能力边界这些回调只控制 SDK 在本次运行中暴露哪些能力工具是否出现、handoff 是否可选它们不能对模型生成的参数或资源选择进行授权。因此函数工具授权判断应在工具实现内部执行或视需要使用工具输入护栏tool input guardrails与批准approvals / human-in-the-loopMCP 服务器必须自行授权其受保护的操作SDK 无法替服务器做授权带input_type的 handoff应在on_handoff的开头应用产生副作用之前检查解析后的输入授权失败时直接抛出异常而不是返回值。注意工具输入护栏不会在 handoff 上执行相关回调生命周期见 handoffs.md 的 Handoff inputs 一节。RunContextWrapper暴露了哪些信息RunContextWrapper是对你应用自定义上下文对象的包装。实践中最常用的成员如下wrapper.context你自己的可变应用状态与依赖唯一由你定义的对象wrapper.usage当前运行累计的请求数与 token 用量。对应源码 usage.py 中的Usage类字段为requests、input_tokens、output_tokens、total_tokens通过Usage.add在各请求间累加见 usage.py。注意流式响应下该值在流的最后一个 chunk 处理完成前可能是过期stale的wrapper.tool_input当当前运行处于Agent.as_tool()内部时其结构化输入wrapper.approve_tool(...)/wrapper.reject_tool(...)当需要在代码中程序化更新批准状态时使用对应 run_context.py 的实现支持always_approve/always_reject粘性决策。牢记只有wrapper.context是你应用定义的对象其余字段都是 SDK 管理的运行时元数据。序列化RunState时的注意事项如果你后续要为 human-in-the-loop 或持久化任务工作流序列化RunState这些运行时元数据usage、approvals、tool_invocations 等会随状态一起保存。因此如果你打算持久化或传输序列化后的状态不要把机密secrets放进RunContextWrapper.context——否则机密会跟着状态被写盘或外发。会话状态是另一回事会话状态conversation state与上面的上下文是两个不同的问题。要根据你想如何跨轮次携带消息来决定使用result.to_input_list()、session、conversation_id还是previous_response_id。相关决策可参考执行结果、Agent 的运行与会话。完整示例把用户信息注入工具以下代码是文档中的标准示例可直接运行演示了上下文对象的创建、传递与读取import asyncio from dataclasses import dataclass from agents import Agent, RunContextWrapper, Runner from agents.decorators import tool dataclass class UserInfo: # (1)! name: str uid: int tool async def fetch_user_age(wrapper: RunContextWrapper[UserInfo]) - str: # (2)! Fetch the age of the user. Call this function to get users age information. return fThe user {wrapper.context.name} is 47 years old async def main(): user_info UserInfo(nameJohn, uid123) agent AgentUserInfo! nameAssistant, tools[fetch_user_age], ) result await Runner.run( # (4)! starting_agentagent, inputWhat is the age of the user?, contextuser_info, ) print(result.final_output) # (5)! # The user John is 47 years old. if __name__ __main__: asyncio.run(main())逐步拆解(1) 上下文对象这里用的是 dataclass你也可以换成 Pydantic 模型或任意类型(2) 工具函数工具的第一个参数是RunContextWrapper[UserInfo]实现体内通过wrapper.context读取上下文中的值——注意 LLM 永远看不到这个对象工具只是“代表”模型去访问本地数据(3) 泛型 Agent用Agent[UserInfo]声明上下文类型让类型检查器能捕获错误例如传入一个接收不同上下文类型的工具(4) 传入运行上下文作为context参数传给Runner.run(5) 结果Agent 正确调用工具并取回年龄。进阶ToolContext——获取工具级元数据在某些场景下你需要访问当前正在执行的工具的额外元数据名称、调用 ID、原始参数字符串等。此时使用继承自RunContextWrapper的ToolContext类。从源码看ToolContext 直接class ToolContext(RunContextWrapper[TContext])并且其tool_name、tool_call_id、tool_arguments三个字段带强制校验tool_context.py确保运行时一定有值。另外它还暴露tool_call原始ResponseFunctionToolCall对象、agent当前 Agent与run_config等增强信息。示例带调试元数据的天气工具from typing import Annotated from pydantic import BaseModel, Field from agents import Agent from agents.decorators import tool from agents.tool_context import ToolContext class WeatherContext(BaseModel): user_id: str class Weather(BaseModel): city: str Field(descriptionThe city name) temperature_range: str Field(descriptionThe temperature range in Celsius) conditions: str Field(descriptionThe weather conditions) 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(citycity, temperature_range14-20C, conditionsSunny with wind.) agent Agent( nameWeather Agent, instructionsYou are a helpful agent that can tell the weather of a given city., tools[get_weather], )ToolContext的字段清单ToolContext提供与RunContextWrapper相同的.context属性并额外提供当前工具调用特有的字段tool_name被调用的工具名tool_call_id本次工具调用的唯一标识符tool_arguments传给工具的原始参数字符串raw arguments stringtool_namespace当工具通过tool_namespace()或其他带命名空间的接口加载时该工具调用的 Responses 命名空间qualified_tool_name存在命名空间时用命名空间限定后的工具名源码实现见 tool_context.py调用了tool_trace_name。何时用ToolContext何时用RunContextWrapper需要在执行期间访问工具级元数据→ 用ToolContext只是想在 Agent 与工具之间共享通用上下文→RunContextWrapper已足够由于ToolContext继承自RunContextWrapper当嵌套的Agent.as_tool()运行提供了结构化输入时它同样能暴露.tool_input。Agent / LLM 上下文把数据送入模型视野当 LLM 被调用时它能看到的唯一数据来自对话历史conversation history。因此要想让模型利用某些新数据就必须以某种方式把这些数据放进历史中。框架提供了四种标准方式1. 写入 Agent 的instructions系统提示 / developer messageinstructions即“系统提示system prompt”或“developer message”。它可以是静态字符串也可以是接收上下文并输出字符串的动态函数——这是让“始终有用的信息”例如用户名、当前日期进入模型视野的常见手法。仓库中提供了现成示例 examples/basic/dynamic_system_prompt.py演示了动态函数型 instructions 的写法。这种方式的信息在对话开始时就会出现在历史中且位于“指令链chain of command”的较高层级。2. 追加到Runner.run的input这与方式 1 类似但允许你放入指令优先级较低的消息对应 OpenAI 模型规范中「chain of command」的层级见 OpenAI Model Spec 相关章节。适用于那些应当被模型参考、但不应压过系统指令的内容。3. 通过FunctionTool实例暴露——按需on-demand上下文这是on-demand按需上下文的最佳实践LLM 自己判断“我现在需要这份数据”然后调用对应的工具去获取。数据不在每次请求中全量注入而是“用到才取”从而节省 token 并保证数据新鲜。fetch_user_age示例本质上就是这种方式——模型决定调用工具工具从wrapper.context读取数据并返回。4. 检索retrieval或 Web 搜索web search这些是能够从文件/数据库检索相关数据retrieval或从 Web 获取数据web search的特殊工具。当你希望模型把回答“基于grounding”在相关的上下文数据上时非常有用。仓库的 examples/tools 目录下提供了web_search.py、file_search.py等可直接运行的示例。四种方式的选型建议方式信息性质注入时机典型场景instructions静态/动态函数始终有用、变化低频每轮对话开始时用户名、当前日期、全局规则input追加消息单轮相关、优先级低于指令本次运行一次性任务背景材料FunctionTool按需获取、可动态变化模型决定调用时数据库查询、API 拉取、用户画像检索 / Web 搜索外部数据、需要 grounding模型决定调用时RAG、事实核查、实时信息总结与最佳实践清单两种上下文别混淆RunContextWrapper.context是给你的代码用的本地对象绝不会发给 LLMLLM 只能看到对话历史里的内容同类型约束一次运行内所有 Agent、工具、钩子必须使用同一类型的上下文配合Agent[T]泛型让类型检查器把关共享语义单次运行内派生 wrapper 共享应用上下文、批准状态与用量嵌套Agent.as_tool()不会默认复制应用状态能力可见性函数工具、MCP 工具、handoff 的启用回调都接收运行上下文把共享策略放进上下文统一适配但这些回调不能做授权授权要放在工具实现、工具输入护栏、批准机制或 MCP 服务器内部机密管理要序列化RunState就别把 secrets 放进context喂给 LLM 的四种姿势动态instructions、input消息、按需FunctionTool、检索/Web 搜索按信息性质与更新频率选择。如需进一步深入可继续阅读仓库中的运行上下文源码、工具上下文源码以及 guardrails、human_in_the_loop、handoffs、sessions 等关联文档构建完整的上下文与运行状态知识体系。【免费下载链接】openai-agents-pythonA lightweight, powerful framework for multi-agent workflows项目地址: https://gitcode.com/GitHub_Trending/op/openai-agents-python创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考