AI 修仙模拟器:鸿蒙 NEXT 原生应用开发实战

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一、项目背景

HarmonyOS NEXT 作为华为自主研发的操作系统,已经进入了全面商用阶段。它去除了 AOSP 兼容层,采用纯鸿蒙内核,为开发者带来了全新的技术栈和开发范式。本文将基于一个真实的鸿蒙原生开源项目 app622,带领读者深入剖析如何在鸿蒙 NEXT 平台上构建一款融合 AI 大语言模型与修仙文化主题的创新应用。

app622 项目包含两个核心模块:AI 修仙模拟器(基于大模型 API 的智能问答系统,以修仙文化为背景,提供 8 大修炼方向的指导)和 拖拽排序组件(使用 Stack 层叠布局实现卡片拖拽重排的视觉反馈效果)。项目已升级至 API 24(HarmonyOS 7.0.0),紧跟鸿蒙生态的最新演进。

本文将从架构设计、核心实现、代码解析、工程实践四个维度,全面展示鸿蒙原生应用的开发全貌。

二、项目全景概览

2.1 模块架构

模块 功能描述 技术亮点
AI 修仙模拟器(Index.ets) 基于 DeepSeek-V3 的智能问答,8 大修仙方向分类指导 SSE 流式响应、古风角色扮演提示词体系、非流式回退机制
拖拽排序演示(DragSortStack.ets) 卡片列表拖拽重排组件 Stack 三层叠加法 + PanGesture 手势联动、声明式动画

2.2 技术栈

维度 选型 说明
开发语言 ArkTS 鸿蒙原生声明式 UI 语言,基于 TypeScript 扩展
UI 框架 ArkUI 鸿蒙原生声明式 UI 框架,响应式数据驱动
网络框架 @kit.NetworkKit 鸿蒙原生 HTTP 网络请求库,支持 SSE 流式
目标 SDK API 24(HarmonyOS 7.0.0) 最新稳定版 SDK
AI 模型 DeepSeek-V3 通过 Gitcode AI API 调用,兼容 OpenAI 格式
构建工具 Hvigor 鸿蒙原生构建系统

三、AI 修仙模拟器:架构设计

3.1 三层架构体系

AI 修仙模拟器采用了经典的分层架构,将 UI 层、服务层、网络层清晰分离:

┌──────────────────────────────────────────────┐
│  UI 层(Index.ets)                           │
│  @Entry @Component struct Index              │
│  ├─ buildHeader()        标题栏 + 仙缘设置     │
│  ├─ buildCategorySelector() 修炼方向选择器     │
│  ├─ buildChatArea()      聊天消息展示区        │
│  ├─ buildInputArea()    输入 + 发送区域        │
│  └─ buildSettingsPanel() 仙缘设置面板          │
├──────────────────────────────────────────────┤
│  服务层(AIChatService.ets)                   │
│  ├─ queryAI()            发起 AI 请求(核心)  │
│  ├─ cancelAI()           取消请求              │
│  ├─ setSystemPrompt()    设置前置心法(提示词) │
│  ├─ setCategoryPrompt()  按修炼方向设置心法     │
│  ├─ setApiConfig()       配置灵脉地址和灵钥     │
│  └─ setModel()           切换修行法门(模型)   │
├──────────────────────────────────────────────┤
│  网络层(@kit.NetworkKit)                    │
│  ├─ http.createHttp()    创建 HTTP 请求        │
│  ├─ on('dataReceive')    SSE 流式数据监听       │
│  └─ request()            发起 POST 请求         │
└──────────────────────────────────────────────┘

UI 层只关心展示和交互,不涉及网络请求细节;服务层封装了所有业务逻辑,包括提示词管理、API 配置、SSE 解析等;网络层由鸿蒙原生 SDK 提供。各层之间通过接口契约通信,耦合度极低,便于单元测试和功能扩展。

3.2 核心数据流

当弟子(用户)在输入框中描述修行疑惑并点击发送时,完整的数据流如下:

弟子发送 → onSendMessage()
  → 校验输入(非空、非加载中)
  → 将弟子问加入 messages[]
  → 设置 isLoading = true(触发 UI 显示加载指示器)
  → 调用 queryAI(callbacks, historyMessages)
    → 取消上一次未完成请求(防止道法冲突)
    → 构造请求体(前置心法 + 历史问答)
    → 注册 dataReceive 监听(SSE 流式)
    → 发起 HTTP POST 请求
      → SSE 模式:逐 token 触发 onData()
        → onData(delta) → currentAIResponse += delta
        → UI 实时刷新(@State 驱动)
      → SSE 结束:触发 onDone()
        → 将累积回复加入 messages[]
        → 重置 isLoading = false
      → 非流式回退:若 dataReceive 未触发
        → 从完整响应体解析 SSE 或 JSON
        → 一次性返回完整内容

