用Agent Skills提升Qt/QML开发效率:三组真实项目对比实验
2026/9/16 10:04:41 网站建设 项目流程

一个普通的工作日下午,我在改一个 Qt Quick 项目的 QML 界面。需求本身不复杂:C++ 后端把设备状态推给前端,QML 根据状态刷新进度条、切换提示文案。这种“老熟人”需求我过去几年写过很多次,但每次还是会忍不住翻旧代码确认几个细节——QVariantMap 展开后 QML 里到底该怎么读、信号触发时机在 UI 线程有没有问题、qmlRegisterType 的上下文该挂在哪层。

就在那段时间,团队里有人讨论起 Agent Skills。他们说要给 AI“装插件”,把开发规范、常用代码模式、易错点直接做成技能包,AI 干活前会自动加载。我第一反应是半信半疑——插件靠不靠谱,不能听人吹,得拿真实项目试一轮。所以我给自己定了个验证计划:同一个 Qt/QML 项目里挑三个真实需求,分别用老办法、普通 AI 对话、Agent Skills 来做,记录耗时、改动次数和一次编译通过的情况。

这么一轮跑下来,结果既有惊喜也有预期内的失望。这篇文章就把完整过程写出来,包括我怎么设计实验、怎么自己写 QML 技能包、以及哪些场景它确实帮不上忙。

1. 为什么反复写还是会反复踩坑:Qt/QML 开发中的高频重复劳动

这几年我主要做桌面客户端,Qt 从 5.9 一路用到 5.15.2,偶尔切到 Qt 6。QML 做界面确实快,但快不代表省心。真正让人头大的不是某个知识点多难,而是大量看似简单的操作,细节多到离谱,每次写都要重新对一遍。

1.1 QML 与 C++ 混合编程:最简单也最容易翻车的部分

qmlRegisterType注册、Q_INVOKABLE暴露方法、signal触发刷新,这套流程我写过上百遍,闭着眼能打。但真实项目里从来不是“一个类一个界面”这么干净。

就像热词里常被搜到的“qml与c++混合编程详解”“qml与c++交互”,很多人搜是因为遇到的问题五花八门:注册的是单例还是普通 QObject、Q_PROPERTY 的 NOTIFY 信号没接对导致界面不刷新、QVariantList 转出来的数组在 QML 侧格式不对、对象生命周期挂错了 parent 导致崩溃。这些问题没有一个是算法级难度,但每个都足够让人花掉半天。

更麻烦的是,这些细节还带“团队属性”。比如我们项目里约定状态对象必须用单例注册,方便 QML 任意位置直接调用;方法必须返回显式类型值,不能藏在QObject*里让 QML 猜。这种规范写不进官方文档,只能靠新同事踩坑、老同事讲解,然后在下一次迭代中继续口口相传。

1.2 国际化和多语言:最容易被“大致能用”带偏

Qt 的国际化不算难,qsTr()tr()lupdatelrelease一套下来,翻译文件也生成了,运行时也加载了。但“能用”和“好用”之间隔着几条深坑。

比如 QML 侧的qsTr()默认上下文是文件名,如果你把文本拆到单独组件里,lupdate生成后索引全乱;再比如 C++ 侧tr()的上下文是你所在类的类名,如果信号处理函数里直接写了中文字符串而不是tr("..."),翻译根本不会生效;还有语言切换后是否要发一个全局信号通知所有 QML 元素重新求值——这个不做,切换语言只有下次重建界面才生效。

这些坑我在不同项目里反复踩过。客观说不是文档没有写,而是太分散,遇到时 Google 一遍、翻一遍源码才能想起来,纯属重复劳动。

1.3 窗口自定义与界面动效:写代码容易,调手感难

热词里“qml实现无边框窗口拖动缩放”“qml 动画”“qt 自定义进度条”热度一直很高。无边框窗口这个需求,十个桌面应用九个要做,但九个人里至少一半做得不顺手。

无边框窗口本身用Qt.FramelessWindowHint就能去掉标题栏,麻烦的是鼠标拖动和边缘缩放。你需要在 MouseArea 里判断pressedmouseYmouseX,然后手动算窗口xywidthheight。听起来直接,一碰到多显示器、DPI 缩放、最小尺寸限制、双击最大化这些边界情况就容易歪。

动效也一样。QML 动画的写法不难,难在“动画曲线怎么定才不生硬”“状态切换时旧动画如何打断”“进度条收到高频状态刷新时怎么做到不闪烁”。这些不是靠记忆,而是靠手感。

