Skip to content

16.5. Stream:聊天流是什么

导读 本章介绍"聊天流"这个概念。一个"聊天流"是 Neo-MoFox 里"一个会话上下文"的运行时容器:一个群或一个私聊各对应一个流。本章先把 stream_id / ChatStream / StreamContext / ChatStreams 表这四层概念讲清楚,再说明 ChatStream / StreamContext 上能读哪些字段。至于具体怎么用 stream_api 管理流(创建、查询、清空上下文等),见 第 24 章 Stream API

前面几章里,stream_id 这个东西其实已经到处出现过了:

  • Chatter 拿到的是 self.stream_id
  • Tool / Agent / Command 都有 self.stream_id
  • Action 拿到的是 self.chat_streamChatStream 对象本身,读 .stream_id 即可)
  • 命令上下文里有 ctx.stream_id
  • 后面讲发消息 / 查消息时,依然要传 stream_id

也就是说,几乎每个和"对话"沾边的组件,都绑着一个 stream_id。但你可能一直没机会正面看清它背后到底是什么。

这一章就来正面回答:

这个 stream_id 背后的"聊天流"到底是什么。

16.5.1 先把一句话记住:聊天流是一个会话上下文的运行时容器

很多插件作者第一次看到 stream,会下意识把它理解成"聊天记录"或"消息列表"。

这种理解不能算错,但漏掉了它最关键的一层定位。

更准确的说法是:

一个聊天流(ChatStream)是"一个会话上下文"的运行时容器——一个群对应一个流,一个私聊也对应一个流。

也就是说,stream 不是"消息本身",而是"消息活在里面的那个上下文"。

它同时持有:

  • 身份信息:这是哪个平台、哪个群 / 哪个用户、Bot 是谁
  • 内存上下文StreamContext——历史消息缓冲、未读消息、当前消息
  • 数据库记录ChatStreams 表里那行持久化的流元信息

所以从结构上看,一个流同时跨了三层:

text
内存层    ChatStream + StreamContext(运行时对象,进程重启会丢)

管理层    stream_api(创建、查询、加载、清空)

持久层    ChatStreams 表(流的元信息)+ Messages 表(流的消息)

stream_api 就处在中间这层——它负责把内存对象和数据库记录串起来,让插件作者不用直接操作底层。这一层 API 的具体用法见 第 24 章,本章只把"流是什么"立住。

16.5.2 先把四个名词彻底分清

这一节非常重要,因为后面所有和 stream 相关的内容都建立在这四个名词上。

名词是什么在哪
stream_id流的唯一标识符,SHA-256 哈希到处都是,作为 key 出现
ChatStream流的运行时对象,持身份信息 + 内存上下文进程内存(StreamManager._streams 字典)
StreamContext流的内存上下文,存历史 / 未读 / 当前消息挂在 ChatStream.context
ChatStreams流的数据库记录,存 stream_id / platform / group_id / 时间戳主数据库

它们的关系可以这样理解:

text
ChatStreams 表(持久)
    └─ 一行 = 一个流的存在证明
       ↓ stream_api.build_stream_from_database()
ChatStream(内存)
    ├─ stream_id        ← 来自 DB
    ├─ platform         ← 来自 DB
    ├─ chat_type        ← 来自 DB(private / group / discuss)
    ├─ bot_id          ← 由 stream_api 从适配器回填
    ├─ stream_name      ← 群名 / 用户名
    └─ context: StreamContext(内存)
        ├─ history_messages   ← 从 Messages 表加载(带数量上限)
        ├─ unread_messages   ← 运行时新进来的、还没被 Chatter 消化的
        ├─ current_message    ← 当前正在处理的那条
        └─ is_chatter_processing ← Chatter 是否正在跑

记住这张图,你后面看 stream_api 的任何函数,都能立刻知道它在操作哪一层。

16.5.3 ChatStreamStreamContext 上能读什么

虽然这一章不展开 stream_api 的函数(那是 第 24 章 的事),但你拿到的 ChatStream / StreamContext 对象上也有不少可读字段。这一节列一下,方便你写插件时知道"哪些东西能直接读"。

ChatStream 可读字段

字段类型说明
stream_idstr流的唯一标识(SHA-256 哈希)
platformstr平台标识,如 "qq"
chat_typestr"private" / "group" / "discuss"
bot_idstrBot 在该平台的 ID(由 stream_api 从适配器回填)
bot_nicknamestrBot 昵称
stream_namestr流名(群聊=群名,私聊=用户名,可能为空)
create_timefloat创建时间戳
last_active_timefloat最后活跃时间戳
contextStreamContext内存上下文对象

StreamContext 可读字段

字段类型说明
stream_idstr所属流 ID
chat_typestr聊天类型
max_history_messagesint历史消息保留上限(默认 100)
history_messageslist[Message]历史消息(已处理过的)
unread_messageslist[Message]未读消息(等 Chatter 消化的)
current_messageMessage | None当前正在处理的那条
is_activebool是否活跃
is_chatter_processingboolChatter 是否正在处理
last_message_timefloat | None最近一次收到新消息的时间戳

读可以,写要小心

这些字段里,history_messages / unread_messages / current_message 原则上由系统维护。如果你直接改它们,可能会和 Chatter 的内部状态对不上。需要清空时,永远走 stream_apiclear_context / load_and_clear_context / bulk_clear_streams(见 第 24 章),不要自己 stream.context.history_messages.clear()

16.5.4 这一章先收在这里

如果把这一章压成最后几句话,我最希望你记住的是:

  1. 一个聊天流(ChatStream)是"一个会话上下文"的运行时容器,一个群或一个私聊各对应一个流;它跨内存(ChatStream + StreamContext)和 DB(ChatStreams + Messages)两层。
  2. 四个名词要彻底分清stream_id 是 key、ChatStream 是运行时对象、StreamContext 是内存上下文、ChatStreams 表是持久记录。
  3. ChatStream / StreamContext 上的字段读可以,写要小心——history_messages / unread_messages 原则上由系统维护。

到这里为止,"聊天流是什么"已经立住了。接下来如果你想知道"作为插件作者,我具体怎么创建、查询、清空一个流",那就进入 第 24 章 Stream API

贡献者

The avatar of contributor named as micraft1024a micraft1024a

页面历史

Released under the GPL-3.0 License.