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

作者:艾莉丝努力练剑日期:2026/9/17

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

❄专栏传送门:《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录》
《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》

⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平


🎬 艾莉丝的简介:


文章目录

  • 1 ~> 项目背景与设计目标
    • 1.1 现有模型接入方案
    • 1.2 现有方案存在的问题
    • 1.3 LLMManager 设计目标
  • 2 ~> 核心抽象与数据结构
    • 2.1 LLMProvider 抽象基类
      • 2.1.1 核心接口契约
        • 2.1.2 子类实现示例(DeepSeekProvider)
    • 2.2 ModelInfo 模型元数据结构体
    • 2.3 LLMManager 核心管理类成员
      • 2.3.1 头文件基础结构
        • 2.3.2 成员变量设计说明
  • 3 ~> LLMManager 公有接口定义
    • 3.1 模型生命周期接口
      • 3.1.1 registerProvider 注册接口
        • 3.1.2 initModel 初始化接口
    • 3.2 模型查询接口
      • 3.2.1 getAvailableModels 获取可用列表
        • 3.2.2 isModelAvailable 可用性检查
    • 3.3 消息交互接口
      • 3.3.1 sendMessage 同步调用
        • 3.3.2 sendMessageStream 流式调用
  • 4 ~> 核心方法实现细节
    • 4.1 注册与初始化逻辑
      • 4.1.1 registerProvider 实现
        • 4.1.2 initModel 实现
    • 4.2 查询逻辑实现
      • 4.2.1 getAvailableModels 实现
        • 4.2.2 isModelAvailable 实现
    • 4.3 消息转发机制
  • 5 ~> 扩展机制与架构价值
    • 5.1 模型扩展流程
    • 5.2 架构设计优势
    • 5.3 当前已接入模型清单
  • 结尾


1 ~> 项目背景与设计目标

1.1 现有模型接入方案

  • 云端模型接入:通过 HTTP API 调用方式接入三类主流云端大语言模型,包括 ChatGPT 系列、Gemini 系列、DeepSeek 系列
  • 本地模型接入:基于 Ollama 第三方推理工具,实现本地大模型的部署、加载与调用管理
  • 基础扩展逻辑:新增模型接入仅需新建对应实现类,重写抽象基类的纯虚方法即可完成适配,无需修改核心框架

1.2 现有方案存在的问题

  • 代码冗余度高:不同云端模型除 API 密钥、服务端点不同外,请求封装、响应解析、流式处理等核心逻辑高度重合;每接入新模型都需重复实现完整逻辑,代码复用率低、可读性差
  • 业务耦合度高:模型数量增多后,上层业务需直接感知具体模型实现类,调用时需实例化对应 Provider,维护与切换成本高
  • 缺乏统一管控:模型状态、配置、生命周期分散在各个实现类中,无法进行统一的状态监控与调度管理

1.3 LLMManager 设计目标

基于面向对象多态机制构建统一模型管理层,实现三大核心目标:

  • 屏蔽底层不同模型的实现差异,对外提供一致的调用接口
  • 集中管理所有模型的注册、初始化、状态校验与消息转发
  • 上层业务无需依赖具体模型实现类,仅通过 LLMManager 即可完成全部模型交互,符合开闭原则

2 ~> 核心抽象与数据结构

2.1 LLMProvider 抽象基类

LLMProvider 是所有模型提供者的抽象基类,定义了统一的接口契约,是多态机制的核心基础。所有具体模型必须继承该类并实现全部纯虚函数。

2.1.1 核心接口契约

1class LLMProvider {
2public:
3    virtual ~LLMProvider() = default;
4
5    // 模型初始化:加载配置、校验密钥、建立连接
6    virtual bool initModel(const std::map<std::string, std::string>& modelConfig) = 0;
7    
8    // 检查模型当前是否可用
9    virtual bool isAvailable() const = 0;
10    
11    // 获取模型元数据信息
12    virtual ModelInfo getModelInfo() const = 0;
13    
14    // 同步发送消息,返回完整回复
15    virtual std::string sendMessage(
16        const std::vector<Message>& messages,
17        const std::map<std::string, std::string>& requestParam
18    ) = 0;
19    
20    // 流式发送消息,通过回调逐块返回数据
21    virtual std::string sendMessageStream(
22        const std::vector<Message>& messages,
23        const std::map<std::string, std::string>& requestParam,
24        std::function<void(const std::string& chunk, bool last)> chunkCallback
25    ) = 0;
26};
27

2.1.2 子类实现示例(DeepSeekProvider)

