从零打造鸿蒙 PC AI 应用:HarmonyOS 智慧校园助手开发实战

本文完整记录一款「智慧校园助手」应用在鸿蒙 PC(HUAWEI MateBook Pro,HarmonyOS 电脑)上从架构设计、大模型接入、五大功能模块实现到真机运行的全过程,包含大量可复现的 ArkTS 代码与鸿蒙 PC 真机运行截图。不同于常见的鸿蒙手机 Demo,本文聚焦电脑端(2in1 形态) 的开发与适配,适合作为设计参考,也适合想在 HarmonyOS 电脑上落地 AI 应用的开发者。

在这里插入图片描述

一、写在前面:为什么在鸿蒙 PC 上做一个「校园助手」

大学生活里,信息是分散的:课表在教务系统,作业 deadline 在各科群里,图书馆规则在公众号,请假流程要问辅导员……学生每天要在十几个入口之间来回切换。而大语言模型的成熟,让「用一句自然语言问出答案」成为可能。

与此同时,鸿蒙生态正在从手机向 PC 延伸。搭载 HarmonyOS 的电脑(如 MateBook Pro)已经成为一个真实的开发与使用场景。相比手机,电脑有更大的屏幕、更适合长文本阅读与录入的键鼠交互——这恰恰非常契合"查课表、管待办、和 AI 深入对话"这类需要沉下心处理信息的校园场景。学生在电脑上写作业、查资料时,一个常驻的智能助手比掏手机更顺手。

于是我萌生了一个想法:在鸿蒙 PC 上做一款把课表、待办、校园问答和 AI 对话整合在一起的智能校园助手。技术上,它要同时具备三种能力:

  1. 本地数据管理(课表、待办的增删改查与持久化);
  2. 端云 AI 交互(接入大模型,实现智能问答);
  3. 面向电脑大屏的良好体验(充分利用 PC 的屏幕空间与交互特性,同时保持一次开发多端可用)。

我选择用 HarmonyOS + ArkTS/ArkUI 来实现——它的声明式 UI 开发效率高,「一次开发、多端部署」的特性又让同一套代码能覆盖手机、平板到 PC。而本文的全部开发与运行,都是在鸿蒙 PC 真机(MateBook Pro) 上完成的。

先看一眼成品。下图是应用的 AI 助手主界面,以窗口形式运行在鸿蒙 PC 桌面上:

AI 助手介绍页

可以看到,应用以窗口化的形式运行在鸿蒙 PC 桌面环境中,对话界面会主动介绍助手能提供的服务分类(学习支持、校园服务指南、生活与成长支持),底部还有快捷问题引导。这是一款完成度较高、可以真正在电脑上日常使用的应用,而不是停留在概念阶段的 Demo。

二、总体架构设计

在动手写代码前,先做架构设计。一个可维护的应用,必须有清晰的分层。我把整个工程分为四层:
在这里插入图片描述

在这里插入图片描述

各层职责如下:

  • entryability:处理 Ability 生命周期,初始化本地存储、配置沉浸式窗口、计算安全区。
  • commonTheme.ets 统一管理配色与尺寸;AIConfig.ets 集中管理大模型服务的地址、密钥、模型名与系统提示词。
  • modelAIService.ets 封装大模型的网络请求与响应解析;CampusStore.ets 负责课程与待办的数据模型和持久化。
  • pages:五个功能页(助手 / 课表 / 问答 / 待办 / 我的)+ 一个 Tab 主壳。

这种分层的核心原则是关注点分离:UI 层只管展示与交互,不直接碰网络和存储;数据获取和 AI 请求全部收敛到 model 层;配置集中在 common 层,改起来一处即可。

下图是工程在 DevEco Studio 中的结构,可以看到清晰的目录组织:

DevEco Studio 工程结构

三、大模型接入层:全应用的智能核心

这是整个应用最关键的部分。所有的智能问答能力,都建立在与大模型的稳定交互之上。

3.1 配置集中化

我把所有与模型服务相关的配置抽到一个 AIConfig 类里。这样做的好处是:换服务、换模型、改提示词,都只需要动一个文件。

export class AIConfig {
  /** 模型服务地址(OpenAI 兼容 chat/completions 接口) */
  static readonly endpoint: string =
    'https://xxxxxxxx/compatible-mode/v1/chat/completions';

