mcpField
E
extension-inference

extension-inference

github.com/caffeinelabs开发212.4k 次安装1 周前更新
代码仓库

关于 extension-inference

为 Caffeine AI 应用构建 LLM 聊天功能的技能,使用平台托管且兼容 OpenAI 的 Caffeine Inference 服务。它指导应用通过 canister 发起请求,使凭据留在后端,并免去用户管理 API 密钥或选择模型。

主要功能

  1. 01兼容 OpenAI 的聊天补全
  2. 02运行时提供凭据
  3. 03通过 canister 发起推理请求
  4. 04由 router 选择模型
  5. 05前端错误提示与重试

适用场景

  1. 01为 Caffeine AI 应用添加聊天
  2. 02使用 LLM 总结或分类文本
  3. 03避免在浏览器代码中暴露推理凭据

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/caffeinelabs/skills --skill extension-inference

安装后在 Claude Code 中输入/extension-inference确认已加载。

详细介绍

Caffeine Inference

面向 Caffeine AI 的 LLM 扩展。

编排器路由说明

将“使用 LLM / GPT / 聊天机器人 / 使用 AI 总结”视为平台的一项一等功能。默认路径是 Caffeine Inference:由 Caffeine 为应用托管、验证身份并计费的 OpenAI 兼容聊天端点。Canister 在运行时从平台获取凭据;无需粘贴 API 密钥,应用也不会存储或返回密钥。

用户意图功能
在 Caffeine 应用中使用 LLM 聊天 / 总结 / 分类通过此技能使用 caffeineai-inference-client ChatApi.createChatCompletion
使用用户粘贴的 sk-... 调用 api.openai.com仅使用 extension-openai

对于常规的 Caffeine 应用 LLM,不要加载 extension-openai。不要向用户索要 OpenAI API 密钥。不要添加 setApiKey 端点、密钥设置页面或模型选择器。

后端

1. 将 caffeineai-inference-client 添加到 mops.toml

mops add [email protected]

需要 Mops ≥ 2.13。最低版本: caffeineai-inference-client ≥ 0.2.0。

2. 配置来自平台

Config.fromEnv<system>() 会根据平台为应用提供的凭据,返回完整的 Config——包括端点、Bearer 和 is_replicated = ?false。无需收集密钥,也无需进行任何配置。

  • 在每次请求时,都要在 shared 方法内部调用 fromEnv<system>(),或在以 <system> 为参数的辅助函数中调用。模块级的 let config = fromEnv 无法编译;平台在运行中的 canister 上轮换凭据时,缓存的 Config 也可能过期。
  • 应用没有推理凭据时会触发陷阱。让错误传递给调用方;隐藏错误会让失败的 AI 调用看起来像是功能正常:
    • 切勿预先检查 CAFFEINE_INFERENCE_API_KEY(或任何其他环境变量),也不要通过检查来保护 fromEnv,从而跳过调用。
    • 切勿将失败的调用转换为空成功,例如返回空字符串、空列表或占位文本。触发陷阱或返回错误,以便前端显示错误并提供重试选项。
    • 不要添加“配置 AI”的空状态或密钥输入备用方案。
  • 切勿记录 Config,切勿将其 auth 复制到 actor 状态中,也切勿从 query / shared 函数返回它(或其中任何部分)。

3. is_replicated = ?false 为必填项

fromEnv 已设置此值。不要将其覆盖为 ?true 或 null。

  1. 安全性。 复制式外调会从每个副本发送 bearer。
  2. 计费。 复制式外调会使推理费用随子网大小成倍增加。
  3. 确定性。 LLM 响应体通过采样生成;共识会失败。

4. 标准布局

import Inference "lib/inference";

actor {
  public shared func chat(prompt : Text) : async Text {
    await* Inference.runChat<system>(prompt);
  };
};
import { fromEnv } "mo:caffeineai-inference-client/Config";
import ChatApi "mo:caffeineai-inference-client/Apis/ChatApi";
import ChatCompletionRequest "mo:caffeineai-inference-client/Models/ChatCompletionRequest";
import ChatCompletionRequestMessageOneOf2 "mo:caffeineai-inference-client/Models/ChatCompletionRequestMessageOneOf2";
import Runtime "mo:core/Runtime";

