news 2026/5/1 7:10:43

鸿蒙版“DeepSeek”客户端实战:基于 HarmonyOS 网络请求与 Markdown 渲染组件,手撸一个 AI 对话 App

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
鸿蒙版“DeepSeek”客户端实战:基于 HarmonyOS 网络请求与 Markdown 渲染组件,手撸一个 AI 对话 App

🚀 前言:当国产之光遇见国产之光

市面上全是 Web 版的套壳 AI,体验极其卡顿。
作为鸿蒙开发者,我们要做就做纯原生 (Native)的。
本教程将带你从零开始,使用ArkTS对接 DeepSeek 官方 API,并攻克最大的技术难点——在鸿蒙原生列表里完美渲染 Markdown 代码块


🏗️ 一、 架构设计:数据流转图

我们要实现的 App 包含三个核心层级:

  1. UI 层:基于List的聊天气泡界面。
  2. 渲染层:封装Web组件,通过loadData动态渲染 Markdown。
  3. 数据层:使用http模块发起 SSE (流式) 或普通 POST 请求。

系统架构 (Mermaid):

UI 渲染层

网络层

1. 点击发送
2. HTTP POST
3. 返回 JSON (Markdown)
4. 更新 @State 数组
5. 渲染数据
6. 注入 HTML

用户输入

ArkTS 业务逻辑

DeepSeek API

List 组件

聊天气泡

Web 组件 (Markdown 渲染器)


🛠️ 二、 核心实战:一步步手撸代码

1. 配置网络权限

首先,别忘了在module.json5中申请网络权限,否则 App 连网都连不上。

"requestPermissions":[{"name":"ohos.permission.INTERNET"}]
2. 封装 DeepSeek API 服务

DeepSeek 兼容 OpenAI 的 API 格式。我们封装一个简单的请求方法。

// DeepSeekService.etsimporthttpfrom'@ohos.net.http';exportclassDeepSeekService{privatestaticAPI_URL='https://api.deepseek.com/chat/completions';privatestaticAPI_KEY='你的_DEEPSEEK_API_KEY';// 记得替换!staticasyncchat(message:string):Promise<string>{lethttpRequest=http.createHttp();try{letresponse=awaithttpRequest.request(this.API_URL,{method:http.RequestMethod.POST,header:{'Content-Type':'application/json','Authorization':`Bearer${this.API_KEY}`},extraData:JSON.stringify({model:"deepseek-chat",messages:[{role:"system",content:"你是 DeepSeek,一个乐于助人的 AI 助手。"},{role:"user",content:message}],stream:false// 教程演示简单起见,暂不使用流式})});if(response.responseCode===200){// 解析返回结果constresult=JSON.parse(response.resultasstring);returnresult.choices[0].message.content;}else{return"网络请求失败: "+response.responseCode;}}catch(err){return"发生错误: "+JSON.stringify(err);}finally{httpRequest.destroy();}}}
3. 攻克难点:Markdown 渲染组件 (MarkdownView)

鸿蒙原生的RichText功能有限。为了支持代码高亮和表格,最稳妥的方案是使用 Web 组件加载本地 HTML 模板,并注入marked.jshighlight.js

// MarkdownView.etsimportweb_webviewfrom'@ohos.web.webview';@Componentexportstruct MarkdownView{@Propcontent:string;// 接收 Markdown 文本controller:web_webview.WebviewController=newweb_webview.WebviewController();// 构建一个包含 Markdown 解析库的 HTML 模板// 在真实项目中,建议将 marked.min.js 放进 rawfile 资源中读取privatehtmlTemplate(mdContent:string):string{return`<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.2.0/github-markdown-light.min.css"> <style> body { padding: 10px; background-color: transparent; } </style> </head> <body> <div id="content" class="markdown-body"></div> <script> document.getElementById('content').innerHTML = marked.parse(\`${mdContent.replace(/`/g,'\\`')}\`); </script> </body> </html>`;}build(){// 关键:使用 Web 组件渲染 HTMLWeb({src:'',controller:this.controller}).onControllerAttached(()=>{// 当 Web 组件加载完成后,注入内容this.controller.loadData(this.htmlTemplate(this.content),"text/html","UTF-8");}).width('100%')// 根据内容动态高度是个大坑,这里简化处理,固定高度或使用 JS 交互算高度.height(300).backgroundColor(Color.Transparent)}}
4. 组装主界面 (Index.ets)

最后,把聊天列表、输入框和我们的MarkdownView组装起来。

