跳转至

会话管理

Echo Agent 的会话系统为每个对话键提供独立的模型上下文,支持多通道、多会话并发交互。

会话隔离不是访问控制

会话键防止一个对话的 working context 误混入另一个对话,但它不证明“谁有权读这个会话”。Dashboard 会话页与 session_search 本来就可以跨会话查看/搜索实例状态。互不信任的用户不应只靠会话键或每人一枚 API Token 共享实例;详见安全模型

会话键组成

会话键由通道与会话两段组成,形如 {channel}:{chat_id},实现见 InboundEvent.session_key

组成部分 来源 说明
channel event.channel 通道注册名,如 slackweixintelegram
chat_id event.chat_id 平台侧的会话标识,私聊与群聊都用这一字段
slack:C67890

若事件带有 session_key_override,则直接采用该值,不再按上述规则拼接。

群聊内按人隔离

群聊场景下可以进一步把发送者纳入键,由 scoped_session_key(scope) 决定:

scope 私聊 群聊
shared slack:C67890 slack:C67890(整群共用一个会话)
per_user slack:D1 slack:C67890:U12345(群内每人独立)

per_user 只在群聊且存在 sender_id 时才追加发送者后缀;私聊下两种策略结果一致。拼接是幂等的,已含发送者后缀的键不会被重复拼接。

隔离模型

同一用户在不同通道、不同群组中的消息互不干扰。是否在群内按人隔离取决于 scope 策略,而非会话键本身的结构。

会话生命周期

创建 → 活跃(active) → 过期(expired) → 归档(archived)

创建

当收到新的复合键对应的首条消息时,系统自动创建会话。会话数据类包含以下字段:

  • key — 复合键
  • messages — 消息列表
  • created_at — 创建时间
  • updated_at — 最后更新时间
  • metadata — 元数据
  • last_consolidated — 最后合并位置
  • status — 状态(active / expired / archived)

活跃

会话处于活跃状态时,持续接收和处理消息。每次交互更新 updated_at 时间戳。

过期

当会话超过 session.expiryHours(默认 72 小时)未活动时,状态变为 expired

过期不是终态:只要该会话仍在内存缓存中,下一次访问会把状态改回 active 并刷新 updated_at,对话得以延续,无需新建会话。这一自动恢复只发生在缓存命中的情况下。

归档

expired 会话在静默满 168 小时(7 天)后进入 archived,并从内存缓存中移除,因此不会像 expired 那样被访问唤回。该时长目前固定在代码中,没有对应的配置项。

归档的落点取决于存储后端:使用数据库后端时,会话留在库中,仅 status 字段变为 archived;使用文件存储时,会话文件被移动到 sessions/archive/ 子目录。

两级状态流转都由 cleanup_expired 批量执行——它扫描会话列表,把该过期的标为过期、把该归档的归档,并返回处理条数;单个会话也可以通过接口单独归档。

历史消息管理

消息数量限制

get_history(max_messages) 方法返回最近的消息记录,默认上限 500 条。

合并边界对齐

历史消息截取时自动对齐到安全边界,确保不会产生孤立的 tool-result 消息。

合并边界

如果截取点落在 tool-call / tool-result 消息对中间,系统会自动向前调整, 避免返回没有对应 tool-call 的孤立 tool-result 消息。

添加消息

session.add_message(role="user", content="你好")
session.add_message(role="assistant", content="你好!有什么可以帮助你的?")

配置

通过 SessionConfig 配置会话行为:

session:
  max_history_messages: 500      # 历史消息最大条数
  expiry_hours: 72               # 会话过期时间(小时)
  context_window_tokens: 128000  # 上下文窗口 token 数
参数 默认值 说明
max_history_messages 500 单次获取历史的最大消息数
expiry_hours 72 无活动后会话过期时间
context_window_tokens 上下文窗口 token 限制

多通道会话隔离

Session Manager 按不同会话键维护独立的消息历史与模型上下文:

# 同一用户在不同通道的独立会话
- channel: slack
  user: alice
  chat: general
  thread: null

- channel: wechat
  user: alice
  chat: group-01
  thread: null

跨通道搜索

session_search 工具支持跨通道搜索会话历史,但会话上下文本身保持隔离。

WebSocket 会话

ws_session.py 提供 WebSocket 长连接的会话管理能力:

  • 维护 WebSocket 连接与会话的映射关系
  • 处理连接断开后的会话状态保持
  • 支持会话在连接恢复后续接

会话的空闲回收由网关的会话策略控制,单位是分钟:

gateway:
  session_policy:
    idle_timeout_minutes: 1440   # 会话空闲超时(分钟),默认 1440 即 24 小时

会话搜索

session_search 工具用于在会话历史中检索信息:

  • 支持跨会话的全文搜索
  • 可按通道、用户、时间范围过滤
  • 返回匹配消息及其上下文

Dashboard 会话页面

Dashboard 的 Sessions 页面提供会话的可视化管理:

  • 查看所有活跃会话列表
  • 查看会话详情和消息历史
  • 按通道、用户筛选会话
  • 监控会话状态和过期情况

相关文件

文件 职责
session/manager.py 会话管理器:隔离、持久化、过期、归档
gateway/session_context.py 网关层会话上下文
gateway/session_policy.py 会话策略配置
gateway/ws_session.py WebSocket 会话管理