Next AI Draw.io 架构设计分析
1. 项目概述
Next AI Draw.io 是一个 AI 驱动的图表创建工具,通过自然语言命令和 AI 辅助可视化来创建、修改和增强 draw.io 图表。
核心特性
- LLM 驱动的图表创建:利用大语言模型通过自然语言直接创建和操作 draw.io 图表
- 基于图像的图表复制:上传现有图表或图像,让 AI 自动复制和增强
- PDF 和文本文件上传:上传 PDF 文档和文本文件以提取内容并生成图表
- AI 推理显示:查看支持模型的 AI 思考过程(OpenAI o1/o3、Gemini、Claude 等)
- 图表历史记录:全面的版本控制,跟踪所有更改
- 交互式聊天界面:与 AI 实时交流以完善图表
- 云架构图表支持:专门支持生成云架构图表(AWS、GCP、Azure)
- 动画连接器:创建动态和动画化的图表元素连接器
技术栈
- 框架:Next.js 16.x + React 19.x
- AI SDK:Vercel AI SDK (
ai+@ai-sdk/*) - 图表渲染:react-drawio
- 样式:Tailwind CSS 4.x
- UI 组件:Radix UI + shadcn/ui
- 多语言支持:i18n
- 桌面应用:Electron
- 部署:Vercel / Cloudflare Workers / EdgeOne Pages
2. 整体架构
graph TB
User[用户] --> Browser[浏览器 / 桌面应用]
Browser --> UI[React 前端 UI]
UI --> Chat[聊天界面]
UI --> DrawIO[Draw.io 编辑器]
UI --> Settings[设置面板]
Chat --> API[Next.js API Routes]
Settings --> API
API --> ChatAPI[api/chat<br/>核心对话接口]
API --> ConfigAPI[api/config<br/>配置接口]
API --> ValidateAPI[api/validate-diagram<br/>图表验证]
API --> ValidateModelAPI[api/validate-model<br/>模型验证]
API --> LogAPI[api/log-*<br/>日志反馈]
API --> ParseURLAPI[api/parse-url<br/>URL 解析]
API --> ServerModelsAPI[api/server-models<br/>服务端模型]
ChatAPI --> AIProviders[AI 提供商层<br/>lib/ai-providers.ts]
ChatAPI --> SystemPrompts[系统提示词<br/>lib/system-prompts.ts]
ChatAPI --> Cache[响应缓存<br/>lib/cached-responses.ts]
ChatAPI --> Quota[配额管理<br/>lib/dynamo-quota-manager.ts]
ChatAPI --> Langfuse[Langfuse 追踪<br/>lib/langfuse.ts]
AIProviders --> VercelAI[Vercel AI SDK]
VercelAI --> OpenAI[OpenAI]
VercelAI --> Anthropic[Anthropic]
VercelAI --> Google[Google AI]
VercelAI --> Bedrock[AWS Bedrock]
VercelAI --> DeepSeek[DeepSeek]
VercelAI --> Others[其他 10+ 提供商]
UI --> LocalStorage[本地存储<br/>IndexedDB]
UI --> SessionStorage[会话存储<br/>lib/session-storage.ts]
style AIProviders fill:#90EE90
style SystemPrompts fill:#FFD700
style VercelAI fill:#87CEEB
3. 项目结构
next-ai-draw-io/
├── app/ # Next.js App Router
│ ├── [lang]/ # 多语言路由
│ ├── api/ # API 路由
│ │ ├── chat/route.ts # 核心聊天 API(34KB)
│ │ ├── config/ # 配置 API
│ │ ├── validate-diagram/ # 图表验证 API
│ │ ├── validate-model/ # 模型验证 API
│ │ ├── log-feedback/ # 日志反馈 API
│ │ ├── log-save/ # 日志保存 API
│ │ ├── parse-url/ # URL 解析 API
│ │ ├── server-models/ # 服务端模型 API
│ │ └── verify-access-code/ # 访问码验证 API
│ ├── globals.css # 全局样式
│ ├── manifest.ts # PWA manifest
│ ├── robots.ts # SEO robots
│ └── sitemap.ts # SEO sitemap
│
├── components/ # React 组件
├── contexts/ # React Context
├── hooks/ # React Hooks
│
├── lib/ # 核心库(业务逻辑)
│ ├── ai-providers.ts # AI 提供商配置(52KB)
│ ├── system-prompts.ts # 系统提示词(20KB)
│ ├── cached-responses.ts # 响应缓存(56KB)
│ ├── dynamo-quota-manager.ts # DynamoDB 配额管理
│ ├── session-storage.ts # 会话存储
│ ├── server-model-config.ts # 服务端模型配置
│ ├── chat-helpers.ts # 聊天助手函数
│ ├── diagram-validator.ts # 图表验证器
│ ├── pdf-utils.ts # PDF 工具
│ ├── url-utils.ts # URL 工具
│ ├── validation-schema.ts # 验证模式
│ ├── validation-prompts.ts # 验证提示词
│ ├── utils.ts # 工具函数(64KB)
│ ├── storage.ts # 存储抽象
│ ├── ssrf-protection.ts # SSRF 防护
│ ├── langfuse.ts # Langfuse 集成
│ ├── use-file-processor.tsx # 文件处理 Hook
│ ├── use-quota-manager.tsx # 配额管理 Hook
│ ├── user-id.ts # 用户 ID 生成
│ ├── base-path.ts # 基础路径
│ └── i18n/ # 国际化
│ └── types/
│
├── packages/ # Monorepo 包
│ └── mcp-server/ # MCP 服务器
│
├── electron/ # Electron 桌面应用
│ ├── main/ # 主进程
│ ├── preload/ # 预加载脚本
│ └── electron-builder.yml # 构建配置
│
├── edge-functions/ # Edge Functions
├── resources/ # 资源文件
├── scripts/ # 构建脚本
├── tests/ # 测试
│
├── public/ # 静态资源
├── docs/ # 文档
│
├── package.json # 项目配置
├── tsconfig.json # TypeScript 配置
├── next.config.ts # Next.js 配置
├── tailwind.config.ts # Tailwind 配置
├── biome.json # Biome 代码规范
├── vercel.json # Vercel 部署配置
├── wrangler.jsonc # Cloudflare Workers 配置
├── docker-compose.yml # Docker Compose
└── Dockerfile # Docker 配置
4. 核心模块详解
4.1 核心聊天 API - app/api/chat/route.ts
这是整个应用的核心入口,处理用户与 AI 的所有交互。
关键功能:
- 访问码验证
- 用户配额检查
- 文件验证
- 缓存响应检查
- AI 模型选择和配置
- 工具调用处理
- 流式响应生成
核心流程代码:
// 核心函数签名
async function handleChatRequest(req: Request): Promise<Response>
// 主要步骤:
// 1. 访问码验证
// 2. 用户 ID 获取(用于 Langfuse 追踪和配额)
// 3. 配额检查(DynamoDB)
// 4. 文件验证
// 5. 缓存检查
// 6. AI 提供商和模型选择
// 7. 系统提示词构建
// 8. 工具定义
// 9. streamText() 调用
// 10. 响应流式返回
关键工具定义:
// 4 个核心工具
const tools = {
display_diagram: tool({
description: "Display a NEW diagram on draw.io",
parameters: z.object({
xml: z.string(),
}),
}),
edit_diagram: tool({
description: "Edit specific parts of the EXISTING diagram",
parameters: z.object({
edits: z.array(z.object({
search: z.string(),
replace: z.string(),
})),
}),
}),
append_diagram: tool({
description: "Continue generating diagram XML when truncated",
parameters: z.object({
xml: z.string(),
}),
}),
get_shape_library: tool({
description: "Get shape/icon library documentation",
parameters: z.object({
library: z.string(),
}),
}),
}
4.2 AI 提供商层 - lib/ai-providers.ts
支持 15+ 个 AI 提供商的统一抽象层。
支持的提供商:
- OpenAI
- Anthropic
- Google AI
- Google Vertex AI
- Azure OpenAI
- AWS Bedrock
- DeepSeek
- OpenRouter
- Ollama
- SiliconFlow
- ModelScope
- SGLang
- Vercel AI Gateway
- ByteDance Doubao
- 更多…
核心代码结构:
// 客户端可选择的提供商
const ALLOWED_CLIENT_PROVIDERS: ProviderName[] = [
"openai", "anthropic", "google", "vertexai", "azure",
"bedrock", "openrouter", "deepseek", "siliconflow",
"sglang", "gateway", "edgeone", "ollama", "doubao",
"modelscope", "glm", "qwen", "qiniu", "kimi", "minimax",
// ... 更多
]
// 核心函数:获取 AI 模型
export async function getAIModel(options: ClientOverrides): Promise<ModelConfig> {
// 根据提供商类型创建对应的模型实例
// 处理 API Key、Base URL、Headers 等配置
}
// 单系统消息提供商(不支持多轮系统消息)
export const SINGLE_SYSTEM_PROVIDERS = new Set<ProviderName>([
"minimax", "glm", "qwen", "kimi", "qiniu",
])
// 图像输入支持检查
export function supportsImageInput(provider: ProviderName): boolean
// 提示词缓存支持检查
export function supportsPromptCaching(provider: ProviderName): boolean
提供商创建示例:
// OpenAI 提供商创建
const openaiProvider = createOpenAI({
apiKey: apiKey,
baseURL: baseUrl,
headers: headers,
})
// Anthropic 提供商创建
const anthropicProvider = createAnthropic({
apiKey: apiKey,
baseURL: baseUrl,
headers: headers,
})
// AWS Bedrock 提供商创建
const bedrockProvider = createAmazonBedrock({
region: awsRegion,
credentials: {
accessKeyId: awsAccessKeyId,
secretAccessKey: awsSecretAccessKey,
sessionToken: awsSessionToken,
},
})
4.3 系统提示词 - lib/system-prompts.ts
精心设计的系统提示词,指导 AI 如何生成和编辑 draw.io 图表。
提示词特点:
- 默认约 1900 tokens,适用于所有模型
- 支持扩展提示词(用于高缓存 token 模型)
- 详细的工具使用说明
- 布局约束规范
- draw.io XML 格式规范
核心提示词结构:
// 默认系统提示词
export const DEFAULT_SYSTEM_PROMPT = `
You are an expert diagram creation assistant specializing in draw.io XML generation.
Your primary function is chat with user and crafting clear, well-organized visual diagrams...
## App Context
You are an AI agent inside a web app. The interface has:
- Left panel: Draw.io diagram editor
- Right panel: Chat interface
## Tools
- display_diagram: Create NEW diagram
- edit_diagram: Edit EXISTING diagram
- append_diagram: Continue truncated XML
- get_shape_library: Get icon library
## Layout constraints
- Keep elements within x: 0-800, y: 0-600
- Max container width: 700px
## XML Best Practices
- Proper mxGraphModel structure
- mxCell with id, value, style, vertex/edge
- Correct parent/child relationships
- ...
`
// 扩展提示词(用于 Opus 等模型)
export const EXTENDED_SYSTEM_PROMPT = DEFAULT_SYSTEM_PROMPT + `
## Additional Guidelines for Advanced Models
...
`
// 系统提示词选择器
export function getSystemPrompt(options: {
modelId: string;
provider: ProviderName;
customSystemMessage?: string;
hasFiles?: boolean;
}): string {
// 根据模型和提供商选择合适的系统提示词
// 合并自定义系统消息
}
4.4 响应缓存 - lib/cached-responses.ts
为常见请求提供快速响应缓存。
缓存策略:
- 仅对第一条消息且空图时缓存
- 支持文本和文件输入的组合缓存
- 预设常见图表模板
缓存数据结构:
interface CachedResponse {
keywords: string[]; // 匹配关键词
hasFiles: boolean; // 是否有文件
xml: string; // 缓存的 XML
}
// 查找缓存响应
export function findCachedResponse(
userInput: string,
hasFiles: boolean
): CachedResponse | undefined {
// 关键词匹配
// 返回预定义的 XML 模板
}
4.5 配额管理 - lib/dynamo-quota-manager.ts
使用 DynamoDB 管理用户 API 配额。
配额维度:
- 每日请求数限制
- 每日 Token 数限制
- TPM(每分钟 Token)限制
核心功能:
// 检查并递增请求计数
export async function checkAndIncrementRequest(
userId: string,
limits: {
requests?: number;
tokens?: number;
tpm?: number;
}
): Promise<{
allowed: boolean;
error?: string;
type?: string;
used?: any;
limit?: any;
}>
// 记录 Token 使用量
export async function recordTokenUsage(
userId: string,
usage: { inputTokens: number; outputTokens: number }
)
// 配额是否启用
export function isQuotaEnabled(): boolean
5. 数据流
5.1 完整的聊天/图表生成数据流
sequenceDiagram
participant User as 用户
participant UI as React 前端
participant API as api/chat
participant Cache as 缓存检查
participant Quota as 配额检查
participant AI as AI 提供商
participant LLM as 大语言模型
participant Tools as 工具执行
participant DrawIO as Draw.io 编辑器
User->>UI: 输入自然语言指令
UI->>API: POST /api/chat {messages, xml, sessionId}
API->>API: 访问码验证
API->>Quota: 检查用户配额
Quota-->>API: 配额状态
alt 配额超限
API-->>UI: 429 Error
UI->>User: 显示配额超限提示
end
API->>Cache: 检查缓存响应
alt 缓存命中
Cache-->>API: 返回缓存 XML
API-->>UI: 流式响应(缓存)
UI->>DrawIO: 渲染图表
DrawIO->>User: 显示图表
end
API->>AI: 配置 AI 模型
API->>API: 构建系统提示词
API->>API: 定义工具(display_diagram 等)
API->>LLM: streamText() 调用
LLM->>LLM: 生成响应
alt 决定使用工具
LLM-->>API: 工具调用请求
API->>Tools: 执行工具
Tools-->>API: 工具结果
API->>LLM: 发送工具结果
LLM->>LLM: 继续生成
end
LLM-->>API: 流式响应
API-->>UI: SSE 流式响应
UI->>UI: useChat() 更新状态
UI->>DrawIO: 更新图表 XML
DrawIO->>User: 实时显示图表更新
UI->>User: 显示 AI 消息
5.2 工具调用详细流程
graph TB
A[接收用户消息] --> B{是否为空图且首条消息?}
B -->|是| C[检查缓存]
C -->|命中| D[返回缓存响应]
C -->|未命中| E[继续]
B -->|否| E
E --> F[选择 AI 提供商和模型]
F --> G[构建系统提示词]
G --> H[定义 4 个工具]
H --> I[调用 streamText]
I --> J{LLM 响应类型}
J -->|文本| K[直接显示文本]
J -->|display_diagram| L[渲染新图表]
J -->|edit_diagram| M[执行搜索替换]
J -->|append_diagram| N[追加 XML 片段]
J -->|get_shape_library| O[返回图标库文档]
L --> P[更新 Draw.io 编辑器]
M --> P
N --> P
P --> Q[保存历史版本]
Q --> R[完成]
6. 关键设计模式
6.1 策略模式 - AI 提供商选择
根据不同的提供商类型使用不同的创建策略:
async function getAIModel(options: ClientOverrides): Promise<ModelConfig> {
switch (options.provider) {
case "openai":
return createOpenAIModel(options)
case "anthropic":
return createAnthropicModel(options)
case "bedrock":
return createBedrockModel(options)
// ... 15+ 个提供商
}
}
6.2 工具模式 - 4 个核心工具
使用 Vercel AI SDK 的工具定义模式:
const tools = {
display_diagram: tool({
description: "...",
parameters: z.object({ xml: z.string() }),
execute: async ({ xml }) => { /* 执行 */ },
}),
edit_diagram: tool({ /* ... */ }),
append_diagram: tool({ /* ... */ }),
get_shape_library: tool({ /* ... */ }),
}
6.3 缓存模式 - 响应缓存
使用简单的关键词匹配缓存:
const CACHED_RESPONSES: CachedResponse[] = [
{
keywords: ["aws architecture", "aws diagram"],
hasFiles: false,
xml: PREDEFINED_AWS_XML,
},
// ... 更多缓存
]
6.4 适配器模式 - 多提供商适配
为每个 AI 提供商创建适配器:
// OpenAI 适配器
function createOpenAIModel(options) {
const provider = createOpenAI({ apiKey: options.apiKey })
return { model: provider(options.modelId) }
}
// Anthropic 适配器
function createAnthropicModel(options) {
const provider = createAnthropic({ apiKey: options.apiKey })
return { model: provider(options.modelId) }
}
7. 扩展性设计
7.1 添加新的 AI 提供商
- 在
lib/ai-providers.ts中添加提供商类型 - 创建提供商适配器函数
- 添加到
ALLOWED_CLIENT_PROVIDERS列表 - 更新
getAIModel()函数
7.2 添加新的工具
- 在系统提示词中添加工具描述
- 在
app/api/chat/route.ts中定义工具 - 实现工具的
execute函数 - 更新前端处理逻辑
7.3 添加新的图标库
- 准备图标库的 XML 定义
- 在
get_shape_library工具中添加库文档 - 更新系统提示词中的使用说明
8. 关键技术决策
8.1 为什么选择 Vercel AI SDK?
- 统一提供商抽象:15+ 提供商一个 API
- 流式响应原生支持:开箱即用的 SSE 流式
- 工具调用框架:完善的工具定义和执行
- TypeScript 优先:完整的类型安全
- 活跃维护:Vercel 官方支持
8.2 为什么使用 4 个工具而不是 1 个?
- display_diagram:全新创建,完整 XML
- edit_diagram:局部修改,搜索替换(高效)
- append_diagram:处理输出截断
- get_shape_library:图标库探索
优势:
- 更精细的控制
- 更好的 Token 效率
- 减少错误概率
8.3 为什么需要缓存?
- 常见请求快速响应:AWS/Azure/GCP 架构图
- 降低 API 成本:避免重复生成相同内容
- 提升用户体验:毫秒级响应
8.4 为什么使用 DynamoDB 配额管理?
- 无服务器:无需管理基础设施
- 自动扩展:应对流量波动
- 低成本:按使用付费
- TTL 支持:自动过期旧数据
9. 安全考虑
9.1 SSRF 防护
// lib/ssrf-protection.ts
export function isSSRFProtected(url: string): boolean {
// 检查内网 IP
// 检查私有地址
// 白名单域名
}
9.2 访问码验证
// 支持多个访问码
const accessCodes = process.env.ACCESS_CODE_LIST?.split(",")
if (accessCodes.length > 0) {
const accessCodeHeader = req.headers.get("x-access-code")
if (!accessCodes.includes(accessCodeHeader)) {
return 401 Error
}
}
9.3 API Key 安全
- 客户端 API Key 仅存储在浏览器本地
- 服务端 API Key 通过环境变量配置
- 支持自定义环境变量名
- 支持负载均衡(多个 API Key)
10. 部署架构
10.1 多平台部署支持
graph TB
Code[代码仓库] --> Vercel[Vercel 部署]
Code --> Cloudflare[Cloudflare Workers]
Code --> EdgeOne[EdgeOne Pages]
Code --> Docker[Docker 容器]
Code --> Electron[Electron 桌面应用]
Vercel --> User1[用户]
Cloudflare --> User2[用户]
EdgeOne --> User3[用户]
Docker --> User4[用户]
Electron --> User5[用户]
style Vercel fill:#909000
style Cloudflare fill:#F38020
style EdgeOne fill:#00A4FF
style Docker fill:#2496ED
style Electron fill:#47848F
10.2 环境变量配置
关键环境变量(见 env.example):
# AI 提供商配置
OPENAI_API_KEY=
ANTHROPIC_API_KEY=
AWS_BEDROCK_REGION=
# 配额管理
DYNAMODB_QUOTA_TABLE=
DAILY_REQUEST_LIMIT=10
DAILY_TOKEN_LIMIT=200000
# Langfuse 追踪
LANGFUSE_SECRET_KEY=
LANGFUSE_PUBLIC_KEY=
LANGFUSE_BASE_URL=
# 访问控制
ACCESS_CODE_LIST=code1,code2
# 服务端模型配置
AI_MODELS_CONFIG='[{"id":"server:model1",...}]'
11. 总结
架构亮点
- 清晰的分层:前端 → API → AI 提供商 → LLM
- 高度可扩展:15+ AI 提供商,易于添加新的
- 完善的工具系统:4 个核心工具覆盖所有用例
- 企业级特性:配额管理、访问控制、缓存、追踪
- 多平台部署:Vercel、Cloudflare、EdgeOne、Docker、Electron
- 优秀的用户体验:流式响应、历史记录、多语言
技术栈优势
- Next.js 16:最新的 App Router,Server Components
- Vercel AI SDK:统一的 AI 抽象,流式响应
- React 19:最新的 React 特性
- Tailwind CSS 4:高性能样式系统
- TypeScript:完整的类型安全
- Electron:跨平台桌面应用
值得学习的设计
- 工具优先的交互模式:让 AI 使用工具而不是直接输出
- 精心设计的系统提示词:1900+ tokens 的详细指导
- 多层次的缓存策略:响应缓存 + 提示词缓存
- 灵活的配额管理:多维度的使用限制
- 完善的可观测性:Langfuse 集成
这个项目展示了如何构建一个生产级的 AI 驱动应用,架构清晰、功能完整、用户体验优秀!