OpenClaw 中的 AI 助手为什么无法跨群组共享上下文?从第一性原理重新思考多渠道 Agent 架构

引言

想象一个场景:你有一个名叫 Javis 的 AI 助手。你在飞书的 A 群组告诉它某个技术决策,然后切换到 B 群组,却发现 Javis "忘记了"你在 A 群说过的话。你切换到私聊,结果 Javis 也不知道你在群里讨论过什么。

看起来像是"两个不同的 Javis"在回复你——但实际上,你确实在和同一个人说话

这不是 bug,而是 OpenClaw(一个开源 AI 代理框架)的架构设计选择的直接结果。本文将深入剖析这个问题的根本原因,以及我们如何从第一性原理出发重新思考多渠道 AI Agent 的设计。


第一部分:问题现象 & 身份认同的困惑

现象:同一个人,不同的"记忆"

当你和 Javis 互动时:

  • 在 A 群组:Javis 知道群里讨论过的技术方案、决策过程、参与者意见
  • 在 B 群组:Javis 对 A 群的任何内容都一无所知
  • 在私聊里:Javis 既不知道 A 群的事,也不知道 B 群的事
  • 切回 A 群:Javis 突然"恢复记忆",知道所有的讨论

本质认同问题

从 Feishu(飞书)API 的角度看:

  • user_id(开放平台的用户标识):ou_39f130f8fa1b499c91dee8bdb1eff90a —— 唯一标识一个用户
  • chat_id(会话标识):可以是 oc_group_aoc_group_boc_dm_xxx —— 标识不同的聊天渠道

从第一性原理出发:

  • 你是一个人:你的 user_id 是唯一的
  • Javis 是一个助手:应该也是一个统一的大脑
  • 群组、私聊只是"窗口":就像打开电话、微信、邮件,你还是同一个你

那么问题来了:为什么 Javis 在不同的"窗口"里,就变成了不同的自己?


第二部分:根本原因 - OpenClaw 的 Session 隔离机制

当前架构:按 chat_id 创建 Session

OpenClaw 的核心设计是这样的:

Feishu 消息进来
  ↓
识别 chat_id(这是 A 群组还是 B 群组?)
  ↓
如果是新的 chat_id → 创建一个新的 Session
  ↓
这个 Session 处理该 chat_id 的所有消息
  ↓
Session 拥有独立的:
  - 内存状态
  - 推理过程
  - 上下文管理
  - 决策历史

为什么这样设计?

这个选择看似是一个无奈的妥协,但背后有合理的工程考量:

1. 隐私隔离
  • A 群组讨论了你的年度计划(机密)
  • B 群组只是日常闲聊
  • 如果 Javis 不隔离这两个上下文,机密信息可能被无意中透露给 B 群的人
2. 上下文管理
  • 一个 LLM 的 context window(上下文窗口)有限制
  • 如果把所有会话的信息都混在一起,token 会快速耗尽
  • 只记得该 chat_id 的对话,可以保持较高的相关性和效率
3. 并发处理
  • 如果 A 群、B 群同时发来消息
  • 统一的大脑会产生竞争条件(race condition)
  • 用独立的 Session 更容易并发处理

看似合理的设计,实际的代价

问题在于,这个设计选择带来了一个难以接受的结果:

一个人在不同的地方和你聊天,却因为 chat_id 的不同,产生了"多重人格"

你在 A 群说:“我们决定用技术方案 X”
然后在 B 群问:“我们之前决定用什么方案?”
B 群里的 Javis:“不知道,你没在 B 群说过”

从 B 群的 Javis 的视角,这是"正确"的——因为它的 Session 确实没有 A 群的记录。但从你的角度,这是荒谬的——你在和同一个助手说话,它怎么会"健忘"呢?


第三部分:当前的尝试 & 它们为什么还不够

尝试 1:LanceDB 的语义存储

有人想到了一个办法:建立一个全局的向量数据库(LanceDB),把所有会话的内容都存储进去。这样,即使 Session 隔离,Javis 也可以主动查询任何历史内容。

A 群消息 ──┐
B 群消息 ──┼──→ 向量化 ──→ LanceDB(全局记忆)
DM 消息 ────┘                      ↓
                        Session A 可以查询
                        Session B 也可以查询

看起来不错,但问题是:

  • ✅ 数据确实被存储了
  • 但 Session 不会主动去查

除非你明确说"查一下之前的决策",否则 Javis 只会用当前 Session 的上下文来回答。这实际上变成了被动的记忆系统,而不是主动的一体化大脑

尝试 2:强制注入机制

有人想,那就修改 Prompt,告诉 Javis “每次回复前都主动查一下 LanceDB”。

System Prompt:
  "在每次生成回复前,主动从 LanceDB 搜索相关历史信息..."

看起来也不错,但新问题出现了:

  • ❌ 什么是"相关"?搜索范围无法精确定义
  • ❌ 每次都查,performance 成本高
  • ❌ Session 隔离的问题依然存在——你还是在和"两个 Javis"说话,只是它们偶尔会查一下共享的记忆

第四部分:从第一性原理出发的新架构

根本问题的重新定义

让我们回到本质:

Q:一个 user_id 对应的是一个人吗?
A:是的。

Q:一个 chat_id 对应的是不同的"地点"吗?
A:是的。

Q:一个人在不同的地点应该有"分身"吗?
A:不应该。

那么,为什么我们现在的设计是"按 chat_id 创建独立 Session"?

