应用场景
开发者使用华为云Astro轻应用开发标准页面时,如果需要通过智能助手组件或其他组件对接外部大模型接口,可以直接在脚本或自定义连接器中配置对大模型接口的调用,支持以流式报文的形式获取大模型接口的返回值。最终在组件中,可实时接收接口返回信息,用户无需等待接口完成全部数据传输即可查看返回数据。
流式报文是指在数据传输过程中,数据不是一次性全部传输完毕,而是以流的形式逐步传输。
本实践将为您介绍,如何在脚本中调用大数据模型接口,实现在应用中接入大数据模型能力,开发AI应用。
方案优势
通过对大模型接口流式报文的支持,增强了智能助手等AI对话组件中调用大模型接口的页面会话体验。用户能够实时获得大模型接口的输出,实现流畅的AI对话。
约束与限制
表1 约束与限制说明
限制类别 |
具体限制 |
脚本中参数限制 |
通过脚本直接调用SSE协议的URL时,需要传入参数“isStream:true”,否则不会走流式的处理逻辑。 |
连接器配置中动作的限制 |
动作中的返回类型必须设置为text/event-stream,否则自定义连接器的执行逻辑不会走流式的处理逻辑。 |
开放接口中参数的限制 |
如果使用开放接口调用SSE协议的脚本,需要将接口信息中的API类型配置为STREAM(默认是REST),同时URL的前缀应该为/service-stream(会根据api类型自动显示),否则不会走流式的处理逻辑,接口执行会报错。 |
操作流程
在华为云Astro轻应用中,通过调用流式报文接口实现智能对话的流程,如图1所示。
图1 调用流式报文接口实现智能对话操作流程
步骤一:在华为云Astro轻应用中对接大模型接口
在华为云Astro轻应用中,提供了脚本和自定义连接器两种方式来对接大模型接口,请根据具体需求和实际情况进行选择。
通过脚本对接大模型接口
- 创建一个低代码应用。
- 参考授权用户使用华为云Astro轻应用并购买实例中操作,申请华为云Astro轻应用免费试用或购买商业实例。
- 实例购买后,在华为云Astro轻应用服务控制台的“主页”中,单击“进入首页”,进入应用开发页面。
- 在“应用”中,单击“新建低代码应用”或单击
,进入新建低代码应用页面。
首次创建应用时,请根据界面提示创建一个命名空间。命名空间一旦创建,不能修改和删除,创建前请确认好相关信息。建议使用公司或团队的缩写作为命名空间。
- 在新建低代码应用页面,应用类型选择“标准应用”,单击“确定”。
- 输入应用的标签和名称,单击“新建”,即可进入应用设计器。
图2 创建一个空白应用
表2 新建空白应用参数说明
参数 |
说明 |
示例 |
标签 |
新建应用的标签,长度不能超过80个字符。标签是应用在系统中的唯一标识,创建后不支持修改。 |
我的第一个应用 |
名称 |
新建应用的名称,输入标签值后单击该参数的输入框,系统会自动生成应用的名称,同时自动在名称前,添加命名空间__。命名要求如下:
|
A |
- 在应用设计器中,选择“逻辑”,单击脚本后的“+”。
- 新建一个空白的脚本,名称设置为“streamScript”,单击“添加”。
图3 创建脚本
表3 新建脚本参数说明
参数 |
说明 |
示例 |
名称 |
在输入框中,输入新建脚本的名称。命名要求如下:
|
streamScript |
- 在脚本编辑器中,输入示例代码。
本示例代码主要实现的功能包括:创建一个客户端,通过POST方法和GET方法调用相应的接口,使后台以处理流式报文的方式处理接口返回的数据。其中,https://example.com为待调用大模型接口的地址。
通过脚本直接调用SSE协议的URL时,传入参数“isStream”必须设置为“true”,否则不会走流式的处理逻辑。
import * as context from 'context';
import * as http from 'http';
/*
* The input parameter is defined by `@action.param()`.
*/
export class Input {
@action.param({ type: "String", required: true, description: "the operation type" })
inputParam: string;
}
/*
* The output parameter is defined by `@action.param()`.
*/
export class Output {
}
/*
* Define the main service class.
*
* - The service entry function is defined by `@action.method()`.
* - All dependent objects should be defined via `@useObject([])` (for objects) or `@useBo([])` (for business objects).
*/
export class CallSseUrl {
@action.method({ input: "Input", output: "Output", description: "do a operation" })
run(input: Input): Output {
let output = new Output();
let cli = http.newClient()
let resp = cli.post("https://example.com",
{ isStream: true, data: { "message": input.inputParam }, headers: { "Content-Type": "application/json" } })
return output;
}
}
- 单击脚本编辑器上方的
,保存脚本。
- 调试脚本验证脚本是否符合预期。
- 在脚本编辑器上方单击
,进入脚本调试页面。
- 在“输入参数”页签中,输入如下示例。
图4 设置输入参数
{
"inputParam": "我想创建一个差旅管理应用"
}
- 单击
,执行脚本。
在“输出参数”中,输出如下流式内容,表明脚本输出正常。
图5 脚本输出内容
好的!为您**智能规划**了"**差旅管理**"应用的构建计划如下:
1. 创建一个名为"**差旅管理**"的低代码应用;
2. 添加模型对象"**差旅管理**",包含字段:
- **出发城市**(下拉选择)
- **目的城市**(下拉选择)
- **出发时间**(日期)
- **结束时间**(日期)
- **出差目的**(文本)
3. 为"**差旅管理**"模型生成一个标准的**增删改查界面**;
4. 配置一条脚本逻辑:"**提交申请后,自动流转到审批人进行审核**"。
请问您是否确认该构建计划?
您可以输入:
- "**确认**",我将开始执行;
- 或输入**修改意见**,例如"增加一个报销单模型"或"把交通工具改为文本字段"。
- 脚本校验符合预期后,单击脚本编辑器上方的
,启用脚本。
通过连接器对接大模型接口
- 创建一个低代码应用。
- 参考授权用户使用华为云Astro轻应用并购买实例中操作,申请华为云Astro轻应用免费试用或购买商业实例。
- 实例购买后,在华为云Astro轻应用服务控制台的“主页”中,单击“进入首页”,进入应用开发页面。
- 在“应用”中,单击“新建低代码应用”或单击
,进入新建低代码应用页面。
首次创建应用时,请根据界面提示创建一个命名空间。命名空间一旦创建,不能修改和删除,创建前请确认好相关信息。建议使用公司或团队的缩写作为命名空间。
- 在新建低代码应用页面,应用类型选择“标准应用”,单击“确定”。
- 输入应用的标签和名称,单击“新建”,即可进入应用设计器。
图6 创建一个空白应用
表4 新建空白应用参数说明
参数 |
说明 |
示例 |
标签 |
新建应用的标签,长度不能超过80个字符。标签是应用在系统中的唯一标识,创建后不支持修改。 |
我的第一个应用 |
名称 |
新建应用的名称,输入标签值后单击该参数的输入框,系统会自动生成应用的名称,同时自动在名称前,添加命名空间__。命名要求如下:
|
A |
- 创建自定义连接器。
- 在应用设计器中,选择“集成”,单击“连接器”下的“连接器实例”。
- 在“类型”中,选择“自定义连接器”,进入自定义连接器页面。
- 单击“+”,配置连接器信息,单击“保存”。
图7 创建自定义连接器
表5 自定义连接器参数说明
参数 |
说明 |
示例 |
标签 |
自定义连接器的标签,创建后可修改。
取值范围:1~64个字符。 |
流式连接器 |
名称 |
自定义连接器的名称,名称是连接器在系统中的唯一标识,创建后不可修改。命名要求如下:
|
streamconnector |
- 为自定义连接器添加动作。
- 在“动作”页签中,单击“新建”。
- 设置动作的基本信息,单击“下一步”。
图8 设置基本信息
表6 动作基本信息参数说明
参数 |
说明 |
示例 |
标签 |
新建动作的标签名,用于在页面显示。
取值范围:1~64个字符。 |
streamaction |
名称 |
新建动作的名称,名称是动作在系统中的唯一标识。命名要求如下:
|
streamaction |
URL |
待调用大模型接口的URL地址。 |
https://example.com |
方法 |
选择请求的方法,可以设置为POST或GET。 |
POST |
内容类型 |
输入内容的类型取决于第三方支持的具体种类,该类型在HTTP标准协议中定义。 |
application/json |
返回类型 |
选择接口的返回类型,支持“application/json”和“text/event-stream”两种类型。
- application/json:选择该类型时,系统将忽略第三方实际返回的“Content-Type”,采用第三方配置的“Content-Type”来解析返回内容。
- text/event-stream:选择该类型时,将以处理流式报文的方式处理接口返回值,需要确保第三方接口的返回值为流式报文,且响应体中的“Content-Type”为“text/event-stream”。
|
text/event-stream
注意:
“返回类型”必须设置为“text/event-stream”,否则自定义连接器的执行逻辑不会走流式的处理逻辑。
|
- 本示例无需设置消息头入参,请单击
删除第一行参数,再单击“下一步”。
- 设置输入参数,单击“下一步”。
图9 输入参数配置页面
表7仅介绍本实践中使用到的参数,其他参数解释请参见使用自定义连接器调用第三方接口。
表7 输入参数说明
参数 |
说明 |
示例 |
标签 |
输入参数的标签名,用于在页面显示。 |
message |
名称 |
新建输入参数的名称,名称是输入参数在系统中的唯一标识。 |
message |
参数位置 |
设置输入参数的位置。 |
消息体 |
数据类型 |
设置输入参数的数据类型,直接在下拉框中选择。 |
字符串 |
- 本示例无需设置输出参数,请单击
删除第一行参数,再单击“保存”。
- 返回动作页签,单击该动作所在行的
,启用该动作。
图10 动作已启用
- 在“认证信息”页签,单击“新建”,为连接器添加认证信息。
图11 添加认证信息
表8 添加认证信息参数说明
参数 |
说明 |
示例 |
标签 |
认证的标签名,用于在页面显示。
取值范围:1~64个字符。 |
streamAuth |
名称 |
认证的名称,名称是认证在系统中的唯一标识。命名要求如下:
|
streamAuth |
- 验证连接器调用流式报文接口。
- 在动作列表中,单击3中创建的动作,进入动作详情页。
- 在动作详情页,单击页面上方的“测试”。
图12 选择测试
- 选择4中创建的认证信息,并设置输入参数,单击“测试”。
图13 测试自定义连接器
{
"message": "我想创建一个差旅管理应用"
}
单击
“测试”后,返回如下接口信息,表明自定义连接器创建成功。
图14 接口返回信息
- 创建脚本或服务编排,调用自定义连接器。
- 方式一:创建一个脚本,在脚本中调用自定义连接器。
- 参考通过脚本对接大模型接口中操作,创建一个空白脚本,在脚本编辑器中输入如下示例代码。其中,“命名空间__streamconnector”为2中创建连接器的名称,“命名空间__streamaction”为3中为连接器添加的动作,“命名空间__streamAuth”为4中为连接器添加的认证信息。
import * as context from 'context';
import * as connector from 'connector';
/*
* The input parameter is defined by `@action.param()`.
*/
export class Input {
@action.param({ type: "String", required: true, description: "the operation type" })
inputParam: string;
}
/*
* The output parameter is defined by `@action.param()`.
*/
export class Output {
}
/*
* Define the main service class.
*
* - The service entry function is defined by `@action.method()`.
* - All dependent objects should be defined via `@useObject([])` (for objects) or `@useBo([])` (for business objects).
*/
export class CallCustomConnector{
@action.method({ input: "Input", output: "Output", description: "do a operation" })
run(input: Input): Output {
let output = new Output();
// 页面上自己创建的自定义连接器的调用方法,第一个参数是创建的自定义连接器名称,第二个参数是认证信息名称
let client2 = connector.newClient("命名空间__streamconnector", "命名空间_streamAuth");
let input2 = { "message": input.inputParam, "stream": true };
// 第一个入参是动作名称, 第二个参数是入参
let resp2 = client2.invoke("命名空间__streamaction", input2);
context.getHttp().response.setBody(resp2.data)
return output;
}
}
- 单击脚本编辑器上方的
,保存脚本。
- 在脚本编辑器上方单击
,调试脚本,调试方法请参考通过脚本对接大模型接口。
- 脚本校验符合预期后,单击脚本编辑器上方的
,启用脚本。
- 方式二:创建一个服务编排,在服务编排调用自定义连接器。
- 在应用设计器中,选择“逻辑”,单击“编排”后的“+”。
- 输入服务编排的名称和标签,单击“添加”,进入服务编排页面。
图15 创建服务编排
表9 添加服务编排参数说明
参数 |
说明 |
示例 |
标签 |
新建服务编排的标签名,用于在界面展示,创建后可修改。
取值范围:1~64个字符。 |
流式编排 |
名称 |
服务编排在系统中的唯一标识,创建后不支持修改。系统会自动在名称前添加“{命名空间}__”streamFlow,当其他功能调用服务编排时,调用的是服务编排的名称,而不是标签。
命名要求如下:
|
streamFlow |
- 在中,拖拽4中连接器的认证信息到画布中。
在服务编排中,如果包含多个图元,建议将流式自定义连接器图元置于服务编排的最后位置。若不将其置于最后,将无法获取到该图元之后其他图元的输出参数。
图16 拖拽连接器到画布中
- 单击
,进入全局上下文页面。
- 单击“变量”后的
,新建message变量,类型为“文本”。
图17 新建message变量
- 选中自定义连接器图元,单击
,选择创建的动作。
图18 选择动作
- 在“输入参数”中单击“新增行”,“目标”选择message,将6.e中创建的变量拖拽到“源”中。
图19 设置输入参数
- 连接图元指定逻辑关系,即从开始图元连向连接器图元。
图20 连接图元
- 单击页面上方的
,保存服务编排。
- 单击页面上方的
,启用服务编排。
步骤二:调用流式报文接口实现智能对话
创建一个标准页面,并拖入一个智能助手组件,通过脚本调用流式报文接口实现智能对话。
- 在应用设计器的左侧导航栏中,选择“界面”。
- 单击页面后的“+”,创建一个空白页面的标准页面。
图21 设置标准页面基本信息
表10 标准页面参数说明
参数 |
说明 |
示例 |
标签 |
输入标准页面的标签名,用于在页面显示,创建后可修改。
取值范围:1~64个字符。 |
流式页面 |
名称 |
输入标准页面的名称,名称是标准页面在系统中的唯一标识,创建后不可修改。命名要求如下:
|
streampage |
- 在中,拖拽“智能助手”组件到右侧画布中。
图22 添加智能助手组件
- 为组件绑定模型,用于存储智能助手响应的数据。
- 选中智能助手组件,在中,单击
,进入模型选择页面。
图23 单击设置按钮图标
- 单击“新增模型”,输入模型名称(如message)、“来源”选择“自定义”,单击“下一步”。
图24 新增模型message
- 自定义模型字段保持不变,单击“下一步”。
- 方法保持不变,单击“确定”,返回选择模型页面。
- 选中已创建的模型,单击“确定”,返回标准页面设计页面,可查看到组件已绑定模型。
图25 选中已创建的message模型
图26 组件绑定模型效果
- 为智能助手组件添加事件。
- 选中智能助手组件,在“事件”页签,单击“发送事件”后的“+”。
- 在自定义动作中,输入如下示例,单击“创建”。
const _component = context.$component.current;
// 获取界面聊天框输入的信息
const messages = _component.getMessages();
// 判断接口返回值是否为JSON,流式接口的返回值不是可解析的JSON格式,需要特殊处理,所以这里填false
const isJson = false;
// 通过脚本名,传入脚本入参,执行脚本。这里的messages是所有界面聊天框已输入信息的集合,最后一位为最新发送的消息
var _script = context.script('命名空间__streamScript').run({ inputParam: messages[messages.length -1].content }, isJson).then(async resp => {
// 创建一个可读流
const reader = resp.body.getReader();
const decoder = new TextDecoder();
// 循环调用流式接口的返回值
while (true) {
const { done, value } = await reader.read();
// 流式接口的返回值,每次返回都会有done字段判断流是否发送结束
if (done) {
// 当前组件
var _component = context.$component.current;
_component.closeLoading();
return;
}
const chunk = decoder.decode(value);
const data = chunk.split('\n').filter(n => n).map(item => {
try {
// 流式接口的返回值,会以data:xxx的格式返回,输出到页面时,需要将data:去除
return JSON.parse(item.replaceAll('data:', '')).content;
}
})
data.forEach(item => {
$model.ref('message').setData(item)
})
}
})
其中,“命名空间__streamScript”为通过脚本对接大模型接口中创建脚本的名称,“message”为4.b中创建模型的名称。
如果6中使用的是通过服务编排调用自定义连接器的方式,此处请输入如下事件代码。其中,“streamFlow”为6.b中创建服务编排的名称,“message”为6.e中新建的变量。
const _component = context.$component.current;
// 获取界面聊天框输入的信息
const messages = _component.getMessages();
// 判断接口返回值是否为JSON,流式接口的返回值不是可解析的JSON格式,需要特殊处理,所以这里填false
// 初始化Flow
var _flow = context.flow(" {{ flowName }}");
// 适用于一次调用,Flow即完成的场景
// 运行Flow
_flow.run({ inputParam: messages[messages.length - 1].content }).then(function (resp) {
// 创建一个可读流
const reader = resp.body.getReader();
const decoder = new TextDecoder();
// 循环调用流式接口的返回值
while (true) {
const { done, value } = await reader.read();
// 流式接口的返回值,每次返回都会有done字段判断流是否发送结束
if (done) {
// 当前组件
var _component = context.$component.current;
_component.closeLoading();
return;
}
const chunk = decoder.decode(value);
const data = chunk.split('\n').filter(n => n).map(item => {
try {
// 流式接口的返回值,会以data:xxx的格式返回,输出到页面时,需要将data:去除
return JSON.parse(item.replaceAll('data:', '')).content;
}
})
data.forEach(item => {
$model.ref('message').setData(item)
})
}
})
- 设计完成后,单击页面上方的
,保存标准页面。
步骤三:验证智能助手是否流式输出
- 在已创建的标准页面中,单击
,进入预览页面。
图27 标准页面预览页面
- 在智能助手的聊天框中,输入文字,例如“我想创建一个差旅管理应用”,单击“发送”。
智能助手返回如下流式结果,表明智能助手组件对接外部大模型接口成功。
图28 智能助手响应效果