关于 ai-model-web
用于通过 `@cloudbase/js-sdk` 在浏览器 Web 应用中调用 AI 模型的 CloudBase 技能,要求在编写 SDK 代码前检查资源资格和模型组状态。
主要功能
- 01浏览器端模型调用
- 02文本响应流式输出
- 03Token 资源包资格检查
- 04模型组与目录检查
- 05托管及自定义模型组
适用场景
- 01在 Web 应用中添加文本生成
- 02在前端流式呈现模型输出
- 03集成前检查环境调用资格
- 04为应用启用模型
MCP 相关
该技能通过 CloudBase MCP 工具查询环境、检查 Token 资源包资格,并在 SDK 调用前发现或配置模型组。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ tencentcloudbase/ cloudbase-ai-toolkit --skill ai-model-web安装后在 Claude Code 中输入/ai-model-web确认已加载。
详细介绍
同级技能(仅本地)
同级 CloudBase 技能与此技能一同提供。请使用 ../auth-tool-cloudbase/SKILL.md 这类本地相对路径。
如果此环境中缺少引用的同级技能文件,请让用户安装完整的 CloudBase 插件(或缺少的技能)。不要通过 HTTP 将远程技能或协议 Markdown 获取到 Agent 上下文中。
何时使用此技能
通过 @cloudbase/js-sdk 在浏览器/Web 应用中调用 AI 模型时,请使用此技能。
🧭 Web 默认使用运行时平面。 只要用户的请求围绕页面、Web 应用、前端、React/Vue/Next/Nuxt、仪表盘 UI 或“为我的 H5 添加 AI”展开,此技能就是默认路由目标。不要先提议使用 Node.js / 云函数 / CloudRun 代理;
@cloudbase/js-sdk可以直接从浏览器调用模型。只有在用户明确要求进行后端/服务端调用、图像生成,或场景确实需要服务端密钥或长时间运行的工作时,才切换到ai-model-nodejs。此决策与用户选择的具体模型无关——模型名称(deepseek-*、glm-*、hunyuan-*、kimi-*等)只影响model字段,不影响路由平面。
在以下情况使用:
- 将 AI 文本生成集成到前端 Web 应用
- 流式传输 AI 回复,改善用户体验
- 从浏览器调用 Hunyuan / DeepSeek / GLM / Kimi / MiniMax 模型
以下情况不要使用:
- Node.js 后端或云函数 → 使用
ai-model-nodejs技能 - 微信小程序 → 使用
ai-model-wechat技能 - 图像生成 → 使用
ai-model-nodejs技能(仅限 Node SDK) - 不支持 CloudBase SDK 的运行时(原生应用、Python、Go 等)→ 使用
http-api-cloudbase技能(该技能现已包含用于直接 HTTP 调用的ai_modelOpenAPI 规范;不要构建自定义 HTTP 代理)
⛔ 停止 — ai.createModel(...) 参数不是厂商/模型名称
请在编写任何 createModel(...) 代码行之前阅读此内容。Agent 为此 SDK 生成代码时,最常见的错误就是臆造参数。合法形式恰好有三种,其他任何形式都是错误。
✅ 合法的 ai.createModel(...) 参数 | 使用时机 |
|---|---|
"cloudbase" | 新项目使用的主要托管组(由 TokenHub 提供支持的多厂商模型池)。厂商和具体模型应放入 generateText / streamText 的 model 字段,例如 { model: "deepseek-v4-flash" }。默认不会启用任何模型 — 调用 SDK 前务必先检查 DescribeAIModels;如果缺少目标模型,则先使用 UpdateAIModel 启用它。 |
"hunyuan-exp" | 仅当 DescribeAIModels 明确为当前环境返回此旧版内置组时使用(主要用于小程序成长计划 — 请参阅 ai-model-wechat)。 |
"custom-<your-name>" | 通过 CreateAIModel 接入的用户自定义 GroupName。必须以 custom- 开头(例如 custom-kimi、custom-openai-compat)。 |
❌ 不要编写以下任何内容 — 它们全都不正确
ai.createModel("deepseek") // wrong — that's a vendor, not a GroupName
ai.createModel("deepseek-v4-flash") // wrong — that's a model name, goes in the `model` field
ai.createModel("hunyuan") // wrong — vendor family, not a GroupName
ai.createModel("hunyuan-2.0-instruct-20251111") // wrong — model name
ai.createModel("glm") / ai.createModel("kimi") / ai.createModel("minimax") // wrong — vendor names
ai.createModel("openai") / ai.createModel("moonshot") // wrong — vendor names
ai.createModel("custom") // wrong — placeholder; use your real custom-<name>
ai.createModel(modelName) // wrong — do not reuse the variable that holds the model id
✅ 正确模式 — GroupName 和 Model 是两个不同的字段
const model = ai.createModel("cloudbase"); // ← GroupName
await model.generateText({
model: "deepseek-v4-flash", // ← concrete model id
messages: [...]
});
决策流程(用户指定具体模型时)
- 用户说“使用 DeepSeek v3.2”/“使用 hunyuan instruct”/“使用 Kimi k2.6”/“使用 GLM-5”/……
createModel("cloudbase")保持不变。- 将模型 ID 填入
model字段:{ model: "deepseek-v3.2" }、{ model: "hunyuan-2.0-instruct-20251111" }、{ model: "kimi-k2.6" }、{ model: "glm-5" },…… - 切勿假设模型已启用。 编写 SDK 调用前,请确认模型已包含在
DescribeAIModels({ GroupName: "cloudbase" }).Models[]中。如果缺少该模型,请调用DescribeManagedAIModelList确认平台支持的确切Model名称(区分大小写,不要猜测拼写),然后通过UpdateAIModel将其启用,并设置Status: 1(请记住,Models会整体替换,因此要重新传入所有已启用的模型以及新模型)。
如果你准备输入
ai.createModel(,而括号内是供应商名称、模型名称或猜测值,请停下。它几乎肯定不属于上述三个合法值。
强制两步预检(编写任何 SDK 代码之前)
生成任何 AI 相关的 SDK 代码之前,请先执行两步预检:① 资格检查,② 分组就绪检查。直接输出 createModel(...),让用户自行排查运行时错误,代价要高得多。
第 0 步:获取环境 ID
调用 MCP 工具 queryEnv,设置 action=info,并从响应中读取 EnvId。后续每项检查和购买链接都使用此 EnvId。
预检 ① — 资格检查(Token Credits 资源包)
调用 MCP 工具:
callCloudApi(service="tcb", action="DescribeEnvPostpayPackage", params={ EnvId })
通过条件(必须全部满足):
-
envPostpayPackageInfoList至少包含一个条目 -
该条目的
postpayPackageId以pkg_tcb_tokencredits_开头 -
该条目的
status不在[3, 4]中(3 / 4 通常表示已过期 / 已停用;请以实时响应为准) -
❌ 未满足 → 停止编写代码,并向用户说明以下内容(将
{envId}替换为实际 ID):当前环境没有启用中的 Token Credits 资源包。调用任何 AI API 前,请先购买资源包: https://buy.cloud.tencent.com/lowcode?buyType=resPack&envId={envId}&resourceType=token
完成后请告知我,我会重新检查资源包状态。
-
✅ 已满足 → 继续进行预检 ②。
根据约定,参数名使用 PascalCase。如果调用返回
InvalidParameter,请改用 camelCase(envId/envPostpayPackageInfoList),并以实时响应为准。对于小程序场景,还需额外检查增长计划分支——请切换到ai-model-wechat技能。
预检 ② — 分组就绪情况(DescribeAIModels → 必要时调用 UpdateAIModel)
仅满足资格条件还不够。**暂时不要调用 createModel("cloudbase")。**首先确认目标 GroupName 在环境中存在且 Status=1,并且目标 Model 已包含在其 Models[] 中。
-
列出当前环境中已配置的分组:
callCloudApi(service="tcb", action="DescribeAIModels", params={ EnvId })返回
AIModelGroups: AIModelGroup[],其中每个AIModelGroup都包含GroupName、Type(builtin/custom)、Models: [{ Model, EnableMCP, Tags }]、Status(1 = 开启 / 2 = 关闭)、BaseUrl、Secret、Remark。主要托管分组的GroupName是cloudbase。 -
**切勿假定某个模型已启用。**检查
cloudbase分组中的AIModelGroups[?].Models[].Model。如果缺少目标模型(或者用户未指定模型时,你打算默认使用的模型,例如deepseek-v4-flash),请跳转到第 4 步并启用它——暂时不要调用createModel("cloudbase")。如果cloudbase分组本身不存在或其Status=2,也请跳转到第 4 步。 -
用户指定了属于托管目录的模型(例如
deepseek-v3.2、hunyuan-2.0-instruct-20251111、glm-5、kimi-k2.6等):检查该Model是否已包含在cloudbase分组的Models[]中。如果没有,请跳转到第 4 步。不要猜测确切的模型 ID——请先通过DescribeManagedAIModelList确认规范写法(第 4 步会介绍)。 -
启用 / 添加托管模型(务必先检查权威目录和定价):
callCloudApi(service="tcb", action="DescribeManagedAIModelList", params={ EnvId })返回
ManagedAIModelGroup[],其中每个分组都列出GroupName(例如cloudbase)、Remark和Models: [{ Model, EnableMCP, ModelSpec{ContextLength, MaxInputToken, MaxOutputToken}, ModelChargingInfo[{Type, InputPrice, OutputPrice, InputOutputUnit, CachePrice}] }]。**这是受支持模型名称和定价的唯一权威来源——不要凭记忆推断。调用UpdateAIModel时,请使用此处返回的确切Model字符串。**启用前也请向用户说明价格。然后启用(注意:
Models是全量替换——请始终连同已启用的模型一起重新传入新模型):callCloudApi(service="tcb", action="UpdateAIModel", params={ EnvId, GroupName: "cloudbase", Models: [ // resend every model that DescribeAIModels already showed as enabled { Model: "<already-enabled model, e.g. deepseek-v4-flash>" }, // append the newly-requested one, using the exact spelling from DescribeManagedAIModelList { Model: "<target model>" } ], Status: 1 }) -
请求的模型不在托管目录中(未通过
DescribeManagedAIModelList找到)→ 跳转到下一节,自定义接入(托管目录之外的模型)。
所有 Actions 均使用
service=tcb、Version=2018-06-08。参数使用 PascalCase(EnvId/GroupName/Models/Status)。只有在调用返回InvalidParameter时,才回退为 camelCase。
可用的提供商和模型
ai.createModel(<GroupName>) 仅接受以下三种合法值:
1. "cloudbase" — 主要托管分组(推荐)
GroupName: "cloudbase"、Type: "builtin"、Remark: "腾讯云开发"(Tencent CloudBase)- 由腾讯云 TokenHub提供支持,这是一个统一托管池,涵盖多个供应商——混元(HY 2.0 Instruct、HY 2.0 Think、Hunyuan-role、Hy3 preview 等)、DeepSeek(DeepSeek-V4-Pro、DeepSeek-V4-Flash、Deepseek-v3.2、Deepseek-v3.1、Deepseek-r1-0528、Deepseek-v3-0324 等)、智谱 GLM(GLM-5、GLM-5-Turbo、GLM-5.1、GLM-5V-Turbo)、Kimi(K2.5、K2.6)、MiniMax(M2.5、M2.7)等。模型列表会持续更新——不要在应用代码中硬编码特定 SKU;请在运行时查询。
- **默认情况下不会启用任何模型。**务必先调用
DescribeAIModels,查看环境中实际启用的模型;如果缺少目标模型,请调用DescribeManagedAIModelList获取权威目录和定价,然后调用UpdateAIModel(Status: 1,Models全量替换)启用模型,再调用 SDK。 - 权威目录和定价:
DescribeManagedAIModelList - 环境中已启用的模型集合:
DescribeAIModels
2. "hunyuan-exp" — 为兼容性保留的旧版内置分组
- 主要适用于小程序增长计划场景;Web 端不要使用,除非环境明确仍有该分组(此流程请改用
ai-model-wechat技能) - 默认模型:
hunyuan-2.0-instruct-20251111;其他 hunyuan SKU 必须在运行时通过DescribeAIModels({ GroupName: "hunyuan-exp" }).Models[]获取,不要硬编码其他 ID
3. 用户自定义 GroupName
- 通过
CreateAIModel接入(见下一节)。自定义GroupName必须以custom-开头(例如custom-kimi、custom-moonshot、custom-openai-compat)。此命名约定可避免与平台未来可能引入的内置或供应商 GroupName(cloudbase、hunyuan-exp、deepseek、glm、kimi、minimax,等等)发生冲突 - 示例:
createModel("custom-kimi")、createModel("custom-openai-compat")
切勿使用
createModel("deepseek")或createModel("custom")这样的猜测值,除非DescribeAIModels明确返回了完全相同的GroupName(旧环境可能仍带有历史遗留的deepseek/hunyuan-exp内置分组;为兼容性仍允许使用,但新项目应始终通过cloudbase接入)。
自定义接入(托管目录之外的模型)
当用户想要调用非托管模型(自托管、企业内部模型、第三方 OpenAI 兼容端点,等等)时,不要阻止。请引导他们完成接入:
选项 1:控制台流程(推荐,由用户自行处理)
https://tcb.cloud.tencent.com/dev?envId={envId}#/ai
选项 2:以编程方式接入(CreateAIModel)
callCloudApi(service="tcb", action="CreateAIModel", params={
EnvId: "<envId>",
GroupName: "custom-<your-name>", // MUST start with "custom-" (e.g. custom-kimi, custom-openai-compat); never start with "cloudbase"
BaseUrl: "<OpenAI-compatible endpoint, e.g. https://api.moonshot.cn/v1>",
Models: [
{ Model: "<model name, e.g. kimi-k2.5>", EnableMCP: true }
],
Remark: "<optional remark>",
Status: 1,
Secret: { ApiKey: "<vendor api key supplied by the user>" }
})
接入后,使用 DescribeAIModels 确认分组已就绪,然后在代码中调用 ai.createModel("<the GroupName you just registered>")。使用 UpdateAIModel 添加或移除模型、轮换密钥,或更改 BaseUrl(请记住,Models 是完全替换)。使用 DeleteAIModel 删除自定义分组(内置分组无法删除)。
自定义模型的费用由第三方提供商收取,不会从 Token Credits 资源包中扣除。字段大小写遵循实时契约;遇到
InvalidParameter时,请改用 camelCase。
安装
npm install @cloudbase/js-sdk
初始化
⚠️ 不要将匿名登录用作默认方式。 新环境默认禁用匿名登录,已有的不活跃环境也已自动禁用。即使手动启用了匿名登录,匿名用户默认也没有调用 AI 模型的权限。AI 模型技能不规定特定的登录界面——请将相关工作交由相应技能处理:
- 启用 / 配置登录提供方(手机短信、电子邮件、微信开放平台、用户名+密码、OAuth 等)→ 遵循
auth-tool-cloudbase技能(通过callCloudApi配置后端)。- 在浏览器中构建实际的登录流程(登录表单、回调、会话守卫)→ 遵循
auth-web-cloudbase技能(使用@cloudbase/js-sdk认证 API,例如signInWithPassword、signInWithPhone、getSession)。AI 功能不要回退到
signInAnonymously()——匿名用户无法调用 AI 模型。仅在用户明确提出要求并接受这一取舍时,才将匿名登录用于非 AI 的只读演示。
import cloudbase from "@cloudbase/js-sdk";
const app = cloudbase.init({
env: "<YOUR_ENV_ID>",
accessKey: import.meta.env.VITE_PUBLISHABLE_KEY // auto-provision via queryAppAuth / manageAppAuth, write to .env.local (see auth-web-cloudbase prerequisites)
});
const auth = app.auth;
// CRITICAL: Use auth.getSession() to check login — NOT the deprecated getLoginState().
// getLoginState() returns uid even without real login (just accessKey), causing false positives.
// getSession() returns data.session === undefined when no real login exists.
// Anonymous users are DENIED AI model permissions — calling AI without real login will fail.
const { data: sessionData } = await auth.getSession();
if (!sessionData?.session || sessionData.session.user?.is_anonymous) {
// No real login or anonymous session — route to sign-in page
window.location.href = "/login";
return;
}
const ai = app.ai();
重要说明:
- 使用顶层导入进行同步初始化
accessKey会导致getLoginState()返回误导性的认证数据——已弃用的getLoginState()即使在未实际登录时也会返回带有uid的对象,这会导致简单的!!loginState检查失效。请改用auth.getSession():在不存在实际登录时,它会返回data.session === undefined,因此!!data.session是可靠的认证门控条件。- 使用 AI 功能前,用户必须通过已验证的登录方式(手机、电子邮件、微信、用户名+密码、自定义方式)完成认证。匿名用户没有 AI 模型权限。具体流程由
auth-web-cloudbase技能负责。 - 从 CloudBase 控制台获取
accessKey
generateText() — 非流式
前提条件: 已通过两步预检(资格检查 + 分组就绪检查),并已确认目标模型存在于
DescribeAIModels({ GroupName: "cloudbase" }).Models[]中——如果模型不存在,则此时应已通过UpdateAIModel启用。以下示例仅以deepseek-v4-flash作说明;请替换为用户实际要求的模型。
const model = ai.createModel("cloudbase");
const result = await model.generateText({
model: "deepseek-v4-flash", // must already be enabled in this env (DescribeAIModels → UpdateAIModel)
messages: [{ role: "user", content: "Give me a one-paragraph intro to Li Bai." }],
});
console.log(result.text); // generated text string
console.log(result.usage); // { prompt_tokens, completion_tokens, total_tokens }
console.log(result.messages); // full message history
console.log(result.rawResponses); // raw model responses
streamText() — 流式
前提条件: 已通过两步预检。
const model = ai.createModel("cloudbase");
const res = await model.streamText({
model: "deepseek-v4-flash",
messages: [{ role: "user", content: "Give me a one-paragraph intro to Li Bai." }],
});
// Option 1: iterate the text stream (recommended)
for await (let text of res.textStream) {
console.log(text); // incremental text chunks
}
// Option 2: iterate the data stream for full response chunks
for await (let data of res.dataStream) {
console.log(data); // full response chunk with metadata
}
// Option 3: access final results
const messages = await res.messages; // full message history
const usage = await res.usage; // token usage
错误处理模式
const model = ai.createModel("cloudbase");
try {
const result = await model.generateText({
model: "deepseek-v4-flash",
messages: [{ role: "user", content: "Generate a concise onboarding checklist." }],
});
console.log(result.text);
} catch (error) {
console.error("Failed to call CloudBase AI from Web", error);
}
类型定义
interface BaseChatModelInput {
model: string; // required: model name
messages: Array<ChatModelMessage>; // required: message array
temperature?: number; // optional: sampling temperature
topP?: number; // optional: nucleus sampling
}
type ChatModelMessage =
| { role: "user"; content: string }
| { role: "system"; content: string }
| { role: "assistant"; content: string };
interface GenerateTextResult {
text: string; // generated text
messages: Array<ChatModelMessage>; // full message history
usage: Usage; // token usage
rawResponses: Array<unknown>; // raw model responses
error?: unknown; // error if any
}
interface StreamTextResult {
textStream: AsyncIterable<string>; // incremental text stream
dataStream: AsyncIterable<DataChunk>; // full data stream
messages: Promise<ChatModelMessage[]>;// final message history
usage: Promise<Usage>; // final token usage
error?: unknown; // error if any
}
interface Usage {
prompt_tokens: number;
completion_tokens: number;
total_tokens: number;
}
最佳实践
- 先执行两步预检 — ① 资格检查(通过
DescribeEnvPostpayPackage检查 Token Credits 资源包)+ ② 分组就绪情况检查(通过DescribeAIModels检查已启用的模型,通过DescribeManagedAIModelList获取权威的受支持模型目录;如果缺少目标模型,则使用完整替换的Models[]和Status: 1调用UpdateAIModel)。跳过预检会直接导致运行时出现“找不到模型”/“模型未启用”错误。 - 绝不要假设任何模型已启用 — 无论是
deepseek-v4-flash、hunyuan-*,还是其他模型。始终先通过DescribeAIModels确认;如果缺少目标模型,就在DescribeManagedAIModelList中查找准确的Model字符串(不要猜拼写或编造供应商前缀),然后调用UpdateAIModel启用它。 createModel只接受三种值 —"cloudbase"(主托管分组)、"hunyuan-exp"(旧版内置分组,适用于成长计划场景),或通过CreateAIModel注册的用户自定义 GroupName(必须以custom-开头,例如custom-kimi、custom-openai-compat)。绝不要猜着使用createModel("deepseek")/createModel("kimi")/createModel("custom")。- 不要编造 SDK 方法名或参数。 此 SKILL.md 是
@cloudbase/js-sdkAI 接口的权威参考——编写代码前,请在此处(或下方的类型定义部分)查找方法签名。如果此处未记录某个方法或字段,请停下来询问,或通过 MCP 工具检查实时契约。不要猜测。 - 启用新的托管模型前,先展示价格 —
DescribeManagedAIModelList会返回ModelSpec(上下文长度、最大输入/输出 Token 数)和ModelChargingInfo(输入/输出/缓存价格、计费单位)。调用UpdateAIModel前,先向用户展示价格。 - 长响应使用流式传输 — 可提升用户感知到的响应速度和交互性。
- 妥善处理错误 — 使用 try/catch 包装 AI 调用。
- 妥善保管
accessKey— 使用可发布密钥,绝不要使用秘密密钥。 - 尽早初始化 — 在应用入口处设置 SDK,以便路由前就绪认证和 AI 功能。
- AI 功能不要使用匿名认证 — 新环境默认禁用匿名登录,且匿名用户没有 AI 模型权限。调用任何 AI API 前,必须先通过已验证的方式登录(手机号、电子邮件、用户名和密码、微信、自定义方式)。将提供商配置交给
auth-tool-cloudbaseskill,将浏览器登录流程交给auth-web-cloudbaseskill;AI-model skill 会检查auth.getSession()并验证loginType,再决定是否允许调用。 - 区分“预检失败”和“模型调用失败” — 前者表示用户需要购买资源包或调用
UpdateAIModel;后者则是提示词/参数/网络问题。针对两种情况向用户提供不同的指引。 - TypeScript:不要使用
any来掩盖 SDK 的类型错误。 SDK 自带类型;如果出现错误,请用unknown配合类型保护进行缩窄,为实际使用的结构编写精确的interface,或在本地.d.ts中扩展类型。绝不要使用: any、as any、@ts-ignore或@ts-nocheck。请参阅web-developmentskill 中的 Engineering constitution。 - 声称完成前先自行验证。 运行
tsc --noEmit和项目构建,通过agent-browser打开页面并实际触发 AI 调用。确认:(a) 文本流到达 UI;(b) 控制台没有新增错误;(c)result.usage非零。没有证据就说“应该可以运行”是不可接受的——请遵循web-development/browser-testing.md。