这些反复踩的坑,就是我决定验证 Agent Skills 的初衷:如果能把“团队规范 + 个人踩坑总结”沉淀成技能包,让 AI 每次自动加载,那会不会比每次重新发起一轮对话更靠谱?

2. 三组对照实验:我用真实项目需求而不是 demo 做测试

为了不让这次验证变成“跑个 hello world 就发朋友圈”,我特意从手头一个正在做的小工具里摘了三个真实任务出来。每个任务都是项目里真的要做的事,不是专门为测试造出来的。

2.1 测试对象与衡量标准

我选了同一个项目、同一个开发分支、同一个人(就是我自己)来做对照实验。三种方式分别是:

  • 老办法:翻旧项目代码 + 查 Qt 文档 + 凭经验手写;
  • 普通 AI 对话:把需求直接丢给 AI,有需要就追加提问,但不提前告诉它项目规范;
  • Agent Skills:先加载一个我写好的 Qt/QML 技能包,再对 AI 提同样的需求。

衡量标准不搞虚的,就看四个数据:从开始编码到能编译通过的耗时、提交前需要手动修改的行数、踩坑次数(编译报错、运行期异常、界面表现不对都算)、以及代码是否遵循团队既有风格。

2.2 任务A:设备状态上报与 QML 界面刷新

这是典型的前后端联动需求。C++ 侧有一个设备管理类,内部维护设备的状态机;QML 侧有一个状态卡片,需要根据 C++ 侧的状态变化实时刷新文字、颜色和进度条。同时界面上要有个按钮,点一下把状态重置。

任务里最麻烦的不是“把数据从 C++ 传到 QML”,而是“传过去之后事件该走哪条链路”。是注册对象让 QML 直接访问属性,还是用信号带参数发送?属性用Q_PROPERTY还是普通signal?这些选择直接决定了 QML 代码的写法,也决定后续维护靠不靠得住。

2.3 任务B:主界面与设置页中英文一键切换

这个任务要求主界面和设置页所有可见文案都支持中英文,且切换语言后不需要重启应用,界面立即刷新。

难点有两个:第一,QML 里的qsTr()要规范到文件名和上下文,否则翻译表生成出来是乱的;第二,运行时语言切换需要有一个全局事件通知,QML 的Text元素才能重新求值。C++ 侧如果也有新的字符串(比如错误提示由 C++ 产生),还要统一走tr()而不是直接写中文字符串。

2.4 任务C:无边框窗口的拖动与边缘缩放

这个任务要的是把系统标题栏去掉,做成自定义标题栏,同时保留“鼠标按住空白处拖动窗口”“鼠标放到边缘能拉大拉小”“窗口有最小尺寸限制”这三个核心交互。

为什么这个任务也能拿来测?因为它代码量不大,但边界情况极多:QML 的 MouseArea 拿到的坐标是相对哪个坐标系、窗口缩放时鼠标位置和窗口尺寸如何换算、怎么避免拖出屏幕、DPI 变化后坐标基准是否要重算。这些恰恰是普通 AI 最容易给出“看起来对、跑起来歪”代码的地方。

三组任务我安排在同一周完成,避免最近我和项目的“手熟程度”影响结果。

3. 验证过程全记录:从安装技能包到逐个用例跑通

先说环境,免得后面代码大家复现对不上。我本机是 Windows 10,Qt 5.15.2 MSVC2019 64 位,用 Qt Creator 做日常编辑,QML 通过qmlRegisterTypeQQmlApplicationEngine装载。然后配合 Claude Code 的 Agent Skills 来做验证。

3.1 把技能装进 Agent 的两条路:社区包和自建包

Agent Skills 的安装方式很简单,一行命令就能从社区仓库拉技能:

npx skills add sandai-org/vidmuse-skills --agent claude-code -g -y

这条命令把仓库里的技能下载到本地,-g表示全局安装,-y跳过确认。实测下来,社区仓库确实有不少现成技能,什么“生成代码审查清单”“配置 Docker 环境”都有。但对我这次要验证的 Qt/QML 场景,社区包覆盖很有限,没找到哪个包内置了我们团队的 QML 命名习惯和 C++ 交互规范。

所以真正的重头戏是我自己写一个技能包。这也是 Agent Skills 最核心的用法——不是装别人的包,而是把团队自己的规范和踩坑经验写成SKILL.md注册进去。

技能包的标准结构是这样:

skills/ qt-qml-dev/ SKILL.md # 技能描述、触发条件、实操规则 examples/ # 放几个可编译通过的示例代码 checklist.md # 常见错误检查清单

