AI Agent生产落地指南:七个要素与七个决策点的工程骨架

📅 发布时间:2026/10/5 12:19:25
AI Agent生产落地指南:七个要素与七个决策点的工程骨架
最近帮团队把一套客服 Agent 从演示环境推到生产环境过程比我想象中要血腥得多——演示时各种表现亮眼上线后连续出了好几起事故。排查过来回一圈问题根源基本都不在大模型本身而是一些工程实现的基础模块没搭好。这其实不是个别现象。我这两年陆陆续续看了不少 AI Agent 项目凡是效果飘忽、一压并发就挂、或者跑几天就失控的十有八九都在同一个地方栽跟头七要素只重视了模型七个决策点一个都没认真拍过板。如果你也在搞 AI Agent 工程实现别急着把别人的示例代码搬进仓库。先跟着我把它拆成七要素再顺着七要素确认七个决策点。这篇文章想做的就是把底下这层骨架给你摆出来像零件清单一样拆明白再拼装能少走很多弯路。1. 七要素全景Agent 不是魔法而是一套可组装的系统我习惯把 Agent 的核心拆成七个要素目标、感知、规划、模型、工具、记忆、反馈。不管你是用 LangChain、LangGraph、Spring AI 还是自己从零撸一套只要你做的是生产级 Agent这七块一定会出现。逃不掉的。为什么是七个不是三个因为一套生产级 Agent 必须回答七个问题它要完成什么怎么读入信息怎么决定下一步用什么推理能力能碰哪些外部系统怎样记住前因后果做完之后怎么复盘。这几个问题全都要在系统设计阶段给到答案缺一个上线后就会以某种形式崩给你看。我习惯把这七要素比作一家小公司目标是董事会定的 KPI感知是市场部规划是操盘手模型是决策团队工具是行政和财务的审批权限记忆是档案柜反馈是周会复盘。一家公司缺了档案柜还能勉强运转但缺了复盘和权限审批早晚出事。Agent 也一样。1.1 目标、感知、规划决定 Agent 会不会“思考”目标要素不只是写一句“帮我处理订单”这么简单。工程上要定义的是任务边界、成功标准和退出条件。比如客服 Agent 收到一个售后问题什么情况下算处理完是回复完就算还是必须把工单状态更新掉这些不写清楚Agent 就会在自己以为完成任务的时候停下来而系统没真正闭环。感知要素决定 Agent 能看到什么。用户输入、历史会话、外部系统返回的数据、图片文档哪些该收入上下文哪些该舍弃需要用一套明确的策略来管。感知做得糙后面规划做得再细都没用因为模型拿到的信息已经是脏的、漏的、超载的。规划要素是 Agent 区别于普通 Chatbot 的核心。普通 Chatbot 你问一句它答一句Agent 需要自己拆解任务、排列步骤、决定先调哪个工具再结合哪个结果。常见的规划模式有 ReAct 式边思考边行动边观察也有 Plan-and-Execute 式先列一个完整计划再逐步执行。规划绝不是越自由越好这部分后面会展开讲。1.2 模型、工具、记忆、反馈决定 Agent 能不能“干活”模型要素大家都熟但工程上要选的不是一个模型而是一套模型策略。推理规划用什么样的模型信息抽取、摘要、分类用什么样的模型成本和延迟分别是什么量级这都要提前想清楚。很多人默认“一个旗舰模型走天下”效果是省事账单和延迟往往很酸爽。工具要素是 Agent 的“手脚”。整个外部世界对 Agent 的暴露面就是工具查询数据库、调用订单 API、发邮件、改工单状态。工具接口定义得好不好、权限边界划得清不清楚直接影响 Agent 的安全性和稳定性。记忆要素负责跨轮次留存信息。短期记忆是当前会话的上下文长期记忆是用户的偏好、历史记录、领域知识。记忆不是越多越好记太多会让模型注意力被噪音淹没记太少又会变成一问三不知。反馈要素是很多项目最后才补的甚至根本不补。Agent 跑完一个任务结果对不对工具调用顺序合不合理耗时和成本是不是异常这些都得有记录、有评估、有修正机制。无反馈的 Agent 就像一个从不复盘的公司同一个坑能跌进去三次。2. 从七要素到七个决策点骨架是模块拍板才是关节七要素是骨架但如果只有骨架系统还是动不起来。真正决定 Agent 命运的是七个决策点——每个要素对应的那个“不能再含糊”的工程拍板时刻。什么叫决策点就是无论你怎么选都有道理但选了之后必须承担相应后果并且要把配套措施一起设计进去的那种选择。比如“上下文怎么放”就是一个决策点你可以全塞给模型也可以做成检索拼装。两种都能跑但性能和成本完全不同。最怕的是一边全塞一边抱怨模型表现不稳一边做检索一边嫌流程复杂两头都没想清楚。我把七个决策点整理成下面这张表你可以在项目启动时对着它逐个过一遍要素核心拍板问题常见选项拍错板的代价目标Agent 什么时候算完成任务固定步数 / 任务自检 / 人工确认无限循环或不懂收手感知上下文全部塞给模型还是按需取用全量窗口 / 滑动窗口 / 检索组装上下文过载或信息丢失规划流程写死还是让模型自由规划状态图 / ReAct 循环 / 混合模式要么死板要么失控模型一个通用模型还是多个专业模型分工单模型 / 多模型路由成本爆炸或能力错配工具哪些动作自动执行哪些要人批准全自动 / 白名单 / 高风险审批越权操作或效率崩盘记忆什么进长期记忆什么留在会话窗口内存 / Redis / 向量库摘要多轮对话失忆或记忆污染反馈线上怎么考核 Agent 做得好不好只有 Demo / 评测集 / 线上全链路观测回归裸奔坏了不知道这张表的核心逻辑是每个决策点都必须在系统写第一行业务代码之前想清楚。你可以先拍一个初始版本后面再迭代但不能不拍。最忌讳的是连决策点的存在都没意识到全靠框架默认选项替你做决定。2.1 前置拍板还是后置踩坑选时机有人说先跑通再说后面再改。这话在写个人小工具时没问题做 Agent 项目会很辛苦。因为 Agent 的每个决策点都是联动的。一个典型的连锁反应记忆决策没定长期记忆和会话窗口混在一起上下文越滚越大上下文一乱规划质量下降规划一乱工具调用就会出错工具出错反馈机制又没建最后整个系统在线上黑盒运行谁也说不清它坏在哪一步。所以我的建议是项目启动第一天就把这张表打印出来每一个决策点写下你当前的答案和理由。哪怕后面推翻至少你留了下决策依据知道当初为什么要这么做改起来也知道影响面在哪。2.2 别让框架替你拍板这里要提醒一句很多人用框架选型替代了决策点。比如选了 LangGraph就觉得状态管理不用想了checkpoint 帮你管了选了 Spring AI就觉得工具调用不用想了注解配上就能用。框架确实能帮你减少一部分重复工作但框架替代不了业务决策。LangGraph 帮你存状态但它不知道你哪一步该自动执行、哪一步需要人工确认Spring AI 帮你封装工具但它不知道你的工具里哪些是低风险的只读操作、哪些是高风险的写操作。框架解决的是“怎么做”的效率问题决策点解决的是“做什么选择”的对错问题两回事。3. 决策点逐个落地上终止条件、上下文、规划权、模型路由这一节我逐个讲前四个决策点。每个决策点都会给到判断依据、落地方法和容易踩的坑。3.1 决策点一Agent 到底做到哪一步算完目标要素对应的核心决策点就是终止条件。很多 Agent 项目翻车不是模型不行是 Agent 压根不知道该在什么时候结束。典型场景Agent 反复调用工具第一次查询结果不满意再查一次再换个关键词查最后 API 账单已经翻了几倍它还在原地打转。终止条件一般有三类实现。第一类是硬指标最大执行步数、最大 token 数、总执行时长。这三样建议无条件设上且设成保守值作为兜底。第二类是软指标让模型自己判断任务是否完成比如生成一个 finished 标记或者对工具结果做一致性验证。第三类是人工确认对高风险场景设置一个“执行前请用户确认”的关卡。我通常的做法是组合使用。低风险任务用“硬指标兜底 软指标判断”高风险任务在软指标基础上再加人工确认。比如客服退款场景Agent 可以自动查物流、查订单、生成回复草稿但真正触发退款动作前必须弹一个人工审批。这样既保留了效率又不会让 Agent 在钱相关的事情上失控。3.2 决策点二上下文全塞给模型还是按需组装感知要素对应的决策点是上下文策略。这是最容易被低估的决策点。我见过不少开发者的第一版方案都是把历史消息整个塞进 Prompt塞到后来模型开始复读历史消息里的废话甚至把用户以前的投诉语气当成当前语气来回应。上下文策略本质上是在做信息预算。我的经验是把上下文分成三层系统约束层、用户会话层、检索知识层。系统约束层放最必须的规则比如“你是一个客服助手不要编造订单信息”这段要固定且精炼用户会话层放最近的若干轮对话老一点的对话压缩成摘要检索知识层按需从数据库或知识库取只在涉及具体订单、具体商品时才拼进 Prompt。落地的时候可以利用结构化数据。比如订单信息不要靠模型从聊天记录里猜直接把订单 JSON 以结构化字段的形式塞进去让模型基于可信数据推理。上下文不是越多越好而是越精准越好。你塞给模型的每一段无关文本都在稀释它对关键信息的注意力。3.3 决策点三流程写死还是让模型自己想规划要素对应的决策点是控制权分配。很多人对 Agent 的理解就是“让模型自由发挥”其实生产环境里自由发挥常常意味着不可控。要不要给 Agent 自由取决于任务的容错率。如果你的业务允许 Agent 说错话甚至做错决定比如帮你搜资料、写周报、整理信息那可以用更自由的 ReAct 循环让模型自主决定调用哪些工具。但如果你的业务流程是固定且强合规的比如处理订单、审核报销、操作后台系统那我强烈建议把主干流程用代码写死把模型的发挥空间限制在分支节点上。用状态图定义好节点的流转条件模型可以在某个节点内决定怎么做但不能擅自越过流程边界。实践中最好的平衡是混合模式主流程写死分支决策交给模型。比如一个内容审核 Agent主流程是“接收内容 - 初步分类 - 调用审核规则 - 输出结论”这个图是固定的但“如何判断某句话属于哪类风险”这种开放判断交给模型。这样既有流程的确定性又有模型的智能性。3.4 决策点四一个模型打天下还是多模型分工模型要素对应的决策点是模型策略。我的建议几乎总是多模型分工而不是一个旗舰模型处理所有事情。原因很简单Agent 的调用链里有大量“不需要顶级智能”的环节。比如把用户消息整理成结构化字段、给长文本做摘要、判断一段文字的情绪这些工作用一个快速且便宜的小模型就够了。真正需要强推理的环节比如拆解复杂任务、规划多步操作才用能力更强的模型。多模型分工还有一个附带的优势你可以针对不同环节独立调 Prompt、独立看成本、独立做优化。如果全链路都用旗舰模型你根本分不清钱花在哪个环节上优化也无从下手。但多模型也意味着多一层管理成本所以务实一点的做法是先用两款模型跑起来旗舰模型做规划和复杂推理经济模型做抽取、摘要、分类之后再根据数据调整比例。4. 决策点逐个落地下工具权限、记忆边界、反馈考核前四个决策点偏“脑”后三个决策点偏“手眼身法步”。如果说前面决定 Agent 聪不聪明后面决定的是它安不安全、稳不稳定、能不能持续改进。4.1 决策点五工具调用的边界和审批画在哪工具要素的决策点是权限模型。Agent 一旦接上工具危险就来了。它能读数据库、能发消息、能改状态那么它调用这些工具的权限边界在哪里我给所有 Agent 项目都建议按风险分级。第一级是无风险工具搜索、查状态、读配置可以直接自动执行。第二级是低风险工具生成草稿、给用户发通知这类可以自动执行但必须留痕。第三级是高风险工具删除数据、转账、批量操作、对外发布这类必须加人工审批或者在代码层面强制二次确认。另一个容易被忽略的坑是工具的幂等性。所谓幂等就是同一个操作执行多少次结果都一样不会造成叠加影响。比如“更新订单状态为已发货”这个操作是幂等的执行两遍和一遍结果相同但“给用户账户增加 100 元余额”就不是幂等的执行两遍就多发了 100 块。Agent 在失败重试时很可能重复调用工具如果你接的工具不幂等重试机制就会变成事故放大器。要么确保工具接口幂等要么在调用侧加执行记录去重。4.2 决策点六哪些记忆进向量库哪些留在会话里记忆要素的决策点是记忆分层。这一层做得好不好直接决定用户对 Agent“聪不聪明”的主观感受。很多 Agent 感觉像金鱼就是记忆策略没做好。我推荐的模型是三层记忆短期会话、长期偏好、领域知识。短期会话就是在当前会话窗口里维护最近若干轮消息超出窗口的部分做滚动摘要。长期偏好来自用户画像比如“这个用户喜欢简洁回复”“这位是老客户他的常用收货地址是哪里”这部分存成结构化数据按用户 ID 索引。领域知识才放向量库比如产品手册、政策文档、历史售后案例通过语义检索在需要时取回。这里要特别提醒不要把聊天历史一股脑全塞进向量库。向量检索擅长找“相似内容”但用户会话是强顺序相关的你把打乱顺序的向量片段拼回家反而会让 Agent 丢失对当前话题的连贯理解。我的做法是聊天历史走窗口摘要领域知识走向量库用户画像走结构化存储三者各管一段不互相污染。4.3 决策点七线下评测、线上监控、用户反馈以谁为准反馈要素的核心决策点是评价体系。没有评价体系的 Agent 项目等于闭着眼睛开车。评价体系至少得有评估集、线上日志、用户反馈三个层面。评估集在开发阶段就要开始积累准备一二十条典型任务每条任务标注清楚正确输出应该是什么每次改版先在评估集上跑一遍看结果怎么变化。这一步的价值在于防止你改了 A 类问题的同时弄坏了 B 类问题。线上日志要记录的除了模型输出还要有完整的链路 trace每一步规划是什么工具调用了什么参数传了什么工具返回了什么耗时多少花费多少。没有链路 trace线上出了问题就只能拍脑袋猜猜测的成本通常远高于多写几个日志结构体的成本。用户反馈则是最后一个校准锚点。让用户在对话结束后点“满意/不满意”把负面反馈的会话捞出来一条一条归因你会发现大量问题是上下文策略导致的而不是模型能力导致的。这正好印证了前面几个决策点的重要性。5. 并发与状态Agent 一上线就遇到的第一道坎很多人问“AI Agent 怎么扛并发”我通常反问一句你先让单个 Agent 跑稳定了没单路跑不稳并发只是把事故复制成很多份。但既然问了我也说说并发这块的工程经验。5.1 无状态化是并发的起点Agent 天然是有状态的它要记住聊到哪了、执行到哪一步了。但扛并发要求你把这个状态尽量外置做成可被独立存储和恢复的形式也就是把 Agent 做成“围绕外部状态运行的计算过程”。具体到实现状态不要存在进程内存里而是按会话 ID 存到 Redis、数据库或专门的 checkpoint 存储。LangGraph 的 checkpointer 机制做的就是这个事每次执行到节点结束时把状态存入指定位置下次继续时读回来。用原生代码写也一样关键是让“运行中的 Agent 是什么状态”这个问题在任意时刻都能被回答而不是等重启进程时烟消云散。5.2 并发不是加几个线程而是带资源预算的调度并发第一个坑是把自己玩死。你开 50 个线程同时跑 Agent每个 Agent 都在调大模型 API很快会撞上模型服务商的限流然后你还要写一堆重试逻辑重试又放大消耗形成恶性循环。正确思路是引入并发预算用一个信号量把全局并发数限制在可控范围同时给每个会话设置单独的令牌配额和时间配额。这里有一个重要的心态转变Agent 并发是几十路的量级不是几千路的量级。因为单路 Agent 的耗时通常以秒计后端如果还要做多步工具调用真实吞吐量很有限。与其硬抗高并发不如设计成异步任务队列请求进来先返回一个任务 IDAgent 在后台慢慢跑前端轮询结果。这是目前最稳妥、最不用堆预算的打法。5.3 幂等、超时、限流并发事故的根源治理并发下最容易看到三种事故重复执行、无限重试、超时堆积。重复执行的根源是客户端或调度器没有幂等控制无限重试的根源是重试策略没有预算上限超时堆积的根源是外部依赖没有统一超时兜底。我的工程红线就三条第一每个工具调用必须有超时设置不设超时的调用一律不接第二Agent 的总步数和总 token 必须有硬上限达到上限直接终止第三任何一步失败最多重试一次且重试前要检查幂等。这三条写进代码并发事故至少少一半。6. 可直接照抄的工程骨架FastAPI LangGraph 实现讲了这么多最后给一套能落地的骨架。我以 FastAPI LangGraph 为例把七个要素映射到代码结构上。6.1 用 StateGraph 把七要素变成图LangGraph 的核心是节点 条件边正好对应我对规划要素的理解主流程写死成图节点内交给模型做判断。先定义状态结构from typing import TypedDict, Annotated, Literal from langgraph.graph import StateGraph, START, END from langgraph.checkpoint.memory import MemorySaver class AgentState(TypedDict): user_id: str session_id: str messages: Annotated[list, lambda a, b: a b] step: int max_step: int tool_results: dict finished: bool这里step和max_step对应决策点一的终止条件messages对应感知和短期记忆。接下来定义节点def perceive(state: AgentState) - AgentState: # 决策点二只保留最近 N 条消息旧的压缩成摘要 state[messages] compress_messages(state[messages]) return state def plan(state: AgentState) - AgentState: # 决策点三在节点内让模型决定下一步动作 if state[step] state[max_step]: state[finished] True return state action llm_decide_next_action(state[messages], state[tool_results]) state[tool_results] action return state def act(state: AgentState) - AgentState: # 决策点五工具执行高风险动作在这里拦截 tool_name state[tool_results].get(tool_name) tool_args state[tool_results].get(tool_args) result execute_tool_with_approval(tool_name, tool_args, state[user_id]) state[step] state[step] 1 state[messages].append({role: tool, content: result}) return state def route_after_plan(state: AgentState) - Literal[act, end]: if state[finished] or state[tool_results].get(action) end: return end return act然后把这些节点装进图graph StateGraph(AgentState) graph.add_node(perceive, perceive) graph.add_node(plan, plan) graph.add_node(act, act) graph.add_edge(START, perceive) graph.add_edge(perceive, plan) graph.add_conditional_edges(plan, route_after_plan, {act: act, end: END}) graph.add_edge(act, plan) checkpointer MemorySaver() compiled graph.compile(checkpointercheckpointer)看到这里你应该有感觉整个控制流是确定的模型只负责在每个节点内做判断和生成内容。这正是我反复强调的“主干流程写死分支交给模型”。6.2 FastAPI 接入与决策点的落点接入 FastAPI 时关键是按会话 ID 隔离状态。LangGraph 的 checkpointer 支持 Thread ID我们把它对应成用户会话即可from fastapi import FastAPI import asyncio app FastAPI() app.post(/agent/run) async def run_agent(payload: dict): user_id payload[user_id] session_id payload[session_id] thread_id f{user_id}:{session_id} config {configurable: {thread_id: thread_id}} initial_state { user_id: user_id, session_id: session_id, messages: [{role: user, content: payload[message]}], step: 0, max_step: payload.get(max_step, 10), tool_results: {}, finished: False, } # 用线程避免阻塞事件循环 final_state await asyncio.to_thread(compiled.invoke, initial_state, config) return {session_id: session_id, messages: final_state[messages]}这段代码很短但它把所有决策点都放到明面上了max_step来自外部请求意味着终止条件可控compress_messages是上下文策略的钩子你可在这里替换成摘要或检索execute_tool_with_approval是工具权限与审批的钩子checkpointer管理会话级状态秒粒度恢复天然支持并发场景。后面扩展时你只需要往图里继续加节点网格骨架能撑住。最后想提醒一句用 LangGraph 这样的框架不代表你可以跳过前面的七个决策点。框架替你做了状态管理和图流转的底层工作但“什么阶段该收手”“哪些风险要审批”“记忆怎么分层”这些问题框架不会替你回答。我自己的心法是从第一行代码开始就把七个决策点写进设计文档哪怕每一条只有一句话。跑通之后回头审视需要调整的是选项而不是决策点的位置。你把这个位置记牢了后面越做越顺。