news 2026/9/25 22:20:29

Agent 到底什么时候该用?FDE 如何设计一个生产级 AI Agent

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Agent 到底什么时候该用?FDE 如何设计一个生产级 AI Agent

Agent 到底什么时候该用?FDE 如何设计一个生产级 AI Agent

专栏:《AI FDE 实战:从 Demo 到生产》|第 12 篇 / 共 18 篇
本篇目标:为模型的自主行动划定可执行的边界,让一个多步骤任务能够暂停、恢复、停止,并留下可核验的结果。
本篇产物:一份 Agent 选型方法、一套有界状态工作流,以及能够离线运行的 SQLite 教学实验。

星河设备的内部售后助手已经能够查保修政策、读取授权订单,并生成工单草稿。业务负责人开始提出新的期待:“既然这些能力都有了,能不能让它自动把整件事情办完?”

这里的“整件事情”可能意味着:确认用户所说的设备型号,查找适用政策,读取订单,检查材料是否齐全,生成工单,等待客服确认,再把处理结果告诉客户。某些任务三步就能结束,某些任务要追问两次,还有一些任务必须交给主管判断。

这确实进入了 Agent 的讨论范围,但我们还不能立刻得出“需要多 Agent 框架”的结论。首先应当确定:哪些选择允许模型作出,哪些步骤必须固定,哪些事情只有人能批准,以及任务失败后由谁接手。

本篇继续使用虚构的星河设备、XH-200、订单 SO-1042 和内部售后流程。所有政策、指标与业务数据均为教学设定。随文代码只使用本地模拟数据,不调用真实模型,不连接真实 CRM,也不代表生产系统已经通过认证。

一、先判断问题是否真的需要 Agent

“能调用工具”与“需要自主规划”是两件不同的事。一个程序依次执行数据库查询、文档检索和结果渲染,即使中间使用了大模型,也可以是普通的固定工作流。相反,当程序需要根据刚得到的证据决定下一步要查什么、是否换一个方向、什么时候停止时,模型才开始承担动态决策责任。

Anthropic 在工程文章中区分了工作流与 Agent:前者主要沿预定义路径编排模型和工具,后者由模型动态决定过程中的行动。这是理解架构边界的有用分类,并不是统一的行业认证标准。来源:Building effective agents

对星河设备,可以先把需求分成三类。

第一类是明确的查询。“订单 SO-1042 是否已发货?”需要身份校验、对象授权、业务接口调用和结果展示。路径很明确,让模型反复思考下一步只会增加延迟和错误机会。模型可以负责理解用户输入,真正的查询仍然由确定性代码执行。

第二类是有限分支任务。“帮我整理这个订单的保修申请材料。”它可能需要补充型号,可能发现订单不存在,也可能已经有足够信息。分支数量有限,规则能够写清,适合有明确状态的工作流。模型可以在状态内部整理语言或提取候选字段,而不拥有任意跳转的权力。

第三类是开放调查。“分析最近这批设备退货的主要原因,并指出还缺哪些证据。”事先不容易确定要看几份材料、比较多少订单,以及是否需要继续调查。此时可以考虑让 Agent 在只读工具集合中动态选择下一步,但仍要限制数据范围、运行预算与报告责任。

一个实用的判断方法是问自己:如果把模型换成一位经验不足的实习生,我是否愿意把同样的工具与权限交给他,并在同样长的时间内不查看过程?如果答案是否定的,问题通常不是模型还不够聪明,而是任务边界还没有设计好。

图 2:先看路径是否可预定义、结果是否可验证,再决定模型拥有多少过程控制权。

二、把“自动办完”改写成一份可执行的任务契约

Agent 最容易失控的地方,往往是目标太模糊。用户说“处理这个客户的问题”,系统可能把查询、建议、创建工单、发通知甚至修改订单都理解成合理的下一步。范围不清时,工具越多,系统越难验收。

