ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

前端转Agent开发实战:从工单需求到企业级智能体

前端转Agent开发实战:从工单需求到企业级智能体 我做了快六年前端React、Vue、可视化大屏都摸过一遍。上个月技术总监丢给我一个需求做一个能自动回答客户售后问题的机器人接入现有的工单系统。我一开始以为是普通问答机器人照着文档拼接几个prompt就完事。结果越做越不对劲客户问的是“我的订单为什么还没发货”这背后要查订单状态、物流轨迹、仓库库存、客服备注甚至还有改地址的权限操作。这根本不是对话这是要把一堆业务系统串起来干活。做完这个项目后我最大的感受是前端转Agent开发最好的切入点不是去学一堆概念而是先接住一个真实需求让需求逼着你去理解Agent是什么。1. 从工单系统到Agent最初的企业需求到底长什么样1.1 客户想要的不是“聊天”而是“把事办成”需求刚从产品那边传过来的时候描述很简单做一个在线客服机器人客户问了之后机器人能自动回复减少人工成本。我当时第一反应是做关键词匹配加FAQ最多再上个RAG检索增强生成把企业文档喂进去。但真正去蹲客服部门看了几天后我发现真实场景复杂得多。客户问“订单怎么还没到”客服不是回复一句“请耐心等待”就完事而是需要完成下面这串动作登录订单系统根据客户手机号查出订单号调第三方物流接口看包裹当前位置如果物流超过三天没更新自动生成一条异常工单如果订单在“已支付未发货”状态超过48小时触发催发货通知最后把可执行的结论预计送达时间、补偿方案返回给客户。这套流程里模型要做的不是生成漂亮话而是理解用户意图、拆解任务、调用多个工具、根据返回结果做决策。这才是真正的企业级Agent形态。也就是从这时候起我决定这个项目不能用传统对话机器人方案来做而是要按照Agent的路子来设计。1.2 为什么传统对话机器人在这个场景下必然翻车传统对话机器人通常是“意图识别 槽位填充 规则响应”。你定义一堆意图比如“查订单”“退换货”“投诉”然后训练模型把用户的话分类到意图里再提取槽位订单号、手机号最后走固定流程返回。这套逻辑在简单FAQ场景下够用但一旦出现需要动态决策的环节就崩了用户说“我昨天买的东西什么时候能到”系统需要先知道“昨天买的”对应哪个订单如果用户有多个订单还要进一步追问用户说“不想要了怎么退”可能涉及“查询订单状态”“判断是否可退”“计算退款金额”“生成退货地址”一系列动作中间任何一步失败都要有回退策略用户说“你们怎么又发错货了”这种情绪化表达里没有明确的工具参数但Agent需要结合用户历史订单和最近一次客服备注去推断。这些问题靠预设对话流根本填不完。Agent把这事情反过来做我不提前定义所有对话分支而是给模型一套工具和明确的决策边界让模型在每一步自己决定“调哪个工具”“传什么参数”“下一步做什么”。前端开发里我们常做状态机来解决复杂交互Agent本质上是一个更动态、更自治的状态机。1.3 真实业务边界Agent不是万能钥匙做项目之前必须先划边界这个比写代码更重要。我一开始天真地以为只要把工具给全Agent什么都能搞定。但实际跑了之后发现不加边界控制的Agent是企业项目里的一颗定时炸弹。我最终确定的边界是Agent只负责“查询类”和“标准操作类”任务比如查订单、查物流、生成工单涉及退款、改地址、补偿金额这类高风险操作Agent只负责起草结论最终由人工确认后执行所有Agent对外回复都必须带有可追溯的引用来源客服能在后台点进去看数据来源。这个边界看起来简单但它决定了后面的架构设计。Agent只有在可控范围内才叫智能体出了边界就是事故。前端同学做这个项目有一层天然优势——我们对“用户确认弹窗”这种交互很熟把同样的思路用在“人工审批节点”上比后端同学想得还细。2. 用前端思维理解Agent架构反而比后端同事更快上手2.1 Agent核心循环感知-规划-行动-记忆对应着前端的渲染-事件-状态我先解释一个最容易让新手绕晕的事Agent到底是什么。换个前端视角立刻清楚起来了。前端框架的核心是UI f(state)事件触发状态变更状态变更触发重新渲染。Agent也类似它的核心循环是感知把用户输入和工具返回结果作为上下文喂给模型规划模型根据上下文决定下一步调用哪个工具或直接生成回复行动执行工具调用得到结果记忆把中间步骤写入context或外部存储供下一步决策使用循环直到模型认为任务完成。这跟前端的事件循环没有本质区别。用户点击按钮是“用户输入”API返回数据是“工具执行结果”全局状态管理就是“记忆层”。我甚至在给团队讲Agent架构的时候直接画了一张类似Redux数据流的图大家秒懂。2.2 当我说“Agent框架”时我实际在用哪些东西前端的“框架”指的是React/Vue这种UI库Agent领域的“框架”抽象层级更高。市面上常见的Agent框架包括LangChain、LangGraph、Dify、Coze还有近期火起来的各类轻量级Agent框架。它们的核心能力可以归纳成三块模型调用层屏蔽不同大模型厂商的接口差异统一成OpenAI兼容格式工具调用层让你把普通函数注册成LLM可识别的工具Tool/Skill并自动完成参数JSON Schema填充编排层定义Agent的执行循环包括单步调用、多步推理、人工审批节点、错误重试等。我最终选型时没有直接用大而全的LangChain而是选了LangGraph做编排配合自己封装的工具注册层。原因很简单这个业务涉及多步工具调用和人工审批节点LangGraph把整个流程画成一张图节点和边都看得见出问题时能定位到具体节点。2.3 前端项目里最容易忽略的模型调用层很多前端同学一上来就想着怎么画聊天界面结果卡在“模型到底怎么调用的”。这里必须搞清楚一个基础概念大模型API本身是无状态的。你上一轮问它什么它下一轮是不记得的除非你手动把聊天记录拼到上下文里。所以Agent开发里必须自己维护消息历史。我刚开始用了一个最简单的方式const messages [ { role: system, content: systemPrompt }, { role: user, content: userQuestion }, ]; // 第一次调用 const response await callModel(messages); // 把模型回复追加进messages messages.push({ role: assistant, content: response.content }); // 判断是否要调用工具 if (response.toolCalls?.length) { for (const call of response.toolCalls) { const result await executeTool(call); messages.push({ role: tool, tool_call_id: call.id, content: JSON.stringify(result), }); } }这段代码看着简单但它体现了Agent开发的核心你不是在写一个“提问-回答”的函数而是在维护一段会生长的对话状态。前端同学如果熟悉Redux这里就是把action和reducer换成了messages数组。3. 第一版落地的技术选型与完整实现路径3.1 技术选型对比直接用LLM API还是上Agent框架我拿到需求后先做了个技术预研列了一张对比表逼着自己做决策。方案优点缺点适合场景直接调LLM API 自己写循环完全可控依赖少多步决策逻辑要自己写开发量大只有一两个工具调用的小项目LangChain生态全上手快抽象层级多出问题时不好排查原型验证、标准流程LangGraph图结构编排节点清晰学习成本中等概念多需要人工审批和多分支流程Dify / Coze 这类低代码平台配置即开发上手最快定制化受限难接私有化复杂系统业务较标准、不想写太多代码我最后选了LangGraph作为编排底层原因有三个第一业务里有多个人工审批节点图结构好表达第二团队里有前端也有后端图比代码更容易沟通第三它支持状态快照机制调试的时候能看每个节点的输入输出这个对排查问题太重要了。3.2 核心代码拆解工具注册、任务编排、上下文拼接整个项目最核心的代码不是聊天界面而是工具注册和执行层。我先定义了一个统一工具结构让前端同事也能像写页面组件一样注册新能力interface AgentToolTArgs, TResult { name: string; description: string; parameters: JSONSchema; // 供模型做参数理解 needsConfirm?: boolean; // 是否走人工审批节点 execute(args: TArgs, context: AgentContext): PromiseTResult; }然后把业务系统的能力一个个注册进去。比如查询订单const queryOrderTool: AgentTool{ keyword: string }, OrderInfo { name: queryOrder, description: 根据手机号或订单号查询客户订单信息包含订单状态、商品明细、金额、下单时间, parameters: { type: object, properties: { keyword: { type: string, description: 手机号或完整订单号, }, }, required: [keyword], }, execute: async ({ keyword }) { // 调用后端订单服务 const res await fetch(/api/orders/search?keyword${keyword}); return res.json(); }, };这段代码前端同学应该看得懂。注意description那段话很关键模型不是靠函数名理解工具的而是靠这段描述判断“什么时候该用它”。这跟组件命名一个道理queryOrder谁都会写但“根据手机号或订单号查询客户订单信息”才是让模型不误用的关键。3.3 把“前端Skills”的想法搬进Agent工具集做前端开发时我们强调组件复用、hooks抽取、props设计。做Agent的Skill设计时我把这套方法论平移了过来。所谓Skill技能本质上是告诉模型“某些特定场景下你该按什么步骤做事”的预置能力。它可以是一段补充Prompt也可以是一个组合工具调用链。举一个例子。客户问“我的订单怎么还没到”如果只给模型一个queryOrder工具它可能查完状态就直接回答“请耐心等待”。但我们真正想做的是让模型进入一个“物流异常排查”技能按顺序执行下面的步骤调用queryOrder获取订单号调用queryLogistics获取物流轨迹如果物流轨迹超过72小时未更新生成工单并触发客服介入把处理结论转成客户能看懂的通俗话术。这个“技能”在LangGraph里就是一条子图。在前端视角里它就是抽取出来一个复用组件不同的地方需要时引用它。这套思路让团队里的后端同事都惊讶原来前端组件化思想还能这么用在Agent上。3.4 会话记忆不能只靠模型上下文硬撑业务上线后第一个实际问题是用户和Agent连续聊了五轮Agent就忘了第一轮说的手机号。原因是消息全塞在上下文里超过窗口后最前面的信息被截断了。我做的记忆层分两块短期记忆当前会话内把关键业务参数手机号、订单号、用户ID单独抽出来存进一个JSON字段每次对话开始时优先注入长期记忆把每个用户的历史工单、历史咨询分类、是否投诉过存进外部存储Agent回答时参考。前端同学可以这样理解短期记忆就像是组件里的state不随渲染丢失长期记忆像是缓存在localStorage里的用户偏好设置每次启动页面时读一次。const contextMemory { userId: U20240001, linkedPhone: 138****1234, orders: [ORD20241001], resolvedOrderId: null, lastEvent: ORDER_STATUS_QUERY, };关键业务参数结构化后上下文拼接就稳定多了。这是第一版上线后做的最重要优化之一效果立竿见影用户重复提供手机号的次数少了八成。4. 真实开发中的踩坑记录不是模型不够聪明而是边界没定义清楚4.1 工具调用参数验证前端同学最拿手却最后才做对刚开始写工具的时候我以为只要把parameters写成JSON Schema就完事了。结果上线第二天模型调用queryOrder时候传了个keyword是空字符串导致后端报错Agent就卡死了。排查链路如下我先把报错日志拉出来看到execute内部抛了“参数不能为空”的错误再往前翻发现模型确实生成了一个keyword: 的工具调用一开始怀疑是模型调用不稳定后来发现是工具描述的歧义问题——description里我没写“必须提供非空手机号或订单号”最关键的是execute函数里缺少一层防御性校验。修复方式有两个层面。先在后端工具入口加了一层参数校验execute: async ({ keyword }) { if (!keyword?.trim()) { return { status: error, message: keyword参数不能为空请先询问用户的手机号或订单号, }; } // ... }再把工具描述改进了一版明确加了约束keyword必填且必须是合法手机号或8位以上订单号若用户没有提供请先追问用户。加了这层之后模型乱传空参数的情况几乎绝迹。这件事让我意识到Agent的工具调用跟前端表单校验一个道理你不能相信用户的输入同样也不能相信模型生成的参数。4.2 上下文窗口被撑爆的排查链路项目跑了一周后有一天突然大量会话失败报错提示“token超出限制”。那时候我第一反应是该升级模型版本了但后来冷静下来一查发现根本不是模型的问题。整个排查过程是这样的我先去模型调用日志里看是什么会话触发的超限发现全是长会话用户和Agent聊了十几轮打开具体会话记录发现上下文数组里被塞进了大量完整的工单详情、JSON返回值换了一个小模型单独测还是超限说明不是模型问题是调用方的上下文管理有缺陷。根因就是我前面说的我在每轮工具执行后把完整工具返回结果原封不动塞进messages导致上下文越来越胖。解决思路不是粗暴截断而是要做信息压缩。工具返回的原始JSON里有大量没用字段我写了一个summarizeToolResult函数在把工具结果拼回上下文之前先对返回内容做摘要只保留对下一步决策有用的字段。比如订单详情原本有40个字段摘要后只保留订单状态、商品名称、预计送达时间、是否需要人工介入。上下文管理不是调参问题而是一个信息架构问题。前端做状态管理时我们时刻提醒自己“别把不相关的数据放进store”Agent开发里也一样。4.3 并发与超时平时写接口现在要写的是长时间任务管道这个坑我在联调阶段踩得最痛。前端的接口请求超时设置一般是10到30秒但Agent处理一个完整任务可能需要30秒甚至更久因为中间要多次调用模型模型本身响应就要几秒。第一版我把整个Agent调用包在一个HTTP请求里结果网关直接超时断连。后来我改成了异步任务模式客户端提交问题后后端立刻返回一个taskIdAgent在后台执行执行进度写入Redis前端通过WebSocket轮询taskId获取实时状态执行完成后把最终结果推送给前端。这套模式前端同学应该很熟就是上传大文件那一套先把任务提交上去再通过轮询或WebSocket拿进度。只是这次任务不是上传文件而是一个可能带有多步工具调用的Agent决策流程。WebSocket这里还要注意一点不要把整个Agent中间步骤都推到前端。我第一版推了所有模型原始响应结果聊天界面刷屏用户根本看不懂。后来只推三个状态执行中、需要人工确认、完成。中间的工具调用轨迹只留在后台日志里只有客服端能看到详细时间线。4.4 人工审批节点Agent和真实业务系统的握手协议我之前说涉及退款、改地址这类高风险操作必须人工确认。这个逻辑在流程图上画出来很简单真正落地时却有一个非常容易被忽略的问题Agent发起了审批然后呢如果用户后续又发来新问题Agent是等审批结果还是先处理新问题我最终的方案是Agent在触发人工审批时先把当前会话锁定在当前子图节点上同时给用户回复“您的退款申请已提交人工审核预计30分钟内处理完毕您也可以继续咨询其他问题”。客服端审批完成后系统把审批结果推回给AgentAgent再结合结果继续后续流程。这个“会话锁”的实现相当于前端里的互斥锁。我用一句话总结给我的团队Agent能发起的操作必须小于它能承诺的范围凡是超出范围的就必须把人放进链路里。5. 这次转型对我做前端开发的反哺与学习路线5.1 组件化思想迁移到Agent的Skill设计说实话前端转Agent开发最大的优势不是会写代码而是有一套已经训练过的抽象思维。Agent的Skill设计本质上就在做三件事找共性把多个业务流程里的重复动作抽出来比如“查客户”“查订单”“生成工单”都是高频动作定边界每个Skill只负责一件事输入输出都明确跟“组件props”一模一样可组合Skill之间可以互相调用一个“发货异常处理”Skill内部包含“查订单”“查物流”“建工单”三个基础Skill。这个思路对我原本的前端工作也有反哺。项目做完后我再写前端组件时会更自然地思考“这个组件会被哪个调用方使用”“它的输入输出协议是否清晰”等于用Agent的视角把前端代码审查了一遍。5.2 Agent开发学习路线从今天到这个项目验收我做了哪些事我整理一下自己从零开始做这个项目的过程想转Agent的前端同学可以直接按这个节奏走。第一步先把“模型调用”这层搞明白。不需要读特别深但一定要自己调通一次API理解什么是system prompt、user消息、assistant消息、工具调用返回。整个过程大概一周。第二步用一个现成的Agent框架做一个最小闭环。我当时用LangGraph做了一个“查天气然后生成穿衣建议”的Demo虽然简单但它把Agent执行循环完整跑通了。这一周的速度主要是踩环境依赖的坑。第三步找一个真实业务场景下的小切面把它做成一个单工具Agent。比如我就选了“查订单状态”这个点先不接物流、不接工单只让Agent学会根据手机号查订单并返回简洁结论。第四步在这个单工具基础上增加分支逐步把物流查询、异常判断、工单生成接进来。每加一个工具跑一遍完整回归观察模型是否会误用工具、参数是否传对。第五步再考虑记忆、并发、上下文压缩、人工审批这些“工程化”问题。整个项目大概用了六周。前三周每天花三小时左右学习和搭骨架后三周主要在联调、修边界的坑。前端基础在这里是很加分的理解API、理解异步、理解状态同步几乎无障碍平移。5.3 给同样想转Agent的前端同学几条实打实的建议第一不要一上来就研究特别深的模型原理。你是做工程交付的不是搞算法研究的。学习模型推理细节不如先写通一次工具调用。第二企业项目里Agent的价值不在于聊天多聪明而在于能不能真正调通业务系统。前端同学如果能把用户界面、身份认证、业务接口摸透做出来的Agent会比一个纯后端做的更贴近真实用户。第三多看框架的调试工具。LangGraph有一个可视化调试界面能看到每一轮模型决策、每个节点的输入输出这个跟前端DevTools里看Network面板一样重要排错全靠它。第四也是我最想强调的保持“怀疑模型”的心态。模型输出的每一个工具调用参数都要当成用户输入来校验。你之前怎么写表单校验现在就怎么写工具参数校验。最后一个实用技巧Agent项目一定要从第一天就把日志打全。我在每个关键节点都加了结构化日志记录模型思考、工具选择、参数、耗时、错误信息。后来所有线上问题的排查几乎都靠这些日志定位而不是靠用户复述。前端做埋点的经验在这里完整复用只是事件名换成了Agent动作名。
返回列表