C++大模型SDK会话管理模块实现
大语言模型本身不会保存会话上下文,多轮对话中的会话、消息和时间状态必须由业务侧手动维护;同时,多线程并发访问会话管理器时,必须做线程安全控制。C++大模型接入SDK中的SessionManager,正是围绕这两个约束设计的会话管理模块。
来源说明:以下实现与接口来自一篇CSDN社区文章的示例代码,属于社区作者的个人实践总结,未经官方核验。文中所有代码、接口命名和设计取舍均以该社区文章为参照,不代表任何官方SDK的规范或承诺。
会话基础概念
该社区文章将会话定义为用户与大模型之间一组连续交互的集合,用于维护聊天上下文与会话状态,保障多轮对话语义连贯。其核心存储模型是 session_id 到 Session 的映射,通过会话ID快速定位会话。
完整的业务需求包括:创建会话并分配唯一 session_id、绑定模型名称;按 session_id 查询会话;向指定会话追加用户或模型消息;获取指定会话全部历史消息,用于组装给大模型的上下文请求;获取全部会话ID列表供 UI 展示;删除指定会话;更新最后更新时间戳;清空全部会话;获取当前会话总数;生成全局唯一 session_id 和会话内唯一的 message_id;以及线程安全。
公共数据结构
在数据结构上,common.h 定义了 Message 和 Session。Message 包含 _messageId、_role、_content,其中 _role 取 user、assistant 或 system;构造函数只接收 role 和 content,_messageId 后续生成。Session 包含 _sessionId、_modelName、_messages、_createdAt、_updatedAt,_messages 是 vector;构造函数初始化 modelName,并把创建时间和更新时间设为当前时间。
// common.h
#pragma once
#include
#include
#include
struct Message {
std::string _messageId;
std::string _role;
std::string _content;
Message(const std::string& role, const std::string& content)
: _role(role), _content(content) {}
};
struct Session {
std::string _sessionId;
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)) {}
};
SessionManager 接口设计
SessionManager.h 的接口覆盖上述业务:createSession、getSession、addMessage、getHistoryMessages、updateSessionTimestamp、getSessionLists、deleteSession、clearAllSessions、getSessionCount。私有工具包括 generateSessionId 和 generateMessageId。成员变量有三个关键点:一是 unordered_map> _sessions;二是 mutable std::mutex _mutex;三是 std::atomic _sessionCounter{0}。
// SessionManager.h
#pragma once
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "common.h"
namespace ai_chat_sdk {
class SessionManager {
public:
std::string createSession(const std::string& modelName);
std::shared_ptr getSession(const std::string& sessionId) const;
bool addMessage(const std::string& sessionId, const Message& message);
std::vector getHistoryMessages(const std::string& sessionId) const;
void updateSessionTimestamp(const std::string& sessionId);
std::vector getSessionLists() const;
bool deleteSession(const std::string& sessionId);
void clearAllSessions();
size_t getSessionCount() const;
private:
std::string generateSessionId();
std::string generateMessageId(size_t messageCounter);
std::unordered_map> _sessions;
mutable std::mutex _mutex;
std::atomic _sessionCounter{0};
};
} // namespace ai_chat_sdk
关键设计要点
存储选择:使用 unordered_map>。该社区文章明确不直接存储 Session 对象值,以避免 map 容器存储大量大对象带来的拷贝开销;会话对象放在堆内存,由智能指针管理生命周期。key 是会话ID字符串,平均 O(1) 查找。
mutable 修饰互斥锁:const 成员函数承诺不修改对象业务数据,但锁的 lock/unlock 会修改 mutex 内部状态,普通 mutex 无法在 const 函数中使用,mutable 专门用于这种场景。
原子变量 _sessionCounter:用于无锁线程安全自增,多线程并发创建会话不会出现序号重复。
对外接口以 session_id 为契约:该社区文章的设计意图是让外部模块通过 session_id 操作会话,以降低模块耦合,适配持久化 SQLite 数据库 CURD,并避免跨进程传递裸内存指针。但需要指出,getSession 返回 shared_ptr,外部调用方可以持有该指针并直接修改 Session 内容,因此“不暴露内部 Session 对象”这一表述并不严格成立。作者分析:若严格遵循该设计意图,getSession 应改为返回只读视图或消息副本;若保留 shared_ptr 返回,则必须在文档中明确调用方不得在锁外修改 Session,否则会绕过互斥锁造成数据竞争。
源文件实现
源文件实现中,createSession 先用 lock_guard 加锁,调用 generateSessionId 生成唯一会话ID,再通过 make_shared 在堆上构造对象,设置 _sessionId 后存入哈希表,最后返回 session_id。getSession 加锁后查找,不存在返回 nullptr,存在则返回 shared_ptr。addMessage 加锁后查找会话,不存在返回 false;以当前 _messages.size() 作为消息序号入参,构造新 Message,设置 _messageId 为 generateMessageId(msgSeq),push_back 进消息列表,并把 _updatedAt 更新为当前时间,返回 true。getHistoryMessages 加锁查找,不存在返回空 vector,存在则返回 _messages。updateSessionTimestamp 加锁查找,不存在直接返回,存在则更新 _updatedAt。getSessionLists 同样加锁,返回全部会话ID列表,并按 _updatedAt 降序排列,使最新会话排在最前面。
```cpp
// SessionManager.cpp
include "SessionManager.h"
include
namespace ai_chat_sdk {
std::string SessionManager::createSession(const std::string& modelName)
{
std::lock_guard lock(_mutex);
std::string sessionId = generateSessionId();
auto session = std::make_shared(modelName);
session->_sessionId = sessionId;
_sessions[sessionId] = session;
return sessionId;
}
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);
}
std::vector SessionManager::getSessionLists() const
{
std::lock_guard lock(_mutex);
std::vector> tmp;
for (const auto& kv : _sessions) {
tmp.emplace_back(kv.second->_updatedAt, kv.first);
}
std::sort(tmp.begin(), tmp.end(),
{ return a.first > b.first; });
std::vector result;
result.reserve(tmp.size());
for (const auto& p : tmp) {
result.push_back(p.second);
}
return result;
}
bool SessionManager::deleteSession(const std::string& sessionId)
{
std::lock_guard lock(_mutex);
return _sessions.erase(sessionId) > 0;
}
void SessionManager::clearAllSessions()
{
std::lock_guard lock(_mutex);
_sessions.clear();
}
size_t SessionManager::getSessionCount() const
{
std::lock_guard lock(_mutex);
return _sessions.size();
}
std::string SessionManager::generateSessionId()
{
int64_t seq = _sessionCounter.fetch_add(1);
std::time_t now = std::time(nullptr);
std::ostringstream oss;
oss ,让会话对象生命周期由智能指针接管,规避裸指针风险。该社区文章还列出常见面试考点:unordered_map 与 map 的会话存储选型、mutable 关键字使用场景、std::atomic fetch_add、RAII 锁 std::lock_guard,以及会话管理器的扩展方向。
工程分析
从工程分析角度看,这套实现把模型无状态与业务侧有状态解耦,以 session_id 为外部契约,内部用哈希表、互斥锁、原子计数和智能指针支撑多轮对话上下文维护。作者建议:该结构可作为 C++ 大模型接入 SDK 会话管理层的参考起点,但生产环境仍需按实际 SDK 约束、持久化方案和并发模型进行验证与调整。