← Back to dashboard
pineconedatabasefresh

Pinecone Integration Guide

What is a vector database?

The real model

ANN indexes (HNSW) over learned embeddings — RAG's retrieval half.

Pinecone is serverless ANN search over dense, sparse, or hybrid vectors. The killer feature for everyone tired of running an embedding service is integrated inference: `createIndexForModel` binds an embedding model (e.g. `multilingual-e5-large`) to the index, so you `upsertRecords` and `searchRecords` with raw text — Pinecone embeds server-side. Records are scoped by `namespace` (per-tenant isolation, free). At query time you can layer a reranker on top of the ANN result to boost precision. For codeAmani the e5-large model is the unlock: Swahili and English live in the same 1024-dim space, so a Lugha-mixed user query retrieves either-language docs without translation.

The five primitives

Index holds the data; namespace isolates it; records carry it; sparse-dense and rerank turn good results into great ones. Tap a card to dig in.

Feel the top-K happen

Twelve documents across three topics, laid out where their meanings would put them. Click anywhere in the plot — or pick a preset — and watch the nearest neighbours re-rank. Real embeddings live in 384+ dimensions, but the intuition transfers: near in space ≈ near in meaning.

2D similarity playgroundquery at (50, 50)
Presets
Top-K
queryAIPayAuth

Tip: click anywhere in the plot to move the query — top-K updates instantly.

topK resultscosine ~ similarity
  1. 1RLS policies in Supabase85.8%
  2. 2Clerk session management82.5%
  3. 3JWT signing and verification79.8%
9 more docs not shown at this top-K.

In a real index these points live in 384–1024 dimensions, not two — but the rule is the same: documents about the same thing cluster together. Click halfway between two clusters and watch how the ranking mixes — that's the same behaviour you'd see on a query like “how do I bill for Daraja API access?” which sits between Payments and AI/Pricing.

The codeAmani angle: Pinecone's default multilingual-e5-large places Swahili and English about the same concept right next to each other — a query in either language retrieves docs in both, with zero translation step.

Text
██████╗ ██╗███╗   ██╗███████╗ ██████╗ ██████╗ ███╗   ██╗███████╗
██╔══██╗██║████╗  ██║██╔════╝██╔════╝██╔═══██╗████╗  ██║██╔════╝
██████╔╝██║██╔██╗ ██║█████╗  ██║     ██║   ██║██╔██╗ ██║█████╗
██╔═══╝ ██║██║╚██╗██║██╔══╝  ██║     ██║   ██║██║╚██╗██║██╔══╝
██║     ██║██║ ╚████║███████╗╚██████╗╚██████╔╝██║ ╚████║███████╗
╚═╝     ╚═╝╚═╝  ╚═══╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝  ╚═══╝╚══════╝

Pinecone Integration Guide

Focus: The retrieval layer for codeAmani's AI. Pinecone is a serverless vector database for RAG — store knowledge, retrieve the most relevant chunks, and feed them into a Claude prompt. With integrated inference you skip running an embedding model entirely; Pinecone embeds text server-side (incl. multilingual-e5-large for Swahili+English).

Overview

Two ways to use Pinecone — pick based on whether you want Pinecone to do the embedding:

  • Integrated inference (recommended for RAG): createIndexForModel binds an embedding model to the index. You then upsertRecords / searchRecords with raw text — no separate embeddings step, no vector math in your app. Optional server-side reranking (bge-reranker-v2-m3) sharpens results.
  • Bring-your-own-vectors: create a serverless index with an explicit dimension, embed text yourself (e.g. via the Vercel AI SDK / Gemini / OpenAI), then upsert / query raw vectors. Use when you need a specific embedding model.

Namespaces partition an index (e.g. per tenant/user) — the multi-tenant isolation primitive. In Claude Code, the Pinecone MCP can create indexes and search records directly.

Here is the integrated-inference path at a glance — notice the embedding happens server-side, so your app never touches a vector:

RAG decision notes

