信息压缩站-长文智能摘要的HarmonyOS开发实践
App27-信息压缩站:长文智能摘要的 HarmonyOS 开发实践
引言
信息爆炸时代,我们每天都在与海量文本打交道。一篇万字长文、一份百页报告、一段冗长的会议纪要——阅读它们需要消耗大量时间,而真正有价值的信息往往只占其中的 20% 甚至更少。据微软研究显示,自 2000 年以来,人类的平均注意力持续时间从 12 秒下降到了 8 秒,这意味着我们比任何时候都更需要高效的信息筛选工具。
「信息压缩站」正是在这样的背景下设计的——一款基于 HarmonyOS 的长文智能摘要应用。用户只需将长文内容粘贴到输入区域,选择摘要长度(一句话 / 短 / 中),点击生成按钮,系统便会输出结构化的摘要结果,包含摘要文本、关键要点编号列表和金句摘录三个维度。与传统的文本摘要工具不同,「信息压缩站」不仅关注「压缩」本身,更注重「信息密度」的保留——通过多维度输出结构,确保用户既能快速获取核心观点,又能深入理解原文的关键论据和精彩表达。
在 AI40 应用工具集矩阵中,App27-信息压缩站是典型的「AI 驱动型」应用。它采用了 Mock 数据先行、AI 接口预留的渐进式开发策略——当前版本通过三套按长度分级的预设 Mock 数据模拟 AI 摘要输出,同时在代码中保留了完整的 AI API 调用桩(Stub)模式,为后续接入鸿蒙原生 AI 能力或云端大模型服务做好了架构准备。这种设计模式在鸿蒙应用开发中具有广泛的参考价值,尤其适用于需要 AI 能力但尚处于原型验证阶段的项目。
本文将按照 6A 工作流(Align 对齐、Architect 架构、Atomize 原子化、Approve 审批、Automate 自动化执行、Assess 评估)来完整复盘「信息压缩站」的设计与开发过程,重点探讨长文摘要领域特有的数据建模挑战——三档长度分级策略、三维输出结构的信息密度设计、以及 AI API 调用桩(Stub)模式在 HarmonyOS 开发中的实践。文中将涉及 鸿蒙 ArkTS、鸿蒙Flutter框架 的对比分析,以及 鸿蒙PC 端适配的前瞻性讨论。希望能为同样在 HarmonyOS 生态中探索 AI 文本处理应用的开发者提供一些参考。
—

