# ai_engine_standard **Repository Path**: CrazyMoo/ai_engine_standard ## Basic Information - **Project Name**: ai_engine_standard - **Description**: No description available - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-05-20 - **Last Updated**: 2026-05-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # **Ai_Engine_Standard** 在线文档链接:[Ai_Engine_Standard](https://doc.weixin.qq.com/doc/w3_AbMAZwbkAFQaPrSgL4iTTOvkCnjGF?scode=AOwAiQfKAAo4UK0eBmAbMAZwbkAFQ) # **简介** Ai_Engine_Standard框架是基于OpenHarmony提供的一款引擎框架。框架中主要包含插件管理、模块管理和通信管理等模块,对AI算法能力进行生命周期管理和按需部署。后续,会逐步定义统一的AI能力接口,便于AI能力的调用。同时,提供适配不同推理框架层级的统一推理接口。 **图1** Ai_Engine_Standard框架 ![img](https://wdcdn.qpic.cn/MTY4ODg1NTU3OTQ4NjEzMQ_703678_KgRdATj-1YDRHoIW_1714299735?w=1262&h=710&type=image/png) # **目录** ``` //foundation/ai/ai_engine_standard # 框架主目录 ├── common # 框架通用模块 │ ├── log │ ├── platform │ ├── predict │ ├── protocol │ └── utils ├── engine_profile # ai能力配置文件 │ ├── ... │ └── img_classify.json ├── interfaces # 框架对外模块 │ ├── inner_api │ └── kits ├── plugin # 预置插件 │ ├── ... │ ├── img_classify_plugin │ │ ├── BUILD.gn │ │ ├── img_classify_plugin.json │ │ ├── include │ │ │ ├── classify_plugin.h │ │ │ └── class_name.h │ │ └── src │ │ └── classify_plugin.cpp │ ├── i_plugin.h ├── plugin_model_files # 预置模型 │ ├── ... │ └── yoloV5Int8.ms ├── sa_profile # sa配置模块 └── services # 框架服务端模块 ├── communication_adapter └── server_executor ``` # **约束** **语言限制:** C/C++语言 **操作系统限制:** OpenHarmony操作系统 **AI服务启动的约束与限制:** SAMGR(System Ability Manager)启动且运行正常 # **使用** 1、编译 ​ Ai_Engine_Standard框架,代码所在路径://foundation/ai/ai_engine_standard ​ 编译指令如下: ```c++ 4.0 全仓编译: ./build.sh --product-name rk3568 --target-cpu arm64 --device-type tablet --no-prebuilt-sdk --ccache 只编译Ai_Engine_Standard框架 ./build.sh --product-name rk3568 --build-target ai_engine_standard_target --target-cpu arm64 --device-type tablet --no-prebuilt-sdk --ccache 4.1 全仓编译: ./build.sh --product-name f8pro --target-cpu arm64 --device-type tablet --ccache --no-prebuilt-sdk --gn-args enable_notice_collection=false --disable-package-image --disable-post-build --gn-args skip_generate_module_list_file=true 只编译Ai_Engine_Standard框架 ./build.sh --product-name f8pro --target-cpu arm64 --device-type tablet --ccache --no-prebuilt-sdk --gn-args enable_notice_collection=false --disable-package-image --disable-post-build --gn-args skip_generate_module_list_file=true -T ai_engine_standard_target --fast-rebuild ``` 2、使用 2.1、导入模块 ```typescript import aie_openvalley from '@ohos.ai.aienginestandard'; ``` 2.2、框架对外提供的api接口声明如下: ```typescript function predict(EId: string, ...args: Array>): Promise>; ``` 2.3、接口示例: ```c++ await aie_openvalley.predict("image_classify", imageInfo.size.height, imageInfo.size.width, 5, arrayBuffer) .then((res: Array | ArrayBuffer>) => { console.log(`[AiEngineStanard]aie_openvalley.predict success>>>>>>>>>>>>>>>>>`); res.forEach(element => { if (Array.isArray(element)) { // 处理类别标签 element.forEach(str => { console.log(`[AiEngineStanard]Array = ${str.toString()}`); }); } else if (element instanceof ArrayBuffer) { // 处理标签打分 let scores = new Float32Array(element); scores.forEach(value => { console.log(`[AiEngineStanard]Float = ${value.toString()}`); }); } }); }).catch((err: Error) => { console.log(`[AiEngineStanard]: predictfailed, erroris${JSON.stringify(err)}`) }) ``` # **开发指导** ## **技术规范** ### **代码管理规范** AI引擎框架为cs架构,其中interface提供对外接口及与server端连接管理功能,server提供插件加载以及任务管理等功能,各Plugin实现由server提供的插件接口完成插件接入;common提供与平台相关的操作方法、引擎协议以及相关工具类,供其他各模块调用。 #### **规则:预置插件存放在plugins目录下,插件配置文件编译输出路径为etc/ai/plugin/profiles** 为了方便对预置插件进行管理,所有预置插件源码都需放置在plugins目录下,server端加载插件是采用dlopen方式,预置插件加载只支持在/usr/lib路径进行,因此插件在编译so时,需要在插件编译配置文件中指定输出路径为/system/lib64/或默认。每个插件都需要有一个配置文件来描述该插件,框架启动时会去etc/ai/plugin/profiles目录下扫描所有的插件配置文件,故须把所有插件配置文件统一放置到etc/ai/plugin/profiles路径下。 #### **规则:AI能力配置文件放在engine_profiles目录下,编译输出路径必须是在/etc/ai/profiles/** 框架启动时server端会去etc/ai/profiles目录下进行扫描所有的AI能力配置文件,然后统一进行解析,故须把所有配置文件统一放置到etc/ai/profiles路径下。 #### **规则:预置的算法模型文件放在plugin_models目录下,编译输出路径必须是在/etc/ai/models/** 框架启动后只会在/etc/ai/models目录下加载模型文件,故须把所有算法模型文件统一放置到/etc/ai/models/路径下。 #### **规则:插件涉及到的一些启动参数或者其他参数配置,可以预置在/etc/ai/plugin/params** #### **规则:插件涉及到的数据,且不是参数配置,可以预置在/etc/ai/plugin/data** #### **规则:插件入参出参key规定** 插件入参出参数据结构为类map数据结构 入参按顺序为key1,key2,key3 ... 出参按顺序为key1,key2,key3 ... ### **命名规范** #### **AI能力配置文件命名规则:领域_关键词<其他信息1_其他信息2…>** 配置文件与插件的关系是多对多的关系,配置文件表示的一套处理流程。 #### **插件命名规则:领域_关键词<其他信息1_其他信息2…>_pligin** 插件在系统中统一存放且会根据名称动态加载的关系,故插件命名需要唯一,插件的的领域、关键词、其他信息等名词解释与要求,均是为了减少重复的几率以及增加插件的名称的可读性。 #### **插件配置文件命名规则:领域_关键词<其他信息1_其他信息2…>_pligin.json** 插件命名与插件报名一致,插件配置文件与插件的关系是一对一的关系,配置文件里包含插件基本信息,描述及所需模型等。 ### **插件接口开发规范** #### **规则:plugin需要实现server定义的IPlugin接口,并使用宏PLUGIN_INTERFACE_IMPL对外提供插件函数指针** Server端管理的插件内部接口实现逻辑各不相同,为了统一插件的加载流程,AI引擎定义了插件接口IPlugin;在运行态,插件是以动态链接库的形式被AI引擎框架通过dlopen方式加载,各插件需要使用PLUGIN_INTERFACE_IMPL语句对外暴露函数指针,否则插件将无法被正常加载使用。 #### **规则:plugin需要使用AI引擎提供的统一数据通道** AI引擎在server与插件之间,提供了一个统一的数据通道,用来处理来自client的推理请求和来自插件的结果返回;plugin在推理接口中,需按数据通道完成请求数据的获取以及推理结果的封装。 ## **插件开发** 插件开发流程可大致分为以下几步: 1. 插件核心能力确认; 2. 插件入参、出参确定; 3. 配置文件撰写; 4. 插件功能开发; 5. 插件使用文档撰写; ### **插件核心能力确认** 插件开发者需要明确插件的核心能力是什么,比如说想要开发一个图片分类插件、目标检测还是一个语音转文字的插件。举个例子,比如我们现在想要开发一个图片分类插件,实现能力:给一张图片,插件内部对这张图片进行推理,然后输出图片的类别信息。 注意:下面流程都将以开发一个图片分类件进行讲解。 ### **插件入参、出参确定** **插件入参确定:** 前面已经确认了插件要针对单张图片进行推理,显而易见插件的入参就是一张图片,但是"一张图片"只是我们人类语言的描述,但是计算机并不知道什么是图片,所以我们此时要把"一张图片"转换成计算机能认识的语言。 我们常见的都是jpg、png等格式的图片,这些都是图片原始数据编码之后产生的格式。而模型推理的入参都是图片原始数据而不是压缩之后的,为了简单我们把图片解码的操作交给开发者自己做,插件只接收图片原始数据、图片宽、高等信息。到此我们已经可以确定插件入参为: | 插件入参名称 | 类型 | 说明 | | ------------ | ------------ | ------------ | | key1 | int | 图片宽度 | | key2 | int | 图片高度 | | key3 | vector | 图片解码数据 | **插件出参确定:** 插件对一张图片数据进行推理结果是很多类别的打分,我们想把所有的类别及对应的打分都返回给调用者自己处理。 所以插件出参为: | 插件出参名称 | 类型 | 说明 | | ------------ | -------------- | ------------ | | key1 | vector | 类别集合 | | key2 | vector | 类别打分集合 | ### **插件功能开发** #### **接口实现** ​ 插件必须继承接口IPlugin类,并实现IPlugin中声明的接口。 Ai_Engine_Standard框架规定了一套算法插件接入规范,插件需实现规定接口以实现获取插件版本信息、名称、同步执行算法(同步算法实现SyncProcess接口,异步算法实现AsyncProcess接口,异步规划中暂不支持)。 算法插件类IPlugin接口设计如下表所示, IPlugin.h: | 接口名 | 接口说明 | 参数要求 | | ------------------------------------------------------------ | ------------------------------------------------------- | ------------------------------------------------------------ | | long long GetVersion() | 作用:获取插件版本信息。返回值:版本号(long long) | - | | std::string GetName() | 作用:获取插件名称信息。返回值:版本号(string) | - | | int Process(const std::map>& abm, const PredictParams *predictParams, PredictParams *predictResult) | 作用:执行插件算法。返回值:0为成功,其他返回值为失败。 | abm(NOT NULL):用于向算法插件算法模型文件。predictParams(NOT NULL):作为入参用于向算法插件传递请求内容。predictResult(NOT NULL):作为出参用于接收算法插件发回的同步算法执行结果。 | #### **插件入参获取** 框架目前支持数据类型包括: int、vector、bool、vector、byte、vector、string、vector、float、vector 根据框架规定,插件入参出参数据都用PredictParams数据结构包裹,可以把它当成一个map来用,其中key是固定规则的字符串,value支持各种类型的数据。目前暂不支持插件自定义变量名,**入参PredictParams**的key为key1、key2、key3...顺序递增,所以插件内部只需要按照顺序把value转换成需要类型的数据即可。 在当前图片分类插件中,接收入参的代码可以这样写: ```c++ // 插件入参处理 int rows = predictParams->GetIntParam("key1", -1); // 获取图片高度 int cols = predictParams->GetIntParam("key2", -1); // 获取图片宽度 std::vector dataArray = predictParams->GetByteArrayParam("key3"); // 获取图片原始数据 ``` #### **插件出参设置** 插件出参设置与入参类似,暂不支持自定义变量名,需要按照固定规则key1、key2......递增为key,然后用PredictParams数据结构包裹传递出去即可,在当前图片分类插件中,出参设置的代码可以这样写: ```c++ const std::vector labels; ...填充标签信息 predictResult->SetParam("key1", labels); const std::vector scores; ...填充推理结果 predictResult->SetParam("key2", scores); ``` #### **插件模型文件获取** 如果插件能力实现过程中需要使用到模型文件,且在配置文件中正确设置了,则可以在const std::map>& abm中获取: ```c++ //配置文件中插件名称为: ["mobilenetv2.ms"] const std::shared_ptr modelBuffer = abm["mobilenetv2.ms"] ``` #### ### **配置文件撰写** 配置文件是插件给框架一个使用说明书,只有正确的完成配置文件,框架才能正确的完成插件动态加载等工作。配置文件的配置规则是框架制定的,下面我们先给出图片分类插件的配置文件,然后再对每个字段进行解释。 图片分类插件的配置文件: ```json { "pluginName": "image_classify_plugin", // 插件名称(全局唯一) "pluginLibrary": "libimage_classify_plugin.z.so", // 插件so名称(全局唯一) "version": "p1.0.0.1", // 插件版本号 "models": [ { "fileName": "mobilenetv2.ms", // 模型文件名称 "version": "m1.0.0.1", // 模型版本号, "description": "xxx model", // 模型描述信息 "needLoad": false, // 是否需要把模型文件加载到内存中, 主要用mindspore支持的模型文件 "needCache": false // 是否把模型存储到/cust/models目录下 } ], "runOnCreate": true, // 插件是否预加载(默认为false) "description": "This is an image recognition plugin." // 插件描述 } ``` 插件配置文件描述: | 属性名称 | 类型 | 说明 | | -------------- | -------------- | ------------------------------------------------------------ | | pluginName | string | 必填;ai能力全局唯一标识符。插件开发者必须保证改id全局唯一,如果出现id重复情况,框架根据版本号高版本覆盖低版本为准。 | | pluginLibrary | string | 必填;插件so路径,根据实际路径填写。如果以/开头为绝对路径会直接去该路径加载;否则认为是相对路径会在前面默认拼接”/etc/ai/pligin/lib/“ | | description | string | 必填;ai能力描述 | | version | string | 必填;必须遵循 ' p ' 开头,后面四段数字格式,如p1.0.0.5;当配置文件eid相同时会高版本覆盖低版本配置 | | models | vector | 必填;必填;如果以fileName以/开头为绝对路径会直接去该路径加载;否则认为是相对路径会在前面默认拼接”/etc/ai/model/“ | | runOnCreate | bool | 选填;默认为false,如果配置为true则在设备启动时就加载该插件 | | isAsync | bool | 选填; 默认为false,如果配置为true则推理接口执行结果返回为callback形式 | AI能力配置文件: ```json { "eid": "img_classify", // AI能力标识符(全局唯一) "name": "图片分类", // AI能力名称(全局唯一) "description": "对输入的图片进行类型识别(优化)", // AI能力描述 "version": "e1.0.0.1", // 版本号 "subtasks": [ // AI能力任务配置 { "id": "task1", // 子任务标识符(当前配置文件唯一) "name": "图片分类", // 子任务名称(当前配置文件唯一) "description": "对输入的图片进行类型识别", // 子任务描述 "params": [], // 子任务入参名称集合 "dependencies": ["img_classify"], // 父任务标识符 "preProcessPlugins": [ // 前处理插件配置 { "pluginName": "image_classify_plugin", // 插件名称(对应插件配置文件中的名称) "option": { // 传递给插件的可选项 "useProcessor": "npu" } } ] } ] } ``` AI能力配置文件描述: | 属性名称 | 类型 | 说明 | | ----------- | -------------- | ------------------------------------------------------------ | | eid | string | 必填;ai能力全局唯一标识符。插件开发者必须保证改id全局唯一,如果出现id重复情况,框架将以第一个配置为准。 | | name | string | 必填;ai能力名称 | | description | string | 必填;ai能力描述 | | version | string | 必填;必须遵循 ' e ' 开头,后面四段数字格式,如e1.0.0.5;当配置文件eid相同时会高版本覆盖低版本配置 | | subtasks | vector\ | 必填;ai能力任务配置 | subtasks item配置: | 属性名称 | 类型 | 说明 | | ------------------ | -------------- | -------------------------------------------------------- | | id | string | 必填,子任务标识符(配置文件内唯一) | | name | bool | 必填;子任务名称 | | description | array\ | 必填;子任务能力描述 | | params | string | 可选;任务所需参数集合,如果为空则表示接收所有父任务出参 | | dependencies | vector\ | 必填;父任务集合 | | preProcessPlugins | vector\ | 可选;前处理插件配置 | | process | object | 可选;框架推理配置 | | postProcessPlugins | vector\ | 可选;后处理插件配置 | preProcessPlugins/postProcessPlugins 配置: | 属性名称 | 类型 | 说明 | | -------------------- | ------ | -------------------------------------- | | pluginName | string | 必填插件名称 | | option->useProcessor | string | 选填;推理类型,预留当前没有实际用处。 | process 配置: | 属性名称 | 类型 | 说明 | | -------------------- | ------ | -------------------------------------- | | algorithmPath | string | 推理所需模型 | | option->useProcessor | string | 选填;推理类型,预留当前没有实际用处。 | #### **demo参考** 以图片分类插件为例: 在代码路径//foundation/ai/ai_engine_standard/services/plugin中添加图片识别插件接口定义,并实现AI能力的调用,如下即为接口定义 ```c++ #include "i_plugin.h" class OpencvPlugin : public IPlugin { public: OpencvPlugin() = default; ~OpencvPlugin() = default; long long GetVersion() override; std::string GetName() override; int32_t Process(const std::map>& abm, const PredictParams *predictParams, PredictParams *predictResult) override; }; ``` 图片插件接口实现: ```c++ int32_t OpencvPlugin::Process(const std::map>& abm, const PredictParams *predictParams, PredictParams *predictResult) { AIE_LOGD("[OpencvPlugin::Process] enter."); // 获取模型数据 auto it = abm.begin(); // mindspore初始化model std::shared_ptr native_model_ = CreateModel(it->second); if (native_model_ == nullptr) { AIE_LOGE("[OpencvPlugin::Process] Failed to new mindspore::model."); return RETCODE_FAILURE; } std::vector inputs = native_model_->GetInputs(); // 插件入参处理 int rows = predictParams->GetIntParam(KEYONE, -1); AIE_LOGD("[OpencvPlugin::Process] predictParams rows is %{public}d", rows); int cols = predictParams->GetIntParam(KEYTWO, -1); AIE_LOGD("[OpencvPlugin::Process] predictParams cols is %{public}d", cols); int type = predictParams->GetIntParam(KEYTHREE, -1); AIE_LOGD("[OpencvPlugin::Process] predictParams id is %{public}d", type); std::vector dataArray = predictParams->GetByteArrayParam(KEYFOUR); //图片预处理、推理等 。。。。。。 // 插件推理结果返回 const std::vector scores = InitScoreVector(outputs.front()); predictResult->SetParam(KEYONE, Lables); AIE_LOGD("[OpencvPlugin::Process] Labels size: %lu", Lables.size()); predictResult->SetParam(KEYTWO, scores); return RETCODE_SUCCESS; } PLUGIN_INTERFACE_IMPL(OpencvPlugin); ```