ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Agent SDK 实战:从业务拆解到工作流编排的落地指南

Agent SDK 实战:从业务拆解到工作流编排的落地指南 1. 从能聊到能干活Agent SDK 到底解决了什么很多人第一次接触 Agent 这个概念都是从聊天机器人开始的。你问它一句它回你一句看起来挺聪明但真到了业务场景里就露馅了——它没法查你的数据库没法调你的接口没法在任务失败时重试更没法把用户发来一张发票图片这件事自动走完识别→校验→录入→通知财务的完整链路。这就是能聊和能干活之间的鸿沟。Agent SDK 这类工具要解决的核心问题就是把大模型的推理能力和真实世界的工具调用能力缝合在一起。它给模型一套手脚可以调用函数、访问外部数据、执行多步决策并且在每一步之后根据结果决定下一步做什么。OpenAI Agents SDK 和 LangGraph 是当前两条主流路线前者偏向轻量、开箱即用后者偏向图结构、可控性强。选哪个不是重点重点是你要理解它们共同的那套心智模型Agent 模型 工具 循环 状态。我见过太多团队在这个阶段踩坑。他们兴冲冲地接了一个 SDK写了个 demo发现哇能自动查天气了然后就想直接上生产。结果一遇到真实业务的多分支、多轮次、需要人工介入的场景整个流程就崩了。原因很简单demo 是线性的业务是网状的。所以这篇文章不打算给你灌一堆概念而是从怎么把一个真实业务场景拆成 Agent 能执行的工作流这个角度把整条链路讲透。这篇文章适合谁如果你已经会写 Python能看懂函数和类但对怎么让 AI 真正下地干活还没找到抓手那这篇就是写给你的。如果你已经在用 LangChain 但觉得链路太死板想升级到更灵活的 Agent 编排也能从里面找到可复用的思路。我会尽量把每一步的为什么讲清楚而不是只丢一段代码让你抄。2. 业务场景拆解先想清楚哪些步骤该交给模型2.1 判断一个场景适不适合 Agent 化不是所有业务都值得做成 Agent。我的经验是用三个问题快速筛一遍这个流程里有没有需要理解自然语言或非结构化信息的环节比如从一段客户描述里提取意图、从一张截图里读出关键字段。如果有Agent 有优势如果全是结构化数据的固定计算那用普通脚本更稳更便宜。这个流程的步骤数是不是超过三步且步骤之间有依赖单步任务直接调一次模型就行没必要上 Agent 框架。三步以上、后一步依赖前一步结果的才值得编排。失败之后能不能自动重试或降级如果每一步失败都必须人工介入那 Agent 的价值会被大幅削弱因为它的核心优势就是自主决策和自愈。举个具体例子。假设你要做一个客户询价自动响应的流程客户发来一段文字描述需求系统要识别产品类别、查询库存和价格、生成报价单、发邮件给客户。这里面识别产品类别和生成报价单文案适合交给模型查询库存价格适合做成工具函数发邮件是确定性动作。这就是一个典型的混合流程非常适合 Agent 化。2.2 把流程画成节点 边再动手写代码在写任何代码之前我强烈建议你先在纸上或者白板上把流程画成图。每个节点是一个动作每条边是动作之间的流转条件。这一步看起来土但能帮你省下大量返工。以询价流程为例节点大致是接收客户消息入口意图识别与信息抽取模型节点判断信息是否完整条件边查询库存与价格工具节点生成报价文案模型节点发送邮件工具节点记录日志并结束出口其中第 3 步会产生两条边信息完整就走第 4 步不完整就回到第 2 步追问客户。这个回环就是 Agent 和普通脚本最大的区别——它能根据状态决定往回走还是往前走。提示画图的时候一定要把异常出口也画出来。比如查询库存接口超时了怎么办是重试三次还是直接转人工这些分支如果不提前想清楚代码写到一半会非常痛苦。2.3 定义清楚每个节点的输入输出契约这是最容易被忽略、但后期最要命的一步。每个节点的输入是什么、输出是什么、输出用什么数据结构必须提前定死。因为 Agent 框架在节点之间传递的是状态对象如果契约不清晰模型很容易在中间步骤自由发挥导致下游节点拿到一堆没法解析的文本。我的做法是给每个节点定义一个明确的返回结构能用结构化输出就用结构化输出。比如意图识别节点不要让它返回一段话而是返回一个 JSON{ intent: inquiry, product_category: industrial_pump, quantity: 20, missing_fields: [delivery_date] }这样下游节点可以直接读字段而不是去猜模型这段话什么意思。OpenAI Agents SDK 支持结构化输出LangGraph 里也可以用 Pydantic 模型约束状态两者都能做到。3. 环境搭建Python 侧最容易翻车的几个地方3.1 Python 版本与虚拟环境的选择Agent 相关的库更新非常快很多新特性只在较新的 Python 版本上可用。我的建议是直接用 Python 3.10 或 3.11不要用 3.8、3.9 这种偏老的版本因为部分依赖会要求 3.10 的类型语法。3.12 也可以但偶尔会遇到某些库还没适配的情况生产环境求稳的话 3.11 是甜点区。虚拟环境一定要建不要图省事装在全局。用 venv 就够了python -m venv .venv source .venv/bin/activate # Linux / macOS .venv\Scripts\activate # Windows装完之后先升级 pip这一步很多人跳过结果装包时各种奇怪的编译错误python -m pip install --upgrade pip3.2 依赖安装与常见报错核心依赖通常包括 Agent 框架本身、模型调用 SDK、以及做数据校验的 pydantic。安装时最容易出问题的是版本冲突尤其是 pydantic 的 v1 和 v2 不兼容。如果你项目里还用了别的老库很可能出现这个库要 pydantic v1那个库要 v2的情况。我的处理原则是新项目一律用 pydantic v2遇到不兼容的老库就找替代品或者升级。装完之后用下面这行验证一下python -c import pydantic; print(pydantic.VERSION)如果打印出来是 2.x 开头就对了。另外如果你在 Windows 上装某些带 C 扩展的库报错多半是缺编译工具装一个 Visual Studio Build Tools 基本能解决。Linux 上则通常是缺 python3-dev 和 build-essential。3.3 API 密钥与配置管理密钥千万不要硬编码在代码里。用环境变量或者 .env 文件管理配合 python-dotenv 读取。一个典型的 .env 长这样MODEL_API_KEYyour_key_here MODEL_BASE_URLhttps://your_endpoint LOG_LEVELINFO然后在代码入口处加载from dotenv import load_dotenv import os load_dotenv() api_key os.getenv(MODEL_API_KEY)注意.env 文件一定要加进 .gitignore我见过不止一个团队把密钥提交到仓库里后来不得不紧急轮换。这种低级错误一旦发生排查起来很浪费时间。4. 用 Agent SDK 编排工作流从单 Agent 到多节点协作4.1 单 Agent 模式的适用边界最简单的 Agent 就是一个模型加几个工具让它自己决定调哪个。OpenAI Agents SDK 里定义一个 Agent 大概是这样from agents import Agent, function_tool function_tool def query_inventory(product_id: str) - dict: 查询指定产品的库存和价格 # 实际业务里这里会调数据库或内部接口 return {product_id: product_id, stock: 120, price: 89.5} agent Agent( name询价助手, instructions你负责处理客户询价先抽取产品信息再查询库存最后生成报价。, tools[query_inventory], )这种模式适合步骤少、分支少的场景。一旦流程超过五六个步骤或者需要严格的控制流比如必须先校验再查询单 Agent 就会变得不可控——它可能跳过校验直接查询也可能在某个环节反复绕圈。这时候就得上图结构。4.2 用 LangGraph 把流程显式建模成状态机LangGraph 的核心思想是把 Agent 流程建模成一张有向图每个节点是一个函数边决定流转。它的好处是控制流完全由你掌握模型只在需要它的节点里发挥作用。先定义状态。状态是一个在节点间传递的字典通常用 TypedDict 或 Pydantic 模型from typing import TypedDict, List class InquiryState(TypedDict): raw_message: str product_category: str quantity: int missing_fields: List[str] quote_text: str status: str然后定义节点函数。每个节点接收状态、返回状态的更新部分def extract_info(state: InquiryState) - dict: # 这里调用模型做信息抽取 result call_model_for_extraction(state[raw_message]) return { product_category: result[category], quantity: result[quantity], missing_fields: result[missing], } def check_completeness(state: InquiryState) - str: if state[missing_fields]: return ask_more return query注意check_completeness返回的是字符串这个字符串会被用作条件边的判断依据。这就是 LangGraph 里条件边的用法——根据当前状态决定下一步走哪个节点。4.3 条件边与循环让流程会回头把节点和边组装成图from langgraph.graph import StateGraph, END graph StateGraph(InquiryState) graph.add_node(extract, extract_info) graph.add_node(ask_more, ask_customer) graph.add_node(query, query_inventory_node) graph.add_node(quote, generate_quote) graph.add_node(send, send_email) graph.set_entry_point(extract) graph.add_conditional_edges(extract, check_completeness, { ask_more: ask_more, query: query, }) graph.add_edge(ask_more, extract) # 追问后回到抽取节点 graph.add_edge(query, quote) graph.add_edge(quote, send) graph.add_edge(send, END) app graph.compile()这里最关键的是graph.add_edge(ask_more, extract)这条边它构成了一个循环信息不全就追问追问完重新抽取直到信息完整才往下走。这个循环必须设置上限否则模型可能永远觉得信息不全陷入死循环。我的做法是在状态里加一个retry_count超过三次就强制转人工。提示所有带循环的 Agent 流程都必须有熔断机制。可以是重试次数上限也可以是超时时间。没有熔断的循环在生产环境里就是定时炸弹。4.4 多 Agent 协作什么时候该拆什么时候不该拆当流程里出现明显不同的角色时可以考虑拆成多个 Agent。比如一个负责理解客户意图一个负责查数据一个负责写文案。每个 Agent 有自己的 instructions 和工具集职责单一调试起来也更容易。但我要泼一盆冷水不要为了拆而拆。我见过有人把本来一个 Agent 能搞定的事情拆成五个结果节点之间传递状态的开销比干活还大而且一旦某个环节出错排查链路长得让人崩溃。判断标准很简单如果两个角色的工具集完全不重叠、instructions 差异很大那就拆如果只是步骤不同但用的是同一套工具那没必要拆。5. 工具调用与状态管理Agent 真正下地干活的关键5.1 工具函数的写法与参数校验工具是 Agent 和真实世界交互的接口。写工具函数有几个硬性要求函数名和 docstring 要清晰因为模型是靠这些来判断什么时候调用它的。名字叫do_stuff的工具模型永远不知道该不该用。参数类型要明确用类型注解。模型会根据类型生成参数类型模糊会导致传参错误。返回值要结构化最好是 dict 或 Pydantic 模型方便下游解析。要有错误处理工具内部抛异常要捕获并返回可读的错误信息而不是让整个流程崩掉。function_tool def query_price(product_id: str, quantity: int) - dict: 根据产品ID和数量查询单价与总价。 Args: product_id: 产品唯一标识 quantity: 采购数量必须为正整数 if quantity 0: return {error: 数量必须大于0} try: unit_price fetch_price_from_db(product_id) return { unit_price: unit_price, total: unit_price * quantity, } except Exception as e: return {error: f查询失败: {str(e)}}5.2 状态在节点间怎么传才不乱状态管理的核心原则是只传必要信息不传中间过程。很多人喜欢把模型的原始输出、思考过程、临时变量全塞进状态里结果状态对象越来越臃肿节点之间互相污染。我的做法是把状态分成两层一层是业务状态只放最终需要的结果字段另一层是调试信息单独存日志不进状态。这样状态对象始终干净节点函数也容易测试。另外LangGraph 里节点返回的是状态更新不是完整状态。框架会自动把更新合并进去。这个机制要理解清楚否则你会困惑为什么节点里读到的状态和返回的不一样。5.3 让模型输出稳定结构化数据的技巧模型输出不稳定是 Agent 落地最大的痛点之一。同一个输入今天返回 JSON明天返回一段带解释的文字。解决办法有几个第一用框架自带的结构化输出能力。OpenAI Agents SDK 支持指定 output_typeLangGraph 里可以配合 with_structured_output。让模型在解码层面就受约束比事后用正则去抠要可靠得多。第二在 prompt 里给明确的 schema 示例。不要只说返回 JSON而是把完整的字段名、类型、示例都写出来。第三加一层校验和重试。拿到输出后先用 Pydantic 校验不通过就把错误信息喂回给模型让它重试。这个重试逻辑最好封装成一个通用函数所有需要结构化输出的节点都复用它。from pydantic import BaseModel, ValidationError class ExtractedInfo(BaseModel): category: str quantity: int missing: list[str] def extract_with_retry(text: str, max_retry: int 3) - ExtractedInfo: for i in range(max_retry): raw call_model(text) try: return ExtractedInfo.model_validate_json(raw) except ValidationError as e: text f{text}\n\n上次输出有误{e}\n请重新输出合法JSON。 raise RuntimeError(结构化输出重试超限)6. 实测中的坑那些文档不会告诉你的问题6.1 模型自作主张跳过步骤这是最常见的问题。你明明设计了先校验再查询的流程但模型在某个节点里直接把两步合并了或者干脆跳过了校验。根本原因是模型倾向于尽快给出答案而不是严格按流程走。解决办法是把关键步骤做成独立的工具节点而不是让模型在一个节点里自由发挥。也就是说能用代码强制的顺序就不要交给模型判断。模型只负责它真正擅长的部分——理解和生成流程控制交给图结构。6.2 工具调用参数类型对不上模型生成的参数经常和函数签名对不上。比如函数要 int模型传了个字符串 20函数要 list模型传了个逗号分隔的字符串。这类问题在测试阶段不容易发现因为模型有时候恰好传对了。我的经验是在工具函数入口做一次强制类型转换和校验把容错做在工具层而不是指望模型每次都传对。同时把参数描述写得更具体比如quantity 是一个整数例如 20不要传字符串。6.3 长流程中的上下文膨胀流程一长状态里积累的信息越来越多每次调用模型都要把整个状态塞进 prompttoken 消耗飙升而且模型容易被无关信息干扰。解决办法是给每个节点只传它需要的那部分状态而不是整个状态对象。LangGraph 里可以在节点函数里只取需要的字段OpenAI Agents SDK 里则可以通过精简 instructions 和上下文来控制。6.4 错误处理与重试的边界重试不是万能的。有些错误重试一百次也没用比如参数本身就不合法有些错误重试一次就好比如网络抖动。我的分类原则是错误类型处理方式网络超时、限流指数退避重试最多3次参数校验失败不重试返回错误让上游修正模型输出格式错误带错误信息重试最多3次业务规则冲突不重试转人工工具内部异常记录日志返回可读错误这张表建议直接做成代码里的错误处理策略而不是每次遇到问题临时判断。7. 从跑通到上线还需要补哪些工程能力7.1 日志与可观测性Agent 流程最大的调试难点是你不知道它中间想了什么。所以日志必须打全每个节点的输入、输出、耗时、调用的工具、模型的原始返回都要记下来。最好给每次流程执行分配一个 trace_id这样出问题时能把整条链路串起来看。我一般会在状态里放一个 trace_id每个节点打日志时都带上它。查询日志时按 trace_id 过滤整条执行路径一目了然。这个习惯在排查线上问题时能救命。7.2 人工介入节点再智能的 Agent 也有搞不定的时候。设计流程时一定要留转人工的出口。可以是某个条件触发也可以是重试超限后自动触发。人工介入节点通常做两件事把当前状态展示给人工让人工补充或修正然后把修正后的状态重新注入流程继续执行。这个能力在早期尤其重要因为你对模型行为的预期往往不准有了人工兜底至少业务不会中断。7.3 成本与性能的平衡Agent 流程的 token 消耗比单次调用高得多因为每一步都要带上下文。控制成本的手段有几个能不用模型的节点就不用比如纯数据查询和格式转换给每个节点的 prompt 做精简去掉冗余说明对简单任务用小模型复杂任务才用大模型。性能方面节点能并行就并行。比如查库存和查物流如果互不依赖可以同时发起而不是串行等待。LangGraph 支持并行节点用好了能显著缩短整体耗时。7.4 测试策略Agent 的测试和普通代码不一样因为输出有随机性。我的做法是分三层测第一层测工具函数这是确定性的用单元测试覆盖第二层测单个节点的输出结构只校验格式和关键字段不校验具体文案第三层测整条流程用一批真实场景的输入跑端到端人工检查结果是否合理。第三层测试最花时间但最有价值。我通常会攒一个回归用例集每次改流程都跑一遍看看有没有把之前能跑通的场景搞坏。这个习惯能避免大量改一处崩三处的问题。8. 一个可复用的落地节奏如果你现在手上就有一个业务场景想 Agent 化我建议按这个节奏走先用纸笔把流程画成节点和边标出哪些节点用模型、哪些用代码然后搭一个最小可运行版本只跑通主干路径不管异常分支接着把工具函数一个个补上每个都单独测通再补条件边和循环加上熔断最后加日志、人工介入和错误处理做端到端回归。这个顺序的好处是每一步都有可验证的产出不会出现写了一堆代码但不知道对不对的情况。我自己做过的几个 Agent 项目凡是按这个节奏来的上线都比较顺凡是上来就写代码、边写边想的后期返工都很惨。最后分享一个我踩过的坑不要一开始就追求全自动。我早期做过一个流程想让 Agent 从接收需求到发合同全自动完成结果因为中间某个环节模型判断失误发出去一份错误报价差点造成实际损失。后来改成关键节点必须人工确认反而跑得更稳业务方也更愿意用。自动化的价值不在于无人而在于把人从重复劳动里解放出来去做真正需要判断的事。这个认知转变比任何技术选型都重要。
返回列表