HarmonyOS AI 应用开发实战:英语口语情景对话系统
本文基于 HarmonyOS + ArkTS 的 Model-Service-Page 架构,详细解析英语口语情景对话 AI 应用的完整开发流程,涵盖语言学习痛点、架构设计、提示词工程、核心实现、性能优化等全链路技术要点。

一、项目背景与需求分析
1.1 英语口语学习的痛点
英语口语能力是全球化时代最重要的技能之一,然而也是大多数英语学习者最薄弱的环节。根据中国英语能力等级量表的调查数据显示,超过 70% 的中国英语学习者的口语能力远低于阅读和写作能力。
英语口语学习面临的核心痛点包括:
- 缺乏真实语境:传统的课堂学习缺乏真实的语言交流场景,学习内容与实际应用脱节
- 练习机会有限:缺少与母语者或高水平学习者的对话练习机会
- 反馈不足:口语练习后缺乏及时的纠正和反馈,错误表达固化
- 场景覆盖不全:日常学习涉及的场景有限,难以覆盖职场、商务、旅行等多场景需求
- 心理障碍:害怕犯错、缺乏自信,导致不敢开口说英语
1.2 产品功能定位
本应用旨在利用 AI 大语言模型的能力,为英语学习者提供沉浸式的口语情景对话练习体验。核心功能包括:
- 情景对话生成:根据用户指定的场景(如商务会议、餐厅点餐、机场值机等),生成多轮情景对话
- 关键词汇学习:提取对话中的关键词汇和短语,附带中文释义
- 发音技巧指导:针对对话中的难点发音提供发音技巧建议
- 难度自适应:根据用户指定的难度等级(初级、中级、高级)调整对话复杂度
1.3 技术选型
| 维度 | 方案 | 说明 |
|---|---|---|
| 平台 | HarmonyOS NEXT | 国产操作系统,教育场景 |
| 语言 | ArkTS | 静态类型,声明式 UI |
| 框架 | ArkUI | 响应式布局 |
| 架构 | Model-Service-Page | 三层分离 |
| AI | 大语言模型 | 情景对话生成 |
二、技术架构设计
2.1 架构总览
┌──────────────────────────────────────────────────────────────┐
│ Page 层 │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ DialogPage │ │
│ │ ├── 输入:场景、难度等级、目标岗位 │ │
│ │ ├── 按钮:AI 生成 │ │
│ │ └── 结果:对话内容、关键词汇、发音技巧 │ │
│ └───────────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────────────┤
│ Service 层 │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ DialogService │ │
│ │ ├── Prompt 构建(场景 + 难度 + 角色) │ │
│ │ ├── AI API 调用 │ │
│ │ ├── 响应解析与数据映射 │ │
│ │ └── 降级策略 │ │
│ └───────────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────────────┤
│ Model 层 │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ DialogData │ │
│ │ ├── scene: string(场景) │ │
│ │ ├── level: string(难度等级) │ │
│ │ ├── role: string(目标岗位) │ │
│ │ ├── dialogue: Record<string, string>[](对话内容) │ │
│ │ ├── key_vocab: Record<string, string>[](关键词汇) │ │
│ │ └── pronunciation_tips: string[](发音技巧) │ │
│ └───────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
2.2 Model 层:数据模型设计
typescript
export class DialogData {
scene: string = ''
level: string = ''
role: string = ''
dialogue: Record<string, string>[] = []
key_vocab: Record<string, string>[] = []
pronunciation_tips: string[] = []
constructor() {
this.scene = ''
this.level = ''
this.role = ''
this.dialogue = []
this.key_vocab = []
this.pronunciation_tips = []
}
}
字段设计分析:
| 字段 | 类型 | 说明 |
|---|---|---|
scene |
string | 对话场景描述 |
level |
string | 难度等级(初级/中级/高级) |
role |
string | 目标岗位或角色 |
dialogue |
Record<string, string>\[\] | 多轮对话内容,每个元素包含说话人和对话内容 |
key_vocab |
Record<string, string>\[\] | 关键词汇,每个元素包含单词和释义 |
pronunciation_tips |
string\[\] | 发音技巧建议列表 |
Record<string, string>\[\] 的使用 :dialogue 使用 Record 数组,每个元素包含 speaker(说话人)和 text(对话内容)两个键,天然适合多轮对话的展示。key_vocab 同样使用 Record 数组,包含 word(单词)和 meaning(释义)两个键。
2.3 Service 层:业务逻辑设计
typescript
import { DialogData } from './英语口语情景对话Model'
export class DialogService {
private model: DialogData
constructor() {
this.model = new DialogData()
}
generateData(input: Record<string, Object>): DialogData {
let result: DialogData = new DialogData()
let scene: string = input['scene'] as string
let level: string = input['level'] as string
let role: string = input['role'] as string
let prompt: string = this.buildPrompt(scene, level, role)
let response: string = this.callAI(prompt)
result = this.parseResponse(response, result)
return result
}
private buildPrompt(scene: string, level: string, role: string): string {
return `你是一位英语口语教学专家,擅长设计情景对话...
场景:${scene}
难度等级:${level}
目标岗位:${role}
请输出 JSON 格式的对话内容...`
}
}
2.4 Page 层:UI 组件设计
typescript
@Entry
@Component
struct DialogPage {
@State inputData: Record<string, Object> = {}
@State resultData: DialogData | null = null
@State showResult: boolean = false
private service: DialogService = new DialogService()
build() {
Column() {
Row() {
Text('← 返回').onClick(() => { router.back() })
Blank()
Text('英语口语情景对话')
Blank()
Text('')
}
Scroll() {
Column() {
Text('场景')
TextInput({ placeholder: '请输入场景' })
.onChange((val: string) => { this.inputData['scene'] = val })
Text('难度等级')
TextInput({ placeholder: '请输入难度等级' })
.onChange((val: string) => { this.inputData['level'] = val })
Text('目标岗位')
TextInput({ placeholder: '请输入目标岗位' })
.onChange((val: string) => { this.inputData['role'] = val })
Button('AI 生成').onClick(() => {
this.resultData = this.service.generateData(this.inputData)
this.showResult = true
})
if (this.showResult && this.resultData !== null) {
Text('生成结果')
Text('英语对话')
}
}
}
}
}
}
三、AI 提示词工程原理
3.1 情景对话提示词设计
3.1.1 角色设定
你是一位英语口语教学专家,拥有 TESOL 国际英语教师资格认证,擅长根据学习者的水平设计真实、自然、有教育意义的情景对话。你精通英语语音学、语用学和跨文化交际。
3.1.2 难度分级策略
难度等级:{level}
各等级要求:
- 初级:使用简单句式和基础词汇,语速建议慢速,对话轮次5-6轮
- 中级:使用复合句和常用短语,语速正常,对话轮次8-10轮
- 高级:使用复杂句式和地道表达,语速自然,对话轮次10-12轮
3.1.3 场景和角色注入
对话场景:{scene}
目标岗位/角色:{role}
请确保对话内容贴合该场景的实际沟通需求,角色语言符合其身份特征。
3.2 完整 Prompt 示例
typescript
buildPrompt(scene: string, level: string, role: string): string {
return `你是一位英语口语教学专家,擅长设计情景对话。
请为以下场景生成英语情景对话:
对话场景:${scene}
难度等级:${level}
目标岗位:${role}
请严格按照以下 JSON 格式输出:
{
"dialogue": [
{"speaker": "A", "text": "说话人A的对话内容"},
{"speaker": "B", "text": "说话人B的对话内容"},
{"speaker": "A", "text": "说话人A的下一句对话内容"}
],
"key_vocab": [
{"word": "关键词1", "meaning": "中文释义"},
{"word": "关键词2", "meaning": "中文释义"}
],
"pronunciation_tips": [
"发音技巧1:针对某个单词的发音指导",
"发音技巧2:针对某个句子的连读/弱读指导"
]
}
要求:
1. 对话内容要真实、自然,符合实际场景
2. 根据难度等级调整句式和词汇复杂度
3. 关键词汇至少5个,包含单词和中文释义
4. 发音技巧至少3条,针对对话中的难点发音
5. 对话轮次根据难度等级确定:初级5-6轮,中级8-10轮,高级10-12轮`
}
3.3 响应解析
typescript
parseResponse(response: string, result: DialogData): DialogData {
try {
let parsed: Object = JSON.parse(response)
if (Array.isArray(parsed['dialogue'])) {
result.dialogue = parsed['dialogue'] as Record<string, string>[]
}
if (Array.isArray(parsed['key_vocab'])) {
result.key_vocab = parsed['key_vocab'] as Record<string, string>[]
}
if (Array.isArray(parsed['pronunciation_tips'])) {
result.pronunciation_tips = parsed['pronunciation_tips'] as string[]
}
} catch (e) {
result.pronunciation_tips = ['AI 服务暂时不可用,请稍后重试']
}
return result
}
四、核心功能实现详解
4.1 输入区域实现
typescript
Text('场景')
.fontSize(14)
.fontWeight(FontWeight.Bold)
.fontColor($r('app.color.text_primary'))
.margin({ top: 12, bottom: 4 })
TextInput({ placeholder: '请输入场景' })
.fontSize(14)
.height(44)
.backgroundColor('#FFFFFF')
.borderRadius(8)
.padding({ left: 12, right: 12 })
.onChange((val: string) => { this.inputData['scene'] = val })
Text('难度等级')
.fontSize(14)
.fontWeight(FontWeight.Bold)
.fontColor($r('app.color.text_primary'))
.margin({ top: 12, bottom: 4 })
TextInput({ placeholder: '请输入难度等级' })
.fontSize(14)
.height(44)
.backgroundColor('#FFFFFF')
.borderRadius(8)
.padding({ left: 12, right: 12 })
.onChange((val: string) => { this.inputData['level'] = val })
Text('目标岗位')
.fontSize(14)
.fontWeight(FontWeight.Bold)
.fontColor($r('app.color.text_primary'))
.margin({ top: 12, bottom: 4 })
TextInput({ placeholder: '请输入目标岗位' })
.fontSize(14)
.height(44)
.backgroundColor('#FFFFFF')
.borderRadius(8)
.padding({ left: 12, right: 12 })
.onChange((val: string) => { this.inputData['role'] = val })
4.2 结果展示区域
typescript
if (this.showResult && this.resultData !== null) {
// 对话内容 - 使用气泡样式
Text('情景对话')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.margin({ top: 16, bottom: 8 })
ForEach(this.resultData.dialogue, (turn: Record<string, string>, index: number) => {
Row() {
if (turn['speaker'] === 'A') {
Text(turn['speaker'])
.fontSize(12)
.fontColor('#3B82F6')
.fontWeight(FontWeight.Bold)
.margin({ right: 8 })
Text(turn['text'])
.fontSize(14)
.fontColor($r('app.color.text_primary'))
.backgroundColor('#E8F0FE')
.padding(10)
.borderRadius(8)
.maxLines(10)
Blank()
} else {
Blank()
Text(turn['text'])
.fontSize(14)
.fontColor($r('app.color.text_primary'))
.backgroundColor('#F0FDF4')
.padding(10)
.borderRadius(8)
.maxLines(10)
Text(turn['speaker'])
.fontSize(12)
.fontColor('#22C55E')
.fontWeight(FontWeight.Bold)
.margin({ left: 8 })
}
}
.width('100%')
.margin({ bottom: 8 })
}, (turn: Record<string, string>, index: number) => index.toString())
// 关键词汇
Text('关键词汇')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.margin({ top: 16, bottom: 8 })
ForEach(this.resultData.key_vocab, (vocab: Record<string, string>, index: number) => {
Row() {
Text(vocab['word'])
.fontSize(14)
.fontWeight(FontWeight.Bold)
.fontColor('#3B82F6')
.margin({ right: 12 })
Text(vocab['meaning'])
.fontSize(14)
.fontColor($r('app.color.text_secondary'))
Blank()
}
.width('100%')
.backgroundColor('#FFFFFF')
.padding(10)
.borderRadius(8)
.margin({ bottom: 6 })
}, (vocab: Record<string, string>, index: number) => index.toString())
// 发音技巧
Text('发音技巧')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.margin({ top: 16, bottom: 8 })
ForEach(this.resultData.pronunciation_tips, (tip: string, index: number) => {
Row() {
Circle()
.width(6)
.height(6)
.fill('#F59E0B')
.margin({ right: 8 })
Text(tip)
.fontSize(14)
.fontColor($r('app.color.text_primary'))
}
.width('100%')
.margin({ bottom: 6 })
}, (tip: string, index: number) => index.toString())
}
4.3 完整数据流
用户输入:场景 = "商务会议自我介绍", 难度等级 = "中级", 目标岗位 = "产品经理"
↓
inputData = { scene: "商务会议自我介绍", level: "中级", role: "产品经理" }
↓
点击 "AI 生成"
↓
service.generateData(inputData)
↓
构建 Prompt → 调用 AI → 解析响应
↓
返回 DialogData 实例
↓
resultData 更新 → showResult = true
↓
UI 渲染:对话气泡、关键词汇列表、发音技巧
五、用户体验优化
5.1 页面布局
┌──────────────────────────────────┐
│ ← 返回 英语口语情景对话 │
├──────────────────────────────────┤
│ 输入信息 │
│ ┌──────────────────────┐ │
│ │ 场景 │ │
│ │ [商务会议自我介绍] │ │
│ │ 难度等级 │ │
│ │ [中级] │ │
│ │ 目标岗位 │ │
│ │ [产品经理] │ │
│ └──────────────────────┘ │
│ ┌──────────────────────┐ │
│ │ AI 生成 │ │
│ └──────────────────────┘ │
│ 情景对话 │
│ ┌──┐ ┌────────────────┐ │
│ │A │ │ 对话内容... │ │
│ └──┘ └────────────────┘ │
│ ┌────────────────┐ ┌──┐ │
│ │ 对话内容... │ │B │ │
│ └────────────────┘ └──┘ │
│ 关键词汇 │
│ ┌──────────────────────┐ │
│ │ collaborate 合作 │ │
│ │ strategy 策略 │ │
│ └──────────────────────┘ │
│ 发音技巧 │
│ • 注意 strategy 中的 /str/... │
└──────────────────────────────────┘
5.2 交互优化
5.2.1 对话气泡设计
说话人 A 的对话左对齐(蓝色背景),说话人 B 的对话右对齐(绿色背景),模拟真实聊天软件的对话界面,提供沉浸式阅读体验。
5.2.2 颜色编码
- 蓝色:说话人 A 和关键词
- 绿色:说话人 B
- 橙色:发音技巧标记
5.3 资源管理
typescript
.fontColor($r('app.color.text_primary'))
.fontColor($r('app.color.text_secondary'))
.backgroundColor('#F8FAFC')
.backgroundColor('#FFFFFF')
.backgroundColor('#E8F0FE') // 说话人A背景
.backgroundColor('#F0FDF4') // 说话人B背景
六、性能优化与最佳实践
6.1 ArkTS 约束适配
6.1.1 Record 数组遍历
typescript
// 正确:遍历 Record 数组
ForEach(this.resultData.dialogue, (turn: Record<string, string>, index: number) => {
Text(turn['speaker'])
Text(turn['text'])
}, (turn: Record<string, string>, index: number) => index.toString())
6.1.2 条件渲染与样式
typescript
// 正确:根据条件渲染不同样式
if (turn['speaker'] === 'A') {
// 左对齐,蓝色背景
} else {
// 右对齐,绿色背景
}
6.2 性能优化
6.2.1 条件渲染
typescript
if (this.showResult && this.resultData !== null) {
// 结果渲染
}
6.2.2 ForEach 列表优化
typescript
// 使用稳定的 key 生成函数
ForEach(items, item => { /* ... */ }, (item, index) => index.toString())
6.3 错误处理
typescript
generateData(input: Record<string, Object>): DialogData {
try {
if (!input['scene'] || !input['level']) {
throw new Error('场景和难度等级为必填')
}
return this.parseResponse(this.callAI(this.buildPrompt(...)), new DialogData())
} catch (e) {
let result: DialogData = new DialogData()
result.pronunciation_tips = ['请确保场景和难度等级已填写']
return result
}
}
6.4 代码组织
英语口语情景对话/
├── 英语口语情景对话Model.ets # 数据模型
├── 英语口语情景对话Service.ets # 业务逻辑
└── 英语口语情景对话Page.ets # 页面组件
七、总结与展望
7.1 项目成果
- 实现了基于 AI 的英语口语情景对话生成
- 对话气泡 UI 设计提供沉浸式阅读体验
- 包含关键词汇和发音技巧,辅助学习
- 难度分级满足不同水平学习者的需求
7.2 技术经验
- 对话气泡 UI 设计提升口语学习体验
- Record 数组适合存储多轮对话数据
- 难度分级提示词设计需要精确的等级描述
7.3 未来展望
- 接入语音合成(TTS),实现对话朗读功能
- 支持语音识别,用户可以跟读并得到评分
- 扩展更多真实场景,覆盖商务、旅游、留学等
本文通过英语口语情景对话 AI 应用的完整开发实践,详细阐述了 HarmonyOS + ArkTS + AI 的技术栈应用。从对话气泡 UI 设计到难度分级提示词工程,全面展示了鸿蒙平台上智慧语言学习工具开发的全流程。