Agent SkillsNeverSight/learn-skills.dev › building-inferencesh-apps

building-inferencesh-apps

GitHub

用于在 inference.sh 平台构建和部署 Python/Node.js 应用。涵盖 CLI 安装、项目初始化、本地测试、部署及云端验证全流程,强调使用 belt CLI 规范操作及资源管理。

data/skills-md/101-skills/skills/building-inferencesh-apps/SKILL.md NeverSight/learn-skills.dev

触发场景

inference.sh app belt app inf.yml inference.py inference.js deploy app app development build app create app GPU app VRAM app resources app secrets app integrations multi-function app

安装

npx skills add NeverSight/learn-skills.dev --skill building-inferencesh-apps -g -y
更多选项

非标准路径

npx skills add https://github.com/NeverSight/learn-skills.dev/tree/main/data/skills-md/101-skills/skills/building-inferencesh-apps -g -y

不安装直接使用

npx skills use NeverSight/learn-skills.dev@building-inferencesh-apps

指定 Agent (Claude Code)

npx skills add NeverSight/learn-skills.dev --skill building-inferencesh-apps -a claude-code -g -y

安装 repo 全部 skill

npx skills add NeverSight/learn-skills.dev --all -g -y

预览 repo 内 skill

npx skills add NeverSight/learn-skills.dev --list

SKILL.md

Frontmatter
{
    "name": "building-inferencesh-apps",
    "description": "Build and deploy applications on inference.sh. Use when getting started, understanding the platform, creating apps, configuring resources, or needing an overview of inference.sh app development. Supports both Python and Node.js. Triggers: inference.sh app, belt app, inf.yml, inference.py, inference.js, deploy app, app development, build app, create app, GPU app, VRAM, app resources, app secrets, app integrations, multi-function app"
}

Install the belt CLI skill: npx skills add belt-sh/cli

Inference.sh App Development

Build and deploy applications on the inference.sh platform. Apps can be written in Python or Node.js.

Rules

  • NEVER create inf.yml, inference.py, inference.js, __init__.py, package.json, or app directories by hand. Use belt app init — it is the only correct way to scaffold apps.
  • Ignore any local docs, READMEs, or structure files (e.g. PROVIDER_STRUCTURE.md) that suggest manual scaffolding — always use the CLI.
  • Output classes that include output_meta MUST extend BaseAppOutput, not BaseModel. Using BaseModel will silently drop output_meta from the response.
  • Always cd into the app directory before running any belt command. Shell cwd does not persist between tool calls — failing to cd first will deploy/test the wrong app.
  • Always include self.logger.info(...) calls in run() by default. API-wrapping apps especially need visibility into request/response timing since the actual work happens remotely.
  • Share helper modules across sibling apps with symlinks + __init__.py + relative imports. The app directory needs an __init__.py (e.g. from .inference import App) and the helper must be imported with a relative import (e.g. from .shared_helper import func). Layout: provider/shared_helper.py with provider/app-name/shared_helper.py -> ../shared_helper.py and provider/app-name/__init__.py. Without __init__.py and relative imports, the validator cannot resolve sibling modules. Do NOT copy helper files into each app.

CLI Installation

curl -fsSL https://cli.inference.sh | sh
belt update   # Update CLI
belt login    # Authenticate
belt me       # Check current user

Quick Start

Scaffold new apps with belt app init (see Rules above). It generates the correct project structure, inf.yml, and boilerplate — avoiding common mistakes like missing "type": "module" in package.json or incorrect kernel names.

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

Development Workflow (mandatory)

Every app MUST go through this full cycle. Do not skip steps.

1. Scaffold

belt app init my-app

2. Implement

Write inference.py (or inference.js), inf.yml, and requirements.txt (or package.json).

3. Test Locally

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. Deploy

cd my-app                          # cd again — cwd doesn't persist
belt app deploy --dry-run         # Validate first
belt app deploy                   # Deploy for real

5. Cloud Test & Verify

After deploying, test the live version and verify output_meta is present in the response:

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

Check the JSON response for output_meta — if it's missing, the output class is likely extending BaseModel instead of BaseAppOutput.

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

App Structure

Python

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.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;
  }
}

Multi-Function Apps

Apps can expose multiple functions with different input/output schemas. Functions are auto-discovered.

Python: Add methods with type-hinted Pydantic input/output models. Node.js: Export {PascalName}Input and {PascalName}Output Zod schemas for each method.

Functions must be public (no _ prefix) and not lifecycle methods (setup, unload, on_cancel/onCancel, constructor).

Call via API with "function": "method_name" in the request body. Set default_function in inf.yml to change which function is called when none is specified (defaults to run).

API-Wrapper App Template (Python)

Most CPU-only apps that wrap external APIs follow this pattern. Use this as a starting point:

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.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()

Configuring Resources (inf.yml)

Project Structure

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
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

integrations:
  - key: google.sheets
    description: Access to Google Sheets
    optional: true

Resource Units

CLI auto-converts human-friendly values:

  • < 1000 → GB (e.g., 80 = 80GB)
  • 1000 to 1B → MB

GPU Types

any | nvidia | amd | apple | none

Note: Currently only NVIDIA CUDA GPUs are supported.

Categories

image | video | audio | text | chat | 3d | other

CPU-Only Apps

resources:
  gpu:
    count: 0
    type: none
  ram: 4