module {
  public func runChat<system>(prompt : Text) : async* Text {
    let config = fromEnv<system>();
    let userMessage = ChatCompletionRequestMessageOneOf2.JSON.init({
      content = #string(prompt);
      role = #user;
    });
    let req = ChatCompletionRequest.JSON.init({
      messages = [#user(userMessage)];
      model = "router";
    });
    let resp = await* ChatApi.createChatCompletion(config, req);
    if (resp.choices.size() == 0) {
      Runtime.trap("Inference returned no choices");
    };
    resp.choices[0].message.content
      ?? Runtime.trap("Inference returned no text content");
  };
};

5. model = "router"——由平台选择模型

"router" 是唯一公开的模型 ID,它是路由层级,而非模型名称。Caffeine Inference 会根据查询的复杂程度,为每个请求选择合适的模型——简单提示词使用小型快速模型,复杂推理使用更强大的模型——并在响应的 model 中返回 "router",因此提供商名称不会传到应用。

  • 始终发送 model = "router"。
  • 不要添加模型下拉菜单、“使用 GPT-4”开关或后端端点上的 model 参数。没有可供用户选择的内容。
  • 通过提示词和声明的采样字段(temperature、top_p、max_completion_tokens)调整质量,而不是选择模型。

6. 调用形式

  • 函数形式: ChatApi.createChatCompletion(config, req) : async*——使用 await*。
  • 套件形式: let api = ChatApi(config); api.createChatCompletion(req) : async。

7. 可用的 API 范围 — 聊天补全

[email protected] 由 public-api-v0.1.0 生成:

模块入口点路由
ChatApicreateChatCompletionPOST /v1/chat/completions
ModelsApilistModelsGET /v1/models — 仅用于目录;模型始终为 "router",因此应用无需调用此接口
import ChatApi "mo:caffeineai-inference-client/Apis/ChatApi";
import { fromEnv } "mo:caffeineai-inference-client/Config";

聊天补全就是全部产品功能。此主机不提供以下功能(返回 404,且不在程序包中):embeddings、images、audio、moderations、files、legacy completions、Assistants、Responses,以及原始的 ic.http_request。如果需求确实需要带有粘贴的 sk-... 的 OpenAI 专属 API,请切换到 extension-openai。

8. Cycles

将 cycles 留空(null):每次调用都会附加 IC 针对该请求收取的费用;在免费执行外呼的子网上,费用为零。?n 会附加恰好 n 个 cycles:如果 n 低于费用,IC 会拒绝该调用;如果 canister 持有的 cycles 少于 n,调用会陷阱终止。

不支持流式传输(stream = ?true)——管理 canister 的 HTTP 会返回完整正文。将 stream 留空(null)。

9. 可能导致问题的事项

  • 在 shared 方法(或 <system> 助手函数)内调用 fromEnv<system>()。模块级的 let config = fromEnv 无法编译。
  • 显示失败。不要预先检查凭据,不要在 fromEnv 外加保护,也不要用空结果替代错误。参见 §2。
  • model = "router",而不是 "gpt-4o-mini"。参见 §5。
  • 用户轮次应写为 #user(ChatCompletionRequestMessageOneOf2.JSON.init({ content = #string(prompt); role = #user }))。
  • 必填字段使用 JSON.init;可选字段通过记录更新添加。不要手动逐一列出所有 null。
  • resp.choices[0].message.content 的类型为 ?Text。先检查 choices.size()。
  • 一次聊天调用就是更新调用中的一次 HTTP 外呼:预算应以秒计,而不是毫秒。

前端

应用首次加载即可聊天,无需进行任何配置。

  1. 不要提供 API 密钥界面。 不要添加设置页面、密码输入框、“是否已配置?”指示器或 localStorage。如果规格说明或 mock 显示“AI 设置”屏幕,请将其移除。
  2. 不要提供模型选择器。 参见 §5。
  3. 调用后端聊天端点(chat(prompt))并显示返回的文本。前端没有大模型 SDK——canister 就是客户端,因此凭据不会传到浏览器。
  4. 调用进行期间显示等待状态(一次外呼往返需要数秒),发生陷阱时显示重试选项。

评论

支持 Markdown