答案是:因为当前的架构缺乏一个更高层的抽象——用户级别的、跨越所有 chat_id 的统一 Session。

新架构:一个大脑,多个窗口

┌──────────────────────────────────┐
│    Javis Agent(唯一的大脑)      │
│  - 统一的思维过程                 │
│  - 单一的内存状态                 │
│  - 所有 user_id 的一个实例        │
└──────────────────────────────────┘
         ↑           ↑          ↑
    消息进入        处理       回复
         │           │          │
    ┌────┴────┬─────┴────┬─────┴────┐
    │          │          │          │
 Window A   Window B   Window C   Window DM
(A 群组)  (B 群组)  (C 群组)  (私聊)

关键点:

  1. 唯一的大脑:每个 user_id 对应一个 Javis 实例,而不是每个 chat_id
  2. 多个窗口:不同的 chat_id 只是输入/输出的管道,不产生新的思维
  3. 统一的内存:无论在哪个窗口收到的信息,都被记录到同一份内存里
  4. 隐私约束在应用层:不是架构层面的隔离,而是 Prompt 层面的隐私规则

这样做的好处

1. 一致性

你在 A 群说的话,Javis 在 B 群也知道。不再有"忘记"的问题。

2. 完整的推理链

Javis 的思考过程是连贯的。A 群的讨论会自然地影响 B 群的回复(如果相关的话)。

3. 真正的"一个人"

从第一性原理的角度,这符合人的直观理解:一个助手,一个大脑,多个沟通渠道

4. 隐私通过规则实现

不需要架构层的"强制隔离"。而是在 Prompt 里明确标注:

[隐私级别] 来自 A 群的私密信息
[可见范围] 仅限 A 群相关讨论时使用
[警告] 不能在 B 群、私聊中暴露

Javis 作为一个足够聪明的助手,理解这些约束,自然不会跨越界限。


第五部分:工程实现的关键点

如何修改 OpenClaw

这个新架构的实现思路很清晰:

改变 Session 创建的粒度

现在(错误):

message.chat_id → 创建/查找 Session

应该(正确):

message.user_id → 创建/查找 Agent Instance

这样,同一个用户的所有消息,无论来自哪个 chat_id,都进入同一个 Agent Instance。

消息的标准化与路由

每条消息进来时,需要标注:

{
  "user_id": "ou_xxx",
  "chat_id": "oc_group_a",
  "chat_type": "group",
  "sender_name": "Alice",
  "privacy_level": "public",  // 或 "private"
  "content": "..."
}
隐私约束在 Prompt 层实现

System Prompt 增加约束信息:

当前窗口: ${window.type}
隐私规则:
- [私密] 来自 DM 的信息不能在群聊中提及
- [公开] 群聊中讨论的技术方案可以跨群引用
- [内部] 仅涉及 user_id:ou_xxx 的信息不能暴露给其他用户
并发处理

如果同时来自 A 群、B 群、DM 的三条消息,同一个 Agent Instance 可以:

  • 用队列化处理(顺序)
  • 或用更细粒度的锁(性能优化)

第六部分:启示与对其他框架的意义

这个问题的通用性

OpenClaw 面临的这个问题,不是 OpenClaw 特有的,而是所有多渠道 AI Agent 框架的共同挑战:

  • Discord 的 bot
  • Slack 的应用
  • 微信机器人
  • Telegram bot
  • ……

任何在多个渠道工作的 AI 助手,都会面临这个选择:用 chat_id(或 channel_id)创建独立实例,还是用 user_id 创建统一实例?

为什么这个问题没有被广泛关注?

  1. 大多数场景不需要跨渠道一致性
    一个仅在 Discord 特定频道工作的 bot,用户不会期望它在 DM 里"记得"频道的讨论。

  2. 技术债务被忽视
    问题存在,但不紧迫。LanceDB 这样的"记忆补丁"暂时解决了最坏情况。

  3. 架构重构成本高
    改变 Session 的创建粒度,会影响整个框架的核心逻辑。

OpenClaw 的机会

OpenClaw 正在构建一个通用的、可扩展的 Agent 框架,它有机会从一开始就做对。

如果 OpenClaw 从第一性原理出发,采用"一个大脑,多个窗口"的架构,它会成为:

  • 更符合人类直觉的 Agent 框架
  • 更容易构建多渠道协调 Agent 的平台
  • 更有竞争力的开源项目

结论:从隐喻回到现实

"一个大脑,多个窗口"不仅是一个架构原则,更是对什么是"一个人"的定义的重新思考。

在飞书上,当我和 Javis 互动时,我本能地认为我在和一个一致的、连贯的、有记忆的助手说话。我不期望它在 A 群"一个样",在 B 群"另一个样"。

但当前 OpenClaw 的架构给了我的体验是:多个"分身"在不同的地方回复我

这不是技术限制,而是架构设计的选择

而我们有机会做出不同的选择。


后记:这个问题的启蒙来源

这篇文章源于一个真实的对话。一个 OpenClaw 开发者在实现 Javis(一个多渠道 AI 助手)时,发现了这个问题。他提出了一个简单而深刻的问题:

“为什么我在和同一个人(按 user_id)说话,但系统把我当作在和不同的人(按 chat_id)互动?”

这个问题打破了我对架构的一些假设,促使我重新从第一性原理思考:什么是一个 Agent?它的身份应该如何定义?

答案并不复杂。但实现它,需要从根本上改变我们对多渠道 Agent 的思考方式。

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