
它解决什么问题
ChatSDK 是一个 C++ 实现的大模型接入静态库,编译产物是 libai_chat_sdk.a。它把 DeepSeek、ChatGPT、Gemini 这类云端模型和 Ollama 本地模型统一收口,对外只暴露一个 ChatSDK 入口类,屏蔽掉会话管理、模型适配和持久化的繁琐细节。使用者不用关心底下是哪个厂商,也不用自己拼 HTTP 请求。
支持的范围:
- 云端模型:deepseek-chat、gpt-4o-mini、gemini-2.0-flash
- 本地 Ollama 模型:deepseek-r1:1.5b
能力上同时提供全量消息和流式消息两种返回模式,会话数据走 SQLite 落盘,可以做多轮对话、新建/删除会话、拉取历史。
源码布局与编译安装
仓库里 sdk 目录平级放着 CMakeLists.txt、include、src 和 build。头文件按职责拆开:chat_sdk.h 是总入口,ILLMProvider.h 是抽象接口,各厂商有各自的 DeepSeekProvider.h、ChatGPTProvider.h、GeminiProvider.h、OllamaDeepSeekProvider.h,会话和持久化分别由 session_manager.h、dataManager.h 负责,日志走 util/my_logger.h。
编译安装就三步:
mkdir build && cd build
cmake ..
sudo make install
装完之后头文件在 /usr/local/include/ai_chat_sdk/,静态库在 /usr/local/lib/libai_chat_sdk.a。
内部骨架:外观模式加面向接口
ChatSDK 是典型的外观(Facade)入口,它用组合关系聚合了 SessionManager、LLMManager 和 Config,把内部复杂度挡在门外。
LLMManager负责模型实例初始化、发消息、取模型名、检测可用性,内部持有LLMProvider抽象接口,自己不写网络请求;SessionManager维护多组Session,每个Session带多条Message,还内嵌一个DataManager做持久化,接口覆盖建会话、列会话、删会话、清场、取总数,sessionId 和 messageId 自动生成;DataManager专管 SQLite 落盘,把内存里的会话对象读写到磁盘;LLMProvider是抽象基类,四个子类DeepSeekProvider、ChatGPTProvider、GeminiProvider、OllamaDeepSeekProvider各管一种模型;Config是配置基类,ApiConfig存云端的 api_key、temperature、max_tokens、model_name,OllamaConfig存本地地址和模型名。
工程怎么接进去
业务侧引入头文件:
#include <ai_chat_sdk/chat_sdk.h>

CMake 里把目标链上:
target_link_libraries(你的项目目标 PRIVATE ai_chat_sdk)
公开接口清单
| 函数签名 | 功能说明 | 参数说明 | 返回值 |
|---|---|---|---|
bool initModels(const std::vector<std::shared_ptr<Config>>& configs) |
批量初始化模型 | configs:多个模型配置智能指针集合 | 初始化成功 true,失败 false |
std::string createSession(const std::string& modelName) |
为指定模型创建全新会话 | modelName:已初始化的模型名称 | 返回会话 sessionId 字符串 |
std::shared_ptr<Session> getSession(const std::string& sessionId) |
获取指定会话对象 | sessionId:会话唯一 ID | 会话智能指针 |
std::vector<std::string> getSessionlist() |
获取全部会话 ID 列表 | 无 | 所有 sessionId 集合 |
std::vector<ModelInfo> getAvailableModels() |
获取所有可用模型信息 | 无 | 模型信息结构体数组 |
bool deleteSession(const std::string& sessionId) |
删除指定会话 | sessionId:待删除会话 ID | 删除成功 true |
std::string sendMessage(const std::string sessionId, const std::string& message) |
非流式发送消息,等待模型全部生成完成返回完整结果 | sessionId 会话 ID;message 用户输入文本 | 完整助手回复字符串 |
std::string sendMessageStream(const std::string sessionId, const std::string& message, std::function<void(const std::string&,bool)> callback) |
流式消息发送,模型分片输出,回调逐段接收内容 | sessionId 会话 ID;message 输入;callback 回调:第一个参数分片文本,第二个 bool 标记是否流式结束 | 完整助手回复字符串 |
相关结构体定义参考头文件 sdk/include/common.h。
跑一个流式对话 Demo
下面这段命令行示例初始化 DeepSeek,建会话,循环读 stdin 做流式问答:
#include <iostream>
#include <string>
#include <cstdio>
#include <memory>
#include <ai_chat_sdk/chat_sdk.h>
#include <ai_chat_sdk/util/my_logger.h>
void sendMessageStreamDemo(ai_chat_sdk::ChatSDK& chatSDK, const std::string& sessionId)
{
std::cout << "\n------发送消息------" << 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;
if(done)
{
std::cout << "\n------接收完成------\n";
}
});
}
int main(int argc,char* argv[])
{
bite::Logger::init_logger("aiChatServer","stdout",spdlog::level::info);
ai_chat_sdk::ChatSDK chatSDK;
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";
std::vector<std::shared_ptr<ai_chat_sdk::Config>> configs;
configs.push_back(std::make_shared<ai_chat_sdk::ApiConfig>(deepseekConfig));
chatSDK.initModels(configs);
std::cout << "\n------创建会话--------"<<std::endl;
std::string sessionId = chatSDK.createSession("deepseek-chat");
std::cout << "创建会话成功,会话ID:" << sessionId << std::endl;
int userOp = 1;
while(true)
{
std::cout << "\n-------1.send message | 0.exit---------"<<std::endl;
std::cin >> userOp;
if(userOp == 0)
{
break;
}
getchar();
sendMessageStreamDemo(chatSDK, sessionId);
}
return 0;
}
bite::Logger::init_logger 依赖 spdlog,max_tokens 在 Demo 里设成了 2048,比接入层默认的 1024 更宽松,长回答不容易被打断。
链接时的传递依赖
静态库本身不带依赖,但它内部用到的东西要在最终链接可执行文件时补齐。SDK 的日志走 spdlog,云端模型走 HTTP 客户端(通常是 libcurl),持久化用 SQLite,HTTPS 场景还要 OpenSSL。拼链接命令时这些库必须跟在 -lai_chat_sdk 后面,否则 ld 从左往右解析符号会漏掉:
g++ main.cpp -lai_chat_sdk -lspdlog -lcurl -lsqlite3 -lssl -lcrypto -lpthread
如果你要把 SDK 编进一个 .so 共享库,源码编译得加 -fPIC 生成位置无关代码,否则链接器会报「relocation R_X86_64_32 against ... can not be used when making a shared object」。
验证装得对不对
# 头文件和库是否到位
find /usr/local -name "*ai_chat_sdk*"
# 确认导出了关键符号
nm /usr/local/lib/libai_chat_sdk.a | grep -E "initModels|sendMessage"
# 跑完 Demo 后,看 SQLite 是否真的落了盘
sqlite3 *.db ".tables"
会话持久化基于 SQLite,直接拿 sqlite3 打开生成的库文件,列一下表就能确认 Session、Message 有没有写进去,比靠肉眼看输出更靠谱。
设计上的几处可取之处
把静态库、头文件、CMake 脚本和使用文档一起托管,第三方接入成本最低。外观模式让调用方只面对 ChatSDK,面向接口的 LLMProvider 让加新模型只是新增一个子类,会话对象与磁盘存储解耦,云端和本地、全量与流式两套模式都能兼顾。

评论0