从零到一:HarmonyOS NEXT 上打造「AI万能手册」—— ArkTS 全栈开发实践

一、缘起:为什么要做「AI万能手册」

2026 年的今天,AI 已融入日常生活。从工作中的效率提升、学习中的疑难解答,到生活技巧、情感疏导、健康咨询,用户越来越需要一个随时随地、即问即答的智能助手。而在 HarmonyOS NEXT 生态中,原生 AI 聊天应用仍是蓝海。因此,我们打造了 「AI万能手册」 —— 一款原生鸿蒙 AI 对话应用,让用户享受到流畅的 AI 原生体验。

1.1 项目定位

「AI万能手册」定位为解决生活中各种实际问题的全能助手,覆盖六大领域:

领域 典型问题
🏢 工作 如何提高工作效率?如何写周报?
📚 学习 怎么记忆更高效?考研如何规划?
🏠 生活 怎样改善睡眠?如何做家常菜?
💕 情感 和伴侣吵架了怎么办?
🏥 健康 久坐腰酸怎么办?
💻 科技 电脑卡顿如何解决?

1.2 技术选型

技术栈 选型 说明
语言 ArkTS(HarmonyOS NEXT) 鸿蒙原生声明式 UI
构建 hvigor 6.26.1 官方构建系统
网络 @kit.NetworkKit 原生 HTTP 通信
模型 DeepSeek-V3(API) 强大中文能力
传输 SSE(Server-Sent Events) 实时逐 token 输出
SDK API 24(Compatible 24.0.0) 广兼容版本

二、项目架构

2.1 初始状态

DevEco Studio 默认生成的 Index.ets 只有 23 行——一个居中显示 “Hello World” 的空白页。而项目中已存在一个名为 111.ets 的服务文件,内部完整实现了 HTTP 请求、SSE 流式解析、非流式回退等逻辑,却被放在了一个无意义的文件名下。我们的任务就是重构架构、重写 UI,把隐形的 AI 能力真正呈现出来。

2.2 最终架构

entry/src/main/ets/
├── entryability/EntryAbility.ets    # 应用入口
└── pages/
    ├── Index.ets                 # 主聊天界面(249 行)
    └── AIChatService.ets         # AI 通信服务(312 行)

核心设计是两层分离

Index.ets(UI层)
  │  import queryAI() / cancelAI()
  ▼
AIChatService.ets(服务层)
  │  POST https://api-ai.gitcode.com/v1/chat/completions
  ▼
DeepSeek-V3 大模型(SSE 流式返回)

三、核心模块详解

3.1 AIChatService:AI 通信服务

3.1.1 系统提示词设计

提示词从原来的"女友对话助手"全面重写为「AI万能手册」:

const SYSTEM_PROMPT: string =
  '你是「AI万能手册」,一个热心、专业的生活助手,擅长解决用户在工作、学习、' +
  '生活、情感、健康、科技等各方面遇到的实际问题。\n\n' +
  '以下是你要遵循的原则:\n' +
  '1. 专业可靠:回答基于可靠知识,不确定时坦承「我不确定」并给出建议的查证方向。\n' +
  '2. 简洁实用:先给出结论和关键步骤,再视需要展开细节。\n' +
  '3. 因人而异:根据问题类型调整语气 — 情感问题温柔共情,技术问题清晰精准,生活技巧简明直接。\n' +
  '4. 鼓励用户:每次回答末尾给一句鼓励或提醒。\n' +
  '5. 注意安全:不提供医疗诊断、法律意见、投资建议等需要专业资质的结论。\n\n' +
  '请用中文回复,保持亲切、有条理。';

五条原则分别针对可信度、可读性、适配性、情绪价值和安全性,尤其是第 5 条明确了 AI 的能力边界。

3.1.2 SSE 流式传输

SSE(Server-Sent Events)是 AI 聊天场景的天然选择——服务器可主动向客户端逐 token 推送数据:

data: {"choices":[{"delta":{"content":"你好"}}]}
data: {"choices":[{"delta":{"content":"!"}}]}
data: {"choices":[{"delta":{"content":"我是"}}]}
data: [DONE]

核心解析函数:

function parseSSEDataLine(line: string): string | null {
  const jsonStr = line.slice(5).trim();  // 去掉 "data:"
  if (!jsonStr) return null;
  try {
    const parsed = JSON.parse(jsonStr);
    const delta = parsed.choices?.[0]?.delta;
    if (delta?.content) return delta.content;
    const message = parsed.choices?.[0]?.message; // 兼容非流式
    if (message?.content) return message.content;
  } catch (_) { /* 跳过非 JSON */ }
  return null;
}
3.1.3 双重保障:流式 + 非流式回退

HarmonyOS 的 http 模块在不同版本上行为有差异——某些环境下 dataReceive 事件(SSE 核心回调)不会被触发。我们设计了双重保障机制

// 场景一:流式(dataReceive 事件)
httpRequest.on('dataReceive', (data: ArrayBuffer) => {
  receivedAnyData = true;
  // 逐行解析 SSE 数据...
});

// 场景二:非流式回退(request 回调体内)
httpRequest.request(API_URL, { ... }, (err, resp) => {
  if (!receivedAnyData && resp.result) {
    // 先 SSE → 再 JSON → 报错
    const sseContent = parseFullSSEBody(bodyStr);
    if (!sseContent) parseNonStreamingBody(bodyStr);
  }
});

这种"先试流式、不行就整段拿"的模式,让应用在不同 HarmonyOS 版本上都能稳定运行。

3.1.4 API 参数调优
参数 说明
model deepseek-ai/DeepSeek-V3 最新版模型
max_tokens 4096 回复长度(原 2048,提升一倍)
temperature 0.7 创造性(原 0.6)
connectTimeout 30000 连接超时 30s
readTimeout 120000 读取超时 2min

3.2 Index.ets:聊天界面

UI 由四个区域构成:

┌────────────────────────────┐
│    AI 万能手册    ← 标题栏  │
├────────────────────────────┤
│  🤖 AI万能手册             │
│  你好!我是AI万能手册...     │
│  ┌──────────────────┐     │ ← 消息列表
│  │ 如何提高工作效率? │     │    (Scroll + Column)
│  └──────────────────┘     │
│  很高兴为你解答...         │
│  ◌◌◌  ← LoadingProgress  │
├────────────────────────────┤
│ ✨ [输入你的问题...]  发送  │ ← 输入区域
└────────────────────────────┘
3.2.1 消息气泡组件
@Component
struct MessageBubble {
  @Prop message: MessageItem;

  build() {
    Row() {
      if (this.message.role === 'user') {
        Blank()
        Column() { Text(this.message.content) }
          .backgroundColor('#007AFF')
          .borderRadius(18)
          .constraintSize({ maxWidth: '80%' })
      } else {
        Column() {
          Row() { Text('🤖'); Text('AI万能手册') }
          Text(this.message.content)
        }
        .backgroundColor('#F0F0F0')
        .borderRadius(18)
        .constraintSize({ maxWidth: '80%' })
        Blank()
      }
    }
  }
}

注意:ArkTS 中 Column 没有 maxWidth 属性,需使用通用属性 .constraintSize({ maxWidth: '80%' })

3.2.2 流式状态管理

用四个 @State 管理响应式状态:

@State messages: MessageItem[] = [];
@State inputText: string = '';
@State isLoading: boolean = false;
@State currentAIContent: string = '';

发送流程:推入用户消息 → 插入空 AI 占位 → 调用 queryAI()onData 触发时用 splice 更新占位内容 → 自动滚动:

queryAI({
  onData: (text: string) => {
    this.currentAIContent += text;
    // splice 触发 @State 响应式更新
    this.messages.splice(aiMsgIndex, 1, {
      role: 'assistant', content: this.currentAIContent,
    });
    setTimeout(() => this.scroller.scrollEdge(Edge.End), 50);
  },
  onDone: () => { this.isLoading = false; },
  onError: (err) => { /* 错误提示 */ },
}, chatHistory);

关键:用 splice 而非直接索引赋值 this.messages[i] = ...,因为 ArkTS 的 @State 数组需要通过结构变化(splice/push/pop)来触发视图重渲染。

