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

本文完整记录了一个基于 HarmonyOS NEXT API 24(API Version 6.1.1)的旅游攻略问答应用的开发全过程,涵盖 ArkTS 声明式 UI、网络请求、SSE 流式数据解析、AI 对话集成等核心知识点,附带完整源码与避坑指南。


一、前言

1.1 为什么选择 HarmonyOS NEXT

HarmonyOS NEXT 是华为面向万物互联时代打造的全场景智能操作系统,自 API 24(SDK 6.1.1)起已全面支持 Stage 模型与 ArkTS 语言。与传统的 Android/Linux 内核不同,HarmonyOS NEXT 采用了微内核架构,具有以下显著优势:

  • 分布式能力:一套代码可运行在手机、平板、智慧屏、手表等多种设备上
  • 原生安全:基于微内核的安全机制,系统服务按最小权限原则设计
  • 高性能 ArkTS 运行时:ArkTS 编译为方舟字节码,性能接近原生
  • 完善的 UI 框架:ArkUI 声明式框架,开发体验对标 SwiftUI / Jetpack Compose

本文所构建的应用 targetSdkVersion6.1.1(24),即 API 24 版本,这是当前 HarmonyOS NEXT 的主流稳定版本。

1.2 项目背景

随着人们生活水平的提高,旅游已成为重要的休闲方式。然而,面对海量的网络信息,规划一次完美的旅行往往需要大量时间和精力。本项目的目标正是利用大语言模型的强大知识能力,构建一个"旅游攻略问答助手",让用户通过自然对话即可获得个性化的旅行建议。

1.3 技术选型

技术层 选型 说明
开发语言 ArkTS HarmonyOS 原生声明式语言
UI 框架 ArkUI 声明式 UI,响应式状态管理
应用模型 Stage 模型 HarmonyOS NEXT 推荐模型
网络请求 @kit.NetworkKit 原生 HTTP 库,支持 SSE
AI 模型 DeepSeek-V3 GitCode API 提供的开源大模型
数据格式 SSE (Server-Sent Events) 服务端流式推送,实现打字机效果
构建工具 hvigor HarmonyOS 官方构建工具
SDK 版本 API 24 (6.1.1) HarmonyOS NEXT 最新稳定版

二、项目搭建与工程结构

2.1 创建项目

使用 DevEco Studio(推荐 5.0+ 版本)创建新项目:

  1. 打开 DevEco Studio → Create Project
  2. 选择 Empty Ability 模板
  3. 配置项目信息:
    • Project Name:Demo022
    • Bundle Name:com.example.demo02
    • Compile SDK:6.1.1(24)
    • Model:Stage
    • Language:ArkTS

2.2 项目目录结构

Demo022/
├── AppScope/                          # 应用级配置
│   ├── app.json5                      # 应用基本信息(bundleName、版本号等)
│   └── resources/base/element/
│       └── string.json                # 字符串资源(应用名称等)
├── entry/                             # 应用模块(entry 类型)
│   ├── build-profile.json5            # 模块构建配置
│   ├── oh-package.json5               # 模块依赖声明
│   ├── obfuscation-rules.txt          # 代码混淆规则
│   ├── src/main/
│   │   ├── ets/                       # ArkTS 源码目录
│   │   │   ├── AIChatService.ets      # AI 聊天服务(网络请求 + SSE 解析)
│   │   │   ├── entryability/
│   │   │   │   └── EntryAbility.ets   # Ability 生命周期管理
│   │   │   ├── entrybackupability/
│   │   │   │   └── EntryBackupAbility.ets  # 备份扩展
│   │   │   └── pages/
│   │   │       └── Index.ets          # 主页面(聊天界面)
│   │   ├── module.json5               # 模块配置文件
│   │   └── resources/base/element/
│   │       ├── color.json             # 颜色资源
│   │       ├── float.json             # 浮点数值资源
│   │       └── string.json            # 字符串资源
│   └── hvigorfile.ts                  # hvigor 构建脚本
├── hvigor/
│   └── hvigor-config.json5            # hvigor 配置
├── build-profile.json5                # 全局构建配置
├── hvigorfile.ts                      # 根构建脚本
├── oh-package.json5                   # 根依赖声明
└── local.properties                   # 本地开发环境配置

