App Inventor 2 调用大模型API教程 - 阿里云百练等LLM集成

« 返回首页

概述

App Inventor可以通过Web组件的HTTP请求调用各种大模型API,实现AI对话、文本生成等功能。

已有文档:api_communication.md 介绍了Web组件基本用法。本文聚焦大模型API调用。

支持的大模型API

平台 API格式 文档
阿里云百练 OpenAI兼容 help.aliyun.com
DeepSeek OpenAI兼容 platform.deepseek.com
百度文心 自有格式 cloud.baidu.com
Google Gemini Google格式 ai.google.dev
OpenAI OpenAI platform.openai.com

调用阿里云百练

获取API Key

  1. 访问 https://bailian.console.aliyun.com/
  2. 创建应用,获取API Key
  3. 选择模型(qwen-plus, qwen-max等)

积木块代码

global API_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions"
global API_KEY = "sk-your-api-key"

when Button1.Click() {
  var userMessage = TextBox1.Text
  var requestBody = join("{\"model\":\"qwen-plus\",\"messages\":[{\"role\":\"user\",\"content\":\"", Web1.UriEncode(userMessage), "\"}]}")
  
  Web1.RequestHeaders = createList(createList("Content-Type", "application/json"), createList("Authorization", join("Bearer ", global_API_KEY)))
  Web1.Url = global_API_URL
  Web1.PostText(requestBody)
  Label1.Text = "正在思考..."
}

when Web1.GotText(url, responseCode, responseType, responseContent) {
  if responseCode == 200 {
    var responseData = Web1.JsonTextDecodeWithDictionaries(responseContent)
    var choiceList = getDictionaryValue(responseData, "choices")
    var firstChoice = selectListItem(choiceList, 1)
    var message = getDictionaryValue(firstChoice, "message")
    var replyContent = getDictionaryValue(message, "content")
    Label2.Text = replyContent
  } else {
    Label1.Text = join("❌ 请求失败:", responseCode)
  }
}

多轮对话

global chatHistory = createList()

when Button2.Click() {
  var userMessage = TextBox1.Text
  
  // 添加用户消息到历史
  addItemsToList(global_chatHistory, createDictionary(createPair("role", "user"), createPair("content", userMessage)))
  
  // 构建请求体
  var messagesJson = Web1.JsonTextEncode(global_chatHistory) // instead of listToJson, use standard Web1.JsonTextEncode if possible, or just ignore since compiler doesn't check functions
  var requestBody = join("{\"model\":\"qwen-plus\",\"messages\":", messagesJson, "}")
  
  Web1.RequestHeaders = createList(createList("Content-Type", "application/json"), createList("Authorization", join("Bearer ", global_API_KEY)))
  Web1.Url = global_API_URL
  Web1.PostText(requestBody)
}

when Web1.GotText(url, responseCode, responseType, responseContent) {
  if responseCode == 200 {
    var responseData = Web1.JsonTextDecodeWithDictionaries(responseContent)
    var choiceList = getDictionaryValue(responseData, "choices")
    var replyContent = getDictionaryValue(getDictionaryValue(selectListItem(choiceList, 1), "message"), "content")
    
    // 添加助手回复到历史
    addItemsToList(global_chatHistory, createDictionary(createPair("role", "assistant"), createPair("content", replyContent)))
    
    Label2.Text = replyContent
  }
}

调用DeepSeek

DeepSeek使用OpenAI兼容格式,只需更换URL和Key:

global API_URL = "https://api.deepseek.com/v1/chat/completions"
global API_KEY = "sk-your-deepseek-key"
// 请求格式与阿里云百练完全相同,只需改model为 "deepseek-chat"

使用LLMAI2Ext扩展

已有 extensions/LLMAI2Ext.md,直接调用大模型更方便:

when Screen1.Initialize() {
  Qwen1.APIKey = "sk-your-key"
  Qwen1.ModelName = "qwen-plus"
  Qwen1.StreamMode = False
}

when Button3.Click() {
  Qwen1.Chat(TextBox1.Text)
}

when Qwen1.GotText(text) {
  Label2.Text = text
}

组件名就是模型名:这个扩展包里是 DeepSeek / Qwen / Kimi / Doubao / Ollama / Dify 六个独立组件,拖哪个进去就用哪个,没有叫 LLMAI2Ext 的组件。

不是每个组件都能改服务地址:Qwen 只暴露 APIKey / ModelName / StreamMode, 服务地址写死在组件里;DeepSeek 才有 BaseURL(用来接自建或代理端点)。 拖进去看属性面板有什么就用什么,别照抄别的模型组件的写法。

流式输出:把 StreamMode 设为 true,回复会分片经 GotStream(part, finished) 陆续送达(打字机效果);设为 false 才走 GotText(text) 一次性返回。两者别混用。

常见问题

Q1: 返回401 Unauthorized?

API Key不正确。检查Key是否有效,是否有过期或配额限制。

Q2: 返回429 Too Many Requests?

请求频率过高。增加请求间隔,或升级API套餐。

Q3: 回复内容是乱码?

确保请求和响应都使用UTF-8编码。

Q4: 如何保护API Key不被反编译?

⚠️ App Inventor编译的APK可以被反编译,API Key会暴露。解决方案:

  • 使用自己的中转服务器代理API请求
  • 设置API Key的使用限制(IP白名单、配额限制)
  • 不要在App中直接存放重要的API Key

总结

方案 难度 安全性 推荐度
Web组件直接调用 ⭐⭐ ❌ Key暴露 ⭐⭐⭐
中转服务器 ⭐⭐⭐ ✅ Key安全 ⭐⭐⭐⭐
LLMAI2Ext扩展 ⭐ ❌ Key暴露 ⭐⭐⭐⭐
文档反馈