  /** 访问密钥(可在设置页运行时覆盖) */
  static readonly apiKey: string = 'sk-****************';

  /** 模型标识 */
  static readonly model: string = 'qwen-plus';

  /** 系统提示词:把模型约束为"校园助手"身份 */
  static readonly systemPrompt: string =
    '你是"智慧校园助手",一款面向高校学生的智能助手。你熟悉校园生活的方方面面:' +
    '选课、考试、图书馆、请假流程、社团活动、宿舍管理、校园卡、四六级、奖学金等。' +
    '请用简洁、友好、条理清晰的中文回答学生的问题。';

  static readonly temperature: number = 0.7;
  static readonly maxTokens: number = 800;
  static readonly timeoutMs: number = 30000;
}

这里有几个设计要点值得强调:

其一,采用 OpenAI 兼容协议。 现在主流的大模型服务大多提供 OpenAI 兼容的 chat/completions 接口。基于这个协议开发,意味着应用不绑定任何特定的模型服务商——今天用这家,明天想换一家,只要它兼容该协议,改一下 endpointmodel 即可,业务代码一行不用动。这是一个很重要的架构解耦。

其二,用 systemPrompt 塑造助手人格。 大模型本身是通用的,但通过一段精心设计的系统提示词,可以把它约束成一个特定角色。这段提示词告诉模型:“你是校园助手,聚焦校园场景,用简洁友好的中文回答”。这就是所谓的"提示工程"——用自然语言给 AI 定义行为边界,是 AI 应用开发的一项核心技能。

其三,密钥可运行时覆盖。 apiKey 虽然有内置默认值,但应用支持在设置页填写覆盖(存到 AppStorage,请求时优先使用)。这让应用具备了灵活性,也为后续把密钥迁移到更安全的存储留了口子。

3.2 网络请求与响应解析

有了配置,接下来是真正发起请求的 AIService。鸿蒙用 @kit.NetworkKithttp 模块发起网络请求。

先定义清晰的数据结构。这里有个 ArkTS 的强约束需要注意:ArkTS 严格模式不允许无类型的对象字面量arkts-no-untyped-obj-literals),所以请求体也要显式定义接口:

/** 一条对话消息 */
export interface ChatMessage {
  role: string;      // system | user | assistant
  content: string;
}

/** chat/completions 请求体 */
interface ChatRequest {
  model: string;
  messages: ChatMessage[];
  temperature: number;
  max_tokens: number;
}

然后是核心的 chat 方法:

export class AIService {
  static async chat(history: ChatMessage[]): Promise<string> {
    // 组织消息:system 提示词 + 历史对话
    const messages: ChatMessage[] = [
      { role: 'system', content: AIConfig.systemPrompt }
    ];
    for (const m of history) {
      messages.push(m);
    }

    const body: ChatRequest = {
      model: currentModel(),
      messages: messages,
      temperature: AIConfig.temperature,
      max_tokens: AIConfig.maxTokens
    };

    const req = http.createHttp();
    try {
      const resp = await req.request(AIConfig.endpoint, {
        method: http.RequestMethod.POST,
        header: {
          'Content-Type': 'application/json',
          'Authorization': 'Bearer ' + currentKey()
        },
        extraData: JSON.stringify(body),
        connectTimeout: AIConfig.timeoutMs,
        readTimeout: AIConfig.timeoutMs
      });

      if (resp.responseCode !== 200) {
        return `(请求失败:${resp.responseCode})请检查网络或服务配置。`;
      }
      const text = AIService.parseContent(`${resp.result}`);
      return text !== '' ? text : '(助手暂时没有返回内容,请重试)';
    } catch (e) {
      return '(网络异常)请检查设备网络连接后重试。';
    } finally {
      req.destroy();     // 务必释放 http 请求对象
    }
  }
}

几个工程细节:

  • 多轮对话上下文:每次请求都把完整的历史消息带上(system + 若干轮 user/assistant),模型才能理解上下文、进行连贯的多轮对话。
  • 超时与异常兜底:设置了连接和读取超时;任何异常都返回友好的中文提示,而不是让应用崩溃或卡死。这对 AI 应用尤其重要——网络请求天然不稳定,优雅降级是必须的。
  • 资源释放finallyreq.destroy() 释放 http 对象,避免内存泄漏。

