第 1 章:第一个 Agent -- 5 分钟跑通

本章目标:用 uv 创建项目环境,安装 SDK,创建一个最简单的 Agent,用三种方式把它跑起来,看懂返回结果。


1. 环境准备

安装 uv

uv 是新一代 Python 包管理器,速度极快。如果还没装:

# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

创建项目

# 创建项目目录并初始化
uv init agent-tutorial
cd agent-tutorial

# 指定 Python 版本(SDK 要求 3.10+)
uv python pin 3.10

# 添加 openai-agents 依赖
uv add openai-agents

执行完后,uv 会自动创建虚拟环境(.venv)、生成 pyproject.tomluv.lock。不需要手动 python -m venv 了。

配置模型

本教程使用兼容 OpenAI 格式的大模型服务(如 Ollama、vLLM、DeepSeek API、硅基流动等),需要设置两个环境变量:

# Linux / macOS
export MODEL_BASE_URL="http://localhost:8317/v1"   # 你的模型服务地址
export MODEL_API_KEY="sk-12345678"                         # API Key
export MODEL_NAME="gpt-5.2"                       # 模型名称
# Windows PowerShell
$env:MODEL_BASE_URL="http://localhost:8317/v1"
$env:MODEL_API_KEY="sk-12345678"
$env:MODEL_NAME="gpt-5.2"

如果你用的是在线 API(如 DeepSeek、硅基流动),把 MODEL_BASE_URL 换成对应的 API 地址,MODEL_API_KEY 填真实 Key 即可。

SDK 默认走 OpenAI 的 Responses API,但大多数第三方模型只支持 Chat Completions API。所以我们在代码里会用 OpenAIChatCompletionsModel 来适配。每章代码开头都会有这段配置:

import os
from openai import AsyncOpenAI
from agents import OpenAIChatCompletionsModel, set_tracing_disabled

# 关闭追踪(如果没有 OpenAI 平台的 API Key,追踪会报错)
set_tracing_disabled(True)

# 创建兼容 OpenAI 格式的客户端
client = AsyncOpenAI(
    base_url=os.getenv("MODEL_BASE_URL", "http://localhost:8317/v1"),
    api_key=os.getenv("MODEL_API_KEY", "sk-12345678"),
)

# 创建模型实例
model = OpenAIChatCompletionsModel(
    model=os.getenv("MODEL_NAME", "gpt-5.2"),
    openai_client=client,
)

# 后续创建 Agent 时传入 model 参数
# agent = Agent(name="xxx", instructions="xxx", model=model)

运行代码

后面所有代码都通过 uv run 执行,它会自动使用项目的虚拟环境:

uv run python hello_agent.py

2. 核心概念:Agent 到底是什么?

一句话:Agent 就是一个有性格、有技能的 AI 员工。

你招一个员工,得告诉他: - 你叫什么name)—— 方便管理,尤其多个 Agent 协作时区分谁是谁 - 你的工作守则instructions)—— 系统提示词,决定了这个 Agent 的行为风格 - 你会用什么工具tools)—— 函数调用,让 AI 能做事而不只是说话 - 你能把活儿转给谁handoffs)—— 多 Agent 协作,后面章节详细讲

SDK 里的 Agent 类就是对这些概念的封装。创建一个 Agent,本质上就是在描述一个"AI 员工"的 profile。


3. 第一个代码:最简 Agent

import asyncio
import os
from openai import AsyncOpenAI
from agents import Agent, Runner, OpenAIChatCompletionsModel, set_tracing_disabled

# --- 模型配置(每章都会有这段,后面不再重复解释)---
set_tracing_disabled(True)
client = AsyncOpenAI(
    base_url=os.getenv("MODEL_BASE_URL", "http://localhost:8317/v1"),
    api_key=os.getenv("MODEL_API_KEY", "sk-12345678"),
)
model = OpenAIChatCompletionsModel(
    model=os.getenv("MODEL_NAME", "gpt-5.2"),
    openai_client=client,
)

