司南 — 记忆路由与传播控制层

基于 Honcho 的集成方案

命名: 司南(战国指南针)—— “司”掌管控,“南”定方向。路由指向该去的 Agent,ACL 把守关口,传播传递方向。 日期: 2026-06-01 来源: git@github.com:plastic-labs/honcho.git(commit b006fa6) 状态: 已拉取源码审查,等待后续集成实现


一、项目概览

Honcho(Plastic Labs)是 AI Agent 的记忆平台,Apache 2.0/AGPL-3.0 开源。共 119 个 Python 文件,~36,445 行

目录结构

src/
├── main.py                  # FastAPI 入口
├── config.py (1339行)       # 全量配置(70+ 参数)
├── models.py (579行)        # SQLAlchemy 模型
├── db.py (79行)             # 数据库会话
├── security.py              # API Key 鉴权(简单的 bearer token)
├── deriver/     (2558行)    # 消息→观察提取 pipeline
├── dreamer/     (2853行)    # 跨 session 模式发现(核心亮点)
├── dialectic/   (921行)     # 按需推理检索
├── crud/        (5711行)    # 数据库访问层
├── llm/         (4430行)    # 多 LLM 后端抽象
├── vector_store/(1029行)    # LanceDB / TurboPuffer
├── routers/     (2284行)    # FastAPI 路由
├── schemas/     (1257行)    # Pydantic 模型
├── cache/                   # 缓存层
├── reconciler/              # 向量同步
├── telemetry/               # 遥测(Sentry + Prometheus)
└── webhooks/                # Webhook 推送

配置体系(config.py)

配置参数极其完善,约 70+ 可配置项:

settings.DREAM.ENABLED               # 总开关
settings.DREAM.DOCUMENT_THRESHOLD    # 触发梦的显式观察数量阈值(默认 20)
settings.DREAM.MIN_HOURS_BETWEEN_DREAMS  # 最短间隔(默认 1h)
settings.DREAM.IDLE_TIMEOUT_MINUTES  # 延迟触发时间(默认 0 = 立即)
settings.DREAM.ENABLED_TYPES         # 启用的梦类型
settings.DREAM.SURPRISAL.ENABLED     # 是否启用奇异值采样
settings.DREAM.DEDUCTION_MODEL_CONFIG/INDUCTION_MODEL_CONFIG  # 专用模型
settings.DREAM.HISTORY_TOKEN_LIMIT   # 上下文历史 token 限制

启示: Honcho 的配置体系本身就是一份”需要哪些参数”的 checklist。


二、Dreaming 模块(2853 行)— 最核心的模块

架构

DreamScheduler(单例)
  └── 事件驱动:新消息达到阈值 → schedule_delay(MIN_IDLE) → 执行
  └── 防重复:同一个 (workspace, observer, observed) 不会同时有两个梦
  └── 在内存队列中,非持久化(重启丢失)

Dream Orchestrator
  ├── 0. Surprisal Sampling(可选)
  │   └── 几何奇异值 → 找"最意外"的观察 → 作为 hints 传给 specialists
  │
  ├── 1. Deduction Specialist(演绎)
  │   ├── 自治 Agent:最多 12 步工具循环
  │   ├── 工具:search_memory, search_messages, get_recent_observations
  │   ├── create_observations_deductive (带 source_ids + premises)
  │   ├── delete_observations_deductive(清理过时)
  │   └── update_peer_card(更新持久身份信息)
  │
  └── 2. Induction Specialist(归纳)
      ├── 自治 Agent:最多 10 步工具循环
      ├── create_observations_inductive(带 source_ids + pattern_type + confidence)
      └── 置信度:2源=low, 3-4=medium, 5+=high

关键设计决策

Specialists 是完全自治的 Agent,不是 prompt:

  • 不做”分析以下文本”这种一次性任务
  • 自己做 discovery(search_memory)→ 决定下一步搜什么 → 创建/删除观察
  • 允许走偏——prompt 强调”follow the evidence, pursue what’s interesting”

Surprisal 作为”软引导”机制:

  • 几何奇异值采样 = 找当前观察集合中”最出乎模型预期”的那些
  • 高奇异值的观察作为 hints 传给 specialists
  • Specialists 可以选择跟或不跟——保持自主性

两阶段顺序:Deduction 先跑,Induction 后跑

  • Deduction 创建的演绎观察可以在同一轮被 Induction 消费
  • Induction 永远不会写 peer card(归 Deduction 管),职责清晰

调度逻辑

