提问背景 Question:
我已经把ai聊天的历史对话,保存到数据库中,表结构如下。CREATE TABLE cms_article (id INTEGER PRIMARY KEY, question TEXT NOT NULL, title TEXT NOT NULL, description TEXT, content TEXT NOT NULL, source TEXT NOT NULL DEFAULT 'manual', ip TEXT DEFAULT NULL, score INTEGER DEFAULT (0), click_count INTEGER DEFAULT 0, like_count INTEGER DEFAULT 0, status INTEGER DEFAULT 0, created_at INTEGER NOT NULL DEFAULT (0), updated_at INTEGER NOT NULL DEFAULT (0), user_id INTEGER DEFAULT (0), msg_type INTEGER DEFAULT (0)),我想把用户保存的最新的20条对话,读取出来,这样重新登录的时候,就能回忆起之前的聊天内容。我用的是go语言。
// 前端需要将 AI 的回复也存入历史时,调用这个简单的辅助函数
func NewContent(role string, text string) genai.Content {
contents := genai.Text(text)
if len(contents) > 0 && contents[0] != nil {
res := *contents[0]
res.Role = role
return res
}
return genai.Content{Role: role}
}
userC := NewContent("user", historyUserMsg)
modelC := NewContent("model", desc)
AppendPairAndTrim(sessionID, userC, modelC) // 写入会话数据库
数据库连接接口
fun.DB
// 开启事务
tx, err := fun.DB.Begin()
if err != nil {
return err
}
defer tx.Rollback()
// 设置管理对象
var SessionConfig = struct {
MaxHistoryPairs int
}{
MaxHistoryPairs: 10,
}
var sessionStore sync.Map
// GetUserHistory 依然保持公开,供外部读取上下文
func GetUserHistory(sessionID string) []genai.Content {
history, ok := sessionStore.Load(sessionID)
if !ok {
return []genai.Content{}
}
return history.([]genai.Content)
}
// 内部私有方法:强制要求所有写入操作必须通过 append 逻辑
func saveUserHistory(sessionID string, history []genai.Content) {
sessionStore.Store(sessionID, history)
}
// AppendPairAndTrim: 唯一的合法写入路径
func AppendPairAndTrim(sessionID string, userContent, modelContent genai.Content) {
history := GetUserHistory(sessionID)
history = append(history, userContent, modelContent)
// 强制执行裁剪,确保不会超额
maxRecords := SessionConfig.MaxHistoryPairs * 2
if len(history) > maxRecords {
history = history[len(history)-maxRecords:]
}
saveUserHistory(sessionID, history)
}
帮我写一个读取某个用户数据库历史记录前20对的对话简要放进内存中。供用户下次对话具有连惯性。主要用于用户关闭浏览器,下次访问时使用。用户登录后,就要聊天窗口中,展开上一次的对话内容。数据库中保存要简要和具体的对话内容。对话发送的主要是ai回复的简要和用户的提问全部内容。
Go语言加载数据库历史会话
为了实现用户登录后恢复对话记忆,建议在用户登录成功后的初始化阶段调用以下函数。该函数从 cms_article 表中按时间倒序读取最近的记录,并将其重建为 []genai.Content 放入 sessionStore。
func LoadUserHistoryToMemory(userID int64, sessionID string) error {
// 查询最近20条(对应10对对话,根据需求可调)记录
rows, err := fun.DB.Query(
"SELECT question, content FROM cms_article WHERE user_id = ? ORDER BY id DESC LIMIT 20",
userID,
)
if err != nil {
return err
}
defer rows.Close()
var history []genai.Content
for rows.Next() {
var q, c string
if err := rows.Scan(&q, &c); err != nil {
continue
}
// 将读取到的记录插入到历史切片中(注意顺序是倒序,需要翻转)
history = append([]genai.Content{
{Role: "user", Parts: []genai.Part{genai.Text(q)}},
{Role: "model", Parts: []genai.Part{genai.Text(c)}},
}, history...)
}
// 存入内存
saveUserHistory(sessionID, history)
return nil
}
关键逻辑说明:
- 倒序读取:
ORDER BY id DESC确保获取的是最新的对话。 - 切片处理:由于从数据库读出的是逆序的,使用
append([]genai.Content{...}, history...)可以保证内存中上下文的顺序与对话逻辑一致。 - 内存同步:直接调用你已有的
saveUserHistory,使得业务逻辑无需关心底层实现,直接通过GetUserHistory获取最新上下文。