多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Agent工程化落地指南:拆解七要素与七个决策点

Agent工程化落地指南:拆解七要素与七个决策点 最近被问得最多的一个问题不是“Agent 能干什么”而是“Agent 到底怎么落地”。市面上的教程大多把 Agent 讲成了魔法一段提示词、一个循环、调几个工具任务就自动完成了。可一旦真去工程化事情马上变味——状态放哪、记忆怎么管、模型调用超时怎么办、并发一上来 token 成本怎么压这些问题教程基本不提。我自己的做法是先把 Agent 拆成七要素再从七个决策点去约束实现。所谓七要素是目标、感知、记忆、规划、工具、执行、反思所谓七个决策点是在工程侧必须拍板的七个选型目标如何注入、状态归谁持有、记忆如何分层、规划器用什么、工具如何暴露、失败怎么恢复、链路如何观测。这篇文章就是把这套思路完整展开适合正在从 demo 走向生产的团队参考也适合刚接触 Agent 开发、想避开常见坑的读者收藏着看。1. 七要素Agent 的骨架到底由什么组成1.1 我为什么把 Agent 拆成“目标、感知、记忆、规划、工具、执行、反思”七块我见过不少团队做 Agent上来就写 while 循环把 LLM 输出、解析、调工具、再喂回去。跑几个 case 没问题一换场景就崩。原因很简单Agent 不是一个循环而是一个信息处理系统。把系统拆成七要素不是为了学术好看是为了让每一层都有对应的工程落点。目标决定了提示词怎么写、评判函数怎么定感知决定了输入怎么清洗、多模态内容怎么统一进上下文记忆决定了哪些信息要在上下文里保留、哪些丢到外部存储规划决定了模型是先想再做还是边做边想工具决定了外部能力以什么契约暴露给模型执行决定了模型输出的解析、工具结果回填、异常兜底反思决定了错误怎么被发现、反馈怎么回到下一轮。七块都有对应的工程组件缺一块系统就只能在特定场景下勉强工作。1.2 两个闭环规划执行闭环与反思反馈闭环七要素不是线性管线真正跑起来是两个闭环。第一个闭环是“规划-执行”闭环模型拿到目标与当前状态生成下一步操作执行器调用工具拿到结果后再回填到上下文模型继续决策。这个循环对应 ReAct 一类的运行时。第二个闭环是“执行-反思”闭环每一轮执行之后都要有检查点工具返回报错、结果为空、模型输出格式非法都是反思信号。要不要重试、要不要换方案、要不要直接交给人来处理必须在实现里留好判断分支。很多工程事故都出在第二个闭环缺失上模型输出一个错误格式解析器报错系统直接崩掉或者陷入无限重试。所以我的建议是七要素里“反思”最容易被人忽略但它恰恰是稳定性最关键的环节。2. 决策点一与决策点二目标如何注入状态归谁持有2.1 目标注入写死在 system prompt 里还是运行时传参决策点一目标定义。有人把目标写死在 system prompt适合内部工具比如“你是客服助手负责答疑”有人把目标作为运行时参数动态注入适合通用平台比如用户创建不同 Agent 时每个 Agent 的 goals 由用户自己定义。我在实际项目中更倾向动态注入但要分层系统层 prompt 写死行为边界比如不许编造、不许越权应用层 prompt 作为参数动态拼装。目标本身还要结构化最好有 goal 加 success_criteria。如果只写一小段自然语言“帮我订机票”最后很难判断 Agent 是否真的做对了。目标定义得越可判定后面的评估环节就越扎实也能直接拿 success_criteria 当自动化评测的评分依据。2.2 状态管理内存、Redis 还是数据库决策点二状态归谁持有。Agent 每次执行都在产生状态已完成的规划步骤、工具返回的中间结果、用户会话的上下文。最省事的做法是把全部状态塞在内存里单进程 demo 没问题一旦上多副本、并发一高内存态立刻变成定时炸弹。我处理过一个线上事故两个副本同时处理同一会话各自维护自己的 plan最终结果互相覆盖。后来改成 Redis 持有会话状态所有副本读取同一份快照才稳定下来。但 Redis 也不是万能的长任务需要落库至少要能看到历史版本。结论是demo 用内存没问题生产环境先想清楚状态归属优先选可共享、可持久化的存储。2.3 用表格快速对比状态存储选型存储方案优点缺点适用场景内存延迟极低实现简单无法跨副本共享重启即丢单机 demo、本地调试Redis延迟低支持分布式锁与过期策略需要额外运维大对象序列化有成本会话级状态、短任务、多副本共享PostgreSQL/MySQL可靠支持审计与回溯延迟相对高需要设计表结构落库、长任务、敏感操作留痕对象存储适合超大中间结果读写延迟高不适合频繁更新文档处理、多模态文件暂存这里的要点不是“哪种最好”而是“你需要在哪一层做一致性”。如果多个副本并发写同一个会话状态光是 Redis 还不够还要考虑加锁或者用版本号防止覆盖。3. 决策点三与决策点四记忆分层与规划器选型3.1 记忆分层短期记忆本质上是 token 预算管理先解释一下 token 是什么。一句话token 是模型输入输出文本的切分单位和字符不是一回事。中文大概一个汉字接近一个 token英文一个单词经常被切成若干个 token所以同样的上下文不同语言的实际成本差异明显。短期记忆就是当前这个请求喂给模型的全部上下文包括用户问题、历史对话、工具返回、模型中间输出它的上限就是模型上下文窗口。实际做 Agent 时短期记忆必须管理历史对话不是全量保留而是摘要化工具返回也不是全量塞进上下文而是抽取关键字段。我常用的做法是每轮结束后对旧对话做一次摘要压缩只保留最近 N 轮原文。缩不缩取决于 token 成本与信息保留的平衡。3.2 长期记忆向量库不是银弹长期记忆用于跨会话的持久信息用户偏好、历史结论、业务知识。很多教程默认用向量库把所有内容切片、embedding、相似度检索然后塞回上下文。但工程上这个方案有几个坑。第一embedding 有延迟和成本不能每轮请求都重新 embedding 全部内容。第二纯向量检索往往会召回一堆语义相似但无关的内容反而污染上下文。第三写向量库之前要先解决权限问题——用户 A 的记忆不能让用户 B 检索到。我的经验是长期记忆按“结构化加向量”混合存事实性信息比如姓名、偏好、订单状态放关系型数据库靠业务字段精确查询非结构化内容才走 embedding 检索。两者结合既精准又省钱。3.3 规划器选型ReAct、Plan-and-Execute 还是 Graph决策点四规划器用什么。最轻的是 ReAct 循环让模型在每一轮思考“下一步是什么”适合任务不固定、需要边做边调整的场景。第二个是 Plan-and-Execute先让模型生成完整步骤列表再逐步执行适合步骤可以提前确定的任务比如报表生成、数据清洗。第三个是基于图的编排像 LangGraph 里那样把每个节点定义为一种能力显式定义边与条件跳转适合流程相对固定、需要可控性的生产系统。我的建议是默认用 ReAct 起步但要在外层加步骤上限。实际上极少数任务真正需要模型做完整规划很多场景下“固定的图加局部 ReAct”才是又稳又灵活的搭配。图的优势是可控你把分支写死了模型只能在关键节点做选择出错概率大幅下降。4. 决策点五与决策点六工具调用与失败恢复4.1 工具调用原生 function calling 是最省心的契约决策点五工具如何暴露。模型“会”用工具但工程上要给它一个“号码簿”。主流方案是用原生 function calling 或 tool calling 协议把你的工具定义成 JSON Schema模型在输出时直接返回“我要调用某个工具参数是什么”运行时再去执行。这样模型就不用自己练习输出 JSON 字符串解析稳定性好得多。如果你的模型不支持 function calling或者你想自己控制解析那就得让模型输出结构化 JSON再用严格的 schema 校验。这种方案自由度更高但很容易踩格式不稳的坑。实测下来能用原生 tool calling 就用原生兼容性最好实在要自解析务必加一个能自动纠错的层格式错了重试一次别直接崩。这里还有一个工程细节工具定义越少、参数越明确模型越容易选对。如果工具清单变成一长串几百个函数光 token 就吃掉一大截还容易误调用。所以工具清单要动态裁剪按当前场景只暴露相关的子集。4.2 失败恢复重试不是万能药决策点六失败恢复。模型调用会超时、工具会报错、解析会失败。最常见的错误处理是重试但盲目重试会砸钱LLM API 超时重试没问题工具调用失败如果是因为业务逻辑错误重试一百次也没用。正确做法是分级处理网络级错误重试一到两次模型输出格式错误把错误信息反馈给模型让它修正一次工具业务报错应该直接把错误文本反馈给模型让它改变策略而不是无脑重试。另一个关键点是设置步骤上限与循环检测。如果模型重复调用同一个工具、参数一样、结果一样就触发中断给出提示并请求人类确认。不问原因的重试等于给成本开闸。我在几个项目里都吃过这个亏最后统一给循环加了一个 global_step 计数器超过预设上限就强制走降级路径。4.3 并发扛得住吗异步、限流、队列三板斧网上经常有人问“AI Agent 怎么扛并发”。我的回答是别先想着“扛”先把 Agent 想成两段——调度端和调用端。调度端负责编排流程本身是轻量的可以多实例横向扩展调用端是 LLM API 和工具 API它才是真正的瓶颈。在 FastAPI 这类异步栈里Agent 的主循环尽量用 async不要让模型请求阻塞 worker。对外部 API 加并发限流用信号量或者令牌桶控制同时对 LLM 的请求数。对长任务走消息队列用户提交任务后立刻返回任务 ID后台 worker 慢慢跑前端轮询结果。这样用户不会干等系统的峰值压力也能被队列削平这是我在生产环境里验证过最稳的组合。5. 决策点七可观测性、安全与评估生产环境的三道防线5.1 可观测性没有 traceAgent 就是黑盒决策点七可观测性。Agent 与传统接口最大的不同是非确定性同一个问题两次调用可能路径完全不同。没有 trace 的情况下线上出了问题根本没法排查。我建议从第一行代码就记录三类信息输入输出快照也就是问题和最终回答调用轨迹每一步决策、模型调用的 prompt、工具调用的参数和结果成本时间指标token 数量、耗时、重试次数。现在有不少现成工具可以接LangSmith、Langfuse 之类的也可以用最朴素的 JSONL 日志自己记。关键是结构要统一。我用过一个很土但有效的方法每次循环都往结构化日志里追加一条 event包含 step、agent_id、goal、action、tool_result、latency、token_used。出问题时按 agent_id 抽日志就能复现全部执行过程排查效率翻倍。5.2 安全与权限Agent 的权限边界要最小化Agent 拿到工具权限等于把一个能自主行动的程序放进了系统。权限设计必须遵循最小化原则给 Agent 的 API token 只开通它任务需要的 scope不要直接给数据库管理员账号工具执行要放在沙箱里限制网络访问和文件系统访问对敏感操作比如下单、转账、删除数据必须设置 human-in-the-loop 审批。这一点我吃过亏。之前一个内部 Agent 挂了一个可以读写知识库的工具token scope 开太宽一次 prompt injection 就把不该暴露的内部文档给读出来了。从那以后凡是 Agent 工具我都坚持白名单式权限默认拒绝按需开通。尤其是涉及外部系统调用时必须让 Agent 只具备“完成任务所需的最小权限”。5.3 评估没有评测集优化就是拍脑袋最后Agent 要有自己的评测集。代码可以单测Agent 必须放评测。准备几十条覆盖典型场景的输入包含正常任务、边界输入、错误路径每次改动模型、提示词或流程后跑一遍记录成功率和 token 消耗。评测不一定要自动化起步时人工标注结果也行但一定要有一个固定样本集否则你会陷在“这次好像更好但说不清哪里好”的泥潭里。我自己的习惯是每个 Agent 项目维护两个文件一个是 seed_cases.json存放典型输入和期望结果一个是 eval_results.jsonl存放每次评估的输出。改动任何配置后跑一次对比前后两轮的成功率和成本让优化有据可依。6. 落地参考一个 FastAPI LangGraph 的最小骨架6.1 骨架如何映射到七要素这里给一个最小骨架用 FastAPI 提供 HTTP 入口LangGraph 做编排。先把状态定义出来from typing import TypedDict class AgentState(TypedDict): goal: str question: str plan: list[str] step_index: int history: list[dict] tool_results: list[dict] final_answer: str这个 AgentState 就是决策点二的答案状态显式定义传给所有节点。LangGraph 会把每个节点返回的部分内容 merge 回状态你可以理解成一份共享的“会话工作台”。然后定义目标注入函数def build_system_prompt(goal: str, knowledge_scope: list[str]) - str: return ( 你是任务执行助手。当前目标: goal 。允许的知识范围: ,.join(knowledge_scope) 。不许越权不许编造结果。 )目标从请求里来动态拼进 system prompt对应决策点一。接着定义规划节点、工具节点、反思节点每个节点都是纯函数输入状态输出一个更新后的部分状态。最后编译图from langgraph.graph import StateGraph, END workflow StateGraph(AgentState) workflow.add_node(plan, plan_node) workflow.add_node(act, act_node) workflow.add_node(reflect, reflect_node) workflow.set_entry_point(plan) workflow.add_edge(plan, act) workflow.add_edge(act, reflect) def should_continue(state: AgentState): if state.get(need_more): return act return END workflow.add_conditional_edges(reflect, should_continue) compiled_agent workflow.compile()这个图对应的就是七要素里的“规划-执行-反思”闭环而不是一个大 while 循环。你可以在 reflect 节点里做停止判断、重试判断、人类审批判断这就是决策点六和决策点七的落点。不同版本的 LangGraph API 名称略有差异但思路是一致的。6.2 FastAPI 入口异步与任务化HTTP 入口我会写两层。轻量任务同步返回from fastapi import FastAPI from pydantic import BaseModel app FastAPI() class AgentRequest(BaseModel): goal: str question: str app.post(/agent/run) async def run_agent(req: AgentRequest): result await compiled_agent.ainvoke( {goal: req.goal, question: req.question} ) return {answer: result[final_answer]}注意这里用 async避免阻塞事件循环LangGraph 的异步入口ainvoke可以配合 FastAPI 的 async 生态。如果任务可能跑几十秒甚至几分钟就换成队列模式先返回 task_id后台跑任务前端再拿 task_id 轮询结果。这就是并发问题里说的“削峰”实测下来比硬等 HTTP 响应稳得多。6.3 几个容易踩的坑提前记下来模型的输出不一定每次都能被 JSON 解析务必在解析层做容错能纠错就纠错纠不了就交给反思节点。工具返回内容先截断再回填一个工具返回几十万字会瞬间打爆上下文窗口。用 total_tokens 做成本监控线上成本异常时第一反应先看是不是某类任务重试次数过多。别让 Agent 在循环里无限跑给节点加 step 上限超了就走降级路径而不是直接报错。本地测试时可以用 mock 工具函数把模型调用缓存成文件能大幅加快调试速度。7. 七要素与七个决策点映射速查表7.1 速查表我最后把七要素和七个决策点的对应关系整理成一张表方便你设计和评审时对照。七要素对应的工程问题七个决策点我常选的做法目标Agent 要完成什么、如何判定成功决策点一目标如何注入系统层写死边界应用层动态拼装目标带 success_criteria感知输入如何清洗、上下文如何构建决策点二状态归谁持有demo 用内存生产用 Redis 加数据库落盘记忆哪些信息留在上下文、哪些外置决策点三记忆如何分层短期摘要压缩长期“结构化加向量”混合存储规划任务怎么拆解、步骤怎么编排决策点四规划器用什么默认 ReAct流程固定时换成图编排工具外部能力以什么契约暴露决策点五工具调用协议优先原生 function calling工具清单动态裁剪执行模型输出如何解析、工具结果如何回填决策点六失败恢复策略网络错误重试业务错误反馈给模型设步骤上限反思错误如何发现、反馈如何利用决策点七有无 trace 与评测结构化日志加固定评测集敏感操作加审批这张表不需要背它只是提醒你每个要素背后都有一个必须拍板的工程问题。如果你发现某个要素在项目里没有对应的决策点大概率说明那部分还没想清楚后续一定会补课。7.2 七个决策点的落地顺序建议如果团队从零开始做一个 Agent我推荐的顺序是先敲定目标注入和状态管理这是地基再搭记忆与规划这两个决定效果上限然后接工具与失败恢复这两个决定稳定性最后再想办法做观测和评估磨质量。反过来很容易翻车先花大量精力优化模型提示词结果状态一乱、工具一报错全盘崩溃前面的优化全白做。说实话Agent 工程实现的门槛不在“调用一个 LLM”而在把这些细节逐一拍板并坚持对齐。我自己踩过的坑几乎都集中在“以为模型能自己搞定结果没有给人留控制点”。所以我的原则很简单给模型足够的自由度去做规划给系统足够的约束去兜底给工程师足够的观测去复盘。这套从七要素到七个决策点的拆法是我目前觉得最不容易跑偏的工程框架。如果你正在做 Agent不妨找一个自己项目里的真实任务按这张表从头过一遍大概率能找到现阶段最该补的那一环。
返回列表