ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

openai-agents-python 安全护栏(Guardrails)完全指南:输入校验、输出过滤与工具调用防护

openai-agents-python 安全护栏(Guardrails)完全指南:输入校验、输出过滤与工具调用防护 openai-agents-python 安全护栏Guardrails完全指南输入校验、输出过滤与工具调用防护【免费下载链接】openai-agents-pythonA lightweight, powerful framework for multi-agent workflows项目地址: https://gitcode.com/GitHub_Trending/op/openai-agents-python导读本指南围绕 openai-agents-python 框架中的 Guardrails安全护栏机制展开系统讲解如何在多智能体工作流中对用户输入与智能体输出进行低成本、高效率的校验与拦截。通过本文你将掌握输入护栏、输出护栏与工具护栏三类防护手段的触发边界、执行模式与绊线Tripwire语义并能在真实业务中组合便宜模型做审查、昂贵模型做主业的成本优化方案以及针对函数工具的敏感信息拦截实战。为什么需要 Guardrails用小模型为大模型把关在多智能体应用中负责核心业务的智能体往往绑定高性能同时也更慢、更贵的模型。例如一个客服智能体使用顶尖模型处理客户请求我们不希望恶意用户诱导该模型帮忙解数学作业——这会白白消耗昂贵模型的 token 与时间。Guardrails 解决这一问题的思路是用快速、廉价的模型单独运行检查逻辑。当护栏检测到恶意或越界使用场景时立即抛出错误从而节省时间与成本。这一设计有一个重要前提即运行模式的选择阻塞执行可以保证昂贵模型根本不会启动并行执行下昂贵模型可能在护栏完成之前就已经开始运行。两种模式的取舍详见下文输入护栏的执行模式一节。Guardrails 的两种基本类型框架将护栏划分为两大基础类型分别面向智能体生命周期的两端输入护栏Input guardrails在最初的用户输入上执行输出护栏Output guardrails在最终的智能体输出上执行。在此基础上还有一类面向工具调用链路的工具护栏Tool guardrails将在后文专门展开。工作流边界护栏并非在任意时刻都运行护栏虽然绑定在智能体与工具上但在多智能体工作流包含 manager、handoff 或委派的 specialist中它们并非在同一时间点全部运行输入护栏仅对链路中的第一个智能体运行输出护栏仅对产出最终输出的智能体运行工具护栏在每一次自定义函数工具调用时运行——输入护栏在工具执行前、输出护栏在工具执行后。因此如果工作流包含 manager、handoff 或委派的 specialist且需要在每次自定义函数工具调用的前后或前后都要做检查请使用工具护栏而不是只依赖智能体级别的输入/输出护栏。输入护栏Input Guardrails三步执行流程输入护栏按以下 3 个步骤运行首先护栏接收到与传入智能体相同的输入然后护栏函数执行并产生GuardrailFunctionOutput它会被包装在InputGuardrailResult中最后检查.tripwire_triggered是否为true。若为true则抛出InputGuardrailTripwireTriggered异常你可以据此向用户给出适当响应或捕获处理该异常。从源码看这三步对应InputGuardrail.run()的实现它调用guardrail_function(context, agent, input)通过inspect.isawaitable同时兼容同步与异步函数最终返回包装了GuardrailFunctionOutput的InputGuardrailResult。为什么护栏属性挂在 Agent 上而不是 Runner.run 上你可能会疑惑为什么guardrails属性配置在 Agent 上而不是传给Runner.run原因在于护栏通常与具体的 Agent 强相关——不同的智能体需要不同的护栏将代码放在同一处Agent 定义处可读性更好。执行模式并行 vs 阻塞输入护栏支持两种执行模式由InputGuardrail的run_in_parallel字段控制并行执行默认run_in_parallelTrue护栏与智能体的执行并发进行。由于二者同时启动延迟最低但若护栏绊线被触发智能体在被取消前可能已经消耗了 token 并执行了工具。阻塞执行run_in_parallelFalse护栏在智能体启动之前运行并完成。若护栏绊线被触发智能体永远不会执行从而杜绝 token 消耗与工具执行。这适合成本优化或当你想避免工具调用可能带来的副作用时。在 src/agents/guardrail.py 中InputGuardrail的run_in_parallel: bool True明确标注了默认行为。你既可以通过input_guardrail装饰器的关键字参数配置如input_guardrail(nameguardrail_name, run_in_parallelFalse)也可以直接构造InputGuardrail实例name参数用于 tracing缺省时取函数名见 get_name()。输出护栏Output Guardrails三步执行流程输出护栏同样按 3 个步骤运行首先护栏接收到智能体生成的输出然后护栏函数执行并产生GuardrailFunctionOutput它会被包装在OutputGuardrailResult中最后检查.tripwire_triggered是否为true。若为true则抛出OutputGuardrailTripwireTriggered异常。对应源码OutputGuardrail.run()同样通过inspect.isawaitable兼容同步/异步函数并在结果中携带agent与agent_output字段供上层排查。边界与限制输出护栏旨在对最终智能体输出运行因此一个智能体的输出护栏仅当它是链路中最后一个智能体时才执行。原因与输入护栏相同护栏与具体 Agent 强相关同处存放可读性更好。输出护栏始终在智能体完成后运行因此不支持run_in_parallel参数。绊线与异常的会话持久化差异输出绊线与护栏函数抛出的异常在会话Session行为上截然不同绊线Tripwire拒绝候选最终输出。绊线触发时runner 要求配置的会话持久化已完成的工具调用与工具输出项连同重放这些调用所需的推理上下文同时排除被拒绝的候选最终输出。该规则对流式与非流式运行同样适用。护栏函数抛出异常而非返回绊线结果时runner 将判定视为未知并会先要求会话持久化已完成的最终回合项然后再把护栏异常抛给上层若该会话写入也失败则会话写入错误优先。流式运行使用与非流式相同的持久化顺序并从stream_events()抛出终末异常。若在输出护栏运行期间立即调用RunResultStreaming.cancel()会取消进行中的护栏并且不会开始最终回合的会话写入。终止型函数工具输出的特殊处理当Agent.tool_use_behavior见 src/agents/agent.py默认run_llm_again使某个函数工具的结果成为最终输出而输出绊线又拒绝了它时工具已经先于智能体级输出护栏执行完毕因此需要额外的处理逻辑仅当 SDK 能从已验证字段重建函数调用/输出对时才会保留可重放的调用/输出对保留的function_call_output载荷会被替换为固定文本Output withheld by an output guardrail.原始工具输出载荷不会保留在会话、RunState、流式运行结果状态或沙盒内存输入中的任何一处SDK 会保留重放所需的已验证函数调用元数据包括函数参数因此该元数据中可能包含曾出现在被拒绝输出里的数据当前响应的OutputGuardrailResult对象中agent_output同样被替换为固定文本且output_info被清空当前响应的ToolOutputGuardrailResult对象保留允许/拒绝的行为类型但承载载荷的output_info与拒绝消息会被替换为同一固定文本更早被接受的回合与护栏执行结果保持不变若响应包含推理内容或其他 SDK 无法安全消毒的形状SDK 会丢弃当前响应的完整后缀而不是保留被拒绝的输出载荷抛出异常的护栏函数并未返回拒绝判定因此已完成的终止型工具回合遵循上文异常持久化行为。与这条链路相关的还有 run_config.py 中定义的OutputGuardrailBlockedMessageFormatter同步格式化器它在终止型工具输出被拒绝后、每个重放与持久化拥有者被替换为无数据占位文本之前执行可用来自定义默认的拒绝提示文案。工具护栏Tool Guardrails设计定位工具护栏包装FunctionTool实例允许你在工具执行前与后校验或拦截对该工具的调用。它们配置在工具自身之上并且每次该工具被调用时都会运行。输入工具护栏在工具执行前运行可以跳过本次调用、将输出替换为一条消息、或触发绊线输出工具护栏在工具执行后运行可以替换输出或触发绊线。与人工审批Approval的配合如果某个函数工具需要审批approval输入工具护栏默认在审批之后、执行之前立即运行。如果你希望在发出待审批中断之前就执行这些输入检查可将RunConfig.tool_execution设置为ToolExecutionConfig(pre_approval_tool_input_guardrailsTrue)。源码 src/agents/run_config.py 中ToolExecutionConfig还包含max_function_tool_concurrency单回合内本地函数工具的最大并发数None表示保持默认、同时启动所有工具调用并做了参数校验pre_approval_tool_input_guardrails必须是布尔值。注意通过预批准检查的调用在工具执行前仍会进行审批后的再次检查。适用范围边界工具护栏仅适用于通过function_tool创建的函数工具Handoff走的是 SDK 的 handoff 管线而非普通函数工具管线因此工具护栏不适用于 handoff 调用本身托管工具WebSearchTool、FileSearchTool、HostedMCPTool、CodeInterpreterTool、ImageGenerationTool与内置执行工具ComputerTool、ShellTool、ApplyPatchTool、LocalShellTool同样不使用这条护栏管线Agent.as_tool()目前不直接暴露工具护栏选项。底层行为模型src/agents/tool_guardrails.py 中的ToolGuardrailFunctionOutput定义了三种行为allow允许工具调用/输出正常继续默认对应ToolGuardrailFunctionOutput.allow()reject_content拒绝工具调用/输出但继续执行并将消息回传给模型对应ToolGuardrailFunctionOutput.reject_content(message)raise_exception抛出ToolGuardrailTripwireTriggered异常以中止执行对应ToolGuardrailFunctionOutput.raise_exception()。输入数据方面输入护栏收到 ToolInputGuardrailData含context与agent输出护栏收到 ToolOutputGuardrailData它在输入数据基础上追加output字段。tool_input_guardrail与tool_output_guardrail装饰器均同时支持同步与异步函数。绊线Tripwires语义当智能体的输入或输出未通过护栏检查时护栏通过绊线发出信号。runner 会立即抛出异常并中止智能体执行智能体级InputGuardrailTripwireTriggered或OutputGuardrailTripwireTriggered工具级ToolInputGuardrailTripwireTriggered或ToolOutputGuardrailTripwireTriggered。对应的异常类定义在 src/agents/exceptions.py智能体级异常暴露guardrail_result属性用于定位是哪个护栏触发了绊线工具级异常则直接暴露触发绊线的guardrail与output。累积结果的可观测性对于 runner 抛出的输入绊线exception.run_data.input_guardrail_results包含运行停止前已完成的所有输入护栏执行结果其中包括触发绊线的那一个输出绊线则通过exception.run_data.output_guardrail_results提供等价的累积结果。工具绊线异常通过run_data.tool_input_guardrail_results与run_data.tool_output_guardrail_results保留失败前已完成回合累积的执行结果触发绊线的那一个结果可通过异常的output取得。其他 runner 管理的失败例如MaxTurnsExceeded也会在同样的列表中保留已完成的工具护栏执行结果。stream_events()抛出异常后流式结果会暴露相同的累积智能体与工具护栏执行结果列表。注意当异常发生在 runner 管理的执行路径之外时run_data可能为Nonesrc/agents/exceptions.py 中这些列表均为可空字段。实战实现一个输入护栏实现护栏的核心是提供一个接收输入、返回GuardrailFunctionOutput的函数。下面的例子内部通过运行一个 Agent 来完成检查——用轻量模型判断用户是否在要求解数学作业from pydantic import BaseModel from agents import ( Agent, GuardrailFunctionOutput, InputGuardrailTripwireTriggered, RunContextWrapper, Runner, TResponseInputItem, ) from agents.decorators import input_guardrail class MathHomeworkOutput(BaseModel): is_math_homework: bool reasoning: str guardrail_agent Agent( # (1)! nameGuardrail check, instructionsCheck if the user is asking you to do their math homework., output_typeMathHomeworkOutput, ) input_guardrail async def math_guardrail( # (2)! ctx: RunContextWrapper[None], agent: Agent, input: str | list[TResponseInputItem] ) - GuardrailFunctionOutput: result await Runner.run(guardrail_agent, input, contextctx.context) return GuardrailFunctionOutput( output_inforesult.final_output, # (3)! tripwire_triggeredresult.final_output.is_math_homework, ) agent Agent( # (4)! nameCustomer support agent, instructionsYou are a customer support agent. You help customers with their questions., input_guardrails[math_guardrail], ) async def main(): # This should trip the guardrail try: await Runner.run(agent, Hello, can you help me solve for x: 2x 3 11?) print(Guardrail didnt trip - this is unexpected) except InputGuardrailTripwireTriggered: print(Math homework guardrail tripped)该 Agent 在护栏函数内部被调用负责输出结构化判定结果。这是护栏函数接收智能体的输入/上下文返回执行结果。可以在护栏结果中携带附加信息output_info。这是定义工作流的真实业务智能体通过input_guardrails[math_guardrail]挂载护栏。更多可运行变体可参考 examples/agent_patterns/input_guardrails.py。实战实现一个输出护栏输出护栏与输入护栏结构类似区别在于它接收的是智能体的最终输出from pydantic import BaseModel from agents import ( Agent, GuardrailFunctionOutput, OutputGuardrailTripwireTriggered, RunContextWrapper, Runner, ) from agents.decorators import output_guardrail class MessageOutput(BaseModel): # (1)! response: str class MathOutput(BaseModel): # (2)! reasoning: str is_math: bool guardrail_agent Agent( nameGuardrail check, instructionsCheck if the output includes any math., output_typeMathOutput, ) output_guardrail async def math_guardrail( # (3)! ctx: RunContextWrapper, agent: Agent, output: MessageOutput ) - GuardrailFunctionOutput: result await Runner.run(guardrail_agent, output.response, contextctx.context) return GuardrailFunctionOutput( output_inforesult.final_output, tripwire_triggeredresult.final_output.is_math, ) agent Agent( # (4)! nameCustomer support agent, instructionsYou are a customer support agent. You help customers with their questions., output_guardrails[math_guardrail], output_typeMessageOutput, ) async def main(): # This should trip the guardrail try: await Runner.run(agent, Hello, can you help me solve for x: 2x 3 11?) print(Guardrail didnt trip - this is unexpected) except OutputGuardrailTripwireTriggered: print(Math output guardrail tripped)这是真实业务智能体的输出类型。这是护栏自身的输出类型。这是护栏函数接收智能体的输出返回执行结果。这是定义工作流的真实智能体通过output_guardrails与output_type完成挂载。可参考 examples/agent_patterns/output_guardrails.py 与流式场景下的 examples/agent_patterns/streaming_guardrails.py。实战实现工具护栏最后是工具护栏示例——在工具执行前拦截包含密钥的调用参数在工具执行后对包含敏感数据的输出进行消毒import json from agents import ( Agent, Runner, ToolGuardrailFunctionOutput, ) from agents.decorators import tool, tool_input_guardrail, tool_output_guardrail tool_input_guardrail def block_secrets(data): args json.loads(data.context.tool_arguments or {}) if sk- in json.dumps(args): return ToolGuardrailFunctionOutput.reject_content( Remove secrets before calling this tool. ) return ToolGuardrailFunctionOutput.allow() tool_output_guardrail def redact_output(data): text str(data.output or ) if sk- in text: return ToolGuardrailFunctionOutput.reject_content(Output contained sensitive data.) return ToolGuardrailFunctionOutput.allow() tool( tool_input_guardrails[block_secrets], tool_output_guardrails[redact_output], ) def classify_text(text: str) - str: Classify text for internal routing. return flength:{len(text)} agent Agent(nameClassifier, tools[classify_text]) result Runner.run_sync(agent, hello world) print(result.final_output)本例中block_secrets从data.context.tool_arguments解析工具参数若发现sk-前缀的疑似密钥则调用reject_content拒绝该次调用并携带提示消息回传给模型redact_output则在工具返回后检查输出文本。两个护栏通过tool装饰器的tool_input_guardrails/tool_output_guardrails参数挂载到同一个函数工具上。测试与验证如何在仓库中确认护栏行为如果你希望深入验证护栏的边界行为仓库提供了完备的测试用例tests/test_guardrails.py智能体级输入/输出护栏的执行流程、绊线异常与累积结果tests/test_tool_guardrails.py工具护栏的允许/拒绝/异常三种行为及工具绊线语义tests/test_output_guardrail_cancellation.py输出护栏运行期间调用RunResultStreaming.cancel()的取消路径tests/test_runner_guardrail_resume.py绊线触发后 runner 的恢复与会话持久化行为tests/test_stream_input_guardrail_timing.py流式场景下输入护栏的时序。这些测试直接印证了本文所述的执行模式、绊线异常与持久化规则是理解 Guardrails 底层实现的最佳补充材料英文原文文档见 docs/guardrails.md日文版即本文所依据的 docs/ja/guardrails.md。小结综合来看openai-agents-python 的 Guardrails 体系围绕检查点思想设计输入护栏守卫工作流的起点仅第一个智能体支持并行/阻塞两种执行模式是控制成本的第一道闸门输出护栏守卫工作流的终点仅最后一个智能体并提供绊线与异常两种差异化的会话持久化语义保障多轮会话的一致性工具护栏为每个自定义函数工具提供执行前/执行后的细粒度拦截能力与审批流程协同工作是防止副作用与敏感信息泄漏的关键手段。在落地时建议遵循便宜模型做审查、昂贵模型做主业的范式将结构化的判定逻辑Pydantic 输出类型 轻量 Agent封装为护栏函数通过tripwire_triggered快速终止异常链路并根据业务对延迟与成本的敏感度为输入护栏选择合适的执行模式。【免费下载链接】openai-agents-pythonA lightweight, powerful framework for multi-agent workflows项目地址: https://gitcode.com/GitHub_Trending/op/openai-agents-python创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表