async def main():
    # 创建一个 Agent:名字、指令、模型
    agent = Agent(
        name="俳句诗人",
        instructions="你只用俳句(三行诗,5-7-5音节)的形式回答问题。",
        model=model,
    )

    # 运行 Agent,传入用户消息
    result = await Runner.run(agent, "给我讲讲递归")
    print(result.final_output)

if __name__ == "__main__":
    asyncio.run(main())

运行一下:

uv run python hello_agent.py

你会看到类似这样的输出:

自己呼自己,
层层拆解到尽头,
归来已成空。

就这么简单。两个核心对象:Agent(描述员工)和 Runner(让员工干活)。


4. 三种运行方式

SDK 提供了三种方式来运行 Agent,适用于不同场景:

4.1 Runner.run() -- 异步运行

import asyncio
from agents import Agent, Runner

# ... 省略模型配置(参考上面的 client/model 初始化代码)...

async def main():
    agent = Agent(name="助手", instructions="用简洁的中文回答问题。", model=model)

    # 异步运行,需要 await
    result = await Runner.run(agent, "Python 的 GIL 是什么?")
    print(result.final_output)

asyncio.run(main())

适用场景: 你的代码本身就是 async 的(比如 FastAPI、异步爬虫)。这是最常用的方式。

4.2 Runner.run_sync() -- 同步运行

from agents import Agent, Runner

# ... 省略模型配置 ...

agent = Agent(name="助手", instructions="用简洁的中文回答问题。", model=model)

# 同步运行,不需要 async/await
result = Runner.run_sync(agent, "Python 的 GIL 是什么?")
print(result.final_output)

适用场景: 脚本、命令行工具、不想写 async 的场合。内部其实就是帮你调了 asyncio.run()

注意:如果当前已经有事件循环在跑(比如在 Jupyter Notebook 或 FastAPI 的异步上下文里),run_sync() 会报错。这时候老老实实用 Runner.run()

4.3 Runner.run_streamed() -- 流式运行

import asyncio
from agents import Agent, Runner

# ... 省略模型配置 ...

async def main():
    agent = Agent(name="助手", instructions="用简洁的中文回答问题。", model=model)

    # 流式运行,逐步获取事件
    result = Runner.run_streamed(agent, "Python 的 GIL 是什么?")

    async for event in result.stream_events():
        # 每个 event 都是一个语义事件,带有 type 字段
        print(event, flush=True)

    # 流结束后,result 上也能拿到最终输出
    print("\n最终输出:", result.final_output)

asyncio.run(main())

适用场景: 需要"打字机效果"的实时输出,比如聊天界面。后面章节会详细展开。

三种方式对比

方式 异步 返回类型 适合场景
Runner.run() RunResult async 代码,最通用
Runner.run_sync() RunResult 脚本、CLI
Runner.run_streamed() RunResultStreaming 实时输出、聊天 UI

5. RunResult 结果解读

Runner.run()Runner.run_sync() 返回的都是 RunResult 对象。重点关注这几个属性:

import asyncio
from agents import Agent, Runner

# ... 省略模型配置 ...

async def main():
    agent = Agent(name="助手", instructions="用简洁的中文回答问题。", model=model)
    result = await Runner.run(agent, "什么是装饰器?")

    # 最终输出文本 —— 最常用的,就是 Agent 的回答
    print("回答:", result.final_output)

    # 最后一个处理请求的 Agent(多 Agent 协作时有用)
    print("最后处理的 Agent:", result.last_agent.name)

    # 运行过程中产生的所有新项目(消息、工具调用等)
    print("新产生的项目数:", len(result.new_items))
    for item in result.new_items:
        print(f"  - {type(item).__name__}")

    # 原始模型响应列表
    print("模型调用次数:", len(result.raw_responses))

asyncio.run(main())
属性 类型 说明
final_output Any Agent 的最终输出。默认是 str,设了 output_type 就是对应的结构化对象
last_agent Agent 最后实际执行的 Agent。有 handoff 时可能跟起始 Agent 不同
new_items list[RunItem] 运行过程中新产生的所有项目:消息、工具调用、工具结果等
raw_responses list[ModelResponse] 原始的模型响应,用于调试或审计
input str \| list 传入的原始输入
input_guardrail_results list 输入护栏的检查结果
output_guardrail_results list 输出护栏的检查结果

