鸿蒙ArkTS实战:从零对接通义千问与文心一言API的避坑指南

在HarmonyOS应用开发中集成AI能力正成为提升产品竞争力的关键路径。本文将带您深入实践,基于API9的Stage模型,使用DevEco Studio 3.1.1完成通义千问与文心一言两大主流模型的对接全流程。不同于简单的接口调用演示,我们将重点剖析两个平台在鉴权机制、请求构造和错误处理上的核心差异,并提供可直接复用的ArkTS代码模板。

1. 环境准备与项目初始化

1.1 开发环境配置

确保您的DevEco Studio版本不低于3.1.1(可通过 Help > About 查看)。新建项目时需特别注意:

// 检查build.gradle中的SDK版本
"compileSdkVersion": 9,
"compatibleSdkVersion": 9,
"targetSdkVersion": 9

常见踩坑点

  • 使用API8及以下版本会导致网络权限声明方式不同
  • 未启用Stage模型将无法使用最新的网络请求API
  • 模拟器需选择支持网络访问的版本(推荐使用本地真机调试)

1.2 网络权限申请

module.json5 中添加以下权限声明:

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET",
        "reason": "Required for API calls"
      }
    ]
  }
}

注意:Stage模型下权限声明位置与FA模型不同,错误配置会导致网络请求直接失败

2. 通义千问API对接实战

2.1 阿里云账号准备

  1. 登录 阿里云DashScope控制台
  2. 开通"通义千问"服务(目前有免费额度)
  3. 在"API-KEY管理"页面创建并保存密钥

关键差异 :阿里云采用直接API-KEY验证,无需二次鉴权流程

2.2 请求构造与错误处理

创建 src/main/ets/http/AliYunService.ets 文件:

import http from '@ohos.net.http';
import promptAction from '@ohos.promptAction';

class AliYunService {
  private static readonly ENDPOINT = 'https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation';
  private static readonly API_KEY = 'sk-your-actual-key'; // 替换为真实KEY

  static async query(prompt: string): Promise<string> {
    const httpRequest = http.createHttp();
    try {
      const response = await new Promise<http.HttpResponse>((resolve, reject) => {
        httpRequest.request(
          this.ENDPOINT,
          {
            method: http.RequestMethod.POST,
            header: {
              'Content-Type': 'application/json',
              'Authorization': `Bearer ${this.API_KEY}`
            },
            extraData: {
              model: 'qwen-turbo',
              input: {
                messages: [{ role: 'user', content: prompt }]
              }
            }
          },
          (err, data) => err ? reject(err) : resolve(data)
        );
      });

      const result = JSON.parse(response.result.toString());
      return result.output.text;
    } catch (error) {
      promptAction.showToast({ message: `请求失败: ${error.code}` });
      throw error;
    } finally {
      httpRequest.destroy();
    }
  }
}

export default new AliYunService();

关键优化点

  • 使用Promise封装异步请求
  • 添加try-catch错误处理
  • 自动释放HTTP资源
  • 返回类型明确为Promise

3. 文心一言API对接的特殊处理

3.1 百度智能云配置流程

  1. 登录 千帆大模型平台
  2. 创建应用并记录API Key/Secret Key
  3. 在"服务管理"中开通所需模型(注意计费方式)

核心差异 :百度采用OAuth2.0鉴权,需先获取access_token

3.2 双重请求实现方案

创建 src/main/ets/http/BaiduService.ets

import http from '@ohos.net.http';

interface TokenResponse {
  access_token: string;
  expires_in: number;
}

class BaiduService {
  private static readonly AUTH_URL = 'https://aip.baidubce.com/oauth/2.0/token';
  private static readonly CHAT_URL = 'https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions';
  private static readonly API_KEY = 'your-client-id';
  private static readonly SECRET_KEY = 'your-client-secret';

  private async getToken(): Promise<string> {
    const httpRequest = http.createHttp();
    const authUrl = `${this.AUTH_URL}?grant_type=client_credentials&client_id=${BaiduService.API_KEY}&client_secret=${BaiduService.SECRET_KEY}`;
    
    const response = await new Promise<http.HttpResponse>((resolve, reject) => {
      httpRequest.request(authUrl, { method: 'POST' }, (err, data) => 
        err ? reject(err) : resolve(data));
    });

    const tokenData: TokenResponse = JSON.parse(response.result.toString());
    return tokenData.access_token;
  }