3.3 非流式回退设计

项目中一个值得称道的设计是非流式回退机制。鸿蒙的 http 模块在不同版本中对 SSE 的支持行为不完全一致,某些版本下 dataReceive 事件可能不被触发。开发者通过 receivedAnyData 标志位检测这种情况,一旦发现则在 request 回调中手动解析完整响应体。这种防御性编程思维,是生产级应用所必需的。

请求完成
  → dataReceive 已触发?→ 是→ 正常 SSE 流式结束
  → dataReceive 未触发?→ 是→ 尝试 SSE 格式解析
    → 成功?→ 是→ 拼接完整内容
    → 失败?→ 尝试 JSON 格式解析
      → 成功?→ 是→ 返回完整内容
      → 失败?→ 返回错误预览

四、修仙修炼方向预设体系

4.1 八大修炼方向

项目的核心亮点是将修仙文化体系融入 AI 对话系统,设计了 8 个修炼方向,每个方向配备精心编写的角色扮演提示词:

修炼方向 图标 角色定位 传授内容
练气入门 🌀 引气长老 感应灵气、打通经脉、吐纳调息
筑基功法 ⛰️ 宗门长老 筑基丹炼制、道基种类、心境磨砺
金丹大道 太上长老 金丹凝练、丹火掌控、心魔抵御
元婴出窍 🌟 大能修士 元婴养炼、元神出窍、神识修炼
炼丹制药 🔥 丹道宗师 丹方配伍、天材地宝、火候掌控
炼器锻造 ⚔️ 隐世器师 法器品阶、材料提纯、器纹铭刻
阵法符箓 📜 阵道宗师 聚灵阵、杀阵、符箓绘制
渡劫飞升 大乘期修士 天劫应对、渡劫准备、心魔降服

4.2 提示词工程解析

每个修炼方向的提示词(在代码中称为"前置心法")都经过精心设计,包含四个维度:

角色定义:明确 AI 的身份和修为境界。例如练气入门的提示词开头:

'你是一位修仙门派中德高望重的引气长老,专司新弟子的启蒙教导。\n\n' +
'你的任务是指导刚刚踏入仙途的弟子掌握练气期的基础法门,包括:\n' +
'  ① 感应天地灵气的基础心法\n' +
'  ② 打通十二正经与奇经八脉的功法\n' +
'  ③ 吐纳调息与周天运转的技巧\n' +

覆盖范围:列出该方向下 AI 能够解答的具体问题类别,每个方向 5 个要点。

回答原则:定义 AI 的回答风格和约束。例如筑基功法的原则包括"因材施教,根据弟子的灵根属性推荐不同的筑基法门"“告诫天道筑基之艰难,地道筑基之稳妥”。

语气风格:统一要求"古风雅韵的中文回复",并针对不同方向微调——练气入门"语气慈祥而威严",金丹大道"语气超然而亲切",炼器锻造"语气刚毅而专注"。这种精细化的角色扮演提示词工程,能显著提升 AI 回答的质量和沉浸感。

五、SSE 流式响应实现

5.1 核心代码

流式响应(Streaming Response)是 AI 对话应用的关键体验。用户发出问题后,AI 的回复逐字逐句地实时展示,而不是等待完整回复生成后再一次性显示。这种体验更接近真实对话,能显著降低等待焦虑。

httpRequest.on('dataReceive', (data: ArrayBuffer) => {
  const text = arrayBufferToString(data);
  buffer += text;
  receivedAnyData = true;

  const lines = buffer.split('\n');
  buffer = lines.pop() ?? '';  // 最后一段可能不完整,留到下次

  for (const line of lines) {
    const trimmed = line.trim();
    if (!trimmed.startsWith('data:')) continue;
    if (trimmed === 'data:[DONE]') {
      if (!isDone) { isDone = true; callbacks.onDone(); }
      continue;
    }
    const content = parseSSEDataLine(trimmed);
    if (content) callbacks.onData(content);
  }
});

5.2 关键技术细节

行缓冲区:SSE 数据分块传输,一个数据块可能包含半行数据。代码使用 buffer 变量累积接收到的数据,每次按 \n 分割后,将最后一段(可能不完整)保留到下一次处理。这是 SSE 解析的标准做法,能确保数据边界正确。

ArrayBuffer 解码:鸿蒙的 dataReceive 事件传递的是 ArrayBuffer 类型,需要自行解码为字符串:

function arrayBufferToString(buffer: ArrayBuffer): string {
  const uint8Arr = new Uint8Array(buffer);
  let text = '';
  for (let i = 0; i < uint8Arr.length; i++)
    text += String.fromCharCode(uint8Arr[i]);
  return text;
}

DONE 标记处理:SSE 流的结束标记 data:[DONE] 需要特殊处理,且通过 isDone 标志位防止重复触发 onDone() 回调。

六、拖拽排序组件:Stack 三层叠加法

6.1 设计理念

拖拽排序组件完全使用 ArkUI 内置的 Stack(层叠布局)和 PanGesture(平移手势)实现,不依赖任何第三方库。其核心设计理念是三层叠加法,将三种视觉状态沿 Z 轴叠放在同一坐标系中:

┌─────────────────────────────────────────────┐
│  第 3 层(最顶层):浮动卡片                   │
│  → 仅被拖拽时可见                            │
│  → shadow + scale + translate 产生悬浮感     │
├─────────────────────────────────────────────┤
│  第 2 层(中间层):静止卡片                   │
│  → 列表正常展示状态                          │
│  → 被拖拽时将透明度降为 0(隐藏原位卡片)      │
├─────────────────────────────────────────────┤
│  第 1 层(最底层):占位虚线框                 │
│  → 仅本项被拖拽时显示                        │
│  → 在原位置展示空槽以引导用户视觉              │
└─────────────────────────────────────────────┘

6.2 核心实现

每一张卡片都是一个 Stack 容器,内部包含三层 Row 布局:

Stack() {
  // 第 1 层:占位虚线框
  if (this.draggingIndex === index) {
    Row()
      .height(this.CARD_HEIGHT)
      .border({ width: 2, color: '#CCCCCC', style: BorderStyle.Dashed })
  }

  // 第 2 层:静止卡片
  Row() { /* 序号标 + 标题 + 描述 + 拖拽手柄 */ }
    .opacity(this.draggingIndex === index ? 0 : 1)

  // 第 3 层:浮动卡片
  Row() { /* 与第 2 层相同的内容 */ }
    .shadow({ radius: 24, offsetY: 8, color: 'rgba(0,0,0,0.20)' })
    .scale({ x: this.draggingIndex === index ? 1.05 : 1.0 })
    .translate({ y: this.draggingIndex === index ? this.dragOffsetY : 0 })
    .opacity(this.draggingIndex === index ? 0.95 : 0)
}
.clip(false)
.animation({ duration: 250, curve: Curve.FastOutSlowIn })

6.3 三大视觉反馈要素

要素 参数值 效果
大阴影 shadow radius: 24, offsetY: 8 卡片从表面浮起,投影在下方
轻微放大 scale: 1.05 卡片比正常大 5%,突出选中感
Y 轴位移 translate y: dragOffsetY 卡片跟随手指移动

6.4 手势处理

手势使用 PanGesture 实现,只监听纵向拖拽,并设置 distance: 10 的触发阈值防止误触:

PanGesture({ direction: PanDirection.Vertical, distance: 10 })
  .onActionStart(() => {
    this.draggingIndex = index;
    this.startGlobalY = event.fingerList[0].globalY;
  })
  .onActionUpdate(() => {
    this.dragOffsetY = currentGlobalY - this.startGlobalY;
    const stepHeight = CARD_HEIGHT + CARD_GAP;
    const offsetSteps = Math.round(this.dragOffsetY / stepHeight);
    this.targetInsertIndex = clamp(index + offsetSteps, 0, items.length - 1);
  })
  .onActionEnd(() => {
    if (this.targetInsertIndex !== index) {
      const moveItem = this.items.splice(index, 1)[0];
      this.items.splice(this.targetInsertIndex, 0, moveItem);
    }
    this.draggingIndex = -1;
    this.dragOffsetY = 0;
  })

目标插入位置的计算公式直观有效:原始索引加上偏移量除以卡片步高(卡片高度 + 间距)的取整值。当拖拽结束且目标位置与原始位置不同时,通过数组的 splice 操作完成重排。

七、鸿蒙开发关键概念

7.1 ArkTS 装饰器体系

ArkTS 扩展了 TypeScript 的装饰器体系,用于声明式 UI 编程。项目中用到了以下核心装饰器:

装饰器 作用 使用示例
@Entry 标记页面入口 Index.ets, DragSortStack.ets
@Component 定义组件 struct Index, struct DragSortPage
@State 声明响应式状态 messages, inputText, draggingIndex
@Builder 定义可复用 UI 构建函数 buildHeader(), buildChatArea()

@State 是 ArkTS 响应式编程的核心。当 @State 装饰的变量被修改时,框架会自动追踪依赖并仅更新受影响的部分 UI,而不是整页重绘。例如,currentAIResponse 每次更新时,只有流式消息气泡区域会重新渲染,标题栏和输入框不受影响。

