v
vibecode
Все скиллы
01Скилл
Реализация
адапт. из anthropics/claude-cookbooks
RAG starter

AI знает твою базу знаний

Минимальный скелет RAG-приложения: pgvector, embeddings, поиск, ответ Claude. Стартовый шаблон для AI-помощника по любым документам.


01aКогда брать

Когда нужно сделать AI-чат который отвечает на вопросы по твоим данным (FAQ компании, документация продукта, корпоративная база знаний, учебник). NOT обычный AI-чат — а с источниками.

02Куда положить
<project>/lib/rag.ts

Создай эту папку и файл (если их нет), вставь содержимое ниже. Затем в Claude Code: /exit и запусти claude заново — команда появится.

03Содержимое

Скопируй всё что внутри блока и вставь в файл по пути выше.

rag.ts
1// Минимальный RAG на Postgres + pgvector + Claude2// Установка: npm i @anthropic-ai/sdk @ai-sdk/openai3 4import Anthropic from "@anthropic-ai/sdk";5import { db } from "./db";6 7const claude = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });8 9// ─── 1. Векторизация (один раз для каждого документа) ───10export async function indexDocument(text: string, source: string) {11  // Простой chunking по 1000 символов12  const chunks = text.match(/.{1,1000}/gs) ?? [];13 14  for (const chunk of chunks) {15    const embedding = await getEmbedding(chunk);16    await db.chunk.create({17      data: { text: chunk, source, embedding },18    });19  }20}21 22// ─── 2. Поиск + генерация ответа ───23export async function answer(question: string) {24  const qEmbedding = await getEmbedding(question);25 26  // top-5 похожих кусков27  const chunks = await db.$queryRaw`28    SELECT text, source FROM chunk29    ORDER BY embedding <=> ${qEmbedding}::vector30    LIMIT 531  `;32 33  const context = chunks.map((c: any) => `Источник: ${c.source}\n${c.text}`).join("\n---\n");34 35  const response = await claude.messages.create({36    model: "claude-sonnet-4-6",37    max_tokens: 1024,38    system: `Отвечай ТОЛЬКО на основе контекста ниже.39Если в контексте нет ответа — скажи "в документах не найдено".40В конце ответа укажи источники.`,41    messages: [{42      role: "user",43      content: `Контекст:\n${context}\n\nВопрос: ${question}`,44    }],45  });46 47  return response.content[0].type === "text" ? response.content[0].text : "";48}49 50// Embedding через OpenAI (дёшево и быстро)51async function getEmbedding(text: string): Promise<number[]> {52  const r = await fetch("https://api.openai.com/v1/embeddings", {53    method: "POST",54    headers: {55      "content-type": "application/json",56      authorization: `Bearer ${process.env.OPENAI_API_KEY}`,57    },58    body: JSON.stringify({59      model: "text-embedding-3-small",60      input: text,61    }),62  });63  const data = await r.json();64  return data.data[0].embedding;65}66 67// ─── Схема Prisma ───68// model Chunk {69//   id        Int    @id @default(autoincrement())70//   text      String71//   source    String72//   embedding Unsupported("vector(1536)")73//   @@index([embedding], type: Vector)74// }
04Как использовать

Примеры команд

  • 01AI-поддержка клиентов по FAQ
  • 02Юрист-бот по локальным законам
  • 03Учебный бот по конкретной книге