鸿蒙 AI 应用开发实战:结构化大模型驱动智能穿搭与衣物护理
鸿蒙 AI 应用开发实战:结构化大模型驱动智能穿搭与衣物护理
关键词:HarmonyOS、ArkTS、ArkUI、应用智能化、智能体、结构化输出、端侧数据、本地持久化、衣物护理、多端协同
本文以“衣见倾心”这一真实可运行的鸿蒙应用为例,记录从生活痛点、产品取舍到 ArkTS 工程实现的完整过程,并讨论如何将大模型能力从一句泛泛的建议,转化为用户可以直接执行的穿搭方案。

一、问题从来不是“缺衣服”,而是缺少一套决策系统
“今天穿什么”是一件极其日常、却并不简单的事。早晨打开衣柜时,用户往往同时面对温度、降雨、通勤或约会场合、已有衣物、刚洗的衣服、已经连续穿过的单品等约束。传统衣橱 App 通常解决的是“记录”:拍照、分类、列表展示;传统天气 App 提供的是“信息”:气温、体感、降雨。二者之间仍然缺了一层真正的决策:在我的衣橱里、面对今天的天气与当前场景,我到底应该穿哪几件,以及为什么。
“衣见倾心”将这个问题重新定义为一个轻量级的个人生活决策场景。它不追求生成一张不可购买、不可穿着的“时尚概念图”,而是从用户已拥有、状态可用的衣物中选择组合;不只给出“温柔风”“学院风”等抽象标签,而是返回衣物 ID、推荐理由和护理提示;也不把 AI 当成唯一事实来源,而是使用本地规则限制温度、状态等硬约束,再让模型完成风格协调、场景表达与语言解释。
这正契合鸿蒙应用智能化实践的核心:AI 不是附在页面顶部的聊天框,而是能读取业务上下文、遵守业务规则、驱动业务对象状态变化的能力。对于本项目而言,业务对象是衣物,业务规则是适温、清洁状态与护理流转,AI 的职责是在规则允许的范围内做个性化组合与解释。
二、项目定位与征文方向的对应关系
本项目选择“AI 穿搭与衣物护理”这一生活化主题,覆盖了多个征文方向。
第一,鸿蒙应用智能化实践。应用将天气、场景和衣橱数据组织为结构化上下文,通过兼容 OpenAI 协议的模型服务生成严格 JSON,再映射回本地衣物实体。模型输出不直接拼到页面上,而是经过校验后驱动页面展示。
第二,鸿蒙智能体与 Skill 实践。当前版本已将能力边界划分为“生成搭配、添加衣物、查询衣橱、更新护理状态”。后续可将其映射为小艺可调用的意图:用户说“今天十八度去约会穿什么”“哪些衣服该洗了”“把这件外套加入衣橱”,系统便可将自然语言转化为应用内动作。
第三,鸿蒙应用开发与工程实践。项目使用 ArkTS 严格类型定义模型,用 ArkUI 的声明式组件构建四个业务页面,用 Preferences 保证本地数据可恢复,用异步网络请求处理模型调用,并通过服务层隔离 UI 与 AI 实现。
第四,跨设备协同与系统能力。手机是拍摄、确认和即时决策的入口;平板或 PC 更适合批量整理衣柜、回看穿搭日历;穿戴设备可在出门前显示下一套搭配、天气突变时提醒加衣。当前 MVP 已将数据模型和服务边界设计为可扩展形态,后续可通过分布式 KV 同步衣橱与穿搭记录。
三、体验设计:先把“能用”做完整,再把“聪明”做可信
应用底部由“今日、衣橱、护理、我的”四个 Tab 组成。这样的信息架构不是按照技术模块切分,而是按照用户一天中的行为路径切分:早晨在“今日”做选择;空闲时在“衣橱”维护资产;洗衣、晾晒时进入“护理”;偏好、提醒和未来能力统一在“我的”管理。

首页先展示城市、天气、温度和衣橱状态,再让用户选择通勤、约会、休闲、运动场景。场景标签是一个重要的产品取舍:与其让用户输入一大段描述,不如先给高频且低成本的选择。用户点击标签或“重新生成我的穿搭”后,按钮会进入“正在生成”状态,并显示反馈文案,避免异步网络调用在视觉上像“没有反应”。

