2025年AI Agent实操五道硬坎:任务闭环、状态管理与工具调用可靠性

1. 项目概述:这不是一篇“AI Agent趋势报告”,而是一份2025年实操现场的血泪手记

“AI Agent”这个词,从2023年底开始像高压蒸汽一样冲进所有技术会议、投资人PPT和招聘JD里。到了2025年,它已经不是“会不会来”的问题,而是“谁在真实跑通、谁在假装跑通、谁在拿Demo当量产”的分水岭时刻。我过去18个月深度参与了6个不同行业的AI Agent落地项目——从制造业设备预测性维护的巡检Agent,到跨境电商客服意图拆解+多系统联动的订单处理Agent,再到律所合同初筛+风险点标注+条款比对的法律辅助Agent。没有一个项目是靠调用某个“全能Agent框架”开箱即用的;所有能稳定上线、被业务方每天主动打开使用的Agent,背后都有一套极其具体、极其琐碎、极其反直觉的设计逻辑。这篇内容不谈LLM能力边界、不画架构图、不列开源项目star数,只讲我在产线服务器上敲过命令、在客户会议室里改过三次需求文档、在凌晨三点盯着日志排查超时错误时,真正确认“这玩意儿确实能干活”的那几个硬核事实。核心关键词是:AI Agent、2025年实操、任务闭环、状态管理、工具调用可靠性、人类接管机制。如果你正打算启动一个Agent项目,或者已经被“自主思考、自动执行”的宣传话术绕晕,又或者刚被老板问“为什么我们的Agent还在写诗而不是修bug”,那么这篇内容就是为你写的——它不提供幻觉,只提供可验证的操作条件。

2. 内容整体设计与思路拆解:为什么90%的Agent Demo在真实场景中会当场失效?

2.1 “Agent”这个词在2025年已被严重污染,必须先做语义清洗

现在市面上几乎所有自称“AI Agent”的产品,都在悄悄偷换概念。它们把“用LLM生成一段文字”叫Agent,把“调用一次API返回结果”叫Agent,甚至把“前端加了个聊天框的CRUD界面”也叫Agent。这种滥用直接导致两个后果:一是业务方预期严重错位,以为买了个数字员工,结果发现连“查一下今天仓库缺货清单”都要人工补三遍提示词;二是技术团队陷入无休止的“调参-失败-换模型-再失败”循环,根本没时间解决真正的工程问题。在我参与的6个项目中,最终能通过UAT(用户验收测试)并进入日常使用的Agent,全部满足一个极简但残酷的定义:它必须能独立完成一个端到端的、有明确输入输出、需跨至少两个异构系统、且失败后能被人类无损接管的业务任务。注意,这里强调的是“独立完成”,不是“辅助完成”;是“端到端”,不是“中间一环”;是“跨异构系统”,不是“只读数据库”;是“失败后可无损接管”,不是“崩溃就丢数据”。这个定义像一把手术刀,立刻切掉了90%的伪Agent项目。比如,某金融公司做的“投研报告生成Agent”,表面看很炫——输入股票代码,输出PDF报告。但它实际流程是:LLM调用Wind API取数据 → LLM格式化成Markdown → 调用LaTeX引擎转PDF。问题在于,Wind API限流时Agent卡死,LaTeX编译报错时无法定位是模板问题还是数据问题,更致命的是,当研究员想手动修改某段分析结论时,系统根本不提供原始数据源和中间Markdown的编辑入口。它不是一个Agent,只是一个带UI的脚本封装器。

2.2 真正决定成败的,从来不是大模型本身,而是“状态管理”这个被集体忽视的底层能力

