新闻详情

新闻详情

首页 / 资讯中心 / 详情

Hermes 三层记忆系统拆解:Mem0、Honcho 与 SQLite 的配置骨架

发布时间:2026/9/26 11:39:32来源:尧图网络
Hermes 三层记忆系统拆解:Mem0、Honcho 与 SQLite 的配置骨架
1. 为什么要把记忆拆成三层Hermes 的记忆系统最近讨论度很高我把它拆开看了一遍核心思路其实一句话别把所有记忆混在一起。用户偏好、历史对话、长期画像这三类信息的生命周期、检索方式、注入模型的位置完全不同硬塞进一个向量库最后就是召回噪声大、token 烧得快、还查不准。Hermes 的做法是分三层。第一层是内置记忆落在MEMORY.md和USER.md两个纯文本文件里存的是「用户喜欢中文回答」「这个项目测试要跑scripts/run_tests.sh」这种短小稳定的事实下一次 session 启动时作为 frozen snapshot 注入 system prompt。第二层是会话搜索完整对话写进 SQLite 的state.db用 FTS5 建全文索引模型主动调session_search工具去翻历史。第三层是外置 Provider通过MemoryProvider接口把 Mem0、Honcho 这类专业记忆系统接进来turn 前 prefetch 召回、turn 后 sync 写入。这套设计适合谁适合正在给 AI 工具或 Agent 搭持久记忆的开发者。你可能已经踩过「全塞向量库」的坑也可能刚上手不知道从哪写配置。这篇就给出一份能直接复制的config.toml加settings.json骨架把三层串起来最后用一次写入-召回动作验证链路真的通了。模型调用统一走 TaoToken 的 Key/API 通道省得每个 provider 各配一套鉴权。2. 前置准备统一 Key 与目录骨架在写配置之前先把两件事定下来目录结构和统一鉴权通道。目录我建议这样放三层各管各的互不干扰hermes-memory/ ├── config.toml # 三层总配置 ├── settings.json # provider 与模型通道 ├── memory/ │ ├── MEMORY.md # 第一层环境事实 │ └── USER.md # 第一层用户偏好 ├── state.db # 第二层SQLite FTS5 └── plugins/ └── memory/ ├── mem0/ └── honcho/鉴权这块Mem0 和 Honcho 如果各自直连你得维护两套 Key还要处理不同 SDK 的 base_url。我的做法是统一走 TaoToken 的 API 通道模型对话和记忆 provider 的推理调用都从这一个入口出。先去控制台拿 Key控制台入口https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewriteAPI Key 管理https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite拿到 Key 之后环境变量统一注入别写死在配置文件里export TAOTOKEN_API_KEYsk-你的key export TAOTOKEN_BASE_URLhttps://taotoken.net/api注意https://taotoken.net/api是 API 基址不要在后面拼多余的路径SDK 会自己补/v1/chat/completions这类端点。如果你还没决定用哪个模型来跑记忆的抽取和摘要可以先去模型对话页试一下效果确认摘要质量再落到配置里模型对话https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite3. 三层协同的 config.toml 骨架config.toml负责声明三层各自的行为。下面这份可以直接抄注释我标了每段对应哪一层。# 第一层内置记忆 [memory.builtin] enabled true memory_file memory/MEMORY.md # 环境事实、项目约定 user_file memory/USER.md # 用户偏好、沟通风格 max_chars 4000 # 字符预算超了会提示 usage inject_on session_start # 只在 session 启动时注入 system prompt atomic_write true # 文件锁 原子写入防并发损坏 # 第二层会话搜索 [memory.session_search] enabled true db_path state.db fts_table messages_fts # 普通全文索引 trigram_table messages_fts_trigram # 中文/日文/韩文子串搜索 max_message_hits 50 # 全局最多匹配 50 条 message max_sessions 3 # 去重后最多选 3 个 session window_chars 100000 # 摘要窗口围绕 query 截断 summarize_model gpt-4o-mini # 辅助模型走统一通道 # 第三层外置 Provider [memory.provider] name mem0 # 可切 mem0 / honcho plugin_dir plugins/memory prefetch_on_turn true # turn 前召回 sync_on_turn true # turn 后写入 inject_tag memory-context # 临时注入标签不写历史 [memory.provider.mem0] api_base https://taotoken.net/api api_key_env TAOTOKEN_API_KEY top_k 8 rerank true [memory.provider.honcho] api_base https://taotoken.net/api api_key_env TAOTOKEN_API_KEY peer_card true reasoning true几个参数值得单独说。inject_on session_start是关键内置记忆中途写入会立刻落盘但不会进当前 session 的 system prompt因为 LLM 是前缀匹配触发缓存改 system prompt 会让缓存失效、token 消耗飙升。max_message_hits 50是全局匹配数不是最近 50 条这点后面排障会再提。window_chars 100000控制送进摘要模型的窗口大小长会话不会全量塞进去。4. settings.json 与 Provider 接口对齐config.toml管行为settings.json管运行时装配。它把 provider 插件、模型通道、召回策略绑在一起。{ runtime: { api_base: https://taotoken.net/api, api_key_env: TAOTOKEN_API_KEY, default_model: gpt-4o-mini }, memory: { layers: [builtin, session_search, provider], provider: { active: mem0, prefetch: { enabled: true, timeout_ms: 800, fail_open: true }, sync: { enabled: true, async: true, dedup: true } }, session_search: { trigger_keywords: [上次, 之前, 我们做过, 还记得], aux_model: gpt-4o-mini } } }fail_open: true是我强烈建议开的。外置 provider 是远程服务网络抖动时 prefetch 可能超时如果 fail_open 为 false整个 turn 会直接失败。开了之后召回失败就降级模型照常回答只是这轮没有外部记忆。Provider 插件要实现的核心接口简化后是这样class MemoryProvider: def initialize(self, session_id, **kwargs): 拿到 session、用户、平台、profile 上下文 ... def prefetch(self, query, *, session_id): turn 前召回返回相关记忆列表 ... def sync_turn(self, user_content, assistant_content, *, session_id): turn 后写入后端负责抽取、去重、建索引 ... def get_tool_schemas(self): 暴露给模型的工具如 mem0_search ... def handle_tool_call(self, tool_name, args): ... def shutdown(self): ...Mem0 和 Honcho 的差异在能力侧重Mem0 偏服务端事实抽取、语义搜索、rerank、去重Honcho 偏用户画像、peer card、context、reasoning。选哪个看你要的是「事实召回」还是「用户建模」。两个都想用就在settings.json里把active切成对应名字插件目录各放一份。5. 写入-召回验证确认三层链路生效配置写完不算完得跑一次端到端验证。我分三步先建库、再写内置记忆、最后触发召回。第一步初始化 SQLite 和 FTS5 索引-- 建表 CREATE TABLE IF NOT EXISTS sessions ( id TEXT PRIMARY KEY, created_at INTEGER, meta TEXT ); CREATE TABLE IF NOT EXISTS messages ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT, role TEXT, content TEXT, created_at INTEGER ); -- 普通全文索引 CREATE VIRTUAL TABLE IF NOT EXISTS messages_fts USING fts5(content, contentmessages, content_rowidid); -- trigram 索引适合中文子串搜索 CREATE VIRTUAL TABLE IF NOT EXISTS messages_fts_trigram USING fts5(content, contentmessages, content_rowidid, tokenizetrigram);第二步往内置记忆写一条稳定事实。这里模拟模型显式调用 memory 工具from pathlib import Path def memory_add(target: str, content: str): path Path(memory/USER.md if target user else memory/MEMORY.md) # 校验空内容、重复、超长都拒绝 if not content.strip(): raise ValueError(empty content) existing path.read_text(encodingutf-8) if path.exists() else if content in existing: return {status: duplicate} # 原子写入 tmp path.with_suffix(.tmp) tmp.write_text(existing \n---\n content, encodingutf-8) tmp.replace(path) return {status: ok, usage: len(existing) len(content)} memory_add(user, 用户希望解释源码时给出文件名和行号)第三步触发会话搜索召回。先塞几条历史消息再调session_searchimport sqlite3 conn sqlite3.connect(state.db) conn.execute( INSERT INTO messages (session_id, role, content, created_at) VALUES (?,?,?,?), (s1, user, 上次我们修了记忆系统断裂的问题, 1700000000), ) conn.execute( INSERT INTO messages (session_id, role, content, created_at) VALUES (?,?,?,?), (s1, assistant, 定位到 FTS5 索引没更新, 1700000001), ) conn.commit() def session_search(query, limit3): cur conn.execute( SELECT m.session_id, m.content FROM messages_fts f JOIN messages m ON m.id f.rowid WHERE messages_fts MATCH ? LIMIT 50, (query,), ) hits cur.fetchall() sessions, seen [], set() for sid, _ in hits: if sid not in seen: seen.add(sid) sessions.append(sid) if len(sessions) limit: break return sessions print(session_search(记忆系统)) # 预期输出[s1]跑通后你会看到[s1]说明 FTS5 索引建对了、query 能命中、session 去重逻辑生效。再确认外置 provider 的 prefetch 有返回整条链路就算通了。6. 本篇常见错排查报错一no such table: messages_ftsFTS5 是 SQLite 的编译选项部分环境默认没开。先确认import sqlite3 conn sqlite3.connect(:memory:) try: conn.execute(CREATE VIRTUAL TABLE t USING fts5(x)) print(FTS5 available) except sqlite3.OperationalError as e: print(FTS5 missing:, e)如果提示 missing换一个带 FTS5 的 SQLite 构建或者用 Python 自带的sqlite3重新编译。报错二中文搜不到普通 FTS5 按空格分词中文没空格就切不开。这就是为什么要建messages_fts_trigram用tokenizetrigram把「记忆系统断裂」切成连续片段。查询时记得走 trigram 表别走普通表。报错三session 选得不对有人以为 session 是按「命中 message 数最多」来选其实不是。Hermes 的逻辑是先按 message 相关性排序再从前往后扫某个 session 第一次出现就选入。所以一个 session 能不能入选取决于它匹配度最高的那条 message 排得靠不靠前。调max_message_hits会影响这个排序池的大小。报错四内置记忆改了但当前对话没生效这是设计如此不是 bug。内置记忆只在 session 启动时注入 system prompt中途写入要等下一次 session。想立刻验证就重开一个 session。报错五provider prefetch 超时拖垮整个 turn检查settings.json里的fail_open是不是 false。设成 true召回失败就降级不影响主流程。同时把timeout_ms调到 800 左右别设太大。报错六鉴权 401确认TAOTOKEN_API_KEY环境变量真的注入了且api_base是https://taotoken.net/api没有多余斜杠或路径。Key 可以在 API Keys 页面重新生成API Keyshttps://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite接入细节和端点说明看文档接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite7. 长期编码与 Agent 场景的通道选择如果你搭这套记忆系统是为了长期跑编码 Agent比如让 Agent 记住项目约定、历史修复方案、用户代码风格那模型调用量会比较大按量计费不一定划算。这种情况可以看 Coding Plan它更适合高频、长期的编码与 Agent 工作负载Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite如果你用的是 Claude Code 这类工具想把它接到统一通道上Anthropic 兼容入口在这里ClaudeCodeAnthropichttps://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaudecodeutm_campaignrewrite回到记忆系统本身三层拆开之后每层的职责边界清楚了排障也简单内置记忆不生效就查 session 启动注入会话搜索搜不到就查 FTS5 索引和 trigram外置 provider 召回空就查 prefetch 超时和 Key。别把三类信息混在一个库里这是 Hermes 这套设计最值得抄的一点。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