  async query(prompt: string): Promise<string> {
    try {
      const token = await this.getToken();
      const httpRequest = http.createHttp();
      
      const response = await new Promise<http.HttpResponse>((resolve, reject) => {
        httpRequest.request(
          `${BaiduService.CHAT_URL}?access_token=${token}`,
          {
            method: 'POST',
            header: { 'Content-Type': 'application/json' },
            extraData: { messages: [{ role: 'user', content: prompt }] }
          },
          (err, data) => err ? reject(err) : resolve(data)
        );
      });

      return JSON.parse(response.result.toString()).result;
    } catch (error) {
      console.error(`Baidu API error: ${JSON.stringify(error)}`);
      throw error;
    }
  }
}

export default new BaiduService();

对比分析

特性 通义千问 文心一言
鉴权方式 API-KEY直接验证 OAuth2.0 token获取
请求次数 单次 至少两次(鉴权+业务)
错误处理重点 请求构造 Token过期处理
免费额度 新用户50万tokens 按模型不同分别计算

4. 调试技巧与性能优化

4.1 日志输出最佳实践

使用 @ohos.hilog 进行分级日志记录:

import hilog from '@ohos.hilog';

const DOMAIN = 0x0001;
const TAG = 'AIDemo';

// 调试日志
hilog.debug(DOMAIN, TAG, 'Request started with prompt: %{public}s', prompt);

// 错误日志
hilog.error(DOMAIN, TAG, 'API error: %{public}s', JSON.stringify(err));

日志等级选择

  • hilog.debug() :开发调试信息
  • hilog.info() :关键流程节点
  • hilog.warn() :非致命异常
  • hilog.error() :需要干预的错误

4.2 网络请求优化策略

  1. Token缓存机制
private cachedToken: string = '';
private tokenExpireTime: number = 0;

async getTokenWithCache(): Promise<string> {
  if (this.cachedToken && Date.now() < this.tokenExpireTime) {
    return this.cachedToken;
  }
  const token = await this.getToken();
  this.cachedToken = token;
  this.tokenExpireTime = Date.now() + 3500 * 1000; // 提前500秒刷新
  return token;
}
  1. 请求超时设置
httpRequest.request(url, {
  method: 'POST',
  connectTimeout: 10000, // 10秒连接超时
  readTimeout: 30000    // 30秒读取超时
}, callback);
  1. 并发控制
const MAX_CONCURRENT = 3;
let activeRequests = 0;

async throttledQuery(prompt: string): Promise<string> {
  while (activeRequests >= MAX_CONCURRENT) {
    await new Promise(resolve => setTimeout(resolve, 100));
  }
  
  activeRequests++;
  try {
    return await this.query(prompt);
  } finally {
    activeRequests--;
  }
}

5. 界面集成与用户体验优化

5.1 状态管理方案

推荐使用 @ohos.app.ability.UIAbility 结合 AppStorage

// 在Ability中初始化
AppStorage.SetOrCreate('isLoading', false);
AppStorage.SetOrCreate('aiResponse', '');

// 在页面组件中调用
@StorageLink('isLoading') isLoading: boolean = false;
@StorageLink('aiResponse') response: string = '';

async queryAI() {
  this.isLoading = true;
  try {
    this.response = await AliYunService.query(this.userInput);
  } catch (e) {
    this.response = `Error: ${e.message}`;
  } finally {
    this.isLoading = false;
  }
}

5.2 流式输出实现

对于支持流式响应的API版本,可以使用 @ohos.net.http 的进度回调:

httpRequest.request(url, options, {
  onHeaderReceive(header) {
    // 处理分块传输头
  },
  onProgress(receivedLen, totalLen) {
    // 实时更新界面
    updateUI(receivedData);
  }
});

体验优化技巧

  • 添加打字机效果动画
  • 实现历史对话持久化存储
  • 添加重试机制和超时提示
  • 针对移动端优化输入框交互

实际开发中发现,百度API的access_token在本地缓存时需要注意同步问题,特别是在应用被系统回收后重新恢复的场景。建议结合 persistentStorage 实现可靠的token存储方案。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