几乎所有失败的Agent项目,根源都出在状态管理上。我们习惯性地把LLM当成“大脑”,却忘了大脑之所以能思考,是因为它有记忆、有上下文、有对自身行为的元认知。而绝大多数Agent框架,把状态当作可选附件,甚至压根不提供状态持久化能力。举个最典型的例子:一个电商售后Agent,任务是“处理用户申请退货的工单”。理想流程是:1)读取工单系统里的用户信息、订单号、商品SKU;2)调用库存系统查该SKU当前可退数量;3)调用物流系统查该用户历史退货履约率;4)综合判断是否批准,并生成审批意见。但在真实运行中,第2步库存接口超时,Agent直接返回“系统繁忙,请稍后再试”;第3步物流系统返回空数据,Agent误判为“该用户无历史记录”,直接批准退货;第4步生成的意见里把商品名称拼错了。这些问题单个看都不致命,但叠加起来,Agent就变成了一个不可信、不可追溯、不可调试的黑箱。我们后来在制造业项目中强制引入了三层状态管理:第一层是内存级临时状态(用于单次推理链路中的变量传递),第二层是Redis缓存状态(保存任务ID、当前步骤、各工具调用返回值、重试次数),第三层是PostgreSQL持久化状态(记录完整任务轨迹、人工干预日志、最终结果快照)。关键不是用了什么技术,而是每个工具调用前,必须检查前置状态是否完备;每次调用后,必须原子化更新状态并标记时间戳;任何异常发生时,必须基于当前状态生成可读的错误摘要,而非抛出“LLM generation failed”这种无意义报错。这套机制让我们的设备故障诊断Agent在产线连续运行117天无须人工重启,而同期另一个没做状态管理的同类Agent,平均每4.2小时就要人工介入一次。

2.3 工具调用(Tool Calling)不是功能开关,而是一场精密的协议协商

2025年,几乎所有Agent框架都宣称“原生支持工具调用”,但实际落地时,95%的团队会栽在这个环节。问题不在于不会写function call的JSON Schema,而在于完全忽略了工具调用背后的协议本质:它不是LLM发指令,工具执行,然后返回结果这么简单;而是一个涉及超时控制、重试策略、错误分类、降级路径、数据校验的完整RPC过程。我们曾为一家物流公司开发运单状态同步Agent,需要调用三个内部系统:TMS(运输管理系统)、WMS(仓储管理系统)、CRM(客户关系系统)。最初版本的工具调用逻辑是:LLM生成调用参数 → 框架序列化为HTTP请求 → 等待响应 → 解析JSON → 继续下一步。结果上线第一天就崩了:TMS接口平均响应2.3秒,但偶发达到8秒,Agent直接超时;WMS返回的JSON里有个字段名从estimated_delivery_date临时改成eta_date,Agent解析失败;CRM系统在流量高峰时返回HTTP 429,Agent把它当成业务错误,反复重试直到触发风控熔断。后来我们重构了整个工具调用层:每个工具注册时必须声明SLA(最大延迟、错误码范围、降级返回值);框架层强制注入超时(TMS设为3秒,WMS设为1.5秒,CRM设为2秒);所有响应必须经过Schema校验,字段名变更由校验器自动映射;HTTP 429等平台级错误统一走降级路径(返回缓存数据或空对象);每次调用都记录trace_id并关联到任务状态。这个改动让工具调用成功率从78.3%提升到99.92%,而开发工作量只增加了不到20%,因为所有逻辑都沉淀在了工具注册配置里,而非散落在各个Agent实现中。

3. 核心细节解析与实操要点:2025年能跑通的Agent,必须跨过这五道硬坎

3.1 坎一:任务分解不能靠LLM“自由发挥”,必须预设结构化子任务树

