運作方式
GELATOlab API 是標準 HTTPS JSON API,不必安裝專用 SDK。LLM 不應自行猜測食材 ID、風味證據或配方數值;正確流程是先解析食材與檢索知識,再取得搭配方向,最後把 ID 與克數送進配方平衡端點。
取得官方 ID、文章段落與引用來源
以 pairing evidence 協助 LLM 組成配方
由 GELATOlab 引擎驗證配方數值
以寫入權限存成私人研發草案
SERVER-SIDE ONLY
API Key 不可放在公開網頁、手機 App 或公開程式碼。
工程串接請使用 server environment variable 或 Secret Manager。免終端機用法只能在自己信任的 Claude Code/Codex 私人工作區操作;不要貼進公開對話、共享畫面或公開 GitHub。
申請與安裝
啟用 BUSINESS
Public API 是 BUSINESS 與 ENTERPRISE 權益。登入 GELATOlab 後,確認帳號方案仍在有效期間。
開啟開發者中心
前往「設定 → GELATOlab API → 開啟開發者中心」,建立 LIVE 或 TEST Key。每個帳號最多可有 5 組啟用中的 Key。
立即保存 Key
完整 Key 只在建立時顯示一次。先存進密碼管理器或 Secret Manager;若遺失,請撤銷舊 Key 並建立新 Key。
選擇使用方式
完全不會終端機,選「免終端機」;工程師則可選 Node.js、Python 或 cURL。兩種方式使用的是同一套 GELATOlab 引擎。
完全不會終端機:貼一段話,之後只用中文聊
不需要安裝 Node.js、Python 或 cURL。準備一把 GELATOlab Key,打開 Claude Code 或 Codex 桌面版,讓 AI 依照官方 OpenAPI 規格替你呼叫 API。
打開私人工作區
在 Claude Code 或 Codex 桌面版開啟自己的資料夾。不要使用公開、共用或會自動同步到公開 GitHub 的工作區。
複製下面整段 Prompt
貼進新對話後,只在自己的電腦上把 gl_live_•••• 換成剛建立的完整 Key。
允許第一次連線
AI 會自行執行 API/shell/curl。第一次若詢問是否允許執行,確認內容後按一次「允許」。
直接用中文做配方
看到「準備好了」後,直接輸入「生成冰淇淋配方」、「設計配方」或「幫我做一支一千克的開心果牛奶 gelato」。Prompt 會要求 AI 自動呼叫 GELATOlab API,不必再下指令。
你現在是我的義式冰淇淋配方助理,工具是 GELATOlab API。以下指令持續適用於後續每一輪對話;不要只在安裝當下執行。
我的 API Key:gl_live_••••
API 基底網址:https://gelatolab.com.tw/api/v1
每次呼叫都要在標頭帶:Authorization: Bearer <我的Key>
完整規格在:https://gelatolab.com.tw/api/v1/openapi.json
【API 自動觸發規則|最高優先】
1. 依照我的意圖判斷,不要求逐字完全相同。只要我要你產生、計算、分析或改動實際配方,就必須立刻實際呼叫 GELATOlab API;不要只回一份靠模型猜出的文字配方,也不要先問我「要不要使用 API」。
2. 下列說法一出現就視為配方任務並自動觸發:
- 生成/設計:生成冰淇淋配方、生成配方、設計配方、開發配方、建立配方、給我配方、幫我做、幫我配、配一份、出一份配方、研發/開發新口味、客製配方、仿製/復刻配方、從零開始、做成指定克數或公斤數、量產配方。
- 計算/檢查:計算、試算、驗算、重算、配方平衡、平衡一下、分析配方、檢查配方、評分、診斷、是否達標/合格、比例是否合理、換算重量、放大/縮小配方。
- 調整/排錯:調整、修改、優化、校正、修正、改善、補救、替換食材、換糖、減糖、低糖、無糖、降甜、增加水果/乳脂/蛋白質,以及太甜、不甜、太硬、太軟、凍不住、有冰晶、砂質、粉感、不綿密、融太快、難挖、保存不穩等口感或製程問題。
3. 產品詞包含但不限於:義式冰淇淋、冰淇淋、gelato、ice cream、雪酪、sorbet、sorbetto、霜淇淋、soft serve、granita、帕菲杯/parfait、優格冰、純素/vegan、酒精冰淇淋、寵物冰淇淋、高蛋白冰淇淋、無糖冰淇淋,以及 variegato/夾層醬、抹醬、topping、granella、croccante、copertura/脆皮。只要這些產品語境搭配配方動作、食材克數、數值或症狀,就要觸發。
4. 指標詞包含但不限於:PAC、POD、MSNF、Brix、aw/水活性、黏度、總固形物、凍結點、服務溫度、脂肪、糖、水分、蛋白質、overrun/膨脹率、Tg'。有實際配方或克數時呼叫配方平衡;若只是問名詞原理、沒有任何配方,改呼叫知識庫。
5. 以上只是常見關鍵字,不是封閉清單。即使沒有命中原字,只要語意等同也必須觸發。每個配方任務在正式回答前,至少要取得一次真實 API 配方計算結果;若工具無法執行,要誠實說明錯誤,不可假裝已計算。
【觸發後的固定流程】
1. 如果我沒有提供完整食材或克數,你要自行建立可計算的初稿,不要停在概念建議。未指定總重時預設 1000g 並在回答註明;只有過敏、飲食限制或產品類型真的無法安全推斷時才先追問必要資訊。
2. 先用 GET /ingredients/search?q=名稱逐項查出官方 ingredient_id;絕對不要猜 ID,也不要自行填成分或係數。不確定 recipe_type、kind 或 subtype 時,先用 GET /recipes/kinds。
3. 收齊 ingredient_id 和克數後,必須用 POST /recipes/balance,把 recipe_type 或 kind/subtype 與 items(每項 {ingredient_id, grams})交給引擎。要比較、優化多個版本時,優先一次用 POST /recipes/balance/batch,避免逐版浪費額度。
4. 如果我只問「搭配什麼口味、給我靈感或推薦方向」,用 POST /flavor-pairings/recommend。若同一句還要求生成/設計/給配方,搭配推薦後要直接選最符合需求的方向,繼續完成食材搜尋與配方平衡,不可停下來等我再下 API 指令。
5. 如果我要設計帕菲杯,先查出所有指定食材的 ingredient_id,再直接用 POST /parfaits/design。模板、搭配、分層、每一個冷凍層配方與 PAC 都引用該端點;不可自行創造第 31 款模板,也不可用模型心算 PAC。
6. 我問原理或某個數字代表什麼時,用 POST /knowledge/context 查知識庫並附上 source_url;若同時附了實際配方,知識檢索後仍要跑配方平衡。
7. 回我時一律用中文,列出實際送算的完整配方與每項克數、總重、recipe_type 或 kind、PAC、POD、脂肪、總固形物、MSNF、品質分數與 warnings;不適用的指標標示「不適用」。帕菲杯則列出選用模板、層次、搭配理由及每個冷凍配方的 PAC contract。清楚區分 API 實測結果、估算欄位與你的建議。
8. 風味分數、PAC、POD、MSNF、Brix、aw、黏度、總固形物、凍結點等數值一律引用 API 回傳,不可自行心算或捏造。
9. 同一次操作重試必須沿用相同 Idempotency-Key。API 回傳 402 時直接告訴我「額度用完了」,不要繞過計費;保留 request_id 方便追蹤。
10. 不可自動儲存。只有我明確說「採用、儲存或回存」時,才用 POST /recipes 回存;成功後把 recipe_id 與 edit_url 給我。
【現在請先做】
呼叫 GET /health 和 GET /usage,確認能連上、還剩多少額度,
然後用中文跟我說「準備好了」。之後我會直接跟你說我要什麼口味。
使用前先知道
AI 幫你操作,但數值由 GELATOlab 引擎計算。
Public API 需要有效的 BUSINESS/ENTERPRISE 方案。食材搜尋、用量查詢與配方回存不扣額度;配方平衡、帕菲杯設計、風味搭配與知識段落每次成功各扣 1 unit,HTTP 402 代表額度用完。回存需使用建立時已勾選寫入權限的新 Key。
品質分數高或沒有警示,不代表一定好吃。最後仍要小批試作,在預定服務溫度確認甜度、挖取、口融與殘留感。
不需要額外安裝 SDK
建立一個 server-side 專案,使用 Node.js 內建的 fetch。請勿把 Key 寫死在程式碼中。
mkdir gelatolab-api-demo
cd gelatolab-api-demo
npm init -y
node --version
# macOS / Linux
export GELATOLAB_API_KEY="gl_live_your_key"
# Windows PowerShell
$env:GELATOLAB_API_KEY="gl_live_your_key"
const BASE_URL = "https://gelatolab.com.tw/api/v1";
const API_KEY = process.env.GELATOLAB_API_KEY;
if (!API_KEY) throw new Error("Missing GELATOLAB_API_KEY");
export async function gelatoLab(path, options = {}) {
const response = await fetch(`${BASE_URL}${path}`, {
...options,
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
...options.headers,
},
});
const body = await response.json();
if (!response.ok) {
const error = new Error(body.message || "GELATOlab API error");
error.status = response.status;
error.code = body.error;
error.requestId = body.request_id;
throw error;
}
return body;
}
使用 requests 建立後端 Client
建議在 virtual environment 中安裝,並從環境變數讀取 Key。
python -m venv .venv
# macOS / Linux
source .venv/bin/activate
# Windows PowerShell
.\.venv\Scripts\Activate.ps1
python -m pip install requests
import os
import requests
BASE_URL = "https://gelatolab.com.tw/api/v1"
API_KEY = os.environ["GELATOLAB_API_KEY"]
def gelatolab(path, method="GET", **kwargs):
headers = kwargs.pop("headers", {})
headers["Authorization"] = f"Bearer {API_KEY}"
response = requests.request(
method,
f"{BASE_URL}{path}",
headers=headers,
timeout=30,
**kwargs,
)
response.raise_for_status()
return response.json()
先用 cURL 驗證連線
健康檢查不需要 Key;其他端點都要帶 Bearer Authorization header。
# 公開健康檢查
curl "https://gelatolab.com.tw/api/v1/health"
# 驗證 API Key
curl "https://gelatolab.com.tw/api/v1/usage" \
-H "Authorization: Bearer $GELATOLAB_API_KEY"
curl.exe "https://gelatolab.com.tw/api/v1/usage" `
-H "Authorization: Bearer $env:GELATOLAB_API_KEY"
驗證與環境
除了 /health 與 /openapi.json,所有請求都必須在 Authorization header 放入 Bearer Key。
Authorization: Bearer gl_live_your_key
gl_live_*
正式服務使用。請依團隊、應用程式或環境分開建立,方便單獨撤銷。
gl_test_*
開發與測試環境使用。TEST 與 LIVE 的 Key 類型必須和建立時的環境一致。
端點與完整流程
/ingredients/search把使用者食材名稱解析成官方 ID
0/knowledge/search搜尋已發布的冰淇淋知識與引用網址
0/knowledge/articles/{slug}取得一篇已發布文章的完整段落
0/knowledge/context為 LLM 取得有長度上限的相關知識段落
1 / success/flavor-pairings/regions列出支援的地區風味偏好
0/flavor-pairings/recommend依食材、地區與創意程度推薦搭配
1 / success/flavor-pairings/score評估指定組合、最弱配對與資料覆蓋
1 / success/parfaits/design從 30 款模板完成風味搭配、分層與冷凍配方 PAC 驗證
1 / success/recipes/kinds列出 9 類平衡、recipe types 與 subtypes
0/recipes/balance計算基底、醬料、顆粒、脆片與淋面的專屬平衡
1 / success/recipes驗算後回存至 API Key 所屬帳號的私人配方庫
0/usage查詢本月 included 與 prepaid 額度
0/health檢查 API、引擎與食材資料版本
0STEP A · RESOLVE INGREDIENTS
先搜尋每一項食材
使用者輸入的「鮮奶」可能是別名。搜尋端點會回傳 GELATOlab 官方食材 ID;後續配方只能傳 ID 與克數,不接受自行填入成分資料。
curl "https://gelatolab.com.tw/api/v1/ingredients/search?q=鮮奶&limit=5" \
-H "Authorization: Bearer $GELATOLAB_API_KEY"
{
"request_id": "...",
"query": "鮮奶",
"matches": [
{
"id": "ilLc1HQsDxs7X4vyVDR1",
"name": "全脂牛奶",
"name_en": "Whole Milk",
"category": "乳製品",
"match_score": 95
}
],
"usage_units": 0
}
STEP B · RETRIEVE KNOWLEDGE
把可引用的知識段落交給 LLM
/knowledge/search 適合搜尋文章標題與摘要;需要直接放進模型 context 時,使用 /knowledge/context。它最多回傳 8 段、12,000 字元,不會另外呼叫生成式模型,每次成功扣 1 unit。
curl "https://gelatolab.com.tw/api/v1/knowledge/context" \
-X POST \
-H "Authorization: Bearer $GELATOLAB_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: knowledge-pac-hard-001" \
--data '{
"query": "PAC 太低,gelato 為什麼會太硬",
"limit": 4,
"max_chars": 6000
}'
{
"knowledge_version": "...",
"passages": [
{
"title": "PAC(抗凍力)",
"section_title": "PAC 如何影響硬度",
"content": "...",
"source_url": "https://gelatolab.com.tw/wiki/glossary-pac"
}
],
"total_chars": 1460,
"usage_units": 1
}
STEP C · FLAVOR AFFINITY
用官方 ID 取得風味搭配方向
基底與候選食材都必須先經過 /ingredients/search。推薦結果會回傳感官分數、分子親和力、搭配類型、最多 8 個共享化合物與資料覆蓋;不會回傳私有感官向量或完整化合物資料庫。
curl "https://gelatolab.com.tw/api/v1/flavor-pairings/recommend" \
-X POST \
-H "Authorization: Bearer $GELATOLAB_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: mango-pairing-tw-001" \
--data '{
"base_ingredient_id": "EXCEL_7681E82C",
"region": "tw",
"creativity": 0.4,
"limit": 8
}'
{
"base_ingredient": { "id": "EXCEL_7681E82C", "name": "芒果泥" },
"region": "tw",
"recommendations": [
{
"ingredient_id": "0lYJJhrJk9bw81463pfG",
"name": "百香果",
"recommendation_score": 77.1,
"pairing_type": "bridge",
"shared_compounds": ["Linalool"],
"data_coverage": { "mode": "molecular" }
}
],
"usage_units": 1
}
STEP D · DESIGN PARFAIT
一句需求完成選模板、搭配、分層與 PAC 配方
先將使用者指定食材逐項解析為官方 ID,再送入 /parfaits/design。伺服器會評分全部 30 款正式模板、套用風味搭配引擎,並為每個 gelato、sorbetto 或 granita 層建立完整配方。每個冷凍配方都會用正式平衡引擎重新計算,只有 raw PAC 落在該層服務溫度調整後的 pac_contract 才會回傳。
curl "https://gelatolab.com.tw/api/v1/parfaits/design" \
-X POST \
-H "Authorization: Bearer $GELATOLAB_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: strawberry-parfait-001" \
--data '{
"ingredient_ids": ["SNiPFvtyMqOSxWgMmuuA"],
"region": "tw",
"creativity": 0.45,
"mode": "auto",
"dietary": "standard",
"batch_weight_g": 1000
}'
{
"template_selection": {
"selected": { "id": "tpl_case_apple_strawberry", "mode": "hybrid" },
"candidates_evaluated": 30
},
"frozen_formulas": [{
"name": "台灣草莓 (大湖) Gelato",
"recipe_type": "milk",
"pac_contract": {
"service_temp_c": -13,
"min": 249,
"max": 314,
"actual": 282,
"status": "ok"
}
}],
"guarantees": {
"template_selected_from": 30,
"pairing_engine_used": true,
"all_requested_ingredients_used": true,
"all_frozen_formulas_pac_compliant": true
},
"usage_units": 1
}
STEP E · BALANCE RECIPE
使用 ID、克數與平衡分類計算配方
先呼叫 GET /recipes/kinds 取得目前支援的 9 個 kind、recipe types 與 subtypes。計費 POST 建議帶一個 8–128 字元的 Idempotency-Key;相同 Key 與相同 request body 重送不會重複扣 unit。
curl "https://gelatolab.com.tw/api/v1/recipes/balance" \
-X POST \
-H "Authorization: Bearer $GELATOLAB_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: recipe-demo-20260717-001" \
--data '{
"recipe_type": "milk",
"items": [
{ "ingredient_id": "ilLc1HQsDxs7X4vyVDR1", "grams": 600 },
{ "ingredient_id": "2Sef4m2eeoyHz11NqQwq", "grams": 150 },
{ "ingredient_id": "v5qYjTLMaisEiKy9has0", "grams": 160 },
{ "ingredient_id": "CFY4HJ1JJXrcB8JvPPXM", "grams": 40 },
{ "ingredient_id": "R3_002", "grams": 50 }
]
}'
{
"recipe_type": "milk",
"kind": "gelato_base",
"subtype": null,
"usage_units": 1,
"balance": {
"totalWeight": 1000,
"water": 66.6,
"fat": 7.39,
"protein": 3.68,
"sugar": 15.97,
"totalSolids": 33.4,
"msnf": 9.86,
"pod": 16.83,
"pac": 181,
"freezingPoint": -1.8,
"overrun": 27.3
},
"estimated_metrics": ["overrun", "yieldLiters", "freezingPoint"],
"pending_metrics": []
}
milkcreamsorbetchocolate_sorbetgranitayogurtveganalcoholpethighProteinsugarFreescoopsoft_servegelato_basesorbetto_basegranitavariegatocrema_spalmabiletoppinggranellacroccantecopertura霜淇淋不是配方基底類型:請傳實際的 recipe_type(例如 milk 或 vegan),另加 serving_format: "soft_serve"。舊版 recipe_type: "soft_serve" 僅保留相容讀取,會正規化為牛奶基底霜淇淋。複合元件不傳 recipe_type,改傳 kind 與 subtype。例如水果夾層醬使用 { "kind": "variegato", "subtype": "fruit", "service_temp_c": -14, "items": [...] }。aw、黏度、融點及保存期限相關欄位會標示為估算或 pending,商用量產仍須做儀器與保存試驗。
STEP F · SAVE AFTER CONFIRMATION
把確認採用的版本回存至 GELATOlab
建立 API Key 時需勾選「允許回存到我的配方庫」,取得 recipes:write scope。只有在使用者明確確認採用後才呼叫;伺服器會重新解析官方食材、驗算數值,並以「研發中」草案寫入。回存本身為 0 unit,但必須提供穩定的 Idempotency-Key。
curl "https://gelatolab.com.tw/api/v1/recipes" \
-X POST \
-H "Authorization: Bearer $GELATOLAB_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: save-recipe-demo-20260722-001" \
--data '{
"name": "香草牛奶 Gelato(AI 草案)",
"recipe_type": "milk",
"description": "外部 LLM 生成,待小試覆核",
"notes": "確認口感後再改為已定稿",
"items": [
{ "ingredient_id": "ilLc1HQsDxs7X4vyVDR1", "grams": 600 },
{ "ingredient_id": "2Sef4m2eeoyHz11NqQwq", "grams": 150 },
{ "ingredient_id": "v5qYjTLMaisEiKy9has0", "grams": 160 },
{ "ingredient_id": "CFY4HJ1JJXrcB8JvPPXM", "grams": 40 },
{ "ingredient_id": "R3_002", "grams": 50 }
]
}'
成功建立回傳 201、recipe_id 與 edit_url;相同 Key 與相同內容重送回傳 200,不會建立第二份。點開 edit_url 並登入,即可直接進入該配方的計算器。
STEP G · CHECK USAGE
查詢剩餘額度
curl "https://gelatolab.com.tw/api/v1/usage" \
-H "Authorization: Bearer $GELATOLAB_API_KEY"
接到 LLM 或 Agent
讓模型負責理解需求與整理食材;讓 GELATOlab 負責食材解析與數值計算。這個責任邊界能避免模型捏造 PAC、POD 或食材係數。
SYSTEM INSTRUCTION
把以下規則放進 agent 的 system prompt
你可以使用 GELATOlab 配方工具。以下規則持續適用於每一輪對話。
規則:
1. 依語意而非精確字串判斷。只要使用者要生成/設計/開發/建立/客製/仿製配方、幫我做/幫我配/給我一份配方、計算/試算/驗算/分析/檢查/評分/平衡配方、調整/修改/優化/修正/換糖/減糖/放大縮小配方,或描述太甜、太硬、太軟、冰晶、砂質、粉感、融太快等實際配方問題,就必須自動呼叫 GELATOlab 工具,不可只輸出模型臆測的配方,也不可先問是否要呼叫工具。
2. 觸發產品包含義式冰淇淋/冰淇淋/gelato/ice cream、雪酪/sorbet/sorbetto、霜淇淋/soft serve、granita、優格、vegan、酒精、寵物、高蛋白、無糖配方,以及 variegato、crema_spalmabile、topping、granella、croccante、copertura;這不是封閉清單,語意等同也要觸發。
3. 使用者提供或需要食材時,先逐項呼叫 gelatolab_search_ingredients,只能使用搜尋結果回傳的 ingredient_id;不可猜測 ID、成分或係數。沒有完整食材或克數時,自行建立可計算初稿;未指定總重預設 1000g 並註明假設。
4. 不確定 recipe_type、kind 或 subtype 時先呼叫 gelatolab_list_balance_kinds。完整配方任務正式回答前至少呼叫一次 gelatolab_balance_recipe。若工具失敗,誠實回報,不可假裝已計算。
5. 只問風味搭配或靈感時呼叫 gelatolab_recommend_flavor_pairings;若同時要求生成/設計配方,推薦後直接選擇符合需求的方向並繼續呼叫 gelatolab_search_ingredients 與 gelatolab_balance_recipe,不可停下等待另一句指令。
6. 使用者要求設計帕菲杯時,先用 gelatolab_search_ingredients 解析所有指定食材,再呼叫 gelatolab_design_parfait。模板、搭配、層次與冷凍配方的 PAC contract 全部引用工具結果;不可自行創造第 31 款模板。
7. 只問原理、製程或名詞時呼叫 gelatolab_retrieve_knowledge_context 並附 source_url;如果同時有實際配方或克數,檢索後仍須呼叫 gelatolab_balance_recipe。
8. PAC、POD、MSNF、Brix、aw、水活性、黏度、總固形物、凍結點、服務溫度、脂肪、糖、水分、蛋白質、overrun、Tg' 等配方數值必須引用 API 結果,不可自行計算。
9. 回答使用中文,列出實際送算的食材克數、總重、recipe_type 或 kind、API metrics、品質分數與 warnings,並區分實測結果、估算欄位與建議。帕菲杯另列出模板、層次與每個冷凍配方的 PAC contract。
10. 同一次操作重試沿用相同 Idempotency-Key。API 回傳 402 時告知額度不足,不得繞過計費;保留 request_id 供追蹤。
11. 絕對不可自動回存。只有使用者明確表示「採用、儲存或回存」後才能呼叫 gelatolab_save_recipe;成功後提供 recipe_id 與 edit_url。
FUNCTION SCHEMA
通用 function calling 工具定義
大多數支援 function calling 的 LLM SDK 都能映射這組 JSON Schema;欄位包裝方式依供應商 SDK 調整。
export const gelatolabTools = [
{
name: "gelatolab_search_ingredients",
description: "把食材名稱解析為 GELATOlab 官方 ingredient_id。配方計算前必須先呼叫。",
inputSchema: {
type: "object",
additionalProperties: false,
required: ["query"],
properties: {
query: { type: "string", minLength: 1, maxLength: 80 },
limit: { type: "integer", minimum: 1, maximum: 20, default: 5 }
}
}
},
{
name: "gelatolab_retrieve_knowledge_context",
description: "取得有引用網址、長度受限的 GELATOlab 知識段落。成功呼叫扣 1 unit。",
inputSchema: {
type: "object",
additionalProperties: false,
required: ["query"],
properties: {
query: { type: "string", minLength: 1, maxLength: 160 },
limit: { type: "integer", minimum: 1, maximum: 8, default: 5 },
max_chars: { type: "integer", minimum: 1000, maximum: 12000, default: 6000 }
}
}
},
{
name: "gelatolab_recommend_flavor_pairings",
description: "依官方食材 ID、地區與創意程度推薦風味搭配。成功呼叫扣 1 unit。",
inputSchema: {
type: "object",
additionalProperties: false,
required: ["base_ingredient_id"],
properties: {
base_ingredient_id: { type: "string" },
candidate_ingredient_ids: { type: "array", maxItems: 100, items: { type: "string" } },
region: { type: "string", enum: ["all", "tw", "jp", "kr", "it", "us", "fr", "th", "mx", "in", "tr", "es", "br"], default: "all" },
creativity: { type: "number", minimum: 0, maximum: 1, default: 0.5 },
limit: { type: "integer", minimum: 1, maximum: 20, default: 10 }
}
}
},
{
name: "gelatolab_design_parfait",
description: "從 GELATOlab 30 款正式模板完成風味搭配、分層,並產生所有冷凍層的 PAC 合規配方。成功呼叫扣 1 unit。",
inputSchema: {
type: "object",
additionalProperties: false,
required: ["ingredient_ids"],
properties: {
name: { type: "string", maxLength: 120 },
ingredient_ids: {
type: "array", minItems: 1, maxItems: 4, uniqueItems: true,
items: { type: "string" }
},
region: { type: "string", enum: ["all", "tw", "jp", "it"], default: "all" },
creativity: { type: "number", minimum: 0, maximum: 1, default: 0.45 },
template_category: {
type: "string",
enum: ["auto", "classic", "fruit", "japanese", "chocolate", "tea", "vegetable", "alcohol"],
default: "auto"
},
mode: { type: "string", enum: ["auto", "frozen", "chilled", "hybrid"], default: "auto" },
dietary: { type: "string", enum: ["standard", "vegan"], default: "standard" },
batch_weight_g: { type: "number", minimum: 500, maximum: 5000, default: 1000 },
service_temp_c: { type: "number", minimum: -25, maximum: -5 }
}
}
},
{
name: "gelatolab_list_balance_kinds",
description: "列出 GELATOlab 9 類平衡、recipe types、subtypes 與估算欄位。0 unit。",
inputSchema: {
type: "object",
additionalProperties: false,
properties: {}
}
},
{
name: "gelatolab_balance_recipe",
description: "使用官方食材 ID、克數與 kind 計算 9 類專屬配方平衡。成功呼叫扣 1 unit。",
inputSchema: {
type: "object",
additionalProperties: false,
required: ["items"],
properties: {
recipe_type: {
type: "string",
enum: ["milk", "cream", "sorbet", "chocolate_sorbet", "granita", "yogurt", "vegan", "alcohol", "pet", "highProtein", "sugarFree"]
},
serving_format: { type: "string", enum: ["scoop", "soft_serve"], default: "scoop" },
kind: {
type: "string",
enum: ["gelato_base", "sorbetto_base", "granita", "variegato", "crema_spalmabile", "topping", "granella", "croccante", "copertura"]
},
subtype: { type: "string" },
service_temp_c: { type: "number", minimum: -40, maximum: 20 },
dip_temp_c: { type: "number", minimum: 0, maximum: 100 },
surface_temp_c: { type: "number", minimum: -40, maximum: 30 },
items: {
type: "array",
minItems: 1,
maxItems: 60,
items: {
type: "object",
additionalProperties: false,
required: ["ingredient_id", "grams"],
properties: {
ingredient_id: { type: "string" },
grams: { type: "number", exclusiveMinimum: 0, maximum: 100000 }
}
}
}
}
}
},
{
name: "gelatolab_save_recipe",
description: "使用者明確確認採用後,將伺服器重新驗算的配方存入其私人 GELATOlab 配方庫。0 unit,需要 recipes:write。",
inputSchema: {
type: "object",
additionalProperties: false,
required: ["idempotency_key", "name", "items"],
properties: {
idempotency_key: { type: "string", minLength: 8, maxLength: 128 },
name: { type: "string", minLength: 1, maxLength: 120 },
description: { type: "string", maxLength: 1000 },
notes: { type: "string", maxLength: 4000 },
source_request_id: { type: "string", minLength: 8, maxLength: 128 },
recipe_type: {
type: "string",
enum: ["milk", "cream", "sorbet", "chocolate_sorbet", "granita", "yogurt", "vegan", "alcohol", "pet", "highProtein", "sugarFree"]
},
serving_format: { type: "string", enum: ["scoop", "soft_serve"], default: "scoop" },
kind: {
type: "string",
enum: ["gelato_base", "sorbetto_base", "granita", "variegato", "crema_spalmabile", "topping", "granella", "croccante", "copertura"]
},
subtype: { type: "string" },
service_temp_c: { type: "number", minimum: -40, maximum: 20 },
dip_temp_c: { type: "number", minimum: 0, maximum: 100 },
surface_temp_c: { type: "number", minimum: -40, maximum: 30 },
items: {
type: "array",
minItems: 1,
maxItems: 60,
items: {
type: "object",
additionalProperties: false,
required: ["ingredient_id", "grams"],
properties: {
ingredient_id: { type: "string" },
grams: { type: "number", exclusiveMinimum: 0, maximum: 100000 }
}
}
}
}
}
}
];
TOOL DISPATCHER
在你的後端執行模型的 tool call
import crypto from "node:crypto";
import { gelatoLab } from "./client.mjs";
export async function runGelatoLabTool(name, input) {
if (name === "gelatolab_search_ingredients") {
const query = new URLSearchParams({
q: input.query,
limit: String(input.limit || 5),
});
return gelatoLab(`/ingredients/search?${query}`);
}
if (name === "gelatolab_retrieve_knowledge_context") {
return gelatoLab("/knowledge/context", {
method: "POST",
headers: { "Idempotency-Key": crypto.randomUUID() },
body: JSON.stringify(input),
});
}
if (name === "gelatolab_recommend_flavor_pairings") {
return gelatoLab("/flavor-pairings/recommend", {
method: "POST",
headers: { "Idempotency-Key": crypto.randomUUID() },
body: JSON.stringify(input),
});
}
if (name === "gelatolab_design_parfait") {
return gelatoLab("/parfaits/design", {
method: "POST",
headers: { "Idempotency-Key": crypto.randomUUID() },
body: JSON.stringify(input),
});
}
if (name === "gelatolab_list_balance_kinds") {
return gelatoLab("/recipes/kinds");
}
if (name === "gelatolab_balance_recipe") {
return gelatoLab("/recipes/balance", {
method: "POST",
headers: { "Idempotency-Key": crypto.randomUUID() },
body: JSON.stringify(input),
});
}
if (name === "gelatolab_save_recipe") {
const { idempotency_key, ...recipe } = input;
return gelatoLab("/recipes", {
method: "POST",
headers: { "Idempotency-Key": idempotency_key },
body: JSON.stringify(recipe),
});
}
throw new Error(`Unknown tool: ${name}`);
}
額度與限制
knowledge/context、flavor-pairings/recommend、flavor-pairings/score、parfaits/design 與配方平衡端點每次成功扣 1 unit;搜尋、文章讀取、地區列表、配方回存與用量查詢為 0 unit。執行失敗會退回預留額度;相同 Idempotency-Key 與相同內容的重送不會重複扣點。每月 included 額度先使用,再扣 prepaid units。
1,000 units
NT$490NT$0.49 / unit
5,000 units
NT$1,990NT$0.398 / unit
20,000 units
NT$5,990NT$0.2995 / unit
LLM 模型 token 費用由你的模型供應商另行計收,不包含在 GELATOlab units 內。
錯誤處理
錯誤回應都是 JSON,包含穩定的 error code、可讀訊息與 request_id。記錄 request_id,但不要把 API Key 寫進 log。
invalid_query / invalid_items修正輸入格式、recipe_type 或 Idempotency-Key。
invalid_api_key確認 Bearer header、Key 是否完整,或重新建立 Key。
insufficient_quota前往開發者中心購買 units,再重送原請求。
business_required / insufficient_scope確認 BUSINESS 權益與 Key scopes。
idempotency_conflict / request_in_progress相同操作沿用原 Key;不同內容產生新 Key。短暫等待後可重試。
knowledge_article_not_found重新搜尋文章,並使用回傳的 slug。
ingredient_not_found / ingredient_not_pairable重新搜尋取得有效 ID;功能性食材可能沒有可用風味資料。
rate_limit_exceeded依 Retry-After header 指示延後,使用 exponential backoff。
internal_error保留 request_id,延遲後重試;不要無限重送。
{
"error": "ingredient_not_found",
"message": "找不到官方食材 ID",
"request_id": "d0f7...",
"details": {
"index": 2,
"ingredient_id": "unknown-id"
}
}
正式上線清單
READY TO FORMULATE