2.3 核心配置文件解析

全局构建配置 build-profile.json5
{
  "app": {
    "signingConfigs": [],
    "products": [
      {
        "name": "default",
        "signingConfig": "default",
        "targetSdkVersion": "6.1.1(24)",
        "compatibleSdkVersion": "6.1.1(24)",
        "runtimeOS": "HarmonyOS",
        "buildOption": {
          "strictMode": {
            "caseSensitiveCheck": true,
            "useNormalizedOHMUrl": true
          }
        }
      }
    ],
    "buildModeSet": [
      { "name": "debug" },
      { "name": "release" }
    ]
  },
  "modules": [
    {
      "name": "entry",
      "srcPath": "./entry",
      "targets": [
        { "name": "default", "applyToProducts": ["default"] }
      ]
    }
  ]
}

关键配置说明:

  • targetSdkVersion: "6.1.1(24)" —— 目标 SDK 版本为 API 24
  • compatibleSdkVersion —— 兼容 SDK 版本,与 target 一致
  • runtimeOS: "HarmonyOS" —— 运行时系统
  • strictMode —— 严格模式,开启大小写检查和 URL 规范化
页面路由配置 module.json5
{
  "module": {
    "name": "entry",
    "type": "entry",
    "mainElement": "EntryAbility",
    "deviceTypes": ["phone"],
    "pages": "$profile:main_pages",
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets",
        "exported": true,
        "skills": [
          {
            "entities": ["entity.system.home"],
            "actions": ["ohos.want.action.home"]
          }
        ]
      }
    ]
  }
}

三、Ability 生命周期管理

3.1 Stage 模型简介

HarmonyOS NEXT 采用 Stage 模型作为应用开发的标准模型。Stage 模型将应用分为 Ability 和 AbilityStage 两层,每个 Ability 对应一个独立的功能单元。

EntryAbility 就是我们应用的主 Ability,其生命周期包含以下阶段:

onCreate → onWindowStageCreate → onForeground → [运行中]
    ↑                                                    ↓
    └────── onBackground ← onWindowStageDestroy ← onDestroy

3.2 EntryAbility 实现

import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';

const DOMAIN = 0x0000;

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    // 设置颜色模式(跟随系统)
    try {
      this.context.getApplicationContext()
        .setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
    } catch (err) {
      hilog.error(DOMAIN, 'testTag', 'Failed to set colorMode. Cause: %{public}s',
        JSON.stringify(err));
    }
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    // 加载主页面
    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) {
        hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s',
          JSON.stringify(err));
        return;
      }
      hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');
    });
  }
  // ... onDestroy, onWindowStageDestroy, onForeground, onBackground
}

知识点

  • setColorMode(COLOR_MODE_NOT_SET) 表示跟随系统自动切换深色/浅色模式
  • loadContent('pages/Index', callback) 加载指定页面,路径与 module.json5 中的 pages 配置对应
  • hilog 是 HarmonyOS 的日志工具,支持领域(DOMAIN)和标签(tag)分类

四、AI 聊天服务层 — AIChatService 深度解析

AIChatService.ets 是整个应用的网络核心,负责与 AI API 的通信、SSE 流式数据解析、以及请求的生命周期管理。

4.1 接口与类型定义

// 聊天消息结构
export interface ChatMessage {
  role: string;      // "system" | "user" | "assistant"
  content: string;   // 消息内容
}

// API 请求体结构
export interface ChatCompletionRequest {
  model: string;
  messages: ChatMessage[];
  stream: boolean;         // 是否启用流式输出
  max_tokens: number;      // 最大输出 token 数
  temperature: number;     // 温度参数(0~2),控制创造性
  top_p: number;           // 核采样参数
  frequency_penalty: number; // 频率惩罚
  thinking_budget: number; // 思考预算
}

