怎么实现codex控制嘉立创EDA绘制原理图

本文记录本项目中"Codex / AI 如何控制嘉立创 EDA 自动绘制原理图"的整体设计和实现方式。这里的"控制"不是让 Codex 直接模拟鼠标键盘点击嘉立创界面,而是把自然语言需求转换成稳定的结构化电路描述,再通过本地后端、Bridge 网关和嘉立创 EDA 运行时 API 执行原理图绘制。

1. 目标

本方案要解决的问题是:

  1. 用户用自然语言描述电路需求,例如"画一个 ESP32-C3 最小系统,USB-C 供电,带复位、BOOT、UART 下载和电源灯"。
  2. AI 只负责理解需求和生成结构化 JSON,不直接操作 EDA。
  3. 程序把 AI 输出校验成 Circuit DSL。
  4. 程序根据 DSL 计算元件位置、网络标签、导线提示和 ERC 提醒。
  5. 程序通过嘉立创 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 调用代码,会有几个风险:

  1. API 参数容易错。
  2. 元件编号、网络连接、坐标和保存动作难以校验。
  3. 不同模型输出风格不稳定。
  4. 一旦执行错误代码,调试成本高。

所以本项目采用中间层 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。它约束了:

  1. component.ref 必须像 U1R3 这样的引用编号。
  2. net.connections 必须是 REF.PIN 格式。
  3. positionHint 只能是 leftrightcenterupper_leftupper_rightlower_leftlower_right
  4. 必须至少有一个元件和一个网络。
  5. 校验阶段会检查重复引用、未知元件引用、是否缺少 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。它会做三层保护:

  1. 使用 Prompt 限制模型只能输出符合 Circuit DSL 1.0 的 JSON。
  2. 使用 normalizeCircuitDsl() 修正常见模型输出偏差,例如把 top-right 归一成 upper_right
  3. 使用 CircuitDslSchemavalidateCircuitDsl() 做结构校验。

如果模型输出仍不符合规范,后端会直接报错,不会进入 EDA 绘制阶段。

4.3 多模型接入

模型调用封装在 server/src/ai/openai-compatible.tsserver/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

这条路线的特点:

  1. 页面运行在嘉立创 EDA 扩展环境中。
  2. 可以直接检测 window.edawindow.api
  3. 调用链最短。
  4. 需要把扩展安装到嘉立创 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

核心概念:

  1. EDA 端作为 eda client 连接 ws://localhost:49620/eda
  2. 普通工具或后端作为 agent client 连接 /agent,也可以直接走 HTTP /execute
  3. Bridge 维护 edaClients,记录每个已连接的 EDA 窗口。
  4. 执行代码时生成请求 ID,发给指定 EDA 窗口,并等待结果返回。
  5. 30 秒超时未返回则报错。

6.2 Gateway 自动发现

easyedaGateway.ts 负责自动发现可用 Gateway:

  1. 优先使用本项目内置 Bridge 状态。
  2. 如果内置 Bridge 未启动,则扫描 127.0.0.1:49620127.0.0.1:49629
  3. 访问 /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()

  1. 先尝试位置参数形式。
  2. 如果失败,再尝试对象参数形式。

例如创建元件时会尝试:

ts 复制代码
component.create(device, x, y, undefined, 0, false, true, true)

失败后再尝试:

ts 复制代码
component.create({ device, x, y, reference, value })

7.2 元件解析

元件解析优先级:

  1. 如果 DSL 中有 lcsc 编号,优先调用 getByLcscIds([lcsc])
  2. 如果没有编号或查不到,使用 name + value + package 调用 search()
  3. 如果仍找不到,停止绘制并提示"未找到库器件"。

这样可以避免把不存在或不确定的元件硬塞进原理图。

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

生成原理图时:

  1. 调用 /api/ai/parse-requirement
  2. 调用 /api/ai/generate-circuit
  3. 检查当前页面是否能直接访问 EDA API。
  4. 如果能访问,调用 writeSchematic(generated)
  5. 如果不能访问,但 Gateway 已连接,调用 /api/gateway/draw
  6. 如果两者都不可用,则提示需要安装并启用 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 可以扮演三个角色:

  1. 作为开发协作者:修改 DSL、后端、Bridge、前端和 EDA 适配代码。
  2. 作为操作入口:根据用户需求调用本地项目,让需求进入 AI -> DSL -> EDA 的链路。
  3. 作为调试助手:查看后端日志、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

然后:

  1. 打开嘉立创 EDA Pro。
  2. 打开项目和原理图编辑器。
  3. 启用 run-api-gateway
  4. 点击 Gateway 的重新连接。
  5. 打开 http://127.0.0.1:5173
  6. 在"模型设置"中测试模型连接。
  7. 点击"检测 Gateway"。
  8. 确认 EDA 客户端数量大于 0。
  9. 在"生成原理图"中输入需求并绘制。

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": []
  }
}

