⚠️ Alpha内测版本警告:此为早期内部构建版本,尚不完整且可能存在错误,欢迎大家提Issue反馈问题或建议。
Skip to content

面向长时间运行应用程序开发的harness设计

过去几个月,我一直在研究两个相互关联的问题:让 Claude 生成高质量的前端设计,以及让它无需人工干预就能构建完整的应用程序。这项工作源于我们早期在前端设计技能和长期运行编码agent框架上的努力,我和同事们通过提示工程和框架设计,成功将 Claude 的性能提升到远高于基准水平——但两者最终都遇到了瓶颈。

为了突破这些瓶颈,我探索了新颖的 AI 工程方法,这些方法适用于两个截然不同的领域:一个由主观审美定义,另一个由可验证的正确性和可用性定义。受生成对抗网络(GANs)的启发,我设计了一个包含生成器和评估器agent的多agent结构。构建一个能够可靠评估输出——并且具备审美判断力——的评估器,意味着首先需要制定一套标准,将“这个设计好吗?”这类主观判断转化为具体、可分级的标准。

随后,我将这些技术应用于长期自主编码,并借鉴了早期框架设计中的两个经验:将构建过程分解为可管理的模块,以及利用结构化工件在会话间传递上下文。最终成果是一个三智能体架构——规划器、生成器和评估器——能够在长达数小时的自主编码会话中产出功能丰富的全栈应用程序。

1.为何简单的实现方式效果不佳

我们先前已证明,框架设计对长期自主编码智能体的效能具有显著影响。在早期实验中,我们使用初始化智能体将产品规格分解为任务列表,并由编码智能体逐项实现功能,同时通过传递工件在会话间保持上下文连贯。更广泛的开发者社区已形成类似共识,例如采用"拉尔夫·维格姆"方法,通过钩子或脚本使智能体保持在持续迭代循环中。

但有些问题依然顽固存在。对于更复杂的任务,智能体仍会随着时间推移逐渐偏离正轨。在剖析这一问题时,我们观察到智能体执行此类任务时存在两种常见的失效模式。

首先是模型在长任务中随着上下文窗口填满容易失去连贯性。某些模型还会表现出"上下文焦虑",即当接近其自认为的上下文容量极限时,会过早地开始收尾工作。通过上下文重置——完全清空上下文窗口并启动全新智能体,同时结合结构化交接流程来传递前序智能体状态与后续步骤——能同时解决这两类问题。

这与压缩不同,压缩是将对话的早期部分就地总结,以便同一智能体能够在缩短的历史记录中继续工作。虽然压缩保持了连续性,但它并没有给智能体一个全新的开始,这意味着上下文焦虑仍然可能存在。重置提供了一个全新的开始,代价是交接工件需要包含足够的状态,以便下一个智能体能够清晰地接手工作。在我们早期的测试中,我们发现 Claude Sonnet 4.5 表现出足够强烈的上下文焦虑,仅靠压缩不足以实现强大的长任务性能,因此上下文重置成为工具设计的关键。这解决了核心问题,但增加了每次工具运行的编排复杂性、令牌开销和延迟。

我们之前未曾提及的第二个问题是自我评估。当要求评估自己完成的工作时,智能体往往会自信地给予高度评价——即便在人类观察者看来,其质量显然平平无奇。这个问题在主观性任务(例如设计)中尤为突出,因为这类任务不存在类似可验证软件测试的二元判断标准。布局设计究竟显得精致还是平庸属于主观判断,而智能体在评估自身作品时总会倾向于给出积极评价。

然而,即便是在那些确实存在可验证结果的任务上,智能体有时仍会表现出判断力不足,从而影响其任务完成的表现。事实证明,将执行工作的智能体与评估工作的智能体分离开来,是解决这一问题的有力手段。这种分离本身并不会立即消除评估的宽容性;评估者本身仍是一个倾向于对 LLM 生成内容持宽容态度的 LLM。但调整一个独立的评估者使其持怀疑态度,远比让生成器对自己的工作持批判态度要容易得多。一旦有了这种外部反馈,生成器就有了具体可迭代改进的依据。

2.前端设计:让主观质量可量化

我从前端设计开始实验,因为自我评估问题在这里最为明显。在没有干预的情况下,Claude 通常会倾向于安全、可预测的布局,这些布局在技术上是可行的,但在视觉上并不出众。

