npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@khaveeai/providers-rag

v0.1.3

Published

RAG (Retrieval-Augmented Generation) provider for Khavee AI SDK

Readme

@khaveeai/providers-rag

npm version License: MIT

Clean and easy-to-use RAG (Retrieval-Augmented Generation) provider for Khavee AI SDK. Seamlessly integrate vector search with your VRM avatar conversations.

✨ Features

  • 🔍 Vector Search - Powered by Qdrant for fast, accurate retrieval
  • 🤖 OpenAI Embeddings - Automatic embedding generation
  • 🎯 Zero Config - Works out of the box with sensible defaults
  • Easy Integration - One function to add RAG to your realtime chat
  • 🛠️ Flexible - Customize search parameters and context formatting
  • 📊 Metadata Support - Include source, title, and custom metadata

📦 Installation

npm install @khaveeai/providers-rag @khaveeai/providers-openai-realtime @khaveeai/react

🚀 Quick Start

1. Next.js with Server Actions (Recommended)

// app/lib/rag.ts
"use server"
import { RAGProvider } from "@khaveeai/providers-rag";

export async function searchKnowledgeBase(query: string) {
  const ragProvider = new RAGProvider({
    qdrantUrl: process.env.QDRANT_URL!,
    qdrantApiKey: process.env.QDRANT_API_KEY,
    collectionName: process.env.QDRANT_COLLECTION!,
    openaiApiKey: process.env.OPENAI_API_KEY!,
  });

  return await ragProvider.search(query);
}

// app/page.tsx
"use client";
import { OpenAIRealtimeProvider } from "@khaveeai/providers-openai-realtime";
import { KhaveeProvider, VRMAvatar } from "@khaveeai/react";
import { searchKnowledgeBase } from "./lib/rag";

const realtime = new OpenAIRealtimeProvider({
  apiKey: process.env.NEXT_PUBLIC_OPENAI_API_KEY!,
  instructions: "Use search_knowledge_base to answer questions accurately.",
  tools: [
    {
      name: "search_knowledge_base",
      description: "Search the knowledge base for relevant information",
      parameters: {
        query: {
          type: "string",
          description: "The search query",
          required: true,
        },
      },
      execute: async (args: { query: string }) => {
        return await searchKnowledgeBase(args.query);
      },
    },
  ],
});

export default function App() {
  return (
    <KhaveeProvider config={{ realtime }}>
      <Canvas>
        <VRMAvatar src="./models/avatar.vrm" />
      </Canvas>
    </KhaveeProvider>
  );
}

2. Environment Variables

# .env.local (Next.js)
# Server-side only (secure)
OPENAI_API_KEY=sk-...
QDRANT_URL=https://your-qdrant-instance.com
QDRANT_API_KEY=your-qdrant-key
QDRANT_COLLECTION=your-collection-name

# Client-side (public)
NEXT_PUBLIC_OPENAI_API_KEY=sk-...  # For OpenAI Realtime only

Security Note: RAG operations should use server-side keys (no NEXT_PUBLIC_ prefix) to keep your Qdrant and OpenAI embeddings API keys secure. Use Next.js server actions as shown above.


## ⚙️ Configuration

### RAGProvider Options