1bool DeepSeekProvider::initModel(const std::map<std::string, std::string>& modelConfig) {
2    // 读取并校验API密钥
3    auto it = modelConfig.find("api_key");
4    if (it == modelConfig.end()) {
5        ERR("DeepSeekProvider initModel api_key not found");
6        return false;
7    }
8    _apiKey = it->second;
9
10    // 读取并校验服务端点
11    it = modelConfig.find("endpoint");
12    if (it == modelConfig.end()) {
13        ERR("DeepSeekProvider initModel endpoint not found");
14        return false;
15    }
16    _endpoint = it->second;
17
18    _isAvailable = true;
19    INFO("DeepSeekProvider initModel success, endpoint: {}", _endpoint);
20    return true;
21}
22
23bool DeepSeekProvider::isAvailable() const {
24    return _isAvailable;
25}
26
27std::string DeepSeekProvider::getModelName() const {
28    return "deepseek-chat";
29}
30

2.2 ModelInfo 模型元数据结构体

定义于common.h头文件,用于存储模型的静态描述信息,实现模型元数据与业务实现的分离,支撑对外信息展示。

1struct ModelInfo {
2    std::string modelName;    // 模型唯一标识名称
3    std::string modelDesc;    // 模型功能与定位描述
4    std::string provider;     // 模型提供厂商
5    std::string endpoint;     // 模型API服务根地址
6    bool isAvailable = false; // 模型实时可用性状态
7
8    // 带默认参数的构造函数
9    ModelInfo(
10        const std::string& modelName = "",
11        const std::string& modelDesc = "",
12        const std::string& provider = "",
13        const std::string& endpoint = ""
14    ) : modelName(modelName), modelDesc(modelDesc), provider(provider), endpoint(endpoint) {}
15};
16

2.3 LLMManager 核心管理类成员

LLMManager 通过双映射容器实现模型实例与元数据的统一管理,是整个 SDK 的核心调度中枢。

2.3.1 头文件基础结构

1#pragma once
2#include <map>
3#include <memory>
4#include <vector>
5#include <string>
6#include <stdexcept>
7#include <functional>
8#include "LLMProvider.h"
9#include "common.h"
10
11namespace ai_chat_sdk {
12
13class LLMManager {
14public:
15    // 公有业务接口(后续章节详细定义)
16
17private:
18    // 模型提供者映射表:key=模型名称, value=模型提供者基类智能指针
19    std::map<std::string, std::shared_ptr<LLMProvider>> providers;
20    
21    // 模型信息映射表:key=模型名称, value=模型元数据对象
22    std::map<std::string, ModelInfo> modelInfos;
23};
24
25} // namespace ai_chat_sdk
26

2.3.2 成员变量设计说明

  • providers:存储所有已注册的模型提供者实例,通过基类指针指向子类对象,利用 C++ 多态特性实现统一调用
  • modelInfos:存储所有模型的元数据信息,与providers通过模型名称一一对应;对外仅暴露该层数据,避免泄露内部实现对象

3 ~> LLMManager 公有接口定义

3.1 模型生命周期接口

3.1.1 registerProvider 注册接口

1void registerProvider(const std::string& modelName, std::shared_ptr<LLMProvider> provider);
2
  • 功能:将具体模型的实现类实例注册到管理容器,是模型纳入统一管理的入口
  • 参数:
    • modelName:模型唯一标识名称,作为后续调用的索引键
    • provider:模型提供者实例的智能指针,必须是 LLMProvider 子类的实例
  • 约束:重复注册同一名称的模型会覆盖原有实例

3.1.2 initModel 初始化接口

1bool initModel(const std::string& modelName, const std::map<std::string, std::string>& modelParam);
2
  • 功能:根据模型名称查找对应实例,完成配置加载与可用性校验
  • 参数:
    • modelName:目标模型的注册名称
    • modelParam:模型初始化参数字典,通常包含api_key、endpoint等配置项
  • 返回值:初始化成功返回 true,失败返回 false
  • 异常:模型未注册时抛出std::runtime_error异常

3.2 模型查询接口

3.2.1 getAvailableModels 获取可用列表

1std::vector<ModelInfo> getAvailableModels() const;
2
  • 功能:返回所有已注册且状态为可用的模型元数据集合
  • 应用场景:客户端新建会话时的模型选择界面展示
  • 返回值:仅包含isAvailable = true的模型信息

3.2.2 isModelAvailable 可用性检查

