应用定义与执行引擎
应用执行链路
应用由草稿定义、发布版本和运行记录组成。流程编排执行节点图,对话编排装配问答能力,专家团按协作方式组织成员;三类应用共用发布、授权、会话与执行记录。
一、定义与运行对象
| 对象 | 职责 |
|---|---|
ai_app | 应用基本信息、类型、草稿与开放状态 |
ai_app_version | 发布定义及版本说明 |
ai_run | 一次调用的状态、输入输出、耗时与轨迹 |
ai_conversation、ai_message | 连续会话及用户、助手消息 |
新建时确定 workflow、chatbot 或 team,建成后不更换类型。草稿调试与发布运行分别读取对应定义。
二、流程执行
开始节点声明输入;连线决定执行关系和上游变量范围;执行器将产出写入节点上下文。变量使用 {{节点标识.字段}} 引用,最终输出由结束节点定义。
NodeType 将 26 种节点关联到配置类,并标记分支、流式和时限类别。NodeExecutor 是节点执行扩展点,各具体实现位于 app 引擎的 provider/node。
输出形态
结束节点的变量输出用于结构化结果;流式输出需在结束节点中指定正文来源节点,发布运行页据此使用对话交互。
三、分支与长时操作
条件、分类、内容审核节点根据 branch 选择出口。循环、子流程、专家团、人工输入和延时等节点有各自的时长及停止语义,扩展和排查时按节点类型分别处理。
人工输入需要保留暂停状态和后续输入;循环应明确集合、迭代项与最终汇总。节点输出、异常和停止事件通过执行轨迹交给工作区展示。
四、对话与专家团
对话编排将提示词、变量、模型、知识、工具和记忆组合为问答定义。专家团包含成员职责、协作模式和最终产出策略,支持自主调度、流水线与并行会诊。
流程编排的知识检索节点与对话编排的知识检索都提供重排开关。开关打开时定义中不写入该字段,按知识库配置的重排模型决定是否重排;关闭时写入 false,只按向量相似度排序。重排规则见 知识处理与检索引擎。
| 位置 | 定义字段 | 服务端配置 | 新建时的召回参数 |
|---|---|---|---|
| 知识检索节点 | config.rerank | RetrievalConfig.rerank,由 RetrievalNodeExecutor 传入检索请求 | 召回条数 5,最低相似度 0.5 |
| 对话编排 | retrieval.rerank | ChatbotDefinition.Retrieval.rerank,由 ChatbotRetriever 传入检索请求 | 召回条数 5,最低相似度 0.7 |
知识检索节点输出 content、sources 与 query。sources 的每条命中包含 knowledgeId、documentId、fileName、fileUrl、text、auxText 与评分字段 score、vectorScore、rerankScore、recallRank,评分含义与 知识检索与问答 一致。对话编排只在选择知识库后显示重排开关。
前端定义编辑与序列化由 src/engine/app 负责;服务端执行位于 blade-ai-app。新增配置项时同步修改前端类型、编辑器、序列化、服务端配置与执行逻辑,使字段在编辑、保存和执行各环节一致生效。
五、发布与验证
保存草稿 → 草稿调试 → 发布版本 → 以已发布版本验证。从未发布的应用按草稿运行;发布后接口与分享页读取发布快照,后续草稿变更需要重新发布才会生效。
详细操作见 流程编排、节点配置与变量引用 与 应用调试与版本发布。
六、扩展示例:文本规范化节点
以下为二次开发示例,为引擎增加 normalize 类型,去除首尾空白,并按配置转成大写。示例需要完成前后端登记后才能使用;平台标准节点为 26 类。
6.1 定义配置与执行器
在 blade-ai-app 的 provider/config/NormalizeConfig.java 中定义配置:
package org.springblade.ai.engine.app.provider.config;
import lombok.Data;
/** 文本规范化配置 */
@Data
public class NormalizeConfig {
private String text;
private Boolean uppercase = false;
}在 NodeType 导入配置类,并增加枚举项:
import org.springblade.ai.engine.app.provider.config.NormalizeConfig;
// 枚举常量区,与其他节点并列
NORMALIZE("normalize", NormalizeConfig.class, false, false),在 provider/node/NormalizeNodeExecutor.java 中实现:
package org.springblade.ai.engine.app.provider.node;
import org.springblade.ai.engine.app.context.FlowContext;
import org.springblade.ai.engine.app.enums.NodeType;
import org.springblade.ai.engine.app.model.FlowNode;
import org.springblade.ai.engine.app.provider.AbstractNodeExecutor;
import org.springblade.ai.engine.app.provider.config.NormalizeConfig;
import org.springblade.core.tool.support.Kv;
import org.springframework.stereotype.Component;
import java.util.Locale;
/** 按配置规范化上游文本 */
@Component
public class NormalizeNodeExecutor extends AbstractNodeExecutor {
@Override
public NodeType type() {
return NodeType.NORMALIZE;
}
@Override
protected Kv doExecute(FlowNode node, FlowContext context) {
NormalizeConfig settings = config(node);
String content = require(settings.getText(), context, "原文").trim();
if (Boolean.TRUE.equals(settings.getUppercase())) {
content = content.toUpperCase(Locale.ROOT);
}
return Kv.create().set("content", content).set("length", content.length());
}
}NodeExecutorFactory 自动收集 Spring 中的 NodeExecutor 并按 type().getCode() 注册。一个类型只配置一个执行器,因此示例新增 NORMALIZE 类型,而非覆盖已有类型的执行器。非流式节点复用基类同步实现;有生成流时再实现相应流式方法。
6.2 扩展前端定义与节点登记
在 Saber-AI 的 src/engine/canvas/core/dsl.ts 中,将 'normalize' 加入 NODE_TYPES,增加配置接口并登记到 NodeConfigs:
export interface NormalizeConfig {
text: string;
uppercase: boolean;
}
// 合并到已有 NodeConfigs,不另建同名对象
normalize: NormalizeConfig;在 core/registry.ts 的 REGISTRY 中增加:
normalize: meta('normalize', 'logic', {
defaults: () => ({ text: '', uppercase: false }),
outputs: () => text(['content', 'string'], ['length', 'number']),
summary: node => [node.config.text],
required: node => require([['text', node.config.text]]),
}),这些登记同时服务节点库、画布卡片、输出选择和定义检查,不另写第二套节点清单。
6.3 配置面板
新增 src/views/app/workflow/panels/normalize.vue:
<template>
<el-form size="small" label-position="top" @submit.prevent>
<ai-panel-section :title="t.canvas.node.normalize()">
<el-form-item :label="t.normalize.text()">
<ai-variable-input
:model-value="node.config.text"
:node-id="node.id"
type="textarea"
:rows="4"
@update:model-value="set('text', $event)"
/>
</el-form-item>
<el-form-item :label="t.normalize.uppercase()">
<el-switch
:model-value="node.config.uppercase"
@update:model-value="set('uppercase', $event)"
/>
</el-form-item>
</ai-panel-section>
</el-form>
</template>
<script setup lang="ts">
import type { FlowNode } from '@/engine/canvas';
import { t } from '@/lang';
import { configSetter } from './context';
import AiPanelSection from '@/components/panel-section/main.vue';
import AiVariableInput from './fields/variable-input.vue';
defineOptions({ name: 'aiPanelNormalize' });
type Node = FlowNode<'normalize'>;
const props = defineProps<{ node: Node; update: (mutate: (node: Node) => void) => void }>();
const set = configSetter(props);
</script>在 panels/index.ts 的 PANELS 中登记 normalize: () => import('./normalize.vue')。在 src/components/glyph/glyphs.ts 中增加同名图标:
'node-normalize': ['M4 6h16', 'M8 6v14', 'M16 6v14', 'M6 20h4', 'M14 20h4'],6.4 补齐双语文案
将下列键合并到中英文语言包的对应对象中:
| 位置 | 中文值 | 英文值 |
|---|---|---|
canvas.node.normalize | 文本规范化 | Normalize Text |
canvas.nodeDesc.normalize | 去除首尾空白,可转为大写 | Trim text and optionally convert to uppercase |
canvas.outputs.normalize.content | 处理后文本 | Normalized text |
canvas.outputs.normalize.length | 文本长度 | Text length |
normalize.text | 原文 | Source text |
normalize.uppercase | 转为大写 | Uppercase |
6.5 构建与验证
构建扩展后的后端并启动,在前端执行类型及工程检查。以 开始 → 文本规范化 → 结束 组成验证流程:开始声明 message;规范化原文引用 {{start.message}} 并开启大写;结束将 content 和 length 映射为结果。
输入 docs_qinghe 时,输出为 {"content":"DOCS_QINGHE","length":11};关闭大写开关后,content 为 docs_qinghe。草稿调试通过后发布,以已发布版本运行同一输入,执行日志中可查看节点产出与最终输出。发布与运行操作见 应用调试与版本发布。
