在传统移动应用开发中,我们遵循的是典型的"按钮-逻辑-结果"模式。以天气查询为例,用户需要明确点击"查询天气"按钮,应用才会执行对应的业务逻辑。这种模式存在两个根本性局限:
AI原生应用彻底改变了这一范式。在HarmonyOS上开发AI原生应用时,最核心的变化是:
typescript复制// 传统方式
Button("查询天气").onClick(() => { this.loadWeather() })
// AI原生方式
Input("你想做什么?").onSubmit(async (text) => {
const result = await agent.run(text)
this.render(result)
})
这种转变的技术本质是实现了"意图驱动"的交互模式。开发者需要构建一个能够理解自然语言、规划任务流程、调用适当工具并返回结构化结果的智能系统。
关键区别:传统应用是功能集合,AI原生应用是能力集合。前者需要用户适配应用,后者是应用适配用户。
一个标准的AI原生鸿蒙应用应采用以下目录结构:
code复制entry
├─ pages # 页面组件
├─ components # 公共组件
├─ services # 业务服务
├─ ai # AI核心模块
│ ├─ agent # 智能体实现
│ ├─ tools # 工具集合
│ ├─ prompt # 提示工程
│ └─ memory # 记忆管理
├─ models # 数据模型
└─ utils # 工具函数
这种结构的关键优势在于:
AI原生应用的核心执行流程包含四个关键环节:
mermaid复制graph TD
A[用户输入] --> B(Agent理解意图)
B --> C{是否需要多步执行}
C -->|是| D[任务拆解]
C -->|否| E[选择工具]
D --> F[创建执行链]
E --> G[调用工具]
F --> G
G --> H[Service执行]
H --> I[返回结果]
typescript复制// ai/agent/Agent.ets
export class Agent {
private tools: ToolRegistry // 工具注册表
private memory?: Memory // 记忆模块
async run(input: string): Promise<any> {
// 1. 意图解析
const intent = await this.parse(input)
// 2. 工具选择
const tool = this.selectTool(intent)
// 3. 执行并返回
return await tool.execute(intent.params)
}
private async parse(input: string): Promise<Intent> {
// 实现细节见下文
}
private selectTool(intent: Intent): Tool {
// 实现细节见下文
}
}
意图解析是Agent最核心的能力之一,在鸿蒙环境下有三种实现方式:
云端大模型方案:
typescript复制private async parse(input: string): Promise<Intent> {
const response = await fetch('https://api.llm-provider.com/v1/parse', {
method: 'POST',
body: JSON.stringify({ text: input })
})
return response.json()
}
优点:理解能力强
缺点:网络依赖、延迟高
端侧小模型方案:
typescript复制private async parse(input: string): Promise<Intent> {
return await LocalModel.infer(input)
}
优点:响应快、隐私好
缺点:能力有限
混合模式:
typescript复制private async parse(input: string): Promise<Intent> {
if (this.isSimpleQuery(input)) {
return LocalModel.infer(input)
}
return CloudModel.infer(input)
}
最佳实践:根据场景动态选择
typescript复制// ai/tools/index.ets
export const toolRegistry = {
getWeather: new WeatherTool(),
sendEmail: new EmailTool(),
// ...其他工具
}
private selectTool(intent: Intent): Tool {
const tool = toolRegistry[intent.action]
if (!tool) {
throw new Error(`No tool registered for action: ${intent.action}`)
}
return tool
}
typescript复制// ai/tools/Tool.ets
export interface Tool {
name: string
description: string
parameters: ParameterDefinition[]
execute(params: Record<string, any>): Promise<any>
}
typescript复制// ai/tools/WeatherTool.ets
export class WeatherTool implements Tool {
name = 'getWeather'
description = '查询指定城市的天气情况'
parameters = [
{
name: 'city',
type: 'string',
required: true,
description: '城市名称'
}
]
async execute(params: { city: string }) {
if (!params.city) {
throw new Error('city参数不能为空')
}
const service = new WeatherService()
try {
const weather = await service.getWeather(params.city)
return {
temperature: weather.temp,
condition: weather.condition,
humidity: weather.humidity
}
} catch (error) {
console.error('天气查询失败:', error)
throw new Error('获取天气信息失败,请稍后重试')
}
}
}
typescript复制// services/WeatherService.ets
export class WeatherService {
private cache = new Map<string, WeatherData>()
private cacheTTL = 30 * 60 * 1000 // 30分钟缓存
async getWeather(city: string): Promise<WeatherData> {
// 检查缓存
if (this.cache.has(city)) {
const cached = this.cache.get(city)!
if (Date.now() - cached.timestamp < this.cacheTTL) {
return cached
}
}
// 调用API
const response = await fetch(`https://api.weather.com/v1/${encodeURIComponent(city)}`)
if (!response.ok) {
throw new Error(`天气API请求失败: ${response.status}`)
}
const data = await response.json()
const result = {
...data,
timestamp: Date.now()
}
// 更新缓存
this.cache.set(city, result)
return result
}
}
typescript复制@Entry
@Component
struct AINativeApp {
@State input: string = ""
@State result: any = null
@State isLoading: boolean = false
private agent = new Agent()
build() {
Column({ space: 20 }) {
// 输入区域
TextInput({ placeholder: "请输入您的需求..." })
.width('90%')
.height(60)
.onChange((val) => this.input = val)
// 执行按钮
Button("执行", { type: ButtonType.Normal })
.width('50%')
.onClick(async () => {
this.isLoading = true
try {
this.result = await this.agent.run(this.input)
} catch (error) {
console.error("执行失败:", error)
this.result = { error: error.message }
} finally {
this.isLoading = false
}
})
// 结果展示
if (this.isLoading) {
LoadingProgress()
} else if (this.result) {
this.renderResult(this.result)
}
}
.width('100%')
.height('100%')
.padding(20)
}
@Builder
private renderResult(result: any) {
// 实现结果渲染逻辑
}
}
typescript复制@Entry
@Component
struct ChatUI {
@State messages: Array<{
role: 'user' | 'assistant'
content: string
timestamp: number
}> = []
@State currentInput: string = ""
private agent = new Agent()
build() {
Column() {
// 消息列表
List({ space: 10 }) {
ForEach(this.messages, (msg) => {
ListItem() {
Column({ space: 5 }) {
Text(msg.role === 'user' ? '你' : 'AI')
.fontColor(msg.role === 'user' ? '#0066CC' : '#FF6600')
Text(msg.content)
.padding(10)
.borderRadius(10)
.backgroundColor(msg.role === 'user' ? '#F0F7FF' : '#FFF0F0')
}
}
})
}
.layoutWeight(1)
// 输入区域
Row({ space: 10 }) {
TextInput({ placeholder: "请输入..." })
.layoutWeight(1)
.onChange((val) => this.currentInput = val)
Button("发送")
.onClick(() => this.handleSend())
}
.width('100%')
.padding(10)
}
}
private async handleSend() {
const userInput = this.currentInput.trim()
if (!userInput) return
// 添加用户消息
this.messages = [...this.messages, {
role: 'user',
content: userInput,
timestamp: Date.now()
}]
this.currentInput = ""
try {
// 获取AI响应
const response = await this.agent.run(userInput)
// 添加AI消息
this.messages = [...this.messages, {
role: 'assistant',
content: typeof response === 'string' ? response : JSON.stringify(response),
timestamp: Date.now()
}]
} catch (error) {
this.messages = [...this.messages, {
role: 'assistant',
content: `出错: ${error.message}`,
timestamp: Date.now()
}]
}
}
}
typescript复制class AdvancedAgent extends Agent {
async run(input: string): Promise<any> {
// 1. 解析意图
const intent = await this.parse(input)
// 2. 任务规划
const plan = await this.createPlan(intent)
// 3. 执行计划
const context = {}
for (const step of plan) {
const tool = this.selectTool(step)
context[step.tool] = await tool.execute({
...step.params,
...context
})
}
return context
}
private async createPlan(intent: Intent): Promise<ExecutionStep[]> {
// 简单任务直接执行
if (this.isSimpleTask(intent)) {
return [{ tool: intent.action, params: intent.params }]
}
// 复杂任务拆解
return await this.planWithLLM(intent)
}
private async planWithLLM(intent: Intent): Promise<ExecutionStep[]> {
const prompt = `
用户意图: ${JSON.stringify(intent)}
可用工具: ${Object.keys(this.tools).join(', ')}
请将任务拆解为执行步骤,返回JSON格式:
[{
"tool": "工具名",
"params": {参数对象}
}]
`
const response = await LLM.generate(prompt)
return JSON.parse(response)
}
}
typescript复制class Memory {
private history: Array<{
role: 'user' | 'assistant' | 'system'
content: string
timestamp: number
}> = []
private maxSize = 20 // 最大记忆条数
add(role: 'user' | 'assistant' | 'system', content: string) {
this.history.push({
role,
content,
timestamp: Date.now()
})
// 限制历史记录大小
if (this.history.length > this.maxSize) {
this.history.shift()
}
}
getContext(): string {
return this.history
.map(entry => `${entry.role}: ${entry.content}`)
.join('\n')
}
clear() {
this.history = []
}
}
typescript复制// ai/models/LocalModel.ets
export class LocalModel {
private static model: ai.AIModel | null = null
static async initialize() {
if (!this.model) {
const context = getContext(this) as common.UIAbilityContext
this.model = await ai.loadModel(context, {
modelName: 'intent-parser',
modelPath: 'entry/resources/rawfile/model.pt'
})
}
}
static async infer(input: string): Promise<Intent> {
await this.initialize()
const tensor = this.preprocess(input)
const output = await this.model.infer(tensor)
return this.postprocess(output)
}
private static preprocess(text: string): ai.Tensor {
// 文本向量化处理
}
private static postprocess(tensor: ai.Tensor): Intent {
// 解析模型输出
}
}
typescript复制class DistributedTool extends Tool {
async execute(params: any) {
// 发现可用设备
const devices = await distributedDeviceManager.getAvailableDevices()
// 选择最适合的设备
const target = this.selectDevice(devices)
// 分布式调用
return await distributedTaskDispatcher.dispatch(target, {
tool: this.name,
params
})
}
private selectDevice(devices: DeviceInfo[]): DeviceInfo {
// 根据设备能力选择最优设备
}
}
工具白名单机制:
typescript复制const allowedTools = ['getWeather', 'searchNews']
private validateTool(toolName: string) {
if (!allowedTools.includes(toolName)) {
throw new Error(`禁止访问工具: ${toolName}`)
}
}
参数严格校验:
typescript复制class SafeTool implements Tool {
async execute(params: any) {
if (!params || typeof params !== 'object') {
throw new Error('参数必须为对象')
}
// 检查每个参数
for (const [key, spec] of Object.entries(this.parameters)) {
if (spec.required && !(key in params)) {
throw new Error(`缺少必要参数: ${key}`)
}
}
}
}
执行限制:
typescript复制class LimitedAgent extends Agent {
private executionCount = 0
private readonly MAX_EXECUTIONS = 10
async run(input: string) {
if (this.executionCount >= this.MAX_EXECUTIONS) {
throw new Error('达到最大执行次数限制')
}
this.executionCount++
try {
return await super.run(input)
} finally {
this.executionCount--
}
}
}
结果缓存:
typescript复制const cache = new LRUCache<string, any>({
max: 100, // 最大缓存数
ttl: 60 * 1000 // 1分钟有效期
})
async function cachedRun(input: string) {
const cacheKey = createHash('md5').update(input).digest('hex')
if (cache.has(cacheKey)) {
return cache.get(cacheKey)
}
const result = await agent.run(input)
cache.set(cacheKey, result)
return result
}
批量处理:
typescript复制class BatchAgent extends Agent {
async batchRun(inputs: string[]): Promise<any[]> {
const batchResults = []
// 并行处理
await Promise.all(inputs.map(async (input) => {
const result = await this.run(input)
batchResults.push(result)
}))
return batchResults
}
}
模型量化:
typescript复制// 在模型加载时应用量化
const quantizedModel = await ai.loadModel(context, {
modelName: 'quantized-model',
quantization: {
bits: 8,
scheme: 'symmetric'
}
})
typescript复制// test/agent.test.ets
describe('Agent测试', () => {
let agent: Agent
before(() => {
agent = new Agent()
})
it('应正确解析简单查询', async () => {
const intent = await agent.parse("上海天气怎么样")
assert.equal(intent.action, 'getWeather')
assert.equal(intent.params.city, '上海')
})
it('应正确处理多步任务', async () => {
const result = await agent.run("帮我查下上海天气然后推荐穿衣")
assert.hasAllKeys(result, ['weather', 'recommendation'])
})
})
typescript复制// e2e/app.test.ets
describe('端到端测试', () => {
let driver: UiDriver
before(async () => {
driver = await UiDriver.create()
})
it('应完成完整交互流程', async () => {
// 启动应用
await driver.delay(1000)
// 输入查询
const input = await driver.findComponent(ON.textInput('请输入您的需求...'))
await input.inputText('查询北京天气')
// 点击执行
const button = await driver.findComponent(ON.text('执行'))
await button.click()
// 验证结果
await driver.assertComponentExist(ON.text('北京'))
await driver.assertComponentExist(ON.text('温度'))
})
})
增强意图解析能力:
丰富工具生态:
改进用户体验:
自适应学习系统:
typescript复制class LearningAgent extends Agent {
private userPreferences: Record<string, any> = {}
async adaptToUser(feedback: UserFeedback) {
// 根据用户反馈调整行为
}
}
多模态交互:
typescript复制class MultiModalAgent extends Agent {
async run(input: Input) {
if (input.type === 'text') {
return super.run(input.content)
} else if (input.type === 'image') {
return this.processImage(input.content)
}
}
}
分布式智能网络:
typescript复制class DistributedAgent extends Agent {
async run(input: string) {
const bestDevice = await this.findOptimalDevice()
return await bestDevice.execute(input)
}
}
在鸿蒙生态中开发AI原生应用,开发者实际上是在构建未来的智能交互标准。这种开发范式不仅适用于消费级应用,在工业、医疗、教育等专业领域同样具有巨大潜力。关键在于深入理解"意图驱动"的本质,构建灵活可扩展的Agent架构,并充分利用鸿蒙的分布式能力。