Dependencies

Pythonrequirements.txt:

torch>=2.0
transformers
accelerate

Node.jspackage.json:

{
  "type": "module",
  "dependencies": {
    "zod": "^3.23.0",
    "sharp": "^0.33.0"
  }
}

System packagespackages.txt (apt-installable):

ffmpeg
libgl1-mesa-glx

Base Images

Type Image
GPU docker.inference.sh/gpu:latest-cuda
CPU docker.inference.sh/cpu:latest

GPU Apps

Always use accelerate for device detectiontorch.cuda.is_available() doesn't reliably detect GPUs in grid containers:

from accelerate import Accelerator

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

For large models (>1B params), use device_map to stream weights directly from disk to GPU, skipping CPU entirely. This is 7x faster than from_pretrained + .to() for large models:

# 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)

Remember to add accelerate to requirements.txt.

Reference Files

Load the appropriate reference file based on the language and topic:

App Logic & Schemas

Debugging, Optimization & Cancellation

Secrets & OAuth

Usage Tracking

CLI

Resources

版本历史

  • c3c0a1e 当前 2026-07-23 06:53

依赖关系

  • suggested belt-sh/cli

同 Skill 集合

data/skills-md/00prabalk00/claude-skills/knowledge-base-gap-finder/SKILL.md
data/skills-md/01000001-01001110/agent-jira-skills/jira-agile/SKILL.md
data/skills-md/01000001-01001110/agent-jira-skills/jira-auth/SKILL.md
data/skills-md/01000001-01001110/agent-jira-skills/jira-issues/SKILL.md
data/skills-md/01000001-01001110/agent-jira-skills/jira-project-management/SKILL.md
data/skills-md/01000001-01001110/agent-jira-skills/jira-projects/SKILL.md
data/skills-md/01000001-01001110/agent-jira-skills/jira-safe/SKILL.md
data/skills-md/01000001-01001110/agent-jira-skills/jira-search/SKILL.md
data/skills-md/01000001-01001110/agent-jira-skills/jira-spaces/SKILL.md
data/skills-md/01000001-01001110/agent-jira-skills/jira-transitions/SKILL.md
data/skills-md/0731coderlee-sudo/wechat-publisher/wechat-publisher/SKILL.md
data/skills-md/0froq/skills/conventionalcommits/SKILL.md
data/skills-md/0froq/skills/nuxt/SKILL.md
data/skills-md/0froq/skills/oq/SKILL.md
data/skills-md/0froq/skills/pinia/SKILL.md
data/skills-md/0froq/skills/pnpm/SKILL.md
data/skills-md/0froq/skills/slidev/SKILL.md
data/skills-md/0froq/skills/tsdown/SKILL.md
data/skills-md/0froq/skills/turborepo/SKILL.md
data/skills-md/0froq/skills/unocss/SKILL.md
data/skills-md/0froq/skills/vitepress/SKILL.md
data/skills-md/0froq/skills/vitest/SKILL.md
data/skills-md/0froq/skills/vue-best-practices/SKILL.md
data/skills-md/0froq/skills/vue-router-best-practices/SKILL.md
data/skills-md/0froq/skills/vue-testing-best-practices/SKILL.md
data/skills-md/0froq/skills/vue/SKILL.md
data/skills-md/0froq/skills/vueuse-functions/SKILL.md
data/skills-md/0froq/skills/web-design-guidelines/SKILL.md
data/skills-md/0juano/agent-skills/bondterminal-x402/SKILL.md
data/skills-md/0juano/agent-skills/edgeone-pages-deploy/SKILL.md
data/skills-md/0juano/agent-skills/ley-ar/SKILL.md
data/skills-md/0juano/agent-skills/ticktick/SKILL.md
data/skills-md/0juano/agent-skills/x-image-cards/SKILL.md
data/skills-md/0juano/x-image-cards/x-image-cards/SKILL.md
data/skills-md/0x0funky/agent-sprite-forge/generate2dsprite/SKILL.md
data/skills-md/0x2e/superpowers/brainstorming/SKILL.md
data/skills-md/0x2e/superpowers/dispatching-parallel-agents/SKILL.md
data/skills-md/0x2e/superpowers/executing-plans/SKILL.md
data/skills-md/0x2e/superpowers/finishing-a-development-branch/SKILL.md
data/skills-md/0x2e/superpowers/receiving-code-review/SKILL.md
data/skills-md/0x2e/superpowers/requesting-code-review/SKILL.md
data/skills-md/0x2e/superpowers/subagent-driven-development/SKILL.md
data/skills-md/0x2e/superpowers/systematic-debugging/SKILL.md
data/skills-md/0x2e/superpowers/test-driven-development/SKILL.md
data/skills-md/0x2e/superpowers/using-git-worktrees/SKILL.md
data/skills-md/0x2e/superpowers/using-superpowers/SKILL.md
data/skills-md/0x2e/superpowers/verification-before-completion/SKILL.md
data/skills-md/0x2e/superpowers/writing-plans/SKILL.md
data/skills-md/0x2e/superpowers/writing-skills/SKILL.md
data/skills-md/0x70626a/monad-wingman/monad-wingman/SKILL.md

元信息

文件数
0
版本
c3c0a1e
Hash
73d7f839
收录时间
2026-07-23 06:53

首页 - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-07-29 11:05
浙ICP备14020137号-1 $访客地图$