目前,在鸿蒙应用开发中集成大模型的主流方式是调用其提供的 API 接口,开发者通常借助网络请求来完成与大模型的交互,并将返回结果整合到应用功能中。下文将具体介绍如何通过网络请求调用大模型 API,并将其集成到鸿蒙应用中。(将会以deepseek,千问,百度的大模型为例)

开发教程

deepseek

先以deepseek为例子,开发一个大模型对话的应用

  1. AI回复的数据结构,这个是用来存网络请求返回的结果的,格式匹配我们才能正确接收到数据

    interface AIMessage {
      content: string;
    }
    ​
    interface AIChoice {
      message: AIMessage;
    }
    ​
    interface AIResult {
      choices?: AIChoice[];
      response?: string;
    }
  2. 创建密钥,从官方文档中找到API调用示例,比如这里的deepseek的接口文档首次调用 API | DeepSeek API Docs,里面就详细的介绍了如何进行网络请求访问,后面也是根据这个来进行网络请求。

    curl https://api.deepseek.com/chat/completions \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer ${DEEPSEEK_API_KEY}" \
      -d '{
            "model": "deepseek-chat",
            "messages": [
              {"role": "system", "content": "You are a helpful assistant."},
              {"role": "user", "content": "Hello!"}
            ],
            "stream": false
          }'
  3.  ai访问类的编写,在这里我们要实现网络请求访问大模型API的核心逻辑,代码中有详细的注释(省流:直接把代码复制到你的应用中,把API密钥和访问地址填好,然后调用这个类的sendRequest(你的问题),就可以得到AI的结果,简单粗暴)

     
    1.    类的代码     

      export class HttpAIService {
        private static instance: HttpAIService;
        private apiUrl: string = 'https://api.deepseek.com/chat/completions'; // 替换为实际API地址
        private apiKey: string = 'xxxxxxxxxxxxxxxxxxxxxxx'; // 替换为实际API密钥
      ​
        private constructor() {}
      ​
        public static getInstance(): HttpAIService {
          if (!HttpAIService.instance) {
            HttpAIService.instance = new HttpAIService();
          }
          return HttpAIService.instance;
        }
      ​
        /**
         * 设置API配置,这里就需要你把你创建的API密钥和访问网址填写进这里
         */
        setConfig(apiUrl: string, apiKey: string): void {
          this.apiUrl = apiUrl;
          this.apiKey = apiKey;
        }
      ​
        /**
         * 发送AI请求,这里就是发送请求给AI,然后接收AI的返回结果
         * @param userInput 用户输入文本
         */
        async sendRequest(userInput: string): Promise<string> {
          //创建一个http请求
          const httpRequest = http.createHttp();
          try {
            console.info('[AI] 发送请求:', userInput);
      ​
            const response = await httpRequest.request(this.apiUrl, {
              method: http.RequestMethod.POST,
              //这里就是根据前面提到的示例来写
              header: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${this.apiKey}`
              },
              extraData: {
                'model': 'qwen-plus',
                "messages": [
                  {
                    "role": "system",
                    "content": "你是一个智能助手"
                  },
                  { "role": "user", "content": userInput }
                ],
              }
            });
            //这里就是处理我们网络请求的返回结果,如果成功的话,我们就返回大模型的回答,如果失败我们就返回错误信息
            if (response.responseCode === 200) {
              //成功的话,返回大模型的回答
              const result: AIResult = JSON.parse(response.result as string);
              return result.choices?.[0]?.message?.content || result.response || '';//这个就是大模型的回答所在的位置
            } 
            //失败我们就返回错误信息
            else {
              console.error('[AI] 请求失败:', response.responseCode);
              return '请求失败';
            }
          } catch (error) {
            console.error('[AI] 请求异常:', error);
            return '网络异常';
          } finally {
            httpRequest.destroy();
          }
        }
      }
  4. 前端UI的编写,接下来就是构建一个简单的AI对话界面,具体的实现逻辑就不细说了,主要就是一个文本输入框,用来发送信息,还有展示对话内容

    /**
     * AI对话和语音交流界面
     * 这是一个支持文字和语音交互的AI聊天界面组件
     */
    import { HttpAIService } from './http_server';  // 导入AI服务类,就是上面写的那个类
    ​
    // 定义聊天消息接口
    interface ChatMessage {
      id: string;           // 消息唯一标识
      role: 'user' | 'ai';  // 消息发送者:用户或AI
      content: string;      // 消息内容
      timestamp: number;    // 消息时间戳
    }
    ​
    @Entry  // 标记为入口组件,表示这是应用的第一个页面
    @Component  // 标记为自定义组件
    export struct AIChatView {
      // @State装饰器:当状态变量变化时,会自动触发UI重新渲染
    ​
      @State messages: ChatMessage[] = [];  // 存储所有聊天消息的数组
      @State inputText: string = '';        // 文本输入框的内容
      @State isListening: boolean = false;  // 是否正在语音识别(当前未使用)
      @State isProcessing: boolean = false; // 是否正在处理AI响应
      @State isVoiceMode: boolean = false;  // 是否为语音模式(当前未使用)
      @State tokenID: number = 0;           // 用户标识(当前未使用)
    ​
      // 私有属性
      private sessionId: string = "";       // 会话ID(当前未使用)
      private currentRecordText: string = ""; // 当前录音文本(当前未使用)
      private aiService = HttpAIService.getInstance(); // AI服务实例(单例模式)
      private scroller: Scroller = new Scroller();     // 列表滚动控制器
    ​
      /**
       * 生命周期方法:组件即将显示时调用
       * 类似于React的componentWillMount
       */
      aboutToAppear() {
        // 添加AI的欢迎消息
        this.addMessage('ai', '你好!我是小智同学,有什么可以帮你的吗?');
      }
    ​
      /**
       * 构建UI界面的方法
       * 使用ArkUI的声明式UI语法
       */
      build() {
        Column() {  // 垂直布局容器
          // ========== 标题栏 ==========
          Row() {
            Text('AI助手')
              .fontSize(24)
              .fontWeight(FontWeight.Bold)  // 字体加粗
          }
          .width('100%')  // 宽度占满父容器
          .padding({ left: 20, right: 20, top: 15, bottom: 10 })  // 内边距
    ​
          // ========== 对话消息列表区域 ==========
          List({ space: 15, scroller: this.scroller }) {  // 列表组件,15px间距
            // 遍历messages数组,为每条消息创建ListItem
            ForEach(this.messages, (msg: ChatMessage) => {
              ListItem() {
                this.MessageBubble(msg)  // 使用自定义Builder渲染消息气泡
              }
            })
          }
          .width('100%')
          .layoutWeight(1)  // 布局权重为1,占满剩余空间
          .padding({ left: 15, right: 15, top: 10 })  // 列表内边距
          .backgroundColor('#F5F5F5')  // 背景色:浅灰色
    ​
          // ========== 底部输入区域 ==========
          Row({ space: 10 }) {  // 水平布局容器,10px间距
            // ========== 文字输入框 ==========
            TextInput({ text: this.inputText, placeholder: '输入消息...' })
              .layoutWeight(1)  // 权重为1,占满Row的剩余空间
              .height(40)       // 固定高度40px
              .fontSize(16)     // 字体大小
              .borderRadius(20) // 圆角(半高=20px,形成胶囊形状)
              .backgroundColor('#F0F0F0')  // 背景色:浅灰色
              // 输入内容变化时的回调
              .onChange((value: string) => {
                this.inputText = value;  // 更新输入文本状态
              })
              // 按下回车键时的回调
              .onSubmit(() => {
                this.sendMessage();  // 发送消息
              })
    ​
            // ========== 发送按钮 ==========
            Button('发送')
              .fontSize(14)
              .height(40)
              .backgroundColor('#2196F3')  // 背景色:蓝色
              .borderRadius(20)            // 圆角胶囊形
              // 启用条件:不处理中且输入框有内容
              .enabled(!this.isProcessing && this.inputText.length > 0)
              .onClick(() => {
                this.sendMessage();  // 点击发送消息
              })
          }
          .width('100%')
          .padding(12)        // 四周12px内边距
          .backgroundColor('#FFFFFF')  // 背景色:白色
        }
        .width('100%')    // 占满父容器宽度
        .height('100%')   // 占满父容器高度
      }
    ​
      /**
       * @Builder装饰的方法:构建消息气泡UI
       * 复用UI代码,类似于React中的render函数或组件
       * @param msg 消息对象
       */
      @Builder
      MessageBubble(msg: ChatMessage) {
        Row() {  // 水平布局容器
          // 如果是用户消息,左侧添加空白占位(右对齐效果)
          if (msg.role === 'user') {
            Blank()  // 空白占位组件
          }
    ​
          // 消息内容区域(垂直布局)
          Column({ space: 5 }) {  // 垂直布局,5px间距
            // 消息文本
            Text(msg.content)
              .fontSize(16)
              // 根据消息角色设置字体颜色
              .fontColor(msg.role === 'user' ? '#FFFFFF' : '#333333')
              .padding(12)  // 内边距
              // 根据消息角色设置背景色
              .backgroundColor(msg.role === 'user' ? '#2196F3' : '#FFFFFF')
              .borderRadius(12)  // 圆角
              .maxLines(100)     // 最大行数(接近无限)
              .textOverflow({ overflow: TextOverflow.None })  // 文本不截断
    ​
            // 消息时间
            Text(this.formatTime(msg.timestamp))
              .fontSize(12)
              .fontColor('#999999')  // 浅灰色时间戳
          }
          // 根据消息角色设置对齐方式
          .alignItems(msg.role === 'user' ? HorizontalAlign.End : HorizontalAlign.Start)
          .constraintSize({ maxWidth: '70%' })  // 限制最大宽度为70%
    ​
          // 如果是AI消息,右侧添加空白占位(左对齐效果)
          if (msg.role === 'ai') {
            Blank()
          }
        }
        .width('100%')  // 占满列表项宽度
      }
    ​
      /**
       * 发送消息到AI服务
       * 异步函数:处理用户消息发送和AI响应
       */
      async sendMessage() {
        // 输入验证:空消息或处理中时不发送
        if (this.inputText.trim().length === 0 || this.isProcessing) {
          return;
        }
    ​
        const userMessage = this.inputText.trim();  // 去除首尾空格
        this.inputText = '';  // 清空输入框
    ​
        // 添加用户消息到聊天记录
        this.addMessage('user', userMessage);
        this.isProcessing = true;  // 标记为处理中状态
    ​
        // 调用AI服务获取响应
        const response = await this.aiService.sendRequest(userMessage);
    ​
        // 添加AI响应到聊天记录
        this.addMessage('ai', response);
    ​
        this.isProcessing = false;  // 重置处理中状态
      }
    ​
      /**
       * 添加消息到聊天记录
       * @param role 消息角色:'user' 或 'ai'
       * @param content 消息内容
       */
      addMessage(role: 'user' | 'ai', content: string) {
        // 创建新消息对象并添加到数组
        this.messages.push({
          id: Date.now().toString(),  // 使用时间戳作为唯一ID
          role: role,
          content: content,
          timestamp: Date.now()       // 当前时间戳
        });
    ​
        // 延迟100ms后滚动到列表底部
        setTimeout(() => {
          this.scroller.scrollEdge(Edge.Bottom);  // 滚动到底部
        }, 100);
      }
    ​
      /**
       * 格式化时间戳为易读的时间字符串
       * @param timestamp 时间戳(毫秒)
       * @returns 格式化的时间字符串 "HH:MM"
       */
      formatTime(timestamp: number): string {
        const date = new Date(timestamp);
        // 获取小时,补零到2位
        const hours = date.getHours().toString().padStart(2, '0');
        // 获取分钟,补零到2位
        const minutes = date.getMinutes().toString().padStart(2, '0');
        return `${hours}:${minutes}`;  // 返回 "时:分" 格式
      }
    }

    至此一个完整的AI对话应用就已经完成了

千问

千问大模型的接入也是和deepseek一样,不同的地方在于网络请求的地址不一样还有API密钥不一样,所以使用千问大模型的话,只需要修改apiUrl和apiKey,还有请求数据中的model,修改完之后,就可以和deepseek一样使用了

具体的使用示例也可以前往官网查看通义千问API参考-大模型服务平台百炼(Model Studio)-阿里云帮助中心

//apiUrl和apiKey
private static instance: HttpAIService;
  private apiUrl: string = 'https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions'; // 替换为实际API地址
  private apiKey: string = 'xxxxxxxxxxxxxxxxx'; // 替换为实际API密钥
  
--------------------------------------------------------------------------
//请求数据
extraData: {
  'model': 'qwen-plus',
  "messages": [
    {
      "role": "system",
      "content": "你是一个智能助手"
    },
    { "role": "user", "content": userInput }
  ],
}

百度

百度文心一言大模型的接入前面的步骤一模一样,这里就不赘述了

总结与展望

本文简单介绍了如何在鸿蒙应用开发中集成国产的大模型,各个大模型厂商的使用过程基本都是一样的,学会一个其他都会用了,核心都是在与网络请求。

上面只是简单的与大模型对话的应用,只展示了如何在应用中与大模型进行后续可以继续加入其他的功能,加入各种各样的MCP服务,让你的大模型应用更加强大,有兴趣的小伙伴可以自行探索。

Logo

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

更多推荐