7.2 Ability 生命周期

鸿蒙中页面被组织在 Ability 中。EntryAbility 负责管理应用的启动和页面加载:

export default class EntryAbility extends UIAbility {
  onCreate(want, launchParam) { /* 初始化 */ }
  onWindowStageCreate(windowStage) {
    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) { hilog.error(...); return; }
    });
  }
  onForeground() { /* 进入前台 */ }
  onBackground() { /* 进入后台 */ }
  onDestroy() { /* 销毁 */ }
}

7.3 API 24 升级要点

本项目的 build-profile 配置已升级至 API 24:

{
  products: [{
    name: "default",
    targetSdkVersion: "7.0.0(24)",
    compatibleSdkVersion: "7.0.0(24)",
    runtimeOS: "HarmonyOS",
  }]
}

API 24(HarmonyOS 7.0.0)相较于 API 23 的主要改进包括:更稳定的 SSE 流式支持、更完善的 ArkUI 动画能力、性能优化和内存管理改进。

八、工程实践与最佳实践

8.1 错误处理

项目中体现了分层次的错误处理策略:

网络层:检查 HTTP 状态码,截断过长的错误信息。解析层:JSON 解析失败时静默跳过,不中断整体流程。UI 层:将错误信息作为 AI 消息展示给用户,而非弹出刺眼的原生对话框。这种做法在用户体验上更温和,即使用户的问题无法解答,应用也会以角色的口吻告知原因。

8.2 资源清理

AI 请求的网络资源在多个场景下需要清理:切换修炼方向时、用户点击取消时、发起新请求前。cancelAI() 函数确保在任何情况下都不会积压未完成的请求:

export function cancelAI(): void {
  if (httpRequestTask) {
    try { httpRequestTask.destroy(); } catch (_) { }
    httpRequestTask = null;
  }
}

8.3 条件渲染

ArkUI 通过 @State 加 if 条件渲染实现动态 UI:

if (messages.length === 0) buildEmptyGuide()
if (isLoading && currentAIResponse.length > 0) buildAIBubble()
if (isLoading && currentAIResponse.length === 0) buildLoadingIndicator()
if (isLoading) buildCancelButton() else buildSendButton()

这些条件逻辑清晰定义了 UI 的四种状态:空状态、等待中、流式输出中、完成。

8.4 模块化设计

AIChatService 作为独立服务模块,通过 export 和 import 机制与 UI 层解耦。项目导出了分类常量(CATEGORY_PROMPTS、CATEGORY_ICONS、CATEGORY_ORDER)和服务函数(queryAI、cancelAI、setSystemPrompt 等),遵循了关注点分离原则。

九、两模块技术对比

维度 AI 修仙模拟器 拖拽排序组件
核心能力 网络通信 + 数据解析 + AI 集成 手势交互 + 动画 + 布局
状态管理 大量 @State 响应式变量 少量 @State + 非响应式变量
异步处理 SSE 流式 + 回调 + 超时 手势事件同步处理
视觉复杂度 气泡 + 列表 + 弹窗 阴影 + 缩放 + 位移
错误处理 多层兜底降级解析 边界约束 + 异常保护
可配置性 灵脉/灵钥/心法均可配置 固定数据展示

AI 修仙模拟器偏向应用层能力集成——对接外部 AI 服务、处理网络异常、提供灵活的配置。拖拽排序组件则展示了原生交互的深度定制——利用 Stack 层叠和手势实现流畅的拖拽体验。两者合在一起,展示了鸿蒙 NEXT 作为成熟移动平台的能力广度。

十、总结与展望

通过深入分析 app622 项目,我们看到了鸿蒙原生应用从架构设计到细节实现的完整图谱。AI 修仙模拟器展示了分层架构、SSE 流式响应、修仙文化角色扮演提示词体系的设计思路;拖拽排序组件展示了 Stack 层叠布局、手势处理、过渡动画的精妙组合。

最值得学习的是项目中贯穿的工程思维——非流式回退机制、多层的解析降级策略、资源清理的防护逻辑。这些看不见的代码才是区分演示项目和实际应用的关键。

项目已升级至 API 24,紧跟鸿蒙生态的最新发展。鸿蒙生态正在蓬勃发展,选择拥抱鸿蒙 NEXT,不仅是进入一个新平台,更是参与到建设自主操作系统生态的历史进程中。希望本文能为你的鸿蒙开发之旅提供有价值的参考。

本文基于 app622 项目源码撰写(HarmonyOS NEXT / ArkTS / API 24)

Logo

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

更多推荐