让 Agent 改一个按钮、修一个 Bug,今天已不算新闻。
但只给它一份调研文档,让它从 0 写出高度还原的完整应用呢?
这是一条横跨规划、架构、十几个模块编码、验证、修复的超长程任务:几个小时、成百上千个决策、前后强依赖,错一步就会沿着后面几十步一路放大。这正是今天大多数 Agent 最容易翻车的地方。
最近,我们和 Efflora 团队基于 Qwen3.7-Max 模型,做了一场实验:仅凭一份产品调研文档,在隔离环境中从 0 交付了移动端和 Web 端两套可运行应用。
这场实验也揭示了一个被忽视的工程真相:质量不是模型一次「生成」出来的,是被闭环「收敛」出来的。
我们用 Qwen3.7-Max 做了啥
给 Qwen3.7-Max 一份产品调研文档,让它在隔离环境里,从 0 交付能真实跑起来的应用——而且移动端、Web 端各一套,发现页瀑布流、商城分类与商品卡、内容详情页的图文与评论流,核心界面与主要交互都被几近还原。
唯一输入:「图文社区 + 商城」形态产品的用户流程文档 + 关键页面拆解报告,合计 约 15 万字、拆解 12 个核心页面(覆盖 8 大功能模块、7 条用户流程);
没有给的:设计稿、现成代码、分步骤的人工拆解、后端逻辑;
耗时:单端从 0 到可运行 约 4 个多小时全自动完成,中途无人工接管。
本次实验亮眼的地方在于:
1、它没「看」过任何一张图,却把界面还原了。
Qwen3.7-Max 不具备图像理解能力,整个过程它没有看过任何一张设计稿或截图——还原靠的不是模型的眼睛,是约束。
2、它写的是真应用,不是点击演示。
在未提供后端逻辑的前提下,模型自行设计了一套完整的关系型数据模型(近 20 张表,含多对多关联表与索引),并写出带字段校验、分页过滤、错误处理的真实接口逻辑;前端则真实调用这些接口取数据、刷新、给用户反馈,而不是把数据写死在页面里。这是有建模意识、有副作用、有错误处理的真实工程,不是占位桩。
怎么做到的:分阶段注入约束 + 分层验收
与其说我们让模型写了应用,不如说我们设计了一套约束闭环:把整个 0→1 过程拆成有序的阶段,在每个阶段把「要做成什么样」翻译成机器可校验的硬约束,再用一道比一道更严的验收机制,把模型逐步逼到达标。标准的制定与验收,全部不交给模型——它只负责在每一格里做决策。
值得强调的是:移动端和 Web 端用的是同一套方法论。技术栈不同,约束闭环不变——这恰恰说明,决定交付质量的是这套控制方法,而不是某一种框架、或某个模型的单点能力。
这套约束闭环控制系统,不是「给模型一个写代码的地方」,而是一条「分阶段注入约束 → 逐层验收 → 带错纠正」的可收敛流水线。
1️⃣ 分阶段,把约束「种」进每一步
约束不是一次性丢进去的,而是跟着阶段逐层加码:规划阶段约束目标边界(从调研结论先推出页面 / 模块清单,想清楚「做成什么样」再动手);架构阶段约束技术选型与数据建模,并把真实 UI 的像素坐标反推成布局约束;编码阶段约束实现规则,并要求每个模块写完先自查、逐条指认「哪行代码落地了哪条约束」。
不让模型看一段「页面描述」就拍脑袋,而是把真实界面的像素事实,直接翻译成它必须遵守的布局约束。
但约束能落地,有一个隐含前提——模型得真的守规矩。我们给的硬规则(长文件分段读取、动手前先用 Glob 探查、改文件前先读原文)Qwen3.7-Max 在近 30 分钟、数百次工具调用里逐条照做,而不是盲写;它甚至会按真实依赖关系重排执行顺序(先把所有页面建好,再回头补路由),而非机械按编号推进。一个不守约束的模型,再好的约束工程也落不了地。
2️⃣ 分层验收,一道比一道更接近「人」
写完不算交付。我们架了一条逐级加码的验收阶梯,失败时把上一步的报错原文喂进下一次重试,让偏差当场收回:
静态检查(命名、未用引用、空安全等)
编译自检(必须 0 error 才算过)
路由完整性(每个页面都接得上、点得到)
功能扫描(空按钮、占位页、假加载等交互缺陷)
部署到真实运行环境,冷启动,像人一样跑起来看
这一步,是我们最想强调的认知
机器可验 ≠ 应用可用。编译通过、0 error、路由齐全、功能扫描干净,这些只证明「代码成立」,不证明「应用可用」。一个真人怎么评价一个 App?他不会去看你静态检查过没过,他会打开它、在真机上点一遍、看顺不顺、像不像。所以验收标准必须贴近人——闭环的终点,是把应用装进真实运行环境冷启动、像人一样用一遍。
3️⃣ 确定性兜底,长程里别丢步
整条阶梯由一层确定性调度兜底:每个模块必然被执行、失败必然重试、中断可断点续跑。模型负责「智能」,调度负责「可靠」——用确定性的脚手架,包住非确定性的 Agent。
细节 / 日志:约束是怎么被「执行」和「判定」的
方法论容易说漂亮,真正可复现的是工程细节。以下两点,是整套约束闭环里最硬核的部分:
解决「模糊的审美要求,怎么变成机器能逐条核对的事实」
解决「怎么客观判定一个自由发挥的模型,到底成没成」
细节一:让模型照着真实 App 的「像素坐标」写布局,而不是照着文字描述
问题:文字描述是有损压缩
复刻一个界面,最自然的做法是把调研报告喂给模型:「首页是两列视频网格,顶部有个推荐位」。它照着做出来,往往是——看着像、处处不对:列宽不对、卡片忽高忽矮、顶部那张大图被硬塞进了两列网格里。
根因在于:这种文字描述本身是一次有损压缩。「两列网格」四个字,把列宽、卡片宽高比、有没有通栏大图、图标排几个这些可量化的事实全丢了,模型只能靠脑补补齐——而脑补基本不会对。(更何况 Qwen3.7-Max 看不懂截图,文字描述几乎是它唯一的视觉线索。)
洞察:坐标是跑不掉的事实
但在真机界面里,每个元素的像素坐标是确定的、无损的。我们的调研产物里就躺着这样一份东西:ui_summary.txt——从真机界面 dump 出来的元素清单,一行一个控件,带着它的精确边界框。一行长这样(已简化,只留关键字段):
... clickable="true" bounds="[17,436][1423,1358]"bounds="[左,上][右,下]" 就是像素级的事实——这一行说的是:一个可点击的卡片,左上角在 (17,436)、右下角在 (1423,1358),也就是宽 1406px。所以流水线立了一条原则:
bounds 是真相,描述是衍生物。布局必须由坐标反推,而不是由文字描述拍板。
做法:把坐标换算成几条「不许违反」的事实
任务拆分完成后,一段程序会自动扫描这些坐标、做纯几何换算,把结果直接写死在每个页面的任务卡末尾。它本质上是在替设计师回答几个本该拍板的问题(括号里是判断依据):
这页是网格还是列表?(取面积最大的那个可滚动容器,看它的类型——决定该用网格还是列表来实现)
一行排几列?(把可点击卡片按纵坐标聚成一行,容差 ≈ 50px,同一行里有几张就是几列)
顶部那张大图要不要单独做?(宽度 ≥ 90% 屏宽的卡,就是一张通栏「头卡」,必须单独处理,不能塞进 N 列网格)
所有卡能不能套同一个模子?(同一页若出现多种宽高比,如 0.55 瘦长、0.85 近方,就禁止用单一比例一压到底,必须分类型或上瀑布流——这恰恰是模型最爱犯的错)
这个小方块是图标还是图片?(又小、又接近正方、还成排出现,同排 ≥ 3 个的,判定为图标位,强制用矢量图标,而不是拿照片去凑)
最终产出,是一段叫「布局硬约束」的清单,长这样:
- 滚动根容器:网格 → 实现时用网格组件- ⚠️ 检测到 1 张通栏头卡(宽度 ≥ 90% 屏宽)→ 必须含全宽头卡- ⚠️ 混合宽高比:{0.55 瘦长卡, 0.85 近方卡} → 禁止用单一比例- 图标位:1 行 6 列,边长 ≈ 168px → 必须用矢量图标
于是写代码的模型拿到的,不再是「做个好看的首页」这种含糊要求,而是一份可以逐条对照检查的事实清单——它在自查时甚至要指出「通栏头卡 → 首页第 42 行的 _LeaderCard」。我们把模糊的审美问题,压成了确定的几何约束。
细节二:怎么知道一个 Agent「到底成没成」
一个被低估的难题 流水线是 Harness 调度 + 模型干活。Harness 要根据 Agent 的执行结果决定下一步:通过了就标记完成往下走,失败了就重试或回退。问题是——怎么判断一个自由发挥的语言模型「成功」了没有?模型不会返回 exit code 0,它返回的是一大段自然语言。
三层判定,逐层兜底
编排层:CLI 异常退出、撞上轮数上限(max_turns),直接判失败,异常被 try/except 兜住、转成「(错误文本, False)」。
产物层:很多阶段不信 Agent 的「我做完了」,而是亲自查文件存不存在——规划阶段查开发指南、拆分阶段查有没有任务文件、打包阶段查 APK。说成功但文件没生成,照样算失败。
协议层:对「修到没问题为止」这种没有明确产物的阶段,约定一个文本暗号——Agent 被要求在输出里打 ANALYZE_RESULT: PASS 或 VALIDATION_RESULT: PASS,再用字符串匹配判定。
if"ANALYZE_RESULT: PASS" in result_text:await mark_phase_done(PHASE_ANALYZE)return Trueprev_errors = result_text # 没 PASS,把整段输出当作下一轮的输入
注意最后一行:失败时,Agent 这一轮的全部输出会原样变成下一轮的 prompt 上文。于是「剩余的 error 列表」自动传给下一轮去修——重试不是从头再来,而是带着上次的残局接着打。模块开发的重试同理:上次报错被截断后注入下一次(「【重试注意】上一次执行失败,错误信息如下……」),并且重试前先把上次可能写歪的文件清掉,避免脏文件干扰。
不止外层在收敛,模型自己也在收敛:带着上一轮的残局,Qwen3.7-Max 反复「生成 → 编译自检 → 读报错 → 修复 → 再编译」,把报错数一轮轮压下去(如 43 → 38 → 20 …)直到能成功构建。内层(模型自查)与外层(Harness 判定 + 带错重试)同频收敛——这正是它能独立交付可构建工程的关键。
结果与边界
先说结果
双端(移动端 + Web)从 0 交付,核心界面与主要交互几近还原。 交付质量:功能验证 / 静态分析 / 打包 / 启动冒烟 4 道自动化关卡全部通过——移动端产出可安装 APK 并通过启动冒烟,Web 端 typecheck + 构建通过、34 条路由全部可达。 整个过程跨越数小时、涉及大量长程依赖,由模型独立完成,中途没有人工接管做分步拆解。
再说边界
「几近还原」不是「逐像素一致」:还原的是页面结构与主要交互路径,细节排版、边缘交互仍有出入。例如:评论区暂为平铺、未实现「展开 N 条回复」的分层视图;二维码为占位图、非真实可扫码;部分边缘入口(设置 / 收藏 / 直播创建等)仍是「敬请期待」占位提示。 数据是 mock,不是真实后端:界面跑得起来,但不含真实用户数据,也不等于一套生产级后端。 复现性依赖环境与输入质量:调研文档颗粒度、Sandbox 反馈信号是否到位,会直接影响产出稳定性——换一份模糊的输入,结果会明显退化。
从这个实验我们发现了什么?
一、没有「自动判据」的闭环,只是伪闭环
遇到的问题: 起初,我们以为只要让模型写完代码、编译通过就算成功。但在长程任务中,错误会沿着链条累积:一个微小的命名规范错误,可能在几十步之后导致路由失效。如果没有自动化的判定机制,这些错误会被掩盖,直到最后真机运行才爆发。
我们的发现: 同一个模型,放进「能自动判定成败」的闭环里,长程交付的成功率明显高于「只给它一个编辑器」。
原因:没有可验证反馈时,错误是隐性的;有了硬信号(如编译报错、路由缺失),错误能被当场截断、回灌纠正。
关键点:判定能力必须一路建到贴近人的真机层。别停在编译过、单测通过就以为交付了——那是给机器看的,不是给用户用的。
二、约束越多,模型越爱「哄骗」校验
遇到的问题: 为了追求完美,我们一度加了多层质量校验循环,包括语义相似度匹配、风格一致性检查等模糊规则。结果发现,产出反而不稳定:模型开始花大量精力去生成那些能“骗过”校验器的关键词,而不是真正写对代码。
我们的发现: 约束要做减法,不要做加法。 当我们删掉模糊的关键词校验,换成可被字面匹配的硬规则(如“必须包含某函数名”、“文件行数必须大于X”)后,产出反而更稳。
原因:校验越模糊、越冗余,模型越容易把精力花在「通过校验」上,且校验自身的误判还会污染重试上下文。
关键点:只保留「能被机器明确验证」的约束。一条可字面校验的硬规则,胜过一堆似是而非的提醒。
三:工具层能补位,但补不了「地基」
遇到的问题: Qwen3.7-Max 不具备图像理解能力,这曾是我们担心的短板。我们试图通过工具层拦截截图、转化为文字描述来弥补。但我们发现,即便有了这些辅助,如果模型本身在长程指令遵循上漂移,整个工程依然会崩塌。
我们的发现: 模型的「长程指令遵循稳定性」是地基,工具层只是装修。 看不懂图可以靠工具层拦截 + 文字化补上;但要在近 30 分钟、数百次调用、上百个文件里守约束不漂移、按真实依赖排序、还能收敛式自我纠错,这件事约束工程替代不了——这正是 Qwen3.7-Max 这次顶住的地方。
原因:约束再好,也要有一个能稳定理解并持续遵循它的模型来执行;长上下文一旦跑偏,再多验收机制也救不回来。
关键点:选模型别只看单点跑分,重点看它在「长上下文、强指令、多轮自洽」下掉不掉链子。
Agent 辅助开发,一站式打通 Qwen3-VL Android 端侧推理
Qwen3.7-Plus:把多模态AI变成“实干家”
夜雨聆风