3.2 SKILL.md 到底怎么组织:规则、示例、检查清单

我第一次写SKILL.md时犯了个错误:把 Qt 文档里关于 QML 和 C++ 交互的内容整段抄进去。结果技能包体积很大,AI 加载慢不说,重点还不突出,给的建议反而比不用技能时更保守。后来我改成“规则 + 精简示例 + 检查清单”的结构才顺过来。

以我写的qt-qml-dev技能包为例,核心内容分四部分:

  • 触发条件:说明这个技能适合处理哪些问题(QML 与 C++ 交互、国际化、窗口行为、常见编译错误);
  • 项目约定:写了团队实际用的几种模式,比如“单例类用qmlRegisterSingletonInstance注册”“暴露给 QML 的方法必须加Q_INVOKABLE”“QML 里不要直接操作 C++ 侧裸指针”;
  • 示例代码:每个约定配一段最小可编译代码,让 AI 有参照物;
  • 检查清单:列出容易犯的低级错误,比如 “C++ 侧字符串没包tr()就直接返回给 QML”“信号名和 QML 侧大小写不匹配”。

写完后把技能包放到项目的.claude/skills/目录下,Agent 在对话时如果判断相关就会自动加载,不需要每次手动指定。

3.3 任务A实测:普通 AI 给了能跑的代码,但对齐规范花了 20 分钟

先跑任务A,需求是设备状态上报和 QML 界面刷新。

我用一句话向普通 AI 提需求:“C++ 类 DeviceManager,QML 界面要实时显示设备状态,点按钮重置。”它给的方案是标准的Q_PROPERTY+signals+onSomePropertyChanged处理,逻辑没大问题,能编译,也能跑通最基础的路径。

但问题出在细节上:

第一,它把DeviceManager注册成了qmlRegisterType,也就是让 QML 自己创建实例。而我们的项目里设备管理对象是启动时由 C++ 侧创建并注入的,QML 侧只能拿到实例,不能自己 new。我改成qmlRegisterSingletonInstance,顺带把 QML 里所有DeviceManager的引用方式都调了一遍。

第二,它给 QML 传状态时用了一个字符串字段,然后文档写“根据 status 字段判断”。看起来简单,但一旦状态枚举增多就会变成一坨 if-else。我们项目一直用整型枚举,这个 AI 没地方知道,只能生成自己认为合理的设计。

最终结果:编译通过前改了 11 行,踩了 2 个坑(注册方式错误、属性绑定方式不匹配团队习惯),耗时约 35 分钟。不算慢,但代码需要人工规整。

再用 Agent Skills 跑同一任务。技能包里已经把“单例注册”“枚举传值”“Q_INVOKABLE 方法命名”这些约定写清楚了,AI 生成时直接按规范输出。这次我只改了 2 行命名,一次编译通过,耗时 12 分钟左右。

3.4 任务B实测:Skill 在“术语表 + 三态语言刷新”上优势明显

任务B是中英文切换,这是几组任务里 Agent Skills 优势最大的一组。

普通 AI 对话里,我告诉它要用qsTrtr,它给了一套标准流程,也提到了用lupdate生成翻译文件。但到我实际编译验证时才想起一个关键点:语言切换后 QML 界面刷新靠什么触发?AI 没主动提,我也没专门问。后来我查了一下,需要 C++ 侧在切换语言后发全局信号,QML 侧通过Connections或者属性绑定收到通知后重新求值,才实现了“不重启、即切即用”。这个过程多花了我 20 分钟查资料和打补丁。

用 Skill 跑就顺很多。我在技能包里内置了国际化的完整流程,包括“QML 的qsTr()上下文会取文件名,拆组件要注意”“C++ 返回给 QML 的字符串必须用tr()包裹”“语言切换后要通知 QML 刷新”这三个高频踩坑点,还附了一个统一术语表,中英文文案写在translations/下面。

AI 拿到技能包后,生成的主要逻辑一次就对了:QML 侧所有文案都包了qsTr(),C++ 侧自定义了一个信号来通知语言切换,lupdate的扫描路径也设计得合理。我只需要把中间几个业务文案的中文术语替换成项目标准叫法。

这次普通 AI 对话耗时 55 分钟,Agent Skills 耗时 18 分钟,差距最大。

3.5 任务C实测:窗口拖动缩放是“手感型”需求,Skill 帮了一半

任务C就复杂了,因为无边框窗口拖动缩放本质是“手感型”需求。不是说给出一段能跑的代码就完事,而是边界情况多到让人烦。

