引言
上篇文章我们的Notepad++插件介绍到Dock窗口集成
,本篇将继续完善插件功能,主要包括两个部分:
- 支持多平台、多模型
- 支持多种授权验证、接口类型
一、多平台
原先的配置项很简单:
// PluginConf.h
class PlatformConf {
public:std::string _baseUrl; // API基础地址std::string _apiSkey; // 认证密钥std::string _modelName; // 模型标识std::string _generateEndpoint; // 生成接口std::string _chatEndpoint; // 对话接口
};
但是插件本身可能需要接入多个平台,因此有必要支持多平台,因此需要重新设计配置文件,如下:
{// 当前选用的运行平台标识// 必须与下方platforms对象中的某个平台键名完全一致// 系统将根据此字段加载对应的平台配置"platform": "OurCopDev",// 多平台环境配置集合// 支持预定义多个平台的配置参数,便于快速切换环境// 每个键名代表平台标识,建议采用有明确含义的命名(如环境类型/业务线)"platforms": {// Infini平台配置(示例第三方系统集成)// 可包含API地址、认证信息、超时设置等参数"infini": {// 平台配置项示例:// "api_endpoint": "https://api.infini.ai",// "auth_token": "xxx-xxx-xxx"},// 生产环境配置// 通常包含正式环境地址、生产用密钥等敏感信息"OurCopProd": {// 平台配置项示例:},// 开发环境配置// 一般包含测试服务器地址、调试参数等非生产配置"OurCopDev": {// 典型配置项}}
}
这样,插件根据当前的配置平台名称platform
支持使用不同的AI平台
二、多模型
因为一般平台会提供多个内置的模型,因此需要在此基础上,支持用户选择不同的模型。
此外,不同的平台接口也不一样,有的是https
,有的是http
,有的是post
接口,有的是get
接口,因此针对各种情况需要抽象细化需求,最终整理设计的平台配置内容如下:
{// SSL配置开关// true: 启用HTTPS协议,所有请求将通过加密通道传输// false: 使用HTTP协议(不建议生产环境使用)// 注意:启用时需确保服务端配置了有效的SSL证书"enable_ssl": true,// 基础服务地址// API请求的根域名/地址,所有接口路径将基于此地址拼接// 示例:https://cloud.infini-ai.com/maas/v1/..."base_url": "cloud.infini-ai.com",// 当前激活的模型名称// 必须与models列表中某个值完全匹配// 用于默认的API请求参数"model_name": "deepseek-r1-distill-qwen-32b",// 可用模型清单// 平台支持的全部模型列表(可动态更新)// 可通过models_endpoint接口自动获取或手动维护"models": [ "deepseek-r1-distill-qwen-32b","deepseek-r1","deepseek-v3"],// 文本生成接口配置// 用于单轮文本生成的API端点设置// prompt字段当前未使用(可能为兼容旧版本保留)"generate_endpoint": {"method": "post", // HTTP请求方法"api": "/maas/v1/completions", // 接口路径"prompt": "" // 保留字段(未来可能用于预设提示词)},// 对话接口配置// 支持多轮对话的API端点设置// prompt字段当前未使用(可能用于会话初始化模板)"chat_endpoint": {"method": "post","api": "/maas/v1/chat/completions","prompt": ""},// 模型列表接口配置// 用于动态获取可用模型列表的API配置// 需要至少包含method和api字段才能启用自动更新// 示例可添加:// "method": "get",// "api": "/maas/v1/models",// "auth_required": true // 是否需要鉴权"models_endpoint": {}
}
补充说明:
- 接口路径均基于base_url拼接,如最终生成接口地址为:
https://cloud.infini-ai.com/maas/v1/completions
- models_endpoint若配置正确,系统可自动更新models列表(目前尚未实现),否则需手动维护
- prompt字段的保留设计可能用于未来支持预设提示词模板功能
三、兼容不同的授权方式
1. API Key(最常见)
- 原理:客户端在请求头或参数中携带唯一密钥,服务端验证密钥有效性。
- 典型场景:
- OpenAI、讯飞星火等大模型 API 调用(如
X-API-Key: your_key
)。 - 云服务商提供的 AI 服务(如图像识别、自然语言处理)。
- OpenAI、讯飞星火等大模型 API 调用(如
- 优势:轻量、易集成,适合开放平台和第三方调用。
- 安全建议:
- 限制密钥权限范围(如绑定 IP、设置调用频率)。
- 定期轮换密钥,防范泄露风险。
2. OAuth 2.0(第三方授权)
- 原理:通过授权服务器颁发
access_token
,客户端携带令牌访问 AI 服务。 - 典型场景:
- 需要用户授权的 AI 服务(如企业级模型调用、个性化推荐)。
- 微信/QQ 登录后调用 AI 能力。
- 流程:
- 用户授权 → 2. 获取
code
→ 3. 兑换access_token
→ 4. 调用 API。
- 用户授权 → 2. 获取
- 优势:支持细粒度权限控制,适合生态化平台。
3. JWT(无状态令牌)
- 原理:服务端生成含用户信息和过期时间的加密 Token,客户端后续请求携带。
- 典型场景:
- 分布式 AI 服务调用(如多模型协同推理)。
- 移动端或单页应用调用 AI 接口(如语音合成、对话机器人)。
- 结构:
Header.Payload.Signature
(如xxxxx.yyyyy.zzzzz
)。 - 优势:无状态,减轻服务端压力;支持短时效+刷新机制。
4. HMAC(防篡改签名)
- 原理:客户端与服务端共享密钥,对请求内容(时间戳、请求体)生成签名。
- 典型场景:
- 金融风控模型调用、支付验证等高安全场景。
- 防止请求被篡改或重放攻击。
- 示例头:
Authorization: HMAC-SHA256 key_id="123", signature="abc123..."
- 优势:确保请求完整性和身份真实性。
5. Basic Auth(基础认证)
- 原理:HTTP 头携带
username:password
的 Base64 编码。 - 典型场景:
- 内部测试环境或低风险 AI 服务调用。
- 配合 HTTPS 使用以加密传输。
- 示例头:
Authorization: Basic base64encode("user:pass")
- 局限:明文传输风险,需严格依赖 HTTPS。
6. 授权实现
基于常见的类型,本插件自持不同的header
方式的认证授权方式。
抽象定义结构对象
class AuthorizationConf : public IConfig
{
public:// 授权类型枚举,定义支持的认证授权方式 enum class AuthType{None, // 无认证授权 Basic, // 基础认证(用户名+密码的Base64编码)Bearer, // Bearer Token认证(如JWT/OAuth 2.0令牌)ApiKey // API Key认证(支持云服务/AI模型调用场景)};// 参数传递方式枚举,定义认证信息传输位置 enum class DeliveryType{Header, // 通过HTTP请求头传递(如Authorization头)Para // 通过请求参数传递(如URL参数或POST参数)};AuthType eAuthType = AuthType::None; // 当前配置的授权类型,默认关闭认证 DeliveryType eDeliveryType = DeliveryType::Header; // 认证信息传递方式,默认使用请求头 // 认证授权数据,内容格式与授权类型强相关:// - Basic: "username:password"的Base64编码 // - Bearer: "access_token"字符串 // - ApiKey: 明文密钥(如"X-API-Key: your_key")std::string auth_data;
};
注解说明:
-
AuthType 枚举:覆盖主流认证方式,其中:
Basic
对应HTTP基础认证,需配合HTTPS使用Bearer
适用于JWT/OAuth 2.0等令牌体系ApiKey
常用于云服务商API调用(如阿里云OSS的C++ SDK)
-
DeliveryType 枚举:区分认证信息的传输载体:
Header
符合RESTful API设计规范(如Authorization: Bearer xxx
)Para
多用于简易场景或兼容旧系统
-
auth_data 格式:需根据认证类型动态调整内容:
- Basic认证需按
user:pass
格式Base64编码 - API Key通常直接使用明文密钥(需HTTPS保障安全)
- Basic认证需按
定义配置加载函数
virtual void from_json(const nlohmann::json& j) override
{std::string strVal;if (Util::JsonGet(j, "type", strVal)){eAuthType = AuthType::None;if (!Util::icasecompare(strVal, "Basic")){eAuthType = AuthType::Basic;}if (!Util::icasecompare(strVal, "Bearer")){eAuthType = AuthType::Bearer;}if (!Util::icasecompare(strVal, "ApiKey")){eAuthType = AuthType::ApiKey;}}Util::JsonGet(j, "data", auth_data);
}
实现接口授权信息的设置
bool AiModel::GetAuthorizationHeader(const AuthorizationConf& auth, std::string& hkey, std::string& hval)
{hkey = ""; // 初始化HTTP头键名hval = ""; // 初始化HTTP头值const std::string& auth_data = auth.auth_data; // 获取认证配置数据switch (auth.eAuthType) {// 无认证授权时直接返回成功(空头信息)case AuthorizationConf::AuthType::None:return true; // 无认证场景直接通过case AuthorizationConf::AuthType::Basic: {// Basic认证需要"username:password"格式size_t colonPos = auth_data.find(':');if (colonPos == std::string::npos) return false; // 缺少分隔符格式错误std::string encoded = Util::Base64Encode(auth_data); // 对凭证进行Base64编码hkey = "Authorization"; // 固定使用标准HTTP头hval = "Basic " + encoded; // 符合RFC 7617规范return true;}case AuthorizationConf::AuthType::Bearer:{if (auth_data.empty()) return false; // 空Token无效hkey = "Authorization"; // 标准Bearer Token头hval = "Bearer " + auth_data; // 符合RFC 6750规范return true;}case AuthorizationConf::AuthType::ApiKey: {if (auth.eDeliveryType == AuthorizationConf::DeliveryType::Header) {// 支持自定义头格式或默认X-API-Key头size_t colonPos = auth_data.find(':');if (colonPos != std::string::npos) {// 用户自定义头格式(如"X-Custom-Key: value")hkey = Util::Trim(auth_data.substr(0, colonPos)); // 提取头名称hval = Util::Trim(auth_data.substr(colonPos + 1)); // 提取头值}else {// 默认使用行业通用的X-API-Key头hkey = "X-API-Key";hval = auth_data;}return true;}// 参数传递需在URL构造阶段处理,此处无法支持return false;}default:return false; // 未知认证类型处理失败}return true; // 默认返回(实际不可达)
}
注解说明:
-
函数职责:根据认证配置生成HTTP请求头的键值对,支持多种认证方式的动态适配
-
Basic认证实现:
- 严格校验
username:password
格式 - 使用Base64编码但非加密(需配合HTTPS)
- 严格校验
-
Bearer Token处理:
- 直接拼接
Bearer
前缀,符合RFC 6750规范 - 适用于JWT/OAuth 2.0等令牌体系
- 直接拼接
-
API Key机制:
- 支持灵活的头定义(如云服务商特定要求)
- 默认使用
X-API-Key
头(遵循行业惯例) - 参数传递方式需在URL构造时实现(如
?api_key=xxx
)
设置授权认证信息
// 初始化HTTP请求头,设置默认的Content-Type为JSON格式,确保数据以UTF-8编码传输
std::unordered_map<std::string, std::string> headers = {{"Content-Type", "application/json; charset=UTF-8"}
};// 从授权配置中提取认证名称和值,若获取成功且认证名称非空则添加到请求头
std::string authName, authValue;
if (GetAuthorizationHeader(plat.authorization, authName, authValue) && !authName.empty()) {headers[authName] = authValue; // 动态添加认证信息到请求头
}// 将构建完成的请求头绑定到HTTP客户端实例,后续请求将自动携带这些头信息
cli.SetHeaders(headers);
注解说明:
headers
初始化块通过显式设置Content-Type
声明了数据交换格式,这符合RESTful接口的通用规范GetAuthorizationHeader
的返回值校验结合了空值检查,确保认证字段有效性(如Bearer Token或API Key)- 使用
unordered_map
的operator[]
进行键值操作,保证认证头的高效存取(O(1)时间复杂度) SetHeaders
调用将配置固化到客户端实例,符合C++ RAII(Resource Acquisition Is Initialization)设计原则
四、总结说明
1. 架构设计核心价值
本AI插件通过分层解耦设计实现了三大核心能力:
- 平台无关性:通过
platforms
配置体系(如OurCopDev
/infini
)实现多环境快速切换 - 模型动态适配:支持
models_endpoint
自动发现机制,结合手动配置保障兼容性 - 认证统一抽象:封装主流授权方式(
Basic
/Bearer
/ApiKey
等),满足从测试到生产的全场景需求
2. 未来演进方向
模块 | 当前状态 | 规划能力 |
---|---|---|
模型管理 | 手动维护models 列表 | 实现models_endpoint 自动同步 |
授权体系 | 支持Header传递 | 扩展DeliveryType::Para 参数级认证 |
协议支持 | HTTP/HTTPS双模 | 增加WebSocket实时接口支持 |
性能优化 | 单线程请求 | 引入异步协程提升并发能力 |
3. 配置模板
{"platform": "OurCopDev","timeout": 90,"platforms": {"infini": {"enable_ssl": true,"base_url": "cloud.infini-ai.com","authorization": {"type": "Bearer","data": "sk-**"},"model_name": "deepseek-r1-distill-qwen-32b","models": [ "deepseek-r1-distill-qwen-32b", "deepseek-r1", "deepseek-v3" ],"generate_endpoint": {"method": "post","api": "/maas/v1/completions","prompt": ""},"chat_endpoint": {"method": "post","api": "/maas/v1/chat/completions","prompt": ""},"models_endpoint": {}},"OurCopProd": {"enable_ssl": true,"base_url": "open.arbboter.com.cn","authorization": {"type": "ApiKey","data": "api-key:k****"},"model_name": "qwq_32b","models": [ "qwq_32b", "deepseek_v3_0324", "deepseek_r1_671b" ],"generate_endpoint": {"method": "post","api": "/maas/v1/completions","prompt": ""},"chat_endpoint": {"method": "post","api": "/prod/llm/personal/v1/chat/completions","prompt": ""},"models_endpoint": {}},"OurCopDev": {"enable_ssl": false,"base_url": "openapi.arbboter.com","authorization": {"type": "ApiKey","data": "api-key:k****"},"model_name": "deepseek_r1_671b","models": [ "qwq_32b", "deepseek_v3_0324", "deepseek_r1_671b" ],"generate_endpoint": {"method": "post","api": "/maas/v1/completions","prompt": ""},"chat_endpoint": {"method": "post","api": "/test/llm/personal/v1/chat/completions","prompt": ""},"models_endpoint": {}}}
}