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 阶段,我们需要回答以下关键问题:

问题一:摘要长度如何分级?

这是整个系统最核心的设计决策。经过对用户阅读场景的调研,我们发现长文摘要的需求可以归纳为三个典型场景:

  1. 一句话(One-Sentence):用户只想快速了解文章的核心主旨,类似于论文的摘要或新闻的导语。适用场景:浏览大量文章时快速筛选、社交媒体分享时提取核心观点。输出要求:一句话(约 50-80 字)概括全文核心,不输出关键要点和金句摘录。

  2. 短摘要(Short):用户需要较为完整的文章梗概,了解主要论点和支撑论据。适用场景:工作汇报前的快速浏览、决策前的信息速览。输出要求:一段约 100-200 字的摘要 + 5 条关键要点 + 2 条金句摘录。

  3. 中摘要(Medium):用户需要深入理解文章的结构和详细内容,适用于深度阅读前的预读。适用场景:学术研究、深度报道的快速理解。输出要求:多段详细摘要(约 300-500 字)+ 5 条关键要点 + 3 条金句摘录。

这三个级别的划分并非随意,而是基于认知心理学中的「信息渐进式获取」模型:从一句话到短摘要再到中摘要,信息密度逐渐增加,用户可以根据自己的时间预算和需求深度选择适合的级别。

问题二:输出结构如何设计?

摘要结果不应该只是一段扁平化的文字,而应该是一个多维度的信息结构。经过分析,我们确定了三维输出结构:

  1. 摘要(Summary):对原文的核心内容进行概括性描述,保留关键论点和核心结论。这是用户获取信息的最主要入口。
  2. 关键要点(Key Points):以编号列表形式提取原文的核心论据和关键数据点。每一条要点都是独立的信息单元,用户可以快速浏览并判断是否需要深入阅读原文。
  3. 金句摘录(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 的三个字段中,summarystring 类型,pointsquotesstring[] 类型,没有使用 anyunknown,符合 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。原因有三点:

  1. ArkTS 状态更新粒度@State 装饰的对象在属性变更时,需要整体替换对象才能触发 UI 刷新。如果使用方案 A,每次更新一个字段都需要重新构造整个对象,增加了不必要的代码和内存分配。信息压缩站的三维结果(摘要、要点、金句)在 UI 中是完全独立的区块,各自有不同的渲染逻辑和样式,使用独立字段让每个区域的更新更加清晰。

  2. 条件渲染友好:关键要点和金句摘录在「一句话」模式下不显示,使用独立字段配合 if (this.resultPoints.length > 0)if (this.resultQuotes.length > 0) 的条件判断更加直观,不需要额外判断对象是否为空。

  3. 调试友好:在调试时,独立的 @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; })
  })
}

这里有几个设计细节值得关注:

  1. Capsule 按钮形状ButtonType.Capsule 是 HarmonyOS 提供的药丸形状按钮,圆角较大,视觉上比矩形按钮更柔和,适合作为选项标签使用。在 鸿蒙Flutter框架 中,类似的胶囊按钮需要自定义 BorderRadius 来实现,而在 ArkUI 中,原生组件直接提供了这一样式,减少了自定义样式的工作量。

  2. 选中态切换:通过 this.selectedLength === item 判断当前按钮是否被选中,选中时使用主题蓝色 #007AFF,未选中时使用浅灰色 #E8E8E8。这种「亮色选中 / 灰色未选」的视觉模式在移动端应用中广泛使用,用户认知成本低。

  3. 默认选中「短」selectedLength 初始值为 '短',因为短摘要是最常用的场景——既能快速了解文章核心,又能获取关键要点和金句,信息密度和阅读效率达到最佳平衡。

  4. 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 模式的关键优势在于:

  1. 接口契约共享generateMockData()callAIAPI() 都将结果写入相同的三个 @State 变量,UI 层不需要任何修改。这意味着从 Mock 到真实 API 的切换是「零 UI 改动」的。

  2. 渐进式集成:在开发阶段,可以先使用 Mock 数据验证 UI 交互和状态流转;在集成测试阶段,逐步替换为真实 API 调用;在生产环境中,保留 Mock 数据作为 API 调用失败时的兜底方案。

  3. 可测试性:Mock 数据和 AI API 共享相同的 CompressResult 接口,单元测试可以针对 Mock 数据编写,集成测试可以针对 API 调用编写,两者互不干扰。

  4. 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 接口的三个字段分别为 stringstring[]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 条件渲染正确性审查

