仿真软件和AI编程助手之间的边界正在变得模糊。我在本地把 Lumerical FDTD 和 Cline、DeepSeek、MCP 串成了一条全自动链路以后,最大的感受是:以前写 FDTD 脚本花掉的时间,现在真的可以压缩到“描述需求 -> 人工审核 -> 等待跑完”这三步。这篇文章就记录我从零搭建这套 AI Agent 的完整过程,包括工具选型、MCP 服务设计、Cline 配置、实测案例和一大堆踩坑记录,给想入手的做光学仿真或光子器件设计的朋友一条能直接铺的路。
1. 整体设计与工具链选型
这套系统本质上干的事情是:让大模型能听懂 Lumerical 的脚本语言,但更重要的是让大模型能“动手”改脚本、跑仿真、读结果,遇到跑挂了还能自己修。所以它不是简单拿 ChatGPT 当顾问,而是要嵌进本地的命令行工作流里。
1.1 为什么选 Cline 而不是 Web 版 AI 或桌面端 IDE 插件
我先说结论:在终端干活,Cline 是现在最顺手的选择。
Lumerical 的光学仿真流程通常涉及三步:用 FDTD 或 MODE 建结构、跑网格化与求解、导出 S 参数或场分布数据。这三步里的每一步都是强命令行倾向的,Lumerical 自己就带fdtd-solutions -run script.lsf这种非交互式执行模式。既然要自动化,就必须找一个能真正执行命令的 Agent 载体。
Cline 在 VSCode 里跑,它能在对话里直接执行终端命令、读写文件,而且它最近补上了 MCP 客户端支持。换句话说,Cline 是一个典型的“Agent 运行时”,DeepSeek 只是它的推理大脑。Web 版对话助手做不到这种“执行 + 反馈 + 修正”的闭环,桌面端 IDE 插件在这方面也在追赶,但 Cline 生态已经非常成熟。
我搭建时选用的三条链路如下:
| 组件 | 角色 | 具体选择 |
|---|---|---|
| 命令行 Agent | 执行载体 | Cline (VSCode 扩展) |
| 推理模型 | 决策大脑 | DeepSeek-Chat (API) |
| 工具协议 | 工具调用标准 | MCP (Model Context Protocol) |
有人问我为什么不用 Codex CLI。Codex 也非常强,但它在“多工具并行 + 自定义 MCP Server + Python 脚本回传”这个组合上,配置自由度目前还是不如 Cline 直接。而且 Cline 的allowlist权限机制在安全性和自动化之间做了不错的平衡,后面会细说。
1.2 为什么需要 MCP 而非纯靠提示词
Lumerical 的脚本语言和普通 Python 完全不一样。它的.lsf文件里充满了addfdtd; addmode; set("dimension","2D"); addport;这样的命令。如果只靠提示词让 DeepSeek 生成脚本,模型大概率会生成语法对但物理不对的代码,比如忘了加 PML 边界条件,或者网格精度设得离谱。
MCP 在这里的价值是:给模型提供“感知—行动”的工具接口。我设计的 MCP Server 暴露了三个核心工具——run_lumerical_script、get_simulation_progress、parse_s_parameters。模型在拿到任务后,可以自主判断“该跑脚本了”或“结果没收敛,我要改网格”,然后直接调用这些工具,像穿了一双手套在操作仿真工具。
这个设计遵循的正是 Agent 领域常说的“工具增强”(tool-augmented)思路。LLM 提供推理和语言能力,MCP Server 提供确定性的执行能力,两者各干各擅长的部分。
1.3 这套方案适合解决什么真实痛点
我之前手动做波导模式分析时,最烦的就是改参数重跑:改一个set("wavelength", 1.55e-6),保存,跑完再看图,不理想再改。一次参数扫描至少折腾 20 分钟。有了 Agent 之后,这个循环变成了:
用户描述 → DeepSeek 拆解 → MCP 执行 Lumerical 脚本 → 解析 log → 反馈结果我可以直接跟 Cline 说:“帮我扫描 1100 nm 到 1600 nm 的透过率,步长 20 nm”,它会自己写好循环脚本,调用 MCP 跑 Lumerical,然后解析输出文件里的透过率数据,最后生成一张汇总表。这就是从“人肉迭代”到“Agent 驱动”的本质变化。
这套链路适合的人群主要有三拨:一是刚接触 Lumerical、写脚本还比较吃力的人,Agent 能当“带教老师”;二是要做参数扫描、优化设计这类重复性工作的老手,直接省掉手工改脚本的时间;三是想在 Agent 开发上练手的技术爱好者,把 Lumerical 当成一个研习对象。
2. Lumerical 脚本语法与仿真环境准备
MCP Server 的设计必须依赖 Lumerical 的命令行语法,所以这块我会把我实际在用的脚本结构和自动化特性先讲清楚。熟悉 Lumerical 的人可以直接跳到 2.3。
2.1 理解 Lumerical 的脚本执行模型
Lumerical FDTD 的脚本执行其实和 Matlab 脚本很相似。一条命令对应一个操作,但区别在于 Lumerical 的脚本是“面向当前仿真对象”的:select("name"); set("property", value);这种选中再修改的模式贯穿始终。
最常用的几条命令如下:
addfdtd; set("dimension", "2D"); set("x min", -2e-6); set("x max", 2e-6); addmode; set("mode selection", "fundamental"); addport; set("port type", "monitor");这里要注意命名空间的概念。addfdtd创建的是 FDTD 求解区域对象,addmode创建的是模式光源,addport创建的是 S 参数端口。它们分别有自己的一套属性列表,这也是为什么模型需要“记住”每个对象有哪些属性,纯靠常识推理很容易踩坑。
2.2 使用非交互式模式跑批处理脚本
Lumerical 提供了一个特别适合自动化的命令行入口。官方文档里的标准做法是:
cd /path/to/project /opt/lumerical/fdtd/fdtd-solutions -run simulation.lsf -log log.txt注意不同版本的进程名会有一点差别,新版 2025 R1 的入口是fdtd-solutions,旧版可能叫fdtd-engine或者fdtd-runner。你可以在安装目录的bin下找到实际的可执行文件名。
-run参数后面接主脚本,-log指定输出日志文件。这个日志文件就是后续 Agent 判断仿真是否成功、是否收敛、哪些警告出现过的唯一事实依据。我强烈建议你在 Lumerical 脚本里显式加上进度输出,比如:
? "Step: building structure"; # 中间内容 ? "Step: starting FDTD run";这样在 log 文件里能看到清晰的阶段信息,后面设计 MCP Server 时就方便多了。另外,批处理模式跑完后会自动退出,非常适合 Agent 在无人工干预情况下反复执行。
2.3 从零搭起一个可复用的仿真脚本模板
我基于一个 MIM(金属-绝缘体-金属)波导透射仿真项目整理了模板。这类结构在表面等离激元研究里特别常见,拿来做 Agent 演示刚刚好。这个模板包含了:定义结构尺寸、添加 FDTD 区域、添加光源和监视器、运行仿真、导出 S 参数。
# metal-insulator-metal waveguide transmission # 单位:米 deleteall; # 定义结构参数 wgap = 50e-9; # 绝缘层宽度 hmetal = 100e-9; # 金属厚度 wavelength_min = 0.8e-6; wavelength_max = 1.6e-6; # 添加 FDTD 区域 addfdtd; set("dimension", "2D"); set("x min", -0.5e-6); set("x max", 0.5e-6); set("y min", -0.3e-6); set("y max", 0.3e-6); set("mesh accuracy", 4); # 添加金属层+介质层 addrect; set("name", "metal1"); set("x min", -0.5e-6); set("x max", 0.5e-6); set("y min", -0.15e-6); set("y max", -0.05e-6); set("material", "Au (Gold) - CRC"); addrect; set("name", "dielectric"); set("x min", -0.5e-6); set("x max", 0.5e-6); set("y min", -0.05e-6); set("y max", 0.05e-6); set("material", "SiO2 (Glass) - CRC"); addrect; set("name", "metal2"); set("x min", -0.5e-6); set("x max", 0.5e-6); set("y min", 0.05e-6); set("y max", 0.15e-6); set("material", "Au (Gold) - CRC"); # 添加模式光源 addmode; set("name", "source1"); set("direction", "forward"); set("mode selection", "user select"); set("wavelength", 1.0e-6); # 添加透射监视器 addpower; set("name", "t_monitor"); set("monitor type", "2D Z-normal"); # 运行仿真 run; # 保存结果 sweep;这份脚本直接喂给 Lumerical 就能跑出一个基础 MIM 结构。但它的发射模式光源位置、监视器区间都需要按实际尺寸改一改。Agent 的“聪明”就在于它能根据你的描述(比如“把波长改成 1.55 微米”),精准地去修改这些参数而不是重写整个脚本。
2.4 给 Agent 做权限设计的三条心得
我也得吐槽一句:如果完全不约束 Agent,它会干出很多离谱的事,比如在错误的目录里创建文件、或者莫名其妙地跑一条危险命令。Cline 提供了比较细致的权限配置,我总结三条实际操作心得:
- 只允许 Lumerical 相关命令自动执行:在 Cline 的权限配置里设 allowlist,把
fdtd-solutions、python、ls、cat放进去。其余命令交给人工确认。 - 脚本文件写操作要谨慎:我允许 Agent 创建和修改
.lsf和.py文件,但内核文件和配置文件目录设为只读,防止 Agent 为了满足一个模糊需求去改环境变量。 - 强制 MCP Server 的日志落盘:MCP 返回的信息一定要保留原始 stdout 和 stderr,这点在后面排查问题时会让你少掉很多头发。
3. 自定义 MCP Server 的完整实现
MCP Server 是整个系统的“手”。DeepSeek 知道该做什么,但真正去执行 Lumerical 命令、读取输出、解析数据得靠这个 Server。MCP 协议本身是个 JSON-RPC 2.0 规范,我直接用 Python 的mcp官方库实现,最省事。
3.1 MCP 协议原理简化和 Server 骨架
MCP 的核心逻辑就三个词:工具列表(tools/list)、工具调用(tools/call)、结果返回。LLM 通过 MCP 客户端(这里就是 Cline)拿到工具列表,按需调用,然后把结果文本拼回上下文里继续推理。
我实现的 Server 骨架大概是:
from mcp.server import Server from mcp.server.stdio import stdio_server from pydantic import BaseModel app = Server("lumerical-mcp") class RunScriptRequest(BaseModel): lsf_path: str timeout_seconds: int = 300 @app.tool() async def run_lumerical_script(lsf_path: str, timeout_seconds: int = 300) -> str: """在本地运行 Lumerical 脚本。返回输出的日志内容。""" # 使用 subprocess 捕获 stdout/stderr # 注意给 Lumerical 足够的超时时间 # 解析 log 文件中的关键步骤和警告 pass @app.tool() async def get_simulation_progress(log_path: str) -> str: """读取 Lumerical 日志文件,提取仿真进度和收敛情况。""" pass @app.tool() async def parse_s_parameters(result_dir: str) -> str: """从 Lumerical 输出的结果目录中解析 S 参数并返回表格。""" pass def main(): stdio_server(app) if __name__ == "__main__": main()这里每个@app.tool()装饰的函数都带 docstring,这很重要,因为 MCP 的 tools/list 接口会把函数名和 docstring 直接暴露给大模型,模型靠这些说明来判断什么时候调用哪个工具。我就是靠 docstring 做到了“让 DeepSeek 知道该在什么场景下跑脚本”。
3.2 run_lumerical_script 的实现细节
这个工具是整个 Server 里最核心的。Lumerical 批处理模式执行命令时,如果脚本里有运行时错误,返回码可能是 0,但 log 里却写着error: invalid index。所以不能只看返回码,必须同时收集 stdout 和 log 内容。
我实际用的实现长这样:
import subprocess, os, time LUMERICAL_BIN = "/opt/lumerical/fdtd/fdtd-solutions" async def run_lumerical_script(lsf_path: str, timeout_seconds: int = 300) -> str: log_path = lsf_path.replace(".lsf", "_run.log") command = [LUMERICAL_BIN, "-run", lsf_path, "-log", log_path] try: proc = subprocess.run( command, capture_output=True, text=True, timeout=timeout_seconds ) except subprocess.TimeoutExpired: return "错误:脚本执行超时,请检查网格精度或结构尺寸是否合理。" if not os.path.exists(log_path): return f"没有生成日志文件。stdout: {proc.stdout[-2000:]}" # 读取 log 末尾 3000 字符,做摘要 tail_content = read_log_tail(log_path, 3000) # 检查关键词 if "FDTD simulation finished successfully" in tail_content: return f"仿真完成。末尾日志: {tail_content}" if "error" in tail_content.lower(): return f"仿真疑似出错。末尾日志: {tail_content}" return f"不确定状态,末尾日志: {tail_content}"有个我实际踩过的坑得提醒你:Lumerical 第一次加载时特别慢,尤其是结构复杂时启动引擎可能需要 1~2 分钟。如果你设置的timeout_seconds太短,比如 60 秒,大概率会误判为“死机”。我在 MCP Server 里给的默认值是 300 秒,遇到特别复杂的 3D 仿真会临时调到 900 秒。
3.3 parse_s_parameters 的日志与数据解析
Lumerical 的项目文件是.fsp格式,结果矩阵存在项目内部,不是简单的文本。但 Lumerical 脚本里可以用export命令把数据导成 CSV 或 mat,这样 MCP Server 解析起来就容易多了。
我给 Lumerical 脚本的尾部加了一段数据导出:
select("t_monitor"); T = transmission("t_monitor"); write("transmission_vs_wavelength.csv", T);parse_s_parameters这个工具要做的,就是读这个 CSV,取其中的wavelength列和T列,转成 Markdown 表格返回。
import csv def parse_s_parameters(result_dir: str) -> str: csv_path = os.path.join(result_dir, "transmission_vs_wavelength.csv") rows = [] with open(csv_path, "r") as f: reader = csv.reader(f) for i, line in enumerate(reader): if i < 2: continue if len(line) >= 2: rows.append((float(line[0]), float(line[1]))) table = "| 波长 (m) | 透过率 |\n|---|---|\n" for wl, t in rows[:20]: table += f"| {wl:.4e} | {t:.4f} |\n" return table这里有个 CSV 格式兼容问题:Lumerical 在不同版本里导出的 CSV 列顺序不太一致。老版本可能是“波长 / T”,新版本 2025 R1 会多一列 “frequency/THz”。所以解析时我不写死列号,而是先读表头,再匹配列名。
3.4 MCP Server 的注册与 Cline 接线
MCP Server 写完后要注册到 Cline 里。Cline 支持 stdio 模式,也就是通过标准输入输出通信,特别适合本地进程。
在 Cline 的 MCP 配置界面,添加一个 server,指向:
{ "mcpServers": { "lumerical-mcp": { "command": "python", "args": ["/path/to/lumerical_mcp_server.py"], "env": {} } } }这里有个高频报错:Cline 里显示MCP connection failed。排查看两点,第一是 Python 环境是否包含了mcp包,第二是路径是否有拼写错误。最笨但最有效的方法是在终端里直接手动跑一次python /path/to/lumerical_mcp_server.py,如果终端能跑起来,Cline 大概率也能连上。如果提示ModuleNotFoundError: mcp,检查是不是 VSCode 用的 Python 解释器和终端用的不是同一个。这种环境错位问题属于 Cline 里最常见的新手坑。
3.5 给 MCP 工具设计“失败反馈”而不是“失败抛错”
这是我从多次实测里悟出来的一个设计原则。MCP 工具只要是抛异常,Cline 会把红色 stack trace 返回给模型,模型很容易被一堆报错信息搞晕。但如果我们把失败结果当作正常文本返回,比如:
仿真失败。日志最后 500 字: error: port 1 has no mode. 原因通常是结构宽度小于模式尺寸。模型就能根据这个“解释型反馈”自主修改结构参数重跑。我建议所有 MCP 工具都走“收尾不抛错,错误描述化”的路子。很多 Agent 拉起一个服务时动不动就挂,问题其实就出在把“异常机制”当作“状态反馈”来用了。
4. Cline + DeepSeek 配置与模型适配
Cline 目前支持多种模型后端,本地跑 DeepSeek 最自然的方式是走 OpenAI 兼容接口。DeepSeek 官方 API 提供https://api.deepseek.com/v1这个 OpenAI 兼容入口。Cline 里新建模型配置时,选 OpenAI Compatible,然后填模型名deepseek-chat。这里有个容易搞混的点:DeepSeek 官方网站上模型名是deepseek-chat或deepseek-reasoner,不是deepseek-v3这种叫法。很多人配置完提示 404,就是模型名写错了。
4.1 Cline 的模型配置参数实测
Cline 的模型配置页面里有几个参数决定它的性能和速度。我实测下来,建议这样配:
{ "apiProvider": "openai-compatible", "baseUrl": "https://api.deepseek.com/v1", "apiKey": "sk-xxxxxx", "model": "deepseek-chat", "temperature": 0.1, "maxTokens": 8192 }temperature一定要调低,这算是我踩过最便宜的坑了。默认值可能是 0.7,用于写诗可以,用于改脚本就是灾难。我调到 0.1 之后,生成 Lumerical 脚本的语法错误率瞬间下降了一个量级。原因也不复杂,做仿真脚本本质上是强语义、强约束的代码生成,不是创意写作,温度越高越容易“自由发挥”。
maxTokens建议给 8192。Lumerical 脚本动辄几十行,加上 Cline 会注入上下文和各种工具返回结果,token 太短会导致模型“说到一半就被掐断”。Cline 对长输出的处理是拼接,但如果超出了模型的最大上下文,就会出现奇怪的现象——比如脚本写到一半停了或者漏掉run;命令。
4.2 Cline 提示词策略:把 Lumerical 的“行业知识”写进系统提示词
模型不认识 Lumerical 的材质库是正常现象。DeepSeek 预训练语料里当然有 Lumerical 相关内容,但不够系统。为了让 Agent 表现稳定,我在 Cline 的 system prompt 里补充了 Lumerical 领域知识。你可以直接在 Cline 设置里追加自定义提示词。
我实际用的系统提示词模板大概是:
你是一名 Lumerical FDTD 仿真专家。你的任务是通过 MCP 工具完成用户的光学仿真需求。 规则: 1. 脚本必须保存为 .lsf 格式,使用 Lumerical 原生命令,不得使用 Python API。 2. 修改参数前先理解结构几何关系,特别注意 x/y 方向尺寸匹配。 3. 若仿真报错,优先查看日志内容,并根据错误描述修正脚本后重试,不要重复提交相同脚本。 4. 数值上注意单位:Lumerical 默认米,波长在近红外范围约 1e-6 量级。 5. 结果整理必须用 Markdown 表格输出,列出波长和对应透过率。这段提示词看似简单,但每一句都对应一个真实事故。第 4 句“单位默认米”就救过我一次。模型曾经在生成脚本时把1.55e-6误写成1.55e-9,结果模式光源波长直接落到紫外区,仿真结果完全变成一片噪声。
4.3 Cline 的allowlist与安全策略
Cline 的权限系统值得单独讲。它可以按命令类型设定是否需要人工确认,我推荐这样的分工,既保证自动化效率又不会失控:
| 权限范围 | 设置建议 | 理由 |
|---|---|---|
ls/cat | 允许 | 读取日志,模型需要自主查看 |
python启动 MCP Server | 允许 | 工具链基础,不弹窗效率高 |
fdtd-solutions -run | 允许 | 核心仿真执行,必须无阻塞跑通 |
rm/ 写系统目录 | 禁止 | 防止模型误删项目文件 |
安装依赖包pip | 人工确认 | 避免模型在无关环节浪费时间 |
Cline 里设置允许工具路径时注意必须写绝对路径。我一开始偷懒写了fdtd-solutions,结果 Cline 找不到命令,日志里回报ESLint错位信息,排了半天才发现是 PATH 问题。后来改成/opt/lumerical/fdtd/fdtd-solutions,问题直接消失。
4.4 为什么 DeepSeek 在这条链路里特别合适
DeepSeek 的 API 成本相对低,上下文窗口和指令遵循能力在同级别模型里相当能打,尤其适合这种“多轮工具调用 + 错误反馈修正”的高频对话场景。
Lumerical 脚本生成过程中,模型可能需要连续调用工具 5~6 次:写脚本、跑仿真、看日志、改参数、再跑、解析结果。DeepSeek 的长上下文和大吞吐量在这个循环里优势明显。相比之下,如果用一个上下文窗口小且费用高的模型,对话还没到第三次工具调用就超限了,Agent 的完整性根本撑不起来。当然 DeepSeek 偶尔也会在复杂的物理逻辑上犯糊涂,比如把金属负介电常数模型搞混,但瑕不掩瑜,配合提示词约束完全够用。
5. 一个完整仿真任务的实测过程
到今天为止,我已经用这套系统跑通了十几个仿真任务。这里挑一个最有代表性的案例完整复盘。这个案例用的是 MIM 波导透射谱仿真,任务本身很简单,但正好能把整套链路的所有环节串起来。
5.1 任务描述与 Agent 自动脚本生成
我给 Cline 下发的原始指令是:
请对 50 nm 绝缘层宽度的 MIM 波导结构扫描 1100 nm 到 1600 nm 的透射谱,步长 25 nm。结构材料用金和二氧化硅,2D FDTD。Cline 接到指令后,DeepSeek 在后台快速做了几件事:调用run_lumerical_script生成初版.lsf文件,脚本里自动写出addrect、addmode、addport、addpower,并定义了扫描循环;然后调用工具执行脚本;读取 log 判断是否跑完。
我实际看到它生成的脚本逻辑非常标准。模式光源波长设置在了中心 1.35 um,扫描步长 25 nm,FDTD 区域边界设置为-0.5e-6到0.5e-6,网格精度4,这些参数搭配合理,基本不需要人工干预。
5.2 仿真报错后 Agent 的自主修复过程
第一次跑完,日志里报了一个经典错误:boundary material not supported at x min boundary。这是 Lumerical 初学者最常遇到的问题。原因是模型生成的二维结构某一边界的材料被设置为金属,而 PML 边界条件无法直接吸收金属里的倏逝波,所以报错。
如果是人处理,得手动去脚本里检查每个addrect的坐标,找到哪个矩形在边界上并把它缩回去或改边界。但 Agent 的处理方式是:读取日志错误、定位问题发生在左边界、重新生成脚本,将x min从-0.5e-6调整为-0.45e-6,让金属层不要紧贴边界,再重跑。
整个过程我基本是盯着对话框看的,它在对话框里打了一行很简短的备注:“左边界金属紧贴 PML,PML 不支持金属介质边界,重新调整几何尺寸。”这个思路非常清晰,说明 DeepSeek 的领域知识被有效调动了。
5.3 数据回传与结果可视化
仿真完成后,Agent 调用了parse_s_parameters,从导出的 CSV 里提取波长和透过率,整理成 Markdown 表格。我要求它进一步画图,它就用 Python 的matplotlib生成了一张透射谱曲线图,保存在本地。
实测下来,从下发指令到拿到曲线图,大约耗时 7 分钟,其中 Lumerical 本身跑 FDTD 扫描花了 6 分多钟。也就是说真正“动脑”写脚本、调参数、查报错的时间不到 1 分钟。这对人工流程来说基本都是纯节省。
这里有个小细节必须提:第一次画图时 Agent 用错了列名索引,它把频率列当成了波长列。我用提示词提醒了一句“CSV 表头里有 wavelength 和 frequency 两列,注意区分”,它很快就修正了。也就是模型在某些局部判断上还是需要人“盯一眼”,但整体校正速度远快于以前手改脚本的节奏。
5.4 加速参数扫描的两种思路
上面的例子是单点波长扫描,但 Lumerical 里更常见的需求是扫结构尺寸。比如想找最优的绝缘层宽度从 40 nm 到 80 nm,步长 5 nm。这要是人工改脚本,得改九次,每改一次重跑一次。Agent 更聪明的做法是直接在.lsf里写一个循环:
for (wgap = 40e-9, wgap <= 80e-9, wgap += 5e-9) { set("name", "dielectric"); set("y min", -wgap/2); set("y max", wgap/2); run; T = transmission("t_monitor"); write("result_" + num2str(wgap/1e-9) + ".csv", T); }这种循环方式完全规避了反复启动 Lumerical 引擎的开销。就算网格精度设得高一点,整个参数扫描也可以在几分钟内完成。如果你要做的扫描维度更高,还可以把循环改成嵌套,或者配合sweep模块优化。Agent 对sweep的把握我觉得更接近“理解意图”而非“语法套用”,这恰恰是它最好用的地方。
6. 高频报错与排查记录
自动化流程跑多了,问题也随之积累。我把踩过的典型问题按出现频率和解决成本列了一张表,适合你搭环境时直接查。
| 症状 | 根因 | 解决手段 |
|---|---|---|
| Cline 连接 MCP Server 失败 | Python 环境不一致,mcp包没装进 VSCode 解释器 | 在 VSCode 内确认解释器路径,用命令行手动启动测通 |
| Lumerical 脚本运行后无输出 | -log路径不对,或脚本里没有run;命令 | 检查日志文件是否生成,加? "Step"埋点 |
仿真报错boundary material not supported | 金属材料紧贴 PML 边界 | 缩小结构区域,留出缓冲空间 |
| 透过率结果全为 0 | 监视器放在了模式光源后面,探测位置不对 | 检查监视器与光源的相对位置 |
| 脚本生成一半被截断 | maxTokens设置过小 | 提高到 8192 并降低 temperature |
| 模型反复使用同一个错误脚本 | MCP 工具没有返回充分的错误描述 | 确认错误信息里包含“根因 + 修改建议” |
| 数据 CSV 列错位 | Lumerical 版本升级后表头变化 | 解析时按列名匹配,不要按固定列号 |
6.1 “Lumerical FDTD run 卡在 updating modes” 的专项排查
这个问题值得单独立一个小节,因为它在很多仿真论坛里都是高频求助帖。特征特别明显:Lumerical 开始运行时没有报错,进度条停在updating modes,然后卡了十甚至二十分钟都不动。
我先说结论:这通常是模式光源的“模式计算”和“网格化”之间出现了死循环。当你设置了mode selection = "user select"但没有指定具体的模式序号,或结构宽度比模式有效尺寸还小时,Lumerical 会反复尝试更新模式轮廓但始终无法收敛。
用这套 Agent 排查这个问题特别有帮助。我给 MCP Server 加了一个检测逻辑:如果在日志里检测到updating modes字样且超过 2 分钟没有新输出,就主动返回“疑似模式计算卡死”。模型收到这个信息后,会自动把set("mode selection", "fundamental")改成set("mode selection", "user select"); set("mode", 1),然后重跑。
人工排查套路也放在这:先检查结构尺寸是不是“窄到模式穿不过”,其次检查是否忘记设置mesh accuracy,再次尝试先设一个非常粗的网格跑通流程,最后再把精度加上去。这套思路如果写进系统提示词,Agent 排查类似问题的速度会和熟练工一样。
6.2 Cline 连续报错自动停止怎么办
Cline 有一个内置保护机制:如果连续出现tool_execution错误达到一定次数(默认 6 次),它会自动停止任务。这个机制很有用,因为我见过模型在同一个错误脚本上反复打滚,没有这个保险,它能把 API 额度烧穿。
但反过来,如果错误是短暂的、可以修正的,自动停止就太“一刀切”了。我的处理方案是在提示词里明确写:
如果工具执行报错,先仔细读错误信息,不要立即重试。至少修改一处可能导致错误的条件后再执行。这招在明显降低连续报错概率。另外,Cline 右上角有个“Auto-approve”滑杆,调成允许工具执行后,配合上面的提示词,能极大减少人工打断次数。
6.3 模型对 Lumerical 材质名称的误识别
我遇到过一个特别刁钻的场景:模型生成脚本时,把金材料的名称写成了"Au (Gold)",但 Lumerical 材质库里的实际名称是"Au (Gold) - CRC",后者的 CRC 后缀代表复折射率数据来源。这个差异直接导致 Lumerical 在加载材质时报警,而模型因为对材质库不熟悉,完全无法意识到问题。
解决方法是把 Lumerical 材质库的关键名称提前写进 MCP Server 的返回信息里。我加了一个get_material_list工具,它返回材质库前缀匹配结果列表。模型拿到候选名称后再写脚本,准确率直接从 70% 拉到了接近 100%。
这个例子再次验证了一个原则:凡是“知识盲区”,都尽量通过 MCP 工具暴露成“即时查询”,不要指望模型靠预训练记忆。把材质库、命令集、属性表这些静态信息做成工具,比塞进提示词更优雅、更准确。
7. 后面可以继续做的方向
整套系统跑通后,我陆续做了一些横向扩展,有些已经落地,有些还在尝试,写下来给你做参考。
把 Lumerical 和 Python 的优化算法接起来是一个很自然的方向。比如用遗传算法或贝叶斯优化去自动搜索结构参数,目标函数由 Lumerical FDTD 计算。Agent 可以每轮负责把候选参数写进.lsf、跑仿真、把透过率返回给优化器。这个闭环一旦跑起来,就是一个真正意义上的“AI 驱动光子设计”雏形。
另一个方向是让 MCP Server 支持更多命令,比如get_field_profile用于提取电场分布、export_near_field用于导出近场数据。字段类和 S 参数类数据的处理逻辑完全不同,需要单独设计。我可以明确告诉你,Lumerical 的场数据导出文件名后缀和 S 参数不一样,解析的时候也得重新写函数。
把对话记录和仿真日志做成自动档案也是个很实用的扩展。每次仿真结束,Agent 自动生成一个 Markdown 报告,包含脚本、日志、结果图和结论。这对做课题研究、留实验记录、向合作方同步进展都非常有价值。Cline 本身有对话记录,但格式比较零散,建议用 MCP Server 单独做结构化落盘。
如果你对 Agent 本身更感兴趣,MCP Server 还可以加一个“自检模式”:让模型定期检查自己的历史操作,找出重复犯错的动作并更新提示词。这是 Agent 自我进化的一个极简实现,虽然还很粗糙,但已经能看到效果了。
这套链路本质上就是用 Agent 把“想”和“做”之间的摩擦降到最低。对光学仿真这种重工具、重经验、重迭代的领域,它的价值会越来越明显。后面我也会持续把这套 MCP Server 的能力往外扩展,争取让 Lumerical 项目里的重复劳动越来越少。