Journal Article

Canvas-Coding:AI驱动的可视化工作流编辑器

Canvas-Coding是基于React Flow的AI驱动工作流设计工具,支持11种节点类型、多Provider模型接入、SSE流式生成节点图和DAG依赖分析。本文从架构设计、核心技术实现到使用指南进行全面解析。

16 min2 views

Canvas-Coding:AI驱动的可视化工作流编辑器

项目地址:GitHub - Canvas-Coding

项目概述

Canvas-Coding 是一个面向软件工程的AI驱动可视化工作流设计工具。通过拖拽节点和连线直观地构建项目架构,并借助 AI 智能体自动生成完整的工作流节点图。

核心价值:将软件项目设计过程可视化,让 AI 理解已有的项目结构上下文,进行增量编辑,而非每次从零开始。


技术架构

code
┌─────────────────────────────────────────────────┐
│                  apps/web (Next.js 16)            │
│  ┌─────────┐  ┌──────────┐  ┌──────────────┐   │
│  │  Canvas  │  │ AiSidebar│  │ PropertyPanel│   │
│  │(React   │  │ (AI交互)  │  │ (属性编辑)    │   │
│  │ Flow)   │  │          │  │              │   │
│  └────┬────┘  └────┬─────┘  └──────┬───────┘   │
│       │            │               │            │
│  ┌────┴────────────┴───────────────┴──────┐    │
│  │            lib/ (核心层)                │    │
│  │  model-provider │ dag │ auth │ prisma   │    │
│  └────┬────────────┬──────────────────────┘    │
│       │            │                            │
│  ┌────┴────┐  ┌────┴─────┐                     │
│  │ Prisma  │  │ AI SDK v6│                     │
│  │(MySQL)  │  │(多Provider)│                    │
│  └─────────┘  └──────────┘                     │
├─────────────────────────────────────────────────┤
│                  mastra/ (Agent 后端)            │
│            AI Agent 编排 & 任务调度              │
├─────────────────────────────────────────────────┤
│             packages/ (共享模块)                 │
│       engine/ (工作流引擎)  shared/ (类型)       │
└─────────────────────────────────────────────────┘

核心功能

1. React Flow 画布引擎

基于 @xyflow/react v12,提供无限画布能力:

tsx
// Canvas.tsx 核心结构
import { ReactFlow, Background, Controls, MiniMap } from '@xyflow/react'

export function Canvas({ workflowId, initialNodes, initialEdges }) {
  return (
    <ReactFlow
      nodes={nodes}
      edges={edges}
      nodeTypes={nodeTypes}  // 11种自定义节点
      onNodesChange={onNodesChange}
      onEdgesChange={onEdgesChange}
      onConnect={onConnect}
      fitView
    >
      <Background />
      <Controls />
      <MiniMap />
    </ReactFlow>
  )
}

2. 11 种节点类型

每个节点都封装了特定的软件工程语义:

类型用途关键配置
project项目信息项目名、语言、框架、描述
module功能模块模块名、接口签名
data-model数据模型字段定义(名称/类型/描述)
apiAPI 端点方法、路径、请求/响应体
generate代码生成描述、代码风格、文件路径模板
test测试策略测试框架、覆盖率目标
validate质量约束lint/type-safety/performance/security
env环境配置环境变量键值对
condition条件分支表达式、分支A/B
example代码示例代码片段、语言、标题
output输出配置格式、模板映射
tsx
// DataModelNode.tsx 示例
export function DataModelNode({ data }: NodeProps) {
  const config = data.config || {}
  return (
    <div className="p-3 bg-purple-50 border-2 border-purple-400 rounded-lg">
      <NodeHeader icon={Database} label={data.label} type="data-model" />
      <div className="mt-2 text-xs">
        {config.fields?.map((field, i) => (
          <div key={i} className="flex gap-2">
            <span className="font-mono">{field.name}</span>
            <span className="text-gray-500">{field.type}</span>
          </div>
        ))}
      </div>
    </div>
  )
}

3. AI 自动生成节点图

上下文注入

AI 能"看到"画布的完整状态,包括所有节点 ID、类型和配置:

tsx
function buildContext(nodes: Node[], edges: Edge[]): string {
  if (nodes.length === 0) return '(空画布,从零开始构建)'
  
  let ctx = `当前画布已有 ${nodes.length} 个节点 + ${edges.length} 条连线
`
  
  // 按类型统计
  ctx += '节点类型分布:
'
  for (const [type, count] of Object.entries(typeCount)) {
    ctx += `  - ${type}: ${count} 个
`
  }
  
  // 完整节点列表(含 ID,供 AI 复用)
  for (const n of nodes) {
    ctx += `  - id:${n.id} type:${n.type} label:"${n.data?.label}"
`
  }
  
  return ctx
}

增量编辑策略

关键设计:保留旧节点复用,而非每次重建。AI 返回的节点列表中,如果 id 匹配已有节点则原地更新,否则新增。如果某个已有节点不在返回列表中则删除。

正在渲染图表...

SSE 流式生成

节点逐个出现在画布上,实时反馈给用户:

tsx
const response = await fetch(`/api/workflows/${workflowId}/auto-layout`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ prompt, existingNodes, existingEdges })
})