审查确认条件渲染逻辑正确:

  • 初始状态:showResultfalse,结果区域不渲染。
  • 输入为空时点击生成: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 的几个关键规范:

  1. 接口声明interface CompressResult 定义了 AI 输出的数据契约。三个字段分别对应摘要、要点和金句。注意 ArkTS 不支持 interface 中的构造函数签名、调用签名和索引签名,只支持纯粹的属性声明。

  2. @State 装饰器:七个状态变量必须在声明时初始化,类型必须显式标注。ArkTS 不支持 let v!: T 形式的确定性赋值断言,因此所有 @State 变量必须有初始值。

  3. import 语句import { router } from '@kit.ArkUI' 必须放在文件最顶部,在所有其他语句之前。ArkTS 不支持 require 导入和 import 赋值,也不支持模块名称中的通配符。

  4. @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的刹车。"——隐私保护专家'
    ];
  }
}

核心设计要点:

  1. 早期返回模式:输入校验放在方法开头,如果输入为空则直接返回,避免后续的无效操作。这种模式在 ArkTS 中尤为重要,因为 @State 变量的赋值会触发 UI 重新渲染,减少不必要的状态更新可以提升性能。

  2. 三路条件分支:使用 if-else if-else 结构处理三个长度级别,每个分支独立设置三个结果变量。这种结构清晰直观,便于后续扩展新的长度级别——只需在 lengthOptions 数组中添加选项,在 generateMockData() 中添加对应的分支即可。

  3. 空数组处理:「一句话」模式下,resultPointsresultQuotes 显式设置为空数组 [],配合 UI 层的 if (this.resultPoints.length > 0) 条件判断,确保不渲染空白区域。

  4. 数据一致性:三个级别的 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 })

设计要点:

  1. 高度设置height(120) 设置为 120vp,约为 5-6 行文本的显示区域,既能容纳一定长度的输入,又不会占用过多屏幕空间。在中摘要模式下,结果区域内容较多,120vp 的输入区域高度是一个合理的折中。

  2. 双向绑定text: this.inputArticle 绑定状态变量,onChange 回调更新状态变量,实现了文本输入的双向同步。ArkTS 的声明式数据绑定机制确保了 UI 和状态始终一致。

  3. Placeholder 提示placeholder: '请输入或粘贴长文内容...' 提供了明确的操作指引,降低用户的使用门槛。提示文本中的「粘贴」一词暗示了该应用支持从剪贴板粘贴内容,这是移动端长文输入的主要场景。

  4. 圆角和边距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%')
}