响应解析要从 OpenAI 兼容格式的 JSON 里取出 choices[0].message.content

private static parseContent(raw: string): string {
  try {
    const obj = JSON.parse(raw) as Record<string, Object>;
    const choices = obj['choices'] as Object[];
    if (choices !== undefined && choices.length > 0) {
      const first = choices[0] as Record<string, Object>;
      const msg = first['message'] as Record<string, Object>;
      if (msg !== undefined && msg['content'] !== undefined) {
        return `${msg['content']}`.trim();
      }
    }
  } catch (e) {
    // 解析失败返回空,由上层兜底
  }
  return '';
}

至此,全应用的"智能核心"就搭好了。任何页面只要调用 AIService.chat(messages),就能拿到大模型的回答。

四、功能模块一:AI 对话助手

这是应用的门面。它本质上是一个聊天界面:用户输入问题,追加到消息列表,调用 AIService 拿到回复,再刷新界面。

4.1 数据结构与状态

interface Bubble {
  role: string;      // user | assistant
  content: string;
  loading: boolean;  // 是否处于"正在思考"状态
}

@State bubbles: Bubble[] = [];
@State input: string = '';
@State sending: boolean = false;
private scroller: Scroller = new Scroller();

Bubble 里的 loading 字段是个巧妙设计:当用户发送问题后,先插入一个 loading: true 的空 AI 气泡显示"正在思考…",等真正的回复回来后,再把这个气泡的内容替换掉。这样用户能立刻得到反馈,体验流畅。

4.2 发送逻辑

async onSend(): Promise<void> {
  const q = this.input.trim();
  if (q === '' || this.sending) { return; }
  this.input = '';
  this.sending = true;

  // 追加用户气泡 + AI loading 占位气泡
  this.bubbles.push({ role: 'user', content: q, loading: false });
  this.bubbles.push({ role: 'assistant', content: '', loading: true });
  this.bubbles = this.bubbles.slice();   // 触发数组刷新
  this.scrollToEnd();

  // 组织历史消息
  const history: ChatMessage[] = [];
  for (const b of this.bubbles) {
    if (!b.loading && b.content !== '') {
      history.push({ role: b.role, content: b.content });
    }
  }

  // 请求大模型
  const answer = await AIService.chat(history);

  // 用回复替换 loading 气泡
  const last = this.bubbles[this.bubbles.length - 1];
  last.content = answer;
  last.loading = false;
  this.bubbles = this.bubbles.slice();
  this.sending = false;
  this.scrollToEnd();
}

这里 this.bubbles = this.bubbles.slice() 是 ArkUI 的一个常见技巧:对 @State 数组做浅拷贝赋值,才能可靠触发 UI 刷新。直接 push 有时不会触发重渲染。

4.3 气泡 UI 与自动滚动

聊天气泡用 @Builder 封装,用户消息靠右(蓝色),助手消息靠左(白底)。发送后通过 Scroller.scrollEdge(Edge.Bottom) 自动滚到底部。

实际运行效果如下——问"期末复习有什么建议?",助手给出了结构化、带 emoji 的实用回答:

AI 助手回答示例

可以看到大模型的回答质量相当高:制定计划、善用资源、主动输出,条理清晰。这正是 systemPrompt 约束 + 大模型能力共同作用的结果。

五、功能模块二:课程表

课表是校园应用的刚需。这个模块要实现:周课表网格展示 + 课程增删 + 本地持久化。

5.1 数据模型与持久化

Preferences(鸿蒙轻量键值存储)做持久化。课程模型:

export interface Course {
  id: string;
  name: string;         // 课程名
  teacher: string;      // 教师
  location: string;     // 地点
  day: number;          // 周几:1-7
  startSection: number; // 起始节次
  endSection: number;   // 结束节次
  colorIndex: number;   // 配色索引
}

CampusStore 封装了读写。一个实用细节是首次运行自动写入示例课程——避免用户第一次打开面对空白课表,直接就有内容可看:

static async listCourses(): Promise<Course[]> {
  if (CampusStore.store === null) { return demoCourses(); }
  const raw = await CampusStore.store.get('courses', '') as string;
  if (raw === '') {
    const seed = demoCourses();       // 首次:写入示例
    await CampusStore.saveCourses(seed);
    return seed;
  }
  return JSON.parse(raw) as Course[];
}