// 回调接口 — 解耦网络层与 UI 层
export interface AICallbacks {
  onData: (text: string) => void;   // 每次收到 token 时触发
  onDone: () => void;               // 流式结束时触发
  onError: (errMsg: string) => void; // 发生错误时触发
}

设计思考:通过 AICallbacks 回调接口将网络请求与 UI 解耦,使得网络层可以独立测试,UI 层只需关注如何展示数据。

4.2 系统提示词 — 旅游攻略专家角色设定

系统提示词(System Prompt)是决定 AI 回答质量的关键。本项目精心设计了针对旅游场景的提示词:

const SYSTEM_PROMPT: string =
  '你是一位资深的旅游攻略专家,擅长为用户提供全面、实用、个性化的旅游规划建议。' +
  '你熟悉国内外各大旅游目的地,了解不同季节的旅行特点,能给出交通、住宿、美食、景点、购物等全方位建议。\n\n' +
  '以下是你要遵循的原则:\n' +
  '1. 先了解需求:分析用户的出行时间、天数、预算、人群和偏好\n' +
  '2. 给攻略:提供目的地概览、行程推荐、交通方式、住宿推荐等\n' +
  '3. 注重实用:推荐具体的景点名称、餐厅、交通工具和预算范围\n' +
  '4. 融入本地特色:突出目的地独特的风土人情和隐藏玩法\n' +
  '5. 温馨提示:提醒天气、签证、安全、语言、货币等实用信息\n\n' +
  '请用中文回复,回答结构清晰,热情友好。';

提示词工程要点

  1. 角色定义 → “资深的旅游攻略专家” 确立 AI 的身份
  2. 能力范围 → 明确涵盖交通、住宿、美食、景点、购物等全方位
  3. 行为准则 → 5 条具体原则,引导 AI 的回答结构
  4. 输出约束 → “用中文回复,结构清晰” 控制回复风格

4.3 SSE 流式数据解析 — 核心难点攻克

SSE(Server-Sent Events)是 AI API 常用的流式传输协议。服务器将数据以 data: <json> 格式逐行推送给客户端,每行对应一个 token 或一段内容。

SSE 协议格式示例
data: {"choices":[{"delta":{"content":"你"}}]}

data: {"choices":[{"delta":{"content":"好"}}]}

data: {"choices":[{"delta":{"content":"!"}}]}

data: [DONE]
逐行解析器 parseSSEDataLine
function parseSSEDataLine(line: string): string | null {
  const jsonStr = line.slice(5).trim();  // 去掉 "data:" 前缀
  if (!jsonStr) return null;

  try {
    const parsed = JSON.parse(jsonStr) as Record<string, Object>;
    const choices = parsed.choices as Object[];
    if (choices && choices.length > 0) {
      const choice = choices[0] as Record<string, Object>;
      // 流式格式使用 delta,非流式使用 message
      const delta = choice.delta as Record<string, Object>;
      if (delta) return delta.content as string;

      const message = choice.message as Record<string, Object>;
      if (message) return message.content as string;
    }
  } catch (_) { /* 跳过解析失败的行 */ }
  return null;
}

关键实现细节

  • line.slice(5) 精确去掉前 5 个字符 data:
  • JSON.parse 解析 JSON 字符串
  • 同时兼容 delta(流式)和 message(非流式)两种格式
  • try-catch 捕获解析异常,防止单行错误影响后续处理
完整响应体解析 parseFullSSEBody

当底层网络库不支持逐事件触发时,需要从完整响应体中提取所有 SSE 行:

function parseFullSSEBody(body: string): string {
  let result = '';
  const lines = body.split('\n');
  for (const line of lines) {
    const trimmed = line.trim();
    if (trimmed.startsWith('data:')) {
      if (trimmed === 'data:[DONE]') break;  // 结束标记
      const content = parseSSEDataLine(trimmed);
      if (content) result += content;
    }
  }
  return result;
}

4.4 网络请求核心 — queryAI 函数

