跳至主要內容
GELATOlab DEVELOPER ATELIER 建立 API Key

PUBLIC API · VERSION 1.0 BETA

讓你的 LLM,
接上配方科學。

不會寫程式也能使用。貼一段 Prompt,就能在 Claude Code 或 Codex 裡用中文做配方;需要工程串接時,也有 Node.js、Python、cURL 與完整 OpenAPI 規格。

BASE URLhttps://gelatolab.com.tw/api/v1
AUTHBearer API Key
RATE LIMIT60 requests / min
ENGINE CALL1 unit / success
IARCHITECTURE

運作方式

GELATOlab API 是標準 HTTPS JSON API,不必安裝專用 SDK。LLM 不應自行猜測食材 ID、風味證據或配方數值;正確流程是先解析食材與檢索知識,再取得搭配方向,最後把 ID 與克數送進配方平衡端點。

01RETRIEVE解析食材與知識

取得官方 ID、文章段落與引用來源

02FORMULATE選擇風味方向

以 pairing evidence 協助 LLM 組成配方

03VERIFY送出配方平衡

由 GELATOlab 引擎驗證配方數值

04SAVE確認後回存

以寫入權限存成私人研發草案

SERVER-SIDE ONLY

API Key 不可放在公開網頁、手機 App 或公開程式碼。

工程串接請使用 server environment variable 或 Secret Manager。免終端機用法只能在自己信任的 Claude Code/Codex 私人工作區操作;不要貼進公開對話、共享畫面或公開 GitHub。

IIQUICKSTART

申請與安裝

01

啟用 BUSINESS

Public API 是 BUSINESS 與 ENTERPRISE 權益。登入 GELATOlab 後,確認帳號方案仍在有效期間。

02

開啟開發者中心

前往「設定 → GELATOlab API → 開啟開發者中心」,建立 LIVE 或 TEST Key。每個帳號最多可有 5 組啟用中的 Key。

03

立即保存 Key

完整 Key 只在建立時顯示一次。先存進密碼管理器或 Secret Manager;若遺失,請撤銷舊 Key 並建立新 Key。

04

選擇使用方式

完全不會終端機,選「免終端機」;工程師則可選 Node.js、Python 或 cURL。兩種方式使用的是同一套 GELATOlab 引擎。

CLAUDE CODE · CODEX DESKTOP

完全不會終端機:貼一段話,之後只用中文聊

不需要安裝 Node.js、Python 或 cURL。準備一把 GELATOlab Key,打開 Claude Code 或 Codex 桌面版,讓 AI 依照官方 OpenAPI 規格替你呼叫 API。

01

打開私人工作區

在 Claude Code 或 Codex 桌面版開啟自己的資料夾。不要使用公開、共用或會自動同步到公開 GitHub 的工作區。

02

複製下面整段 Prompt

貼進新對話後,只在自己的電腦上把 gl_live_•••• 換成剛建立的完整 Key。

03

允許第一次連線

AI 會自行執行 API/shell/curl。第一次若詢問是否允許執行,確認內容後按一次「允許」。

04

直接用中文做配方

看到「準備好了」後,直接輸入「生成冰淇淋配方」、「設計配方」或「幫我做一支一千克的開心果牛奶 gelato」。Prompt 會要求 AI 自動呼叫 GELATOlab API,不必再下指令。

PROMPT.TXT · 整段複製
你現在是我的義式冰淇淋配方助理,工具是 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。

品質分數高或沒有警示,不代表一定好吃。最後仍要小批試作,在預定服務溫度確認甜度、挖取、口融與殘留感。

IIIAUTHENTICATION

驗證與環境

除了 /health/openapi.json,所有請求都必須在 Authorization header 放入 Bearer Key。

HTTP HEADER
Authorization: Bearer gl_live_your_key
LIVE KEY

gl_live_*

正式服務使用。請依團隊、應用程式或環境分開建立,方便單獨撤銷。

TEST KEY

gl_test_*

開發與測試環境使用。TEST 與 LIVE 的 Key 類型必須和建立時的環境一致。

IVENDPOINTS

端點與完整流程

METHODPATH用途UNITS
GET/ingredients/search

把使用者食材名稱解析成官方 ID

0
GET/knowledge/search

搜尋已發布的冰淇淋知識與引用網址

0
GET/knowledge/articles/{slug}

取得一篇已發布文章的完整段落

0
POST/knowledge/context

為 LLM 取得有長度上限的相關知識段落

1 / success
GET/flavor-pairings/regions

列出支援的地區風味偏好

0
POST/flavor-pairings/recommend

依食材、地區與創意程度推薦搭配

1 / success
POST/flavor-pairings/score

評估指定組合、最弱配對與資料覆蓋

1 / success
POST/parfaits/design

從 30 款模板完成風味搭配、分層與冷凍配方 PAC 驗證

1 / success
GET/recipes/kinds

列出 9 類平衡、recipe types 與 subtypes

0
POST/recipes/balance

計算基底、醬料、顆粒、脆片與淋面的專屬平衡

1 / success
POST/recipes

驗算後回存至 API Key 所屬帳號的私人配方庫

