
AI Agent 几乎成了从去年到现在内容社区里最热的词之一但如果你把 Agent 当成一个软件工程问题来做而不是一个概念来聊会发现外面大部分文章都停在“什么是 Agent、Agent 能做什么”真正能指导你落地的东西少得可怜。我自己最开始做 Agent 时也犯过很幼稚的错误以为给模型绑几个 function再套一层 while 循环就是一个 Agent 服务了。结果一压并发服务两三分钟就出现大串超时用户随口问一句模型能在工具调用里来回绕七八轮。后来我把 Agent 当成一个有内部结构的系统来重新设计才慢慢摸清门道。这篇文章不聊概念包装只讲工程实现。我会从七要素和七个决策点两个维度来解释 Agent前者回答“一个 Agent 内部到底由什么组成”后者回答“从零开始搭建时你应该在哪几个节点做取舍”。最后给出一套 FastAPI LangGraph 的最小参考实现并把我在生产环境中真正踩过的坑一并说出来。不管你是准备用 LangChain 系、Spring AI还是想用 Rust 生态自己造轮子这套拆解方法都适用。1. AI Agent 解决的核心问题从“会聊天”到“下地干活”很多人把 Agent 理解成“更聪明的聊天机器人”这个理解不能算错但非常容易误导工程决策。聊天机器人的核心是“生成一段合理的回答”而 Agent 的核心是“完成一个任务”。任务意味着目标、步骤、动作、依赖、结果验证。聊天机器人答错一句话用户顶多觉得体验差Agent 在一个自动化链路里做错一步可能直接导致数据写错、订单下错、下游系统做出错误响应。我做 Agent 时给自己定过一个判断标准如果这个系统去掉大模型只剩规则和代码也能跑通那它就是一个传统工作流如果这个系统去掉大模型后完全不知道该干什么那它才谈得上 Agent 化。这个标准很粗糙但能帮你过滤掉大量假 Agent 项目。1.1 Agent 与 Workflow、RAG 的分界线Workflow工作流是提前画好的有向图节点和边都是确定的模型顶多在某一步做一次判断。比如“先查库存再算运费最后生成订单”这种链路用代码写死反而更稳定。问题在于很多业务流程里“下一步该怎么做”本身就是模糊的或者每一步都需要根据上一步的结果临时决定这时候固定工作流就脆了。RAG检索增强生成解决的是“模型不知道某件事”的问题把外部知识检索出来塞进上下文让回答更准确。但 RAG 本身没有闭环检索一次生成一次结束。Agent 可以把 RAG 当成一个工具来用也可以在检索结果不满意时主动换关键词再检索一次甚至决定什么时候停止检索。所以 RAG 是 Agent 工具箱里的一件工具而不是 Agent 本身。Agent 和这两者的本质区别在于它有状态、有工具、有反馈闭环。它会在“当前状态”下决定“下一步做什么”执行工具后把结果作为“新的状态”再次参与决策。这个循环可以重复很多次直到满足终止条件。1.2 Agent 的最小行为闭环一个完整的 Agent 行为闭环可以简化为四步根据当前目标和记忆决定下一步动作。如果动作是调用工具执行工具并拿到结果。把工具结果合并进上下文更新状态。判断任务是否完成完成就输出结局没完成就回到第 1 步。这个闭环看起来不复杂但工程实现里每一步都埋着坑。决定下一步动作时模型可能给出一个不存在的工具名执行工具时网络超时、权限不足、参数校验失败都是常态更新状态时历史消息太长可能超出上下文窗口判断是否完成时模型经常自信地认为“已经做完”了实际产出物根本没验证过。所以后面说的七要素其实就是针对这个闭环每一环的精细化拆解。你只有把每一环都当成独立模块去设计才能在问题发生时快速定位到具体位置而不是对着一个黑盒反复调 prompt。2. 七要素把 Agent 拆开以后你才知道哪里会出问题七要素不是某个学术框架是我在实现中总结出来的最小划分。它不解决“模型聪明不聪明”的问题它解决的是“模型再聪明工程上怎么不失控”的问题。下面这张表可以先给你一个整体印象再逐个展开。要素工程上要回答的问题常见实现模型内核用什么模型做推理和决策闭源 API、私有化模型、大小模型组合任务拆解模糊目标怎么变成可执行步骤提示词脚手架、Plan-and-Execute记忆系统历史信息存在哪、怎么用上下文窗口、Redis、向量库工具层模型如何安全地触达外部系统Function Calling、API Schema、MCP规划决策下一步用工具还是直接回答ReAct 循环、状态图、多 Agent 协商动作执行工具调用怎么保证稳定超时、重试、幂等、权限校验反馈修正结果错了我怎么知道结果校验、反射机制、人审开关2.1 模型内核推理底座不是知识库很多团队把大模型当成“内置数据库”希望它什么都知道。实际上Agent 场景里模型最重要的能力不是知识储备而是指令遵循和工具调用稳定性。你给模型一个 JSON Schema它能不能每次都生成合法的参数你给它一个模糊的用户需求它能不能拆出靠谱的步骤——这比它能不能背出某个知识点重要得多。我在选模型时有个习惯不只看榜单分数而是拿 50 条真实业务请求统计“工具名正确率、参数合法率、终止条件达成率”。这三个指标直接决定 Agent 能不能用。2.2 目标理解与任务拆解不给模型一张白纸用户说“帮我整理一下这堆资料”这句话落到系统里几乎没有任何可执行性。Agent 需要把这句话转换成“读取资料目录、提取每份文档的摘要、按主题分类、生成一份汇总报告”这样的步骤。工程上这个拆解可以在提示词里显式引导也可以先用一个轻量的“规划模型”生成计划再交给执行模型分步执行。关键是不要让模型在没有任何约束的情况下一步一步自由发挥那样非常容易跑偏。我会在初始 prompt 里固定三块目标、约束、产出物。产出物明确以后模型才知道自己干到什么时候算完。2.3 记忆系统会话状态不是聊天记录的备份记忆是 Agent 工程里被误解最深的部分。有人以为把聊天记录存进 Redis 就是记忆有人以为给 Agent 接一个向量库就是长期记忆。实际上记忆需要分层次短期记忆是当前任务上下文通常就是放入模型上下文窗口的对话历史长期记忆是用户画像、业务事实、历史偏好存在外部存储里需要时才检索出来。我常用的分层方式是最近几轮对话直接放上下文业务实体的关键信息从数据库读出来拼进系统提示沉淀下来的用户偏好或历史结论放进向量库按相似度检索引用。如果你把什么都往上下文里塞token 成本会很快失控而且长上下文并不会让模型更聪明。2.4 工具层模型只能说话工具才能真正办事Agent 的价值一半在工具层。模型本身不查天气、不发消息、不写数据库它只是生成一个“想调用某个函数的意图”。工具层负责把意图真正执行掉。工具层工程上要关注的事情很多工具描述是否清晰参数是否经过校验接口超时和重试策略是什么有没有操作权限隔离。我见过太多 Agent 项目工具层就是一个裸 HTTP 请求超时、限流、鉴权全都没做。模型一调用工具整个链路就跟着失控。2.5 规划与决策机制让每一步都有依据规划机制决定 Agent 用什么样的策略完成任务。ReAct 是目前最常见的模式思考Reason→ 行动Act→ 观察Observation→ 再思考循环往复。Plan-and-Execute 则是先让模型生成完整计划再逐步执行适合步骤明确但过程较长的任务。Reflexion 会更进一步让 Agent 在失败后先反思原因再调整策略重试。这三种不是互斥的实际系统里经常混用先用 Plan-and-Execute 拆计划执行过程中用 ReAct 处理异常失败次数超限后用 Reflexion 做一次复盘再决定是否继续。2.6 动作执行层保证每一次工具调用都可靠动作执行层是 Agent 的“手脚”它把模型输出的工具调用意图变成真实系统的副作用。这一层最容易忽略的是幂等性和超时控制。比如“创建订单”这个动作如果网络超时后重试就可能产生重复订单如果工具卡住不返回Agent 就会一直等白白消耗资源。我的习惯是所有写操作尽量设计成幂等接口重试前先查询上一次执行结果所有工具调用必须有硬超时执行结果必须包含明确的状态码和可读信息而不是只回一个裸字符串。2.7 反馈与修正环路没有反馈Agent 就是一次性调用如果 Agent 执行完工具、生成完回答就直接结束那它只是一个会调 API 的聊天机器人。真正的 Agent 应该有反馈修正机制工具返回结果后校验它是否符合预期不符合就重新规划最终产出物也要验证比如生成 SQL 前先做语法检查调用下单接口前先让模型自己列出关键字段。更重要的是在这个环节加入“人审”位。高风险动作不要等系统做完了再去补救而是在动作执行前把人放进来。后面我会专门讲人审开关怎么设计。3. 七个决策点动手前必须想清楚的取舍清单七要素告诉你 Agent 由什么构成七个决策点则是你在构建过程中至少要拍板七次的选择题。这些决策没有标准答案但如果没有明确答案代码很快就会变成一团互相拉扯的技术债。3.1 决策点一先定义 Agent 形态而不是先选框架同样的业务用单 Agent、多 Agent 还是“Agent 工作流混合”结果完全不同。我见过最典型的问题是需求明明是一条固定审批链路团队非要做成多 Agent 自由协商结果每天的产出都是随机的。我的判断标准很简单如果步骤和分支都明确就用工作流编排模型只做节点内的判断如果步骤不明确需要根据中间结果动态决定下一步再用图状态机实现单 Agent 循环如果问题实在太复杂单 Agent 上下文和 token 都不够用再考虑多 Agent 拆分工种。上来就搞多 Agent 的基本都是给自己加戏。3.2 决策点二模型选型与 token 预算要一起算模型选型不是越强越好。Agent 的每一次工具循环都可能消耗几轮模型调用单轮质量再高如果经常走弯路总成本就可能爆炸。我一般把“完成一个任务需要多少轮调用、多少 token”作为选型指标而不是只盯着“单次回答准不准”。token 这个词可以理解为模型处理文本时的计费和计算单位它不等于“字的个数”一个中文词可能对应一到两个 token。在 Agent 里token 不仅决定成本还决定你能塞进去多少上下文。如果上下文太长模型反而容易忽略关键信息。我的做法是给任务设置 token 预算上限超过预算就尽快收敛而不是无限追加。参数选择上我倾向于大小模型配合意图识别、工具参数生成用能力更强的大模型简单分类、格式转换用便宜的小模型两端之间用规则和状态机连接。这样既控成本又能保证核心环节的质量。3.3 决策点三框架选型怎么选才不变成技术债现在 Agent 框架非常多选错框架比选错模型还难受因为框架会深度绑架你的业务逻辑。下面这个对比是我实际调研时的判断依据供你参考。技术方向适合场景优势主要代价LangGraph / LangChain 系快速验证、复杂状态图、生态齐全状态管理成熟社区资料多抽象层次多版本演进快Spring AIJava 团队、已有 Spring 技术栈与现有工程体系融合好Agent 原生能力不如 Python 生态Rust 生态如 Rig 等高并发、资源敏感的服务性能好、内存占用可控生态早期调试成本高自研协议 状态机高度定制、内部系统绑定深完全可控没有框架包袱所有轮子都要自己造我自己的偏好是团队已经有 Java 体系就考虑 Spring AI从零做高并发 Agent 服务首选 Python 生态里的 LangGraph因为它把“状态、循环、工具节点”这层最难的东西直接做了如果未来要处理超高并发且团队有 Rust 能力可以再逐步把核心链路用 Rust 重写。不要一开始就自研先把业务跑起来再决定要不要造轮子。3.4 决策点四状态、会话、记忆到底放在哪Agent 是有状态的但状态往往没有地方放。我见过最容易翻车的设计是把所有状态存在进程内存里服务一重启所有会话全部归零或者用全局变量存状态两个用户请求互相覆盖串号串到没法看。工程上要把状态拆成两类一类是会话运行状态包括当前执行到哪一步、已经调用过哪些工具、消息列表这类状态跟着请求走一类是长期记忆跨会话保留放在 Redis、数据库或向量库里。用 LangGraph 这类框架时状态会通过 checkpoint 机制持久化你要做的就是给每个会话指定一个唯一的 thread_id保证并发请求互不干扰。生产环境里不要把 checkpoint 放在本地内存至少用 Redis 或 Postgres 的后端实现。3.5 决策点五工具调用的协议、校验与容错模型输出工具调用时你收到的不是一个可以直接执行的函数而是一个 JSON 结构里面包含工具名和参数。你必须自己完成四件事白名单校验、参数格式校验、执行权限校验、结果返回封装。有的团队直接把模型输出的参数 key 拿给业务函数用结果模型多传了一个字段程序就崩了或者工具返回一段很长的原始数据模型被带偏。我会在每个工具前面包一层“适配器”负责把模型的 JSON 转成业务系统真正需要的参数格式并对所有输入做防御性校验。模型可能犯错适配器就是最后一道质检。3.6 决策点六并发模型、资源隔离和流式响应这是“AI Agent 怎么扛并发”这个问题最核心的部分。Agent 不是一个普通 HTTP 接口它的一次请求会经历多轮模型调用和工具调用端到端耗时可能从几秒到几十秒。如果你用同步阻塞的方式去处理一个请求占一个线程几分钟服务很快就完蛋。我的经验是把“同步接口思维”改成“异步流式思维”。服务端用异步框架接收请求Agent 执行链路用异步调用每来一个 token 就通过 Server-Sent Events 或 WebSocket 推给前端。同时要加并发信号量或队列限制同时处理的 Agent 任务数量超过阈值就先返回排队状态而不是无限创建任务把 provider 打爆。还要特别注意资源隔离不同租户、不同任务类型的会话状态必须隔离慢任务不能占光所有模型配额。一个简单的做法是给不同任务设置独立的并发 Semaphore 和独立的模型调用缓冲队列。3.7 决策点七可观测性、评估与安全边界Agent 链路比普通接口长好几倍出了问题如果只能靠用户截图反馈那基本等于盲飞。我会在系统里记录四类数据每次模型调用的输入输出和 token 消耗、每次工具调用的参数和返回、每个 Session 的状态跳转记录、终止原因是正常结束、超时还是人工干预。评估方面单看“AI 回答像不像人话”没有意义。我给 Agent 建了任务级指标目标达成率、工具调用成功率、平均轮数、平均耗时、无效循环率。每条线上前放一组 golden set每次改完 prompt 或框架就跑一遍回归数字掉了就不上线。安全边界再强调也不为过模型决定调用工具前系统必须校验这个工具在当前用户上下文里是否有权限工具执行必须走独立的审计日志高影响动作默认要有人工确认。不要相信模型“只做只读操作”这种承诺要把权限在系统层面掐死。4. 参考实现FastAPI LangGraph 搭一个能扛并发的 Agent 服务前面讲了那么多抽象概念下面给一个可以照着改的最小实现。技术栈就用搜索热词里最常见的组合FastAPI 做 HTTP 层LangGraph 做 Agent 状态图Redis 或 MemorySaver 做会话状态asyncio.Semaphore 做并发控制。4.1 为什么是 FastAPI LangGraphFastAPI 天然支持异步能扛住大量长连接和流式响应而且写起来足够简单。LangGraph 的价值在于它把 Agent 的循环、状态传递和工具节点封装成了一幅图你有明确的节点、明确的边、明确的终止条件而不是在 prompt 里靠运气让模型“自己多想想”。这个组合的边界也很清晰LangGraph 管“Agent 内部的下一步是什么”FastAPI 管“请求怎么进来、结果怎么出去”。两者职责分离出现问题定位很快。4.2 最小核心代码定义工具、模型节点和条件边先安装必要的依赖。这里以 Python 环境为例pip install fastapi uvicorn langgraph langchain-openai下面是一个最简单的带工具调用的 Agent 图。代码以 langgraph 0.2 附近版本的 API 为参考不同小版本可能略有差异。import operator from typing import Annotated, TypedDict from langchain_core.tools import tool from langchain_openai import ChatOpenAI from langgraph.graph import StateGraph, START, END from langgraph.prebuilt import ToolNode, tools_condition class AgentState(TypedDict): messages: Annotated[list, operator.add] tool def get_weather(city: str) - str: 查询指定城市的当前天气入参必须是中文城市名。 return f{city}晴25℃湿度 60%。 tools [get_weather] llm ChatOpenAI(modelgpt-4o-mini, temperature0).bind_tools(tools) def agent_node(state): response llm.invoke(state[messages]) return {messages: [response]} graph StateGraph(AgentState) graph.add_node(agent, agent_node) graph.add_node(tools, ToolNode(tools)) graph.add_edge(START, agent) graph.add_conditional_edges(agent, tools_condition) graph.add_edge(tools, agent) agent_app graph.compile()这段代码里最关键的是add_conditional_edges它检查 agent 节点输出的消息里有没有工具调用意图。有就跳去执行工具没有就直接结束。tools_condition是 LangGraph 预置的逻辑实际项目里你可以替换成自己的判断函数比如增加“需要人工审批时挂起”的分支。4.3 把状态持久化和并发限流加进去上面的图每跑一次就丢掉所有状态不符合真实需求。加上 checkpointer 之后同一个 thread_id 的请求会自动携带历史消息。生产环境不要用 MemorySaver这里只用来演示。from langgraph.checkpoint.memory import MemorySaver agent_app graph.compile(checkpointerMemorySaver())再写一个 FastAPI 接口用 asyncio.Semaphore 限制同时进行的 Agent 任务数。import asyncio from fastapi import FastAPI from pydantic import BaseModel app FastAPI() semaphore asyncio.Semaphore(20) class AgentRequest(BaseModel): session_id: str message: str app.post(/agent) async def agent_endpoint(req: AgentRequest): config {configurable: {thread_id: req.session_id}} # 限制并发避免把模型供应商的配额打爆 async with semaphore: result await agent_app.ainvoke( {messages: [(user, req.message)]}, configconfig, ) return {reply: result[messages][-1].content}这里有三件容易被忽略的事一定要用ainvoke不要用同步的invoke。thread_id 必须由调用方显式传过来不能全局共享。Semaphore 只是单机限流多实例部署时要把并发控制放到 Redis 或消息队列面去否则每台机器各自为战还是会打爆上游。如果要流式输出把接口改成 StreamingResponse在 async for 里遍历 agent 的事件流把流式 token 拼成 SSE 报文一帧一帧推给前端。流式响应不只是体验问题它还能让用户提前看到“Agent 正在干什么”避免几十秒空白期直接超时。4.4 部署时还要补的基础设施这个最小服务能跑通但离上线还差三层一是状态后端换成 Redis 或 Postgres不然重启全丢二是模型 API key 走独立的密钥管理服务不写进环境变量就提交到仓库三是加一层任务队列把长时间运行的 Agent 任务和短请求分开长任务走异步回调短任务走同步返回。队列层我推荐先别用太重的东西。单机场景用 Redis Stream 足够了等业务量大了再考虑专用消息队列。核心思想是不要让用户请求直接压到 Agent 图的执行链路而是把任务先接住再按配额慢慢执行。5. 从 Demo 到生产最容易翻车的六个环节我这个部分本来想写“避坑指南”但仔细想想大多数人踩的坑其实来来回回就那几个。与其一条条罗列不如把最容易让项目翻车的六件事直接摊开讲。5.1 “上下文很长”不等于“模型理解得很好”很多团队把模型上下文从 8K 换到 128K以为 Agent 变聪明了。实测下来上下文越长模型越容易在无关信息里迷失工具调用的准确率反而可能下降。长上下文的正确用法是把历史信息先做压缩、过滤、摘要只把当前任务最相关的部分放进 prompt。不要做“全量堆叠式”上下文。5.2 工具调用后台出错Agent 不会自动知道模型的工具调用意图是“我想查某个接口”但接口可能返回 500、可能超时、可能参数不对。如果你只是在工具返回里写一句“调用失败”模型大概率会继续重复同样的调用或者瞎编一个结果。正确的做法是工具适配器捕获异常后把结构化的错误原因返回给模型比如“参数 city 不是合法城市名请从候选列表中选择”。模型拿到明确反馈才有机会修正下一步动作。5.3 没有最大轮数和预算上限的 Agent会烧穿成本Agent 陷入死循环是一个非常现实的成本黑洞。模型可能反复调用同一个工具每次都在消耗 token。我的做法是给每个 Session 设置最大迭代轮数默认 8 轮超过就强制终止并转人工同时跟踪这个 Session 的累计 token超出预算就自动降级成更简单的模型或直接切断。成本控制不是财务部门的事而是 Agent 系统的基础能力。5.4 并发高了挂的第一环往往是模型供应商限流有一次压测我的服务 CPU 和内存都正常结果用户开始大面积报错日志一看全是模型 API 返回 429。自己服务没问题但上游限流扛不住了。这个问题的解法是在客户端做配额管理和重试退避而不是无限重试。更稳妥的是把模型 API 封装成一层带令牌桶的代理所有请求先经过配额检查再出去避免突发流量把 API Key 打爆。5.5 人审开关应该是一等公民不是补丁金融下单、自动发消息、批量修改数据这类操作必须把人工确认做成一个正式节点。我的设计是Agent 在执行到高风险动作前先生成一个“待审批动作”把意图、参数、影响范围列出来通过企业 IM 推给对应负责人负责人审批后Agent 才继续执行。这个节点不是一个弹窗提醒而是状态图里的一个分支卡住了就不继续超时了就走人工处理线。5.6 评估不能只问“这轮回答像不像人话”用大模型给大模型打分做评测容易得到“表面流畅”但“任务没完成”的结论。我的回归集按任务类型分开每个用例都标注终点状态比如“用户问天气应该调用 get_weather 并返回城市天气而不是直接编造”。运行时自动判断工具是否被正确调用、终止条件是否合理、最终答复中是否包含关键字段。这些硬指标比“像不像人话”可靠得多。6. 如果让我重做一次优先级会怎么排做了几个 Agent 项目之后我最后想说的是Agent 工程最重要的其实不是“智能”而是“控制”。你不需要让模型在每一步都自由发挥反而应该把任务边界、工具权限、最大轮数、人审节点都提前定死。七要素是让你知道该控制哪些点七个决策点是让你知道每一步怎么选。如果让我重做一次我会按这个顺序推进先把任务边界画清楚哪些走工作流哪些走 Agent。选一个小场景一个模型三五个工具跑通闭环。把状态持久化、并发限流、日志跟踪加上再谈扩展多 Agent。最后优化模型参数和 token 成本。我自己做过太多次“先跑起来再说”最后都回去补状态管理和评估体系。现在如果再有人问我“AI Agent 怎么搭建、怎么扛并发、怎么部署”我的回答通常是先忘掉花哨的架构图把一个带三五个工具的单 Agent 做成可观测、可限流、可恢复的稳定服务再说别的。