1bool isModelAvailable(const std::string& modelName) const;
2
  • 功能:校验指定名称的模型是否存在且处于可用状态
  • 返回值:模型不存在或不可用均返回 false,可用返回 true
  • 作用:消息发送前的前置校验,避免无效调用

3.3 消息交互接口

3.3.1 sendMessage 同步调用

1std::string sendMessage(
2    const std::string& modelName,
3    const std::vector<Message>& messages,
4    const std::map<std::string, std::string>& requestParam
5);
6
  • 功能:向指定模型同步发送对话消息,等待并返回完整回复文本
  • 参数:
    • modelName:目标模型名称
    • messages:对话历史消息列表,包含角色与内容
    • requestParam:请求超参数,如temperature、max_tokens等

3.3.2 sendMessageStream 流式调用

1std::string sendMessageStream(
2    const std::string& modelName,
3    const std::vector<Message>& messages,
4    const std::map<std::string, std::string>& requestParam,
5    std::function<void(const std::string& chunk, bool last)> chunkCallback
6);
7
  • 功能:向指定模型发送流式请求,通过回调函数逐块返回生成的文本
  • 回调参数:
    • chunk:当前返回的文本片段
    • last:是否为最后一块数据,为 true 时表示响应结束
  • 返回值:最终拼接完成的完整回复文本
  • 流式回调使用示例:
    • auto writeChunk = [](const std::string& chunk, bool last) { INFO("chunk: {}", chunk); if (last) { INFO("[DONE]"); } }; std::string fullData = manager.sendMessageStream("deepseek-chat", messages, requestParam, writeChunk);

4 ~> 核心方法实现细节

4.1 注册与初始化逻辑

4.1.1 registerProvider 实现

1void LLMManager::registerProvider(const std::string& modelName, std::shared_ptr<LLMProvider> provider) {
2    providers[modelName] = provider;
3    // 同步写入模型基础信息,保证双映射表数据一致
4    modelInfos[modelName] = provider->getModelInfo();
5}
6
  • 实现要点:注册阶段同时维护providers与modelInfos两个容器,保证数据一致性;注册仅存储实例,不执行初始化

4.1.2 initModel 实现

1bool LLMManager::initModel(const std::string& modelName, const std::map<std::string, std::string>& modelParam) {
2    auto it = providers.find(modelName);
3    if (it == providers.end()) {
4        throw std::runtime_error("Model provider not found: " + modelName);
5    }
6    
7    // 多态调用:基类指针调用子类重写的初始化方法
8    bool success = it->second->initModel(modelParam);
9    // 更新元数据中的可用性状态
10    modelInfos[modelName].isAvailable = success;
11    return success;
12}
13
  • 多态原理:基类指针根据指向对象的实际类型,调用对应子类重写的虚函数,实现 “一个接口,多种实现”
  • 状态同步:初始化结果同步更新到modelInfos,确保查询接口返回最新状态

4.2 查询逻辑实现

4.2.1 getAvailableModels 实现

1std::vector<ModelInfo> LLMManager::getAvailableModels() const {
2    std::vector<ModelInfo> models;
3    for (const auto& pair : modelInfos) {
4        if (pair.second.isAvailable) {
5            models.push_back(pair.second);
6        }
7    }
8    return models;
9}
10
  • 实现逻辑:遍历元数据映射表,过滤出可用状态的模型并返回;不直接操作providers容器,符合信息隐藏原则

4.2.2 isModelAvailable 实现

1bool LLMManager::isModelAvailable(const std::string& modelName) const {
2    auto it = modelInfos.find(modelName);
3    if (it == modelInfos.end()) {
4        return false;
5    }
6    return it->second.isAvailable;
7}
8
  • 容错处理:模型不存在时直接返回 false,不抛出异常,保证接口调用的安全性

4.3 消息转发机制

LLMManager 本身不处理具体的 HTTP 请求、协议封装与响应解析,所有消息交互均采用路由转发模式:

1std::string LLMManager::sendMessage(
2    const std::string& modelName,
3    const std::vector<Message>& messages,
4    const std::map<std::string, std::string>& requestParam
5) {
6    auto it = providers.find(modelName);
7    if (it == providers.end()) {
8        throw std::runtime_error("Model provider not found: " + modelName);
9    }
10    if (!it->second->isAvailable()) {
11        throw std::runtime_error("Model is not available: " + modelName);
12    }
13    // 转发给具体模型提供者执行
14    return it->second->sendMessage(messages, requestParam);
15}
16
  • 职责边界:LLMManager 仅负责路由寻址、前置校验与结果转发,业务逻辑完全下沉到各 Provider 子类
  • 流式接口实现逻辑与同步接口一致,仅增加回调函数透传

