我用 Docker 自托管了 AI 记忆系统,踩了 5 个坑全记录

背景:AI Agent 的"失忆症"

最近在用 AI Agent(比如 Claude、GPT 这类)帮我写代码,发现一个很烦的问题------每次开新对话,它完全不记得我之前是谁、做什么项目、用什么技术栈。每次都要重新自我介绍一遍,效率极低。

市面上的方案要么贵(按月付费),要么数据不在自己手里(云端存储)。我想找个自托管、免费、数据本地、支持多 Agent 共享的记忆系统。

调研了一圈,选了 Honcho------一个用 Python + FastAPI 写的自托管记忆服务,支持多 Agent、向量检索、方言推理。刚好我手头有 WSL2 + Docker Desktop,LLM 用的是 DeepSeek(便宜)。

下面是我从头搭建到跑通的完整过程,重点是我踩的 5 个坑


整体架构

css 复制代码
┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│  Hermes     │    │  Claude     │    │  其他 Agent  │
│  (你)       │    │  Code       │    │             │
└──────┬──────┘    └──────┬──────┘    └──────┬──────┘
       │                  │                  │
       └──────────────────┼──────────────────┘
                          │
                   ┌──────▼──────┐
                   │   Honcho    │  ← 自托管 Docker
                   │   API :8000 │
                   └──────┬──────┘
                          │
          ┌───────────────┼───────────────┐
          │               │               │
    ┌─────▼─────┐  ┌──────▼──────┐  ┌─────▼─────┐
    │ Deriver   │  │  Embedding  │  │ Postgres  │
    │ (DeepSeek)│  │  (jina-v2)  │  │ +pgvector │
    └───────────┘  └─────────────┘  └───────────┘

三个核心组件:

  • Honcho API:接收消息、管理会话
  • Deriver:用 LLM 从对话中提取关键信息
  • Embedding 服务:把文本转成向量,支持语义搜索

环境

  • Windows 11 + WSL2(Ubuntu)
  • Docker Desktop(WSL2 集成模式)
  • DeepSeek API(deepseek-chat 模型)
  • 本地 embedding 服务(jina-embeddings-v2-base-zh,768 维)

坑 1:Docker 镜像拉不下来

第一个命令就跑不通:

bash 复制代码
git clone https://github.com/plastic-labs/honcho.git
cd honcho
docker compose up -d   # ❌ 卡住不动

Docker Hub 在国内基本不可达。解决:在 Docker Desktop → Settings → Docker Engine 里加上镜像源:

json 复制代码
{
  "registry-mirrors": [
    "https://docker.1ms.run",
    "https://docker.xuanyuan.me"
  ]
}

改完记得 wsl --shutdown 重启 WSL,否则不生效。

另外如果开了代理(比如 clash-verge,本地端口 10808),还可以在 Docker Desktop Settings → Resources → Proxies 里配上 HTTP/HTTPS 代理,双保险。


坑 2:DeepSeek 当 LLM + Embedding 的"分裂"配置

Honcho 默认用 OpenAI,但我要用 DeepSeek。.env 配置如下:

bash 复制代码
# LLM 配置
LLM_MODEL_CONFIG__TRANSPORT=deepseek
LLM_MODEL_CONFIG__MODEL=deepseek-chat
LLM_MODEL_CONFIG__API_KEY=sk-xxxxxxxx
LLM_MODEL_CONFIG__BASE_URL=https://api.deepseek.com

# 关键:DeepSeek 没有 embedding API!
# 必须显式配置 embedding provider,否则会走 OpenAI 的 text-embedding-3-small
EMBEDDING_MODEL_CONFIG__TRANSPORT=openai
EMBEDDING_MODEL_CONFIG__MODEL=jina-embeddings-v2-base-zh
EMBEDDING_MODEL_CONFIG__API_KEY=not-needed
EMBEDDING_MODEL_CONFIG__BASE_URL=http://localhost:8080/v1

