ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

AI Agent工程实现:七要素拆解与七个关键决策点指南

AI Agent工程实现:七要素拆解与七个关键决策点指南 写 Agent 的工程实现最怕的就是“看了很多概念一动手就懵”。网上讲 AI Agent 的文章要么堆术语要么只给 demo真正能指导你把一个 Agent 从想法推到可运行状态的很少。这篇文章我打算换个思路不聊虚的把 Agent 拆成两半来看一半是它运行所需要的七要素一半是你在工程里必须拍板的七个决策点。七要素回答“一个 Agent 由什么构成”七个决策点回答“你该怎么把它做出来”。七要素是解剖学七个决策点是施工图两套东西合起来才是完整的工程视角。这篇文章适合两类人一是准备在项目里引入 Agent、但还在犹豫架构怎么搭的开发者二是已经跑过简单的 Agent demo、想搞清楚下一步该往哪使劲的人。我会把每个要素和每个决策点背后的为什么讲清楚——为什么这么选、不这么做会踩什么坑、换一种方案代价是什么。最后给一个最小可跑的工程样例和一份排查清单你照着改就能用。在动手之前先搞清楚 Agent 到底在解决什么问题很多团队掉进一个坑把 Agent 当成普通的 API 封装以为就是一个大模型加几个提示词。结果做出来东西能聊天干不了活。想理解 Agent 的工程实现先得理解它和你以前写的软件到底有什么不一样。1.1 从“聊天窗口”到“能干活的人”传统软件是确定性的你写一个函数传参它返回结果逻辑分支是写死的。LLM 应用是概率性的你给一段提示词它生成一段文字结果有一定的不可预测性。而 Agent 处在两者的交叉点上——它要用概率性的模型去执行确定性目标比如“帮我把这周的用户反馈整理成表格”“定时检查服务器日志并给出告警”。这意味着 Agent 的代码逻辑不是从输入到输出的一条直线而是一个循环感知当前状态决定下一步做什么调用工具观察结果再决定下一步。很多人把 Agent 理解成“带工具的大模型”这是不够的。带工具只是让它能行动真正的 Agent 要有“目标—计划—行动—观察—调整”的闭环。你可以类比成带实习生你不能只给他一份文档让他汇报工作你得给他目标、给他人脉和工具还得容忍他中间走错路再自己绕回来。工程上这种循环的通用名称叫 Agent Loop核心就是 ReAct 模式Reason Act的变体。它的基本结构是模型收到用户请求先推理Reason判断当前需要什么信息、应该走哪条路径。模型输出一个动作Act往往是调用某个函数比如搜索、查数据库、发请求。系统执行动作把结果喂回给模型。模型基于新信息继续推理直到任务完成。这里有一个大家容易忽略的点模型在哪一步停止怎么判断任务完成通常不靠模型自觉而是靠工程上的终止条件。这一点后面在决策点部分会专门展开。先记住结论——Agent 的本质是一个带反馈闭环的任务执行系统不是单次生成。1.2 Agent 跟传统软件差的不是功能是“控制流”传统程序里控制流是你写死的if 分支、for 循环、函数调用都在代码里。Agent 里控制流变成了模型根据上下文动态生成的决策。代码不再决定每一步做什么只决定“每一步可能有哪些选项、什么情况下可以做什么、做了之后如何反馈”。这对程序员是一个很大的心智转变。举个直观的例子。你想写一个自动处理客户邮件并按紧急程度分类的程序。传统做法是先设规则标题含“投诉”且正文含“退款”则标为高优再写一堆正则维护起来很痛苦规则永远追不上语言的多样性。Agent 的做法是给模型一个“标记紧急程度”的工具让它自己读邮件、判断紧急程度、调用工具打标签甚至写一段回复草稿。规则没有变少而是从“预先穷举”变成“动态判断”规则变成了工具的边界、模型的约束而不是逻辑本身。由此引出 Agent 工程实现的第一个基本矛盾自由度和可控性。Agent 自由度越高越能处理复杂任务但越难控制、越容易出错。自由度太低又退化成规则系统失去 Agent 的意义。整个工程实现的过程说白了就是在画一条边界在边界之内让模型自由发挥在边界之外用代码兜底。七要素里的“安全与约束”和七个决策点里的“终止条件与降级策略”都是在处理这一件事。1.3 这套思路能帮你省下什么把七要素和七个决策点吃透最大的收益不是能写出一个惊艳的 demo而是避开几个大坑。第一个坑是架构冒进。一上来就上多 Agent 编排、搞复杂的记忆系统结果问题本身用一个函数调用就能解决白白引入大量延迟和不确定性。理解了七要素你会知道记忆、规划、编排各自解决什么问题按需裁剪。第二个坑是评测缺失。很多团队把 Agent 接入生产之后出了 bug 不知道该修模型、修提示词还是修改器因为没有一套系统的评测集和回归测试。七个决策点里专门有评测与迭代这一环我会给一套低成本可落地的评测方案。第三个坑是成本失控。Agent 是一个会循环调用模型的系统一次任务可能消耗几十万 tokens如果不对工具调用次数、上下文长度、模型规格做约束账单会教你重新做人。这个在部署决策点里详细说。解构七要素一台能跑起来的 Agent身上必须有这几块骨头七要素是我从工程视角抓出来的、一个 Agent 系统必备的七个组成部分。跟你可能见过的其他分类法略有不同这套更偏“运行依赖”而不是“学术概念”每个要素对应一个明确的工程模块。2.1 七要素全景速览先给一张总表把七个要素、它解决的问题、以及对应的工程模块列清楚。后面逐个拆解。要素解决什么问题对应工程模块大模型底座理解和生成的自然语言能力模型 API / 本地部署任务规划器决定下一步做什么提示词策略、规划器组件记忆系统保存历史信息与长期知识会话缓存、向量数据库、KV存储工具集与外部世界交互的接口Function Calling、工具注册中心编排框架组织上述模块的循环Agent Loop、状态机、框架LangGraph等反馈与反思机制从失败或结果中改进Evaluator、Reflection Prompt、自我修正安全与约束限制行为边界与控制风险权限控制、输入输出过滤、熔断降级这张表你要竖着看大模型是底座但光有它什么都做不了规划、记忆、工具是三个支柱分别解决“想”“记”“做”编排是骨架把它们串起来反馈和安全是两个护城河前者保证越跑越好后者保证不跑偏。在工程里这七个要素并不总是独立模块。比如规划器和反馈机制很多时候就是几个提示词的区别工具集和记忆系统往往要共享同一个底层存储。但拆开想是必要的因为每个要素都有自己独立的故障模式。下面逐个讲它们的原理、陷阱和最少实现方式。2.2 逐一拆解七个要素大模型底座。这是最容易选、也最容易选错的要素。容易选是因为选择多GPT、Claude、通义千问、GLM、Llama、Qwen开源闭源一大堆。容易选错是因为很多人只看跑分和价格忽略了两个关键维度。第一是“工具调用能力”。Agent 系统高度依赖模型在结构化输出上的稳定程度——模型能不能稳定输出符合 schema 的 JSON能不能在上下文很长之后仍然按照指令返回而不是开始胡编。这类能力在普通榜单上看不出来必须自己拿任务样例实测。第二是“上下文窗口的实际可用长度”。标称 128K 的模型往往在超过 50K 之后表现明显下降、思维开始跳跃。你在选型时一定要记住标称值和实际值之间有差距Agent 场景必须压测。任务规划器。规划是 Agent 和“AI 搜索”“聊天助手”的分水岭。它的职责是把一个模糊的指令拆成具体的子目标序列。工程实现有三种主流方案复杂度和效果递增第一种是 ReAct 风格即边做边想。模型每一步输出“thought—action—observation”动态决定下一步适合开放任务但 token 消耗大、每一步都有出错风险。第二种是 Plan-then-Execute先让模型生成一份完整计划再按计划执行甚至计划可以单独用一个模型生成。优点是可控性强、每一步有据可依缺点是计划可能一开始就错了而且模型不会中途轻易调整。第三种是混合式比如 ReAct 循环 定期重规划。执行过程中如果检测到连续 N 步没有进展触发一次重规划。这种方式实现成本高一点但稳定性最好适合长期任务。我的经验是刚起步不要实现第三种先用 ReAct 跑通遇到规划质量问题了再升级。后面决策点部分我会讲怎么判断到底该不该升级。记忆系统。记忆是 Agent 被低估的组件。很多初版 Agent 不做记忆每次任务都是“失忆开局”导致同样的问题反复错。记忆至少分两层来设计。短期记忆对应会话内的上下文就是你现在 Prompt 里塞的那些对话记录。工程上要管的是上下文长度不控制的话几轮对话就能把窗口撑爆所以要有截断、摘要、滑动窗口机制。长期记忆是跨会话的持久信息。最好的形态是“向量检索 结构化存储”组合向量库存语义相似的历史KV 或关系库存明确事实比如用户的偏好设置。工程上注意一个矛盾不是所有信息都值得入库。存得越多检索噪声越大。经验法则是能直接从对话历史拿到的信息不要入长期记忆频繁被查询的事实优先入记忆写入要有准入条件。工具集。工具是 Agent 的四肢决定了它能做什么。工程实现核心是 Function Calling 这一套协议。所谓 Function Calling本质上是让模型输出一个结构化的“工具调用请求”而不是自由文本。你做这件事的时候就干三步把工具定义成 JSON Schema包括名称、描述、参数结构。描述要写清楚什么时候用这个工具、参数格式是什么因为模型是靠描述来选择工具的。系统接收模型返回的工具调用请求做参数校验然后执行真实函数的调用。把执行结果返回给模型让其继续推理。这里面九成的问题出在工具描述写得不清楚或者参数校验没做——模型返回了一个不合法的参数你没拦住还直接发给后端导致各种脏数据。后面排查清单里我会给具体症状和修法。编排框架。编排负责把前四者串成循环。你可以自己写死循环也可以选框架。自己写的自由度高但状态管理容易乱框架省事但引入抽象和限制。目前主流的选择是 LangGraph它把 Agent Loop 显式建模成图结构节点是“推理”“调用工具”“用户交互”边是条件转移。比 LangChain 早期的 Chain 模型更贴合 Agent 场景也更好控制。没有历史包袱的新项目建议直接上 LangGraph 而不是 LangChain。LlamaIndex 在处理“文档 知识库”类的 Agent 时更顺手如果你的 Agent 主要任务就是 RAG优先考虑它。如果项目对性能要求高、又不想引入 Python 生态依赖Rust 生态里也有不错的选择比如 rig、genkit 这类库只是生态成熟度比 Python 还是有差距选它之前先确认手册和社区资源能满足你的问题排查需求。反馈与反思机制。Agent 不可能一次做对所以必须要有一套机制把“做错”变成“做对”。两层设计第一层是执行中的自我修正。模型调用工具得到结果后发现结果不对可以再试一次或换一个工具。工程上你要给这种“重试”留出次数上限防止模型在同一问题上无限循环。第二层是执行后的反思。一次任务结束后让模型写一段反思哪里做得不好、为什么、下次怎么做。反思结果可以作为记忆写回长期存储下次类似任务直接调用。反思不是玄学本质上是“让模型基于结果做一次归因分析”。归因分析的质量取决于你喂给它的信息是否完整。所以工程上要保证日志记录了完整的轨迹thought、action、observation、final answer反思 prompt 才能拿到原材料。安全与约束。这项最后讲但优先级最高。Agent 的安全性分三个层面第一层是权限控制。Agent 调用的每个工具都要按最小权限原则授权。能让它只读的不要给它写权限能给它试运行环境的不要直接上生产。很多人直接给 Agent 配了数据库管理员权限一个错误的 SQL 就把表删了。第二层是内容安全。模型的输入输出要有过滤和审查机制防止提示词注入——让外部输入比如网页内容、用户消息变成“指令”劫持 Agent。第三层是熔断降级。设置调用次数上限、异常重试上限、危险操作确认机制。比如 Agent 连续调用工具失败 5 次之后不要继续尝试应当把控制权交还给人。到这里七要素就拆完了。你会发现它们之间不是孤立的模型能力影响规划上限规划结果决定工具调用工具结果写入记忆记忆又反过来影响下一次规划编排把所有环节串成循环反馈和安全保证循环可靠。七要素是横向的解剖结构下面七个决策点是纵向的施工选择。七个决策点做 Agent 时真正要拍板的那些事如果说七要素是“必须有哪些零件”七个决策点就是“每个零件你打算怎么做”。决策点不分先后对错只看场景适配。我按从“买什么模型”到“怎么上线运维”的顺序来讲你可以照着这个顺序做一次选型评估。3.1 决策点一模型选型——不要只看跑分要压测工具调用能力模型选型是整个 Agent 的基石选错了后面全都白搭。原则就一条拿你的真实任务去做压测别拿跑分当唯一指标。具体操作建议准备一个 20 到 30 条的“黄金评测集”里面覆盖你 Agent 最典型的任务类型。比如你的 Agent 要查库存、生成订单评测集就包含“不同表述但相同意图”的查询语句以及几组容易混淆的边界情况。然后用候选模型各跑一轮重点看三项指标一是工具调用格式的规范率。模型返回的 tool call 是不是总能符合 JSON Schema有没有多余的字段、缺失参数、JSON 格式错误。二是边界情况的处理能力。面对含糊的用户指令模型是主动追问还是自己瞎猜。三是长上下文表现。把上下文逐步拉长到 50K 以上看推理质量有没有肉眼可见的崩塌。关于是否用本地模型除非你有数据不出内网之类的合规要求否则初期直接商用 API开发效率高一个量级。私有化部署的拐点在“调用量稳定且足够大”之后那时候用 vLLM 之类的推理框架跑开源模型单位成本才划算。3.2 决策点二规划策略——用 ReAct 保底按需升级规划策略本质上是在“效率”和“确定性”之间权衡。我建议的路径是默认 ReAct遇到特定瓶颈再升级。具体来说出现以下三种情况之一就考虑从纯 ReAct 升级到 Plan-then-Execute 或混合式任务链条很长超过 5 个子步骤ReAct 的轨迹太长容易在中途跑偏。换成先出计划再执行至少可以在第一步拦住明显错误的计划。任务的每一步之间依赖关系明确比如“先查汇率再算总价最后下单”。这种流程适合预定义 Plan让模型按部就班走减少自由度。排查问题时发现模型在同一个错误上来回绕说明它缺少对全局的把握升级为重规划机制每 N 步检查一次进度卡住了就强制换策略。对应地如果你的任务只有两三步、用户意图相对明确就别加复杂规划器了ReAct 的简单循环完全够用。这里有一个很实用的原则控制流的复杂度应该跟任务复杂度匹配而不是跟技术潮流匹配。3.3 决策点三记忆设计——先分清“该记的”和“该忘的”记忆设计最容易犯的错是“过度设计”。一上来就上向量数据库、加实体图谱结果数据根本没积累起来白白增加系统复杂度。我的建议是分三个层级递进每个层级都有明确的触发条件。第一层是会话内滑动窗口 摘要。这是所有 Agent 的标配。只保留最近几轮对话原文更早的内容用模型摘要成一段话放在上下文最前面。这个层级的核心参数是窗口大小经验值 10 到 20 轮再结合模型上下文窗口动态调整。第二层是工作记忆把当前任务进行到一半的状态比如“已查过库存待确认价格”存进一个结构化对象里。这种记忆不需要向量库一个 JSON 对象就够。工作记忆要保证在每次模型推理时都能“看到”因为它是任务推进的骨架。第三层才是长期记忆用向量库存事实性内容。这里要定好写入规则和检索规则。写入规则要有准入条件这条信息是否会在未来的任务中被再次需要含混不清的不要写。检索规则要限 top-k比如取最相似的 5 条宁可少取也不要让噪声干扰模型判断。有一个容易忽略的工程细节所有记忆操作都要跟业务数据隔离。Agent 的长期记忆存的是“辅助决策信息”不是业务系统的权威数据。如果你让 Agent 把用户订单写进自己的记忆库里等待你的将是数据一致性的噩梦。权威数据留在业务库里Agent 的记忆只做缓存和索引。3.4 决策点四工具接入——工具描述写得好不好直接决定 Agent 的上限工具接入是 Agent 工程里性价比最高的一环同一个模型工具设计得好任务完成率可以从 60% 提到 90%。而工具设计的功夫九成花在写描述上。每个工具的描述要回答三个问题这个工具是干什么的什么时候该用、什么时候不该用参数分别代表什么、有什么格式要求千万不要写得像 API 文档一样干巴巴全是字段名要把使用场景写出来。举例说明一个“查询天气”的工具差的描述是“根据城市名查天气”好的描述是“当用户询问某个城市的天气情况时调用。城市名必须是中文如‘北京’。若用户只提供日期未提供城市需要先追问城市名再调用”。注意最后一句这其实是把“对话策略”写进了工具描述里相当于给模型打了补丁。另外工具数量不是越多越好。模型在数十个工具之间做选择时准确率会明显下降。经验上限是 10 到 15 个工具。超过之后建议做工具分组或者把多个相关操作合成一个工具用参数区分动作。参数的强校验也务必加上。模型输出参数偶尔会漏字段、类型错误你要在调用真实函数之前做一次 schema 校验不合法就打回让模型重新生成。这一步不是可选项生产环境必须有。3.5 决策点五单 Agent 还是多 Agent——别为了“高级”而上多角色多 Agent 现在是热门话题但它不是银弹。我的建议很直接单 Agent 能解决的问题永远不要用多 Agent。多 Agent 的引入至少要多付三倍以上的 token 成本、多管理几倍的失败模式还要处理 Agent 之间的上下文隔离和信息传递。什么场景真的需要多 Agent三条判断标准任务里存在天然的角色边界比如“研究助手”和“写作助手”它们各自需要不同的系统提示词、不同的工具集混在一起会让模型频繁切换上下文、表现下降。单个 Agent 的上下文窗口装不下所有需要的背景信息用多个 Agent 各管一段可以有效切分上下文。子任务必须并行执行比如同时查多路数据源单 Agent 串行会太慢。即使满足其中一条你也要优先考虑“逻辑上的拆分”而不是“物理上的多 Agent 进程”。比如你还是用一个模型但通过系统的状态机去切不同的提示词和工具集这就是一个逻辑多 Agent 的实现。这种方案成本低得多只是领域内的“一个 Agent”工程上可控性更好。如果你最终决定上多 Agent务必要有主控 Agent或者一个编排器来统筹任务分发和结果汇总不要让 Agent 之间直接协商。没有主控的 Agent 群聊看着热闹实际跑起来就是一场事故根本收不了场。3.6 决策点六评测与回归——没有评测集的 Agent就是一辆没刹车的车评测是 Agent 工程里最容易被跳过的环节但它是上线前的最后一道闸门。Agent 的评测跟传统 LLM 评测不一样你不仅要测“最终答案对不对”还要测“过程对不对”——工具调了几次、有没有浪费时间在无关调用上、有没有走向危险的路径。低成本可落地的评测方案有三层第一层是最终答案质量。传统办法可以人工打分或者用更强的模型做裁判。这层只看结果实现简单能拦下大部分明显错误。第二层是过程正确性。检查执行轨迹里的每一步工具调用是否合理、参数是否正确、步骤顺序是否恰当。建议做成规则校验比如“凡是调用支付工具前没有查余额的都算失败”。这层能抓到结果对但过程危险的情况。第三层是回归测试集。每次改提示词、改工具定义、换模型都要跑一遍同一套测试集对比通过率和轨迹差异防止“修好一个 bug、引出三个新 bug”。评测集不是为了上线前跑一次而是为了上线后每一次迭代都跑。把它纳入你的 CIAgent 变更自动触发回归。没有这套机制后续优化基本靠感觉踩坑是迟早的事。3.7 决策点七部署与成本——把 Agent 当服务来设计而不是当脚本Agent 上线和普通 API 服务有很多不同最大的差异在于“执行时长”。一次 Agent 任务可能耗时几十秒甚至几分钟所以把它包装成同步 HTTP 接口等着返回体验会很差。更合理的形态是任务化提交一个任务返回任务 ID前端轮询或者后端起 WebSocket 通知结果。成本控制是部署环节的重头戏。Agent 的 token 消耗大头在两部分一是循环过程本身二是塞进上下文的记忆和工具结果。控制方法有四个限制最大迭代步数比如撑死 15 步到了没完成就强制结束防止模型在死循环里烧 token。对工具返回结果做截断。数据库查回来 1000 行只拿前 20 行给模型看其余存起来按需再查。这个措施能省下大量 token。启用语义缓存。相同或相似的用户请求直接复用之前的 Agent 执行结果或中间步骤结果不要重新跑。在一个用户问题高度重复的业务里缓存能省 30% 以上调用量。分级用模型。规划用便宜的小模型关键推理和工具选择用贵的大模型。这一步能显著降低成本但对架构复杂度有要求建议第一个版本先统一大模型稳定后再优化。部署运维上还要把每一次 Agent 运行的全链路轨迹记录成结构化日志。这些日志既是排查问题的依据也是后续优化评测集的素材。日志字段要包含任务 ID、输入、每一步的 thought、action、observation、中间 token 数、耗时、最终结果、错误信息。日志记录得越好后面迭代越快。最小可用的 Agent 工程样例从代码理解整套体系前面讲了这么多落到代码上才有体感。下面给一个最小但五脏俱全的 Agent 实现方案基于 Python LangGraph核心功能是“天气查询 备忘录用例”你可以在此基础上扩展自己的工具集。4.1 工程结构与依赖准备工程结构建议如下agent_project/ ├── main.py # 入口函数 ├── agent/ │ ├── graph.py # LangGraph 图定义 │ ├── tools.py # 工具函数注册 │ ├── state.py # 状态定义 │ └── prompts.py # 提示词管理 ├── tests/ │ └── eval_set.json # 评测集 └── pyproject.toml依赖安装核心就三个库pip install langgraph langchain-openai python-dotenv我这里用 langgraph 作为编排框架因为它把“节点 条件边”这套 Agent Loop 逻辑表达得最直观。需要说明的是各家的工具定义接口会随版本变化但总体思路一致把工具注册给框架框架负责把工具描述传给模型、把模型生成的工具调用翻译成真实函数执行。4.2 核心实现状态、工具、图Agent 的状态用 TypedDict 定义。状态会在每个节点之间传递相当于“工作记忆”的载体。这里把 messages 和 remaining_steps 放进了状态里前者记录会话历史后者记录剩余迭代步数。from typing import Annotated, TypedDict class AgentState(TypedDict): messages: Annotated[list, accepted_messages] remaining_steps: int工具函数是 Agent 的四肢。每个工具用装饰器注册框架会根据函数签名和 docstring 自动生成 JSON Schema。值得注意的是docstring 就是“工具描述”你要把使用场景、参数格式、何时调用写清楚这直接决定模型能不能调用对。import json from langchain_core.tools import tool import httpx tool def get_weather(city: str) - str: 查询指定城市的当前天气。 适用于用户询问天气的场景。城市参数必须是中文城市名例如“北京”。 如果用户没有给出城市名或给了英文城市名先向用户追问或转换为中文后再调用。 # 实际项目里替换成真实天气 API mock_data { 北京: {temp: 18, condition: 晴}, 上海: {temp: 22, condition: 多云}, } data mock_data.get(city, {temp: unknown, condition: unknown}) return json.dumps({city: city, **data}, ensure_asciiFalse) tool def save_note(content: str) - str: 保存一条备忘录。 当用户明确说“记住”“记一下”“备忘”等指令时调用。 content 参数是用户想保存的完整文字内容。 with open(notes.txt, a, encodingutf-8) as f: f.write(content \n) return 已保存图是编排的核心。这里的关键代码是 define_agent_graph 函数它创建了一个 agent 节点模型推理、一个 tools 节点执行工具调用并在 tools 之后判断“是否还有步骤剩余”来决定是回到 agent 还是退出到 END。模型节点和工具节点交替执行就是一个标准的 Agent Loop。from langgraph.graph import StateGraph, END from langchain_openai import ChatOpenAI def create_agent_graph(): llm ChatOpenAI(modelgpt-4o-mini) tools [get_weather, save_note] llm_with_tools llm.bind_tools(tools) def agent_node(state: AgentState): messages state[messages] # 把剩余步数告知模型防止它无限循环 remaining state.get(remaining_steps, 10) instruction f注意你最多还有 {remaining} 步完成用户请求。 response llm_with_tools.invoke(messages [{role: system, content: instruction}]) return {messages: messages [response], remaining_steps: remaining - 1} def tools_node(state: AgentState): last_message state[messages][-1] # 遍历模型返回的工具调用请求逐个执行 tool_results [] for tool_call in last_message.tool_calls: tool_name tool_call[name] tool_args tool_call[args] matched_tool next(t for t in tools if t.name tool_name) result matched_tool.invoke(tool_args) tool_results.append({ role: tool, tool_call_id: tool_call[id], content: str(result), }) return {messages: state[messages] tool_results} def should_continue(state: AgentState): last_message state[messages][-1] # 模型没有要求调用工具说明任务结束了 if not last_message.tool_calls: return END # 步数耗尽强制结束 if state.get(remaining_steps, 0) 0: return END return tools graph StateGraph(AgentState) graph.add_node(agent, agent_node) graph.add_node(tools, tools_node) graph.set_entry_point(agent) graph.add_conditional_edges(agent, should_continue, {tools: tools, END: END}) graph.add_edge(tools, agent) return graph.compile()主入口负责接受用户输入、初始化状态并运行图。这里的一个细节是用户消息被封装成“user”角色的 message进入 agent 节点后模型才能感知到任务目标。def main(): graph create_agent_graph() print(Agent 已启动输入问题输入 exit 退出) while True: user_input input( ) if user_input.strip().lower() exit: break result graph.invoke({ messages: [{role: user, content: user_input}], remaining_steps: 8, }) final_answer result[messages][-1].content print(Agent:, final_answer) if __name__ __main__: main()4.3 跑通后的三个优化方向这个最小实现跑通之后你有三个优先级很高的优化方向。第一个是把记忆加进来。现在的实现里每次 invoke 都是独立的线程退出就丢了上下文。你可以把 messages 持久化到 Redis 或者 SQLite下次启动时读回最近几轮再让模型把更早的内容做摘要。这对应七要素里的记忆系统。第二个是给工具参数加强校验。现在模型返回非法参数时代码会直接抛异常中止循环。你应该在 tools_node 里先做 JSON Schema 校验不合法就让模型重试。实际生产里这一步能减少至少三成的诡异故障。第三个是加评测集。建一个 tests/eval_set.json里面放十条用户指令和期望的工具调用序列每次改完提示词就跑一遍确保没有破坏已有能力。常见问题与排查技巧实录最后这部分是实战中的高频问题每一个我都亲眼见过或者亲手修过。按“症状—原因—解决办法”整理成表方便你遇到问题时直接查。5.1 Agent 高频故障速查表症状常见原因排查与解决模型反复调用同一工具陷入死循环缺少迭代步数上限工具结果让模型产生了误解设置 remaining_steps 上限检查工具返回结果是否清晰必要时给结果加一条“已成功/已失败”的判定字段模型该调用工具时不调用工具描述模糊模型能力不足以理解复杂指令重写工具描述明确触发场景和触发条件换更强的模型或换一个更擅长工具调用的系列工具返回结果很长token 消耗暴涨没有对工具输出做截断工具节点里限制返回给模型的字符数把大数据量的查询拆成“先确认数量再分批取详情”模型连续跟用户确认“你确定吗”系统提示词里没有明确约束模型不确定性太高在系统提示词里写明“能查就查不要反复确认”降低模型温度检查工具定义是否覆盖了所有必要参数——如果每次都要追问才能凑齐参数不如让工具支持默认参数兜底多工具场景下总是选错工具工具签名的描述太接近工具数量太多拉大不同工具描述的文字差异按业务域对工具分组让模型先选组再选工具必要时升级为多 Agent各 Agent 只挂一组工具任务执行到一半模型忘了最初目标上下文过长注意力分散缺少目标追踪用工作记忆保存“任务目标”字段每一步推理时都放到上下文最前部必要时每几步总结一次当前进度生产环境偶发超时Agent 循环次数多单次执行时间不可控给每一步超时设置上限整个任务设置看门狗优化模型选择比重试更快的通道考虑用任务化接口替代同步请求避免用户长时间阻塞5.2 排查思路一条完整的止血路径遇上一个诡异 bug不要零敲碎打地试提示词。我尝试过很多种方式最有效的是下面这条路径第一步复现并固定输入。把触发问题的用户输入原样记录下来。第二步回放全链路日志。看每一步模型输出了什么 thought、调用了哪个工具、工具返回了什么结果。这一步能定位问题是出在模型推理、工具执行还是状态管理。第三步做局部模拟。把模型输出的内容手动替换成你应该期望的内容继续往下走看系统后面能不能恢复正常。这能区分“前面错了导致后面全错”还是“每一步都对但最后没收敛”。第四步改了之后一定要跑评测集。很多时候你发现修好了 A 场景却悄悄破坏了 B 场景。没有评测集的回护每一步修改都像是在打地鼠。这也是为什么我在决策点部分反复强调评测集的重要切身体会。5.3 三个压低故障率的防御性设计除了问题出现之后的排查还有几个防御性设计能前置很多麻烦实测效果立竿见影。一是给模型“认错退路”。在系统提示词里加一句“如果你发现自己一直重复某个操作或者连续三次没有进展直接告诉用户你需要更多信息或建议换一种方式”。这相当于给死循环装了一个逃生门可以省掉你半夜爬起来杀进程的时间。二是给工具增加“副作用声明”。在工具描述里注明这个工具是否只是查询还是会产生写入比如“此操作会向用户发送通知”模型在决定调用之前就会多一层判断并且会在最终回答里告诉用户“我已为你保存了备忘录”之类的结果反馈。这个设计可以减少用户困惑和误操作。三是把危险动作做成显式确认。凡是涉及支付、删除、发送消息这类操作不要直接让模型调用。改成“模型先生成一个待确认请求由人工或前端确认后再执行”这就是经典的 human-in-the-loop 模式。Agent 的定位永远是辅助最终授权还是得握在人手里。这套从七要素到七个决策点的拆法跟网上很多讲 Agent 的文章出发点不同不追求把概念讲全只求把你把项目做出来还能上线。我见过太多项目死在过度设计上也见过死在没设计上。最后有一句话想送给准备上车的你先跑通一个不完美的 Agent再逐步把记忆、规划、评测这些模块加进去边跑边修正比什么都有效。等你跑完一个完整流程再回来看这七个要素、七个决策点你会有完全不同的体感——到那时候你自己就能判断哪些环节该加强、哪些可以继续砍掉了。
返回列表