1. 项目概述当自然语言遇见架构图最近在折腾一个挺有意思的东西一个能把你说的话直接变成技术架构图的AI智能体。听起来有点科幻对吧但实际做下来发现核心逻辑并没有想象中那么遥不可及。简单来说这个项目的目标就是让产品经理、业务方甚至是不太懂技术的同事能用最自然的方式描述他们想要的系统样子比如“我要一个用户登录后能看到个人仪表盘数据从MySQL读用Redis缓存热点通过Kafka异步处理日志”然后AI就能理解这句话并自动生成一张清晰、标准的架构图。这背后解决的痛点非常实际。在技术方案评审、新项目启动或者向非技术伙伴解释系统设计时画架构图是个高频且费时费力的活。工具从Visio、Draw.io到Lucidchart虽然强大但都得手动拖拽、连线、调整样式。更头疼的是当讨论中方案有调整图就得重画或大改沟通成本很高。我这个项目的初衷就是想用AI作为“翻译官”和“绘图员”把人类模糊的、非结构化的语言转化为精确的、结构化的图形表达让创意和设计的流转更顺畅。这个智能体适合任何需要频繁进行技术设计、方案沟通或知识沉淀的开发者、架构师和技术负责人。即使你只是对AI应用开发感兴趣想了解如何串联大语言模型LLM、知识库和绘图引擎这个项目也是一个很好的练手案例。接下来我会详细拆解我是如何一步步把它构建出来的从核心思路到技术选型从Prompt工程到前后端集成并分享其中踩过的坑和总结的经验。2. 核心思路与系统设计拆解2.1 从语言到图形的核心挑战要实现“说话成图”我们需要解决几个核心的转化问题。首先自然语言是模糊且充满歧义的。比如“服务器”这个词可能指物理机、虚拟机、一个K8s Pod或者一个云函数。其次架构图有自己严格的语法和语义组件类型数据库、队列、服务、组件之间的关系数据流、调用依赖、分组和层级都需要被明确定义。最后生成的图形不仅要“对”符合语义还要“好”布局美观、符合制图规范。因此整个系统的设计思路遵循一个清晰的管道Pipeline模式理解 - 结构化 - 渲染。这不是一个端到端的黑箱模型而是一个由多个专门化模块组成的协作系统。我的设计原则是“让专业的模块做专业的事”用大语言模型LLM做它最擅长的语言理解和逻辑推理用专门的规则引擎或图数据库来处理结构化关系用成熟的图形库来负责最终的视觉呈现。这样的解耦设计使得每个环节都可以独立优化、调试和替换。2.2 技术栈选型与架构设计基于上述思路我选择了以下技术栈来搭建这个AI智能体语言理解与推理层大脑OpenAI GPT-4 API。我尝试过Claude和国内的一些大模型但GPT-4在遵循复杂指令、进行多步推理以及输出结构化JSON方面目前表现最为稳定可靠。它是整个系统的“大脑”负责将自然语言“翻译”成机器可理解的设计意图。结构化中间表示层骨架自定义的架构描述语言ADL Schema。这是项目的关键创新点之一。我并没有让LLM直接输出图形指令而是定义了一套简化的JSON Schema用来描述架构元素。这个Schema定义了核心对象比如Component(组件)、Relationship(关系)、Layer(分层) 等每个对象都有type,name,properties等字段。LLM的任务就是将自然语言映射到这个Schema上。这样做的好处是将易变的自然语言与后端的渲染逻辑解耦无论前端说什么我们首先得到的是一个标准化的、可供程序处理的数据结构。图形渲染层画笔Mermaid.js。选择Mermaid的原因很简单它可以通过文本定义来生成图表完美契合我们“从结构化数据到图形”的流程。我们只需要将上一步得到的JSON Schema通过一个转换器Transformer转换成Mermaid语法例如graph TD流程图或C4Context图Mermaid就能在浏览器或Node.js环境中渲染出SVG或PNG图片。它支持多种图表类型社区活跃完全开源。智能体编排与后端LangChain FastAPI。LangChain框架极大地简化了与LLM的交互、Prompt模板的管理以及复杂链Chain的构建。我用它来组装整个处理流程。FastAPI则提供了高性能、易于编写API的后端服务负责接收用户请求调用LangChain处理链并返回最终的图片或图表代码。前端交互Streamlit。为了快速构建一个可交互的演示界面我选择了Streamlit。它可以用纯Python快速创建Web应用非常适合原型演示。界面包含一个文本输入框、一个生成按钮和一个显示图片的区域。整个系统的数据流如下图所示此处以文字描述用户在前端输入自然语言描述 - FastAPI后端接收 - LangChain调用GPT-4 API结合预设的Prompt和Schema进行推理 - GPT-4返回符合Schema的JSON - 后端的转换器将JSON转换为Mermaid代码 - 调用Mermaid渲染引擎生成图片 - 图片数据流返回前端展示。注意这里的关键是“中间表示层”JSON Schema的设计。它直接决定了AI理解的“世界观”和最终成图的质量。Schema不能太复杂否则LLM难以准确填充也不能太简单否则无法表达丰富的架构概念。我花了大量时间在迭代这个Schema上。3. 核心模块实现细节3.1 定义架构描述语言ADLSchema这是整个项目的基石。我的设计目标是足够表达常见的架构概念同时保持简洁。以下是我定义的v1版本的核心部分以Python Pydantic模型为例from pydantic import BaseModel, Field from typing import List, Optional, Literal class Component(BaseModel): id: str Field(..., description组件唯一标识符如 user_service) name: str Field(..., description组件显示名称如 用户服务) type: Literal[service, database, queue, cache, api_gateway, load_balancer, function, storage, external] Field(..., description组件类型) technology: Optional[str] Field(None, description具体技术如 MySQL, Redis, Kafka) layer: Optional[str] Field(None, description所属层级如 Presentation, Application, Data) properties: Optional[dict] Field(default_factorydict, description扩展属性) class Relationship(BaseModel): source: str Field(..., description关系发起方组件ID) target: str Field(..., description关系接收方组件ID) type: Literal[http_request, database_query, publish, subscribe, async_call, sync_call] Field(..., description关系类型) description: Optional[str] Field(None, description关系描述如 读取用户数据) class ArchitectureDiagram(BaseModel): components: List[Component] Field(..., description架构中的所有组件) relationships: List[Relationship] Field(..., description组件之间的关系) title: str Field(系统架构图, description图表标题) notation: Literal[c4, flowchart] Field(flowchart, description使用的图示法)这个Schema明确告诉LLM一个架构图由若干组件和关系构成组件有类型和技术栈关系有方向和类型。notation字段可以控制最终用C4模型图还是普通流程图来渲染。3.2 构建高效的Prompt工程有了Schema下一步就是教会LLM如何使用它。Prompt的设计至关重要。我的Prompt结构如下角色设定明确告诉AI它扮演一个“资深系统架构师”。核心任务清晰说明需要将自然语言描述转化为指定的JSON格式。格式约束直接给出上面定义的Pydantic模型的JSON Schema定义要求AI严格按此输出。规则与示例提供详细的规则如“如果用户提到‘数据库’默认类型为database技术栈可推断为MySQL”和1-2个完整的输入输出示例Few-shot Learning。用户输入最后附上用户的自然语言描述。一个简化版的Prompt示例你是一个专业的系统架构师擅长将模糊的业务需求转化为清晰的技术架构描述。 你的任务是将用户用自然语言描述的系统架构转换成一个结构化的JSON数据模型。该模型必须严格遵守以下JSON Schema定义 {schema_definition} 请遵循以下规则 1. 从描述中识别出所有独立的组件如服务、数据库、消息队列等。 2. 为每个组件分配一个唯一的、简洁的英文id如auth_service。 3. 推断组件间的关系明确source和target。 4. 如果用户未明确指定技术可根据上下文进行合理推断如“数据库”可推断为“MySQL”“缓存”可推断为“Redis”。 示例 用户输入“一个Web应用通过API网关访问用户服务用户服务会查询MySQL数据库。” 输出 { components: [ {id: web_app, name: Web应用, type: service}, {id: api_gateway, name: API网关, type: api_gateway}, {id: user_service, name: 用户服务, type: service}, {id: mysql_db, name: 用户数据库, type: database, technology: MySQL} ], relationships: [ {source: web_app, target: api_gateway, type: http_request}, {source: api_gateway, target: user_service, type: http_request}, {source: user_service, target: mysql_db, type: database_query} ], title: 示例架构, notation: flowchart } 现在请处理以下用户输入 用户输入{user_input}实操心得在Prompt中提供示例Few-shot的效果远好于只给指令Zero-shot。示例能更直观地展示“边界情况”如何处理比如如何命名id如何推断未明确的技术。同时要求LLM输出JSON时明确指定“不要包含任何解释性文字只输出JSON对象”可以避免后续解析的麻烦。3.3 实现JSON到Mermaid的转换器得到标准化的JSON数据后我们需要一个转换器将其变成Mermaid代码。这个转换器本质上是一个模板渲染器根据notation字段选择不同的模板。对于flowchart流程图 notation转换逻辑相对直接def convert_to_mermaid_flowchart(diagram: ArchitectureDiagram) - str: lines [graph TD] # 添加组件节点可以按类型进行样式映射 for comp in diagram.components: node_style get_style(comp.type) # 根据类型映射形状如数据库为圆柱形 lines.append(f {comp.id}[{comp.name}]::{node_style}) # 添加关系连线 for rel in diagram.relationships: arrow get_arrow(rel.type) # 根据关系类型映射箭头如--表示HTTP-.-表示异步 lines.append(f {rel.source} {arrow} {rel.target}) return \n.join(lines)对于更专业的c4notation我利用了Mermaid对C4模型的支持需要引入C4插件。转换时需要将我们的通用组件类型映射到C4的特定元素Person, System, Container, Component等并设置合理的标签和技术栈信息。注意事项Mermaid的C4语法有一定限制对布局的控制力较弱。如果对图形美观度要求极高可以考虑将JSON转换为Draw.io的XML格式但这会复杂很多。在易用性和表现力之间我优先选择了Mermaid。3.4 集成LangChain构建处理链使用LangChain可以优雅地将上述步骤串联起来。我构建了一个LLMChain其核心是ChatPromptTemplate里面包含了我们精心设计的Prompt。然后使用PydanticOutputParser来强制LLM的输出符合我们的ArchitectureDiagram模型这能极大地提高输出格式的稳定性。from langchain.chains import LLMChain from langchain.prompts import ChatPromptTemplate from langchain.output_parsers import PydanticOutputParser from langchain.chat_models import ChatOpenAI # 初始化模型和解析器 llm ChatOpenAI(modelgpt-4, temperature0.1) # temperature调低保证输出稳定性 parser PydanticOutputParser(pydantic_objectArchitectureDiagram) # 构建Prompt模板将格式指令和schema动态注入 prompt_template ChatPromptTemplate.from_template(...) # 此处填入完整的Prompt模板字符串 # 创建处理链 chain LLMChain(llmllm, promptprompt_template, output_parserparser) # 运行链 user_input 一个微服务架构订单服务调用支付服务两者都读写同一个PostgreSQL数据库并用Redis缓存商品信息。 result chain.run(user_input) # result 已是一个ArchitectureDiagram实例这样我们通过一个chain.run()调用就完成了从自然语言到结构化数据的全过程。4. 前后端搭建与部署实践4.1 使用FastAPI构建高效后端后端API的设计很简单主要两个端点POST /generate_diagram: 接收自然语言描述返回生成的图片Base64编码或Mermaid代码。POST /generate_schema: 接收自然语言描述返回结构化的JSON Schema用于调试。核心的生成视图函数如下from fastapi import FastAPI, HTTPException from pydantic import BaseModel import base64 from io import BytesIO app FastAPI(titleArchitecture Diagram AI Agent) class DiagramRequest(BaseModel): description: str notation: str flowchart output_format: str png # 支持 png, svg, mermaid app.post(/generate) async def generate_diagram(request: DiagramRequest): try: # 1. 调用LangChain链生成ArchitectureDiagram对象 diagram: ArchitectureDiagram chain.run(request.description) # 2. 根据notation将diagram对象转换为Mermaid代码 mermaid_code converter.convert(diagram, request.notation) # 3. 根据output_format渲染图形 if request.output_format in [png, svg]: # 使用mermaid-cli或pyppeteer等库在服务端渲染 img_bytes render_mermaid_to_image(mermaid_code, request.output_format) img_b64 base64.b64encode(img_bytes).decode(utf-8) return {image: fdata:image/{request.output_format};base64,{img_b64}} else: return {mermaid_code: mermaid_code} except Exception as e: raise HTTPException(status_code500, detailf生成失败: {str(e)})踩坑记录服务端渲染Mermaid图是一个挑战。最初我尝试用mermaid-cliPuppeteer驱动但在Docker容器中部署时遇到了Chromium依赖和字体问题。后来我转向了pyppeteerPython版的Puppeteer通过启动一个无头浏览器来渲染虽然速度稍慢但兼容性更好。对于生产环境可以考虑预启动一个浏览器实例池来优化性能。4.2 快速构建交互式前端StreamlitStreamlit让前端开发变得极其简单一个Python脚本搞定import streamlit as st import requests import base64 st.set_page_config(page_titleAI架构图生成器, layoutwide) st.title( 用自然语言描述生成你的系统架构图) api_url http://localhost:8000/generate # 后端API地址 with st.sidebar: st.header(设置) notation st.selectbox(图示法, [flowchart, c4]) output_format st.selectbox(输出格式, [png, svg, mermaid代码]) user_input st.text_area( 请输入你的架构描述越详细越好:, height150, placeholder例如一个前端React应用通过REST API与后端的Spring Boot用户服务通信用户服务将数据存入MySQL并使用Redis缓存会话信息。 ) if st.button(生成架构图, typeprimary): if not user_input.strip(): st.warning(请输入描述内容) else: with st.spinner(AI正在理解并绘制架构图...): try: payload {description: user_input, notation: notation, output_format: output_format} response requests.post(api_url, jsonpayload) if response.status_code 200: result response.json() if output_format in [png, svg]: # 显示图片 img_data result[image].split(,)[1] img_bytes base64.b64decode(img_data) st.image(img_bytes, caption生成的架构图, use_column_widthTrue) st.download_button(下载图片, dataimg_bytes, file_namefdiagram.{output_format}) else: # 显示Mermaid代码 st.code(result[mermaid_code], languagemermaid) st.caption(你可以将上述代码复制到支持Mermaid的编辑器如GitHub Markdown, Obsidian中查看。) else: st.error(f请求失败: {response.text}) except Exception as e: st.error(f生成过程中出现错误: {e})这个界面虽然简单但包含了核心功能输入、设置、调用、展示和下载。Streamlit的会话状态Session State还能轻松实现历史记录等进阶功能。4.3 部署考量与优化对于本地测试分别运行FastAPI后端和Streamlit前端即可。对于生产部署需要考虑以下几点API密钥管理绝对不要将OpenAI API密钥硬编码在代码中。使用环境变量或秘密管理服务如AWS Secrets Manager。异步处理生成图片尤其是服务端渲染可能是耗时操作几秒到十几秒。对于HTTP请求应考虑使用异步端点async def或通过消息队列如Celery将任务异步化先返回一个任务ID客户端再轮询结果。缓存相同的描述文本可以生成相同的图前提是LLM输出稳定。引入缓存如Redis可以显著提升重复请求的响应速度并节省API调用费用。容器化使用Docker将后端、前端和无头浏览器环境打包可以保证环境一致性简化部署。限流与监控对API进行限流防止滥用。同时监控API调用次数、响应时间和错误率。5. 效果评估、局限性与优化方向5.1 实际效果展示与测试我使用了一系列从简单到复杂的描述进行测试简单描述“一个客户端访问一个服务器。” - 能正确生成两个节点和一条连线。典型Web架构“用户通过浏览器访问负载均衡器负载均衡器将请求分发给多个Web服务器Web服务器从MySQL数据库读取数据。” - 能准确识别出browser、load_balancer、web_server、mysql等组件及关系并选择合适的图标。复杂微服务场景“订单服务Order Service接收到下单请求后会同步调用库存服务Inventory Service扣减库存同时异步发布一个‘订单创建’事件到Kafka。支付服务Payment Service和通知服务Notification Service都订阅了这个事件。” - 这是对AI理解能力的较大考验。测试中GPT-4能较好地识别出四个服务、一个消息队列并区分出“同步调用”和“发布/订阅”两种不同的关系类型生成的C4容器图也基本符合预期。成功的关键因素在于Prompt的清晰度和Schema设计的合理性。当描述中组件和关系明确时生成效果非常出色。图形布局由Mermaid引擎负责虽然有时不是最优但清晰可读。5.2 当前存在的局限性没有任何系统是完美的这个AI智能体目前存在一些明显的局限性对模糊描述的“脑补”可能不符合预期当用户描述非常简略时如“做一个电商系统”LLM会基于其训练数据中的“常识”进行大量补全生成一个庞大而通用的电商架构。这个架构可能符合一般规律但未必是用户心中所想的具体设计。对复杂逻辑和约束的理解不足例如“服务A在正常时调用服务B超时时则降级调用服务C”这类包含条件逻辑的架构当前的Schema和Prompt难以精确表达LLM可能无法正确生成这种分支关系。图形布局的不可控性Mermaid的自动布局算法有时会产生交叉线过多或节点排列不直观的图形。我们无法通过自然语言指令来微调布局比如“把数据库放在左边”。成本与延迟每次调用都涉及GPT-4 API对于高频使用会产生成本。同时LLM推理加上服务端渲染整个流程的延迟在几秒到十几秒不适合实时交互要求极高的场景。领域知识依赖虽然LLM有广泛的常识但对于非常小众、特定的技术栈或公司内部架构规范它可能无法准确识别或映射。5.3 可行的优化与扩展方向针对上述局限未来可以从以下几个方向进行优化和扩展引入交互式澄清当用户描述过于模糊时AI可以主动提问例如“您指的‘网关’是API网关还是网络网关”、“这个‘数据处理服务’具体负责什么”。这需要构建一个多轮对话的智能体而不仅仅是单次请求-响应。增强Schema表达能力在现有Schema中增加Condition条件、AlternativeFlow备选流等字段以支持更复杂的架构模式描述。同时可以定义更丰富的properties允许用户指定颜色、图标等样式偏好尽管这超出了“自然语言”的范畴。后处理与布局优化在生成Mermaid代码后可以加入一个后处理步骤利用图布局算法如Dagre对节点位置进行初步计算和优化生成更美观的Mermaid代码再交给Mermaid渲染。支持多轮对话与迭代修改这是最具价值的扩展。允许用户在第一版图生成后说“把Redis移到数据库前面”或者“把用户服务和订单服务合并成一个‘业务中台’”。这需要系统能理解“增删改”的指令并维护当前架构图的状态。实现上可以将每次修改视为对当前结构化数据JSON的一次“补丁”操作。集成企业知识库通过RAG检索增强生成技术将公司内部的架构规范文档、现有系统文档作为知识库提供给LLM。这样当用户提到“我们的通用用户中心”时AI能检索到该系统的实际技术栈和接口生成更贴近公司实际情况的图。输出格式多样化除了Mermaid可以增加对PlantUML、Graphviz DOT语言甚至直接生成Draw.io文件的支持满足不同团队的工具偏好。构建这个AI智能体的过程是一次将前沿大模型能力与具体工程问题结合的深度实践。它不是一个能完全替代人类架构师的工具而是一个强大的“辅助脑”和“加速器”能将我们从重复性的绘图劳动中解放出来更专注于设计本身。技术的边界正在被快速拓宽如何用它来增强而非取代我们的创造力和判断力才是更值得持续探索的课题。
基于LLM与Mermaid的智能架构图生成:从自然语言到可视化设计
1. 项目概述当自然语言遇见架构图最近在折腾一个挺有意思的东西一个能把你说的话直接变成技术架构图的AI智能体。听起来有点科幻对吧但实际做下来发现核心逻辑并没有想象中那么遥不可及。简单来说这个项目的目标就是让产品经理、业务方甚至是不太懂技术的同事能用最自然的方式描述他们想要的系统样子比如“我要一个用户登录后能看到个人仪表盘数据从MySQL读用Redis缓存热点通过Kafka异步处理日志”然后AI就能理解这句话并自动生成一张清晰、标准的架构图。这背后解决的痛点非常实际。在技术方案评审、新项目启动或者向非技术伙伴解释系统设计时画架构图是个高频且费时费力的活。工具从Visio、Draw.io到Lucidchart虽然强大但都得手动拖拽、连线、调整样式。更头疼的是当讨论中方案有调整图就得重画或大改沟通成本很高。我这个项目的初衷就是想用AI作为“翻译官”和“绘图员”把人类模糊的、非结构化的语言转化为精确的、结构化的图形表达让创意和设计的流转更顺畅。这个智能体适合任何需要频繁进行技术设计、方案沟通或知识沉淀的开发者、架构师和技术负责人。即使你只是对AI应用开发感兴趣想了解如何串联大语言模型LLM、知识库和绘图引擎这个项目也是一个很好的练手案例。接下来我会详细拆解我是如何一步步把它构建出来的从核心思路到技术选型从Prompt工程到前后端集成并分享其中踩过的坑和总结的经验。2. 核心思路与系统设计拆解2.1 从语言到图形的核心挑战要实现“说话成图”我们需要解决几个核心的转化问题。首先自然语言是模糊且充满歧义的。比如“服务器”这个词可能指物理机、虚拟机、一个K8s Pod或者一个云函数。其次架构图有自己严格的语法和语义组件类型数据库、队列、服务、组件之间的关系数据流、调用依赖、分组和层级都需要被明确定义。最后生成的图形不仅要“对”符合语义还要“好”布局美观、符合制图规范。因此整个系统的设计思路遵循一个清晰的管道Pipeline模式理解 - 结构化 - 渲染。这不是一个端到端的黑箱模型而是一个由多个专门化模块组成的协作系统。我的设计原则是“让专业的模块做专业的事”用大语言模型LLM做它最擅长的语言理解和逻辑推理用专门的规则引擎或图数据库来处理结构化关系用成熟的图形库来负责最终的视觉呈现。这样的解耦设计使得每个环节都可以独立优化、调试和替换。2.2 技术栈选型与架构设计基于上述思路我选择了以下技术栈来搭建这个AI智能体语言理解与推理层大脑OpenAI GPT-4 API。我尝试过Claude和国内的一些大模型但GPT-4在遵循复杂指令、进行多步推理以及输出结构化JSON方面目前表现最为稳定可靠。它是整个系统的“大脑”负责将自然语言“翻译”成机器可理解的设计意图。结构化中间表示层骨架自定义的架构描述语言ADL Schema。这是项目的关键创新点之一。我并没有让LLM直接输出图形指令而是定义了一套简化的JSON Schema用来描述架构元素。这个Schema定义了核心对象比如Component(组件)、Relationship(关系)、Layer(分层) 等每个对象都有type,name,properties等字段。LLM的任务就是将自然语言映射到这个Schema上。这样做的好处是将易变的自然语言与后端的渲染逻辑解耦无论前端说什么我们首先得到的是一个标准化的、可供程序处理的数据结构。图形渲染层画笔Mermaid.js。选择Mermaid的原因很简单它可以通过文本定义来生成图表完美契合我们“从结构化数据到图形”的流程。我们只需要将上一步得到的JSON Schema通过一个转换器Transformer转换成Mermaid语法例如graph TD流程图或C4Context图Mermaid就能在浏览器或Node.js环境中渲染出SVG或PNG图片。它支持多种图表类型社区活跃完全开源。智能体编排与后端LangChain FastAPI。LangChain框架极大地简化了与LLM的交互、Prompt模板的管理以及复杂链Chain的构建。我用它来组装整个处理流程。FastAPI则提供了高性能、易于编写API的后端服务负责接收用户请求调用LangChain处理链并返回最终的图片或图表代码。前端交互Streamlit。为了快速构建一个可交互的演示界面我选择了Streamlit。它可以用纯Python快速创建Web应用非常适合原型演示。界面包含一个文本输入框、一个生成按钮和一个显示图片的区域。整个系统的数据流如下图所示此处以文字描述用户在前端输入自然语言描述 - FastAPI后端接收 - LangChain调用GPT-4 API结合预设的Prompt和Schema进行推理 - GPT-4返回符合Schema的JSON - 后端的转换器将JSON转换为Mermaid代码 - 调用Mermaid渲染引擎生成图片 - 图片数据流返回前端展示。注意这里的关键是“中间表示层”JSON Schema的设计。它直接决定了AI理解的“世界观”和最终成图的质量。Schema不能太复杂否则LLM难以准确填充也不能太简单否则无法表达丰富的架构概念。我花了大量时间在迭代这个Schema上。3. 核心模块实现细节3.1 定义架构描述语言ADLSchema这是整个项目的基石。我的设计目标是足够表达常见的架构概念同时保持简洁。以下是我定义的v1版本的核心部分以Python Pydantic模型为例from pydantic import BaseModel, Field from typing import List, Optional, Literal class Component(BaseModel): id: str Field(..., description组件唯一标识符如 user_service) name: str Field(..., description组件显示名称如 用户服务) type: Literal[service, database, queue, cache, api_gateway, load_balancer, function, storage, external] Field(..., description组件类型) technology: Optional[str] Field(None, description具体技术如 MySQL, Redis, Kafka) layer: Optional[str] Field(None, description所属层级如 Presentation, Application, Data) properties: Optional[dict] Field(default_factorydict, description扩展属性) class Relationship(BaseModel): source: str Field(..., description关系发起方组件ID) target: str Field(..., description关系接收方组件ID) type: Literal[http_request, database_query, publish, subscribe, async_call, sync_call] Field(..., description关系类型) description: Optional[str] Field(None, description关系描述如 读取用户数据) class ArchitectureDiagram(BaseModel): components: List[Component] Field(..., description架构中的所有组件) relationships: List[Relationship] Field(..., description组件之间的关系) title: str Field(系统架构图, description图表标题) notation: Literal[c4, flowchart] Field(flowchart, description使用的图示法)这个Schema明确告诉LLM一个架构图由若干组件和关系构成组件有类型和技术栈关系有方向和类型。notation字段可以控制最终用C4模型图还是普通流程图来渲染。3.2 构建高效的Prompt工程有了Schema下一步就是教会LLM如何使用它。Prompt的设计至关重要。我的Prompt结构如下角色设定明确告诉AI它扮演一个“资深系统架构师”。核心任务清晰说明需要将自然语言描述转化为指定的JSON格式。格式约束直接给出上面定义的Pydantic模型的JSON Schema定义要求AI严格按此输出。规则与示例提供详细的规则如“如果用户提到‘数据库’默认类型为database技术栈可推断为MySQL”和1-2个完整的输入输出示例Few-shot Learning。用户输入最后附上用户的自然语言描述。一个简化版的Prompt示例你是一个专业的系统架构师擅长将模糊的业务需求转化为清晰的技术架构描述。 你的任务是将用户用自然语言描述的系统架构转换成一个结构化的JSON数据模型。该模型必须严格遵守以下JSON Schema定义 {schema_definition} 请遵循以下规则 1. 从描述中识别出所有独立的组件如服务、数据库、消息队列等。 2. 为每个组件分配一个唯一的、简洁的英文id如auth_service。 3. 推断组件间的关系明确source和target。 4. 如果用户未明确指定技术可根据上下文进行合理推断如“数据库”可推断为“MySQL”“缓存”可推断为“Redis”。 示例 用户输入“一个Web应用通过API网关访问用户服务用户服务会查询MySQL数据库。” 输出 { components: [ {id: web_app, name: Web应用, type: service}, {id: api_gateway, name: API网关, type: api_gateway}, {id: user_service, name: 用户服务, type: service}, {id: mysql_db, name: 用户数据库, type: database, technology: MySQL} ], relationships: [ {source: web_app, target: api_gateway, type: http_request}, {source: api_gateway, target: user_service, type: http_request}, {source: user_service, target: mysql_db, type: database_query} ], title: 示例架构, notation: flowchart } 现在请处理以下用户输入 用户输入{user_input}实操心得在Prompt中提供示例Few-shot的效果远好于只给指令Zero-shot。示例能更直观地展示“边界情况”如何处理比如如何命名id如何推断未明确的技术。同时要求LLM输出JSON时明确指定“不要包含任何解释性文字只输出JSON对象”可以避免后续解析的麻烦。3.3 实现JSON到Mermaid的转换器得到标准化的JSON数据后我们需要一个转换器将其变成Mermaid代码。这个转换器本质上是一个模板渲染器根据notation字段选择不同的模板。对于flowchart流程图 notation转换逻辑相对直接def convert_to_mermaid_flowchart(diagram: ArchitectureDiagram) - str: lines [graph TD] # 添加组件节点可以按类型进行样式映射 for comp in diagram.components: node_style get_style(comp.type) # 根据类型映射形状如数据库为圆柱形 lines.append(f {comp.id}[{comp.name}]::{node_style}) # 添加关系连线 for rel in diagram.relationships: arrow get_arrow(rel.type) # 根据关系类型映射箭头如--表示HTTP-.-表示异步 lines.append(f {rel.source} {arrow} {rel.target}) return \n.join(lines)对于更专业的c4notation我利用了Mermaid对C4模型的支持需要引入C4插件。转换时需要将我们的通用组件类型映射到C4的特定元素Person, System, Container, Component等并设置合理的标签和技术栈信息。注意事项Mermaid的C4语法有一定限制对布局的控制力较弱。如果对图形美观度要求极高可以考虑将JSON转换为Draw.io的XML格式但这会复杂很多。在易用性和表现力之间我优先选择了Mermaid。3.4 集成LangChain构建处理链使用LangChain可以优雅地将上述步骤串联起来。我构建了一个LLMChain其核心是ChatPromptTemplate里面包含了我们精心设计的Prompt。然后使用PydanticOutputParser来强制LLM的输出符合我们的ArchitectureDiagram模型这能极大地提高输出格式的稳定性。from langchain.chains import LLMChain from langchain.prompts import ChatPromptTemplate from langchain.output_parsers import PydanticOutputParser from langchain.chat_models import ChatOpenAI # 初始化模型和解析器 llm ChatOpenAI(modelgpt-4, temperature0.1) # temperature调低保证输出稳定性 parser PydanticOutputParser(pydantic_objectArchitectureDiagram) # 构建Prompt模板将格式指令和schema动态注入 prompt_template ChatPromptTemplate.from_template(...) # 此处填入完整的Prompt模板字符串 # 创建处理链 chain LLMChain(llmllm, promptprompt_template, output_parserparser) # 运行链 user_input 一个微服务架构订单服务调用支付服务两者都读写同一个PostgreSQL数据库并用Redis缓存商品信息。 result chain.run(user_input) # result 已是一个ArchitectureDiagram实例这样我们通过一个chain.run()调用就完成了从自然语言到结构化数据的全过程。4. 前后端搭建与部署实践4.1 使用FastAPI构建高效后端后端API的设计很简单主要两个端点POST /generate_diagram: 接收自然语言描述返回生成的图片Base64编码或Mermaid代码。POST /generate_schema: 接收自然语言描述返回结构化的JSON Schema用于调试。核心的生成视图函数如下from fastapi import FastAPI, HTTPException from pydantic import BaseModel import base64 from io import BytesIO app FastAPI(titleArchitecture Diagram AI Agent) class DiagramRequest(BaseModel): description: str notation: str flowchart output_format: str png # 支持 png, svg, mermaid app.post(/generate) async def generate_diagram(request: DiagramRequest): try: # 1. 调用LangChain链生成ArchitectureDiagram对象 diagram: ArchitectureDiagram chain.run(request.description) # 2. 根据notation将diagram对象转换为Mermaid代码 mermaid_code converter.convert(diagram, request.notation) # 3. 根据output_format渲染图形 if request.output_format in [png, svg]: # 使用mermaid-cli或pyppeteer等库在服务端渲染 img_bytes render_mermaid_to_image(mermaid_code, request.output_format) img_b64 base64.b64encode(img_bytes).decode(utf-8) return {image: fdata:image/{request.output_format};base64,{img_b64}} else: return {mermaid_code: mermaid_code} except Exception as e: raise HTTPException(status_code500, detailf生成失败: {str(e)})踩坑记录服务端渲染Mermaid图是一个挑战。最初我尝试用mermaid-cliPuppeteer驱动但在Docker容器中部署时遇到了Chromium依赖和字体问题。后来我转向了pyppeteerPython版的Puppeteer通过启动一个无头浏览器来渲染虽然速度稍慢但兼容性更好。对于生产环境可以考虑预启动一个浏览器实例池来优化性能。4.2 快速构建交互式前端StreamlitStreamlit让前端开发变得极其简单一个Python脚本搞定import streamlit as st import requests import base64 st.set_page_config(page_titleAI架构图生成器, layoutwide) st.title( 用自然语言描述生成你的系统架构图) api_url http://localhost:8000/generate # 后端API地址 with st.sidebar: st.header(设置) notation st.selectbox(图示法, [flowchart, c4]) output_format st.selectbox(输出格式, [png, svg, mermaid代码]) user_input st.text_area( 请输入你的架构描述越详细越好:, height150, placeholder例如一个前端React应用通过REST API与后端的Spring Boot用户服务通信用户服务将数据存入MySQL并使用Redis缓存会话信息。 ) if st.button(生成架构图, typeprimary): if not user_input.strip(): st.warning(请输入描述内容) else: with st.spinner(AI正在理解并绘制架构图...): try: payload {description: user_input, notation: notation, output_format: output_format} response requests.post(api_url, jsonpayload) if response.status_code 200: result response.json() if output_format in [png, svg]: # 显示图片 img_data result[image].split(,)[1] img_bytes base64.b64decode(img_data) st.image(img_bytes, caption生成的架构图, use_column_widthTrue) st.download_button(下载图片, dataimg_bytes, file_namefdiagram.{output_format}) else: # 显示Mermaid代码 st.code(result[mermaid_code], languagemermaid) st.caption(你可以将上述代码复制到支持Mermaid的编辑器如GitHub Markdown, Obsidian中查看。) else: st.error(f请求失败: {response.text}) except Exception as e: st.error(f生成过程中出现错误: {e})这个界面虽然简单但包含了核心功能输入、设置、调用、展示和下载。Streamlit的会话状态Session State还能轻松实现历史记录等进阶功能。4.3 部署考量与优化对于本地测试分别运行FastAPI后端和Streamlit前端即可。对于生产部署需要考虑以下几点API密钥管理绝对不要将OpenAI API密钥硬编码在代码中。使用环境变量或秘密管理服务如AWS Secrets Manager。异步处理生成图片尤其是服务端渲染可能是耗时操作几秒到十几秒。对于HTTP请求应考虑使用异步端点async def或通过消息队列如Celery将任务异步化先返回一个任务ID客户端再轮询结果。缓存相同的描述文本可以生成相同的图前提是LLM输出稳定。引入缓存如Redis可以显著提升重复请求的响应速度并节省API调用费用。容器化使用Docker将后端、前端和无头浏览器环境打包可以保证环境一致性简化部署。限流与监控对API进行限流防止滥用。同时监控API调用次数、响应时间和错误率。5. 效果评估、局限性与优化方向5.1 实际效果展示与测试我使用了一系列从简单到复杂的描述进行测试简单描述“一个客户端访问一个服务器。” - 能正确生成两个节点和一条连线。典型Web架构“用户通过浏览器访问负载均衡器负载均衡器将请求分发给多个Web服务器Web服务器从MySQL数据库读取数据。” - 能准确识别出browser、load_balancer、web_server、mysql等组件及关系并选择合适的图标。复杂微服务场景“订单服务Order Service接收到下单请求后会同步调用库存服务Inventory Service扣减库存同时异步发布一个‘订单创建’事件到Kafka。支付服务Payment Service和通知服务Notification Service都订阅了这个事件。” - 这是对AI理解能力的较大考验。测试中GPT-4能较好地识别出四个服务、一个消息队列并区分出“同步调用”和“发布/订阅”两种不同的关系类型生成的C4容器图也基本符合预期。成功的关键因素在于Prompt的清晰度和Schema设计的合理性。当描述中组件和关系明确时生成效果非常出色。图形布局由Mermaid引擎负责虽然有时不是最优但清晰可读。5.2 当前存在的局限性没有任何系统是完美的这个AI智能体目前存在一些明显的局限性对模糊描述的“脑补”可能不符合预期当用户描述非常简略时如“做一个电商系统”LLM会基于其训练数据中的“常识”进行大量补全生成一个庞大而通用的电商架构。这个架构可能符合一般规律但未必是用户心中所想的具体设计。对复杂逻辑和约束的理解不足例如“服务A在正常时调用服务B超时时则降级调用服务C”这类包含条件逻辑的架构当前的Schema和Prompt难以精确表达LLM可能无法正确生成这种分支关系。图形布局的不可控性Mermaid的自动布局算法有时会产生交叉线过多或节点排列不直观的图形。我们无法通过自然语言指令来微调布局比如“把数据库放在左边”。成本与延迟每次调用都涉及GPT-4 API对于高频使用会产生成本。同时LLM推理加上服务端渲染整个流程的延迟在几秒到十几秒不适合实时交互要求极高的场景。领域知识依赖虽然LLM有广泛的常识但对于非常小众、特定的技术栈或公司内部架构规范它可能无法准确识别或映射。5.3 可行的优化与扩展方向针对上述局限未来可以从以下几个方向进行优化和扩展引入交互式澄清当用户描述过于模糊时AI可以主动提问例如“您指的‘网关’是API网关还是网络网关”、“这个‘数据处理服务’具体负责什么”。这需要构建一个多轮对话的智能体而不仅仅是单次请求-响应。增强Schema表达能力在现有Schema中增加Condition条件、AlternativeFlow备选流等字段以支持更复杂的架构模式描述。同时可以定义更丰富的properties允许用户指定颜色、图标等样式偏好尽管这超出了“自然语言”的范畴。后处理与布局优化在生成Mermaid代码后可以加入一个后处理步骤利用图布局算法如Dagre对节点位置进行初步计算和优化生成更美观的Mermaid代码再交给Mermaid渲染。支持多轮对话与迭代修改这是最具价值的扩展。允许用户在第一版图生成后说“把Redis移到数据库前面”或者“把用户服务和订单服务合并成一个‘业务中台’”。这需要系统能理解“增删改”的指令并维护当前架构图的状态。实现上可以将每次修改视为对当前结构化数据JSON的一次“补丁”操作。集成企业知识库通过RAG检索增强生成技术将公司内部的架构规范文档、现有系统文档作为知识库提供给LLM。这样当用户提到“我们的通用用户中心”时AI能检索到该系统的实际技术栈和接口生成更贴近公司实际情况的图。输出格式多样化除了Mermaid可以增加对PlantUML、Graphviz DOT语言甚至直接生成Draw.io文件的支持满足不同团队的工具偏好。构建这个AI智能体的过程是一次将前沿大模型能力与具体工程问题结合的深度实践。它不是一个能完全替代人类架构师的工具而是一个强大的“辅助脑”和“加速器”能将我们从重复性的绘图劳动中解放出来更专注于设计本身。技术的边界正在被快速拓宽如何用它来增强而非取代我们的创造力和判断力才是更值得持续探索的课题。