推荐卡展示标题、天气与场景、选中的衣物、原因和提示。卡片只展示模型已经映射到本地实体的衣物,因此不会出现“建议穿一件你没有的蓝色羊毛大衣”这种断裂体验。若网络异常、服务超时或模型输出无法解析,应用会退回本地推荐策略,保证首页始终有结果可用。这种“可用优先、智能增强”的策略,比完全依赖网络更符合移动应用的可靠性要求。
四、ArkUI 页面搭建:声明式 UI 如何承载生活化信息
在 Index.ets 中,应用使用 Tabs 组织四个页面,并通过 @State current 保持当前选中项。页面主题集中在 Theme.ets 中维护,例如背景色、卡片色、主色、圆角和统一边距,避免颜色散落在每个页面里。柔和的粉白色背景与卡片化布局不是单纯的视觉装饰,它让“衣橱”“护理”这类高频生活信息保持低压力、易浏览的阅读节奏。
首页 TodayTab 的状态定义如下:
@State clothes: Clothing[] = [];
@State weather: WeatherInfo = OutfitAI.mockWeather();
@State plan: OutfitPlan | null = null;
@State scene: string = '通勤';
@State loading: boolean = false;
@State feedback: string = '';
这里的关键是让状态与用户可见内容一一对应。clothes 影响衣橱统计和推荐候选;scene 影响提示词和本地策略;plan 驱动推荐卡;loading 控制按钮文案与点击保护;feedback 则为异步过程提供可感知的反馈。状态粒度不要过粗,否则页面一处变化会引起大量无关刷新;也不要把所有临时状态放入全局,否则会失去页面封装性。
点击生成按钮的处理逻辑如下:
async generate(): Promise<void> {
if (this.loading) { return; }
this.loading = true;
this.feedback = '正在根据你的衣橱生成新搭配…';
try {
this.plan = await OutfitAI.recommend(this.clothes, this.weather, this.scene);
this.feedback = '已更新一套新的搭配建议';
} finally {
this.loading = false;
}
}
finally 的意义非常重要。无论成功、解析失败还是网络抛错,loading 都会被复位,用户不会陷入永久禁用的按钮状态。对 AI 场景而言,失败不是异常路径,而是必须被产品设计覆盖的常规路径。
五、衣橱不是图片墙:建立可计算的数据模型

如果衣物只保存一张照片和一个名称,AI 无法可靠完成温度匹配、风格筛选和护理提醒。因此项目定义了 Clothing 接口:
export interface Clothing {
id: string;
name: string;
category: string;
color: string;
season: string[];
style: string[];
temperatureMin: number;
temperatureMax: number;
emoji: string;
status: ClothingStatus;
wornCount: number;
lastWorn: string;
careTip: string;
}
其中 id 是模型输出与本地实体之间的稳定主键;category 用于保证一套搭配至少包含上装、下装或裙装、鞋履等必要角色;temperatureMin/temperatureMax 是硬约束;style、color 是模型做审美判断的上下文;status、wornCount、lastWorn 让应用从静态衣柜进入动态衣物生命周期管理;careTip 则将衣物知识沉淀在每个对象上。
状态机采用 clean | worn | washing | drying 四种状态。它虽然简单,却覆盖了用户真正关心的关键事实:这件衣服能不能穿、是不是该洗、是否还在晾晒。更复杂的状态并不一定更好;MVP 阶段要优先保证状态可解释、流转可预测。护理页面中,“去清洗—去晾晒—已收纳”按钮恰好对应这条有向链路。