```tsx
const ragProvider = new RAGProvider({
  // Required
  qdrantUrl: "https://your-qdrant-instance.com",
  collectionName: "your-collection",
  openaiApiKey: "sk-...",
  
  // Optional
  qdrantApiKey: "your-key",              // Required for protected Qdrant instances
  embeddingModel: "text-embedding-3-large", // Default (3072 dimensions)
  topK: 10,                               // Number of results (default: 10)
  scoreThreshold: 0.21,                   // Minimum relevance (default: 0.21)
  includeMetadata: true,                  // Include metadata (default: true)
  metadataFields: ["title", "source"],    // Metadata to include
});

// Note: Make sure your Qdrant collection uses 3072-dimensional vectors
// if using text-embedding-3-large (default)

Custom Tool Configuration

const ragTool = createRAGTool({
  ragProvider,
  toolName: "search_docs",                // Custom tool name
  toolDescription: "Search product documentation", // Custom description
  promptTemplate: (query, context) =>     // Custom formatting
    `Question: ${query}\n\nRelevant docs:\n${context}`
});

📖 Usage Examples

Example 1: Customer Support Bot

import { RAGProvider, createRAGTool } from "@khaveeai/providers-rag";
import { OpenAIRealtimeProvider } from "@khaveeai/providers-openai-realtime";

const ragProvider = new RAGProvider({
  qdrantUrl: process.env.QDRANT_URL!,
  qdrantApiKey: process.env.QDRANT_API_KEY,
  collectionName: "customer-support-docs",
  openaiApiKey: process.env.NEXT_PUBLIC_OPENAI_API_KEY!,
  topK: 5,
  scoreThreshold: 0.3,
});

const supportTool = createRAGTool({
  ragProvider,
  toolName: "search_support_docs",
  toolDescription: "Search customer support documentation for answers",
});

const realtime = new OpenAIRealtimeProvider({
  apiKey: process.env.NEXT_PUBLIC_OPENAI_API_KEY!,
  instructions: `You are a helpful customer support assistant.
    Use the search_support_docs tool to find accurate answers from our documentation.
    Always cite your sources when using information from the knowledge base.`,
  tools: [supportTool],
  voice: "coral",
});

Example 2: Product Expert

const productRag = new RAGProvider({
  qdrantUrl: process.env.QDRANT_URL!,
  collectionName: "product-catalog",
  openaiApiKey: process.env.NEXT_PUBLIC_OPENAI_API_KEY!,
  metadataFields: ["title", "category", "price", "brand"],
});

const productTool = createRAGTool({
  ragProvider: productRag,
  toolName: "search_products",
  toolDescription: "Search product information and specifications",
  promptTemplate: (query, context) => 
    `Product search for: "${query}"\n\nMatching products:\n${context}\n\nUse this information to help the customer.`
});

const realtime = new OpenAIRealtimeProvider({
  apiKey: process.env.NEXT_PUBLIC_OPENAI_API_KEY!,
  instructions: "You are a product expert. Help customers find the right products.",
  tools: [productTool],
});

Example 3: Multi-Source RAG

// Multiple knowledge bases
const docsRag = new RAGProvider({
  qdrantUrl: process.env.QDRANT_URL!,
  collectionName: "documentation",
  openaiApiKey: process.env.NEXT_PUBLIC_OPENAI_API_KEY!,
});

const faqRag = new RAGProvider({
  qdrantUrl: process.env.QDRANT_URL!,
  collectionName: "faq",
  openaiApiKey: process.env.NEXT_PUBLIC_OPENAI_API_KEY!,
  topK: 3,
});

const tools = [
  createRAGTool({
    ragProvider: docsRag,
    toolName: "search_docs",
    toolDescription: "Search technical documentation",
  }),
  createRAGTool({
    ragProvider: faqRag,
    toolName: "search_faq",
    toolDescription: "Search frequently asked questions",
  }),
];

const realtime = new OpenAIRealtimeProvider({
  apiKey: process.env.NEXT_PUBLIC_OPENAI_API_KEY!,
  instructions: "Search docs for technical questions, FAQ for common questions.",
  tools,
});

🔧 Advanced Usage

Manual Context Preparation

const ragProvider = new RAGProvider({...});

// Get context without tool wrapper
const context = await ragProvider.prepareContext("What is VRM?");

console.log(context.query);             // Original query
console.log(context.documents);         // Array of documents
console.log(context.formattedContext);  // Formatted string

// Use in custom prompt
const prompt = await ragProvider.createPromptWithContext(
  "Explain VRM avatars",
  (query, context) => `${query}\n\nContext:\n${context}`
);

Update Configuration Dynamically

const ragProvider = new RAGProvider({...});

// Update search parameters
ragProvider.updateConfig({
  topK: 15,
  scoreThreshold: 0.4,
});

// Get current config
const config = ragProvider.getConfig();
console.log(config);

Direct Search

const ragProvider = new RAGProvider({...});

// Search directly
const results = await ragProvider.searchDocuments("query");

results.forEach(result => {
  console.log(result.id);
  console.log(result.score);
  console.log(result.payload);
});

📊 Data Structure

Expected Qdrant Payload Format

Your Qdrant documents should have this structure:

{
  "text": "Your document content here",
  "metadata": {
    "title": "Document Title",
    "source": "https://example.com",
    "category": "FAQ"
  }
}

Or with _node_content (like your Morritt project):

{
  "_node_content": "{\"text\":\"Content here\",\"metadata\":{\"title\":\"Title\"}}"
}

Both formats are automatically handled!

🎯 How It Works

  1. User asks a question → OpenAI Realtime API receives it
  2. AI decides to search → Calls your RAG tool automatically
  3. Generate embedding → OpenAI creates vector for query
  4. Search Qdrant → Finds most relevant documents
  5. Format context → Prepares formatted response
  6. AI responds → Uses context to answer accurately

🐛 Troubleshooting

"No relevant information found"

// Lower the score threshold
const ragProvider = new RAGProvider({
  scoreThreshold: 0.15, // Lower = more permissive
  topK: 20,             // Get more results
  // ...
});

Metadata not showing

const ragProvider = new RAGProvider({
  includeMetadata: true,
  metadataFields: ["title", "source", "author", "date"], // Add your fields
  // ...
});

Connection issues

# Test Qdrant connection
curl https://your-qdrant-instance.com/collections

# Test OpenAI API
curl https://api.openai.com/v1/models \
  -H "Authorization: Bearer $OPENAI_API_KEY"

📝 Complete Example

"use client";
import { KhaveeProvider, VRMAvatar, useRealtime } from "@khaveeai/react";
import { OpenAIRealtimeProvider } from "@khaveeai/providers-openai-realtime";
import { RAGProvider, createRAGTool } from "@khaveeai/providers-rag";
import { Canvas } from "@react-three/fiber";
import { Environment } from "@react-three/drei";

// Setup RAG
const ragProvider = new RAGProvider({
  qdrantUrl: process.env.QDRANT_URL!,
  qdrantApiKey: process.env.QDRANT_API_KEY,
  collectionName: process.env.QDRANT_COLLECTION!,
  openaiApiKey: process.env.NEXT_PUBLIC_OPENAI_API_KEY!,
  topK: 10,
  scoreThreshold: 0.21,
});

const ragTool = createRAGTool({
  ragProvider,
  toolName: "search_knowledge",
  toolDescription: "Search company knowledge base",
});

// Setup Realtime with RAG
const realtime = new OpenAIRealtimeProvider({
  apiKey: process.env.NEXT_PUBLIC_OPENAI_API_KEY!,
  instructions: `You are a knowledgeable assistant with access to our knowledge base.
    Use the search_knowledge tool when you need specific information to answer questions.
    Always provide accurate, helpful responses based on the available information.`,
  tools: [ragTool],
  voice: "coral",
});

// Monitor RAG usage
realtime.onToolCall = (toolName, args, result) => {
  console.log(`🔍 RAG Search: ${args.query}`);
  console.log(`📊 Result: ${result.success ? 'Found' : 'Not found'}`);
};

function Chat() {
  const { connect, isConnected, conversation, chatStatus } = useRealtime();
  
  return (
    <div>
      {!isConnected && <button onClick={connect}>Start Chat</button>}
      <div>Status: {chatStatus}</div>
      {conversation.map((msg, i) => (
        <div key={i}>{msg.role}: {msg.text}</div>
      ))}
    </div>
  );
}

export default function App() {
  return (
    <KhaveeProvider config={{ realtime }}>
      <Canvas>
        <VRMAvatar src="./models/avatar.vrm" position-y={-1.25} />
        <Environment preset="sunset" />
        <ambientLight intensity={0.5} />
      </Canvas>
      <Chat />
    </KhaveeProvider>
  );
}

📄 License

MIT License - see LICENSE file for details.

🤝 Support

🚀 Contributing

Contributions welcome! Please read our contributing guidelines and submit pull requests to our GitHub repository.