🎬 个人主页:艾莉丝努力练剑
❄专栏传送门:《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录》 《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》
⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平
🎬 艾莉丝的简介:

文章目录
- 1 ~> ChatSDK 整体实现
-
- 1.1 整体类结构
-
- 1.1.1 ChatSDK 类核心成员
- 1.1.2 LLMManager 类职责
- 1.1.3 继承配置体系 common.h
- 1.2 模型注册与初始化 initModels
-
- 1.2.1 registerAllProvider 模型注册阶段
-
- 1.2.1.1 云端模型注册(deepseek‑chat /gpt‑4o‑mini /gemini‑2.0‑flash)
- 1.2.1.2 dynamic_pointer_cast 向下转型知识点
- 1.2.2 initProviders 模型实例初始化阶段
-
- 1.2.2.1 initAPIModelProviders 云端模型初始化
- 1.2.2.2 initOllamaModelProviders Ollama 本地模型初始化
- 1.3 Session 会话管理实现
-
- 1.3.1 createSession 创建会话
- 1.3.2 getSession 获取会话对象
- 1.3.3 getSessionLists 获取全部会话 ID 列表
- 1.3.4 deleteSession 删除会话
- 1.4 消息发送接口实现
-
- 1.4.1 sendMessage 全量一次性返回应答
- 1.4.2 sendMessageStream 流式增量回调返回
- 2 ~> 关键 C++ 核心易错点面试总结
-
- 2.1 unique_ptr 所有权转移
- 2.2 shared_ptr 多态向下转型
- 2.3 云端模型 vs Ollama 本地模型差异对比
- 3 ~> ChatSDK 整体编译交付流程
- 4 ~> 完整业务调用时序(外部用户视角)
- 结尾

