会话管理¶
Echo Agent 的会话系统为每个对话键提供独立的模型上下文,支持多通道、多会话并发交互。
会话隔离不是访问控制
会话键防止一个对话的 working context 误混入另一个对话,但它不证明“谁有权读这个会话”。Dashboard 会话页与 session_search 本来就可以跨会话查看/搜索实例状态。互不信任的用户不应只靠会话键或每人一枚 API Token 共享实例;详见安全模型。
会话键组成¶
会话键由通道与会话两段组成,形如 {channel}:{chat_id},实现见 InboundEvent.session_key:
| 组成部分 | 来源 | 说明 |
|---|---|---|
channel |
event.channel |
通道注册名,如 slack、weixin、telegram |
chat_id |
event.chat_id |
平台侧的会话标识,私聊与群聊都用这一字段 |
若事件带有 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 策略,而非会话键本身的结构。
会话生命周期¶
创建¶
当收到新的复合键对应的首条消息时,系统自动创建会话。会话数据类包含以下字段:
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 连接与会话的映射关系
- 处理连接断开后的会话状态保持
- 支持会话在连接恢复后续接
会话的空闲回收由网关的会话策略控制,单位是分钟:
会话搜索¶
session_search 工具用于在会话历史中检索信息:
- 支持跨会话的全文搜索
- 可按通道、用户、时间范围过滤
- 返回匹配消息及其上下文
Dashboard 会话页面¶
Dashboard 的 Sessions 页面提供会话的可视化管理:
- 查看所有活跃会话列表
- 查看会话详情和消息历史
- 按通道、用户筛选会话
- 监控会话状态和过期情况
相关文件¶
| 文件 | 职责 |
|---|---|
session/manager.py |
会话管理器:隔离、持久化、过期、归档 |
gateway/session_context.py |
网关层会话上下文 |
gateway/session_policy.py |
会话策略配置 |
gateway/ws_session.py |
WebSocket 会话管理 |