衣橱页支持分类筛选和 AI 识别入库演示。当前版本以模拟识别完成从“拍摄入口”到“标签化衣物档案”的交互闭环,后续替换为视觉模型时,界面与数据层无需重写:只需将识别结果转换为 Clothing。这是先稳定领域模型、再替换能力实现的工程思路。
六、本地持久化:把用户衣橱保留在用户手里
衣物数据是强个人化数据,默认应可离线使用。项目通过 @kit.ArkData 的 Preferences 封装 WardrobeStore,将存储细节从 UI 中移除。初始化时先获取 Preferences 实例,如果首次运行没有任何数据,则写入示例衣物;查询、添加、状态更新都经由 Store 完成。
static async updateStatus(id: string, status: ClothingStatus): Promise<void> {
const list = await WardrobeStore.list();
list.forEach((item: Clothing) => {
if (item.id === id) {
item.status = status;
if (status === 'worn') {
item.wornCount += 1;
item.lastWorn = '今天';
}
}
});
await WardrobeStore.save(list);
}
持久化方法在写入后调用 flush(),使数据及时落盘。这样做的好处是:即使应用在后台被系统回收,衣橱数据也不会因为只存在内存中而丢失。对于将来分布式协同的版本,本地 Preferences 仍然可以作为离线缓存和冲突合并前的基础层。
七、模型调用:让大模型只做它擅长的事情
模型服务层位于 OutfitAI.ets。它的输入不是一段随意拼接的自然语言,而是 WeatherInfo + scene + WardrobePromptItem[] 组成的 JSON。WardrobePromptItem 保留 ID、名称、分类、颜色、风格、适温、状态与最近穿着时间,避免发送无关 UI 字段。
private static buildPrompt(clothes: Clothing[], weather: WeatherInfo, scene: string): string {
const wardrobe: WardrobePromptItem[] = [];
for (const item of clothes) {
wardrobe.push({
id: item.id,
name: item.name,
category: item.category,
color: item.color,
style: item.style,
temperature: [item.temperatureMin, item.temperatureMax],
status: item.status,
lastWorn: item.lastWorn
});
}
return JSON.stringify({ weather, scene, wardrobe });
}
系统提示词要求模型只返回以下 JSON:
{
"title": "搭配标题",
"itemIds": ["衣物id"],
"reason": "推荐理由",
"tips": "穿着或天气提醒"
}
为什么必须返回 itemIds,而不是衣物名称?因为名称不是可靠主键,用户可能拥有两件“白色衬衫”;而 ID 能稳定映射回本地对象。为什么要把提示词限制为 JSON?因为 UI 需要的是可渲染字段,而不是不可预测的长文本。为什么还要在客户端检查映射结果?因为模型可能输出不存在的 ID,或因网络、限流、格式问题返回异常内容。
服务请求使用 @kit.NetworkKit 的 http.createHttp(),设置 JSON 请求头、认证头、连接超时与读取超时。无论请求是否成功,客户端都在 finally 中释放 Http 实例。对于移动端资源管理来说,这个细节不可忽略。
try {
const response = await client.request(AIConfig.endpoint, options);
if (response.responseCode !== 200) {
return OutfitAI.localRecommend(clothes, weather, scene);
}
// 解析 JSON 并映射 itemIds
} catch (e) {
return OutfitAI.localRecommend(clothes, weather, scene);
} finally {
client.destroy();
}
八、为何需要本地规则兜底
“接了大模型”不等于“所有决策都要交给大模型”。项目中的 localRecommend 先筛选状态为 clean 且适温范围覆盖当前气温的衣物,然后寻找上衣、外套、下装/裙装、鞋履。这是确定性规则,适合处理不应被模型随意突破的条件。
模型调用失败时,本地策略仍能产生一套基本可用的搭配;模型调用成功时,模型可以在候选之间选择更符合场景与色彩语义的组合,并给出自然语言解释。两者关系不是替代,而是分工:规则负责可靠性,模型负责个性化和表达力。
这样的分层还能带来可观测性。当用户认为推荐“不合适”时,我们能判断问题是天气数据错误、衣物标签不完整、本地硬规则太严,还是提示词策略不佳;如果所有逻辑都藏在一段模型对话里,就很难定位和迭代。
九、衣物护理:把一次穿搭变成完整生活闭环

