Skip to main content

llm-project-development

Build LLM-powered applications and pipelines using proven methodology - task-model fit analysis, pipeline architecture, structured outputs, file-based state, and cost estimation. Use when building AI features, data processing pipelines, agents, or any LLM-integrated system. Inspired by Karpathy's methodology and production case studies.

ソース情報

リポジトリ
greyhaven-ai/claude-code-config
ソースの最終更新活動
2026年4月17日 23:11
検出された SKILL.md の言語
英語
スター
29
フォーク
5

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

ファイルエクスプローラー
10 ファイル

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
llm-project-development
description
Build LLM-powered applications and pipelines using proven methodology - task-model fit analysis, pipeline architecture, structured outputs, file-based state, and cost estimation. Use when building AI features, data processing pipelines, agents, or any LLM-integrated system. Inspired by Karpathy's methodology and production case studies.
skills
["code-style","data-validation","prompt-engineering"]
allowed-tools
["Read","Write","MultiEdit","Bash","Grep","Glob","TodoWrite","WebFetch"]
# LLM Project Development Skill Build **production LLM applications** using proven methodology from Karpathy's HN Time Capsule, Vercel d0, Manus, and Anthropic's research. **Core principle**: Validate manually first, then build deterministic pipelines around the non-deterministic LLM core. ## Supporting Documentation All files under 500 lines per Anthropic best practices: - **[references/](references/)** - Methodology foundations - [case-studies.md](references/case-studies.md) - Karpathy, Vercel d0, Manus patterns - [pipeline-patterns.md](references/pipeline-patterns.md) - Python/TypeScript code patterns - [INDEX.md](references/INDEX.md) - Reference navigation - **[examples/](examples/)** - Grey Haven implementations - [tanstack-pipeline.md](examples/tanstack-pipeline.md) - TanStack Start example - [fastapi-pipeline.md](examples/fastapi-pipeline.md) - FastAPI backend example - [INDEX.md](examples/INDEX.md) - Examples navigation - **[templates/](templates/)** - Copy-paste starters - [pipeline-template.ts](templates/pipeline-template.ts) - TypeScript pipeline - [pipeline-template.py](templates/pipeline-template.py) - Python pipeline - **[checklists/](checklists/)** - Validation - [llm-project-checklist.md](checklists/llm-project-checklist.md) - Pre-launch checklist ## The Methodology ### Phase 1: Task-Model Fit Analysis **Before writing any code, determine if LLMs are the right tool.** #### LLM-Suited Tasks | Characteristic | Why LLMs Excel | Grey Haven Example | |----------------|----------------|-------------------| | **Synthesis over precision** | Combining context, not calculating | Summarizing tenant activity | | **Subjective judgment** | No single correct answer | Categorizing support tickets | | **Error tolerance** | Graceful degradation acceptable | Content recommendations | | **Human-like processing** | Natural language understanding | Chat-based tenant onboarding | | **Creative output** | Novel combinations required | Generating marketing copy | #### LLM-Unsuited Tasks (Use Traditional Code) | Characteristic | Why LLMs Fail | Better Approach | |----------------|---------------|-----------------| | **Precise computation** | Math errors, hallucinations | SQL queries, Python math | | **Real-time requirements** | Latency too high | Pre-computed indices | | **Deterministic output** | Need exact same result | Database lookups | | **Structured data lookup** | LLMs guess, don't retrieve | Drizzle/SQLModel queries | | **High-frequency calls** | Cost explodes | Caching, batching | #### The Manual Prototype Step **CRITICAL**: Before building automation, validate with the target model manually. ```markdown ## Manual Validation Checklist - [ ] Copy ONE real example into the LLM UI - [ ] Test with the EXACT model you'll use in production - [ ] Verify output quality meets requirements - [ ] Note edge cases and failure modes - [ ] Estimate cost per operation ## Example: Karpathy's Approach 1. Took ONE Hacker News thread 2. Pasted into ChatGPT with analysis prompt 3. Confirmed Opus 4.5 could do the task 4. THEN built automation pipeline ``` ### Phase 2: Pipeline Architecture **Design principle**: Deterministic stages wrapping one non-deterministic core. ``` ┌─────────────────────────────────────────────────────────────────┐ │ DETERMINISTIC │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ ACQUIRE │ → │ PREPARE │ → │ PROCESS │ → │ RENDER │ │ │ │ (fetch) │ │ (format) │ │ (LLM) │ │ (output) │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ ↑ ↑ ↑ ↑ │ │ Deterministic Deterministic NON-DETERMINISTIC Deterministic│ │ (retry safe) (retry safe) (cache results) (retry safe) │ └─────────────────────────────────────────────────────────────────┘ ``` #### Stage Details | Stage | Purpose | Grey Haven Implementation | |-------|---------|--------------------------| | **Acquire** | Get raw data | Drizzle queries, Firecrawl scraping, API calls | | **Prepare** | Format for LLM | Jinja templates, TypeScript string builders | | **Process** | LLM inference | Anthropic SDK, structured outputs | | **Parse** | Extract from response | Zod schemas, Pydantic models | | **Render** | Final output | React components, markdown, JSON | #### TypeScript Pipeline Example (TanStack Start) ```typescript // lib/pipelines/content-analyzer.ts import Anthropic from "@anthropic-ai/sdk"; import { z } from "zod"; import { existsSync, mkdirSync, writeFileSync, readFileSync } from "fs"; import { join } from "path"; // Stage 1: Schema definition const AnalysisSchema = z.object({ summary: z.string(), sentiment: z.enum(["positive", "neutral", "negative"]), topics: z.array(z.string()), action_items: z.array(z.string()), }); type Analysis = z.infer<typeof AnalysisSchema>; // Stage 2: Acquire - Get data from database async function acquire(tenant_id: string, content_id: string) { const content = await db.query.contents.findFirst({ where: and( eq(contents.tenant_id, tenant_id), eq(contents.id, content_id) ), }); if (!content) throw new Error(`Content ${content_id} not found`); return content; } // Stage 3: Prepare - Format prompt function prepare(content: Content): string { return `Analyze this content and provide structured output. CONTENT: ${content.body} Respond with JSON matching this schema: { "summary": "2-3 sentence summary", "sentiment": "positive" | "neutral" | "negative", "topics": ["topic1", "topic2"], "action_items": ["action1", "action2"] }`; } // Stage 4: Process - LLM call with caching async function process( prompt: string, cacheDir: string, cacheKey: string ): Promise<string> { const cachePath = join(cacheDir, `${cacheKey}.json`); // Check cache first if (existsSync(cachePath)) { return JSON.parse(readFileSync(cachePath, "utf-8")).response; } const client = new Anthropic(); const response = await client.messages.create({ model: "claude-sonnet-4-20250514", max_tokens: 1024, messages: [{ role: "user", content: prompt }], }); const text = response.content[0].type === "text" ? response.content[0].text : ""; // Cache result mkdirSync(cacheDir, { recursive: true }); writeFileSync(cachePath, JSON.stringify({ response: text, timestamp: new Date().toISOString() })); return text; } // Stage 5: Parse - Validate with Zod function parse(response: string): Analysis { const jsonMatch = response.match(/\{[\s\S]*\}/); if (!jsonMatch) throw new Error("No JSON found in response"); const parsed = JSON.parse(jsonMatch[0]); return AnalysisSchema.parse(parsed); } // Stage 6: Render - Save to database async function render( tenant_id: string, content_id: string, analysis: Analysis ) { await db.update(contents) .set({ analysis_summary: analysis.summary, analysis_sentiment: analysis.sentiment, analysis_topics: analysis.topics, updated_at: new Date(), }) .where(and( eq(contents.tenant_id, tenant_id), eq(contents.id, content_id) )); return analysis; } // Main pipeline function export async function analyzeContent( tenant_id: string, content_id: string ): Promise<Analysis> { const cacheDir = join(process.cwd(), ".cache", "analyses", tenant_id); const content = await acquire(tenant_id, content_id); const prompt = prepare(content); const response = await process(prompt, cacheDir, content_id); const analysis = parse(response); await render(tenant_id, content_id, analysis); return analysis; } ``` #### Python Pipeline Example (FastAPI) ```python # app/pipelines/content_analyzer.py from pathlib import Path from pydantic import BaseModel from anthropic import Anthropic import json class Analysis(BaseModel): summary: str sentiment: str # positive | neutral | negative topics: list[str] action_items: list[str] class ContentAnalyzerPipeline: def __init__(self, tenant_id: str, cache_dir: Path | None = None): self.tenant_id = tenant_id self.cache_dir = cache_dir or Path(".cache/analyses") / tenant_id self.client = Anthropic() async def acquire(self, content_id: str, db: AsyncSession) -> Content: """Stage 1: Get content from database.""" result = await db.execute( select(Content).where( Content.tenant_id == self.tenant_id, Content.id == content_id ) ) content = result.scalar_one_or_none() if not content: raise ValueError(f"Content {content_id} not found") return content def prepare(self, content: Content) -> str: """Stage 2: Format prompt.""" return f"""Analyze this content and provide structured output. CONTENT: {content.body} Respond with JSON: {{ "summary": "2-3 sentence summary", "sentiment": "positive" | "neutral" | "negative", "topics": ["topic1", "topic2"], "action_items": ["action1"] }}""" async def process(self, prompt: str, cache_key: str) -> str: """Stage 3: LLM call with file-based caching.""" cache_path = self.cache_dir / f"{cache_key}.json" # Check cache if cache_path.exists(): return json.loads(cache_path.read_text())["response"] response = self.client.messages.create( model="claude-sonnet-4-20250514", max_tokens=1024, messages=[{"role": "user", "content": prompt}] ) text = response.content[0].text # Cache result self.cache_dir.mkdir(parents=True, exist_ok=True) cache_path.write_text(json.dumps({ "response": text, "timestamp": datetime.utcnow().isoformat() })) return text def parse(self, response: str) -> Analysis: """Stage 4: Parse and validate with Pydantic.""" import re match = re.search(r'\{[\s\S]*\}', response) if not match: raise ValueError("No JSON found in response") return Analysis.model_validate_json(match.group()) async def render( self, content_id: str, analysis: Analysis, db: AsyncSession ) -> Analysis: """Stage 5: Save to database.""" await db.execute( update(Content) .where( Content.tenant_id == self.tenant_id, Content.id == content_id ) .values( analysis_summary=analysis.summary, analysis_sentiment=analysis.sentiment, analysis_topics=analysis.topics, updated_at=datetime.utcnow() ) ) await db.commit() return analysis async def run(self, content_id: str, db: AsyncSession) -> Analysis: """Execute full pipeline.""" content = await self.acquire(content_id, db) prompt = self.prepare(content) response = await self.process(prompt, content_id) analysis = self.parse(response) return await self.render(content_id, analysis, db) ``` ### Phase 3: File System as State Machine **Key insight from Karpathy**: File existence determines work state. ```python # Pipeline state management def get_pipeline_state(work_dir: Path, item_id: str) -> str: """Determine pipeline state from file existence.""" item_dir = work_dir / item_id if not item_dir.exists(): return "pending" if not (item_dir / "raw.json").exists(): return "acquired" if not (item_dir / "prepared.txt").exists(): return "prepared" if not (item_dir / "response.json").exists(): return "processed" if not (item_dir / "analysis.json").exists(): return "parsed" return "complete"
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る