最近在做优化的时候涉及到了这块内容,觉得值得写下来,方便以后翻阅。
🎬 个人主页:艾莉丝努力练剑
❄专栏传送门:《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录》
《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》
⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平
🎬 艾莉丝的简介:
文章目录
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.3.1 createSession 创建会话
- 1.3.2 getSession 获取会话对象
- 1.3.3 getSessionLists 获取全部会话 ID 列表
- 1.3.4 deleteSession 删除会话
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 _modelConfigs:保存各个模型对应的配置对象
initModels():批量注册并初始化模型,SDK 入口初始化函数createSession():创建会话,返回 sessionIdgetSession():根据 sessionId 获取会话对象getSessionLists():获取全部会话 id 列表deleteSession():删除指定会话getAvailableModels():获取当前已经就绪可用模型列表sendMessage():发送消息,全量一次性返回应答sendMessageStream():发送消息,流式增量返回,回调推送分片数据
registerAllProvider():遍历配置,注册全部模型 ProviderinitProviders():遍历配置,调用对应初始化逻辑搞定模型实例初始化initAPIModelProviders():云端 API 模型初始化辅助函数initOllamaModelProviders():本地 Ollama 模型初始化辅助函数
1.1.2 LLMManager 类职责
1. 维护_providers:std::unordered_map,保存模型名称与 provider 实例独占指针
2. 维护_modelInfos:保存每个模型运行状态、描述信息
3. 核心接口
registerProvider():注册 LLM 提供者,接收模型名 + unique_ptr,发生资源转移 std::move
4. initModel():对已注册模型执行 provider 的initModel,搞定模型实例初始化
5. isModelAvailable():判断模型是否注册且初始化完成可用
6. getAvailableModels():获取全部可用模型信息
7. sendMessage():全量模式下发消息给底层 provider
8. sendMessageStream():流式模式下发消息给底层 provider,传入回调
1.1.3 继承配置体系 common.h
多态配置,std::vector容器能够存放不同子类配置;基类必须定义虚析构,保证 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& 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,unique_ptr 禁止拷贝,必须用std::move将左值转为右值完成独占所有权转移。 - 即使子类
DeepSeekProvider公有继承基类LLMProvider,unique_ptr 不会执行隐式转换,必须显式 std::move。
void ChatSDK::registerAllProvider(const std::vector& configs)
{
//注册deepseek‑chat
if(!_llmManager.isModelAvailable("deepseek‑chat")){
auto deepseekProvider = std::make_unique();
//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();
_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();
_llmManager.registerProvider("gemini‑2.0‑flash", std::move(geminiProvider));
INFO("gemini‑2.0‑flash provider registered successed");
}
//Ollama本地模型批量注册,来源于外部传入configs
std::unordered_set modelNames; //去重,避免重复注册同一个模型
for(const auto& config : configs)
{
//安全向下转型:基类shared_ptr → 子类OllamaConfig shared_ptr
auto ollamaConfig = std::dynamic_pointer_cast(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();
_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,需要区分是APIConfig还是OllamaConfig。
1.2.2 initProviders 模型实例初始化阶段
遍历 configs,dynamic_cast 区分配置类型,分别调用initAPIModelProviders / initOllamaModelProviders。
void ChatSDK::initProviders(const std::vector& configs)
{
for(const auto& config : configs)
{
//尝试转型云端API配置
if(auto apiConfig = std::dynamic_pointer_cast(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(config))
{
initOllamaModelProviders(ollamaConfig->_modelName, ollamaConfig);
}
else
{
ERR("Config {} is not supported", config->_modelName);
}
}
}
1.2.2.1 initAPIModelProviders 云端模型初始化
- 将 APIConfig 配置提取组装为
std::map参数,传给LLMManager::initModel - 云端模型 endpoint 能够内置默认值,用户传入配置可覆盖默认地址;必须校验 apikey 不为空。
bool ChatSDK::initAPIModelProviders(const std::string& modelName, const std::shared_ptr& 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 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)
{
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 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 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 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。 公共前置逻辑:
校验 SDK 初始化标记_initialized根据 sessionId 获取会话 Session 对象将用户输入 user 消息添加到会话从 session 拿到绑定的 modelName,在_modelConfigs取出温度、max_tokens,组装请求参数从 Session 读取完整历史消息调用_llmManager底层接口发送请求将 assistant 应答写入会话,更新会话时间戳
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 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 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 callback
- 第二个 bool 参数:标记是否为最终一块分片
std::string ChatSDK::sendMessageStream(const std::string& sessionId, const std::string& message,
std::function 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 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 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不会隐式转换为unique_ptr,必须显式std::move。 std::move只是将左值强制转换为右值引用,本身不做内存释放;移动之后源对象变为空。
2.2 shared_ptr 多态向下转型
1. dynamic_pointer_cast()
运行时 RTTI 检查,安全向下转型;要求基类必须存在虚函数(虚析构)。
2. 类型不匹配,返回nullptr;可以用 if 判断转型结果。
static_pointer_cast<T>()
1. 编译期强制转换,无运行时检查;如果原始对象并不是目标子类,产生未定义行为 UB。
本项目Config基类添加virtual ~Config()=default;,目的就是为了支持dynamic_pointer_cast安全向下转型。
2.3 云端模型 vs Ollama 本地模型差异对比
项目云端 API 模型(deepseek/gpt/gemini)Ollama 本地模型鉴权必须 apikey不需要 apikey服务端点 endpoint代码内置默认值,用户可覆盖必须外部配置传入,无默认值模型名称代码写死固定名称完全由外部 config 配置传入,可以多个 ollama 模型配置结构体APIConfigOllamaConfig
3 ~> ChatSDK 整体编译交付流程
1. 完成全部类代码实现:ChatSDK、LLMManager、SessionManager、各个 LLMProvider 实现类
2. 将 SDK 编译为静态库 (.a)
3. 对外交付:头文件 + 编译产出静态库
4. 用户侧:引入头文件,链接静态库,构造vector配置,调用ChatSDK::initModels完成初始化,之后调用会话、发消息接口。
4 ~> 完整业务调用时序(外部用户视角)
1. 构造std::vector configs,填入需要用的模型配置(APIConfig/OllamaConfig)
2. ChatSDK sdk; sdk.initModels(configs); 完成模型注册、初始化
3. std::string sid = sdk.createSession("模型名称"); 创建会话
4. 调用 sdk.sendMessage(sid, "用户提问") 或者 sdk.sendMessageStream(sid, "提问", callback) 进行对话
5. 可选:getSessionLists查询会话,deleteSession销毁会话。
结尾
uu们,这里的内容到这里就全部结束了,艾莉丝在这里再次
艾莉丝努力练剑
C/C++ & Linux 底层探索者 | 一个正在努力练剑的技术博主
👀 【关注】 跟随我一起深耕技术领域,见证每一次成长。
❤️
【点赞】 让优质内容被更多人看见,让知识传递更有力量。
⭐
【收藏】 把核心知识点存好,在需要时随时查、随时用。
💬
【评论】 分享你的经验或疑问,评论区一起交流避坑!
不要忘记给博主“一键四连”哦!
“今日练剑达成!”
“技术之路难免有困惑,但同行的人会让前进更有方向。”
结语:希望对学习Linux相关内容的uu有所帮助,不要忘记给博主“一键四连”哦!
往期回顾:
🗡博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!🗡
>
૮₍ ˶ ˊ ᴥ ˋ˶₎ა
以上就是这次整理的全部内容,希望对你有所启发。如果有不同见解,欢迎在评论区交流讨论。
评论 (0)
暂无评论