2276 字
约 7 分钟
2
AI 聊天数据如何写入 Cassandra:从一次对话到可持久化的消息记录

AI 聊天数据如何写入 Cassandra:从一次对话到可持久化的消息记录

做 AI 聊天应用时,用户发出的提问、模型生成的回答、工具调用记录和流式输出状态,都需要被可靠保存下来。

如果系统用户量不大,用 MySQL 或 PostgreSQL 保存聊天记录完全没有问题。但当聊天消息量持续增长、写入并发很高、服务还需要多机房高可用时,Apache Cassandra 是一个值得考虑的选择。

这篇文章以“将 AI 聊天数据存入 Cassandra”为例,讲清楚它适合解决什么问题、表应该怎么设计,以及一次消息从产生到落库的基本流程。

一、为什么 AI 聊天应用需要持久化数据?

一条 AI 对话看起来只是用户问一句、模型答一句,但实际往往会产生多类数据:

  • 用户消息,例如“帮我写一封邮件”;
  • AI 回复,例如模型最终生成的内容;
  • 流式输出片段,例如逐字返回的 Token;
  • 会话元信息,例如标题、创建时间、使用的模型;
  • 工具调用,例如搜索、数据库查询、代码执行;
  • 审计和行为记录,例如点赞、踩、复制、重新生成;
  • 用量数据,例如 Token 消耗、响应时长、调用次数。

这些数据不仅用于展示聊天历史,也用于问题排查、统计分析、模型评估和合规审计。

当系统规模变大后,聊天记录通常有两个特点:

  1. 写入很多:每次对话至少写入用户消息和 AI 回复。
  2. 查询模式固定:最常见的查询是“读取某个会话的历史消息”。

这正是 Cassandra 擅长的场景。

二、整体数据流长什么样?

一次典型的 AI 对话流程可以理解为:

用户发送问题
   ↓
后端创建用户消息并写入 Cassandra
   ↓
后端调用大模型
   ↓
模型以流式方式返回内容
   ↓
后端将最终回复或分段内容写入 Cassandra
   ↓
前端显示回复;后续可从 Cassandra 恢复历史会话

重点在于:Cassandra 负责保存高频、海量的聊天消息;模型推理仍由大模型服务完成。

三、先明确查询需求,再设计表

使用 Cassandra 时,不要先想着“我要存哪些字段”,而要先想“我要怎么查”。

一个 AI 聊天系统最常见的需求是:

给定 conversation_id,按时间顺序读取该会话的消息。

因此,conversation_id 很适合作为分区键(Partition Key),消息时间或消息 ID 适合作为排序字段。

四、创建 Keyspace 和消息表

先创建一个 Keyspace。开发环境可以使用简单复制策略:

CREATE KEYSPACE ai_chat
WITH replication = {
  'class': 'SimpleStrategy',
  'replication_factor': 1
};

进入 Keyspace:

USE ai_chat;

接着创建聊天消息表:

CREATE TABLE chat_messages (
  conversation_id text,
  message_id timeuuid,
  role text,
  content text,
  model text,
  status text,
  created_at timestamp,
  token_count int,
  PRIMARY KEY (conversation_id, message_id)
) WITH CLUSTERING ORDER BY (message_id ASC);

这张表中:

字段 用途
conversation_id 会话 ID,也是分区键
message_id 基于时间生成的唯一 ID,用于排序
role 消息角色,如 userassistantsystemtool
content 消息正文
model 产生回复的模型名称
status 消息状态,如 streamingcompletedfailed
created_at 创建时间
token_count Token 使用量,可用于计费或统计

主键 PRIMARY KEY (conversation_id, message_id) 的含义是:

  • 同一个会话的数据聚集在一起;
  • 同一个会话内,消息会按照 message_id 的时间顺序排序;
  • 查询某个会话的历史消息会很快。

五、写入用户消息和 AI 回复

当用户发送消息时,后端可以先写入一条 user 类型的消息:

INSERT INTO chat_messages (
  conversation_id,
  message_id,
  role,
  content,
  status,
  created_at
) VALUES (
  'conv_10001',
  now(),
  'user',
  '帮我解释一下什么是 Cassandra',
  'completed',
  toTimestamp(now())
);

模型生成回复后,再写入一条 assistant 消息:

INSERT INTO chat_messages (
  conversation_id,
  message_id,
  role,
  content,
  model,
  status,
  created_at,
  token_count
) VALUES (
  'conv_10001',
  now(),
  'assistant',
  'Cassandra 是一个分布式 NoSQL 数据库……',
  'gpt-5',
  'completed',
  toTimestamp(now()),
  128
);