The headline trade-off — Pinecone's integrated inference vs. running your own embeddings — is summarized in the Insight callout at the top of this page. A few more decision points worth knowing:

  • When NOT to use integrated inference: if you need a specific embedding model (e.g. to match vectors you already store elsewhere, or a domain-tuned model), use the bring-your-own-vectors path (§4) and embed with the AI SDK instead.
  • Reranking earns its cost: a 2-stage retrieve→rerank (bge-reranker-v2-m3) noticeably lifts answer quality for FAQ/support RAG — keep topK wide (e.g. 20) and topN tight (e.g. 3).
  • Chunking matters more than the DB: retrieval quality is dominated by how you split source docs (size + overlap), not by Pinecone config — tune chunks first.
  • Serverless = scale-to-zero: no idle index cost, so spinning up a per-product knowledge base is cheap for early-stage SME features.

Chunking strategy

Since chunking dominates retrieval quality (see the note above), here is concrete guidance — all sizes are in tokens, not characters.

Size — start fixed, then iterate. Pinecone's chunking guide recommends starting with fixed-size chunking and only moving to fancier strategies once it proves insufficient. For sizing, the guide says to "start by exploring a variety of chunk sizes, including smaller chunks (e.g. 128 or 256 tokens) ... and larger chunks (e.g. 512 or 1024 tokens)" (pinecone.io/learn/chunking-strategies). Practical default for FAQ/support docs: ~512 tokens. Smaller chunks give sharper, more precise matches; larger chunks carry more context per hit but dilute the embedding.

Overlap — 10–20% is the commonly-documented range. Pinecone's guide itself does not prescribe a fixed overlap percentage; it instead favours chunk expansion (pulling neighbouring chunks at query time) to recover context. Across the broader RAG literature, a 10–20% overlap (e.g. 50–100 tokens on a 512-token chunk) is the widely-cited starting point to avoid splitting a sentence's meaning across a boundary. Treat it as a knob to tune, not gospel — some recent benchmarks find overlap adds indexing cost with little gain, so measure on your own corpus.

Semantic vs fixed splitting — when to switch:

  • Fixed-size (token windows + overlap): deterministic, fast, zero document understanding. Use as your default and for uniform text (support tickets, chat logs, plain prose).
  • Content-aware / recursive (split on \n\n, \n, sentences, then fall back): respects structure. Use for Markdown/HTML docs, USSD scripts, code where paragraph and heading boundaries are meaningful.
  • Semantic (embed sentences, cut where the topic shifts): highest quality, highest cost. Use only for long, topic-switching documents (multi-section policy/compliance PDFs) where fixed splitting visibly hurts answer quality.

Keep chunk_text (the field in your index fieldMap) as the only text field per record, and store source metadata (doc_id, section, chunk_index) so you can rebuild context.

TypeScript
// Fixed-size, overlapping chunker — run BEFORE upsertRecords (§2).
// Approximate tokens with a chars-per-token ratio (English ~4; tune for Swahili).
const CHARS_PER_TOKEN = 4;

function chunkText(
  text: string,
  { chunkTokens = 512, overlapTokens = 80 } = {},
): string[] {
  const size = chunkTokens * CHARS_PER_TOKEN;        // ~2048 chars
  const overlap = overlapTokens * CHARS_PER_TOKEN;    // ~320 chars
  const stride = Math.max(size - overlap, 1);         // guard: overlap < size
  const chunks: string[] = [];
  for (let start = 0; start < text.length; start += stride) {
    const slice = text.slice(start, start + size).trim();
    if (slice) chunks.push(slice);
  }
  return chunks;
}

// Wire chunks into the §2 integrated-inference upsert:
const records = chunkText(sourceDoc).map((chunk, i) => ({
  id: `faq-mpesa#${i}`,           // stable id = doc + chunk index
  chunk_text: chunk,             // must match the index fieldMap
  doc_id: "faq-mpesa",
  chunk_index: i,
  topic: "payments",
}));
await index.upsertRecords({ records });

