一个模型一个接口?不存在的。
这篇文章带你认识 ChatSDK —— 一款用 C++ 实现的大模型接入库:一套接口,同时接入 DeepSeek、ChatGPT、Gemini,还能本地跑 Ollama;自带多轮对话、流式输出、会话管理和 SQLite 持久化。
从它是什么到5 分钟跑通第一个对话,然后再到接入自己的项目。
一、ChatSDK 是什么?
ChatSDK 是一个用 C++ 封装的大模型统一接入库,把不同厂商的 API 差异藏在一个抽象接口后面。
目前它支持的能力:
| 云端模型 | 已接入 deepseek-chat、gpt-4o-mini、gemini-2.0-flash |
| 本地模型 | 支持 Ollama 本地接入 deepseek-r1:1.5b |
| 对话形式 | 多轮聊天,支持全量返回和流式返回两种模式 |
| 会话管理 | 获取历史会话、获取历史会话消息 |
| 数据持久化 | 用 SQLite 存储会话数据,重启不丢 |
它解决的核心痛点
如果你直接调各家大模型的 API,会遇到这样的问题:
- DeepSeek 一套 JSON 格式、ChatGPT 一套、Gemini 又一套;
- 换模型就要改一堆业务代码;
- 多轮对话的上下文要自己拼;
- 会话历史要自己存。
ChatSDK 的设计目标是:让上层只认模型名和消息,具体怎么调各家 API,交给底层实现。
二、核心设计:面向接口 + 策略模式
先看它的类关系(架构骨架):

