
我见过太多人问同一个问题AI写代码到底能不能落地尤其对于Qt这类自带GUI框架、又要跟编译环境死磕的技术栈AI生成的代码常常是“看着对跑不起来”。这次我干脆选了一个最经典的练手项目——学生成绩管理系统用一个AI对话式编程工具从头到尾辅助生成再把踩过的坑全部记录下来。结论提前说一句AI助写Qt程序完全可行但必须把它当成一个话痨但偶尔短路的高级实习生而不是全能的架构师。这篇文章适合三类人刚学Qt想找一个完整参考项目的新手想知道怎么用AI把需求变成C界面代码的开发者以及被Qt编译错误折磨过、想系统排查一遍环境问题的老伙计。我会把从需求拆解到最终可运行程序的每个步骤、每段关键代码、每个翻车现场都写清楚你可以直接照着复现。1. 为什么选“学生成绩管理系统”当AI辅助开发的试验田选项目不选大的只选合适的。现在AI辅助编程的演示项目满天飞不是购物车就是TodoList老实说这些都不太适合拿来验证Qt开发的真实痛点。我选择学生成绩管理系统有几个很实在的理由第一功能边界清晰。它包含经典的增删改查对学生记录的添加、删除、修改、查询这是所有管理类软件的骨架。AI对这种高频需求模式的训练数据非常充分生成出来不会太离谱。第二存在真正的业务逻辑。成绩要对语数外三科做总分统计、平均分计算、及格率计算、排序展示这些逻辑一旦耦合到界面代码里就会很乱。AI能不能把逻辑和界面分层处理是一个很好的检验点。第三它天然需要对话框交互。添加学生不能直接在表格里裸输需要一个表单弹窗确认删除时需要弹个提示框。这涉及到Qt的QDialog、信号槽、模态窗口这些基础机制AI对这些机制的回答质量参差不齐正好用来测试它会不会一本正经地编API。第四我还加了一个“不太安分”的需求把成绩分布做成柱状图。这倒不是学校管理系统的必备功能但我需要看看AI在面对Qt Charts模块时是会正确引入模块还是随便写一个不存在的头文件。在动手之前我先把预期管理做在前面。AI生成Qt代码最典型的三个失真点我在这次实践中全部遇到了API版本混淆。AI的数据里混着Qt4、Qt5、Qt6的内容它可能给你的connect写法是老的SIGNAL()/SLOT()宏也可能给你一个只在Qt6里存在的新API。中文字符串乱码。这个说不清是AI的锅还是编译器的锅但它生成的中文文本在Windows的MSVC环境下经常变成问号尤其是源码编码处理不好时。模块依赖缺失。它会在#include QtCharts上做得好像一切顺理成章但你的Qt安装包可能根本没装Charts模块一编译就报unknown module(s)。所以我给自己定了一条规矩AI输出的每一段代码编译之前必须人工过一遍重点看头文件、构造参数、父子对象关系。这不是不信任AI而是对编译器负责。2. 三连prompt把模糊需求变成可编译的Qt代码很多人用AI写代码上来就甩一句“帮我写一个学生成绩管理系统”然后等一个巨型main.cpp出来——这基本注定是垃圾。AI生成的代码长度一上来就爆炸它会把所有东西塞进一个MainWindow类之后你想改任何东西都会觉得无从下手。我用的方法是把需求拆成五个阶段分多次对话生成每次只让AI干一件事生成项目的构建骨架CMakeLists.txt 和 main.cpp。生成主窗口界面基于.ui文件的MainWindow。生成表格数据模型StudentModel。生成添加/编辑学生的对话框。生成统计与图表逻辑。第一轮对话我给的prompt是这样的你是一名资深Qt/C桌面应用开发工程师。请帮我生成一个基于Qt 5.15.2、使用CMake构建的学生成绩管理系统的项目骨架。编译器是MinGW 64位。请生成CMakeLists.txt和main.cpp要求使用Qt Widgets模块不要使用qmake不要生成任何业务逻辑代码只保证程序能启动并显示一个空窗口。注意几个关键设定指定Qt版本号指定构建工具指定编译器环境。这能极大减少AI给你生成一个qmake工程或者Qt6专用语法的概率。如果它后面生成了不兼容的API你也可以直接拿版本号去压它“Qt 5.15.2不支持这个写法请改用Qt5的API。”AI给的CMakeLists.txt第一次编译就能过内容如下cmake_minimum_required(VERSION 3.16) project(StudentScoreManager) set(CMAKE_CXX_STANDARD 17) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) find_package(Qt5 COMPONENTS Widgets REQUIRED) add_executable(StudentScoreManager main.cpp mainwindow.cpp mainwindow.h mainwindow.ui ) target_link_libraries(StudentScoreManager PRIVATE Qt5::Widgets)这段属于样板代码AI基本不会出错。但如果我不指定版本它很可能就写find_package(Qt6 COMPONENTS Widgets)了你这会儿要是装的Qt5直接卡死。所以环境信息一定要在prompt里写死。main.cpp倒是简单就三行核心#include QApplication #include mainwindow.h int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }第一轮到这就够了能编译、能跑出空窗口就说明地基是稳的。很多人在这里犯的错是让AI一把梭哈全部代码然后丢给你几百行编译报错几十个AI自己都改不过来了。分阶段生成的最大好处是错误出现时你永远知道是哪个阶段的锅。第二轮和第三轮我继续用同样的角色设定但把任务范围收紧在现有项目基础上请添加一个StudentModel类继承自QAbstractTableModel管理学生信息。学生有姓名、学号、语文、数学、英语三门成绩。请实现rowCount、columnCount、data、headerData、setData、flags这几个重载函数并提供addStudent和removeStudent两个公开方法。数据保存在内部的QList 里Student结构体也一并生成。这种指向性明确的promptAI生成出来的代码可用度非常高。我拿到后几乎没有修改就通过了编译因为所有函数名都是标准虚函数重载语法是固定的AI在这种“填空题”上比人还靠谱。再说一个细节AI生成一个对话框时通常是直接new一个QDialog然后push_back控件不会用.ui文件。但既然我们建了Qt工程用Qt Designer做界面才是正经路子这也是很多人在网上搜“qt designer界面设计”的原因。我在第四轮里专门要求它输出基于QDialog的类但界面用Qt Designer生成的addstudentdialog.ui。AI虽然理解这个需求但生成出来的对话框代码里有一个很常见的坑——它会在QDialog构造函数里直接setModal(true)。弹窗自己设模态没问题可模态窗口被当作局部变量AddStudentDialog dlg(this); dlg.exec();使用时父窗口传得对不对就看它心情了。这个我后面人工修正了。3. 骨架好不等于能用数据模型与界面解耦的改写过程AI生成的第一版代码问题很小小到你可能忽略它但忽略之后会越来越痛苦。它居然老老实实生成了StudentModel可让我没想到的是它在MainWindow里直接又搞了一个QListStudent成员变量表格数据却直接塞进了QTableWidget。这在功能上是能跑的而且对于新手来说特别直观。但问题是当你要排序时QTableWidget的排序是按控件行的字符串排的“89”会排在“100”后面当你删除中间一行时你得自己维护一个行号到Student的映射当你做统计时你又得从控件里逐行取值转数字。整个界面和业务逻辑搅成一锅粥我后来把这段全部推倒重写统一走QAbstractTableModel路线。重构后的StudentModel核心代码长这样class Student { public: QString name; QString studentId; double chinese 0.0; double math 0.0; double english 0.0; }; class StudentModel : public QAbstractTableModel { Q_OBJECT public: enum Column { ColName 0, ColStudentId, ColChinese, ColMath, ColEnglish, ColTotal, ColumnCount }; explicit StudentModel(QObject *parent nullptr); int rowCount(const QModelIndex parent QModelIndex()) const override; int columnCount(const QModelIndex parent QModelIndex()) const override; QVariant data(const QModelIndex index, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; bool setData(const QModelIndex index, const QVariant value, int role) override; Qt::ItemFlags flags(const QModelIndex index) const override; void addStudent(const Student stu); void removeStudent(int row); double averageOf(int column) const; double passRateOf(int column) const; private: QListStudent m_students; };这里有一个业务决策要讲清楚总分列我直接在data()里现算不存进结构体。为什么不存因为总分是动态的只要三门成绩改了总分就应该跟着变。存一份冗余字段就意味着你得在任何setData的地方手动同步总分漏掉一处就是数据不一致。AI如果对着这个结构去生成它大概率会老老实实在Student里加一个total字段。你不主动提出“总分动态计算”它就不会想到这一层。界面侧的统一入口是QTableViewm_model new StudentModel(this); m_proxy new QSortFilterProxyModel(this); m_proxy-setSourceModel(m_model); ui-tableView-setModel(m_proxy); ui-tableView-setSortingEnabled(true);以后无论添加、删除还是修改界面只认Model的信号表格自动刷新。我只需要在MainWindow对应槽里调用m_model-addStudent(stu)剩下的交给QAbstractTableModel的数据变更通知机制。这个模式的收益在写删除功能时尤其明显你不需要关心表格当前选中行在源Model里是哪一行因为选中行是QModelIndex转给QSortFilterProxyModel之后再映射到源模型就行QModelIndex proxyIndex ui-tableView-currentIndex(); if (!proxyIndex.isValid()) return; QModelIndex srcIndex m_proxy-mapToSource(proxyIndex); m_model-removeStudent(srcIndex.row());这个映射机制如果不熟悉很容易在排序之后删错数据。AI生成的代码里通常不会替你考虑排序后删除的映射问题它大概率还是“取当前行号直接删”所以你一旦点了表头排序再删除删掉的可能就是另一条记录了。这个点属于非常典型的“看着简单AI考虑不到”的情况。为什么我不直接用QSqlTableModel加SQLite说实话如果目标是真实的学校系统用SQLite数据文件肯定是更好的选择。但当前阶段我想保持项目简单——不用管数据库驱动、不用管SQL语句、不用管事务把精力集中在界面和模型结构上。数据落盘我用的是最土的JSON序列化够用、直观、不容易出错。我还在MainWindow里保留了QStandardItemModel作为备选方案但写完这个项目之后我反而更加坚定了一个观点只要你需要自定义列的数值计算QAbstractTableModel永远比QTableWidget和QStandardItemModel好用。它本质上是把“表长什么样”和“数据是什么”分开后者只适合纯静态展示。4. 成绩统计与排序让AI写业务逻辑时最容易翻车的几个点功能做到这一步增删改查基本能用了。但一个学生成绩管理系统如果只做到“录入数据”那它没有灵魂。接下来我让AI加两个统计指标单科平均分和单科及格率再加一个点击表头排序的效果。这一段才是真正考验AI业务能力的地方。先看及格率的实现需求及格率 分数大于等于60的人数 / 总人数 × 100%。听起来简单但AI在第一版给的代码是int passed 0; for (int r 0; r model-rowCount(); r) { double score model-data(model-index(r, StudentModel::ColMath)).toDouble(); if (score 60.0) passed; } double rate passed * 100.0 / model-rowCount();单看这段逻辑没有错但它根本处理不了空表。当rowCount()是0时这是除以零虽然浮点运算不会像整数那样直接崩溃但结果是一个inf界面上显示“及格率inf%”非常难看。AI在写业务逻辑时对边界条件的敏感度远低于对正常路径的敏感度。我后来在StudentModel::passRateOf里强制加了空表判断double StudentModel::passRateOf(int column) const { if (m_students.isEmpty()) return 0.0; int passed 0; for (const Student s : m_students) { double score 0.0; switch (column) { case ColChinese: score s.chinese; break; case ColMath: score s.math; break; case ColEnglish: score s.english; break; default: return 0.0; } if (score 60.0) passed; } return passed * 100.0 / m_students.size(); }平均分那里也一样要小心分母为0。这是一个很不起眼但实际使用时一定会踩的坑因为一个管理系统不可能永远有数据。关于排序QSortFilterProxyModel已经帮我们扛下了99%的活但有一个细节要调默认情况下QTableView开启排序后点击表头会把数值列按字符串排序。QSortFilterProxyModel不知道某一列是int还是double它的比较机制是由data()返回的类型决定的。我们Model的data()里要正确处理数值列的Qt::DisplayRole返回QVariant(double)而不是先把数字转成QString再返回。这是AI最容易帮你埋雷的地方因为它很习惯写一行return QVariant(tr(%1).arg(value));这么写界面是能显示但排序就成了字符串比较“9”会排在“80”后面。正确的做法是if (role Qt::DisplayRole) { switch (index.column()) { case ColChinese: return QVariant(m_students.at(index.row()).chinese); // 其他科目同理 } }也就是说数据返回什么类型排序就按什么类型走。所有格式化的活比如保留一位小数应该在DecorationRole之外另外想办法或者直接不改数据、让QTableView的默认显示承担格式化。界面显示分数我默认显示到小数点后一位是在data()里返回double正面数值再靠QTableView的itemDelegateForColumn做显示格式化。这个设计虽然绕一点但排序正确性优先。接下来是图表。Qt Charts的接入流程是CMakeLists里find_package要增加Charts组件target_link_libraries要加Qt5::Charts源码里包含QtCharts头文件链接时用QT_CHARTS_USE_NAMESPACE或者直接通过QtCharts::前缀访问类。AI生成时最典型的错误是给你一个#include QChart而没有#include QtCharts/QChart或者find_package(Qt5 COMPONENTS Widgets Charts)没写Charts。这些错误编译时都会以unknown module或者fatal error: QChart: No such file or directory的形式跳出来属于“AI生成一时爽编译火葬场”的重灾区。柱状图那段我是这样的#include QtCharts/QChart #include QtCharts/QBarSeries #include QtCharts/QBarSet #include QtCharts/QBarCategoryAxis #include QtCharts/QValueAxis QT_CHARTS_USE_NAMESPACE QBarSet *set new QBarSet(数学); for (const Student s : model-students()) { *set s.math; } QBarSeries *series new QBarSeries(); series-append(set); QChart *chart new QChart(); chart-addSeries(series); chart-setTitle(数学成绩分布); chart-legend()-setVisible(true);其实到这一步AI的代码只要修掉CMake的模块引用几乎能直接用。图表这块它的训练数据反而很多因为网上的QtCharts教程本来就套路化。真正让我无语的是它会在中文标题上翻车如果源码文件不是UTF-8 with BOM编码MSVC下chart-setTitle(数学成绩分布)会直接变乱码。这个问题我在第一次跑程序时就撞上了。乱码的根因是MSVC编译器对源码的默认解析编码不是UTF-8而是本地代码页中文Windows下是GBK。当源码文件是UTF-8无BOM时MSVC会把中文字符串按GBK去解释于是出现乱码。解决办法有这么几个给源码换成UTF-8 with BOM或者在main.cpp开头加#pragma execution_character_set(utf-8)或者侮辱性极强但确实有效的——全部用QString::fromUtf8(u8中文)。我在项目里统一用QStringLiteral包裹中文字符串并把整个项目源码保持UTF-8编码顺手在CMakeLists里没有额外设置编译选项因为这版本MinGW没有MSVC那么矫情。如果你用的是MSVC编译器建议直接在CMake里加add_compile_options($$CXX_COMPILER_ID:MSVC:/utf-8)一行搞定比什么都省心。5. 编译环境里常见的拦路虎版本、库名与运行插件的排查这个项目本身不算复杂但真正耗掉我大量时间的不是功能代码而是编译和运行环境。Qt开发就是这样代码写得再漂亮环境不对就是寸步难行。我这次用的工具链是Qt 5.15.2 MinGW 64位 CMake在Windows上开发。结果我在网上搜集资料时发现下面这几类问题几乎每天都在有人问我把它们的排查链路完整写一遍。5.1 fatal: cannot mix incompatible qt library (version ex50601) with this librar我第一次在网上看到这个报错的时候整个人是蒙的因为报错信息看起来被截断成了半句。实际上完整的错误往往是这样的fatal: cannot mix incompatible Qt library (version 0x50601) with this library (version 0x50602)这是一句来自Qt核心库的版本自检信息意思是当前程序在链接时发现有两个不同版本的Qt头文件/库文件混在一起了。比如你明明装的是Qt 5.15.2但你的PATH环境变量里有旧版Qt的bin目录CMake找到的却是另一个库路径下的Qt 5.15.5或者编译一个旧项目时编译器使用了新版Qt的dll但编译参数里引用了旧版头文件。排查步骤我建议按这个顺序先查CMake缓存确认CMAKE_PREFIX_PATH指向的Qt路径是否唯一。再查系统PATH看看有没有多个Qt版本的bin目录混在里面。最后看实际链接的库路径在CMakeLists里加一句message(STATUS Qt5_DIR${Qt5_DIR})确认find_package到底命中了哪个目录。这个错误发生后最直接的办法是清理CMake缓存删除build目录然后重新用Qt Creator打开项目。Qt Creator自带的编译器套件会帮你选好对应的qmake路径所以从Qt Creator里启动时不太容易出现这种版本混合问题。如果你是从命令行直接跑cmake请务必先执行where qmake看命中顺序。我之前就是因为在系统PATH里残留了一个Qt 5.9的bin目录导致CMake找到5.15.2的库再混进5.9的dll直接崩了。5.2 qt.qpa.plugin: could not find the Qt platform plugin linuxfb这个报错的经典场景有两个一个是在树莓派或嵌入式Linux上跑Qt程序时构件平台插件没被打进可执行目录另一个是桌面Linux环境下有人为了省资源设置了环境变量QT_QPA_PLATFORMlinuxfb但当前系统里根本没装qlinuxfb这个插件。QPA是Qt Platform Abstraction的缩写翻译过来就是“平台抽象层”。Qt在真正调用窗口系统之前要先通过一个QPA插件去创建窗口。Windows上用的插件是qwindows桌面Linux上的是qxcb或qwayland嵌入式Linux上才用qlinuxfb、qeglfs这些。当程序启动时系统会根据命令行-platform参数或QT_QPA_PLATFORM环境变量去加载插件加载不到就报这个错。我自己的排查顺序是先看是否设置了QT_QPA_PLATFORM环境变量有就unset掉再看程序运行目录下有没有platforms文件夹且里面有没有对应的qwindows.dll或qlinuxfb插件最后检查是不是从Qt Creator运行时能正常运行、但从命令行或双击图标运行时崩溃——如果是说明部署时少拷贝了platforms目录。顺便提醒一个部署常识用windeployqt工具发布Windows程序时它会把platforms目录自动拷贝过去但如果你用了QT_QPA_PLATFORM强行指定为linuxfb部署后照样会崩。这个坑不是AI挖的是环境变量残留挖的。5.3 qt 编译时候 cannot find -lpublic这个错误在MinGW/GCC环境下特别常见它的样子是cannot find -lpublic我第一次见还以为是少装了什么库四处搜“public”库结果折腾半天才明白-l是链接库的选项-lpublic的意思是让编译器去链接一个叫libpublic.a或libpublic.dll的东西。问题在于这个库名根本不是CMake或者代码里直接写的而是源文件里某个#pragma comment(lib, public)或者CMake里出现了target_link_libraries(... public ...)之类被GCC误当成库名的写法。对你没猜错。CMake里给目标添加依赖时有PRIVATE、PUBLIC、INTERFACE这几个关键字。如果某人在target_link_libraries里写了target_link_libraries(MyApp PUBLIC)后面跟了一个空参数或者库名列表被错误解析GCC就会从参数里抓到public并当成一个要链接的库名于是报cannot find -lpublic。还有一种常见原因是在源码里写#pragma comment(lib, public)这是MSVC的写法MinGW根本不认但MinGW的链接器会把public当作库名去解析。遇到这个错误我的处理方式先用cmake --build build --verbose看具体是哪条链接命令带出了-lpublic然后顺藤摸瓜找到CMakeLists里对应的target_link_libraries或源文件里的pragma。绝大多数情况下删除错误的PUBLIC关键字或pragma就能解决。这个坑如果让AI来背其实有点冤——代码是AI写的但它通常会根据我提供的CMakeLists模板来写所以只要我模板是对的AI一般不会产生这种错误。但如果是别人给你的AI生成工程这错误真能让你怀疑人生半小时。5.4 unknown module(s) in qt: webenginewidgets这个报错一般是这样的:-1: error: unknown module(s) in QT: webenginewidgets它出现在.pro文件qmake工程或.cmake配置里引用webenginewidgets模块但当前安装的Qt没有这个模块。Qt WebEngine模块体积巨大在线安装器默认情况下并不全勾选很多人安装Qt 5.15.2时只勾了MinGW下的Widgets和Charts没勾WebEngine那么任何引用QtWebEngineWidgets的代码都会在构建配置阶段直接失败。这个报错跟AI的关系比较大因为很多老教程或AI引用的示例项目会用QWebEngineView来做一个嵌入浏览器的界面结果你本地Qt没装编译期直接挂。解决思路特别直白要么重新运行Qt在线安装器把对应的模块补装要么从工程里删掉对webenginewidgets的引用。对于一个学生成绩管理系统你压根不需要浏览器组件我在工程里直接废弃了这个模块一点损失都没有。这给我一个很重要的启发不是Qt安装得越全越好。有些模块比如WebEngine会极大缩短程序启动速度、增大安装包体积如果项目用不到就该在安装时直接不勾选。AI推荐的模块你要先问自己“这个功能真的需要浏览器内核吗”答案是不需要那就砍。5.5 Qt写的关于CAN通讯的软件很容易闪退报0000005这个不是本次项目直接遇到的但我看到网上反复有人提顺便讲透了。0x0000005是Windows下的“访问违规”异常对应现代MinGW调试器里的SIGSEGV本质上就是程序访问了非法内存地址。Qt程序里最常见的闪退根源有四个对已删除的QObject调用方法。比如你在某个对话框关闭后继续访问它的成员指针而对话框已经被delete。C裸指针生命周期管理失误。new出来的对象没有被delete但父对象QObject父子机制自动delete了之后又手动delete一次变成双重释放。lambda表达式捕获了已销毁的this指针。异步回调触发时窗口已经被关闭了。删除QList中的项时迭代器失效。排查这种闪退我不建议靠盲目加qDebug直接在Qt Creator的调试模式下运行让它停在崩溃点看调用堆栈。堆栈里几乎总是能看到问题的真实源头——比如某个MainWindow的成员变量已经被置空或者某个QTableView的currentIndex()返回了非法索引后你没有做isValid()检查继续往下取数据导致崩溃。AI生成的代码特别喜欢把一系列函数调用链写得很长中间不设任何有效性检查。比如它可能给你这样的代码QModelIndex cur ui-tableView-currentIndex(); QString id cur.siblingAtColumn(1).data().toString();如果cur本身是无效索引行第二行就不安全虽然它可能不立刻崩但一旦模型变更、行数减少就会在某个随机的时机触发访问违规。凡是跟索引相关的代码我的习惯是拿到索引先做isValid()判断再往下走。这个习惯能避免90%的莫名闪退。5.6 环境配置总表和排查速查我把这篇涉及到的环境问题做了一张速查表方便以后遇到问题直接对照错误现象根因快速处理cannot mix incompatible Qt library多个Qt版本dll/库路径混杂清理PATH和CMake缓存确认唯一Qt目录Could not find the Qt platform plugin linuxfbQPA插件缺失或环境变量指定错误删除QT_QPA_PLATFORM确认platforms插件目录就位cannot find -lpublicCMake的PUBLIC被误当库名或冗余pragma查链接命令删错误关键字unknown module(s): webenginewidgetsQt安装时未勾选对应模块补装模块或移除引用闪退0x0000005无效索引、悬空指针、双重释放合法索引校验检查父对象生命周期中文乱码源码编码与编译器默认编码不一致CMake加/utf-8或源码存UTF-8 BOM6. AI辅助开发的边界哪些环节必须自己把关跑完一遍整个流程我对AI辅助写Qt程序这件事有了更清醒的判断。它确实能把开发周期压缩到一个很夸张的程度——从零到可用的成绩管理系统如果全手工写怎么也要大半天加上调试可能一天这次借助AI辅助从第一行prompt到最终跑通大概用了三个小时。但这个效率收益都建立在“我知道自己在做什么”的前提下。如果完全不了解Qt让AI闭眼全自动写大概率会在某些隐蔽的地方翻车而你连错误信息都看不懂。我的经验可以浓缩成几个原则。第一样板代码和数据结构定义可以交给AI。QAbstractTableModel那一堆虚函数重载手写十几遍之后你也能背下来但让AI生成确实更快。结构体定义、构造函数、枚举、常量这些AI的训练数据极其充分它闭眼都能写对而且几乎不会有逻辑分支。这一块是纯受益区域。第二编译错误可以贴回给AI去解释。很多人在编译报错时习惯自己瞪眼其实把报错原文贴给AI它给出的分析往往很准因为它见过海量的同类问题。但要注意AI擅长解释错误未必擅长修复架构性缺陷。像“cannot mix incompatible Qt library”这种环境病AI能告诉你大概是版本问题但具体是哪个PATH变量里的哪个dll在捣乱仍需你自己动手确认。它的建议只能当方向不能当结论。第三数据一致性和生命周期必须自己把关。AI生成的代码几乎不会主动考虑用户操作顺序的极端情况表格里没有选中行时点删除按钮、排序之后进行删除、连续快速双击添加按钮弹出多个对话框……这些场景AI写出来永远是“理想流程下的网线直通版”你需要自己补边界校验。我的做法是给MainWindow的所有按钮槽函数开头先做守卫不合法就return宁可程序不响应不能让它崩溃。第四架构决策不能外包。用QTableWidget还是QAbstractTableModel用QSqlTableModel还是内建KList这种选择直接决定项目后续的可维护性AI不会替你权衡。它只会顺着你的prompt走你问“怎么做”它给你一个能跑的方案你问“在可扩展的架构下怎么做”它才会往Model/View方向走。所以你给AI的prompt本身要包含架构倾向。我这次的第一轮需求拆分里就写了“数据模型单独封装界面与业务逻辑分层”AI生成的方向立刻就不一样了。第五打包发布需要手动收尾。AI不会替你考虑windeployqt把哪些dll带进安装目录也不会替你处理“把程序发给同事后同事电脑上缺运行库”这种破事。成绩管理系统做完了要想分发需要在Qt命令行环境里执行windeployqt StudentScoreManager.exe然后检查platforms、iconengines、imageformats这几个目录是否都出现在可执行文件旁边。如果你用了Qt Charts还得确认Qt5Charts.dll被带上了。这一环节AI基本帮不上忙因为它是运行时环境问题不是代码问题。但只要你掌握了检查逻辑几步就搞定。最后给一个小技巧如果某个错误你搜遍全网都找不到完全一致的说法试着把报错信息里夹带的版本号、模块名、文件路径全部去掉只留骨架再搜往往能命中真正的核心问题。这个方法我和AI配合用了很多次特别好使。AI辅助写Qt程序这件事说到底就是一句话让它替你干脏活累活但方向盘得握在自己手里。学生成绩管理系统这个项目不大不小正好能把这个协作模式的每一个环节都测一遍。你要是也想拿别的练手项目试建议保持同样的节奏——拆细需求、分段生成、手动审查、编译回灌、环境自查。这套流程跑下来你会发现自己对Qt的掌控力比手写一个完整项目还要扎实因为AI逼着你去想清楚了很多以前糊弄过去的边界问题。