# dream_scheduler.py 核心逻辑
check_and_schedule_dream(collection):
  if explicit_docs >= THRESHOLD:
    if hours_since_last_dream >= MIN_HOURS:
      if no pending dream in queue:
        schedule_delayed_dream(IDLE_TIMEOUT)
  • 触发条件:新显式观察达到 DOCUMENT_THRESHOLD(默认 20)
  • 延迟:IDLE_TIMEOUT_MINUTES(默认 0 = 立即)
  • 冷却:MIN_HOURS_BETWEEN_DREAMS(默认 1h)
  • 防并发:schedule 和 queue 双重检查

观察层级

explicit   → 原始提取(Deriver 产出)
deductive  → 逻辑推论(Deduction Specialist 产出)
inductive  → 模式归纳(Induction Specialist 产出)

关键:Dreaming 只消费 explicit 级别做触发条件,避免自循环。

实现参考价值

如果需要自研 Simplified Dreaming,2853 行中最有价值的部分:

  1. Specialist 的工具定义(agent_tools.py 中的工具函数)
  2. Surprisal sampling 算法(surprisal.py)
  3. Agent 循环 + 异常处理模式(orchestrator.py 的 try/finally 确保遥测不丢)

但如果选择集成 Honcho 而非自研,Dreaming 可以直接开箱即用。


三、Deriver 模块(2558 行)

架构

新消息(REST API)
  → enqueue.py(新消息队列)
    → QueueManager(后台队列管理)
      → consumer.py(消费线程)
        → 调 LLM:从消息提取观察
          → 写入 Document 表(level=explicit)
            → check_and_schedule_dream(触发梦)

三种队列

deriver_queue      → 观察提取(每条消息必走)
dream_queue        → 梦的执行(异步,有延迟)
reconciliation_queue → 向量同步(维护向量索引一致性)

Deriver 的消息处理

每条消息过 LLM,系统 prompt 要求提取:

  • 关于 user 的显式事实
  • 偏好/倾向
  • 承诺/计划
  • identity markers

输出格式是结构化的 JSON observation 列表,写入 Document 表(level=explicit)。

实现参考

Deriver 的 prompt 设计(src/deriver/prompts.py)和队列管理(src/deriver/queue_manager.py)是两份高价值参考。

但集成场景下 Deriver 也可选——如果我们不需要每条消息都过 LLM,可以只走批量/异步提取,路由层的实体提取 + FTS5 才是实时路径。


四、Dialectic 模块(921 行)

比想象中轻。核心是 dialectic/core.py 的实现:

get_context()
  → 根据 tokens 限制,拉取最近消息 + 摘要
  → 如果 hits 不足,用 semantic search 补充
  → 可选包含 peer card
  → 输出 OpenAI/Anthropic 格式的 messages

chat() → 5 级深度的推理链
  levels: minimal → low → medium → high → max
  每级增加搜索轮次和推理深度

Dialectic 是最容易直接集成的部分——get_context() 作为路由层的快速检索后端,chat() 作为深水区推理。

921 行的工作量如果自研大概 2-3 天可以复刻。


五、存储模型(models.py 579 行)

核心表

workspace — 顶层隔离域(一个 app = 一个 workspace)

  ├── peer — 实体(用户/Agent,各有一个 knowledge graph)

  ├── session — 会话分组(对应 channel/对话)

  ├── message — 原子消息(每个 turn 的记录)

  ├── document — 观察(核心记忆单元)
  │   ├── level: explicit | deductive | inductive
  │   ├── content: 观察内容(纯文本)
  │   ├── source_ids: 来源 document 的 ID 列表(用于归因)
  │   ├── observer: 谁做的观察
  │   └── observed: 关于谁的观察

  ├── collection — Document 的聚合单位
  │   └── internal_metadata: JSON(存储 dream 状态等)

  ├── peer_card — Peer 的持久身份信息
  │   └── 格式:IDENTITY:/ATTRIBUTE:/RELATIONSHIP:/INSTRUCTION:

  └── representation — 向量嵌入缓存

对我们 ACL 设计的启示

Honcho 的 document/collection/peer_card 模型可以直接承载 ACL 元数据。ACL 信息可以存在 collection 的 internal_metadata 中,或扩展 document 增加 visibility 字段:

// 扩展 document,增加 ACL 字段
{
  "content": "用户的 API key 在配置文件里",
  "level": "explicit",
  "visibility": "private",        // 新增
  "allowed_peers": ["user-A"],    // 新增
  "owner_peer": "user-A"          // 新增
}

Honcho 的 internal_metadata 是 JSON 字段,不需要 schema 变更就可以存这些信息。


六、集成方案(不是重造)

架构分层

