低代码平台中 AI 驱动的业务逻辑编排:可视化流程图到可执行代码的转换

低代码平台中 AI 驱动的业务逻辑编排:可视化流程图到可执行代码的转换

一、低代码的最后一公里

低代码平台在 UI 搭建层面已经相当成熟——拖拽生成表单、表格、图表页面的体验足够流畅。但当需求触及"业务逻辑"时,瓶颈出现了:一个审批流程需要"当金额超过 5 万时,自动升级到部门总监审批,并发送钉钉通知",这种逻辑很难用纯拖拽方式表达。

传统的低代码方案在这里往往退回到写代码。AI 的加入改变了这一困局:用自然语言或可视化流程图描述业务逻辑,由 AI 负责将其转换为可执行的函数代码——这补上了低代码的"最后一公里"。

二、从可视化流程图到中间表示

flowchart TB A[可视化流程图] --> B[中间表示层 IR] B --> C[AI 代码生成] C --> D[可执行代码] D --> E[沙箱校验] E -->|通过| F[部署至运行时] E -->|失败| G[错误定位与修复] G --> C H[自然语言补充] --> C

2.1 流程图的标准化中间表示

可视化编辑器的输出通常是 JSON 格式的节点和连线列表。需先将其规范化为 AST 友好的中间表示。

// ir/types.ts /** 流程图节点类型 */ type NodeType = | 'start' // 开始节点 | 'end' // 结束节点 | 'condition' // 条件判断 | 'action' // 动作(调用 API / 操作数据) | 'assignment' // 变量赋值 | 'loop' // 循环 | 'parallel' // 并行分支 | 'wait' // 等待/延迟 | 'subprocess'; // 子流程 /** 中间表示:规范化后的流程图 */ interface FlowIR { id: string; name: string; description: string; inputs: InputParam[]; nodes: IRNode[]; edges: IREdge[]; } interface IRNode { id: string; type: NodeType; label: string; config: Record<string, any>; // 节点在画布上的元数据(仅用于生成注释,不影响逻辑) position?: { x: number; y: number }; } interface IREdge { id: string; source: string; // 源节点 id target: string; // 目标节点 id condition?: string; // 条件边上的表达式 label?: string; } interface InputParam { name: string; type: 'string' | 'number' | 'boolean' | 'object' | 'array'; required: boolean; defaultValue?: any; }

2.2 拓扑排序与代码骨架生成

将流程图节点按拓扑顺序排列,区分顺序执行和条件分支:

// ir/topological-sort.ts interface ExecutionBlock { type: 'sequential' | 'conditional' | 'loop' | 'parallel'; nodes: IRNode[]; branches?: ExecutionBlock[][]; // 条件分支的子块 } /** * 将流程图 IR 转换为执行块结构。 * 这是 AI 代码生成的输入。 */ function buildExecutionPlan(ir: FlowIR): ExecutionBlock[] { // 构建邻接表 const adjacency = new Map<string, IREdge[]>(); const inDegree = new Map<string, number>(); for (const node of ir.nodes) { adjacency.set(node.id, []); inDegree.set(node.id, 0); } for (const edge of ir.edges) { adjacency.get(edge.source)?.push(edge); inDegree.set(edge.target, (inDegree.get(edge.target) ?? 0) + 1); } // 找到起始节点 const startNode = ir.nodes.find((n) => n.type === 'start'); if (!startNode) { throw new Error('流程图中未找到起始节点'); } // BFS 拓扑遍历 const visited = new Set<string>(); const plan: ExecutionBlock[] = []; const queue: string[] = [startNode.id]; while (queue.length > 0) { const nodeId = queue.shift()!; if (visited.has(nodeId)) continue; visited.add(nodeId); const node = ir.nodes.find((n) => n.id === nodeId); if (!node) continue; if (node.type === 'condition') { // 条件节点:建立条件执行块 const branches = buildConditionBranches(node, ir, adjacency); plan.push({ type: 'conditional', nodes: [node], branches, }); } else if (node.type === 'loop') { plan.push({ type: 'loop', nodes: [node] }); } else { plan.push({ type: 'sequential', nodes: [node] }); } // 将后继节点加入队列 const edges = adjacency.get(nodeId) ?? []; for (const edge of edges) { if (!visited.has(edge.target)) { queue.push(edge.target); } } } return plan; } function buildConditionBranches( condNode: IRNode, ir: FlowIR, adjacency: Map<string, IREdge[]>, ): ExecutionBlock[][] { const branches: ExecutionBlock[][] = []; const edges = adjacency.get(condNode.id) ?? []; for (const edge of edges) { // 沿每条条件分支向下遍历直到合并点 const branch: ExecutionBlock[] = []; let currentId = edge.target; while (currentId) { const node = ir.nodes.find((n) => n.id === currentId); if (!node) break; branch.push({ type: 'sequential', nodes: [node] }); const nextEdges = adjacency.get(currentId); if (!nextEdges || nextEdges.length !== 1) break; currentId = nextEdges[0].target; } branches.push(branch); } return branches; }