export function queryAI(
  callbacks: AICallbacks,
  messages: ChatMessage[],
): void {
  // 1. 取消上一次未完成的请求
  if (httpRequestTask) {
    httpRequestTask.destroy();
    httpRequestTask = null;
  }

  const httpRequest = http.createHttp();
  httpRequestTask = httpRequest;

  // 2. 构建请求体(合并 system prompt)
  const fullMessages: ChatMessage[] = [
    { role: 'system', content: SYSTEM_PROMPT },
    ...messages,
  ];
  const requestBody: ChatCompletionRequest = {
    model: 'deepseek-ai/DeepSeek-V3',
    messages: fullMessages,
    stream: true,
    max_tokens: 2048,
    temperature: 0.6,
    top_p: 0.95,
    frequency_penalty: 0,
    thinking_budget: 2048,
  };

  // 3. 状态标记
  let isDone = false;
  let receivedAnyData = false;
  let buffer = '';

  // 4. 注册 dataReceive 事件(SSE 流式接收)
  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. dataEnd 事件
  httpRequest.on('dataEnd', () => {
    if (!isDone) { isDone = true; callbacks.onDone(); }
    httpRequestTask = null;
  });

  // 6. 发起 POST 请求
  httpRequest.request(
    API_URL,
    {
      method: http.RequestMethod.POST,
      header: {
        Authorization: `Bearer ${API_KEY}`,
        'Content-Type': 'application/json',
        Accept: 'text/event-stream',  // 告知服务器需要 SSE
      },
      extraData: JSON.stringify(requestBody),
      connectTimeout: 30000,  // 连接超时 30s
      readTimeout: 120000,    // 读取超时 120s
    },
    (err, resp) => {
      // 错误处理 + 非流式回退逻辑(见下文)
    },
  );
}

4.5 非流式回退机制 — 兼容性保障

HarmonyOS NEXT 的 http 模块在不同版本中对 SSE 的支持表现不一致。部分版本的 dataReceive 事件可能不会被触发。为此,我们实现了完善的非流式回退机制:

// 在 request 回调中,如果 dataReceive 从未触发过
if (!receivedAnyData && resp.result) {
  const bodyStr = typeof resp.result === 'string'
    ? resp.result
    : arrayBufferToString(resp.result as ArrayBuffer);

  // 优先解析 SSE 格式(兼容流式但未触发事件的情况)
  const sseContent = parseFullSSEBody(bodyStr);
  if (sseContent) {
    callbacks.onData(sseContent);
  } else {
    // 回退到 JSON 格式
    const jsonContent = parseNonStreamingBody(bodyStr);
    if (jsonContent) {
      callbacks.onData(jsonContent);
    } else {
      callbacks.onError(`无法解析响应: ${preview}`);
      return;
    }
  }
  if (!isDone) { isDone = true; callbacks.onDone(); }
}

三层回退策略

  1. 首选dataReceive 事件逐 token 推送(最佳体验,打字机效果)
  2. 次选 → 完整响应按 SSE 格式解析(兼容流式响应)
  3. 兜底 → 按非流式 JSON 解析(兼容标准 JSON 响应)

4.6 请求取消机制

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

每次发起新请求前也会自动取消上一次请求,避免多个请求并行导致消息错乱。


五、页面 UI 实现 — Index.ets

5.1 声明式 UI 设计理念

ArkUI 采用声明式 UI 范式,开发者只需描述"UI 应该是什么样子",框架自动处理状态变化后的界面更新。

核心概念:

  • @State 装饰器:标记响应式状态变量,状态变化时自动触发界面重绘
  • @Builder 装饰器:定义可复用的 UI 片段
  • @Entry 装饰器:标记页面入口
  • @Component 装饰器:定义可复用的组件

5.2 页面结构总览

