mcpField
B
building-inferencesh-apps

building-inferencesh-apps

github.com/inference-sh開発789709 回インストール2 週間前に更新
リポジトリ

building-inferencesh-apps について

inference.sh 上で Python または Node.js のアプリを開発・デプロイするためのスキルです。CLI によるひな形作成を軸に、テストやデプロイ、プラットフォーム固有の実装方法を案内します。

主な機能

  1. 01CLI によるアプリのひな形作成
  2. 02Python と Node.js の開発ガイド
  3. 03ローカルテストとデプロイの手順
  4. 04複数関数アプリのパターン
  5. 05GPU とリソースの設定

活用シーン

  1. 01inference.sh アプリの開発開始
  2. 02belt によるアプリのテストとデプロイ
  3. 03複数の呼び出し可能な関数を持つアプリの構築

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/inference-sh/skills --skill building-inferencesh-apps

インストール後、Claude Code で/building-inferencesh-appsを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
cli.md
node-app-logic.md
node-patterns.md
node-secrets-oauth.md
node-tracking.md
python-app-logic.md
python-patterns.md
python-secrets-oauth.md
python-tracking.md

詳細

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 してください。ツール呼び出し間でシェルの作業ディレクトリは維持されません。先に cd しないと、誤ったアプリをデプロイ/テストしてしまいます。
  • デフォルトで run() 内に必ず self.logger.info(...) の呼び出しを含めてください。BaseApp には logger 属性がありません。まず import logging し、setup() で self.logger = logging.getLogger(__name__) を設定してください。実際の処理がリモートで行われるため、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   # Update CLI
belt login    # Authenticate
belt me       # Check current user

クイックスタート

新しいアプリは belt app init でひな形から作成してください(上記のルールを参照)。正しいプロジェクト構成、inf.yml、ボイラープレートが生成されるため、package.json の "type": "module" の記載漏れや、カーネル名の誤りといったよくあるミスを避けられます。

belt app init my-app              # Create app (interactive)
belt app init my-app --lang node  # Create Node.js app

開発ワークフロー(必須)

すべてのアプリで、この一連の手順を必ず実施してください。手順を省略しないでください。

1. ひな形の作成
belt app init my-app
2. 実装

inference.py(または inference.js)、inf.yml、および requirements.txt(または package.json)を記述します。

3. ローカルでテスト
cd my-app                          # ALWAYS cd into app dir first
belt app test --save-example      # Generate sample input from schema
belt app test                     # Run with input.json
belt app test --input '{"prompt": "hello"}'  # Or inline JSON
4. デプロイ
cd my-app                          # cd again — cwd doesn't persist
belt app deploy --dry-run         # Validate first
belt app deploy                   # Deploy for real
5. クラウドでテストして確認

デプロイ後、稼働中のバージョンをテストし、レスポンスに output_meta が含まれていることを確認してください。

belt app run user/app --json --input '{"prompt": "hello"}'

JSON レスポンスに output_meta があるか確認してください。含まれていない場合、出力クラスが BaseAppOutput ではなく BaseModel を継承している可能性があります。

# Other useful commands
belt app run user/app --input input.json
belt app sample user/app
belt app sample user/app --save input.json

アプリの構成

Python
import logging

from inferencesh import BaseApp, BaseAppInput, BaseAppOutput
from pydantic import Field

class AppSetup(BaseAppInput):
    """Setup parameters — triggers re-init when changed"""
    model_id: str = Field(default="gpt2", description="Model to load")

class AppInput(BaseAppInput):
    prompt: str = Field(description="Input prompt")

class AppOutput(BaseAppOutput):
    result: str = Field(description="Output result")

class App(BaseApp):
    async def setup(self, config: AppSetup):
        """Runs once when worker starts or config changes"""
        self.logger = logging.getLogger(__name__)
        self.model = load_model(config.model_id)

    async def run(self, input_data: AppInput) -> AppOutput:
        """Default function — runs for each request"""
        self.logger.info(f"Processing prompt: {input_data.prompt[:50]}")
        result = self.model.generate(input_data.prompt)
        self.logger.info("Generation complete")
        return AppOutput(result=result)

    async def unload(self):
        """Cleanup on shutdown"""
        pass

    async def on_cancel(self):
        """Called when user cancels — for long-running tasks"""
        return True
Node.js
import { z } from "zod";

export const AppSetup = z.object({
  modelId: z.string().default("gpt2").describe("Model to load"),
});

export const RunInput = z.object({
  prompt: z.string().describe("Input prompt"),
});

export const RunOutput = z.object({
  result: z.string().describe("Output result"),
});

export class App {
  async setup(config) {
    /** Runs once when worker starts or config changes */
    this.model = loadModel(config.modelId);
  }

