我太懂那种感觉了:从AI那边复制一段代码,自信满满地粘贴进项目,回车运行,然后屏幕上冒出一串红色报错。这时候脑子里全是“AI也不行啊”的念头,但说实话,在你点关闭报错窗口之前,真正的问题往往被情绪盖住了。AI生成的代码跑不通,不是你运气差,而是缺一套固定的抢救顺序。我这些年用AI写脚本、接业务需求、做辅助工具,踩了无数坑之后,总结出了一套流程,从最开始只会乱试一通,到现在绝大多数代码都能按顺序救回来。这篇文章就是把这套顺序完整摊开,适合所有经常把AI当作编码帮手、但一看到报错就头大的人。
1. 先别急着改,给“跑不通”分个类
1.1 三种死法:环境、API、逻辑
AI生成的代码跑不通,别上来就怀疑算法逻辑,绝大多数时候问题根本不在那里。我习惯把跑不通的现场分成三类。
第一类是环境问题。AI不知道你的机器上装着什么版本的Python、Node、数据库、驱动,也不知道你有没有装它用的那个包。举个例子,我让AI写一个操作Excel的脚本,它直接用了pandas,结果我本机压根没装pandas,一运行就是ModuleNotFoundError。再比如AI生成了一段依赖某个硬件的C代码,里面用到的头文件在你当前的开发环境里根本不存在,编译直接就死。这类问题特征很明显:报错集中在import、安装、编译、环境变量、路径相关的位置。
第二类是语法与API版本问题。AI的记忆是一种模糊的概率组合,它会把各个年代的代码风格混在一起。我收到过把Python 2的xrange直接写进Python 3脚本的代码,也见过在Pandas新版里调用已经被移除的df.ix接口导致AttributeError的情况。还有一次更典型,AI为前端项目生成了一段用process.env读环境变量的代码,项目跑起来直接报process is not defined,因为浏览器环境根本没有process这个对象。这都属于“代码在某个环境里可能是对的,但放在你的环境里就是错的”。
第三类是逻辑问题。代码能跑,但结果不对:排序排错、循环进了死胡同、递归少了终止条件、SQL插进去的数据跟预期不符。这类问题最隐蔽,也最耗时间,但在AI生成的“跑不通”场景里,占比其实比你想的低得多。我自己的观察,至少六成是环境与依赖,三成是API版本,真正需要掰扯算法逻辑的,不到一成。搞清楚这个分布,你就知道该从哪里下手了。
1.2 学会用报错前三行做“定位”
很多人在看到报错的时候,习惯性只扫一眼“Error”附近几个单词,然后就去问AI“为什么报错”。这是效率最低的方式。报错信息本身就是最好的线索,关键你要知道看哪里。
不管什么语言,报错信息里通常有三样东西值得看:错误类型、错误描述、出错位置。以Python为例,TypeError: unsupported operand type(s) for +: 'int' and 'str'告诉你类型出了问题,某个地方拿int和str相加了;File "test.py", line 9告诉你在第几行。MySQL的1064错误更直接,near 'xxx' at line 1会指给你看SQL语句从哪里开始出问题。JavaScript的运行时错误,要重点关注stack trace里最后一个由项目代码产生的调用帧,那个往往才是真正的根源,前面的框架内部帧大多是噪音。
有个细节值得单独提一下:永远复制完整报错,所有行都复制,不要自己觉得“重点信息我已经抄下来了”。很多AI生成代码的报错信息里,包含了一段完整SQL、一个变量名、一段失败数据,这些恰恰是判断原因的关键。只截两三行去问AI,信息量完全不够。
1.3 为什么排查顺序必须是:环境、语法、逻辑
这个顺序不是我拍脑袋定的,是大量翻车经历磨出来的。先说环境为什么优先。AI生成代码时,脑子里默认的是一套“理想环境”:Python版本是新版、包都装好了、系统路径正确、数据库字符集正常。但你的真实环境大概率离理想状态差着十万八千里。环境问题不解决,后面查什么都白搭,就像菜谱没问题,但你连锅和燃气都没准备,根本不可能做出菜来,第一步就卡死。
再说说语法和API为什么排在逻辑前面。AI代码的语法错误是“硬伤”,运行起来立刻报错,好查。而逻辑问题是“暗伤”,报错可能延迟出现在几十行之后,或者根本不报错只是结果错。先处理立刻蹦出来的硬伤,可以快速缩小排查范围,等代码能正常运行了,再去核对结果对不对,事半功倍。
还有一个很实际的原因:环境与语法问题的修复成本极低,往往一行配置、一个pip install就能解决。逻辑问题则需要人脑参与,可能要重写一段函数。把所有低成本、高概率的问题先排掉,剩下的才是真正需要动脑的部分。这是我这几年调试AI生成代码最核心的一条经验。
2. 按顺序抢救:五步操作流程
2.1 第一步:用注释法把问题缩小到一屏
拿到一堆跑不通的代码,不要直接在完整工程里翻来找去。工程里的代码动辄几百行,报错只提示其中一行,但你肉眼扫过去全是干扰信息。正确做法是先做一个最小复现,把问题缩到一个一屏能看完的范围内。
我常用的办法是注释法。把代码从中间切开,注释掉后半段,只跑前半段。如果报错依旧,说明问题在前半段;如果报错消失了,说明问题在后半段。就这样二分之一、四分之一地缩小范围,最多五六次就能把问题定位到几行之内。比如那次我让AI生成一个“批量下载文件、解析、再入库”的脚本,跑到最后入库时报错。如果从头一步步跑,网络请求要发好几遍,每次等半天。我干脆写了个只有解析和入库的测试函数,用一条假数据去跑,几秒钟就发现是SQL拼接的引号问题。全程没动过网络下载的部分。
这里有个容易踩的坑需要注意:注释代码的时候手要稳,别把括号、缩进、结构块注释得缺胳膊少腿。如果你注释完发现报错变成了SyntaxError,这就是你亲手制造的新问题,会严重干扰判断。注释大段代码时,保留函数签名、保留括号配对,尽量整块注释而不是注释到一半。
2.2 第二步:核对环境与依赖,统一版本
定位到具体代码行之后,先别急着修逻辑,先确认这行代码在吐槽环境还是吐槽语法。最常见的情况就是你缺了它依赖的东西。
先看代码用了什么:开头import了什么包、项目依赖了哪些库。然后在你的环境里核对版本。Python项目可以运行pip list看已安装包一览表;Node项目用npm ls <包名>看实际安装版本。如果压根没装,直接pip install或npm install;如果装是装了但版本不对,比如AI写的代码要求某个新接口,而你本地还是老版本,那就升级,或者反过来让代码降到兼容版本。
这里我强烈建议用虚拟环境,不要用全局环境干活。Python用python -m venv .venv创建一个独立环境,Windows下激活是..venv\Scripts\activate,Linux或macOS是source .venv/bin/activate。Node项目用单独目录加package-lock.json锁定依赖就可以。虚拟环境的意义在于:每个项目依赖互相隔离,AI代码把环境搞乱了,你删掉重建成本极低。我在全局环境里吃过亏,一个项目的numpy从1.x升到2.x,另一个项目直接跑不了,那种痛苦经历过一次就再也不图省事了。
核对完基础依赖,还要注意系统层差异。Windows路径分隔符是反斜杠,Linux是正斜杠;脚本里如果有文件路径硬编码,从AI那拷过来跑不通太正常了。Linux下可能还有权限问题,文件没有chmod执行权限,脚本直接报Permission denied。数据库场景要看字符集、SQL模式、表名大小写敏感度。这些都属于环境问题,在动手改逻辑之前都值得过一遍。
2.3 第三步:对照当前版本的API用法
环境正常了还会报错,大概率是AI用了一个它自己以为存在、但实际在你这个版本里已经变了或者根本不存在的方法。这类问题在AI生成代码里非常高频,典型的有三挂。
第一挂是Python 2的阴魂不散。xrange、print后面不加括号、raw_input这类写法,在Python 3里全是NameError或SyntaxError。你现在装的基本都是Python 3,遇到这种直接改掉即可。第二挂是旧版库API被移除。我踩过的坑包括:pandas里的df.ix[]写法,新版本已经删掉,要用df.iloc[]或df.loc[];numpy里的np.float、np.int是旧别名,新版要用np.float64、np.int64;sklearn里以前的cross_validation模块改名成了model_selection。这些报错信息通常都是AttributeError: module 'xxx' has no attribute 'yyy',一看就懂是API变了。第三挂是JavaScript运行时环境搞混,最常见就是process is not defined,浏览器端没有Node的process对象,正确写法是用import.meta.env,或者在构建工具的define配置里注入环境变量。
遇到这种API版本问题,最快路径是直接问AI:把“你用的那个库名+本地版本号”丢回去,让它检查代码里是否有不存在的API并给出兼容写法。AI对自己的幻觉往往一被点破就能修正。也可以靠IDE的代码诊断插件提前发现,pylint、eslint这类工具在你运行之前就能标出可疑调用,比跑去运行再排错舒服多了。
2.4 第四步:把完整报错喂回给AI
很多人已经走到了这里,但方式错了。他们只发一句“我运行报错了,帮我看看”,然后把报错第一行贴上去。这等于你去医院,只跟医生说“我不舒服”却不说哪里疼,医生只能瞎开药。正确做法是给足上下文。
我现在遇到AI代码报错,会把完整报错从第一行复制到最后一帧,连同能触发报错的最小代码片段一起贴回去,再附上运行命令、Python或Node版本、关键依赖包版本。然后明确要求它“先解释原因,再给出修复后的完整代码”。这个提示词模板我用了无数遍,非常管用。AI拿到完整的Traceback和最小复现,能够结合上下文自己发现错在哪,经常它在解释解释着就自己承认“抱歉,我写错了API”。
有个技巧值得试试:如果AI给了一个修复版,你又跑了,报错变成了另一个地方,这是好现象,说明问题在收敛。但如果同一个报错连续两三轮都没变,或者AI给的解释明显在绕圈子,果断开一个新会话重新问,或者换一个AI工具。继续在同一个会话里纠缠,大概率只是重复生成类似的错误答案,浪费你的时间。
2.5 第五步:该重写的就痛快重写
有些代码真的不值得修,我总结出三条硬性标准:一个函数超过50行且嵌套多层循环或递归,AI自己都解释不清这段逻辑;同一个报错连续修了两轮还在原地打转;代码涉及钱、数据安全、账号鉴权逻辑,必须人工确认。满足任何一条,都别再当救火队员了,直接重写。
重写的时候反过来利用AI反而更高效。你自己用最朴素的写法把核心逻辑跑通,哪怕是for循环手写、字符串直接拼,也别管优雅不优雅,先让功能跑通。然后让AI对这段代码做Code Review,让它挑漏洞、提优化建议,再让它加类型注解和单元测试。这样一来,AI从“无中生有的生成者”变成了“基于你已验证代码的检查者”,反而靠谱得多。我写一个量化回测脚本时就这么干过,AI初版用了一堆花哨的列表推导式,跑起来各种边界错误。我自己重写成一个简单的for循环版本,跑通了,再让AI优化性能,一次就成功。先有骨架再谈装修,顺序错了全是返工。
3. 实战:一个AI生成的Excel入库脚本,报错四连击后救回
3.1 需求与AI初版
纸上谈兵没意思,拿一个真实的抢救过程来说透。有次我想快速做一个批量处理Excel并写入MySQL的小工具,文件里一张几千行的销售明细表,需要每行数据拆出来插入数据库,顺带生成一个统计摘要。我图省事,直接把需求扔给AI,几秒钟它给了我这段代码。
import pandas as pd import pymysql df = pd.read_excel('销售.xlsx') conn = pymysql.connect(host='localhost', user='root', passwd='123456', db='shop') cur = conn.cursor() for i in range(len(df)): sql = "INSERT INTO 销售表(商品,销售额,日期) VALUES ('{}',{},{})".format(df.loc[i,'商品'], df.loc[i,'销售额'], df.loc[i,'日期']) cur.execute(sql) conn.commit()我不做预判,直接丢到环境里跑。结果撞上了一连串报错,前后算下来一共四个,但每修完一个,问题就往前走一步,整个过程就是“环境问题 → 语法问题 → 字符集问题 → 数据格式问题”的典型递进。
3.2 从报错第一击到第四击
第一击:ModuleNotFoundError: No module named 'pymysql'。
环境问题。AI默认我装了pymysql,但我电脑上根本没有。这种报错不用多想,直接倒一杯水,等它装上,pip install pymysql,完事。同时心底默默记一笔:下次把本机库清单发给AI,能省一步。
第二击:MySQL 1064语法错误,报错信息是ProgrammingError: 1064 (42000): You have an error in your SQL syntax; near ''销售表'(商品,销售额,日期) VALUES...'。
这个问题是AI把中文表名直接写成SQL对象了。MySQL在SQL语句里遇到中文表名,需要反引号括起来,否则要么当成保留字,要么当成非法标识符,直接1064。加上AI用format拼接SQL,字符串值内部的引号也没处理好。看到“near”后面跟着的那段话,问题其实已经很清楚了。我在控制台里加上了一句print(sql),看到了实际生成出来的SQL长什么样,才知道是把表名和值混在一起了。修复方式:表名和字段名改成英文,并在SQL里用占位符传参,不要用format直接拼。改成英文表名是为了减少字符集和语法层面的麻烦,这是低成本高收益的做法。
第三击:UnicodeEncodeError: 'latin-1' codec can't encode characters。
数据库连上了,表名也通了,结果数据一进去,中文商品名报了编码错误。pymysql默认连接字符集可能是latin-1,根本不认识中文。修复方法是连接参数里显式加上charset='utf8mb4'。这一步很典型:不是代码逻辑错了,是数据库客户端和表的字符集配置跟数据不匹配。属于环境类问题的一个变体,藏在数据层里。这类问题在AI初版代码里极容易踩,因为AI压根不知道你的数据库默认字符集是什么。
第四击:日期格式问题,数据插进去但日期字段变成了0000-00-00之类的异常值。
Excel里的日期单元格被读出来可能是datetime对象,也可能读成了字符串“2024/01/10”,MySQL的DATE字段接收的格式标准是“2024-01-10”。AI初版直接把原始值塞进去,MySQL要么报错,要么把不标准的值转成废数据。这次的修复不是在SQL层面了,而是在Python里对日期字段做一次统一的格式处理,字符串就先用datetime.strptime解析,再strftime成标准格式;datetime对象就直接strftime。
3.3 修复后的完整代码长这样
几轮下来,最终代码我改成了这样:
import pandas as pd import pymysql from datetime import datetime conn = pymysql.connect( host='localhost', user='root', passwd='123456', db='shop', charset='utf8mb4' ) cur = conn.cursor() rows = [] for _, row in df.iterrows(): product = row['商品'].replace("'", "''") sale = float(row['销售额']) d = row['日期'] if isinstance(d, str): d = datetime.strptime(d, '%Y/%m/%d').strftime('%Y-%m-%d') else: d = d.strftime('%Y-%m-%d') rows.append((product, sale, d)) cur.executemany( "INSERT INTO sale_detail(product, amount, sale_date) VALUES (%s, %s, %s)", rows ) conn.commit()对比AI初版,改了四处:用executemany批量插入取代了逐条循环,性能好得多;用%s占位符取代了直接字符串拼接,既能躲开引号问题,也顺便堵住了SQL注入风险;日期字段做了显式格式化;表名字段名改成英文,并在连接时指定utf8mb4。这几处都不是什么高深技术,但AI恰恰最容易在这几个点上翻车,因为生成代码的人,没有你的真实数据样本。
3.4 这次调试的复盘心得
整套抢救过程历时大概半小时,最耗时间的不是修改本身,而是每一步怎么判断“现在修哪个”。如果一开始就跳进代码里瞎试,先碰上语法错,改完又碰到字符集,再跑又遇到日期,那种挫败感会很重。反过来按顺序走,每修完一个,报错变新样貌,你心里反而踏实,因为你知道问题在收敛。
还有一条心得是当天晚上记下的:任何SQL报错,第一件事是打印出实际执行的SQL语句。打印出来瞬间就能看出是引号缺了、表名没加反引号,还是值根本不是预期类型。print大法在SQL调试里几乎百试百灵,我甚至怀疑很多MySQL 1064相关的问题,大家之所以半天看不出来,是因为从没看过拼接后的SQL整体长什么样。
4. 高频报错速查与养成排查好习惯
4.1 先对号入座:常见AI代码报错速查表
我在用AI生成代码的过程中,把遇到次数最多的报错整理成了一张表。看到相似的报错直接对号入座,能省很多时间。
| 报错或现象 | 大概率原因 | 首选排查方向 |
|---|---|---|
| ModuleNotFoundError / No module named | 依赖没装或装在别的环境 | pip list核对,装到当前虚拟环境 |
| AttributeError: 'xxx' object has no attribute 'yyy' | 用了已移除或拼错的API | 查该库当前版本文档,确认方法名 |
| SyntaxError | Python 2/3混用、括号缺失、缩进混乱 | 看报错行附近,用格式化工具重排 |
| MySQL 1064 SQL语法错误 | 拼接SQL有问题、中文名没反引号、保留字 | 打印最终SQL,直接观察 |
| process is not defined | 浏览器端用了Node专属对象 | 改用import.meta.env或构建时注入 |
| TypeError: unsupported operand type | 类型不匹配,int加str | 在报错行前打印type() |
| RecursionError | 递归缺终止条件或边界错误 | 检查递归函数出口 |
| UnicodeEncodeError | 数据库或文件字符集配置不对 | 连接参数加charset=utf8mb4 |
| ReferenceError: xxx is not defined | 变量作用域或拼写错误 | 检查变量定义位置 |
这张表没法覆盖所有情况,但每一条都是实际战斗中总结的,尤其是UnicodeEncodeError和1064这两块,AI生成代码的概率极高。遇到报错先对号入座,不对应再往下查层。
4.2 几个让你少熬夜的调试习惯
除了按顺序排查,平时写代码时养成一些小习惯,AI代码跑不通的概率会直线下降。
第一,永远在虚拟环境里调试。这个前面反复强调,是真的重要。AI代码不知道会给你装点什么奇怪的依赖,锁在虚拟环境里,坏了就删,重新创建一分钟的事。全局环境一旦被搞乱,清理起来想死的心都有。
第二,print大法和日志双管齐下。Python里就跑一段加几个print,把变量类型、数值、SQL语句打出来;前端就在浏览器DevTools里console.log;C/C++和嵌入式场景用调试器,gdb的break、next、bt这些命令虽然老,但在真正复杂的运行现场,比盲改代码可靠得多。别嫌print土,它能帮你确认“代码走到了这一步”和“这一步的东西是什么”,这两个信息能解开一半的谜题。
第三,先小数据跑通,再上全量数据。AI生成一套脚本,别拿生产数据直接试。先用一个只有两行数据的临时文件或者临时表跑一遍,确认逻辑没问题,再放全量。一个小数据样本能让你几百倍地减少等待时间,也方便肉眼验证结果。这个习惯我之前吃过亏,跑了十几分钟最后发现数据全插错了,等于白跑。
第四,每次修改都要留档。用git哪怕只在本地提交,每次改一行就commit一次,提交信息写清楚“修了什么报错”。这样万一改岔了,可以随时回滚。你会发现AI帮你迭代的代码,很多时候是越改越乱的,没有存档就没有后悔药。
第五,用IDE的诊断功能。代码诊断插件、pylint、eslint、类型检查器,能在代码跑起来之前把可疑点标出来。我一般先把AI代码黏进编辑器,等右下角提示安静下来,再运行。很多时候诊断已经标出了明显漏洞,根本不用运行就知道问题在哪。
4.3 三个场景化提问模板,让AI帮你一起找问题
最后把话收回到AI本身。AI生成的代码挂在AI手上再正常不过,但你完全可以再反手把问题丢回给AI帮你找,前提是提问的方式要到位。我自己常用的有三个模板,百试百灵。
排查模板一:解释并修复。适用范围:代码直接报错时。先把完整报错、最小代码、运行命令、环境版本都填进去,最后落一句“先解释原因,再给出修复后的完整代码”。注意是“先解释再给代码”,逼它先思考而不是直接蒙一个答案。这个顺序对提高命中率很有帮助。
排查模板二:版本校对。适用范围:怀疑代码用了旧API但拿不准。直接把“我环境里的库版本”亮出来,问它“你生成的代码里是否有该版本不存在或已弃用的API,请给兼容写法”。让AI基于事实版本重新检查,而不是凭感觉。
排查模板三:代码审查。适用范围:代码能跑但结果不对。让AI“不要改代码,逐行解释逻辑,并指出可能隐藏bug的地方”。这一步其实是把AI当免费Code Review工具用。它解释着解释着,很可能自己就意识到边界条件写错了。
说实话,我自己的体会是,AI生成代码的本质就是在做一个“常用片段排列组合”的即场发挥,它并没有真正理解你的业务和数据。它跑不通了,第一步永远不是骂它,也不是无头绪地改。按环境、语法、逻辑的顺序走一遍,给上下文、对版本、缩范围,最后舍得重写,这套顺序能救回绝大多数代码。真正让我放弃抢救的,往往不是报错有多刁钻,而是连我自己都没想清楚这段代码到底要干嘛。AI只是效率工具,代码能不能跑,最终还是得你对逻辑负责的那个人负责。