┌──────────────────────────────────────────────┐
│              你的路由传播层                     │
│                                                │
│  实体提取(NER/FTS5) → 路由决策 → 懒加载调度  │
│  ACL 校验(visibility check)                  │
│  传播总线(事件驱动,跨 Peer 推送)              │
│                                                │
│  新增:                                         │
│  - FTS5 倒排索引(实体 → 上下文块)              │
│  - ACL 元数据存储 → 每次检索前插入权限过滤        │
│  - 改动写入路径:新消息 → Honcho SDK → 更新 FTS5  │
└──────────────────┬───────────────────────────┘
                   │ Honcho SDK (Python)
                   ▼
┌──────────────────────────────────────────────┐
│              Honcho v3 存储+推理               │
│                                                │
│  POST /workspaces/{ws}/peers/{ob}/documents   │
│  POST /workspaces/{ws}/peers/{ob}/messages    │
│  GET  /workspaces/{ws}/peers/{ob}/context     │
│                                                │
│  异步后台:                                     │
│  - Deriver: 消息 → explicit observations       │
│  - Dreaming: explicit → deductive → inductive  │
│  - Dreaming: peer card 更新                     │
└──────────────────────────────────────────────┘

API 集成级

不需要改 Honcho 一行源码,通过 REST API 或 SDK 对接:

from honcho import Honcho
 
client = Honcho(base_url="http://localhost:8010")
 
# 1. 消息进入
session = client.get_or_create_session(workspace, observer, observed)
session.add_message(role="user", content="...")
 
# 2. 路由层实体更新
entities = extract_entities(content)  # 你的 NER
fts5_index.update(entities, session_id=session.id)
 
# 3. 路由 + ACL 校验
for entity in entities_mentioned_in_new_message:
    if fts5_index.match(entity):
        docs = fts5_index.get_context_blocks(entity)
        allowed_docs = acl.filter(docs, target_peer=target)  # 你的 ACL
        inject_to_context(allowed_docs)

我们需要写的代码

组件估算行数依赖 Honcho?
实体提取 + FTS5 索引~500否(完全独立)
路由决策引擎~300
懒加载调度器~200
ACL 模型 + 校验~500否(元数据存 Honcho)
传播总线~400是(需要 Honcho 的 peer 模型)
Honcho SDK 封装~200
总计~2100 行

两个改动路径

此方案需要在 Honcho 的写入路径上插一个代理——新消息写入时,路由层同步更新 FTS5 索引:

写入路径:
  新消息 → Honcho API
          → Deriver 处理(异步)
          → 到达你的路由层(同异步均可)
            → 更新 FTS5 倒排索引
              → 写入 ACL 元数据(存 collection.metadata)

读取路径:
  新问题 → 实体提取
         → 查 FTS5(路由决策:需要加载哪些上下文块?)
           → ACL 过滤(目标 peer 有权限读吗?)
             → 调用 Honcho get_context() 获取
               → 注入当前 prompt

七、自研 vs 集成对照

维度自研(最初的偏误方向)集成 Honcho
Dreaming自己造 Agent 循环直接用 — 代码已验证 86.9% LoCoMo
Deriver自己写队列 + LLM pipeline直接用 — 但可以按需开关
Dialectic约 2-3 天直接用 — get_context() + chat()
存储层自己设计模型复用 — 但需要加 ACL 字段
我们的核心代码全栈~2100 行(路由+ACL+传播)
外部依赖风险Honcho 断崖变更(v3 刚改完)
控制力完全受 Honcho 设计约束
部署复杂度高(Honcho 需要 PG + Redis + 向量)

八、关键发现汇总

  1. Dreaming 是最不可替代的模块——自治 Agent 循环 + Surprisal 采样,纯 prompt 工程无法复现质量。且代码已完全开源,直接用。
  2. ACL 不需要 Honcho 改代码——利用 collection.internal_metadata 的 JSON 字段,扩展 visibility + allowed_peers 即可。Document 也可以在创建时加自定义字段。
  3. Deriver 按需开关——如果追求低延迟,实时路径走路由层的 FTS5(不调 LLM),异步批量走 Deriver(产生 explicit observations 给 Dreaming 消费)。
  4. 写入路径代理是关键设计点——路由层不能”嵌入”Honcho,需要在 Honcho SDK 外面包一层,确保写入顺序:先写 Honcho → 更新 FTS5 → 写入 ACL 元数据。
  5. 代码规模参考——如果未来决定自研 Simplified Honcho,Dreaming(2853 行)+ Deriver(2558 行)是两座大山。集成方案只需要我们自己写约 2100 行新代码。