最近在做优化的时候涉及到了这块内容,觉得值得写下来,方便以后翻阅。
**
🎬 个人主页:艾莉丝努力练剑
❄专栏传送门:《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录》
《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》
⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平
🎬 艾莉丝的简介:
文章目录
1.2 公共数据结构 common.h 1.3 SessionManager 头文件 SessionManager.h 1.4 SessionManager 源文件 SessionManager.cpp1.5 核心技术细节拆解 1.6 常见面试考点- 1.6.1 unordered_map vs map,会话存储选型
- 1.6.2 mutable 关键字用场景
- 1.6.3 std::atomic fetch_add
- 1.6.4 RAII 锁 std::lock_guard
- 1.6.5 会话管理器的扩展方向(面试拓展)
1 ~> C++大模型SDK会话管理模块 SessionManager
核心业务背景:大语言模型本身不会保存会话上下文,所有多轮对话的会话、消息、时间状态必须业务侧手动维护;多线程并发访问会话管理器,必须做线程安全控制。
1.1 会话基础概念
1.1.1 会话定义
- 会话:用户与大模型之间一组连续交互集合,维护聊天上下文与会话状态,保障多轮对话语义连贯。
- 核心存储模型:
[session_id → Session会话对象]映射关系,实现通过会话 ID 快速定位会话。
1.1.2 会话管理完整业务需求
1. 创建会话:新建对话会话,分配唯一 session_id,绑定对话用的模型名称。
2. 通过 session_id 查询指定会话。
3. 向指定会话追加用户 / 模型消息。
4. 获取指定会话全部历史消息,用于组装给大模型的上下文请求。
5. 获取全部会话 ID 列表,UI 展示历史会话。
6. 删除指定会话。
7. 更新会话最后更新时间戳。
8. 清空全部会话。
9. 获取当前会话总数量。
10. 生成全局唯一会话 ID session_id。
11. 生成全局唯一消息 ID message_id。
12. 线程安全:多线程并发增删改查会话,互斥锁保护共享资源。
1.2 公共数据结构 common.h
1.2.1 Message 消息结构体
单条聊天消息,存储角色、消息内容、消息唯一 ID。
// common.h
#pragma once
#include
struct Message {
std::string _messageId; // 消息唯一ID
std::string _role; // 角色:user / assistant / system
std::string _content; // 消息文本内容
Message(const std::string& role, const std::string& content)
: _role(role), _content(content) {}
};
1.2.2 Session 会话结构体
一个会话对应多组 Message,维护会话元信息与消息列表。
// common.h
#include
#include
struct Session {
std::string _sessionId; // 会话唯一ID
std::string _modelName; // 当前会话使用的大模型名称
std::vector _messages; // 会话内全部消息集合
std::time_t _createdAt; // 会话创建时间戳
std::time_t _updatedAt; // 会话最后更新时间戳
explicit Session(const std::string& modelName = "")
: _modelName(modelName), _createdAt(std::time(nullptr)), _updatedAt(std::time(nullptr)) {}
};
1.3 SessionManager 头文件 SessionManager.h
1.3.1 头文件依赖说明
- ``:会话哈希存储,O (1) 平均麻烦度查询;相比 map 红黑树,查询性能更高,会话 ID 有序性无业务要求。
- ``:互斥锁,多线程保护共享会话资源。
- `
:std::shared_ptr`智能指针,管理堆上 Session 对象生命周期,规避裸指针风险。 - ``:原子变量,无锁计数,用于生成会话 ID 序号。
- ``:时间戳接口。
- ``:字符串流,拼接格式化 ID 字符串。
- ``:sort 排序,会话列表按更新时间降序。
1.3.2 完整头文件代码
// sdk/include/SessionManager.h
#pragma once
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "common.h"
namespace ai_chat_sdk {
class SessionManager {
public:
// 创建会话,传入模型名称,返回生成的session_id
std::string createSession(const std::string& modelName);
// 根据session_id获取会话,返回shared_ptr,不存在返回nullptr;const成员函数
std::shared_ptr getSession(const std::string& sessionId) const;
// 向指定会话追加消息;成功返回true,会话不存在返回false
bool addMessage(const std::string& sessionId, const Message& message);
// 获取指定会话全部历史消息;会话不存在返回空vector;const
std::vector getHistoryMessages(const std::string& sessionId) const;
// 更新会话最后更新时间戳
void updateSessionTimestamp(const std::string& sessionId);
// 获取全部会话ID列表,返回的列表按照会话_updatedAt时间戳降序排列;const
std::vector getSessionLists() const;
// 删除指定session_id会话;存在删除返回true,不存在返回false
bool deleteSession(const std::string& sessionId);
// 清空内存中全部会话
void clearAllSessions();
// 获取当前会话总数量;const
size_t getSessionCount() const;
private:
// 私有工具:生成会话唯一ID,格式 session_时间戳_8位序号
std::string generateSessionId();
// 私有工具:生成消息唯一ID,格式 msg_时间戳_8位序号
std::string generateMessageId(size_t messageCounter);
private:
/**
* 会话存储容器
* key: session_id字符串
* value: Session会话对象的shared_ptr,对象分配在堆内存
* 使用unordered_map哈希表,平均O(1)查询效率
*/
std::unordered_map _sessions;
/**
* mutable修饰互斥锁
* const成员函数不能修改普通成员变量;
* 但const方法依然需要加锁解锁修改mutex内部状态,因此使用mutable放开修改权限
*/
mutable std::mutex _mutex;
// 原子会话计数器;线程安全自增;用于拼接会话ID序号,初始值0
std::atomic _sessionCounter{0};
};
} // end namespace ai_chat_sdk
1.3.3 关键设计要点
1. 存储选择unordered_map
不直接存储 Session 对象值:避免 map 容器存储大量大对象带来的拷贝开销;会话对象放到堆内存,智能指针管理生命周期。
2. key 会话 ID 字符串,平均 O (1) 查找。
mutable std::mutex _mutex
1. const 修饰成员函数语义:承诺不修改对象业务数据;
2. 但是锁的 lock/unlock 会修改 mutex 对象内部状态,普通 mutex 无法在 const 函数使用;mutable专门用于这种场景。
std::atomic<int64_t> _sessionCounter
1. 原子变量,无锁线程安全自增,多线程并发创建会话不会出现序号重复。
对外接口全部使用 session_id 操作会话,不暴露内部 Session 对象给外部模块:
1. 降低模块耦合;适配持久化 SQLite 数据库 CURD;避免跨进程传递裸内存指针。
1.4 SessionManager 源文件 SessionManager.cpp
```
// sdk/src/SessionManager.cpp
include "SessionManager.h"
include // std::setw std::setfill
namespace ai_chat_sdk {
// 创建会话
std::string SessionManager::createSession(const std::string& modelName)
{
// lock_guard RAII自动加锁解锁,离开作用域自动释放互斥锁
std::lock_guard lock(_mutex);
// 生成唯一会话ID
std::string sessionId = generateSessionId();
// 在堆上构造Session对象,智能指针接管生命周期
auto session = std::make_shared(modelName);
session->_sessionId = sessionId;
// 存入哈希map
_sessions[sessionId] = session;
return sessionId;
}
// 通过session_id获取会话
std::shared_ptr SessionManager::getSession(const std::string& sessionId) const
{
std::lock_guard lock(_mutex);
auto iter = _sessions.find(sessionId);
if (iter == _sessions.end()) {
return nullptr;
}
return iter->second;
}
// 向会话追加消息
bool SessionManager::addMessage(const std::string& sessionId, const Message& message)
{
std::lock_guard lock(_mutex);
auto iter = _sessions.find(sessionId);
if (iter == _sessions.end()) {
return false;
}
// 当前会话消息数量作为消息序号入参
size_t msgSeq = iter->second->_messages.size();
Message newMsg(message._role, message._content);
newMsg._messageId = generateMessageId(msgSeq);
// 消息追加进会话消息列表
iter->second->_messages.push_back(newMsg);
// 添加消息后更新会话最后修改时间戳
iter->second->_updatedAt = std::time(nullptr);
return true;
}
// 获取会话全部历史消息
std::vector SessionManager::getHistoryMessages(const std::string& sessionId) const
{
std::lock_guard lock(_mutex);
auto iter = _sessions.find(sessionId);
if (iter == _sessions.end()) {
return {};
}
return iter->second->_messages;
}
// 更新会话时间戳
void SessionManager::updateSessionTimestamp(const std::string& sessionId)
{
std::lock_guard lock(_mutex);
auto iter = _sessions.find(sessionId);
if (iter == _sessions.end()) {
return;
}
iter->second->_updatedAt = std::time(nullptr);
}
// 获取会话ID列表,按updatedAt降序(最新会话排在最前面)
std::vector SessionManager::getSessionLists() const
{
std::lock_guard lock(_mutex);
// 临时vector存储 pair
std::vector tempList;
tempList.reserve(_sessions.size());
for (const auto& item : _sessions) {
tempList.emplace_back(item.second->_updatedAt, item.second);
}
// lambda比较器:时间戳降序,大的时间在前
std::sort(tempList.begin(), tempList.end(),
[](const std::pair& a,
const std::pair& b)
{
return a.first > b.first;
});
// 提取排序搞定后的session_id
std::vector resultIds;
resultIds.reserve(tempList.size());
for (const auto& item : tempList) {
resultIds.push_back(item.second->_sessionId);
}
return resultIds;
}
// 删除指定会话
bool SessionManager::deleteSession(const std::string& sessionId)
{
std::lock_guard lock(_mutex);
auto iter = _sessions.find(sessionId);
if (iter == _sessions.end()) {
return false;
}
_sessions.erase(iter);
return true;
}
// 清空全部会话
void SessionManager::clearAllSessions()
{
std::lock_guard lock(_mutex);
_sessions.clear();
}
// 获取会话总数
size_t SessionManager::getSessionCount() const
{
std::lock_guard lock(_mutex);
return _sessions.size();
}
// 生成会话ID 格式: session_时间戳_8位0填充序号
std::string SessionManager::generateSessionId()
{
// 原子变量fetch_add(1)线程安全自增
int64_t seq = _sessionCounter.fetch_add(1, std::memory_order_relaxed);
std::time_t now = std::time(nullptr);
std::ostringstream oss;
oss
就写这么多吧,内容比较基础,适合入门回顾。有补充的地方欢迎留言一起完善。
评论 (0)
暂无评论