去年底我就在琢磨一件事:AI Agent 到底能不能直接上手写鸿蒙应用?当时市面上的 Agent 写 Python、写前端已经很溜了,但鸿蒙开发一直没什么人聊。原因也简单,鸿蒙的工程结构和 ArkTS 语法对 AI 来说算是“小众知识”,报错信息又经常绕,搞不好就让 Agent 直接懵圈。但换个角度想,鸿蒙应用开发恰恰是最适合 Agent 去试错折腾的场景——工程结构固定、编译链路清晰、报错可复现,只要把 DevEco CLI 这条命令行链路打通,Agent 完全可以自己走完“写代码 → 编译 → 看报错 → 改代码”的闭环。我搭好环境实测了几轮,今天就把整个过程拆开讲清楚,包括工具链怎么选、指令怎么下、踩了哪些坑、Agent 怎么自己修 bug,希望能给研究 AI Agent 和鸿蒙开发结合点的朋友一点参考。
1. 项目思路:AI Agent 凭什么能写鸿蒙应用
1.1 拆开 AI Agent 的“黑盒”:它到底怎么干活的
很多人对 Agent 有个误解,觉得它就是“高级一点的聊天机器人”,其实完全不是一回事。普通对话模型是“你说一句,它回一句”,输出完就结束了,既不验证结果,也不关心你项目里现在到底是啥状态。AI Agent 则是一个持续运行的循环,核心是“观察 → 思考 → 行动 → 观察结果”四个步骤反复迭代。放在写代码这个场景里,就是 Agent 先看一眼工程目录结构,再决定要不要新建文件,写完之后执行一次构建命令,读到报错信息,然后分析是哪里出了问题,再改代码、再编译。
这个过程跟一个刚入职的初级开发很像。你给他一个需求,他不会一步到位,但好在他能自己看报错、自己查资料、自己迭代。Agent 的优势在于它“不知疲倦”,跑一百次编译也没怨言,而且上下文里能装下大量工程文档和代码片段。所以与其说“让 AI 写代码”,不如说“让 AI 像开发者一样在终端里工作”。这也是整篇实验的核心逻辑:Agent 不是用来生成一段孤立的代码,而是用来驱动一套完整的开发工具链。
我在实测前专门花时间梳理了 Agent 的运行逻辑。一个合格的 Coding Agent 至少要具备三样东西:第一,规划能力,能把一个模糊需求拆成具体任务列表;第二,工具调用能力,能执行终端命令、读写文件;第三,记忆能力,能记得自己前面改了什么、报错历史是什么。三者缺一不可,尤其是第三个,很多 Agent 写代码翻车就是因为它忘了自己刚改过哪里,重复犯错。
1.2 为什么偏偏选 DevEco CLI,而不是 DevEco Studio
做鸿蒙开发,官方主推的是 DevEco Studio 这个图形化 IDE,但它对 Agent 来说其实很不友好。Agent 没法用鼠标点按钮,也没法盯着屏幕看渲染出来的页面长什么样。哪怕有一些 GUI 自动化方案可以模拟点击和截图,那也非常脆弱,稍微换个窗口尺寸就失灵了。基于文本和命令行的工具链才是 Agent 的主场。
DevEco CLI 就是鸿蒙开发里那套命令行工具链的代称,核心是 hvigor 构建引擎和它配套的 hvigorw 脚本。项目工程建好之后,终端里执行 ./hvigorw assembleHap 就能编译出 HAP 安装包,所有输出都是纯文本日志,Agent 能轻松读取和理解。文件操作也完全基于目录结构,创建页面、修改配置、添加依赖,全部可以通过读写普通文本文件完成。这意味着 Agent 只需要两个基础能力——执行命令和读写文件,就能完整参与鸿蒙应用的开发流程,不需要任何视觉识别能力。
对比下来,DevEco CLI 的最大价值是“确定性”。图形界面操作每次点击的像素位置都可能变,但命令行只要命令正确、环境正确,输出结果就是稳定可预期的。这种确定性对 Agent 来说至关重要,因为 Agent 的自我纠错机制完全建立在“动作产生的结果可被读取”这个前提上。没有这个前提,Agent 就只能瞎猜。
1.3 整条链路怎么设计
我的整体链路设计其实不复杂,核心是一个闭环:需求描述 → Agent 规划任务 → 创建/修改代码文件 → 执行 DevEco CLI 构建 → 读取编译日志 → 失败则让 Agent 分析报错并修复 → 直到 HAP 产物生成。这个闭环每一步都是文本和命令,没有人工干预点,所以理论上可以全自动跑完。
实际执行时,我把这个链路拆成了三段。第一段是环境准备,把 DevEco Studio、SDK、hvigorw、模拟器全部安装并验证好;第二段是 Agent 工具配置,把终端执行、文件读写、代码搜索这些能力以“工具”的形式注册给 Agent;第三段才是正式实测,让 Agent 从头开发一个应用。这种分段的思路很重要,因为如果环境本身没配好,Agent 会陷入“同一个命令反复报错”的死循环,你会分不清到底是 Agent 笨还是环境有问题。先人工把地基打好,再让 Agent 上场,这是让 AI 写代码成功率最高的姿势。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备:先把地基打牢
2.1 安装 DevEco 命令行工具链
很多人一上来就想让 Agent 直接跑,结果第一步就卡住了。DevEco 的命令行工具链不是独立分发的,它跟着 DevEco Studio 一起装。所以你先要装一个 DevEco Studio,装完不要只盯着那个看得见的 IDE,要用的是它目录底下的 hvigor、SDK 和 hdc(手机调试桥)这些命令行组件。安装完之后,建议把几个关键路径加到 shell 的环境变量里,比如 SDK 所在目录、hvigor 相关脚本目录、hdc 工具的目录。
为了验证环境是否可用,我习惯先手工创建一个最小工程,跑一次完整构建,确认“开发机这边没有任何问题”。举个例子,在工程根目录执行:
bash复制# 查看 hvigor 版本,确认构建工具可用
./hvigorw --version
# 安装工程依赖,类似于 npm install
ohpm install
# 执行构建,生成 HAP 包
./hvigorw assembleHap --mode module -p product=default
如果这三条命令能顺下来,说明工具链没问题。这一步建议一定要做,因为后续 Agent 所有操作都建立在这套命令能跑通的基础上。我见过太多人跳过验证环节,最后 Agent 疯狂报同样的错,一查发现是 JDK 版本不对或者环境变量没配好,白白浪费 token。
2.2 给 Agent 装好“手和眼睛”
Agent 要操作终端和文件,光有模型不够,必须给它注册工具(Tools)。我当时用的方案是选一个支持工具调用的 Agent 框架,然后给它配三类工具:终端执行工具、文件读写工具、目录浏览工具。终端执行工具就是允许 Agent 在指定工作目录下运行 shell 命令;文件读写工具允许它创建、修改、删除工程内的代码文件;目录浏览工具让它可以看当前项目结构、搜索某个关键词出现在哪个文件里。
这里要说一下安全边界,非常重要。Agent 虽然有智能,但本质上还是概率模型,你给它越大的权限,它闯祸的可能就越大。我的做法是强制约束它的工作目录,只允许它访问当前这个鸿蒙工程目录,禁止它去系统目录或者其它项目乱串。命令层面也要做白名单,像 rm -rf 这种危险操作直接拒绝,sudo 也不允许。实际操作中,Agent 基本上只需要 ls、cat、sed、mkdir、hvigorw、ohpm 这几个命令,白名单不会限制到正常开发。
还有一个实用技巧是给 Agent 配置“技能”(Skill)。每个 Agent 框架叫法不一样,有的叫 Skill,有的叫 Plugin,但思路是一样的:把一组常用操作打包成语义化的工具,让 Agent 不需要记住复杂的参数组合。我把“构建 HAP”封装成一个叫 build_hap 的技能,内部自动执行环境变量加载和 hvigorw 构建;把“安装到模拟器”封装成 install_to_emulator,内部自动调用 hdc 命令。这样 Agent 不需要理解鸿蒙工具链的细节,只需要说“编译一下”,它就知道该调用哪个技能。这其实也是“ai agent skill”这个概念在真实项目里最有价值的落地场景。
2.3 初始化一个最小可编译工程
配置好 Agent 工具之后,我开始准备工程。这一步也有讲究:是让 Agent 从零建工程,还是先手工建一个模板再让 Agent 改?实测下来,我强烈建议先手工建一个最小可编译的工程,再交给 Agent。原因有两点。第一,鸿蒙工程的骨架文件很多,包括 AppScope、entry 模块、module.json5、build-profile.json5、hvigorfile.ts 等,让 Agent 从零生成这些文件的成功率并不高,很容易漏掉某个关键配置。第二,Agent 的价值在于快速迭代功能和修复问题,而不是重复造脚手架的轮子。先把一个干净的模板工程准备好,相当于给了 Agent 一个安全网,它所有的修改都有明确的参照。
建工程不一定非要点 IDE 的图形界面,可以用命令行工具完成。DevEco Studio 配套的 CLI 是支持创建项目的,大致方式是指定工程名、包名、模板类型,生成一个标准工程骨架。如果你们的 CLI 版本没带这个命令,也可以直接复制一个已有的最小工程,把包名和产品名清空,效果差不多。反正确认 ./hvigorw assembleHap 能跑出 HAP 就对了。
做完这一步,我的工作目录里就有了一套配置好环境变量的命令行工具链、一个可以正常编译的鸿蒙空工程、以及一个注册了终端和文件读写能力的 AI Agent。万事俱备,就差让它正式干活了。
3. 实测:从一句需求到一个能跑的 App
3.1 需求指令怎么写才能让 Agent 不跑偏
Agent 写代码成功与否,一半取决于它的模型能力,另一半取决于你给的指令。我写完几条指令后发现,很多失败的案例其实是需求描述太模糊导致的。比如你跟 Agent 说“帮我写一个待办事项应用”,它大概率会给你生成一个泛泛的 TodoList,但页面样式、交互逻辑、数据存储方式全都不符合你的预期。反过来,如果指令里包含了技术栈约束、页面结构、功能清单、验收标准,Agent 的表现会稳定很多。
我实测用的是一条经过多次调整的指令模板,核心结构是:角色设定 + 技术栈约束 + 功能需求 + 工程要求 + 自检要求。给大家看一下我当时实际下发的内容:
text复制你是一名鸿蒙应用开发工程师。请使用 ArkTS 和 ArkUI 在现有工程中开发一个待办事项 App,不要修改工程的基础配置,页面代码放在 entry/src/main/ets 目录下。
功能需求:
1. 首页展示待办事项列表,支持新增、勾选完成、删除
2. 新增功能使用一个输入框加确认按钮完成
3. 数据用本地数组保存,无需持久化
工程要求:
1. 必须保证代码符合 ArkTS 语法规范,类型定义完整
2. 不得使用任何需要额外安装的三方库
3. 页面布局适配手机竖屏,用普通尺寸估算即可
自检要求:
完成代码编写后,运行 ./hvigorw assembleHap --mode module -p product=default 进行编译,如果报错,根据报错信息修复代码,直到构建成功。
这条指令看着不算长,但信息密度很高。角色设定让 Agent 选择正确的技术语言,功能需求划定了明确边界,工程要求限制了它的发挥空间,自检要求强制它进入“写代码 → 编译 → 修 bug”的闭环。实测中,Agent 基本能按照这个流程走完,不会跑到无关方向。
3.2 Agent 的执行过程:它真的在“写代码”
指令下发后,我没有做任何干预,只开了日志记录,观察 Agent 的执行轨迹。它先浏览了一下工程目录结构,确认 entry/src/main/ets 下面有哪些目录,然后又看了一眼现有的入口文件内容,接着开始创建页面文件、修改路由配置。整个过程的节奏很像一个工程师在开工前先熟悉现有代码,只不过它的速度要快得多,几十秒内就完成了几轮文件操作。
Agent 生成的首页代码用的是 ArkUI 的声明式写法,结构比较清晰。我给一个小片段展示一下它实际写出来的东西:
typescript复制@Entry
@Component
struct TodoIndex {
@State todos: TodoItem[] = [];
@State inputText: string = '';
build() {
Column({ space: 12 }) {
Text('待办事项')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.margin({ top: 20 })
Row({ space: 8 }) {
TextInput({ placeholder: '输入待办内容', text: this.inputText })
.onChange((value: string) => {
this.inputText = value;
})
.layoutWeight(1)
Button('添加')
.onClick(() => {
this.addTodo();
})
}
.padding({ left: 16, right: 16 })
List({ space: 8 }) {
ForEach(this.todos, (item: TodoItem, index: number) => {
ListItem() {
Row() {
Text(item.content)
.textDecoration(item.done ? TextDecorationType.LineThrough : TextDecorationType.None)
.layoutWeight(1)
Button(item.done ? '取消' : '完成')
.onClick(() => {
this.toggleTodo(index);
})
Button('删除')
.onClick(() => {
this.removeTodo(index);
})
}
}
}, (item: TodoItem, index: number) => `${item.content}_${index}_${item.done}`)
}
.layoutWeight(1)
.padding({ left: 16, right: 16 })
}
.width('100%')
.height('100%')
}
// 对应的方法实现,Agent 也一并补齐了
}
说实话,这段代码在细节上跟手写的还有差距,比如列表更新的 key 处理不够优雅,按钮的样式也偏朴素。但作为第一版,它能编译、能交互、逻辑也没错,已经超出我的预期了。更重要的是,Agent 并没有只写这一版就交差——它执行完编译命令后果然报错了,报错内容是关于某个结构体的类型声明问题。然后它自己读了报错信息,定位到文件,修改了类型定义,再次编译,这次成功通过了。这个“编译失败 → 读日志 → 改代码 → 重新编译”的过程,我看下来是最接近人类开发者的地方。
3.3 编译验证与产物检查
构建成功的日志最后会出现 BUILD SUCCESSFUL 的字样,同时在工程的 entry/build/default/outputs/default 目录下生成一个 .hap 文件。这个文件就是鸿蒙应用的安装包。我第一次跑通的时候还特意验证了一下安装流程,用 hdc 命令把 HAP 装到本地模拟器上,启动应用,页面能正常渲染,点击按钮也能响应。
验证过程中有一点要提醒大家:HAP 生成成功只能证明代码能编译,不代表运行逻辑完全正确。比如我们这次生成的 TodoList,编译没问题,但运行时如果列表为空,ForEach 渲染空数组会不会有异常?输入框的 placeholder 会不会遮挡文字?这些都是需要人工或额外测试去确认的。所以我把“编译成功”定义为完成标准,但没有把它定义为“产品可用”,这个边界要拎清楚。
4. 踩坑记录与排查技巧
4.1 高频报错速查表
实测过程中,Agent 当然不是一帆风顺的。我整理了一个高频报错速查表,这些错误在 Agent 驱动 DevEco CLI 开发时几乎一定会遇到,提前知道能省很多时间。
| 报错类型 | 常见原因 | 处理方法 |
|---|---|---|
| ohpm 依赖相关报错 | 工程依赖未安装 | 先执行 ohpm install 再构建 |
| ArkTS 类型校验失败 | Agent 对 strict 类型语法不熟 | 让 Agent 阅读官方 Interface 类型定义,再修改声明 |
| module.json5 配置缺失 | 权限或能力声明不完整 | 检查是否需要添加 ohos.permission.xxx |
| API 版本不匹配 | 某 API 在当前 SDK 版本不存在 | 确认 targetSdkVersion,换成低版本兼容替代 |
| 签名相关错误 | 没有配置调试证书 | 在 DevEco Studio 里生成自动调试签名,或者配置本地 keystore |
这里想特别讲一下 ArkTS 类型校验的问题。Agent 写习惯了 TypeScript,很容易在鸿蒙里写出过于松散的类型用法。ArkTS 是基于 TS 的严格子集,很多 TS 特性它不支持,比如 any 类型在某些场景下被禁用、对象字面量必须用 interface 声明等。Agent 第一次生成代码经常踩这个坑,报错信息又长又绕,如果你没有让它先了解 ArkTS 的语法约束,它可能会反复用同样的思路改错方向。我的解法是在 Agent 的技能库里放一份 ArkTS 语法摘要,当构建报错里出现类型相关关键词时,主动触发一份“ArkTS 编码规范参考”技能,让它在修改代码前先读一遍规范,效果立竿见影。
4.2 权限、签名与真机调试
鸿蒙应用开发里,权限声明和签名配置这两个环节特别容易出幺蛾子,也是 Agent 自己很难独立搞定的地方。先说权限。如果你在代码里调用了定位、相机、网络之类的接口,光在代码里写逻辑是没用的,还得在 module.json5 文件里加对应权限声明。Agent 往往会忘记这一步,导致编译通过但运行时报错权限不足。这种情况只能让 Agent 去检查 module.json5 里的 requestPermissions 配置,或者干脆在你的人工验收清单里加一条“检查权限声明”。
签名的问题更麻烦。鸿蒙应用需要签名才能安装到真机,而调试签名默认是在 DevEco Studio 图形界面里自动生成的,Agent 没法点那个界面。我的做法是在交给 Agent 之前,就手工生成好调试签名,并确认 hvigor 配置里能读取到。这样后续所有构建都不会被签名问题卡住。如果你要打 release 包,那更复杂,需要配置发布证书和 Profile 文件,这个阶段基本必须人工介入,Agent 帮不上太多忙,我也建议不要把自动化链路延伸到发布签名这一步。
真机调试还有一个隐藏坑:hdc 连接真机后,首次连接需要手机端弹窗授权。这个弹窗是 GUI 的,Agent 没法自己点,如果你全程无人值守,调用 install 命令会一直卡在等待授权状态。解决办法很简单,在进入自动化流程之前,先手工连接一次手机、点掉授权弹窗,之后 USB 调试授权就会保持信任状态。做无人值守流程时,这个细节能避免很多无意义的超时。
4.3 让 Agent 自己修 bug 的闭环技巧
Agent 自己修 bug 能不能成,很大程度上取决于你给它的上下文是“完整性”还是“碎片化”。实测初期,我犯过的最大错误是让错误信息直接堆给 Agent,它一看整个 build 日志就懵了,开始东改西改。后来我发现,Compile Error 里最重要的是两个局部信息:报错文件名 + 具体的行号列号。把这两个信息提取出来,再附上该文件中出错代码段的上下文,Agent 的修复率会显著提升。
我设计了一个简单的“报错归因提示词”,每次构建失败后自动重组消息,发给 Agent 的格式大概是:
text复制构建失败。以下是最新的错误摘要,请只关注这些文件:
- 文件: entry/src/main/ets/pages/TodoIndex.ets
错误位置: 第 42 行,第 15 列
错误信息: 类型 'undefined' 不能赋值给类型 'string'
请先阅读对应文件的相关代码,定位问题,再给出修复方案并直接修改文件。
修复后重新运行构建命令,直到构建成功或你确认无法解决。
加了这一步之后,Agent 的行为明显从“乱枪打鸟”变成了“定向修复”。另外,一定要给 Agent 的自修复操作设上限,我在框架里设置了最多 6 轮编译尝试,超过之后自动停止并把日志打包给我。因为如果 Agent 前几轮都没修好,大概率已经陷入思路死循环,继续跑只会白白消耗 token。停止之后,我可以手动介入看问题,或者换一个更强的模型重新起一轮任务。
5. 实操心得与进阶方向
5.1 什么场景真正适合 Agent 写鸿蒙
实测跑了几轮之后,我对“AI Agent 写鸿蒙应用”这件事的适用边界有了比较清晰的判断。最适合的场景是三类:第一类是原型验证,需求模糊、想快速看一个界面效果,给 Agent 一个描述就能出雏形;第二类是批量生成模板页面,比如一个应用里有很多结构相似的列表页、表单页,让 Agent 按统一风格生成效率很高;第三类是配置调整和依赖管理,像改 module.json5、调整 API 版本这类工作,Agent 处理起来比人快得多。
不适合的场景也很明显。一是复杂性能优化,比如列表卡顿、内存泄漏这类问题,Agent 很难定位到具体瓶颈,需要依赖 Profiler 工具做深度分析,这个层面人的经验优势依然巨大;二是涉及核心商业逻辑的模块,我不建议直接把代码交给第三方 Agent 服务处理,存在信息泄露风险;三是需要深度定制 UI 动效的场景,Agent 生成的效果离设计稿差距还是比较大,手工调更靠谱。总结一句话:Agent 擅长“从 0 到 1 的快速生成”,不擅长“从 90 到 100 的精雕细琢”。
成本方面也要心里有数。实测一个中等的页面应用,Agent 从生成到编译通过,大概要消耗比较可观的 token 数量。如果用的是付费的大模型 API,算下来可能不比一个人工开发便宜多少。但它的核心价值不是“便宜”,而是“快”和“省人力”,能把重复劳动压缩到分钟级。所以判断要不要用 Agent,应该看这个任务的重复度以及你对交付时间的要求,而不是单纯看 token 费用。
5.2 代码审查与安全底线
我用 Agent 写代码的时候,有两条底线是不破的。第一条是代码审查,任何 Agent 产出都必须经过 diff 审查,不搞一键合并。具体做法是让 Agent 每轮修改都形成一个明确的增量,然后把变更文件通过 git diff 展示出来,我确认没有异常再继续。Agent 在生成代码时偶尔会“灵光一闪”写一些你没要求的东西,比如偷偷加一个网络请求、创建一个外部链接,这种超预期行为在无人审查的场景下风险极大。所以哪怕流程再自动化,人工 review 这个环节一定要保留。
第二条是依赖安全和敏感信息管理。Agent 可能因为训练数据或上下文误导,建议你安装某个三方库,或者更危险的是直接把一个假想的包名拼到 oh-package.json5 里。遇到这种情况,我一般不采纳,让 Agent 坚持用现有依赖或者标准库完成。此外,我要强调一点:绝对不要让 Agent 生成任何包含密钥、token、密码的代码。在指令模板里就要写死“禁止硬编码任何认证信息”,并且事后用正则扫一遍代码。安全这根弦,任何时候都不能松。
5.3 后续还能怎么玩
这次实测跑通之后,我又在思考几个扩展方向,这里一并分享。一个方向是把知识库接进 Agent。鸿蒙官方文档更新速度快、内容庞杂,Agent 内置的训练知识未必是最新的,但如果我能在本地准备一份 ArkUI 组件文档切片,Agent 在编码前先检索相关文档再动手,生成质量会进一步提升。这个思路跟“知识库 + Agent”的组合很像,本质上是给 Agent 一个可检索的外部记忆库,弥补模型参数里的知识滞后问题。
另一个方向是从单 Agent 向多 Agent 协作演进。这次实测是让一个 Agent 从头干到尾,它既要理解需求、又要写代码、又要调试,压力比较大。更合理的设计是拆成三个角色:需求 Agent 负责把模糊想法拆成规格;编码 Agent 专注写代码和改构建报错;测试 Agent 负责跑 lint 和基础用例。三个 Agent 之间通过任务队列传递信息,每个角色都只做自己擅长的事。这条路我已经开始在搭了,后续有结论再单独写一篇。
还有一个小方向其实也很实用,就是把这次沉淀下来的 DevEco CLI 技能包整理成模板。以后每次开新项目,我只需要让 Agent 加载这套技能配置,它就知道鸿蒙工程的构建命令、文件组织方式和常见报错怎么处理,不用每次重新调教。做 AI Agent 开发时间久了你会发现,真正值钱的不是某一次生成的代码,而是你沉淀下来的这套“技能包”和“流程模板”,它们才是可以复用的资产。
最后说一点个人的真实感受。很多人担心 Agent 会取代开发者,我实测完反而觉得没那么悲观。Agent 确实能写代码、能修 bug,但遇到需要产品直觉、架构权衡、安全判断的场景,它依然差得远。归根结底,它更像一个执行力极强但需要明确指令的协作者。你把路标设置得越清晰,它能跑得越远;你要是把摊子一甩就撒手不管,它也能在沟里挖一天。所以与其担心被替代,不如先把它变成趁手的工具,该定规则定规则,该设边界设边界,然后让它去干那些重复、繁琐、你早就不想碰的活。
