AI 修仙大法:当鸿蒙遇上修仙 —— 古风 AI 对话应用开发实战
AI 修仙大法:当鸿蒙遇上修仙 —— 古风 AI 对话应用开发实战(API 24)
用 ArkTS 打造一位会修仙的 AI 老祖,全部兼容 OpenHarmony 6.1.1
目录
- 缘起:为什么会有 AI 修仙大法
- 核心理念:修仙语境 × 实用内核
- 整体架构与技术栈
- 古风 UI 的设计哲学
- 系统提示词:如何给 AI 注入修仙灵魂
- SSE 流式响应与修仙动画的融合
- API 24 兼容性实战记录
- 代码深度解读
- 颜色体系:在 API 24 中营造古风意境
- 性能优化与注意事项
- 部署与使用指南
- 总结与修仙感悟
1. 缘起:为什么会有 AI 修仙大法
1.1 一个有趣的想法
想象一下:当你向 AI 询问"我最近工作压力很大怎么办"时,AI 没有用冰冷的机器人语气回答,而是说——
“道友,依老夫观之,你這是遇到了功法瓶頸。你如今處於『金丹中期』境界,欲破此關,需先固本培元,再尋突破之機。且聽老夫道來……”
是不是瞬间就有画面感了?
AI 修仙大法 正是这样一个跨界融合的项目。它把传统 AI 对话助手的实用内核,包裹在一层浓郁的修仙文化外衣之下,让每一次问答都变成一场"老祖赐教"的修行体验。
1.2 修仙文化的当代价值
修仙玄幻是中国网络文学中最受欢迎的题材之一。但修仙文化不只是在小说里打怪升级——它本质上是一套关于成长、突破、修心、悟道的隐喻系统:
| 修仙概念 | 现实映射 |
|---|---|
| 练气筑基 | 学习基础知识、培养习惯 |
| 金丹元婴 | 专业技能形成、核心竞争力 |
| 化神炼虚 | 认知升级、思维突破 |
| 渡劫飞升 | 重大挑战、职业转型 |
| 心魔劫数 | 焦虑、拖延、自我怀疑 |
| 灵丹妙药 | 高效方法、实用工具 |
| 功法秘籍 | 知识体系、方法论 |
| 道心坚定 | 目标明确、意志力 |
把日常生活问题映射到修仙体系里,天然具有趣味性和记忆点。
1.3 项目定位
| 维度 | 描述 |
|---|---|
| 应用名称 | AI 修仙大法 |
| 角色设定 | 青云山逍遥老祖(十萬年修为) |
| 目标用户 | 修仙爱好者、二次元用户、泛娱乐用户 |
| 核心功能 | AI 知识问答,修仙化包装 |
| 技术基线 | HarmonyOS SDK 24(API 24) |
| 交互方式 | 文本对话 + 流式输出 |
1.4 技术挑战
在 API 24 环境下实现这个项目,我们面临四大挑战:
- UI 风格:如何用有限的 API 营造古风意境?
- 角色一致性:如何让 AI 始终维持修仙老祖的人设?
- 流式体验:如何在 Android 风格的滚动列表里实现流畅逐字输出?
- 兼容性:API 24 中大量高级 API 不可用,如何找到替代方案?
2. 核心理念:修仙语境 × 实用内核
2.1 双层架构
AI 修仙大法的回答采用"双层架构":
┌─────────────────────────────────────┐
│ 外层:修仙语境 │
│ 功法 / 境界 / 心法 / 灵丹 / 劫数 │
├─────────────────────────────────────┤
│ 内层:实用内核 │
│ 具体步骤 / 可执行建议 / 真实方案 │
└─────────────────────────────────────┘
2.2 语境映射表
| 用户问题 | 修仙翻译 | 实质建议 |
|---|---|---|
| “代码写不出来” | “功法参悟受阻” | 拆解问题 → 查阅文档 → 调试步骤 |
| “和女朋友吵架了” | “情劫降临” | 共情 → 沟通 → 和解策略 |
| “怎么减肥?” | “淬体筑基法” | 饮食 → 运动 → 作息方案 |
| “要不要换工作?” | “机缘抉择” | 利弊分析 → 风险评估 → 决策框架 |
| “总是拖延怎么办?” | “心魔缠身” | 原因分析 → 番茄钟 → 目标拆解 |
2.3 老祖的对话风格
系统提示词规定了老祖的六大人设特征:
const SYSTEM_PROMPT =
'你是一位活了十万年的修仙老祖。\n' +
'1. 修仙语境:把所有问题类比为修炼之道\n' +
'2. 境界体系:用练气/筑基/金丹/元婴/化神/炼虚/合体/大乘/渡劫来评估进度\n' +
'3. 语气古风:使用"老夫""道友""善""妙""心魔""道心"等用语\n' +
'4. 实用为本:内核必须提供可落地的真实建议\n' +
'5. 鼓励为主:引导用户找到自己的道\n' +
'6. 称呼:自称"老夫"或"本座",称呼用户为"道友"'
2.4 为何选择 DeepSeek-V3
| 因素 | DeepSeek-V3 | 其他模型 |
|---|---|---|
| 角色扮演能力 | 优秀,能稳定维持人设 | 参差不齐 |
| 中文古风理解 | 出色(中文原生训练) | 一般 |
| API 兼容性 | OpenAI 协议,SSE 流式 | 兼容或有差异 |
| 性价比 | Token 价格低廉 | 相对较高 |
3. 整体架构与技术栈
3.1 架构总览
┌─────────────────────────────────────────┐
│ Index.ets │
│ @State 消息列表 / 输入 / 加载状态 │
│ @Builder 气泡组件 / 加载指示器 │
│ sendMessage() / scrollToBottom() │
├─────────────────────────────────────────┤
│ AIChatService.ets │
│ queryAI() — 构建请求 + SSE 监听 │
│ cancelAI() — 请求取消 │
│ parseSSEDataLine() — SSE 行解析 │
│ parseFullSSEBody() — 完整体回退解析 │
├─────────────────────────────────────────┤
│ @kit.NetworkKit (http) │
│ POST → api.gitcode.com/v1/chat/completions │
│ SSE dataReceive → dataEnd │
└─────────────────────────────────────────┘
3.2 技术栈明细
| 层面 | 技术选型 | 版本 / API |
|---|---|---|
| 语言 | ArkTS | 5.0 (API 24) |
| UI 框架 | ArkUI 声明式 | OpenHarmony 6.1.1 |
| 网络 | @kit.NetworkKit http |
API 24 |
| AI 模型 | DeepSeek-V3 | gitcode API |
| 通信协议 | REST + SSE | OpenAI 兼容 |
| 构建工具 | Hvigor | 5.x |
| 包名 | com.example.design20 | - |
3.3 三层职责分离
| 层 | 文件 | 核心职责 |
|---|---|---|
| UI 层 | Index.ets |
组件渲染、用户交互、消息管理 |
| 服务层 | AIChatService.ets |
网络请求、SSE 解析、错误回退 |
| 配置层 | 常量定义 | API URL、API Key、系统提示词 |
4. 古风 UI 的设计哲学
4.1 色彩体系:黑夜 + 鎏金
修仙大法的 UI 色彩体系来自中国古代文人画的审美传统——黑纸金墨。
主背景 #0D0D1A 极黑夜色(墨池深处)
顶栏背景 #1A1A2E 深靛蓝(夜空)
标题金色 #D4AF37 鎏金(御笔朱批)
正文米色 #E8D5B7 宣纸白(古卷泛黄)
输入背景 #2A2A3E 砚台灰(墨色未干)
用户气泡 #2A3A2A 墨绿(青竹)
老祖气泡 #1E1E30 紫灰(道袍)
边框金色 #8B7355 古铜(香炉)
4.2 标题栏:御笔钦题
Stack() {
Rect().width('100%').height(64).backgroundColor('#1A1A2E')
Rect().width('100%').height(2).backgroundColor('#D4AF37').position({ x:0, y:62 })
Row() {
Text('⚜').fontSize(16).fontColor('#D4AF37')
Text('AI 修仙大法').fontSize(22).fontWeight(FontWeight.Bold).fontColor('#D4AF37')
Text('⚜').fontSize(16).fontColor('#D4AF37')
}
Text('—— 老祖指點 · 道法自然 ——').fontSize(10).fontColor('#8B7355').position({ x:'50%', y:48 })
}
设计细节:
- 顶部金色细线如同古书的书眉装饰线
- 两侧 ⚜ 符号模拟玉玺印章
- 副标题使用小号字和古铜色,致敬落款题跋
4.3 老祖头像:道骨仙风
由于 API 24 不支持 .overlay(组件),老祖头像用 Stack 双层圆实现:
Stack() {
Circle().width(36).height(36).backgroundColor('#2A2A3E') // 外圈
Circle().width(32).height(32).backgroundColor('#3A2A1A') // 内圈
Text('祖').fontSize(14).fontWeight(FontWeight.Bold).fontColor('#D4AF37')
}
双层圆形模拟道袍领口 + 内衬,"祖"字用金色呈现,视觉上像一个道家护身符。
4.4 用户气泡:青竹简牍
Text(content)
.fontSize(16)
.fontColor('#E8D5B7') // 米色文字
.backgroundColor('#2A3A2A') // 墨绿底色
.borderRadius({ topLeft: 16, topRight: 4, bottomLeft: 16, bottomRight: 16 })
墨绿色底 + 米色文字,灵感来自竹简刻字。右上角的小圆角模拟纸张层叠的错落感。
4.5 老祖气泡:宣纸古卷
Text(content)
.fontSize(16)
.fontColor('#E8D5B7')
.backgroundColor('#1E1E30') // 紫灰底色
.borderRadius({ topLeft: 4, topRight: 16, bottomLeft: 16, bottomRight: 16 })
紫灰色底比墨绿更"仙气",左上角的小圆角与老祖头像形成视觉连接,仿佛老祖执笔书写。
4.6 加载动画:掐指一算
Row() {
Text('老').Text('夫').Text('掐').Text('指').Text('一').Text('算').Text('…')
}
.backgroundColor('#1E1E30')
.borderRadius(16)
“老夫掐指一算…” 七个字 + 省略号,比枯燥的 spinning indicator 更有代入感。
5. 系统提示词:如何给 AI 注入修仙灵魂
5.1 提示词设计原则
系统提示词(System Prompt)是 AI 行为的总控。设计时遵循 ROLE 框架:
| 维度 | 说明 | 修仙示例 |
|---|---|---|
| R — Role | 明确身份 | “活了十万年的修仙老祖” |
| O — Objective | 核心目标 | “以修炼之道解读万事” |
| L — Language | 语言风格 | “老夫”“道友”“妙哉” |
| E — Examples | 范式引导 | 功法/境界/心法比喻 |
5.2 完整提示词
const SYSTEM_PROMPT =
'你是一位活了十万年的修仙老祖,通晓天地大道、万法本源。' +
'无论用户向你询问什么——工作、学习、情感、健康、还是人生困惑——' +
'你都用修仙的框架来解读和回答。\n\n' +
'以下是你要遵循的原则:\n' +
'1. 修仙语境:把一切问题类比为修炼之道。\n' +
'2. 境界体系:用练气/筑基/金丹/元婴/化神/炼虚/合体/大乘/渡劫来评估进度。\n' +
'3. 语气风格:古风但不晦涩,使用"老夫""道友""善""心魔""道心"等用语。\n' +
'4. 实用为本:内核必须给出可落地的真实建议。\n' +
'5. 鼓励为主:引导用户找到自己的道。\n' +
'6. 自称"老夫"或"本座",称呼用户为"道友"。'
5.3 提示词中的关键控制点
第 1 条 — 修仙语境:这是最核心的指令。它告诉 AI 要进行"语义映射",把现实问题翻译成修仙语言。
第 4 条 — 实用为本:这是命门。修仙包装不能牺牲实用性,否则就成了"不说人话"。这一条保证 AI 内核仍然是真正有用的知识助手。
第 5 条 — 鼓励为主:修仙叙事天然倾向"成长型思维"——没有失败,只有"机缘未到"。这个设定让 AI 天然具有正向激励效果。
5.4 角色一致性的挑战
AI 模型在长对话中容易"出戏"(忘记自己的人设)。解决方案:
- 每次请求都带 System Prompt:而不是只在首轮传入
- 历史消息上下文:通过
fullMessages数组传递 - 风格短语锚定:提示词中的"老夫""道友"等关键词引导 AI 持续使用修仙用语
// 每次 queryAI 调用都插入 SYSTEM_PROMPT
const fullMessages: ChatMessage[] = [
{ role: 'system', content: SYSTEM_PROMPT },
...messages,
]
6. SSE 流式响应与修仙动画的融合
6.1 流式体验设计
AI 修仙大法的流式体验分为三个阶段:
用户发送 → [loading: 老夫掐指一算…] → 逐字输出老祖回答 → 完成
6.2 流式渲染的代码实现
onData: (chunk: string) => {
this.currentResponse += chunk
const lastIdx = this.messages.length - 1
const lastMsg = this.messages[lastIdx]
if (lastMsg && lastMsg.role === 'user') {
// 首次收到 token:插入 AI 消息
this.messages.push({ role: 'assistant', content: this.currentResponse })
} else if (lastMsg && lastMsg.role === 'assistant') {
// 后续 token:原地更新
this.messages[lastIdx] = { role: 'assistant', content: this.currentResponse }
}
this.scrollToBottom()
}
6.3 从 loading 切换到流式渲染的时机
时间线:
用户点击发送 → isLoading=true → loadingIndicator 显示
↓
queryAI 调用 → onData 首次触发 → isLoading 继续保持
↓
新 AI 消息 push 到 messages → loading 仍在(新消息下方)
↓
onData 继续触发 → 更新已有 AI 消息内容 → 用户看到"逐字输出"
↓
onDone 触发 → isLoading=false → loading 消失
这里的关键设计是:loading 组件和 AI 消息可以同时存在。当第一条 token 到达时,AI 消息插入到 loading 上方,用户看到"老祖正在写字"的同时,文字已经在逐行出现。
6.4 自动滚动
每次收到新 token 或状态变更,都触发滚动到底部:
scrollToBottom(): void {
setTimeout(() => {
this.scroller.scrollEdge(Edge.Bottom)
}, 100) // 100ms 确保 UI 已更新
}
7. API 24 兼容性实战记录
7.1 兼容性问题全景
在开发 AI 修仙大法的过程中,我们遇到了以下 API 24 特有的兼容性问题:
| 问题 | 文件 | 行号 | 错误信息 | 严重程度 |
|---|---|---|---|---|
.fill() 不可用 |
Index.ets | Circle 组件 | Property 'fill' does not exist |
ERROR |
.overlay(组件) 不支持 |
Index.ets | Circle 使用 | Unexpected token |
ERROR |
Color.fromArgb() 不存在 |
Index.ets | 颜色构造 | Property 'fromArgb' does not exist |
ERROR |
Color.Purple 未定义 |
Index.ets | 命名颜色 | Property 'Purple' does not exist |
ERROR |
.fillColor() 不可用 |
Index.ets | 按钮图标 | Property 'fillColor' does not exist |
ERROR |
7.2 逐个击破:详细解决方案
7.2.1 形状着色:.fill() → .backgroundColor()
问题:Circle().fill('#D4AF37') 在 API 24 中编译报错。
原因:fill 属性是 API 26 引入的,API 24 的形状组件不支持着色方法。
修复:
// ❌ API 24 不允许
Circle().width(32).height(32).fill('#D4AF37')
// ✅ API 24 兼容
Circle().width(32).height(32).backgroundColor('#D4AF37')
原理:backgroundColor 是通用组件属性,所有组件都支持;fill 是形状组件专有着色方法,API 26 才引入。
7.2.2 overlay 组件传递:.overlay(Text()) → Stack 嵌套
问题:.overlay(Text('祖').fontSize(14)) 导致 Rollup 抛出 Unexpected token。
原因:API 24 的 overlay 方法签名只接受 string | CustomBuilder 类型,不能直接传组件表达式。
修复:
// ❌ API 24 不允许
Circle().width(32).height(32).backgroundColor('#3A2A1A')
.overlay(Text('祖').fontSize(14).fontColor('#D4AF37'))
// ✅ API 24 兼容 — Stack 嵌套
Stack() {
Circle().width(36).height(36).backgroundColor('#2A2A3E')
Circle().width(32).height(32).backgroundColor('#3A2A1A')
Text('祖').fontSize(14).fontWeight(FontWeight.Bold).fontColor('#D4AF37')
}
.width(36).height(36)
优势:用 Stack 替代 overlay 不仅兼容 API 24,而且布局控制更灵活——可以实现双层圆、任意间距控制等 overlay 做不到的效果。
7.2.3 Color.fromArgb() → 十六进制字符串
问题:Color.fromArgb(255, 212, 175, 55) 编译报错。
原因:API 24 的 Color 类没有 fromArgb 静态方法(API 26 才引入)。
修复:
// ❌ API 24 不允许
Color.fromArgb(255, 212, 175, 55) // 鎏金色
// ✅ API 24 兼容
'#D4AF37' // 鎏金色
'#8B7355' // 古铜色
'#E8D5B7' // 米白色
'#1A1A2E' // 深靛蓝
'#0D0D1A' // 极黑
原理:ArkTS 中 backgroundColor()、fontColor()、placeholderColor() 等方法接受 ResourceColor 类型,该类型兼容十六进制字符串。
7.2.4 Color.Purple → 自定义字符串
问题:Color.Purple 在 API 24 中未定义。
原因:部分命名颜色在 API 24 的 Color 枚举中不存在。
修复:统一使用十六进制字符串 '#800080' 代替。
经验:在 API 24 中,安全的命名颜色只有 Color.Red、Color.Blue、Color.Green、Color.Gray、Color.White、Color.Black、Color.Transparent、Color.Orange、Color.Yellow、Color.Pink、Color.Brown。超出这个范围的颜色建议都用字符串代替。
7.2.5 Image.fillColor() → 移除或使用 Text 替代
问题:Image($r('app.media.icon')).fillColor(Color.White) 中 fillColor 不存在。
方案:直接用 Text 组件替代图标按钮。发送按钮改用金色"問"字:
// 替代方案:文字按钮
Button() {
Text('問')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor('#1A1A2E')
}
.width(56).height(48)
.backgroundColor('#D4AF37')
.borderRadius({ topRight: 24, bottomRight: 24 })
7.3 HTTP API 弃用问题
警告:httpRequest.on('dataReceive') 显示 'on' has been deprecated。
分析:虽然标记为弃用,但 API 24 中没有提供替代的 SSE 监听 API。on 事件依然是流式响应的唯一通道。因此我们保留使用,并在注释中记录待后续 SDK 升级时迁移。
解决方案:忽略此警告,功能正常。升级到 API 26+ 后可迁移到新的事件 API。
7.4 ArkTS 特有语法约束
| 约束 | 说明 | 解决方案 |
|---|---|---|
| import 必须在顶部 | 装饰器之前 | 将 import 放在文件第一行 |
| 无声明合并 | 不能重复声明同名类型 | 自定义类型加上前缀/后缀 |
| @BuilderParam 需初始化 | 必须有默认值 | 提供空 Builder 函数 |
| 箭头函数限制 | 不能直接调用变量函数 | 在 @Builder 中调用 |
| 类型声明严格 | 变量必须有类型 | 显式标注所有变量类型 |
8. 代码深度解读
8.1 文件结构
entry/src/main/ets/pages/
├── Index.ets # 主页面(约 350 行)
└── AIChatService.ets # AI 服务层(约 330 行)
8.2 Index.ets 核心数据结构
// 消息列表:存储所有聊天内容
@State private messages: ChatMessage[] = []
// 输入框内容绑定
@State private inputText: string = ''
// 请求状态锁
@State private isLoading: boolean = false
// 流式响应当前累积
@State private currentResponse: string = ''
// 滚动控制器
private scroller: Scroller = new Scroller()
8.3 组件树结构
Column (root)
├── Stack (标题栏)
│ ├── Rect (背景)
│ ├── Rect (金色装饰线)
│ ├── Row (标题文字)
│ └── Text (副标题)
├── Scroll (消息列表)
│ ├── Column
│ │ ├── userBubble × N
│ │ ├── aiBubble × N
│ │ └── loadingIndicator (条件)
└── Row (输入区)
├── TextArea (输入框)
└── Button (发送)
8.4 sendMessage() 完整执行流程
sendMessage(): void {
// 1. 输入校验
const text = this.inputText.trim()
if (!text || this.isLoading) return
// 2. 更新 UI 状态
this.messages.push({ role: 'user', content: text })
this.inputText = ''
this.isLoading = true
this.scrollToBottom()
// 3. 构建历史(跳过欢迎语)
const history: ChatMessage[] = []
for (let i = 1; i < this.messages.length - 1; i++) {
history.push({ role: this.messages[i].role, content: this.messages[i].content })
}
// 4. 发起 AI 请求
let response = ''
queryAI({
onData: (chunk) => {
response += chunk
// 流式更新 UI
const last = this.messages[this.messages.length - 1]
if (last.role === 'user') {
this.messages.push({ role: 'assistant', content: response })
} else {
this.messages[this.messages.length - 1] = { role: 'assistant', content: response }
}
this.scrollToBottom()
},
onDone: () => {
this.isLoading = false
this.scrollToBottom()
},
onError: (err) => {
this.isLoading = false
this.messages.push({ role: 'assistant', content: `⚠️ 道心受擾:${err}` })
}
}, history)
}
8.5 三个 @Builder 组件
| Builder | 用途 | 关键样式 |
|---|---|---|
userBubble(content) |
用户消息气泡 | 墨绿底 #2A3A2A + 米色字 #E8D5B7 |
aiBubble(content, index) |
老祖消息气泡 | 紫灰底 #1E1E30 + "祖"字头像 |
loadingIndicator() |
加载指示器 | “老夫掐指一算…” 文字动画 |
9. 颜色体系:在 API 24 中营造古风意境
9.1 全颜色对照表
| 用途 | 颜色名 | 十六进制 | RGB | API 24 写法 |
|---|---|---|---|---|
| 主背景 | 极黑 | #0D0D1A |
13,13,26 | '#0D0D1A' |
| 顶栏背景 | 深靛蓝 | #1A1A2E |
26,26,46 | '#1A1A2E' |
| 标题 / 装饰 | 鎏金 | #D4AF37 |
212,175,55 | '#D4AF37' |
| 正文 / 输入 | 宣纸米 | #E8D5B7 |
232,213,183 | '#E8D5B7' |
| 输入背景 | 砚台灰 | #2A2A3E |
42,42,62 | '#2A2A3E' |
| 用户气泡 | 青竹绿 | #2A3A2A |
42,58,42 | '#2A3A2A' |
| 老祖气泡 | 道袍紫灰 | #1E1E30 |
30,30,48 | '#1E1E30' |
| 老祖头像外圈 | 深紫灰 | #2A2A3E |
42,42,62 | '#2A2A3E' |
| 老祖头像内圈 | 赭石色 | #3A2A1A |
58,42,26 | '#3A2A1A' |
| 辅助文字 | 古铜 | #8B7355 |
139,115,85 | '#8B7355' |
| 占位文字 | 土棕 | #6B5B4F |
107,91,79 | '#6B5B4F' |
| 发送按钮禁用 | 灰褐 | #5C4B3A |
92,75,58 | '#5C4B3A' |
9.2 API 24 颜色最佳实践
- 优先使用十六进制字符串:
'#RRGGBB'格式在所有 API 版本中通用 - 避免 Color.fromArgb():API 24 不支持
- 避免不存在的命名颜色:
Color.Purple、Color.LightGray等可能不存在 - 安全的命名颜色:
Color.Red、Color.Blue、Color.Green、Color.Gray、Color.White、Color.Black、Color.Transparent - 透明度使用 #AARRGGBB:如
'#80D4AF37'表示半透明鎏金
10. 性能优化与注意事项
10.1 布局优化
-
使用
.layoutWeight(1)填充剩余空间消息列表区域使用
.height(1).layoutWeight(1)自适应填充,避免硬编码高度。 -
ForEach key 的稳定性
ForEach(..., (msg, index) => ..., (msg, index) => index.toString())使用 index 作为 key 确保每次渲染时组件的可预测性。
-
限制消息气泡最大宽度
.constraintSize({ maxWidth: '72%' })防止超长消息撑满屏幕。
10.2 网络优化
-
请求超时控制
connectTimeout: 30000 // 30 秒连接超时 readTimeout: 120000 // 120 秒读取超时 -
请求取消机制
每次新请求前取消旧请求,防止资源泄漏和回调冲突。
-
SSE 缓冲区管理
使用
buffer.split('\n')按行处理,最后一行不完整时暂存到下一次dataReceive。
10.3 状态管理优化
-
isLoading 状态锁
双重防止重复提交:
// 函数入口 if (!text || this.isLoading) return // UI 层面 .enabled(!this.isLoading && this.inputText.trim().length > 0) -
流式响应的两种更新路径
场景 操作 原因 最后一条是 user push新消息首次收到 token 最后一条是 assistant assign替换已有流式内容,追加更新
10.4 可预见的扩展点
| 功能 | 代码改动量 | 复杂度 |
|---|---|---|
| 添加多模型切换 | 中(新增选择器) | 低 |
| 对话历史持久化 | 中(数据持久化) | 中 |
| 语音输入 | 大(语音模块集成) | 高 |
| 自定义老祖形象配置 | 小(颜色变量化) | 低 |
| 修仙功法知识库(RAG) | 大(向量数据库) | 高 |
11. 部署与使用指南
11.1 环境准备
| 工具 | 版本 | 备注 |
|---|---|---|
| DevEco Studio | 5.0+ | IDE |
| HarmonyOS SDK | API 24 | OpenHarmony 6.1.1 |
| Node.js | 18+ | Hvigor 依赖 |
| 真机 / 模拟器 | API 24+ | 运行目标 |
11.2 部署步骤
# 1. 项目根目录
cd D:\hongmeng\design20
# 2. 替换 API Key(必要)
# 编辑 AIChatService.ets:13,将 API_KEY 替换为你的有效 Key
# 3. 检查网络权限
# 编辑 entry/src/main/module.json5,确认包含:
# "requestPermissions": [
# { "name": "ohos.permission.INTERNET" }
# ]
# 4. 编译
hvigorw assembleHap --mode module -p module=entry -p product=default
# 5. 安装到设备
hvigorw install --mode module -p module=entry -p product=default
11.3 常见构建错误与解决方案
| 错误信息 | 原因 | 解决方案 |
|---|---|---|
Property 'fill' does not exist |
API 24 不支持 .fill() |
替换为 .backgroundColor() |
Unexpected token at overlay |
API 24 不支持 .overlay(组件) |
替换为 Stack 嵌套 |
'fromArgb' does not exist |
API 24 不支持 | 替换为 '#RRGGBB' 字符串 |
Duplicate identifier 'Offset' |
与 SDK 内置类型冲突 | 重命名为 Offset2D 等 |
Decorators are not valid here |
import 放错了位置 | import 必须放在文件最顶部 |
BUILD FAILED: CompileArkTS |
语法错误 | 查看具体行号定位错误 |
12. 总结与修仙感悟
12.1 项目回顾
AI 修仙大法从一个有趣的想法出发,最终落地为一个功能完整的鸿蒙原生 AI 对话应用。它证明了一件事:技术可以有趣,有趣也可以实用。
12.2 关键技术收获
- Stack 嵌套实现复杂布局:用 Stack + Circle × 2 + Text 实现了 API 24 中原本需要 overlay 的头像效果
- 十六进制字符串统一颜色管理:避开 Color API 的版本差异,做到跨版本兼容
- SSE 流式 + 文字动画:在国内网络环境下实现了流畅的逐字输出体验
- 系统提示词的角色控制:通过精心设计的 ROLE 框架,让 AI 稳定维持修仙老祖人设
12.3 给 API 24 开发者的建议
修 仙 四 境 界 → 开 发 四 阶 段
练气期(入门) → Stack + .position() 基础布局
筑基期(进阶) → @Builder 组件封装 + 流式渲染
金丹期(精通) → AIChatService 封装 + SSE 兼容
元婴期(化境) → 自定义布局组件 + 性能优化
12.4 未来可延伸的方向
| 方向 | 描述 | 修仙命名 |
|---|---|---|
| 语音交互 | 语音输入 + TTS 输出 | 传音入密 |
| 功法图鉴 | 预设的修仙功法模板 | 藏经阁 |
| 修炼进度 | 用户每日打卡记录 | 修炼日志 |
| 多老祖切换 | 不同性格的 AI 老祖 | 万仙来朝 |
| 道侣模式 | 双人对话 AI 辅助 | 双修功法 |
12.5 最后的话
道可道,非常道。AI 修仙大法虽然只是一次跨界尝试,但它展示了一个方向:技术产品可以有文化温度。
道友,你的道,找到了吗?
本文基于 HarmonyOS SDK 24(API 24)编写,对应 OpenHarmony 6.1.1。
项目源码位于D:\hongmeng\design20,所有代码均经过编译验证。
更多推荐



所有评论(0)