【AI大模型接入SDK】C++会话管理模块(SessionManager)设计与实现
·
《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》
🎬 艾莉丝的简介:

文章目录

1 ~> C++大模型SDK会话管理模块 SessionManager
核心业务背景:大语言模型本身不会保存会话上下文,所有多轮对话的会话、消息、时间状态必须业务侧手动维护;多线程并发访问会话管理器,必须做线程安全控制。
1.1 会话基础概念
1.1.1 会话定义
- 会话:用户与大模型之间一组连续交互集合,维护聊天上下文与会话状态,保障多轮对话语义连贯。
- 核心存储模型:
[session_id → Session会话对象]映射关系,实现通过会话 ID 快速定位会话。
1.1.2 会话管理完整业务需求
- 创建会话:新建对话会话,分配唯一 session_id,绑定对话使用的模型名称。
- 通过 session_id 查询指定会话。
- 向指定会话追加用户 / 模型消息。
- 获取指定会话全部历史消息,用于组装给大模型的上下文请求。
- 获取全部会话 ID 列表,UI 展示历史会话。
- 删除指定会话。
- 更新会话最后更新时间戳。
- 清空全部会话。
- 获取当前会话总数量。
- 生成全局唯一会话 ID
session_id。 - 生成全局唯一消息 ID
message_id。 - 线程安全:多线程并发增删改查会话,互斥锁保护共享资源。
1.2 公共数据结构 common.h
1.2.1 Message 消息结构体
单条聊天消息,存储角色、消息内容、消息唯一 ID。
// common.h
#pragma once
#include <string>
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 <vector>
#include <ctime>
struct Session {
std::string _sessionId; // 会话唯一ID
std::string _modelName; // 当前会话使用的大模型名称
std::vector<Message> _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 头文件依赖说明
<unordered_map>:会话哈希存储,O (1) 平均复杂度查询;相比 map 红黑树,查询性能更高,会话 ID 有序性无业务要求。<mutex>:互斥锁,多线程保护共享会话资源。<memory>:std::shared_ptr智能指针,管理堆上 Session 对象生命周期,规避裸指针风险。<atomic>:原子变量,无锁计数,用于生成会话 ID 序号。<ctime>:时间戳接口。<sstream>:字符串流,拼接格式化 ID 字符串。<algorithm>:sort 排序,会话列表按更新时间降序。
1.3.2 完整头文件代码
// sdk/include/SessionManager.h
#pragma once
#include <unordered_map>
#include <mutex>
#include <memory>
#include <atomic>
#include <vector>
#include <string>
#include <ctime>
#include <sstream>
#include <algorithm>
#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<Session> getSession(const std::string& sessionId) const;
// 向指定会话追加消息;成功返回true,会话不存在返回false
bool addMessage(const std::string& sessionId, const Message& message);
// 获取指定会话全部历史消息;会话不存在返回空vector;const
std::vector<Message> getHistoryMessages(const std::string& sessionId) const;
// 更新会话最后更新时间戳
void updateSessionTimestamp(const std::string& sessionId);
// 获取全部会话ID列表,返回的列表按照会话_updatedAt时间戳降序排列;const
std::vector<std::string> 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<std::string, std::shared_ptr<Session>> _sessions;
/**
* mutable修饰互斥锁
* const成员函数不能修改普通成员变量;
* 但const方法依然需要加锁解锁修改mutex内部状态,因此使用mutable放开修改权限
*/
mutable std::mutex _mutex;
// 原子会话计数器;线程安全自增;用于拼接会话ID序号,初始值0
std::atomic<int64_t> _sessionCounter{0};
};
} // end namespace ai_chat_sdk
1.3.3 关键设计要点
- 存储选择
unordered_map<std::string, std::shared_ptr<Session>>- 不直接存储 Session 对象值:避免 map 容器存储大量大对象带来的拷贝开销;会话对象放到堆内存,智能指针管理生命周期。
- key 会话 ID 字符串,平均 O (1) 查找。
mutable std::mutex _mutex- const 修饰成员函数语义:承诺不修改对象业务数据;
- 但是锁的 lock/unlock 会修改 mutex 对象内部状态,普通 mutex 无法在 const 函数使用;
mutable专门用于这种场景。
std::atomic<int64_t> _sessionCounter- 原子变量,无锁线程安全自增,多线程并发创建会话不会出现序号重复。
- 对外接口全部使用 session_id 操作会话,不暴露内部 Session 对象给外部模块:
- 降低模块耦合;适配持久化 SQLite 数据库 CURD;避免跨进程传递裸内存指针。
1.4 SessionManager 源文件 SessionManager.cpp
// sdk/src/SessionManager.cpp
#include "SessionManager.h"
#include <iomanip> // std::setw std::setfill
namespace ai_chat_sdk {
// 创建会话
std::string SessionManager::createSession(const std::string& modelName)
{
// lock_guard RAII自动加锁解锁,离开作用域自动释放互斥锁
std::lock_guard<std::mutex> lock(_mutex);
// 生成唯一会话ID
std::string sessionId = generateSessionId();
// 在堆上构造Session对象,智能指针接管生命周期
auto session = std::make_shared<Session>(modelName);
session->_sessionId = sessionId;
// 存入哈希map
_sessions[sessionId] = session;
return sessionId;
}
// 通过session_id获取会话
std::shared_ptr<Session> SessionManager::getSession(const std::string& sessionId) const
{
std::lock_guard<std::mutex> 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<std::mutex> 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<Message> SessionManager::getHistoryMessages(const std::string& sessionId) const
{
std::lock_guard<std::mutex> 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<std::mutex> lock(_mutex);
auto iter = _sessions.find(sessionId);
if (iter == _sessions.end()) {
return;
}
iter->second->_updatedAt = std::time(nullptr);
}
// 获取会话ID列表,按updatedAt降序(最新会话排在最前面)
std::vector<std::string> SessionManager::getSessionLists() const
{
std::lock_guard<std::mutex> lock(_mutex);
// 临时vector存储 pair<更新时间戳,会话智能指针>
std::vector<std::pair<std::time_t, std::shared_ptr<Session>>> 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<std::time_t, std::shared_ptr<Session>>& a,
const std::pair<std::time_t, std::shared_ptr<Session>>& b)
{
return a.first > b.first;
});
// 提取排序完成后的session_id
std::vector<std::string> 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<std::mutex> lock(_mutex);
auto iter = _sessions.find(sessionId);
if (iter == _sessions.end()) {
return false;
}
_sessions.erase(iter);
return true;
}
// 清空全部会话
void SessionManager::clearAllSessions()
{
std::lock_guard<std::mutex> lock(_mutex);
_sessions.clear();
}
// 获取会话总数
size_t SessionManager::getSessionCount() const
{
std::lock_guard<std::mutex> 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 << "session_"
<< now
<< "_"
<< std::setw(8)
<< std::setfill('0')
<< seq;
return oss.str();
}
// 生成消息ID 格式: msg_时间戳_8位0填充序号
std::string SessionManager::generateMessageId(size_t messageCounter)
{
std::time_t now = std::time(nullptr);
std::ostringstream oss;
oss << "msg_"
<< now
<< "_"
<< std::setw(8)
<< std::setfill('0')
<< messageCounter;
return oss.str();
}
} // end namespace ai_chat_sdk
1.5 核心技术细节拆解
1.5.1 线程安全实现
- 全部读写
_sessions共享容器的成员函数均使用std::lock_guard<std::mutex>RAII 锁。 - RAII 特性:作用域结束自动析构释放锁,杜绝异常路径死锁、忘记 unlock。
mutable std::mutex _mutex解决 const 成员函数加锁问题。- 会话计数器
_sessionCounter使用std::atomic,无锁自增,生成 ID 阶段不竞争互斥锁。
1.5.2 ID 生成规则
- session_id:
session_<unix时间戳>_<8位十进制序号>- unix 时间戳保证大范围时间维度唯一性;原子计数器保证同一秒内多个会话 ID 不重复;
setw(8)+setfill('0')固定宽度补零格式化。
- unix 时间戳保证大范围时间维度唯一性;原子计数器保证同一秒内多个会话 ID 不重复;
- message_id:
msg_<unix时间戳>_<会话内消息序号>- 序号取自会话内部 messages vector 当前 size,代表该会话内第 N 条消息。
1.5.3 getSessionLists 会话排序业务
- 原始 unordered_map 容器本身无序,直接遍历返回 session_id 顺序不可控。
- 业务需求 UI 展示历史会话,最近更新会话置顶,因此需要:
- 遍历 map,将
<updatedAt时间戳,会话shared_ptr>存入临时 vector; std::sort配合 lambda 比较器,按_updatedAt降序;- 从排好序的临时容器提取 session_id 返回上层。
- 遍历 map,将
为什么不直接返回 Session 对象集合:
- 返回完整 Session 对象会触发大量对象拷贝,内存开销高;
- 上层模块统一使用 session_id 作为操作句柄,直接返回 Session 会提升模块耦合;
- 如果后续会话持久化 SQLite,全部数据库 CURD 都以 session_id 为主键,返回 ID 接口天然适配持久层。
1.5.4 内存模型:为什么使用shared_ptr<Session>
- 如果
unordered_map直接存储Session值对象,插入 map 会触发 Session 完整拷贝;会话消息 vector 体积大,拷贝开销巨大。 - 使用
std::make_shared在堆分配 Session 对象,map 只保存智能指针,拷贝仅复制指针,开销极小。 shared_ptr自动管理对象生命周期,erase 会话的时候引用计数自动递减,会话对象自动释放内存,杜绝内存泄漏。
1.6 常见面试考点
1.6.1 unordered_map vs map,会话存储选型
| 容器 | 底层结构 | 查询平均复杂度 | 有序性 |
|---|---|---|---|
std::unordered_map | 哈希表 | O(1) | 无序,key 不排序 |
std::map | 红黑树 | O(logN) | key 有序 |
**会话业务:**不需要 session_id 有序;优先选择 unordered_map 获得更高查询性能。
1.6.2 mutable 关键字使用场景
- mutable 作用:突破 const 成员函数对成员变量的修改限制。
- 仅用于这种场景:const 承诺业务数据不变,但是内部同步原语(mutex)需要修改内部状态;业务数据绝对不可以标记 mutable。
1.6.3 std::atomic fetch_add
fetch_add(1, memory_order_relaxed)原子自增,多线程并发调用不会出现数据竞争。- 不要直接
++_sessionCounter,虽然 atomic 支持重载 ++ 运算符,fetch_add语义更加明确。
1.6.4 RAII 锁 std::lock_guard
- 不要手动调用
_mutex.lock(); _mutex.unlock();,函数提前 return、抛出异常会导致锁忘记释放,产生死锁。 - lock_guard 在对象构造加锁,析构释放锁,无论函数以任何路径退出都会释放互斥锁。
1.6.5 会话管理器的扩展方向(面试拓展)
- 内存会话数据持久化到 SQLite 磁盘,程序重启会话数据不丢失;
- 会话消息数量上限,自动裁剪旧消息,控制上下文窗口长度,适配大模型上下文 token 上限;
- 会话过期淘汰机制,长时间未访问会话做 LRU 淘汰;
- 读写锁优化:读多写少场景,替换 mutex 为
std::shared_mutex,读共享写排他,提升并发读性能。
1.7 业务易错坑点总结
- const 成员函数中普通 mutex 无法 lock,忘记添加 mutable 修饰,编译报错。
- ID 格式化忘记引入
<iomanip>头文件,std::setw / std::setfill编译报错。 - 排序 lambda 写反比较逻辑,会话列表变成旧会话置顶。
- 生成消息 ID 直接使用全局计数器,没有使用会话内消息序号,业务逻辑错误。
- 直接返回裸指针
Session*给上层调用,存在悬空指针内存安全风险,必须使用std::shared_ptr。 - addMessage 追加消息之后**忘记更新****
_updatedAt**时间戳,会话排序功能失效。 - 多线程访问会话容器,忘记加锁,引发数据竞争、内存崩溃。
结尾
uu们,本文的内容到这里就全部结束了,艾莉丝在这里再次感谢您的阅读!
|
结语:希望对学习Linux相关内容的uu有所帮助,不要忘记给博主“一键四连”哦!
往期回顾:
🗡博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!🗡 ૮₍ ˶ ˊ ᴥ ˋ˶₎ა
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)