两个见解塑造了我为前端设计构建的框架。首先,虽然美学不能完全简化为一个分数——个人品味总是会有所不同——但可以通过编码设计原则和偏好的评分标准来改进。"这个设计漂亮吗?"很难一致地回答,但"这个设计是否遵循了我们的良好设计原则?"给了 Claude 一些具体的评分依据。其次,通过将前端生成与前端评分分开,我们可以创建一个反馈循环,推动生成器产生更强的输出。

考虑到这一点,我写了四个评分标准,并在提示中同时提供给生成器和评估器代理:

  • 设计质量 (Design quality): 设计是否感觉像一个连贯的整体,而不是零散的部分的集合?在这方面表现出色意味着颜色、排版、布局、图像和其他细节相结合,创造出独特的氛围和身份。
  • 原创性 (Originality): 是否存在定制决策的证据,还是仅仅使用了模板布局、库默认设置和 AI 生成的模式?一位人类设计师应当能够识别出有意识的创意选择。未经修改的现成组件——或者 AI 生成的典型迹象,比如白色卡片上的紫色渐变——在这方面是不合格的。
  • 工艺 (Craft): 技术执行:字体层次、间距一致性、色彩协调、对比度比例。这是一项能力检查而非创意检查。大多数合理的实现默认都能在此处表现良好;失败则意味着基础不牢。
  • 功能性 (Functionality): 可用性独立于美学。用户能否理解界面的作用,找到主要操作,并在无需猜测的情况下完成任务?

我强调设计质量和原创性,而非工艺和功能性。Claude 在工艺和功能性方面已经默认表现出色,因为所需的技术能力往往自然而然地体现在模型中。但在设计和原创性方面,Claude 的输出往往平淡无奇。评估标准明确惩罚了高度通用的“AI 垃圾”模式,通过更重视设计和原创性,推动模型进行更具美学风险的尝试。

我使用带有详细分数分解的少量示例来校准评估器。这确保了评估者的判断与我的偏好一致,并减少了迭代过程中的分数漂移。

我在 Claude Agent SDK 上构建了这个循环,这使得整个编排过程保持简洁明了。一个生成器代理首先根据用户提示创建 HTML/CSS/JS 前端。我为评估器配备了 Playwright MCP,使其能够在评分每个标准并撰写详细评论之前,直接与实时页面进行交互。在实际操作中,评估器会自主浏览页面,截取屏幕截图并仔细研究实现细节,然后才生成评估报告。这些反馈会作为下一轮迭代的输入,回流给生成器。每代设计我运行 5 到 15 次迭代,每次迭代通常都会推动生成器朝着更独特的方向发展,以响应评估器的批评。由于评估器是主动浏览页面,而不是对静态截图进行评分,每个周期都需要实际的挂钟时间。完整的运行过程可能长达四个小时。我还指示生成器在每次评估后做出战略决策:如果评分趋势良好,则继续优化当前方向;如果当前方法效果不佳,则转向完全不同的美学风格。

在多次运行中,评估者的判断随着迭代次数增加而提升,随后趋于稳定,但仍存在改进空间。部分生成结果实现了渐进式优化,而另一些则在迭代间发生了显著的审美转向。

评估标准的措辞以我未能完全预料的方式引导了生成器。诸如"最佳设计应达到博物馆级品质"这类表述,将设计推向特定的视觉趋同方向,这表明与标准相关联的提示语直接塑造了输出结果的特性。

虽然评分总体上随迭代次数提升,但变化规律并非总是简单的线性增长。后期版本整体表现更优,但我经常发现某些中间迭代版本比最终版本更符合偏好。随着迭代轮次增加,实现复杂度也呈上升趋势,生成器会根据评估者的反馈尝试更具雄心的解决方案。即使在首次迭代中,输出结果也明显优于完全无提示的基线水平,这表明评估标准及其相关表述本身就能引导模型摆脱通用默认模式,无需评估者反馈即可实现初步优化。

在一个显著的例子中,我提示模型为一家荷兰艺术博物馆创建网站。到第九次迭代时,它已经为一个虚构的博物馆制作了一个简洁、深色主题的着陆页。页面视觉上很精致,但基本符合我的预期。然后,在第十轮中,它完全抛弃了之前的思路,将网站重新构想为一种空间体验:一个用 CSS 透视渲染的、带有棋盘格地板的 3D 房间,艺术品以自由形式悬挂在墙上,画廊房间之间通过门道导航,而不是滚动或点击。这是一种我之前从未在单次生成中见过的创造性飞跃。