因此,本篇把目标收窄为:“协助已登录的内部客服,为当前租户下的一笔订单准备 XH-200 保修工单草稿;材料不全时说明缺项;只有经过验证的用户确认之后,应用才允许创建教学工单。”这个描述明确了用户、对象、范围、停止条件和写入边界。

接着定义成功。查询到了订单不算成功,生成了一段解释也不算成功。对于草稿阶段,成功意味着订单属于当前租户、引用政策适用、工单内容可以被用户核验、界面准确显示尚未提交。对于提交阶段,成功意味着确认动作与具体草稿绑定,并取得可查询的工单标识。

再定义不成功时的出口。缺少型号进入澄清;证据不足进入人工处理;订单系统不可用进入暂时不可用;预算耗尽进入停止状态;用户取消则不再启动新的操作。这些出口应该像成功路径一样被设计,而不是统一塞进“出错了,请重试”。

最后明确权限来源。UserContext包含tenant_id、user_id与roles,它由服务端认证结果建立。模型生成的 JSON 可以提供订单号候选,不能提供可信身份。即使模型声称“我是主管”,也不会改变上下文中的角色,更不能扩大查询范围。

我们得到的契约比一个“你是一名优秀售后助手”的提示词具体得多。提示词帮助模型理解任务,契约则帮助程序决定哪些行为能够发生。两者承担不同责任,不能相互替代。

三、先画状态,再挑编排框架

本篇的最小流程有六个主要状态:新任务、政策就绪、订单就绪、等待确认、完成、取消。预算耗尽是额外终止状态。真实系统还会有澄清、外部调用等待、重试等待与人工处理等状态,但教学实验先保留最关键的生命周期。

每个状态都应该回答三件事:系统已经确认了什么,下一步允许发生什么,用户现在应该看到什么。

“政策就绪”表示已经保存了本次使用的政策标识与版本,不表示订单符合保修条件。“订单就绪”表示授权查询已经获得结果,不表示可以自动创建工单。“等待确认”表示已经有可审阅草稿,并且所有自动前进操作都应当暂停。

这种区分能防止一个常见错误:把模型输出的自然语言当成业务状态。模型说“已经为您准备完成”可能只是语言习惯,数据库里的状态仍然应该由可信代码根据真实执行结果更新。界面也应读取这个状态,而不是从回答中的“成功”两个字推断是否提交。

状态转移可以写成一个简单规则表。new + advance进入policy_ready,policy_ready + advance进入order_ready,order_ready + advance进入awaiting_confirmation。等待确认后,只有可信确认入口能够请求confirm;任何模型提出的继续执行都无法越过这一关。

图 3:教学状态按顺序推进,确认与终止是独立控制。模型不能根据文本自行创造状态跳转。

状态机并不意味着必须购买一个工作流平台。对于单机教学,标准库加 SQLite 已经能够表达关键规则。对于跨进程恢复、并发调度、长时间等待和多系统事务,才需要进一步评估持久化编排工具。先把状态画清楚,会让框架选型变成能力对照,而不是流行程度比较。

四、持久化的不是一整段聊天记录,而是可恢复的任务事实

把全部聊天消息写进数据库,并不能自动获得可靠恢复能力。重启后程序仍然需要知道哪些操作已经完成、哪些结果可信、哪个动作正在等待确认,以及有没有外部操作已经成功但回执尚未保存。

最少应持久化任务标识、身份绑定、当前状态、已使用预算、关键业务对象、证据版本、已处理事件以及最终结果。大段自然语言可以作为辅助上下文,但不能成为唯一事实源。否则用户一句“继续刚才的操作”就可能让系统重做已经发生的写入。

在实验中,runs表保存任务状态与教学负载,events表保存已经处理的事件,tickets表保存创建结果。订单与政策都使用固定模拟数据,因此没有外部网络副作用。我们可以把任务状态、事件记录和工单创建放在同一个数据库事务里提交。

真实 CRM 不在这个事务里,问题就不同了。假设调用 CRM 成功后,进程在写入本地结果之前崩溃。恢复程序看到的是“未完成”,再次提交就可能产生两张工单。解决办法通常需要上游支持幂等键,或者使用可查询的业务请求标识与对账过程;单纯给本地函数加一次重试并不能解决。