5 ~> 扩展机制与架构价值

5.1 模型扩展流程

新增模型接入严格遵循开闭原则,无需修改 LLMManager 核心代码,标准流程如下:

  1. 新建模型 Provider 类,公开继承 LLMProvider 抽象基类
  2. 重写所有纯虚函数:initModel、isAvailable、getModelInfo、sendMessage、sendMessageStream
  3. 上层业务实例化新模型 Provider,调用registerProvider注册到 LLMManager
  4. 传入配置参数调用initModel,完成初始化后即可通过统一接口调用

5.2 架构设计优势

  • 业务解耦:上层业务仅依赖 LLMManager 与通用数据结构,与具体模型实现完全隔离,模型切换无需修改业务代码
  • 统一规范:所有模型遵循相同的接口契约,保证调用方式、参数结构、错误处理的一致性
  • 可维护性:各模型实现逻辑内聚于独立的 Provider 类,故障定位、功能迭代、性能优化互不影响
  • 可测试性:可基于 LLMProvider 接口注入 Mock 实现,在无真实 API 的环境下完成单元测试

5.3 当前已接入模型清单

模型名称接入方式定位说明
deepseek-r1:70b本地 OllamaDeepSeek 旗舰级开源大模型,128K 上下文,主打深度理解与推理
gemini-2.0-flash云端 APIGoogle 极速响应模型,面向大规模部署与快速交互场景
gpt-4o-mini云端 APIOpenAI 轻量级高性价比模型,核心能力接近 GPT-4 Turbo
deepseek-chat云端 API中文优化通用对话模型,适用于日常问答与创意创作场景

结尾

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

艾莉丝努力练剑 C/C++ & Linux 底层探索者 | 一个正在努力练剑的技术博主 👀 【关注】 跟随我一起深耕技术领域,见证每一次成长。 ❤️ 【点赞】 让优质内容被更多人看见,让知识传递更有力量。 ⭐ 【收藏】 把核心知识点存好,在需要时随时查、随时用。 💬 【评论】 分享你的经验或疑问,评论区一起交流避坑! **不要忘记给博主“一键四连”哦! “今日练剑达成!” “技术之路难免有困惑,但同行的人会让前进更有方向。”

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

**往期回顾:

【AI大模型接入SDK】Ollama API 流式增量响应

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

૮₍ ˶ ˊ ᴥ ˋ˶₎ა


《【AI大模型接入SDK】LLMManager架构设计与实现》 是转载文章,点击查看原文。


相关推荐


2024上半年,零售行业三大观察
2601_962099082026/9/9

字数:1563;阅读时间:4分钟 宏观层面增长放缓 将目光投至2024年上半年, 零售业相关数据有了体现, 增长速度变缓的景象慢慢明晰起来, 逐一被揭晓呈显出, 并且渐次清晰可见。 以国家统计局所给出的数据来看, 社会消费品零售总额尽管呈现出保持增长的态势, 不过, 其增速显著地放缓了, 同比增长为3.7%, 那么, 这一数字背后隐匿着零售业的哪些秘密呢? 不同零售业态的表现呈现出分化的态势。 便利店的零售额增长速度, 与专业店以及超市有所不同。其中, 便利店同比增长率以5.8%占


2.django - 项目结构和模板语法
Aa123456789_552026/9/1

静态文件要放在app/static目录中。Django会自动在这个文件中寻找对应模板 模板语法 本质上是django专属在HTML中的一些占位符。 list 取值 索引取值: 通过 “.”+索引 For循环取值 Dict字典取值 通过索引取值 获取所有key值。N3.keys 获取所有value值. N3.values 获取key和value值. N3.items 判断语句


深入理解 TCP 协议(二):TCP 可靠传输与高效通信机制详解
Mortalbreeze2026/8/24

目录 前言 一、确认应答机制 二、超时重传机制 2.1 理解丢包的本质 2.2 超时时间如何确定 三、滑动窗口机制 3.1 深度理解 send/write 和发送缓冲区 3.2 理解滑动窗口 3.3 理解结合滑动窗口发送报文的流程 3.4 滑动窗口机制的进一步理解——发送缓冲区的空间复用 3.5 滑动窗口机制的进一步优化——快速重传机制 3.6 滑动窗口的大小如何确定 四、流量控制机制 4.1 零窗口探测 4.2 16 位窗口大小的限制与窗口扩大因子 五、拥塞


如何使用GSAP实现一个 `pinned` 滚动楼层叙事?
Mh2026/8/11