核心教训:DeepSeek 有 Chat API 但没有 Embedding API 。如果不显式配 EMBEDDING_MODEL_CONFIG,Honcho 会默认走 OpenAI,但又没有 OpenAI key,直接挂掉。

我选的是 jina-embeddings-v2-base-zh,用 sentence-transformers 在本机 8080 端口起了一个兼容 OpenAI 格式的 embedding 服务。768 维,中文友好,单条 51ms,内存占用 ~1.2GB。


坑 3:pgvector 维度不匹配------最隐蔽的坑

Honcho 默认用 PostgreSQL + pgvector 存向量,默认维度是 1536(OpenAI text-embedding-3-small 的输出维度)。

但 jina-v2 输出的是 768 维

直接写入会报错:

yaml 复制代码
ERROR: expected 1536 dimensions, not 768

解决分两步:

第一步:改数据库

sql 复制代码
-- 连接数据库(注意数据库名是 postgres,不是 honcho)
docker exec honcho-database-1 psql -U postgres -d postgres

-- 改两表的向量列
ALTER TABLE documents ALTER COLUMN embedding TYPE vector(768);
ALTER TABLE message_embeddings ALTER COLUMN embedding TYPE vector(768);

-- 重建 HNSW 索引
DROP INDEX IF EXISTS documents_embedding_idx;
CREATE INDEX documents_embedding_idx ON documents USING hnsw (embedding vector_cosine_ops);

DROP INDEX IF EXISTS message_embeddings_embedding_idx;
CREATE INDEX message_embeddings_embedding_idx ON message_embeddings USING hnsw (embedding vector_cosine_ops);

第二步:改源码

Honcho 有个向量迁移策略:schema 里的 Vector(1536) 是硬编码的,并且有个 MIGRATED 环境变量控制是否走新代码路径。但代码里用的是 or not MIGRATED,导致 MIGRATED=false 时永远走旧路径。

需要把 6 个文件里的 or not MIGRATED 改成 and not MIGRATED

python 复制代码
# 改前
if not MIGRATED or not migrated:
# 改后
if not MIGRATED and not migrated:

涉及文件:

  • src/config.py
  • src/crud/message.py
  • src/crud/document.py
  • src/search.py
  • src/sync_vectors.py

改完重建镜像:

bash 复制代码
docker compose build --no-cache api deriver
docker compose up -d api deriver

坑 4:DeepSeek json_object 兼容性------deriver 直接罢工

最坑的一个。

Honcho 的 deriver 组件负责用 LLM 从对话中提取关键信息(观察)。它会调用 DeepSeek API,设置 response_format: json_object

但 DeepSeek 有一条奇葩要求:prompt 里必须包含单词 "json",否则 400 错误

vbnet 复制代码
ERROR - Error code: 400 - "Prompt must contain the word 'json' in some form 
to use 'response_format' of type 'json_object'."

Honcho deriver 的系统提示词是 "Analyze messages from {peer_id} to extract explicit atomic facts..."------你仔细看,全篇没有一个 "json" 单词

deriver 重试 3 次后直接放弃,队列里堆了 49 条消息没人处理,整个推理功能不可用。

解决:src/llm/backends/openai.py 两处注入 "Respond in JSON."

python 复制代码
# 位置 1:_build_params() 中 json_mode 分支
if extra_params.get("json_mode"):
    params["response_format"] = {"type": "json_object"}
    # 注入这一行
    system_msg["content"] += "\nRespond in JSON."

# 位置 2:_create_structured_response() 中 json_schema 回退路径
# 类似地,在设置 json_object 后向消息追加 "\nRespond in JSON."

改完同样的 docker compose build --no-cache api deriver && docker compose up -d api deriver


坑 5:FLUSH_ENABLED------短消息会永久卡在队列

