AI写AutoLISP总翻车?TmAgent执行验证闭环让代码自己跑通

发布时间:2026/10/20 20:21:53
AI写AutoLISP总翻车?TmAgent执行验证闭环让代码自己跑通 1. 为什么“AI 写完 AutoLISP 直接交付”这件事一直不靠谱AutoLISP 这门语言在工程制图圈子里属于典型的“小众但刚需”。它跑在 CAD 环境内部语法古老、调试手段原始很多写法依赖宿主环境的运行时状态。你让一个通用大模型直接吐一段 AutoLISP 出来它大概率能给你一段“看起来很像”的代码——括号配对没问题函数名也眼熟但一加载就报错或者更糟不报错但画出来的东西是错的。我最早尝试用 AI 辅助写 AutoLISP 的时候踩的就是这个坑。当时的需求很简单批量给一批图元按图层改颜色再统计数量输出到命令行。AI 给的代码逻辑上没毛病ssget过滤、entmod修改、princ输出结构完整。但实际跑起来ssget的过滤条件里用了一个在当前 CAD 版本里已经废弃的组码结果选择集永远是空的程序“成功”跑完什么都没改。这种“静默失败”比直接报错更可怕因为你以为它干完了。这就是标题里那个核心痛点的来源AI 生成代码的能力已经够用了缺的是“自己跑通、自己确认结果正确”的闭环。TmAgent 这类智能体框架的价值不在于它能写 AutoLISP而在于它能驱动一个真实的 CAD 环境去执行、去验证、去根据反馈修正。换句话说它把“写代码”和“验证代码”这两件事绑在了一起而不是把验证的锅甩给用户。这篇文章我想聊的就是这套思路的完整落地怎么让一个智能体真正把 AutoLISP 跑起来怎么设计验证环节让它能判断“结果对不对”以及在这个过程中有哪些只有实际做过才会知道的坑。适合已经会用 AutoLISP 做基础自动化、想进一步把 AI 引入工作流的工程师也适合对智能体落地感兴趣、想找一个具体场景练手的开发者。2. TmAgent 驱动 AutoLISP 的执行闭环到底长什么样2.1 拆解“写完就跑通”需要的四个能力很多人对“AI 编程助手”的想象是我描述需求它给代码我复制粘贴。这个模式在 AutoLISP 上基本行不通因为 AutoLISP 没有独立的编译运行环境它必须寄生在 CAD 进程里。所以一个能“自己跑通”的智能体至少要具备四个能力缺一不可。第一个是代码生成能力这个现在的大模型都具备但要注意 AutoLISP 的语料相对稀少模型容易把其他 Lisp 方言的写法混进来比如把 Common Lisp 的setf当成 AutoLISP 的赋值用这是高频错误。第二个是环境注入能力。智能体得知道怎么把生成的代码送进 CAD。常见做法有两种一种是通过 CAD 的命令行接口把代码写成临时文件再用load加载另一种是通过进程间通信直接把表达式发给运行中的 CAD 实例。前者简单但每次都要落盘后者响应快但对环境配置要求高。第三个是执行监控能力。代码送进去之后智能体要能拿到执行结果——是正常返回、还是抛了异常、还是卡住了。AutoLISP 的错误处理比较弱很多错误不会中断整个程序而是返回nil继续往下跑所以监控不能只看“有没有崩”还要看关键变量的值。第四个是结果验证能力这也是最容易被忽略的一环。验证分两个层次语法层验证代码能不能加载和语义层验证执行结果符不符合预期。前者靠 CAD 的加载反馈就行后者需要智能体自己设计断言比如“修改后图层 A 的图元数量应该等于修改前的数量”“新生成的图元坐标应该落在指定范围内”。把这四个能力串起来才构成一个完整的闭环。我见过不少方案只做了前两个生成完注入进去就完事结果就是用户还得自己盯着看对不对那智能体的价值就打了对折。2.2 一个最小可用的执行链路设计具体到实现层面我建议的最小链路是这样的智能体先生成代码同时生成一段“验证脚本”两者一起注入 CAD。验证脚本负责在代码执行后检查关键状态把结果写到一个约定的输出位置智能体再读取这个输出判断成败。这里有个设计上的取舍值得说。为什么不把验证逻辑直接写在主代码里因为主代码是要交付给用户用的塞一堆验证逻辑进去会污染代码而且用户环境里未必有验证需要的辅助函数。把验证脚本独立出来主代码保持干净验证只在智能体的工作流里跑交付时只给主代码。这个分离思路很重要后面讲交付环节还会用到。验证脚本的写法有讲究。AutoLISP 里做断言不像 Python 那么方便没有现成的assert。我的做法是定义一个简单的检查函数把“期望值”和“实际值”传进去不相等就往一个全局列表里追加错误信息。代码执行完后智能体读取这个列表空的就是通过非空就带着错误信息回去让模型修。;; 验证辅助函数示例 (setq *verify-errors* nil) (defun vcheck (label expected actual) (if (not (equal expected actual)) (setq *verify-errors* (cons (strcat label : expected (vl-princ-to-string expected) , got (vl-princ-to-string actual)) *verify-errors*))))这段代码本身很简单但它是整个闭环的支点。没有它智能体就只能靠“代码跑完没报错”来判断成功而 AutoLISP 的静默失败会让这个判断完全失效。2.3 为什么验证脚本必须由智能体动态生成有人可能会想验证脚本能不能写死一套通用的答案是基本不行。因为验证的内容高度依赖具体任务。改颜色的任务要验证颜色值画线的任务要验证端点坐标统计的任务要验证计数。通用验证脚本只能检查“有没有报错”检查不了“结果对不对”。所以验证脚本必须和主代码一起由智能体根据需求动态生成。这对智能体的要求就高了一层它不仅要理解“要做什么”还要理解“做完之后怎么判断做对了”。这其实是一个很好的约束因为一个连验证方法都想不出来的需求往往本身就是模糊的逼着智能体在生成阶段就把需求想清楚。我在实际用的时候发现让智能体先写验证脚本、再写主代码效果比反过来好。因为写验证的过程会倒逼它明确“输入是什么、输出是什么、中间状态怎么变”主代码反而写得更准。这个顺序上的小技巧是我试了好几轮才总结出来的。3. 让智能体判断“结果正确”的验证策略设计3.1 从“跑通”到“跑对”的鸿沟“跑通”和“跑对”之间的差距在 AutoLISP 场景里被放得特别大。原因前面提过AutoLISP 的错误处理机制太宽松。一个函数调用失败返回nil如果调用方没检查返回值程序会若无其事地继续执行下一行。等整个程序跑完你看到的是“命令执行完毕”但中间可能有一半的操作根本没生效。我遇到过一个典型案例批量偏移多段线。代码逻辑是遍历选择集对每个多段线调用vla-offset。问题在于当偏移距离过大导致自交时vla-offset会失败返回nil但代码没检查继续处理下一个。最后程序报告“处理完成”实际上有一批多段线被跳过了用户拿到结果还以为全处理了。要避免这种情况验证策略必须覆盖到“每个操作单元”的层面而不是只看整体有没有崩。具体来说我通常会让智能体设计三层验证。第一层是前置条件验证在操作前检查输入是否符合预期。比如选择集是否为空、目标图层是否存在、关键参数是否在合理范围内。这一层能在问题发生前就拦住一部分错误。第二层是操作结果验证每个关键操作后检查返回值或状态变化。比如entmod之后重新读取实体属性确认修改生效vla-offset之后确认返回了新对象而不是nil。第三层是后置状态验证全部操作完成后做整体检查。比如图元总数是否符合预期、关键属性是否全部正确、有没有遗漏的对象。三层验证叠起来才能把“静默失败”的空间压到最小。当然验证越密代码量越大执行越慢这里要根据任务的重要程度做权衡。对于一次性的小工具可能只做第三层就够了对于要反复用的批处理三层都值得加上。3.2 用“预期状态快照”做对比验证有一种验证思路我觉得特别适合 AutoLISP就是“预期状态快照对比”。做法是在操作前把关键状态记录下来操作后重新记录然后对比差异是否符合预期。举个例子任务是“把所有红色图元改成蓝色”。操作前智能体先统计红色图元的数量 N。操作后检查红色图元数量是否为 0蓝色图元数量是否增加了 N。如果红色还剩几个说明有遗漏如果蓝色增加的数量对不上说明有误改。这个对比逻辑简单但非常有效能抓住绝大多数逻辑错误。实现上快照可以用关联列表存键是图层名或颜色值值是数量。对比的时候遍历预期键逐个检查。这种结构在 AutoLISP 里用assoc和cdr就能操作不需要复杂的数据结构。;; 统计指定颜色图元数量的快照函数 (defun snapshot-by-color (color / ss count) (setq count 0) (if (setq ss (ssget X (list (cons 62 color)))) (setq count (sslength ss))) count)用这个函数操作前后各调一次对比返回值就能判断修改是否完整。这种“用数据说话”的验证方式比让智能体去“读代码判断逻辑对不对”可靠得多因为代码逻辑可以自洽但结果错误而数据对比是骗不了人的。3.3 验证失败后的自动修复循环怎么设验证失败之后怎么办这是区分“玩具”和“工具”的关键。如果验证失败只是报个错让用户自己改那智能体的价值还是有限。真正有用的是让它带着失败信息回去自动修复。修复循环的设计要注意几点。首先是重试次数要有上限我一般设 3 次。AutoLISP 的很多错误是环境相关的模型再聪明也修不了比如 CAD 版本不支持某个函数重试多少次都没用不如早点放弃让用户介入。其次是失败信息要具体。不能只说“验证失败”要把哪个检查项失败、期望值多少、实际值多少都带上。模型拿到具体信息才能定位问题。前面那个vcheck函数把 label、expected、actual 都记下来就是为了这个。第三是修复要有策略。我观察到模型在修复时容易“过度修改”把原本没问题的部分也改了结果引入新 bug。所以我会在提示里明确要求“只修改与失败项相关的代码其他部分保持不变”。这个约束能显著提高修复成功率。实际跑下来大部分问题在第一次修复就能解决少数需要两次。三次还修不好的基本就是需求本身有问题或者环境不支持这时候让智能体输出一份“失败分析报告”说明它尝试了什么、卡在哪里对用户也有参考价值。4. 交付前的最后一道关把验证结果变成可读的交付说明4.1 交付物不只是代码智能体跑通验证之后交付给用户的不应该只是一段代码。用户需要知道这段代码干了什么、怎么用、验证过哪些点、有什么限制。这些信息如果让用户自己去读代码总结那智能体的价值又打了折扣。我的做法是让智能体在验证通过后自动生成一份简短的交付说明包含四块内容功能描述、使用方法、验证结论、已知限制。功能描述用一两句话讲清楚代码做什么使用方法说明怎么加载、怎么调用、需要什么前置条件验证结论列出实际验证了哪些检查项、结果如何已知限制说明在什么情况下可能不适用。这份说明不需要很长但要具体。比如验证结论不能只写“验证通过”要写“验证了图元数量守恒、颜色值正确、无遗漏对象”这样的具体项。用户看到这些才能对代码的可靠性有个判断。4.2 把验证证据一并附上比交付说明更进一步的做法是把验证过程中的关键证据也附上。比如操作前后的状态快照对比、关键检查项的通过记录。这些证据让用户能自己复核而不是只能信任智能体的结论。我通常会让智能体把验证输出整理成一个简单的表格列出每个检查项、期望值、实际值、结论。这个表格在验证脚本执行时就能生成不需要额外工作。用户拿到这个表格一眼就能看出代码在哪些方面被验证过、哪些方面没覆盖到。检查项期望值实际值结论红色图元数量00通过蓝色图元数量原红色数原蓝色数匹配通过图元总数操作前总数匹配通过图层属性完整性无变化无变化通过这种表格的价值在于它把“智能体说没问题”变成了“数据说没问题”。用户对智能体的信任应该建立在这种可复核的证据上而不是盲信。4.3 交付说明里必须写清楚“没验证什么”这一点我觉得特别重要但很容易被忽略。验证再全面也总有覆盖不到的地方。诚实地说明“没验证什么”比假装什么都验证了更专业。比如一个批量修改图元的工具验证可能覆盖了数量、颜色、图层这些属性但没验证修改后图元的显示顺序、没验证在极端数据量下的性能、没验证在特定 CAD 版本下的兼容性。这些“没验证”的点用户在实际使用时可能会碰到提前说明能帮他们规避风险。让智能体生成这部分内容其实也是在训练它对自己的输出保持诚实。一个总是宣称“完全正确”的智能体反而让人不敢用。承认边界才是可靠的表现。5. 实操中踩过的坑和几条硬经验5.1 括号配对只是最低要求别被它骗了AutoLISP 最出名的就是括号多所以很多人把“括号配对”当成代码正确的标志。但括号配对只是语法正确的最低要求配对正确但逻辑错误的代码太常见了。我见过把if的 then 分支和 else 分支写反的括号完全正确结果完全相反。所以验证绝对不能停在“能加载”这一层。能加载只说明语法没问题说明不了任何逻辑问题。真正的验证必须跑到语义层检查执行结果。这一点我在前面反复强调因为它是整个方案成立的前提。5.2 选择集操作是静默失败的重灾区如果要选一个 AutoLISP 里最容易出静默失败的地方我投选择集操作一票。ssget的过滤条件写错返回空集后续遍历直接跳过程序正常结束。ssadd、ssdel操作失败也是返回nil不报错。这些地方如果不加检查问题会一直藏着。我的经验是凡是涉及选择集的地方操作后都要检查一下集合是否为空、长度是否符合预期。这个检查成本很低但能拦住大量问题。具体做法是在遍历前加一句判断集合为空就记录一条警告而不是默默跳过。5.3 别让智能体在验证脚本里“偷懒”智能体生成验证脚本时有个倾向是写得过于宽松。比如检查数量时用“大于 0”而不是“等于预期值”检查坐标时用“在某个大范围内”而不是“精确匹配”。这种宽松验证看起来通过了实际上没起到把关作用。我的应对办法是在提示里明确要求“验证条件要尽可能严格能用等号就不用范围能精确匹配就不模糊匹配”。同时我会抽查几次生成的验证脚本发现偷懒就调整提示。这个调优过程需要几轮但一旦调好后面就稳定了。5.4 执行超时和死循环的兜底AutoLISP 代码如果写了死循环CAD 会直接卡死智能体也跟着卡住。这种情况必须有兜底。我的做法是在执行环节加超时控制超过设定时间就强制中断把控制权收回来。超时时间设多少要看任务复杂度简单的属性修改几秒就够复杂的批量处理可能要几十秒。我一般设 30 秒作为默认值特殊任务再调。中断之后智能体要能判断是“任务太复杂”还是“代码有死循环”前者可以提示用户拆分任务后者要回去修代码。5.5 版本兼容性是个绕不开的坎AutoLISP 在不同 CAD 版本之间是有差异的有些函数在新版本里废弃了有些行为变了。智能体如果不知道目标版本生成的代码可能在某些版本上跑不了。我的处理方式是在任务开始时就让用户指定目标版本把这个信息作为约束传给智能体。如果用户不确定就按较老的版本生成因为老版本能跑的代码通常在新版本也能跑反过来不一定。这个策略不完美但能减少大部分兼容性问题。6. 这套方案适合什么场景不适合什么场景6.1 最适合的是“规则明确、结果可量化”的任务这套方案在规则明确、结果可量化的任务上效果最好。比如批量修改属性、按条件筛选统计、标准化图层命名、生成规则图形。这些任务的共同点是“做对了什么样”很容易定义验证脚本好写智能体的闭环能跑得很顺。我实际用下来这类任务的首次通过率能到七八成剩下的一两次修复基本能解决。这个成功率已经能显著提升效率了尤其是那些重复性的、逻辑不复杂但写起来烦的活儿。6.2 涉及复杂交互和主观判断的任务要谨慎反过来涉及复杂用户交互或者主观判断的任务这套方案就不太适用。比如需要用户在运行过程中做选择的工具或者“美观”“合理”这种没法量化的标准验证脚本很难写智能体也没法判断做得好不好。这类任务不是不能做而是验证环节要弱化更多依赖用户自己判断。这时候智能体的价值就退回到“帮你写代码”闭环的那部分用不上。认清这个边界能避免在不合适的场景上浪费时间。6.3 一次性脚本和长期工具的投入产出比不同还有一点值得考虑的是投入产出比。如果只是写个一次性用的小脚本花大力气设计验证可能不划算简单跑一下看看结果就行。但如果是会反复使用的工具或者要交给别人用的那验证的投入就非常值得因为一次验证能省下后面无数次的排查。我的建议是对于要交付给他人的工具验证环节一定要做扎实因为别人不会像你一样了解代码的边界出了问题排查成本很高。对于自己临时用的小脚本可以适当简化但基本的数量检查还是要有防止静默失败。7. 我对这套工作流的一点个人体会用这套方案跑了一段时间之后我最大的感受是智能体的可靠性不取决于它写代码多聪明而取决于它的验证多严格。一个写代码一般但验证扎实的智能体比一个写代码漂亮但验证敷衍的智能体有用得多。因为前者你知道它交付的东西是经过检验的后者你永远得自己再验一遍。另一个体会是验证脚本的设计能力其实是比代码生成能力更稀缺的。让模型写一段 AutoLISP 不难让它设计一套能抓住问题的验证方案需要它对任务本质有更深的理解。这也是为什么我在提示里会花不少篇幅引导它先想清楚“怎么算做对了”再动手写代码。最后分享一个小技巧如果你也在搭类似的流程不妨先从最简单的任务开始把验证闭环跑通再逐步增加任务复杂度。我一开始就想做个能处理各种情况的通用工具结果验证逻辑复杂到没法维护。后来退回到“一次只做一类任务”反而跑得很稳。这个从简到繁的路径比一上来就追求大而全要靠谱得多。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询