ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

C++大模型SDK会话管理模块实现

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