3.2.3 快速问题与停止生成
  • ✨ 按钮:随机从预设问题列表选一个填入输入框,降低使用门槛
  • ⏹ 按钮:加载中发送按钮变为停止按钮,调用 cancelAI() 取消请求

四、开发踩坑实录

4.1 @Link 在 ForEach 中失效

现象:子组件用 @Link 绑定 ForEach 迭代的 msg,父组件更新数组后 UI 无变化。

原因:ForEach 传入的是数组元素的副本,不是引用。@Link 需要 @State 引用绑定,副本无法建立此关系。

解决:改为 @Prop。子组件只需展示数据,单向数据流足以满足需求。

4.2 对象字面量需显式类型

错误:Object literal must correspond to some explicitly declared class or interface

原因:ArkTS 类型安全比 TS 更严格,对象字面量必须匹配已声明的接口。

解决:加 as ChatMessage 断言:

this.messages.map(msg => ({
  role: msg.role, content: msg.content
}) as ChatMessage);

4.3 Column 没有 maxWidth

错误:Property 'maxWidth' does not exist on type 'ColumnAttribute'

解决:使用通用尺寸约束方法 .constraintSize({ maxWidth: '80%' }),所有组件均支持。

4.4 SSE 在部分设备不触发 dataReceive

现象httpRequest.on('dataReceive', ...) 在某些 HarmonyOS 版本上不触发,流式输出失效。

解决:在 request 回调中检测 receivedAnyData 标记,若未触发则从完整响应体解析数据——先试 SSE 格式、再试 JSON 格式,兜底报错。

4.5 hvigor 首次构建缓慢

解决:加 --no-daemon 跳过守护进程初始化,直接指定 assembleHap 任务。最终全量编译仅需 7.9 秒


五、构建与验证

hvigorw --no-daemon -p product=default assembleHap

构建流水线耗时:

阶段 耗时
PreBuild 93ms
CompileResource 675ms
CompileArkTS 2.67s
PackageHap 352ms
总计 7.9s

BUILD SUCCESSFUL — 0 错误

编译顺利通过,验证了 ArkTS API 24 的完整兼容性:声明式 UI 组件树、@kit.NetworkKit 原生网络请求、SSE 流式解析逻辑、constraintSize 布局约束等全部正常工作。

警告说明:

  • .on('headerReceive', ...) 已弃用但功能正常
  • ohos.permission.INTERNET 网络权限提示

六、应用亮点与展望

功能特性

特性 实现方式
流式输出 SSE dataReceive 逐 token 实时显示
非流式回退 完整响应体解析兼容不同系统版本
双向停止 cancelAI() 取消进行中请求
快速问题 随机预设列表降低使用门槛
自动滚动 scrollEdge(Edge.End)
欢迎消息 aboutToAppear 自动问候

可扩展方向

  1. Markdown 渲染 — 代码块、列表、表格富文本展示
  2. 语音输入 — 对接 HarmonyOS 语音识别 API
  3. 主题切换 — 暗色模式
  4. 对话缓存 — 本地持久化

七、写在最后

从 23 行的 “Hello World” 到 561 行的完整 AI 聊天应用,这个项目虽小但覆盖了现代应用开发的核心技术栈。几个关键收获:

  1. ArkTS 比 TypeScript 更严格 — 对象字面量需显式类型、@Link/@Prop 需谨慎选择、属性须查官方文档。严格带来的是运行时稳定。

  2. SSE 流式是 AI 聊天体验的灵魂 — 用户实时看到 AI"打字"的过程,体验远超等待完整响应。HarmonyOS 的 dataReceive 事件天然适配。

  3. 防御性编程在跨版本兼容中至关重要 — 非流式回退机制保障了应用在不同 HarmonyOS 版本上都能正常工作。

  4. 工具链成熟 — hvigor 6.26.1 + Node.js 24,全量编译不到 8 秒,体验接近原生开发。

「AI万能手册」 虽然是一个单页面应用,但网络通信、流式数据处理、声明式 UI、状态管理一应俱全,是 HarmonyOS NEXT 入门开发者的一个完整参考项目。


本文由 AtomCode (deepseek-v4-flash) 撰写,代码基于实际编译验证通过的 HarmonyOS NEXT 项目(API 24)。
在这里插入图片描述

Logo

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

更多推荐