很多团队迷信“让LLM自己决定怎么做”,结果Agent在复杂任务中反复兜圈子。比如“为新入职员工配置全套IT权限”,LLM可能先去查AD域控,再查Jira权限组,再查Zoom账号池,最后发现Zoom账号已满,又回头去查备用账号池……整个过程耗时17秒,且无法预测下一步。我们在律所项目中彻底放弃了这种模式,改为预定义子任务树(Subtask Tree):主任务“配置律师入职权限”被硬编码分解为5个原子子任务:① 创建AD账户(依赖:HR系统提供的员工编号);② 加入默认安全组(依赖:①成功);③ 分配邮箱(依赖:①成功);④ 开通Zoom(依赖:③成功且Zoom账号池>0);⑤ 同步至Okta(依赖:①②③④全部成功)。每个子任务有明确的输入约束、输出契约、失败码定义。LLM只负责在子任务执行前,根据当前状态和业务规则,选择下一个该执行的子任务(例如,当Zoom账号池=0时,跳过④,直接报错并通知IT管理员)。这样做的好处是:任务路径完全可预测、可审计、可中断恢复;失败时能精确定位到哪个子任务、哪个依赖缺失;更重要的是,业务方能看懂整个流程——他们不需要理解LLM怎么想,只需要知道“第④步卡住了,因为Zoom账号用完了”。我们用YAML定义子任务树,配合轻量级状态机引擎(用Python的transitions库实现),整套机制代码不到300行,但让权限配置Agent的首次成功率从41%跃升至92%。

3.2 坎二:人类接管(Human-in-the-loop)不是“加个按钮”,而是设计成任务流的自然分支

所有声称“支持人工审核”的Agent,99%只是在最后一步弹出一个审批弹窗。这在真实业务中毫无价值。真正的接管,必须嵌入到任务流的每一个可能断裂点。我们在跨境电商项目中设计了三级接管机制:一级是静默接管——当Agent调用支付网关失败时,不报错,而是自动生成一个标准格式的工单(含trace_id、失败时间、原始请求payload、网关返回的error_code),推送到客服后台,由人工在5分钟内补单;二级是半自动接管——当Agent识别到用户咨询中包含“律师”“合同”“赔偿”等高风险词时,自动暂停,将当前对话上下文、已提取的订单号、用户情绪分(用轻量级BERT模型实时计算)打包,推送给法务专员,专员点击“接管”后,Agent自动切换为辅助模式(只提供信息检索和话术建议,不生成回复);三级是全权接管——当同一用户30分钟内触发5次以上接管,系统自动锁定该用户会话,后续所有请求均由人工坐席处理,Agent退为后台知识库助手。关键点在于:接管动作本身必须生成可追踪的事件日志;接管后的状态必须无缝继承原任务状态(不能丢失已填的表单字段);接管完成后,必须能一键将本次接管过程(包括人工操作步骤)反哺为新的训练样本,用于优化Agent的拦截策略。这套机制让我们的客服Agent在保持73%自动化率的同时,客诉率下降了64%,因为所有“差点出事”的case都被精准捕获并闭环了。

3.3 坎三:工具集成不是“写个API Wrapper”,而是构建领域专用的适配器层

看到“集成CRM系统”就去翻Salesforce文档写REST Client?这是2023年的做法。2025年,成熟的Agent项目必须构建领域适配器(Domain Adapter)。以我们对接的某国产ERP为例,它的API存在三大顽疾:① 接口命名混乱(查库存叫/api/v2/stock/query,查在途库存却叫/api/erp/shipment/get);② 字段含义模糊(status字段在不同接口中分别表示“订单状态”“发货状态”“付款状态”);③ 错误码不统一(成功时有时返回200有时返回201,失败时400可能代表参数错也可能代表权限不足)。如果让LLM直接面对这些,它99%会出错。我们的解法是:在工具调用层之上,加一层薄薄的适配器,它只做三件事:第一,统一资源模型——定义InventoryItem实体,包含sku,warehouse_id,available_quantity,in_transit_quantity等标准化字段;第二,统一操作契约——所有库存相关操作只暴露get_inventory()reserve_inventory()两个方法,参数和返回值严格遵循上述模型;第三,统一错误分类——将ERP千奇百怪的错误码,映射为InvalidParameterError,PermissionDeniedError,ResourceNotFoundError,RateLimitExceededError四类标准错误。适配器本身用TypeScript编写,配合JSDoc生成类型定义,LLM调用时看到的永远是干净、一致、有明确契约的接口。这个适配器层让我们在3周内完成了对5个异构业务系统的接入,而之前团队单独对接一个系统平均要花6周。