import{DeepSeekService}from'./DeepSeekService';import{MarkdownView}from'./MarkdownView';// 定义消息模型classChatMessage{id:number;role:'user'|'ai';content:string;constructor(role:'user'|'ai',content:string){this.id=Date.now();this.role=role;this.content=content;}}@Entry@Componentstruct Index{@Statemessages:ChatMessage[]=[];@StateinputText:string="";@StateisLoading:boolean=false;scroller:Scroller=newScroller();asyncsendMessage(){if(this.inputText.trim()==="")return;// 1. 添加用户消息constuserMsg=this.inputText;this.messages.push(newChatMessage('user',userMsg));this.inputText="";this.isLoading=true;// 2. 调用 DeepSeek APIconstaiResponse=awaitDeepSeekService.chat(userMsg);// 3. 添加 AI 消息this.messages.push(newChatMessage('ai',aiResponse));this.isLoading=false;// 滚动到底部this.scroller.scrollEdge(Edge.Bottom);}build(){Column(){// 标题Text("DeepSeek Harmony").fontSize(20).fontWeight(FontWeight.Bold).height(50)// 聊天列表区List({scroller:this.scroller}){ForEach(this.messages,(msg:ChatMessage)=>{ListItem(){Row(){if(msg.role==='user'){// 用户消息 (右侧)Text(msg.content).backgroundColor('#95EC69').padding(10).borderRadius(8).margin({left:50})}else{// AI 消息 (左侧,支持 Markdown)Column(){MarkdownView({content:msg.content})}.backgroundColor('#FFFFFF').borderRadius(8).margin({right:20}).width('90%')}}.width('100%').justifyContent(msg.role==='user'?FlexAlign.End:FlexAlign.Start).padding(10)}})}.layoutWeight(1)// 占据剩余空间.backgroundColor('#F5F5F5')// 底部输入区Row(){TextInput({text:this.inputText,placeholder:"问点什么..."}).onChange((value)=>this.inputText=value).layoutWeight(1).backgroundColor(Color.White).margin({right:10})Button(this.isLoading?"思考中...":"发送").onClick(()=>this.sendMessage()).enabled(!this.isLoading)}.padding(10).backgroundColor('#EEEEEE')}.height('100%')}}

💡 三、 避坑指南与性能优化

  1. Web 组件高度自适应
    上面的代码为了演示给MarkdownView写死了高度。在生产环境中,你需要使用Web组件的onConsole或 JSBridge,在 HTML 渲染完成后将document.body.scrollHeight传回给 ArkTS,然后动态设置组件高度,否则长文会被截断。
  2. 流式响应 (Stream)
    DeepSeek 支持 Stream 模式(打字机效果)。在鸿蒙中,这需要使用http模块的on('headerReceive')on('dataReceive')监听事件,逐步拼接字符串并刷新 UI。这能极大提升用户体验。
  3. API Key 安全
    永远不要把 API Key 硬编码在客户端代码里上传到 Git!建议通过自己的后端服务器中转请求。

🎯 总结

通过不到 200 行代码,我们就在 HarmonyOS Next 上跑通了一个“DeepSeek”客户端。
这不仅验证了鸿蒙生态的开发效率,也展示了ArkTS + Web 组件混合开发的强大能力。

Next Step:
尝试给你的 App 加上“流式输出”功能,让 AI 的回复像打字机一样一个个蹦出来,体验瞬间提升 10 倍!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/25 11:47:41

新药发现、疫苗设计、精准医疗大模型 PaddleHelix(中文名“螺旋桨”)是百度基于飞桨(PaddlePaddle)深度学习框架开源的**生物计算平台**,把 AI 能力打包成一套“即插即用”的工

PaddleHelix&#xff08;中文名“螺旋桨”&#xff09;是百度基于飞桨&#xff08;PaddlePaddle&#xff09;深度学习框架开源的生物计算平台&#xff0c;把 AI 能力打包成一套“即插即用”的工具集&#xff0c;主要服务新药发现、疫苗设计、精准医疗三大场景。 一句话理解&…

作者头像 李华
网站建设 2026/4/23 13:13:04

终极免费PS3模拟器RPCS3:告别手动升级的完整配置方案

终极免费PS3模拟器RPCS3&#xff1a;告别手动升级的完整配置方案 【免费下载链接】rpcs3 PS3 emulator/debugger 项目地址: https://gitcode.com/GitHub_Trending/rp/rpcs3 还在为PS3模拟器的繁琐更新而烦恼吗&#xff1f;RPCS3作为目前最强大的免费PlayStation 3模拟器…

作者头像 李华
网站建设 2026/4/24 2:13:00

如何快速使用OpenAI Whisper:语音转文本完整使用指南

如何快速使用OpenAI Whisper&#xff1a;语音转文本完整使用指南 【免费下载链接】whisper-base.en 项目地址: https://ai.gitcode.com/hf_mirrors/openai/whisper-base.en 想要将语音内容快速转换为可编辑的文字吗&#xff1f;OpenAI Whisper作为当前最先进的语音识别…

作者头像 李华
网站建设 2026/4/24 18:10:13

C++库链接策略终极指南:5分钟掌握项目部署的核心抉择

C库链接策略终极指南&#xff1a;5分钟掌握项目部署的核心抉择 【免费下载链接】stb stb single-file public domain libraries for C/C 项目地址: https://gitcode.com/gh_mirrors/st/stb 还在为C项目部署时频繁出现的"未定义符号"错误而苦恼吗&#xff1f;面…

作者头像 李华
网站建设 2026/4/26 14:09:44

别让 AI 替你「假装读完」:我如何用「做幻灯」倒逼论文精读?

痛点读论文这件事&#xff0c;最大的谎言大概就是「我读完了」。其实很多时候&#xff0c;你只是「翻过了」。当你把 PDF 关掉&#xff0c;脑子里往往只剩下一堆模糊的关键词&#xff1a;Transformer、扩散模型、泛化能力…… 但如果我追问一句&#xff1a;「这篇论文的核心冲突…

作者头像 李华
网站建设 2026/5/1 2:15:52

Fashion-MNIST完全攻略:10个步骤从新手到专家的深度学习之旅

Fashion-MNIST完全攻略&#xff1a;10个步骤从新手到专家的深度学习之旅 【免费下载链接】fashion-mnist fashion-mnist - 提供了一个替代MNIST的时尚产品图片数据集&#xff0c;用于机器学习算法的基准测试。 项目地址: https://gitcode.com/gh_mirrors/fa/fashion-mnist …

作者头像 李华