  async run(inputData) {
    /** Default function — runs for each request */
    return { result: "done" };
  }

  async unload() {
    /** Cleanup on shutdown */
  }

  async onCancel() {
    /** Called when user cancels — for long-running tasks */
    return true;
  }
}

複数関数を持つアプリ

アプリでは、入出力スキーマの異なる複数の関数を公開できます。関数は自動検出されます。

Python: 型ヒントを付けた Pydantic の入出力モデルを持つメソッドを追加します。 Node.js: 各メソッドについて、{PascalName}Input および {PascalName}Output の Zod スキーマをエクスポートします。

関数はパブリックである必要があり(_ で始まらないこと)、ライフサイクルメソッド(setup、unload、on_cancel/onCancel、constructor)であってはなりません。

リクエストボディに "function": "method_name" を指定して API を呼び出します。呼び出す関数が指定されていない場合に呼び出される関数を変更するには、inf.yml で default_function を設定します(デフォルトは run です)。

API ラッパーアプリのテンプレート(Python)

外部 API をラップする CPU のみを使用するアプリの多くは、このパターンに従います。出発点として使用してください。

import logging
import os
import httpx
from inferencesh import BaseApp, BaseAppInput, BaseAppOutput, File
from inferencesh.models.usage import OutputMeta, ImageMeta  # or TextMeta, AudioMeta, etc.
from pydantic import Field

class AppInput(BaseAppInput):
    prompt: str = Field(description="Input prompt")

class AppOutput(BaseAppOutput):  # NOT BaseModel — output_meta requires this
    image: File = Field(description="Generated image")

class App(BaseApp):
    async def setup(self, config):
        self.logger = logging.getLogger(__name__)
        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"Calling API with prompt: {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()

        # Write output file
        output_path = "/tmp/output.png"
        with open(output_path, "wb") as f:
            f.write(response.content)

        # Read actual dimensions (don't hardcode!)
        from PIL import Image
        with Image.open(output_path) as img:
            width, height = img.size

        self.logger.info(f"Generated {width}x{height} image")

        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           # Configuration
├── inference.py      # App logic
├── requirements.txt  # Python packages (pip)
└── packages.txt      # System packages (apt) — optional

Node.js:

my-app/
├── inf.yml           # Configuration
├── src/
│   └── inference.js  # App logic
├── package.json      # Node.js packages (npm/pnpm)
└── packages.txt      # System packages (apt) — optional
inf.yml
name: my-app               # the slug that addresses the app: namespace/name
title: My App              # optional — how it reads on the app's page
description: What my app does
category: image
kernel: python-3.11     # or node-22

# For multi-function apps (default: run)
# default_function: generate

resources:
  gpu:
    count: 1
    vram: 24    # 24GB (auto-converted)
    type: any
  ram: 32       # 32GB

env:
  MODEL_NAME: gpt-4

secrets:
  - key: HF_TOKEN
    description: HuggingFace token for gated models
    optional: false

credentials:
  - key: google.sheets
    description: Access to 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
ベースイメージ
種類イメージ
GPUdocker.inference.sh/gpu:latest-cuda
CPUdocker.inference.sh/cpu:latest

GPU アプリ

デバイスの検出には必ず accelerate を使用してください — torch.cuda.is_available() はグリッドコンテナ内で GPU を確実に検出できません。

from accelerate import Accelerator

accelerator = Accelerator()
self.device = accelerator.device

大規模モデル(パラメーター数が 10 億超)には device_map を使用してください。重みをディスクから GPU に直接ストリーミングし、CPU を完全に介さずに済みます。大規模モデルでは、from_pretrained と .to() を使う方法より 7 倍高速です。

# Large models — streams disk → GPU directly
self.model = AutoModel.from_pretrained("org/model", dtype=torch.bfloat16, device_map=str(self.device))

# Small models or unsupported libraries — load then move
self.model = SomeModel.from_pretrained("org/model")
self.model = self.model.to(device=self.device, dtype=torch.float16)

requirements.txt に accelerate を追加してください。

参照ファイル

言語とトピックに応じて、適切な参照ファイルを読み込んでください。

アプリのロジックとスキーマ
デバッグ、最適化、キャンセル
  • references/python-patterns.md — Python:CUDA のデバッグ、デバイス検出、モデルの読み込み、メモリの解放、混合精度、キャンセル
  • references/node-patterns.md — Node.js:ESM/インポートのデバッグ、ストリーミング、メモリ管理、並行処理、キャンセル
シークレットと OAuth
使用状況の追跡
CLI
  • references/cli.md — CLI コマンドの完全なリファレンス、両言語の前提条件

リソース

コメント