
1. Agent七要素一个能独立干活而不是只会聊天的系统先聊个观察。这一两年我看了很多AI Agent项目从研究原型到生产系统都有。有一个现象挺明显的能用LLM做“聊天机器人”的人很多但能把Agent做成“能独立干活”的系统的人少很多。差距在哪不在于会不会调模型而在于有没有把Agent当成一个系统来设计而不是当成一次API调用来写。我自己复盘过好几个Agent项目包括基于LangGraph写的工作流编排、基于FastAPI LangChain的服务端实现以及几个给业务团队用的自动化工具。总结下来一个真正能跑的Agent至少要过一遍这七个要素的检查清单少一个后面都会以某种形式出问题。1.1 大脑大模型内核是决策起点第一要素也是大家最熟的Agent需要一个LLM内核。它负责理解用户的自然语言指令根据上下文生成行动计划并对执行结果做解读。这里的关键不是“接一个大模型”而是“怎么选大模型”这个问题我放在后面的决策点展开。先说一个容易踩的坑很多人一开始就把GPT或Claude挂上去结果一问复杂问题就崩。原因不是模型不行而是你还没给模型搭好“思考的环境”。Agent的大模型不是在“生成一句话”而是在“做决策”——它要先理解用户问题再回忆任务目标、结合工具返回结果、判断下一步动作。这个链路里上下文的长短、工具描述是否清晰、系统提示的结构是否合理都会直接影响模型是否能做出正确决策。我常跟团队讲一句话模型是你的员工你要把你期待的执行逻辑、边界、输出约束都写在员工手册里。员工手册就是System Prompt加上Function Description这块写不好后面全盘崩。1.2 目标与角色系统提示不是写作文是定规矩第二个要素是目标和角色的定义。很多初级项目不写System Prompt或者随便写两句“你是一个助手”。这等于招了个能力很强的实习生但你什么也没交代他当然天马行空。真正可复用的Agent系统提示必须包含四部分角色画像你是谁、任务边界你负责什么、不负责什么、执行风格直接给结果还是逐步分析、输出格式JSON还是Markdown。我见过一个项目Agent偶尔会“跑偏”——用户问A它答B后来排查发现是系统提示里夹了一大段无关的业务介绍模型把重心带偏了。把系统提示当作一段“有约束力的工作说明书”来对待模型的表现会稳定非常多。还有一个实操技巧系统提示要尽量结构化用编号、分隔线、块状描述模型对这种格式的遵循程度远高于散文式提示。1.3 记忆上下文窗口不等于记忆第三个要素是记忆。很多人把记忆等同于“把所有对话都塞进上下文窗口”。这在Demo阶段可行一旦上生产就完蛋Token成本、响应延迟、上下文漂移会同时爆发。Agent的记忆至少分三层短期记忆当前任务上下文、长期记忆用户偏好、历史结论、外部记忆知识库、向量数据库、业务数据库。工程实现上短期记忆就是上下文窗口长期记忆要落到向量库或KV存储外部记忆则是通过检索工具做实时访问。我常用的做法是把Agent的执行过程拆成“任务单元”每个任务单元只保留命中任务的上下文结束后把关键结论压缩成摘要写入长期记忆。这个做法能控制上下文膨胀也能让Agent在多轮任务之间保持一致性。实测下来同样的任务用了打包压缩的Agent比纯堆上下文的版本Token消耗降低了40%左右而且回答准确率反而更高。1.4 规划把大任务拆成可执行动作第四个要素是规划能力。简单说Agent要能把“帮我整理一份市场调研报告”拆成“搜索行业数据→筛选平台→整理成PPT结构→输出文档”这样一连串可执行的动作。规划有一种最朴素也最好用的实现方式叫ReActReason Act让模型先思考Reason下一步该干什么然后再调用工具执行Act根据返回结果再次思考如此循环。这个模式在LangChain和LangGraph里都有现成封装。但这里有个常见认知误区不是所有任务都需要“规划”也不是所有Agent都要“会规划”。简单任务查天气、算算术走固定流程就行甚至不需要AI来规划。规划能力的引入一定要匹配任务的复杂度。给一个“回邮件”的Agent加复杂规划器纯属给自己找麻烦徒增延迟和Token消耗。1.5 手与脚工具调用是Agent真正“落地”的支点第五个要素工具调用。这是Agent从“只说不做”变成“真干活”的核心一环。工具可以是API、数据库查询、代码执行器、文件读写器、浏览器操作等。工程实现上工具调用有两种主流方案。一种是LLM的Function Calling原生能力模型根据用户咨询选择调用哪个函数并填充参数应用侧拿到参数发给对应服务。另一种是让模型生成代码再执行Code Interpreter模式适合数据分析、图表生成类场景。我做工具封装时有个习惯把每个工具的能力描述写清楚包括输入参数的类型、约束、示例值以及执行成功返回什么、失败了抛什么错误。这个描述会直接参与模型的推理写不清楚的后果就是——模型生成一堆无效的调用参数返回404你都不知道为什么。你可以用“给我一个工具”的视角来理解新工具不是端上来就行你得告诉模型这工具怎么用、什么时候用、不能干什么。1.6 反馈循环没有执行结果回灌Agent就是“半瞎”第六个要素是反馈循环。Agent执行一个动作之后必须把结果拿回来重新喂给模型模型基于真实结果判断下一步怎么走。没有这个循环Agent只能靠“猜”来组织后续动作那基本上等于让员工闭着眼睛工作。实现反馈循环的核心是状态管理。以LangGraph为例它把Agent的执行过程抽象成图节点是“模型思考”“调用工具”“读取结果”边是状态转移。每一步执行结果都更新State对象模型节点读取最新状态继续推理。这个设计保证了Agent的行为是可追踪、可回溯、可回滚的。这里要提一个实战问题工具返回的结果通常很乱有JSON、HTML、错误栈等等。反馈给模型之前一定要做结果清洗和裁剪。否则模型会被大段的原始HTML干扰甚至被错误信息带偏输出创意但无用的内容。我通常在工具层加一个“适配器”把各种返回统一成简洁的文本结构提取关键词和结论再回灌给模型。1.7 安全与约束给Agent上护栏而不是裸奔第七个要素最容易被忽视安全与约束。LLM的输出是被概率驱动的永远有不可控风险。放任Agent去调外部API、操作数据库、自动发消息一旦出错后果可能很严重。约束手段从软到硬排系统提示规则最弱、参数控制温度调低、输出长度限制、结构化输出约束JSON Schema、工具权限白名单操作层阻断、执行审批关键动作人工确认。我经历过一次事故Agent在自动回复邮件时错把“会话总结”发给了客户。排查发现是我当时图方便给“发送邮件”工具开了全量权限没有加入审核环节。后面凡是“高影响动作”发送、删除、支付全部改成“需审批模式”Agent执行到这一步会自动生成请求等人确认后再真正执行。安全是整个Agent工程里最容易返工的部分。前面偷懒省一分钟后面可能要花一周去收拾。2. 七个决策点从“能跑”到“能用”的工程分水岭七要素解决的是“Agent需要有什么”七个决策点回答的是“你在具体项目里怎么选、怎么做”。我把这些年反复纠结过的问题收敛成了七个决策点覆盖架构选型、模型选择、工具设计、并发策略、可观测性等工程维度。2.1 决策一工作流、单Agent还是多Agent编排第一个决策也是最根本的架构决策任务到底应该走固定工作流还是交给单Agent自由发挥还是拆给多个Agent协作。我给出的建议基于一个非常朴素的判断标准——任务流程是否确定。流程完全确定比如“读取上传文件→数据清洗→生成报表→邮件推送”就走工作流不要用Agent。流程部分确定、部分需要动态决策比如“分析用户意图→调用合适工具→根据结果调整方案”就用单Agent。任务本身是解耦的、可以并行处理比如“同时分析三个竞品→汇总结论”就考虑多Agent。很多团队一上来就堆多Agent结果多个Agent互相踢皮球、上下文互相覆盖、费用飙升。我见过一个系统用5个Agent协作实际效果还不如一个带5个工具的Agent。多头协作的收益只在任务能真正并行、或者角色差异足够大时才成立。否则多Agent只是徒增开销和复杂度。2.2 决策二模型怎么选——推理型、通用型还是小模型模型选型是Agent效果的上限决定因素分享前面说过的“决策起点”的延伸。我现在的选择标准很直白任务的推理复杂度决定模型档位。需要多步规划、复杂工具组合、长文档理解的任务选推理型强模型o系列或Claude的思考模式。常规任务问答、分类、摘要用通用模型。高并发、低延迟的场景用小模型或专用模型。这里想强调一点不要把“最强模型”当默认答案。实际项目中我经常给同一个Agent配两个模型一个负责“规划”推理型慢但准一个负责“执行细节”通用型快且便宜。这个思路能显著降低成本。实测一个客服Agent采用大模型规划小模型生成话术的方式API费用降了约35%用户基本无感知。2.3 决策三工具的粒度怎么定——一个工具还是一组动作工具设计是Agent工程里最影响体验的部分。工具粒度太粗例如“处理报告”模型不知道具体怎么填参粒度太细例如“打开文件A”“读取第3行”“写入第5列”模型走流程容易出错调用次数暴增。我的经验是工具的粒度以“一个业务动作”为单位而不是一个API接口。比如你要做一个“数据看板”Agent不应该暴露“postLog”“getLogById”“updateLog”这类接口应该封装成“analyzeTodayTraffic”或“queryAbnormalLog”。因为Agent需要的不是“操作接口”而是“达成目标的动作”。LLM理解“分析今天流量异常”的成功率远高于理解“先getXXX再parseXXX再compareXXX”这种逻辑。工具描述还有一个细节写清“什么时候不能用”。比如一个工具只能处理2024年之后的数据你一定要在描述里写清楚“早于2024年的数据返回错误请告知用户暂不支持”。这能避免Agent在错误方向上浪费多轮调用。2.4 决策四记忆放在哪——上下文窗口还是外部存储我前面提过记忆分层这里聊具体的工程决策。第一优先级是尽量避免“所有东西都塞进上下文”。上下文是Cost成本和Noise噪声不是“记忆库”。如果你要做多轮对话Agent方案是用外部存储保存关键信息Redis存会话状态和临时变量、PG存业务数据、向量库存语义记忆。每次对话开始时通过检索把“与此轮相关的摘要”注入上下文而不是把历史全量灌进去。我自己的一个笔记类Agent历史会话超过50轮平均每轮注入的上下文不到3K Token。做法是每次对话结束时用模型生成一段结构化的摘要包括提到的实体、偏好、结论存到JSON里下一轮对话开始时先选择最近3次摘要加上向量检索的命中结果一起注入。这样用户换话题后旧细节虽然不在上下文里但触达关键的“锚点信息”还在。这个设计跑了一段时间感觉非常稳定。2.5 决策五同步调用还是异步编排——Agent怎么扛并发顺带把热搜里“AI Agent怎么扛并发”这个苦水一起倒了。Agent和普通API不一样它的单次请求链路很重多次LLM推理、工具调用、状态流转耗时通常在几秒到几分钟。如果每个用户请求都同步阻塞等Agent跑完后端很快就被拖垮。我的并发策略分三层。第一层是HTTP接入层用FastAPI的异步协程池async def让I/O等待期间不占线程。第二层是把耗时长的Agent任务丢到消息队列Celery或Redis Queue里异步执行前端用WebSocket或轮询拿结果。第三层是LLM调用层做并发限制避免一个用户把模型QPS打满影响其他用户。实测一个并发峰值约2000的客服Agent采用异步编排之后服务稳得很单容器QPS上去了上一版同步阻塞版一压测就502问题根本不在于模型多快而在于编排模式。不要把Agent做成“串行阻塞”单体宁可把它做成“接单 干活 出结果”三段式。2.6 决策六自由度怎么限——给Agent多大操作权限这直接关系到我前边说的安全要素。决策核心是Agent能在什么范围内自由决策在什么边界必须被卡死。我的默认实践是“宽进严出”工具调用链路内让Agent尽量自主不要每一步都弹确认框否则体验极差但凡是涉及“对外部系统产生永久性影响”的动作发邮件、改数据库、删文件、推送消息、下单支付一律走审批。另一个限制维度是参数校验Agent生成的工具参数在真正执行前必须过一层Schema校验层。比如Agent调数据库工具SQL语句必须校验只允许SELECT不允许DELETE。这一层不能靠模型自觉要在代码层面硬卡住。AI越强越要给它清楚划出“可以做”和“不能做”的篱笆。2.7 决策七可观测性怎么做——Agent能白盒化吗最后一个决策点你如何知道Agent在干什么、为什么这么干。LLM推理本质上是黑盒但在工程层你完全可以把Agent的“决策线索”变成白盒。实现这个目标的方式全链路追踪。每条Agent执行记录要包含用户原始意图、每一步状态变化、每个工具调用的输入输出、每次LLM推理的输入token、最终响应与耗时。用了LangGraph的话天然能拿到这些trace数据用LangChain也支持LangSmith或OpenTelemetry。我强烈建议从第一天就接上可观测性而不是出了问题才加。因为Agent的bug很难靠单测覆盖它的故障分布是“概率性”的同一句话十次有九次正确、一次错误只有靠全链路追踪去回放才能定位。没有trace的Agent排查等于在大海捞针。3. 工程实现实录一个能跑通业务的Agent落地过程理论聊得差不多了我直接拆一个真正落过地的项目例子。这个项目的需求是“做一个客户反馈的自动分类和跟进Agent”输入是客户留言输出是分类标签、紧急度评分、建议回复话术必要时自动创建工单。我选了FastAPI LangChain LangGraph的组合重点讲实现的关键路径和代码骨架你可以直接照着把结构搭起来。3.1 场景定义与Agent形态选择第一步明确问题边界。这个任务的核心是“分类”和“决策”流程相对固定读留言→分类→评分→生成回复→条件建工单。按我的决策标准这类“流程确定但内容需要理解”的任务最适合的不是纯自由Agent也不是硬编码工作流而是“动态路由 固定节点”的混合模式。这里最关键的是加分分类结果不是唯一的动作还要触发后续分支。用LangGraph的条件边来实现“如果是退款问题就走退款工单节点如果是技术咨询就走FAQ检索节点”比在一个Agent里写死逻辑要清晰得多。这个设计的好处是核心逻辑可以被测试覆盖LLM只负责“理解内容”路由和动作由代码控制。3.2 工具层的设计与落地这个项目需要两个外部动作查询历史工单只读和创建新工单写操作。按照决策三的粒度原则我把“查历史工单”封装成工具search_tickets参数是客户ID和关键词“创建工单”封装成create_ticket参数是标题、描述、优先级。每个工具都写了清晰的描述包括何时使用、参数含义、返回结构。创建工单这个操作是高影响动作按“决策六”的原则我没有让Agent直接写库而是让它生成一个“工单草稿”存在待确认区由后端接口推送人工审核后再创建。这个设计很省钱——不用AI自己背责任也避免误操作。# 示例工具定义的简化结构 tools [ { name: search_tickets, description: 查询客户的历史工单记录用于判断是否为重复反馈, parameters: { customer_id: string, 客户唯一标识, keyword: string, 工单内容关键词可为空 } }, { name: create_ticket_draft, description: 创建工单草稿不直接落库草稿需人工确认后转为正式工单, parameters: { title: string, 工单标题, description: string, 简要描述问题, priority: high|medium|low } } ]3.3 LangGraph的状态图编排LangGraph的核心概念是“图”。每个节点是一个操作每条边是状态转移。我的Agent图长这样classify_node调用LLM输入客户留言输出分类与紧急度search_node根据分类决定是否检索历史工单draft_node生成回复话术和工单草稿end_node汇总结果返回前端这个编排有几个好处一是节点可以单独测试比如单独测分类节点看它在不同留言下的表现二是状态是显式对象节点A的输出就是节点B的输入不会像自由Agent那样上下文失控。关键代码如下这是一个简化版的状态类实际项目里字段会更多from typing import TypedDict, Annotated import operator class AgentState(TypedDict): message: str # 原始客户留言 category: str # 分类结果 urgency: str # 紧急度 related_tickets: list # 检索到的历史工单 created_draft_id: str # 工单草稿ID reply_text: str # 生成的回复话术 def classify_node(state: AgentState): result llm.invoke(f请将以下客户留言分类...\n留言:{state[message]}) return {category: result.category, urgency: result.urgency} def search_node(state: AgentState): if state[category] in [售后, 退款]: tickets search_tools.invoke(customer_id..., keyword...) return {related_tickets: tickets} return {related_tickets: []} def draft_node(state: AgentState): prompt build_reply_prompt(state) reply llm.invoke(prompt) draft_id create_draft(reply) return {reply_text: reply, created_draft_id: draft_id}这里说一个实操细节每个节点返回的字段只会更新状态对象里对应的key不是全量覆盖。所以节点之间是松耦合的。classify_node不知道search_node怎么实现search_node不知道draft_node的回复风格。改一个节点不会牵连其他节点工程上非常好维护。3.4 异步并发与前端交互按决策五的思路这个Agent的前端不搞同步等待。用户提交留言后API立刻返回一个任务ID后端把任务推到Celery队列Agent在Worker里异步跑。跑完后状态写入Redis前端每秒轮询任务状态拿到结果后展示。整个链路的RT从用户视角看是2~3秒但API层的响应是同步的“已接收”不会把请求卡死。FastAPI这层用async接口数据库用异步驱动整体高并发下很稳。分享一个实测参数8核16G的单个容器跑这个Agent的HTTP接入层单秒能扛住约5000个“提交任务”的请求因为只做了入队操作真正的Agent逻辑在Worker池里并发跑。而Worker池的并发数要跟模型API限流对齐我这里的配置是20个Worker并发既不吃满模型配额也能保障吞吐。3.5 成本、Token与延迟的平衡这个项目让我实打实理解了“Token就是钱”。一个典型的分类回复任务如果全部走强推理模型总Token约4000左右成本不算高但如果日请求量上万月成本就是一笔不小的数。我做了一个很简单的分流先用一个小模型做预筛把明显的“闲聊”“无意义留言”挡掉只有需要“深度理解”的留言才进入Agent完整链路。预筛模型的精度做到95%以上成本是大模型的1/5。这个“前置过滤”设计在大多数Agent场景都适用强烈建议尝试。延迟方面也分享一个心得LLM生成回复时用流式输出SSE用户端可以边生成边看到文字体感上比“憋好几秒一次性出来”好太多。Agent因为要多次调用模型每次都用流式配合前端打字机效果整体体验完全不一样。4. 常见问题与排查技巧实录日志里攒了大半年四个高频问题值得拿出来讲。4.1 问题一模型总生成无效工具参数症状Agent明明调用了工具但参数是编的比如customerId传了一个根本不存在的值或者把日期传成非标准格式。排查发现根因往往是工具的参数约束没有写进描述里模型只能“猜”。解法一是所有参数必须声明类型和枚举值二是在Schema校验层直接拦参数不过校验就抛一个“参数错误”给模型让模型重新生成三是在提示词里强调“如果不知道参数值请先向用户询问不要臆造”。实测改进后错误调用率从约12%降到了2%以内。4.2 问题二上下文被撑爆生成长度开始失控症状多轮任务跑一半模型突然开始重复输出、答非所问。通常是上下文里积累了太多历史Action结果噪声覆盖了有效信息。解法严格控制每次工具结果的注入格式。超过一定字符数就做摘要保留关键字段丢弃HTML样式、日志堆栈。另外每轮消息里给模型的“历史聊天”只保留最近3轮完整对话更早的压缩成摘要。这个方法能保证上下文长期稳定在可管理的大小Agent决策质量也稳了很多。4.3 问题三Agent陷入循环不停调用同一个无效工具症状Agent调用工具AA返回失败模型又调用A又失败来回十几次Token哗哗烧用户干等。解法两步走。第一步给工具调用加“重试上限”同一个工具连续失败超过3次就把错误信息汇总返回给模型并强制让它“尝试另一个策略或直接给用户说明”第二步在Agent状态里增加一个trial_count计数器每轮循环加一超过5次强制走结束节点。本质上是“循环熔断”一定要在架构层面兜底。4.4 问题四并发上去之后模型限流、响应排队症状并发用户一多模型API开始报429限流或每次请求排队好几秒。解法一是全局加令牌桶限流把模型QPS控制在安全水位二是加一个择优降级策略当主力模型排队过长时把请求切换到一个备用模型宁可结果粗一点也要保持服务可用三是把用户能感的交互逻辑与Agent内部逻辑解耦用户先看到“任务已接收”而不是死等Agent内部推理。这部分跟前面决策五讲的异步编排是配套的。4.5 测试与回归Agent怎么测才靠谱最后补一个测试的实战建议。Agent很难用传统单测覆盖因为同一个输入可能有不同输出。我的实践是“双轨测试”一轨是结构化断言比如分类结果是否落在允许的枚举里、工具调用参数是否符合Schema、高影响动作是否走了审批另一轨是样本集回归提前准备50~100条代表性用户输入每次改完代码就全量跑一遍用“关键结论是否一致”来判断回归是否通过。我在团队里立了一个规矩任何Agent代码修改如果要上线必须跑一遍这两轨测试结构化断言失败直接拦截样本集回归里超过5%不一致就必须人工复查。这套机制让我的Agent项目上线后稳定了很多很少出现“上周还能用今天不知道怎么就废了”的情况。我自己做Agent项目到现在最大的体会是不要神化Agent也不要低估它。它不是一个魔盒你丢一段Prompt进去它就能替你干活它是一个需要认真设计的工程系统。七要素帮你检查“该有的有没有”七个决策点帮你决定“具体怎么做”把这两套框架跑一遍你会发现Agent突然变得可靠、可控、可维护了。哪怕后续你的技术栈换了框架也用得上因为Agent工程的核心从来不是某个框架而是你在设计时想的有没有足够深、足够周全。