首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
鸿蒙ArkTS与大模型融合:AI内容创作应用实战指南
📅 2026/11/2 17:54:00
✍️ 爱科研究院
👁 阅读 3,247
大概半年前我接到一个需求在鸿蒙设备上做一个 AI 内容创作应用。说白了用户输入一个主题或一段模糊想法应用借助大模型生成一篇可编辑、可导出、可复用的内容可能是社交媒体文案、短视频脚本也可能是 AI 绘画提示词。客户点名要求必须用 ArkTS 原生开发不要套 WebView。当时团队里有两种声音一种觉得直接套壳网页最快一种觉得 ArkTS 声明式 UI 做这种流式刷新的场景反而更顺。我们最后选了 ArkTS并且在这个项目里做了很深的 ArkTS 与大模型能力的智能融合过程中踩了不少编译、并发、渲染层面的坑也沉淀出一套可以复用的套路。这篇文章就围绕这套玩法展开想给正在鸿蒙生态里做 AI 应用的同行做个参照。如果你正准备做类似应用还没想清楚技术选型我的建议是先看两个问题一是你的应用到底是聊天工具还是创作工具二是你是否需要深度调用系统能力。这两个问题直接决定了 ArkTS 声明式开发是不是比 WebView 套壳更值得。下面我会从选型理由开始讲到网络链路、页面交互、踩坑记录和上架前必须处理的事基本按一个真实项目的推进顺序来写。1. 为什么拿 ArkTS 做 AI 内容创作而不是套个 WebView1.1 先分清你要做的是创作工具还是聊天机器人很多 AI 应用团队一开始就做错了定位他们嘴上说要做内容创作实际做出来的是一个通用聊天机器人。我在项目启动阶段先列了一张表把 AI 内容创作应用的常见形态都摆出来应用形态用户输入AI 输出核心难点社交文案生成主题、语气、字数图文并茂的文案风格控制、内容合规短视频脚本助手选题、时长、目标人群分镜脚本结构化输出、分镜合理性AI 绘画提示词工厂一句画面描述包含画风、镜头、参数的提示词提示词工程、多语言支持长文续写/润色零散段落完整文章上下文管理、段落衔接这些形态有一个共性输入通常很短但输出很长而且用户拿到结果之后还会反复编辑。这个共性意味着应用不只是一个生成按钮的演示品它需要给用户提供编辑、回退、复制、导出、历史记录这类强交互能力。聊天机器人可以容忍一条消息直接展示但内容创作工具不行。用户在等 AI 输出时会盯着屏幕看它打字过程中可能随时想中断、修改输入、切换风格。这些交互用 ArkTS 的声明式 UI 做起来特别顺手因为数据状态变了界面自动跟着变不需要手动操作 DOM。1.2 ArkTS 在 AI 场景里的三个天然优势既然决定不用 WebView就得说清楚 ArkTS 在 AI 内容创作场景里到底赢在哪。我这套方案里受益最大的三点第一是声明式数据绑定。ArkTS 配合 ArkUI 的State、Prop、Observed这些装饰器可以把 AI 返回的内容直接绑定到界面上的文本组件。流式输出时我只需要不断更新状态变量Text组件会自动局部刷新不需要写一堆查 DOM、改 innerHTML的样板代码。对做惯了传统前端的人来说这个体验是革命性的。第二是系统能力融合。纯 WebView 页面很难流畅调用鸿蒙的剪贴板、分享面板、沙箱文件、语音输入这些系统服务。我在应用里集成了一键复制结果导出为 txt 文件调起系统分享这几个能力都是用 ArkTS 直接操作系统接口延迟极低。这个就叫 ArkTS 与大模型的智能融合——不只是网上对话而是让 AI 产出进入系统级工作流。第三是任务分发。AI 内容创作不是拿到文本就结束我通常还会对输出做后处理比如统计字数、提取关键词、检测敏感词。ArkTS 的 TaskPool 和 Worker 可以把这些 CPU 密集型操作放到子线程避免阻塞 UI。在长文本场景里这个优势会直接决定应用是不是用起来很卡。1.3 明确不做什么应用边界与降级策略一个好的 AI 内容创作应用必须知道自己的边界。我在需求评审时就被反复提醒不要试图做一个所有问题都能回答的通用助手否则用户会在应用里输入明天天气怎么样然后抱怨你没有天气插件。我最终确定的应用边界是只服务内容生产链路也就是从想法到初稿这段。不在应用里做社交、不做通用搜索、不做聊天陪伴。与其做成一个大而全的怪物不如把一个内容创作流程做得顺滑。边界定下来之后还要考虑降级策略。AI 接口不是永远稳定的我在实际使用中遇到过服务商限流、超时、单次返回为空等各类情况。所以客户端必须有明确的降级方案断网时给用户看内置的离线文案模板至少还能产生编辑价值超时或限流时提示重试并保留用户已输入的内容不让他从头再敲一遍模型返回空内容时给一个再试一次的按钮而不是白屏。这些降级逻辑在 ArkTS 里写起来并不复杂关键是必须在架构设计阶段就考虑进去。很多团队是等项目快上线了才想起来处理异常结果代码里全是补丁后续迭代一次痛一次。2. 打通 AI 能力链路请求封装、流式返回与 Prompt 工程2.1 请求通道和安全设计API Key 不应该出现在客户端AI 内容创作应用最核心的一条链路就是客户端把 Prompt 发给模型服务商拿到生成结果。听起来很简单但真正落到 ArkTS 上第一个要考虑的是安全问题。我强烈建议不要直接把大模型服务商的 API Key 写进客户端。无论是内置在代码里还是存在本地配置里APK 侧的反编译工具都可以把它扒出来。我在项目里采用的标准做法是鸿蒙应用只跟自己的后端代理服务通信由后端保存 API Key、做限流、做内容安全审核再把模型结果返回给客户端。后端代理不算复杂但要做几件事统一收敛模型服务商的接口差异把密钥放在环境变量里对客户端请求做 basic auth 或 token 校验可选地在代理层做敏感词过滤。客户端这边封装一个请求模块面向的是自己的代理而不是某个特定模型厂商。ArkTS 侧我用的是系统自带的ohos.net.http模块封装成一个简单函数import http from ohos.net.http; export async function requestAICompletion(prompt: string, templateId: string): Promisestring { const httpRequest http.createHttp(); try { const response await httpRequest.request( https://your-proxy.example.com/api/v1/completion, { method: http.RequestMethod.POST, header: { Content-Type: application/json }, extraData: JSON.stringify({ prompt: prompt, templateId: templateId }), connectTimeout: 15000, readTimeout: 60000 } ); const result JSON.parse(response.result as string) as CompletionResult; if (response.responseCode 200 result.text) { return result.text; } throw new Error(AI request failed, code${response.responseCode}); } finally { httpRequest.destroy(); } }这段代码里有几个容易忽略的细节。http.createHttp()创建的请求对象用完之后必须destroy()否则连接会一直占着应用长时间运行后可能出现请求发不出去的情况。readTimeout要设置得足够长大模型生成文本通常需要十几秒甚至更久我用的是 60 秒。response.result拿到的是字符串直接用JSON.parse之前要先定义好返回结构。2.2 流式输出的打字机效果怎么实现AI 生成的文本是一段一段或一个字一个字流式返回的。用户已经习惯了 ChatGPT 那样的打字机效果你如果做一个转圈 15 秒然后一次性吐出一整篇文章的应用体验上会显得很笨。真正的流式接入在鸿蒙上有几种做法。最理想的方式是后端代理把模型返回的 SSE 流透传给客户端客户端通过ohos.net.http的进度回调增量接收数据边收边解析。这样的体验最接近网页版 AI 应用但实现复杂度最高因为你要处理半包、粘包、流中断等网络边界问题。我在实际项目里采用了一个更务实的两段式方案后端代理还是走标准请求等到模型全部生成完再一次性返回客户端拿到完整文本后通过一个渲染缓冲层按固定时间间隔逐段追加显示。比如每 30 毫秒往结果文本里追加 2 到 4 个字符看起来和流式几乎一样但通信链路的稳定性大幅提升。用 ArkTS 写这个缓冲层时要注意定时器的清理。我见过不少同行在页面销毁后忘了关setInterval导致组件还在更新一个已经销毁的状态直接崩溃。后来我在aboutToDisappear里统一清理所有定时器问题才彻底解决。aboutToDisappear(): void { if (this.displayTimer) { clearInterval(this.displayTimer); this.displayTimer undefined; } }如果你的用户对实时性有更强要求或者生成时间超过 30 秒我建议还是上真正的 SSE 方案。但那意味着你的后端代理也要改造不是客户端换一个 API 就行要把它当成一个独立项目来排期。2.3 Prompt 模板中心让一个页面承载多种创作模式AI 内容创作应用不能只有一个万能生成框。用户在不同场景下需要不同的输出格式写短视频脚本要分镜列表写小红书文案要有标题和话题标签写绘画提示词要按主体、画风、镜头、光线、参数拆开。所以我做了一个 Prompt 模板中心把模板和页面逻辑解耦。每个模板对应一段带占位符的 Prompt 文本比如你是一名短视频编导。请根据以下主题输出一个 60 秒内的短视频脚本包含 1. 开场悬念 2. 内容要点3 个 3. 结尾钩子 主题{topic} 目标人群{audience}这一段字符串里的{topic}和{audience}是占位符用户在应用的输入区填好字段后客户端把占位符替换成真实内容再拼上一些固定的系统指令system prompt最后才发给后端代理。我还做了一件事把所有模板按templateId存在一个本地 JSON 文件里页面用资源引用加载不硬编码在业务代码中。这样做的好处是运营同学可以直接改 JSON 文件调整模板措辞不需要动代码。有时候模板明明是运营改的他们非说应用坏了最后发现是措辞有歧义导致生成结果不合格——把模板独立出来之后这种扯皮少了很多。3. 让创作页面从能出结果到好用3.1 别用布尔值管理请求生命周期请用状态机第一个版本我偷懒用两个布尔值isLoading和isDone来控制界面。后来发现完全不够用流式输出期间用户点了停止生成怎么办请求失败后还想重试怎么办模型返回空内容但要保留提示词怎么办三个状态根本表达不了这么复杂的界面逻辑。我最后把所有状态收敛成一个明确的联合类型type CreateStatus idle | loading | streaming | success | error;idle表示用户还没开始生成loading是正在请求streaming是文本正在分段显示success是完整内容已经展示error是请求失败。每个状态对应界面上不同的组件组合loading转圈加提示文案streaming显示打字机文本加停止按钮error显示重试按钮。用状态机的核心收益是你永远不会出现界面上同时显示加载中又显示结果这种自相矛盾的情况因为状态是互斥的。在 ArkTS 里这个状态变量直接绑定 UI每次状态切换界面自动刷新。后期如果要加暂停生成之类的功能只需要在状态机里增加一个转移逻辑非常清晰。3.2 组件选型输入区、结果区、模式切换怎么搭ArkUI 的组件库已经足够支撑一个完整的创作页面不一定要引第三方 UI 库。我用的核心组合是顶部用Tabs或SegmentedButton切换创作模式中间是输入区下面是结果区。输入区我选TextArea而不是TextInput因为用户可能粘贴一段长想法进来。TextArea要设置合理的maxLength我限制在 2000 字既保证模型接收的上下文可控也避免极端内容刷爆内存。输入框下面放参数调节比如生成字数创意温度用Slider组件绑定数值传给后端的时候再转换成模型参数。结果区是整个页面的视觉中心。我在Scroll里放一个Text把生成内容用State resultText绑定。流式显示过程中每追加一段文本就调用scrollController.scrollEdge(ScrollEdge.EDGE_BOTTOM)滚动到底部让用户时刻看到最新内容。这里有个性能细节Scroll内部的Text如果一次性绑定几万字的文本首次渲染会有明显卡顿。我的做法是只在流式阶段积累完整文本但 UI 上展示的是已显示缓冲区的子串等用户看完整段内容且不做滚动时再把全量文本发回给状态。说白了State里放的数据和你真正渲染给用户的文本可以不是同一个中间加一层已显示进度的控制。3.3 看着小但很重要的细节自动滚动、一键复制、导出与分享真正决定一个 AI 内容创作应用好不好用的往往是这些零碎细节。我用一个列表把它们列出来每一条都是被用户反馈催着补上的自动滚动到底部。没有这个功能用户生成一篇 1000 字的文案时结果区会一直停在顶部看起来像什么都没发生。一键复制。生成结果后要让用户在不选中文本的情况下直接复制全文这个用系统剪贴板接口几行代码就够。导出为 txt 文件。我把生成内容按时间戳命名写到应用沙箱的documents目录同时提供一个打开所在目录的按钮。调起系统分享。用户写好的文案可以直接分享到即时通讯软件这块用 ArkTS 的systemShare能力比 WebView 里折腾 JS Bridge 可靠得多。停止生成按钮。生成过程中要允许用户随时中断否则长文本生成时用户只能干等。这些功能单项看都很简单但集中在一个页面里节奏感要把握好。我的经验是生成前界面保持简洁生成中只给停止一个操作入口生成完成后操作按钮才全部展开。用户注意力应该被引导到阅读结果这件事上而不是被一堆按钮包围。4. 我在接入过程里踩过的坑逐个复盘4.1 ArkTS 严格类型下JSON 解析被逼着重写ArkTS 是 TypeScript 的严格子集但和标准 TS 有个非常大的区别它不允许使用any很多标准 TS 的自由类型操作在 ArkTS 里都会编译报错。我在解析模型返回的 JSON 时第一次踩到这个坑。模型返回的数据结构经常是嵌套的比如{ choices: [{ message: { content: ... } }] }。在标准 TS 里你会很自然地写const content data.choices[0].message.content;但 ArkTS 要求你先定义明确的interface然后做类型断言。更麻烦的是从JSON.parse拿到的对象很可能被推断为多层嵌套的联合类型直接访问choices[0]会报对象可能为空或隐式 any错误。我的解决方案是给每个模型返回定义严格的接口类型并写一个防御性工具函数interface ChatChoice { delta?: { content?: string; }; } interface ChatResult { choices?: ChatChoice[]; text?: string; } function extractContent(result: ChatResult): string { if (result.text result.text.length 0) { return result.text; } const choices result.choices; if (choices choices.length 0) { return choices[0]?.delta?.content ?? ; } return ; }这种代码在标准 TS 里显得有点死板但在 ArkTS 里是必须的。它能保证即使模型返回结构里某个字段缺失也不会在运行时抛异常。如果你是从 Web 前端转过来的我建议你在搭工程第一天就把接口类型先行落实到代码规范里否则后面测试会发现一大半崩溃源于 JSON 解析。4.2 定时器、页面销毁与状态更新的崩溃现场打字机效果用setInterval实现这个方案本身没问题但它引入了一个非常隐蔽的崩溃用户正在生成内容时切换页面或者直接退出定时器还在跑回调里还在修改一个已经销毁的页面的State变量。HarmonyOS 会直接把这个页面对象标记为无效回调执行时触发底层错误应用闪退。我当时的崩溃日志反复指向同一个内存地址查了快一天才意识到是定时器没有清理。后来我总结了一个强制规则凡是在组件里创建的setInterval、setTimeout、长连接回调必须在aboutToDisappear中清理解除。不要指望开发者自己记得最好用一个统一的工具类管理全局定时器组件销毁时批量清理。还有一个容易踩的坑是 HTTP 请求回调晚于页面销毁。哪怕页面已经关了请求完成后的回调仍然会执行里面如果直接改State同样会有崩溃风险。稳妥的做法是给请求模块加一个请求 ID页面销毁后把对应 ID 标记为已失效回调回来先检查 ID 是否还活着活着才更新状态。4.3 模型输出不稳定空内容、截断和内容安全过滤AI 模型的输出不像传统接口那么可预期。我统计过一个月的线上日志大约 5% 的请求会出现异常包括完全空内容、内容被截断、返回结构缺字段、返回内容格式跟 Prompt 要求不符等。针对空内容和截断我做了三层兜底。第一层是请求超时重试最多重试一次第二层是后端代理检查文本长度如果低于阈值就重新请求一次第三层是客户端展示友好错误提示并且把用户输入完整保留在输入框里。用户看到生成失败已经够烦了如果还要重新输入那就是产品事故。内容安全过滤也是必须做的。AI 生成内容可能携带不合规的信息我不仅在后端做了敏感词过滤还在客户端加了一层展示拦截如果模型返回的内容命中某些规则直接显示内容未通过安全审核请调整输入后重试。这块要特别重视因为内容创作应用是用户直接面对生成结果的一旦出现违规内容影响比聊天应用更大。5. 从 Demo 到能上架持久化、签名与下一步融合方向5.1 创作记录怎么存Preferences 和 RelationalStore 的选择Demo 阶段我把创作记录放在内存里应用一重启就清零后来用户反馈说刚写的好几条文案全没了。这个需求逼着我做了持久化。鸿蒙提供两种本地存储方案。轻量级的ohos.data.preferences适合存键值对比如用户的设置项、最近的一次 Prompt 草稿重量级的RelationalStore关系型数据库适合存列表类数据比如历史创作记录。我的选择是草稿和参数设置用 Preferences创作记录用 RelationalStore。创作记录的核心字段包括创作模式、用户输入的原始主题、模型返回的完整内容、生成时间、是否被编辑过。建一张表存这些字段查询时按时间倒序。我在应用里做了一个历史记录列表页每一条记录支持重新加载、删除、导出。用LazyForEach配合分页加载就算积累上千条记录也不会卡。RelationalStore第一次上手会有点繁琐要先建库、建表、写 SQL。但比起每次都把全量 JSON 序列化到 Preferences 里它的查询和更新要灵活得多尤其是只查最近 20 条这种场景SQL 一条语句就解决了。5.2 打包签名与发布前的检查清单HarmonyOS 应用要发布到应用市场签名打包是绕不开的一环。我用 DevEco Studio 的项目签名工具生成调试证书和发布证书流程其实界面化得很友好但有几个点必须注意不同环境用不同的证书调试证书和发布证书不要混用否则上架审核会被拒。应用必须声明网络权限否则所有 HTTP 请求都会静默失败。这个权限在module.json5里配别等真机测试才发现。API Key 一定不能出现在客户端代码里即使应用不开源也要按可反编译的假设来设计。检查所有需要联网的页面在网络异常时的表现不能出现白屏。我还列了一个发布前检查清单填完整条流程基本就能保证产品像样首屏加载是否超过 3 秒、AI 生成中是否能中断、生成结果是否可复制、返回后再次进入能否恢复上次的结果、历史记录是否按时间正确排序、分享出去的内容格式是否正常。这些看起来琐碎但每个都是用户感知明显的体验点。5.3 更进一步的智能融合多模型协作、语音输入与个性化人设项目上线后我有余力继续迭代目前在探索的方向有三个。一个是多模型协作。同一个创作任务同时发给两个不同的模型等两个结果都回来之后并排展示。用户会觉得这个应用变聪明了因为不同的模型优势不同一个擅长结构一个擅长文案润色。当前会话解决不了的还可以把两个模型的输出合并出一个新的精修版。一个是语音输入。用户在手机上打字写主题的效率不高但口述想法要快得多。鸿蒙有本地语音识别能力我把它集成到 Prompt 输入框中用户点一下麦克风把帮我写一个关于周末露营的短视频脚本这种需求直接转成文字再进入生成流程。这属于大模型和系统 AI 能力的融合也是智能融合在这个项目里最自然的延伸。还有一个是个性化人设。通过记录用户历史编辑习惯比如用户总是把生成结果缩短到 300 字我就把这一偏好回传给 Prompt 模板让模型一开始就按这个风格输出。这块现在只是雏形但它让应用从通用工具变成私人写作助理。我个人在实际操作中的体会是AI 内容创作应用的核心不是模型多强而是能否把用户从想法到成稿的摩擦降到最低。选 ArkTS 的好处在于流式输出、系统分享、本地存储这些围绕内容生产的配套能力都在同一个技术栈里不需要跨端拼接。最后再分享一个提升体验的小技巧让模型返回带 Markdown 的内容客户端用一个轻量的 Markdown 组件渲染标题、列表、加粗都能直接展示成稿的质感会立刻比纯文本高一截。如果你正在做类似方向这个技巧值得第一时间用上。
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/11/2 17:54:00
表格型Q-Learning收敛、探索与最大化偏差避坑指南
2026/11/2 17:54:00
开源本地语音克隆与视频配音工具VoiceStudio技术解析
2026/11/2 17:54:00
开源设备管理平台OpenRig:解决开发板与硬件装备的混乱
2026/11/2 18:49:25
11-linux设备模型
2026/11/2 18:44:24
如何为SQL to ER Diagram贡献代码:目录结构、新增SQL方言与PR实践清单
2026/11/2 18:44:24
OpenCore Legacy Patcher:5 张任务卡让 2008 年老 Mac 装上 macOS Sequoia
2026/11/2 18:44:23
从零开始学AI19——贝叶斯公式
2026/11/2 18:44:23
如何使用大黄蜂轨迹 创建出自己的模拟动态行车轨迹?
2026/11/2 18:44:23
迅雷怎么加快下载速度_迅雷在线解析工具
2026/11/2 1:03:35
工业SPI隔离方案:K64主控+MAX14431从设计到排查
2026/11/2 1:03:35
SPI隔离器MAX14431与PIC18F8722实现工业级稳定通信的实战指南
2026/11/2 1:03:35
雷达信号调制技术解析:从LFM到相位连续调频波形设计
2026/11/2 2:42:45
面向复杂光照与角度的宠物面部识别鲁棒性增强策略
2026/11/2 2:42:47
DRV8818PWPR与R7FA8M1AHECBD工业步进驱动实战指南
2026/11/2 2:42:50
STM32与DRV8818双极步进电机驱动方案:从选型到调试全流程解析
2026/11/2 2:42:45
面向复杂光照与角度的宠物面部识别鲁棒性增强策略
2026/11/2 2:42:47
DRV8818PWPR与R7FA8M1AHECBD工业步进驱动实战指南
2026/11/2 2:42:50
STM32与DRV8818双极步进电机驱动方案:从选型到调试全流程解析