这两天一直在研究这个话题,踩了几个坑,把遇到的东西整理成文,供有需要的朋友参考。
🎬 个人主页:艾莉丝努力练剑
❄专栏传送门:《C语言》《数据结构与算法》《C/C++干货分享&学过程记录》
《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》
⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平
🎬 艾莉丝的简介:
文章目录
1.2 智能指针选型优化 1.3 unique_ptr 核心特性与容器适配 2 ~> 模型注册接口达成 3 ~> 模型初始化接口达成 4 ~> 模型查询与可用性检测 5 ~> 消息发送接口实现 5.2 流式增量消息接口 结尾1 ~> LLMManager 类架构与智能指针选型
1.1 核心组件定义
1.1.1 类职责与成员变量
LLMManager 是大语言模型 SDK 的统一管理入口,负责 LLM 提供者的生命周期托管、注册状态维护、可用性校验与请求转发。
- 私有成员:
std::map _providers:键为模型唯一名称,值为模型提供者实例的独占智能指针,所有权由 LLMManager 全权持有
std::map _modelInfos:键为模型名称,值为模型元信息集合,存储描述、端点、可用状态等数据
1.1.2 ModelInfo 元信息结构体
用于标准化描述 LLM 模型的基础属性,作为对外暴露模型信息的统一数据结构。
struct ModelInfo {
std::string _modelName; // 模型唯一标识名称
std::string _modelDesc; // 模型功能描述
std::string _provider; // 模型提供厂商
std::string _endpoint; // API服务基础端点
bool _isAvailable = false; // 模型初始化完成、可服务状态标记
ModelInfo(const std::string& modelName,
const std::string& modelDesc,
const std::string& provider,
const std::string& endpoint)
: _modelName(modelName),
_modelDesc(modelDesc),
_provider(provider),
_endpoint(endpoint) {}
};
1.2 智能指针选型优化
1.2.1 初始方案缺陷
初始设计采用std::shared_ptr<LLMProvider>管理提供者实例,存在设计冗余:
- LLMProvider 实例仅在 LLMManager 内部使用,无跨类共享场景
- shared_ptr 的引用计数机制带来额外内存与性能开销
- 不符合独占所有权的设计语义,存在意外共享导致生命周期错乱的风险
1.2.2 优化方案:unique_ptr 独占语义
替换为std::unique_ptr<LLMProvider>,完全匹配设计需求:
- 严格遵循 RAII 独占所有权原则,资源由 LLMManager 唯一持有
- 无引用计数开销,运行时性能更优
- 编译期强制禁止拷贝,从语法层面保证资源唯一性
1.3 unique_ptr 核心特性与容器适配
1.3.1 拷贝语义禁用
- C++11 标准:通过
= delete显式删除拷贝构造函数与拷贝赋值运算符 - C++98 兼容方案:将拷贝构造、拷贝赋值声明为 private 且不提供实现
- 直接赋值 unique_ptr 会触发编译错误,务必通过移动语义完成所有权转移
1.3.2 容器插入方法
向 std::map 等容器插入 unique_ptr 时,务必通过std::move转移资源所有权,不能直接拷贝赋值。
2 ~> 模型注册接口实现
2.1 接口签名定义
namespace ai_chat_sdk {
class LLMManager {
public:
// 注册LLM提供者实例
// @param modelName 模型唯一标识
// @param provider 模型提供者独占指针
// @return 注册成功返回true,失败返回false
bool registerProvider(const std::string& modelName,
std::unique_ptr provider);
private:
std::map _providers;
std::map _modelInfos;
};
}
2.2 执行流程
1. 参数合法性校验:检测 provider 是否为空指针,空指针直接终止流程并输出错误日志
2. 资源所有权转移:通过std::move将 provider 实例的所有权转移至_providers 容器
3. 元信息初始化:向_modelInfos 插入对应模型的初始元信息对象
4. 状态返回:注册完成输出信息日志,返回 bool 类型的注册结果
2.3 完整实现代码
#include "../include/LLMManager.h"
#include "../include/util/myLog.h"
#include "../include/Common.h"
namespace ai_chat_sdk {
bool LLMManager::registerProvider(const std::string& modelName,
std::unique_ptr provider) {
// 空指针校验:禁止注册无效提供者
if (!provider) {
ERR("cannot register nullptr provider, modelName={}", modelName);
return false;
}
// 移动语义转移所有权,存入提供者容器
_providers[modelName] = std::move(provider);
// 初始化模型元信息
_modelInfos[modelName] = ModelInfo(modelName);
INFO("register provider success, modelName={}", modelName);
return true;
}
}
3 ~> 模型初始化接口实现
3.1 接口签名定义
namespace ai_chat_sdk {
class LLMManager {
public:
// 初始化指定模型
// @param modelName 目标模型名称
// @param modelParam 模型初始化配置参数键值对
// @return 初始化成功返回true,失败返回false
bool initModel(const std::string& modelName,
const std::map& modelParam);
};
}
3.2 执行流程
1. 注册状态校验:在_providers 中查找目标模型,未注册则直接返回失败
2. 底层初始化调用:通过迭代器获取 LLMProvider 实例,调用其 initModel 方法传入配置
3. 状态更新:初始化成功后,更新_modelInfos 中的模型描述、可用状态标记
4. 错误处理:初始化失败时输出错误日志,向上层返回失败状态
3.3 完整实现代码
bool LLMManager::initModel(const std::string& modelName,
const std::map& modelParam) {
// 校验模型是否已注册
auto it = _providers.find(modelName);
if (it == _providers.end()) {
ERR("model provider not found, modelName={}", modelName);
return false;
}
// 调用底层提供者执行初始化
bool isSuccess = it->second->initModel(modelParam);
if (!isSuccess) {
ERR("init model failed, modelName={}", modelName);
return false;
}
// 初始化成功,更新元信息与可用状态
INFO("init model success, modelName={}", modelName);
_modelInfos[modelName]._modelDesc = it->second->getModelDesc();
_modelInfos[modelName]._isAvailable = true;
return isSuccess;
}
4 ~> 模型查询与可用性检测
4.1 获取可用模型列表
- 功能:返回所有已完成初始化、状态为可用的模型元信息集合
- 实现逻辑:遍历_modelInfos 容器,筛选
_isAvailable为 true 的条目存入 vector 返回 - 实现代码:
std::vector LLMManager::getAvailableModels() const {
std::vector models;
for (const auto& pair : _modelInfos) {
// 仅返回处于可用状态的模型
if (pair.second._isAvailable) {
models.push_back(pair.second);
}
}
return models;
}
4.2 单模型可用性检测
- 功能:查询指定名称的模型是否处于可服务状态
- 实现逻辑:先校验模型是否存在,不存在直接返回 false;存在则返回其可用状态标记
- 实现代码:
bool LLMManager::isModelAvailable(const std::string& modelName) const {
auto it = _modelInfos.find(modelName);
if (it == _modelInfos.end()) {
return false;
}
return it->second._isAvailable;
}
5 ~> 消息发送接口实现
5.1 全量同步消息接口
5.1.1 接口定义
- 功能:向指定模型发送对话消息,同步等待完整响应结果
- 返回值:
std::string类型的模型完整响应文本
5.1.2 前置校验机制
1. 校验模型是否已完成注册(_providers 中存在对应条目)
2. 校验模型是否已初始化且处于可用状态
3. 任意校验失败均输出错误日志并返回空字符串
5.1.3 实现代码
std::string LLMManager::sendMessage(const std::string& modelName,
const std::vector& messages,
const std::map& requestParam) {
// 校验模型注册状态
auto it = _providers.find(modelName);
if (it == _providers.end()) {
ERR("model provider not found, modelName={}", modelName);
return "";
}
// 校验模型可用状态
if (!it->second->isAvailable()) {
ERR("model not available, modelName={}", modelName);
return "";
}
// 转发请求到底层LLM提供者实现
return it->second->sendMessage(messages, requestParam);
}
5.2 流式增量消息接口
5.2.1 接口定义
- 功能:向指定模型发送流式对话请求,支持增量式返回响应内容
- 返回值:
bool类型标识流式请求是否成功启动
5.2.2 实现逻辑
- 前置校验逻辑与全量接口完全一致
- 校验通过后调用底层 LLMProvider 的
sendMessageStream方法 - 流式数据的拼接、回调输出由底层提供者具体实现,LLMManager 仅做转发
结尾
uu们,本文的内容到这里就全部完成了,艾莉丝在这里再次
艾莉丝努力练剑
C/C++ & Linux 底层探索者 | 一个正在努力练剑的技术博主
👀 【关注】 跟随我一起深耕技术领域,见证每一次成长。
❤️
【点赞】 让优质内容被更多人看见,让知识传递更有力量。
⭐
【收藏】 把核心知识点存好,在得时随时查、随时用。
💬
【评论】 分享各位的经验或疑问,评论区一起交流避坑!
不要忘记给博主“一键四连”哦!
“今日练剑达成!”
“技术之路难免有困惑,但同行的人会让前进更有方向。”
结语:希望对学Linux相关内容的uu有所帮助,不要忘记给博主“一键四连”哦!
往期回顾:
🗡博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!🗡
>
૮₍ ˶ ˊ ᴥ ˋ˶₎ა
本次分享就到这里。技术这东西越研究越有意思,后续有新的收获我也会继续更新。
评论 (0)
暂无评论