
1. 从一次多智能体协作翻车说起OpenAI Agents SDK 是 OpenAI 官方推出的轻量级智能体运行时与编排框架它把多轮执行循环、工具调用、Agent 之间的 Handoff、Guardrail、Session 记忆和 Tracing 都封装成一套清晰的 Python 抽象。适合谁适合已经会用 Python 写函数、想让多个 Agent 分工协作、又不想自己手写调度循环的开发者。我最初接触它时想搭一个「工程问题分诊」的小系统用户丢一句问题分诊 Agent 判断类型再移交给视觉部署或机器人集成专家。结果第一次跑就卡住了——Handoff 之后目标 Agent 没有按预期接管工具调用参数也报类型错误排查半天才发现是模型接入层配置没对齐。这类问题在本地复现时特别常见SDK 本身逻辑没问题但模型端点、API Key、Base URL 这些前置配置一旦错位Runner 的循环就会在第一次模型调用时直接抛异常或者 Handoff 静默失败。所以这篇不空谈架构而是给你一套可复现的配置骨架settings.json 与 config.toml 怎么写、Runner/Tools/Handoff 怎么串起来、一次完整的 Handoff 调用链怎么验证。目标很明确——照着做你能在本地稳定跑通 Agents SDK 的接入流程而不是停在「装完包就报错」的阶段。下面所有配置都以 TaoToken 作为模型接入层来演示因为它的 API 端点兼容 OpenAI 协议改一行 base_url 就能让 Agents SDK 走通省去自己搭转发层的麻烦。你如果已经有别的兼容端点把地址换掉即可配置结构完全一样。2. TaoToken 前置把模型接入层先固定下来Agents SDK 默认走 OpenAI 的 Responses API但它的模型抽象允许你指定自定义 Provider。对本地开发来说最省事的做法是让 SDK 通过一个兼容 OpenAI 协议的端点访问模型这样 Agent、Runner、Handoff 的代码一行都不用改只改环境变量和配置文件。TaoToken 在这里扮演的就是这个「模型接入层」角色。它的 API 地址是https://taotoken.net/api兼容 OpenAI 的请求格式。你需要先在控制台创建一个 API Key然后把它写进环境变量。注意不要把 Key 硬编码进业务代码也不要提交到 Git后面我会用 settings.json 和 config.toml 把这类敏感信息集中管理。创建 Key 的入口在控制台的 API Keys 页面登录后新建一个即可。拿到 Key 之后先别急着写 Agent先用一条 curl 确认端点通不通export TAOTOKEN_API_KEYsk-你的key curl -s https://taotoken.net/api/v1/models \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ | head -c 400如果返回一个包含模型列表的 JSON说明 Key 和网络都没问题。这一步很关键因为 Agents SDK 报错时往往把底层 HTTP 错误包在 Runner 异常里先单独验证端点能省掉大量排查时间。接下来安装 SDK。建议用虚拟环境锁定版本避免 SDK 更新导致接口漂移python -m venv .venv source .venv/bin/activate pip install -U openai-agents0.18.3 pydantic版本号写死是有原因的Agents SDK 迭代很快Handoff 和 Session 的接口在不同小版本间有过调整。生产项目一定要锁版本升级前跑回归测试。3. 可复制配置settings.json 与 config.toml 骨架Agents SDK 本身不强制你用某种配置文件但工程上把模型端点、超时、轮数上限这些参数外置能让同一套 Agent 代码在本地、测试、生产之间切换。我用两个文件分工settings.json管运行时参数config.toml管模型与工具声明。先看settings.json放在项目根目录{ model: { provider: openai-compatible, base_url: https://taotoken.net/api, api_key_env: TAOTOKEN_API_KEY, default_model: gpt-4o-mini, timeout_seconds: 60, max_retries: 2 }, runner: { max_turns: 8, tool_timeout_seconds: 5.0, max_parallel_tools: 4 }, session: { backend: sqlite, db_path: agent_sessions.db }, tracing: { enabled: true, redact_keys: [api_key, authorization, password] } }这里几个参数值得说明。base_url指向 TaoToken 的 API 地址SDK 会在此基础上拼接/v1/responses之类的路径。api_key_env表示 Key 从环境变量读取而不是写在文件里。max_turns是 Runner 的循环上限防止 Agent 陷入工具调用死循环。tool_timeout_seconds给每个 Function Tool 设默认超时。再看config.toml用来声明 Agent 和工具的结构[agents.triage] name Engineering Triage Agent instructions 识别工程问题类型并移交给最合适的专家。 handoffs [vision, robot] [agents.vision] name Vision Deployment Agent handoff_description 负责 ONNX、TensorRT 和视觉模型部署。 instructions 给出可落地的模型转换、预处理和性能验证方案。 [agents.robot] name Robot Integration Agent handoff_description 负责 ROS2、传感器和控制接口集成。 instructions 重点考虑 ROS2 接口、时序、坐标系和安全控制。 [tools.query_device_profile] type function module tools.device function query_device_profile timeout 5.0然后在 Python 里读取这两个文件构造 Agent。读取逻辑我封装成一个build_agents.pyimport json import os import tomllib from pathlib import Path from agents import Agent, function_tool ROOT Path(__file__).parent def load_settings() - dict: with open(ROOT / settings.json, r, encodingutf-8) as f: return json.load(f) def load_config() - dict: with open(ROOT / config.toml, rb) as f: return tomllib.load(f) def build_agents(): settings load_settings() config load_config() # 把 base_url 和 key 注入 SDK 的模型 Provider os.environ.setdefault(OPENAI_API_KEY, os.environ[settings[model][api_key_env]]) os.environ.setdefault(OPENAI_BASE_URL, settings[model][base_url]) agents_cfg config[agents] vision Agent( nameagents_cfg[vision][name], handoff_descriptionagents_cfg[vision][handoff_description], instructionsagents_cfg[vision][instructions], ) robot Agent( nameagents_cfg[robot][name], handoff_descriptionagents_cfg[robot][handoff_description], instructionsagents_cfg[robot][instructions], ) triage Agent( nameagents_cfg[triage][name], instructionsagents_cfg[triage][instructions], handoffs[vision, robot], ) return triage, vision, robot注意OPENAI_BASE_URL这个环境变量Agents SDK 底层复用 OpenAI 客户端设置它就能让所有模型请求走 TaoToken 的端点。这是整个接入流程里最关键的一行很多人 Handoff 失败就是因为只改了 Key 没改 Base URL请求打到了默认端点。4. Runner、Tools 与 Handoff 的完整调用链配置就绪后把三大核心概念串起来。Runner 是执行循环的入口Tools 是 Agent 能调用的能力Handoff 是 Agent 之间的控制权移交。我写一个main.py包含一个 Function Tool 和一次完整的 Handoff 验证。先定义工具。工具函数要有清晰的类型注解和 DocstringSDK 会据此生成 JSON Schemafrom agents import function_tool function_tool(timeout5.0) async def query_device_profile(device: str) - dict: 查询设备的部署画像。 Args: device: 设备型号例如 Jetson Orin NX 16GB。 profiles { Jetson Orin NX 16GB: { memory_gb: 16, runtime: [TensorRT, ONNX Runtime, CUDA], notes: 适合边缘视觉和中小型多模态模型。, } } return profiles.get(device, {error: device_not_found})然后把它挂到视觉 Agent 上并跑一次 Handoffimport asyncio from agents import Runner from build_agents import build_agents from tools.device import query_device_profile async def main(): triage, vision, robot build_agents() vision.tools [query_device_profile] result await Runner.run( triage, 如何把 PointPillars ONNX 推理接入 ROS2 点云节点, max_turns8, ) print(最终 Agent:, result.last_agent.name) print(输出:, result.final_output) if __name__ __main__: asyncio.run(main())这段代码的执行链是这样的Runner 启动 triage Agent模型判断问题属于视觉部署触发 Handoff 到 vision Agentvision Agent 接管后如果问题涉及设备参数会调用query_device_profile工具工具结果写回上下文模型生成最终回答。result.last_agent会告诉你最终是哪个 Agent 完成的这是验证 Handoff 是否生效的直接证据。如果你想让 Handoff 更可控可以在 triage 的 instructions 里明确路由规则比如「涉及 ONNX、TensorRT 的问题交给 vision涉及 ROS2、传感器的问题交给 robot」。模型会据此选择 handoff 目标。实测下来指令越具体路由准确率越高。5. 验证请求与成功结果跑起来之后怎么确认整条链路真的通了我习惯分三层验证。第一层看 Runner 是否正常返回。运行python main.py如果输出类似最终 Agent: Vision Deployment Agent 输出: 针对 PointPillars ONNX 接入 ROS2建议先用 ONNX Runtime 做...说明 Handoff 成功最终 Agent 是 vision 而不是 triage。如果last_agent还是 triage说明模型没触发 Handoff检查 handoff_description 是否足够清晰。第二层看工具是否被调用。在工具函数里加一行日志function_tool(timeout5.0) async def query_device_profile(device: str) - dict: 查询设备的部署画像。 print(f[tool] query_device_profile called with device{device}) ...如果日志没打印说明模型没选择调用工具可能是 instructions 里没强调「必须调用工具后再回答」。第三层看 Tracing。SDK 默认开启 Tracing你可以在控制台看到完整的 Span 树Agent Span、Generation Span、Function Span、Handoff Span。Handoff Span 存在就证明控制权移交被记录下来了。生产环境建议把 Trace 和 request_id、tenant_id 关联方便排查。一个成功的完整输出应该包含Handoff 发生、工具被调用、最终输出符合预期、Trace 里有对应 Span。四者齐了接入流程就算稳定复现了。6. 本篇常见错误排查报错一AuthenticationError: Incorrect API key最常见的原因是OPENAI_API_KEY没设置或者设置成了别的值。检查settings.json里的api_key_env指向的环境变量是否真的存在。另外注意Agents SDK 读的是OPENAI_API_KEY不是TAOTOKEN_API_KEY所以build_agents.py里那行os.environ.setdefault(OPENAI_API_KEY, ...)不能省。报错二Connection error或请求打到默认端点只改了 Key 没改 Base URL。确认OPENAI_BASE_URL被设置为https://taotoken.net/api。可以在代码里打印os.environ.get(OPENAI_BASE_URL)确认。报错三MaxTurnsExceededAgent 在工具调用和 Handoff 之间循环超过max_turns。先调大上限看是否只是任务复杂如果还是超检查工具返回是否让模型无法收敛比如返回了模糊的错误信息导致模型反复重试。给工具返回稳定的结构化结果能显著减少循环。报错四Handoff 不触发last_agent始终是起始 Agent。原因通常是handoff_description太笼统或者起始 Agent 的 instructions 没说明何时移交。把每个目标 Agent 的职责写具体并在起始 Agent 里给出明确的路由规则。报错五工具参数类型错误Function Tool 的参数注解和实际传入不匹配。SDK 用 Pydantic 校验输入如果模型生成的参数不符合 Schema会直接报错。确保参数名、类型、Docstring 描述一致必要时用Field加约束。报错六Session 数据串了多个用户共用一个 Session ID导致上下文污染。Session 的 key 要包含租户和用户维度比如tenant-a:user-1001:conversation-42不要用全局固定值。7. 下一步把骨架跑成你自己的系统到这里你已经有了一个可复现的骨架settings.json 管运行时参数config.toml 管 Agent 声明build_agents.py 负责组装main.py 跑 Handoff 验证。接下来可以按需扩展。如果你要长期跑编码类 Agent比如让 Agent 持续调用工具、维护会话、跨多次运行保留记忆建议了解一下 Coding Plan它更适合这种长周期、多轮次的场景。如果你只是想先验证某个模型在 Handoff 里的表现可以直接在模型对话里试几轮确认路由逻辑再落到代码。接入过程中如果遇到 Key 或端点问题去 API Keys 页面重新生成一个再对照接入文档检查 Base URL 和请求头。我的经验是先把单 Agent 单工具跑通再加第二个 Agent 和 Handoff最后才上 Session 和 Tracing。每加一层都验证一次last_agent和工具日志出问题时范围小、好定位。这套骨架我用了几个项目改的只是 config.toml 里的 Agent 声明和工具模块Runner 和 Handoff 的代码基本没动过。