智能体持久化自主行为:从对话记忆到任务闭环的工程实践
智能体正在从“大模型对话插件”走向真正能独立完成任务的软件实体。最近在智能体项目落地过程中很多团队都遇到同一个问题智能体本身能力很强但会话一旦变长它就开始“失忆”隔天再跑任务又得像第一次一样把所有背景重新交代一遍。这种状态缺失、行为碎片化的问题正是“持久化”与“自主行为”没有打通造成的。这篇文章围绕“智能体涌现出持久化自主行为”这一主题展开。先解释智能体、持久化、自主行为分别是什么再拆解持久化自主行为的核心机制然后结合 Dify、Coze 等平台和开源框架分析当下常见的实现路径最后给出一个可运行的 Python 示例演示如何让智能体在不丢失记忆的前提下持续执行任务。适合正在学习 Agent 开发、搭建企业级智能体或者做 AI 应用落地的开发者阅读。1. 智能体的基础概念先回答三个问题1.1 什么是智能体智能体Agent可以简单理解为一个“能自己想办法完成任务的 AI 程序”。它不只回答你“今天天气怎么样”还能拆分任务、调用工具、检查结果、反复尝试最终把一件更复杂的事情做完。在学术上智能体通常被描述为在某个环境中通过感知获取信息通过决策选择行动再通过行动影响环境如此循环往复的自主实体。但在工程实践中我们很少去扣这个定义。大家更关心的是它能不能记住上下文、能不能调数据库、能不能调接口、能不能按计划执行多步操作。换句话说智能体和传统问答机器人的最大区别不是“模型更强”而是它拥有了行动能力。它能从“聊天”走向“做事”。1.2 持久化记忆与状态“持久化”这个词来自计算机体系结构意思是把数据保存到断电后不会丢失的存储介质中例如磁盘、数据库。在智能体场景下持久化更直白的解释是让智能体拥有长期记忆和可恢复的状态。过去很多智能体是无状态的。用户问一句模型答一句会话一关前面的对话内容全部消失。无状态设计在简单问答场景没有问题但一旦涉及多轮任务、用户偏好、历史决策、跨天执行就会非常痛苦。举个例子用户告诉智能体“以后所有周报都按市场部的模板格式整理”。智能体回答“好的”。第二天用户说“继续昨天的周报任务”。智能体却完全不知道模板是什么也不知道昨天的任务进度到哪里。这就是没有持久化的问题。智能体没有把用户偏好、任务进度、历史记录保存下来所以无法形成连续的行为基线。1.3 自主行为从单轮问答到任务闭环“自主行为”是指智能体在无人干预的情况下根据目标、环境信息和已有记忆自行规划动作并执行。自主行为不是凭空出现的它依赖三个条件确定的目标智能体知道要完成什么。可用的工具智能体有办法影响外部环境。有效的反馈机制智能体能判断动作是否完成、结果是否正确。当你把持久化能力和自主行为结合在一起时有趣的事情就发生了。智能体不再是“问一句答一句”的工具而是能在一个长期目标下持续工作并在一次次执行中积累经验。随着状态不断沉淀智能体表现出的行为会越来越像一个独立的“数字员工”。这种系统层面的表现就是很多文章里提到的“涌现”。它并不是玄学而是多个机制叠加后的必然结果。2. 从无状态到有状态智能体演变的关键一步2.1 无状态智能体的典型问题先来看一个没有持久化的智能体在真实业务中会遇到什么问题。假设你开发了一个智能客服 Agent它能查询订单状态、处理退款申请、记录客诉。第一版比较简单每次用户提问都会把当前问题发给大模型模型只根据当前输入回答。上线后你会很快发现这些问题多轮信息断裂用户说“我的订单怎么还没到”智能体回答后用户接着问“那退货运费谁承担”智能体已经搞不清“那”指代的是哪个订单。短期记忆与长期记忆缺失用户一周前投诉过物流今天再问智能体完全不知道这件事。任务无法续跑智能体在生成退款单的过程中断线恢复后无法从断点继续只能重新开始。最终表现就是用户觉得你做的智能体很“蠢”。其实模型能力没问题问题出在缺少状态层。2.2 状态信息的分类要设计持久化方案首先要搞清楚智能体需要保存哪些状态。我把常见的状态数据分成四类数据类型典型示例存储建议会话上下文当前对话的消息列表、临时变量Redis、内存、会话表用户长期偏好用户语言、格式要求、常用信息数据库用户表、Key-Value 存储任务进度当前执行到第几步、已完成哪些子任务数据库任务表、状态机外部资源凭证数据库连接、API Token、账号信息密钥管理服务严禁明文存储不同状态数据的生命周期不同。会话上下文可能只需要保留几小时用户偏好需要保留几个月甚至永久任务进度需要根据任务类型灵活配置凭证则要放在安全边界内。2.3 持久化如何催生“自主行为”当状态可以被保存和恢复智能体的行为模式会发生质变。第一目标可以跨会话延续。用户今天创建了一个“每周五自动汇总本周数据”的任务明天、下周、下个月这个目标依然存在。智能体不需要每次重新理解目标只需要按计划执行。第二执行可以从断点继续。任务执行到一半API 超时了、网络断了、模型报错了恢复后智能体可以从最近一个已完成步骤继续而不是从零开始。第三经验可以积累。智能体今天发现某个工具的返回格式特殊它可以把处理方式写进记忆里下次遇到同样情况就不用再绕弯。这种“越用越顺手”的效果正是持久化带来的长期回报。所以持久化可以说是自主行为的“地基”。没有记忆的智能体只能在单轮对话里短暂地“聪明”有了持久化智能体才可能在长期任务中表现出真正的自主性。3. 持久化自主行为的四大核心机制3.1 记忆系统短时记忆与长期记忆记忆是持久化自主行为最基础的组成部分。在设计智能体记忆系统时通常会把记忆分为两层。短时记忆对应当前任务工作区通常是一次会话内或一个工作流内的临时状态。可以放在内存中用会话 ID 作为隔离维度。比如用户正在填写表单已经填了姓名和手机号这些数据放入短时记忆即可。长期记忆需要写入持久化存储。常见做法有将历史消息存入数据库每次请求时把最近 N 条取出来作为上下文。将用户偏好、业务规则、项目配置存成 Key-Value 或结构化字段。使用向量数据库保存“语义记忆”当用户提到相似问题时通过向量检索召回相关历史。在 Dify、Coze 这类低代码平台里知识库和变量其实就是长期记忆的落地形态。你可以把业务资料放进知识库把流程中需要共享的字段定义为全局变量。平台帮你处理了大部分存储细节你要做的是设计好变量作用域和数据更新时机。3.2 规划与反思自主性的来源有记忆只解决“记得住”智能体还要能“想清楚”。目前比较主流的方法是让大模型通过特定提示词结构完成“规划-执行-反思”循环。典型流程如下用户提出目标。智能体把目标拆解成多个子步骤。智能体依次执行子步骤每个步骤观察工具返回结果。如果某一步失败智能体分析原因并调整策略。全部子步骤完成后汇总输出最终答案。这就是 ReActReasoning and Acting思想的工程化实现。你不需要专门训练一个新模型只需要在提示词中要求模型先思考、再行动、再观察结果即可。自主行为不是“模型自己乱跑”而是在一套可控制的循环框架内由模型决定下一步动作。关键是设计好边界和终止条件这部分在第六章会专门展开。3.3 工具调用让智能体拥有“手”没有工具的智能体只能输出文本有了工具的智能体才能完成任务。工具Tool本质上是对外部能力的封装常见类型包括查数据库调用 HTTP API读写文件执行 shell 命令发送邮件操作第三方系统工具调用的难点不在于“怎么调”而在于“让模型正确地选择工具并传参”。工程上通常用 JSON Schema 描述工具签名模型根据用户请求生成对应参数再由代码执行实际调用。这里必须强调一个安全原则工具权限必须最小化。智能体能下调数据库的删除语句不代表你该给它这个权限。在开发阶段可以放开调试但进入生产环境一定要对工具做白名单、参数校验、操作审计尤其是涉及删除、覆盖、转账、发消息这类高风险动作时必须加入人工确认环节。3.4 多智能体协作中的状态传递当任务复杂到一定程度单个智能体可能搞不定。这时可以把任务拆给多个智能体协作比如一个负责数据查询一个负责内容生成一个负责最终审核。多智能体协作最大的坑就是状态同步。智能体 A 查到了数据但智能体 B 不知道结果 B 又查了一遍A 已经确认某个结论B 还在推翻。要解决这个问题通常需要引入共享状态层或消息总线用 Redis 做共享缓存让多个智能体都能读写同一份中间结果。用任务队列传递消息每个智能体只处理自己负责的一环。用数据库任务表记录整体进度每个智能体完成后更新状态。从我接触过的项目来看多智能体不是“越多越好”。每增加一个智能体状态管理和错误排查的复杂度都会翻倍。除非业务确实需要不同角色分工否则优先用“单智能体 工作流”的方式解决问题。4. 当下常见的实现路径4.1 低代码平台Dify、CozeDify 和 Coze 是目前国内开发者接触最多的两个智能体平台。Dify 偏向企业级应用开发比较强调工作流编排、知识库管理、API 接入和自部署能力。在 Dify 中你可以用可视化方式搭建 Agent 工作流设置变量、节点、工具调用和条件分支也可以把发布后的应用接回自己的业务系统。Coze扣子则更偏 Bot 生态和市场玩法适合快速搭建聊天机器人、插件化工具也支持多智能体模式。最近很多做流量和营销方向的开发者会在 Coze 上搭建追热点、视频脚本生成类的智能体。这类平台最大的价值是把门槛降下来了。不需要写太复杂的代码就可以完成记忆、知识库、工具调用等能力配置。但平台也有局限流程复杂后调试困难、自定义逻辑受平台规则限制、数据主权方面需要仔细评估。4.2 开源框架如果要更高的自由度可以基于开源框架自研智能体。常见梯队如下LangChain / LlamaIndex生态最成熟工具和文档丰富适合做研究、原型验证。AutoGPT / MetaGPT强调自动化任务分解和多角色协作适合实验性项目。Dify 社区版以低代码为主同时支持 API 和自定义插件。自研轻量框架直接基于 OpenAI 或其他大模型提供商的 API自己实现工具调用、记忆和任务循环。如果你只是想做内部工具或者想深入理解智能体原理我比较推荐自己动手写一个轻量实现。这个过程能帮你把“提示词、上下文、工具、记忆”之间的关系彻底想清楚。4.3 自研方案需要考虑的模块自研智能体并不是只写几个函数就行至少要包含以下模块模型接入层统一封装大模型 API方便替换服务商。记忆层负责读写短期和长期状态。工具层注册工具、校验参数、执行调用、返回结果。循环控制层实现“思考-行动-观察”的主循环管理最大步数和终止条件。日志和观测层记录每一步的输入输出方便定位问题。这几个模块并不复杂但非常考验工程组织能力。下一章我会用代码一步步演示一个最小实现。5. 动手实践搭建一个会“记住”的智能体5.1 场景设定为了直观演示“持久化”如何影响智能体行为我们搭一个简单的“任务提醒 用户偏好记忆”智能体。需求很简单用户告诉智能体自己的偏好比如“我喜欢在写方案前先列大纲”。下次用户再提到写方案时智能体要能回忆起这个偏好并主动按这个方式来执行。在这个示例中我们不用 LangChain直接用 Python 标准库 一个 OpenAI 兼容接口把核心逻辑完整展示出来。整个项目结构如下agent-demo/ ├── storage.py # 基于 JSON 的记忆存储 ├── sqlite_memory.py # 基于 SQLite 的状态存储 ├── agent.py # 智能体主程序 └── requirements.txt # 依赖说明5.2 基于 JSON 文件的记忆先写一个最基础的记忆类用于保存用户历史消息。这里使用 JSON 文件作为存储介质方便读者理解原理。# 文件路径agent-demo/storage.py import json import os from datetime import datetime class JSONMemory: 基于 JSON 文件的简易长期记忆。 def __init__(self, memory_filememory.json): self.memory_file memory_file self._init_file() def _init_file(self): if not os.path.exists(self.memory_file): self._write({}) def _write(self, data): with open(self.memory_file, w, encodingutf-8) as f: json.dump(data, f, ensure_asciiFalse, indent2) def _read(self): with open(self.memory_file, r, encodingutf-8) as f: return json.load(f) def save_message(self, user_id, role, content): 保存一条消息到用户的历史记录中。 data self._read() if user_id not in data: data[user_id] [] data[user_id].append({ role: role, content: content, time: datetime.now().isoformat() }) self._write(data) def get_history(self, user_id, limit10): 获取某个用户最近 limit 条历史消息。 data self._read() return data.get(user_id, [])[-limit:]这个类很直观_init_file在文件不存在时创建空数据。save_message按user_id隔离不同用户的数据。get_history返回最近 N 条消息用于拼装大模型上下文。JSON 存储适合学习和小型测试但不适合高并发和复杂查询。实际项目中通常要换数据库。5.3 用 SQLite 做结构化状态存储JSON 适合保存消息流但如果要记录“用户偏好、任务状态”这类结构化数据更推荐用 SQLite 或关系型数据库。下面用 SQLite 实现一个通用的用户状态存储。# 文件路径agent-demo/sqlite_memory.py import sqlite3 import json from datetime import datetime class SQLiteMemory: 基于 SQLite 的结构化状态存储。 def __init__(self, db_pathagent_memory.db): self.db_path db_path self._init_table() def _get_conn(self): conn sqlite3.connect(self.db_path) conn.row_factory sqlite3.Row return conn def _init_table(self): with self._get_conn() as conn: conn.execute( CREATE TABLE IF NOT EXISTS user_state ( user_id TEXT NOT NULL, key TEXT NOT NULL, value TEXT NOT NULL, updated_at TEXT NOT NULL, PRIMARY KEY (user_id, key) ) ) def set_state(self, user_id, key, value): 写入或更新某个用户的键值状态。 now datetime.now().isoformat() with self._get_conn() as conn: conn.execute( INSERT INTO user_state(user_id, key, value, updated_at) VALUES (?, ?, ?, ?) ON CONFLICT(user_id, key) DO UPDATE SET value excluded.value, updated_at excluded.updated_at , (user_id, key, json.dumps(value, ensure_asciiFalse), now)) def get_state(self, user_id, key): 读取某个用户指定键的状态。 with self._get_conn() as conn: row conn.execute( SELECT value FROM user_state WHERE user_id ? AND key ?, (user_id, key) ).fetchone() if row: return json.loads(row[value]) return None def clear_state(self, user_id): 清空某个用户的全部状态谨慎使用。 with self._get_conn() as conn: conn.execute( DELETE FROM user_state WHERE user_id ?, (user_id,) )这个实现有几个对生产有参考价值的点使用user_id key作为联合主键保证同一用户同一键只有一条记录。使用ON CONFLICT DO UPDATE避免“先查再写”的竞态问题。clear_state方法在真实业务中要加权限校验不能随意调用。5.4 接入大模型 API 并完成自主决策循环上面两个模块解决了“记忆”问题接下来解决“自主行为”问题。我们写一个通用的 LLM 调用函数和 ReAct 主循环。先封装一个 OpenAI 兼容接口的调用函数。注意不同服务商接口细节可能不同这里以常见兼容格式为例。# 文件路径agent-demo/agent.py import json import requests from storage import JSONMemory from sqlite_memory import SQLiteMemory def call_llm(messages, modelgpt-4o-mini, base_urlhttps://api.openai.com/v1, api_keysk-your-key): 调用 OpenAI 兼容接口。 response requests.post( f{base_url}/chat/completions, headers{ Authorization: fBearer {api_key}, Content-Type: application/json, }, json{ model: model, messages: messages, temperature: 0.2, }, timeout60 ) response.raise_for_status() data response.json() return data[choices][0][message][content]接下来定义一个简单的工具函数。这里以“获取当前日期”和“记录用户偏好”为例实际项目可以替换成天气、数据库查询、定时任务等工具。# 继续写入 agent.py from datetime import date TOOLS { get_current_date: { description: 获取今天的日期, handler: lambda: str(date.today()), }, remember_user_preference: { description: 记住用户的偏好设置参数格式: {\key\: \偏好名\, \value\: \偏好内容\}, handler: lambda params: 偏好已记录, }, } def build_system_prompt(): tool_desc \n.join( [f- {name}: {info[description]} for name, info in TOOLS.items()] ) return f你是一个有长期记忆的智能助手。 你可以使用以下工具 {tool_desc} 请按以下格式输出 Thought: 你的思考 Action: 工具名 Action Input: {{json 参数}} 当你认为任务完成时请只输出 Final Answer: 最终回答 注意如果用户告诉你任何偏好请先调用 remember_user_preference 记录偏好再回答用户。 现在写主循环。智能体会先取出历史记忆和历史偏好拼进上下文然后循环调用模型直到模型输出 Final Answer。# 继续写入 agent.py import re def run_agent(user_id, user_question, json_memory, sqlite_memory, max_steps5): # 读取历史消息与偏好 history json_memory.get_history(user_id, limit10) preference sqlite_memory.get_state(user_id, preference) messages [{role: system, content: build_system_prompt()}] if preference: messages.append({ role: system, content: f用户历史偏好{json.dumps(preference, ensure_asciiFalse)} }) for msg in history: messages.append({role: msg[role], content: msg[content]}) messages.append({role: user, content: user_question}) for step in range(max_steps): reply call_llm(messages) # 判断是否结束 if reply.strip().startswith(Final Answer:): final_answer reply.strip().replace(Final Answer:, ).strip() json_memory.save_message(user_id, user, user_question) json_memory.save_message(user_id, assistant, final_answer) return final_answer # 解析 Action 和 Action Input action_match re.search(rAction:\s*(.), reply) input_match re.search(rAction Input:\s*(\{.*\}), reply, re.S) if action_match and input_match: action_name action_match.group(1).strip() action_input json.loads(input_match.group(1).strip()) tool TOOLS.get(action_name) if not tool: observation f错误未知工具 {action_name} else: try: observation tool[handler](action_input) except Exception as e: observation f工具执行失败{e} # 把模型上一轮输出和观察结果追加到上下文 messages.append({role: assistant, content: reply}) messages.append({role: user, content: fObservation: {observation}}) else: # 模型没有正确输出 Action直接终止避免死循环 messages.append({role: assistant, content: reply}) messages.append({role: user, content: 请严格按指定格式输出。}) return 达到最大执行步数任务已中止。这段代码演示的是 ReAct 循环的最小实现流程如下从 JSON 记忆和历史状态中读取上下文。把系统和历史消息发给大模型。模型返回结果。如果结果以Final Answer开头保存对话并返回。如果结果包含Action执行对应工具把观察结果追加回上下文。循环直到结束或达到最大步数。在真实项目中你还需要处理模型 JSON 解析失败、工具超时、并发写冲突等问题。但在原理演示阶段这段代码已经能清楚展示“持久化 工具调用 自主循环”是如何工作的。6. 提示词与工具设计让自主行为可控6.1 ReAct 范式上一章的示例其实已经用到了 ReAct 范式。ReAct 的核心思想是让模型交替进行“推理Reason”和“行动Act”。Thought描述当前这一步的想法。Action决定调用哪个工具。Action Input传给工具的参数。Observation工具返回的结果。这种格式的好处是过程可视化。你可以在日志中看到智能体每一步在想什么、做什么、得到什么结果。一旦任务出错也能快速定位是理解问题还是工具问题。设计 ReAct 提示词时有两点容易踩坑格式样例要给完整。不要只写“请用指定格式”最好给出一个完整的示例包括 Thought、Action、Action Input、Observation 的往返过程。终止条件要明确。如果模型始终不输出 Final Answer循环会无限执行。所以一定要设置最大步数并在提示词中强调“确认任务完成后直接输出 Final Answer”。6.2 工具注册与参数校验工具不是你写好函数就能直接给模型用的。模型不知道你的函数长什么样它只知道你在提示词里写了什么。所以每新增一个工具都要做三件事写清楚功能描述。描述要具体到“什么时候该用这个工具”。定义参数 Schema。建议使用 JSON Schema 格式并让模型严格按 Schema 输出参数。在代码层校验参数。模型可能产生幻觉传入不存在的键、错误的类型。代码层一定要做防御性校验不能直接把模型输出塞进函数。示例def safe_call_tool(tool_name, params): tool TOOLS.get(tool_name) if not tool: return 错误未找到工具 # 参数校验这里简化处理 if not isinstance(params, dict): return 错误工具参数必须是 JSON 对象 try: return tool[handler](params) except Exception as e: return f工具执行失败{e}6.3 终止条件与人工确认自主行为越强越要重视“刹车机制”。在智能体设计里我建议至少设置三层控制控制层说明最大执行步数防止死循环通常设置为 5~10 步高风险操作确认删除、转账、发送、发布等操作必须经过人工确认超时与熔断单个工具调用超时后自动失败累计失败次数过多时停止整个任务在低代码平台中Dify 和 Coze 也提供了类似机制。比如可以设置节点超时、条件分支判断、人工审核节点。这些能力不要觉得多余生产环境里往往是它们救了项目。7. 常见问题与排查思路7.1 智能体“失忆”换了个会话就什么都不记得问题现象常见原因解决思路新会话无法回忆历史没有把历史记录写入持久化存储在对话结束时调用 save_message或通过平台变量保存有存储但读取不到user_id 不一致每次请求用了不同标识统一使用稳定的用户标识记忆混乱串用户数据没有按 user_id 隔离数据所有读取和写入都带上用户维度排查这类问题时先看存储层有没有数据再看读取逻辑有没有过滤条件。八成问题是出在“写进去了但没读出来”或“读出来但过滤条件不对”。7.2 智能体执行到一半就停或死循环问题现象常见原因解决思路执行几轮后自动停止达到 max_steps 上限提高步数上限或优化任务拆分粒度来回调用同一个工具模型没有收到有效 Observation检查工具返回内容是否太复杂试试精简返回格式模型输出格式不固定提示词缺少示例在提示词中补充完整 ReAct 示例7.3 工具调用报错问题现象常见原因解决思路模型传入不存在的参数参数 Schema 不明确完善工具描述和参数类型定义工具返回导致上下文过长工具结果太大对返回结果做截断或摘要权限校验失败Token 过期或权限不足检查凭证时效和角色授权范围特别注意涉及删除、覆盖、发消息、转账等操作时工具执行前一定要有参数校验和权限校验。工具权限要遵循最小化原则不要图省事给智能体一个超级管理员账号。8. 工程化建议从“能用”到“可靠”8.1 存储选型跑通 Demo 容易生产环境则是另一套逻辑。持久化存储选型建议如下低并发 / 内部工具SQLite 足够部署简单不需要额外运维。中高并发 / 多实例部署使用 PostgreSQL 或 MySQL注意连接池和索引设计。会话级临时状态Redis设置过期时间避免内存无限增长。非结构化知识 / 语义记忆向量数据库配合 Embedding 模型做相似度检索。8.2 安全边界与权限最小化智能体拥有工具调用能力后安全问题会明显放大。我的建议是所有工具调用必须经过统一的鉴权层不能直接透传。数据库连接使用只读账号除非业务确需写操作。文件操作限制在指定目录内禁止路径穿越。外部 API 的 Token 使用密钥管理服务保存不要写进代码或数据库明文。高风险操作加入人工确认节点。8.3 可观测性与审计日志智能体是“黑盒 行动力”的组合。如果没有日志出了问题会非常难排查。每个项目至少需要记录以下信息每次请求的输入输出。模型每一步的 Thought、Action、Action Input。工具调用的参数、返回结果、耗时。用户标识和会话标识。最终结果与终止原因。这些日志不仅用于排错也是改进提示词和调整工具设计的重要依据。9. 总结与下一步学习方向这篇文章从概念到实践把“智能体涌现出持久化自主行为”拆成了三个层面持久化解决记忆问题工具调用解决行动问题循环控制解决自主行为问题。没有记忆智能体只能做单轮问答没有工具智能体只能输出文字没有循环控制智能体无法独立完成多步任务。三者叠加才会表现出我们常说的“自主性”。如果你刚开始接触 Agent 开发建议先动手把第五章的代码跑通改一改记忆的保存逻辑、加一个自己的工具函数观察智能体的行为变化。然后再去尝试 Dify、Coze 这类平台把工作流搭建、知识库、人工确认这些能力用起来。继续往下走可以研究更细的主题比如提示词工程、向量检索、多智能体协作、任务规划算法以及 Harness Engineering 中所强调的“构建可控 AI 智能体系统工程实践”。智能体的能力边界还在快速扩展但底层的工程问题——如何记住、如何行动、如何控制——不会变。把这几个问题想清楚再做任何复杂的 AI 应用都会从容很多。