openai/openai-cs-agents-demo 是个好东西-分享解释

543 阅读12分钟

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
    护栏系统 :用于对话控制的相关性和越狱护栏

图示逻辑:

image.png

OpenAI Agents SDK介绍:

OpenAI Agents SDK 是一个轻量级但功能强大的框架,专为构建多代理工作流设计,强调代理间的协作、工具调用和安全控制。以下基于官方文档和核心实践,详细解析你列出的关键类及其在架构中的作用:


🧠 一、核心架构与运行机制

OpenAI Agents SDK 的核心是 Agent(代理),它由大语言模型(LLM)驱动,通过 Runner 执行循环(Run Loop)协调工作流。流程如下:

  1. 输入处理:用户输入经过 InputGuardrail 安全检查。
  2. 决策生成:LLM 解析意图,决定调用工具、发起交接或直接回复。
  3. 动作执行
    • 调用工具(如 API、函数)并返回结果;
    • 通过 Handoff 转移控制权给其他代理;
    • 生成文本回复。
  4. 输出处理:结果经 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)  # 输出天气代理的响应

💡 四、应用场景与优势

  1. 复杂任务处理
    • 单代理处理简单任务(如天气查询);
    • 多代理协作处理跨领域任务(如客服→技术支持的交接)。
  2. 安全可控性
    • Guardrails 确保输入/输出合规;
    • InputGuardrailTripwireTriggered 快速拦截风险。
  3. 灵活扩展
    • 工具库可自定义(API、函数、其他代理);
    • 交接机制支持动态任务分配。

小结 :

导入的类覆盖了 OpenAI Agents SDK 的核心操作层级:

  • Runner 是中枢,驱动代理执行;
  • 输出项类(如 MessageOutputItemToolCallItem)封装运行时数据;
  • 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_itemsRunResult 的关键属性,存储代理在运行过程中生成的 中间项(Run Items)。这些项代表代理的阶段性动作,例如:
    • MessageOutputItem:文本消息(如代理的初步回复)。
    • ToolCallItem:工具调用请求(如调用天气查询函数)。
    • HandoffOutputItem:代理间交接请求(如转移任务到其他代理)。
  • 用途
    通过遍历 result.new_items,可以:
    1. 执行工具调用:检测 ToolCallItem 并执行对应的工具函数(如调用 API)。
    2. 处理交接:检测 HandoffOutputItem 并切换至目标代理。
    3. 捕获中间输出:提取 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
  • 关键步骤
    1. 记录事件:标记源代理(source_agent)向目标代理(target_agent)的交接。
    2. 查找交接规则:从源代理的handoffs列表中匹配目标代理的配置(Handoff对象)。
    3. 执行回调:若交接规则定义了on_invoke_handoff函数,则触发并记录为工具调用事件(tool_call)。
    4. 切换代理:将当前代理更新为目标代理,后续操作由新代理接管。
  • 设计意义:实现动态任务委派(例如客服路由场景)。

5. 工具调用处理 (ToolCallItemToolCallOutputItem)

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)))
  • 工具调用流程
    1. ToolCallItem:代理请求调用工具(如display_seat_map),记录调用参数。
    2. 特殊工具逻辑:某些工具(如display_seat_map)会触发前端渲染指令(DISPLAY_SEAT_MAP)。
    3. ToolCallOutputItem:工具执行完成后返回结果,记录输出事件。
  • 典型场景
    • 调用网络搜索工具获取实时信息
    • 执行代码生成或数据库查询
    • 触发前端交互组件(如座位选择器)。

🧩 设计思想与架构意义

  1. 事件驱动架构

    • 所有代理操作(消息、工具调用、交接)均转化为标准化事件(AgentEvent),便于集中监控和分析。
    • Tracing机制:事件日志可直接对接OpenAI的跟踪仪表盘,实现可视化调试(见图2)。
  2. 多代理动态协作

    • 通过HandoffOutputItem实现代理间无缝切换,支持复杂工作流分解(例如:路由代理 → 专业代理)。
    • 回调机制(on_invoke_handoff)允许在交接时执行自定义逻辑(如权限检查或数据转换)。
  3. 工具扩展性与UI集成

    • 工具调用(ToolCallItem)支持任意功能扩展(如API、计算、UI指令)。
    • 工具与前端深度集成(例如display_seat_map触发界面渲染)体现SDK的端到端能力。

💡 总结

这段代码是多代理系统的中枢处理逻辑,核心价值在于:

  1. 标准化中间项处理:将代理运行中的异构操作(消息、交接、工具)统一转为结构化数据。
  2. 支持复杂协作:通过动态代理切换(current_agent更新)和工具回调实现灵活工作流。
  3. 赋能可观测性:事件日志(events)为调试、审计和优化提供数据基础,呼应SDK的Tracing设计理念

通过此模式,开发者能以简洁代码构建高扩展性的AI代理系统,涵盖从基础问答到多步骤自动化任务的全场景需求。