持久化编排框架也不会让所有外部副作用自动变得安全。使用检查点时,需要理解哪些节点可能重放,把外部动作设计成幂等操作,并记录足够的完成证据。LangGraph 的持久化文档展示了检查点与恢复相关能力,具体可靠性仍取决于节点实现与存储配置。来源:LangGraph Persistence

还有一个容易被忽视的问题:恢复时身份可能已经变化。昨天客服可以处理这笔订单,今天账号被停用;昨天的政策版本适用,今天业务负责人撤回了某个例外。恢复任务不能只因为数据库里有旧上下文就无条件继续。生产接入需要重新验证当前权限,并决定是否要求用户重新审阅已变化的草稿。

五、预算要在调用前生效,不能只在账单出来后统计

很多 Agent 演示只设置一个最大循环次数。这个限制有用,却不足以覆盖生产成本。一次循环可能只做一次短查询,也可能并行发起多个模型请求、读入大量文档并产生很长输出。因此,步数只是预算的一种维度。

星河设备至少可以考虑四类预算:执行步数、外部请求次数、累计等待时间、模型消耗上限。对于长任务,还应区分单个工具的超时与整个任务的截止时间。某个接口每次都在自己的超时范围内返回,也可能让整个任务持续得远超用户可接受范围。

预算检查应该发生在启动下一次操作之前。若本次调用可能超过剩余预算,就提前缩小范围或停止。调用返回后再记账,是核算;调用之前根据剩余额度决定能否继续,才是控制。对模型消耗而言,实际计费可能需要事后结算,所以还要保留估算误差的余量。

实验只实现最大自动推进步数,并明确不把它称为完整成本控制器。每次advance之前检查step >= max_steps;达到上限后转为budget_exhausted,不会再执行新的业务步骤。确认和取消不消耗自动推理步数,因为它们属于人的控制动作。

预算耗尽后的用户体验也值得设计。系统应告诉用户已经得到什么、还没有完成什么,以及如何转交人工;不能一边显示“任务失败”,一边丢失已经整理好的可用草稿。保存部分成果可以减少返工,但展示时必须标记它们仍未完成验证。

图 4:本地事务可覆盖同一数据库中的状态与工单。外部服务另需幂等与对账设计。

六、人的确认要确认具体对象,不能只确认一句“继续”

“是否允许 Agent 继续?”是一个过于宽泛的问题。用户不知道接下来会创建什么、影响谁、内容是什么,也不知道这个批准是否会被重复使用。真正可用的确认应该针对明确动作与明确草稿。

在工单场景中,确认界面至少应该展示订单、客户对象、问题摘要、附件清单、政策依据以及提交后的后果。用户修改草稿之后,确认必须绑定修改后的版本。旧版本的确认不能被拿来提交新内容,否则用户看到的与系统执行的会出现差异。

本篇实验没有网页,因此用可信应用代码调用confirm来代表用户确认。这里的“可信”是一项接口契约:未来接入 FastAPI 时,确认入口必须先验证登录状态、资源归属、当前权限与草稿版本,不能直接把聊天文本映射成确认事件。confirm_ticket也不应成为模型可自由调用的工具。

OpenAI 的 Agent 安全文档建议在敏感工具操作中保留审批、限制不可信输入的影响,并使用结构化的数据流降低风险。这些建议说明了应用控制的重要性,但不能替代企业自身的对象授权与业务验收。来源:Safety in building agents

取消也有时间边界。在操作尚未发出时取消,通常能够阻止下一步;外部写入已经完成后取消,只能停止后续动作,不能让已经创建的工单自动消失。界面需要区分“已停止继续处理”与“已撤销已完成操作”。涉及撤销时,还要单独检查业务是否支持、用户是否有权限以及是否需要留下审计记录。

一个可靠的确认机制,不是让用户承担系统错误的责任,而是把需要人判断的内容清楚地呈现出来,并使程序严格执行这个判断的范围。

