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에서 보기