概述
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
- 访问 https://bailian.console.aliyun.com/
- 创建应用,获取API Key
- 选择模型(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暴露 | ⭐⭐⭐⭐ |
扫码添加客服咨询