几个关键点:
三、代码结构与编译安装
1. 目录结构
.
├── sdk
│ ├── CMakeLists.txt
│ ├── include
│ │ ├── ChatGPTProvider.h
│ │ ├── chat_sdk.h
│ │ ├── common.h
│ │ ├── dataManager.h
│ │ ├── DeepSeekProvider.h
│ │ ├── GeminiProvider.h
│ │ ├── ILLMProvider.h
│ │ ├── LLMManager.h
│ │ ├── OllamaDeepSeekProvider.h
│ │ ├── session_manager.h
│ │ └── util
│ │ └── my_logger.h
│ ├── src
│ │ ├── ChatGPTProvider.cpp
│ │ ├── chat_sdk.cpp
│ │ ├── DataManager.cpp
│ │ ├── DeepSeekProvider.cpp
│ │ ├── GeminiProvider.cpp
│ │ ├── LLMManager.cpp
│ │ ├── OllamaDeepSeekProvider.cpp
│ │ ├── session_manager.cpp
│ │ └── util
│ │ └── my_logger.cpp
└── build
2. 编译安装
进入 sdk 所在目录,依次执行:
mkdir build && cd build # 创建 build 目录并进入
cmake .. # 生成构建文件,最终生成 libai_chat_sdk.a 静态库
sudo make install # 安装
安装后:
- 静态库:/usr/local/lib
- 头文件:/usr/local/include/ai_chat_sdk
四、核心 API:ChatSDK 类
使用时,你几乎只需要跟 ChatSDK 这一个类打交道。头文件:
#include <ai_chat_sdk/ChatSDK.h>
ChatSDK 的公开函数一览:
| bool initModels(const std::vector<std::shared_ptr<Config>>& configs) | 初始化所支持的模型 | 成功返回 true |
| std::string createSession(const std::string& modelName) | 为指定模型创建会话 | 返回会话 ID |
| std::shared_ptr<Session> getSession(const std::string& sessionId) | 获取指定会话信息 | 会话对象 |
| std::vector<std::string> getSessionList() | 获取所有会话 | 会话列表 |
| std::vector<ModelInfo> getAvailableModels() | 获取支持的所有模型 | 模型列表 |
| bool deleteSession(const std::string& sessionId) | 删除指定会话 | 成功返回 true |
| std::string sendMessage(const std::string sessionId, const std::string& message) | 发消息,模型一次性返回完整回复 | 完整回复 |
| std::string sendMessageStream(const std::string sessionId, const std::string& message, std::function<void(const std::string&, bool)> callback) | 发消息,模型生成一点返回一点(流式) | 完整回复 |
相关数据结构(如 Message、ModelInfo 等)在 sdk/include/common.h 里定义。
两种发消息方式的区别
- sendMessage(全量):等模型全部生成完,一次性返回。简单,但不适合长回答。
- sendMessageStream(流式):生成一段就回调一段,适合做「打字机效果」。回调函数的签名是 (const std::string& response, bool done):
- response:本次返回的片段
- done:是否已结束
五、快速上手:5 分钟跑通第一个对话
完整示例代码
#include <iostream>
#include <ai_chat_sdk/chat_sdk.h>
#include <ai_chat_sdk/util/my_logger.h>
// 发送一条消息(流式)
void sendMessageStream(ai_chat_sdk::ChatSDK& chatSDK, const std::string& sessionId)
{
std::cout << "————–发送消息————–" << std::endl;
std::cout << "user消息 > ";
std::string message;
std::getline(std::cin, message);
std::cout << "————–发送消息完成————–" << std::endl;
chatSDK.sendMessageStream(sessionId, message,
[](const std::string& response, bool done) {
std::cout << "assistant消息: " << response << std::endl;
if (done) {
std::cout << "————–接收消息完成————–" << std::endl;
}
});
}
int main(int argc, char* argv[])
{
// 1. 初始化日志
bite::Logger::init_logger("aiChatServer", "stdout", spdlog::level::info);
ai_chat_sdk::ChatSDK chatSDK;
// 2. 配置 deepseek 模型信息
ai_chat_sdk::ApiConfig deepseekConfig;
deepseekConfig.api_key = std::getenv("deepseek_apikey");
deepseekConfig.temperature = 0.7;
deepseekConfig.max_tokens = 2048;
deepseekConfig.model_name = "deepseek-chat";
// 3. 组装配置列表并初始化模型
std::vector<std::shared_ptr<ai_chat_sdk::Config>> configs;
configs.push_back(std::make_shared<ai_chat_sdk::ApiConfig>(deepseekConfig));
chatSDK.initModels(configs);
// 4. 创建会话
std::cout << "————–创建会话————–" << std::endl;
std::string sessionId = chatSDK.createSession("deepseek-chat");
std::cout << "创建会话成功, 会话ID: " << sessionId << std::endl;
// 5. 循环对话
int userOP = 1;
while (true) {
std::cout << "——-1. send message 0. exit—————–" << std::endl;
std::cin >> userOp;
if (userOP == 0) break;
getchar();
sendMessageStream(chatSDK, sessionId);
}
std::cout << "————–程序退出————–" << std::endl;
return 0;
}
关键步骤解析:
这里有一个坑:getenv 可能返回空指针
deepseekConfig.api_key = std::getenv("deepseek_apikey");
如果环境变量 deepseek_apikey 没有设置,std::getenv 会返回 nullptr,把它赋给 std::string 是未定义行为,程序直接崩溃。
稳妥写法:
const char* key = std::getenv("deepseek_apikey");
if (key == nullptr) {
std::cerr << "请先设置环境变量 deepseek_apikey" << std::endl;
return -1;
}
deepseekConfig.api_key = key;
六、接入自己的项目:CMake 配置
可以在自己的项目里写 CMakeLists.txt,参考如下:
# 项目名称
project(AIChatDemo)
# 使用 C++17,不允许降级
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 构建类型
set(CMAKE_BUILD_TYPE Debug)
# 可执行文件
add_executable(AIChatDemo cmdChatDemo.cpp)
# 查找 OpenSSL
find_package(OpenSSL REQUIRED)
include_directories(${OPENSSL_INCLUDE_DIR})
# 添加库搜索目录(ai_chat_sdk 装在这里)
link_directories(/usr/local/lib)
# 链接 SDK 及依赖
target_link_libraries(AIChatDemo PRIVATE
ai_chat_sdk
fmt
jsoncpp
OpenSSL::SSL
OpenSSL::Crypto
gflags
spdlog
sqlite3
)
编译运行:
mkdir build && cd build
cmake ..
make
七、注意事项
八、总结
ChatSDK 这套设计最值得学的,不是某个具体 API,而是它的分层思想:
- 门面(ChatSDK) 收口所有对外能力;
- 抽象接口(LLMProvider / Config) 隔离变化;
- 具体实现(各家 Provider) 各自为战;
- 数据层(DataManager) 负责持久化。
上层只认抽象,下层随便换厂商——这就是多模型统一接入的正确姿势。