Column (根容器)
├── Row (顶部标题栏) ── Text("🗺️ 旅游攻略问答")
├── Scroll (聊天列表)
│   └── Column
│       ├── ForEach → MessageBubble(item)   ── 用户/AI 消息气泡
│       ├── [if isLoading && currentAIResponse] → AIBubble()  ── 流式内容
│       └── [if isLoading && !currentAIResponse] → LoadingIndicator() ── 等待动效
└── Row (底部输入区)
    ├── TextInput (文本输入框)
    ├── Blank (间距)
    └── Button (发送/取消按钮)

5.3 状态管理

@State messages: MessageItem[] = [ /* 初始欢迎消息 */ ];
@State inputText: string = '';
@State isLoading: boolean = false;
@State currentAIResponse: string = '';

四个 @State 变量控制整个页面的渲染:

  • messages — 聊天历史消息列表,每次 push 新消息自动刷新 UI
  • inputText — 输入框文本,控制发送按钮的启用状态
  • isLoading — 请求状态,控制 loading 显示和按钮交互
  • currentAIResponse — 当前流式回复内容,实时追加显示

5.4 消息气泡组件 (@Builder)

用户消息(绿色右对齐)
if (item.role === 'user') {
  Blank()  // 占位,使气泡靠右
  Column() {
    Text(item.content)
      .fontSize(15)
      .fontColor('#333333')
      .lineHeight(22)
  }
  .padding({ left: 14, right: 14, top: 10, bottom: 10 })
  .backgroundColor('#95EC69')    // 绿色背景
  .borderRadius({
    topLeft: 16, topRight: 4,     // 右上角小圆角(气泡尾巴效果)
    bottomLeft: 16, bottomRight: 16
  })
  .constraintSize({ maxWidth: '75%' })
  .margin({ bottom: 10 })
}

设计细节

  • 使用 Blank() 占位实现靠右布局
  • borderRadius 非对称圆角营造"气泡对话"的视觉风格
  • constraintSize({ maxWidth: '75%' }) 限制气泡最大宽度
  • 颜色 #95EC69 是典型的聊天应用用户气泡绿
AI 消息(白色左对齐,带头像)
Column() {
  Row() {
    Text('🤖').fontSize(18)
    Text(' 攻略助手').fontSize(12).fontColor('#999999')
  }
  .margin({ bottom: 6 })

  Text(item.content)
    .fontSize(15).fontColor('#333333').lineHeight(22)
}
.padding({ left: 14, right: 14, top: 10, bottom: 10 })
.backgroundColor('#FFFFFF')
.borderRadius({
  topLeft: 4, topRight: 16,     // 左上角小圆角
  bottomLeft: 16, bottomRight: 16
})
.constraintSize({ maxWidth: '80%' })

5.5 流式加载状态设计

三种状态的处理:

// 在 Scroll 的 Column 内部
if (this.isLoading) {
  if (this.currentAIResponse) {
    // 已有内容 → 流式打字效果
    this.AIBubble(this.currentAIResponse)
  } else {
    // 等待中 → Loading 动画
    this.LoadingIndicator()
  }
}

Loading 动画组件

@Builder LoadingIndicator() {
  Row() {
    Column() {
      Row() {
        Text('🤖').fontSize(18)
        Text(' 攻略助手').fontSize(12).fontColor('#999999')
      }
      .margin({ bottom: 8 })

      Row() {
        LoadingProgress()       // HarmonyOS 原生加载动画
          .width(24).height(24)
          .color('#FF6B35')     // 橙色主题色
        Text(' 正在思考旅行方案...')
          .fontSize(14).fontColor('#999999')
      }
    }
    .padding({ left: 14, right: 14, top: 10, bottom: 10 })
    .backgroundColor('#FFFFFF')
    .borderRadius(...)
  }
}

5.6 发送按钮的交互状态

Button() {
  if (this.isLoading) {
    LoadingProgress()
      .width(22).height(22).color('#FFFFFF')
  } else {
    Image($r('app.media.startIcon'))
      .width(22).height(22).objectFit(ImageFit.Contain)
  }
}
.backgroundColor(
  this.inputText.trim() && !this.isLoading ? '#FF6B35' : '#CCCCCC'
)
.enabled(!!this.inputText.trim() && !this.isLoading)
.onClick(() => {
  if (this.isLoading) {
    // 取消请求
    cancelAI();
    this.isLoading = false;
    this.currentAIResponse = '';
  } else {
    this.sendMessage();
  }
})