普通 AI 给的代码逻辑是对的:onPressed记录起始鼠标位置和窗口位置,onPositionChanged更新xy;缩放则是判断鼠标在四条边和四个角时分别改变宽高。编译能过,简单拖动也能跑。

但一测就发现问题:

  • 在多显示器下,窗口位置可能落到副屏负坐标,处理mouseX时需要加回窗口坐标偏移;
  • 鼠标在边缘缩放时,如果只改widthheight,窗口的对角位置不变,但靠左或靠上的边会“跳一下”;
  • 未限制最小尺寸,窗口能缩成一小块。

用 Agent Skills 跑,我在技能包里预先写了两条自己常踩的规则:“拖动的位移计算基准使用全局坐标,不是相对窗口的局部坐标”“缩放时需要同时调整 x/y 和 width/height,否则靠左靠上的边会跳”。AI 在这些规则的辅助下生成的代码,直接解决了前两个问题,最小尺寸的检查清单也自动带上了。

但第三个问题更微妙:窗口拖动手感、缩放的灵敏度和角上操作的触发区域,这些需要实际体验才能定,AI 无法替你决定。最终我还是花了十分钟手工调参数。

这轮普通 AI 对话耗时 40 分钟,Agent Skills 耗时 28 分钟,差距没那么大,因为“手感”本身无法靠规则描述。

4. Agent Skills 真正值钱的地方:把“项目常识”固定下来

三组实验跑完,我心里对 Agent Skills 的定位清晰了很多。它不是让 AI 能力变强了,而是让 AI 不需要每次都“重新认识你的项目”。

4.1 与普通 AI 对话差别在哪:不是能力跃升,是省掉了重复“自我介绍”

普通 AI 对话里,你每次提需求,AI 看到的只是一个独立的会话。它不知道你项目里哪几个类已经存在、不知道你们团队的单例注册习惯、也不知道你踩过哪些坑。所以同样的需求,它每次都给你“最通用”的答案,而“最通用”往往不是你项目里最该用的那个。

Agent Skills 解决的正是这个。你把团队约定写成SKILL.md,AI 在回答前先读一遍,再基于这些约定生成方案。相当于每次给它安排了一个“项目常识预加载”。

我在任务A里体会最深。写qmlRegisterType还是qmlRegisterSingletonInstance,这个决定直接影响 QML 侧是“自己创建对象”还是“拿全局单例”。普通 AI 选了qmlRegisterType,从通用角度看没错,但对我们的项目就是错的。技能包一句话就把方向拽回来了。

4.2 Skill 和文档的区别:文档等人读,Skill 是给 AI 用的行为规范

有人说“这些规范写成文档不也一样吗”。不完全一样。文档是给人读的,新同事翻文档看的是“理解”,而 Skill 给 AI 的是“照做”。当然,Agent 也不能保证 100% 遵循,但它至少每个需求都会带上规则,比纯粹丢一个文档链接让 AI 自己理解靠谱得多。

我甚至觉得,Skill 的最佳形态是一个“会被 AI 反复读取的活文档”。团队里新规更新,改SKILL.md一处,后续所有生成代码都会跟着变。这么一来,技能包本身就变成了团队代码资产的一部分,需要 review,需要版本管理。

4.3 实测数据汇总

三组实验的核心数据整理如下:

任务方式编译通过前修改行数踩坑数总耗时
任务A 状态刷新普通AI对话11235分钟
任务A 状态刷新Agent Skills2012分钟
任务B 国际化普通AI对话14155分钟
任务B 国际化Agent Skills3018分钟
任务C 无边框窗口普通AI对话8340分钟
任务C 无边框窗口Agent Skills5128分钟

数据规模不算大,但趋势明显:越是包含“团队规范”“项目约定”的任务,Agent Skills 的提升越明显;越是需要个人手感、主观判断的任务,提升有限。

5. 它搞不定的地方:别对 Agent Skills 抱过度期待

如果这篇文章只讲 Agent Skills 有多好用,那容易害人。它有自己的边界,而且边界还挺明显。

5.1 复杂的异步调试和线程问题,技能包很难穷尽

Qt 开发里有一类经典难题,就是热词里搜“qt如何把modbus串口接收放到线程”这类问题。串口接收你不想让它卡 UI,所以要挪到工作线程,工作线程拿到数据再通过信号回传主线程。这个链路里任何一环出问题,表现往往是“程序偶尔崩溃”“UI 偶发卡顿”“数据丢失时好时坏”。