5.2 课表网格的实现

课表网格是这个模块的技术难点。核心思路:左侧是节次列,右侧是 7 天列,每一天是一个 Stack——底层铺背景格子,上层根据课程的起止节次绝对定位课程块

课程块的高度和上边距根据节次计算:

@Builder
courseBlock(c: Course) {
  Column({ space: 2 }) {
    Text(c.name).fontSize(11).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
    Text(c.location).fontSize(9).fontColor('#FFFFFFDD')
  }
  .width('92%').padding(5)
  .height((c.endSection - c.startSection + 1) * 58 - 4)   // 高度=跨越节次数×格高
  .margin({ top: (c.startSection - 1) * 58 + 2 })          // 上边距=起始节次偏移
  .backgroundColor(C.courseColors[c.colorIndex % C.courseColors.length])
  .borderRadius(8)
  .onClick(() => { this.onDelete(c); })
}

不同课程用轮转的配色区分,视觉上一目了然。运行效果:

我的课表

高数、大学英语、数据结构、操作系统、体育五门课,用蓝、绿、橙、紫、青五种颜色排布在周课表上,跨节次的课程(如数据结构占第 3-5 节)也正确地拉伸了高度。点击右下角"+ 添加课程"可以弹出表单新增。

六、功能模块三:校园问答

问答模块解决"高频问题快速查"的需求。它的设计有个巧思:预置答案 + AI 兜底的混合模式

常见问题分成"教务、生活、图书馆、证书考试"四类。每个问题有两种处理方式:

  • 预置答案的(如"如何借书续借"),直接展示,无需联网、秒开;
  • 预置答案为空的(如"图书馆开放时间"这种因校而异的),标记为 AI,点击时实时调用大模型生成回答。
async openAnswer(qa: QA): Promise<void> {
  this.answerQ = qa.q;
  this.showAnswer = true;
  if (qa.a !== '') {
    this.answer = qa.a;          // 预置答案,直接显示
  } else {
    this.loading = true;          // 走 AI
    const history: ChatMessage[] = [{ role: 'user', content: qa.q }];
    this.answer = await AIService.chat(history);
    this.loading = false;
  }
}

这种混合设计非常实用:高频固定的问题用本地答案(快、省、稳),个性化或长尾的问题交给 AI(灵活、覆盖广)。既保证了体验,又控制了 AI 调用成本。

运行效果如下,点击"校园卡丢了怎么办?"弹出预置答案:

校园问答

AI 标记的问题(如"食堂几点开饭")则会调用大模型返回答案。

七、功能模块四:待办日程

待办模块管理作业、考试、事项三类日程,支持增删、完成勾选、截止提醒。

数据模型简单:

export interface Todo {
  id: string;
  title: string;
  type: string;      // 作业 | 考试 | 事项
  dueTime: number;   // 截止时间 ms
  done: boolean;
}

列表按截止时间升序排列。一个体验细节是临期标红:距离截止不到 2 天的未完成待办,日期文字会变成红色,起到提醒作用:

isUrgent(t: Todo): boolean {
  return !t.done && (t.dueTime - Date.now()) < 2 * 86400000;
}

dueText(ms: number): string {
  const diff = Math.ceil((ms - Date.now()) / 86400000);
  if (diff < 0) { return '已过期'; }
  if (diff === 0) { return '今天'; }
  if (diff === 1) { return '明天'; }
  return `${diff}天后`;
}

不同类型用不同颜色的标签区分(考试红、作业蓝、事项青),左滑可删除,点击圆形勾选框标记完成。运行效果:

待办日程

可以看到"英语四级报名(明天)"“高数第三章习题(2天后)”"数据结构期中考(7天后)"三条待办,分别标注了类型和临期状态。

八、功能模块五:我的与设置

"我的"页承担个人信息展示、数据统计和模型服务配置

最有价值的是模型配置功能。它允许用户在不改代码的情况下,运行时覆盖 API 密钥和模型名——这些覆盖值存入 AppStorageAIService 请求时优先使用:

function currentKey(): string {
  const k = AppStorage.get<string>('cfgApiKey');
  return (k !== undefined && k !== '') ? k : AIConfig.apiKey;
}

