TencentDB-Agent-Memory 开源贡献手记:孤儿 Agent 级联删除的修复与验证

TencentDB-Agent-Memory 开源贡献手记:孤儿 Agent 级联删除的修复与验证

muzimu217

2026-09-19 发布50 浏览 · 0 点赞 · 0 收藏

摘要:在 TencentDB-Agent-Memory 中,当成员被移出团队或用户被删除时,其创建的 Agent 会变成 owner 悬空的「孤儿 Agent」,且任何角色都无法删除,最终导致前端 403、团队资源卡死。本文记录 issue #1321 的根因分析、修复方案和验证过程,并分享我们用于组织开源贡献的工作流。

关键词:TencentDB-Agent-Memory, Agent Memory, 开源贡献, 级联删除, 数据一致性


一、项目背景

TencentDB-Agent-Memory 是腾讯开源的 Agent 记忆层项目,提供 L0–L3 四层记忆、Memory Hub、知识库等能力,供大模型 Agent 在长期对话中保持上下文。它采用 Node/TypeScript 服务层 + SQLite/MongoDB 持久化的架构。

最近我围绕该项目参与了一次开源贡献挑战,选题是 #1321 孤儿 Agent 级联删除。这个问题影响面比较典型:团队人员流动后,旧 Agent 既占资源又无法清理,属于「看着小、踩坑深」的类型。

二、问题现象

移出团队成员或删除用户后:

  • 该用户创建的 Agent 的 owner_user_id 仍然指向已被删除的用户;
  • Agent 删除接口原本只校验「是否为 owner」,没有考虑 admin / team admin 的兜底权限;
  • 结果是:任何角色(包括系统管理员)都删不掉这些 Agent;
  • 团队面板里残留可见的「孤儿 Agent」,访问时前端返回 403,相关 skill 也被卡死。

三、根因分析

issue 里把问题拆成三条互相咬合的缺陷链:

  1. removeTeamMemberForCaller 只删除成员行,没有级联清理该成员的 Agent;
  2. deleteUsers 清除了 keys、members、acl,却漏了 meta_agents;
  3. deleteAgentsForCaller 直接调用 assertCallerIsAgentOwner,没有参考 isSystemAdmin;而 assertCallerIsAgentOwnerOrTeamAdmin 其实已经存在,只是没被用上。

简单说:删人时忘了删 Agent;删 Agent 时又只认 owner,不认管理员。

四、修复方案

基于 issue 给出的预期,我在 代码厂/m3-orphan-agent-fix 做了以下改动(核心 5 步):

  1. 人员删除前级联收集 Agent:在 removeTeamMemberForCaller / deleteUsersForCaller 里,先收集目标用户的 Agent 列表,再执行硬删除(admin 校验已在前置流程建立)。
  2. 放宽删除权限校验:deleteAgentsForCaller / archiveAgentForCaller 改用 assertCallerIsAgentOwnerOrTeamAdmin;当 isSystemAdmin 为 true 时直接跳过 owner 校验。
  3. Panel 权限对齐:delete-cascade 权限从 owner-only 放宽到 owner / team admin / system admin。
  4. 团队删除时完整级联:deleteTeams(sqlite + mongodb 同步实现)先收集该团队下所有 agent_ids,再调用 deleteAgents() 走完整级联,避免残留 task_agents、fixed_assets、chat_memory。
  5. 补契约测试:新增 IMetadataStore 级联删除契约测试,覆盖 sqlite / mongodb 两种存储形态。

额外考虑的安全兜底:与其直接硬删,未来可以更温和地先做 ownership transfer(把孤儿 Agent 转给 team admin),避免误删活跃资产。这次先按 issue 预期完成级联清理,transfer 作为后续优化点。

五、验证证据

本地与测试服务器都跑了一遍:

  • 服务层:metadata-service.agent-access.test.ts 8/8 通过;
  • SQLite 契约测试:sqlite-adapter.test.ts 61/61 通过(58 个存量 + 3 个新增级联场景);
  • MemoryCore 全量:69 passed / 61 skipped(mongodb 无 URI 自动 skip)/ 0 failed;
  • 类型检查:改动生产代码无新增 TypeScript 错误;
  • 诚实声明:memory-core/hub/proxy 三件套完整部署联调、MongoDB 真实服务端持久化验证尚未覆盖,已在成果卡中标注为「未验证」。

六、我们的组织方式:四厂 + 多方向并行

这次贡献不是「看 issue 直接改代码」的线性流程。为了能在 90 分钟现场里同时推进多个方向,我们把工作区分成四厂:

  • 规划厂:放总控手册、经验复用指南、成果卡模板;
  • 代码厂:每个选题生成一个独立的方向文件夹(如 pi-profile-fix、m3-orphan-agent-fix);
  • 文章厂 / 分类:放成果卡草稿、技术短文、00-总索引;
  • 统一产出物:每方向以 成果展示卡.html + 设计说明.md + 参展贴.md 交卷。

工作流上,选方向可以多选;复刻公开 PR / issue 根因是可选环节,没有现成经验就直接进入本地开发验证。所有成果在「向外审批」前都由人工确认。

七、结语

#1321 是一个典型的「删除语义不完整」问题:人员级联删除缺一环,权限校验又过严,结果导致资源悬空。修复它的核心不是加功能,而是把「谁该被删、谁能删、删的时候还要清什么」这三件事对齐。这次修复和验证给了我一个比较干净的闭环,也验证了「四厂 + 方向文件夹 + 可选复刻」这种工作流在短时间开源贡献里的可行性。

如果你也在做 Agent Memory 相关贡献,欢迎在 issue 下交流,或者一起聊聊 ownership transfer 这类更安全的清理策略。

请前往 登录/注册 即可发表您的看法…