3.扩展到全栈编码

基于这些发现,我将这种受 GAN 启发的模式应用于全栈开发。生成器-评估器循环自然地映射到软件开发生命周期中,其中代码审查和 QA 扮演着与设计评估器相同的结构性角色。

4.架构设计

在我们早期的长时程开发框架中,我们通过初始化代理、每次处理一个功能的编码代理以及会话间的上下文重置,解决了连贯的多会话编码问题。上下文重置是关键突破:该框架使用 Sonnet 4.5 模型,该模型表现出前文提到的“上下文焦虑”倾向。构建一个能在上下文重置中良好工作的框架,是保持模型专注于任务的关键。Opus 4.5 模型在很大程度上自行消除了这种行为,因此我能够完全从这个框架中移除上下文重置。在整个构建过程中,代理以单一连续会话的形式运行,Claude Agent SDK 的自动压缩机制在此过程中处理上下文的增长。

在这项工作中,我以原始框架为基础构建了一个三智能体系统,每个智能体都针对我在先前运行中观察到的特定不足。该系统包含以下智能体角色:

  • 计划者 (Planner): 我们之前的长期运行框架要求用户预先提供详细规格说明。我希望自动化这一步骤,因此创建了一个规划者智能体,它能将简单的 1-4 句提示扩展为完整的产品规格说明。我引导它在范围设定上保持雄心,并专注于产品背景和高级技术设计,而非详细的技术实现。这种强调源于一个考量:如果规划者试图预先指定细粒度的技术细节并出现错误,规格说明中的错误将级联影响下游实现。更明智的做法似乎是约束智能体需要交付的成果,让它们在工作中自行探索实现路径。我还要求规划者在产品规格说明中寻找融入人工智能功能的机会。
  • 生成器 (Generator): 早期测试框架中一次实现一个功能的方法在范围管理方面效果很好。我在此应用了类似模式,指导生成器采用冲刺式开发,每次从规范中选取一个功能进行实现。每个冲刺周期都使用 React、Vite、FastAPI 和 SQLite(后期改用 PostgreSQL)技术栈来构建应用,并要求生成器在每个冲刺结束时先进行自我评估,再交付给质量保证团队。版本控制方面则采用 git 进行管理。
  • 评估器 (Evaluator): 早期测试框架构建的应用往往表面光鲜,但实际使用时仍存在真实缺陷。为捕捉这些问题,评估器通过 Playwright MCP 工具模拟用户操作流程,对运行中的应用进行点击测试,涵盖 UI 功能、API 端点和数据库状态验证。随后根据发现的缺陷以及一套源自前端实验的评估标准(此处调整为涵盖产品深度、功能完整性、视觉设计和代码质量)对每个冲刺成果进行评分。每项标准都设有硬性阈值,任何一项不达标即判定该冲刺失败,生成器将收到关于具体问题的详细反馈。

在每个冲刺开始前,生成器与评估器会协商一份冲刺契约:在编写任何代码之前,就当前工作模块的"完成标准"达成共识。设立这一环节是因为产品规格书有意保持高层级描述,而我需要一个步骤来弥合用户故事与可测试实现之间的鸿沟。生成器提出它将构建的内容及验证成功的方式,评估器则审核该提案以确保生成器正在构建正确的内容。双方反复沟通直至达成一致。

沟通通过文件进行:一个智能体会写入文件,另一个智能体读取该文件并通过同一文件或新建文件作出回应,再由前一个智能体依次读取。随后,生成器依据已达成共识的契约进行构建,再将成果移交至质量保证环节。这种方式既确保工作忠实于规格要求,又避免了过早过度细化实施方案。

5.运行harness框架

在该测试框架的首个版本中,我使用了 Claude Opus 4.5 模型,分别对完整框架和单智能体系统运行用户提示以进行对比。选择 Opus 4.5 是因为在我开始这些实验时,这是我们最优秀的编码模型。 我写了以下提示词来生成一个复古视频游戏制作工具: 创建一个 2D 复古游戏制作工具,功能包括关卡编辑器、精灵编辑器、实体行为系统和可玩的测试模式。

