extension-inference
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCaffeine Inference
Caffeine Inference
LLM extension for Caffeine AI.
面向Caffeine AI的LLM扩展。
Orchestrator routing notes
编排器路由说明
Treat “use an LLM / GPT / chatbot / summarise with AI” as a first-class
platform feature. The default path is Caffeine Inference: an
OpenAI-compatible chat endpoint that Caffeine hosts, authenticates, and bills
for the app. The canister gets its credentials from the platform at runtime;
nobody pastes an API key, and the app never stores or returns one.
| User intent | Capability |
|---|---|
| Chat / summarise / classify with an LLM in a Caffeine app | |
Call | |
Do not load for a normal Caffeine-app LLM. Do not
ask the user for an OpenAI API key. Do not add endpoints, a
key-settings page, or a model picker.
extension-openaisetApiKey将“使用LLM/GPT/聊天机器人/AI总结”视为一等平台功能。默认路径为Caffeine Inference:这是一个由Caffeine托管、认证并为应用计费的兼容OpenAI的聊天端点。Canister在运行时从平台获取凭证;无需任何人粘贴API密钥,应用也绝不会存储或返回密钥。
| 用户意图 | 实现方式 |
|---|---|
| 在Caffeine应用中使用LLM进行聊天/总结/分类 | 通过本技能使用 |
使用用户粘贴的 | 仅使用 |
请勿为常规Caffeine应用的LLM加载。请勿向用户索要OpenAI API密钥。请勿添加端点、密钥设置页面或模型选择器。
extension-openaisetApiKeyBackend
后端
1. Add caffeineai-inference-client
to mops.toml
caffeineai-inference-clientmops.toml1. 在mops.toml
中添加caffeineai-inference-client
mops.tomlcaffeineai-inference-clientbash
mops add caffeineai-inference-client@0.1.0Requires Mops ≥ 2.13. Minimum version: .
caffeineai-inference-client ≥ 0.1.0bash
mops add caffeineai-inference-client@0.1.0要求Mops版本≥2.13。最低版本要求:。
caffeineai-inference-client ≥ 0.1.02. Config comes from the platform
2. 配置来自平台
Config.fromEnv<system>()Configis_replicated = ?false- Call inside the
fromEnv<system>()method, or in ashared-parameterised helper, on every request. A module-level<system>will not compile, and a cachedlet config = fromEnvcan go stale when the platform rotates credentials on a running canister.Config - It traps when the app has no inference credentials. That is a platform condition, not something the app can fix — do not add a "configure AI" empty state or a key-input fallback for it.
- Never log the , never copy its
Configinto actor state, and never return it (or any part of it) from aauth/queryfunction.shared
Config.fromEnv<system>()Configis_replicated = ?false- 请在方法内部,或带有
shared参数的辅助函数中,每次请求时调用<system>。模块级别的fromEnv<system>()无法编译,且缓存的let config = fromEnv可能会在平台为运行中的canister轮换凭证时失效。Config - 当应用没有推理凭证时会触发trap。这是平台层面的问题,应用无法修复——请勿添加“配置AI”的空状态或密钥输入回退方案。
- 绝不要记录,绝不要将其
Config字段复制到actor状态中,绝不要从auth/query函数返回它(或其任何部分)。shared
3. is_replicated = ?false
is REQUIRED
is_replicated = ?false3. 必须设置is_replicated = ?false
is_replicated = ?falsefromEnv?truenull- Security. A replicated outcall sends the bearer from every replica.
- Billing. Replicated outcalls multiply inference spend by subnet size.
- Determinism. LLM bodies are sampled; consensus would fail.
fromEnv?truenull- 安全性:复制式出站调用会从每个副本发送Bearer令牌。
- 计费:复制式出站调用会将推理费用乘以子网大小。
- 确定性:LLM输出是采样生成的;共识会失败。
4. Canonical layout
4. 标准代码结构
motoko
import Inference "lib/inference";
actor {
public shared func chat(prompt : Text) : async Text {
await* Inference.runChat<system>(prompt);
};
};motoko
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");
};
};motoko
import Inference "lib/inference";
actor {
public shared func chat(prompt : Text) : async Text {
await* Inference.runChat<system>(prompt);
};
};motoko
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"
— the platform picks the model
model = "router"5. model = "router"
——由平台选择模型
model = "router""router""router"model- Always send .
model = "router" - Do not add a model dropdown, a "use GPT-4" toggle, or a parameter on the backend endpoint. There is nothing for the user to choose.
model - Steer quality with the prompt and with the declared sampling fields
(,
temperature,top_p), not with model selection.max_completion_tokens
"router""router"model- 请始终发送。
model = "router" - 请勿添加模型下拉菜单、“使用GPT-4”切换按钮或后端端点的参数。用户无需进行任何选择。
model - 通过提示词和声明的采样字段(、
temperature、top_p)来控制输出质量,而非通过选择模型。max_completion_tokens
6. Call shapes
6. 调用形式
- Function form: — use
ChatApi.createChatCompletion(config, req) : async*.await* - Suite form: .
let api = ChatApi(config); api.createChatCompletion(req) : async
- 函数形式:—— 使用
ChatApi.createChatCompletion(config, req) : async*。await* - 套件形式:。
let api = ChatApi(config); api.createChatCompletion(req) : async
7. Available API surface — chat completions
7. 可用API范围——聊天补全
caffeineai-inference-client@0.1.0public-api-v0.1.0| Module | Entry point | Route |
|---|---|---|
| | |
| | |
motoko
import ChatApi "mo:caffeineai-inference-client/Apis/ChatApi";
import { fromEnv } "mo:caffeineai-inference-client/Config";Chat completions are the whole product surface. Not available on this host
(404, and not in the package): embeddings, images, audio, moderations, files,
legacy completions, Assistants, Responses, and raw . If the
spec genuinely needs an OpenAI-only API with a pasted , switch to
.
ic.http_requestsk-...extension-openaicaffeineai-inference-client@0.1.0public-api-v0.1.0| 模块 | 入口点 | 路由 |
|---|---|---|
| | |
| | |
motoko
import ChatApi "mo:caffeineai-inference-client/Apis/ChatApi";
import { fromEnv } "mo:caffeineai-inference-client/Config";聊天补全是全部的产品功能范围。在此主机上不可用的功能(会返回404,且未包含在包中):嵌入、图像、音频、内容审核、文件、旧版补全、Assistants、Responses以及原生。如果需求文档确实需要使用粘贴的密钥调用OpenAI专属API,请切换至。
ic.http_requestsk-...extension-openai8. Cycles
8. Cycles设置
defaultConfig.cycles = 30_000_000_000motoko
{ fromEnv<system>() with cycles = 100_000_000_000 }Streaming () is unsupported — management-canister HTTP returns
the full body. Leave .
stream = ?truestream = nulldefaultConfig.cycles = 30_000_000_000motoko
{ fromEnv<system>() with cycles = 100_000_000_000 }流式传输()不受支持——管理canister的HTTP请求会返回完整响应体。请保持。
stream = ?truestream = null9. Things that will bite you
9. 需要注意的陷阱
- Call inside the
fromEnv<system>()method (or asharedhelper). A module-level<system>will not compile.let config = fromEnv - — not
model = "router". See §5."gpt-4o-mini" - User turns are .
#user(ChatCompletionRequestMessageOneOf2.JSON.init({ content = #string(prompt); role = #user })) - for required fields; layer optionals with record update. Do not hand-list every
JSON.init.null - is
resp.choices[0].message.content. Check?Textfirst.choices.size() - One chat call is one HTTP outcall inside an update call: budget seconds, not milliseconds.
- 在方法(或
shared辅助函数)内部调用<system>。模块级别的fromEnv<system>()无法编译。let config = fromEnv - ——而非
model = "router"。请参见第5节。"gpt-4o-mini" - 用户消息的格式为。
#user(ChatCompletionRequestMessageOneOf2.JSON.init({ content = #string(prompt); role = #user })) - 必填字段使用;通过记录更新来处理可选字段。请勿手动列出每个
JSON.init。null - 的类型是
resp.choices[0].message.content。请先检查?Text。choices.size() - 一次聊天调用对应更新调用中的一次HTTP出站调用:预算以秒为单位,而非毫秒。
Frontend
前端
The app is ready to chat on first load — there is nothing to configure.
- No API-key UI. No settings page, no password input, no "configured?" indicator, no localStorage. If a spec or mock shows an "AI settings" screen, drop it.
- No model picker. See §5.
- Call the backend chat endpoint () and render the returned text. There is no frontend LLM SDK — the canister is the client, so the credentials never reach the browser.
chat(prompt) - Show a pending state while the call is in flight (an outcall round-trip takes seconds) and surface a retry on trap.
应用在首次加载时即可使用聊天功能——无需任何配置。
- 无API密钥UI:无设置页面、无密码输入框、无“已配置?”指示器、无本地存储。如果需求文档或原型包含“AI设置”界面,请移除它。
- 无模型选择器:请参见第5节。
- 调用后端聊天端点()并渲染返回的文本。没有前端LLM SDK——canister作为客户端,因此凭证永远不会到达浏览器。
chat(prompt) - 在调用过程中显示加载状态(出站调用往返需要数秒),并在触发trap时提供重试选项。