三种状态

  1. 空闲 + 有输入 → 橙色按钮,可点击发送
  2. 空闲 + 无输入 → 灰色按钮,禁用
  3. 加载中 → 显示 LoadingProgress,点击可取消请求

5.7 发送消息流程

sendMessage(): void {
  const text = this.inputText.trim();
  if (!text || this.isLoading) return;

  // 1. 添加用户消息到列表
  this.messages.push({ role: 'user', content: text });
  this.inputText = '';

  // 2. 滚动到底部
  setTimeout(() => {
    this.scroller.scrollEdge(Edge.Bottom);
  }, 100);

  // 3. 准备 AI 请求
  this.isLoading = true;
  this.currentAIResponse = '';

  // 4. 构建历史消息(不含 system prompt)
  const chatHistory: ChatMessage[] = this.messages.map<ChatMessage>((m) => ({
    role: m.role,
    content: m.content,
  }));

  // 5. 调用 AI
  queryAI(
    {
      onData: (text: string) => {
        this.currentAIResponse += text;   // 追加到流式缓冲区
        this.scroller.scrollEdge(Edge.Bottom);  // 自动滚屏
      },
      onDone: () => {
        // 流式完成,将完整回复加入消息列表
        if (this.currentAIResponse) {
          this.messages.push({ role: 'assistant', content: this.currentAIResponse });
        }
        this.isLoading = false;
        this.currentAIResponse = '';
      },
      onError: (errMsg: string) => {
        this.messages.push({ role: 'assistant', content: '😅 抱歉,出错了:' + errMsg });
        this.isLoading = false;
        this.currentAIResponse = '';
      },
    },
    chatHistory,
  );
}

关键点

  • 使用 setTimeout 延迟滚动,确保 DOM 更新完成后才滚动
  • map<ChatMessage>() 显式指定泛型类型,满足 ArkTS 严格类型检查
  • onDone 中将流式内容 currentAIResponse 整体加入消息列表,而非逐 token 加入

六、ArkTS 严格模式与常见编译错误

API 24 引入了更严格的编译检查(arkts-no-untyped-obj-literals 等),以下是开发过程中遇到的典型错误及解决方案:

6.1 arkts-no-untyped-obj-literals

错误:对象字面量必须对应显式声明的类或接口

// ❌ 错误写法
const chatHistory = this.messages.map((m) => ({
  role: m.role,
  content: m.content,
}));

// ✅ 正确写法 — 使用泛型指定类型
const chatHistory: ChatMessage[] = this.messages.map<ChatMessage>((m) => ({
  role: m.role,
  content: m.content,
}));

6.2 maxWidth 在 ColumnAttribute 上不存在

错误:ArkUI 的 Column 组件属性链中不包含 maxWidth 方法

// ❌ 错误写法
Column() { /* ... */ }
  .maxWidth('75%')

// ✅ 正确写法 — 使用 constraintSize
Column() { /* ... */ }
  .constraintSize({ maxWidth: '75%' })

constraintSize 是一个通用的尺寸约束属性,可同时设置 minWidthmaxWidthminHeightmaxHeight

6.3 on 方法已弃用

// 当前写法(可用但产生警告)
httpRequest.on('dataReceive', callback);

// 建议改为(API 24+ 推荐)
// httpRequest.on('dataReceive', callback); 
// 新版本中应使用事件监听器的替代 API

七、性能优化与最佳实践

7.1 网络请求优化

  1. 连接复用:通过 http.createHttp() 创建实例后复用,而不是每次请求都创建新的
  2. 超时配置connectTimeout: 30sreadTimeout: 120s,避免长时间等待
  3. 请求取消:每次新请求前取消上一次,防止回调错乱和资源泄漏