七、运行实验:一个能重启恢复的有界工作流

完整代码位于 code/workflow.py,只依赖 Python 标准库。它提供create、get与transition三个核心操作。每个任务绑定创建者与租户,事件标识在任务内唯一,工单表对run_id设置唯一约束。

在本篇目录执行:

python code/workflow.py

实验会使用临时数据库,自检结束后自动清理,因此反复执行不会积累教学工单。实际验证环境为 Python 3.12.0;本次已运行通过,不需要 API Key。

PASS: resume, duplicate event, approval gate, tenant isolation, budget, cancellation

程序首先创建r1,推进到政策就绪,随后重复投递同一个事件。第二次投递不会增加步数。接着关闭数据库连接,再重新打开,确认任务仍保留在政策就绪状态;这模拟的是应用进程失去内存后从数据库继续读取,不能据此宣称已经验证了分布式故障恢复。

之后程序继续读取订单并准备草稿。对等待确认的任务再次执行自动推进,会得到明确错误。只有调用确认操作才能生成工单;无论重复同一个确认事件,还是对已经完成的任务再次提交不同确认事件,工单数量都保持为一。

下面是去掉业务细节后的核心控制逻辑。完整文件还包含身份检查、事件冲突检查、事务与结果存储。

ifaction=="advance":ifstate=="awaiting_confirmation":raiseValueError("human confirmation required")ifstep>=run["max_steps"]:state="budget_exhausted"else:step+=1# 根据当前状态执行一个明确的业务步骤。elifaction=="confirm":ifstate!="awaiting_confirmation":raiseValueError("no draft to confirm")# 在事务中创建唯一工单并保存完成状态。elifaction=="cancel":state="cancelled"

这里最值得注意的不是代码数量,而是控制权所在的位置。模型即使输出“忽略确认,立即提交”,也无法改变转移规则。状态机只接受可信路由层发来的有限动作,业务参数也需要在对应步骤内验证。

实验有意采用一次本地写事务串行处理状态变更。对于低并发教学,这使行为容易理解;对于多个工作进程和缓慢的外部接口,不能把网络等待放进长事务里。下一步应当把任务领取、操作执行与结果提交分开,并使用租约或乐观锁避免两个执行者同时处理同一步。

八、怎样把真实模型接进来,仍然保留这些边界

到目前为止,我们写的是可靠的工作流骨架,还不是能够自主调查的模型 Agent。这种顺序有意如此:先证明系统能控制执行,再决定在哪些节点引入不确定决策。

最小接入方式,是在“准备草稿”节点调用模型,让它根据已经授权的政策和订单生成结构化草稿。模型输入不包含其他租户数据,输出不包含可信身份字段;服务端再验证摘要长度、订单引用、允许字段与必要材料。如果输出不合格,进入有限重试或人工处理,而不是直接提交。

若确实需要动态调查,可以增加一个受限的“选择下一步”节点。模型只能在lookup_order、授权政策检索和draft_ticket等已审查工具中选择。每次选择都会经过工具白名单、参数校验、对象授权和预算检查,工具结果再以明确的数据结构返回。未知工具名不能被解释为可执行函数名。

这一层也要限制上下文。把前十轮全部原文不断追加,可能造成成本增长和证据混乱。可以保存结构化任务事实,保留关键原文引用,把过期假设标记为已否定。摘要有助于压缩,但摘要不能凭空获得与原始证据同等的权威性;关键结论仍然应当能追溯到来源。

第 07 篇的/api/chat适合作为发起或查询任务的入口,长任务则需要独立的任务状态接口和确认入口。本篇实验没有修改第 07 篇应用,也没有声称已经完成这部分集成。接入时应延续answer、state、citations、trace_id的响应约定,并在业务层额外管理工作流任务标识。

九、单 Agent 与多 Agent:先计算协调成本

