鸿蒙 AI 自动化开发:让 AI 学会自己编译、自己调试

📅 2026/7/15 21:11:46 👁️ 阅读次数 📝 编程学习
鸿蒙 AI 自动化开发:让 AI 学会自己编译、自己调试

鸿蒙 AI 自动化开发:让 AI 学会自己编译、自己调试

参考文档

当前 AI 开发流程的真正瓶颈

用 AI 辅助编码半年后,大多数开发者都有一个感受:AI 写代码已经够用了,但围绕 AI 的人工配合太累了。

一个典型的场景:你让 AI 在首页加个下拉刷新,它几秒钟就写出了代码。然后——

  • 你来编译,报错了。你把错误信息复制给 AI,等它改。
  • 改完再编译,又报错。你再复制,再等。
  • 终于编译通过了。你手动启动应用,导航到首页,操作一遍——发现 UI 不对。你截图,描述给 AI,再等它改。
  • 改完再编译、再部署、再手动验证……

整个过程里,AI 只负责一件事:生成代码。而编译、部署、运行、看界面、判断对不对——全是你在做。你本质上在给 AI 当编译器、调试器和 QA

你的日常工作流: 你 → 告诉 AI 需求 AI → 生成代码 你 → 编译 ← 人工 你 → 看报错 ← 人工 你 → 把报错复制给 AI ← 人工 AI → 修复代码 你 → 再编译 ← 人工 你 → 部署到设备 ← 人工 你 → 打开应用看界面 ← 人工 你 → 看日志排查问题 ← 人工 你 → 截图 + 复制日志给 AI ← 人工 AI → 再修复 ...(重复直到你满意)

问题很明显:AI 能写代码,但它看不见自己写的代码跑起来是什么样。它不知道编译有没有过,不知道界面长什么样,不知道日志里有没有报错,不知道功能对不对。每一次反馈都需要你手动介入——你就是 AI 的眼睛、耳朵和手。

换个思路:让 AI 自己编译、自己看界面

如果 AI 能自己编译呢?编译报错了,它自己读错误信息、自己改、自己重新编译——不需要你复制粘贴。

如果 AI 能自己部署运行呢?改完代码,它自己把应用装到设备上、自己启动。

如果 AI 能自己"看"界面呢?它能看到当前页面上有哪些元素、文字对不对、按钮在不在、布局是否符合预期——不需要你截图描述。

如果 AI 能自己读日志呢?它能自己抓取运行日志,看到崩溃堆栈、网络请求结果、业务流程走到了哪个分支——不需要你复制粘贴日志。

换句话说:不是让流水线替人做事,而是教会 AI 使用开发者每天都在用的那些工具——hvigor 编译、hdc 部署、uitest 查看 UI、hilog 读日志。AI 一旦拥有了这些能力,它就不再是一个只能输出代码片段的文本生成器,而是一个能独立完成「编码 → 编译 → 部署 → 验证 → 修复」循环的自主开发者。

新的工作流: 你 → 告诉 AI 需求 AI → 生成代码 AI → 自己编译 ← AI 自己做 AI → 编译报错?自己读错误、自己改、自己重编译 ← AI 自己做 AI → 编译通过 → 自己部署到设备 ← AI 自己做 AI → 自己查看 UI 是否符合预期 ← AI 自己做 AI → 自己读日志,检查有没有异常 ← AI 自己做 AI → 不对?自己分析 UI 树 + 日志、自己修复 ← AI 自己做 AI → 输出验证报告(含截图 + 关键日志) 你 → 看一眼报告,确认通过

你的角色从「AI 的编译器和眼睛」变成了「最终审批者」。


给 AI 四种能力

要实现这个转变,需要给 AI 补上四种它目前不具备的能力:

能力一:自己编译、自己修

鸿蒙的构建工具 hvigor 可以通过命令行调用:

./hvigorw--modeproject-pproduct=develop-pbuildMode=debug assembleApp

编译输出是结构化的——包含文件路径、行号、错误类型和详细描述。AI 完全可以自己跑这个命令,自己读输出,自己定位问题。

具体流程:

AI 执行 hvigorw 编译 ↓ 编译失败 → AI 解析错误输出 ↓ AI 读取报错文件的对应代码 ↓ AI 修改代码 → 重新编译 ↓ 循环直到编译通过(或达到上限,比如 5 轮)

