一、当前架构与参考项目对比
1.1 当前实现(ERP-Agent)
核心文件:MemoryManager (backend/core/memory.py)
-
短期记忆:滑动窗口机制(window_size=100轮 = 200条消息)
-
持久化方式:JSON 文件存储(命名格式:{session_id}.json)
-
元数据管理:{session_id}.meta.json(包含标题、owner、时间戳等信息)
-
实体记忆:EntityMemory 模块(用于提取对话中的关键实体,如项目名、模块名等)
核心特点:
-
✅ 架构简单直接,易于理解和维护
-
✅ 支持关键实体提取,辅助对话理解
-
❌ 缺乏记忆压缩/摘要机制,无法保留早期对话信息
-
❌ 长对话场景下,滑动窗口会丢失早期上下文
-
❌ 无跨会话知识积累能力,会话间信息孤立
1.2 Nanobot 实现(参考项目)
核心文件:MemoryStore (nanobot/agent/memory.py)
-
长期记忆:MEMORY.md(结构化事实存储,持续更新)
-
历史日志:HISTORY.md(时间线式日志,支持grep搜索)
-
自动压缩:当消息token消耗超过预算时,通过LLM自动总结归档
-
容错机制:压缩失败3次后,直接归档原始消息
核心特点:
-
✅ 双层记忆架构(事实存储+时间线日志),分工明确
-
✅ 自动压缩机制,确保不丢失重要信息
-
✅ 历史日志可搜索,便于追溯对话过程
-
✅ 支持跨会话知识积累,实现长期记忆
-
❌ 实现复杂,需额外调用LLM,增加成本和复杂度
1.3 Claw-Code 实现(参考项目)
核心模块:Session Memory(Rust语言实现)
-
消息历史:完整保留所有消息,按token预算进行裁剪
-
项目上下文:整合Git状态、配置文件、指令文件等项目相关信息
-
状态跟踪:实时统计message_count、turns、token使用量等指标
-
配置加载:支持多层配置文件(项目级、用户级),适配不同场景
核心特点:
-
✅ 具备项目上下文感知能力,可关联Git、配置等外部信息
-
✅ 完善的Token预算管理,精准控制上下文规模
-
✅ 多层配置系统,适配不同使用场景
-
❌ 缺乏记忆压缩机制,长对话仍可能出现信息冗余
二、优化方案(分阶段实施)
阶段1:增强当前记忆系统(低成本,高收益)
1.1 添加 Token 预算管理
当前问题:仅按消息数量(100轮)裁剪上下文,未考虑消息实际token消耗,可能出现短消息未达数量上限但token超标的情况,或长消息未达数量却已超出LLM上下文窗口。
优化方案:在MemoryManager类中新增max_tokens参数,实现按token预算裁剪上下文,代码调整如下:
python
class MemoryManager:
def __init__(
self,
persist_dir: str = "./rag_data/memory",
window_size: int = 100,
max_tokens: int = 8000, # 新增:最大 token 预算
):
self.max_tokens = max_tokens
def _trim(self, session_id: str):
# 新增逻辑:计算当前上下文token总量,超过max_tokens时裁剪
# 优先保留最新消息,确保关键上下文不丢失
pass
实施收益:
-
实现更精确的上下文控制,适配LLM的上下文窗口限制
-
避免因长消息导致的token超标问题,提升对话稳定性
-
区分长消息和短消息,合理利用token预算,减少不必要的裁剪
1.2 添加会话摘要(Session Summary)
当前问题:滑动窗口机制会直接丢弃早期对话内容,导致LLM无法获取对话前期的关键信息,影响对话连贯性和准确性。
优化方案:在MemoryManager中新增会话摘要生成方法,基于规则提取早期对话关键信息,存入元数据文件,代码如下:
python
class MemoryManager:
def get_session_summary(self, session_id: str) -> str:
"""生成会话摘要(关键信息提取)"""
meta = self._read_meta(session_id)
# 如果已有摘要,直接返回,避免重复生成
if "summary" in meta:
return meta["summary"]
# 否则,从历史消息中提取关键信息(规则提取,无需LLM调用)
# 提取规则:用户核心需求、关键操作、重要结果、实体信息等
history = self.get_history(session_id)
summary = self._extract_key_info(history)
# 将摘要存入元数据,持久化保存
meta["summary"] = summary
self._write_meta(session_id, meta)
return summary
使用场景:在系统提示词中注入会话摘要,帮助LLM理解对话背景,代码示例如下:
# 在系统提示词中注入会话摘要 summary = memory.get_session_summary(session_id) if summary: system_prompt += f"\n\n## 会话背景\n{summary}\n"
实施收益:
-
保留早期对话的关键信息,避免因滑动窗口裁剪导致的信息丢失
-
帮助LLM快速掌握对话背景,提升回复的准确性和连贯性
-
采用规则提取方式,无需额外调用LLM,成本低、效率高
1.3 增强实体记忆(EntityMemory)
当前问题:实体记忆(EntityMemory)与主记忆(对话历史、摘要)独立存在,未实现联动,导致LLM无法同时获取实体信息和对话上下文,影响对话理解能力。
优化方案:新增统一的上下文生成接口,整合会话摘要、实体记忆和操作历史,为LLM提供完整的上下文信息,代码如下:
python
class MemoryManager:
def get_context_for_llm(self, session_id: str) -> str:
"""生成完整的上下文信息(摘要 + 实体 + 近期对话)"""
parts = []
# 1. 会话摘要(早期关键信息)
summary = self.get_session_summary(session_id)
if summary:
parts.append(f"## 会话背景\n{summary}")
# 2. 实体记忆(关键实体信息)
entity_memory = self.get_entity_memory(session_id)
if entity_memory:
parts.append(f"## 关键实体\n{entity_memory}")
# 3. 近期对话(滑动窗口内的最新消息)
recent_history = self.get_recent_history(session_id)
if recent_history:
parts.append(f"## 近期对话\n{recent_history}")
# 拼接所有部分,返回完整上下文
return "\n\n".join(parts) if parts else ""
实施收益:
-
提供统一的上下文接口,简化LLM调用逻辑
-
整合摘要、实体、近期对话,为LLM提供更完整的对话上下文
-
强化实体信息的利用,提升LLM对业务场景(如ERP查询)的理解能力
阶段2:借鉴 Nanobot 的双层记忆(中等成本)
2.1 添加 MEMORY.md(长期事实)与 HISTORY.md(时间线日志)
设计方案:调整记忆存储目录结构,新增长期事实文件和时间线日志文件,实现短期记忆与长期记忆的分离存储,目录结构如下:
python
rag_data/memory/{session_id}/
├── messages.json # 当前实现(短期记忆,滑动窗口内消息)
├── messages.meta.json # 元数据(含会话摘要、owner、时间戳等)
├── MEMORY.md # 新增:长期事实(结构化存储关键信息)
└── HISTORY.md # 新增:时间线日志(可搜索,记录完整对话轨迹)
MEMORY.md 示例:
python
# 会话记忆:ERP 查询助手
## 用户偏好
- 喜欢以表格形式展示查询结果
- 关注组织 ID 86 的相关数据
## 已知数据库信息
- 主要使用 APPS schema
- 常用表:HR_OPERATING_UNITS(组织表)
- 连接信息:APPS / app_3hincerp / HEHE_SIT / Normal
## 关键操作记录
- 已查询组织 ID 86 的基本信息,结果为:NAME=XX公司,ORGANIZATION_ID=86
- 已调用知识库检索,获取 ERP 组织管理相关文档3份
HISTORY.md 示例:
# 会话历史日志 [2026-04-14 17:10] 用户查询组织 ID 86 的信息 - 调用工具:search_knowledge_base - 检索到 3 个文档 - 调用工具:query_oracle_data - SQL: SELECT NAME, ORGANIZATION_ID FROM APPS.HR_OPERATING_UNITS WHERE ORGANIZATION_ID = 86 - 结果:1 行数据(NAME=XX公司,ORGANIZATION_ID=86) [2026-04-14 17:15] 用户要求以表格形式展示上述结果 - 响应:生成表格展示查询结果,用户确认无误 [2026-04-14 17:20] 用户询问该组织的关联数据表 - 调用工具:query_oracle_metadata - 检索到关联表:HR_EMPLOYEES、HR_DEPARTMENTS - 响应:返回关联表信息及简要说明
2.2 自动压缩机制(可选,暂缓实施)
触发条件:满足以下任一条件时,触发记忆压缩:
-
消息数超过200条
-
当前上下文token消耗超过10000
压缩流程:
async def consolidate_memory(self, session_id: str): """将旧消息压缩到 MEMORY.md,释放短期记忆空间""" history = self.get_history(session_id) # 1. 取出最早的 50 条消息(可配置),作为压缩对象 to_consolidate = history[:50] # 2. 调用 LLM 提取关键信息,更新到 MEMORY.md prompt = f""" 分析以下对话内容,提取关键信息并更新到结构化事实中,要求: 1. 保留用户核心需求、关键操作、重要结果 2. 补充新的实体信息、配置信息、用户偏好 3. 语言简洁,结构化呈现(分章节、分点) 4. 不保留冗余的对话交互细节 对话内容: {to_consolidate} """ # 调用LLM生成压缩后的关键信息 consolidated_info = await llm_client.generate(prompt) # 3. 将压缩信息追加到 MEMORY.md self._append_to_memory_md(session_id, consolidated_info) # 4. 删除已压缩的旧消息,释放短期记忆空间 self._delete_history(session_id, to_consolidate) # 5. 容错处理:若压缩失败3次,直接将原始消息归档到HISTORY.md pass
实施收益:
-
实现长对话支持,避免早期关键信息丢失
-
支持跨会话知识积累,后续会话可复用历史关键信息
-
时间线日志可搜索,便于管理员追溯对话过程、排查问题
阶段3:借鉴 Claw-Code 的项目上下文(高级,可选)
3.1 项目上下文感知
设计方案:新增ProjectContext类,整合项目相关的上下文信息(Git状态、配置文件、Oracle连接历史等),为LLM提供更全面的业务场景信息,代码如下:
class ProjectContext: """项目上下文管理,整合项目相关的外部信息""" def __init__(self, workspace: Path): self.workspace = workspace # 项目工作目录 self.git_context = self._get_git_context() # Git状态信息 self.config_context = self._get_config_context() # 配置文件信息 self.db_context = self._get_db_context() # 数据库连接历史 def _get_git_context(self) -> str: """获取Git状态上下文(分支、提交记录、未提交修改等)""" # 调用git命令获取当前分支、最近提交信息等 pass def _get_config_context(self) -> str: """获取项目配置上下文(项目级、用户级配置)""" # 读取多层配置文件,提取关键配置信息(如ERP系统地址、端口等) pass def _get_db_context(self) -> str: """获取数据库连接上下文(历史连接信息、常用表等)""" # 从记忆系统中提取Oracle连接历史、常用表信息等 pass def get_context(self) -> str: """获取完整的项目上下文,用于注入系统提示词""" parts = [] if self.git_context: parts.append(f"## Git 项目状态\n{self.git_context}") if self.config_context: parts.append(f"## 项目配置信息\n{self.config_context}") if self.db_context: parts.append(f"## 数据库上下文\n{self.db_context}") return "\n\n".join(parts) if parts else ""
使用方式:在系统提示词中注入项目上下文,提升LLM对业务场景的感知能力:
# 在系统提示词中注入项目上下文 project_ctx = ProjectContext(workspace).get_context() system_prompt += f"\n\n{project_ctx}\n"
实施收益:
-
实现更智能的上下文感知,LLM可获取项目相关的外部信息
-
减少用户重复输入配置信息(如Oracle连接信息),提升交互效率
-
适配ERP业务场景,帮助LLM更好地理解项目相关的查询和操作需求
三、推荐实施顺序(4周规划)
第1周:阶段1.1 + 1.2 + 1.3(立即可做,低成本高收益)
-
✅ 完成Token预算管理功能开发与测试
-
✅ 实现会话摘要生成(规则提取方式),并集成到元数据管理
-
✅ 开发统一上下文接口,实现摘要、实体记忆与近期对话的联动
预期收益:快速解决当前核心问题,实现上下文的精准控制和早期信息保留,无需额外成本,提升对话稳定性和准确性。
第2-3周:阶段2.1(需要测试,中等成本)
-
✅ 调整记忆存储目录结构,新增MEMORY.md和HISTORY.md文件
-
✅ 实现手动压缩功能(管理员触发),将旧消息关键信息归档到MEMORY.md
-
⏸️ 自动压缩功能暂缓实施(需额外LLM调用,成本高且需容错设计)
预期收益:实现长对话支持和跨会话知识积累,历史日志可搜索,便于问题追溯和知识复用。
第4周:阶段3.1(可选,高级优化)
-
✅ 开发ProjectContext类,实现Git状态、项目配置的感知
-
✅ 整合Oracle连接历史、常用表信息,完善数据库上下文
-
✅ 将项目上下文注入系统提示词,优化LLM业务场景理解能力
预期收益:进一步提升ERP-Agent的智能化水平,减少重复配置,适配更复杂的业务场景。
四、核心建议
优先级1:Token 预算管理(必做)
当前按消息数量裁剪上下文的方式不够精确,易导致token超标或信息浪费,改为按token预算裁剪是解决长对话稳定性问题的核心,开发成本低、收益高,必须优先实施。
优先级2:会话摘要(推荐)
采用规则提取方式生成会话摘要,无需额外调用LLM,可有效保留早期对话关键信息,帮助LLM理解对话背景,提升回复准确性,是低成本高收益的优化点,推荐紧随Token预算管理实施。
优先级3:双层记忆(可选)
适合长期使用、需要跨会话知识积累的场景(如长期ERP查询助手),但需要额外的开发和测试成本,建议在阶段1验证效果后,根据实际业务需求决定是否实施。
不推荐:自动压缩(暂缓)
自动压缩需要额外调用LLM,增加成本和系统复杂度,且存在压缩失败的风险,需设计完善的容错机制。建议在业务场景确实需要长对话自动管理时,再考虑实施。
总结:建议优先实施阶段1的优化内容,快速解决当前核心问题、验证效果;后续根据业务需求,逐步推进阶段2和阶段3的优化,平衡开发成本与业务收益。