// SSE 流式读取
const reader = response.body.getReader()
const decoder = new TextDecoder()

while (true) {
  const { done, value } = await reader.read()
  if (done) break
  const chunk = decoder.decode(value)
  const data = JSON.parse(chunk.replace('data: ', ''))
  // 增量更新画布
  setNodes(prev => mergeNodes(prev, data.nodes))
  setEdges(prev => mergeEdges(prev, data.edges))
}

4. 多 Provider 统一接入

通过 model-provider.ts 统一封装 Vercel AI SDK,支持多种 AI 平台:

ts
// 自动检测模型厂商
export function detectProvider(model: string): Provider {
  const lower = model.toLowerCase()
  if (lower.startsWith("claude-")) return "anthropic"
  if (lower.startsWith("gemini-")) return "google"
  return "openai"  // 默认兼容 OpenAI 格式
}

// 统一创建模型实例
export function createModel(options: ModelOptions): LanguageModel {
  switch (detectProvider(options.model)) {
    case "anthropic":
      return createAnthropic({ apiKey: options.anthropicKey })(options.model)
    case "google":
      return createGoogleGenerativeAI({ apiKey: options.googleKey })(options.model)
    default:
      return createOpenAI({
        apiKey: options.openaiKey,
        baseURL: options.openaiBaseUrl
      })(options.model)
  }
}

支持平台:OpenAI / DeepSeek / Anthropic Claude / Google Gemini / 自定义 OpenAI 兼容平台


5. DAG 依赖分析

使用 DFS 三色标记法 检测循环依赖:

ts
export function hasCycle(nodes: Node[], edges: Edge[]): boolean {
  const adj = new Map<string, string[]>()
  for (const e of edges) {
    const list = adj.get(e.source) ?? []
    list.push(e.target)
    adj.set(e.source, list)
  }

  const WHITE = 0, GRAY = 1, BLACK = 2
  const color = new Map(nodes.map(n => [n.id, WHITE]))

  function dfs(u: string): boolean {
    color.set(u, GRAY)
    for (const v of adj.get(u) ?? []) {
      if (color.get(v) === GRAY) return true    // 发现环
      if (color.get(v) === WHITE && dfs(v)) return true
    }
    color.set(u, BLACK)
    return false
  }

  return nodes.some(n => color.get(n.id) === WHITE && dfs(n.id))
}

6. AI Agent 系统

基于 Mastra 框架编排 AI 工作流:

  • 创建和管理自定义 Agent
  • 绑定到特定节点类型
  • 独立配置 System Prompt
code
mastra/
├── agents/          # Agent 定义
├── workflows/       # 工作流编排
└── tools/           # Agent 工具

项目结构

code
CanvasCoding/
├── apps/web/                    # 主应用 (Next.js 16)
│   ├── app/
│   │   ├── (auth)/              # 登录/注册
│   │   ├── api/
│   │   │   ├── agents/           # Agent CRUD
│   │   │   ├── auth/             # NextAuth
│   │   │   └── workflows/
│   │   │       ├── [id]/auto-layout/  # AI 生成
│   │   │       └── [id]/generate/     # Prompt 批量生成
│   │   ├── dashboard/           # 仪表板
│   │   └── workflows/[id]/      # 工作流编辑器
│   └── src/
│       ├── components/flow/     # 画布核心
│       │   ├── AiSidebar.tsx     # AI 交互侧边栏
│       │   ├── Canvas.tsx        # 画布入口
│       │   ├── Toolbox.tsx       # 工具箱
│       │   ├── PropertyPanel.tsx # 属性面板
│       │   └── nodes/           # 11 种自定义节点
│       └── lib/
│           ├── model-provider.ts # 多 Provider 统一接入
│           ├── dag.ts            # 循环依赖检测
│           └── utils.ts          # 工具函数
├── mastra/                       # AI Agent 编排
├── packages/
│   ├── engine/                   # 工作流引擎
│   ├── shared/                   # 共享类型定义
│   └── ui/                       # 共享 UI 组件
└── prisma/
    └── schema.prisma             # 数据库 Schema

技术栈

层级技术
框架Next.js 16 + React 19 + TypeScript
画布React Flow (@xyflow/react v12)
UIshadcn/ui + TailwindCSS 4
认证NextAuth.js v4 + bcryptjs
数据库Prisma 7 + MySQL (MariaDB)
AI SDKVercel AI SDK v6 (OpenAI / Anthropic / Google)
AI 编排Mastra v1
包管理pnpm workspace (monorepo)

用户系统

  • NextAuth.js + bcrypt 邮箱密码认证
  • 数据隔离:每个用户独立的工作流和 Agent 数据
  • 软删除:工作流支持软删除和恢复

总结

Canvas-Coding 展示了一个完整的 AI + 可视化编辑器 应用范式:

  1. 可视化:React Flow 无限画布,拖拽式节点连接
  2. AI 上下文理解:提取画布状态,增量编辑而非全量重建
  3. 流式反馈:SSE 实时推送,节点逐个出现
  4. 多模型支持:统一 Provider 抽象,一套代码适配所有 AI 平台
  5. 循环依赖检测:DFS 三色标记法,确保工作流可执行
  6. Agent 系统:Mastra 编排 AI 工作流,支持自定义 Agent