openai/openai-cs-agents-demo 是个好东西-分享解释,
它是agent开发的一个典型例子,有用有效的agent就是这样开发的。同时它又是客服开发的典型例子,功能齐全,稍微修改则可以用在自己的客服项目。以下为介绍:
openai/openai-cs-agents-demo:Customer Service Agents Demo 存储库,该存储库通过完整的航空公司客户服务应用程序展示了 OpenAI 的 Agents SDK。该系统在生产就绪的全栈环境中演示了智能代理编排、跨代理协作和护栏实施。
Backend Agent Orchestration System 后端代理编排系统
-
Python Backend: FastAPI/Uvicorn server running on
localhost:8000
Python 后端 :运行在localhost:8000上的 FastAPI/Uvicorn 服务器 -
OpenAI Agents SDK Integration: Implements the customer service example from the Agents SDK
OpenAI Agents SDK 集成 :实现 Agents SDK 中的客户服务示例 -
Specialized Agents: Triage Agent, Seat Booking Agent, Flight Status Agent, FAQ Agent, and Cancellation Agent
专业代理 :分流代理、座位预订代理、航班状态代理、常见问题解答代理和取消代理 -
Guardrail System: Relevance and Jailbreak guardrails for conversation control
护栏系统 :用于对话控制的相关性和越狱护栏
图示逻辑:
OpenAI Agents SDK介绍:
OpenAI Agents SDK 是一个轻量级但功能强大的框架,专为构建多代理工作流设计,强调代理间的协作、工具调用和安全控制。以下基于官方文档和核心实践,详细解析你列出的关键类及其在架构中的作用:
🧠 一、核心架构与运行机制
OpenAI Agents SDK 的核心是 Agent(代理),它由大语言模型(LLM)驱动,通过 Runner 执行循环(Run Loop)协调工作流。流程如下:
- 输入处理:用户输入经过
InputGuardrail安全检查。 - 决策生成:LLM 解析意图,决定调用工具、发起交接或直接回复。
- 动作执行:
- 调用工具(如 API、函数)并返回结果;
- 通过
Handoff转移控制权给其他代理; - 生成文本回复。
- 输出处理:结果经
OutputGuardrail验证后返回用户。
⚙️ 二、关键类详解
1. Runner:执行引擎
- 功能:管理代理运行循环,协调工具调用、交接、异常处理。
- 核心方法:
run_sync():同步执行代理;run():异步执行(推荐用于生产环境)。
- 示例:
from agents import Runner, Agent agent = Agent(name="Assistant", instructions="Help users with queries.") result = Runner.run_sync(agent, "What's the weather today?") print(result.final_output) # 输出代理的最终响应 - 作用场景:贯穿整个代理生命周期,处理输入到输出的全流程。
2. 输出项类型(Output Items)
代理运行中可能生成多种输出类型,需通过 ItemHelpers 辅助操作:
-
MessageOutputItem:- 功能:表示文本消息(来自用户或代理)。
- 示例:用户提问 "How to reset my password?" 会被封装为此类。
-
HandoffOutputItem:- 功能:触发代理间控制权转移。
- 关联类:
Handoff定义交接规则(如目标代理、输入过滤)。 - 示例:路由代理将西班牙语请求转交给西语专精代理。
-
ToolCallItem&ToolCallOutputItem:- 功能:
ToolCallItem:工具调用的请求(如调用天气 API);ToolCallOutputItem:工具执行结果的封装(如 API 返回的数据)。
- 示例:
当用户询问天气时,@function_tool def get_weather(city: str) -> str: return f"Weather in {city}: Sunny" agent = Agent(tools=[get_weather]) # 工具绑定到代理ToolCallItem触发get_weather,结果由ToolCallOutputItem返回。
- 功能:
3. 异常项:InputGuardrailTripwireTriggered
- 功能:表示输入触发防护栏(Guardrail),例如检测到违规内容(如暴力、隐私问题)。
- 处理逻辑:Runner 会中断流程,返回预设的安全响应(如 "I can't answer that")。
- 示例:
若输入含敏感词,生成此异常项并终止流程。@input_guardrail def content_filter(input: str) -> bool: return "violence" in input # 触发条件
4. Handoff:代理间交接控制
- 功能:定义代理间的任务转移规则,包括目标代理、输入预处理等。
- 核心参数:
to_agent:目标代理实例;input_mapping:输入数据的转换规则(如提取用户问题中的关键词)。
- 示例:
用于构建多代理协作系统(如客服路由场景)。handoff_to_spanish = Handoff( to_agent=spanish_agent, input_mapping=lambda x: {"query": x.split(":")[1]} # 提取西语问题 )
5. ItemHelpers:输出项操作工具
- 功能:提供辅助方法,用于:
- 过滤特定类型的输出项(如提取所有
ToolCallItem); - 转换输出格式(如将
MessageOutputItem转为纯文本)。
- 过滤特定类型的输出项(如提取所有
- 典型场景:在复杂工作流中解析代理的中间输出。
🔧 三、实战工作流示例
以下代码展示多代理协作场景(客服系统):
from agents import Agent, Runner, Handoff, function_tool
# 定义工具:天气查询
@function_tool
def get_weather(city): ...
# 定义代理:路由代理 & 天气专精代理
triage_agent = Agent(name="Triage", instructions="Route questions.")
weather_agent = Agent(name="Weather", tools=[get_weather], instructions="Answer weather queries.")
# 定义交接:路由到天气代理
handoff_to_weather = Handoff(to_agent=weather_agent, input_mapping=lambda x: x)
# 配置路由代理的交接规则
triage_agent.handoffs = {"weather": handoff_to_weather}
# 运行流程
result = Runner.run_sync(triage_agent, "What's the weather in Paris?")
print(result.final_output) # 输出天气代理的响应
💡 四、应用场景与优势
- 复杂任务处理:
- 单代理处理简单任务(如天气查询);
- 多代理协作处理跨领域任务(如客服→技术支持的交接)。
- 安全可控性:
Guardrails确保输入/输出合规;InputGuardrailTripwireTriggered快速拦截风险。
- 灵活扩展:
- 工具库可自定义(API、函数、其他代理);
- 交接机制支持动态任务分配。
小结 :
导入的类覆盖了 OpenAI Agents SDK 的核心操作层级:
Runner是中枢,驱动代理执行;- 输出项类(如
MessageOutputItem、ToolCallItem)封装运行时数据; Handoff实现多代理协同;InputGuardrailTripwireTriggered强化安全边界;ItemHelpers提供数据处理支持。
该框架通过解耦模型、工具、代理逻辑,大幅降低了构建复杂 AI 工作流的门槛,尤其适合客服系统、任务路由等场景。
核心Agent运行逻辑(Runner.run)解释:
result = await Runner.run(current_agent, state["input_items"], context=state["context"])
for item in result.new_items:
result = await Runner.run(current_agent, state["input_items"], context=state["context"]) 及其后续的 for item in result.new_items 是 OpenAI Agents SDK 中用于执行代理任务并处理运行结果的核心代码片段。其含义和运行机制如下:
1. Runner.run() 的作用
- 功能:
通过Runner.run()异步执行一个代理(current_agent),传入输入数据(state["input_items"])和上下文(state["context"])。该函数会驱动代理的循环(Agent Loop),直到生成最终输出或触发交接、工具调用等操作。 - 参数说明:
current_agent:当前运行的代理实例,需配置指令、工具等属性。state["input_items"]:输入数据(如用户消息或任务描述)。context=state["context"]:全局上下文对象,用于传递跨代理共享的数据(如用户会话状态)。
- 返回值:
返回RunResult对象,包含运行结果的所有信息(如最终输出、中间项、错误等)。
2. result.new_items 的含义
- 功能:
new_items是RunResult的关键属性,存储代理在运行过程中生成的 中间项(Run Items)。这些项代表代理的阶段性动作,例如:MessageOutputItem:文本消息(如代理的初步回复)。ToolCallItem:工具调用请求(如调用天气查询函数)。HandoffOutputItem:代理间交接请求(如转移任务到其他代理)。
- 用途:
通过遍历result.new_items,可以:- 执行工具调用:检测
ToolCallItem并执行对应的工具函数(如调用 API)。 - 处理交接:检测
HandoffOutputItem并切换至目标代理。 - 捕获中间输出:提取
MessageOutputItem用于实时流式响应。
- 执行工具调用:检测
3. 完整工作流解析
以下代码展示了典型的多步骤处理流程:
# 1. 运行代理,传入输入和上下文
result = await Runner.run(
current_agent,
input_items=state["input_items"],
context=state["context"]
)
# 2. 遍历运行过程中生成的中间项
for item in result.new_items:
if isinstance(item, ToolCallItem):
# 执行工具调用(如搜索天气)
tool_output = execute_tool(item.tool_name, item.arguments)
# 将结果反馈给代理继续处理
state["input_items"].append(tool_output)
elif isinstance(item, HandoffOutputItem):
# 切换至目标代理(如转交西班牙语代理)
current_agent = item.target_agent
# 重新运行新代理
result = await Runner.run(current_agent, state["input_items"])
break # 跳出当前循环,进入新代理的处理
elif isinstance(item, MessageOutputItem):
# 实时输出消息(如流式响应)
print(item.content)
4. 关键设计思想
- Agent Loop 自动化:
Runner.run()内部自动处理循环逻辑(调用 LLM → 解析响应 → 执行工具/交接 → 更新状态),开发者只需关注中间项的处理。 - 上下文共享:
context参数确保跨代理的数据一致性(如用户 ID、会话历史)。 - 模块化扩展:
通过new_items分离不同操作(工具调用、交接),便于添加自定义逻辑(如审计工具调用记录)。
5. 典型应用场景
- 多代理协作:
路由代理(Triage Agent)生成HandoffOutputItem,将任务转交专业代理(如语言专家)。 - 工具增强任务:
代理生成ToolCallItem调用外部 API,并将结果返回 LLM 生成最终响应。 - 实时监控:
流式输出MessageOutputItem到前端界面,提升用户体验。
小结:
Runner.run():驱动代理运行的核心方法,返回包含中间项的结果对象。result.new_items:代理运行中产生的动作项集合,需开发者遍历处理以实现工具调用、交接等逻辑。- 设计优势:通过分离中间项与最终输出,实现了复杂工作流的模块化控制,同时支持异步和流式处理。
此模式是构建多代理系统(如客服路由、多步骤任务)的基础,充分体现了 SDK 的灵活性与扩展性。
解释 API.py(项目核心文件):
以下是对该代码逻辑的详细解释,结合OpenAI Agents SDK的核心架构和工作流设计:
🧠 代码整体功能
这段代码处理Runner.run()执行后返回的result.new_items,将不同输出项(Message、Handoff、ToolCall等)转换为两类结构化数据:
messages:用户可见的最终响应消息列表(如文本回复、UI指令)events:系统内部的事件日志(用于监控、调试或触发后续动作)
核心目的:解析代理运行过程中的中间操作,实现多代理协作、工具调用和实时状态追踪。
🔍 逐段逻辑解析
1. 初始化数据结构
messages: List[MessageResponse] = []
events: List[AgentEvent] = []
messages:存储最终返回给用户的消息(例如聊天回复或UI指令)events:记录代理运行中的所有关键事件(如工具调用、代理交接),用于系统监控或后续分析。
2. 遍历 result.new_items
for item in result.new_items:
result.new_items是代理运行中生成的中间项集合,包含多种类型(如消息、工具调用、交接请求)。- 需根据类型分别处理(通过
isinstance()判断)。
3. 消息输出处理 (MessageOutputItem)
if isinstance(item, MessageOutputItem):
text = ItemHelpers.text_message_output(item)
messages.append(MessageResponse(content=text, agent=item.agent.name))
events.append(AgentEvent(id=uuid4().hex, type="message", agent=item.agent.name, content=text))
- 功能:
- 提取消息文本(
ItemHelpers.text_message_output) - 将消息添加到用户可见列表(
messages) - 记录消息事件(
events)
- 提取消息文本(
- 场景:代理生成的文本回复(例如回答用户问题)。
4. 代理交接处理 (HandoffOutputItem)
elif isinstance(item, HandoffOutputItem):
# 记录交接事件
events.append(AgentEvent(...))
# 查找源代理定义的交接规则
ho = next((h for h in from_agent.handoffs if h.agent_name == to_agent.name), None)
# 执行交接回调(如有)
if ho and ho.on_invoke_handoff:
cb = ho.on_invoke_handoff
events.append(AgentEvent(type="tool_call", agent=to_agent.name, content=cb_name))
# 切换当前代理
current_agent = item.target_agent
- 关键步骤:
- 记录事件:标记源代理(
source_agent)向目标代理(target_agent)的交接。 - 查找交接规则:从源代理的
handoffs列表中匹配目标代理的配置(Handoff对象)。 - 执行回调:若交接规则定义了
on_invoke_handoff函数,则触发并记录为工具调用事件(tool_call)。 - 切换代理:将当前代理更新为目标代理,后续操作由新代理接管。
- 记录事件:标记源代理(
- 设计意义:实现动态任务委派(例如客服路由场景)。
5. 工具调用处理 (ToolCallItem 与 ToolCallOutputItem)
elif isinstance(item, ToolCallItem):
# 解析工具名和参数
tool_name = item.raw_item.name
tool_args = json.loads(item.raw_item.arguments) # 尝试解析JSON参数
# 记录工具调用事件
events.append(AgentEvent(type="tool_call", agent=item.agent.name, content=tool_name))
# 特殊工具处理(如UI渲染)
if tool_name == "display_seat_map":
messages.append(MessageResponse(content="DISPLAY_SEAT_MAP", agent=item.agent.name))
elif isinstance(item, ToolCallOutputItem):
# 记录工具执行结果
events.append(AgentEvent(type="tool_output", agent=item.agent.name, content=str(item.output)))
- 工具调用流程:
ToolCallItem:代理请求调用工具(如display_seat_map),记录调用参数。- 特殊工具逻辑:某些工具(如
display_seat_map)会触发前端渲染指令(DISPLAY_SEAT_MAP)。 ToolCallOutputItem:工具执行完成后返回结果,记录输出事件。
- 典型场景:
- 调用网络搜索工具获取实时信息
- 执行代码生成或数据库查询
- 触发前端交互组件(如座位选择器)。
🧩 设计思想与架构意义
-
事件驱动架构
- 所有代理操作(消息、工具调用、交接)均转化为标准化事件(
AgentEvent),便于集中监控和分析。 - Tracing机制:事件日志可直接对接OpenAI的跟踪仪表盘,实现可视化调试(见图2)。
- 所有代理操作(消息、工具调用、交接)均转化为标准化事件(
-
多代理动态协作
- 通过
HandoffOutputItem实现代理间无缝切换,支持复杂工作流分解(例如:路由代理 → 专业代理)。 - 回调机制(
on_invoke_handoff)允许在交接时执行自定义逻辑(如权限检查或数据转换)。
- 通过
-
工具扩展性与UI集成
- 工具调用(
ToolCallItem)支持任意功能扩展(如API、计算、UI指令)。 - 工具与前端深度集成(例如
display_seat_map触发界面渲染)体现SDK的端到端能力。
- 工具调用(
💡 总结
这段代码是多代理系统的中枢处理逻辑,核心价值在于:
- 标准化中间项处理:将代理运行中的异构操作(消息、交接、工具)统一转为结构化数据。
- 支持复杂协作:通过动态代理切换(
current_agent更新)和工具回调实现灵活工作流。 - 赋能可观测性:事件日志(
events)为调试、审计和优化提供数据基础,呼应SDK的Tracing设计理念。
通过此模式,开发者能以简洁代码构建高扩展性的AI代理系统,涵盖从基础问答到多步骤自动化任务的全场景需求。