LFModel
全局变量:LFModel · 启用方式:// @require model
调用PluginX AI 网关。所有调用固定归属当前应用(计入其预算),经扩展后台携带PluginX登录态,不能指定其它应用身份。
本地开发中的项目
还没有上架的本地项目不设预算,消耗合并计入账号的「本地开发」:getBudget() 返回不限额,getUsage() 返回所有本地项目的合计,getBudgetUrl() 打开积分详情页。上架为应用后才按应用单独计算预算与消耗。
方法
LFModel.listModels({ force?, page?, pageSize?, q?, ids? }?): Promise<{ models, page, pageSize, total, count, hasMore, ... }>列出当前账号可用的模型
LFModel.getModel(modelId): Promise<ModelDescriptor>读取单个模型的描述信息
LFModel.chat(payload): Promise<ChatCompletionsResponse>对话补全(非流式),OpenAI 风格 payload
LFModel.chatStream(payload): AsyncIterable<StreamChunk>流式对话,异步迭代 { kind: "delta", data } 分片
LFModel.image(payload): Promise<ImageGenerationsResponse>图片生成
LFModel.getBalance(): Promise<BalanceInfo>查询账户余额
LFModel.getBudget(): Promise<BudgetInfo>查询当前应用的预算配置
LFModel.getSpendable(): Promise<SpendableInfo>一次拿到可消费积分快照:min(账户余额, 应用预算剩余) + 余额不足/预算耗尽判定
LFModel.getUsage(options?): Promise<UsageInfo>查询用量统计(range: 1d / 7d / 30d / all)
LFModel.getPlansUrl(): Promise<string>官网订阅套餐页深链(本期积分用完时引导用户订阅或升级)
LFModel.getBudgetUrl(): Promise<string>官网本应用预算面板深链(预算耗尽时引导用户提额)
参数详解
chat(payload) / chatStream(payload)
payload 是 OpenAI Chat Completions 风格的请求体,未知字段透传给上游;app_scope 由后台强制注入为当前应用,自己传的会被剥离:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
model | string | 是 | 模型 id,取自 listModels() 返回的 models[].id |
messages | ChatMessage[] | 是 | 每条 { role: 'system' / 'user' / 'assistant' / 'tool', content };多模态 content 支持 [{ type: 'text', text }, { type: 'image_url', image_url: { url } }] |
tools / tool_choice | OpenAITool[] / 'auto' 等 | 否 | 函数调用声明与选择策略,原样转发 |
temperature / top_p / max_tokens | number | 否 | 采样与长度控制,原样转发;上游模型明确拒收某个采样参数时(如部分新版 Claude 只接受默认 temperature),网关会去掉该参数自动重发。思考型模型会把一部分 max_tokens 花在推理上,请留足余量,否则正文可能被 finish_reason: 'length' 截断 |
reasoning_effort | 'low' / 'medium' / 'high' / 'xhigh' | 否 | 统一的思考强度档位(也接受 camelCase reasoningEffort;另接受 max,none / minimal 按 low 处理,其它值静默忽略)。对所有模型都用这一组值,不要传厂商私有参数(thinking、enable_thinking、thinking_budget 等,thinking / reasoning 字段会被网关剔除)。网关按上游协议映射:OpenAI 兼容上游透传 low/medium/high,xhigh / max 收敛为 high;GLM 映射为 low/high/max(medium→high、xhigh→max);Anthropic 新模型(Claude 5 系列、Opus 4.5+、Sonnet 4.6+)透传为 effort(支持全部五档,带 tools 同样生效,并去掉 temperature / top_p / top_k);老模型换算为 thinking 预算,请求带 tools 或 max_tokens 放不下 1024 的最低思考预算时不开启 thinking,开启时会去掉 temperature;Gemini 换算为 thinkingBudget。不支持推理的模型会剔除该字段。不传则用上游默认档 |
response_format | { type, json_schema? } | 否 | type 为 'text' / 'json_object' / 'json_schema';json_schema 时需附 { name, schema, strict? } |
stop / n / seed / frequency_penalty / presence_penalty | — | 否 | 原样转发(多数上游 n 上限为 1) |
stream | boolean | 否 | chat() 强制为 false;要流式请用 chatStream() |
chat() 返回标准 OpenAI 响应:choices[0].message.content 是文本(模型走工具调用时可能为 null),message.tool_calls[] 每项 { id, type: 'function', function: { name, arguments } }(arguments 是 JSON 字符串),思考型模型附 message.reasoning_content。计费规范字段是 usage.cost_points、usage.cost_unit === 'points' 与 lingfeng_billing.charge_points(1 CNY = 200 points);旧 CNY/cents 字段仅 deprecated compatibility,无币种 charge_cents 可能是 USD,不能当 CNY 积分。
chatStream() 返回异步迭代器,每个元素二选一:{ kind: 'delta', data }(data 是已解析的 OpenAI 流式 chunk 对象而不是字符串,增量文本在 data.choices[0].delta.content,可能为空;可含 usage.cost_points)或 { kind: 'billing', billing }(最后一条计费事件,规范字段 billing.charge_points)。break 跳出循环会自动中止上游请求。出错时由 for await 循环抛出 LFModelError(见下方错误类型)。
image(payload)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
model | string | 是 | 图片模型 id(kind === 'image') |
prompt | string | 是 | 文本提示词 |
size | string | 否 | 如 '1024x1024',须在 model.supported_sizes 内 |
response_format | 'url' / 'b64_json' | 否 | 须在 model.capabilities.supported_response_formats 内 |
n / quality / style / image / mode | — | 否 | 生成数量(部分上游会拼成一张网格图,要 K 张独立图请分次调用)/ 质量 / 风格 / 图生图参考图 / 生成模式 |
返回 { created, data: [{ url?, b64_json?, revised_prompt? }], usage?, lingfeng_billing };图片同样以 usage.cost_points / lingfeng_billing.charge_points 为规范计费字段。
listModels 分页与筛选 / 其它查询方法返回结构
listModels() 的模型目录与 IDE agent 窗口的模型选择器同源:优先取服务端运营配置的精选目录(可见范围与顺序都由服务端决定,对话模型排在最前),运营未配置时回落到全量目录并按 page / pageSize 分页。所以你在 agent 模型选择器里看到的模型,就是应用能查到的模型——不要硬编码模型 id。注意精选目录约束的是发现:chat() / image() 直接打推理端点,传入精选之外的 id 是否可用由服务端网关决定。
| 方法 | 关键返回字段 |
|---|---|
listModels({ force?, page?, pageSize?, q?, ids? }) | page 默认 1,pageSize 默认 40;q 搜索,ids 精确筛选 id。返回 models[]、page、pageSize、total、count、hasMore;每个查询/分页独立内存缓存,同查询并发请求自动合并,force: true 强制刷新该项。另含定价参数 priceWindowK / priceMarkupRatio。模型字段包括 id、name / display_name、context_length、kind('chat' / 'image')、capabilities、pricing_cny_per_1m、isFree。不支持按 kind 过滤,对话与图片模型混在同一列表里,请自行 models.filter((m) => m.kind === 'chat') |
getModel(modelId) | 按 id 读取单个模型(与 listModels 共用缓存),找不到时抛 MODEL_NOT_FOUND。未配置精选目录时用精确 ids 查询,不拉取整页目录;配置了精选目录时在精选列表里查找,所以只能查到精选内的模型——精选之外的 id 即使 chat() 能用,getModel() 也会抛 MODEL_NOT_FOUND |
getBalance() | balance_points(规范余额积分);balance_cents / balance_micro 等旧字段仅 deprecated compatibility。钱包是用户级的,与应用无关 |
getBudget() | 规范字段 budget_points(null=不限)、spent_points、remaining_points;旧 budget_cents / spent_cents / spent_micro / remaining_cents 仅 deprecated compatibility;固定查询当前应用 |
getSpendable() | 规范字段:spendable_points(min(账户余额, 应用预算剩余))、balance_points,预算有限时还有 budget_remaining_points;另含 exhausted / exhausted_reason / limiting_factor。spendable_cents / spendable_micro 仅 deprecated compatibility |
getUsage({ range? }) | range 取 '1d' / '7d'(默认)/ '30d' / 'all';total.charge_points 与 by_model[].charge_points 是规范积分聚合,旧 charge_cents / charge_micro 仅 deprecated compatibility |
getPlansUrl / getBudgetUrl 支付引导深链
两个方法都返回官网深链字符串(由扩展后台按当前环境域名拼出,请勿硬编码 URL):getPlansUrl() 打开官网订阅套餐页,适合 INSUFFICIENT_BALANCE(本期积分用完)时引导用户订阅或升级——积分每 31 天随套餐重置,按需购买已下线;getBudgetUrl() 打开 AI 面板并自动弹出当前应用的预算面板,适合 APP_BUDGET_EXHAUSTED(账户还有积分、但本应用预算用完)时引导用户提高预算。在你的应用 UI 里渲染成可点击的链接或 window.open(url, '_blank') 按钮即可。
错误类型
所有方法失败抛 LFModelError(可用 instanceof LFModel.LFModelError 判断):status(HTTP 状态码)、errorCode(稳定枚举:INSUFFICIENT_BALANCE 本期积分用完、APP_BUDGET_EXHAUSTED 应用预算耗尽、MODEL_REQUIRES_PAID_PLAN 模型仅限订阅用户、MODEL_NOT_FOUND、NO_AVAILABLE_PROVIDER、UPSTREAM_ERROR 等)、payload(上游原始错误体)。按 errorCode 分支处理,不要解析 message 文本;INSUFFICIENT_BALANCE 配合 getPlansUrl()、APP_BUDGET_EXHAUSTED 配合 getBudgetUrl() 给出一键跳转;MODEL_REQUIRES_PAID_PLAN 表示该模型仅限订阅用户,同样引导到 getPlansUrl() 或换用未加锁模型。
几个例外:
chatStream()的错误只带errorCode,status恒为 0、payload为 null;请只按errorCode分支。- 网络故障、扩展通信中断等没有到达网关的失败,
errorCode为空字符串、status为 0。后台连接在没有错误信息的情况下断开时,chatStream()的迭代会像正常结束一样停止,需要确认完整性时可检查是否收到了billing元素。 - 运行环境没有消息通道(既未启用 USER_SCRIPT messaging,也不在终端 run 中)时抛普通
Error。
示例
// @require model
const { models } = await LFModel.listModels();
// 列表里同时有对话模型和图片模型,按 kind 挑选
const chatModel = models.find((m) => m.kind === "chat");
// 调用前检查可消费积分(= min(账户余额, 应用预算剩余)),并区分是哪一侧不够
const spendable = await LFModel.getSpendable();
if (spendable.exhausted) {
const url = spendable.exhausted_reason === "APP_BUDGET_EXHAUSTED"
? await LFModel.getBudgetUrl() // 预算用完 → 引导去官网提高本应用预算
: await LFModel.getPlansUrl(); // 本期积分用完 → 引导去订阅/升级套餐
window.open(url, "_blank");
} else {
console.log(`当前可消费 ${spendable.spendable_points} 积分`);
}
// 非流式
const reply = await LFModel.chat({
model: chatModel.id,
messages: [{ role: "user", content: "你好" }],
});
console.log(reply.choices[0].message.content);
// 流式:delta 的 data 是 OpenAI chunk 对象,文本在 choices[0].delta.content
let text = "";
for await (const chunk of LFModel.chatStream({
model: chatModel.id,
messages: [{ role: "user", content: "讲个笑话" }],
})) {
if (chunk.kind === "delta") text += chunk.data.choices?.[0]?.delta?.content ?? "";
}
console.log(text);