这里有一个关键细节:不需要把整个文件发给 AI。编译错误已经告诉你哪个文件哪一行出了什么问题,只需要取错误行上下 ±20 行源码就够了。一个 2000 行的文件只发 40 行,token 消耗降 98%。

另一个细节是错误去重。一个类型定义错误可能触发十几个下游报错(「找不到属性」「类型不匹配」……),全部喂给 AI 只会干扰判断。正确做法是按优先级排序,每轮只处理 Top 错误,修完重编译看残留。

能力二:自己部署、自己运行

编译通过后,AI 需要把应用装到设备上并启动。HarmonyOS 的hdc(HarmonyOS Device Connector)提供了完整的命令行接口:

# 安装应用hdcinstallentry/build/default/outputs/default/entry-default-signed.hap# 启动应用hdc shell aa start-aEntryAbility-baaa

这两条命令就是开发者每次手动「跑一下」的自动化版本。AI 执行完就能拿到一个正在运行的应用实例,接下来该「看」界面了。

能力三:自己"看"界面、自己判断

这是最关键、也最有价值的能力。AI 怎么"看"界面?

不是靠截图识别——视觉模型的 UI 理解能力不够稳定,容易误判。

而是靠 UI 树(可访问性树)。HarmonyOS 的uitest工具可以把当前页面的 UI 层级结构导出为 JSON:

uitest dumpLayout