这类问题难在它不是“规则缺失”,而是“运行时行为依赖具体环境”:串口数据到达频率、线程调度延迟、QML 界面刷新时机、事件循环状态,全都会影响结果。技能包能告诉 AI 要用QtConcurrent::run还是QThread,能提醒它信号用QueuedConnection连接,但它没法替你做现场调试。我自己排查一个串口线程问题时,Agent 给的方案最后证明方向没错,但具体哪一行会崩,还是靠打印日志定位出来的。

所以这类问题我的建议是:技能包沉淀“规范”可以,别指望它替代调试。

5.2 需要产品语义理解的架构决策,AI 没有足够上下文

任务B里“语言切换后界面即时刷新”其实已经涉及一点“为什么需要即时刷新”的产品语义——这是切换按钮点下去用户立刻要看效果,而不是切完重启。AI 能理解这个需求,但它不会主动替你问“这个刷新是必须的吗”“局域网环境里延迟可接受吗”。

做架构决策更明显。比如要决定新的设置页是放进同一个 QML 文件里用 Loader 懒加载,还是拆成独立模块在 C++ 侧管理路由。这个问题依赖你是不是还有第二个页面也要复用它、团队对新页面的性能预期、以及后续是否有第三个人要维护。这些信息不在技能包里,AI 也没有足够的上下文帮你拍板,只能给你通用建议。

5.3 写技能包时最容易踩的坑

还有几个坑是写技能包过程中我自己踩到的,也分享出来。

第一个坑是“技能包贪多求全”。我最初把 Qt 模块涉及的所有最佳实践都塞进去,AI 加载后反而不知道听谁的了。后来精简成只保留项目常用、踩过坑的部分,效果立刻好很多。技能包的核心是“减负”,不是“百科全书”。

第二个坑是“示例代码没编译通过就放进去”。由于 Agent 会模仿你的示例代码写新代码,如果你贴了一段根本不存在的 API,它也会一本正经照着写,翻车概率极高。我把技能包里每个示例都单独建了 Qt 工程编译过一次才放进去。

第三个坑是“规则写得像口头建议”。比如“尽量用单例”这种措辞,Agent 会根据上下文自行判断“尽量”的程度。要把规则写成可检查的硬性要求,例如“所有需要暴露给 QML 的类都用 qmlRegisterSingletonInstance 注册,不要用 qmlRegisterType”。规则越明确,Agent 越能稳定执行。

第四个坑是“技能包不更新”。技能包会过时。项目从 Qt 5 升到 Qt 6,一些 API 变了;团队成员换了,风格也可能调整。如果技能包不跟着更新,AI 反而成为“最坚持旧规范的那个人”。我现在会把技能包跟项目主分支一起 review,每次代码评审时顺便看SKILL.md有没有要改的地方。

6. 给 Qt/QML 开发者的一份技能包清单建议

如果你也做 Qt/QML 开发,且打算试试 Agent Skills,我结合这次验证,给一份“值得先沉淀成技能包”的清单:

  • QML 与 C++ 交互规范:注册方式、Q_INVOKABLE 方法命名、信号槽绑定、类型转换约束;
  • 国际化完整流程:qsTr 上下文规则、C++ 侧 tr 包裹、运行时切语言刷新机制;
  • 无边框窗口模板:拖动基准坐标、缩放边界处理、最小尺寸限制;
  • QML 动画模式:项目约定的动画时长、缓动曲线、状态机切换;
  • 自定义控件样式规范:颜色、字体、间距的统一变量;
  • 串口或 Modbus 开发时的线程模型:工作线程回传信号的连接方式、避免卡 UI 的基本套路;
  • 打包发布清单:Qt 依赖项、平台插件、翻译文件怎么一起打进安装包。

不一定一次全写完。从你最痛、最常做的场景开始,写一个只有三条规则的技能包,跑一个任务,有用了再慢慢加。技能包的维护本身就是持续投入,我现在的习惯是“每踩一个坑,值得记下来就补一条”,不让它变成一次性产物。

最后再分享一个小技巧:技能包的目录最好跟着项目一起做版本管理,不要只放在个人机器的隐藏目录里。这样团队其他人 clone 项目下来,技能包已经在里面;代码评审时别人可以提出“这个规则是不是过时了”“这样写会不会限制 AI 太多”;新同学加入时,看一遍SKILL.md也比翻三个月代码更快的了解团队习惯。

Agent Skills 不是魔法,不会让你什么都不懂就写出生产级 Qt 应用,但它确实能把你和团队已经验证过的经验固化下来,让 AI 在正确的框架里帮你写代码。至少对我这种做了几年 Qt/QML、受够了反复解释项目背景的人来说,这套流程值得留在工具箱里。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询