鸿蒙 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 可以通过命令行调用:

bash 复制代码
./hvigorw --mode project -p product=develop -p buildMode=debug assembleApp

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

具体流程:

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

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

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

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

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

bash 复制代码
# 安装应用
hdc install entry/build/default/outputs/default/entry-default-signed.hap

# 启动应用
hdc shell aa start -a EntryAbility -b aaa

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

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

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

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

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

bash 复制代码
uitest dumpLayout

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

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

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

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

bash 复制代码
# 点击指定坐标
uitest uiInput click 540 1200

# 滑动
uitest uiInput swipe 540 1500 540 500 500

# 输入文字
uitest uiInput text "搜索内容"

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

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

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

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

bash 复制代码
# 实时抓取日志,按应用进程过滤
hdc shell hilog | grep "aaa"

# 按日志级别过滤(只看 Error 和 Warn)
hdc shell hilog --level E

# 按 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 的日志。比如:

typescript 复制代码
// 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 的命令行调用包装成语义化的函数:

python 复制代码
class HdcHelper:
    def build(self) -> BuildResult:
        """执行 hvigorw 编译,返回结构化的编译结果"""
        ...

    def install_and_launch(self, bundle_name: str):
        """安装 HAP 包并启动应用"""
        ...

    def dump_layout(self) -> dict:
        """导出当前页面的 UI 树"""
        ...

    def screenshot(self, name: str) -> str:
        """截图并返回本地路径"""
        ...

    def click_text(self, text: str):
        """在 UI 树中找到指定文字并点击"""
        ...

    def has_text(self, text: str) -> bool:
        """检查当前页面是否存在某文案"""
        ...

    def swipe(self, x1, y1, x2, y2, ms: int):
        """模拟滑动手势"""
        ...

    def clear_log(self):
        """清空日志缓冲区"""
        ...

    def get_log(self, tag: str = None, level: str = None) -> str:
        """抓取日志,可按 tag/级别过滤"""
        ...

    def get_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 验证脚本:

python 复制代码
def test_home_pull_to_refresh():
    hdc = HdcHelper()
    hdc.install_and_launch("aaa")

    # 等待首页加载
    assert hdc.has_text("推荐"), "首页未加载"
    hdc.screenshot("01_home_loaded")

    # 清空日志,准备捕获刷新操作的日志
    hdc.clear_log()

    # 执行下拉操作
    hdc.swipe(540, 1500, 540, 500, 500)

    # 检查日志:确认刷新流程走到了预期分支
    log = hdc.get_log(tag="PullRefresh")
    assert "刷新完成" in log, "刷新流程未完成,请检查日志"

    # 验证 UI:刷新后数据更新
    assert hdc.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 使用工具。

相关推荐
HarmonyOS_SDK1 小时前
差异化推送消息能力,助力支付宝腕上消息业务闭环
harmonyos
heroboyluck2 小时前
AI工程师第四课 - 深度学习入门
人工智能·python·深度学习·llama
武子康2 小时前
OpenAI 把 Codex 接进 Claude Code:Coding Agent 从单兵工具进入协作系统
人工智能·openai·claude
延凡科技2 小时前
延凡科技综合监控预警处置平台—— 一体化视频AI安防闭环系统设计与功能实现[特殊字符]️
数据库·人工智能·科技·安全·能源
王莎莎2 小时前
论文命中不是终点,Related Works 才是科研 Agent 的第二跳
人工智能·设计
一楼的猫2 小时前
网文AI辅助怎么过审?番茄200+维度检测与去AI味实战
人工智能·学习·机器学习·自然语言处理·ai写作
Smoothcloud润云2 小时前
训练一个7B参数的大模型需要多少张GPU?大概要跑多久?
人工智能·深度学习·ai·开源·gpu算力
前沿AI社2 小时前
Grok CLI 偷传代码库事件复盘:智能体安全与国产开源智能体的本地优先路径
人工智能
大金SEO2 小时前
GEO优化:写给AI看的标题怎么写?
人工智能