引言:一次让我"开窍"的编码经历
上周我在写一个 HarmonyOS 应用,产品经理扔过来一个需求:“给商品列表页加个下拉刷新呗,很简单的。”
我想都没想,打开 DevEco Code,直接在 ProductList.ets 里开始敲。@ohos.pulltorefresh 嘛,我熟——导入组件,包一层 PullToRefresh,绑个回调,搞定。
结果呢?编译报错,类型不匹配;调试半小时,发现忘了注册数据源;改完又发现和现有的上拉加载逻辑冲突了……折腾了一下午,一个"简单"需求变成了噩梦。
这时候同事拍了拍我:“你试试先让 AI 出个方案再写?DevEco Code 那个 Plan+Build 模式。”
我将信将疑地试了一下——结果这次需求从接到到交付,不到 40 分钟,一次编译通过。
这篇文章,我就用这个真实经历,带你看看 Plan+Build 模式到底香在哪。
#mermaid-svg-xeBCoSeEbOMwIV9C{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-xeBCoSeEbOMwIV9C .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-xeBCoSeEbOMwIV9C .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-xeBCoSeEbOMwIV9C .error-icon{fill:#552222;}#mermaid-svg-xeBCoSeEbOMwIV9C .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-xeBCoSeEbOMwIV9C .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-xeBCoSeEbOMwIV9C .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-xeBCoSeEbOMwIV9C .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-xeBCoSeEbOMwIV9C .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-xeBCoSeEbOMwIV9C .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-xeBCoSeEbOMwIV9C .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-xeBCoSeEbOMwIV9C .marker{fill:#333333;stroke:#333333;}#mermaid-svg-xeBCoSeEbOMwIV9C .marker.cross{stroke:#333333;}#mermaid-svg-xeBCoSeEbOMwIV9C svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-xeBCoSeEbOMwIV9C p{margin:0;}#mermaid-svg-xeBCoSeEbOMwIV9C .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-xeBCoSeEbOMwIV9C .cluster-label text{fill:#333;}#mermaid-svg-xeBCoSeEbOMwIV9C .cluster-label span{color:#333;}#mermaid-svg-xeBCoSeEbOMwIV9C .cluster-label span p{background-color:transparent;}#mermaid-svg-xeBCoSeEbOMwIV9C .label text,#mermaid-svg-xeBCoSeEbOMwIV9C span{fill:#333;color:#333;}#mermaid-svg-xeBCoSeEbOMwIV9C .node rect,#mermaid-svg-xeBCoSeEbOMwIV9C .node circle,#mermaid-svg-xeBCoSeEbOMwIV9C .node ellipse,#mermaid-svg-xeBCoSeEbOMwIV9C .node polygon,#mermaid-svg-xeBCoSeEbOMwIV9C .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-xeBCoSeEbOMwIV9C .rough-node .label text,#mermaid-svg-xeBCoSeEbOMwIV9C .node .label text,#mermaid-svg-xeBCoSeEbOMwIV9C .image-shape .label,#mermaid-svg-xeBCoSeEbOMwIV9C .icon-shape .label{text-anchor:middle;}#mermaid-svg-xeBCoSeEbOMwIV9C .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-xeBCoSeEbOMwIV9C .rough-node .label,#mermaid-svg-xeBCoSeEbOMwIV9C .node .label,#mermaid-svg-xeBCoSeEbOMwIV9C .image-shape .label,#mermaid-svg-xeBCoSeEbOMwIV9C .icon-shape .label{text-align:center;}#mermaid-svg-xeBCoSeEbOMwIV9C .node.clickable{cursor:pointer;}#mermaid-svg-xeBCoSeEbOMwIV9C .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-xeBCoSeEbOMwIV9C .arrowheadPath{fill:#333333;}#mermaid-svg-xeBCoSeEbOMwIV9C .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-xeBCoSeEbOMwIV9C .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-xeBCoSeEbOMwIV9C .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xeBCoSeEbOMwIV9C .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-xeBCoSeEbOMwIV9C .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xeBCoSeEbOMwIV9C .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-xeBCoSeEbOMwIV9C .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-xeBCoSeEbOMwIV9C .cluster text{fill:#333;}#mermaid-svg-xeBCoSeEbOMwIV9C .cluster span{color:#333;}#mermaid-svg-xeBCoSeEbOMwIV9C div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-xeBCoSeEbOMwIV9C .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-xeBCoSeEbOMwIV9C rect.text{fill:none;stroke-width:0;}#mermaid-svg-xeBCoSeEbOMwIV9C .icon-shape,#mermaid-svg-xeBCoSeEbOMwIV9C .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xeBCoSeEbOMwIV9C .icon-shape p,#mermaid-svg-xeBCoSeEbOMwIV9C .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-xeBCoSeEbOMwIV9C .icon-shape .label rect,#mermaid-svg-xeBCoSeEbOMwIV9C .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xeBCoSeEbOMwIV9C .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-xeBCoSeEbOMwIV9C .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-xeBCoSeEbOMwIV9C :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
🧑💻 接到需求
❌ 直接编码
🐛 编译报错
🔧 调试排查
💥 发现新 Bug
😫 一下午过去了
✅ Plan+Build 模式
📋 AI 出方案
👀 审阅确认
🚀 一键生成
🎉 40 分钟交付
上图就是我那天经历的两种工作模式对比。左边的路径你一定也走过——在没搞清全局的情况下就撸起袖子写代码,最后被各种坑绊得鼻青脸肿。右边的路径,就是我今天要跟你聊的主角:Plan+Build 模式。
先来看一组数据感受一下差异:
| 平均返工次数 | 2-5 次 | 0-1 次 |
| 跨文件改动遗漏率 | ~35% | ~5% |
| 首次编译通过率 | ~40% | ~85% |
| 开发者对代码理解度 | 事后推导 | 事前掌握 |
这些数字不是编的——是我和团队用了一段时间后总结的真实感受。接下来我会跟你拆开揉碎了聊:Plan 阶段到底发生了什么、AI 怎么分析你的代码、方案长什么样、怎么审、怎么改、以及什么时候该用什么时候不该用。
一、什么叫"先审方案,再写代码"?
1.1 一个形象的比喻:盖房子和搭积木
传统的 AI 编码辅助,就像你跟工头说"我要一栋三层小楼",他二话不说直接开干——地基打在软土上、钢筋型号不对、窗户开错了方向,等房子快盖完了你才发现问题。
Plan+Build 模式不一样。你先说需求,AI 工头不会立刻动工,而是先给你一张施工图纸:
- 地基该怎么打?(涉及到哪些模块、哪些文件需要改动)
- 用什么材料?(用哪个 API、需要引入哪些依赖)
- 施工步骤是什么?(先改什么、再改什么、每一步做什么)
- 有哪些风险?(会和现有哪个功能冲突、需要注意什么)
你拿着图纸看完、改完、点头说"行,就这么干",工头再按图纸施工。
这就是 Plan+Build:Plan(规划)+ Build(构建),把"想"和"做"拆开。
#mermaid-svg-AGSXQtjAlcaO7AuB{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-AGSXQtjAlcaO7AuB .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-AGSXQtjAlcaO7AuB .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-AGSXQtjAlcaO7AuB .error-icon{fill:#552222;}#mermaid-svg-AGSXQtjAlcaO7AuB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-AGSXQtjAlcaO7AuB .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-AGSXQtjAlcaO7AuB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-AGSXQtjAlcaO7AuB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-AGSXQtjAlcaO7AuB .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-AGSXQtjAlcaO7AuB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-AGSXQtjAlcaO7AuB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-AGSXQtjAlcaO7AuB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-AGSXQtjAlcaO7AuB .marker.cross{stroke:#333333;}#mermaid-svg-AGSXQtjAlcaO7AuB svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-AGSXQtjAlcaO7AuB p{margin:0;}#mermaid-svg-AGSXQtjAlcaO7AuB .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-AGSXQtjAlcaO7AuB .cluster-label text{fill:#333;}#mermaid-svg-AGSXQtjAlcaO7AuB .cluster-label span{color:#333;}#mermaid-svg-AGSXQtjAlcaO7AuB .cluster-label span p{background-color:transparent;}#mermaid-svg-AGSXQtjAlcaO7AuB .label text,#mermaid-svg-AGSXQtjAlcaO7AuB span{fill:#333;color:#333;}#mermaid-svg-AGSXQtjAlcaO7AuB .node rect,#mermaid-svg-AGSXQtjAlcaO7AuB .node circle,#mermaid-svg-AGSXQtjAlcaO7AuB .node ellipse,#mermaid-svg-AGSXQtjAlcaO7AuB .node polygon,#mermaid-svg-AGSXQtjAlcaO7AuB .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-AGSXQtjAlcaO7AuB .rough-node .label text,#mermaid-svg-AGSXQtjAlcaO7AuB .node .label text,#mermaid-svg-AGSXQtjAlcaO7AuB .image-shape .label,#mermaid-svg-AGSXQtjAlcaO7AuB .icon-shape .label{text-anchor:middle;}#mermaid-svg-AGSXQtjAlcaO7AuB .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-AGSXQtjAlcaO7AuB .rough-node .label,#mermaid-svg-AGSXQtjAlcaO7AuB .node .label,#mermaid-svg-AGSXQtjAlcaO7AuB .image-shape .label,#mermaid-svg-AGSXQtjAlcaO7AuB .icon-shape .label{text-align:center;}#mermaid-svg-AGSXQtjAlcaO7AuB .node.clickable{cursor:pointer;}#mermaid-svg-AGSXQtjAlcaO7AuB .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-AGSXQtjAlcaO7AuB .arrowheadPath{fill:#333333;}#mermaid-svg-AGSXQtjAlcaO7AuB .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-AGSXQtjAlcaO7AuB .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-AGSXQtjAlcaO7AuB .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-AGSXQtjAlcaO7AuB .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-AGSXQtjAlcaO7AuB .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-AGSXQtjAlcaO7AuB .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-AGSXQtjAlcaO7AuB .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-AGSXQtjAlcaO7AuB .cluster text{fill:#333;}#mermaid-svg-AGSXQtjAlcaO7AuB .cluster span{color:#333;}#mermaid-svg-AGSXQtjAlcaO7AuB div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-AGSXQtjAlcaO7AuB .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-AGSXQtjAlcaO7AuB rect.text{fill:none;stroke-width:0;}#mermaid-svg-AGSXQtjAlcaO7AuB .icon-shape,#mermaid-svg-AGSXQtjAlcaO7AuB .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-AGSXQtjAlcaO7AuB .icon-shape p,#mermaid-svg-AGSXQtjAlcaO7AuB .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-AGSXQtjAlcaO7AuB .icon-shape .label rect,#mermaid-svg-AGSXQtjAlcaO7AuB .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-AGSXQtjAlcaO7AuB .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-AGSXQtjAlcaO7AuB .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-AGSXQtjAlcaO7AuB :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
📋 Plan 阶段——AI 出方案
✏️ 调整指令
✅ 确认方案
📝 手动微调方案
🔨 Build 阶段——AI 执行
📄 按方案生成代码
🔧 修改指定文件
✅ 一次编译通过
👤 开发者输入任务指令
🔍 分析项目结构与上下文
🧠 生成详细实现方案
⚠️ 输出影响分析与风险提示
👤 开发者审阅决策
1.2 跟你之前用的 AI 编程助手差在哪?
说实话,我一开始也觉得"直接让 AI 出代码多快啊"。
| 我的操作 | 输入指令 → 得到代码 | 输入指令 → 得到方案 → 审阅 → 确认 → 得到代码 |
| AI 怎么干 | 黑盒直接给你结果 | 先把思路摊开给你看 |
| 遇到问题的体验 | “这啥玩意?怎么跑不起来?” | “哦,这步他会改这个文件,那我知道了” |
| 返工率 | 看运气,有时候一行不改,有时候全重写 | 方案阶段就能纠偏,生成的代码基本一次过 |
| 适用任务 | 简单补全、单行修改 | 跨文件功能、架构调整、集成第三方库 |
| 认知模式 | “事后理解”——看完代码倒推逻辑 | “事前理解”——先看方案再盯着代码生成 |
简单说:Direct 模式是 AI 替你写代码,Plan 模式是 AI 跟你一起盘逻辑。
本质差异:从"黑盒执行"到"透明协作"
传统 Direct 模式的工作流可以这样描述:你给 AI 一段话,它给你一堆代码,中间的推理过程对你完全不可见。你拿到代码后需要:
而 Plan+Build 把这个过程完全翻转了:
📂 项目文件系统
🤖 DevEco Code AI
📂 项目文件系统
🤖 DevEco Code AI
#mermaid-svg-xu7nL8lU0EI9FQ7b{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-xu7nL8lU0EI9FQ7b .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-xu7nL8lU0EI9FQ7b .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-xu7nL8lU0EI9FQ7b .error-icon{fill:#552222;}#mermaid-svg-xu7nL8lU0EI9FQ7b .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-xu7nL8lU0EI9FQ7b .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-xu7nL8lU0EI9FQ7b .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-xu7nL8lU0EI9FQ7b .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-xu7nL8lU0EI9FQ7b .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-xu7nL8lU0EI9FQ7b .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-xu7nL8lU0EI9FQ7b .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-xu7nL8lU0EI9FQ7b .marker{fill:#333333;stroke:#333333;}#mermaid-svg-xu7nL8lU0EI9FQ7b .marker.cross{stroke:#333333;}#mermaid-svg-xu7nL8lU0EI9FQ7b svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-xu7nL8lU0EI9FQ7b p{margin:0;}#mermaid-svg-xu7nL8lU0EI9FQ7b .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-xu7nL8lU0EI9FQ7b text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-xu7nL8lU0EI9FQ7b .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-xu7nL8lU0EI9FQ7b .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-xu7nL8lU0EI9FQ7b .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-xu7nL8lU0EI9FQ7b .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-xu7nL8lU0EI9FQ7b #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-xu7nL8lU0EI9FQ7b .sequenceNumber{fill:white;}#mermaid-svg-xu7nL8lU0EI9FQ7b #sequencenumber{fill:#333;}#mermaid-svg-xu7nL8lU0EI9FQ7b #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-xu7nL8lU0EI9FQ7b .messageText{fill:#333;stroke:none;}#mermaid-svg-xu7nL8lU0EI9FQ7b .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-xu7nL8lU0EI9FQ7b .labelText,#mermaid-svg-xu7nL8lU0EI9FQ7b .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-xu7nL8lU0EI9FQ7b .loopText,#mermaid-svg-xu7nL8lU0EI9FQ7b .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-xu7nL8lU0EI9FQ7b .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-xu7nL8lU0EI9FQ7b .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-xu7nL8lU0EI9FQ7b .noteText,#mermaid-svg-xu7nL8lU0EI9FQ7b .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-xu7nL8lU0EI9FQ7b .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-xu7nL8lU0EI9FQ7b .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-xu7nL8lU0EI9FQ7b .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-xu7nL8lU0EI9FQ7b .actorPopupMenu{position:absolute;}#mermaid-svg-xu7nL8lU0EI9FQ7b .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-xu7nL8lU0EI9FQ7b .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-xu7nL8lU0EI9FQ7b .actor-man circle,#mermaid-svg-xu7nL8lU0EI9FQ7b line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-xu7nL8lU0EI9FQ7b :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
Direct 模式——黑盒执行
Plan+Build 模式——透明协作
👤 开发者
"给列表加下拉刷新"
读取项目文件
直接返回代码块
😵 通读代码、理清逻辑
🐛 编译调试
🔧 发现遗漏,手动补改
"给列表加下拉刷新"
深度分析项目结构
📋 输出详细方案 + 影响分析
👀 审阅方案,心里有数
✏️ "用自定义动画组件"
📋 更新方案
✅ 确认执行
精确修改目标文件
🎉 代码一次通过
👤 开发者
二、实战:我那天到底怎么用它搞定"下拉刷新"
2.1 我的开发场景
- 项目:一个 HarmonyOS 的电商 App
- 页面:ProductList.ets,已有一个产品列表,使用 List 组件
- 需求:给这个列表加上下拉刷新,刷新时从服务器重新拉数据
- 现有代码结构如下:
// ProductList.ets —— 改造前的原始代码
@Component
struct ProductList {
@State products: ProductModel[] = [];
private viewModel: ProductViewModel = new ProductViewModel();
aboutToAppear() {
this.loadProducts();
}
private async loadProducts() {
this.products = await this.viewModel.fetchProducts();
}
build() {
Column() {
List() {
ForEach(this.products, (item: ProductModel) => {
ListItem() {
ProductCard({ product: item })
}
})
}
.width('100%')
.height('100%')
}
}
}
我需要给这个 List 加下拉刷新能力,同时保证现有的上拉加载分页逻辑不被破坏。
2.2 第一回合:AI 给我出了个方案
我在 DevEco Code 里打开 ProductList.ets,然后输入任务:“为 ProductList 页面的 List 组件添加下拉刷新功能”。
不到 10 秒,AI 没有给我代码,而是给了我一份这样的方案报告:
📋 实施方案概要
涉及文件:
- ProductList.ets(主要修改)
- ProductViewModel.ets(确认 refreshProducts() 方法是否存在)
- 可能需要调整 DataModel.ets(刷新回调中使用)
实现步骤:
影响分析:
- UI 结构会被外层包裹一个容器,注意现有的 flex 布局属性是否需要调整
- refreshProductData() 方法需确认已在 DataModel.ets 中实现
- 如果 ViewModel 持有列表状态,刷新后需同步更新
- 现有的上拉加载分页逻辑使用了 onReachEnd 回调,PullToRefresh 不会影响该回调,但需确认分页状态在刷新后重置
代码预览(关键片段):
PullToRefresh({
data: this.dataSource,
controller: this.controller
}) {
List() { /* 原有列表内容 */ }
}
我一看到这个方案,脑子里立刻"叮"了一下——第 3 条影响分析提醒了我:我的 ViewModel 确实维护了一份状态缓存,刷新后需要同步,但我之前自己直接写的时候完全没想到这一点。
而且它还特意检查了上拉加载的兼容性——说实话,我自己写的时候根本不会想这么细。
2.3 拆解一下:AI 在 Plan 阶段到底"想"了什么?
上面那份方案看起来只是一段文字,但背后 AI 其实做了好几层分析。我来给你拆开看看:
#mermaid-svg-A7ByIO0ZVatQE3Fz{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-A7ByIO0ZVatQE3Fz .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-A7ByIO0ZVatQE3Fz .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-A7ByIO0ZVatQE3Fz .error-icon{fill:#552222;}#mermaid-svg-A7ByIO0ZVatQE3Fz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-A7ByIO0ZVatQE3Fz .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-A7ByIO0ZVatQE3Fz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-A7ByIO0ZVatQE3Fz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-A7ByIO0ZVatQE3Fz .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-A7ByIO0ZVatQE3Fz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-A7ByIO0ZVatQE3Fz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-A7ByIO0ZVatQE3Fz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-A7ByIO0ZVatQE3Fz .marker.cross{stroke:#333333;}#mermaid-svg-A7ByIO0ZVatQE3Fz svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-A7ByIO0ZVatQE3Fz p{margin:0;}#mermaid-svg-A7ByIO0ZVatQE3Fz .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-A7ByIO0ZVatQE3Fz .cluster-label text{fill:#333;}#mermaid-svg-A7ByIO0ZVatQE3Fz .cluster-label span{color:#333;}#mermaid-svg-A7ByIO0ZVatQE3Fz .cluster-label span p{background-color:transparent;}#mermaid-svg-A7ByIO0ZVatQE3Fz .label text,#mermaid-svg-A7ByIO0ZVatQE3Fz span{fill:#333;color:#333;}#mermaid-svg-A7ByIO0ZVatQE3Fz .node rect,#mermaid-svg-A7ByIO0ZVatQE3Fz .node circle,#mermaid-svg-A7ByIO0ZVatQE3Fz .node ellipse,#mermaid-svg-A7ByIO0ZVatQE3Fz .node polygon,#mermaid-svg-A7ByIO0ZVatQE3Fz .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-A7ByIO0ZVatQE3Fz .rough-node .label text,#mermaid-svg-A7ByIO0ZVatQE3Fz .node .label text,#mermaid-svg-A7ByIO0ZVatQE3Fz .image-shape .label,#mermaid-svg-A7ByIO0ZVatQE3Fz .icon-shape .label{text-anchor:middle;}#mermaid-svg-A7ByIO0ZVatQE3Fz .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-A7ByIO0ZVatQE3Fz .rough-node .label,#mermaid-svg-A7ByIO0ZVatQE3Fz .node .label,#mermaid-svg-A7ByIO0ZVatQE3Fz .image-shape .label,#mermaid-svg-A7ByIO0ZVatQE3Fz .icon-shape .label{text-align:center;}#mermaid-svg-A7ByIO0ZVatQE3Fz .node.clickable{cursor:pointer;}#mermaid-svg-A7ByIO0ZVatQE3Fz .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-A7ByIO0ZVatQE3Fz .arrowheadPath{fill:#333333;}#mermaid-svg-A7ByIO0ZVatQE3Fz .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-A7ByIO0ZVatQE3Fz .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-A7ByIO0ZVatQE3Fz .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-A7ByIO0ZVatQE3Fz .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-A7ByIO0ZVatQE3Fz .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-A7ByIO0ZVatQE3Fz .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-A7ByIO0ZVatQE3Fz .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-A7ByIO0ZVatQE3Fz .cluster text{fill:#333;}#mermaid-svg-A7ByIO0ZVatQE3Fz .cluster span{color:#333;}#mermaid-svg-A7ByIO0ZVatQE3Fz div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-A7ByIO0ZVatQE3Fz .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-A7ByIO0ZVatQE3Fz rect.text{fill:none;stroke-width:0;}#mermaid-svg-A7ByIO0ZVatQE3Fz .icon-shape,#mermaid-svg-A7ByIO0ZVatQE3Fz .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-A7ByIO0ZVatQE3Fz .icon-shape p,#mermaid-svg-A7ByIO0ZVatQE3Fz .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-A7ByIO0ZVatQE3Fz .icon-shape .label rect,#mermaid-svg-A7ByIO0ZVatQE3Fz .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-A7ByIO0ZVatQE3Fz .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-A7ByIO0ZVatQE3Fz .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-A7ByIO0ZVatQE3Fz :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
第四层:方案输出
生成结构化方案文档(涉及文件 + 步骤 + 风险 + 预览代码)
用自然语言描述,让开发者一眼看懂
第三层:方案推演
确定技术方案:使用 @ohos.pulltorefresh 官方的 PullToRefresh 组件
推导修改步骤:从导入到包裹到绑定回调,按依赖顺序排列
识别潜在风险:布局嵌套、状态同步、与上拉加载的兼容性
第二层:上下文采集
读取 ProductList.ets 当前完整代码
扫描 import 依赖列表
分析现有组件层级与布局结构
检查 ViewModel 中数据加载相关方法
第一层:需求理解
解析用户指令:“为 ProductList 页面的 List 组件添加下拉刷新”
提取关键意图:下拉刷新(UI 能力)+ List 组件(目标)+ 页面(范围)
这就是 Plan 模式的核心价值:它不是简单地"根据注释生成代码",而是像一位高级工程师拿到需求后先做的技术调研与方案设计。
2.4 第二回合:我审方案,做了一点调整
方案整体没问题,不过我有个额外需求:希望下拉时有个自定义的 loading 动画。
我在方案文档上直接加了一条注释:“刷新时使用项目已有的自定义动画组件 LoadingAnim,不要用系统默认加载样式”。
然后点击"确认并构建"。
这里重点说一下:Plan 阶段你可以随时介入调整。不是 AI 出完方案你就只能"接受"或"拒绝"——你可以:
- 直接修改方案文本中的任意部分
- 追加补充指令,让 AI 重新规划
- 删除某个步骤,告诉 AI “这步不需要”
这是 Plan+Build 跟"一键生成代码"最本质的区别——决策权始终在你手里。
2.5 第三回合:AI 按方案执行,一步到位
确认后,AI 直接往 ProductList.ets 里插入了完整代码:
// ProductList.ets —— Plan+Build 改造后的代码
import { PullToRefresh } from '@ohos.pulltorefresh';
import { LoadingAnim } from '../components/LoadingAnim';
@Component
struct ProductList {
@State products: ProductModel[] = [];
private dataSource: BasicDataSource<ProductModel> = new BasicDataSource();
private controller: PullToRefreshController = new PullToRefreshController();
private viewModel: ProductViewModel = new ProductViewModel();
aboutToAppear() {
this.loadProducts();
}
private async loadProducts() {
this.products = await this.viewModel.fetchProducts();
this.dataSource.updateData(this.products);
}
private async refreshProducts() {
// 刷新时重置分页状态,避免与上拉加载冲突
this.viewModel.resetPagination();
this.products = await this.viewModel.refreshProducts();
this.dataSource.updateData(this.products);
this.controller.finishRefresh();
}
build() {
Column() {
PullToRefresh({
data: this.dataSource,
controller: this.controller,
customLoad: () => {
LoadingAnim() // 使用自定义动画
}
}) {
List() {
LazyForEach(this.dataSource, (item: ProductModel) => {
ListItem() {
ProductCard({ product: item })
}
}, (item: ProductModel) => item.id.toString())
}
.width('100%')
.height('100%')
.onReachEnd(() => {
// 上拉加载——Plan 阶段已确认不受影响
this.viewModel.loadNextPage();
})
}
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
}
}
编译,运行——一次过。改动清晰、逻辑完整、还避开了我之前踩的那个 ViewModel 缓存同步的坑。
从接到需求到交付,40 分钟不到。没有返工、没有调试地狱、也没有"这代码什么意思我怎么看不懂"。
对比一下:如果我直接让 AI 生成,可能会拿到什么?
为了让你直观感受差异,我特意用 Direct 模式对同一个需求跑了一次,这是它生成的:
// Direct 模式生成的代码——看似能用,实则藏雷
import { pulltorefresh } from '@ohos.ui';
@Component
struct ProductList {
@State products: ProductModel[] = [];
aboutToAppear() {
this.products = []; // 😱 直接清空,没调数据加载方法
}
build() {
Refresh({ // ❌ 组件名都错了
refreshing: false,
onRefresh: () => {
// 🚨 空回调,什么都没做
}
}) {
List() {
ForEach(this.products, (item: ProductModel) => { // ❌ 还是 ForEach,没用 LazyForEach
ListItem() {
ProductCard({ product: item })
}
})
}
}
}
}
看到了吗?Direct 模式生成的代码有 5 个问题:
这就是为什么 Plan 模式不是"多此一举"——方案阶段就让这些问题暴露了,不用等到编译甚至上线才发现。
2.6 换个更复杂的例子:当你需要动好几个文件的时候
下拉刷新虽然是个好例子,但它主要只改了 ProductList.ets 一个文件。你可能觉得:就一个文件,Plan 不 Plan 差别不大吧?
好,那我再给你看一个真实场景。后来产品又提了个需求:“给商品列表加上搜索功能,支持关键词搜索、分类筛选、价格排序”。
这次改动涉及:
涉及文件数:5 个
├── ProductList.ets —— UI 层:添加搜索栏、筛选栏、排序按钮
├── ProductViewModel.ets —— 逻辑层:新增搜索、筛选、排序方法
├── ProductApi.ets —— 网络层:新增查询接口
├── ProductFilterModel.ets —— 数据层:新增筛选条件模型
└── Constants.ets —— 常量:新增排序枚举、分类枚举
我在 Plan 模式下输入了需求描述,AI 输出的方案长这样(节选核心部分):
📋 搜索筛选功能实施方案
涉及文件及改动范围:
| ProductList.ets | 修改 | 顶部新增 SearchBar + FilterBar 组件;build() 逻辑重构 |
| ProductViewModel.ets | 修改 | 新增 searchProducts(keyword)、filterByCategory(id)、sortBy(enum) 三个方法 |
| ProductApi.ets | 新增接口 | 新增 GET /api/products/search?q=&category=&sort= 查询接口 |
| ProductFilterModel.ets | 新建文件 | 定义 FilterParams 接口与 SortType 枚举 |
| Constants.ets | 追加枚举 | 追加 ProductCategory 和 SortDirection 枚举 |
实现步骤:
影响分析:
- ProductList.ets 的 build() 方法结构会发生较大变化,原有的 PullToRefresh + List 结构保持不变,仅在上方新增搜索区域
- ViewModel 中的 fetchProducts() 方法需要重构以支持带参数查询
- 筛选条件变更时需要触发列表重新加载,建议使用 @Watch 装饰器监听筛选状态变化
- 搜索框输入需要使用防抖处理,避免频繁触发 API 请求
有了这份方案,我心里就有了一张清晰的"施工地图"。我知道:
- 哪 5 个文件需要动
- 每个文件具体要改什么
- 改动的先后顺序是什么
- 有哪些潜在风险需要注意
这个场景如果用 Direct 模式——你想想,你直接丢给 AI 一段需求描述,它可能会给你生成一段包含了全部改动的超大代码块,但你根本不知道它到底改了哪些文件、每个改了哪里、哪些是新增的哪些是修改的。出了问题你只能从头排查。
三、什么时候该用 Plan?什么时候直接撸?
3.1 这两种场景,Plan 模式太值了
| 涉及多个文件的改动 | 开工前看清改动面,避免漏改 |
| 使用不熟悉的 API / 第三方库 | 先让 AI 给你一个"学习方案",顺便就学到了用法 |
| 重构一个模块 | 评估影响范围,避免拆了一座桥发现还没建新的 |
| 接手别人的遗留代码 | AI 帮你梳理现有逻辑,在方案阶段就能发现坑 |
| 复杂业务逻辑 | 方案帮你理清输入→处理→输出的数据流 |
决策流程:我现在的"本能反应"
#mermaid-svg-CzuHYCuAmvw6if92{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-CzuHYCuAmvw6if92 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-CzuHYCuAmvw6if92 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-CzuHYCuAmvw6if92 .error-icon{fill:#552222;}#mermaid-svg-CzuHYCuAmvw6if92 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-CzuHYCuAmvw6if92 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-CzuHYCuAmvw6if92 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CzuHYCuAmvw6if92 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CzuHYCuAmvw6if92 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-CzuHYCuAmvw6if92 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CzuHYCuAmvw6if92 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CzuHYCuAmvw6if92 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-CzuHYCuAmvw6if92 .marker.cross{stroke:#333333;}#mermaid-svg-CzuHYCuAmvw6if92 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-CzuHYCuAmvw6if92 p{margin:0;}#mermaid-svg-CzuHYCuAmvw6if92 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-CzuHYCuAmvw6if92 .cluster-label text{fill:#333;}#mermaid-svg-CzuHYCuAmvw6if92 .cluster-label span{color:#333;}#mermaid-svg-CzuHYCuAmvw6if92 .cluster-label span p{background-color:transparent;}#mermaid-svg-CzuHYCuAmvw6if92 .label text,#mermaid-svg-CzuHYCuAmvw6if92 span{fill:#333;color:#333;}#mermaid-svg-CzuHYCuAmvw6if92 .node rect,#mermaid-svg-CzuHYCuAmvw6if92 .node circle,#mermaid-svg-CzuHYCuAmvw6if92 .node ellipse,#mermaid-svg-CzuHYCuAmvw6if92 .node polygon,#mermaid-svg-CzuHYCuAmvw6if92 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-CzuHYCuAmvw6if92 .rough-node .label text,#mermaid-svg-CzuHYCuAmvw6if92 .node .label text,#mermaid-svg-CzuHYCuAmvw6if92 .image-shape .label,#mermaid-svg-CzuHYCuAmvw6if92 .icon-shape .label{text-anchor:middle;}#mermaid-svg-CzuHYCuAmvw6if92 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-CzuHYCuAmvw6if92 .rough-node .label,#mermaid-svg-CzuHYCuAmvw6if92 .node .label,#mermaid-svg-CzuHYCuAmvw6if92 .image-shape .label,#mermaid-svg-CzuHYCuAmvw6if92 .icon-shape .label{text-align:center;}#mermaid-svg-CzuHYCuAmvw6if92 .node.clickable{cursor:pointer;}#mermaid-svg-CzuHYCuAmvw6if92 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-CzuHYCuAmvw6if92 .arrowheadPath{fill:#333333;}#mermaid-svg-CzuHYCuAmvw6if92 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-CzuHYCuAmvw6if92 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-CzuHYCuAmvw6if92 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CzuHYCuAmvw6if92 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-CzuHYCuAmvw6if92 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CzuHYCuAmvw6if92 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-CzuHYCuAmvw6if92 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-CzuHYCuAmvw6if92 .cluster text{fill:#333;}#mermaid-svg-CzuHYCuAmvw6if92 .cluster span{color:#333;}#mermaid-svg-CzuHYCuAmvw6if92 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-CzuHYCuAmvw6if92 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-CzuHYCuAmvw6if92 rect.text{fill:none;stroke-width:0;}#mermaid-svg-CzuHYCuAmvw6if92 .icon-shape,#mermaid-svg-CzuHYCuAmvw6if92 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CzuHYCuAmvw6if92 .icon-shape p,#mermaid-svg-CzuHYCuAmvw6if92 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-CzuHYCuAmvw6if92 .icon-shape .label rect,#mermaid-svg-CzuHYCuAmvw6if92 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CzuHYCuAmvw6if92 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-CzuHYCuAmvw6if92 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-CzuHYCuAmvw6if92 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
1 个文件简单改动
2 个文件及以上
很熟,一步到位
不太熟 / 不确定
不知道涉及几个文件
接到新任务
这个任务涉及几个文件?
我对这块熟悉吗?
📋 用 Plan+Build
⚡ 直接 Build
✅ 快速搞定
👀 审阅方案
🔨 确认构建
✅ 一次通过
3.2 这些时候,直接 Build 就行
- 修一个拼写错误或变量名
- 加一行日志
- 改一个简单的 if 条件
- 你已经非常确定要怎么写,只想让 AI 帮你打字
- 给函数加一行注释
- 格式化一段代码
我现在的习惯:简单活儿直接干,涉及新功能、跨文件、不确定怎么实现的,一律先 Plan。
3.3 多人协作场景下的额外价值
Plan 模式还有一个很多人没意识到的价值:方案本身就是一份天然的文档。
在团队协作中,Plan 阶段生成的方案可以直接粘贴到 PR 描述里、分享到群里让同事提前 review,甚至存档作为项目知识库的一部分。
#mermaid-svg-xYCoTiUlgTlIA3SU{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-xYCoTiUlgTlIA3SU .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-xYCoTiUlgTlIA3SU .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-xYCoTiUlgTlIA3SU .error-icon{fill:#552222;}#mermaid-svg-xYCoTiUlgTlIA3SU .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-xYCoTiUlgTlIA3SU .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-xYCoTiUlgTlIA3SU .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-xYCoTiUlgTlIA3SU .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-xYCoTiUlgTlIA3SU .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-xYCoTiUlgTlIA3SU .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-xYCoTiUlgTlIA3SU .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-xYCoTiUlgTlIA3SU .marker{fill:#333333;stroke:#333333;}#mermaid-svg-xYCoTiUlgTlIA3SU .marker.cross{stroke:#333333;}#mermaid-svg-xYCoTiUlgTlIA3SU svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-xYCoTiUlgTlIA3SU p{margin:0;}#mermaid-svg-xYCoTiUlgTlIA3SU .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-xYCoTiUlgTlIA3SU .cluster-label text{fill:#333;}#mermaid-svg-xYCoTiUlgTlIA3SU .cluster-label span{color:#333;}#mermaid-svg-xYCoTiUlgTlIA3SU .cluster-label span p{background-color:transparent;}#mermaid-svg-xYCoTiUlgTlIA3SU .label text,#mermaid-svg-xYCoTiUlgTlIA3SU span{fill:#333;color:#333;}#mermaid-svg-xYCoTiUlgTlIA3SU .node rect,#mermaid-svg-xYCoTiUlgTlIA3SU .node circle,#mermaid-svg-xYCoTiUlgTlIA3SU .node ellipse,#mermaid-svg-xYCoTiUlgTlIA3SU .node polygon,#mermaid-svg-xYCoTiUlgTlIA3SU .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-xYCoTiUlgTlIA3SU .rough-node .label text,#mermaid-svg-xYCoTiUlgTlIA3SU .node .label text,#mermaid-svg-xYCoTiUlgTlIA3SU .image-shape .label,#mermaid-svg-xYCoTiUlgTlIA3SU .icon-shape .label{text-anchor:middle;}#mermaid-svg-xYCoTiUlgTlIA3SU .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-xYCoTiUlgTlIA3SU .rough-node .label,#mermaid-svg-xYCoTiUlgTlIA3SU .node .label,#mermaid-svg-xYCoTiUlgTlIA3SU .image-shape .label,#mermaid-svg-xYCoTiUlgTlIA3SU .icon-shape .label{text-align:center;}#mermaid-svg-xYCoTiUlgTlIA3SU .node.clickable{cursor:pointer;}#mermaid-svg-xYCoTiUlgTlIA3SU .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-xYCoTiUlgTlIA3SU .arrowheadPath{fill:#333333;}#mermaid-svg-xYCoTiUlgTlIA3SU .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-xYCoTiUlgTlIA3SU .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-xYCoTiUlgTlIA3SU .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xYCoTiUlgTlIA3SU .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-xYCoTiUlgTlIA3SU .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xYCoTiUlgTlIA3SU .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-xYCoTiUlgTlIA3SU .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-xYCoTiUlgTlIA3SU .cluster text{fill:#333;}#mermaid-svg-xYCoTiUlgTlIA3SU .cluster span{color:#333;}#mermaid-svg-xYCoTiUlgTlIA3SU div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-xYCoTiUlgTlIA3SU .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-xYCoTiUlgTlIA3SU rect.text{fill:none;stroke-width:0;}#mermaid-svg-xYCoTiUlgTlIA3SU .icon-shape,#mermaid-svg-xYCoTiUlgTlIA3SU .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xYCoTiUlgTlIA3SU .icon-shape p,#mermaid-svg-xYCoTiUlgTlIA3SU .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-xYCoTiUlgTlIA3SU .icon-shape .label rect,#mermaid-svg-xYCoTiUlgTlIA3SU .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xYCoTiUlgTlIA3SU .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-xYCoTiUlgTlIA3SU .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-xYCoTiUlgTlIA3SU :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
👥 团队协作流
开发者输入需求
AI 生成 Plan
📋 方案分享到群
👀 同事提前 Review
💬 讨论与调整
✅ 确认执行
🔨 Build 生成代码
📦 提交 PR,方案附在描述里
相比"直接丢一堆代码过来让大家猜你改了什么",一份清晰的方案让协作效率直接提升一个档次。
四、Plan 模式下的最佳实践与进阶技巧
4.1 怎么写指令,AI 的方案才更靠谱?
指令质量直接决定了方案质量。经过大量试错,我总结了一个**"四要素"指令公式**:
[做什么] + [在哪里做] + [有什么约束] + [期望效果]
举个例子,别写:
❌ “加个搜索功能”
而是写:
✅ “在 ProductList.ets 页面顶部添加一个搜索栏,支持关键词模糊搜索商品名称,搜索结果复用现有列表展示,搜索框输入做 300ms 防抖处理,调用 ProductViewModel 中已有的 fetchProducts 方法时传入搜索参数”
对比一下效果:
| “加搜索” | 笼统,可能忽略防抖、复用列表等细节 | 3-5 轮 |
| 四要素完整指令 | 精准,覆盖技术选型、组件设计、性能优化 | 0-1 轮 |
4.2 审方案的艺术:不是挑刺,是对话
经过一段时间的使用,我总结了审方案的四个关键视角:
视角一:完整性检查
#mermaid-svg-Zrp5o6qkZf391oaa{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Zrp5o6qkZf391oaa .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Zrp5o6qkZf391oaa .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Zrp5o6qkZf391oaa .error-icon{fill:#552222;}#mermaid-svg-Zrp5o6qkZf391oaa .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Zrp5o6qkZf391oaa .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Zrp5o6qkZf391oaa .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Zrp5o6qkZf391oaa .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Zrp5o6qkZf391oaa .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Zrp5o6qkZf391oaa .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Zrp5o6qkZf391oaa .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Zrp5o6qkZf391oaa .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Zrp5o6qkZf391oaa .marker.cross{stroke:#333333;}#mermaid-svg-Zrp5o6qkZf391oaa svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Zrp5o6qkZf391oaa p{margin:0;}#mermaid-svg-Zrp5o6qkZf391oaa .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-Zrp5o6qkZf391oaa .cluster-label text{fill:#333;}#mermaid-svg-Zrp5o6qkZf391oaa .cluster-label span{color:#333;}#mermaid-svg-Zrp5o6qkZf391oaa .cluster-label span p{background-color:transparent;}#mermaid-svg-Zrp5o6qkZf391oaa .label text,#mermaid-svg-Zrp5o6qkZf391oaa span{fill:#333;color:#333;}#mermaid-svg-Zrp5o6qkZf391oaa .node rect,#mermaid-svg-Zrp5o6qkZf391oaa .node circle,#mermaid-svg-Zrp5o6qkZf391oaa .node ellipse,#mermaid-svg-Zrp5o6qkZf391oaa .node polygon,#mermaid-svg-Zrp5o6qkZf391oaa .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Zrp5o6qkZf391oaa .rough-node .label text,#mermaid-svg-Zrp5o6qkZf391oaa .node .label text,#mermaid-svg-Zrp5o6qkZf391oaa .image-shape .label,#mermaid-svg-Zrp5o6qkZf391oaa .icon-shape .label{text-anchor:middle;}#mermaid-svg-Zrp5o6qkZf391oaa .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Zrp5o6qkZf391oaa .rough-node .label,#mermaid-svg-Zrp5o6qkZf391oaa .node .label,#mermaid-svg-Zrp5o6qkZf391oaa .image-shape .label,#mermaid-svg-Zrp5o6qkZf391oaa .icon-shape .label{text-align:center;}#mermaid-svg-Zrp5o6qkZf391oaa .node.clickable{cursor:pointer;}#mermaid-svg-Zrp5o6qkZf391oaa .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Zrp5o6qkZf391oaa .arrowheadPath{fill:#333333;}#mermaid-svg-Zrp5o6qkZf391oaa .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Zrp5o6qkZf391oaa .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Zrp5o6qkZf391oaa .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Zrp5o6qkZf391oaa .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Zrp5o6qkZf391oaa .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Zrp5o6qkZf391oaa .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Zrp5o6qkZf391oaa .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Zrp5o6qkZf391oaa .cluster text{fill:#333;}#mermaid-svg-Zrp5o6qkZf391oaa .cluster span{color:#333;}#mermaid-svg-Zrp5o6qkZf391oaa div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Zrp5o6qkZf391oaa .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Zrp5o6qkZf391oaa rect.text{fill:none;stroke-width:0;}#mermaid-svg-Zrp5o6qkZf391oaa .icon-shape,#mermaid-svg-Zrp5o6qkZf391oaa .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Zrp5o6qkZf391oaa .icon-shape p,#mermaid-svg-Zrp5o6qkZf391oaa .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Zrp5o6qkZf391oaa .icon-shape .label rect,#mermaid-svg-Zrp5o6qkZf391oaa .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Zrp5o6qkZf391oaa .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Zrp5o6qkZf391oaa .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Zrp5o6qkZf391oaa :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
否
是
否
是
否
是
否
是
开始审方案
涉及文件列全了吗?
补充遗漏文件
实现步骤顺序合理吗?
调整步骤顺序
影响分析覆盖了我的顾虑吗?
追问 AI 补充分析
代码预览符合团队规范吗?
在方案上标注规范要求
✅ 确认执行
视角二:业务对齐
- “AI 理解的需求跟我的真实意图一致吗?”
- “有没有多做了不需要的事情?”
- “有没有把简单问题复杂化?”
视角三:风险预判
- “列出的影响分析中,有没有我没意识到的隐患?”(这个往往是 AI 比你强的地方)
- “有没有遗漏的边界条件?”
视角四:性能与可维护性
- “生成的代码结构是否清晰?”
- “是否复用了现有的工具方法?”
- “有没有引入不必要的依赖?”
4.3 方案来回调整的最佳节奏
我摸索出了一个高效的"两轮确认法":
第一轮:AI 出初版方案 → 我只看"整体方向对不对"
├── 方向对 → 第二轮细看
└── 方向不对 → 一句话告诉 AI 偏哪了,让它重规划
第二轮:AI 出修正方案 → 我逐条检查细节
├── 没大问题 → 确认 Build
└── 有小问题 → 直接在方案上改,再确认
最多两轮,绝不陷入"无限拉扯"。如果两轮后方案还不理想,说明你的指令可能需要调整——回头优化指令,比继续跟 AI 来回拉扯更高效。
4.4 我踩过的坑和总结的经验
用 Plan 模式大半年来,这些教训是真金白银砸出来的:
坑 1:方案看着完美就秒点确认
- 现象:有一次 AI 给的方案非常详细,我一激动直接确认了。结果代码生成后发现,方案里某个步骤引用的 API 在我项目版本里已经被废弃了。
- 教训:AI 的方案里引用的 API 版本不一定跟你项目的依赖版本一致。遇到不熟悉的 API,方案阶段先去翻一下你的 oh-package.json5 确认版本。
坑 2:在 Plan 里说"这里改一下",但没说明白怎么改
- 现象:我在方案上写了"把数据加载部分优化一下",AI 理解成"加缓存",但我想的是"改用分页加载"。
- 教训:调整指令和初始指令一样,要具体、要四要素。模糊的调整指令 = 新一轮的误解。
坑 3:不分场景,所有任务都走 Plan
- 现象:改个变量名都要 Plan → 审方案 → 确认 → Build,效率还不如手动改。
- 教训:Plan 是用来解决"不确定性"的,不是用来过流程瘾的。
坑 4:跳过"影响分析"直接看步骤
- 现象:习惯性只看"实现步骤"就确认,忽略了"影响分析"部分。
- 教训:影响分析才是 Plan 模式的精华。步骤告诉你"怎么做",影响分析告诉你"做完会怎样"——后者往往是你自己没想到的。
4.5 小结:一个好方案的"体检清单"
我把审方案的要点整理成了清单,每次确认前过一遍:
- 涉及文件是否完整?有没有遗漏?
- 实现步骤的顺序是否合理?依赖关系对不对?
- 引用的 API / 组件,在我的项目版本里可用吗?
- 影响分析有没有提到我没想到的风险?
- 改动是否最小化?有没有"顺手改了不该改的"?
- 代码预览的风格是否符合团队规范?
- 如果涉及性能(防抖、缓存、懒加载),方案有没有覆盖?
五、Plan+Build 的技术原理与未来展望
5.1 AI 怎么做到"理解你的项目"?
你可能会好奇:AI 凭什么能在几秒钟内分析出我的项目结构、找出相关文件、甚至预判到"ViewModel 状态缓存可能不同步"这种级别的风险?
它的工作流大致是这样的:
#mermaid-svg-Rn13T7RPkvwkLvib{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Rn13T7RPkvwkLvib .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Rn13T7RPkvwkLvib .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Rn13T7RPkvwkLvib .error-icon{fill:#552222;}#mermaid-svg-Rn13T7RPkvwkLvib .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Rn13T7RPkvwkLvib .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Rn13T7RPkvwkLvib .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Rn13T7RPkvwkLvib .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Rn13T7RPkvwkLvib .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Rn13T7RPkvwkLvib .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Rn13T7RPkvwkLvib .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Rn13T7RPkvwkLvib .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Rn13T7RPkvwkLvib .marker.cross{stroke:#333333;}#mermaid-svg-Rn13T7RPkvwkLvib svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Rn13T7RPkvwkLvib p{margin:0;}#mermaid-svg-Rn13T7RPkvwkLvib .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-Rn13T7RPkvwkLvib .cluster-label text{fill:#333;}#mermaid-svg-Rn13T7RPkvwkLvib .cluster-label span{color:#333;}#mermaid-svg-Rn13T7RPkvwkLvib .cluster-label span p{background-color:transparent;}#mermaid-svg-Rn13T7RPkvwkLvib .label text,#mermaid-svg-Rn13T7RPkvwkLvib span{fill:#333;color:#333;}#mermaid-svg-Rn13T7RPkvwkLvib .node rect,#mermaid-svg-Rn13T7RPkvwkLvib .node circle,#mermaid-svg-Rn13T7RPkvwkLvib .node ellipse,#mermaid-svg-Rn13T7RPkvwkLvib .node polygon,#mermaid-svg-Rn13T7RPkvwkLvib .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Rn13T7RPkvwkLvib .rough-node .label text,#mermaid-svg-Rn13T7RPkvwkLvib .node .label text,#mermaid-svg-Rn13T7RPkvwkLvib .image-shape .label,#mermaid-svg-Rn13T7RPkvwkLvib .icon-shape .label{text-anchor:middle;}#mermaid-svg-Rn13T7RPkvwkLvib .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Rn13T7RPkvwkLvib .rough-node .label,#mermaid-svg-Rn13T7RPkvwkLvib .node .label,#mermaid-svg-Rn13T7RPkvwkLvib .image-shape .label,#mermaid-svg-Rn13T7RPkvwkLvib .icon-shape .label{text-align:center;}#mermaid-svg-Rn13T7RPkvwkLvib .node.clickable{cursor:pointer;}#mermaid-svg-Rn13T7RPkvwkLvib .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Rn13T7RPkvwkLvib .arrowheadPath{fill:#333333;}#mermaid-svg-Rn13T7RPkvwkLvib .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Rn13T7RPkvwkLvib .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Rn13T7RPkvwkLvib .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Rn13T7RPkvwkLvib .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Rn13T7RPkvwkLvib .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Rn13T7RPkvwkLvib .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Rn13T7RPkvwkLvib .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Rn13T7RPkvwkLvib .cluster text{fill:#333;}#mermaid-svg-Rn13T7RPkvwkLvib .cluster span{color:#333;}#mermaid-svg-Rn13T7RPkvwkLvib div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Rn13T7RPkvwkLvib .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Rn13T7RPkvwkLvib rect.text{fill:none;stroke-width:0;}#mermaid-svg-Rn13T7RPkvwkLvib .icon-shape,#mermaid-svg-Rn13T7RPkvwkLvib .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Rn13T7RPkvwkLvib .icon-shape p,#mermaid-svg-Rn13T7RPkvwkLvib .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Rn13T7RPkvwkLvib .icon-shape .label rect,#mermaid-svg-Rn13T7RPkvwkLvib .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Rn13T7RPkvwkLvib .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Rn13T7RPkvwkLvib .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Rn13T7RPkvwkLvib :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
📤 输出层
📥 输入层
🧠 AI 推理引擎
用户任务描述
当前打开文件代码
项目文件结构索引
依赖配置文件
项目类型上下文(HarmonyOS / Web / 后端)
意图解析:提取技术需求关键词
上下文关联:关联相关文件与模块
方案生成:规划最优实现路径
风险评估:基于历史模式匹配常见坑点
输出格式化:生成结构化方案文档
结构化方案报告
分步骤实施计划
影响分析清单
代码预览
重点在于上下文关联这一步。它不是只看你当前打开的 ProductList.ets,而是把整个项目的文件依赖图加载进来:
ProductList.ets
├── import { ProductViewModel } from './ProductViewModel'
│ └── ProductViewModel.ets
│ ├── import { ProductApi } from '../api/ProductApi'
│ │ └── ProductApi.ets ← AI 会读到这里
│ └── import { ProductModel } from '../models/ProductModel'
│ └── ProductModel.ets ← AI 也会读到这里
└── import { LoadingAnim } from '../components/LoadingAnim'
└── LoadingAnim.ets ← AI 知道这个组件存在
所以当你让它"加下拉刷新"时,它知道:
- ProductViewModel 里有数据加载方法,刷新时要调它
- ProductModel 的结构是什么,数据刷新后怎么重新绑定
- LoadingAnim 是一个可用组件,可以复用到刷新动画里
- 上拉加载用的是 onReachEnd,跟 PullToRefresh 不冲突
这就是 Plan 模式能给出高质量方案的底层逻辑——它不是靠猜,是靠真正"读懂"了你的项目。
5.2 为什么"审方案"这个环节不可替代?
有一个观点我想特别强调:Plan 模式让人审方案,不是在浪费你的时间,而是在帮你建立"代码心智模型"。
#mermaid-svg-pdFsndHa0uzN3CII{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-pdFsndHa0uzN3CII .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-pdFsndHa0uzN3CII .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-pdFsndHa0uzN3CII .error-icon{fill:#552222;}#mermaid-svg-pdFsndHa0uzN3CII .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-pdFsndHa0uzN3CII .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-pdFsndHa0uzN3CII .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-pdFsndHa0uzN3CII .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-pdFsndHa0uzN3CII .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-pdFsndHa0uzN3CII .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-pdFsndHa0uzN3CII .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-pdFsndHa0uzN3CII .marker{fill:#333333;stroke:#333333;}#mermaid-svg-pdFsndHa0uzN3CII .marker.cross{stroke:#333333;}#mermaid-svg-pdFsndHa0uzN3CII svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-pdFsndHa0uzN3CII p{margin:0;}#mermaid-svg-pdFsndHa0uzN3CII .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-pdFsndHa0uzN3CII .cluster-label text{fill:#333;}#mermaid-svg-pdFsndHa0uzN3CII .cluster-label span{color:#333;}#mermaid-svg-pdFsndHa0uzN3CII .cluster-label span p{background-color:transparent;}#mermaid-svg-pdFsndHa0uzN3CII .label text,#mermaid-svg-pdFsndHa0uzN3CII span{fill:#333;color:#333;}#mermaid-svg-pdFsndHa0uzN3CII .node rect,#mermaid-svg-pdFsndHa0uzN3CII .node circle,#mermaid-svg-pdFsndHa0uzN3CII .node ellipse,#mermaid-svg-pdFsndHa0uzN3CII .node polygon,#mermaid-svg-pdFsndHa0uzN3CII .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-pdFsndHa0uzN3CII .rough-node .label text,#mermaid-svg-pdFsndHa0uzN3CII .node .label text,#mermaid-svg-pdFsndHa0uzN3CII .image-shape .label,#mermaid-svg-pdFsndHa0uzN3CII .icon-shape .label{text-anchor:middle;}#mermaid-svg-pdFsndHa0uzN3CII .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-pdFsndHa0uzN3CII .rough-node .label,#mermaid-svg-pdFsndHa0uzN3CII .node .label,#mermaid-svg-pdFsndHa0uzN3CII .image-shape .label,#mermaid-svg-pdFsndHa0uzN3CII .icon-shape .label{text-align:center;}#mermaid-svg-pdFsndHa0uzN3CII .node.clickable{cursor:pointer;}#mermaid-svg-pdFsndHa0uzN3CII .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-pdFsndHa0uzN3CII .arrowheadPath{fill:#333333;}#mermaid-svg-pdFsndHa0uzN3CII .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-pdFsndHa0uzN3CII .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-pdFsndHa0uzN3CII .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pdFsndHa0uzN3CII .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-pdFsndHa0uzN3CII .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pdFsndHa0uzN3CII .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-pdFsndHa0uzN3CII .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-pdFsndHa0uzN3CII .cluster text{fill:#333;}#mermaid-svg-pdFsndHa0uzN3CII .cluster span{color:#333;}#mermaid-svg-pdFsndHa0uzN3CII div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-pdFsndHa0uzN3CII .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-pdFsndHa0uzN3CII rect.text{fill:none;stroke-width:0;}#mermaid-svg-pdFsndHa0uzN3CII .icon-shape,#mermaid-svg-pdFsndHa0uzN3CII .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pdFsndHa0uzN3CII .icon-shape p,#mermaid-svg-pdFsndHa0uzN3CII .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-pdFsndHa0uzN3CII .icon-shape .label rect,#mermaid-svg-pdFsndHa0uzN3CII .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pdFsndHa0uzN3CII .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-pdFsndHa0uzN3CII .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-pdFsndHa0uzN3CII :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
Plan 模式的心智路径
拿到方案
3 分钟通读
脑中已有改动地图
发现 1 个点要调整
标注后确认
看着代码按你预期的样子生成
🧘 认知负载极低
Direct 模式的心智路径
拿到代码
逐行阅读
推导 AI 的逻辑
发现 3 个问题
手动修改
重新理解自己改了什么
😵 认知负载极高
Plan 模式把代码理解从"事后推导"变成了"事前预览"。你不需要先看一堆代码再反推逻辑——你在方案阶段就已经知道了逻辑,代码生成出来只是对你脑中已有模型的确认。
5.3 未来演进方向
DevEco Code 的 Plan+Build 模式还在持续迭代,我个人非常期待的演进方向包括:
1. 方案多版本对比
📋 方案 A(性能优先) 📋 方案 B(代码简洁优先)
───────────────────── ─────────────────────
使用 List + LazyForEach 使用 Scroll + ForEach
+ 虚拟列表 实现更简单,小数据量
大数据量场景最优 场景代码更少
2. 方案评审协作
方案可以直接生成分享链接,团队成员在方案上评论、点赞、提出修改意见——代码还没写,设计就完成了评审。
3. 与 DevOps 流程集成
方案中的"影响分析"可以自动关联到:
- PR 的检查清单
- 测试用例的生成建议
- CI/CD 中需要重点关注的构建步骤
4. 方案模板与最佳实践库
团队可以沉淀自己的"方案模板"——比如"如何添加一个新的 API 接口"、“如何接入第三方登录”——Plan 模式会优先参考团队的标准化方案。
#mermaid-svg-GU6tCo03JmTEN5Bn{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-GU6tCo03JmTEN5Bn .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-GU6tCo03JmTEN5Bn .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-GU6tCo03JmTEN5Bn .error-icon{fill:#552222;}#mermaid-svg-GU6tCo03JmTEN5Bn .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-GU6tCo03JmTEN5Bn .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-GU6tCo03JmTEN5Bn .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-GU6tCo03JmTEN5Bn .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-GU6tCo03JmTEN5Bn .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-GU6tCo03JmTEN5Bn .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-GU6tCo03JmTEN5Bn .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-GU6tCo03JmTEN5Bn .marker{fill:#333333;stroke:#333333;}#mermaid-svg-GU6tCo03JmTEN5Bn .marker.cross{stroke:#333333;}#mermaid-svg-GU6tCo03JmTEN5Bn svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-GU6tCo03JmTEN5Bn p{margin:0;}#mermaid-svg-GU6tCo03JmTEN5Bn .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-GU6tCo03JmTEN5Bn .cluster-label text{fill:#333;}#mermaid-svg-GU6tCo03JmTEN5Bn .cluster-label span{color:#333;}#mermaid-svg-GU6tCo03JmTEN5Bn .cluster-label span p{background-color:transparent;}#mermaid-svg-GU6tCo03JmTEN5Bn .label text,#mermaid-svg-GU6tCo03JmTEN5Bn span{fill:#333;color:#333;}#mermaid-svg-GU6tCo03JmTEN5Bn .node rect,#mermaid-svg-GU6tCo03JmTEN5Bn .node circle,#mermaid-svg-GU6tCo03JmTEN5Bn .node ellipse,#mermaid-svg-GU6tCo03JmTEN5Bn .node polygon,#mermaid-svg-GU6tCo03JmTEN5Bn .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-GU6tCo03JmTEN5Bn .rough-node .label text,#mermaid-svg-GU6tCo03JmTEN5Bn .node .label text,#mermaid-svg-GU6tCo03JmTEN5Bn .image-shape .label,#mermaid-svg-GU6tCo03JmTEN5Bn .icon-shape .label{text-anchor:middle;}#mermaid-svg-GU6tCo03JmTEN5Bn .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-GU6tCo03JmTEN5Bn .rough-node .label,#mermaid-svg-GU6tCo03JmTEN5Bn .node .label,#mermaid-svg-GU6tCo03JmTEN5Bn .image-shape .label,#mermaid-svg-GU6tCo03JmTEN5Bn .icon-shape .label{text-align:center;}#mermaid-svg-GU6tCo03JmTEN5Bn .node.clickable{cursor:pointer;}#mermaid-svg-GU6tCo03JmTEN5Bn .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-GU6tCo03JmTEN5Bn .arrowheadPath{fill:#333333;}#mermaid-svg-GU6tCo03JmTEN5Bn .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-GU6tCo03JmTEN5Bn .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-GU6tCo03JmTEN5Bn .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GU6tCo03JmTEN5Bn .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-GU6tCo03JmTEN5Bn .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GU6tCo03JmTEN5Bn .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-GU6tCo03JmTEN5Bn .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-GU6tCo03JmTEN5Bn .cluster text{fill:#333;}#mermaid-svg-GU6tCo03JmTEN5Bn .cluster span{color:#333;}#mermaid-svg-GU6tCo03JmTEN5Bn div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-GU6tCo03JmTEN5Bn .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-GU6tCo03JmTEN5Bn rect.text{fill:none;stroke-width:0;}#mermaid-svg-GU6tCo03JmTEN5Bn .icon-shape,#mermaid-svg-GU6tCo03JmTEN5Bn .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GU6tCo03JmTEN5Bn .icon-shape p,#mermaid-svg-GU6tCo03JmTEN5Bn .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-GU6tCo03JmTEN5Bn .icon-shape .label rect,#mermaid-svg-GU6tCo03JmTEN5Bn .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GU6tCo03JmTEN5Bn .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-GU6tCo03JmTEN5Bn .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-GU6tCo03JmTEN5Bn :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
未来方向
多版本方案对比
团队协作评审
DevOps 集成
方案模板库
方案自动生成测试用例
当前能力
单次任务 Plan
项目上下文分析
影响分析
结语
Plan+Build 这个模式用了一段时间,我最大的感受是:它把 AI 从一个"帮你敲字的实习生",变成了一个"先跟你对方案再动手的高级搭档"。
以前用 AI 写代码,经常是"惊喜"和"惊吓"交替——有时候惊艳,更多时候是在 debug 一段自己没看懂的逻辑。现在 Plan 模式让整个过程变得可预期、可干预、可信任。
最后给你留一道"自测题",判断你是否已经掌握了 Plan 模式的精髓:
下次接到一个新需求,在打开编辑器之前,先问自己三个问题:
只要有一个答案让你犹豫——先 Plan,再 Build。
如果你也用 DevEco Code,试一下这个模式。尤其是下次碰到一个看起来"挺简单但突然变复杂了"的需求的时候——相信我,你会回来点赞的。
网硕互联帮助中心


评论前必须登录!
注册