一、Align 对齐阶段:从模糊需求到精确规范
1.1 原始需求
「信息压缩站」的初始需求概括为:用户输入长文内容,选择摘要长度,系统返回结构化的摘要结果,包括摘要文本、关键要点和金句摘录。这个需求看似简单,但在对齐阶段,我们需要将模糊的「长文摘要」概念转化为精确的技术规范。
1.2 需求拆解与边界确认
在 Align 阶段,我们需要回答以下关键问题:
问题一:摘要长度如何分级?
这是整个系统最核心的设计决策。经过对用户阅读场景的调研,我们发现长文摘要的需求可以归纳为三个典型场景:
-
一句话(One-Sentence):用户只想快速了解文章的核心主旨,类似于论文的摘要或新闻的导语。适用场景:浏览大量文章时快速筛选、社交媒体分享时提取核心观点。输出要求:一句话(约 50-80 字)概括全文核心,不输出关键要点和金句摘录。
-
短摘要(Short):用户需要较为完整的文章梗概,了解主要论点和支撑论据。适用场景:工作汇报前的快速浏览、决策前的信息速览。输出要求:一段约 100-200 字的摘要 + 5 条关键要点 + 2 条金句摘录。
-
中摘要(Medium):用户需要深入理解文章的结构和详细内容,适用于深度阅读前的预读。适用场景:学术研究、深度报道的快速理解。输出要求:多段详细摘要(约 300-500 字)+ 5 条关键要点 + 3 条金句摘录。
这三个级别的划分并非随意,而是基于认知心理学中的「信息渐进式获取」模型:从一句话到短摘要再到中摘要,信息密度逐渐增加,用户可以根据自己的时间预算和需求深度选择适合的级别。
问题二:输出结构如何设计?
摘要结果不应该只是一段扁平化的文字,而应该是一个多维度的信息结构。经过分析,我们确定了三维输出结构:
- 摘要(Summary):对原文的核心内容进行概括性描述,保留关键论点和核心结论。这是用户获取信息的最主要入口。
- 关键要点(Key Points):以编号列表形式提取原文的核心论据和关键数据点。每一条要点都是独立的信息单元,用户可以快速浏览并判断是否需要深入阅读原文。
- 金句摘录(Quotes):提取原文中最具代表性的精彩语句或重要引述。这些金句既可以作为社交分享的素材,也可以帮助用户记住文章的核心表达。
三个维度分别对应三种信息需求:「是什么」(摘要)、「为什么」(关键要点)、「怎么表达的」(金句摘录)。这种结构设计确保了对原文信息的多层次覆盖。
问题三:三个长度级别的内容差异化如何实现?
不同长度级别的内容差异不仅仅是「字数不同」,而应该体现在信息结构的完整性上:
| 长度级别 | 摘要字数 | 关键要点 | 金句摘录 | 信息密度 | 适用场景 |
|---|---|---|---|---|---|
| 一句话 | 50-80 字 | 无 | 无 | 最高 | 快速筛选、社交分享 |
| 短 | 100-200 字 | 5 条 | 2 条 | 中等 | 工作速览、决策参考 |
| 中 | 300-500 字 | 5 条 | 3 条 | 较低 | 深度预读、学术研究 |
值得注意的是,从短到中,摘要的长度增加了 2-3 倍,关键要点保持不变(都是 5 条),但每条要点的详略有显著差异——短摘要的要约 20-30 字,中摘要的要约 30-50 字,包含更多具体数据和细节。金句摘录从 2 条增加到 3 条。
问题四:AI 模型调用策略如何设计?
当前的实现采用 Mock 数据,但架构设计上预留了 AI API 调用接口。在 Align 阶段,我们需要明确 AI 调用的策略:
- Prompt 结构:System Prompt 定义摘要专家的角色和输出规范,User Prompt 包含原文内容和长度要求。
- 输出格式:要求 LLM 返回严格的 JSON 结构,包含
summary(字符串)、points(字符串数组)、quotes(字符串数组)三个字段。 - 温度参数:Temperature 设置为 0.3,因为摘要生成需要较高的确定性和一致性,减少随机性。
- 长度控制:通过 Prompt 中的长度指令控制输出字数,而非事后截断,确保摘要的语义完整性。
- 兜底策略:当 AI API 调用失败或超时时,回退到预置的 Mock 数据,确保系统始终可用。
这种「AI API 调用桩(Stub)模式」是 HarmonyOS AI 应用开发中的重要实践模式:在开发阶段使用 Mock 数据快速验证 UI 和交互逻辑,在集成阶段替换为真实的 API 调用,两者共享相同的接口契约,实现平滑过渡。
问题五:异常情况如何处理?
当用户未输入任何内容直接点击「生成」按钮时,系统需要给出明确的响应。我们设计了输入校验逻辑:如果输入内容为空(去除首尾空格后长度为 0),则隐藏结果区域,避免 UI 展示空白内容。这种「静默拒绝」的策略比弹出错误提示对话框更符合移动端交互的轻量级原则。
1.3 数据模型定义
基于以上分析,我们在对齐阶段定义了核心数据模型:
interface CompressResult {
summary: string; // 摘要文本
points: string[]; // 关键要点数组
quotes: string[]; // 金句摘录数组
}
这个接口设计的核心考量是「三维输出」的语义区分:summary 是连续文本,points 是离散的要点列表,quotes 是原文中提取的精彩语句。三个字段的语义和用途各不相同,因此没有将它们合并为一个扁平数组,而是保持了结构化的区分。
在 ArkTS 中,interface 的定义必须紧凑,不能使用条件类型别名、映射类型、交叉类型等高级特性。CompressResult 的三个字段中,summary 是 string 类型,points 和 quotes 是 string[] 类型,没有使用 any 或 unknown,符合 ArkTS 的语法约束。同时,ArkTS 不支持对象类型中的调用签名和构造函数签名,因此 CompressResult 的设计保持纯粹的「数据契约」角色。
1.4 ArkTS 严苛模式下的技术约束
在 Align 阶段,必须明确 HarmonyOS 的 ArkTS 语言对开发实践的约束。ArkTS 是 TypeScript 的严格子集,舍弃了许多动态特性以确保编译时类型安全和运行时性能。以下是本项目必须遵守的关键约束:
| 约束项 | 说明 | 对本项目的影响 |
|---|---|---|
禁止 any/unknown 类型 |
所有类型必须显式声明 | 所有接口、参数、返回值必须有明确类型标注 |
| 禁止解构赋值/解构声明 | 必须使用临时变量逐字段操作 | 数据传递时不能使用 const { a, b } = obj |
禁止 for..in 循环 |
必须使用常规 for 循环或 ForEach |
遍历数组时使用 ForEach 组件方法 |
禁止 var 关键字 |
必须使用 let |
所有变量声明使用 let |
禁止索引访问 obj["key"] |
必须使用 obj.key 语法 |
访问对象属性时使用点语法 |
| 禁止函数表达式 | 必须使用箭头函数 | 回调全部使用 (): void => {} 形式 |
| 禁止嵌套函数 | 必须使用 lambda | 函数内不再定义 function,改用箭头函数 |
禁止 typeof 用于类型标注 |
必须显式声明类型 | 不使用 typeof someVar 作为类型 |
禁止 is 运算符 |
必须使用 instanceof |
类型判断使用 instanceof |
| Scroll 组件单子节点约束 | Scroll 内只能有一个直接子组件 |
使用 Column 包裹所有子元素 |
禁止 # 私有标识符 |
必须使用 private 关键字 |
私有成员使用 private 修饰符 |
| 禁止对象字面量直接作为类型 | 必须显式声明类和接口 | 所有数据类型通过 interface 定义 |
1.5 验收标准
基于以上分析,制定以下可测试的验收标准:
| 编号 | 验收项 | 验收标准 | 验证方式 |
|---|---|---|---|
| AC-01 | 文本输入 | 支持在 TextInput 中输入长文内容,支持中文输入 | 手动输入测试 |
| AC-02 | 长度切换 | 三个长度选项按钮可独立选中,高亮状态正确切换 | 点击各按钮验证 |
| AC-03 | 摘要生成 | 点击生成按钮后,根据选中长度级别展示对应 Mock 数据 | 逐级验证输出 |
| AC-04 | 摘要展示 | 摘要文本以白色卡片形式展示,字体大小 14sp | 视觉验证 |
| AC-05 | 要点展示 | 关键要点以编号列表形式展示,编号连续递增,蓝色标注 | 视觉验证 |
| AC-06 | 金句展示 | 金句摘录以斜体形式展示,浅黄色背景,橙色引号 | 视觉验证 |
| AC-07 | 结果区域滚动 | 当中摘要内容超出屏幕高度时,可滚动查看全部内容 | 中模式验证 |
| AC-08 | 空状态处理 | 未输入内容时点击生成,不显示结果区域 | 初始状态检查 |
| AC-09 | 返回导航 | 点击返回按钮可调用 router.back() 返回上一页 | 导航测试 |
| AC-10 | ArkTS 编译通过 | 零编译错误、零警告 | hvigor 构建验证 |
| AC-11 | AI 接口预留 | 代码中存在注释的 AI API 调用桩,结构完整可取消注释启用 | 代码审查 |
二、Architect 架构阶段:从规范到系统设计
2.1 整体架构
「信息压缩站」的架构采用三层模型:UI 交互层、状态管理层、数据生成层。
┌────────────────────────────────────────────────────────────┐
│ ArkUI 层 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 顶部导航栏(返回按钮 + 标题「信息压缩站」) │ │
│ ├──────────────────────────────────────────────────────┤ │
│ │ 长文内容输入区(TextInput,多行输入,120vp 高度) │ │
│ ├──────────────────────────────────────────────────────┤ │
│ │ 摘要长度选择区(三个 Capsule 按钮,单选切换) │ │
│ │ [一句话] [短] [中] │ │
│ ├──────────────────────────────────────────────────────┤ │
│ │ 「生成」按钮(蓝色圆角,居中,60% 宽度) │ │
│ ├──────────────────────────────────────────────────────┤ │
│ │ 结果展示区(条件渲染,Scroll 包裹,垂直排列) │ │
│ │ ┌────────────────────────────────────────────────┐ │
│ │ │ 摘要卡片(白色底,14sp 文本) │ │
│ │ │ 关键要点列表(编号列表,蓝色数字) │ │
│ │ │ 金句摘录列表(浅黄底,斜体,橙色引号) │ │
│ │ └────────────────────────────────────────────────┘ │
│ └──────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────┐
│ 状态管理层(@State) │
│ inputArticle, selectedLength, showResult, │
│ resultSummary, resultPoints, resultQuotes │
└────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────┐
│ 数据生成层 │
│ generateMockData(): 输入校验 → 长度判断 → 条件分支 → 赋值 │
│ callAIAPI(): 预留,Prompt 构建 → API 调用 → JSON 解析 │
└────────────────────────────────────────────────────────────┘
2.2 状态管理的扁平化设计
在状态管理方面,我们面临一个设计选择:是使用一个 CompressResult 对象来管理三个结果字段,还是使用三个独立的 @State 变量?
方案 A(对象管理):
@State currentResult: CompressResult = {
summary: '',
points: [],
quotes: []
};
方案 B(独立字段):
@State resultSummary: string = '';
@State resultPoints: string[] = [];
@State resultQuotes: string[] = [];
最终我们选择了方案 B。原因有三点:
-
ArkTS 状态更新粒度:
@State装饰的对象在属性变更时,需要整体替换对象才能触发 UI 刷新。如果使用方案 A,每次更新一个字段都需要重新构造整个对象,增加了不必要的代码和内存分配。信息压缩站的三维结果(摘要、要点、金句)在 UI 中是完全独立的区块,各自有不同的渲染逻辑和样式,使用独立字段让每个区域的更新更加清晰。 -
条件渲染友好:关键要点和金句摘录在「一句话」模式下不显示,使用独立字段配合
if (this.resultPoints.length > 0)和if (this.resultQuotes.length > 0)的条件判断更加直观,不需要额外判断对象是否为空。 -
调试友好:在调试时,独立的
@State变量可以直接在 DevTools 中查看和修改,而对象属性则需要展开后才能看到细节。对于三个不同语义的字段,独立管理可以更快定位问题。
这种「扁平化状态管理」模式在 HarmonyOS 开发中是一个值得关注的设计实践:当 UI 区域之间相互独立时,将状态变量扁平化优于嵌套对象。这在 鸿蒙PC 端适配中尤为重要——桌面端屏幕更大,UI 区域可能采用不同的布局方案(如要点和金句放在摘要两侧),独立的状态变量使得布局调整不会影响数据流的稳定性。
2.3 长度选择器的设计
长度选择器使用了三个 ButtonType.Capsule 按钮,通过 ForEach 循环渲染:
@State selectedLength: string = '短';
@State lengthOptions: string[] = ['一句话', '短', '中'];
Row() {
ForEach(this.lengthOptions, (item: string, index: number) => {
Button(item)
.fontSize(14)
.type(ButtonType.Capsule)
.backgroundColor(this.selectedLength === item ? '#007AFF' : '#E8E8E8')
.fontColor(this.selectedLength === item ? '#FFFFFF' : '#333333')
.margin({ left: 8, right: 8 })
.onClick(() => { this.selectedLength = item; })
})
}
这里有几个设计细节值得关注:
-
Capsule 按钮形状:
ButtonType.Capsule是 HarmonyOS 提供的药丸形状按钮,圆角较大,视觉上比矩形按钮更柔和,适合作为选项标签使用。在 鸿蒙Flutter框架 中,类似的胶囊按钮需要自定义BorderRadius来实现,而在 ArkUI 中,原生组件直接提供了这一样式,减少了自定义样式的工作量。 -
选中态切换:通过
this.selectedLength === item判断当前按钮是否被选中,选中时使用主题蓝色#007AFF,未选中时使用浅灰色#E8E8E8。这种「亮色选中 / 灰色未选」的视觉模式在移动端应用中广泛使用,用户认知成本低。 -
默认选中「短」:
selectedLength初始值为'短',因为短摘要是最常用的场景——既能快速了解文章核心,又能获取关键要点和金句,信息密度和阅读效率达到最佳平衡。 -
ForEach 的 key 策略:在这个场景中,
lengthOptions的元素是固定的三个字符串,不会动态增删,因此可以使用默认的 index 作为 key。但如果lengthOptions可能动态变化,建议使用item本身作为 key。
2.4 结果区域的色彩编码设计
三个结果区域使用了不同的颜色方案,形成视觉层次:
| 区域 | 背景色 | 文字色 | 色彩语义 | 视觉权重 |
|---|---|---|---|---|
| 摘要 | #FFFFFF(白色) | #333333 | 中性、清晰、主体信息 | 最高 |
| 关键要点 | #FFFFFF(白色) | #333333(正文)+ #007AFF(编号) | 结构化、条理清晰 | 中等 |
| 金句摘录 | #FFF8E1(浅黄) | #666666(正文)+ #FF9500(引号) | 温暖、人文、点睛之笔 | 较低 |
这种色彩编码设计遵循了信息设计中的「视觉层次」原则:摘要作为主体信息,使用白色底和深色文字,保持最高的可读性;关键要点通过蓝色编号吸引注意力,帮助用户快速扫描;金句摘录使用浅黄色背景和橙色引号,营造温暖的人文气息,同时降低视觉权重(灰色文字),避免与摘要和要点争夺注意力。
这种色彩策略在 HarmonyOS 的 鸿蒙Flutter框架 和原生 ArkUI 中都可以方便地实现,但在 ArkUI 中,由于不需要额外的跨平台抽象层,颜色渲染的性能更优——这在后续的 鸿蒙PC 端适配中尤其重要,因为桌面端屏幕更大,色彩细节更丰富,对渲染性能的要求也更高。
2.5 AI API 调用桩(Stub)模式
作为 MVP 版本,「信息压缩站」当前使用 Mock 数据,但架构上预留了完整的 AI API 调用接口。这种「Stub 模式」的核心思想是:
// 当前实现:Mock 数据生成
generateMockData(): void {
if (this.inputArticle.trim().length === 0) {
this.showResult = false;
return;
}
this.showResult = true;
if (this.selectedLength === '一句话') {
this.resultSummary = '...';
this.resultPoints = [];
this.resultQuotes = [];
} else if (this.selectedLength === '短') {
this.resultSummary = '...';
this.resultPoints = ['...', '...', '...', '...', '...'];
this.resultQuotes = ['...', '...'];
} else {
this.resultSummary = '...';
this.resultPoints = ['...', '...', '...', '...', '...'];
this.resultQuotes = ['...', '...', '...'];
}
}
// 未来实现:AI API 调用(预留接口)
// async callAIAPI(): Promise<void> {
// const prompt: string = this.buildPrompt();
// try {
// const response = await fetch('https://api.example.com/summarize', {
// method: 'POST',
// header: { 'Content-Type': 'application/json' },
// extraData: JSON.stringify({
// text: this.inputArticle,
// length: this.selectedLength
// })
// });
// const data: CompressResult = await response.json();
// this.resultSummary = data.summary;
// this.resultPoints = data.points;
// this.resultQuotes = data.quotes;
// } catch (error) {
// // 兜底:回退到 Mock 数据
// this.generateMockData();
// }
// }
Stub 模式的关键优势在于:
-
接口契约共享:
generateMockData()和callAIAPI()都将结果写入相同的三个@State变量,UI 层不需要任何修改。这意味着从 Mock 到真实 API 的切换是「零 UI 改动」的。 -
渐进式集成:在开发阶段,可以先使用 Mock 数据验证 UI 交互和状态流转;在集成测试阶段,逐步替换为真实 API 调用;在生产环境中,保留 Mock 数据作为 API 调用失败时的兜底方案。
-
可测试性:Mock 数据和 AI API 共享相同的
CompressResult接口,单元测试可以针对 Mock 数据编写,集成测试可以针对 API 调用编写,两者互不干扰。 -
Prompt 与 UI 解耦:在 Stub 阶段,Mock 数据的内容是人工设计的,可以精确控制输出质量和格式。当切换到真实 AI 模型时,Prompt 的调优成为独立的工作流,不影响 UI 层的开发进度。
这种 Stub 模式在 HarmonyOS AI 应用开发中具有普适性。对于大多数 AI 应用来说,UI 开发与 AI 接口调试往往是并行的——前端需要一个「看起来像真的」数据来设计和验证 UI,后端需要时间来调优 Prompt 和模型参数。Stub 模式让两者可以独立推进,互不阻塞。在 鸿蒙PC 端场景中,由于桌面端对 AI 能力的期待更高(如实时流式输出、长文本处理),Stub 模式的这种解耦特性尤为重要——可以先在移动端验证核心交互,再逐步扩展到桌面端的复杂场景。
三、Atomize 原子化阶段:任务分解与执行
3.1 原子任务分解
在 Atomize 阶段,我们将整个开发任务分解为以下原子单元:
| 序号 | 原子任务 | 依赖 | 预估工时 |
|---|---|---|---|
| A1 | 定义 CompressResult 接口 | 无 | 3min |
| A2 | 编写 3 个长度级别的 Mock 数据(含摘要、要点、金句) | A1 | 30min |
| A3 | 实现长文内容输入区 UI(TextInput) | 无 | 10min |
| A4 | 实现摘要长度选择器 UI(Capsule 按钮组) | 无 | 10min |
| A5 | 实现 Mock 数据生成逻辑(输入校验 + 长度判断 + 条件分支) | A1, A2 | 15min |
| A6 | 实现三维结果展示区 UI(摘要卡片 + 要点列表 + 金句列表) | A1 | 25min |
| A7 | 实现输入校验逻辑(空内容检测) | A5 | 5min |
| A8 | 实现顶部导航栏(返回按钮 + 标题) | 无 | 10min |
| A9 | 预留 AI API 调用桩接口 | A1 | 10min |
| A10 | 整体 UI 整合与样式调优 | A3-A8 | 15min |
3.2 依赖关系图
A1 (CompressResult 接口)
├── A2 (Mock 数据设计)
│ └── A5 (generateMockData 方法)
├── A9 (AI API Stub)
└── A6 (结果展示区 UI)
A3 (输入区 UI) ──┐
A4 (选择器 UI) ──┤
A8 (导航栏) ──┼── A10 (整体整合)
A5 (生成逻辑) ──┤
A6 (结果区 UI) ──┤
A7 (输入校验) ──┘
3.3 关键原子任务详解
A2:三级 Mock 数据设计
Mock 数据的设计是整个应用最核心的部分。每个长度级别需要覆盖三个维度,且内容需要体现该级别的独特策略。
「一句话」级别只输出摘要文本,不输出要点和金句——这是最精简的模式,适用于快速筛选场景。精选了一条约 60 字的摘要,概括了 AI 技术的核心价值与挑战。
「短」级别输出约 150 字的摘要 + 5 条关键要点 + 2 条金句摘录。这是最常用的模式,信息密度适中,既能快速了解文章核心,又能获取关键论据。5 条要点覆盖了 AI 产业落地、医疗应用、教育应用、金融应用和经济影响五个维度,每条要点 20-30 字,包含具体的数据支撑。
「中」级别输出约 400 字的详细摘要 + 5 条更详细的要点 + 3 条金句摘录。摘要从单段扩展为多段,加入了空行分隔,提升了可读性。要点从 20-30 字扩展到 30-50 字,每条要点的数据更加具体(如「诊断准确率 95%+」「学习效率+40%」「风控效率+300%」)。金句从 2 条增加到 3 条,增加了关于隐私保护的引述。
A5:Mock 数据生成逻辑
generateMockData() 方法的核心逻辑是一个三路条件分支,根据 selectedLength 的值选择对应的 Mock 数据。方法首先进行输入校验,如果输入为空则隐藏结果区域并直接返回。这种「早期返回」模式避免了不必要的嵌套,提高了代码的可读性。
generateMockData(): void {
if (this.inputArticle.trim().length === 0) {
this.showResult = false;
return;
}
this.showResult = true;
if (this.selectedLength === '一句话') {
this.resultSummary = '...';
this.resultPoints = [];
this.resultQuotes = [];
} else if (this.selectedLength === '短') {
this.resultSummary = '...';
this.resultPoints = ['...', '...', '...', '...', '...'];
this.resultQuotes = ['...', '...'];
} else {
this.resultSummary = '...';
this.resultPoints = ['...', '...', '...', '...', '...'];
this.resultQuotes = ['...', '...', '...'];
}
}
四、Approve 审批阶段:代码审查与质量门控
4.1 代码质量审查
在 Approve 阶段,对代码进行全面的质量审查,重点关注以下维度:
4.1.1 ArkTS 语法合规性
审查确认所有代码均符合 ArkTS 严苛模式要求:
- 无
any/unknown类型使用:所有接口字段、方法参数、返回值均显式标注类型。CompressResult接口的三个字段分别为string和string[],generateMockData()方法返回类型为void。 - 无解构赋值:数据传递使用点语法逐字段访问。
- 无
var关键字:所有变量声明使用let,但本项目中没有独立的let变量声明,所有状态变量使用@State装饰器。 - 无
for..in循环:数组遍历统一使用ForEach组件方法。 - 无索引访问:对象属性访问使用
obj.field语法。 - 无函数表达式:所有回调使用箭头函数
() => {}。例如onClick(() => { this.selectedLength = item; })。 - 无嵌套函数:
generateMockData()方法内部没有嵌套函数定义。 - Scroll 组件内只有一个直接子组件
Column,符合 ArkUI 的 Scroll 单子节点约束。
4.1.2 组件结构审查
审查确认 build() 方法的组件树结构清晰合理:
Column (根容器)
├── Row (Header - 导航栏)
│ ├── Button "← 返回"
│ └── Text "信息压缩站"
└── Scroll (可滚动内容区)
└── Column (Scroll 唯一子节点)
├── Text "长文内容" (输入标签)
├── TextInput (长文输入)
├── Text "摘要长度" (选择标签)
├── Row (长度选择器)
│ └── ForEach → Button × 3
├── Button "生成"
└── if (showResult) → Column (结果区域)
├── Text "摘要" + Text (摘要内容)
├── if (points.length > 0) → Column (要点区域)
│ ├── Text "关键要点"
│ └── ForEach → Row × N
└── if (quotes.length > 0) → Column (金句区域)
├── Text "金句摘录"
└── ForEach → Row × N
4.1.3 状态管理审查
审查确认所有状态变量的使用符合 ArkUI 声明式范式:
- 状态变量仅在
@State声明时初始化,在方法中通过this.xxx = value赋值触发 UI 更新。 - 不存在直接修改状态变量内部属性的情况(如
this.resultPoints.push()),所有修改都通过整体赋值完成。 showResult作为条件渲染的开关,在generateMockData()方法中统一设置。selectedLength的默认值'短'与lengthOptions数组中的值一致,确保不会出现选中状态与实际值不匹配的情况。
4.1.4 条件渲染正确性审查
审查确认条件渲染逻辑正确:
- 初始状态:
showResult为false,结果区域不渲染。 - 输入为空时点击生成:
generateMockData()将showResult设置为false,结果区域隐藏。 - 输入非空时点击生成:
generateMockData()将showResult设置为true,结果区域渲染。 - 关键要点区域:仅在
resultPoints.length > 0时渲染,对应「一句话」模式下的无要点场景。 - 金句摘录区域:仅在
resultQuotes.length > 0时渲染,同样对应「一句话」模式下的无金句场景。
4.2 Mock 数据质量审查
审查确认 Mock 数据覆盖了三个长度级别,且各级别的数据丰富度与长度级别成正比:
| 长度级别 | 摘要字数 | 要点数 | 金句数 | 数据特征 |
|---|---|---|---|---|
| 一句话 | ~60 字 | 0 | 0 | 极致精简,一句话概括核心 |
| 短 | ~150 字 | 5 | 2 | 标准摘要,覆盖五大维度 |
| 中 | ~400 字 | 5 | 3 | 详细摘要,多段结构,数据详实 |
Mock 数据以「人工智能技术发展」为主题,覆盖了医疗、教育、金融三大应用领域,以及数据隐私、算法偏见、就业冲击三大挑战,内容具有代表性且贴近真实场景。要点包含具体的数据指标(如「95%+」「+40%」「300%」「15 万亿美元」「4-8 亿」),增强了演示的可信度。
4.3 质量门控结果
| 检查项 | 状态 | 备注 |
|---|---|---|
| ArkTS 编译零错误 | 通过 | 所有语法符合 ArkTS 严苛模式 |
| 接口定义完整性 | 通过 | CompressResult 接口字段完整 |
| 状态管理规范性 | 通过 | @State 变量声明和赋值符合范式 |
| Mock 数据真实性 | 通过 | 三级覆盖,数据贴近真实场景 |
| AI Stub 完整性 | 通过 | 请求/响应结构完整,可快速启用 |
| UI 样式一致性 | 通过 | 蓝色主色调统一,卡片风格一致 |
| 条件渲染正确性 | 通过 | showResult 初始为 false,生成后为 true |
| 边界条件处理 | 通过 | 空输入不显示结果,一点通有要点/金句为空处理 |
| Scroll 滚动正确性 | 通过 | 中模式内容可完整滚动 |
五、Automate 自动化执行阶段:代码实现细节
5.1 核心实现——数据模型与状态声明
信息压缩站的数据层由一个接口和七个状态变量构成,代码实现在文件顶部集中声明:
import { router } from '@kit.ArkUI';
interface CompressResult {
summary: string;
points: string[];
quotes: string[];
}
@Entry
@Component
struct InfoCompressor {
@State inputArticle: string = '';
@State selectedLength: string = '短';
@State lengthOptions: string[] = ['一句话', '短', '中'];
@State showResult: boolean = false;
@State resultSummary: string = '';
@State resultPoints: string[] = [];
@State resultQuotes: string[] = [];
这段代码展示了 ArkTS 的几个关键规范:
-
接口声明:
interface CompressResult定义了 AI 输出的数据契约。三个字段分别对应摘要、要点和金句。注意 ArkTS 不支持interface中的构造函数签名、调用签名和索引签名,只支持纯粹的属性声明。 -
@State 装饰器:七个状态变量必须在声明时初始化,类型必须显式标注。ArkTS 不支持
let v!: T形式的确定性赋值断言,因此所有@State变量必须有初始值。 -
import 语句:
import { router } from '@kit.ArkUI'必须放在文件最顶部,在所有其他语句之前。ArkTS 不支持require导入和import赋值,也不支持模块名称中的通配符。 -
@Entry 和 @Component:
@Entry标记该组件为页面入口,@Component标记为自定义组件。struct关键字用于定义组件结构体,ArkTS 不支持将类用作对象或直接赋值给变量。
5.2 核心实现——Mock 数据生成逻辑
generateMockData() 是信息压缩站的核心业务逻辑方法,负责根据用户输入和长度选择生成对应的 Mock 摘要数据:
generateMockData(): void {
if (this.inputArticle.trim().length === 0) {
this.showResult = false;
return;
}
this.showResult = true;
if (this.selectedLength === '一句话') {
this.resultSummary = '人工智能技术正从实验室走向产业落地,在医疗、教育、金融等领域创造巨大价值,但同时也面临数据隐私、算法偏见和就业冲击等严峻挑战。';
this.resultPoints = [];
this.resultQuotes = [];
} else if (this.selectedLength === '短') {
this.resultSummary = '人工智能技术正加速从实验室走向产业应用...';
this.resultPoints = [
'AI技术已进入产业落地阶段,在医疗、教育、金融三大领域应用最广泛',
'医疗AI可辅助诊断准确率提升至95%以上,但需解决数据隐私问题',
'教育AI实现个性化学习路径,但需警惕算法偏见对学生评价的影响',
'金融AI风控效率提升300%,但"黑箱"模型存在监管难题',
'预计2030年AI对全球经济贡献超15万亿美元,但可能导致8亿岗位被替代'
];
this.resultQuotes = [
'"AI不是要取代人类,而是增强人类的能力。"——李飞飞',
'"我们需要的不是更聪明的AI,而是更负责任的AI。"——业内人士'
];
} else {
this.resultSummary = '人工智能技术正在经历从理论研究到产业落地的关键转折期...';
this.resultPoints = [
'AI产业落地关键期:医疗(诊断准确率95%+)、教育(学习效率+40%)、金融(风控效率+300%)',
'数据隐私:GDPR和《个人信息保护法》对AI数据处理提出严格要求',
'算法偏见:可能导致不公平决策,需建立审计机制',
'就业冲击:预计2030年4-8亿岗位被替代,需完善再就业培训体系',
'全球竞争:中美欧均将AI列为国家战略,投入持续加大'
];
this.resultQuotes = [
'"AI不是要取代人类,而是增强人类的能力。"——李飞飞',
'"我们需要的不是更聪明的AI,而是更负责任的AI。"——业内人士',
'"数据是AI的燃料,但隐私是AI的刹车。"——隐私保护专家'
];
}
}
核心设计要点:
-
早期返回模式:输入校验放在方法开头,如果输入为空则直接返回,避免后续的无效操作。这种模式在 ArkTS 中尤为重要,因为
@State变量的赋值会触发 UI 重新渲染,减少不必要的状态更新可以提升性能。 -
三路条件分支:使用
if-else if-else结构处理三个长度级别,每个分支独立设置三个结果变量。这种结构清晰直观,便于后续扩展新的长度级别——只需在lengthOptions数组中添加选项,在generateMockData()中添加对应的分支即可。 -
空数组处理:「一句话」模式下,
resultPoints和resultQuotes显式设置为空数组[],配合 UI 层的if (this.resultPoints.length > 0)条件判断,确保不渲染空白区域。 -
数据一致性:三个级别的 Mock 数据共享同一主题(AI 技术),但信息密度和细节程度逐级递增。从一个级别切换时,用户看到的是同一主题的不同粒度呈现,而非完全不同的内容。
5.3 核心实现——输入区域 UI
输入区域由标签文本和 TextInput 组件组成,支持长文输入:
Text('长文内容')
.fontSize(16)
.fontWeight(FontWeight.Medium)
.width('100%')
.padding({ left: 16, top: 16 })
TextInput({ placeholder: '请输入或粘贴长文内容...', text: this.inputArticle })
.height(120)
.width('100%')
.padding(12)
.backgroundColor('#FFFFFF')
.borderRadius(8)
.onChange((value: string) => { this.inputArticle = value; })
.margin({ left: 16, right: 16 })
设计要点:
-
高度设置:
height(120)设置为 120vp,约为 5-6 行文本的显示区域,既能容纳一定长度的输入,又不会占用过多屏幕空间。在中摘要模式下,结果区域内容较多,120vp 的输入区域高度是一个合理的折中。 -
双向绑定:
text: this.inputArticle绑定状态变量,onChange回调更新状态变量,实现了文本输入的双向同步。ArkTS 的声明式数据绑定机制确保了 UI 和状态始终一致。 -
Placeholder 提示:
placeholder: '请输入或粘贴长文内容...'提供了明确的操作指引,降低用户的使用门槛。提示文本中的「粘贴」一词暗示了该应用支持从剪贴板粘贴内容,这是移动端长文输入的主要场景。 -
圆角和边距:
borderRadius(8)和margin设置使输入区域与整体 UI 风格保持一致,8vp 的圆角是 HarmonyOS 设计规范中推荐的卡片圆角值。
5.4 核心实现——结果区域 UI
结果区域是信息压缩站的核心展示层,采用条件渲染 + 三维垂直布局:
if (this.showResult) {
Column() {
Text('摘要')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.width('100%')
.padding({ left: 16, top: 8, bottom: 4 })
Text(this.resultSummary)
.fontSize(14)
.fontColor('#333333')
.width('100%')
.padding(12)
.backgroundColor('#FFFFFF')
.borderRadius(8)
.margin({ left: 16, right: 16, bottom: 12 })
if (this.resultPoints.length > 0) {
Text('关键要点')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.width('100%')
.padding({ left: 16, top: 4, bottom: 4 })
ForEach(this.resultPoints, (item: string, index: number) => {
Row() {
Text((index + 1) + '. ')
.fontSize(13)
.fontColor('#007AFF')
.fontWeight(FontWeight.Bold)
Text(item)
.fontSize(13)
.fontColor('#333333')
}
.width('100%')
.padding(10)
.backgroundColor('#FFFFFF')
.borderRadius(4)
.margin({ left: 16, right: 16, bottom: 4 })
})
}
if (this.resultQuotes.length > 0) {
Text('金句摘录')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.width('100%')
.padding({ left: 16, top: 12, bottom: 4 })
ForEach(this.resultQuotes, (item: string, index: number) => {
Row() {
Text('"')
.fontSize(18)
.fontColor('#FF9500')
.fontStyle(FontStyle.Italic)
Text(item)
.fontSize(13)
.fontColor('#666666')
.fontStyle(FontStyle.Italic)
}
.width('100%')
.padding(10)
.backgroundColor('#FFF8E1')
.borderRadius(4)
.margin({ left: 16, right: 16, bottom: 4 })
})
}
}
.width('100%')
}
设计要点:
-
三维结果分层展示:摘要卡片 → 关键要点列表 → 金句摘录列表,自上而下排列,符合用户从上到下的阅读习惯。每个区域有独立的标题和样式,视觉上明确区分了三个信息维度。
-
要点编号渲染:使用
(index + 1) + '. '动态生成编号文本,蓝色(#007AFF)加粗显示,与正文内容形成对比。编号从 1 开始连续递增,符合人类的计数习惯。 -
金句视觉设计:浅黄色背景(
#FFF8E1)传递温暖感,橙色引号(#FF9500)作为视觉锚点,斜体文字(FontStyle.Italic)营造引述的排版感,灰色正文(#666666)降低视觉权重。这种设计让金句区域在视觉上与其他区域形成明显区分,用户一眼就能识别出这是「引述」而非「正文」。 -
条件渲染的嵌套使用:外层
if (this.showResult)控制整体结果区域的显示,内层if (this.resultPoints.length > 0)和if (this.resultQuotes.length > 0)分别控制要点和金句区域的显示。这种「条件嵌套」模式在 ArkUI 中是完全合法的,且运行时性能良好——未渲染的组件不会占用内存和渲染资源。
5.5 核心实现——Scroll 滚动容器
整个内容区域被 Scroll 组件包裹,确保在中摘要模式下内容可以完整滚动:
Scroll() {
Column() {
// 输入区域、选择器、生成按钮、结果区域全部在此 Column 内
}
.width('100%')
}
.layoutWeight(1)
关键设计点:
-
Scroll 单子节点约束:ArkUI 的
Scroll组件要求只能有一个直接子组件。因此,必须使用Column作为 Scroll 的唯一子节点,将所有内容包裹其中。这是一个容易犯错的点——在开发者从其他框架迁移到 ArkUI 时,可能会习惯性地在 Scroll 中放置多个子组件,导致编译错误。 -
layoutWeight 布局:
Scroll使用layoutWeight(1)占据剩余空间,使得顶部导航栏固定,Scroll 区域自动填充剩余高度。这种布局方式在 HarmonyOS 中非常常见,比手动计算高度更加灵活和可靠。 -
性能考量:在 鸿蒙PC 端场景中,由于屏幕更大,单屏可显示的内容更多,
Scroll的滚动区域可以更宽,但需要注意长文本的渲染性能。ArkUI 的虚拟滚动机制只渲染可视区域内的组件,即使内容很长也能保持流畅的滚动体验。
六、Assess 评估阶段:项目复盘与经验总结
6.1 项目成果评估
「信息压缩站」的开发完成度评估如下:
| 维度 | 评分 | 说明 |
|---|---|---|
| 需求覆盖 | 100% | 三级长度摘要、三维输出结构、输入校验等核心需求全部实现 |
| 代码质量 | 优秀 | 零编译错误,ArkTS 语法完全合规,状态管理清晰 |
| UI 体验 | 良好 | 视觉层次分明,色彩编码合理,三级长度切换流畅 |
| 可扩展性 | 优秀 | AI API Stub 预留完整,数据接口标准化,扩展新级别只需加分支 |
| 文档完整性 | 良好 | 本文档覆盖了 6A 工作流的全部阶段 |
6.2 关键技术决策回顾
决策一:三维输出结构 vs 扁平文本
最初我们考虑过只输出一段摘要文本,但经过分析发现,用户对长文摘要的需求是多样化的——有些用户只想快速了解主旨,有些用户需要提取关键论据,有些用户希望保存精彩引述。三维输出结构(摘要 + 要点 + 金句)满足了这三种需求,且结构清晰,不会造成信息过载。
决策二:Mock 数据先行 vs 直接接入 AI
在项目初期,我们选择了 Mock 数据先行的策略。这个决策的关键考量是:AI 模型调优需要大量时间和实验,而 UI 开发和交互验证可以并行推进。通过 Mock 数据,我们可以在 AI 模型准备好之前完成 UI 的全部开发和测试,当 AI 模型就绪时,只需替换数据源即可——这正是 Stub 模式的核心价值。
决策三:扁平化状态管理 vs 对象管理
选择六个独立的 @State 变量而非一个 CompressResult 对象,是基于 ArkTS 状态管理机制的考量。独立的 @State 变量在更新时不需要整体替换,减少了不必要的对象构造和内存分配。同时,六个变量的语义清晰,调试和维护都更加方便。
6.3 经验教训
-
ArkTS 的严苛模式是挑战也是机遇:ArkTS 对 TypeScript 的严格限制(禁止
any、禁止解构、禁止for..in等)在初期会造成一定的不适应,但这些限制也迫使开发者编写更规范、更安全的代码。在信息压缩站的开发中,这些限制没有造成实质性的障碍,反而帮助我们在编译阶段就发现了潜在的类型问题。 -
Stub 模式是 AI 应用开发的最佳实践:在 AI 应用中,UI 开发和 AI 模型调优是两个独立的工作流。Stub 模式让两者解耦,互不阻塞。信息压缩站的 Mock 数据不仅是 UI 开发的占位符,更是 AI 输出的「质量基准」——当 AI 模型的实际输出质量达不到 Mock 数据的水平时,说明 Prompt 还需要继续调优。
-
三维输出结构的设计需要前置思考:三维输出(摘要 + 要点 + 金句)的设计在 Align 阶段就确定了,这为后续的架构设计和 UI 开发提供了清晰的指引。如果等到开发阶段再确定输出结构,可能会导致大量的返工。
-
Scroll 组件的单子节点约束容易被忽视:ArkUI 的
Scroll组件要求只能有一个直接子组件,这是一个常见的「坑」。在开发初期,我们曾尝试在Scroll中直接放置多个子组件,导致编译错误。解决方案是使用Column作为 Scroll 的唯一子节点。
6.4 与鸿蒙生态的深度结合
鸿蒙 ArkTS 的优势:
信息压缩站的开发充分体现了 ArkTS 作为鸿蒙原生开发语言的优势。声明式 UI 范式使得组件的状态和 UI 之间建立了清晰的双向绑定关系,@State 变量的变化自动触发 UI 重新渲染,开发者无需手动操作 DOM。与 鸿蒙Flutter框架 相比,ArkTS 没有额外的跨平台抽象层,编译后的代码直接运行在鸿蒙的方舟运行时上,启动速度和渲染性能都优于 Flutter 的 Dart VM 层。
鸿蒙PC 端的适配展望:
信息压缩站当前主要面向移动端,但其架构设计为 鸿蒙PC 端适配做好了准备。在 PC 端场景中,信息压缩站可以发挥更大的价值:
- 更大的输入区域:PC 端屏幕更大,可以将 TextInput 的高度从 120vp 增加到 200vp 甚至更高,支持更长的文本输入。同时可以利用键盘快捷键(Ctrl+V 粘贴、Ctrl+Enter 生成)提升操作效率。
- 并排布局:移动端的三维结果采用垂直排列,PC 端可以采用「摘要在上,要点和金句左右并排」的布局,更好地利用横向空间。由于状态变量是独立的,这种布局调整不会影响数据流。
- 多窗口交互:PC 端可以支持「拖拽文件到输入区域」和「浮动摘要窗口」等高级交互模式,进一步提升用户体验。
鸿蒙Flutter框架 的对比思考:
在技术选型时,我们评估了 鸿蒙Flutter框架 的可行性。Flutter 的优势在于跨平台一致性——一套代码可以同时运行在 Android、iOS 和鸿蒙上。但对于信息压缩站这类轻量级 AI 应用,Flutter 的跨平台抽象层带来的性能损耗和包体积增长是不必要的。ArkTS 的原生开发模式在性能、包体积和 API 调用便利性上都优于 Flutter。此外,Flutter 在鸿蒙上的适配仍处于早期阶段,部分原生 API(如 AI 能力调用)的封装还不够完善。因此,选择 ArkTS 作为开发语言是当前阶段的最优方案。
七、总结与展望
「信息压缩站」是 AI40 工具集矩阵中又一款基于 AI 的 HarmonyOS 应用,它通过三维输出结构(摘要 + 关键要点 + 金句摘录)和三级长度选择(一句话 / 短 / 中),为用户提供了灵活、高效的长文摘要体验。从技术实现的角度,它展示了以下几个关键实践模式:
-
Mock 数据先行的 AI 应用开发策略:通过预设的 Mock 数据验证 UI 和交互逻辑,同时预留 AI API 调用桩,实现 UI 开发与 AI 调优的并行推进。
-
扁平化状态管理:在 ArkTS 的
@State机制下,将独立的状态变量扁平化,避免不必要的对象构造和整体替换,提升 UI 更新性能。 -
三维输出结构的信息密度设计:将摘要输出分为摘要、要点和金句三个维度,分别满足「是什么」「为什么」「怎么表达的」三种信息需求,体现了对用户阅读心理的深刻理解。
-
ArkTS 严苛模式下的合规开发:严格遵守 ArkTS 的语法约束(禁止
any、禁止解构、禁止for..in等),确保代码的编译通过率和运行时稳定性。 -
Scroll 单子节点约束的正确处理:使用
Column作为 Scroll 的唯一子节点,避免常见的编译错误。
在 AI 能力日益普及的今天,文本摘要已不再是高高在上的「黑科技」,而是每个用户都触手可及的日常工具。「信息压缩站」的使命,就是让这项技术变得简单、直观、高效——用户只需粘贴文本、选择长度、点击生成,三步即可完成长文的智能摘要。未来,随着鸿蒙原生 AI 能力的不断成熟,以及 鸿蒙PC 端生态的完善,「信息压缩站」将逐步从「Mock 数据驱动」演进为「AI 模型驱动」,从「移动端」扩展到「全场景」,为用户提供更加智能、更加便捷的长文摘要体验。
本文是 AI40 应用工具集系列技术博客的第二十七篇。AI40 是一套基于 HarmonyOS ArkTS 开发的 40 个 AI 应用工具集,覆盖了文本处理、信息管理、生活助手、创意生成等多个领域。每篇博客均按照 6A 工作流(Align-Architect-Atomize-Approve-Automate-Assess)复盘完整的设计与开发过程,旨在为 HarmonyOS 开发者提供可复用的技术实践参考。
更多推荐

所有评论(0)