CLI vs Telegram Gateway 核心机制分析

一、架构总览

CLI 模式(单进程同步)

┌──────────────────────────────────────────┐
│  HermesCLI (一个进程)                      │
│  ┌─────────────┐  直接调用   ┌──────────┐ │
│  │  cmdloop()  │ ────────> │ AIAgent  │ │
│  │  read-eval  │ <──────── │ run_conv │ │
│  │  -print     │  同步返回   │          │ │
│  └─────────────┘           └──────────┘ │
│  一个进程 = 一个会话                        │
└──────────────────────────────────────────┘

Telegram Gateway 模式(异步事件驱动)

┌─────────────────────────────────────────────────────────────┐
│  Gateway (asyncio, 多会话复用)                                │
│                                                              │
│  会话A ← Telegram适配器 ← 用户1                               │
│  会话B ← Telegram适配器 ← 用户2    ┌───────────────────────┐  │
│  会话C ← Discord适配器  ← 用户3    │ AIAgent (线程池)       │  │
│                    ...           │ run_conversation()     │  │
│                        ────────> │ 每次消息 fork 线程执行   │  │
│                        <──────── │                       │  │
│  中断机制: 新消息 → interrupt_event → 旧轮停止                │
└─────────────────────────────────────────────────────────────┘

二、逐项对比

维度CLITelegram Gateway
进程模型单进程同步 REPLasyncio 事件循环 + 线程池
会话管理1 CLI 进程 = 1 会话1 Gateway 管理 N 会话 × M 平台
消息处理直接调 run_conversation()_process_message_background() → 异步编排
中断机制无(必须等当前轮完成)新消息 → interrupt_event → 旧轮停止
工具过滤全部可用_get_platform_tools() 按平台过滤
正在输入提示_keep_typing() 每 2 秒刷新
消息投递print() 到 stdout平台适配器的 send_message()
多用户共享单用户交互群组 topic 模式下多人可参与同一会话
tool progress内联 ANSI 渲染消息编辑模式
session 持久化SessionStore (SQLite)同上,共用同一套引擎

三、核心引擎相同

CLI 和 Telegram 共享同一套核心引擎:

  • run_conversation() — agent/conversation_loop.py
  • AIAgent — run_agent.py
  • 同一套 tool call 执行引擎
  • 同一套 context compression
  • 同一套 SQLite session 存储
  • 同一套 skill/memory 系统

差异仅在交互层:消息来源不同(stdin vs Telegram webhook)、投递方式不同(print vs send_message)、中端机制不同(无 vs interrupt_event)。

四、会话隔离规则(源码级)

build_session_key 源码

# 文件: gateway/session.py, 第 600-665 行

def build_session_key(source, group_sessions_per_user=True, thread_sessions_per_user=False):
    # DM: 按 chat_id 隔离
    if source.chat_type == "dm":
        return f"agent:main:{platform}:dm:{dm_chat_id}"

    # 非 DM: 关键规则
    isolate_user = group_sessions_per_user        # 默认 True
    if source.thread_id and not thread_sessions_per_user:  # thread 默认共享
        isolate_user = False                      # ← 不隔离!所有人共享

    if isolate_user and participant_id:
        key_parts.append(str(participant_id))     # 仅非 thread 时加 user_id

    return ":".join(key_parts)

实际 session_key 示例

场景session_key 格式
CLI 默认agent:main:cli
Telegram DMagent:main:telegram:dm:-100xxxx
Telegram 群组(非 topic)agent:main:telegram:group:-100xxxx:user_id_xxx(每人独立)
Telegram 群组 topicagent:main:telegram:group:-100xxxx:thread_yyy(所有人共享)

多用户消息标记

# 文件: gateway/run.py, 第 7950 行
if _is_shared_multi_user and source.user_name:
    message_text = f"[{source.user_name}] {message_text}"

agent 眼中看到的格式:

[at] 帮我改代码
[zhangsan] 我也看一下
[at] 这里报错了

所有消息按时间顺序混编成一个对话历史提供给 AIAgent。

五、多用户记忆限制分析

为什么无法成长性识别每个人风格

1. 记忆系统没有用户维度

memory 工具和 fact_store 是整个 Hermes 实例全局的。CLI、Telegram、Dashboard 存的记忆所有人都读得到。没有 user_id 作为记忆的 scope key。

关键源码路径:

  • agent/memory_provider.pyMemoryProvider 抽象类:load()/save() 没有 user_id 参数
  • plugins/memory/holographic/__init__.pyHolographicMemoryProvider 同样无用户维度
  • tools/memory_tool.pymemory 工具的 handler 不识别调用者身份

2. session key 不区分用户

同一个 topic 里,每个人的消息进同一个 session_key,同一个 AIAgent 实例。run_conversation() 加载的 conversation_history 是所有人的混编消息。

3. [at] 前缀只是纯文本标签,不是身份

agent 看到 [at] / [zhangsan] 知道是谁在说话,但没有:

  • 独立的 user_profile 存储
  • 每个用户的记忆隔离空间
  • 从对话中自动提取"某人的风格"并归类的机制

如果要实现需要改什么

# 需要新增(目前不存在)
class UserProfile:
    user_id: str
    display_name: str
    communication_style: str  # "简洁" / "详细" / "代码优先"
    preferences: dict
    memory_scoped_to_user: List[str]

# memory 工具需要加 user_id scope
memory(action="add", target="user", content="...", scope_user="at")

# run_conversation 需要按 user_id 加载独立 profile 到 system prompt
system_prompt += f"\n当前用户 {user_name} 的风格偏好: {profile}"

六、总结

场景推荐使用原因
STDD 项目开发(高强度编码)CLI ✅视野全、响应快、无截断、实时看 tool call 输出
查看状态报告、轻度交互Telegram ✅移动端方便、可中断、多人可看
多人协作同一 agentTelegram topic ⚠️共享会话但无个人风格记忆