准备工作 技术栈: vue + gsap 最近在做的一个动画,特意去网上查了一下叫 pinned 滚动叙事,感觉蛮有趣,分享给你们。 实现的动画如下: 对应的模仿网址是:www.vaporesso.com/series-prod… 思考过程🤔 多滚动几次上面的动画,感官上大致可以得出一个粗浅的感受。 页面滚到某一段时,画面突然停住了。你继续滚动,页面没有向下走,而是像一条时间线一样开始播放:卡片移动到中心、放大、图片和文字拉开距离,然后卡片退场,背后的内容一层一层覆盖进来。等这一段讲完,卡片


06|眼睛:LLM 的「视野」怎么拼出来,又怎么不爆
浪遏2026/8/2

这是《Agent全栈实战》的第 6 篇。整个系列以 catbuddy(一个本地优先的 AI 编程助手,约 3.6 万行 TypeScript)为案例,由浅入深拆解 harness 设计。前面我们讲了心脏(Agent Loop)和手脚(工具系统)。这一篇聊「眼睛」——模型每次开口之前,它到底看到了什么。你给 LLM 的那一长串 messages,不是随手拼的,而是一条五层流水线装出来的;而对话一长,这串东西就会撑爆上下文窗口,撞上窗口红线直接 context_length_exceeded。所以这


Java Jetty 实战详解:从嵌入式 HTTP 服务到 Spring Boot 容器替换
唐青枫2026/7/25

简介 Jetty 是 Eclipse 基金会维护的 Java Web 服务器,也是一个 Servlet 容器。 它主要能做这些事: 监听 HTTP 端口 处理 HTTP 请求和响应 运行 Servlet / Filter / Listener 部署 WAR 包 支持 WebSocket、HTTP/2、HTTP/3 作为库嵌入到 Java 程序里启动 作为 Spring Boot 的内嵌容器 一句话概括: Jetty 既能像 Tomcat 一样单独部署 Web 应用,也能像普通 Java 库一样


学习 OpenMontage 的工具发现与打分选择器
日习一技2026/7/17

在前面的几篇文章里,我们已经体验了 OpenMontage 的零成本玩法:用 Piper 配音、用免费素材剪纪录片、用 Remotion 把图片做成动画,全程不花一分钱 API 费用。我们也试过贴一个参考视频,让 agent 帮我们拆解出差异化的制作方案。 不过零成本路径终究有上限。想要 FLUX 的图、Veo 或 Kling 的真实运动镜头、ElevenLabs 的高质量配音,就得接入对应的 provider。OpenMontage 支持的 provider 有几十个,同一个能力往往有好几个、


LeetCode 28. 找出字符串中第一个匹配项的下标
Best_Jerry2026/7/9

leetcode.cn/problems/fi… programmercarl.com/0028.%E5%AE… 给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回  -1 ****。   示例 1: 输入: haystack = "sadbutsad", needle = "sad" 输出: 0 解释: "sad" 在下标 0 和


图解 MongoDB 22|读写关注:持久性与一致性的档位选择
十三Tech2026/7/1

前面几篇多次提到 w: "majority",这篇把它彻底讲清楚。读写关注(read/write concern)是 MongoDB 控制持久性和一致性的核心参数——它们决定了「一个写入要被几个节点确认才算成功」「一个读取从哪个节点读、读到什么程度的一致」。理解了它们,才能在不同业务场景下精准调出「够用且不浪费」的持久性/一致性档位。 先把机制边界说清楚 读写关注是三个相关但独立的参数: writeConcern(写关注):写操作要被几个节点确认才算成功。控制持久性。 readPreferen


图解 MongoDB 05|文档模型设计:内嵌 vs 引用,反范式不是免费午餐
十三Tech2026/6/22

刚从 MySQL 迁到 MongoDB 的人,最容易把关系建模那一套照搬过来:每个实体建一个集合,用 userId、orderId 这种字段做关联,查询时再 $lookup 拼。这种写法能跑,但它把 MongoDB 用成了「没有外键约束的关系库」,丢掉了文档模型最大的优势——访问局部性。 文档模型真正的价值,不是「字段随便加」,而是把一个业务实体的相关信息内嵌成一个文档,应用读一次就能拿到全部信息。但内嵌也不是免费午餐:它换来访问效率的同时,要承担冗余、一致性维护和文档膨胀的成本。这一篇讲清楚内

首页编辑器站点地图

本站内容在 CC BY-SA 4.0 协议下发布

Copyright © 2026 聚合阅读