6. Agent 核心参数速查

from agents import Agent

agent = Agent(
    # === 必填 ===
    name="客服助手",              # Agent 名称,用于标识和日志

    # === 常用 ===
    instructions="你是一个友善的客服...",  # 系统提示词,定义 Agent 的行为
    model=model,                  # 使用的模型(传入 OpenAIChatCompletionsModel 实例)
    tools=[],                     # 工具列表(函数调用),下一章详解
    handoffs=[],                  # 可以转交的其他 Agent
    output_type=None,             # 输出类型,None 表示纯文本 str

    # === 进阶 ===
    model_settings=None,          # 模型参数调优(temperature 等)
    input_guardrails=[],          # 输入护栏,检查用户输入
    output_guardrails=[],         # 输出护栏,检查 Agent 输出
    hooks=None,                   # 生命周期钩子,用于监控和干预
    tool_use_behavior="run_llm_again",  # 工具调用后的行为策略
)

几个要点:


7. 完整可运行代码

把所有知识点串起来,下面是两个完整版本,直接复制就能跑。

异步版

"""
hello_agent_async.py
异步版 Hello Agent -- 展示 Runner.run() 的用法
"""
import asyncio
import os
from openai import AsyncOpenAI
from agents import Agent, Runner, OpenAIChatCompletionsModel, set_tracing_disabled

# --- 模型配置 ---
set_tracing_disabled(True)
client = AsyncOpenAI(
    base_url=os.getenv("MODEL_BASE_URL", "http://localhost:8317/v1"),
    api_key=os.getenv("MODEL_API_KEY", "sk-12345678"),
)
model = OpenAIChatCompletionsModel(
    model=os.getenv("MODEL_NAME", "gpt-5.2"),
    openai_client=client,
)


async def main():
    # 创建 Agent
    agent = Agent(
        name="旅行顾问",
        instructions="你是一个专业的旅行顾问,用简洁友好的中文回答旅行相关问题。",
        model=model,
    )

    # 异步运行
    result = await Runner.run(agent, "推荐三个适合冬天去的国内城市,每个一句话说明理由。")

    # 输出结果
    print("=== Agent 回答 ===")
    print(result.final_output)

    print("\n=== 运行信息 ===")
    print(f"最后处理的 Agent: {result.last_agent.name}")
    print(f"模型调用次数: {len(result.raw_responses)}")
    print(f"新产生的项目数: {len(result.new_items)}")


if __name__ == "__main__":
    asyncio.run(main())

同步版

"""
hello_agent_sync.py
同步版 Hello Agent -- 展示 Runner.run_sync() 的用法
"""
import os
from openai import AsyncOpenAI
from agents import Agent, Runner, OpenAIChatCompletionsModel, set_tracing_disabled

# --- 模型配置 ---
set_tracing_disabled(True)
client = AsyncOpenAI(
    base_url=os.getenv("MODEL_BASE_URL", "http://localhost:8317/v1"),
    api_key=os.getenv("MODEL_API_KEY", "sk-12345678"),
)
model = OpenAIChatCompletionsModel(
    model=os.getenv("MODEL_NAME", "gpt-5.2"),
    openai_client=client,
)


def main():
    # 创建 Agent
    agent = Agent(
        name="旅行顾问",
        instructions="你是一个专业的旅行顾问,用简洁友好的中文回答旅行相关问题。",
        model=model,
    )

    # 同步运行,不需要 async/await
    result = Runner.run_sync(agent, "推荐三个适合冬天去的国内城市,每个一句话说明理由。")

    # 输出结果
    print("=== Agent 回答 ===")
    print(result.final_output)

    print("\n=== 运行信息 ===")
    print(f"最后处理的 Agent: {result.last_agent.name}")
    print(f"模型调用次数: {len(result.raw_responses)}")
    print(f"新产生的项目数: {len(result.new_items)}")


if __name__ == "__main__":
    main()

8. 小结

这一章你学到了:

下一章我们给 Agent 装上工具(Tools),让它不只会说话,还能干活。

第2章 工具 →