问题描述
控制面使用 PostgreSQL(官方支持的标准配置,见 docs/configuration.md §"Agent memory vs control plane" 与 ADR 002)时,agent 记忆按默认规则自动指向同一 PG DSN(octop/infra/agents/memory_backend.py 的 use_control_plane_dsn 路径)。此时 harness-memory 的整条记忆管道静默失效:capture / recall / extract / GC 全部失败,memory_search 恒空,长期跨会话记忆实际不可用,且每条消息都会触发一批必然失败的 PG 查询(日志噪音 + 额外延迟)。
PG 中 harness_memory schema 12 张表 DDL 正常创建,但所有表 0 行——从未有数据写入成功。
环境
- Octop: 0.9.28(官方安装脚本)
- Python: 3.12
- harness-memory: 0.9.7(PyPI 最新版)
- 控制面: PostgreSQL(12 表 schema 正常创建)
- OS: Ubuntu (Linux x86_64)
最小复现
- 控制面选择 PostgreSQL(setup 向导或
OCTOP_DATABASE_* 环境变量)。
- 保持 agent 记忆默认启用(不设置
memory.backend → 自动走 PG 控制面 DSN)。
- 正常对话若干轮。
- 检查 PG:
SELECT count(*) FROM harness_memory.atoms; → 0;memory_search 工具无任何结果;日志中记忆管道持续报错。
根因分析
存储层(storage/backends/postgres.py)是完整的:独立 DDL + 全套公共 API(save/list/search/delete raw/atom/candidate/node 等)。问题在 lifecycle 管道层直接绕过存储层公共 API、硬编码 SQLite 方言:
-
pipeline/lifecycle/gc.py:285-291 — _sqlite_conn(memory) 读取 SQLite 后端私有属性 backend._conn(PG 后端无此语义),随后:
- L242:
conn.execute(f"SELECT quote_event_id, raw_event_ids FROM {ns}_atoms")
- L247:
conn.execute(f"SELECT raw_event_ids FROM {ns}_candidates")
- L305:
conn.execute(f"DELETE FROM {ns}_atoms WHERE id = ?", (atom_id,))
两处 SQLite-only 假设:{ns}_ 表前缀是 SQLite 的命名空间机制(PG 后端用独立 schema 隔离);? 占位符在 psycopg(%s)下无效。
-
pipeline/lifecycle/maintenance.py:300-307 — conn.in_transaction(aiosqlite API)+ PRAGMA wal_checkpoint(TRUNCATE)(SQLite 专属 PRAGMA,PG 下直接报错)。
-
pipeline/lifecycle/vacuum.py — SQLite VACUUM 语句(PG 的 autovacuum 机制完全不同)。
-
pipeline/lifecycle/checkpoint_gc.py — 同类问题。
影响面
- 所有 PG 控制面部署(文档支持的配置)记忆系统整体不可用,不是部分降级。
- 每条消息都触发确定性失败的 PG 查询:日志噪音 + 可避免的延迟。
- 用户无法从表象判断是"记忆没生效"还是"后端坏了"(静默失败,无显著报错)。
建议修复方向
- lifecycle 管道改为只走 backend 公共 API(
list_atoms / list_candidates / 删除接口等),不访问 backend._conn;
PRAGMA/VACUUM 类操作做后端类型判断,PG 下跳过(autovacuum 兜底);
- 参照控制面的做法增加 PG 集成测试(
@pytest.mark.postgresql + OCTOP_TEST_DATABASE_URL gating),覆盖 capture → extract → recall → GC 全链路。
临时规避(已验证)
按 docs/configuration.md 在 agent 配置中设置:
"memory": { "backend": { "type": "sqlite" } }
记忆回落到 {workspace}/memory.sqlite,管道恢复正常。注意:checkpointer 与记忆后端同库(harness_agent/agent.py _resolve_checkpointer),切换后端会使旧线程的模型侧上下文重置(会话 JSONL 历史保留)。
附注
PyPI harness-memory 元数据指向的仓库 https://github.com/TencentCloud/harness-memory 当前 404(API 与网页均确认,GitHub 全站搜索无同名仓库),故在此仓库提报。
问题描述
控制面使用 PostgreSQL(官方支持的标准配置,见
docs/configuration.md§"Agent memory vs control plane" 与 ADR 002)时,agent 记忆按默认规则自动指向同一 PG DSN(octop/infra/agents/memory_backend.py的use_control_plane_dsn路径)。此时 harness-memory 的整条记忆管道静默失效:capture / recall / extract / GC 全部失败,memory_search恒空,长期跨会话记忆实际不可用,且每条消息都会触发一批必然失败的 PG 查询(日志噪音 + 额外延迟)。PG 中
harness_memoryschema 12 张表 DDL 正常创建,但所有表 0 行——从未有数据写入成功。环境
最小复现
OCTOP_DATABASE_*环境变量)。memory.backend→ 自动走 PG 控制面 DSN)。SELECT count(*) FROM harness_memory.atoms;→ 0;memory_search工具无任何结果;日志中记忆管道持续报错。根因分析
存储层(
storage/backends/postgres.py)是完整的:独立 DDL + 全套公共 API(save/list/search/delete raw/atom/candidate/node 等)。问题在 lifecycle 管道层直接绕过存储层公共 API、硬编码 SQLite 方言:pipeline/lifecycle/gc.py:285-291—_sqlite_conn(memory)读取 SQLite 后端私有属性backend._conn(PG 后端无此语义),随后:conn.execute(f"SELECT quote_event_id, raw_event_ids FROM {ns}_atoms")conn.execute(f"SELECT raw_event_ids FROM {ns}_candidates")conn.execute(f"DELETE FROM {ns}_atoms WHERE id = ?", (atom_id,))两处 SQLite-only 假设:
{ns}_表前缀是 SQLite 的命名空间机制(PG 后端用独立 schema 隔离);?占位符在 psycopg(%s)下无效。pipeline/lifecycle/maintenance.py:300-307—conn.in_transaction(aiosqlite API)+PRAGMA wal_checkpoint(TRUNCATE)(SQLite 专属 PRAGMA,PG 下直接报错)。pipeline/lifecycle/vacuum.py— SQLiteVACUUM语句(PG 的 autovacuum 机制完全不同)。pipeline/lifecycle/checkpoint_gc.py— 同类问题。影响面
建议修复方向
list_atoms/list_candidates/ 删除接口等),不访问backend._conn;PRAGMA/VACUUM类操作做后端类型判断,PG 下跳过(autovacuum 兜底);@pytest.mark.postgresql+OCTOP_TEST_DATABASE_URLgating),覆盖 capture → extract → recall → GC 全链路。临时规避(已验证)
按
docs/configuration.md在 agent 配置中设置:记忆回落到
{workspace}/memory.sqlite,管道恢复正常。注意:checkpointer 与记忆后端同库(harness_agent/agent.py_resolve_checkpointer),切换后端会使旧线程的模型侧上下文重置(会话 JSONL 历史保留)。附注
PyPI
harness-memory元数据指向的仓库https://github.com/TencentCloud/harness-memory当前 404(API 与网页均确认,GitHub 全站搜索无同名仓库),故在此仓库提报。