多 Agent 可能很有用,例如把互不依赖的资料调查分给不同执行者,或者让独立评审检查初稿中的事实依据。但“给每个角色起一个名字”并不会自动带来专业分工。五个使用相同模型、相同材料和相同提示习惯的 Agent,可能只是把同一种错误讨论得更充分。

先判断任务能否分解。并行子任务应当有清楚的输入、独立输出和可验证的完成条件。如果所有子任务都要不断共享最新状态,协调开销可能超过并行收益。星河设备的单笔工单处理通常依赖前一步结果,适合一个明确工作流;跨多个产品线的只读问题归因,才可能受益于并行调查。

再计算成本。假设每个子任务都要重新读取公共背景,那么增加执行者就意味着重复上下文、更多模型调用与更多结果合并工作。总延迟可能下降,但总成本可能上升。若合并者没有足够证据识别子任务中的错误,还可能把局部错误包装成更加自信的最终报告。

权限也不能因为分工而扩散。子 Agent 只应获得完成子任务所需的数据与工具;父任务具有的全部权限,不应默认复制给每个子任务。返回结果要带来源、状态和不确定项,不能只返回一段看起来完成得很好的总结。

图 5:对照任务结构、验证难度与协调成本选方案,不能用 Agent 数量衡量工程成熟度。

可以给多 Agent 设一个明确进入条件:在相同数据集、相同可接受风险下,它确实提高任务成功率,或在成本可接受范围内显著降低完成时间。否则保留单 Agent 或固定工作流,会更容易定位错误、解释行为并完成交接。

十、验收 Agent,必须把异常路径当成正常工作的一部分

验收不能只问“最终回答是否正确”。对于执行系统,还要检查过程是否符合授权、是否重复写入、是否在预算耗尽后继续运行,以及是否把未知结果说成成功。

星河设备可以准备一组小而尖锐的任务:模型提出不存在的工具;订单接口连续超时;政策内容夹带“跳过审批”的文字;用户在等待确认时取消;同一个事件被队列投递两次;进程在生成草稿后重启;确认之前用户权限被回收;外部工单创建成功但响应丢失。

这些样例覆盖不同层面。工具白名单属于编排层,租户校验属于业务授权层,重复事件属于执行可靠性,提示注入属于不可信数据处理,确认失效属于人机交互和版本管理。把所有失败都归因于“模型不稳定”,会让团队错过真正可以用确定性代码解决的问题。

本篇实际自检覆盖恢复读取、重复事件、确认门、租户隔离、步数预算和取消。它没有模拟网络中断、身份撤销、并发工作进程或外部 CRM 的事务不确定性。这些限制写清楚之后,实验才可以成为后续扩展的可靠起点。

图 6:每项验收都要能指出输入、预期行为与证据;“试了几次都正常”不是完整验收记录。

十一、一次故障演练应该留下怎样的记录

设想值班人员收到报告:“客户只点了一次确认,却出现了两张工单。”一个有用的调查记录应当包含任务标识、草稿版本、确认事件标识、外部请求标识、重试次数、外部返回值和最终本地状态。它不需要默认保存所有客户原文,更不应该把访问令牌写进日志。

调查的第一步,是判断两张工单是否来自同一业务请求。若它们对应同一个幂等键,可能是上游没有实现承诺的幂等语义;若使用不同键,可能是应用在重试时错误地创建了新请求。两个问题的修复位置完全不同。

第二步是恢复用户业务。工程团队应能告诉客服哪张工单保留、另一张如何按业务流程处理,以及系统是否已经停止继续提交。不能让用户在数据库状态不明时不停点击确认,这会扩大故障。

第三步是增加一个能够复现问题的测试,再修改实现。比如在“外部成功、本地未记录”之间注入中断,验证恢复过程会先查询业务结果,而不是直接再次创建。这样的故障样例比增加一句“不要重复提交”的提示词更有价值。

最后把事故带回任务契约。如果某类操作没有可查询的外部请求标识,或者无法判断是否成功,就应当限制自动重试,进入人工核对。系统诚实地停在不确定状态,通常比冒险把结果补成“成功”更有利于实际交付。