三、AI 代码生成:将中间表示转为可执行代码

3.1 Prompt 构建策略

// codegen/prompt-builder.ts interface CodeGenContext { /** 平台可用的 API 列表 */ availableAPIs: { name: string; description: string; params: Record<string, string> }[]; /** 可用的数据源 */ dataSources: { name: string; schema: Record<string, string> }[]; /** 目标语言/框架 */ target: 'typescript-function' | 'python-lambda' | 'json-logic'; } function buildCodeGenPrompt( plan: ExecutionBlock[], ir: FlowIR, context: CodeGenContext, ): string { const planJson = JSON.stringify(plan, null, 2); const apisJson = JSON.stringify(context.availableAPIs, null, 2); const inputsJson = JSON.stringify(ir.inputs, null, 2); return `你是一个业务逻辑代码生成器。根据以下执行计划生成 TypeScript 代码。 ## 流程信息 - 名称: ${ir.name} - 描述: ${ir.description} - 输入参数: ${inputsJson} ## 执行计划 ${planJson} ## 可用 API ${apisJson} ## 代码要求 1. 导出 async 函数,函数签名: export async function ${toSafeFunctionName(ir.name)}(inputs: InputType): Promise<OutputType> 2. 每个步骤添加中文注释,标注对应节点的 label 3. 条件分支使用 if/else 或 switch 4. API 调用须有 try/catch 错误处理 5. 使用 TypeScript 严格模式类型 6. 只输出代码,不包含解释文字 ## 输出格式 \`\`\`typescript // 代码在此 \`\`\` `; } function toSafeFunctionName(name: string): string { return name .replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, '_') .replace(/_{2,}/g, '_') .replace(/^_|_$/g, '') || 'processFlow'; }

3.2 代码生成示例

假设一个"员工请假审批"流程,流程图包含:开始 → 计算请假天数 → 判断是否超过 3 天 → 是:发送部门总监审批 → 否:发送直属主管审批 → 记录日志 → 结束。AI 应生成如下代码:

// 由 AI 生成的业务逻辑代码 interface LeaveRequest { employeeId: string; employeeName: string; startDate: string; endDate: string; leaveType: 'annual' | 'sick' | 'personal'; reason: string; } interface ApprovalResult { requestId: string; approved: boolean; approver: string; comment: string; notifiedAt: string; } /** * 员工请假审批流程。 * * 流程图路径: 开始 -> 计算天数 -> 判断超时 -> 分支审批 -> 记录 -> 结束 */ export async function processLeaveApproval( inputs: LeaveRequest, ): Promise<ApprovalResult> { // === 步骤1: 计算请假天数 === const startDate = new Date(inputs.startDate); const endDate = new Date(inputs.endDate); if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) { throw new Error(`日期格式无效: ${inputs.startDate} ~ ${inputs.endDate}`); } const diffTime = endDate.getTime() - startDate.getTime(); const leaveDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) + 1; // === 步骤2: 判断是否超过 3 天 === let approverId: string; let approvalLevel: string; if (leaveDays > 3) { // 超过 3 天:发送部门总监审批 approverId = await getDepartmentDirector(inputs.employeeId); approvalLevel = 'director'; } else { // 不超过 3 天:发送直属主管审批 approverId = await getDirectSupervisor(inputs.employeeId); approvalLevel = 'supervisor'; } // === 步骤3: 发送审批通知 === try { await sendNotification(approverId, { type: 'leave_approval', title: `${inputs.employeeName} 的请假申请`, body: `请假类型: ${inputs.leaveType}\n天数: ${leaveDays}天\n原因: ${inputs.reason}`, employeeId: inputs.employeeId, }); } catch (error) { console.error(`通知发送失败 (approverId=${approverId}):`, error); // 通知失败不中断流程,但记录异常 } // === 步骤4: 记录审批日志 === const requestId = generateRequestId(); await logApprovalRecord({ requestId, employeeId: inputs.employeeId, leaveDays, approvalLevel, approverId, createdAt: new Date().toISOString(), }); return { requestId, approved: false, // 等待审批人处理 approver: approverId, comment: `已提交${approvalLevel}审批`, notifiedAt: new Date().toISOString(), }; } // === 平台提供的 API 函数(由运行时注入) === declare function getDepartmentDirector(employeeId: string): Promise<string>; declare function getDirectSupervisor(employeeId: string): Promise<string>; declare function sendNotification(userId: string, notification: object): Promise<void>; declare function logApprovalRecord(record: object): Promise<void>; declare function generateRequestId(): string;

四、安全校验与沙箱执行

AI 生成的代码不能直接在用户浏览器或服务端解析执行。需要沙箱校验:

// validator/sandbox.ts interface ValidationResult { valid: boolean; errors: ValidationError[]; warnings: ValidationWarning[]; sandboxOutput?: string; } interface ValidationError { line: number; message: string; severity: 'error' | 'warning'; } /** * 对 AI 生成的代码进行静态和动态校验。 */ async function validateGeneratedCode( code: string, ir: FlowIR, ): Promise<ValidationResult> { const errors: ValidationError[] = []; // 1. 静态检查:禁止使用危险 API const forbiddenPatterns = [ { pattern: /\beval\s*\(/, message: '禁止使用 eval()' }, { pattern: /\bFunction\s*\(/, message: '禁止使用 Function 构造函数' }, { pattern: /import\s+.*\bchild_process\b/, message: '禁止导入子进程模块' }, { pattern: /\bdocument\./, message: '禁止直接操作 DOM' }, { pattern: /\bwindow\./, message: '禁止直接访问 window 对象' }, ]; const lines = code.split('\n'); for (const { pattern, message } of forbiddenPatterns) { for (let i = 0; i < lines.length; i++) { if (pattern.test(lines[i])) { errors.push({ line: i + 1, message, severity: 'error' }); } } } // 2. 检查是否包含所有 IR 节点的处理逻辑 for (const node of ir.nodes) { if (node.type === 'action' && !code.includes(node.id)) { errors.push({ line: 0, message: `缺失节点逻辑: ${node.label} (${node.id})`, severity: 'warning', }); } } return { valid: errors.filter((e) => e.severity === 'error').length === 0, errors: errors.filter((e) => e.severity === 'error'), warnings: errors.filter((e) => e.severity === 'warning'), }; }

五、总结

AI 驱动的业务逻辑编排,本质上是在可视化建模和代码执行之间引入了一个智能翻译层。这个翻译层接受结构化的流程中间表示,结合平台 API 的上下文信息,产出类型安全、可审计的生产级代码。

当前方案的核心限制在于:复杂分支逻辑(嵌套超过 3 层)的生成准确率下降明显;跨流程的数据共享与事务一致性需要额外的平台层面支持。下一步的改进方向包括:引入向量化的流程模板库加速匹配、用执行日志反哺代码回归测试用例、将生成代码的线上运行异常自动反馈到 AI 的修正循环中。低代码 + AI 的结合,还有很长的路要走,但"最后一公里"的可执行代码生成,已经迈出了关键一步。