实际使用时 componentsnets 不能为空,上面只是展示接口形状。

12. 常见问题

12.1 页面显示"浏览器模式"

这是正常现象。普通浏览器没有 window.eda。如果走路线 B,只要 Gateway 已连接并且 EDA 客户端数量大于 0,就仍然可以控制 EDA。

12.2 Gateway 客户端数量一直是 0

说明 Bridge 已启动,但嘉立创 EDA 没有连接进来。检查:

  1. 嘉立创 EDA 是否打开了项目和原理图。
  2. run-api-gateway 是否安装并启用。
  3. 是否允许外部交互。
  4. 是否点击了重新连接。
  5. Bridge 地址是否在 49620-49629 端口范围内。

12.3 生成 DSL 成功但绘图失败

常见原因:

  1. 元件库搜索不到 DSL 中的元件。
  2. 嘉立创 API 参数和当前版本 SDK 有差异。
  3. 当前窗口不是原理图编辑器。
  4. Gateway 连接到了错误窗口。
  5. DSL 中的管脚名和库器件实际管脚不一致。

12.4 AI 输出字段不规范

后端已经使用 normalizeCircuitDsl() 修正常见问题,并用 Zod 严格校验。如果仍失败,应该优先调整 Prompt 或 DSL 归一化逻辑,而不是放松执行端。

13. 当前限制

当前实现仍是 MVP,有这些限制:

  1. 布局是锚点式布局,不是完整自动布局。
  2. 网络主要由标签表达,短导线只是视觉提示。
  3. 元件库匹配依赖 LCSC 编号或关键词搜索,无法保证每次命中最合适器件。
  4. 管脚名需要和嘉立创库器件一致,否则后续精细连接可能需要人工复核。
  5. ERC 规则仍比较基础,只做部分工程提醒。
  6. Gateway 执行的是 JS 代码,需要信任本地后端和当前项目代码。

14. 后续优化方向

建议按这个顺序继续增强:

  1. 为常用芯片建立稳定模板,例如 ESP32-C3、STM32F103、CH32V003。
  2. 为模板补齐真实 pin map,减少模型生成管脚名的自由度。
  3. 建立本地元件映射表,把常见电阻、电容、LDO、USB-C、排针映射到确定 LCSC 编号。
  4. 增强 ERC,例如电源反接、LED 限流、USB-C CC 下拉、电容缺失、BOOT/EN 上下拉。
  5. 把布局策略从固定锚点升级为模块化布局。
  6. 增加绘制前预览,让用户确认 DSL 后再写入 EDA。
  7. 记录每次绘制的 DSL、Gateway 返回和 EDA 报错,便于复盘。

15. 一句话总结

本项目实现 Codex 控制嘉立创 EDA 的方法是:让 AI 生成可校验的 Circuit DSL,用确定性 TypeScript 代码把 DSL 转成嘉立创 EDA API 调用;在 EDA 扩展环境中直接调用 window.eda,在普通浏览器环境中通过本地 Bridge / Gateway 把代码送入嘉立创 EDA 窗口执行。这样既保留了自然语言生成电路的灵活性,又把真正落图动作控制在可审查、可调试、可回滚的工程代码里。

相关推荐
青梅橘子皮1 小时前
Linux---冯诺伊曼体系结构,操作系统概况
java·linux·运维
鹏大师运维1 小时前
不用装远程桌面!统信UOS通过SSH直接调用麒麟图形界面程序
linux·运维·网络·ssh·麒麟·x11·统信v25
Jason_zhao_MR1 小时前
RK3506工业网关:如何打通现场采集、无线传输与行业规约接入?
linux·嵌入式硬件·物联网·系统架构·嵌入式
lingx_gps1 小时前
领新北斗(TracSeek)车辆动态监控系统 - Linux(Ubuntu) 安装部署完整指南
linux·运维·ubuntu·jt808·车辆监控·jt1078·北斗定位
灰灰勇闯IT2 小时前
pto-isa:昇腾 Graph Compiler 的虚拟指令集
linux·运维·服务器
.千余2 小时前
【Linux】Socket编程UDP
linux·运维·服务器·开发语言·网络协议·学习·udp
小鹏linux12 小时前
Ubuntu 22.04 部署开源免费具有精美现代web页面的Casdoor账号管理系统
linux·前端·ubuntu·开源·堡垒机
在角落发呆12 小时前
Linux转发配置:解锁网络互联的核心密码
linux·运维·网络
齐潇宇13 小时前
Zabbix 7 概述与配置
linux·zabbix·监控告警