1. 个人 AI 记忆系统到底解决什么问题
个人 AI 记忆系统,简单说就是让 AI 助手不再“聊完就忘”,而是把你和它之间的对话、你写下的笔记、你查过的资料,沉淀成一套可以随时召回、回溯、关联的长期记忆。它适合三类人:一是每天和 AI 大量对话、希望历史结论能被复用的开发者;二是维护 Obsidian、Notion 等知识库、想让笔记自动变成可检索记忆的知识工作者;三是正在折腾 Agent、想让自己的助手具备“记住用户偏好”能力的独立开发者。
我自己的场景很典型:和 AI 讨论过的技术选型、定下的项目方案、随手记的灵感,散落在聊天记录、笔记软件和脑子里。过两周再问 AI“上次那个向量维度怎么定的”,它一脸茫然。于是我决定搭一套全栈链路,用 Hermes 做记忆编排(负责把对话和笔记转成结构化记忆)、Hindsight 做回溯检索(负责事实记忆的存储与召回)、GBrain 做知识沉淀(负责概念关系和知识图谱),三者共享同一个 Embedding 服务,最终通过 TaoToken 统一接入大模型通道,避免到处配 Key。
这套系统的核心价值在于“分工”。Hindsight 像日记本,存的是“谁在什么时候说了什么、有什么偏好”,比如“老板喜欢喝美式咖啡”“项目截止日期是下周三”。GBrain 像笔记本,存的是概念和关系,比如“Qwen3-Embedding 是通义千问团队开发的”“Hindsight 用 PostgreSQL 存向量”。两者互补,缺一不可——单一系统没法同时满足“记住对话内容”和“理解知识结构”。
数据量上,我的 GBrain 有 3032 个 chunk,Hindsight 有 569 条 memory,合计约 3600 条。这个量级决定了我不需要动辄 4B、8B 的大模型,0.6B 的 Embedding 模型绑绑有余。整套系统跑在一台 Ubuntu 24.04、16 核 27G 内存的服务器上,额外硬件成本 0 元,全量迁移耗时约 45 分钟。下面我把从零搭建的每一步、可复制的配置片段、以及一轮“写入—召回—回溯”的验证动作完整写出来,你可以直接跟着做。
2. TaoToken 统一接入与前置准备
在动手搭记忆系统之前,先把大模型通道统一掉,否则后面 Hermes 编排、Hindsight 抽取事实、GBrain 生成摘要,每个组件都要单独配一套 Key,维护起来很痛苦。TaoToken 在这里扮演的角色就是“统一入口”:一个 Base URL、一个 API Key,兼容 OpenAI 风格的接口,Hermes、Hindsight、GBrain 以及各种编码工具都能直接对接。
前置准备分三块。第一块是账号与 Key:打开官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 注册后进入控制台,在 API Keys 页面创建一个 Key,建议按用途命名,比如memory-stack,方便后面区分。创建后立刻复制保存,页面刷新后就不再完整显示。第二块是模型选择:记忆系统里有两类调用,一类是 Embedding(把文本转向量),一类是 Chat/Completion(Hermes 编排、事实抽取、摘要生成)。Embedding 我后面用本地 TEI 服务跑 Qwen3-Embedding-0.6B,Chat 类调用统一走 TaoToken,模型 ID 按控制台里可用的填,比如claude-sonnet-4-5或gpt-4o-mini这类,具体以你控制台列表为准。第三块是环境变量约定:我习惯把 Key 和 Base URL 写进~/.memory-stack/env,所有组件 source 同一个文件,避免散落。
这里要强调一个关键点:TaoToken 的 API 地址是 https://taotoken.net/api ,不带任何查询参数,配置时 Base URL 就填这个,路径拼接交给 SDK。很多新手会把官网地址和 API 地址搞混,结果请求打到网页上返回 HTML,报错Unexpected token < in JSON,这个坑后面排障章节会细说。
前置检查清单如下,建议逐条确认再往下走:
| 检查项 | 预期结果 | 说明 |
|---|---|---|
| TaoToken Key 已创建 | 控制台可见memory-stack | 复制保存,只显示一次 |
| Base URL 确认 | https://taotoken.net/api | 不带 UTM、不带斜杠结尾 |
| 服务器内存 | ≥ 16G | Embedding 服务约 1.5G,PG 约 2G |
| PostgreSQL | 已安装,支持 pgvector | CREATE EXTENSION vector;可执行 |
| Python | ≥ 3.10 | 后面脚本依赖 psycopg2、requests |
| 模型文件 | Qwen3-Embedding-0.6B 已下载 | 约 1.2GB |
环境变量文件这样写,路径按你的实际用户名替换:
# ~/.memory-stack/env export TAOTOKEN_API_KEY="sk-你的Key" export TAOTOKEN_BASE_URL="https://taotoken.net/api" export TAOTOKEN_CHAT_MODEL="claude-sonnet-4-5" export EMBEDDING_BASE_URL="http://localhost:8082/v1" export EMBEDDING_MODEL="Qwen3-Embedding-0.6B" export EMBEDDING_DIM="1024"写完执行source ~/.memory-stack/env,然后echo $TAOTOKEN_BASE_URL确认输出正确。这一步看着简单,但后面所有组件都依赖它,配错了会连环报错。如果你还想先验证模型通道是否通,可以到模型对话页面 https://taotoken.net/api 对应的控制台入口里发一条测试消息,确认 Key 有效再继续。长期做编码和 Agent 的话,Coding Plan 页面 https://taotoken.net/api 对应的套餐入口也值得看一眼,按量还是包月根据你的调用频率决定。
3. 可复制配置:Embedding 服务与三组件接入
这一节是全文最核心的部分,所有配置片段都可以直接复制。先部署共享 Embedding 服务,再分别配置 GBrain 和 Hindsight 指向它,最后把 Hermes 的编排通道接到 TaoToken。
3.1 部署 TEI Embedding 服务
模型下载用 hf-mirror 加速,避免卡在下载环节:
HF_ENDPOINT=https://hf-mirror.com huggingface-cli download \ Qwen/Qwen3-Embedding-0.6B \ --local-dir /home/xiaoyu/models/Qwen3-Embedding-0.6B下载完约 1.2GB,用 sentence-transformers 验证维度:
from sentence_transformers import SentenceTransformer model = SentenceTransformer('/home/xiaoyu/models/Qwen3-Embedding-0.6B') embedding = model.encode(["测试文本"]) print(f"维度: {embedding.shape}") # 期望 (1, 1024)接着用 systemd 管理 TEI 服务,保证开机自启和崩溃重启:
# /etc/systemd/system/tei-embedding.service [Unit] Description=TEI Embedding Service After=network.target [Service] Type=simple User=xiaoyu ExecStart=/usr/local/bin/tei \ --model-id /home/xiaoyu/models/Qwen3-Embedding-0.6B \ --port 8082 \ --max-client-batch-size 32 Restart=on-failure RestartSec=10 [Install] WantedBy=multi-user.target启动并验证:
sudo systemctl daemon-reload sudo systemctl enable tei-embedding sudo systemctl start tei-embedding curl http://localhost:8082/health # 期望: {"status":"ok","model":"Qwen3-Embedding-0.6B","max_length":8192}3.2 GBrain 接入配置
GBrain 之前用 bge-base-en-v1.5(768 维),现在要迁到 1024 维。先备份数据库,这一步千万别省:
pg_dump -U postgres -d gbrain > /tmp/gbrain-backup-$(date +%Y%m%d).sql然后改向量维度。因为维度不匹配,必须先清空旧向量再改列类型:
-- psql -U postgres -d gbrain UPDATE content_chunks SET embedding = NULL WHERE embedding IS NOT NULL; ALTER TABLE content_chunks ALTER COLUMN embedding TYPE vector(1024);GBrain 自带的gbrain reindex有内置超时,3000+ 条数据跑到 416 条左右就被 SIGTERM 杀掉。绕过 CLI,用 Python 直连 PostgreSQL 加 TEI API:
import psycopg2, requests, json conn = psycopg2.connect(host='localhost', dbname='gbrain', user='postgres') cur = conn.cursor() cur.execute("SELECT id, chunk_text FROM content_chunks WHERE embedding IS NULL ORDER BY id") rows = cur.fetchall() api_url = "http://localhost:8082/v1/embeddings" model = "Qwen3-Embedding-0.6B" batch_size = 32 for i in range(0, len(rows), batch_size): batch = rows[i:i+batch_size] texts = [r[1][:2000] for r in batch] ids = [r[0] for r in batch] resp = requests.post(api_url, json={"model": model, "input": texts}, timeout=120) if resp.status_code == 200: embeddings = [item['embedding'] for item in resp.json()['data']] for chunk_id, emb in zip(ids, embeddings): cur.execute( "UPDATE content_chunks SET embedding = %s::vector WHERE id = %s", (json.dumps(emb), chunk_id) ) conn.commit() print(f"进度: {min(i+batch_size, len(rows))}/{len(rows)}") cur.execute(""" CREATE INDEX idx_chunks_embedding_hnsw ON content_chunks USING hnsw (embedding vector_cosine_ops) WITH (m=16, ef_construction=200) """) conn.commit()3.3 Hindsight 接入配置
Hindsight 原来用本地 ONNX(multilingual-e5-small,384 维),改成指向共享 TEI。编辑/home/xiaoyu/.hindsight/profiles/hermes.env:
# 注释掉原来的本地 ONNX 配置 # HINDSIGHT_API_EMBEDDINGS_PROVIDER=local # HINDSIGHT_API_EMBEDDINGS_ONNX_MODEL_ID=intfloat/multilingual-e5-small # 新增 OpenAI 兼容配置 HINDSIGHT_API_EMBEDDINGS_PROVIDER=openai HINDSIGHT_API_EMBEDDINGS_OPENAI_API_KEY=not-needed HINDSIGHT_API_EMBEDDINGS_OPENAI_MODEL=Qwen3-Embedding-0.6B HINDSIGHT_API_EMBEDDINGS_OPENAI_BASE_URL=http://localhost:8082/v1注意这里用的是 OpenAI 兼容模式,不是 TEI 模式。Hindsight 的 TEI 客户端会去调/info端点,而我们的 TEI 服务没有这个端点,会报 404。改完维度后重启:
-- psql -U postgres -d hindsight UPDATE memory_units SET embedding = NULL WHERE embedding IS NOT NULL; ALTER TABLE memory_units ALTER COLUMN embedding TYPE vector(1024);sudo systemctl restart hindsight-api # 日志中应出现: Embeddings: OpenAI provider initialized (model: Qwen3-Embedding-0.6B, dim: 1024)Hindsight 没有暴露 reindex API,同样用 Python 脚本直连 PG 批量更新,569 条约 2 分钟完成。
3.4 Hermes 编排通道接入 TaoToken
Hermes 负责把对话和笔记转成结构化记忆,它的 Chat 调用走 TaoToken。配置文件里这样写:
# ~/.hermes/config.toml [llm] provider = "openai-compatible" base_url = "https://taotoken.net/api" api_key_env = "TAOTOKEN_API_KEY" model = "claude-sonnet-4-5" timeout = 120 [memory] hindsight_endpoint = "http://127.0.0.1:9092" gbrain_dsn = "postgresql://postgres@localhost/gbrain"三件套对照表,方便你核对:
| 组件 | Base URL | Key 来源 | Model ID |
|---|---|---|---|
| Hermes | https://taotoken.net/api | TAOTOKEN_API_KEY | claude-sonnet-4-5 |
| Hindsight | http://localhost:8082/v1 | not-needed | Qwen3-Embedding-0.6B |
| GBrain | http://localhost:8082/v1 | not-needed | Qwen3-Embedding-0.6B |
4. 验证请求:写入—召回—回溯一轮跑通
配置写完必须验证,否则你不知道是链路通了还是某个环节静默失败。这一节给出一轮完整的“写入—召回—回溯”动作和预期输出。
第一步,写入一条记忆。通过 Hindsight 的 retain 接口写入一条事实:
curl -X POST http://127.0.0.1:9092/v1/default/banks/hermes/memories/retain \ -H "Content-Type: application/json" \ -d '{"content": "项目向量维度最终定为1024,使用Qwen3-Embedding-0.6B", "tags": ["project", "embedding"]}'预期返回包含id和status: stored。如果返回 401,说明 Hindsight 的鉴权配置有问题;如果返回 500 且日志里有 embedding 相关错误,说明 TEI 服务没起来或维度不匹配。
第二步,召回验证。用语义查询而不是关键词:
curl http://127.0.0.1:9092/v1/default/banks/hermes/memories/recall \ -H "Content-Type: application/json" \ -d '{"query": "向量维度是多少", "limit": 3}'预期返回刚才写入的那条记忆,且score在 0.7 以上。这里能验证 Embedding 服务是否正常工作——如果召回为空,多半是向量没写进去或维度对不上。
第三步,GBrain 知识图谱验证。查一下 chunk 的向量覆盖情况:
psql -U postgres -d gbrain -c \ "SELECT count(*) as embedded, (SELECT count(*) FROM content_chunks) as total FROM content_chunks WHERE embedding IS NOT NULL;" # 期望: 3032 | 3032第四步,跨系统语义搜索。同一个问题同时打两个系统,看能否分别返回事实记忆和知识图谱内容。比如问“老板喜欢什么”,Hindsight 返回“喜欢喝美式咖啡”,GBrain 返回“果壳科技创始人,经营 AI Agent 业务”。这一步是整套系统的价值验证点。
第五步,Hermes 编排验证。让 Hermes 处理一段对话,确认它调用了 TaoToken 的 Chat 接口并写入了记忆:
source ~/.memory-stack/env hermes ingest --text "今天决定把 Embedding 服务统一到 8082 端口,两个系统共享" # 预期日志: LLM call -> https://taotoken.net/api, tokens used: xxx # 预期日志: memory retained -> hindsight id=xxx如果 Hermes 日志里出现Connection refused指向taotoken.net,检查 Base URL 是否误写成官网地址;如果出现401 Unauthorized,检查TAOTOKEN_API_KEY是否 source 成功。
5. 本篇常见错误排查
搭建过程中我踩了不少坑,这里按真实报错对照给出排查路径,你遇到时可以直接对号入座。
报错一:401 Unauthorized来自 TaoToken。现象是 Hermes 或任何走 TaoToken 的组件返回 401。原因通常是 Key 没 source、Key 复制时带了空格、或者用了错误的 Base URL。排查顺序:先echo $TAOTOKEN_API_KEY确认非空,再curl -H "Authorization: Bearer $TAOTOKEN_API_KEY" https://taotoken.net/api/models看是否返回模型列表。如果 curl 通但组件不通,检查组件配置里读的是不是同一个环境变量名。
报错二:local proxy failed或Connection refused。这类错误多半是本地服务没起来。TEI 服务检查systemctl status tei-embedding,Hindsight 检查systemctl status hindsight-api。如果服务在跑但连不上,用ss -tlnp | grep 8082确认端口监听正常。注意 Hindsight 的 recall 端口是 9092,不是 8082,两个别搞混。
报错三:reading 'choices'或Unexpected token < in JSON。这是典型的 Base URL 配错,请求打到了网页而不是 API。检查你的 Base URL 是不是https://taotoken.net/api,而不是官网首页。SDK 会自动拼/chat/completions,所以 Base URL 不要带多余路径。
报错四:OAuth相关错误或invalid_grant。如果你用的是 Claude Code 或 Codex 这类工具,它们可能默认走 OAuth 流程。接入 TaoToken 时要显式配置 API Key 模式,在settings.json或auth.json里把认证方式改成 API Key。Claude Code 的配置片段:
{ "apiProvider": "openai-compatible", "baseURL": "https://taotoken.net/api", "apiKey": "sk-你的Key", "model": "claude-sonnet-4-5" }Codex 的auth.json类似,把OPENAI_BASE_URL指向 TaoToken,OPENAI_API_KEY填你的 Key。Cline MCP 场景下,在 MCP 配置里同样写全 Base URL、Key、Model ID 三件套,缺一个都会静默失败。
报错五:gbrain reindex跑到 416 条被 SIGTERM。这是内置超时,不是数据问题。解决方案就是第 3 节里的 Python 脚本,绕过 CLI 直连数据库。脚本里 batch_size 设 32,超时设 120 秒,3000 条数据约 10 分钟跑完。
报错六:Hindsight 启动报404 Not Found for url http://localhost:8082/info。这是 TEI 模式不兼容,改用 OpenAI 兼容模式即可,配置见 3.3 节。改完记得重启服务并确认日志里的 provider 是 openai。
报错七:env 文件注释行被误改。用 sed 替换HINDSIGHT_API_EMBEDDINGS_PROVIDER=local时,注释掉的同名行也被改了。解决方法是精确匹配行首:sed -i 's/^HINDSIGHT_API_EMBEDDINGS_PROVIDER=local/#&/',或者干脆手动编辑。
排障时如果拿不准是通道问题还是组件问题,先单独用 curl 测 TaoToken 的模型对话接口,确认通道本身没问题,再往组件层排查。接入文档里有各语言的调用示例,对照着改配置最快。
6. 长期编码与 Agent 场景的接入建议
如果你不只是搭记忆系统,还想把它和日常编码、Agent 工作流串起来,有几个实践建议。第一,把 TaoToken 的 Coding Plan 作为长期编码通道,按调用量选套餐,避免每次手动充值。第二,Hermes 的编排提示词里显式要求“先查 Hindsight 再查 GBrain”,这样召回时能同时拿到事实和知识,回答更完整。第三,定期跑一次向量覆盖检查,确保新写入的记忆都被 embed 了,我习惯每周跑一次第 4 节的 SQL。
模型升级路径也提前想好:当数据量增长到 1 万条以上时,0.6B 的表达力可能不够,可以考虑升级到 Qwen3-Embedding-4B,维度从 1024 升到 2560。升级时流程和这次一样——备份、清空、改维度、重建、建索引,只是内存占用会从 1.5G 涨到 8G,服务器要留够余量。
最后说个真实体会:这套系统搭完之后,最大的变化不是技术指标,而是我不再担心“聊过就忘”。上周讨论的方案、上个月定的选型,现在问 AI 都能准确召回。技术只是手段,想清楚你要记什么、怎么用,才是这套系统真正值钱的地方。