MyBatis大字段查询引发慢SQL?selectByExampleWithBLOBs避坑指南 2026/9/26 12:24:28

MyBatis大字段查询引发慢SQL?selectByExampleWithBLOBs避坑指南

1. 一次线上事故复盘:列表页为什么突然卡了三秒先交代一下背景。前段时间接手了一个旧项目,Spring Boot 2.x 搭配 MyBatis Generator 生成的通用 Mapper 代码。某个核心列表接口在压测时表现还不错,QPS 大约 500 左右,P99 延迟稳定…

阅读更多 →
LLM 基准大逃杀:MMLU、ARC、HellaSwag 三大评测基准的“生死”逻辑与 TaoToken 配置实战 2026/9/26 12:24:21

LLM 基准大逃杀:MMLU、ARC、HellaSwag 三大评测基准的“生死”逻辑与 TaoToken 配置实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
开源硬件项目怎么找?别搜代码,要找完整生态 2026/9/26 12:24:21

开源硬件项目怎么找?别搜代码,要找完整生态

1. 开源硬件不是“找代码”而是“找生态”:为什么90%的人搜不到真正可用的智能家居项目你是不是也试过在GitHub上搜“smart home”“home automation”“esp32 home”,结果翻了二十页全是半年没更新的空仓库、只有README没代码的“计划中”项目&#xff…