读取整个会话的历史记录:

SELECT * FROM chat_messages
WHERE conversation_id = 'conv_10001';

因为查询条件中包含了分区键 conversation_id,这是 Cassandra 推荐的高效查询方式。

六、如何处理流式输出?

AI 聊天通常是流式返回的:模型不是一次性给出完整回答,而是不断推送一小段内容。

这里有两种常见保存方式。

方式一:完成后再保存完整回复

这是最简单、最推荐的入门方案。

流程是:

  1. 前端实时收到模型输出;
  2. 后端在内存中累积完整内容;
  3. 模型结束后,把完整回复写入 Cassandra。

优点是表结构简单、查询方便、写入次数少。

缺点是如果服务在生成过程中异常退出,尚未完成的内容可能丢失。

方式二:分段保存流式内容

如果业务要求断线恢复或保留完整生成过程,可以保存每个内容片段:

CREATE TABLE chat_message_chunks (
  conversation_id text,
  message_id timeuuid,
  chunk_index int,
  content text,
  created_at timestamp,
  PRIMARY KEY ((conversation_id, message_id), chunk_index)
) WITH CLUSTERING ORDER BY (chunk_index ASC);

每生成一段内容,就写入一条 chunk:

INSERT INTO chat_message_chunks (
  conversation_id,
  message_id,
  chunk_index,
  content,
  created_at
) VALUES (
  'conv_10001',
  8f52b8b0-0000-11f0-8000-000000000001,
  1,
  'Cassandra 是',
  toTimestamp(now())
);

恢复消息时,按 chunk_index 读取并拼接即可。

不过不要为了每一个 Token 都立刻写数据库。更实用的做法是按几十到几百个字符、或按固定时间间隔进行批量写入,避免产生过多微小写操作。

七、会话元信息应该放在哪里?

除了消息内容,系统通常还需要保存会话标题、所属用户、创建时间和最后活跃时间。

可以单独创建一张会话表:

CREATE TABLE conversations_by_user (
  user_id text,
  updated_at timestamp,
  conversation_id text,
  title text,
  model text,
  created_at timestamp,
  PRIMARY KEY (user_id, updated_at, conversation_id)
) WITH CLUSTERING ORDER BY (updated_at DESC);

这样就可以支持另一个常见查询:

查询某个用户最近的会话列表。

查询示例:

SELECT * FROM conversations_by_user
WHERE user_id = 'user_001'
LIMIT 20;

注意:这张表是为“按用户读取会话列表”设计的;消息表则是为“按会话读取消息历史”设计的。它们虽然可能保存部分重复信息,但这种冗余在 Cassandra 中是正常且常见的。

八、一个容易踩坑的问题:超大分区

如果一个热门会话永远只用同一个 conversation_id 作为分区键,长期来看可能产生一个非常大的分区。

对于普通聊天产品,这通常不是最先出现的问题;但对于群聊、客服会话、长时间 AI Agent 任务,需要提前规划。

一种常见办法是增加时间桶:

PRIMARY KEY ((conversation_id, month), message_id)

例如:

conversation_id = conv_10001
month = 2026-09

这样,同一个会话每个月的数据会放到不同分区中,避免单个分区无限膨胀。

读取历史消息时,根据月份依次查询并合并结果即可。

九、Cassandra 在 AI 应用中的位置

一个成熟的 AI 聊天系统通常不会只使用 Cassandra:

数据类型 更适合的存储
用户、权限、订阅、支付 PostgreSQL 或 MySQL
聊天消息、事件记录、访问日志 Cassandra
图片、文件、音频 对象存储
知识库向量与相似度检索 向量数据库
缓存、会话短状态、限流 Redis

也就是说,Cassandra 很适合作为 AI 聊天系统中的“消息历史与事件数据层”,但不需要承担所有数据存储职责。

十、总结

Cassandra 可以帮助 AI 聊天系统稳定保存大量对话数据,尤其适合以下模式:

  • 高并发写入聊天消息;
  • 按会话读取消息历史;
  • 保存模型调用事件和工具调用日志;
  • 通过多节点部署提高可用性;
  • 随着用户增长,增加服务器进行横向扩容。

入门时,最重要的原则只有一个:

先确定查询方式,再为每种查询方式设计表。

如果你的核心需求是“按会话查看聊天记录”和“按用户查看最近会话”,Cassandra 可以成为一个非常合适的持久化方案。

AI 聊天数据如何写入 Cassandra:从一次对话到可持久化的消息记录
http://clxhxhhr.top/posts/625/
作者
clxstart
发布于
2026-09-15
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。