引言
上篇文章我們的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": {}}}
}