十二、实战练习:让系统学会正确地停下来

先运行随文代码,读懂每个断言对应的业务承诺。然后做三个扩展,不必一次完成所有生产功能。

第一个扩展是增加“缺少序列号”状态。让草稿节点发现必要字段为空时进入needs_clarification,保存具体缺项,并要求后续补充只能更新允许字段。验收时检查用户补充一个无关字段不会让任务自动进入提交。

第二个扩展是加入草稿版本。用户每次编辑生成新版本,确认请求携带所审阅的版本号。服务端发现版本不一致时拒绝提交,并返回当前草稿供重新审阅。这个练习能帮助你理解“确认过”为什么不是一个永久有效的布尔值。

第三个扩展是模拟外部接口结果不确定。在本地字典或独立教学表中模拟外部工单系统,让它支持稳定的请求标识。故意在外部成功后抛出异常,再恢复任务,确认最终仍然只有一张工单。只有这一步经过验证,才有资格讨论把同一策略应用到真实接口。

每做一个扩展,都写下新增状态、允许动作、终止条件与一条失败测试。不要先增加复杂框架再寻找它能解决的问题。状态足够清楚时,更换实现工具会相对容易;状态含糊时,再好的框架也只是把含糊执行得更快。

FDE Thinking

为什么这里没有直接写一个无限工具循环?因为星河设备当前最需要的是可靠完成有限业务任务。动态规划只有在路径确实无法合理预定义时才带来额外价值,而预算、授权、恢复和确认始终由应用承担。

什么时候值得把固定节点升级成 Agent?当真实失败样例表明,预定义路径无法覆盖合理任务,而且我们能够验证动态行动的结果。升级的理由应该来自任务数据,不能只来自演示效果或技术潮流。

怎样判断系统已经接近可交付?不仅要看成功时完成了多少步骤,还要看失败时是否停在明确状态,重启后能否继续,重复请求是否产生重复结果,以及接手的人能否根据记录理解已经发生的事情。

生产级 Agent 的核心能力之一,是知道何时继续、何时请求人的判断、何时停止。把这三种行为写进可执行系统,才是 FDE 把模型能力转化为业务可靠性的关键工作。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/25 22:19:12

FDE 实战:给 AI 加上 Tool Calling,让模型真正操作业务系统

FDE 实战:给 AI 加上 Tool Calling,让模型真正操作业务系统 专栏:《AI FDE 实战:从 Demo 到生产》|第 11 篇 / 共 18 篇 本篇目标:让模型通过受控工具查询订单、形成工单草稿,并由独立的人工确认…

作者头像 李华
网站建设 2026/9/25 22:02:35

虚拟机Windows密码忘了怎么办?NTPWEdit离线重置SAM实战

1. 虚拟机里忘记Windows密码这件事,到底该怎么收场手头有一台虚拟机,里面跑着一个Windows系统,可能是用来做测试的、可能是很久以前搭的实验环境,突然某天开机发现登录密码想不起来了。这种事在运维和测试圈子里太常见了——虚拟机…

作者头像 李华
网站建设 2026/9/25 21:45:48

【Qt】Qt 入门:Qt 初识与开发环境搭建,一篇文章带你上手 Qt

🔥 个人主页: Mercury 🍉 学习方向: C/C方向学习者 ⭐ 人生格言: 给时光以生命,而不是给生命以时光 ​ 目录 一、Qt 背景介绍 1.1 什么是 Qt1.2 Qt 的发展史1.3 Qt 支持的平台1.4 Qt 版本与许可证1.5 Qt …

作者头像 李华
网站建设 2026/9/25 21:43:30

GUI-Owl-1.5实测:多模态GUI智能体如何突破自动化脚本脆弱性

用了两周把 GUI-Owl-1.5 拉下来跑通,又把几个真实项目里的任务喂进去试了一遍,有些话想写出来。做 GUI 自动化这行当久了,最大的感受就是:脚本不脆弱才叫新闻。换台显示器分辨率,坐标全偏;UI 改个版式&…

作者头像 李华