设置页还实时显示"服务状态"(是否已配置密钥),方便排查问题。运行效果:

我的与设置

顶部是个人卡片,中间是课程数、待办数、助手状态三个统计卡,下方是可展开的模型服务配置区。整体信息层次清晰。

九、应用入口与多端适配

9.1 入口初始化

EntryAbilityonWindowStageCreate 里做三件事:初始化本地存储、加载首页、配置沉浸式全屏并计算安全区。

async onWindowStageCreate(windowStage: window.WindowStage): Promise<void> {
  await CampusStore.init(this.context);   // 初始化存储

  windowStage.loadContent('pages/Index', (err) => {
    if (err.code) { return; }
    const win = windowStage.getMainWindowSync();
    win.setWindowLayoutFullScreen(true);   // 沉浸式全屏
    // 计算安全区(状态栏/导航条高度),存入全局
    const top = win.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM);
    const bottom = win.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR);
    AppStorage.setOrCreate('safeTop', px2vp(top.topRect.height));
    AppStorage.setOrCreate('safeBottom', px2vp(bottom.bottomRect.height));
  });
}

计算安全区并存入全局状态,各页面通过 @StorageProp('safeTop') 统一避让——这是适配不同设备(手机刘海、PC 窗口边框)的关键。

9.2 面向鸿蒙 PC 的适配实践

这是本项目区别于普通鸿蒙手机 Demo 的重点。应用的主要运行环境是鸿蒙 PC(2in1 形态),因此适配的核心,是让一套代码在电脑大屏上也有良好表现。

首先在 module.json5 里声明支持的设备类型,把 2in1(PC 形态)纳入:

"deviceTypes": ["phone", "tablet", "2in1"]

其次,真正让应用在鸿蒙 PC 上"不违和",靠的是以下几点工程实践:

其一,全程弹性布局,不写死尺寸。 应用中的宽度全部使用 layoutWeight、百分比与 Flex 自动换行,不出现硬编码的固定像素宽度。这样在鸿蒙 PC 的大窗口下,内容能自然铺展,而不是被拉伸变形或挤在一角。例如课表的 7 天列用 layoutWeight(1) 均分,无论窗口多宽都能等分排布。

其二,窗口化运行与安全区适配。 鸿蒙 PC 上应用以窗口形式运行,非安全区不再是手机的刘海,而是窗口边框。前面 getWindowAvoidArea 计算安全区、存入全局的做法,在 PC 上同样生效——页面统一避让,标题栏不会被窗口边框遮挡。同一套安全区逻辑,覆盖了手机刘海到 PC 窗口边框的差异。

其三,键鼠交互的天然兼容。 ArkUI 的点击、输入、滚动事件在鸿蒙 PC 上会自动映射到鼠标与键盘。比如 AI 对话的输入框,在 PC 上就是用物理键盘输入、回车发送——这对"和 AI 深入对话"这种需要大量文字录入的场景,体验远好于手机虚拟键盘。这也是我选择把校园助手做到 PC 上的重要原因之一。

其四,大屏信息密度。 电脑屏幕大,能一屏承载更多信息。五 Tab 的结构 + 卡片式布局,在 PC 的大窗口里显得从容、不拥挤,课表、待办列表都能一览无余,减少滚动。

本文所有截图,实际上都是在华为 MateBook Pro(鸿蒙 PC) 上运行截取的——从对话、课表到设置页,都是电脑端的真实表现。这正是"一次开发、多端部署"落到 PC 场景的直接体现:我没有为 PC 单独写一套界面,同一套 ArkTS 代码就能在电脑上流畅运行。

在 DevEco Studio 的设备列表里,可以看到鸿蒙生态丰富的目标设备形态,从穿戴、手机一直到 PC:

DevEco Studio 设备选择

我的目标设备正是列表里那台真机 HUAWEI MateBook Pro。值得一提的是,SDK 版本已经到了 HarmonyOS 6.1.0,鸿蒙 PC 的开发支持已经相当成熟。选中它直接 Run,应用就以窗口形式跑在了电脑桌面上。

十、五 Tab 主壳

最后用一个 Tabs 把五个页面组织起来,底部导航:

@Entry
@Component
struct Index {
  @State current: number = 0;