Gotcha: chunk sizes are measured in tokens, but most splitters (including the char-based helper above) cut on characters. The ~4-chars-per-token ratio is an English approximation — Swahili and other non-English text often run fewer chars per token, so a "512-token" char window can silently overshoot the embedding model's context limit and get truncated server-side. For production, count with a real tokenizer (e.g. tiktoken / js-tiktoken) instead of a fixed ratio, and verify against your model's window (multilingual-e5-large = 512 tokens).

Official Documentation


1. Install + credentials

Bash
npm install @pinecone-database/pinecone     # JS/TS
pip install pinecone                         # Python 3.10+
Bash
PINECONE_API_KEY=...    # server-side only (.env.local / Vercel env, or Infisical)

2. RAG with integrated inference (no embedding layer) — TypeScript

TypeScript
import { Pinecone } from "@pinecone-database/pinecone";

const pc = new Pinecone({ apiKey: process.env.PINECONE_API_KEY! });

// 2a. Create an index bound to an embedding model (multilingual = Swahili + English)
const model = await pc.createIndexForModel({
  name: "kb",
  cloud: "aws",
  region: "us-east-1",
  embed: { model: "multilingual-e5-large", fieldMap: { text: "chunk_text" } },
  waitUntilReady: true,
});
const index = pc.index({ host: model.host });

// 2b. Upsert RAW TEXT — Pinecone embeds it server-side
await index.upsertRecords({
  records: [
    { id: "doc1", chunk_text: "M-Pesa STK Push prompts the user on their phone.", topic: "payments" },
    { id: "doc2", chunk_text: "Daraja tokens expire after one hour.", topic: "payments" },
  ],
});

// 2c. Search with a text query (+ optional rerank)
const hits = await index.searchRecords({
  query: { topK: 4, inputs: { text: "how does M-Pesa checkout work?" }, filter: { topic: { $eq: "payments" } } },
  rerank: { model: "bge-reranker-v2-m3", topN: 2, rankFields: ["chunk_text"] },
  fields: ["chunk_text", "topic"],
});

3. Close the RAG loop (Pinecone → Claude via the AI SDK)

You are one short hop from a full answer — retrieved chunks become Claude's context, with Pinecone as memory and Claude as generator:

TypeScript
import { generateText } from "ai";

const context = hits.result.hits.map(h => h.fields.chunk_text).join("\n---\n");
const { text } = await generateText({
  model: "anthropic/claude-sonnet-4-20250514",      // via Vercel AI Gateway
  prompt: `Answer using ONLY this context:\n${context}\n\nQ: How does M-Pesa checkout work?`,
});

4. Bring-your-own-vectors (Python, explicit dimension)

Python
from pinecone import Pinecone, ServerlessSpec
pc = Pinecone(api_key="...")
pc.indexes.create(name="kb", dimension=1536, metric="cosine",
                  spec=ServerlessSpec(cloud="aws", region="us-east-1"))
index = pc.index("kb")
index.upsert(vectors=[("id1", embedding_1536d)], namespace="tenant-a")
res = index.query(vector=query_vec, top_k=10, namespace="tenant-a")

codeAmani notes

  • Fills the retrieval gap: this is the missing layer for RAG over codeAmani docs/FAQs/ product knowledge. Retrieve top-k chunks, then pass them to Claude via the Vercel AI SDK (see vercel-ai-sdk). Keep Claude as the generator; Pinecone as the memory.
  • Multilingual by default: multilingual-e5-large embeds Swahili and English in one space — East-African content (mixed-language support FAQs, USSD scripts) works without a custom model. Strong fit for the AFRICAN_MARKET_GUIDE.md audience.
  • Multi-tenant: use a namespace per customer/SME for isolation (RLS-like separation).
  • Security: PINECONE_API_KEY is server-side only (.env.local / Vercel env, or move it into Infisical). Query from API routes / server actions, never the browser.
  • Cost: serverless pay-per-use; reads cost readUnits and reranking costs rerankUnits — cache hot queries (pairs with the Upstash cache) and keep topK/topN tight.
  • Claude Code: the Pinecone MCP (create-index-for-model, search-records, upsert-records) lets you build and inspect indexes interactively without leaving the editor.