0
GET/usage

查詢本月 included 與 prepaid 額度

0
GET/health

檢查 API、引擎與食材資料版本

0

STEP A · RESOLVE INGREDIENTS

先搜尋每一項食材

使用者輸入的「鮮奶」可能是別名。搜尋端點會回傳 GELATOlab 官方食材 ID;後續配方只能傳 ID 與克數,不接受自行填入成分資料。

REQUEST
curl "https://gelatolab.com.tw/api/v1/ingredients/search?q=鮮奶&limit=5" \
  -H "Authorization: Bearer $GELATOLAB_API_KEY"
200 RESPONSE
{
  "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。

REQUEST
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
  }'
200 RESPONSE · EXCERPT
{
  "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 個共享化合物與資料覆蓋;不會回傳私有感官向量或完整化合物資料庫。

REQUEST
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
  }'
200 RESPONSE · EXCERPT
{
  "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 才會回傳。

REQUEST
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
  }'
200 RESPONSE · EXCERPT
{
  "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。

REQUEST
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 }
    ]
  }'
200 RESPONSE · EXCERPT
{
  "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": []
}
SUPPORTED RECIPE TYPES
milkcreamsorbetchocolate_sorbetgranitayogurtveganalcoholpethighProteinsugarFree
SUPPORTED SERVING FORMATS
scoopsoft_serve
SUPPORTED BALANCE KINDS
gelato_basesorbetto_basegranitavariegatocrema_spalmabiletoppinggranellacroccantecopertura

霜淇淋不是配方基底類型:請傳實際的 recipe_type(例如 milkvegan),另加 serving_format: "soft_serve"。舊版 recipe_type: "soft_serve" 僅保留相容讀取,會正規化為牛奶基底霜淇淋。複合元件不傳 recipe_type,改傳 kindsubtype。例如水果夾層醬使用 { "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

REQUEST
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 }
    ]
  }'

成功建立回傳 201recipe_idedit_url;相同 Key 與相同內容重送回傳 200,不會建立第二份。點開 edit_url 並登入,即可直接進入該配方的計算器。

STEP G · CHECK USAGE

查詢剩餘額度

REQUEST
curl "https://gelatolab.com.tw/api/v1/usage" \
  -H "Authorization: Bearer $GELATOLAB_API_KEY"
VAGENT INTEGRATION

接到 LLM 或 Agent

讓模型負責理解需求與整理食材;讓 GELATOlab 負責食材解析與數值計算。這個責任邊界能避免模型捏造 PAC、POD 或食材係數。

SYSTEM INSTRUCTION

把以下規則放進 agent 的 system prompt

PROMPT.TXT
你可以使用 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 調整。

TOOLS.JS
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

DISPATCHER.MJS
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}`);
}
VIUSAGE & BILLING

額度與限制

MONTHLY INCLUDED100units / API account
SEARCH & READ0unit / request
CONTEXT · PAIRING · PARFAIT · BALANCE1unit / success
RATE LIMIT60requests / minute / key

knowledge/contextflavor-pairings/recommendflavor-pairings/scoreparfaits/design 與配方平衡端點每次成功扣 1 unit;搜尋、文章讀取、地區列表、配方回存與用量查詢為 0 unit。執行失敗會退回預留額度;相同 Idempotency-Key 與相同內容的重送不會重複扣點。每月 included 額度先使用,再扣 prepaid units。

STARTER

1,000 units

NT$490

NT$0.49 / unit

SCALE

20,000 units

NT$5,990

NT$0.2995 / unit

LLM 模型 token 費用由你的模型供應商另行計收,不包含在 GELATOlab units 內。

VIIERRORS

錯誤處理

錯誤回應都是 JSON,包含穩定的 error code、可讀訊息與 request_id。記錄 request_id,但不要把 API Key 寫進 log。

HTTP常見 error code處理方式
400invalid_query / invalid_items

修正輸入格式、recipe_type 或 Idempotency-Key。

401invalid_api_key

確認 Bearer header、Key 是否完整,或重新建立 Key。

402insufficient_quota

前往開發者中心購買 units,再重送原請求。

403business_required / insufficient_scope

確認 BUSINESS 權益與 Key scopes。

409idempotency_conflict / request_in_progress

相同操作沿用原 Key;不同內容產生新 Key。短暫等待後可重試。

404knowledge_article_not_found

重新搜尋文章,並使用回傳的 slug。

422ingredient_not_found / ingredient_not_pairable

重新搜尋取得有效 ID;功能性食材可能沒有可用風味資料。

429rate_limit_exceeded

依 Retry-After header 指示延後,使用 exponential backoff。

5xxinternal_error

保留 request_id,延遲後重試;不要無限重送。

ERROR SHAPE
{
  "error": "ingredient_not_found",
  "message": "找不到官方食材 ID",
  "request_id": "d0f7...",
  "details": {
    "index": 2,
    "ingredient_id": "unknown-id"
  }
}
VIIIGO LIVE

正式上線清單

READY TO FORMULATE

先建立一組 TEST Key,完成第一支配方。

開啟開發者中心