  build() {
    Tabs({ barPosition: BarPosition.End, index: this.current }) {
      TabContent() { ChatTab() }.tabBar(this.bar('助手', '🤖', 0))
      TabContent() { ScheduleTab() }.tabBar(this.bar('课表', '📚', 1))
      TabContent() { QATab() }.tabBar(this.bar('问答', '💬', 2))
      TabContent() { TodoTab() }.tabBar(this.bar('待办', '📝', 3))
      TabContent() { ProfileTab() }.tabBar(this.bar('我的', '🎓', 4))
    }
    .scrollable(false)
    .onChange((idx: number) => { this.current = idx; })
  }
}

scrollable(false) 禁用了 Tab 间的滑动切换,避免和页面内的滚动手势冲突——这是个容易被忽略但影响体验的细节。

十一、开发过程中的几个坑

真实开发难免踩坑,记录几个有代表性的,供后来者避雷。

坑一:ArkTS 严格类型,禁止无类型对象字面量。 编译时报 arkts-no-untyped-obj-literals,就是因为直接写了个 const body = { ... } 没有类型。ArkTS 比 TypeScript 严格得多,所有对象字面量必须对应一个明确的 interfaceclass。解决办法就是老老实实为每个数据结构定义接口。

坑二:app.json5 的 SDK 字段。 早期版本我在 app.json5 里写了 compileSdkVersion 等字段,结果 schema 校验报错——这些字段属于 build-profile.json5app.json5 里只认 minAPIVersion / targetAPIVersion。鸿蒙的配置文件 schema 很严格,字段放错位置就编译不过。

坑三:@State 数组刷新。 直接对数组 push 有时不触发 UI 重渲染,需要 this.arr = this.arr.slice() 做一次浅拷贝赋值。这在聊天列表、待办列表里反复用到。

坑四:http 请求对象要释放。 每次 http.createHttp() 创建的对象,用完必须在 finallydestroy(),否则频繁请求会泄漏资源。

坑五:构建环境的干扰。 曾遇到 NODE_OPTIONS 环境变量被外部工具污染,导致 hvigor 构建报 ERR_WORKER_INVALID_EXEC_ARGV,连 IDE 内部 Sync 都失败。这类问题和代码无关,但排查很费时——彻底重启 IDE、清理环境变量即可。

十二、可扩展方向与总结

这款「智慧校园助手」已经是一个五模块齐全、可在鸿蒙 PC 上真机运行的完整应用。如果要继续深化,还有不少方向:

  1. 流式输出:目前 AI 回复是一次性返回,可改造成 SSE 流式,实现打字机效果,在 PC 大屏上阅读长回答的体验会更好。
  2. 本地知识库 + RAG:把学校的规章制度做成本地知识库,检索后拼进提示词,让 AI 回答更贴合本校实际。
  3. 课表智能导入:拍照识别或粘贴文本,用大模型解析成结构化课表,免去手动录入。
  4. 多端协同:结合鸿蒙分布式能力,实现手机与鸿蒙 PC 间的数据流转与任务接续——比如手机上加的待办,电脑端实时同步。
  5. PC 端窗口能力深化:利用鸿蒙 PC 的多窗口、窗口分栏等特性,把课表与 AI 对话并排展示,进一步发挥大屏优势。

回顾整个开发过程,这个项目虽然不大,却完整覆盖了一款现代 AI 应用的关键技术栈:声明式 UI、本地持久化、大模型端云交互、提示工程、面向 PC 大屏的多端适配。更重要的是,它验证了一件事——在鸿蒙 PC 上落地一款体验完整的 AI 应用,是完全可行的,而且开发效率相当高。相比拥挤的手机小屏,电脑端的大屏和键鼠交互,反而让"校园助手"这类信息管理型应用有了更好的用武之地。

对于想做类似项目(尤其是毕业设计)的同学,我的建议是:先把架构分层想清楚,把 AI 接入层做扎实(配置集中、异常兜底、协议解耦),再逐个模块堆功能。 同时,不妨像本文一样,把目光投向鸿蒙 PC——这是一个正在快速成熟、却还相对蓝海的方向,做出来的作品也更有辨识度。
在这里插入图片描述

希望这篇基于鸿蒙 PC 的实战复盘对你有帮助。如果你也在 HarmonyOS 电脑上探索 AI 应用,欢迎交流。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