belt CLIスキルのインストール:
npx skills add belt-sh/cli
Inference.sh アプリ開発
inference.shプラットフォーム上でアプリケーションを構築・デプロイします。アプリは Python または Node.js で記述できます。
ルール
inf.yml、inference.py、inference.js、__init__.py、package.json、またはアプリディレクトリを手動で作成してはいけません。belt app initを使用してください。これがアプリをスキャフォールドする唯一の正しい方法です。- 手動でのスキャフォールディングを示唆するローカルのドキュメント、README、構造ファイル(例:
PROVIDER_STRUCTURE.md)は無視してください。常にCLIを使用してください。 output_metaを含む出力クラスは、BaseModelではなくBaseAppOutputを拡張しなければなりません。BaseModelを使用すると、output_metaがレスポンスから静かに削除されます。- 任意の
beltコマンドを実行する前に、必ずアプリディレクトリにcdしてください。シェルのカレントワーキングディレクトリ(cwd)はツールコール間で保持されません。cdを忘れると、間違ったアプリのデプロイ/テストが行われます。 - デフォルトで
run()にself.logger.info(...)呼び出しを常に含めてください。特にAPIラッパーアプリでは、実際の処理がリモートで行われるため、リクエスト/レスポンスのタイミングを可視化するために必要です。 - 兄弟アプリ間でヘルパーモジュールを共有するには、シンボリックリンク +
__init__.py+ 相対インポート を使用してください。アプリディレクトリには__init__.py(例:from .inference import App)が必要であり、ヘルパーは相対インポート(例:from .shared_helper import func)でインポートする必要があります。レイアウト:provider/shared_helper.pyとprovider/app-name/shared_helper.py -> ../shared_helper.py、provider/app-name/__init__.py。__init__.pyと相対インポートがないと、バリデーターは兄弟モジュールを解決できません。ヘルパーファイルを各アプリにコピーしないでください。
CLIのインストール
curl -fsSL https://cli.inference.sh | sh
belt update # CLIの更新
belt login # 認証
belt me # 現在のユーザー確認
クイックスタート
新しいアプリは belt app init でスキャフォールドします(上記ルールを参照)。正しいプロジェクト構造、inf.yml、ボイラープレートコードを生成し、package.json の "type": "module" の欠落や誤ったカーネル名などのよくある間違いを防ぎます。
belt app init my-app # アプリ作成(対話式)
belt app init my-app --lang node # Node.jsアプリを作成
開発ワークフロー(必須)
すべてのアプリはこの全サイクルを経る必要があります。ステップをスキップしないでください。
1. スキャフォールド
belt app init my-app
2. 実装
inference.py(または inference.js)、inf.yml、requirements.txt(または package.json)を記述します。
3. ローカルテスト
cd my-app # 最初に必ずアプリディレクトリにcd
belt app test --save-example # スキーマからサンプル入力を生成
belt app test # input.jsonで実行
belt app test --input '{"prompt": "hello"}' # またはインラインJSON
4. デプロイ
cd my-app # 再度cd — cwdは保持されない
belt app deploy --dry-run # まず検証
belt app deploy # 実際にデプロイ
5. クラウドテストと確認
デプロイ後、ライブバージョンをテストし、レスポンスに output_meta が含まれていることを確認します:
belt app run user/app --json --input '{"prompt": "hello"}'
JSONレスポンスで output_meta を確認します — 欠落している場合、出力クラスが BaseAppOutput ではなく BaseModel を拡張している可能性があります。
# その他の便利なコマンド
belt app run user/app --input input.json
belt app sample user/app
belt app sample user/app --save input.json
アプリ構造
Python
from inferencesh import BaseApp, BaseAppInput, BaseAppOutput
from pydantic import Field
class AppSetup(BaseAppInput):
"""セットアップパラメータ — 変更時に再初期化をトリガー"""
model_id: str = Field(default="gpt2", description="読み込むモデル")
class AppInput(BaseAppInput):
prompt: str = Field(description="入力プロンプト")
class AppOutput(BaseAppOutput):
result: str = Field(description="出力結果")
class App(BaseApp):
async def setup(self, config: AppSetup):
"""ワーカー起動時または設定変更時に1回実行"""
self.model = load_model(config.model_id)
async def run(self, input_data: AppInput) -> AppOutput:
"""デフォルト関数 — 各リクエストに対して実行"""
self.logger.info(f"プロンプトを処理中: {input_data.prompt[:50]}")
result = self.model.generate(input_data.prompt)
self.logger.info("生成完了")
return AppOutput(result=result)
async def unload(self):
"""シャットダウン時のクリーンアップ"""
pass
async def on_cancel(self):
"""ユーザーがキャンセルしたときに呼び出される — 長時間タスク用"""
return True
Node.js
import { z } from "zod";
export const AppSetup = z.object({
modelId: z.string().default("gpt2").describe("読み込むモデル"),
});
export const RunInput = z.object({
prompt: z.string().describe("入力プロンプト"),
});
export const RunOutput = z.object({
result: z.string().describe("出力結果"),
});
export class App {
async setup(config) {
/** ワーカー起動時または設定変更時に1回実行 */
this.model = loadModel(config.modelId);
}
async run(inputData) {
/** デフォルト関数 — 各リクエストに対して実行 */
return { result: "done" };
}
async unload() {
/** シャットダウン時のクリーンアップ */
}
async onCancel() {
/** ユーザーがキャンセルしたときに呼び出される — 長時間タスク用 */
return true;
}
}
複数機能アプリ
アプリは異なる入出力スキーマを持つ複数の関数を公開できます。関数は自動検出されます。
Python: 型ヒント付きのPydantic入出力モデルを持つメソッドを追加します。
Node.js: 各メソッドに対して {パスカル名}Input および {パスカル名}Output のZodスキーマをエクスポートします。
関数はパブリック(_ プレフィックスなし)であり、ライフサイクルメソッド(setup、unload、on_cancel/onCancel、constructor)であってはいけません。
API経由で呼び出す場合は、リクエストボディに "function": "method_name" を含めます。inf.yml で default_function を設定すると、関数が指定されていない場合に呼び出される関数を変更できます(デフォルトは run)。
APIラッパーアプリテンプレート(Python)
外部APIをラップするほとんどのCPU専用アプリはこのパターンに従います。これを開始点として使用してください:
import os
import httpx
from inferencesh import BaseApp, BaseAppInput, BaseAppOutput, File
from inferencesh.models.usage import OutputMeta, ImageMeta # または TextMeta, AudioMeta など
from pydantic import Field
class AppInput(BaseAppInput):
prompt: str = Field(description="入力プロンプト")
class AppOutput(BaseAppOutput): # BaseModelではない — output_metaにはこれが必要
image: File = Field(description="生成された画像")
class App(BaseApp):
async def setup(self, config):
self.api_key = os.environ["API_KEY"]
self.client = httpx.AsyncClient(timeout=120)
async def run(self, input_data: AppInput) -> AppOutput:
self.logger.info(f"プロンプトでAPIを呼び出し中: {input_data.prompt[:80]}")
response = await self.client.post(
"https://api.example.com/generate",
headers={"Authorization": f"Bearer {self.api_key}"},
json={"prompt": input_data.prompt},
)
response.raise_for_status()
# 出力ファイルを書き込む
output_path = "/tmp/output.png"
with open(output_path, "wb") as f:
f.write(response.content)
# 実際の寸法を読み取る(ハードコードしない!)
from PIL import Image
with Image.open(output_path) as img:
width, height = img.size
self.logger.info(f"{width}x{height}の画像を生成しました")
return AppOutput(
image=File(path=output_path),
output_meta=OutputMeta(
outputs=[ImageMeta(width=width, height=height, count=1)]
),
)
async def unload(self):
await self.client.aclose()
リソースの設定(inf.yml)
プロジェクト構造
Python:
my-app/
├── inf.yml # 設定
├── inference.py # アプリロジック
├── requirements.txt # Pythonパッケージ(pip)
└── packages.txt # システムパッケージ(apt) — オプション
Node.js:
my-app/
├── inf.yml # 設定
├── src/
│ └── inference.js # アプリロジック
├── package.json # Node.jsパッケージ(npm/pnpm)
└── packages.txt # システムパッケージ(apt) — オプション
inf.yml
name: my-app
description: アプリの説明
category: image
kernel: python-3.11 # または node-22
# 複数機能アプリの場合(デフォルト: run)
# default_function: generate
resources:
gpu:
count: 1
vram: 24 # 24GB(自動変換)
type: any
ram: 32 # 32GB
env:
MODEL_NAME: gpt-4
secrets:
- key: HF_TOKEN
description: ゲート付きモデル用のHuggingFaceトークン
optional: false
integrations:
- key: google.sheets
description: Google Sheetsへのアクセス
optional: true
リソース単位
CLIは人間に優しい値を自動変換します:
- < 1000 → GB(例:
80= 80GB) - 1000 ~ 1B → MB
GPUタイプ
any | nvidia | amd | apple | none
注意: 現在はNVIDIA CUDA GPUのみがサポートされています。
カテゴリ
image | video | audio | text | chat | 3d | other
CPU専用アプリ
resources:
gpu:
count: 0
type: none
ram: 4
依存関係
Python — requirements.txt:
torch>=2.0
transformers
accelerate
Node.js — package.json:
{
"type": "module",
"dependencies": {
"zod": "^3.23.0",
"sharp": "^0.33.0"
}
}
システムパッケージ — packages.txt(aptでインストール可能):
ffmpeg
libgl1-mesa-glx
ベースイメージ
| タイプ | イメージ |
|---|---|
| GPU | docker.inference.sh/gpu:latest-cuda |
| CPU | docker.inference.sh/cpu:latest |
GPUアプリ
デバイス検出には常に accelerate を使用してください — torch.cuda.is_available() はグリッドコンテナ内のGPUを確実に検出できません:
from accelerate import Accelerator
accelerator = Accelerator()
self.device = accelerator.device
大規模モデル(1Bパラメータ超)の場合は、device_map を使用して 重みをディスクからGPUに直接ストリーミングし、CPUを完全にスキップします。これは大規模モデルにおいて from_pretrained + .to() よりも7倍高速です:
# 大規模モデル — ディスク→GPUに直接ストリーミング
self.model = AutoModel.from_pretrained("org/model", dtype=torch.bfloat16, device_map=str(self.device))
# 小規模モデルまたはサポートされていないライブラリ — ロード後に移動
self.model = SomeModel.from_pretrained("org/model")
self.model = self.model.to(device=self.device, dtype=torch.float16)
accelerate を requirements.txt に追加することを忘れないでください。
リファレンスファイル
言語とトピックに基づいて適切なリファレンスファイルを読み込んでください:
アプロジックとスキーマ
- references/python-app-logic.md — Python: Pydanticモデル、BaseApp、ファイル処理、型ヒント、複数機能パターン
- references/node-app-logic.md — Node.js: Zodスキーマ、ファイル処理、ESM、ジェネレーター、複数機能パターン
デバッグ、最適化、キャンセル
- references/python-patterns.md — Python: CUDAデバッグ、デバイス検出、モデル読み込み、メモリクリーンアップ、混合精度、キャンセル
- references/node-patterns.md — Node.js: ESM/importデバッグ、ストリーミング、メモリ管理、並行処理、キャンセル
シークレットとOAuth
- references/python-secrets-oauth.md — Python: os.environ、OpenAIクライアント、HuggingFaceトークン、Googleサービスアカウント
- references/node-secrets-oauth.md — Node.js: process.env、OpenAIクライアント、Google資格情報JSON
使用量トラッキング
- references/python-tracking.md — Python: OutputMeta、TextMeta、ImageMeta、VideoMeta、AudioMetaクラス
- references/node-tracking.md — Node.js: textMeta、imageMeta、videoMeta、audioMetaファクトリ関数
CLI
- references/cli.md — 完全なCLIコマンドリファレンス、両言語の前提条件
リソース
- 完全ドキュメント: inference.sh/docs
- サンプル: github.com/inference-sh/grid