本节摘要:Runner 是"执行层"的主角——它把 Agent 的定义变成实际对话。本节讲清 Runner 的执行流程(模型循环 + 工具循环)、三种运行模式(同步/异步/流式)、结果对象的结构,以及如何用 Runner 处理复杂流程。
阅读完本节,你应当能够:
"智能体怎么自动调工具的?"——答案在 Runner 里。Runner 维护一个循环:调模型 → 模型说要调工具 → Runner 执行工具 → 结果回传 → 再调模型,直到模型给出最终答案。开发者不用写这个循环,Runner 全包了——这是 SDK 最省心的部分。
理解 Runner 还有一个更实际的动机:它是所有"执行细节"的集中地。同步还是异步、上下文怎么传、最多循环几轮、结果怎么取,这些工程问题都在 Runner 这一层解决。掌握了 Runner,你就掌握了 SDK 的执行模型。
Runner 的执行本质是循环调度:
一次运行就是"模型调用 → 工具执行"的往复,直到模型输出最终答案。

| 模式 | 用法 | 场景 |
|---|---|---|
| 同步 | run_sync | 脚本、演示、简单调用 |
| 异步 | await Runner.run | Web 服务、并发 |
| 流式 | run_streamed | 打字机效果、长响应 |
结果对象包含:final_output(最终回答)、last_agent(哪个 Agent 收尾)、items(完整过程)。
from agents import Agent, Runner agent = Agent(name="demo", instructions="用中文回答。") # 同步 r1 = Runner.run_sync(agent, "同步运行") # 异步(需要 async 环境) async def main(): r2 = await Runner.run(agent, "异步运行") print(r2.final_output) # 流式:逐段产出 r3 = Runner.run_streamed(agent, "流式运行") async for event in r3.stream_events(): print(event) # 处理文本增量、工具调用等事件
💡 关键直觉:Runner 帮你管住"循环",但你要看懂"循环"——排查"为什么没调工具"时,看模型输出与工具日志,就知道是模型没决定调,还是工具执行失败。
result = Runner.run_sync(agent, "查一下订单状态") print(result.final_output) # 最终回答 print(result.last_agent) # 收尾的智能体 print(result.trace_id) # 本次运行的追踪 ID for item in result.new_items: print(type(item).__name__, item) # 本次新增的消息与工具调用
new_items 在多轮会话场景特别有用:你可以只取"本轮新增"的内容拼进下一轮,避免重复传历史。
from agents import Agent, Runner agent = Agent(name="助手", instructions="回答用户问题。") # Web 场景用异步,避免阻塞 async def handle(user_input: str) -> str: result = await Runner.run(agent, user_input) return result.final_output
| 现象 | 排查 |
|---|---|
| 工具没被调用 | 看模型是否"决定"调工具,看 tools 是否挂载 |
| 循环卡住 | 设置最大轮数限制 |
| 结果为空 | 检查模型与工具返回 |
⚠️ 常见坑:无限制循环。模型可能反复调工具(比如工具一直返回异常)。生产环境务必设置最大迭代次数,防失控。SDK 的 RunConfig 里可以配置 max_turns 等限制,上线前一定确认。
⚠️ 常见坑:在同步函数里跑 async。忘了
asyncio.run或事件循环,程序会报错或阻塞——先想清楚自己的运行环境,脚本用同步,服务用异步。
流式模式(run_streamed)不只是"打字机特效",它有三个实用场景:第一,长回答的用户体验——先给用户"正在思考"的反馈,再逐步展示内容,避免白屏等待;第二,长流程的进度提示——智能体在处理多个工具时,可以先把每个阶段的状态流式推给前端;第三,实时拦截——输出过程中发现异常内容,可以在流式阶段就处理,而不是等完整结果出来再补救。实现时按事件类型消费即可:文本增量事件用于渲染,工具调用事件用于展示进度。
from agents import Agent, Runner agent = Agent(name="流式助手", instructions="用中文回答。") async def chat_stream(user_input: str): result = Runner.run_streamed(agent, user_input) async for event in result.stream_events(): # 文本增量:实时渲染;工具事件:展示进度 print(event)
from agents import Agent, Runner agent = Agent(name="多轮助手", instructions="用中文回答。") # 第一轮 r1 = Runner.run_sync(agent, "我叫小明,记一下") # 第二轮:把上一轮结果作为输入的一部分,保持上下文 r2 = Runner.run_sync(agent, r1.to_input_list() + [{"role": "user", "content": "我叫什么?"}]) print(r2.final_output)
多轮对话的本质是"把历史消息喂回去"。to_input_list() 可以把上一轮结果转成可继续输入的消息列表,配合会话管理(第 3 章)使用,就能搭出真正连续的对话体验。
Runner 会用了,下一节看引擎——模型集成与管理。