• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 格物开发指导
2<!--Kit: Kernel Enhance Kit-->
3<!--Subsystem: Kernel-->
4<!--Owner: @gatieme-->
5<!--Designer: @tanyihua-->
6<!--Tester: @panny060-->
7<!--Adviser: @fang-jinxu-->
8## 场景介绍
9
10从API version 20开始支持。端侧推理场景具有保障用户数据隐私、部署成本低、时延低、不受网络影响的高可用性等优点。但是,相比于云侧推理而言,端侧推理也面临着更大的挑战,因为端侧设备的内存资源受限、算力受限、对功耗敏感,并且还需要在运行端侧推理业务时保障用户体验、不卡顿。为了应对端侧推理的这些挑战,格物服务提供QoS感知的推理加速和资源管理优化能力。本文将指导开发者使用格物接口。
11
12## 接口
13
14### 错误码
15
16`OH_QoS_GewuErrorCode`枚举型作为格物的错误码类型,各函数接口返回的错误码含义见接口描述。
17
18### 会话句柄
19
20会话句柄用于会话的管理。通过`OH_QoS_GewuSession`成功创建会话时可获得会话句柄,可用于提交/中止请求和销毁会话。
21
22```C
23typedef unsigned int OH_QoS_GewuSession;
24```
25
26### 请求句柄
27
28请求句柄用于请求的管理。通过`OH_QoS_GewuSubmitRequest`成功提交请求时可获得请求句柄,可用于中止请求。
29
30```C
31typedef unsigned int OH_QoS_GewuRequest;
32```
33
34### 函数
35
36| 函数名                      | 简介                       |
37| --------------------------- | -------------------------- |
38| `OH_QoS_GewuCreateSession`  | 创建会话                   |
39| `OH_QoS_GewuDestroySession` | 销毁会话                   |
40| `OH_QoS_GewuSubmitRequest`  | 提交请求                   |
41| `OH_QoS_GewuAbortRequest`   | 中止请求                   |
42
43**`OH_QoS_GewuCreateSession`**
44
45描述
46
47`OH_QoS_GewuCreateSession`接口用于创建会话。
48
49该接口异步处理请求,即该接口只是发起创建会话,并不会等到会话资源分配完成、模型加载完成才返回。格物优化端侧推理资源管理,可以动态按需加载资源。
50
51会话对象的生命周期从`OH_QoS_GewuCreateSession`函数返回开始,到调用`OH_QoS_GewuDestroySession`为止。
52
53声明
54
55```C
56typedef struct {
57    OH_QoS_GewuSession session;
58    OH_QoS_GewuErrorCode error;
59} OH_QoS_GewuCreateSessionResult;
60
61OH_QoS_GewuCreateSessionResult OH_QoS_GewuCreateSession(const char* attributes);
62```
63
64参数
65
66* `const char* attributes`参数表示会话属性的json字符串。该json字符串支持以下字段:
67    * "model": string 表示会话使用的模型的路径。
68
69`attributes` json字符串例子:
70
71```json
72{
73    "model": "/data/storage/el2/base/files/qwen2/"
74}
75```
76
77返回值
78
79如果创建会话成功,返回值`OH_QoS_GewuCreateSessionResult`里的`error`为`OH_QOS_GEWU_OK`,而`session`为创建出来的会话句柄。
80如果创建会话失败,返回值`OH_QoS_GewuCreateSessionResult`里的`error`为错误原因,其中`OH_QOS_GEWU_NOMEM`表示没有足够的内存创建会话。
81
82**`OH_QoS_GewuDestroySession`**
83
84描述
85
86`OH_QoS_GewuDestroySession`接口用于销毁会话。
87
88建议用户应当等待至所有请求都已完成或中止,然后再调用该接口来销毁会话。如果调用该接口时还有正在进行的请求,那些请求将会被中止,且用户不会再收到回复。注意,在调用完该接口后,会话对象无法再被使用。
89
90声明
91
92```C
93OH_QoS_GewuErrorCode OH_QoS_GewuDestroySession(OH_QoS_GewuSession session);
94```
95
96参数
97
98* `OH_QoS_GewuSession session`参数为要销毁的会话的句柄。
99
100返回值
101
102如果会话销毁成功,返回值为`OH_QOS_GEWU_OK`。
103如果会话销毁失败,返回值为错误原因,其中`OH_QOS_GEWU_NOENT`表示找不到会话。
104
105**`OH_QoS_GewuSubmitRequest`**
106
107描述
108
109`OH_QoS_GewuSubmitRequest`接口用于提交请求。该接口异步执行请求,即该接口只是发起请求,并不直接返回结果,该接口返回时请求可能尚未开始执行。请求的结果通过调用用户提供的回调返回给用户。
110
111声明
112
113```C
114typedef struct {
115    OH_QoS_GewuRequest request;
116    OH_QoS_GewuErrorCode error;
117} OH_QoS_GewuSubmitRequestResult;
118
119typedef void (*OH_QoS_GewuOnResponse)(void* context, const char* response);
120
121OH_QoS_GewuSubmitRequestResult OH_QoS_GewuSubmitRequest(OH_QoS_GewuSession session, const char* request,
122    OH_QoS_GewuOnResponse callback, void* context);
123```
124
125参数
126
127`OH_QoS_GewuSubmitRequest`函数的各参数如下:
128
129* `OH_QoS_GewuSession session`参数是会话句柄,表示请求要提交到哪个会话。
130* `const char* request`参数为请求的json字符串,支持以下字段:
131    * "messages": array. 表示消息的数组其中每个元素支持以下字段:
132        * "role": string. 消息的角色类型。其中"developer"表示开发者或系统提供的指示,"user"表示用户输入,"assistant"表示模型生成结果。
133        * "content": string. 消息内容。
134    * "stream": boolean or null. 是否使能流式推理,默认为非流式。
135* `OH_QoS_GewuOnResponse callback`参数为请求的回调函数。
136* `void* context`参数为用户提供的上下文指针,用于传递给回调函数。一般用法中,用户代码可通过该参数找到与收到的回复对应的请求,从而进行相应的处理。
137
138另外,`OH_QoS_GewuOnResponse`回调函数的各参数如下:
139
140* `void* context`参数是调用`OH_QoS_GewuSubmitRequest`时传进来的`context`指针。
141* `const char* response`参数是回复的json字符串,包含以下字段:
142    * "message": 回复消息,包含以下字段:
143        * "role": string. 消息的角色类型,应为"assistant"。
144        * "content": string. 消息内容。
145    * "finish_reason": string or null. 停止原因,可能的值如下:
146        * null: 表示没有停止。流式推理中会有多次回复,只有最后一次回复有非空的"finish_reason"。而非流式推理只有一次回复,且"finish_reason"非空。
147        * "stop": 正常停止。
148        * "abort": 用户主动提前中止。
149        * "length": token数超过限制。
150
151返回值
152
153如果提交请求成功,返回值`OH_QoS_GewuSubmitRequestResult`里的`error`为`OH_QOS_GEWU_OK`,`request`为请求句柄。
154如果提交请求失败,返回值`OH_QoS_GewuSubmitRequestResult`里的`error`为错误原因,其中`OH_QOS_GEWU_NOMEM`表示没有足够的内存处理该请求。
155
156**`OH_QoS_GewuAbortRequest`**
157
158描述
159
160`OH_QoS_GewuAbortRequest`接口用于提前中止请求。
161
162正常情况下,用户调用`OH_QoS_GewuSubmitRequest`接口提交请求后,等待至推理完成(即收到`"finish_reason"`不为空的回复),不需要调用`OH_QoS_GewuAbortRequest`接口。
163只有当用户希望提前中止推理请求的时候,才需要调用`OH_QoS_GewuAbortRequest`接口。
164
165成功调用该函数后,用户不会再收到该请求的回复,且该请求句柄无法再被使用。
166
167声明
168
169```C
170OH_QoS_GewuErrorCode OH_QoS_GewuAbortRequest(OH_QoS_GewuSession session, OH_QoS_GewuRequest request);
171```
172
173参数
174
175* `OH_QoS_GewuSession session`参数为请求所述的会话的句柄。
176* `OH_QoS_GewuRequest request`参数为要中止的请求的句柄。
177
178返回值
179
180如果请求中止成功,返回值为`OH_QOS_GEWU_OK`。
181如果请求中止失败,返回值为错误原因,其中`OH_QOS_GEWU_NOENT`表示找不到请求。
182
183
184## 示例
185
186示例如下:
187
188```CPP
189#include <future>
190#define LOG_TAG "DEMO"
191#include <hilog/log.h>
192#include <nlohmann/json.hpp>
193#include <qos/qos.h>
194#include <string>
195
196#define DEMO_LOGD(fmt, ...) OH_LOG_DEBUG(LOG_APP, fmt, ##__VA_ARGS__)
197#define DEMO_LOGI(fmt, ...) OH_LOG_INFO(LOG_APP, fmt, ##__VA_ARGS__)
198#define DEMO_LOGW(fmt, ...) OH_LOG_WARN(LOG_APP, fmt, ##__VA_ARGS__)
199#define DEMO_LOGE(fmt, ...) OH_LOG_ERROR(LOG_APP, fmt, ##__VA_ARGS__)
200
201using json = nlohmann::json;
202
203/* 用于保存聊天状态 */
204struct ChatContext {
205public:
206    ChatContext()
207    {
208        future = promise.get_future();
209    }
210
211    void Join()
212    {
213        assert(future.valid());
214        std::string stopReasonStr = future.get();
215        DEMO_LOGI("stopReasonStr=%s", stopReasonStr.c_str());
216    }
217
218    std::promise<std::string> promise;
219    std::future<std::string> future;
220    std::string responseContent;
221    bool earlyAbort = false;
222};
223
224/* 接收到推理结果时的回调函数 */
225void OnChatResponse(void *context, const char *response)
226{
227    ChatContext *chatContext = static_cast<ChatContext *>(context);
228    if (chatContext->earlyAbort) {
229        DEMO_LOGD("ignore response after early abort");
230        return;
231    }
232    try {
233        json responseJson = json::parse(response);
234        chatContext->responseContent += responseJson.at("message").at("content").get<std::string>();
235        json finishReasonJson = responseJson.at("finish_reason");
236        if (!finishReasonJson.is_null()) {
237            /* finish */
238            std::string finishReasonStr = finishReasonJson.get<std::string>();
239            chatContext->promise.set_value(finishReasonStr);
240        } else if (chatContext->responseContent.find("\n") != std::string::npos) {
241            /* customized stop */
242            chatContext->promise.set_value("customized");
243            chatContext->earlyAbort = true;
244        } else {
245            /* continue */
246            ;
247        }
248    } catch (json::exception &e) {
249        DEMO_LOGE("failed to parse response: %s", e.what());
250    }
251}
252
253int Demo(void)
254{
255    DEMO_LOGI("Demo starts");
256    json attrJson = {
257        /* 模型文件位置,根据实际情况修改 */
258        {"model", "/data/storage/el2/base/files/qwen2-awq"},
259    };
260    std::string attrStr = attrJson.dump(4);
261
262    /* 创建会话 */
263    OH_QoS_GewuCreateSessionResult createResult = OH_QoS_GewuCreateSession(attrStr.c_str());
264    if (createResult.error != OH_QOS_GEWU_OK) {
265        DEMO_LOGE("failed to create session, error=%d", (int)createResult.error);
266        return -1;
267    }
268    OH_QoS_GewuSession session = createResult.session;
269
270    /* 创建并提交请求 */
271    ChatContext context;
272    json requestJson = {
273        {"messages", json::array({
274            {{"role", "developer"}, {"content", "You are a helpful assistant"}},
275            {{"role", "user"}, {"content", "What is LLM?"}},
276        })},
277        {"stream", true},
278    };
279    std::string requestStr = requestJson.dump(4);
280    OH_QoS_GewuSubmitRequestResult submitResult = OH_QoS_GewuSubmitRequest(session, requestStr.c_str(),
281                                                                           OnChatResponse, &context);
282    if (submitResult.error != OH_QOS_GEWU_OK) {
283        DEMO_LOGE("failed to submit request, error=%d", (int)submitResult.error);
284        return -1;
285    }
286    OH_QoS_GewuRequest request = submitResult.request;
287    context.Join();
288
289    /* 提前中止请求 */
290    if (context.earlyAbort) {
291        OH_QoS_GewuErrorCode error = OH_QoS_GewuAbortRequest(session, request);
292        if (error != OH_QOS_GEWU_OK) {
293            DEMO_LOGE("failed to abort request, error=%d", (int)error);
294            return -1;
295        }
296    }
297
298    /* 打印结果 */
299    DEMO_LOGI("response: %s", context.responseContent.c_str());
300
301    /* 销毁会话 */
302    OH_QoS_GewuErrorCode error = OH_QoS_GewuDestroySession(session);
303    if (error != OH_QOS_GEWU_OK) {
304        DEMO_LOGE("failed to destroy session, error=%d", (int)error);
305        return -1;
306    }
307    return 0;
308}
309```
310