设计要点:

  1. 三维结果分层展示:摘要卡片 → 关键要点列表 → 金句摘录列表,自上而下排列,符合用户从上到下的阅读习惯。每个区域有独立的标题和样式,视觉上明确区分了三个信息维度。

  2. 要点编号渲染:使用 (index + 1) + '. ' 动态生成编号文本,蓝色(#007AFF)加粗显示,与正文内容形成对比。编号从 1 开始连续递增,符合人类的计数习惯。

  3. 金句视觉设计:浅黄色背景(#FFF8E1)传递温暖感,橙色引号(#FF9500)作为视觉锚点,斜体文字(FontStyle.Italic)营造引述的排版感,灰色正文(#666666)降低视觉权重。这种设计让金句区域在视觉上与其他区域形成明显区分,用户一眼就能识别出这是「引述」而非「正文」。

  4. 条件渲染的嵌套使用:外层 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)

关键设计点:

  1. Scroll 单子节点约束:ArkUI 的 Scroll 组件要求只能有一个直接子组件。因此,必须使用 Column 作为 Scroll 的唯一子节点,将所有内容包裹其中。这是一个容易犯错的点——在开发者从其他框架迁移到 ArkUI 时,可能会习惯性地在 Scroll 中放置多个子组件,导致编译错误。

  2. layoutWeight 布局Scroll 使用 layoutWeight(1) 占据剩余空间,使得顶部导航栏固定,Scroll 区域自动填充剩余高度。这种布局方式在 HarmonyOS 中非常常见,比手动计算高度更加灵活和可靠。

  3. 性能考量:在 鸿蒙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 经验教训

  1. ArkTS 的严苛模式是挑战也是机遇:ArkTS 对 TypeScript 的严格限制(禁止 any、禁止解构、禁止 for..in 等)在初期会造成一定的不适应,但这些限制也迫使开发者编写更规范、更安全的代码。在信息压缩站的开发中,这些限制没有造成实质性的障碍,反而帮助我们在编译阶段就发现了潜在的类型问题。

  2. Stub 模式是 AI 应用开发的最佳实践:在 AI 应用中,UI 开发和 AI 模型调优是两个独立的工作流。Stub 模式让两者解耦,互不阻塞。信息压缩站的 Mock 数据不仅是 UI 开发的占位符,更是 AI 输出的「质量基准」——当 AI 模型的实际输出质量达不到 Mock 数据的水平时,说明 Prompt 还需要继续调优。

  3. 三维输出结构的设计需要前置思考:三维输出(摘要 + 要点 + 金句)的设计在 Align 阶段就确定了,这为后续的架构设计和 UI 开发提供了清晰的指引。如果等到开发阶段再确定输出结构,可能会导致大量的返工。

  4. 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 应用,它通过三维输出结构(摘要 + 关键要点 + 金句摘录)和三级长度选择(一句话 / 短 / 中),为用户提供了灵活、高效的长文摘要体验。从技术实现的角度,它展示了以下几个关键实践模式:

  1. Mock 数据先行的 AI 应用开发策略:通过预设的 Mock 数据验证 UI 和交互逻辑,同时预留 AI API 调用桩,实现 UI 开发与 AI 调优的并行推进。

  2. 扁平化状态管理:在 ArkTS 的 @State 机制下,将独立的状态变量扁平化,避免不必要的对象构造和整体替换,提升 UI 更新性能。

  3. 三维输出结构的信息密度设计:将摘要输出分为摘要、要点和金句三个维度,分别满足「是什么」「为什么」「怎么表达的」三种信息需求,体现了对用户阅读心理的深刻理解。

  4. ArkTS 严苛模式下的合规开发:严格遵守 ArkTS 的语法约束(禁止 any、禁止解构、禁止 for..in 等),确保代码的编译通过率和运行时稳定性。

  5. Scroll 单子节点约束的正确处理:使用 Column 作为 Scroll 的唯一子节点,避免常见的编译错误。

在 AI 能力日益普及的今天,文本摘要已不再是高高在上的「黑科技」,而是每个用户都触手可及的日常工具。「信息压缩站」的使命,就是让这项技术变得简单、直观、高效——用户只需粘贴文本、选择长度、点击生成,三步即可完成长文的智能摘要。未来,随着鸿蒙原生 AI 能力的不断成熟,以及 鸿蒙PC 端生态的完善,「信息压缩站」将逐步从「Mock 数据驱动」演进为「AI 模型驱动」,从「移动端」扩展到「全场景」,为用户提供更加智能、更加便捷的长文摘要体验。


本文是 AI40 应用工具集系列技术博客的第二十七篇。AI40 是一套基于 HarmonyOS ArkTS 开发的 40 个 AI 应用工具集,覆盖了文本处理、信息管理、生活助手、创意生成等多个领域。每篇博客均按照 6A 工作流(Align-Architect-Atomize-Approve-Automate-Assess)复盘完整的设计与开发过程,旨在为 HarmonyOS 开发者提供可复用的技术实践参考。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