本文记录本项目中"Codex / AI 如何控制嘉立创 EDA 自动绘制原理图"的整体设计和实现方式。这里的"控制"不是让 Codex 直接模拟鼠标键盘点击嘉立创界面,而是把自然语言需求转换成稳定的结构化电路描述,再通过本地后端、Bridge 网关和嘉立创 EDA 运行时 API 执行原理图绘制。
1. 目标
本方案要解决的问题是:
- 用户用自然语言描述电路需求,例如"画一个 ESP32-C3 最小系统,USB-C 供电,带复位、BOOT、UART 下载和电源灯"。
- AI 只负责理解需求和生成结构化 JSON,不直接操作 EDA。
- 程序把 AI 输出校验成 Circuit DSL。
- 程序根据 DSL 计算元件位置、网络标签、导线提示和 ERC 提醒。
- 程序通过嘉立创 EDA Pro 的扩展 API 或本地 Gateway,把元件和网络写入当前原理图。
这样做的核心收益是:AI 的输出被限制在可校验的数据结构里,真正的落图动作由确定性代码执行,避免模型直接生成不可控脚本。
2. 总体架构
项目由四层组成:
text
用户 / Codex / AI 对话
-> React 前端面板
-> Node 本地 AI 后端
-> Circuit DSL
-> EDA 写入器 / Gateway
-> 嘉立创 EDA Pro API
对应目录如下:
text
shared/src/circuit-dsl.ts Circuit DSL 类型、Zod Schema、校验逻辑
server/src 本地 AI 后端和 Gateway 后端
server/src/gateway EasyEDA Bridge / Gateway 调用封装
extension/src/panel React 操作面板
extension/src/eda 原理图写入器、布局、EDA API 适配层
extension/src/extension-entry.ts 嘉立创扩展入口,打开 iframe 面板
scripts/dev.mjs 一键启动 Bridge、Server、Extension
3. 为什么使用 Circuit DSL
如果直接让 AI 输出嘉立创 API 调用代码,会有几个风险:
- API 参数容易错。
- 元件编号、网络连接、坐标和保存动作难以校验。
- 不同模型输出风格不稳定。
- 一旦执行错误代码,调试成本高。
所以本项目采用中间层 Circuit DSL 1.0。AI 只生成类似下面的结构:
json
{
"dslVersion": "1.0",
"project": {
"title": "ESP32-C3 最小系统"
},
"components": [
{
"ref": "U1",
"role": "mcu",
"name": "ESP32-C3",
"package": "QFN-32",
"positionHint": "center"
}
],
"nets": [
{
"name": "3V3",
"connections": ["U1.3V3"]
}
],
"rules": [],
"warnings": []
}
DSL 的 Schema 定义在 shared/src/circuit-dsl.ts。它约束了:
component.ref必须像U1、R3这样的引用编号。net.connections必须是REF.PIN格式。positionHint只能是left、right、center、upper_left、upper_right、lower_left、lower_right。- 必须至少有一个元件和一个网络。
- 校验阶段会检查重复引用、未知元件引用、是否缺少 GND 网络。
这使得 AI 的创造力被放在"电路结构设计"上,而不是放在"随手写执行脚本"上。
4. AI 到 DSL 的后端流程
本地后端入口是 server/src/index.ts,默认监听:
text
http://127.0.0.1:8787
前端生成原理图时会依次调用:
text
POST /api/ai/parse-requirement
POST /api/ai/generate-circuit
POST /api/gateway/draw 或在扩展环境内直接 writeSchematic()
4.1 需求解析
server/src/services/parseRequirement.ts 会把自然语言解析为需求对象。Prompt 在 server/src/ai/prompts.ts 中,要求模型只输出 JSON:
json
{
"intent": "create_schematic",
"circuitType": "mcu_minimum_system",
"mainChip": "ESP32-C3",
"powerInput": "USB-C",
"powerOutput": "3.3V",
"features": ["reset_button", "boot_button", "uart_download", "power_led"],
"missing": [],
"confidence": 0.86
}
4.2 生成 Circuit DSL
server/src/services/generateCircuit.ts 接收需求对象后调用模型生成 DSL。它会做三层保护:
- 使用 Prompt 限制模型只能输出符合
Circuit DSL 1.0的 JSON。 - 使用
normalizeCircuitDsl()修正常见模型输出偏差,例如把top-right归一成upper_right。 - 使用
CircuitDslSchema和validateCircuitDsl()做结构校验。
如果模型输出仍不符合规范,后端会直接报错,不会进入 EDA 绘制阶段。
4.3 多模型接入
模型调用封装在 server/src/ai/openai-compatible.ts 和 server/src/ai/providers.ts。项目支持 OpenAI 兼容接口和部分厂商预设,包括:
text
openai
deepseek
kimi
qwen
zhipu
volcengine
siliconflow
openrouter
gemini
anthropic
custom
前端可以在"模型设置"里选择 provider、model、Base URL 和 API Key。后端也可以通过 .env 固定配置。
5. 嘉立创 EDA 的两条控制路线
项目保留了两条路线,分别适合不同运行环境。
5.1 路线 A:作为嘉立创 EDA 本地扩展运行
路线 A 是最直接的方式:把本项目打包成嘉立创 EDA 扩展,运行在嘉立创 EDA 内部。此时前端 iframe 页面能直接访问运行时注入的 eda 对象。
流程:
text
嘉立创 EDA 扩展菜单
-> extension/src/extension-entry.ts
-> eda.sys_IFrame.openIFrame("/iframe/index.html", 1200, 760, ...)
-> React 面板
-> writeSchematic(dsl)
-> window.eda / window.api
-> sch_PrimitiveComponent、sch_PrimitiveWire、sch_Document 等 API
扩展入口在 extension/src/extension-entry.ts:
ts
eda.sys_IFrame.openIFrame("/iframe/index.html", 1200, 760, "jlc-ai-schematic-assistant");
扩展菜单声明在 extension/extension.json,菜单项会注册:
text
openAiSchematicAssistant
打包命令:
powershell
npm.cmd run package:extension
输出:
text
release/jlc-ai-schematic.eext
这条路线的特点:
- 页面运行在嘉立创 EDA 扩展环境中。
- 可以直接检测
window.eda或window.api。 - 调用链最短。
- 需要把扩展安装到嘉立创 EDA Pro。
5.2 路线 B:普通浏览器通过 Gateway 控制嘉立创 EDA
路线 B 是当前更适合本地开发和 Codex 协同的方式。前端运行在普通浏览器:
text
http://127.0.0.1:5173
普通浏览器没有 window.eda,所以不能直接控制嘉立创 EDA。为了解决这个问题,引入 Gateway:
text
React 前端
-> 本项目后端 /api/gateway/draw
-> EasyEDA Bridge Server
-> 嘉立创 EDA 中的 run-api-gateway 扩展
-> 当前 EDA 窗口内执行 JS
-> 调用 eda API 绘制原理图
本项目启动时会运行:
powershell
npm.cmd run dev
scripts/dev.mjs 会同时启动:
text
bridge:easyeda 本地 EasyEDA Bridge
dev:server AI 后端,http://127.0.0.1:8787
dev:extension Vite 前端,http://127.0.0.1:5173
Bridge 端口范围:
text
http://localhost:49620 - http://localhost:49629
这条路线需要在嘉立创 EDA 中安装并启用 run-api-gateway 或等价的 EDA 网关扩展。该扩展负责从 EDA 内部连接本地 Bridge。连接成功后,本项目后端就能把 JS 代码发送进 EDA 当前窗口执行。
6. Bridge 的实现方法
Bridge 的核心实现位于:
text
server/src/gateway/bridgeServer.ts
server/src/gateway/easyedaGateway.ts
server/src/services/gateway.ts
6.1 本地 Bridge Server
bridgeServer.ts 会在 49620-49629 中寻找可用端口,启动 HTTP + WebSocket 服务。
它提供:
text
GET /health
GET /eda-windows
POST /eda-windows/select
POST /execute
WS /eda
WS /agent
核心概念:
- EDA 端作为
eda client连接ws://localhost:49620/eda。 - 普通工具或后端作为
agent client连接/agent,也可以直接走 HTTP/execute。 - Bridge 维护
edaClients,记录每个已连接的 EDA 窗口。 - 执行代码时生成请求 ID,发给指定 EDA 窗口,并等待结果返回。
- 30 秒超时未返回则报错。
6.2 Gateway 自动发现
easyedaGateway.ts 负责自动发现可用 Gateway:
- 优先使用本项目内置 Bridge 状态。
- 如果内置 Bridge 未启动,则扫描
127.0.0.1:49620到127.0.0.1:49629。 - 访问
/health成功后记录baseUrl。
前端"检测 Gateway"按钮实际调用:
text
GET /api/gateway/health
成功时页面会显示 Bridge 地址和 EDA 客户端数量。只有 edaWindowCount > 0 或等价的客户端数量大于 0 时,才说明嘉立创 EDA 已经连接进来。
6.3 执行 EDA 代码
普通浏览器不能直接调用 eda。所以绘图时后端会根据 DSL 生成一段自执行 JS:
ts
(async () => {
const dsl = {...};
const api = typeof eda !== "undefined" ? eda : globalThis.eda;
...
})()
然后通过:
text
POST /api/gateway/execute
或封装后的:
text
POST /api/gateway/draw
发给 Bridge。Bridge 再把这段代码转发到 EDA 窗口。代码真正执行的位置是嘉立创 EDA 内部,因此可以访问 eda API。
7. 原理图写入器
路线 A 中直接使用:
text
extension/src/eda/schematic-writer.ts
路线 B 中后端生成的执行脚本复用了同一套思路。写入步骤如下:
text
validateCircuitDsl(dsl)
-> planLayout(dsl)
-> checkCircuit(dsl)
-> createComponent()
-> createNetLabel()
-> createWire()
-> save()
7.1 EDA API 适配
适配层在:
text
extension/src/eda/eda-adapter.ts
它会检测:
ts
window.eda ?? window.api
并兼容多种可能的 API 命名:
text
sch_PrimitiveComponent / SCH_PrimitiveComponent / sch.PrimitiveComponent
sch_PrimitiveWire / SCH_PrimitiveWire / sch.PrimitiveWire
sch_Document / SCH_Document / sch.Document
lib_Device / LIB_Device / lib.Device
实际使用的能力包括:
text
lib_Device.getByLcscIds
lib_Device.search
sch_PrimitiveComponent.create
sch_PrimitiveComponent.createNetFlag
sch_PrimitiveComponent.createNetPort
sch_PrimitiveWire.create
sch_Document.autoLayout
sch_Document.autoRouting
sch_Document.save
为了兼容 SDK 参数差异,代码使用了 callBestEffort():
- 先尝试位置参数形式。
- 如果失败,再尝试对象参数形式。
例如创建元件时会尝试:
ts
component.create(device, x, y, undefined, 0, false, true, true)
失败后再尝试:
ts
component.create({ device, x, y, reference, value })
7.2 元件解析
元件解析优先级:
- 如果 DSL 中有
lcsc编号,优先调用getByLcscIds([lcsc])。 - 如果没有编号或查不到,使用
name + value + package调用search()。 - 如果仍找不到,停止绘制并提示"未找到库器件"。
这样可以避免把不存在或不确定的元件硬塞进原理图。
7.3 布局策略
布局逻辑在:
text
extension/src/eda/layout-planner.ts
MVP 阶段没有做复杂自动布局,而是使用稳定锚点:
text
left 输入,如 USB-C
upper_left 电源,如 LDO
center 主控,如 ESP32-C3
right 接口,如 UART 排针
lower_left 按键
lower_right LED
upper_right 其他外围器件
每个锚点下的多个元件按固定间距向下排列。网络标签位置通过连接元件坐标的平均值推导。
7.4 网络连接策略
当前 MVP 主要用网络标签表达电气连接:
text
createNetFlag() 用于 GND、3V3、5V、VBUS、VCC 等电源网络
createNetPort() 用于普通网络
对于只有两个连接点的网络,会额外画短导线作为视觉提示:
text
sch_PrimitiveWire.create
也就是说,电气连通以网络标签为主,短导线更多是帮助人读图。
8. 前端如何选择绘制路线
前端主逻辑在:
text
extension/src/panel/main.tsx
生成原理图时:
- 调用
/api/ai/parse-requirement。 - 调用
/api/ai/generate-circuit。 - 检查当前页面是否能直接访问 EDA API。
- 如果能访问,调用
writeSchematic(generated)。 - 如果不能访问,但 Gateway 已连接,调用
/api/gateway/draw。 - 如果两者都不可用,则提示需要安装并启用 Gateway,或启用浏览器预览。
伪代码如下:
ts
const parsed = await parseRequirement(text);
const generated = await generateCircuit(parsed);
if (edaStatus.available) {
await writeSchematic(generated);
} else if (gateway.ok) {
await post("/api/gateway/draw", { dsl: generated, baseUrl: gateway.baseUrl });
} else if (allowPreview) {
await writeSchematic(generated);
} else {
throw new Error("没有 EDA API,也没有 Gateway");
}
9. Codex 在方案中的角色
在这个项目里,Codex 可以扮演三个角色:
- 作为开发协作者:修改 DSL、后端、Bridge、前端和 EDA 适配代码。
- 作为操作入口:根据用户需求调用本地项目,让需求进入 AI -> DSL -> EDA 的链路。
- 作为调试助手:查看后端日志、Gateway 状态、HTTP 返回、DSL 校验错误和 EDA API 报错。
需要注意的是,Codex 本身不直接拥有嘉立创 EDA 的内部 API。真正能操作 EDA 的是运行在嘉立创 EDA 窗口里的 eda 对象。Codex 要控制嘉立创,必须通过本项目提供的桥接层,把命令送到拥有 eda 对象的环境里执行。
可以把关系理解为:
text
Codex 提出意图或修改代码
本地项目把意图转成 DSL / JS
Bridge 把 JS 送入 EDA
EDA 内部的 eda API 完成真实操作
10. 启动和使用流程
推荐启动顺序:
powershell
cd E:\0WJL\嘉立创eda接入
npm.cmd install
npm.cmd run dev
正常会启动:
text
Bridge: http://localhost:49620-49629
Server: http://127.0.0.1:8787
Extension: http://127.0.0.1:5173
然后:
- 打开嘉立创 EDA Pro。
- 打开项目和原理图编辑器。
- 启用
run-api-gateway。 - 点击 Gateway 的重新连接。
- 打开
http://127.0.0.1:5173。 - 在"模型设置"中测试模型连接。
- 点击"检测 Gateway"。
- 确认 EDA 客户端数量大于 0。
- 在"生成原理图"中输入需求并绘制。
11. 调试接口
后端健康检查:
http
GET http://127.0.0.1:8787/api/health
模型 provider:
http
GET http://127.0.0.1:8787/api/ai/providers
Gateway 状态:
http
GET http://127.0.0.1:8787/api/gateway/health
Bridge 状态:
http
GET http://localhost:49620/health
查看 EDA 窗口:
http
POST http://127.0.0.1:8787/api/gateway/windows
执行任意 EDA 代码:
http
POST http://127.0.0.1:8787/api/gateway/execute
Content-Type: application/json
{
"code": "return { ok: true, hasEda: typeof eda !== 'undefined' }"
}
发送 DSL 绘图:
http
POST http://127.0.0.1:8787/api/gateway/draw
Content-Type: application/json
{
"dsl": {
"dslVersion": "1.0",
"project": { "title": "Demo" },
"components": [],
"nets": [],
"rules": [],
"warnings": []
}
}
实际使用时 components 和 nets 不能为空,上面只是展示接口形状。
12. 常见问题
12.1 页面显示"浏览器模式"
这是正常现象。普通浏览器没有 window.eda。如果走路线 B,只要 Gateway 已连接并且 EDA 客户端数量大于 0,就仍然可以控制 EDA。
12.2 Gateway 客户端数量一直是 0
说明 Bridge 已启动,但嘉立创 EDA 没有连接进来。检查:
- 嘉立创 EDA 是否打开了项目和原理图。
run-api-gateway是否安装并启用。- 是否允许外部交互。
- 是否点击了重新连接。
- Bridge 地址是否在
49620-49629端口范围内。
12.3 生成 DSL 成功但绘图失败
常见原因:
- 元件库搜索不到 DSL 中的元件。
- 嘉立创 API 参数和当前版本 SDK 有差异。
- 当前窗口不是原理图编辑器。
- Gateway 连接到了错误窗口。
- DSL 中的管脚名和库器件实际管脚不一致。
12.4 AI 输出字段不规范
后端已经使用 normalizeCircuitDsl() 修正常见问题,并用 Zod 严格校验。如果仍失败,应该优先调整 Prompt 或 DSL 归一化逻辑,而不是放松执行端。
13. 当前限制
当前实现仍是 MVP,有这些限制:
- 布局是锚点式布局,不是完整自动布局。
- 网络主要由标签表达,短导线只是视觉提示。
- 元件库匹配依赖 LCSC 编号或关键词搜索,无法保证每次命中最合适器件。
- 管脚名需要和嘉立创库器件一致,否则后续精细连接可能需要人工复核。
- ERC 规则仍比较基础,只做部分工程提醒。
- Gateway 执行的是 JS 代码,需要信任本地后端和当前项目代码。
14. 后续优化方向
建议按这个顺序继续增强:
- 为常用芯片建立稳定模板,例如 ESP32-C3、STM32F103、CH32V003。
- 为模板补齐真实 pin map,减少模型生成管脚名的自由度。
- 建立本地元件映射表,把常见电阻、电容、LDO、USB-C、排针映射到确定 LCSC 编号。
- 增强 ERC,例如电源反接、LED 限流、USB-C CC 下拉、电容缺失、BOOT/EN 上下拉。
- 把布局策略从固定锚点升级为模块化布局。
- 增加绘制前预览,让用户确认 DSL 后再写入 EDA。
- 记录每次绘制的 DSL、Gateway 返回和 EDA 报错,便于复盘。
15. 一句话总结
本项目实现 Codex 控制嘉立创 EDA 的方法是:让 AI 生成可校验的 Circuit DSL,用确定性 TypeScript 代码把 DSL 转成嘉立创 EDA API 调用;在 EDA 扩展环境中直接调用 window.eda,在普通浏览器环境中通过本地 Bridge / Gateway 把代码送入嘉立创 EDA 窗口执行。这样既保留了自然语言生成电路的灵活性,又把真正落图动作控制在可审查、可调试、可回滚的工程代码里。