文章目录
-
- 每日一句正能量
- 前言
- 一、前言:低代码智能体编排的范式革新
- 二、核心特性解析与技术选型
-
- [2.1 HMAF在低代码编排中的价值](#2.1 HMAF在低代码编排中的价值)
- [2.2 沉浸光感在可视化编排中的创新应用](#2.2 沉浸光感在可视化编排中的创新应用)
- [2.3 悬浮导航的编排适配](#2.3 悬浮导航的编排适配)
- 三、项目实战:"智流工坊"架构设计
-
- [3.1 应用场景与功能规划](#3.1 应用场景与功能规划)
- [3.2 技术架构图](#3.2 技术架构图)
- 四、环境配置与模块依赖
-
- [4.1 模块依赖配置](#4.1 模块依赖配置)
- [4.2 权限声明(module.json5)](#4.2 权限声明(module.json5))
- 五、核心组件实战
-
- [5.1 窗口沉浸配置(EntryAbility.ets)](#5.1 窗口沉浸配置(EntryAbility.ets))
- [5.2 节点类型光效系统(NodeLightEffect.ets)](#5.2 节点类型光效系统(NodeLightEffect.ets))
- [5.3 HMAF可视化编排引擎(OrchestrationEngine.ets)](#5.3 HMAF可视化编排引擎(OrchestrationEngine.ets))
- [5.4 悬浮编排导航(OrchestrationFloatNavigation.ets)](#5.4 悬浮编排导航(OrchestrationFloatNavigation.ets))
- [5.5 可视化编排画布(OrchestrationCanvas.ets)](#5.5 可视化编排画布(OrchestrationCanvas.ets))
- [5.6 浮动属性面板窗口(PropertyPanelWindow.ets)](#5.6 浮动属性面板窗口(PropertyPanelWindow.ets))
- [5.7 多窗口光效同步管理器(WindowLightSync.ets)](#5.7 多窗口光效同步管理器(WindowLightSync.ets))
- [5.8 主页面集成(Index.ets)](#5.8 主页面集成(Index.ets))
- 六、关键技术总结
-
- [6.1 HMAF可视化编排开发清单](#6.1 HMAF可视化编排开发清单)
- [6.2 沉浸光感实现清单](#6.2 沉浸光感实现清单)
- [6.3 节点类型光效映射](#6.3 节点类型光效映射)
- [6.4 编排模式光效映射](#6.4 编排模式光效映射)
- [6.5 PC端多窗口光效协同](#6.5 PC端多窗口光效协同)
- 七、调试与适配建议
- 八、总结与展望

每日一句正能量
保持极度自律,不断鞭策自己,你才能真正做出一番事业与成就。
自律不是偶尔为之,而是一种持续的内在驱动力。成功不是靠一时激情,而是靠日复一日对抗惰性的执行系统。
前言
摘要:随着AI智能体应用的爆发式增长,非技术用户快速构建智能体应用的需求日益迫切。HarmonyOS 6(API 23)引入的鸿蒙智能体框架(HMAF)配合小艺开放平台的四种编排模式,为低代码可视化智能体开发提供了全新可能。本文将实战开发一款面向HarmonyOS PC的"智流工坊"应用,展示如何利用HMAF构建拖拽式可视化智能体编排引擎,通过悬浮导航实现画布与组件库状态实时切换,基于沉浸光感打造"节点即氛围"的编排体验,以及基于多窗口架构构建浮动属性面板、预览窗口和调试控制台窗口的协作开发体验。
一、前言:低代码智能体编排的范式革新
2026年,AI智能体已从技术极客的玩具演变为企业数字化转型的核心引擎。蚂蚁数科Agentar、Dify、Coze等低代码智能体平台的崛起,证明了"可视化编排+智能体协同"模式的巨大市场潜力。 然而,这些平台大多运行在Web端,缺乏原生操作系统的深度集成能力。
HarmonyOS 6(API 23)的HMAF框架不仅支持LLM模式、工作流模式、A2A模式和OpenClaw模式四种编排方式, 更关键的是将智能体能力下沉至操作系统层,配合**悬浮导航(Float Navigation)与沉浸光感(Immersive Light Effects)**特性,为PC端低代码智能体编排带来了"节点即氛围、连线即光效"的全新交互范式。
本文核心亮点:
- 节点类型光效:根据智能体节点类型(LLM节点/工具节点/条件节点/循环节点/输出节点)动态切换环境光色与脉冲节奏
- 悬浮编排导航:底部悬浮页签替代传统工具栏,支持画布缩放、节点库切换、运行状态实时徽章
- HMAF可视化编排引擎:基于Agent Framework Kit构建拖拽式节点编排引擎,支持四种编排模式无缝切换
- 多窗口协作开发:主画布窗口 + 浮动属性面板 + 浮动预览窗口 + 浮动调试控制台窗口的光效联动
- 运行状态沉浸感知:通过Intents Kit实时理解编排意图,自动调整界面光效与导航形态
二、核心特性解析与技术选型
2.1 HMAF在低代码编排中的价值
HarmonyOS 6的HMAF采用三层架构设计:底层是统一的AI系统底座,中间层是意图理解和任务编排引擎,上层是开放的智能体交互协议。 在"智流工坊"中,这种架构能够:
- 原生智能调度:智能体不再是应用的附属品,而是系统的基础能力,支持跨应用任务编排
- 意图即编排:通过Intents Kit将用户拖拽操作意图转化为结构化编排任务
- 四种编排模式:LLM模式(单Agent自主决策)、工作流模式(可视化画布编排)、A2A模式(Agent间通信)、OpenClaw模式(轻量个性化)
- 分布式智能体协同:利用鸿蒙分布式软总线,实现PC编排+手机测试+平板预览的多设备协作
2.2 沉浸光感在可视化编排中的创新应用
HarmonyOS 6的systemMaterialEffect通过模拟物理光照模型,为编排节点状态反馈带来细腻的视觉表达。在低代码编排场景中,这种材质效果能够:
- 增强节点人格化:不同节点类型拥有专属光效人格(LLM节点智慧紫、工具节点功能蓝、条件节点决策黄、循环节点循环绿、输出节点成果橙)
- 状态直觉感知:拖拽时的吸附蓝光、运行时的脉冲金光、调试时的数据流光、完成时的确认闪光
- 提升编排专注度:动态环境光随画布复杂度变化,简单流程柔和、复杂流程强烈
2.3 悬浮导航的编排适配
与传统开发工具不同,低代码编排平台需要处理:
- 高频模式切换:用户常在四种编排模式间快速切换
- 画布信息密度平衡:既要保证导航可见,又不能遮挡编排画布
- 实时运行徽章:编排任务运行状态需要实时徽章提示(运行中脉冲、完成确认、异常警示)
HarmonyOS 6的悬浮页签支持**强(85%)、平衡(70%)、弱(55%)**三档透明度自定义,结合PC端的自由窗口能力,可以实现"需要时出现,专注时隐退"的智能导航体验。
三、项目实战:"智流工坊"架构设计
3.1 应用场景与功能规划
面向HarmonyOS PC的低代码可视化智能体编排场景,核心功能包括:
| 功能模块 | 技术实现 | 沉浸光感/HMAF应用 |
|---|---|---|
| 主画布窗口 | Canvas + Gesture |
节点光效、连线流光、吸附高亮 |
| 悬浮编排导航 | HdsTabs + systemMaterialEffect |
玻璃拟态页签,模式徽章 |
| 节点库面板 | Grid + Drag |
节点类型色光效 |
| 属性面板 | Form + HdsInput |
选中节点主题色同步 |
| LLM编排模式 | HMAF LLM Mode | 智慧紫光效 |
| 工作流编排模式 | HMAF Workflow Mode | 流程蓝光效 |
| A2A编排模式 | HMAF A2A Mode | 通信青光效 |
| OpenClaw编排模式 | HMAF OpenClaw Mode | 轻量粉光效 |
| 浮动预览窗口 | 子窗口 + WebView |
运行状态光效 |
| 浮动调试控制台 | 子窗口 + List |
日志级别颜色编码 |
3.2 技术架构图
┌─────────────────────────────────────────────────────────────┐
│ 智流工坊 - 应用层 │
├─────────────┬─────────────┬─────────────┬─────────────────────┤
│ LLM编排模式 │ 工作流编排模式 │ A2A编排模式 │ OpenClaw编排模式 │
│ (LLM Mode) │ (Workflow) │ (A2A Mode) │ (OpenClaw Mode) │
├─────────────┴─────────────┴─────────────┴─────────────────────┤
│ HMAF - 智能体框架层 │
│ Agent Framework Kit + Intents Kit + NLU Kit │
├─────────────────────────────────────────────────────────────┤
│ AI系统底座 - 能力层 │
│ MindSpore Lite(端侧) │ 鸿蒙大模型4.0(云端) │ 分布式软总线 │
├─────────────────────────────────────────────────────────────┤
│ ArkUI - 表现层 │
│ 悬浮导航 │ 沉浸光感 │ 多窗口管理 │ 安全区扩展 │ 动画系统 │
└─────────────────────────────────────────────────────────────┘
四、环境配置与模块依赖
4.1 模块依赖配置
在oh-package.json5中添加HMAF及相关Kit依赖:
json
{
"name": "zhiliu_workshop",
"version": "1.0.0",
"description": "Low-Code Visual Agent Orchestration Platform",
"dependencies": {
"@ohos/hmaframework": "^6.0.0",
"@ohos/intentskit": "^6.0.0",
"@ohos/nlukit": "^6.0.0",
"@ohos/mindsporelite": "^6.0.0",
"@ohos/aiengine": "^6.0.0",
"@ohos/hds": "^6.0.0",
"@ohos/workflowengine": "^6.0.0"
}
}
4.2 权限声明(module.json5)
json
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": ["phone", "tablet", "2in1"],
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:layered_image",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:startIcon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"skills": [
{
"entities": ["entity.system.home"],
"actions": ["action.system.home"]
}
]
}
],
"requestPermissions": [
{
"name": "ohos.permission.INTERNET",
"reason": "$string:internet_permission"
},
{
"name": "ohos.permission.SYSTEM_FLOAT_WINDOW",
"reason": "$string:float_window_permission",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "always"
}
},
{
"name": "ohos.permission.DISTRIBUTED_DATASYNC",
"reason": "$string:distributed_permission"
},
{
"name": "ohos.permission.AI_ENGINE_ACCESS",
"reason": "$string:ai_engine_permission"
}
]
}
}
五、核心组件实战
5.1 窗口沉浸配置(EntryAbility.ets)
typescript
// entry/src/main/ets/entryability/EntryAbility.ets
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';
export default class EntryAbility extends UIAbility {
private windowStage: window.WindowStage | null = null;
onWindowStageCreate(windowStage: window.WindowStage): void {
this.windowStage = windowStage;
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
console.error('Failed to load content:', JSON.stringify(err));
return;
}
console.info('Succeeded in loading content.');
this.setupImmersiveWindow(windowStage);
});
}
private async setupImmersiveWindow(windowStage: window.WindowStage): Promise<void> {
try {
const mainWindow = windowStage.getMainWindowSync();
await mainWindow.setWindowLayoutFullScreen(true);
await mainWindow.setWindowBackgroundColor('#00000000');
await mainWindow.setWindowSystemBarProperties({
statusBarColor: '#00000000',
navigationBarColor: '#00000000',
statusBarContentColor: '#FFFFFF',
navigationBarContentColor: '#FFFFFF'
});
await mainWindow.setWindowAvoidAreaOption({
type: window.AvoidAreaType.TYPE_SYSTEM,
enabled: true
});
console.info('Immersive window setup completed');
} catch (error) {
console.error('Failed to setup immersive window:', (error as BusinessError).message);
}
}
onWindowStageDestroy(): void {
this.windowStage = null;
}
}
代码亮点 :通过setWindowLayoutFullScreen(true)实现内容延伸至非安全区,配合setWindowAvoidAreaOption启用HarmonyOS 6新增的安全区避让机制,确保悬浮导航不会遮挡编排画布。
5.2 节点类型光效系统(NodeLightEffect.ets)
代码亮点 :这是本应用的核心创新组件。它将编排节点类型映射为动态光效------LLM节点智慧紫、工具节点功能蓝、条件节点决策黄、循环节点循环绿、输出节点成果橙。每个节点类型拥有专属脉冲节奏与光晕强度,通过AppStorage全局状态实现跨组件光效同步。
typescript
// entry/src/main/ets/components/NodeLightEffect.ets
import { hmaf } from '@kit.HMAFramework';
// 节点类型枚举
export enum NodeType {
LLM = 'llm', // LLM节点
TOOL = 'tool', // 工具节点
CONDITION = 'condition', // 条件节点
LOOP = 'loop', // 循环节点
OUTPUT = 'output' // 输出节点
}
// 节点类型色彩配置
export const NodeColors: Record<NodeType, string> = {
[NodeType.LLM]: '#9B59B6', // 智慧紫
[NodeType.TOOL]: '#4A90D9', // 功能蓝
[NodeType.CONDITION]: '#F5A623', // 决策黄
[NodeType.LOOP]: '#2ECC71', // 循环绿
[NodeType.OUTPUT]: '#E67E22' // 成果橙
};
// 光效配置
interface LightEffectConfig {
baseColor: string;
pulseSpeed: number; // 脉冲周期(ms)
pulseIntensity: number; // 脉冲强度(0-1)
glowRadius: number; // 光晕半径
particleCount: number; // 粒子数量
}
@Component
export struct NodeLightEffect {
@State currentNodeType: NodeType = NodeType.LLM;
@State nodeState: 'idle' | 'dragging' | 'running' | 'completed' | 'error' = 'idle';
@State lightIntensity: number = 0.4;
@State pulsePhase: number = 0;
@State particlePositions: Array<{x: number, y: number, size: number, opacity: number}> = [];
private pulseTimer: number = -1;
private particleTimer: number = -1;
aboutToAppear(): void {
this.startPulseAnimation();
this.startParticleAnimation();
// 监听全局节点类型变化
AppStorage.setOrCreate('node_type_change', (type: NodeType) => {
this.currentNodeType = type;
this.updateLightEffect();
});
}
aboutToDisappear(): void {
clearInterval(this.pulseTimer);
clearInterval(this.particleTimer);
}
private startPulseAnimation(): void {
this.pulseTimer = setInterval(() => {
this.pulsePhase = (this.pulsePhase + 0.05) % (Math.PI * 2);
this.lightIntensity = this.calculatePulseIntensity();
}, 50);
}
private calculatePulseIntensity(): number {
const baseIntensity = this.getNodeConfig().pulseIntensity;
const variation = Math.sin(this.pulsePhase) * 0.3;
return Math.max(0.1, Math.min(1.0, baseIntensity + variation));
}
private startParticleAnimation(): void {
this.particleTimer = setInterval(() => {
if (this.nodeState === 'running') {
this.updateParticles();
}
}, 100);
}
private updateParticles(): void {
const newParticles: Array<{x: number, y: number, size: number, opacity: number}> = [];
for (let i = 0; i < this.getNodeConfig().particleCount; i++) {
newParticles.push({
x: Math.random() * 100,
y: Math.random() * 100,
size: Math.random() * 4 + 2,
opacity: Math.random() * this.lightIntensity
});
}
this.particlePositions = newParticles;
}
private getNodeConfig(): LightEffectConfig {
const configs: Record<<NodeType, LightEffectConfig> = {
[NodeType.LLM]: {
baseColor: NodeColors[NodeType.LLM],
pulseSpeed: 3000,
pulseIntensity: 0.6,
glowRadius: 100,
particleCount: 8
},
[NodeType.TOOL]: {
baseColor: NodeColors[NodeType.TOOL],
pulseSpeed: 2500,
pulseIntensity: 0.5,
glowRadius: 90,
particleCount: 6
},
[NodeType.CONDITION]: {
baseColor: NodeColors[NodeType.CONDITION],
pulseSpeed: 2000,
pulseIntensity: 0.7,
glowRadius: 110,
particleCount: 10
},
[NodeType.LOOP]: {
baseColor: NodeColors[NodeType.LOOP],
pulseSpeed: 3500,
pulseIntensity: 0.5,
glowRadius: 95,
particleCount: 7
},
[NodeType.OUTPUT]: {
baseColor: NodeColors[NodeType.OUTPUT],
pulseSpeed: 2800,
pulseIntensity: 0.6,
glowRadius: 105,
particleCount: 9
}
};
return configs[this.currentNodeType] || configs[NodeType.LLM];
}
private updateLightEffect(): void {
const config = this.getNodeConfig();
AppStorage.setOrCreate('current_node_color', config.baseColor);
AppStorage.setOrCreate('current_node_pulse', config.pulseSpeed);
AppStorage.setOrCreate('current_node_intensity', config.pulseIntensity);
}
build() {
Stack() {
// 主光晕层
Column()
.width(400)
.height(400)
.backgroundColor(this.getNodeConfig().baseColor)
.blur(this.getNodeConfig().glowRadius)
.opacity(this.lightIntensity)
.position({ x: '50%', y: '30%' })
.anchor('50%')
.animation({
duration: this.getNodeConfig().pulseSpeed,
curve: Curve.EaseInOut,
iterations: -1,
playMode: PlayMode.Alternate
})
// 粒子层(运行状态时显示)
if (this.nodeState === 'running') {
ForEach(this.particlePositions, (particle: {x: number, y: number, size: number, opacity: number}, index: number) => {
Column()
.width(particle.size)
.height(particle.size)
.backgroundColor(this.getNodeConfig().baseColor)
.borderRadius(particle.size / 2)
.opacity(particle.opacity)
.position({
x: `${particle.x}%`,
y: `${particle.y}%`
})
.animation({
duration: 1000,
curve: Curve.Linear,
iterations: -1
})
})
}
// 状态指示器环
Column()
.width(200)
.height(200)
.backgroundColor('transparent')
.border({
width: 3,
color: this.getNodeConfig().baseColor,
style: BorderStyle.Solid
})
.borderRadius(100)
.opacity(this.lightIntensity * 0.5)
.animation({
duration: this.getNodeConfig().pulseSpeed,
curve: Curve.EaseInOut,
iterations: -1,
playMode: PlayMode.Alternate
})
}
.width('100%')
.height('100%')
}
}
5.3 HMAF可视化编排引擎(OrchestrationEngine.ets)
代码亮点:基于HMAF Agent Framework Kit构建核心编排引擎,支持四种编排模式(LLM/工作流/A2A/OpenClaw)的无缝切换。引擎通过Intents Kit解析用户拖拽操作意图,自动创建节点连接关系,并实时监控编排运行状态。
typescript
// entry/src/main/ets/services/OrchestrationEngine.ets
import { hmaf } from '@kit.HMAFramework';
import { intents } from '@kit.IntentsKit';
import { nlu } from '@kit.NLUKit';
// 编排节点定义
interface OrchestrationNode {
id: string;
type: NodeType;
position: { x: number; y: number };
properties: Record<string, unknown>;
inputs: string[];
outputs: string[];
}
// 编排连线定义
interface OrchestrationEdge {
id: string;
source: string;
target: string;
condition?: string;
}
// 编排模式
export enum OrchestrationMode {
LLM = 'llm',
WORKFLOW = 'workflow',
A2A = 'a2a',
OPENCLAW = 'openclaw'
}
export class OrchestrationEngine {
private static instance: OrchestrationEngine;
private nodes: Map<string, OrchestrationNode> = new Map();
private edges: Map<string, OrchestrationEdge> = new Map();
private hmafSession: hmaf.AgentSession | null = null;
private intentEngine: intents.IntentEngine | null = null;
private currentMode: OrchestrationMode = OrchestrationMode.WORKFLOW;
private constructor() {}
static getInstance(): OrchestrationEngine {
if (!OrchestrationEngine.instance) {
OrchestrationEngine.instance = new OrchestrationEngine();
}
return OrchestrationEngine.instance;
}
async initialize(): Promise<void> {
try {
// 初始化HMAF会话
this.hmafSession = await hmaf.createAgentSession({
mode: hmaf.AgentMode.MULTI_AGENT,
maxConcurrentAgents: 10,
enableDistributed: true
});
// 初始化意图引擎
this.intentEngine = await intents.createIntentEngine({
supportedDomains: ['orchestration', 'workflow_design', 'agent_config'],
language: 'zh-CN'
});
console.info('OrchestrationEngine initialized successfully');
} catch (error) {
console.error('Failed to initialize OrchestrationEngine:', error);
throw error;
}
}
// 切换编排模式
async switchMode(mode: OrchestrationMode): Promise<void> {
this.currentMode = mode;
// 根据模式更新全局光效
const modeColors: Record<OrchestrationMode, string> = {
[OrchestrationMode.LLM]: '#9B59B6',
[OrchestrationMode.WORKFLOW]: '#4A90D9',
[OrchestrationMode.A2A]: '#1ABC9C',
[OrchestrationMode.OPENCLAW]: '#FF69B4'
};
AppStorage.setOrCreate('orchestration_mode_color', modeColors[mode]);
AppStorage.setOrCreate('orchestration_mode', mode);
console.info(`Switched to ${mode} mode`);
}
// 添加节点
addNode(type: NodeType, position: { x: number; y: number }): OrchestrationNode {
const nodeId = `node-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
const node: OrchestrationNode = {
id: nodeId,
type: type,
position: position,
properties: this.getDefaultProperties(type),
inputs: [],
outputs: []
};
this.nodes.set(nodeId, node);
// 触发节点添加光效
AppStorage.setOrCreate('node_added', { nodeId, type });
return node;
}
private getDefaultProperties(type: NodeType): Record<string, unknown> {
const defaults: Record<<NodeType, Record<string, unknown>> = {
[NodeType.LLM]: {
model: 'qwen-max',
temperature: 0.7,
maxTokens: 2048,
systemPrompt: ''
},
[NodeType.TOOL]: {
toolName: '',
parameters: {}
},
[NodeType.CONDITION]: {
condition: '',
trueBranch: '',
falseBranch: ''
},
[NodeType.LOOP]: {
loopType: 'for',
iterations: 10,
condition: ''
},
[NodeType.OUTPUT]: {
outputType: 'text',
format: 'json'
}
};
return defaults[type] || {};
}
// 添加连线
addEdge(source: string, target: string, condition?: string): OrchestrationEdge {
const edgeId = `edge-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
const edge: OrchestrationEdge = {
id: edgeId,
source: source,
target: target,
condition: condition
};
this.edges.set(edgeId, edge);
// 更新节点输入输出
const sourceNode = this.nodes.get(source);
const targetNode = this.nodes.get(target);
if (sourceNode) {
sourceNode.outputs.push(target);
}
if (targetNode) {
targetNode.inputs.push(source);
}
// 触发连线光效
AppStorage.setOrCreate('edge_added', { edgeId, source, target });
return edge;
}
// 删除节点
removeNode(nodeId: string): void {
const node = this.nodes.get(nodeId);
if (!node) return;
// 删除相关连线
for (const [edgeId, edge] of this.edges.entries()) {
if (edge.source === nodeId || edge.target === nodeId) {
this.edges.delete(edgeId);
}
}
this.nodes.delete(nodeId);
}
// 运行编排
async runOrchestration(): Promise<<Record<string, unknown>> {
const results: Record<string, unknown> = {};
try {
// 根据当前模式选择执行策略
switch (this.currentMode) {
case OrchestrationMode.LLM:
return await this.runLLMMode();
case OrchestrationMode.WORKFLOW:
return await this.runWorkflowMode();
case OrchestrationMode.A2A:
return await this.runA2AMode();
case OrchestrationMode.OPENCLAW:
return await this.runOpenClawMode();
default:
throw new Error('Unknown orchestration mode');
}
} catch (error) {
console.error('Orchestration execution failed:', error);
throw error;
}
}
private async runLLMMode(): Promise<<Record<string, unknown>> {
// LLM模式:单Agent自主决策
const llmNodes = Array.from(this.nodes.values()).filter(n => n.type === NodeType.LLM);
for (const node of llmNodes) {
const result = await this.hmafSession?.sendTask({
targetAgent: 'llm-agent',
taskType: 'llm_inference',
parameters: {
model: node.properties.model,
prompt: node.properties.systemPrompt,
temperature: node.properties.temperature
},
timeout: 30000
});
results[node.id] = result;
}
return results;
}
private async runWorkflowMode(): Promise<<Record<string, unknown>> {
// 工作流模式:按拓扑排序执行
const sortedNodes = this.topologicalSort();
for (const nodeId of sortedNodes) {
const node = this.nodes.get(nodeId);
if (!node) continue;
// 更新节点状态为运行中
AppStorage.setOrCreate('node_state_update', { nodeId, state: 'running' });
const result = await this.executeNode(node);
results[nodeId] = result;
// 更新节点状态为完成
AppStorage.setOrCreate('node_state_update', { nodeId, state: 'completed' });
}
return results;
}
private async runA2AMode(): Promise<<Record<string, unknown>> {
// A2A模式:Agent间通信
const agents = Array.from(this.nodes.values()).map(n => ({
id: n.id,
type: n.type,
capabilities: n.properties
}));
const result = await this.hmafSession?.sendTask({
targetAgent: 'a2a-coordinator',
taskType: 'agent_coordination',
parameters: { agents },
timeout: 60000
});
return { a2a_result: result };
}
private async runOpenClawMode(): Promise<<Record<string, unknown>> {
// OpenClaw模式:轻量个性化
const openClawConfig = {
personality: '',
tools: Array.from(this.nodes.values())
.filter(n => n.type === NodeType.TOOL)
.map(n => n.properties.toolName)
};
const result = await this.hmafSession?.sendTask({
targetAgent: 'openclaw-agent',
taskType: 'personalized_assistant',
parameters: openClawConfig,
timeout: 30000
});
return { openclaw_result: result };
}
private async executeNode(node: OrchestrationNode): Promise<unknown> {
switch (node.type) {
case NodeType.LLM:
return await this.executeLLMNode(node);
case NodeType.TOOL:
return await this.executeToolNode(node);
case NodeType.CONDITION:
return await this.executeConditionNode(node);
case NodeType.LOOP:
return await this.executeLoopNode(node);
case NodeType.OUTPUT:
return await this.executeOutputNode(node);
default:
throw new Error(`Unknown node type: ${node.type}`);
}
}
private async executeLLMNode(node: OrchestrationNode): Promise<unknown> {
return await this.hmafSession?.sendTask({
targetAgent: 'llm-executor',
taskType: 'text_generation',
parameters: {
model: node.properties.model,
prompt: node.properties.systemPrompt,
temperature: node.properties.temperature,
maxTokens: node.properties.maxTokens
},
timeout: 30000
});
}
private async executeToolNode(node: OrchestrationNode): Promise<unknown> {
return await this.hmafSession?.sendTask({
targetAgent: 'tool-executor',
taskType: 'tool_invocation',
parameters: {
toolName: node.properties.toolName,
parameters: node.properties.parameters
},
timeout: 20000
});
}
private async executeConditionNode(node: OrchestrationNode): Promise<unknown> {
const condition = node.properties.condition as string;
// 评估条件表达式
const result = await this.hmafSession?.sendTask({
targetAgent: 'condition-evaluator',
taskType: 'condition_evaluation',
parameters: { condition },
timeout: 10000
});
return { condition: condition, result: result };
}
private async executeLoopNode(node: OrchestrationNode): Promise<unknown> {
const iterations = node.properties.iterations as number;
const results = [];
for (let i = 0; i < iterations; i++) {
const result = await this.hmafSession?.sendTask({
targetAgent: 'loop-executor',
taskType: 'loop_iteration',
parameters: {
iteration: i,
condition: node.properties.condition
},
timeout: 15000
});
results.push(result);
}
return { iterations, results };
}
private async executeOutputNode(node: OrchestrationNode): Promise<unknown> {
return {
outputType: node.properties.outputType,
format: node.properties.format,
timestamp: Date.now()
};
}
private topologicalSort(): string[] {
const visited = new Set<string>();
const result: string[] = [];
const visit = (nodeId: string) => {
if (visited.has(nodeId)) return;
visited.add(nodeId);
const node = this.nodes.get(nodeId);
if (node) {
for (const input of node.inputs) {
visit(input);
}
}
result.push(nodeId);
};
for (const nodeId of this.nodes.keys()) {
visit(nodeId);
}
return result;
}
getNodes(): OrchestrationNode[] {
return Array.from(this.nodes.values());
}
getEdges(): OrchestrationEdge[] {
return Array.from(this.edges.values());
}
getCurrentMode(): OrchestrationMode {
return this.currentMode;
}
}
5.4 悬浮编排导航(OrchestrationFloatNavigation.ets)
代码亮点:底部悬浮导航栏不仅承载页面切换功能,更重要的是实时显示编排模式和运行状态。每个导航项配备模式徽章------LLM模式智慧紫、工作流模式功能蓝、A2A模式通信青、OpenClaw模式轻量粉。支持长按展开透明度调节面板。
typescript
// entry/src/main/ets/components/OrchestrationFloatNavigation.ets
import { window } from '@kit.ArkUI';
import { NodeType, NodeColors } from './NodeLightEffect';
import { OrchestrationMode } from '../services/OrchestrationEngine';
// 导航项配置
interface OrchestrationNavItem {
id: string;
icon: Resource;
label: string;
page: string;
mode?: OrchestrationMode;
}
@Component
export struct OrchestrationFloatNavigation {
@State currentIndex: number = 0;
@State navTransparency: number = 0.70;
@State isExpanded: boolean = false;
@State bottomAvoidHeight: number = 0;
@State currentMode: OrchestrationMode = OrchestrationMode.WORKFLOW;
@State isRunning: boolean = false;
private navItems: OrchestrationNavItem[] = [
{ id: 'canvas', icon: $r('app.media.ic_canvas'), label: '画布', page: 'CanvasPage' },
{ id: 'llm', icon: $r('app.media.ic_llm'), label: 'LLM', page: 'LLMPage', mode: OrchestrationMode.LLM },
{ id: 'workflow', icon: $r('app.media.ic_workflow'), label: '工作流', page: 'WorkflowPage', mode: OrchestrationMode.WORKFLOW },
{ id: 'a2a', icon: $r('app.media.ic_a2a'), label: 'A2A', page: 'A2APage', mode: OrchestrationMode.A2A },
{ id: 'openclaw', icon: $r('app.media.ic_openclaw'), label: 'OpenClaw', page: 'OpenClawPage', mode: OrchestrationMode.OPENCLAW }
];
aboutToAppear(): void {
this.getBottomAvoidArea();
// 监听编排模式变化
AppStorage.setOrCreate('orchestration_mode', (mode: OrchestrationMode) => {
this.currentMode = mode;
});
// 监听运行状态变化
AppStorage.setOrCreate('orchestration_running', (running: boolean) => {
this.isRunning = running;
});
}
private async getBottomAvoidArea(): Promise<void> {
try {
const mainWindow = await window.getLastWindow();
const avoidArea = mainWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR);
this.bottomAvoidHeight = avoidArea.bottomRect.height;
} catch (error) {
console.error('Failed to get avoid area:', error);
}
}
private getModeColor(mode?: OrchestrationMode): string {
const colors: Record<OrchestrationMode, string> = {
[OrchestrationMode.LLM]: '#9B59B6',
[OrchestrationMode.WORKFLOW]: '#4A90D9',
[OrchestrationMode.A2A]: '#1ABC9C',
[OrchestrationMode.OPENCLAW]: '#FF69B4'
};
return mode ? colors[mode] : '#666666';
}
private getModeBadgeAnimation(): object {
if (this.isRunning) {
return {
duration: 1000,
curve: Curve.Linear,
iterations: -1
};
}
return { duration: 0 };
}
build() {
Stack({ alignContent: Alignment.Bottom }) {
// 内容层
Column() {
this.contentBuilder()
}
.padding({ bottom: this.bottomAvoidHeight + 80 })
// 悬浮导航栏
Column() {
Stack() {
// 玻璃拟态背景
Column()
.width('100%')
.height('100%')
.backgroundBlurStyle(BlurStyle.REGULAR)
.opacity(this.navTransparency)
.backdropFilter($r('sys.blur.20'))
// 渐变光效层
Column()
.width('100%')
.height('100%')
.linearGradient({
direction: GradientDirection.Top,
colors: [
['rgba(255,255,255,0.15)', 0.0],
['rgba(255,255,255,0.05)', 1.0]
]
})
}
.width('100%')
.height('100%')
.borderRadius(24)
.shadow({
radius: 20,
color: 'rgba(0,0,0,0.2)',
offsetX: 0,
offsetY: -4
})
// 导航项
Row() {
ForEach(this.navItems, (item: OrchestrationNavItem, index: number) => {
Column() {
Stack() {
Image(item.icon)
.width(24)
.height(24)
.fillColor(this.currentIndex === index ? this.getModeColor(item.mode) : '#666666')
// 运行状态徽章
if (item.mode === this.currentMode && this.isRunning) {
Column()
.width(10)
.height(10)
.backgroundColor(this.getModeColor(item.mode))
.borderRadius(5)
.position({ x: 18, y: -4 })
.shadow({
radius: 6,
color: this.getModeColor(item.mode),
offsetX: 0,
offsetY: 0
})
.animation(this.getModeBadgeAnimation())
}
// 模式指示器
if (item.mode === this.currentMode) {
Column()
.width(6)
.height(6)
.backgroundColor(this.getModeColor(item.mode))
.borderRadius(3)
.position({ x: 20, y: 20 })
}
}
.width(40)
.height(40)
Text(item.label)
.fontSize(11)
.fontColor(this.currentIndex === index ? this.getModeColor(item.mode) : '#999999')
.margin({ top: 4 })
}
.layoutWeight(1)
.onClick(() => {
this.currentIndex = index;
if (item.mode) {
this.switchMode(item.mode);
}
this.triggerHapticFeedback();
})
})
}
.width('100%')
.height(80)
.padding({ left: 16, right: 16 })
.justifyContent(FlexAlign.SpaceAround)
// 透明度调节
if (this.isExpanded) {
Row() {
Text('透明度')
.fontSize(12)
.fontColor('#666666')
.margin({ right: 8 })
Slider({
value: this.navTransparency * 100,
min: 55,
max: 85,
step: 15,
style: SliderStyle.InSet
})
.width(120)
.onChange((value: number) => {
this.navTransparency = value / 100;
})
Text(`${Math.round(this.navTransparency * 100)}%`)
.fontSize(12)
.fontColor('#666666')
.margin({ left: 8 })
}
.width('100%')
.height(40)
.justifyContent(FlexAlign.Center)
.backgroundColor('rgba(255,255,255,0.5)')
.borderRadius({ topLeft: 12, topRight: 12 })
}
}
.width('92%')
.height(this.isExpanded ? 120 : 80)
.margin({ bottom: this.bottomAvoidHeight + 12, left: '4%', right: '4%' })
.animation({
duration: 300,
curve: Curve.Spring,
iterations: 1
})
.gesture(
LongPressGesture({ duration: 500 })
.onAction(() => {
this.isExpanded = !this.isExpanded;
})
)
}
.width('100%')
.height('100%')
}
@BuilderParam contentBuilder: () => void = this.defaultContentBuilder;
@Builder
defaultContentBuilder(): void {
Column() {
Text('内容区域')
.fontSize(16)
.fontColor('#999999')
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
private async switchMode(mode: OrchestrationMode): Promise<void> {
const engine = await import('../services/OrchestrationEngine').then(m => m.OrchestrationEngine.getInstance());
await engine.switchMode(mode);
}
private triggerHapticFeedback(): void {
try {
import('@kit.SensorServiceKit').then(sensor => {
sensor.vibrator.startVibration({
type: 'time',
duration: 50
}, { id: 0 });
});
} catch (error) {
console.error('Haptic feedback failed:', error);
}
}
}
5.5 可视化编排画布(OrchestrationCanvas.ets)
代码亮点:实现具有节点光效和连线流光的可视化编排画布。支持拖拽创建节点、连线连接节点、节点属性编辑。节点根据类型显示专属色彩边框,运行时光效脉冲。
typescript
// entry/src/main/ets/components/OrchestrationCanvas.ets
import { NodeType, NodeColors } from './NodeLightEffect';
import { OrchestrationEngine } from '../services/OrchestrationEngine';
interface CanvasNode {
id: string;
type: NodeType;
x: number;
y: number;
width: number;
height: number;
isSelected: boolean;
isRunning: boolean;
}
interface CanvasEdge {
id: string;
source: string;
target: string;
path: string;
}
@Component
export struct OrchestrationCanvas {
@State nodes: CanvasNode[] = [];
@State edges: CanvasEdge[] = [];
@State selectedNodeId: string = '';
@State isDragging: boolean = false;
@State dragOffset: { x: number; y: number } = { x: 0, y: 0 };
@State scale: number = 1.0;
@State currentModeColor: string = '#4A90D9';
private engine: OrchestrationEngine = OrchestrationEngine.getInstance();
private canvasContext: CanvasRenderingContext2D | null = null;
aboutToAppear(): void {
// 监听模式颜色变化
AppStorage.setOrCreate('orchestration_mode_color', (color: string) => {
this.currentModeColor = color;
});
// 监听节点状态变化
AppStorage.setOrCreate('node_state_update', (update: {nodeId: string, state: string}) => {
const node = this.nodes.find(n => n.id === update.nodeId);
if (node) {
node.isRunning = update.state === 'running';
}
});
}
private getNodeColor(type: NodeType): string {
return NodeColors[type] || '#666666';
}
private getNodeAnimation(node: CanvasNode): object {
if (node.isRunning) {
return {
duration: 1000,
curve: Curve.Linear,
iterations: -1
};
}
if (node.isSelected) {
return {
duration: 1500,
curve: Curve.EaseInOut,
iterations: -1,
playMode: PlayMode.Alternate
};
}
return { duration: 0 };
}
build() {
Stack() {
// 画布背景
Column()
.width('100%')
.height('100%')
.backgroundColor('#0a0a0f')
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
// 网格背景
Canvas(this.canvasContext)
.width('100%')
.height('100%')
.onReady(() => {
this.drawGrid();
})
// 节点层
ForEach(this.nodes, (node: CanvasNode) => {
Stack() {
// 节点光效背景
Column()
.width(node.width + 20)
.height(node.height + 20)
.backgroundColor(this.getNodeColor(node.type))
.blur(20)
.opacity(node.isRunning ? 0.6 : 0.3)
.position({ x: '50%', y: '50%' })
.anchor('50%')
.animation(this.getNodeAnimation(node))
// 节点主体
Column() {
// 节点标题栏
Row() {
Text(this.getNodeIcon(node.type))
.fontSize(16)
.margin({ right: 8 })
Text(node.type.toUpperCase())
.fontSize(14)
.fontColor('#FFFFFF')
.fontWeight(FontWeight.Bold)
}
.width('100%')
.padding(12)
.backgroundColor(`${this.getNodeColor(node.type)}80`)
.borderRadius({ topLeft: 8, topRight: 8 })
// 节点内容
Column() {
Text(`ID: ${node.id.substr(0, 8)}...`)
.fontSize(12)
.fontColor('#AAAAAA')
.margin({ bottom: 8 })
if (node.isRunning) {
Text('运行中...')
.fontSize(12)
.fontColor(this.getNodeColor(node.type))
.animation({
duration: 1000,
curve: Curve.Linear,
iterations: -1
})
}
}
.width('100%')
.padding(12)
}
.width(node.width)
.height(node.height)
.backgroundColor('rgba(30,30,50,0.9)')
.borderRadius(8)
.border({
width: node.isSelected ? 3 : 2,
color: node.isSelected ? this.getNodeColor(node.type) : `${this.getNodeColor(node.type)}60`,
style: BorderStyle.Solid
})
.shadow({
radius: node.isSelected ? 20 : 10,
color: `${this.getNodeColor(node.type)}${node.isSelected ? '60' : '30'}`,
offsetX: 0,
offsetY: 0
})
.position({ x: node.x, y: node.y })
.gesture(
GestureGroup(GestureMode.Sequence,
LongPressGesture({ duration: 500 })
.onAction(() => {
this.selectedNodeId = node.id;
node.isSelected = true;
}),
PanGesture()
.onActionStart((event: GestureEvent) => {
this.isDragging = true;
this.dragOffset = { x: event.offsetX, y: event.offsetY };
})
.onActionUpdate((event: GestureEvent) => {
if (this.isDragging) {
node.x = event.offsetX - this.dragOffset.x;
node.y = event.offsetY - this.dragOffset.y;
}
})
.onActionEnd(() => {
this.isDragging = false;
})
)
)
}
})
// 连线层
Canvas(this.canvasContext)
.width('100%')
.height('100%')
.onReady(() => {
this.drawEdges();
})
// 缩放控制
Row() {
Button() {
Text('+')
.fontSize(20)
.fontColor('#FFFFFF')
}
.type(ButtonType.Circle)
.backgroundColor('rgba(255,255,255,0.2)')
.width(40)
.height(40)
.onClick(() => {
this.scale = Math.min(2.0, this.scale + 0.1);
})
Button() {
Text('-')
.fontSize(20)
.fontColor('#FFFFFF')
}
.type(ButtonType.Circle)
.backgroundColor('rgba(255,255,255,0.2)')
.width(40)
.height(40)
.margin({ left: 8 })
.onClick(() => {
this.scale = Math.max(0.5, this.scale - 0.1);
})
}
.position({ x: 20, y: 100 })
}
.width('100%')
.height('100%')
}
private getNodeIcon(type: NodeType): string {
const icons: Record<<NodeType, string> = {
[NodeType.LLM]: '🧠',
[NodeType.TOOL]: '🔧',
[NodeType.CONDITION]: '❓',
[NodeType.LOOP]: '🔄',
[NodeType.OUTPUT]: '📤'
};
return icons[type] || '📦';
}
private drawGrid(): void {
// 绘制网格背景
if (!this.canvasContext) return;
const ctx = this.canvasContext;
const width = ctx.canvas.width;
const height = ctx.canvas.height;
const gridSize = 20 * this.scale;
ctx.strokeStyle = 'rgba(255,255,255,0.05)';
ctx.lineWidth = 1;
for (let x = 0; x < width; x += gridSize) {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, height);
ctx.stroke();
}
for (let y = 0; y < height; y += gridSize) {
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(width, y);
ctx.stroke();
}
}
private drawEdges(): void {
// 绘制连线
if (!this.canvasContext) return;
const ctx = this.canvasContext;
for (const edge of this.edges) {
const sourceNode = this.nodes.find(n => n.id === edge.source);
const targetNode = this.nodes.find(n => n.id === edge.target);
if (!sourceNode || !targetNode) continue;
const startX = sourceNode.x + sourceNode.width / 2;
const startY = sourceNode.y + sourceNode.height;
const endX = targetNode.x + targetNode.width / 2;
const endY = targetNode.y;
// 绘制流光连线
const gradient = ctx.createLinearGradient(startX, startY, endX, endY);
gradient.addColorStop(0, `${this.getNodeColor(sourceNode.type)}80`);
gradient.addColorStop(0.5, this.currentModeColor);
gradient.addColorStop(1, `${this.getNodeColor(targetNode.type)}80`);
ctx.strokeStyle = gradient;
ctx.lineWidth = 2;
ctx.setLineDash([5, 5]);
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.bezierCurveTo(
startX, startY + 50,
endX, endY - 50,
endX, endY
);
ctx.stroke();
// 绘制流动粒子
const particleX = startX + (endX - startX) * 0.5;
const particleY = startY + (endY - startY) * 0.5;
ctx.fillStyle = this.currentModeColor;
ctx.beginPath();
ctx.arc(particleX, particleY, 3, 0, Math.PI * 2);
ctx.fill();
}
}
// 添加节点
addNode(type: NodeType, x: number, y: number): void {
const nodeId = `node-${Date.now()}`;
const newNode: CanvasNode = {
id: nodeId,
type: type,
x: x,
y: y,
width: 180,
height: 120,
isSelected: false,
isRunning: false
};
this.nodes.push(newNode);
// 同步到引擎
this.engine.addNode(type, { x, y });
}
// 添加连线
addEdge(sourceId: string, targetId: string): void {
const edgeId = `edge-${Date.now()}`;
const newEdge: CanvasEdge = {
id: edgeId,
source: sourceId,
target: targetId,
path: ''
};
this.edges.push(newEdge);
// 同步到引擎
this.engine.addEdge(sourceId, targetId);
}
}
5.6 浮动属性面板窗口(PropertyPanelWindow.ets)
代码亮点 :实现可拖拽的浮动属性面板,支持节点属性编辑、模式切换、运行配置。窗口激活时边缘发光增强,失活时自动降低光效强度,通过WindowManager与主窗口光效联动。
typescript
// entry/src/main/ets/windows/PropertyPanelWindow.ets
import { window } from '@kit.ArkUI';
import { NodeType, NodeColors } from '../components/NodeLightEffect';
import { OrchestrationMode } from '../services/OrchestrationEngine';
@Component
export struct PropertyPanelWindow {
@State isActive: boolean = false;
@State selectedNode: {id: string, type: NodeType, properties: Record<string, unknown>} | null = null;
@State windowLightColor: string = '#4A90D9';
@State lightIntensity: number = 0.6;
@State currentMode: OrchestrationMode = OrchestrationMode.WORKFLOW;
private mainWindow: window.Window | null = null;
aboutToAppear(): void {
this.setupWindow();
// 监听主窗口光效变化
AppStorage.setOrCreate('orchestration_mode_color', (color: string) => {
this.windowLightColor = color;
});
// 监听选中节点变化
AppStorage.setOrCreate('selected_node', (node: {id: string, type: NodeType, properties: Record<string, unknown>}) => {
this.selectedNode = node;
});
}
private async setupWindow(): Promise<void> {
try {
this.mainWindow = await window.getLastWindow();
await this.mainWindow.setWindowBackgroundColor('#00000000');
// 设置窗口为浮动样式
await this.mainWindow.setWindowDecorVisible(false);
await this.mainWindow.resize(350, 600);
// 监听窗口焦点变化
this.mainWindow.on('windowFocusChange', (isFocused: boolean) => {
this.isActive = isFocused;
this.lightIntensity = isFocused ? 0.8 : 0.3;
});
} catch (error) {
console.error('Failed to setup property panel window:', error);
}
}
build() {
Stack() {
// 窗口边框光效
Column()
.width('100%')
.height('100%')
.backgroundColor('transparent')
.border({
width: 2,
color: `${this.windowLightColor}${this.isActive ? 'FF' : '40'}`,
style: BorderStyle.Solid
})
.borderRadius(16)
.animation({
duration: 300,
curve: Curve.EaseInOut
})
// 内容层
Column() {
// 标题栏
Row() {
Text('⚙️ 属性面板')
.fontSize(16)
.fontColor('#FFFFFF')
.fontWeight(FontWeight.Bold)
if (this.selectedNode) {
Text(this.selectedNode.type.toUpperCase())
.fontSize(12)
.fontColor('#FFFFFF')
.backgroundColor(NodeColors[this.selectedNode.type])
.borderRadius(8)
.padding({ left: 8, right: 8, top: 4, bottom: 4 })
}
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
.padding(16)
// 节点属性编辑
if (this.selectedNode) {
Column() {
Text(`节点ID: ${this.selectedNode.id}`)
.fontSize(14)
.fontColor('#FFFFFF')
.margin({ bottom: 12 })
// LLM节点属性
if (this.selectedNode.type === NodeType.LLM) {
this.buildLLMProperties()
}
// 工具节点属性
if (this.selectedNode.type === NodeType.TOOL) {
this.buildToolProperties()
}
// 条件节点属性
if (this.selectedNode.type === NodeType.CONDITION) {
this.buildConditionProperties()
}
}
.width('100%')
.padding(16)
.backgroundColor('rgba(255,255,255,0.05)')
.borderRadius(12)
.margin({ bottom: 16 })
}
// 模式切换
Column() {
Text('编排模式')
.fontSize(14)
.fontColor('#FFFFFF')
.fontWeight(FontWeight.Bold)
.margin({ bottom: 12 })
Row() {
ForEach([OrchestrationMode.LLM, OrchestrationMode.WORKFLOW, OrchestrationMode.A2A, OrchestrationMode.OPENCLAW], (mode: OrchestrationMode) => {
Button() {
Text(mode.toUpperCase())
.fontSize(11)
.fontColor(this.currentMode === mode ? '#FFFFFF' : '#888888')
}
.type(ButtonType.Capsule)
.backgroundColor(this.currentMode === mode ? this.windowLightColor : 'rgba(255,255,255,0.1)')
.height(28)
.margin({ left: 4, right: 4 })
.onClick(() => {
this.currentMode = mode;
AppStorage.setOrCreate('orchestration_mode', mode);
})
})
}
.width('100%')
.justifyContent(FlexAlign.SpaceAround)
}
.width('100%')
.padding(16)
.backgroundColor('rgba(255,255,255,0.05)')
.borderRadius(12)
}
.width('100%')
.height('100%')
.padding(2) // 为边框光效留出空间
}
.width('100%')
.height('100%')
.backgroundColor('rgba(15,15,35,0.95)')
.borderRadius(16)
.shadow({
radius: 30,
color: `${this.windowLightColor}${this.isActive ? '40' : '15'}`,
offsetX: 0,
offsetY: 0
})
.animation({
duration: 300,
curve: Curve.EaseInOut
})
}
@Builder
buildLLMProperties(): void {
Column() {
Text('模型配置')
.fontSize(13)
.fontColor('#AAAAAA')
.margin({ bottom: 8 })
TextInput({ placeholder: '模型名称', text: 'qwen-max' })
.width('100%')
.height(36)
.backgroundColor('rgba(255,255,255,0.1)')
.fontColor('#FFFFFF')
.borderRadius(8)
.margin({ bottom: 8 })
Text('Temperature')
.fontSize(12)
.fontColor('#AAAAAA')
Slider({ value: 0.7, min: 0, max: 1, step: 0.1 })
.width('100%')
.margin({ bottom: 8 })
Text('System Prompt')
.fontSize(12)
.fontColor('#AAAAAA')
TextArea({ placeholder: '输入系统提示词...' })
.width('100%')
.height(80)
.backgroundColor('rgba(255,255,255,0.1)')
.fontColor('#FFFFFF')
.borderRadius(8)
}
.width('100%')
}
@Builder
buildToolProperties(): void {
Column() {
Text('工具配置')
.fontSize(13)
.fontColor('#AAAAAA')
.margin({ bottom: 8 })
TextInput({ placeholder: '工具名称', text: '' })
.width('100%')
.height(36)
.backgroundColor('rgba(255,255,255,0.1)')
.fontColor('#FFFFFF')
.borderRadius(8)
.margin({ bottom: 8 })
Text('参数配置')
.fontSize(12)
.fontColor('#AAAAAA')
TextArea({ placeholder: '输入JSON格式参数...' })
.width('100%')
.height(80)
.backgroundColor('rgba(255,255,255,0.1)')
.fontColor('#FFFFFF')
.borderRadius(8)
}
.width('100%')
}
@Builder
buildConditionProperties(): void {
Column() {
Text('条件配置')
.fontSize(13)
.fontColor('#AAAAAA')
.margin({ bottom: 8 })
TextInput({ placeholder: '条件表达式', text: '' })
.width('100%')
.height(36)
.backgroundColor('rgba(255,255,255,0.1)')
.fontColor('#FFFFFF')
.borderRadius(8)
.margin({ bottom: 8 })
Text('True分支')
.fontSize(12)
.fontColor('#AAAAAA')
TextInput({ placeholder: 'True分支目标节点', text: '' })
.width('100%')
.height(36)
.backgroundColor('rgba(255,255,255,0.1)')
.fontColor('#FFFFFF')
.borderRadius(8)
.margin({ bottom: 8 })
Text('False分支')
.fontSize(12)
.fontColor('#AAAAAA')
TextInput({ placeholder: 'False分支目标节点', text: '' })
.width('100%')
.height(36)
.backgroundColor('rgba(255,255,255,0.1)')
.fontColor('#FFFFFF')
.borderRadius(8)
}
.width('100%')
}
}
5.7 多窗口光效同步管理器(WindowLightSync.ets)
代码亮点:管理主窗口与浮动属性面板窗口、预览窗口、调试控制台窗口之间的光效联动。当编排模式变化时,所有窗口同步切换主题色;当窗口焦点变化时,自动调整光效强度,形成层次分明的视觉体验。
typescript
// entry/src/main/ets/managers/WindowLightSync.ets
import { window } from '@kit.ArkUI';
import { OrchestrationMode } from '../services/OrchestrationEngine';
// 窗口类型
export enum WindowType {
MAIN = 'main',
PROPERTY_PANEL = 'property_panel',
PREVIEW = 'preview',
DEBUG_CONSOLE = 'debug_console'
}
// 光效主题
export interface LightTheme {
primaryColor: string;
secondaryColor: string;
intensity: number;
pulseSpeed: number;
glowRadius: number;
}
export class WindowLightSync {
private static instance: WindowLightSync;
private windows: Map<<WindowType, window.Window> = new Map();
private currentTheme: LightTheme = {
primaryColor: '#4A90D9',
secondaryColor: '#6BB6FF',
intensity: 0.6,
pulseSpeed: 2000,
glowRadius: 100
};
private focusWindow: WindowType = WindowType.MAIN;
private constructor() {}
static getInstance(): WindowLightSync {
if (!WindowLightSync.instance) {
WindowLightSync.instance = new WindowLightSync();
}
return WindowLightSync.instance;
}
registerWindow(type: WindowType, win: window.Window): void {
this.windows.set(type, win);
// 监听窗口焦点
win.on('windowFocusChange', (isFocused: boolean) => {
if (isFocused) {
this.focusWindow = type;
this.updateFocusLightEffect();
}
});
}
// 同步所有窗口光效
async syncLightEffect(theme: LightTheme): Promise<void> {
this.currentTheme = theme;
for (const [type, win] of this.windows.entries()) {
try {
const isFocused = type === this.focusWindow;
const intensity = isFocused ? theme.intensity : theme.intensity * 0.4;
// 设置窗口背景光效
await win.setWindowBackgroundColor(`#00000000`);
// 同步到AppStorage供各窗口组件读取
AppStorage.setOrCreate(`window_${type}_color`, theme.primaryColor);
AppStorage.setOrCreate(`window_${type}_intensity`, intensity);
AppStorage.setOrCreate(`window_${type}_focused`, isFocused);
} catch (error) {
console.error(`Failed to sync light effect for ${type}:`, error);
}
}
}
// 根据编排模式更新主题
updateThemeByMode(mode: OrchestrationMode): void {
const themes: Record<OrchestrationMode, LightTheme> = {
[OrchestrationMode.LLM]: {
primaryColor: '#9B59B6',
secondaryColor: '#C39BD3',
intensity: 0.6,
pulseSpeed: 3000,
glowRadius: 100
},
[OrchestrationMode.WORKFLOW]: {
primaryColor: '#4A90D9',
secondaryColor: '#6BB6FF',
intensity: 0.6,
pulseSpeed: 2500,
glowRadius: 100
},
[OrchestrationMode.A2A]: {
primaryColor: '#1ABC9C',
secondaryColor: '#76D7C4',
intensity: 0.6,
pulseSpeed: 2800,
glowRadius: 100
},
[OrchestrationMode.OPENCLAW]: {
primaryColor: '#FF69B4',
secondaryColor: '#FFB6C1',
intensity: 0.6,
pulseSpeed: 3200,
glowRadius: 100
}
};
const theme = themes[mode] || themes[OrchestrationMode.WORKFLOW];
this.syncLightEffect(theme);
}
private updateFocusLightEffect(): void {
// 重新应用当前主题,根据新的焦点窗口调整强度
this.syncLightEffect(this.currentTheme);
}
// 创建浮动窗口
async createFloatWindow(type: WindowType, width: number, height: number, x: number, y: number): Promise<<window.Window> {
try {
const floatWindow = await window.createWindow({
name: type,
windowType: window.WindowType.TYPE_FLOAT,
ctx: getContext()
});
await floatWindow.moveWindowTo(x, y);
await floatWindow.resize(width, height);
await floatWindow.setWindowBackgroundColor('#00000000');
await floatWindow.showWindow();
this.registerWindow(type, floatWindow);
return floatWindow;
} catch (error) {
console.error(`Failed to create float window ${type}:`, error);
throw error;
}
}
}
5.8 主页面集成(Index.ets)
typescript
// entry/src/main/ets/pages/Index.ets
import { OrchestrationCanvas } from '../components/OrchestrationCanvas';
import { OrchestrationEngine, OrchestrationMode } from '../services/OrchestrationEngine';
import { WindowLightSync, WindowType } from '../managers/WindowLightSync';
import { PropertyPanelWindow } from '../windows/PropertyPanelWindow';
@Entry
@Component
struct Index {
private engine: OrchestrationEngine = OrchestrationEngine.getInstance();
private lightSync: WindowLightSync = WindowLightSync.getInstance();
aboutToAppear(): void {
this.initializeWindows();
this.initializeEngine();
}
private async initializeEngine(): Promise<void> {
await this.engine.initialize();
await this.engine.switchMode(OrchestrationMode.WORKFLOW);
}
private async initializeWindows(): Promise<void> {
try {
const mainWindow = await window.getLastWindow();
this.lightSync.registerWindow(WindowType.MAIN, mainWindow);
// 创建浮动属性面板(PC端特有)
if (deviceInfo.deviceType === '2in1' || deviceInfo.deviceType === 'tablet') {
await this.lightSync.createFloatWindow(
WindowType.PROPERTY_PANEL,
350, 600,
100, 100
);
}
} catch (error) {
console.error('Failed to initialize windows:', error);
}
}
build() {
Stack() {
// 动态环境光背景
Column() {
Column()
.width(400)
.height(400)
.backgroundColor(AppStorage.get<string>('orchestration_mode_color') || '#4A90D9')
.blur(150)
.opacity(0.4)
.position({ x: '50%', y: '30%' })
.anchor('50%')
.animation({
duration: 3000,
curve: Curve.EaseInOut,
iterations: -1,
playMode: PlayMode.Alternate
})
}
.width('100%')
.height('100%')
.backgroundColor('#0a0a0f')
// 内容层
Column() {
// 编排画布
OrchestrationCanvas()
.layoutWeight(1)
}
.width('100%')
.height('100%')
}
.width('100%')
.height('100%')
}
}
六、关键技术总结
6.1 HMAF可视化编排开发清单
| 技术点 | API/方法 | 应用场景 |
|---|---|---|
| 智能体会话创建 | hmaf.createAgentSession({ mode: MULTI_AGENT }) |
多智能体协作编排 |
| 意图解析 | intents.createIntentEngine({ supportedDomains }) |
用户拖拽意图理解 |
| 任务分发 | hmafSession.sendTask({ targetAgent, taskType }) |
智能体间编排任务调度 |
| 状态监听 | AppStorage全局状态回调 |
跨组件编排状态同步 |
| 分布式协同 | enableDistributed: true |
多设备编排协作 |
| 四种编排模式 | LLM/Workflow/A2A/OpenClaw |
不同场景模式切换 |
6.2 沉浸光感实现清单
| 技术点 | API/方法 | 应用场景 |
|---|---|---|
| 系统材质效果 | systemMaterialEffect: SystemMaterialEffect.IMMERSIVE |
HdsNavigation标题栏 |
| 背景模糊 | backgroundBlurStyle(BlurStyle.REGULAR) |
悬浮导航玻璃拟态 |
| 背景滤镜 | backdropFilter($r('sys.blur.20')) |
精细模糊控制 |
| 安全区扩展 | expandSafeArea([SafeAreaType.SYSTEM], [...]) |
全屏沉浸布局 |
| 窗口沉浸 | setWindowLayoutFullScreen(true) |
无边框模式 |
| 光效动画 | animation({ duration, iterations: -1 }) |
呼吸灯背景 |
| 动态透明度 | backgroundOpacity |
焦点感知降级 |
6.3 节点类型光效映射
| 节点类型 | 光效颜色 | 脉冲速度 | 光晕半径 | 视觉语义 |
|---|---|---|---|---|
| LLM节点 | #9B59B6 | 3000ms | 100px | 智慧紫光,AI推理 |
| 工具节点 | #4A90D9 | 2500ms | 90px | 功能蓝光,工具调用 |
| 条件节点 | #F5A623 | 2000ms | 110px | 决策黄光,逻辑判断 |
| 循环节点 | #2ECC71 | 3500ms | 95px | 循环绿光,迭代执行 |
| 输出节点 | #E67E22 | 2800ms | 105px | 成果橙光,结果输出 |
6.4 编排模式光效映射
| 编排模式 | 光效颜色 | 脉冲速度 | 光晕半径 | 视觉语义 |
|---|---|---|---|---|
| LLM模式 | #9B59B6 | 3000ms | 100px | 智慧紫光,自主决策 |
| 工作流模式 | #4A90D9 | 2500ms | 100px | 流程蓝光,规则执行 |
| A2A模式 | #1ABC9C | 2800ms | 100px | 通信青光,Agent协同 |
| OpenClaw模式 | #FF69B4 | 3200ms | 100px | 轻量粉光,快速定制 |
6.5 PC端多窗口光效协同
- 主窗口:全屏沉浸,编排模式光效延伸至所有安全区边缘
- 浮动属性面板窗口:置顶、圆角、阴影,激活时边缘发光增强
- 光效同步 :通过
WindowLightSync管理器实现跨窗口主题色联动 - 焦点感知:窗口激活时边缘发光增强,失活时自动降低光效强度
- 模式一致性:同一编排模式在所有窗口中保持相同色彩标识
七、调试与适配建议
- HMAF会话管理:多智能体并发时注意会话资源释放,避免内存泄漏
- 光效功耗优化:夜间模式降低光效刷新率,延长OLED屏幕寿命
- 意图识别校准:不同编排场景需训练专用意图模型,提升解析准确率
- 分布式设备测试:测试跨设备编排协作时的网络延迟与状态同步
- 无障碍支持:为视障用户提供语音播报编排状态,光效切换时播放提示音
- 性能优化:复杂画布(100+节点)时启用虚拟渲染,仅渲染可视区域节点
八、总结与展望
本文基于HarmonyOS 6(API 23)的悬浮导航 、沉浸光感 与HMAF智能体框架特性,完整实战了一款面向 PC端的"智流工坊"低代码可视化智能体编排平台。核心创新点总结:
-
HMAF四种编排模式:基于Agent Framework Kit支持LLM模式(单Agent自主决策)、工作流模式(可视化画布编排)、A2A模式(Agent间通信)、OpenClaw模式(轻量个性化),实现一套引擎四种范式的无缝切换
-
节点类型光效系统:每个节点类型拥有专属光效人格(LLM节点智慧紫、工具节点功能蓝、条件节点决策黄、循环节点循环绿、输出节点成果橙),根据运行状态动态切换脉冲节奏与光晕强度,实现"节点直觉感知"
-
悬浮编排导航:底部悬浮页签不仅承载页面切换,更实时显示编排模式徽章(LLM紫光、工作流蓝光、A2A青光、OpenClaw粉光)和运行状态脉冲,玻璃拟态设计+三档透明度调节
-
PC级多窗口协作开发 :主画布窗口 + 浮动属性面板 + 浮动预览窗口 + 浮动调试控制台窗口的四层架构,通过
WindowLightSync实现跨窗口光效联动与焦点感知 -
可视化拖拽编排 :基于
Canvas和Gesture实现节点拖拽创建、连线连接、属性编辑,支持拓扑排序执行和实时状态反馈
未来扩展方向:
- 接入分布式软总线4.0,实现PC编排+手机测试+平板预览的多设备协作
- AI智能体市场:支持第三方开发者发布自定义节点,通过光效标识区分能力类型
- 数字孪生集成:接入IoT设备数据,编排流程自动感知物理世界状态并调整执行策略
- VR/AR融合:支持VR头显接入,实现完全沉浸式的3D智能体编排空间
- 自然语言编排:通过语音指令直接生成编排流程,"说即所得"
转载自:https://blog.csdn.net/u014727709/article/details/161166078
欢迎 👍点赞✍评论⭐收藏,欢迎指正