阅读更多 →
Vibe Coding实战:从自然语言到可运行项目的AI编程工作流 2026/9/26 12:24:21

Vibe Coding实战:从自然语言到可运行项目的AI编程工作流

最近编程圈要是还没聊过“Vibe Coding”,那多半是断网超过三天了。这个词从2025年年初火起来之后,几乎成了AI编程话题里的“房间里的大象”——有人把它夸成码农解放宣言,有人把它骂成代码事故源头。我自己写了十几年代码,一开始听…

阅读更多 →
STM32嵌入式AI实战:从Model Zoo到自研模型的演进路线 2026/9/26 12:24:21

STM32嵌入式AI实战:从Model Zoo到自研模型的演进路线

1. 先搞清楚 ST Model Zoo 到底给了我们什么ST 官方这几年在嵌入式 AI 这条线上动作挺密集的,从最早的 X-CUBE-AI 扩展包,到后来的 STM32Cube.AI,再到现在的 ST Edge AI Suite,整个工具链一直在迭代。Model Zoo 这个概念其实是从 …

阅读更多 →
基于springboot + vue智能电动车租赁管理系统(源码+数据库+文档) 2026/9/26 12:24:21

基于springboot + vue智能电动车租赁管理系统(源码+数据库+文档)

智能电动车租赁系统 目录 基于springboot vue智能电动车租赁系统 一、前言 二、系统功能演示 三、技术选型 四、其他项目参考 五、代码参考 六、测试参考 七、最新计算机毕设选题推荐 八、源码获取: 基于springboot vue智能电动车租赁系统 一、前言 博主…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