7.2 UI 渲染优化

  1. 条件渲染:使用 if 条件语句而非 Visibility 属性控制组件显示,减少组件树的复杂度和内存占用
  2. ForEach keyForEach 的第三个参数 (item, index) => index.toString() 提供唯一 key,帮助框架高效复用和更新节点
  3. 延迟滚动:状态更新后使用 setTimeout 延迟 50-100ms 再执行滚动,确保布局完成后再触发

7.3 内存管理

  1. 组件资源释放:在 onPageHide 或组件销毁时调用 cancelAI() 取消进行中的网络请求
  2. 流式缓冲区清空onDoneonError 回调中将 currentAIResponse 置空,不保留过期数据

7.4 ArkTS 编码规范

  1. 显式类型声明:所有变量和函数参数都添加类型注解,避免依赖类型推断
  2. 接口先行:先定义接口(如 ChatMessageAICallbacks),再基于接口实现逻辑
  3. 模块化拆分:将网络层 AIChatService 与 UI 层 Index.ets 分离,降低耦合

八、项目部署与测试

8.1 构建命令

# 开发调试构建
hvigorw assembleHap --mode module -p module=entry@default -p product=default

# 生产构建
hvigorw assembleHap --mode module -p module=entry@release -p product=default

8.2 真机调试

  1. 使用 USB 连接 HarmonyOS 设备
  2. DevEco Studio 中点击 Run 按钮
  3. 或使用命令行:
    hdc install entry/build/default/outputs/default/entry-default-unsigned.hap
    

8.3 常见问题排查

问题 原因 解决方案
on has been deprecated httpRequest.on() API 弃用 可忽略(兼容旧 API)
INTERNET 权限警告 未配置网络权限 module.json5 中添加 ohos.permission.INTERNET
签名警告 未配置签名 开发阶段可忽略,发布前在 build-profile.json5 中配置
SSE 不触发 HarmonyOS 版本兼容性 非流式回退机制自动处理
编译失败: 对象字面量 ArkTS 严格模式 添加泛型注解

九、总结与展望

9.1 项目亮点

  1. 完整的 AI 对话应用闭环:从 Ability 生命周期、网络请求、SSE 流式解析到 UI 呈现,覆盖了 HarmonyOS 应用开发的全链路
  2. 专业级提示词工程:5 条旅游攻略原则,确保 AI 输出的专业性和实用性
  3. 健壮的容错机制:三层 SSE 解析回退策略,兼容不同 HarmonyOS 版本的网络行为差异
  4. 优雅的交互设计:气泡对话、流式打字效果、加载动效、自动滚屏等,提供类即时通讯的流畅体验
  5. 声明式 UI 实践:基于 ArkUI 的 @State + @Builder 模式,代码简洁且易于维护

9.2 可扩展方向

  1. 多轮上下文理解:当前已支持多轮对话历史传递,可进一步优化上下文窗口管理
  2. 图片/位置分享:利用 HarmonyOS 的分布式能力,支持分享景点图片和地图位置
  3. 离线知识库:集成本地旅游知识库,在无网络时也能提供基础攻略
  4. 多设备协同:利用 HarmonyOS 分布式技术,手机规划 → 手表查看行程 → 平板展示地图
  5. 语音交互:集成 @kit.VoiceKit,支持语音输入旅游问题

9.3 写在最后

HarmonyOS NEXT 的 ArkTS 语言和 ArkUI 框架为应用开发带来了现代化的声明式编程体验。通过本项目,我们不仅掌握了一个完整的 AI 聊天应用的开发流程,更深入理解了 HarmonyOS 的网络编程、状态管理、类型系统等核心概念。希望本文能为正在学习 HarmonyOS 开发的你提供有价值的参考。

完整项目源码已在本地可用,欢迎在此基础上进行二次开发和创新!


本文基于 HarmonyOS NEXT API 24(SDK 6.1.1)编写,于 2026 年 6 月完成。API 和 SDK 版本更新后部分接口可能发生变化,请以官方文档为准。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