


一、引言
随着大语言模型(LLM)技术的快速发展,将 AI 对话能力集成到原生应用中已成为移动开发的刚需。从智能客服到个人助理,从学习辅导到情感陪伴,AI 对话正在改变用户与应用的交互方式。
本文将以一个完整的「AI 万能手册」应用为依托,详细讲解如何在 HarmonyOS NEXT(API 24)上使用 ArkTS 原生框架构建一个支持流式响应的 AI 对话应用。内容涵盖:
- 项目架构设计与页面导航
- 原生 HTTP 网络请求(
@kit.NetworkKit) - SSE(Server-Sent Events)流式响应解析
- 声明式 UI 的聊天气泡组件设计
- 系统提示词(System Prompt)工程
- 状态管理与流式文本拼接
- 编译错误排查与 ArkTS 语法避坑
二、项目架构与入口
2.1 应用入口 EntryAbility
鸿蒙应用的入口是 UIAbility 的子类。每个应用有且只有一个 EntryAbility,它负责应用的初始化、生命周期管理和页面加载。
// entry/src/main/ets/entryability/EntryAbility.ets
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(0x0000, 'App', 'Ability onCreate');
}
onWindowStageCreate(windowStage: window.WindowStage): void {
hilog.info(0x0000, 'App', 'Ability onWindowStageCreate');
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
hilog.error(0x0000, 'App',
'Failed to load content: %{public}s', JSON.stringify(err));
return;
}
hilog.info(0x0000, 'App', 'Succeeded in loading content.');
});
}
onForeground(): void { /* 应用进入前台 */ }
onBackground(): void { /* 应用进入后台 */ }
}
关键点:
loadContent('pages/Index')加载Index.ets页面。路径不含.ets后缀。hilog是鸿蒙的日志工具,来自@kit.PerformanceAnalysisKit。- 生命周期
onCreate→onWindowStageCreate→onForeground→onBackground的顺序是固定的。
2.2 项目文件结构
entry/src/main/ets/
├── entryability/
│ └── EntryAbility.ets # 应用入口
└── pages/
├── Index.ets # AI 聊天主界面
├── AIChatService.ets # AI 服务层(网络请求 + SSE 解析)
├── RunnerPage.ets
└── TabsBottomDemo.ets
2.3 应用架构分层
应用采用经典的三层架构:
Index.ets(UI 层)
↓ 调用 queryAI() / cancelAI()
AIChatService.ets(服务层)
↓ @kit.NetworkKit HTTP 请求
GitCode AI API(AI 模型层)
这种分层的好处是:
- UI 层只关心渲染和用户交互,不关心网络细节
- 服务层封装所有网络和解析逻辑,可独立测试和复用
- AI 模型层可随时切换不同的 API 供应商
三、AI 服务层:AIChatService.ets
服务层是整个应用的「发动机」。它负责将用户的聊天消息通过 HTTP POST 请求发送到 AI API,并通过 SSE(Server-Sent Events)流式接收和解析 AI 的回复。
3.1 数据模型定义
首先定义聊天的核心数据结构:
/** 聊天消息结构体 */
export interface ChatMessage {
role: string; // 'system' | 'user' | 'assistant'
content: string; // 消息文本内容
}
/** 请求体结构体 */
export interface ChatCompletionRequest {
model: string; // 模型名称
messages: ChatMessage[]; // 消息历史
stream: boolean; // 是否流式
max_tokens: number; // 最大生成长度
temperature: number; // 温度参数(0~2)
top_p: number; // 核采样参数
frequency_penalty: number; // 频率惩罚
thinking_budget: number; // 思考预算
}
/** SSE 解析结果回调 */
export interface AICallbacks {
onData: (text: string) => void; // 收到新 token
onDone: () => void; // 响应结束
onError: (errMsg: string) => void; // 错误处理
}
设计考量:
ChatMessage的role字段遵循 OpenAI API 规范:system(系统提示词)、user(用户)、assistant(AI)AICallbacks使用回调模式而不是 Promise,因为 SSE 是流式的——数据会分多次到达,Promise 只能 resolve 一次stream: true是关键标记,告诉 API 以 SSE 格式返回响应
3.2 系统提示词工程
系统提示词(System Prompt)是决定 AI 行为和回答质量的关键。一个好的系统提示词应该包含:
- 角色定义:AI 是谁?
- 能力范围:能解决什么问题?
- 回答结构:如何组织回答?
- 风格约束:语气、长度、格式等
const SYSTEM_PROMPT: string =
'你是一位名叫「AI 万能手册」的智能生活助手,擅长解决用户生活中遇到的各种问题。' +
'你的回答应遵循以下原则:\n\n' +
'1. 领域覆盖:涵盖但不限于以下生活场景——\n' +
' · 情感关系:恋爱沟通、家庭矛盾、友谊维护\n' +
' · 职场工作:职业规划、沟通技巧、压力管理\n' +
' · 学习成长:学习方法、时间管理、技能提升\n' +
' · 健康生活:饮食营养、运动健身、睡眠调节\n' +
' · 日常生活:家务技巧、旅行攻略、消费决策\n' +
' · 心理情绪:焦虑缓解、情绪管理、自我调节\n' +
' · 社交人际:社交技巧、聚会礼仪、沟通话术\n' +
' · 法律常识:消费维权、租房合同、劳动权益(仅作参考,建议咨询专业律师)\n\n' +
'2. 回答结构:每个回答包含——\n' +
' · 共情理解:先理解用户的处境和情绪\n' +
' · 问题分析:简要分析问题的关键点\n' +
' · 实用建议:提供 1~3 条具体可执行的建议\n' +
' · 温馨提示:如有需要,补充注意事项\n\n' +
'3. 回答风格:\n' +
' · 语气温和亲切,像一位有经验的朋友在聊天\n' +
' · 用词通俗易懂,避免过于专业的术语\n' +
' · 建议具体可行,不空泛不鸡汤\n' +
' · 涉及法律/医疗等专业领域时,务必注明「建议咨询专业人士」\n\n' +
'4. 格式要求:\n' +
' · 使用中文回答\n' +
' · 适当使用 emoji 让回答更生动\n' +
' · 分点排列,方便阅读\n' +
' · 保持回答简洁,一般不超过 500 字\n\n' +
'请记住:你的使命是用智慧和温度,帮助用户解决生活中的每一个问题。';
提示词工程要点:
- 角色明确:定义 AI 的名字和使命,让回答有「人格」
- 范围清晰:明确列出 8 大生活领域,避免 AI 回答跑题
- 结构约束:要求「共情→分析→建议→提示」的四段式结构
- 风格约束:温和亲切、通俗易懂、具体可行
- 安全边界:法律/医疗领域必须标注「建议咨询专业人士」
- 格式约束:中文 + emoji + 分点 + 500 字上限
3.3 SSE 流式响应解析
SSE(Server-Sent Events)是一种服务器推送协议,允许服务器向客户端持续发送数据流。AI 对话中的「打字机效果」就是通过 SSE 实现的。
SSE 数据格式如下:
data: {"choices":[{"delta":{"content":"你好"}}]}
data: {"choices":[{"delta":{"content":",我"}}]}
data: {"choices":[{"delta":{"content":"是AI"}}]}
data: [DONE]
每条消息以 data: 开头,以 \n\n 结尾。[DONE] 标记流结束。
/**
* 解析 SSE data 行,提取 content 增量
*/
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 (_) { /* JSON 解析失败,跳过 */ }
return null;
}
解析逻辑:
- 去掉
data:前缀(前 5 个字符) - 将剩余部分解析为 JSON
- 提取
choices[0].delta.content(流式格式) - 如果
delta不存在,尝试message.content(非流式回退)
3.4 非流式回退机制
并非所有的 HarmonyOS 设备都能正确触发 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}`);
}
}
}
回退优先级:
- 流式 dataReceive(最佳体验,逐字显示)
- SSE 格式解析(dataReceive 未触发时,从完整响应体中解析 SSE)
- 非流式 JSON 解析(API 返回完整 JSON)
- 错误提示(以上全部失败)
3.5 完整请求流程
export function queryAI(
callbacks: AICallbacks,
messages: ChatMessage[],
): void {
// 1. 取消上一次未完成的请求
if (httpRequestTask) {
httpRequestTask.destroy();
httpRequestTask = null;
}
// 2. 创建 HTTP 请求
const httpRequest = http.createHttp();
httpRequestTask = httpRequest;
// 3. 构建完整消息列表(系统提示词 + 对话历史)
const fullMessages: ChatMessage[] = [
{ role: 'system', content: SYSTEM_PROMPT },
...messages,
];
// 4. 构建请求体
const requestBody: ChatCompletionRequest = {
model: 'deepseek-ai/DeepSeek-V3',
messages: fullMessages,
stream: true,
max_tokens: 2048,
temperature: 0.6,
};
// 5. 注册 SSE 监听
httpRequest.on('dataReceive', (data: ArrayBuffer) => {
// 逐块接收 SSE 数据
});
httpRequest.on('dataEnd', () => {
// 数据接收完毕
});
// 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,
readTimeout: 120000,
}, callback);
}
四、UI 层:Index.ets 聊天界面
UI 层负责渲染聊天界面和处理用户交互。主要包含三个区域:顶部标题栏、消息列表区、底部输入区。
4.1 聊天气泡组件 ChatBubble
聊天气泡是聊天界面的核心视觉元素。我们需要区分用户消息和 AI 消息:
@Component
struct ChatBubble {
private msg: ChatMessage = { role: 'user', content: '' };
private isLoading: boolean = false;
build() {
Column() {
if (this.msg.role === 'user') {
// ── 用户消息:蓝色气泡,右对齐 ──
Row() {
Blank() // 左侧弹簧,将气泡推到右侧
Column() {
Text(this.msg.content)
.fontSize(15).fontColor('#ffffff')
}
.padding(14)
.backgroundColor('#2d5f8a') // 蓝色气泡
.borderRadius({
topLeft: 16, topRight: 4, // 右上角小圆角 → "尾巴"效果
bottomLeft: 16, bottomRight: 16
})
.constraintSize({ maxWidth: '80%' })
}
.width('100%')
} else {
// ── AI 消息:灰色气泡 + 🤖 头像,左对齐 ──
Row() {
// AI 头像
Column() { Text('🤖').fontSize(20) }
.width(36).height(36)
.backgroundColor('#eef2f7').borderRadius(18)
.margin({ right: 8 })
// 气泡内容
Column() {
if (this.isLoading && !this.msg.content) {
// ★ 正在输入动画:三个小圆点依次闪烁 ★
Row() {
ForEach([0, 1, 2], (idx: number) => {
Circle()
.width(6).height(6).fill('#2d5f8a')
.opacity(0.4 + idx * 0.3) // 透明度依次递增
.margin({ left: 2, right: 2 })
})
}
.padding(14).backgroundColor('#f0f4f8').borderRadius(16)
} else {
Text(this.msg.content)
.fontSize(15).fontColor('#1a1a2e')
}
}
.padding(14)
.backgroundColor('#f0f4f8') // 灰色气泡
.borderRadius({
topLeft: 4, topRight: 16, // 左上角小圆角 → "尾巴"效果
bottomLeft: 16, bottomRight: 16
})
.constraintSize({ maxWidth: '70%' })
Blank() // 右侧弹簧
}
.width('100%')
}
}
.margin({ bottom: 12 })
}
}
设计要点:
- 用户气泡右对齐:使用
Blank()占据左侧空间,将气泡推到右侧 - AI 气泡左对齐:左侧放头像,右侧放气泡,使用
Blank()占据右侧空间 - 圆角方向差异:用户气泡的右上角小圆角(4px),AI 气泡的左上角小圆角(4px),模拟聊天气泡的「尾巴」
- 加载动画:
isLoading为 true 且内容为空时,显示三个渐变透明度的圆点
4.2 状态管理
页面级状态使用 @State 装饰器管理:
@Entry
@Component
struct AIUniversalManualPage {
@State messages: ChatMessage[] = []; // 聊天消息列表
@State inputText: string = ''; // 输入框文本
@State isLoading: boolean = false; // 是否正在请求 AI
@State currentAIResponse: string = ''; // 流式拼接中的 AI 回复
}
@State 的作用域规则:
@State变量变化时,所在组件的build()方法会重新执行- 只有被
@State装饰的变量才能触发 UI 更新 - 普通成员变量变化不会触发重渲染
4.3 发送消息流程
sendMessage(text: string): void {
if (this.isLoading || !text.trim()) return;
// 1. 添加用户消息到列表
const userMsg: ChatMessage = { role: 'user', content: text.trim() };
this.messages.push(userMsg);
this.inputText = ''; // 清空输入框
this.isLoading = true;
this.currentAIResponse = ''; // 清空之前的回复
// 2. 构建对话历史(保留最近 20 条)
const history: ChatMessage[] = this.messages
.filter(m => m.content !== '')
.slice(-20);
// 3. 调用 AI 服务
queryAI(
{
onData: (content: string) => {
// 流式拼接:每收到一个 token 就追加到 currentAIResponse
this.currentAIResponse += content;
},
onDone: () => {
// 流式结束:将完整回复加入消息列表
if (this.currentAIResponse) {
this.messages.push({
role: 'assistant',
content: this.currentAIResponse,
});
}
this.currentAIResponse = '';
this.isLoading = false;
},
onError: (errMsg: string) => {
// 错误处理:显示友好错误信息
this.messages.push({
role: 'assistant',
content: `😅 抱歉,我遇到了问题:${errMsg}`,
});
this.isLoading = false;
},
},
history,
);
}
关键流程:
- 用户消息立即加入
messages列表 → 气泡立即显示 isLoading = true→ 显示「正在输入」动画onData每次被调用时,currentAIResponse更新 → UI 中流式显示文字onDone被调用时,将完整回复加入messages→ 固化为静态气泡onError时显示错误信息
4.4 空白引导页
当用户首次打开应用时,显示引导页而不是空列表:
if (this.messages.length === 0) {
Column() {
Text('🤖').fontSize(56)
Text('AI 万能手册').fontSize(22).fontWeight(FontWeight.Bold)
Text('解决你生活中的各种问题').fontSize(14).fontColor('#666')
// 6 大能力卡片
Row() {
ForEach(features, (item: FeatureItem) => {
Column() {
Text(item.icon).fontSize(24)
Text(item.text).fontSize(11).fontColor('#555')
}
.width(72).height(72)
.backgroundColor('#f5f7fa').borderRadius(12)
})
}
.justifyContent(FlexAlign.Center)
// 4 个快捷问题按钮
Row() {
ForEach(QUICK_QUESTIONS, (q: string) => {
Text(q).padding(12)
.backgroundColor('#eef2f7').borderRadius(16)
.onClick(() => { this.sendMessage(q); })
})
}
}
}
五、编译错误排查与 ArkTS 语法避坑
在开发过程中,我们遇到并修复了多个编译错误。以下是最常见的 7 类错误及其解决方案。
5.1 类型推断错误
错误信息:
Use explicit types instead of "any", "unknown" (arkts-no-any-unknown)
原因:ArkTS 默认禁止 any 类型,要求显式类型注解。
修复:
// ❌ 错误:隐式 any
ForEach(data, (item) => { ... })
// ✅ 正确:显式类型
ForEach(data, (item: FeatureItem) => { ... })
// 或使用 as 断言
ForEach([
{ icon: '💕', text: '情感关系' },
] as FeatureItem[], (item: FeatureItem) => { ... })
5.2 属性不存在
错误信息:
Property 'maxWidth' does not exist on type 'ColumnAttribute'
原因:ArkTS 组件的属性名可能与预期不同。
修复:
// ❌ 错误:maxWidth 不存在
Column() { }
.maxWidth('80%')
// ✅ 正确:使用 constraintSize
Column() { }
.constraintSize({ maxWidth: '80%' })
5.3 Flex 容器属性差异
错误信息:
Property 'flexDirection' does not exist on type 'FlexAttribute'. Did you mean 'direction'?
Property 'flexWrap' does not exist on type 'FlexAttribute'
Property 'justifyContent' does not exist on type 'FlexAttribute'
原因:在 HarmonyOS NEXT API 24 中,Flex 组件的属性集非常有限。justifyContent、flexDirection 等属性仅在 Row 和 Column 上可用。
修复:
// ❌ 错误:Flex 没有 justifyContent
Flex() { }
.justifyContent(FlexAlign.Center)
// ✅ 正确:使用 Row 替代
Row() { }
.justifyContent(FlexAlign.Center)
总结:ArkUI 中 Flex、Row、Column 的关系:
Row= 弹性水平容器(支持 justifyContent、alignItems、layoutWeight)Column= 弹性垂直容器(支持 justifyContent、alignItems、layoutWeight)Flex= 底层弹性容器(API 24 中属性有限,大部分场景用 Row/Column 替代)
5.4 overlay 回调格式
错误信息:
Argument of type '{ builder: () => TextAttribute; }' is not assignable to parameter of type 'string | CustomBuilder | ComponentContent<Object>'
原因:overlay() 方法接受一个 CustomBuilder 函数,而不是一个包含 builder 属性的对象。
修复:
// ❌ 错误:对象格式
Circle()
.overlay({
builder: () => Text('↑').fontColor('#ffffff')
})
// ✅ 正确:直接传函数
Circle()
.overlay((): void => {
Text('↑').fontSize(20).fontColor('#ffffff')
})
5.5 私有属性初始化
警告信息:
Property 'msg' is private and can not be initialized through the component constructor
原因:在 ArkTS 中,组件的 private 属性不能通过构造函数参数初始化。
修复:这只是一个警告,不影响运行。可以将 private 改为 public 或移除访问修饰符:
// 有警告:private 属性不能通过构造函数传值
@Component
struct ChatBubble {
private msg: ChatMessage = { role: 'user', content: '' };
}
// 无警告:移除 private
@Component
struct ChatBubble {
msg: ChatMessage = { role: 'user', content: '' };
}
5.6 文本字符区分
问题描述:发送按钮显示汉字「上」而非箭头符号「↑」。
原因:在代码中写了 Text("上") 而不是 Text('↑')。
修复:
// ❌ 显示汉字
Text("上").fontSize(20)
// ✅ 显示箭头
Text('↑').fontSize(20)
Unicode 箭头符号需要用单引号包裹,
"上"是汉字,'↑'是箭头符号。
5.7 权限配置
警告信息:
To use this API, you need to apply for the permissions: ohos.permission.INTERNET
原因:网络请求需要 ohos.permission.INTERNET 权限。
修复:在 module.json5 中添加:
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
}
]
}
}
六、ArkTS 组件设计模式
6.1 @Builder 自定义构建器
@Builder 是 ArkTS 中复用 UI 片段的核心机制。它类似于一个不返回值的函数,可以在 build() 方法中直接被调用:
@Component
struct MyComponent {
@State count: number = 0;
build() {
Column() {
this.MyButton('点击', '#2d5f8a')
}
}
@Builder
MyButton(label: string, color: string) {
Button(label)
.backgroundColor(color)
.fontColor('#ffffff')
.onClick(() => { this.count++ })
}
}
在底部 Tabs 导航中,我们大量使用 @Builder 来自定义 Tab 样式:
.tabBar(this.BottomTabBuilder(idx, tab))
@Builder
BottomTabBuilder(index: number, tab: TabData) {
Column() {
Stack() {
Text(tab.icon).fontSize(22)
if (tab.badge > 0) {
Text(`${tab.badge}`)
.backgroundColor('#e74c3c').borderRadius(8)
}
}
Text(tab.label).fontSize(10)
}
}
6.2 @BuilderParam 插槽模式
@BuilderParam 是 ArkTS 的「插槽」机制,允许父组件向子组件注入 UI 片段:
@Component
struct SectionCard {
@BuilderParam content?: () => void;
build() {
Column() {
// ... 标题和描述
if (this.content) {
this.content() // ← 渲染注入的内容
}
// ... 代码块
}
}
}
// 使用
SectionCard({
content: MyCustomContent() // ← 注入自定义内容
})
这种模式在演示页面中广泛使用,实现了「通用卡片容器 + 可变内容」的优雅分离。
6.3 @State + @Link 数据驱动
@State 是组件的内部状态,@Link 是父组件向子组件传递的引用状态:
@Component
struct Child {
@Link value: number;
build() {
Button(`值: ${this.value}`)
.onClick(() => { this.value++ }) // ★ 修改 @Link 会同步到父组件 ★
}
}
@Component
struct Parent {
@State count: number = 0;
build() {
Column() {
Child({ value: this.count }) // 传递 @State 给 @Link
}
}
}
七、AI 对话应用最佳实践
7.1 对话历史管理
// 保留最近 N 条消息,避免超出 token 上限
const history = messages
.filter(m => m.content !== '') // 过滤空消息
.slice(-20); // 最多保留 20 条
原则:
- 保留系统提示词 + 最近 20 条对话
- 过滤掉空的 AI 回复(流式拼接过程中产生的临时空字符串)
- 系统提示词始终在消息列表最前面
7.2 请求取消机制
当用户快速发送多条消息时,需要取消上一次未完成的请求:
let httpRequestTask: http.HttpRequest | null = null;
export function cancelAI(): void {
if (httpRequestTask) {
try {
httpRequestTask.destroy();
} catch (_) { /* ignore */ }
httpRequestTask = null;
}
}
在 UI 层,提供「停止」按钮和「清空」按钮都调用 cancelAI():
// 停止按钮(仅加载中可见)
if (this.isLoading) {
Text('停止').onClick(() => {
cancelAI();
this.isLoading = false;
})
}
// 清空按钮
Text('清空').onClick(() => {
cancelAI();
this.messages = [];
this.currentAIResponse = '';
this.isLoading = false;
})
7.3 错误处理策略
onError: (errMsg: string) => {
// 向用户显示友好错误信息,而非崩溃或静默失败
this.messages.push({
role: 'assistant',
content: `😅 抱歉,我遇到了问题:${errMsg}`,
});
this.isLoading = false;
}
错误处理原则:
- 绝不崩溃:所有网络错误都应捕获并显示
- 友好提示:使用 emoji 和口语化表达
- 显示错误详情:帮助用户判断是网络问题还是 API 问题
- 恢复状态:确保
isLoading被重置,UI 恢复正常
八、性能优化
8.1 流式渲染 vs 全量渲染
流式渲染(SSE)的核心优势是「逐字显示」,用户无需等待完整的 AI 回复即可开始阅读。这在长回复场景下大幅提升了用户体验。
实现原理:
- AI 服务器将回复拆成多个 token
- 每个 token 到达后,
onData回调被触发 currentAIResponse累加新内容@State触发 UI 重渲染- 气泡中的文字实时更新
8.2 对话历史截断
AI 模型的 token 上限是有限的(DeepSeek-V3 支持 32K tokens)。如果不截断历史,过长的对话会导致 API 调用失败。我们的策略是保留最近 20 条消息,这在实际使用中已足够维持上下文连贯性。
8.3 请求超时配置
connectTimeout: 30000, // 连接超时 30 秒
readTimeout: 120000, // 读取超时 120 秒
较长的读取超时时间是因为 AI 生成完整回复可能需要 10-60 秒(取决于回复长度和服务器负载)。
九、ArkTS vs TypeScript/JavaScript 差异总结
| 特性 | TypeScript | ArkTS |
|---|---|---|
any 类型 | 允许 | ❌ 禁止 |
unknown 类型 | 允许 | ❌ 禁止 |
| 联合类型 | 支持 | 有限支持 |
Flex 组件属性 | — | 仅支持基础属性 |
Row/Column | — | 支持 justifyContent/alignItems |
overlay() | 对象格式 | 函数格式 |
@State | 无 | 必须用于响应式数据 |
| 私有属性传参 | 允许 | 警告 |
| 模块导入 | ES Module | @kit.xxx 格式 |
十、总结与展望
本文通过一个完整的「AI 万能手册」应用,详细讲解了在 HarmonyOS NEXT(API 24)上使用 ArkTS 构建 AI 对话应用的完整流程。从项目架构、服务层设计、SSE 流式解析、UI 组件设计到编译错误排查,覆盖了全链路开发要点。
核心技术点回顾:
- 网络层:使用
@kit.NetworkKit的http模块发起 SSE 请求 - 数据层:通过回调模式实现流式数据拼接
- UI 层:
@State驱动消息列表实时更新 - 提示词工程:通过 System Prompt 精确控制 AI 回答行为和质量
- 错误处理:三层回退机制保障网络异常时的可用性
AI 对话应用只是鸿蒙原生 AI 集成的起点。后续可以扩展的方向包括:
- 加入 TTS(文本转语音)能力,让 AI「说」出回复
- 接入图片理解模型,支持多模态交互
- 结合本地数据库,实现对话持久化
- 加入语音输入,提升输入效率

1万+

被折叠的 条评论
为什么被折叠?