3.4 坎四:评估不能只看“准确率”,必须建立面向业务结果的多维指标体系

还在用“Agent回答是否正确”来评估?这就像用“厨师切菜是否均匀”来评价餐厅好不好。2025年,Agent的评估必须回归业务本质。我们在制造业项目中定义了四个不可妥协的核心指标:

  • 任务完成率(Task Completion Rate):在统计周期内,成功走到最终状态(非中间态)的任务数 / 总发起任务数。要求≥95%。
  • 人类接管率(Human Takeover Rate):被人工接管的任务数 / 总发起任务数。要求≤5%,且其中≥80%的接管必须发生在预设的风险节点(如设备停机预警、备件库存低于阈值)。
  • 端到端延迟(E2E Latency):从任务触发到返回最终结果(含所有工具调用、LLM推理、状态更新)的P95耗时。要求≤3.5秒(对实时性要求高的场景)或≤12秒(对分析类任务)。
  • 状态一致性(State Consistency):Agent声称“已执行X操作”后,下游系统实际状态与Agent状态记录的差异率。要求=0%。

提示:我们发现,只要把“状态一致性”作为一票否决项,团队就会自发重视状态管理、事务边界和幂等性设计。很多技术债,都是因为评估指标太软、太虚才积累下来的。

3.5 坎五:安全不是“加个内容过滤器”,而是贯穿数据生命周期的纵深防御

2025年,Agent的安全风险远超想象。它不再只是“生成有害内容”,而是可能:① 在工具调用中泄露敏感凭证(如把AWS密钥拼进API请求头);② 将内部系统错误信息(含数据库表名、路径)原样返回给用户;③ 在状态持久化时,把用户身份证号明文存进Redis。我们在所有项目中强制执行“数据流沙盒”原则:Agent进程内所有数据,按敏感等级分为L0(公开)、L1(内部)、L2(敏感)、L3(机密)四级;任何数据跨级流动,必须经过显式脱敏或加密;所有工具调用的输入输出,必须经过沙盒扫描器(基于正则+轻量NLP模型)实时检测;状态存储前,L2+数据自动触发AES-256加密,密钥由KMS托管。最有效的实践是:在LLM的system prompt里,用强硬语气写明“你绝不能输出任何L2及以上级别的原始数据,如果必须提及,请用[REDACTED]占位,并在调用工具后立即向状态管理器申请解密授权”。这条规则让我们的法律Agent在处理合同时,从未发生过一次敏感信息泄露事故。

4. 实操过程与核心环节实现:从零搭建一个能过UAT的售后工单Agent(以电商场景为例)

4.1 第一步:定义最小可行任务(MVP Task)与验收标准

不要一上来就想做“全渠道智能客服”。先锁死一个最痛、最可控、价值最清晰的MVP任务。我们选的是:“处理用户通过APP提交的‘商品破损’退货申请”。验收标准必须量化:

  • 输入:APP工单系统推送的JSON,含order_id,sku,user_id,photo_urls(最多3张)
  • 输出:在WMS系统创建退货入库单,并在CRM系统更新用户售后记录
  • 成功率:连续7天≥98%
  • 平均耗时:P95 ≤ 8.2秒
  • 接管率:≤3%,且所有接管必须附带可复现的trace_id和错误摘要

注意:这个MVP故意避开了“判断照片是否真破损”这个AI难题,而是把照片URL直接透传给WMS质检员。Agent的价值是“把该走的流程一步走完”,不是“代替人做判断”。很多项目失败,就是因为一开始就把MVP定得太高。

4.2 第二步:构建领域适配器与工具契约(以WMS为例)

WMS的真实API是这样的:

# 创建入库单(极其反人类) POST /wms/api/v3/inbound/create?tenant_id=abc123 Headers: { "Authorization": "Bearer xxx", "X-Request-ID": "req-xxx" } Body: { "inbound_order_no": "IO-2025-XXXXX", "warehouse_code": "WH-SH-01", "supplier_code": "SUP-ECOM-001", "items": [{ "sku": "SKU-123456", "quantity": 1, "reason_code": "DAMAGE", # 必须是枚举值 "damage_photos": ["https://img.xxx/1.jpg", "https://img.xxx/2.jpg"] }] }

我们的适配器暴露的契约是:

interface WmsAdapter { /** * 创建退货入库单 * @param order - 订单信息(来自APP工单) * @param damagePhotos - 破损照片URL数组(最多3张) * @returns 入库单号(IO-2025-XXXXX)或错误 */ createReturnInbound(order: { orderId: string; sku: string }, damagePhotos: string[]): Promise<string | WmsError>; }

适配器内部做了三件事:① 自动生成符合WMS规范的inbound_order_no(用日期+哈希);② 自动填充warehouse_codesupplier_code(从配置中心读取);③ 将reason_code映射为DAMAGE,并校验damagePhotos长度。这样,LLM调用时只需关心“我要创建一个退货单”,不用记住WMS那些令人抓狂的细节。

4.3 第三步:设计状态机与任务流(用YAML定义)

# taskflow.yaml name: "process_damage_return" initial_state: "start" states: - name: "start" on_entry: "parse_app_ticket" transitions: - event: "parsed_successfully" target: "check_stock" - event: "parse_failed" target: "fail" - name: "check_stock" on_entry: "call_wms_check_stock" transitions: - event: "stock_available" target: "create_inbound" - event: "stock_unavailable" target: "notify_user_out_of_stock" - event: "wms_timeout" target: "retry_check_stock" - name: "create_inbound" on_entry: "call_wms_create_inbound" transitions: - event: "inbound_created" target: "update_crm" - event: "wms_error" target: "fail_with_wms_context" - name: "update_crm" on_entry: "call_crm_update_record" transitions: - event: "crm_updated" target: "succeed" - event: "crm_error" target: "fail_with_crm_context" transitions: - from: "retry_check_stock" to: "check_stock" actions: ["increment_retry_count"] conditions: ["retry_count < 3"] - from: "retry_check_stock" to: "fail" conditions: ["retry_count >= 3"]

这个YAML被加载到状态机引擎后,Agent的每一步行动都变得可预测、可测试、可回滚。我们甚至能用这个YAML生成流程图,直接拿去和业务方对齐。

4.4 第四步:实现LLM的“决策层”(Prompt Engineering实战)

LLM在这里的角色,不是生成答案,而是在给定状态和工具契约下,选择下一个合法的state transition。我们的system prompt核心段落是:

你是一个严格的流程控制器,不是创意助手。你的唯一职责是:根据当前任务状态(见<state>标签)和可用工具(见<tools>标签),选择一个且仅一个预定义的事件(event)来推进流程。你绝不生成自由文本,绝不猜测,绝不发明新事件。如果状态不满足任何事件的触发条件,请输出{"event": "fail", "reason": "状态不满足任何事件条件"}。所有输出必须是严格JSON格式,无额外字符。

输入给LLM的context是:

{ "state": { "current": "check_stock", "data": { "app_ticket": {"order_id": "ORD-2025-789", "sku": "SKU-123456"}, "retry_count": 0 } }, "tools": [ { "name": "wms_check_stock", "description": "检查SKU在指定仓库的可用库存,返回数量", "parameters": {"sku": "string", "warehouse_code": "string"} } ] }

LLM的输出只能是:

{"event": "wms_timeout", "tool_call": {"name": "wms_check_stock", "parameters": {"sku": "SKU-123456", "warehouse_code": "WH-SH-01"}}}

这个设计把LLM从“全能大脑”降级为“智能路由”,大幅提升了稳定性和可解释性。我们用GPT-4o和Qwen2.5-7B在相同测试集上对比,GPT-4o的事件选择准确率是92.7%,Qwen2.5-7B是89.1%,差距不大,但Qwen2.5-7B的推理成本只有GPT-4o的1/18,这才是2025年务实的选择。