Honcho 有一个消息 flush 机制:新消息会先进队列,等待攒够一定量后再由 deriver 批量处理。但如果你发了一条很短的消息(比如 "你好"),可能永远凑不够批量阈值,消息就一直卡着。

加上这行到 .env

bash 复制代码
FLUSH_ENABLED=true

这样每条消息都会触发即时处理,不再等待攒批。

代价是多消耗一点 LLM token(每次都调一次 API),但对个人使用来说完全可忽略。


端到端验证:别信容器状态

容器全部 healthy 不代表功能正常。我总结了一套三步验证法:

bash 复制代码
# 1. 写入测试
curl -X POST http://localhost:8000/v3/workspaces/hermes/sessions/test/messages \
  -H "Content-Type: application/json" \
  -d '{"content": "用户用 Python 写后端,喜欢 FastAPI", "peer_name": "sanlin"}'

# 2. 搜索验证(等 30 秒让 deriver 处理)
curl http://localhost:8000/v3/workspaces/hermes/peers/sanlin/search \
  -d '{"query": "Python"}'

# 3. 推理验证
# 使用 honcho CLI 或 API 调用推理接口

三步全通过才算"正常运行"。


成本

项目 费用
DeepSeek API ~0.1 元/天(个人使用,对话量不大)
jina-v2 embedding 免费(本地跑,1.2GB 内存)
Honcho 服务 免费(自托管)
Docker Desktop 免费(个人版)

每月花销不到 3 块钱。


总结

五个坑按隐蔽程度排序:

  1. ⭐⭐⭐⭐⭐ pgvector 维度不匹配------既要改数据库,又要改源码
  2. ⭐⭐⭐⭐ json_object 兼容性------DeepSeek 特有要求,报错信息明确但不明显
  3. ⭐⭐⭐ Embedding 配置分离------DeepSeek 无 embedding API,必须显式配
  4. ⭐⭐ Docker 镜像拉取------国内通用问题,有标准解法
  5. FLUSH_ENABLED------文档有提但不醒目

如果你也想自托管 Honcho + DeepSeek,照着这五个坑提前填好,应该能少走很多弯路。


最后安利一下 Honcho 的 Peer 模型设计:同一个用户画像(sanlin)可以被多个 Agent(Hermes、Claude Code、自写脚本)共享,但每个 Agent 的行为和记忆又是隔离的。这比简单的"全局记忆池"灵活太多。

相关推荐
火山引擎开发者社区34 分钟前
基于 AgentKit 的端到端需求交付平台:从个人提效到组织提效的 AI 落地实践
人工智能
三声三视1 小时前
75 条文章索引被一条 add 清成 1 条,退出码还是 0:tri-article 的 index.py 我读了 205 行
人工智能·ai·skill·tri-skills·tri-article
蓝速科技1 小时前
医院导诊 AI 数字人一体机场景适配与落地指南丨蓝速科技
运维·数据库·人工智能·科技·自然语言处理·技术分享
QYR-分析1 小时前
重轨受电弓行业深度报告:市场格局、技术迭代与发展前景
大数据·数据库·人工智能
火山引擎开发者社区2 小时前
# 开发者集结!共探 AI Agent 创新应用新可能
人工智能
牛油果子哥q2 小时前
生产级AI项目上线全流程:Docker容器化、服务编排、监控告警、日志收集、容灾降级、线上运维闭环
人工智能·ai
Pocker_Spades_A2 小时前
视频不用再一张张截图:ClipSketch AI 把关键画面转成漫画,还能顺手生成文案
人工智能·音视频
小小测试开发2 小时前
LLM 结构化输出测试:Schema 契约 + 故障注入,让工具调用的 JSON 不再靠重试赌运气
人工智能·json
阿里云大数据AI技术2 小时前
淘宝直播 AI 分身:基于阿里云 Milvus 的商品知识召回实践
人工智能
猎头南楼2 小时前
大模型后训练与 Agent 自迭代:两类工程能力的观察
人工智能·深度学习·机器学习