ARTICLE DETAIL

资讯详情

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

AI Agent核心三件套:记忆、推理与决策的工程实践

AI Agent核心三件套:记忆、推理与决策的工程实践 开头如果你之前一直在做传统的后端或全栈开发突然被喊去研究AI Agent那种感觉我太熟了。刚接触这个词的时候我花了好几天搞清楚它到底比普通LLM调用多了什么因为当时网上一堆资料要么玄学要么碎片真正讲透的少。等到自己真正上手做了一个能自主规划任务、调用工具、反复试错的Agent之后才发现核心就三件事记忆系统、推理链路、决策机制。把这三块拆明白Agent就不再是黑盒而是你手上一条清晰的生产线。这篇文章是我从传统开发转型到AI Agent研发的实操记录不会跟你聊那种“AI改变世界”的空话只讲记忆系统怎么设计、推理链路怎么串、决策机制怎么落地还会附带我在实践中踩过的坑和总结出来的排查经验。适合三种人看打算从业务开发转Agent方向的工程师、正在做Agent架构选型或技术方案的技术负责人以及被“Agent开发”这个词吸引但对内部原理一头雾水的新手。读完不敢说你立刻能写出生产级框架但至少心里那根“从哪下手”的弦能绷准。1. Agent到底是什么一次把概念抠清楚1.1 LLM、AI模型和Agent的区别先解决一个最基础也最容易混的问题常说的DeepSeek到底属于哪一层我个人的理解是——DeepSeek这类模型属于LLM大语言模型也就是那个“大脑CPU”。你给它一句话它根据训练学到的概率分布生成下一段最可能合理的文字。但它本身没有“主动做事”的能力不会自己去看时间、不会帮你查天气、不会连续保存你上一次偏好除非你把它封装在某种工程结构里每次手工把状态塞给它。所以我把这层关系想成AI模型是发动机LLM是涡轮增压版发动机而Agent是一辆能认路、能自己决定踩油门还是刹车的车。发动机再强没有车身、轮子、方向盘和一套驾驶逻辑它哪儿也去不了。Agent就是那个把发动机装进整车、并配上“自动驾驶逻辑”的完整系统。那这个“整车”由什么组成我按自己工程上的理解拆成五块感知模块接收用户输入和外部反馈、规划模块把目标拆成步骤、记忆模块保存对话上下文和长期知识、工具调用模块对接API、代码执行器、数据库等、行动执行模块把最终结果输出或落地。这五块里最容易被低估的就是记忆因为很多初版Agent只把“聊天上下文”当记忆远没到系统设计的程度。1.2 Agent的组成结构一个典型的闭环我画过一张特别土但特别有用的示意用户输入 → 感知理解 → 查记忆取相关上下文 → 推理规划结合当前状态想步骤 → 决策选工具或直接回答 → 执行 → 写回记忆 → 输出结果。这其实是一个循环不是一次性的。第一次跑这种闭环的时候我踩了一个特别典型的坑以为Agent只要能“多轮对话”就算有记忆。后来发现真正的记忆是跨任务、跨会话、跨模态的。比如用户上周让Agent分析过某份财务报表今天问“跟上一次比有哪些变化”如果Agent没有高效的记忆系统去检索到上周的上下文它就只能装作失忆。后来我把记忆拆成了工作记忆、短期记忆、长期记忆三层来设计这个问题才算真正解决。后面我会专门开一章讲。1.3 为什么记忆推理决策是核心三件套如果只让我用一句话总结Agent架构的核心Agent 记忆系统 推理链路 决策机制。为什么不是感知和工具因为感知和工具是“输入/输出设备”相对标准化而记忆、推理、决策决定了Agent的“智能上限”。把同样的LLM接入两套不同的记忆、推理、决策设计产出的效果天差地别。举个例子你给两个Agent同一个任务调研一下某行业近三个月的公开招标信息写一份摘要。Agent A没有记忆设计每次调用都是裸上下文Agent B有记忆且能主动查询历史记录。B会先检索记忆发现用户上次关注过A类项目于是自动调整关键词权重。同样是调研任务B产出的东西更贴合需求。这就是记忆推理决策组合发力的结果。2. 记忆系统Agent怎么“记住你说的”2.1 记忆分层的设计思路工作记忆、短期记忆、长期记忆我在早期做Agent时直接把整段对话历史塞进提示词结果两个问题特别明显token消耗爆炸而且塞入太多无关信息后模型输出质量急剧下降。后来参考认知科学的分层方法把记忆拆成三类工作记忆当前任务进行中需要临时引用的内容相当于代码里的局部变量。短期记忆当前会话窗口里的对话记录相当于一次请求中的上下文一般用滑动窗口或摘要方式管理。长期记忆离线存储的用户偏好、历史任务结论、领域知识相当于数据库或向量库跨会话持久化。这样分层以后设计Agent就顺多了工作记忆不进token短期记忆控制长度长期记忆按需检索。实际实现时短期记忆我用一个队列维护最近N轮对话并在接近窗口上限时触发一次摘要长期记忆则是写入向量库同时保留结构化字段比如用户ID、会话ID、任务类型、时间戳做过滤。2.2 向量检索与记忆召回怎么快速找到相关内容长期记忆存储我用的是向量库。核心流程就是把文本拆成chunk → 用embedding模型转成向量 → 存入向量库 → 查询时也转成向量做相似度检索。这个过程里面最关键的是怎么拆chunk。一开始我按固定字符长度1000个字符硬切结果经常切断语义检索出来一堆废话。后来改成按段落和语义边界来切比如先按“标题、换行、句号”分层再拼接效果好了很多。操作上我记得一次实际调优同样的3000条历史记录用固定长度切分时用户问“上次那个项目的费用预算是多少”召回正确率只有六成左右。改成按语义段落切并给每个chunk打了标签比如“费用”“时间”“人员”之后召回正确率到了八成多。为什么因为固定长度切分把“预算审批通过”这样完整语义的句子拆成了两半向量压根儿对不齐。这个经验后来成了我团队的固定规范先按结构化边界拆再按长度兜底标签宁可多打也不要少打。检索时我也不是只看相似度Top1而是会做一个两阶段召回。第一阶段用向量相似度取Top20候选第二阶段再用一个轻量级rerank比如用LLM对候选打个分选出Top3-5真正有用的内容。第二阶段很费token但能显著提升准确率尤其是在知识库很杂的场景下。2.3 记忆遗忘与更新不只有“记”还得会“忘”记忆系统的另一面是遗忘和更新。这个点很多人会忽略但它直接决定Agent会不会“越用越乱”。我早期做过一个版本长期记忆只增不改结果用户把收货地址从A改成B之后Agent每次还会把A当成备选搞得用户很火大。后来我设计了记忆更新策略核心是给每条记忆加三个字段置信度、最后访问时间、冲突标识。当新信息和旧信息冲突时不直接覆盖旧的而是新增一条并标记冲突在下一次推理时让LLM根据“时间更近、来源更可靠”的原则去判断用哪条。另外定期清理低置信度且长期未访问的旧记忆避免向量库越涨越脏。这里有个小技巧更新记忆时不要把旧的物理删除而是逻辑标记为“过期”。因为有一些看似过期的信息比如用户去年提过某个偏好可能在特殊场景下仍有价值。用逻辑标记既能保证Agent不引用过期信息又保留了回溯能力。2.4 实操一套可落地的记忆管理模块我把我现在常用的一套记忆管理方案整理一下代码是伪代码但结构可以直接落地class MemoryManager: def __init__(self, vector_store, llm, max_short_turns10): self.vector_store vector_store self.llm llm self.short_memory deque(maxlenmax_short_turns) self.working_memory {} def add_short_term(self, role, content): self.short_memory.append({role: role, content: content}) if len(self.short_memory) self.short_memory.maxlen: self.compress_short_term() def compress_short_term(self): old_turns list(self.short_memory) summary self.llm.compress(old_turns) # 让LLM产出摘要 self.short_memory.clear() self.short_memory.append({role: system, content: f[历史摘要] {summary}}) self.save_long_term(summary, memory_typesession_summary) def search_long_term(self, query, top_k5): candidates self.vector_store.search(query, top_ktop_k * 4) reranked self.rerank(query, candidates)[:top_k] return reranked def save_long_term(self, content, memory_type, user_id, metadataNone): chunks self.semantic_chunking(content) for chunk in chunks: self.vector_store.insert( textchunk, metadata{type: memory_type, user_id: user_id, time: now(), **metadata} ) self.consistency_check(user_id) # 冲突检测这套模块里最关键的是semantic_chunking和consistency_check。前者做语义切分后者检查新记忆是否与旧记忆冲突并打标记。我建议你在自己的项目里至少先实现这两块其余部分都可以逐步增强。3. 推理链路Agent的“思考”是怎么串起来的3.1 推理链路到底是什么推理链路是Agent在处理一个任务时从收到输入到产出动作之间的一系列中间思考步骤。你问一个Agent“我要不要买这个股票”它先想到“需要查行情→需要看财报→需要对比历史数据→再给建议”这就是一条推理链路。没有推理链路的Agent就像一个不动脑子直接开干的新人有推理链路的Agent至少会先列个计划。最开始我做Agent只依赖模型“自由发挥”发现它经常跳过关键步骤比如直接给结论不查数据。后来我把推理链路拆成“规划-执行-反思”三段式才稳定下来。这里我顺便说一句不要以为推理链路不重要也不要以为它只在任务复杂时才有用。就算是回答“今天天气怎么样”链路里也有一个看似不起眼的决策要不要查实时数据还是直接用模型内置知识回答这个决策就是推理的一部分。3.2 主流推理模式CoT、ReAct、Plan-and-Execute怎么选业界常见的推理模式我按从简到繁排个序CoTChain of Thought让模型把推理过程写出来再做最终回答。本质上是把“思考的文字化”。适合那些需要逻辑推导、但不需要外部交互的问答场景。ReActReason Act让模型交替进行Reason推理和Act行动比如调一个工具并根据行动结果继续推理。这是目前最主流的Agent推理框架之一大多数开源Agent项目都在用。Plan-and-Execute先生成一份完整计划Plan再去逐步执行Execute执行过程中允许修正计划。这种模式适合任务周期长、步骤明确的工作流。我的选择经验是如果任务只是问答用CoT就够你甚至不需要引入复杂度如果任务中间要查资料、调API且步骤不固定用ReAct如果任务有明确阶段比如“先爬数据→再清洗→再建模→再出报告”用Plan-and-Execute。还要说明一点ReAct和Plan-and-Execute还可以混合比如大计划用Plan单步执行时用ReAct这样兼顾全局稳定性和局部灵活性。3.3 实操一个带自我反思的推理链路示例下面我用一个具体场景演示一下推理链路怎么设计。场景用户问Agent“帮我分析一下今天要不要带伞”。第1步感知用户输入“今天要不要带伞”Agent判断这是一个天气查询建议类任务。第2步规划Agent计划先定位用户城市再查天气接口再看降水概率最后给建议。第3步执行调用城市定位API、天气API拿到温度、降水概率、风力等数据。第4步反思Agent检查拿到的数据中“降水概率”是否存在如果接口返回异常或缺失就重新调用或换数据源。第5步决策根据降水概率50%则建议带伞否则不带。第6步输出把建议表达出来。这里面的“反思”环节非常关键我会让Agent在每次执行完动作后做一个信息完整性检查。比如判断“我要的数据是否拿到了”“中间是否出现了错误”如果没拿到Agent有两条路再次尝试或换一种工具。这就是推理链路的自我纠错能力。实际写成代码大致是# 伪代码演示ReAct循环 def run_agent(task): messages seed(task) # 初始消息 for step in range(MAX_STEPS): thought llm_call(messages, promptthink step by step) if thought.action finish: return thought.result observation execute_tool(thought.action) messages.append(observation) return 达到了最大步数任务未完成这是一个极简的ReAct循环但它足够说明问题每次迭代都是一轮“思考→行动→观察”。你们在实现时一定要设置MAX_STEPS上限不然模型可能无限循环。我之前没设上限时遇到过Agent为了查一个问题连续调用十几次工具的情况既费钱又费时间。4. 决策机制Agent如何决定“下一步干什么”4.1 决策机制的两个层次选路径与选动作决策跟推理是连在一块的推理负责“想清楚”决策负责“拍板”。我习惯拆成两层来看。第一层是路径决策现在应该继续当前做法还是换一种方案第二层是动作决策下一步具体调用哪个工具、给什么参数、要不要直接回答用户好多人只写一层尤其只写“工具调用”这一层却忽略了路径决策。结果就是Agent一旦陷入僵局就会死循环或者一条道走到黑。在企业级场景里路径决策尤其值钱。举个例子一个任务是要从PDF中抽取表格数据Agent第一次用某个PDF解析库失败如果只有动作决策它会反复尝试同一个库如果有路径决策它会判断“当前解析库不兼容该PDF格式换成OCR方案”这才是真正的智能化。4.2 工具选择的评分逻辑不是所有可调用工具都值得调我早期把工具列表全部塞进提示词让模型自己选结果模型经常选错。后来改成给每个工具写清楚“工具名、用途、输入参数、输出格式、适用条件、成本”并在决策前让模型先参考这个工具描述。这不是什么高深技巧但效果立竿见影。我还建过一个简单的工具选择评分逻辑每个工具在每轮决策中都有三个分数——匹配度是否匹配当前任务、成功率历史调用该工具的成功率预估、成本分时间成本和费用。让模型综合这三个维度打分再选分数最高的。不一定非要用复杂算法很多时候模型自己就能根据打分理由做出很好选择。下面我给出一个决策模块的伪代码def decide_next_action(task_state, available_tools): prompt build_decision_prompt(task_state, available_tools) # 返回JSON包含selected_tool和tool_input decision llm_call(prompt, response_formatjson) return parse_decision(decision)关键是把决策结果限定为“结构化JSON”而不是自由文本。这样后续代码可以稳定解析不容易出错。4.3 成本与可靠性的权衡什么时候调用LLM什么时候用规则我不建议把Agent的每一步都交给LLM决定很不划算。实际工程里能规则判断的就用规则只有规则覆盖不了的分支才交给LLM。比如“当前天气接口返回状态码是200还是500”这种判断写死就行了“根据返回内容判断今天适宜做什么活动”这种才值得交给LLM。我在生产项目里遵循一个“三级决策”策略第一级硬规则例如参数校验、权限判断、接口异常重试全部代码化不浪费token。第二级模板决策例如常见的分类问题用少量样本模板做few-shot让LLM做轻量分类。第三级深度推理例如开放式任务规划、多条件权衡才用完整推理链路。这套策略帮我省了大量成本。有一次我把一个Agent的LLM调用量下降了40%而任务完成率反而小幅提升原因就是很多“看起来需要智能”的地方其实用规则更准还不会出现模型偶尔抽风的问题。4.4 实操决策机制的兜底策略决策机制一定会遇到模型乱选工具的情况。我建议在代码层面加一个“兜底策略”无论模型选择了什么都要经过一个tool_guard模块做校验。这个模块负责确认参数必填项是否齐全、确认调用权限是否允许、确认该工具是否在当前场景下被禁用。校验不通过就直接拦截并返回错误原因给Agent让它重新选择。我在实践中踩过最典型的坑是模型想把“删除数据库”这种危险工具当普通工具调用幸好有tool_guard拦住了。所以建议各位凡是涉及写操作、删除操作、资金操作的工具必须加高危工具二次确认机制绝对不能完全信任模型的自主决策。5. 从传统开发到Agent研发的心法转型5.1 思维转变你写的不是代码是“可控的不确定性”传统开发追求确定性同样的输入必有同样的输出Agent开发追求“可容忍的不确定性”同样的输入可能输出不同结果但工程上要保证它在可接受范围内波动。这个思维转变对我来说是最难的。以前写接口我最怕“不可复现的bug”现在写Agent最怕“这个Agent今天正常明天抽风”。后来我想明白一个道理Agent工程本质上是在和概率做对抗。你要做的不是消除概率而是用工程手段收窄概率的方差。方法包括把关键逻辑用规则固定住给LLM更多结构化引导增加评估用例来回归等等。接受这个理念之后很多“玄学问题”都有了解法。5.2 测试与评估没有评估体系的Agent开发都是摸黑传统开发有单元测试、集成测试Agent开发同样必须有测试但要分两层一层是工程测试验证工具调用、参数传递、异常处理等代码逻辑是否正确另一层是效果评估验证Agent在给定任务上的产出质量是否达标。效果评估不能只看“回答得像不像”得定义具体的评分维度。我实际在用的评估指标有任务完成率、平均轮次是否在合理步数内完成、工具调用准确率调用了正确的工具吗、关键词命中率关键信息是否有输出、人工抽检通过率。其中“工具调用准确率”这个指标在Agent应用中比“回答好不好”更有工程意义因为工具调错了哪怕最终回答漂亮也是靠模型硬圆回来的。评估集怎么建我会把真实用户的历史问题收集起来挑出200到500条典型场景做成一个冒烟测试集。每次修改Agent的提示词或推理逻辑后先跑一遍集看指标有没有明显下降。这套流程虽然粗糙但能挡住80%的回归问题。5.3 可观测性设计Agent内部到底发生了什么传统开发出Bug打日志就行Agent出问题光看日志看不出来因为你不知道模型每一步是怎么想的。所以必须做“思考链日志”和“决策轨迹”的观测设计。我在每个Agent的关键节点都会埋点记录当前推理链、候选工具列表、决策结果、工具返回摘要、反思结果等。这样出问题时就能把Agent的“大脑活动”拉出来复盘。这个设计在排障时太重要了。有一次Agent在生成周报时总是漏掉“用户姓名”这一项我看日志才发现它一直在从“历史对话”里找姓名但对话里从未明确出现过。它只是“猜”了一个姓名却当成已获取信息。如果没有决策轨迹日志这种问题根本无从查起。现在我的排障流程永远是先看轨迹日志再定位是哪一环出了偏差。5.4 工程化落地从Demo到生产环境的建议Demo阶段怎么都能跑生产环境就不一样了。我强烈建议在Agent项目里引入这几个工程化模块限流与配额防止Agent失控调用API、重试与超时每个工具调用都要设超时、任务队列所有Agent任务丢进队列方便追溯和重放、人审机制对于高影响操作保留人工审批入口。还有一个容易被忽略的点异常降级。Agent调用大模型失败时不能直接把错误抛给用户要降级成“根据已有信息生成的确定回答”或者提示用户稍后再试。这种降级方案我在生产环境里用过很多次有效降低了对用户的负面体验。6. 常见问题与踩坑实录6.1 记忆污染植入错误上下文后Agent会“一本正经胡说”我最早遇到的问题是长期记忆里存了一条错误的用户偏好导致Agent每次都按错误偏好回答用户怎么纠正都改不回来。排查后发现那条错误记忆的置信度竟然很高因为写入时没有校验来源。后来我在写入记忆时强制加入“来源字段”比如来源用户主动声明、来源模型推断、来源工具执行结果。用户主动声明优先于模型推断这样“污染”会少很多。还有一个实操技巧当Agent根据记忆回答用户问题时输出里带一个明确的引用标记比如“根据你上次提到的XX”。这样用户在发现Agent记错时会主动纠正能形成一套反馈闭环。6.2 推理死循环Agent一直调工具怎么办死循环是Agent最常遇到的问题。我有一次收到告警某个Agent任务跑了30分钟还在执行一查日志发现它在“查快递信息-失败-重试-再次查询”之间来回打转。后来我在三个层面做了限制第一设定全局步数上限默认15步第二同一个工具连续调用失败超过3次直接禁掉该工具并切换备选方案第三加入“重复动作检测”若最近三步内出现过相同工具相同参数就强制打断并让Agent重新规划。这三板斧下来死循环问题基本绝迹。要记住Agent研发里你不仅要写好“做什么”更要写好“什么时候停下来”。6.3 决策失误模型因“上下文混淆”选了错误工具模型选错工具的场景我见过很多明明需要查实时天气却调用了一个文档搜索工具明明需要算数学公式却调用了翻译工具。根因通常是工具描述不清晰或者工具之间的边界模糊。解决方法是给每个工具写“什么时候该用什么时候不该用”的独立描述并在决策提示词里明确提醒“如果工具描述与当前任务不匹配不要强行选择。”这个方法很土但真的有效。我建议你们抽时间做一次工具描述重构把每个工具负责什么、绝对不负责什么写清楚模型的表现会立竿见影。6.4 常见问题速查表下面这张表是我整理出的高频问题、现象和推荐排查方向方便你快速定位问题现象可能原因排查与修复建议Agent反复尝试同一失败工具缺少失败计数与路径切换机制增加连续失败3次即禁止工具的逻辑记忆回答与上次事实矛盾记忆冲突未被检测或过期信息权重过高增加冲突检测按时间和来源调整记忆优先级任务提前收尾漏掉关键步骤推理链路缺少反思环节强制在输出结论前增加完整性自检同一问题不同回答波动大上下文或推理链路不够结构化用固定模板引导推理流程减少自由度工具调用参数乱填决策模块没有参数校验加tool_guard拦截参数格式不合法调用token成本过高短期记忆无限累积、过度使用LLM决策滑动窗口摘要压缩尽量用规则替代LLMAgent“编造”工具返回结果模型在没拿到真实结果时自行补齐在提示词中明确不允许假设工具返回加执行结果校验结尾写了这么多其实核心就是一句话Agent开发不神秘但要沉下心把记忆、推理、决策这三个齿轮咬合好。我个人的体会是这三者没有谁比谁更重要它们是一个闭环缺一个Agent就“不聪明”或者“不可控”。如果你正准备转型或者正在做Agent项目建议先从一个小场景入手把记忆管理模块、ReAct循环和工具决策模块各写一版然后逐步加反思、评估和观测。不要刚开始就追求大而全的框架那样只会被复杂度吞掉。最后再分享一个小技巧也是我现在项目的标配给Agent写一段“行为规范”提示词把“什么时候停止、什么时候反问、什么时候道歉、什么时候升级给人”都写清楚。很多Agent表现不稳定的问题其实是行为边界没定义好你在调试时多花半小时把行为规范调好后面会省出一整天。希望这篇记录对你有用。如果你也在做Agent开发欢迎带着你的踩坑故事来交流——毕竟这行最大的共识就是大家都还在路上。
返回列表