4.5 第五步:部署与可观测性(不是加个Prometheus就行)

Agent上线后,最大的挑战不是性能,而是“它到底在想什么”。我们强制要求每个Agent实例必须暴露三个端点:

  • /health:返回当前状态机状态、最近10次任务的P95延迟、工具调用成功率
  • /trace/{trace_id}:返回该任务的完整执行链路,包括每个state的进入/退出时间、工具调用的request/response(脱敏后)、LLM的输入输出(脱敏后)、所有事件日志
  • /debug/state:返回当前内存中所有活跃任务的状态快照(仅限内网访问)

最关键的是,我们把/trace/{trace_id}的URL,作为每个任务的最终输出,直接返回给APP工单系统。当客服人员看到工单状态变成“已创建入库单”,他点开这个链接,就能看到整个过程:哪一步花了4.2秒,WMS返回了什么,LLM为什么选择那个事件,有没有触发重试……这种透明度,让业务方第一次真正信任了Agent。我们用OpenTelemetry采集所有跨度,用Grafana看板监控P95延迟突增,用ELK搜索特定错误码。没有这些,Agent就是个黑箱,迟早会被业务方弃用。

5. 常见问题与排查技巧实录:那些凌晨三点让我头皮发麻的Bug,现在都成了SOP

5.1 问题:Agent在高峰期大量超时,但单点压测一切正常

现象:P95延迟从2.1秒飙升到15.7秒,错误日志全是TimeoutError,但用JMeter单独压测WMS工具调用,TPS 200时延迟仍稳定在1.3秒。
排查路径

  1. 首先排除LLM瓶颈——检查/health端点,发现LLM队列积压,但GPU利用率只有35%,说明不是LLM慢;
  2. 查看/debug/state,发现大量任务卡在check_stock状态,且retry_count都为0,说明还没开始重试就超时了;
  3. 抓包分析Agent到WMS的HTTP请求,发现所有请求的X-Request-ID都一样(req-abc123),而WMS的限流策略是按X-Request-ID维度计数的!
    根因:我们为了简化,在适配器里把X-Request-ID写死了。WMS把所有请求当成同一个客户端,1秒内超过5次就限流。
    修复:在适配器里用crypto.randomUUID()动态生成X-Request-ID
    经验:所有外部系统交互的Header,绝不能硬编码。必须把“唯一标识”作为工具调用的必填参数,由状态机在每次调用前注入。

5.2 问题:Agent偶尔把正确结果判定为失败,触发不必要的接管

现象:WMS返回{"success": true, "inbound_no": "IO-2025-123"},但Agent日志显示event: "wms_error",并创建了接管工单。
排查路径

  1. /trace/{trace_id},发现LLM的输出是{"event": "wms_error", "reason": "response does not contain inbound_no"}
  2. 对比WMS真实响应和LLM看到的输入,发现我们在适配器里做了JSON转换,把inbound_no字段名改成了inboundNumber(为了统一命名规范);
  3. 但LLM的system prompt里写的还是inbound_no,它在检查字段时自然找不到。
    根因:适配器的字段映射,和LLM的prompt认知不一致。
    修复:在适配器的JSDoc里,用@see明确标注字段映射关系;在LLM的system prompt里,用<tools>标签展示适配器暴露的最终契约,而非原始API。
    经验:LLM永远只认它看到的契约。适配器可以改字段,但必须同步更新LLM的认知。我们后来加了一条CI检查:所有适配器的JSDoc变更,必须触发对应LLM prompt的更新PR。

5.3 问题:状态持久化后,Redis里出现大量过期的僵尸任务

