欢迎光临
我们一直在努力

【AI大模型接入SDK】ChatSDK整体实现

头像

🎬 个人主页:艾莉丝努力练剑

❄专栏传送门:《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 类职责

  • 维护_providers:std::unordered_map<std::string, std::unique_ptr<LLMProvider>>,保存模型名称与 provider 实例独占指针
  • 维护_modelInfos:保存每个模型运行状态、描述信息
  • 核心接口
  • registerProvider():注册 LLM 提供者,接收模型名 + unique_ptr<LLMProvider>,发生资源转移 std::move
  • initModel():对已注册模型执行 provider 的initModel,完成模型实例初始化
  • isModelAvailable():判断模型是否注册且初始化完成可用
  • getAvailableModels():获取全部可用模型信息
  • sendMessage():全量模式下发消息给底层 provider
  • sendMessageStream():流式模式下发消息给底层 provider,传入回调
  • 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。 公共前置逻辑:

  • 校验 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<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 多态向下转型

  • dynamic_pointer_cast<T>()
  • 运行时 RTTI 检查,安全向下转型;要求基类必须存在虚函数(虚析构)。
  • 类型不匹配,返回nullptr;可以用 if 判断转型结果。
  • static_pointer_cast<T>()
  • 编译期强制转换,无运行时检查;如果原始对象并不是目标子类,产生未定义行为 UB。
  • 本项目Config基类添加virtual ~Config()=default;,目的就是为了支持dynamic_pointer_cast安全向下转型。

    2.3 云端模型 vs Ollama 本地模型差异对比

    项目云端 API 模型(deepseek/gpt/gemini)Ollama 本地模型
    鉴权 必须 apikey 不需要 apikey
    服务端点 endpoint 代码内置默认值,用户可覆盖 必须外部配置传入,无默认值
    模型名称 代码写死固定名称 完全由外部 config 配置传入,可以多个 ollama 模型
    配置结构体 APIConfig OllamaConfig

    3 ~> ChatSDK 整体编译交付流程

  • 完成全部类代码实现:ChatSDK、LLMManager、SessionManager、各个 LLMProvider 实现类
  • 将 SDK 编译为静态库 (.a)
  • 对外交付:头文件 + 编译产出静态库
  • 用户侧:引入头文件,链接静态库,构造vector<shared_ptr<Config>>配置,调用ChatSDK::initModels完成初始化,之后调用会话、发消息接口。

  • 4 ~> 完整业务调用时序(外部用户视角)

  • 构造std::vector<std::shared_ptr<Config>> configs,填入需要使用的模型配置(APIConfig/OllamaConfig)
  • ChatSDK sdk; sdk.initModels(configs); 完成模型注册、初始化
  • std::string sid = sdk.createSession("模型名称"); 创建会话
  • 调用 sdk.sendMessage(sid, "用户提问") 或者 sdk.sendMessageStream(sid, "提问", callback) 进行对话
  • 可选:getSessionLists查询会话,deleteSession销毁会话。

  • 结尾

    uu们,本文的内容到这里就全部结束了,艾莉丝在这里再次感谢您的阅读!

    艾莉丝努力练剑

    C/C++ & Linux 底层探索者 | 一个正在努力练剑的技术博主


    👀
    【关注】 跟随我一起深耕技术领域,见证每一次成长。

    ❤️
    【点赞】 让优质内容被更多人看见,让知识传递更有力量。

    ⭐
    【收藏】 把核心知识点存好,在需要时随时查、随时用。

    💬
    【评论】 分享你的经验或疑问,评论区一起交流避坑!

    不要忘记给博主“一键四连”哦!

    “今日练剑达成!”

    “技术之路难免有困惑,但同行的人会让前进更有方向。”

    结语:希望对学习Linux相关内容的uu有所帮助,不要忘记给博主“一键四连”哦!

    往期回顾:

    【AI大模型接入SDK】ChatSDK架构设计与实现

    🗡博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!🗡

    ૮₍ ˶ ˊ ᴥ ˋ˶₎ა

    在这里插入图片描述

    赞(0)
    未经允许不得转载:171主机测评 » 【AI大模型接入SDK】ChatSDK整体实现
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址