输出的 JSON 是一棵树,每个节点包含:

  • 组件类型(Text、Image、Button、List 等)
  • 文本内容(text属性)
  • 元素 ID(id属性)
  • 位置坐标(bounds
  • 是否可见、是否可点击等状态

AI 读这棵树,就像开发者用 DevTools 检查元素一样——它能看到页面上有什么文字、按钮在哪里、列表是否渲染了数据。这比截图对比稳定得多,因为文字断言不受字体、颜色、分辨率的影响。

除了"看",AI 还能"操作":

# 点击指定坐标uitest uiInput click5401200# 滑动uitest uiInput swipe5401500540500500# 输入文字uitest uiInput text"搜索内容"

AI 可以模拟用户操作,然后重新 dump UI 树,验证操作后的页面状态是否符合预期。

能力四:自己读日志、自己分析

UI 树告诉 AI「界面上有什么」,但无法告诉 AI「程序内部发生了什么」。一个按钮在页面上确实存在,但点击后没有反应——是回调没触发?是网络请求失败了?还是数据解析出了异常?这些信息只存在于运行日志里。

开发者日常调试时,最常用的手段之一就是盯着 DevEco Studio 的 Log 面板看输出。AI 同样可以做到——HarmonyOS 的hilog提供了完整的命令行接口:

# 实时抓取日志,按应用进程过滤hdc shell hilog|grep"aaa"# 按日志级别过滤(只看 Error 和 Warn)hdc shell hilog--levelE# 按 domain/tag 过滤hdc shell hilog--tag"WSRequest"# 导出日志到文件hdc shell hilog-e>/tmp/app.log

AI 读日志能覆盖的场景,是 UI 树和截图覆盖不了的:

问题类型UI 树能发现?日志能发现?
按钮文字错误不能
元素缺失/布局错乱不能
点击后无响应(回调未触发)不能
网络请求失败/超时不能
数据解析异常(JSON 字段缺失)不能
空指针/类型转换崩溃不能
状态未更新(业务逻辑 bug)不一定

换句话说:UI 树是 AI 的"眼睛",日志是 AI 的"听诊器"。一个看外表,一个听内里。两者配合,AI 才能做出完整的诊断。

实际调试中,AI 的典型做法是:

1. 操作前:清空日志缓冲区(hilog -r) 2. 执行操作:click / swipe / 页面跳转 3. 操作后:抓取这段时间内的日志(按时间范围或 tag 过滤) 4. AI 分析日志: - 有 ERROR/Exception → 定位崩溃原因,读对应源码,修复 - 有网络请求的 URL 和响应码 → 判断接口是否异常 - 有 xlog 输出的业务日志 → 判断业务流程是否走到预期分支 - 日志正常但 UI 不对 → 结合 UI 树分析渲染问题

这里有一个实用技巧:让 AI 在生成业务代码时,在关键分支埋入带特定 tag 的日志。比如:

// AI 生成的代码中自动加入调试日志xlog.info('PullRefresh','开始刷新,当前页码: ${this.page}')// ... 请求完成后xlog.info('PullRefresh','刷新完成,返回 ${data.length} 条数据')

这样 AI 在验证阶段读日志时,就能直接看到业务流程是否按预期执行。相当于 AI 给自己装了"调试探针"——它知道自己在哪些关键位置留了日志,读日志时就能快速定位问题。

需要注意的是,日志量可能很大。一个应用启动后几秒内就可能产生上千条日志。全部发给 AI 会浪费大量 token。正确做法是预处理:按 tag 过滤只保留应用自身的日志,按级别过滤优先保留 Error 和 Warn,截取操作前后的时间窗口。通常经过这些过滤后,日志量可以从几千行压缩到几十行,足够 AI 做出准确判断。


实现方案:Python 封装层 + AI 调用

为什么用 Python

主项目是 ArkTS,但验证层我们选择了 Python。原因很实际:

  • hdcuitest的 Python 封装生态更成熟,社区现成方案多
  • 验证脚本与业务代码解耦,独立维护,不会污染项目代码
  • AI 可以在同一轮对话中同时生成 ArkTS 业务代码和 Python 验证脚本

封装层设计

Python 层封装一个HdcHelper,把 hdc 和 uitest 的命令行调用包装成语义化的函数:

classHdcHelper:defbuild(self)->BuildResult:"""执行 hvigorw 编译,返回结构化的编译结果"""...definstall_and_launch(self,bundle_name:str):"""安装 HAP 包并启动应用"""...defdump_layout(self)->dict:"""导出当前页面的 UI 树"""...defscreenshot(self,name:str)->str:"""截图并返回本地路径"""...defclick_text(self,text:str):"""在 UI 树中找到指定文字并点击"""...defhas_text(self,text:str)->bool:"""检查当前页面是否存在某文案"""...defswipe(self,x1,y1,x2,y2,ms:int):"""模拟滑动手势"""...defclear_log(self):"""清空日志缓冲区"""...defget_log(self,tag:str=None,level:str=None)->str:"""抓取日志,可按 tag/级别过滤"""...defget_errors(self)->str:"""只获取 Error 级别日志"""...

AI 的自主调试循环

有了这些能力,AI 的工作方式变成了:

1. AI 根据需求生成/修改代码(同时在关键分支埋入调试日志) 2. AI 调用 build() 编译 - 失败 → AI 读错误信息,读对应源码,修改代码,回到 2 - 成功 → 继续 3. AI 调用 install_and_launch() 部署并启动应用 4. AI 调用 clear_log() 清空日志缓冲区 5. AI 执行操作(click / swipe / 页面跳转) 6. AI 调用 dump_layout() 查看当前页面 UI 状态 7. AI 调用 get_log() / get_errors() 抓取运行日志 8. AI 综合诊断: - UI 树异常 → 修改代码,回到 2 - 日志中有 ERROR/Exception → 定位崩溃或逻辑错误,修改代码,回到 2 - 日志中业务流程未走到预期分支 → 修改代码,回到 2 - UI 和日志均正常 → 继续 9. AI 调用 screenshot() 截图留档 10. AI 输出验证报告(含截图 + UI 树快照 + 关键日志片段)

注意:这个循环里没有人。不是人编译了告诉 AI 结果,不是人看了界面告诉 AI 哪里不对,不是人翻了日志告诉你哪里报错。AI 自己编译、自己看 UI 树、自己读日志、自己综合诊断、自己修复。

验证脚本也可以 AI 生成

对于复杂场景,AI 在生成业务代码的同时,可以同步生成一个 Python 验证脚本:

deftest_home_pull_to_refresh():hdc=HdcHelper()hdc.install_and_launch("aaa")# 等待首页加载asserthdc.has_text("推荐"),"首页未加载"hdc.screenshot("01_home_loaded")# 清空日志,准备捕获刷新操作的日志hdc.clear_log()# 执行下拉操作hdc.swipe(540,1500,540,500,500)# 检查日志:确认刷新流程走到了预期分支log=hdc.get_log(tag="PullRefresh")assert"刷新完成"inlog,"刷新流程未完成,请检查日志"# 验证 UI:刷新后数据更新asserthdc.has_text("刚刚更新"),"下拉刷新未生效"hdc.screenshot("02_after_refresh")

这个脚本本身也是 AI 生成的——AI 知道需求是「下拉刷新」,所以它知道要验证「下拉后数据更新」。脚本运行后的结果(通过/失败、截图、UI 树快照)同样可以作为 AI 自我修复的输入。


整体架构

┌──────────────────────────────────────────────┐ │ 开发者 │ │ 输入需求描述 → 等待 → 审批最终结果 │ └─────────────────┬────────────────────────────┘ │ ┌─────────────────▼────────────────────────────┐ │ AI 自主开发循环 │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ 生成代码 │──→│ 自己编译 │──→│ 自己部署 │ │ │ │ +埋日志 │ └────┬─────┘ └────┬─────┘ │ │ └──────────┘ │ │ │ │ ↑ 编译失败? │ │ │ │ 自己读错误 │ │ │ │ 自己修改 │ │ │ │ │ │ │ │ │ └──→ 回到修改 ──┘ │ │ │ │ │ │ │ ┌────▼──────┐ │ │ │ │ 清空日志 │ │ │ │ │ 执行操作 │ │ │ │ └────┬──────┘ │ │ │ │ │ │ │ ┌──────────▼───────┐ │ │ ├──── 不对?自己改 ←│ 自己看 UI + 读日志 │ │ │ │ │ UI 树 + hilog │ │ │ │ │ + 截图留档 │ │ │ │ └──────────────────┘ │ │ ┌────▼──────────────────────────────────┐ │ │ │ 输出验证报告 │ │ │ │ 代码变更 + 截图 + UI 树快照 + 关键日志 │ │ │ └───────────────────────────────────────┘ │ └──────────────────────────────────────────────┘

实践中踩过的坑

1. UI 树的时序问题

dumpLayout拿到的是执行那一刻的 UI 快照。页面中的异步内容(网络请求、动画渲染)可能还没完成,AI 就会看到「元素缺失」并误判为 bug。

解法:引入轮询等待。对预期应出现的元素,在 5 秒超时窗口内周期性重试 dump,而非一次失败就判定为 bug。页面跳转后设置 1 秒固定延迟再首次 dump。

2. 编译错误的级联膨胀

一个类型定义错误可能触发十几个下游报错。如果 AI 试图一次性修所有报错,很容易改东改西、越改越乱。

解法:每轮只处理 Top-3 错误,按类型错误 > 语法错误 > 警告排序。修完重编译,很多下游报错会自然消失。

3. Token 消耗

AI 自己编译、自己看 UI 树,意味着每轮循环都要消耗 token。一个需求迭代 5-6 轮下来,token 消耗可能是纯代码生成的 3-5 倍。

解法:分层上下文 + 按需检索。核心规范固定注入(~500 token),组件文档按需求关键词动态检索(~1000 token),不要全量灌入。同时,编译错误只发错误行 ±20 行源码,UI 树只发相关子树而非整棵树。

4. AI 陷入死循环

某些情况下 AI 会反复修改同一段代码但始终修不对——比如对某个 ArkUI API 的理解本身就有误。

解法:设置熔断机制。编译最多重试 5 轮,UI 验证最多重试 3 轮。超过上限就终止循环,输出完整的错误报告(包含所有尝试过的修改和失败原因),交给人介入。


现在就能做的事

你不需要一次性搭完整个自动化系统。但有一件事今天就可以做,而且会立刻提升 AI 辅助编码的质量:

整理你的AGENTS.md

把代码规范、组件索引、架构约定、禁用手法写成 AI 可消费的格式。这份文档做两件事:

  1. 即使没有自动化流水线,你每次跟 AI 对话时把它作为上下文喂进去,AI 生成的代码质量会显著提升——因为它知道了你项目的规矩。
  2. 当你准备搭建自动化流水线时,这份文档就是 AI 的「项目知识库」,直接复用。

下一步,你可以尝试让 AI 自己跑编译命令、自己读编译输出。大多数 AI 编码助手已经支持执行终端命令——你只需要在 prompt 里告诉它:「写完代码后执行./hvigorw ...编译,如果报错就自己读错误信息并修复,直到编译通过。」

再下一步,才是接入hdcuitest,让 AI 学会自己看界面。

流水线的终点是 AI 全自主,但起点是教会 AI 使用工具。