mcpField
L
llm-application-dev

llm-application-dev

github.com/moizibnyousaf開発1.2k463 回インストール5 週間前に更新
リポジトリ

llm-application-dev について

LLM アプリ開発向けのリファレンスで、プロンプト設計、API 呼び出し、RAG、エラー処理を扱います。キャッシュ、評価、プライバシーなど実装上の指針もまとめています。

主な機能

  1. 01構造化プロンプトと少数例
  2. 02OpenAI と Anthropic の API パターン
  3. 03ストリーミング応答の処理
  4. 04RAG、文書分割、埋め込み保存
  5. 05リトライとフォールバックによるエラー処理
  6. 06評価・キャッシュ・プライバシーの実践

活用シーン

  1. 01ルールと例を含むプロンプトの設計
  2. 02LLM API 接続とストリーミング出力の処理
  3. 03文書検索生成パイプラインの構築

インストール

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

$npx skills add https://github.com/moizibnyousaf/ai-agent-skills --skill llm-application-dev

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

詳細

LLM アプリケーション開発

プロンプトエンジニアリング

構造化プロンプト
const systemPrompt = `You are a helpful assistant that answers questions about our product.

RULES:
- Only answer questions about our product
- If you don't know, say "I don't know"
- Keep responses concise (under 100 words)
- Never make up information

CONTEXT:
{context}`;

const userPrompt = `Question: {question}`;
少数ショットの例
const prompt = `Classify the sentiment of customer feedback.

Examples:
Input: "Love this product!"
Output: positive

Input: "Worst purchase ever"
Output: negative

Input: "It works fine"
Output: neutral

Input: "${customerFeedback}"
Output:`;
思考の連鎖
const prompt = `Solve this step by step:

Question: ${question}

Let's think through this:
1. First, identify the key information
2. Then, determine the approach
3. Finally, calculate the answer

Step-by-step solution:`;

API 統合

OpenAI パターン
import OpenAI from 'openai';

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

async function chat(messages: Message[]): Promise<string> {
  const response = await openai.chat.completions.create({
    model: 'gpt-4',
    messages,
    temperature: 0.7,
    max_tokens: 500,
  });

  return response.choices[0].message.content ?? '';
}
Anthropic パターン
import Anthropic from '@anthropic-ai/sdk';

const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });

async function chat(prompt: string): Promise<string> {
  const response = await anthropic.messages.create({
    model: 'claude-3-opus-20240229',
    max_tokens: 1024,
    messages: [{ role: 'user', content: prompt }],
  });

  return response.content[0].type === 'text'
    ? response.content[0].text
    : '';
}
ストリーミング応答
async function* streamChat(prompt: string) {
  const stream = await openai.chat.completions.create({
    model: 'gpt-4',
    messages: [{ role: 'user', content: prompt }],
    stream: true,
  });

  for await (const chunk of stream) {
    const content = chunk.choices[0]?.delta?.content;
    if (content) yield content;
  }
}

RAG(検索拡張生成)

基本的な RAG パイプライン
async function ragQuery(question: string): Promise<string> {
  // 1. Embed the question
  const questionEmbedding = await embedText(question);

  // 2. Search vector database
  const relevantDocs = await vectorDb.search(questionEmbedding, { limit: 5 });

  // 3. Build context
  const context = relevantDocs.map(d => d.content).join('\n\n');

  // 4. Generate answer
  const prompt = `Answer based on this context:\n${context}\n\nQuestion: ${question}`;
  return await chat(prompt);
}
ドキュメントのチャンク分割
function chunkDocument(text: string, options: ChunkOptions): string[] {
  const { chunkSize = 1000, overlap = 200 } = options;
  const chunks: string[] = [];

  let start = 0;
  while (start < text.length) {
    const end = Math.min(start + chunkSize, text.length);
    chunks.push(text.slice(start, end));
    start += chunkSize - overlap;
  }

  return chunks;
}
埋め込みの保存
// Using Supabase with pgvector
async function storeEmbeddings(docs: Document[]) {
  for (const doc of docs) {
    const embedding = await embedText(doc.content);

    await supabase.from('documents').insert({
      content: doc.content,
      metadata: doc.metadata,
      embedding: embedding,  // vector column
    });
  }
}

async function searchSimilar(query: string, limit = 5) {
  const embedding = await embedText(query);

  const { data } = await supabase.rpc('match_documents', {
    query_embedding: embedding,
    match_count: limit,
  });

  return data;
}

エラー処理

async function safeLLMCall<T>(
  fn: () => Promise<T>,
  options: { retries?: number; fallback?: T }
): Promise<T> {
  const { retries = 3, fallback } = options;

  for (let i = 0; i < retries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.status === 429) {
        // Rate limit - exponential backoff
        await sleep(Math.pow(2, i) * 1000);
        continue;
      }
      if (i === retries - 1) {
        if (fallback !== undefined) return fallback;
        throw error;
      }
    }
  }
  throw new Error('Max retries exceeded');
}

ベストプラクティス

  • トークン管理:使用量を追跡し、上限を設定します
  • キャッシュ:埋め込みと一般的なクエリをキャッシュします
  • 評価:多様な入力でプロンプトをテストします
  • ガードレール:使用前に出力を検証します
  • ログ記録:デバッグ用にプロンプトと応答を記録します
  • コスト管理:単純なタスクにはより安価なモデルを使用します
  • レイテンシ:UX を向上させるため、応答をストリーミングします
  • プライバシー:個人を特定できる情報(PII)を外部 API に送信しないでください

コメント