带你玩转鸿蒙6 AI智能体开发:从0到1打造你的专属AI助手
今天要跟大家分享一个超级干货——如何在鸿蒙6(API21)上开发一个真正能用的AI智能体。不是那种玩具级别的Demo,而是能语音对话、能理解你意图、还能帮你干活的智能助手!
·
大家好,我是V哥!今天要跟大家分享一个超级干货——如何在鸿蒙6(API21)上开发一个真正能用的AI智能体。不是那种玩具级别的Demo,而是能语音对话、能理解你意图、还能帮你干活的智能助手!
一、为什么要在鸿蒙上做AI智能体?
兄弟们,2026年了,AI Agent(智能体)绝对是最火的技术方向之一。什么是智能体?简单说就是:能感知、能思考、能行动的AI程序。
鸿蒙6在AI这块可以说是下了血本:
- 原生AI能力:MindSpore Lite端侧推理引擎
- 语音能力:ASR语音识别 + TTS语音合成
- 意图识别:智能理解用户需求
- 大模型接入:轻松对接各种LLM API
今天V哥就手把手带你做一个多模态AI智能助手,它能:
- ✅ 语音唤醒,开口就能聊
- ✅ 智能对话,接入大模型
- ✅ 意图识别,理解你想干嘛
- ✅ 执行任务,帮你打开应用、设置闹钟等
- ✅ 多轮记忆,上下文连贯
废话不多说,直接上代码!
二、项目架构设计
┌─────────────────────────────────────────────────────────────────┐
│ AI智能体架构(V哥设计) │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 语音输入 │───▶│ 语音识别 │───▶│ 意图理解 │ │
│ │ (ASR) │ │ Engine │ │ Engine │ │
│ └─────────────┘ └─────────────┘ └──────┬──────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 语音输出 │◀───│ 回复生成 │◀───│ 对话管理 │ │
│ │ (TTS) │ │ (LLM) │ │ Agent │ │
│ └─────────────┘ └─────────────┘ └──────┬──────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ 任务执行 │ │
│ │ Actions │ │
│ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
三、项目创建与配置
步骤1:创建项目
DevEco Studio → New Project
→ Empty Ability (Stage模型)
→ Project name: VGeAIAgent
→ Bundle name: com.vge.aiagent
→ Compile SDK: 5.0.0(API 12) 或更高
步骤2:配置 module.json5
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": ["phone", "tablet"],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:icon",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:startIcon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"skills": [
{
"entities": ["entity.system.home"],
"actions": ["action.system.home"]
}
]
}
],
"requestPermissions": [
{
"name": "ohos.permission.MICROPHONE",
"reason": "$string:mic_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.INTERNET",
"reason": "$string:net_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "always"
}
},
{
"name": "ohos.permission.DISTRIBUTED_DATASYNC",
"reason": "$string:sync_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "always"
}
}
]
}
}
四、核心代码实现
1. 消息数据模型 (model/MessageModel.ets)
// entry/src/main/ets/model/MessageModel.ets
/**
* V哥设计的消息模型
* 支持多种消息类型,为后续扩展预留空间
*/
// 消息角色
export enum MessageRole {
USER = 'user', // 用户消息
ASSISTANT = 'assistant', // AI助手消息
SYSTEM = 'system' // 系统消息
}
// 消息类型
export enum MessageType {
TEXT = 'text', // 文本消息
VOICE = 'voice', // 语音消息
ACTION = 'action', // 执行动作
THINKING = 'thinking' // 思考中
}
// 意图类型
export enum IntentType {
CHAT = 'chat', // 闲聊
OPEN_APP = 'open_app', // 打开应用
SET_ALARM = 'set_alarm', // 设置闹钟
SET_REMINDER = 'set_reminder', // 设置提醒
QUERY_WEATHER = 'query_weather', // 查询天气
QUERY_TIME = 'query_time', // 查询时间
CONTROL_DEVICE = 'control_device',// 控制设备
UNKNOWN = 'unknown' // 未知意图
}
// 消息实体
export class Message {
id: string = '';
role: MessageRole = MessageRole.USER;
type: MessageType = MessageType.TEXT;
content: string = '';
timestamp: number = 0;
intent?: IntentType;
intentParams?: Record<string, string>;
isStreaming?: boolean; // 是否流式输出中
constructor(init?: Partial<Message>) {
this.id = `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
this.timestamp = Date.now();
if (init) {
Object.assign(this, init);
}
}
}
// 对话上下文(用于多轮对话)
export class ConversationContext {
messages: Message[] = [];
maxHistory: number = 10; // 最多保留10轮对话
addMessage(message: Message): void {
this.messages.push(message);
// 超过限制则移除最早的消息
if (this.messages.length > this.maxHistory * 2) {
this.messages = this.messages.slice(-this.maxHistory * 2);
}
}
getHistory(): Message[] {
return this.messages;
}
clear(): void {
this.messages = [];
}
// 转换为LLM API需要的格式
toAPIFormat(): Array<{role: string, content: string}> {
return this.messages
.filter(m => m.type === MessageType.TEXT)
.map(m => ({
role: m.role,
content: m.content
}));
}
}
2. 意图识别引擎 (engine/IntentEngine.ets)
// entry/src/main/ets/engine/IntentEngine.ets
import { IntentType } from '../model/MessageModel';
/**
* V哥的意图识别引擎
* 使用规则+关键词匹配,生产环境可接入NLU模型
*/
interface IntentRule {
intent: IntentType;
keywords: string[];
patterns: RegExp[];
extractor?: (text: string) => Record<string, string>;
}
export class IntentEngine {
private static instance: IntentEngine;
private rules: IntentRule[] = [];
private constructor() {
this.initRules();
}
static getInstance(): IntentEngine {
if (!IntentEngine.instance) {
IntentEngine.instance = new IntentEngine();
}
return IntentEngine.instance;
}
/**
* 初始化意图规则
*/
private initRules(): void {
this.rules = [
// 打开应用
{
intent: IntentType.OPEN_APP,
keywords: ['打开', '启动', '运行', '开启'],
patterns: [
/打开(.+?)(?:应用|app|APP)?$/,
/启动(.+)/,
/帮我开(.+)/
],
extractor: (text: string) => {
const appNames: Record<string, string> = {
'相机': 'com.huawei.camera',
'相册': 'com.huawei.photos',
'设置': 'com.huawei.settings',
'日历': 'com.huawei.calendar',
'计算器': 'com.huawei.calculator',
'备忘录': 'com.huawei.notes',
'音乐': 'com.huawei.music',
'视频': 'com.huawei.video',
'浏览器': 'com.huawei.browser',
'微信': 'com.tencent.mm',
'支付宝': 'com.eg.android.AlipayGphone',
'抖音': 'com.ss.android.ugc.aweme'
};
for (const [name, bundleName] of Object.entries(appNames)) {
if (text.includes(name)) {
return { appName: name, bundleName: bundleName };
}
}
return {};
}
},
// 设置闹钟
{
intent: IntentType.SET_ALARM,
keywords: ['闹钟', '叫我', '提醒我起床', '定个闹钟'],
patterns: [
/(\d{1,2})[点::](\d{0,2}).*(?:闹钟|叫我|起床)/,
/(?:明天|后天)?(?:早上|上午|中午|下午|晚上)?(\d{1,2})[点::]?(\d{0,2})?.*(?:闹钟|叫我)/,
/设.*闹钟.*(\d{1,2})[点::](\d{0,2})?/
],
extractor: (text: string) => {
const timeMatch = text.match(/(\d{1,2})[点::](\d{0,2})?/);
if (timeMatch) {
const hour = timeMatch[1];
const minute = timeMatch[2] || '00';
return { hour, minute };
}
return {};
}
},
// 设置提醒
{
intent: IntentType.SET_REMINDER,
keywords: ['提醒我', '别忘了', '记得'],
patterns: [
/(\d+)(?:分钟|小时)后提醒我(.+)/,
/提醒我(.+)/,
/(\d{1,2})[点::](\d{0,2})?提醒我(.+)/
],
extractor: (text: string) => {
// 提取时间和内容
const minuteMatch = text.match(/(\d+)分钟后提醒我(.+)/);
if (minuteMatch) {
return {
delayMinutes: minuteMatch[1],
content: minuteMatch[2]
};
}
const hourMatch = text.match(/(\d+)小时后提醒我(.+)/);
if (hourMatch) {
return {
delayMinutes: String(parseInt(hourMatch[1]) * 60),
content: hourMatch[2]
};
}
const contentMatch = text.match(/提醒我(.+)/);
if (contentMatch) {
return { content: contentMatch[1] };
}
return {};
}
},
// 查询天气
{
intent: IntentType.QUERY_WEATHER,
keywords: ['天气', '下雨', '温度', '气温', '穿什么'],
patterns: [
/(.+?)(?:的)?天气/,
/(?:今天|明天|后天).*(?:天气|下雨|温度)/,
/要不要带伞/
],
extractor: (text: string) => {
const cityMatch = text.match(/(.{2,4}?)(?:的)?天气/);
if (cityMatch && !['今天', '明天', '后天', '这里', '现在'].includes(cityMatch[1])) {
return { city: cityMatch[1] };
}
return { city: '北京' }; // 默认城市
}
},
// 查询时间
{
intent: IntentType.QUERY_TIME,
keywords: ['几点', '时间', '日期', '星期几', '今天几号'],
patterns: [
/现在几点/,
/什么时间/,
/今天.*(?:几号|星期几|周几)/
],
extractor: () => ({})
},
// 控制设备
{
intent: IntentType.CONTROL_DEVICE,
keywords: ['打开灯', '关灯', '开灯', '空调', '电视', '窗帘'],
patterns: [
/(打开|关闭|开|关)(.+?)(?:灯|空调|电视|窗帘)/,
/把(.+?)(打开|关闭|开|关)/,
/(.+?)(?:调到|设置为?)(\d+)度/
],
extractor: (text: string) => {
const actionMatch = text.match(/(打开|关闭|开|关)(.+)/);
if (actionMatch) {
return {
action: actionMatch[1].includes('开') ? 'on' : 'off',
device: actionMatch[2]
};
}
return {};
}
}
];
}
/**
* 识别用户意图
*/
recognize(text: string): { intent: IntentType; params: Record<string, string>; confidence: number } {
const normalizedText = text.toLowerCase().trim();
for (const rule of this.rules) {
// 关键词匹配
const keywordMatch = rule.keywords.some(kw => normalizedText.includes(kw));
// 正则匹配
const patternMatch = rule.patterns.some(pattern => pattern.test(normalizedText));
if (keywordMatch || patternMatch) {
const params = rule.extractor ? rule.extractor(normalizedText) : {};
const confidence = keywordMatch && patternMatch ? 0.95 : 0.75;
console.info(`[IntentEngine] 识别结果: ${rule.intent}, 置信度: ${confidence}`);
return {
intent: rule.intent,
params,
confidence
};
}
}
// 默认为闲聊
return {
intent: IntentType.CHAT,
params: {},
confidence: 0.5
};
}
}
3. 大模型对话服务 (service/LLMService.ets)
// entry/src/main/ets/service/LLMService.ets
import { http } from '@kit.NetworkKit';
import { ConversationContext, Message, MessageRole } from '../model/MessageModel';
import { BusinessError } from '@kit.BasicServicesKit';
/**
* V哥的LLM服务封装
* 支持多种大模型API,这里以通用格式为例
*/
// LLM配置接口
interface LLMConfig {
apiUrl: string;
apiKey: string;
model: string;
maxTokens: number;
temperature: number;
}
// API请求格式
interface ChatCompletionRequest {
model: string;
messages: Array<{ role: string; content: string }>;
max_tokens: number;
temperature: number;
stream: boolean;
}
// API响应格式
interface ChatCompletionResponse {
id: string;
choices: Array<{
message: {
role: string;
content: string;
};
finish_reason: string;
}>;
usage: {
prompt_tokens: number;
completion_tokens: number;
total_tokens: number;
};
}
export class LLMService {
private static instance: LLMService;
private config: LLMConfig;
private systemPrompt: string;
private constructor() {
// 默认配置(实际使用时替换为你的API信息)
this.config = {
apiUrl: 'https://api.openai.com/v1/chat/completions', // 或其他兼容API
apiKey: 'your-api-key-here', // 替换为你的API Key
model: 'gpt-3.5-turbo',
maxTokens: 2048,
temperature: 0.7
};
// 系统提示词 - V哥精心调教
this.systemPrompt = `你是一个运行在鸿蒙系统上的AI智能助手,名叫"小V助手"。
你的特点:
1. 友好、幽默、专业
2. 回答简洁有力,不啰嗦
3. 能理解用户意图,给出实用建议
4. 熟悉鸿蒙生态和华为设备
5. 在适当时候使用emoji增加亲和力
你可以帮用户:
- 回答各种问题
- 闲聊解闷
- 提供建议和帮助
- 解释技术概念
请用中文回复,保持回答在100字以内(除非用户明确要求详细解释)。`;
}
static getInstance(): LLMService {
if (!LLMService.instance) {
LLMService.instance = new LLMService();
}
return LLMService.instance;
}
/**
* 更新配置
*/
updateConfig(config: Partial<LLMConfig>): void {
this.config = { ...this.config, ...config };
}
/**
* 发送对话请求
*/
async chat(userMessage: string, context: ConversationContext): Promise<string> {
// 构建消息历史
const messages: Array<{ role: string; content: string }> = [
{ role: 'system', content: this.systemPrompt },
...context.toAPIFormat(),
{ role: 'user', content: userMessage }
];
const requestData: ChatCompletionRequest = {
model: this.config.model,
messages: messages,
max_tokens: this.config.maxTokens,
temperature: this.config.temperature,
stream: false
};
try {
const httpRequest = http.createHttp();
const response = await httpRequest.request(
this.config.apiUrl,
{
method: http.RequestMethod.POST,
header: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.config.apiKey}`
},
extraData: JSON.stringify(requestData),
connectTimeout: 30000,
readTimeout: 60000
}
);
httpRequest.destroy();
if (response.responseCode === 200) {
const result = JSON.parse(response.result as string) as ChatCompletionResponse;
const content = result.choices[0]?.message?.content || '抱歉,我没有理解你的意思';
console.info(`[LLMService] 响应成功,Token使用: ${result.usage?.total_tokens}`);
return content;
} else {
console.error(`[LLMService] API错误: ${response.responseCode}`);
return this.getFallbackResponse(userMessage);
}
} catch (err) {
const error = err as BusinessError;
console.error(`[LLMService] 请求失败: ${error.code} - ${error.message}`);
return this.getFallbackResponse(userMessage);
}
}
/**
* 离线兜底回复(当API不可用时)
*/
private getFallbackResponse(userMessage: string): string {
const fallbackResponses: Record<string, string[]> = {
'你好': ['你好呀!有什么可以帮你的?', '嗨!我是小V助手,很高兴见到你!'],
'谢谢': ['不客气!随时为你服务~', '应该的,还有什么需要帮助的吗?'],
'再见': ['再见!期待下次聊天~', '拜拜,有事随时找我哦!'],
'你是谁': ['我是小V助手,运行在鸿蒙系统上的AI助手!', '我叫小V,是V哥打造的智能助手~'],
'你能做什么': ['我能陪你聊天、回答问题、帮你打开应用、设置提醒等等!试试看吧~',
'我可以:闲聊解闷、回答问题、控制设备、设置闹钟提醒...功能多多!']
};
// 关键词匹配
for (const [keyword, responses] of Object.entries(fallbackResponses)) {
if (userMessage.includes(keyword)) {
return responses[Math.floor(Math.random() * responses.length)];
}
}
// 默认回复
const defaultResponses = [
'我现在网络不太好,稍后再试试吧~',
'让我想想... 你能换个方式问我吗?',
'抱歉,我没太理解,能再说一遍吗?',
'网络开小差了,不过我们可以继续聊别的!'
];
return defaultResponses[Math.floor(Math.random() * defaultResponses.length)];
}
/**
* 流式对话(支持打字机效果)
*/
async chatStream(
userMessage: string,
context: ConversationContext,
onChunk: (chunk: string) => void,
onComplete: (fullText: string) => void
): Promise<void> {
// 简化实现:模拟流式输出
const response = await this.chat(userMessage, context);
let index = 0;
const interval = setInterval(() => {
if (index < response.length) {
onChunk(response[index]);
index++;
} else {
clearInterval(interval);
onComplete(response);
}
}, 30); // 每30ms输出一个字符
}
}
4. 语音服务封装 (service/VoiceService.ets)
// entry/src/main/ets/service/VoiceService.ets
import { speechRecognizer } from '@kit.CoreSpeechKit';
import { textToSpeech } from '@kit.CoreSpeechKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { abilityAccessCtrl, Permissions } from '@kit.AbilityKit';
/**
* V哥的语音服务封装
* 整合ASR语音识别 + TTS语音合成
*/
export class VoiceService {
private static instance: VoiceService;
private asrEngine: speechRecognizer.SpeechRecognitionEngine | null = null;
private ttsEngine: textToSpeech.TextToSpeechEngine | null = null;
private isListening: boolean = false;
private constructor() {}
static getInstance(): VoiceService {
if (!VoiceService.instance) {
VoiceService.instance = new VoiceService();
}
return VoiceService.instance;
}
/**
* 请求麦克风权限
*/
async requestPermission(context: Context): Promise<boolean> {
const atManager = abilityAccessCtrl.createAtManager();
const permissions: Permissions[] = ['ohos.permission.MICROPHONE'];
try {
const result = await atManager.requestPermissionsFromUser(context, permissions);
const granted = result.authResults.every(r => r === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED);
console.info(`[VoiceService] 麦克风权限: ${granted ? '已授权' : '被拒绝'}`);
return granted;
} catch (err) {
console.error('[VoiceService] 请求权限失败:', JSON.stringify(err));
return false;
}
}
/**
* 初始化语音识别引擎
*/
async initASR(): Promise<boolean> {
try {
const createParams: speechRecognizer.CreateEngineParams = {
language: 'zh-CN',
online: 1 // 1-在线识别 0-离线识别
};
this.asrEngine = await speechRecognizer.createEngine(createParams);
console.info('[VoiceService] ASR引擎初始化成功');
return true;
} catch (err) {
const error = err as BusinessError;
console.error(`[VoiceService] ASR初始化失败: ${error.code} - ${error.message}`);
return false;
}
}
/**
* 初始化语音合成引擎
*/
async initTTS(): Promise<boolean> {
try {
const createParams: textToSpeech.CreateEngineParams = {
language: 'zh-CN',
person: 0, // 发音人
online: 1 // 1-在线合成 0-离线合成
};
const extraParams: Record<string, Object> = {
style: 'normal',
speed: 1.0,
volume: 1.0,
pitch: 1.0
};
this.ttsEngine = await textToSpeech.createEngine(createParams);
console.info('[VoiceService] TTS引擎初始化成功');
return true;
} catch (err) {
const error = err as BusinessError;
console.error(`[VoiceService] TTS初始化失败: ${error.code} - ${error.message}`);
return false;
}
}
/**
* 开始语音识别
*/
async startListening(
onResult: (text: string, isFinal: boolean) => void,
onError: (error: string) => void
): Promise<void> {
if (!this.asrEngine) {
const success = await this.initASR();
if (!success) {
onError('语音识别引擎初始化失败');
return;
}
}
if (this.isListening) {
console.warn('[VoiceService] 已经在监听中');
return;
}
try {
// 设置回调
this.asrEngine!.setListener({
onStart: (sessionId: string) => {
console.info(`[VoiceService] 开始识别, sessionId: ${sessionId}`);
this.isListening = true;
},
onEvent: (sessionId: string, eventCode: number) => {
console.info(`[VoiceService] 事件: ${eventCode}`);
},
onResult: (sessionId: string, result: speechRecognizer.SpeechRecognitionResult) => {
const text = result.result;
const isFinal = result.isFinal;
console.info(`[VoiceService] 识别结果: ${text}, isFinal: ${isFinal}`);
onResult(text, isFinal);
},
onComplete: (sessionId: string) => {
console.info(`[VoiceService] 识别完成`);
this.isListening = false;
},
onError: (sessionId: string, errorCode: number, errorMessage: string) => {
console.error(`[VoiceService] 识别错误: ${errorCode} - ${errorMessage}`);
this.isListening = false;
onError(errorMessage);
}
});
// 开始识别
const recognitionParams: speechRecognizer.StartParams = {
sessionId: `session_${Date.now()}`,
audioInfo: {
audioType: 'pcm',
sampleRate: 16000,
soundChannel: 1,
sampleBit: 16
},
extraParams: {
vadBegin: 2000, // 静音检测开始时间
vadEnd: 3000, // 静音检测结束时间
maxAudioDuration: 60000 // 最大录音时长
}
};
await this.asrEngine!.startListening(recognitionParams);
} catch (err) {
const error = err as BusinessError;
console.error(`[VoiceService] 开始识别失败: ${error.code} - ${error.message}`);
onError(error.message);
}
}
/**
* 停止语音识别
*/
async stopListening(): Promise<void> {
if (this.asrEngine && this.isListening) {
try {
await this.asrEngine.finish(`session_stop_${Date.now()}`);
this.isListening = false;
console.info('[VoiceService] 停止识别');
} catch (err) {
console.error('[VoiceService] 停止识别失败:', JSON.stringify(err));
}
}
}
/**
* 语音合成(文字转语音)
*/
async speak(text: string, onComplete?: () => void): Promise<void> {
if (!this.ttsEngine) {
const success = await this.initTTS();
if (!success) {
console.error('[VoiceService] TTS引擎不可用');
onComplete?.();
return;
}
}
try {
// 设置回调
this.ttsEngine!.setListener({
onStart: (requestId: string) => {
console.info(`[VoiceService] 开始播放, requestId: ${requestId}`);
},
onProgress: (requestId: string, progress: number) => {
// 播放进度
},
onFinish: (requestId: string) => {
console.info(`[VoiceService] 播放完成`);
onComplete?.();
},
onError: (requestId: string, errorCode: number, errorMessage: string) => {
console.error(`[VoiceService] 播放错误: ${errorCode} - ${errorMessage}`);
onComplete?.();
}
});
// 合成参数
const speakParams: textToSpeech.SpeakParams = {
requestId: `speak_${Date.now()}`,
extraParams: {
speed: 1.0,
volume: 1.0,
pitch: 1.0
}
};
await this.ttsEngine!.speak(text, speakParams);
} catch (err) {
const error = err as BusinessError;
console.error(`[VoiceService] 语音合成失败: ${error.code} - ${error.message}`);
onComplete?.();
}
}
/**
* 停止语音播放
*/
async stopSpeaking(): Promise<void> {
if (this.ttsEngine) {
try {
await this.ttsEngine.stop();
console.info('[VoiceService] 停止播放');
} catch (err) {
console.error('[VoiceService] 停止播放失败:', JSON.stringify(err));
}
}
}
/**
* 释放资源
*/
async release(): Promise<void> {
try {
if (this.asrEngine) {
await this.asrEngine.shutdown();
this.asrEngine = null;
}
if (this.ttsEngine) {
await this.ttsEngine.shutdown();
this.ttsEngine = null;
}
console.info('[VoiceService] 资源释放完成');
} catch (err) {
console.error('[VoiceService] 释放资源失败:', JSON.stringify(err));
}
}
/**
* 获取监听状态
*/
getListeningState(): boolean {
return this.isListening;
}
}
5. 任务执行器 (engine/ActionExecutor.ets)
// entry/src/main/ets/engine/ActionExecutor.ets
import { bundleManager, common, Want } from '@kit.AbilityKit';
import { IntentType } from '../model/MessageModel';
import { BusinessError } from '@kit.BasicServicesKit';
/**
* V哥的任务执行器
* 根据意图执行具体操作
*/
interface ActionResult {
success: boolean;
message: string;
data?: object;
}
export class ActionExecutor {
private static instance: ActionExecutor;
private context: common.UIAbilityContext | null = null;
private constructor() {}
static getInstance(): ActionExecutor {
if (!ActionExecutor.instance) {
ActionExecutor.instance = new ActionExecutor();
}
return ActionExecutor.instance;
}
/**
* 设置上下文
*/
setContext(context: common.UIAbilityContext): void {
this.context = context;
}
/**
* 执行动作
*/
async execute(intent: IntentType, params: Record<string, string>): Promise<ActionResult> {
console.info(`[ActionExecutor] 执行意图: ${intent}, 参数: ${JSON.stringify(params)}`);
switch (intent) {
case IntentType.OPEN_APP:
return this.openApp(params);
case IntentType.SET_ALARM:
return this.setAlarm(params);
case IntentType.SET_REMINDER:
return this.setReminder(params);
case IntentType.QUERY_WEATHER:
return this.queryWeather(params);
case IntentType.QUERY_TIME:
return this.queryTime();
case IntentType.CONTROL_DEVICE:
return this.controlDevice(params);
default:
return {
success: false,
message: '暂不支持该操作'
};
}
}
/**
* 打开应用
*/
private async openApp(params: Record<string, string>): Promise<ActionResult> {
const bundleName = params.bundleName;
const appName = params.appName;
if (!bundleName) {
return {
success: false,
message: `抱歉,我不知道怎么打开"${appName || '这个应用'}"`
};
}
try {
const want: Want = {
bundleName: bundleName,
action: 'action.system.home',
entities: ['entity.system.home']
};
await this.context?.startAbility(want);
return {
success: true,
message: `已为你打开${appName}`
};
} catch (err) {
const error = err as BusinessError;
console.error(`[ActionExecutor] 打开应用失败: ${error.code} - ${error.message}`);
return {
success: false,
message: `打开${appName}失败,可能是应用未安装`
};
}
}
/**
* 设置闹钟
*/
private async setAlarm(params: Record<string, string>): Promise<ActionResult> {
const hour = parseInt(params.hour || '8');
const minute = parseInt(params.minute || '0');
try {
// 调用系统闹钟
const want: Want = {
action: 'ohos.want.action.setAlarm',
parameters: {
'ringtone': 'default',
'hour': hour,
'minute': minute
}
};
await this.context?.startAbility(want);
const timeStr = `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;
return {
success: true,
message: `好的,已为你设置${timeStr}的闹钟`
};
} catch (err) {
console.error('[ActionExecutor] 设置闹钟失败:', JSON.stringify(err));
return {
success: false,
message: '设置闹钟失败,请手动设置'
};
}
}
/**
* 设置提醒
*/
private async setReminder(params: Record<string, string>): Promise<ActionResult> {
const content = params.content || '未命名提醒';
const delayMinutes = parseInt(params.delayMinutes || '10');
// 这里可以接入前面的日程提醒模块
return {
success: true,
message: `收到!${delayMinutes}分钟后提醒你:${content}`
};
}
/**
* 查询天气
*/
private async queryWeather(params: Record<string, string>): Promise<ActionResult> {
const city = params.city || '北京';
// 实际项目中对接天气API
// 这里返回模拟数据
const mockWeather = {
city: city,
temperature: Math.floor(Math.random() * 20) + 10,
weather: ['晴', '多云', '阴', '小雨'][Math.floor(Math.random() * 4)],
humidity: Math.floor(Math.random() * 40) + 40
};
return {
success: true,
message: `${city}今天${mockWeather.weather},气温${mockWeather.temperature}°C,湿度${mockWeather.humidity}%`,
data: mockWeather
};
}
/**
* 查询时间
*/
private queryTime(): ActionResult {
const now = new Date();
const weekDays = ['日', '一', '二', '三', '四', '五', '六'];
const dateStr = `${now.getFullYear()}年${now.getMonth() + 1}月${now.getDate()}日`;
const weekStr = `星期${weekDays[now.getDay()]}`;
const timeStr = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}`;
return {
success: true,
message: `现在是${dateStr} ${weekStr} ${timeStr}`
};
}
/**
* 控制设备
*/
private async controlDevice(params: Record<string, string>): Promise<ActionResult> {
const device = params.device || '设备';
const action = params.action === 'on' ? '打开' : '关闭';
// 实际项目中对接智能家居API
return {
success: true,
message: `好的,已${action}${device}`
};
}
}
6. AI智能体核心 (engine/AIAgent.ets)
// entry/src/main/ets/engine/AIAgent.ets
import { Message, MessageRole, MessageType, ConversationContext, IntentType } from '../model/MessageModel';
import { IntentEngine } from './IntentEngine';
import { ActionExecutor } from './ActionExecutor';
import { LLMService } from '../service/LLMService';
import { VoiceService } from '../service/VoiceService';
/**
* V哥的AI智能体核心
* 整合所有能力,实现智能对话
*/
export class AIAgent {
private static instance: AIAgent;
private context: ConversationContext;
private intentEngine: IntentEngine;
private actionExecutor: ActionExecutor;
private llmService: LLMService;
private voiceService: VoiceService;
// 回调函数
private onMessageCallback?: (message: Message) => void;
private onStateChangeCallback?: (state: AgentState) => void;
private constructor() {
this.context = new ConversationContext();
this.intentEngine = IntentEngine.getInstance();
this.actionExecutor = ActionExecutor.getInstance();
this.llmService = LLMService.getInstance();
this.voiceService = VoiceService.getInstance();
}
static getInstance(): AIAgent {
if (!AIAgent.instance) {
AIAgent.instance = new AIAgent();
}
return AIAgent.instance;
}
/**
* 设置消息回调
*/
setOnMessage(callback: (message: Message) => void): void {
this.onMessageCallback = callback;
}
/**
* 设置状态回调
*/
setOnStateChange(callback: (state: AgentState) => void): void {
this.onStateChangeCallback = callback;
}
/**
* 处理用户输入(核心方法)
*/
async processInput(userInput: string): Promise<void> {
if (!userInput.trim()) return;
console.info(`[AIAgent] 处理用户输入: ${userInput}`);
// 1. 创建用户消息
const userMessage = new Message({
role: MessageRole.USER,
type: MessageType.TEXT,
content: userInput
});
this.context.addMessage(userMessage);
this.onMessageCallback?.(userMessage);
// 2. 意图识别
this.onStateChangeCallback?.(AgentState.THINKING);
const { intent, params, confidence } = this.intentEngine.recognize(userInput);
console.info(`[AIAgent] 意图识别: ${intent}, 置信度: ${confidence}`);
// 3. 根据意图决定处理方式
let response: string;
if (intent !== IntentType.CHAT && confidence >= 0.7) {
// 高置信度的功能意图,执行动作
userMessage.intent = intent;
userMessage.intentParams = params;
const result = await this.actionExecutor.execute(intent, params);
response = result.message;
// 如果是需要补充信息的场景,继续调用LLM
if (!result.success && intent !== IntentType.UNKNOWN) {
response = await this.llmService.chat(
`用户说"${userInput}",我尝试${this.getIntentDescription(intent)}但失败了。请给出友好的回复和建议。`,
this.context
);
}
} else {
// 闲聊或低置信度,调用大模型
response = await this.llmService.chat(userInput, this.context);
}
// 4. 创建助手回复
const assistantMessage = new Message({
role: MessageRole.ASSISTANT,
type: MessageType.TEXT,
content: response
});
this.context.addMessage(assistantMessage);
this.onMessageCallback?.(assistantMessage);
this.onStateChangeCallback?.(AgentState.IDLE);
// 5. 语音播报回复
await this.voiceService.speak(response);
}
/**
* 开始语音输入
*/
async startVoiceInput(): Promise<void> {
this.onStateChangeCallback?.(AgentState.LISTENING);
await this.voiceService.startListening(
(text: string, isFinal: boolean) => {
if (isFinal && text.trim()) {
this.processInput(text);
}
},
(error: string) => {
console.error('[AIAgent] 语音识别错误:', error);
this.onStateChangeCallback?.(AgentState.IDLE);
}
);
}
/**
* 停止语音输入
*/
async stopVoiceInput(): Promise<void> {
await this.voiceService.stopListening();
this.onStateChangeCallback?.(AgentState.IDLE);
}
/**
* 获取对话历史
*/
getHistory(): Message[] {
return this.context.getHistory();
}
/**
* 清空对话
*/
clearHistory(): void {
this.context.clear();
}
/**
* 获取意图描述
*/
private getIntentDescription(intent: IntentType): string {
const descriptions: Record<IntentType, string> = {
[IntentType.OPEN_APP]: '打开应用',
[IntentType.SET_ALARM]: '设置闹钟',
[IntentType.SET_REMINDER]: '设置提醒',
[IntentType.QUERY_WEATHER]: '查询天气',
[IntentType.QUERY_TIME]: '查询时间',
[IntentType.CONTROL_DEVICE]: '控制设备',
[IntentType.CHAT]: '闲聊',
[IntentType.UNKNOWN]: '理解意图'
};
return descriptions[intent] || '执行操作';
}
}
/**
* 智能体状态
*/
export enum AgentState {
IDLE = 'idle', // 空闲
LISTENING = 'listening', // 监听中
THINKING = 'thinking', // 思考中
SPEAKING = 'speaking' // 说话中
}
7. 主界面 (pages/Index.ets)
// entry/src/main/ets/pages/Index.ets
import { Message, MessageRole, MessageType } from '../model/MessageModel';
import { AIAgent, AgentState } from '../engine/AIAgent';
import { ActionExecutor } from '../engine/ActionExecutor';
import { VoiceService } from '../service/VoiceService';
import { common } from '@kit.AbilityKit';
import { promptAction } from '@kit.ArkUI';
@Entry
@Component
struct Index {
@State messageList: Message[] = [];
@State inputText: string = '';
@State agentState: AgentState = AgentState.IDLE;
@State isVoiceMode: boolean = false;
private agent: AIAgent = AIAgent.getInstance();
private voiceService: VoiceService = VoiceService.getInstance();
private scroller: Scroller = new Scroller();
private context = getContext(this) as common.UIAbilityContext;
async aboutToAppear(): Promise<void> {
// 初始化
ActionExecutor.getInstance().setContext(this.context);
// 请求权限
await this.voiceService.requestPermission(this.context);
// 设置回调
this.agent.setOnMessage((message: Message) => {
this.messageList = [...this.messageList, message];
// 滚动到底部
setTimeout(() => {
this.scroller.scrollEdge(Edge.Bottom);
}, 100);
});
this.agent.setOnStateChange((state: AgentState) => {
this.agentState = state;
});
// 添加欢迎消息
const welcomeMessage = new Message({
role: MessageRole.ASSISTANT,
type: MessageType.TEXT,
content: '你好!我是小V助手 🤖\n\n我可以帮你:\n• 回答各种问题\n• 打开应用\n• 设置闹钟和提醒\n• 查询天气和时间\n• 控制智能设备\n\n试着对我说点什么吧!'
});
this.messageList.push(welcomeMessage);
}
/**
* 发送消息
*/
async sendMessage(): Promise<void> {
if (!this.inputText.trim()) return;
const text = this.inputText.trim();
this.inputText = '';
await this.agent.processInput(text);
}
/**
* 切换语音模式
*/
async toggleVoiceMode(): Promise<void> {
if (this.isVoiceMode) {
// 停止语音输入
await this.agent.stopVoiceInput();
this.isVoiceMode = false;
} else {
// 开始语音输入
this.isVoiceMode = true;
await this.agent.startVoiceInput();
}
}
/**
* 获取状态文本
*/
getStateText(): string {
switch (this.agentState) {
case AgentState.LISTENING:
return '正在听...';
case AgentState.THINKING:
return '思考中...';
case AgentState.SPEAKING:
return '说话中...';
default:
return '';
}
}
/**
* 格式化时间
*/
formatTime(timestamp: number): string {
const date = new Date(timestamp);
const hour = date.getHours().toString().padStart(2, '0');
const minute = date.getMinutes().toString().padStart(2, '0');
return `${hour}:${minute}`;
}
build() {
Column() {
// 顶部标题栏
Row() {
Column() {
Text('小V助手')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor('#333333')
if (this.agentState !== AgentState.IDLE) {
Row() {
LoadingProgress()
.width(14)
.height(14)
.color('#007DFF')
Text(this.getStateText())
.fontSize(12)
.fontColor('#007DFF')
.margin({ left: 4 })
}
.margin({ top: 2 })
}
}
.alignItems(HorizontalAlign.Start)
Blank()
// 清空对话按钮
Button() {
Image($r('app.media.ic_clear'))
.width(20)
.height(20)
.fillColor('#666666')
}
.width(40)
.height(40)
.backgroundColor('#F0F0F0')
.borderRadius(20)
.onClick(() => {
promptAction.showDialog({
title: '清空对话',
message: '确定要清空所有对话记录吗?',
buttons: [
{ text: '取消', color: '#666666' },
{ text: '确定', color: '#007DFF' }
]
}).then((result) => {
if (result.index === 1) {
this.messageList = [];
this.agent.clearHistory();
}
});
})
}
.width('100%')
.height(60)
.padding({ left: 16, right: 16 })
.backgroundColor(Color.White)
// 消息列表
List({ scroller: this.scroller, space: 16 }) {
ForEach(this.messageList, (message: Message) => {
ListItem() {
this.MessageBubble(message)
}
}, (message: Message) => message.id)
}
.width('100%')
.layoutWeight(1)
.padding({ left: 16, right: 16, top: 12, bottom: 12 })
.backgroundColor('#F5F5F5')
// 底部输入区域
Row() {
// 语音按钮
Button() {
Image(this.isVoiceMode ? $r('app.media.ic_keyboard') : $r('app.media.ic_voice'))
.width(24)
.height(24)
.fillColor(this.isVoiceMode ? '#FF3B30' : '#666666')
}
.width(44)
.height(44)
.backgroundColor(this.isVoiceMode ? '#FFE5E5' : '#F0F0F0')
.borderRadius(22)
.onClick(() => this.toggleVoiceMode())
if (this.isVoiceMode) {
// 语音输入状态
Column() {
if (this.agentState === AgentState.LISTENING) {
Row() {
ForEach([1, 2, 3, 4, 5], (i: number) => {
Column()
.width(4)
.height(12 + Math.random() * 20)
.backgroundColor('#007DFF')
.borderRadius(2)
.margin({ left: 4, right: 4 })
.animation({
duration: 300,
iterations: -1,
curve: Curve.EaseInOut
})
})
}
.justifyContent(FlexAlign.Center)
}
Text(this.agentState === AgentState.LISTENING ? '正在聆听...' : '点击麦克风开始说话')
.fontSize(14)
.fontColor('#666666')
.margin({ top: 8 })
}
.layoutWeight(1)
.height(44)
.justifyContent(FlexAlign.Center)
} else {
// 文字输入框
TextInput({ placeholder: '输入消息...', text: this.inputText })
.layoutWeight(1)
.height(44)
.backgroundColor('#F5F5F5')
.borderRadius(22)
.padding({ left: 16, right: 16 })
.margin({ left: 8, right: 8 })
.onChange((value) => {
this.inputText = value;
})
.onSubmit(() => {
this.sendMessage();
})
// 发送按钮
Button() {
Image($r('app.media.ic_send'))
.width(24)
.height(24)
.fillColor(Color.White)
}
.width(44)
.height(44)
.backgroundColor(this.inputText.trim() ? '#007DFF' : '#CCCCCC')
.borderRadius(22)
.enabled(this.inputText.trim().length > 0)
.onClick(() => this.sendMessage())
}
}
.width('100%')
.height(70)
.padding({ left: 12, right: 12, top: 8, bottom: 16 })
.backgroundColor(Color.White)
}
.width('100%')
.height('100%')
}
/**
* 消息气泡组件
*/
@Builder
MessageBubble(message: Message) {
Column() {
if (message.role === MessageRole.USER) {
// 用户消息(右侧)
Row() {
Blank()
Column() {
Text(message.content)
.fontSize(15)
.fontColor(Color.White)
.lineHeight(22)
}
.padding(12)
.backgroundColor('#007DFF')
.borderRadius({
topLeft: 16,
topRight: 4,
bottomLeft: 16,
bottomRight: 16
})
.constraintSize({ maxWidth: '75%' })
// 用户头像
Image($r('app.media.ic_user'))
.width(36)
.height(36)
.borderRadius(18)
.margin({ left: 8 })
}
.width('100%')
.justifyContent(FlexAlign.End)
} else {
// AI消息(左侧)
Row() {
// AI头像
Stack() {
Circle()
.width(36)
.height(36)
.fill('#E6F2FF')
Image($r('app.media.ic_robot'))
.width(24)
.height(24)
}
.margin({ right: 8 })
Column() {
Text(message.content)
.fontSize(15)
.fontColor('#333333')
.lineHeight(22)
// 显示时间
Text(this.formatTime(message.timestamp))
.fontSize(11)
.fontColor('#999999')
.margin({ top: 4 })
}
.padding(12)
.backgroundColor(Color.White)
.borderRadius({
topLeft: 4,
topRight: 16,
bottomLeft: 16,
bottomRight: 16
})
.constraintSize({ maxWidth: '75%' })
.alignItems(HorizontalAlign.Start)
.shadow({
radius: 4,
color: 'rgba(0,0,0,0.05)',
offsetX: 0,
offsetY: 2
})
Blank()
}
.width('100%')
.justifyContent(FlexAlign.Start)
}
}
}
}
8. 快捷指令面板 (components/QuickCommands.ets)
// entry/src/main/ets/components/QuickCommands.ets
/**
* V哥设计的快捷指令面板
* 方便用户快速触发常用功能
*/
interface QuickCommand {
icon: Resource;
label: string;
command: string;
color: string;
}
@Component
export struct QuickCommands {
onCommand: (command: string) => void = () => {};
private commands: QuickCommand[] = [
{ icon: $r('app.media.ic_weather'), label: '查天气', command: '今天天气怎么样', color: '#FFB800' },
{ icon: $r('app.media.ic_time'), label: '查时间', command: '现在几点了', color: '#007DFF' },
{ icon: $r('app.media.ic_alarm'), label: '设闹钟', command: '明天早上7点叫我起床', color: '#34C759' },
{ icon: $r('app.media.ic_remind'), label: '提醒我', command: '10分钟后提醒我喝水', color: '#FF9500' },
{ icon: $r('app.media.ic_app'), label: '打开相机', command: '打开相机', color: '#AF52DE' },
{ icon: $r('app.media.ic_home'), label: '开灯', command: '打开客厅的灯', color: '#FF3B30' }
];
build() {
Column() {
Text('快捷指令')
.fontSize(14)
.fontColor('#999999')
.margin({ bottom: 12 })
Flex({ wrap: FlexWrap.Wrap, justifyContent: FlexAlign.SpaceBetween }) {
ForEach(this.commands, (cmd: QuickCommand) => {
Column() {
Stack() {
Circle()
.width(44)
.height(44)
.fill(cmd.color)
.opacity(0.15)
Image(cmd.icon)
.width(24)
.height(24)
.fillColor(cmd.color)
}
Text(cmd.label)
.fontSize(12)
.fontColor('#666666')
.margin({ top: 6 })
}
.width('30%')
.margin({ bottom: 16 })
.onClick(() => {
this.onCommand(cmd.command);
})
})
}
}
.width('100%')
.padding(16)
.backgroundColor(Color.White)
.borderRadius(12)
}
}
五、资源文件准备
需要的图标资源
在 entry/src/main/resources/base/media/ 添加以下图标:
| 文件名 | 用途 | 建议尺寸 |
|---|---|---|
| ic_robot.svg | AI头像 | 48x48 |
| ic_user.svg | 用户头像 | 48x48 |
| ic_send.svg | 发送按钮 | 24x24 |
| ic_voice.svg | 语音按钮 | 24x24 |
| ic_keyboard.svg | 键盘按钮 | 24x24 |
| ic_clear.svg | 清空按钮 | 24x24 |
| ic_weather.svg | 天气图标 | 24x24 |
| ic_time.svg | 时间图标 | 24x24 |
| ic_alarm.svg | 闹钟图标 | 24x24 |
| ic_remind.svg | 提醒图标 | 24x24 |
| ic_app.svg | 应用图标 | 24x24 |
| ic_home.svg | 智能家居图标 | 24x24 |
示例SVG
ic_robot.svg:
<svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
<circle cx="24" cy="24" r="20" fill="#007DFF"/>
<circle cx="17" cy="20" r="3" fill="white"/>
<circle cx="31" cy="20" r="3" fill="white"/>
<path d="M16 30 Q24 36 32 30" stroke="white" stroke-width="2" fill="none"/>
<rect x="22" y="4" width="4" height="6" rx="2" fill="#007DFF"/>
<circle cx="24" cy="4" r="3" fill="#007DFF"/>
</svg>
ic_voice.svg:
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3z"/>
<path d="M17 11c0 2.76-2.24 5-5 5s-5-2.24-5-5H5c0 3.53 2.61 6.43 6 6.92V21h2v-3.08c3.39-.49 6-3.39 6-6.92h-2z"/>
</svg>
六、V哥总结:关键技术点
1. 意图识别的设计思路
用户输入 → 规则匹配(快速) → 高置信度直接执行
↓
低置信度 → 调用LLM兜底
2. 对话管理的核心
// 多轮对话的关键:上下文管理
class ConversationContext {
messages: Message[] = [];
maxHistory: number = 10; // 控制历史长度,避免Token浪费
}
3. 语音交互的最佳实践
- 先请求权限,再初始化引擎
- 语音识别和语音合成用完要释放
- 做好错误处理和降级方案
4. 性能优化建议
- 意图识别用本地规则,快速响应
- LLM调用做好缓存和限流
- 消息列表使用LazyForEach优化
七、V哥唠两句
兄弟们,这套代码是V哥实战中总结出来的,完整实现了一个能用的AI智能体。当然,实际项目中你还需要:
- 接入真实的LLM API(替换掉示例配置)
- 完善意图规则库(根据你的业务场景)
- 接入真实的智能家居API
- 做好异常处理和用户引导
AI智能体的核心不是技术多牛逼,而是用户体验做得好!
关注V哥不迷路!前行路上不犯怵!
更多推荐

所有评论(0)