许多穿搭产品只关心“穿之前”,而忽略“穿之后”。但对用户而言,今天穿了什么、是否该清洗、是否仍在晾晒,直接影响明天能穿什么。因此“护理”并不是附属页,而是让衣橱数据保持真实可信的关键模块。
护理页按状态汇总待清洗、晾晒中、洁净可穿数量,并将非洁净衣物显示在待办清单中。用户每点击一次操作,WardrobeStore.updateStatus 就会更新实体并重新拉取列表,页面自动刷新。由于状态和护理建议都被绑定到同一份 Clothing 数据,今日推荐和护理列表天然保持一致。
未来可以在此基础上增加材质、洗涤方式、晾晒时长、季节收纳、防蛀提醒;也可以让模型根据用户的衣物材质与天气湿度生成更个性化的建议。但必须坚持一个原则:涉及衣物护理的建议应明确为辅助信息,用户仍应以衣标为准,避免以生成内容替代专业洗护说明。
十、关于智能体、Skill 与跨设备协同的下一步

当前项目已经具备将业务能力开放为智能体工具的条件。可以设计如下意图:RecommendOutfit(scene, temperature)、AddClothing(image)、QueryWardrobe(style)、UpdateCareStatus(clothingId, status)、QueryCareList()。用户对小艺说“今天下雨,帮我选一套通勤穿搭”,意图框架提取场景和天气参数,调用 RecommendOutfit,再把结果展示为卡片或拉起应用首页。
跨设备协同同样不应只是“把页面放大”。手机承担拍摄、快速确认和外出提醒;平板可用双栏布局管理分类、批量编辑标签;PC 可提供穿搭日历、衣物统计和胶囊衣橱规划;穿戴设备可以在出门前显示简短的“18℃,带外套”提示。共享的核心不是 UI,而是衣物实体、状态流转、用户偏好与推荐历史。后续使用分布式 KV 存储同步时,应将这些数据按用户授权、设备可信关系和最小必要原则分层处理。
十一、工程目录与可维护性

项目目录按职责划分:pages 只关心显示与交互;model 定义领域对象和持久化;service 负责天气、模型或未来系统能力;common 放置主题与配置;entryability 处理应用生命周期。这种分层在小项目中也很必要,因为 AI 功能极易扩张:今天是文本推荐,明天可能增加视觉识别、语音意图、云端同步。若从一开始把网络请求写在页面点击事件里,后续维护成本会迅速上升。
项目构建已使用 DevEco Studio 与 Hvigor 验证通过。实际发布时,应将模型密钥放到服务端代理或受控凭证体系,而不是暴露在客户端;客户端只请求自有服务,由服务端完成鉴权、限流、审计和模型调用。本文展示的直接请求方式适合原型验证,不能等同于生产安全方案。
十二、复盘:从“AI 功能”走向“可信的智能体验”
这次实践最重要的收获,不是完成了一个能调用模型的页面,而是明确了生活类 AI 应用的三个判断标准。
第一,AI 输出必须能落在业务对象上。穿搭结果应返回本地衣物 ID,而不是一句无法执行的风格描述。第二,AI 必须有边界。温度、清洁状态、用户是否拥有某件衣服等事实约束,应由确定性数据和规则守住。第三,AI 必须可失败。网络异常、接口限流、输出格式波动都不应该让用户失去基本功能,因此本地兜底与清晰反馈同样是智能化体验的一部分。
“衣见倾心”仍是 MVP,但它已经形成了完整闭环:衣物被结构化记录,状态随使用而变化,天气与场景触发推荐,模型在受控上下文中产生建议,结果回写到用户可理解的卡片,护理任务再让衣物回到可穿状态。未来接入视觉识别、实时天气、小艺意图、服务卡片和跨设备数据流转后,这个闭环会从“一个 App 的功能”成长为“鸿蒙全场景生活服务”的一个具体切面。
结语
智能化不应该让用户多学习一套复杂操作,而应该减少用户在真实生活中做重复决策的成本。把“今天穿什么”做成一项可调用、可解释、可恢复、可协同的服务,正是鸿蒙应用智能化实践的价值所在。希望这份实现能为 ArkTS、ArkUI、结构化大模型输出以及生活场景智能体设计提供一份可复用的参考。
更多推荐




所有评论(0)