1. 从一次失控的工具调用说起:Agent到底是什么
去年我帮一家零售企业做售后知识库Agent,第一版上线时团队内部最大的争议是“要不要用LangGraph”,大家普遍认为Prompt写得好就够了。结果上线第二周就被现实打脸:用户问“我上个月买的风扇怎么退货”,Agent先去查订单,拿到订单号之后,下一轮对话里订单号被后续的工具返回覆盖了,它又调了一次查询接口;接着又把用户地址误当成收货地址,触发了一次改地址操作。整段对话像喝醉了酒,用户投诉直接怼到了管理层。
排查到最后,不是代码bug,而是上下文设计问题——我们根本没有把工具调用过程作为“状态”来管理。这个事故让我重新想清楚一件事:AI Agent不是“LLM接口外面套一层Prompt”,它是一个有自主决策循环的执行系统。如果你把Agent当成传统接口来做,早晚会在某个用户会话里翻车。
1.1 事故复盘:循环决策里的状态是怎么丢的
先还原一下那个故障链路的真实运行过程。普通LLM应用只需要把“系统提示词 + 用户消息”发给模型,拿到回答就结束了。Agent化之后,同样一次用户请求,后端实际发生的事情是:
- Agent把用户问题发给LLM,LLM判断“需要调用查询订单工具”。
- Agent去ERP接口拿订单数据,工具返回一长串JSON。
- Agent要把这个JSON拼回上下文,再发给LLM,让它根据订单状态回答用户。
- LLM这时候可能发现订单是三个月前买的,已经过了退货期,所以需要再调用一次售后政策查询工具。
- 工具返回之后,Agent又要拼上下文再发给LLM,直到LLM认为可以结束。
也就是说,一个简单问题背后可能是3到5轮“LLM调用 + 工具调用”的循环。每一轮,中间产物都要写进上下文。问题就出在这里:我们当时用固定长度的消息列表,新工具结果进来时把旧工具结果挤掉了,LLM看不到“这个订单号是哪一次查询得到的”,逻辑就开始错乱。
类似的坑还有工具侧的状态残留。比如用户说“帮我查一下杭州店的库存”,Agent调用门店查询工具,工具返回了store_id,下一轮用户说“再看看上海店”,Agent如果没把store_id重新换掉,就可能用杭州店的门店编号去查上海的库存,得到一份看似合理其实错了的结果。
这个事故给我最大的教训是:Agent系统的核心单元不是“一段对话”,而是“一轮执行状态”。状态要清晰、要持久化,且每一步都要能被追溯。
1.2 Agent化应用与普通LLM应用的分水岭
普通LLM应用的本质是“文本进、文本出”,是一个非常线性的管道:请求来了,拼Prompt,调模型,返回结果,结束。Agent应用的本质是“输入进来之后,由模型决定下一步做什么”,于是响应路径从直线变成了循环加分支。
这个循环的标准样子,大部分人应该都听过:感知输入 → 规划下一步 → 调用工具 → 观察结果 → 再规划,直到认为目标完成。不管底层用ReAct、Plan-and-Execute还是Tool Calling,落到工程上其实都是这个闭环。
闭环带来了三个普通接口没有的工程变化,这是每个做Agent落地的人都要面对的:
- 状态不再是隐形的。你需要明确知道“当前执行到哪一步、上一步的结果是什么、下一步的计划是什么”。
- 执行链路需要被持久化。如果服务重启、网络抖动、容器被杀,用户会话不能从头再来。这和人做事的道理一样,总不能每接一个电话都把前五分钟的话重说一遍。
- 每一步都要可观测。“模型为什么调用这个工具”“工具返回了什么”“为什么最后给出了这个答案”,这些问题必须在日志里能回答,否则出了问题就只能瞎猜。
看到这里你应该明白,Agent并不是什么玄学概念,它就是把“一个人用工具完成一个目标”的流程数字化了。基于这个理解,下面聊架构范式才有意义。
2. 三种编排范式:单Agent、多Agent与图式工作流
关于Agent的架构范式,坊间有各种各样的说法,什么“Agent = LLM + 记忆 + 规划 + 工具”,听起来很有道理,但真正落地的时候你会发现,范式的关键不在组件,而在“流程怎么编排”。我按实际项目里的使用频率,把主流范式分成三种:单Agent、多Agent协作、图式工作流。它们不是互斥关系,很多时候是混着用的。
2.1 单Agent:大多数业务的默认选项
单Agent是指一个Agent实例同时承担“理解用户意图、规划步骤、调用工具、组织回答”的全部职责。它看起来像一个智能体,实际上就是一个带工具集的强化版LLM循环。
大多数业务场景,单Agent是性价比最高的选择。比如售后知识库、订单查询、门店信息问答,这些任务目标明确,工具数量在十个以内,单Agent完全扛得住。选它的理由也很直白:
- 维护成本低。只有一个模型、一套Prompt、一组工具,排错链路短。
- token消耗可控。多Agent会有额外的通信和上下文传递开销,单Agent没有这个问题。
- 迭代速度快。你改一个工具的描述,或者调一下Prompt,立刻能验证效果,不必牵动整张图。
单Agent并不是没有缺点。当工具数量超过一定量级,比如超过三四十个,模型在每次决策时都要从长列表中做选择,准确率会明显下降;当业务有严格的流程要求,比如必须先核验身份再查数据,单Agent的“自由发挥”就会成为风险。这时候你需要考虑更确定的编排方式。
2.2 多Agent协作:从角色拆分到通信开销
多Agent的思路是把一个大而全的Agent拆成多个各司其职的小Agent,比如一个Planner负责拆解任务,几个Worker分别负责查询不同域的数据,一个Critic负责检查最终答复质量。
这种范式在概念上很优雅,像一支小团队:有人定计划,有人干活,有人检查。但我要很坦率地说,多Agent在工程上的收益远没有概念上那么美好,三个问题绕不开:
第一个是上下文放大。每个Agent都要接收任务描述、中间结果、协作消息。同样的信息在多个Agent之间传递,token消耗呈指数级增长。第二个是通信协议成本。Agent之间如何传递结构化结果,谁来定义接口,传递的消息要不要校验,这些都需要额外设计。第三个是故障定位复杂。一个用户问题最终答案出错,你要在多个Agent的日志里来回翻,才能找到是哪一环改坏了信息。
所以我通常只在两种情况下推荐多Agent:一种是角色之间的“世界知识”差异很大,比如法律顾问Agent和财务核算Agent,拆开之后各自指令清晰;另一种是业务本身就有明确的角色边界,不拆反而不自然。更多时候,一个“路由式”的准多Agent结构就够用了——简单说,先用一个分类器或模型判断请求类型,再转发给对应的单Agent处理,各Agent之间不互相聊天,这样既获得了分工的好处,又避开了协作通信的泥潭。
2.3 图式编排:用有向图把流程焊死
图式编排是我现在最推荐生产使用的方式。它的核心是用一张有向图来定义流程,节点是“动作”,边是“流转条件”,Agent不再自由发挥,而是沿着图上的路径一步一步走,走错就回到指定节点重试。
以LangGraph为例。你可以把节点定义成“理解意图”“调用工具”“生成回复”,再用条件边控制走向。某些节点必须前置执行,某些分支只对特定条件开放。这种方式最大的好处是:Agent的灵活性和系统的可控性之间,可以自己调节比例。
实际项目中,我很少会用“纯自由”的单Agent,也很少用完全焊死的流程,最佳实践是“自由为主,关键节点用图控制”。比如客服Agent,整个流程可以保持自由,但“下单”和“退款”这两个节点必须是确定的——必须先校验用户身份,再执行操作,失败就返回重新确认。把这些关键控制点画进图里,其余步骤让模型自己走。灵活性保住了,风险也压住了。
三种范式的选择,我的建议是按顺序来:优先单Agent,复杂度压不住时做路由式拆分,流程中有关键控制点时引入图式编排。下面用表格把几个关键维度放在一起对比:
| 维度 | 单Agent | 多Agent协作 | 图式编排 |
|---|---|---|---|
| 灵活性 | 最高 | 中高 | 中低,可按需调节 |
| 维护成本 | 低 | 高 | 中高 |
| Token开销 | 低 | 高 | 中 |
| 故障定位 | 容易 | 困难 | 相对容易 |
| 适用场景 | 目标明确、工具少 | 角色差异大、边界清晰 | 有严格流程控制点 |
| 代表框架 | ReAct | LangGraph多角色、AutoGen | LangGraph、自研状态机 |
3. 核心组件拆开看:记忆、工具与自我修正
范式决定了Agent的骨架,组件决定了Agent能不能真正干活。我拆项目的时候,习惯把组件分成三层来看:记忆层、工具层、规划与自我修正层。这三层每一层都有不少反直觉的坑,下面一个个讲。
3.1 记忆:短期窗口怎么管,长期记忆怎么存
记忆分为短期记忆和长期记忆,这个分类大家都懂,但落地时最容易犯的错是把全部历史都塞给模型。一篇2000字的对话历史、几段工具返回、再加上用户新输入,一次性放进上下文,最先遭殃的是注意力——模型会被中间过程的长文本带跑,把用户最初的需求忽略掉。
我对短期记忆的处理策略是“分层裁剪”。保留最近5到8轮完整消息,更早的内容在每次新请求进来时做一次摘要,只把摘要和最近消息一起发给模型。这样既保留了对用户需求的理解,又不会让上下文无限膨胀。实现摘要可以用一次额外的LLM调用,也可以用一个简单的“截断+关键字段提取”函数,具体看业务要求。
长期记忆则是另一个话题。很多团队一上来就建向量库,把用户所有历史都灌进去,但实际使用时发现召回质量很差,因为大多数Agent场景根本不需要长期记忆。需要长期记忆的场景通常有明确特征:用户身份重要、跨会话偏好明显、历史行为会直接影响下一次决策。比如理财助手记住用户的风险偏好,这是合理的长期记忆;客服系统记住用户上个月买过什么,那更像是短期业务数据,应该走数据库查询,而不是让Agent用向量检索去猜。
3.2 工具调用:Schema设计是成败关键
工具层是Agent真正“动手干活”的地方,也是最容易被低估的一层。模型本身不会调用任何接口,它只负责输出一个结构化的调用意图,真正执行的是你的代码。所以工具能否被准确调用,很大程度上取决于“工具描述”和“参数Schema”写得好不好。
我在项目中总结了几条工具注册的硬规则:
- 参数名要贴近业务语言。比如查订单的工具,参数叫order_id比叫oid好;工具描述里写清“用户说的‘我刚买的’可能对应最近30天订单,不能默认是全部订单”。
- 工具描述必须包含边界条件。你的工具只能查直营店库存,就必须在描述里写明“仅支持直营门店,加盟店请勿调用”,否则模型会把所有门店问题都交给它。
- 工具数量控制在合理范围内。单Agent配置二三十个工具是上限,超过之后建议按领域拆分。
- 每个工具都要做超时和幂等设计。尤其涉及状态变更的操作,比如“更新地址”“创建工单”,不能让一次网络重试产生两条工单。
工具返回的内容也要注意。真实业务系统返回的JSON经常很长,一坨全塞给模型既费token又干扰判断。我的做法是在工具函数内部先做字段精简,只保留模型回答用户问题所需要的最小字段集;同时设置返回长度上限,超长时截断并附一段摘要。
3.3 规划器与自我修正:如何让Agent“知错能改”
规划器的职责是决定“下一步做什么”。在简单场景里,规划器就是模型本身——它根据上下文直接输出下一步动作;在复杂场景里,规划器可以是一个独立的模型调用,专门输出一个多步骤计划,然后逐步骤执行。
自我修正这件事我需要泼一盆冷水:让LLM反复检查自己,并不会无限提升准确率,反而会显著增加成本。有研究表明,模型对自己的错误输出并没有可靠的“识别能力”,盲目反思往往是把对的改成错的,或者陷入“检查-发现错误-再检查-再发现错误”的循环。
正确的姿势是给反思设置边界。我通常的做法是:限制最大反思轮数,比如最多重新规划两次,第三次直接输出当前结果并附一段“我对部分信息不太确定”的说明;同时,只有当工具返回异常或者结果校验失败时才触发反思,而不是每次回答前都强制自检。
工具结果校验是自我修正里最实用的一环。比如查询订单后,写一个独立的校验函数,检查返回里有没有订单编号、金额是否合理、是否与用户描述一致。校验函数不依赖模型,逻辑完全确定,一旦失败就触发一次重新规划或要求用户补充信息。这种“确定性校验 + 有限反思”的组合,比纯靠模型自纠要稳得多。
4. 并发是第一道生产坎:Agent服务如何扛住真实流量
“AI Agent怎么扛并发”是最近被问得最多的问题之一。很多人把Agent服务当成普通HTTP服务来设计,结果压测一跑就崩。Agent的并发问题有其特殊性,普通Web服务那套“加机器、加线程”的思路,直接搬过来往往不奏效。
4.1 瓶颈到底在哪:请求放大效应
先算一笔账。一个传统查询接口,用户请求到来后,后端查一次数据库,耗时50毫秒,整个过程只占用一个线程50毫秒。而一个Agent请求进来以后,可能要经历3到5次LLM调用,每次2到4秒;期间还夹着若干次外部工具调用,每次几百毫秒。也就是说,一个用户请求背后的处理器占用时间,从50毫秒被放大到了十几秒,甚至几十秒。
这个“请求放大效应”是Agent并发问题的根源。假设你的服务用10个worker线程处理请求,传统接口可以轻松扛住每秒200个请求,而Agent服务同一时间只能处理两三个并发请求,剩下的全部排队超时。所以Agent服务的并发优化,首要目标不是加快单次响应,而是降低每次请求对系统资源的持续占用。
4.2 无状态化与会话快照:解决多副本扩展问题
Agent执行过程中,状态是不断更新的:已调用的工具、中间结果、计划步骤、消息历史。如果这些状态只存在进程内存里,你的服务就无法横向扩展——因为新副本不知道旧副本发生了什么,负载均衡一转发,会话就断了。
解法是把状态外置。我推荐使用Redis或类似的高性能KV存储,用session_id作为键,把整个Agent状态序列化存进去。每次循环执行完后,把最新状态写回Redis;下一次请求进来时,从Redis恢复状态,接着执行。这样所有副本共享同一份状态,无论请求被转发到哪台机器,执行都能继续。
这里有一个细节:不要让Redis成为瓶颈。Agent状态往往比较大,如果每个请求都要读出全部历史再写入,Redis的带宽也会被打满。我的做法是“增量更新 + 定期压缩”,每个节点执行完后只更新变化的部分,每执行完一轮完整循环后,做一次状态压缩,丢掉已经用不上的中间变量。
4.3 超时、熔断与降级策略
Agent调用的外部依赖太多了:LLM接口、内部API、第三方服务。任何一个依赖变慢,整个Agent都会被拖住。所以在Agent服务里,超时和熔断不是可选项,而是必选项。
我给LLM调用设置的超时通常是15秒到30秒,超过就返回给用户“我现在有点忙,请稍后再试”。工具调用的超时更严格,控制在3到5秒。熔断方面,如果同一个工具连续出错超过5次,就自动降级——不再调用该工具,而是直接告诉用户“这个功能暂时不可用”。这样即使下游系统故障,Agent服务也不至于全线雪崩。
还有一个容易被忽略的细节是用户侧限流。Agent接口响应慢,用户往往会忍不住多点几次“重试”,于是同一个用户产生了多个并发请求,每个请求都在跑同一个会话状态,互相覆盖,最终结果乱成一团。我通常的做法是按用户维度做并发限制,同一个session_id同一时间只允许一个Active请求,新的请求要么排队,要么直接返回“正在处理中”。
4.4 流式输出与连接数的双重影响
Agent单次响应时间长,如果让用户盯着空白页面等几十秒,体验非常差。所以生产环境必须做流式输出,把Agent的思考过程、工具调用状态、最终文本一五一十地推给前端。
流式有两种技术路线:SSE和WebSocket。SSE实现简单,基于HTTP,防火墙友好,适合“服务端单向推送”的场景,大部分Agent应用够用了。WebSocket适合双向实时交互,比如用户可以在Agent执行过程中打断它说“换个思路”,但这种场景复杂度高,我建议不要在初期引入。
流式输出带来的新问题,是长连接对网关和负载均衡的连接数压力。Agent响应几十秒,意味着几十秒内这条连接不能释放,单机连接数很容易堆到几千上万。部署时要注意调整网关的连接超时时间、空闲超时时间,同时保证后端服务支持长连接不断开。多副本部署时,最好让同一会话的流式请求稳定路由到同一副本,避免连接片段。
5. 一套可复制的落地路径:FastAPI + LangChain + LangGraph
聊完理论和并发,讲讲从零搭建一套生产级Agent服务的实操路径。我的默认技术栈是FastAPI + LangChain + LangGraph,这是目前生态最成熟、社区资料最全、还是最容易上手的组合,没有之一。
5.1 技术选型的理由:为什么是这三件套
选型之前我先说一句:不用迷信框架,但在生态成熟度相差悬殊时,选成熟框架是性价比最高的决策。
- FastAPI:基于异步的Python Web框架。Agent服务需要大量异步I/O,FastAPI原生支持async/await,天然适配Agent场景。它还自带OpenAPI文档、参数校验,开发效率高。
- LangChain:提供统一的LLM调用接口、工具抽象、Prompt模板、输出解析器。它最大的价值不是某一项功能,而是把“模型、工具、记忆”的标准用法沉淀成了一层规范,团队协作时接口是统一的。
- LangGraph:专门做Agent状态编排的框架。它把状态机、节点、边、循环、条件分支这些概念落成了代码,比你自己手写一个状态机要省太多时间。
这个组合在国内环境下完全可以用。模型层面可以接国内大模型,工具层写自己的业务API,框架本身只是编排层,不绑定任何特定厂商。
5.2 一个可运行的Agent服务骨架
先看目录结构,这是我目前最常用的组织方式:
app/ ├── agents/ │ ├── state.py # LangGraph状态Schema │ ├── nodes.py # 图中各节点的执行逻辑 │ └── graph.py # 图定义与编译 ├── tools/ │ ├── registry.py # 工具注册与Schema管理 │ ├── order.py # 订单类工具 │ └── logistics.py # 物流类工具 ├── memory/ │ └── redis_store.py # 基于Redis的状态与记忆存储 ├── api/ │ └── chat.py # FastAPI路由 ├── config.py └── main.py核心的LangGraph图定义大致长这样。下面是一个最小但完整的状态图,包含“思考”和“执行工具”两个节点,以及一个条件路由:
from typing import TypedDict from langgraph.graph import StateGraph, END class AgentState(TypedDict): messages: list tool_calls: list tool_result: str finished: bool def think_node(state: AgentState): # 1. 读取state里的历史消息与工具结果 # 2. 调用LLM,让它决定下一步是调工具还是直接回答 # 3. 把模型输出的tool_calls写回state return {"tool_calls": [...]} def tool_node(state: AgentState): # 1. 遍历state里的tool_calls # 2. 逐个执行对应工具函数 # 3. 把结果精简后写回state.tool_result return {"tool_result": "..."} def route_after_think(state: AgentState): if state["tool_calls"]: return "tools" return END graph = StateGraph(AgentState) graph.add_node("think", think_node) graph.add_node("tools", tool_node) graph.add_edge("think", "tools") graph.add_conditional_edges("think", route_after_think, {"tools": "tools", END: END}) app_graph = graph.compile()FastAPI侧只需要一个聊天路由,把请求接进来,用异步方式跑Agent图并把事件流式返回:
from fastapi import FastAPI from fastapi.responses import StreamingResponse app = FastAPI() async def agent_events(session_id: str, user_input: str): config = {"configurable": {"session_id": session_id}} async for event in app_graph.astream_events( {"messages": [{"role": "user", "content": user_input}]}, config=config, version="v1" ): yield format_sse(event) @app.post("/chat") async def chat(session_id: str, user_input: str): return StreamingResponse( agent_events(session_id, user_input), media_type="text/event-stream" )这里有三点要强调。第一,astream_events是LangGraph提供的异步事件流API,它能把执行过程中的每个节点事件都推给前端,用户可以看到Agent“正在查订单”“正在核对地址”这类过程状态。第二,session_id贯穿整个请求,所有状态读写都以它为准,这是实现多副本扩展的基础。第三,工具函数内部必须自己实现超时和错误处理,不要指望框架帮你兜底。
5.3 生产化改造五步:从demo到上线
demo跑通之后,离上线还差五步改造,每一步都不复杂,但缺一步都可能在生产环境出事。
第一步,状态外置。把LangGraph的MemorySaver换成基于Redis的持久化存储,保证进程重启不丢会话。
第二步,工具链加固。给每个工具函数加重试、超时、熔断逻辑。涉及写操作的工具必须做幂等处理,用幂等键或请求号去重。
第三步,消费端限流。在API入口加按用户限流,同一session只允许一个活跃请求。超出配额的请求直接返回友好提示。
第四步,全链路可观测。给每次Agent执行生成一个trace_id,从入口到每次LLM调用、每个工具调用全部打点记录。日志里至少包含:模型输入的完整消息、模型输出的原始内容、工具入参和出参、每一步的耗时。
第五步,回归评测集。抽50到100条真实历史问题,固化成一个自动化评测集。每次改Prompt、加工具、升模型版本时,先跑一遍评测集,对比通过率再决定是否上线。没有评测集的Agent项目,上线就是靠运气。
5.4 可观测性:Agent的每一步都要留痕
Agent和传统接口最大的不同在于中间过程不可控。同一个问题,可能今天调了工具A,明天直接回答了。没有中间过程的记录,你根本无法判断行为是否符合预期。
我推荐的日志结构是“一次执行一条主记录 + 每个步骤一条子记录”。主记录包含session_id、trace_id、用户问题、最终回答、总耗时;子记录按时间顺序记录每一步的事件类型、事件内容、所依赖的模型或工具、耗时。这样打开日志系统,一条时间线就能还原Agent当时的完整决策过程。
如果预算允许,可以考虑接入LangSmith这样的专用可观测平台,它会自动把图执行过程可视化。不做可视化也不是不行,自建一张events表,把每次执行过程的关键字段结构化存储,同样能达到排查问题的目的。
6. 场景边界与中台化:哪些需求值得做Agent化
Agent不是万能的。做了一年多Agent项目,我越来越意识到场景边界的重要性。有些需求天生适合Agent化,有些需求则是硬往Agent上靠,最后既贵又难用。
6.1 值得优先Agent化的三类场景
第一类,目标明确的业务问答。比如客服、售前咨询、企业知识库问答。这类场景工具边界清晰、用户问题相对集中、容错率较高,即使Agent偶尔答错,人力还能兜底。
第二类,多步骤信息收集与汇总。比如让Agent跨多个系统收集项目进度、汇总周报、对比不同渠道的价格。这类任务单靠传统接口写起来很死板,Agent的灵活性能切中痛点。
第三类,确定性流程的辅助执行。比如工单创建前的信息核对、审批流程的前置检查。Agent负责理解用户意图、填好参数,关键动作仍然走原有审批流,出错的概率被控制住了。
判断一个需求是否适合Agent化,我有个简单的标准:如果这个任务你招一个人来做,需要培训三天以上、过程中还要不断查内部系统,那它就适合Agent化;如果一个人看一眼就能完成,那传统接口更快更稳。
6.2 个人自动化交易类需求的现实边界
“个人使用AI Agent可以做期货交易吗”这类问题我经常被问到。我的第一反应是:能做,但绝大多数人不应该做。
Agent做交易不是技术上的问题。只要你有API,Agent完全可以做到监控行情、分析信号、自动下单。真正的麻烦在于风险控制。Agent的执行链路非常长,每一个环节都有延迟:行情数据要拉取几十秒甚至几分钟,模型分析要几秒,下单接口调用又要几秒,这几秒里行情可能已经反转了。而且Agent的“分析”本质是概率性的,它没有真正理解市场,只是基于历史数据和模型参数生成了一种看起来合理的判断,这种判断在低延迟、高波动的交易场景里非常危险。
如果你坚持要尝试,我的建议是把边界缩到最小:让Agent做“信息聚合和风险提醒”的角色,把行情摘要、新闻情绪、关键技术指标整理好推送给你,下单这个动作永远由人来做。所有决策都保留人工确认环节,Agent绝不能直接持有交易权限。这既体验了Agent的能力,又不至于把风险完全交给一个不可控的系统。
6.3 Agent中台与低代码平台:什么时候该用扣子这类产品
现在国内有不少Agent搭建平台,扣子是其中典型代表。低代码平台非常适合两类人:一类是想快速验证想法的业务人员,不懂代码也能拖拽出一个客服Agent;另一类是企业内部轻量自动化场景,比如行政助手、IT工单机器人,不需要深度定制,平台上架就够。
但平台产品也有明确的边界:多租户隔离、私有化部署、复杂工具协议、与既有系统的深度集成,这些在低代码平台上往往很难做好。我的判断标准是:如果核心业务数据必须留在企业内网,或者Agent要对接的自建系统非常多,那就应该走自研路线,不要在低代码平台上死磕。
至于是不是要建Agent中台,我的看法是:中台的核心价值不是技术框架,而是把工具、Prompt、知识库、评测集沉淀成可复用的资产。当你的Agent项目超过三个,且多个项目共用同一批内部工具和知识库时,中台的必要性才会显现。在那之前,一个规范化的Git仓库加上统一的工具注册表,比一个重中台更实用。
7. 学习路线与避坑清单
Agent领域的技术更新非常快,模型版本一迭代,网上就会出现一批“新架构”“新概念”。学这一行,大部分人缺的不是信息,而是主线。我结合自己和团队成员的成长路径,梳理一条相对稳的学习路线。
7.1 从原理到框架再到底层,不跳步
第一步,把基础概念吃透。ReAct模式是什么、Tool Calling什么时候触发、记忆分哪几类、Agent循环的过程是怎样的。不要一上来就啃框架源码,先把原理层面的人话版本搞明白。这一阶段推荐去看模型的Function Calling文档、LangChain核心概念页,以及几篇讲Agent架构的中文综述,有一个全局印象就够了。
第二步,搭一个简单的demo。这一步目标不是做出多完善的系统,而是亲身体验一遍“用户输入 → 模型决策 → 工具调用 → 返回结果”的完整链路。用LangGraph跑通一个小型客服Agent,或者用扣子这类平台拖一个最简单的机器人,都算数。体验过一遍,很多概念才真正落到地上。
第三步,去读LangGraph的源码,只看状态管理那部分就够。很多人以为LangGraph很神秘,它的核心就是一个状态图编译器加状态持久化器。你亲手给它接上Redis、跑通并发场景,对这个框架的理解就能超过大半同行。顺带把LangChain的工具调用抽象读一遍,理解参数Schema是如何被动态传给模型的。
第四步,做一次真正的工程化改造。把自己的demo从单机版改成可部署版:状态外置、异步化、加流式输出、加日志追踪、建一个小的评测集。这一步做完,你就不再是Agent的“使用者”,而是能驾驭它的人。
第五步,沉淀自己的方法论。把你做过的项目按场景归类,哪些环节模型决策稳、哪些环节容易漂、哪些工具描述最容易被模型误解析,总结成自己的经验库。这套东西才是你在Agent领域真正的核心竞争力。
7.2 我踩过的坑与对应解法
最后把这一年多踩过的坑集中列一下,希望后来者少走弯路。
第一个坑,一上来就搭多Agent。曾经有个项目,原本一个Agent就能解决的问题,我们为了架构噱头拆了三个角色,结果通信开销上升、排错困难、成本翻倍,最后又退回单Agent加路由。多Agent只有在角色边界天然清晰时才有价值,别为设计而设计。
第二个坑,把所有历史都塞给模型。上下文越长,模型越容易“迷失”,token成本也越高。一定要做分层记忆管理,保持最近几轮完整消息加历史摘要的组合。
第三个坑,工具返回不做裁剪。一个大接口的原始JSON可能有几百行,全部拼进prompt后模型经常抓不住重点。在工具函数内部做字段精简,是最容易见效的优化。
第四个坑,没有评测集就上线。早期我改一个Prompt,感觉变好了就发上去了,结果生产环境准确率不升反降,因为没有量化对比。后来老老实实建了回归集,每次改动跑一遍,心里才有底。
第五个坑,忽略重试与幂等。有一次Agent把一条重复工单建了三遍,原因就是网络抖动导致工具函数被重复执行。这之后我给所有写操作都加了幂等键,再也没发生过同类事故。
第六个坑,把Agent执行过程当成黑盒。只要看不到中间步骤,出问题就只能靠猜。建立全链路日志不是可有可无的增强,而是Agent系统的基本盘。
我现在的原则是,Agent的复杂度必须由业务收益买单。能用单Agent解决的,绝不引入多Agent;能让关键节点确定的,绝不把全部流程都交给模型自由发挥。最后再说一个很实用的小经验:每次上线前,找几个真实用户的问题,手工走一遍Agent的完整链路,截图记录每一节点的表现。这套“人工巡检”虽然土,但比任何自动化评估都能更快发现问题。Agent这门技术,一大半价值在细节里,另一半在踩坑后沉淀下来的判断力里。