现象:Redis内存持续增长,KEYS "task:*"返回上万条key,但/health显示活跃任务只有23个。
排查路径

  1. 随机抽查几个僵尸key,发现expire_at字段是0(表示永不过期);
  2. 查代码,发现状态更新逻辑里,只有在state == "succeed"state == "fail"时才设置TTL,而在state == "retry_check_stock"时漏写了;
  3. 更糟的是,retry_check_stock状态会不断重试,每次重试都写新key,旧key永远不删。
    根因:状态机的每个state,都必须有明确的TTL策略。不能只在终态设过期。
    修复:在状态机定义里,为每个state添加ttl_seconds属性;状态机引擎在每次set_state时,自动为key设置对应TTL。
    经验:状态生命周期管理,必须和状态机定义强绑定。我们后来把TTL写进了YAML schema,用JSON Schema Validator强制校验。

5.4 问题:人类接管后,Agent无法恢复,任务永久卡住

现象:客服人员点击“接管”,工单状态变灰,但30分钟后,Agent既没继续执行,也没报错,/debug/state里该任务状态仍是"current": "update_crm"
排查路径

  1. /trace/{trace_id},发现最后一条日志是{"event": "human_takeover", "timestamp": "2025-04-10T02:15:22Z"},之后再无日志;
  2. 检查接管逻辑,发现我们只发了通知消息,但没在状态机里定义human_takeover这个event;
  3. 状态机引擎遇到未知event,直接静默忽略,任务停滞。
    根因:接管不是外部事件,而是状态机必须原生支持的一等公民。
    修复:在YAML状态定义里,为每个可能被接管的state,添加on_event: "human_takeover"分支,目标state设为"human_handled",并在"human_handled"state里实现“等待人工完成”的轮询逻辑。
    经验:所有可能中断流程的外部动作(接管、超时、系统维护),都必须在状态机里预设event。不能指望“外部系统会通知我”。

5.5 问题:Agent在处理多图时,把三张照片URL拼成一个超长字符串,WMS API拒绝

现象:WMS返回400 Bad Request,错误信息是"damage_photos must be an array of strings"
排查路径

  1. /trace/{trace_id},发现LLM的输出里,damagePhotos字段值是"https://img1.jpg,https://img2.jpg,https://img3.jpg"(字符串);
  2. 追溯LLM输入,发现APP工单系统推送的JSON里,photo_urls字段确实是数组["https://img1.jpg", ...]
  3. 但我们在适配器里,为了“方便LLM理解”,把数组join(",")成了字符串,再塞给LLM。
    根因:我们篡改了原始数据结构,破坏了契约。LLM看到的是字符串,它当然会原样返回字符串。
    修复:适配器绝不修改原始数据结构。LLM的输入context里,photo_urls必须保持为JSON数组;LLM的输出里,damagePhotos也必须是数组;适配器只负责把LLM输出的数组,按WMS要求的格式序列化。
    经验:数据保真度高于一切。任何为了“方便LLM”做的数据变形,最终都会付出十倍代价。我们后来加了一条lint规则:所有适配器的输入/输出,必须和原始API的OpenAPI Spec 100%匹配。

6. 最后一点个人体会:Agent不是终点,而是业务数字化的新起点

做完这6个Agent项目,我越来越确信:所谓AI Agent,本质上是一次对业务流程的深度逆向工程。你必须亲手拆开每一个螺丝,弄清每个系统为什么这样设计,每个字段为什么叫这个名字,每个错误码背后藏着什么业务逻辑。这个过程痛苦,但收获巨大——它逼着技术团队真正听懂了业务语言,也让业务方第一次看清了自己流程里的冗余、断点和黑洞。现在回头看,那些花在调prompt、换模型上的时间,远不如花在梳理WMS的reason_code枚举值上更有价值。2025年,最成功的Agent项目,往往不是技术最炫的那个,而是那个产品经理、开发、运维、业务方一起,在白板上画了17版流程图,把每个异常分支都标红,把每个接管按钮都讨论了半小时的项目。Agent不会取代人,但它会无情地暴露:哪些流程本就不该存在,哪些决策本就该交给机器,哪些环节才真正需要人的智慧。所以,别再问“我的Agent什么时候能上线”,先问问:“我们敢不敢,把这张画满红叉的流程图,贴在全员都能看到的地方?”