1 ~> ChatSDK 整体实现
ChatSDK 对外提供统一接口,屏蔽云端大模型、本地 Ollama 模型差异;核心依赖LLMManager做模型管理,SessionManager管理会话上下文。整体工作流程:SDK 初始化模型 → 创建会话 session → 基于 session 发送消息(全量 / 流式增量返回)。
1.1 整体类结构
1.1.1 ChatSDK 类核心成员
- 私有成员
- bool _initialized:SDK 整体初始化标记位
- LLMManager _llmManager:模型管理器,完成模型注册、实例初始化、消息下发
- SessionManager _sessionManager:会话管理器,负责会话创建、删除、历史消息持久化
- std::unordered_map<std::string, std::shared_ptr<Config>> _modelConfigs:保存各个模型对应的配置对象
- 对外公开接口
- initModels():批量注册并初始化模型,SDK 入口初始化函数
- createSession():创建会话,返回 sessionId
- getSession():根据 sessionId 获取会话对象
- getSessionLists():获取全部会话 id 列表
- deleteSession():删除指定会话
- getAvailableModels():获取当前已经就绪可用模型列表
- sendMessage():发送消息,全量一次性返回应答
- sendMessageStream():发送消息,流式增量返回,回调推送分片数据
- 私有内部辅助函数
- registerAllProvider():遍历配置,注册全部模型 Provider
- initProviders():遍历配置,调用对应初始化逻辑完成模型实例初始化
- initAPIModelProviders():云端 API 模型初始化辅助函数
- initOllamaModelProviders():本地 Ollama 模型初始化辅助函数
1.1.2 LLMManager 类职责
1.1.3 继承配置体系 common.h
多态配置,std::vector<std::shared_ptr<Config>>容器可以存放不同子类配置;基类必须定义虚析构,保证 dynamic_pointer_cast 安全向下转型
//模型公共基类配置
struct Config{
std::string _modelName; //模型名称
double _temperature = 0.7; //生成随机性温度参数
int _maxTokens = 2048; //最大输出token
virtual ~Config() = default; //虚析构,多态向下转型dynamic_cast必备
};
//云端API模型配置:deepseek‑chat / gpt‑4o‑mini / gemini‑2.0‑flash
struct APIConfig : public Config{
std::string _apikey;
};
//本地Ollama模型配置,不需要apikey,需要本地服务端点
struct OllamaConfig : public Config{
std::string _modelDesc; //模型描述
std::string _endpoint; //ollama服务地址,如http://127.0.0.1:11434
};
1.2 模型注册与初始化 initModels
ChatSDK::initModels() 外部调用入口,分为两大阶段:注册 Provider、初始化 Provider。
bool ChatSDK::initModels(const std::vector<std::shared_ptr<Config>>& configs)
{
registerAllProvider(configs); //第一步:注册所有模型provider对象
initProviders(configs); //第二步:执行每个provider的初始化
_initialized = true;
return true;
}
1.2.1 registerAllProvider 模型注册阶段
1.2.1.1 云端模型注册(deepseek‑chat /gpt‑4o‑mini /gemini‑2.0‑flash)
- 关键点:LLMManager::registerProvider入参是std::unique_ptr<LLMProvider>,unique_ptr 禁止拷贝,必须使用std::move将左值转为右值完成独占所有权转移。
- 即使子类DeepSeekProvider公有继承基类LLMProvider,unique_ptr 不会执行隐式转换,必须显式 std::move。
void ChatSDK::registerAllProvider(const std::vector<std::shared_ptr<Config>>& configs)
{
//注册deepseek‑chat
if(!_llmManager.isModelAvailable("deepseek‑chat")){
auto deepseekProvider = std::make_unique<DeepSeekProvider>();
//std::move转移独占所有权,不发生拷贝
_llmManager.registerProvider("deepseek‑chat", std::move(deepseekProvider));
INFO("deepseek‑chat provider registered successed");
}
//注册gpt‑4o‑mini
if(!_llmManager.isModelAvailable("gpt‑4o‑mini")){
auto gpt4oProvider = std::make_unique<ChatGPTProvider>();
_llmManager.registerProvider("gpt‑4o‑mini", std::move(gpt4oProvider));
INFO("gpt‑4o‑mini provider registered successed");
}
//注册gemini‑2.0‑flash
if(!_llmManager.isModelAvailable("gemini‑2.0‑flash")){
auto geminiProvider = std::make_unique<GeminiProvider>();
_llmManager.registerProvider("gemini‑2.0‑flash", std::move(geminiProvider));
INFO("gemini‑2.0‑flash provider registered successed");
}
//Ollama本地模型批量注册,来源于外部传入configs
std::unordered_set<std::string> modelNames; //去重,避免重复注册同一个模型
for(const auto& config : configs)
{
//安全向下转型:基类shared_ptr → 子类OllamaConfig shared_ptr
auto ollamaConfig = std::dynamic_pointer_cast<OllamaConfig>(config);
if(ollamaConfig)
{
std::string modelName = ollamaConfig->_modelName;
if(modelNames.find(modelName) == modelNames.end())
{
modelNames.insert(modelName);
if(!_llmManager.isModelAvailable(modelName))
{
auto ollamaProvider = std::make_unique<OllamaLLMProvider>();
_llmManager.registerProvider(modelName, std::move(ollamaProvider));
INFO("OllamaLLMProvider {} registered successed", modelName);
}
}
}
}
}
1.2.1.2 dynamic_pointer_cast 向下转型知识点
- static_pointer_cast:不安全向下转型,不做运行时校验;如果原始对象不是目标子类,得到非法指针,UB 未定义行为。
- dynamic_pointer_cast:安全多态向下转型,运行时 RTTI 校验;基类必须存在虚函数(虚析构);类型不匹配返回 nullptr。
- 使用场景:容器存放基类shared_ptr<Config>,需要区分是APIConfig还是OllamaConfig。
1.2.2 initProviders 模型实例初始化阶段
遍历 configs,dynamic_cast 区分配置类型,分别调用initAPIModelProviders / initOllamaModelProviders。
void ChatSDK::initProviders(const std::vector<std::shared_ptr<Config>>& configs)
{
for(const auto& config : configs)
{
//尝试转型云端API配置
if(auto apiConfig = std::dynamic_pointer_cast<APIConfig>(config))
{
if(apiConfig->_modelName == "deepseek‑chat"
|| apiConfig->_modelName == "gpt‑4o‑mini"
|| apiConfig->_modelName == "gemini‑2.0‑flash")
{
initAPIModelProviders(apiConfig->_modelName, apiConfig);
}
else
{
ERR("Model {} is not supported", apiConfig->_modelName);
}
}
//尝试转型Ollama本地模型配置
else if(auto ollamaConfig = std::dynamic_pointer_cast<OllamaConfig>(config))
{
initOllamaModelProviders(ollamaConfig->_modelName, ollamaConfig);
}
else
{
ERR("Config {} is not supported", config->_modelName);
}
}
}
1.2.2.1 initAPIModelProviders 云端模型初始化
- 将 APIConfig 配置提取组装为std::map<std::string,std::string>参数,传给LLMManager::initModel
- 云端模型 endpoint 可以内置默认值,用户传入配置可覆盖默认地址;必须校验 apikey 不为空。
bool ChatSDK::initAPIModelProviders(const std::string& modelName, const std::shared_ptr<APIConfig>& apiConfig)
{
if(modelName.empty()){
ERR("ChatSDK::initAPIModelProviders:modelName is empty");
return false;
}
if(!apiConfig || apiConfig->_apikey.empty()){
ERR("ChatSDK::initAPIModelProviders:apikey is empty");
return false;
}
if(!_llmManager.isModelAvailable(modelName)){
ERR("ChatSDK::initAPIModelProviders:model {} is not available", modelName);
return false;
}
std::map<std::string, std::string> modelParams;
modelParams["api_key"] = apiConfig->_apikey;
//endpoint:优先取用户配置,没有则使用内置厂商默认域名
//modelParams["endpoint"] = apiConfig->_endpoint;
if(!_llmManager.initModel(modelName, modelParams)){
ERR("ChatSDK::initAPIModelProviders: init model failed {}", modelName);
return false;
}
_modelConfigs[modelName] = apiConfig; //保存配置
INFO("ChatSDK::initAPIModelProviders:model {} init successed", modelName);
return true;
}
1.2.2.2 initOllamaModelProviders Ollama 本地模型初始化
- Ollama 没有内置固定服务地址,model_name、model_desc、endpoint全部由外部配置传入,缺一不可。
bool ChatSDK::initOllamaModelProviders(const std::string& modelName, const std::shared_ptr<OllamaConfig>& ollamaConfig)
{
if(modelName.empty()){
ERR("ChatSDK::initOllamaModelProviders:modelName is empty");
return false;
}
if(!ollamaConfig || ollamaConfig->_endpoint.empty()){
ERR("ChatSDK::initOllamaModelProviders:endpoint is empty");
return false;
}
if(!_llmManager.isModelAvailable(modelName)){
ERR("ChatSDK::initOllamaModelProviders:model {} is not available", modelName);
return false;
}
std::map<std::string, std::string> modelParams;
modelParams["model_name"] = modelName;
modelParams["model_desc"] = ollamaConfig->_modelDesc;
modelParams["endpoint"] = ollamaConfig->_endpoint;
if(!_llmManager.initModel(modelName, modelParams)){
ERR("ChatSDK::initOllamaModelProviders:init model failed {}", modelName);
return false;
}
_modelConfigs[modelName] = ollamaConfig;
INFO("ChatSDK::initOllamaModelProviders: model {} init successed", modelName);
return true;
}
1.3 Session 会话管理实现
ChatSDK 会话相关接口全部转发调用SessionManager,每一个会话绑定一个模型,维护该会话完整消息历史。
1.3.1 createSession 创建会话
std::string ChatSDK::createSession(const std::string& modelName)
{
if(!_initialized){
ERR("ChatSDK::createSession:SDK is not initialized");
return "";
}
std::string sessionId = _sessionManager.createSession(modelName);
if(sessionId.empty()){
ERR("ChatSDK::createSession:create session failed");
return "";
}
INFO("ChatSDK::createSession create session {} successed", sessionId);
return sessionId;
}
1.3.2 getSession 获取会话对象
std::shared_ptr<Session> ChatSDK::getSession(const std::string& sessionId)
{
if(!_initialized){
ERR("ChatSDK::getSession:SDK is not initialized");
return nullptr;
}
auto session = _sessionManager.getSession(sessionId);
if(!session){
ERR("ChatSDK::getSession: session {} not found", sessionId);
}
return session;
}
1.3.3 getSessionLists 获取全部会话 ID 列表
std::vector<std::string> ChatSDK::getSessionLists() const
{
if(!_initialized){
ERR("ChatSDK::getSessionLists: SDK is not initialized");
return {};
}
return _sessionManager.getSessionLists();
}
1.3.4 deleteSession 删除会话
bool ChatSDK::deleteSession(const std::string& sessionId)
{
if(!_initialized){
ERR("ChatSDK::deleteSession:SDK is not initialized");
return false;
}
bool result = _sessionManager.deleteSession(sessionId);
if(!result){
ERR("ChatSDK::deleteSession:delete session failed {}", sessionId);
return false;
}
INFO("ChatSDK::deleteSession:delete session {} successed", sessionId);
return true;
}
1.4 消息发送接口实现
两个接口:全量返回sendMessage;流式增量返回sendMessageStream。 公共前置逻辑:
1.4.1 sendMessage 全量一次性返回应答
std::string ChatSDK::sendMessage(const std::string& sessionId, const std::string& message)
{
if(!_initialized){
ERR("ChatSDK::sendMessage: SDK is not initialized");
return "";
}
auto session = _sessionManager.getSession(sessionId);
if(!session){
ERR("ChatSDK::sendMessage: session not found {}", sessionId);
return "";
}
// 1. 将用户消息加入会话
Message userMessage{"user", message};
_sessionManager.addMessage(sessionId, userMessage);
// 2. 获取会话全部历史消息
std::vector<Message> historyMessages = _sessionManager.getHistoryMessages(sessionId);
// 3. 获取模型配置,组装请求参数
auto it = _modelConfigs.find(session->_modelName);
if(it == _modelConfigs.end()){
ERR("ChatSDK::sendMessage:model {} not found", session->_modelName);
return "";
}
std::map<std::string, std::string> requestParam;
requestParam["temperature"] = std::to_string(it->second->_temperature);
requestParam["max_tokens"] = std::to_string(it->second->_maxTokens);
// 4. 调用LLMManager下发消息
std::string response = _llmManager.sendMessage(session->_modelName, historyMessages, requestParam);
if(response.empty()){
ERR("ChatSDK::sendMessage: send message to model {} failed", session->_modelName);
return "";
}
// 5. 将助手回复写入会话,更新会话时间戳
Message assistantMessage{"assistant", response};
_sessionManager.addMessage(sessionId, assistantMessage);
_sessionManager.updateSessionTimestamp(sessionId);
INFO("ChatSDK::sendMessage send message to model {} successed", session->_modelName);
return response;
}
1.4.2 sendMessageStream 流式增量回调返回
- 入参回调std::function<void(const std::string&, bool)> callback
- 第一个参数:模型返回的增量分片字符串
- 第二个 bool 参数:标记是否为最后一块分片
- 底层 LLMManager 收到分片数据,反复调用回调推送数据;函数返回完整拼接后的应答文本。
std::string ChatSDK::sendMessageStream(const std::string& sessionId, const std::string& message,
std::function<void(const std::string&, bool)> callback)
{
if(!_initialized){
ERR("ChatSDK::sendMessageStream: SDK is not initialized");
return "";
}
auto session = _sessionManager.getSession(sessionId);
if(!session){
ERR("ChatSDK::sendMessageStream:session not found {}", sessionId);
return "";
}
Message userMessage{"user", message};
_sessionManager.addMessage(sessionId, userMessage);
std::vector<Message> historyMessages = _sessionManager.getHistoryMessages(sessionId);
auto it = _modelConfigs.find(session->_modelName);
if(it == _modelConfigs.end()){
ERR("ChatSDK::sendMessageStream:model {} not found", session->_modelName);
return "";
}
std::map<std::string, std::string> requestParam;
requestParam["temperature"] = std::to_string(it->second->_temperature);
requestParam["max_tokens"] = std::to_string(it->second->_maxTokens);
std::string response = _llmManager.sendMessageStream(session->_modelName, historyMessages, requestParam, callback);
if(response.empty()){
ERR("ChatSDK::sendMessageStream:send message to model {} failed", session->_modelName);
return "";
}
Message assistantMessage{"assistant", response};
_sessionManager.addMessage(sessionId, assistantMessage);
_sessionManager.updateSessionTimestamp(sessionId);
INFO("ChatSDK::sendMessageStream send message to model {} successed", session->_modelName);
return response;
}
2 ~> 关键 C++ 核心易错点面试总结
2.1 unique_ptr 所有权转移
- unique_ptr是独占所有权智能指针,禁止拷贝构造、拷贝赋值,只允许移动语义std::move。
- 即使子类指针可以隐式转换为基类裸指针,unique_ptr<SubClass>不会隐式转换为unique_ptr<BaseClass>,必须显式std::move。
- std::move只是将左值强制转换为右值引用,本身不做内存释放;移动之后源对象变为空。
2.2 shared_ptr 多态向下转型
本项目Config基类添加virtual ~Config()=default;,目的就是为了支持dynamic_pointer_cast安全向下转型。
2.3 云端模型 vs Ollama 本地模型差异对比
| 鉴权 | 必须 apikey | 不需要 apikey |
| 服务端点 endpoint | 代码内置默认值,用户可覆盖 | 必须外部配置传入,无默认值 |
| 模型名称 | 代码写死固定名称 | 完全由外部 config 配置传入,可以多个 ollama 模型 |
| 配置结构体 | APIConfig | OllamaConfig |
3 ~> ChatSDK 整体编译交付流程
4 ~> 完整业务调用时序(外部用户视角)
结尾
uu们,本文的内容到这里就全部结束了,艾莉丝在这里再次感谢您的阅读!
|
艾莉丝努力练剑
C/C++ & Linux 底层探索者 | 一个正在努力练剑的技术博主 👀 ❤️ ⭐ 💬 不要忘记给博主“一键四连”哦! “今日练剑达成!” “技术之路难免有困惑,但同行的人会让前进更有方向。” |
结语:希望对学习Linux相关内容的uu有所帮助,不要忘记给博主“一键四连”哦!
往期回顾:
【AI大模型接入SDK】ChatSDK架构设计与实现
🗡博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!🗡
૮₍ ˶ ˊ ᴥ ˋ˶₎ა