下表显示了测试框架类型、运行时长和总成本。

框架时长成本
单次 (Solo)20 分钟$9
完整框架 (Full harness)6 小时$200

harness的成本高出 20 倍以上,但输出质量的差异是显而易见的。

我原本期待一个能构建关卡及其组件(精灵、实体、瓦片布局)的界面,然后点击播放即可实际体验关卡。我首先打开了单人运行的输出,初始应用程序似乎符合这些预期。

然而,随着我不断点击,问题开始浮现。布局浪费了大量空间,固定高度的面板让大部分视窗区域空空如也。工作流程僵化不堪。尝试填充关卡时,系统提示我先创建精灵和实体,但界面中没有任何指引表明需要遵循这个顺序。更重要的是,游戏本身根本无法运行。我的实体虽然显示在屏幕上,却对任何输入都没有反应。深入代码排查后发现,实体定义与游戏运行时的连接已经断裂,而界面表层没有任何迹象显示问题出在哪里。

评估完单人运行后,我将注意力转向了工具运行。这次运行从相同的单句提示开始,但规划步骤将该提示扩展为横跨十个冲刺周期的 16 项功能规格。其范围远超单人运行的尝试。除了核心编辑器和游玩模式外,该规格还要求包含精灵动画系统、行为模板、音效与音乐、AI 辅助精灵生成器与关卡设计器,以及可分享链接的游戏导出功能。我向规划器开放了前端设计技能权限,规划器读取并运用该技能,在规格中为应用创建了视觉设计语言。每个冲刺周期中,生成器与评估器通过协商确定合约,明确该冲刺的具体实施细节,以及用于验证完成度的可测试行为。

与独立运行相比,该应用立即展现出更高的完成度和流畅性。画布充分利用了视口空间,面板尺寸设计合理,界面具有统一且符合规格书设计方向的视觉识别系统。不过独立运行中存在的部分笨拙操作仍然保留——工作流程仍未明确提示用户应在填充关卡前先创建精灵和实体,我不得不通过自行摸索来理解这一点。这反映出基础模型在产品直觉方面的缺陷,而非工具链设计需要解决的问题,但确实提示了在工具链内进行针对性迭代有助于进一步提升输出质量。

通过操作各个编辑器,新版本相较于独立运行的优势愈发明显。精灵编辑器功能更丰富完善,工具面板更简洁,颜色选择器更优化,缩放控制功能也更实用。

由于我要求规划器将 AI 功能融入规格设计,该应用还内置了 Claude 集成功能,允许我通过提示词生成游戏的各个组成部分。这显著加快了工作流程。

最大的区别在于游玩模式。我实际上能够移动我的实体并玩游戏。物理效果有些粗糙——我的角色跳上一个平台,但最终与平台重叠,这感觉明显不对——但核心功能是有效的,而单独运行则未能实现。在四处移动了一会儿后,我确实遇到了 AI 游戏关卡构建的一些限制。有一堵大墙我无法跳过,因此我被困住了。这表明存在一些常识性的改进和边缘情况,该工具可以处理以进一步完善应用程序。

翻阅日志时,可以清楚地看到评估者始终确保实现与规范保持一致。每个冲刺阶段,它都会逐条检查冲刺合约的测试标准,并通过 Playwright 对运行中的应用进行测试,一旦发现与预期行为不符之处便会提交缺陷报告。这些合约条款非常细致——仅冲刺 3 就包含了 27 项针对关卡编辑器的标准——而评估者的发现也足够具体,无需额外调查即可直接处理。下表展示了评估者识别出的若干问题示例:

标准评估器发现
矩形填充工具允许通过点击拖动,用选定的图块填充一个矩形区域失败 — 工具仅在拖动起点/终点放置图块,而不是填充区域。fillRectangle 函数存在,但未能在 mouseUp 时正确触发。
用户可以选择并删除已放置的实体生成点失败LevelEditor.tsx:892 处的删除键处理程序要求同时设置 selectionselectedEntityId,但点击实体仅设置了 selectedEntityId。条件应为 `selection
用户可以通过 API 重新排序动画帧失败PUT /frames/reorder 路由定义在 /{frame_id} 路由之后。FastAPI 将 'reorder' 匹配为 frame_id 整数并返回 422:"无法将字符串解析为整数。"

让评估器达到这个水平需要付出努力。Claude 在开箱即用时是一个糟糕的 QA 代理。在早期运行中,我观察到它识别出合理的问题,然后说服自己认为这些问题无关紧要,最终仍然批准了工作。它还倾向于进行表面测试,而不是深入探究边界情况,因此更细微的漏洞常常被忽略。调整循环包括阅读评估器的日志,找出其判断与我的判断不一致的例子,并更新 QA 提示以解决这些问题。经过几轮这样的开发循环后,评估器的评分方式才变得合理。即便如此,测试框架的输出仍然显示了模型 QA 能力的局限性:小的布局问题、某些地方感觉不直观的交互,以及评估器未充分测试的更深层嵌套功能中未发现的漏洞。显然,通过进一步调整,还有更多的验证空间可以挖掘。但与独立运行相比,当时应用程序的核心功能根本无法工作,改进的效果是显而易见的。

6.迭代harness

第一组测试结果令人兴奋,但同时也显得笨重、缓慢且成本高昂。合理的下一步是寻找简化测试框架的方法,同时不降低其性能。这既是常识使然,也遵循一个更普遍的原则:测试框架中的每个组件都编码了关于模型自身无法完成之事的假设,而这些假设值得进行压力测试——既因为它们可能不正确,也因为在模型改进时这些假设会迅速过时。我们博客文章《构建高效智能体》将核心理念概括为"寻找尽可能简单的解决方案,仅在需要时增加复杂性",对于任何维护智能体测试框架的人来说,这都是一个反复出现的模式。

在首次简化尝试中,我大幅削减了测试框架并尝试了几个创新想法,但未能复现原始版本的性能。同时,我也难以分辨测试框架设计中哪些部分真正起关键作用,以及具体如何发挥作用。基于这次经验,我转向了更系统化的方法:每次只移除一个组件,并评估其对最终结果的影响。

在进行这些迭代周期的同时,我们还发布了 Opus 4.6 版本,这进一步激励我们降低工具链的复杂性。我们有充分理由预期 4.6 版本所需的脚手架会比 4.5 版本更少。正如我们在发布博客中所说:“[Opus 4.6] 规划更周密,能更持久地维持智能体任务,在大型代码库中运行更可靠,并具备更优的代码审查和调试能力以自行发现错误。”该版本在长上下文检索方面也有显著提升。这些正是我们构建工具链旨在增强的能力。

7.移除冲刺结构

我首先完全移除了冲刺周期这一概念。冲刺结构原本有助于将工作分解为小块,以便模型能够连贯地处理。考虑到 Opus 4.6 版本的改进,我们有充分理由相信模型能够在不进行此类分解的情况下,原生地胜任这项工作。

我保留了规划器和评估器,因为两者都持续带来显著价值。若没有规划器,生成器的工作范围会不足:面对原始提示时,它会直接开始构建而不先规划工作内容,最终开发出的应用程序功能丰富度将低于规划器所设计的版本。

随着冲刺结构的取消,我将评估环节移至运行结束时一次性进行,而非每个冲刺阶段都进行评分。由于模型能力大幅提升,评估器在某些运行中的重要性发生了变化——其效用取决于任务难度相对于模型独立可靠完成能力的边界位置。在 4.5 版本中,这个边界非常接近:我们的构建任务正好处于生成器独立运作的能力临界点,评估器能发现整个构建过程中存在的实质性问题。到了 4.6 版本,模型的原始能力得到增强,边界随之向外扩展。许多原本需要评估器核查才能确保连贯性的任务,现在已落入生成器独立处理良好的范围;对于边界内的任务,评估器反而成了不必要的开销。但对于那些仍处于生成器能力边界的构建环节,评估器依然能提供实质性的提升作用。

实际意义在于,评估并非一个固定的“是或否”决策。当任务超出当前模型独立可靠完成的范围时,付出评估成本是值得的。

在结构简化的同时,我还增加了提示功能,以改进工具链如何将 AI 功能构建到每个应用中——具体而言,是让生成器构建出能够通过工具驱动应用自身功能的智能体。这需要真正的迭代过程,因为相关知识较新,Claude 的训练数据对此覆盖有限。但经过充分调优后,生成器已能正确构建智能体。

8.harness结构更新后的结果

为了测试更新后的测试框架,我使用了以下提示来生成一个数字音频工作站(DAW),这是一个用于作曲、录音和混音的音乐制作程序: “使用 Web Audio API 在浏览器中构建功能齐全的数字音频工作站。”

运行过程仍然漫长且昂贵,花费了大约 4 个小时和 124 美元的 token 成本。

大部分时间花在了构建器上,它连贯运行了两个多小时,没有出现 Opus 4.5 所需的冲刺分解。

智能体 & 阶段时长成本
计划者 (Planner)4.7 分钟$0.46
构建 (第1轮)2 小时 7 分钟$71.08
QA (第1轮)8.8 分钟$3.24
构建 (第2轮)1 小时 2 分钟$36.89
QA (第2轮)6.8 分钟$3.09
构建 (第3轮)10.9 分钟$5.88
QA (第3轮)9.6 分钟$4.06
整体 V2 框架3 小时 50 分钟$124.70

与之前的测试框架类似,规划器将单行提示扩展为完整规范。从日志中可以看出,生成模型在规划应用程序和代理设计、连接代理以及移交 QA 前进行测试方面都表现出色。

话虽如此,质量保证代理仍然发现了真正的漏洞。在其第一轮反馈中,它指出:

这是一款功能强大的应用程序,具有出色的设计保真度、扎实的 AI 代理和良好的后端。主要不足之处在于功能完整性——虽然该应用看起来令人印象深刻,AI 集成也运行良好,但几个核心数字音频工作站功能仅为展示性质,缺乏交互深度:片段无法在时间轴上拖拽/移动,没有乐器 UI 面板(合成器旋钮、鼓垫),也没有视觉效果编辑器(均衡器曲线、压缩器仪表)。这些并非边缘情况——它们是使数字音频工作站可用的核心交互功能,而规格说明中已明确要求包含这些功能。

在其第二轮反馈中,它再次抓住了几个功能上的差距:

剩余漏洞:

  • 音频录制仍仅为存根(按钮可以切换但无法捕获麦克风)
  • 未实现通过拖动边缘调整剪辑大小和剪辑分割
  • 效果可视化是数字滑块,不是图形(没有 EQ 曲线)

生成器在自主运行时仍可能遗漏细节或功能存缺,而质量检测环节通过发现这些最终阶段问题供生成器修正,依然发挥着重要作用。

根据提示,我期待的是一个能创作旋律、和声与鼓点节奏,将其编排成曲,并在过程中获得集成智能体辅助的程序。下方视频展示了实际运行效果。

这款应用远非专业的音乐制作软件,智能体的歌曲创作能力显然还有很大提升空间。此外,克劳德实际上不具备听觉能力,这使得质量评估反馈在音乐品味方面的效果大打折扣。

但最终的应用程序具备了功能性音乐制作程序的所有核心部件:一个可运行在浏览器中的编曲视图、混音器和走带控制。除此之外,Claude 能够完全通过提示词拼接出一个简短的歌曲片段:智能体设置了速度和调号,铺下了旋律,构建了鼓轨,调整了混音器音量,并添加了混响。用于歌曲创作的核心原语都存在,智能体可以自主驱动它们,使用工具端到端地创建一个简单的作品。你可能会说它还不够完美——但它正在达到那个水平。

9.展望

随着模型性能持续提升,我们可以大致预期它们能够处理更长时间、更复杂的任务。在某些情况下,这意味着围绕模型构建的辅助框架会逐渐变得不那么重要,开发者可以等待下一代模型出现,看着某些问题自行解决。另一方面,模型越强大,就越有空间开发出能够完成超出模型基础能力的复杂任务的辅助系统。

基于这些思考,这项工作中有些经验值得延续。始终建议的做法是:针对您构建的模型进行实验,在实际问题上分析其运行轨迹,并调整性能以实现预期目标。处理更复杂的任务时,有时可以通过任务分解并为问题各方面配置专用智能体来提升空间。当新模型发布时,通常应重新审视评估框架,移除不再影响性能的冗余部分,并新增组件以实现以往难以达到的更强能力。

从这项工作中,我坚信随着模型性能的提升,有趣的应用组合空间并不会缩小。相反,它会不断迁移,而 AI 工程师的有趣任务正是持续发掘下一个新颖的组合方式。