chore: import upstream snapshot with attribution
Test Vector Database Adaptors / Test MCP Vector DB Tools (push) Has been cancelled
Tests / Code Quality (Ruff & Mypy) (push) Has been cancelled
Tests / Fast Unit Tests (parallel) (macos-latest, 3.11) (push) Has been cancelled
Tests / Fast Unit Tests (parallel) (macos-latest, 3.12) (push) Has been cancelled
Tests / Tests (push) Has been cancelled
Docker Publish / Build and Push Docker Images (map[description:Skill Seekers CLI - Convert documentation to AI skills dockerfile:Dockerfile name:skill-seekers]) (push) Has been cancelled
Docker Publish / Build and Push Docker Images (map[description:Skill Seekers MCP Server - 25 tools for AI assistants dockerfile:Dockerfile.mcp name:skill-seekers-mcp]) (push) Has been cancelled
Docker Publish / Test Docker Images (push) Has been cancelled
Tests / Fast Unit Tests (parallel) (ubuntu-latest, 3.10) (push) Has been cancelled
Tests / Fast Unit Tests (parallel) (ubuntu-latest, 3.11) (push) Has been cancelled
Tests / Fast Unit Tests (parallel) (ubuntu-latest, 3.12) (push) Has been cancelled
Tests / Serial / Integration / E2E Tests (push) Has been cancelled
Tests / MCP Server Tests (push) Has been cancelled
Test Vector Database Adaptors / Test chroma Adaptor (push) Has been cancelled
Test Vector Database Adaptors / Test faiss Adaptor (push) Has been cancelled
Test Vector Database Adaptors / Test qdrant Adaptor (push) Has been cancelled
Test Vector Database Adaptors / Test weaviate Adaptor (push) Has been cancelled
Test Vector Database Adaptors / Test MCP Vector DB Tools (push) Has been cancelled
Tests / Code Quality (Ruff & Mypy) (push) Has been cancelled
Tests / Fast Unit Tests (parallel) (macos-latest, 3.11) (push) Has been cancelled
Tests / Fast Unit Tests (parallel) (macos-latest, 3.12) (push) Has been cancelled
Tests / Tests (push) Has been cancelled
Docker Publish / Build and Push Docker Images (map[description:Skill Seekers CLI - Convert documentation to AI skills dockerfile:Dockerfile name:skill-seekers]) (push) Has been cancelled
Docker Publish / Build and Push Docker Images (map[description:Skill Seekers MCP Server - 25 tools for AI assistants dockerfile:Dockerfile.mcp name:skill-seekers-mcp]) (push) Has been cancelled
Docker Publish / Test Docker Images (push) Has been cancelled
Tests / Fast Unit Tests (parallel) (ubuntu-latest, 3.10) (push) Has been cancelled
Tests / Fast Unit Tests (parallel) (ubuntu-latest, 3.11) (push) Has been cancelled
Tests / Fast Unit Tests (parallel) (ubuntu-latest, 3.12) (push) Has been cancelled
Tests / Serial / Integration / E2E Tests (push) Has been cancelled
Tests / MCP Server Tests (push) Has been cancelled
Test Vector Database Adaptors / Test chroma Adaptor (push) Has been cancelled
Test Vector Database Adaptors / Test faiss Adaptor (push) Has been cancelled
Test Vector Database Adaptors / Test qdrant Adaptor (push) Has been cancelled
Test Vector Database Adaptors / Test weaviate Adaptor (push) Has been cancelled
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,695 @@
|
||||
# Using Skill Seekers with Cursor IDE
|
||||
|
||||
**Last Updated:** February 5, 2026
|
||||
**Status:** Production Ready
|
||||
**Difficulty:** Easy ⭐
|
||||
|
||||
---
|
||||
|
||||
## 🎯 The Problem
|
||||
|
||||
Cursor IDE offers powerful AI coding assistance, but:
|
||||
|
||||
- **Generic Knowledge** - AI doesn't know your project-specific frameworks
|
||||
- **No Custom Context** - Can't reference your internal docs or codebase patterns
|
||||
- **Manual Context** - Copy-pasting documentation is tedious and error-prone
|
||||
- **Inconsistent** - AI responses vary based on what context you provide
|
||||
|
||||
**Example:**
|
||||
> "When building a Django app in Cursor, the AI might suggest outdated patterns or miss project-specific conventions. You want the AI to 'know' your framework documentation without manual prompting."
|
||||
|
||||
---
|
||||
|
||||
## ✨ The Solution
|
||||
|
||||
Use Skill Seekers to create **custom documentation** for Cursor's AI:
|
||||
|
||||
1. **Generate structured docs** from any framework or codebase
|
||||
2. **Package as .cursorrules** - Cursor's custom instruction format
|
||||
3. **Automatic Context** - AI references your docs in every interaction
|
||||
4. **Project-Specific** - Different rules per project
|
||||
|
||||
**Result:**
|
||||
Cursor's AI becomes an expert in your frameworks with persistent, automatic context.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Start (5 Minutes)
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Cursor IDE installed (https://cursor.sh/)
|
||||
- Python 3.10+ (for Skill Seekers)
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
# Install Skill Seekers
|
||||
pip install skill-seekers
|
||||
|
||||
# Verify installation
|
||||
skill-seekers --version
|
||||
```
|
||||
|
||||
### Generate .cursorrules
|
||||
|
||||
```bash
|
||||
# Example: Django framework
|
||||
skill-seekers create --config configs/django.json
|
||||
|
||||
# Package for Cursor
|
||||
skill-seekers package output/django --target markdown
|
||||
|
||||
# Extract SKILL.md (this becomes your .cursorrules content)
|
||||
# output/django-markdown/SKILL.md
|
||||
```
|
||||
|
||||
### Setup in Cursor
|
||||
|
||||
**Option 1: Global Rules** (applies to all projects)
|
||||
```bash
|
||||
# Copy to Cursor's global config
|
||||
cp output/django-markdown/SKILL.md ~/.cursor/.cursorrules
|
||||
```
|
||||
|
||||
**Option 2: Project-Specific Rules** (recommended)
|
||||
```bash
|
||||
# Copy to your project root
|
||||
cp output/django-markdown/SKILL.md /path/to/your/project/.cursorrules
|
||||
```
|
||||
|
||||
**Option 3: Multiple Frameworks**
|
||||
```bash
|
||||
# Create modular rules file
|
||||
cat > /path/to/your/project/.cursorrules << 'EOF'
|
||||
# Django Framework Expert
|
||||
You are an expert in Django. Use the following documentation:
|
||||
|
||||
EOF
|
||||
|
||||
# Append Django docs
|
||||
cat output/django-markdown/SKILL.md >> /path/to/your/project/.cursorrules
|
||||
|
||||
# Add React if needed
|
||||
echo "\n\n# React Framework Expert\n" >> /path/to/your/project/.cursorrules
|
||||
cat output/react-markdown/SKILL.md >> /path/to/your/project/.cursorrules
|
||||
```
|
||||
|
||||
### Test in Cursor
|
||||
|
||||
1. Open your project in Cursor
|
||||
2. Open any file (`.py`, `.js`, etc.)
|
||||
3. Use Cursor's AI chat (Cmd+K or Cmd+L)
|
||||
4. Ask: "How do I create a Django model with relationships?"
|
||||
|
||||
**Expected:** AI responds using patterns and examples from your .cursorrules!
|
||||
|
||||
---
|
||||
|
||||
## 📖 Detailed Setup Guide
|
||||
|
||||
### Step 1: Choose Your Documentation Source
|
||||
|
||||
**Option A: Framework Documentation**
|
||||
```bash
|
||||
# Available presets: django, fastapi, react, vue, etc.
|
||||
skill-seekers create --config configs/react.json
|
||||
skill-seekers package output/react --target markdown
|
||||
```
|
||||
|
||||
**Option B: GitHub Repository**
|
||||
```bash
|
||||
# Scrape from GitHub repo
|
||||
skill-seekers create facebook/react --name react
|
||||
skill-seekers package output/react --target markdown
|
||||
```
|
||||
|
||||
**Option C: Local Codebase**
|
||||
```bash
|
||||
# Analyze your own codebase
|
||||
skill-seekers create /path/to/repo --preset comprehensive
|
||||
skill-seekers package output/codebase --target markdown
|
||||
```
|
||||
|
||||
**Option D: Multiple Sources**
|
||||
```bash
|
||||
# Combine docs + code via a unified config (sources array with docs + github)
|
||||
skill-seekers create --config configs/fastapi-unified.json
|
||||
|
||||
skill-seekers package output/fastapi-complete --target markdown
|
||||
```
|
||||
|
||||
### Step 2: Optimize for Cursor
|
||||
|
||||
Cursor has a **200KB limit** for .cursorrules. Skill Seekers markdown output is optimized, but for very large documentation:
|
||||
|
||||
**Strategy 1: Summarize (Recommended)**
|
||||
```bash
|
||||
# Use AI enhancement to create concise version
|
||||
skill-seekers enhance output/django --mode LOCAL
|
||||
|
||||
# Result: More concise, better structured SKILL.md
|
||||
```
|
||||
|
||||
**Strategy 2: Split by Category**
|
||||
```bash
|
||||
# Create separate rules files per category
|
||||
# In your .cursorrules:
|
||||
cat > .cursorrules << 'EOF'
|
||||
# Django Models Expert
|
||||
You are an expert in Django models and ORM.
|
||||
|
||||
When working with Django models, reference these patterns:
|
||||
EOF
|
||||
|
||||
# Extract only models category from references/
|
||||
cat output/django/references/models.md >> .cursorrules
|
||||
```
|
||||
|
||||
**Strategy 3: Router Approach**
|
||||
```bash
|
||||
# Use a router skill (split large docs, then generate the router)
|
||||
python -m skill_seekers.cli.split_config configs/django.json --strategy router
|
||||
|
||||
# Result: Lightweight architectural guide
|
||||
cat output/django/ARCHITECTURE.md > .cursorrules
|
||||
```
|
||||
|
||||
### Step 3: Configure Cursor Settings
|
||||
|
||||
**.cursorrules format:**
|
||||
```markdown
|
||||
# Framework Expert Instructions
|
||||
|
||||
You are an expert in [Framework Name]. Follow these guidelines:
|
||||
|
||||
## Core Concepts
|
||||
[Your documentation here]
|
||||
|
||||
## Common Patterns
|
||||
[Patterns from Skill Seekers]
|
||||
|
||||
## Code Examples
|
||||
[Examples from documentation]
|
||||
|
||||
## Best Practices
|
||||
- Pattern 1
|
||||
- Pattern 2
|
||||
|
||||
## Anti-Patterns to Avoid
|
||||
- Anti-pattern 1
|
||||
- Anti-pattern 2
|
||||
```
|
||||
|
||||
**Cursor respects this structure** and uses it as persistent context.
|
||||
|
||||
### Step 4: Test and Refine
|
||||
|
||||
**Good prompts to test:**
|
||||
```
|
||||
1. "Create a [Framework] component that does X"
|
||||
2. "What's the recommended pattern for Y in [Framework]?"
|
||||
3. "Refactor this code to follow [Framework] best practices"
|
||||
4. "Explain how [Specific Feature] works in [Framework]"
|
||||
```
|
||||
|
||||
**Signs it's working:**
|
||||
- AI mentions specific framework concepts
|
||||
- Suggests code matching documentation patterns
|
||||
- References framework-specific terminology
|
||||
- Provides accurate, up-to-date examples
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Advanced Usage
|
||||
|
||||
### Multi-Framework Projects
|
||||
|
||||
```bash
|
||||
# Generate rules for full-stack project
|
||||
skill-seekers create --config configs/fastapi.json
|
||||
skill-seekers create --config configs/react.json
|
||||
skill-seekers create --config configs/postgresql.json
|
||||
|
||||
skill-seekers package output/fastapi --target markdown
|
||||
skill-seekers package output/react --target markdown
|
||||
skill-seekers package output/postgresql --target markdown
|
||||
|
||||
# Combine into single .cursorrules
|
||||
cat > .cursorrules << 'EOF'
|
||||
# Full-Stack Expert (FastAPI + React + PostgreSQL)
|
||||
|
||||
You are an expert in full-stack development using FastAPI, React, and PostgreSQL.
|
||||
|
||||
---
|
||||
# Backend: FastAPI
|
||||
EOF
|
||||
|
||||
cat output/fastapi-markdown/SKILL.md >> .cursorrules
|
||||
|
||||
echo "\n\n---\n# Frontend: React\n" >> .cursorrules
|
||||
cat output/react-markdown/SKILL.md >> .cursorrules
|
||||
|
||||
echo "\n\n---\n# Database: PostgreSQL\n" >> .cursorrules
|
||||
cat output/postgresql-markdown/SKILL.md >> .cursorrules
|
||||
```
|
||||
|
||||
### Project-Specific Patterns
|
||||
|
||||
```bash
|
||||
# Analyze your codebase
|
||||
skill-seekers create . --preset comprehensive
|
||||
|
||||
# Extract patterns and architecture
|
||||
cat output/codebase/SKILL.md > .cursorrules
|
||||
|
||||
# Add custom instructions
|
||||
cat >> .cursorrules << 'EOF'
|
||||
|
||||
## Project-Specific Guidelines
|
||||
|
||||
### Architecture
|
||||
- Use EventBus pattern for cross-component communication
|
||||
- All API calls go through services/api.ts
|
||||
- State management with Zustand (not Redux)
|
||||
|
||||
### Naming Conventions
|
||||
- Components: PascalCase (e.g., UserProfile.tsx)
|
||||
- Hooks: camelCase with 'use' prefix (e.g., useAuth.ts)
|
||||
- Utils: camelCase (e.g., formatDate.ts)
|
||||
|
||||
### Testing
|
||||
- Unit tests: *.test.ts
|
||||
- Integration tests: *.integration.test.ts
|
||||
- Use vitest, not jest
|
||||
EOF
|
||||
```
|
||||
|
||||
### Dynamic Context per File Type
|
||||
|
||||
Cursor supports **directory-specific rules**:
|
||||
|
||||
```bash
|
||||
# Backend rules (for Python files)
|
||||
cat output/fastapi-markdown/SKILL.md > backend/.cursorrules
|
||||
|
||||
# Frontend rules (for TypeScript files)
|
||||
cat output/react-markdown/SKILL.md > frontend/.cursorrules
|
||||
|
||||
# Database rules (for SQL files)
|
||||
cat output/postgresql-markdown/SKILL.md > database/.cursorrules
|
||||
```
|
||||
|
||||
When you open a file, Cursor uses the closest `.cursorrules` in the directory tree.
|
||||
|
||||
### Cursor + RAG Pipeline
|
||||
|
||||
For **massive documentation** (>200KB):
|
||||
|
||||
1. **Use Pinecone/Chroma for vector storage**
|
||||
2. **Use Cursor for code generation**
|
||||
3. **Build API to query vectors**
|
||||
|
||||
```python
|
||||
# cursor_rag.py - Custom Cursor context provider
|
||||
from pinecone import Pinecone
|
||||
from openai import OpenAI
|
||||
|
||||
def get_relevant_docs(query: str, top_k: int = 3) -> str:
|
||||
"""Fetch relevant docs from vector store."""
|
||||
pc = Pinecone()
|
||||
index = pc.Index("framework-docs")
|
||||
|
||||
# Create query embedding
|
||||
openai_client = OpenAI()
|
||||
response = openai_client.embeddings.create(
|
||||
model="text-embedding-ada-002",
|
||||
input=query
|
||||
)
|
||||
query_embedding = response.data[0].embedding
|
||||
|
||||
# Query Pinecone
|
||||
results = index.query(
|
||||
vector=query_embedding,
|
||||
top_k=top_k,
|
||||
include_metadata=True
|
||||
)
|
||||
|
||||
# Format for Cursor
|
||||
context = "\n\n".join([
|
||||
f"**{m['metadata']['category']}**: {m['metadata']['text']}"
|
||||
for m in results["matches"]
|
||||
])
|
||||
|
||||
return context
|
||||
|
||||
# Usage in .cursorrules
|
||||
# "When answering questions, first call cursor_rag.py to get relevant context"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 Best Practices
|
||||
|
||||
### 1. Keep Rules Focused
|
||||
|
||||
**Good:**
|
||||
```markdown
|
||||
# Django ORM Expert
|
||||
You are an expert in Django's ORM system.
|
||||
|
||||
Focus on:
|
||||
- Model definitions
|
||||
- QuerySets and managers
|
||||
- Database relationships
|
||||
- Migrations
|
||||
|
||||
[Detailed ORM documentation]
|
||||
```
|
||||
|
||||
**Bad:**
|
||||
```markdown
|
||||
# Everything Expert
|
||||
You know everything about Django, React, AWS, Docker, and 50 other technologies...
|
||||
[Huge wall of text]
|
||||
```
|
||||
|
||||
### 2. Use Hierarchical Structure
|
||||
|
||||
```markdown
|
||||
# Framework Expert
|
||||
|
||||
## 1. Core Concepts (High-level)
|
||||
Brief overview of key concepts
|
||||
|
||||
## 2. Common Patterns (Mid-level)
|
||||
Practical patterns and examples
|
||||
|
||||
## 3. API Reference (Low-level)
|
||||
Detailed API documentation
|
||||
|
||||
## 4. Troubleshooting
|
||||
Common issues and solutions
|
||||
```
|
||||
|
||||
### 3. Include Anti-Patterns
|
||||
|
||||
```markdown
|
||||
## Anti-Patterns to Avoid
|
||||
|
||||
❌ **DON'T** use class-based components in React
|
||||
✅ **DO** use functional components with hooks
|
||||
|
||||
❌ **DON'T** mutate state directly
|
||||
✅ **DO** use setState or useState updater function
|
||||
```
|
||||
|
||||
### 4. Add Code Examples
|
||||
|
||||
```markdown
|
||||
## Creating a Django Model
|
||||
|
||||
✅ **Recommended Pattern:**
|
||||
```python
|
||||
from django.db import models
|
||||
|
||||
class Product(models.Model):
|
||||
name = models.CharField(max_length=200)
|
||||
price = models.DecimalField(max_digits=10, decimal_places=2)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ['-created_at']
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
```
|
||||
|
||||
### 5. Update Regularly
|
||||
|
||||
```bash
|
||||
# Set up monthly refresh
|
||||
crontab -e
|
||||
|
||||
# Add line to regenerate rules monthly
|
||||
0 0 1 * * cd ~/projects && skill-seekers create --config configs/django.json && skill-seekers package output/django --target markdown && cp output/django-markdown/SKILL.md ~/.cursorrules
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔥 Real-World Examples
|
||||
|
||||
### Example 1: Django + React Full-Stack
|
||||
|
||||
**.cursorrules:**
|
||||
```markdown
|
||||
# Full-Stack Developer Expert (Django + React)
|
||||
|
||||
## Backend: Django REST Framework
|
||||
|
||||
You are an expert in Django and Django REST Framework.
|
||||
|
||||
### Serializers
|
||||
Always use ModelSerializer for database models:
|
||||
```python
|
||||
from rest_framework import serializers
|
||||
from .models import User
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ['id', 'username', 'email', 'date_joined']
|
||||
read_only_fields = ['id', 'date_joined']
|
||||
```
|
||||
|
||||
### ViewSets
|
||||
Use ViewSets for CRUD operations:
|
||||
```python
|
||||
from rest_framework import viewsets
|
||||
|
||||
class UserViewSet(viewsets.ModelViewSet):
|
||||
queryset = User.objects.all()
|
||||
serializer_class = UserSerializer
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Frontend: React + TypeScript
|
||||
|
||||
You are an expert in React with TypeScript.
|
||||
|
||||
### Components
|
||||
Always type props and use functional components:
|
||||
```typescript
|
||||
interface UserProps {
|
||||
user: User;
|
||||
onUpdate: (user: User) => void;
|
||||
}
|
||||
|
||||
export function UserProfile({ user, onUpdate }: UserProps) {
|
||||
// Component logic
|
||||
}
|
||||
```
|
||||
|
||||
### API Calls
|
||||
Use TanStack Query for data fetching:
|
||||
```typescript
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
function useUser(id: string) {
|
||||
return useQuery({
|
||||
queryKey: ['user', id],
|
||||
queryFn: () => api.getUser(id),
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Project Conventions
|
||||
|
||||
- Backend: `/api/v1/` prefix for all endpoints
|
||||
- Frontend: `/src/features/` for feature-based organization
|
||||
- Tests: Co-located with source files (`.test.ts`)
|
||||
- API client: `src/lib/api.ts` (single source of truth)
|
||||
```
|
||||
|
||||
### Example 2: Godot Game Engine
|
||||
|
||||
**.cursorrules:**
|
||||
```markdown
|
||||
# Godot 4.x Game Developer Expert
|
||||
|
||||
You are an expert in Godot 4.x game development with GDScript.
|
||||
|
||||
## Scene Structure
|
||||
Always use scene tree hierarchy:
|
||||
- Root node matches script class name
|
||||
- Group related nodes under containers
|
||||
- Use descriptive node names (PascalCase)
|
||||
|
||||
## Signals
|
||||
Prefer signals over direct function calls:
|
||||
```gdscript
|
||||
# Declare signal
|
||||
signal health_changed(new_health: int)
|
||||
|
||||
# Emit signal
|
||||
health_changed.emit(current_health)
|
||||
|
||||
# Connect in parent
|
||||
player.health_changed.connect(_on_player_health_changed)
|
||||
```
|
||||
|
||||
## Node Access
|
||||
Use @onready for node references:
|
||||
```gdscript
|
||||
@onready var sprite = $Sprite2D
|
||||
@onready var animation_player = $AnimationPlayer
|
||||
```
|
||||
|
||||
## Project Patterns (from codebase analysis)
|
||||
|
||||
### EventBus Pattern
|
||||
Use autoload EventBus for global events:
|
||||
```gdscript
|
||||
# EventBus.gd (autoload)
|
||||
signal game_started
|
||||
signal game_over(score: int)
|
||||
|
||||
# In any script
|
||||
EventBus.game_started.emit()
|
||||
```
|
||||
|
||||
### Resource-Based Data
|
||||
Store game data in Resources:
|
||||
```gdscript
|
||||
# item_data.gd
|
||||
class_name ItemData extends Resource
|
||||
|
||||
@export var item_name: String
|
||||
@export var icon: Texture2D
|
||||
@export var price: int
|
||||
```
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Issue: .cursorrules Not Loading
|
||||
|
||||
**Solutions:**
|
||||
```bash
|
||||
# 1. Check file location
|
||||
ls -la .cursorrules # Project root
|
||||
ls -la ~/.cursor/.cursorrules # Global
|
||||
|
||||
# 2. Verify file is UTF-8
|
||||
file .cursorrules
|
||||
|
||||
# 3. Restart Cursor completely
|
||||
# Cmd+Q (macOS) or Alt+F4 (Windows), then reopen
|
||||
|
||||
# 4. Check Cursor settings
|
||||
# Settings > Features > Ensure "Custom Instructions" is enabled
|
||||
```
|
||||
|
||||
### Issue: Rules Too Large (>200KB)
|
||||
|
||||
**Solutions:**
|
||||
```bash
|
||||
# Check file size
|
||||
ls -lh .cursorrules
|
||||
|
||||
# Reduce size:
|
||||
# 1. Use --enhance to create concise version
|
||||
skill-seekers enhance output/django --mode LOCAL
|
||||
|
||||
# 2. Extract only essential sections
|
||||
cat output/django/SKILL.md | head -n 1000 > .cursorrules
|
||||
|
||||
# 3. Use category-specific rules (split by directory)
|
||||
cat output/django/references/models.md > models/.cursorrules
|
||||
cat output/django/references/views.md > views/.cursorrules
|
||||
```
|
||||
|
||||
### Issue: AI Not Using Rules
|
||||
|
||||
**Diagnostics:**
|
||||
```
|
||||
1. Ask Cursor: "What frameworks do you know about?"
|
||||
- If it mentions your framework, rules are loaded
|
||||
- If not, rules aren't loading
|
||||
|
||||
2. Test with specific prompt:
|
||||
"Create a [Framework-specific concept]"
|
||||
- Should use terminology from your docs
|
||||
|
||||
3. Check Cursor's response format:
|
||||
- Does it match patterns from your docs?
|
||||
- Does it mention framework-specific features?
|
||||
```
|
||||
|
||||
**Solutions:**
|
||||
- Restart Cursor
|
||||
- Verify .cursorrules is in correct location
|
||||
- Check file size (<200KB)
|
||||
- Test with simpler rules first
|
||||
|
||||
### Issue: Inconsistent AI Responses
|
||||
|
||||
**Solutions:**
|
||||
```markdown
|
||||
# Add explicit instructions at top of .cursorrules:
|
||||
|
||||
# IMPORTANT: Always reference the patterns and examples below
|
||||
# When suggesting code, use the exact patterns shown
|
||||
# When explaining concepts, use the terminology defined here
|
||||
# If you don't know something, say so - don't make up patterns
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Before vs After Comparison
|
||||
|
||||
| Aspect | Without Skill Seekers | With Skill Seekers |
|
||||
|--------|---------------------|-------------------|
|
||||
| **Context** | Generic, manual | Framework-specific, automatic |
|
||||
| **Accuracy** | 60-70% (generic knowledge) | 90-95% (project-specific) |
|
||||
| **Consistency** | Varies by prompt | Consistent across sessions |
|
||||
| **Setup Time** | Manual copy-paste each time | One-time setup (5 min) |
|
||||
| **Updates** | Manual re-prompting | Regenerate .cursorrules (2 min) |
|
||||
| **Multi-Framework** | Confusing, mixed knowledge | Clear separation per project |
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Community & Support
|
||||
|
||||
- **Questions:** [GitHub Discussions](https://github.com/yusufkaraaslan/Skill_Seekers/discussions)
|
||||
- **Issues:** [GitHub Issues](https://github.com/yusufkaraaslan/Skill_Seekers/issues)
|
||||
- **Documentation:** [https://skillseekersweb.com/](https://skillseekersweb.com/)
|
||||
- **Cursor Forum:** [https://forum.cursor.sh/](https://forum.cursor.sh/)
|
||||
|
||||
---
|
||||
|
||||
## 📚 Related Guides
|
||||
|
||||
- [LangChain Integration](./LANGCHAIN.md)
|
||||
- [LlamaIndex Integration](./LLAMA_INDEX.md)
|
||||
- [Pinecone Integration](./PINECONE.md)
|
||||
- [RAG Pipelines Overview](./RAG_PIPELINES.md)
|
||||
|
||||
---
|
||||
|
||||
## 📖 Next Steps
|
||||
|
||||
1. **Generate your first .cursorrules** from a framework you use
|
||||
2. **Test in Cursor** with framework-specific prompts
|
||||
3. **Refine and iterate** based on AI responses
|
||||
4. **Share your .cursorrules** with your team
|
||||
5. **Automate updates** with monthly regeneration
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** February 5, 2026
|
||||
**Tested With:** Cursor 0.41+, Claude Sonnet 4.5
|
||||
**Skill Seekers Version:** v3.6.0
|
||||
@@ -0,0 +1,583 @@
|
||||
# FAISS Integration with Skill Seekers
|
||||
|
||||
**Status:** ✅ Production Ready
|
||||
**Difficulty:** Intermediate
|
||||
**Last Updated:** February 7, 2026
|
||||
|
||||
---
|
||||
|
||||
## ❌ The Problem
|
||||
|
||||
Building RAG applications with FAISS involves several challenges:
|
||||
|
||||
1. **Manual Index Configuration** - Choosing the right FAISS index type (Flat, IVF, HNSW, PQ) requires deep understanding
|
||||
2. **Embedding Management** - Need to generate and store embeddings separately, track document IDs manually
|
||||
3. **Billion-Scale Complexity** - Optimizing for large datasets (>1M vectors) requires index training and parameter tuning
|
||||
|
||||
**Example Pain Point:**
|
||||
|
||||
```python
|
||||
# Manual FAISS setup for each framework
|
||||
import faiss
|
||||
import numpy as np
|
||||
from openai import OpenAI
|
||||
|
||||
# Generate embeddings
|
||||
client = OpenAI()
|
||||
embeddings = []
|
||||
for doc in documents:
|
||||
response = client.embeddings.create(
|
||||
model="text-embedding-ada-002",
|
||||
input=doc
|
||||
)
|
||||
embeddings.append(response.data[0].embedding)
|
||||
|
||||
# Create index
|
||||
dimension = 1536
|
||||
index = faiss.IndexFlatL2(dimension)
|
||||
index.add(np.array(embeddings))
|
||||
|
||||
# Save index + metadata separately (complex!)
|
||||
faiss.write_index(index, "index.faiss")
|
||||
# ... manually track which ID maps to which document
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ The Solution
|
||||
|
||||
Skill Seekers automates FAISS integration with structured, production-ready data:
|
||||
|
||||
**Benefits:**
|
||||
- ✅ Auto-formatted documents with consistent metadata
|
||||
- ✅ Works with LangChain FAISS wrapper for easy ID tracking
|
||||
- ✅ Supports flat (small datasets) and IVF (large datasets) indexes
|
||||
- ✅ GPU acceleration compatible (billion-scale search)
|
||||
- ✅ Serialization-ready for production deployment
|
||||
|
||||
**Result:** 10-minute setup, production-ready similarity search that scales to billions of vectors.
|
||||
|
||||
---
|
||||
|
||||
## ⚡ Quick Start (10 Minutes)
|
||||
|
||||
### Prerequisites
|
||||
|
||||
```bash
|
||||
# Install FAISS (CPU version)
|
||||
pip install faiss-cpu>=1.7.4
|
||||
|
||||
# For GPU support (if available)
|
||||
pip install faiss-gpu>=1.7.4
|
||||
|
||||
# Install LangChain for easy FAISS wrapper
|
||||
pip install langchain>=0.1.0 langchain-community>=0.0.20
|
||||
|
||||
# OpenAI for embeddings
|
||||
pip install openai>=1.0.0
|
||||
|
||||
# Or with Skill Seekers
|
||||
pip install skill-seekers[all-llms]
|
||||
```
|
||||
|
||||
**What you need:**
|
||||
- Python 3.10+
|
||||
- OpenAI API key (for embeddings)
|
||||
- Optional: CUDA GPU for billion-scale search
|
||||
|
||||
### Generate FAISS-Ready Documents
|
||||
|
||||
```bash
|
||||
# Step 1: Scrape documentation
|
||||
skill-seekers create --config configs/react.json
|
||||
|
||||
# Step 2: Package for LangChain (FAISS-compatible)
|
||||
skill-seekers package output/react --target langchain
|
||||
|
||||
# Output: output/react-langchain.json (FAISS-ready)
|
||||
```
|
||||
|
||||
### Create FAISS Index with LangChain
|
||||
|
||||
```python
|
||||
import json
|
||||
from langchain.vectorstores import FAISS
|
||||
from langchain.embeddings import OpenAIEmbeddings
|
||||
from langchain.schema import Document
|
||||
|
||||
# Load documents
|
||||
with open("output/react-langchain.json") as f:
|
||||
docs_data = json.load(f)
|
||||
|
||||
# Convert to LangChain Documents
|
||||
documents = [
|
||||
Document(
|
||||
page_content=doc["page_content"],
|
||||
metadata=doc["metadata"]
|
||||
)
|
||||
for doc in docs_data
|
||||
]
|
||||
|
||||
# Create FAISS index (embeddings generated automatically)
|
||||
embeddings = OpenAIEmbeddings(model="text-embedding-ada-002")
|
||||
vectorstore = FAISS.from_documents(documents, embeddings)
|
||||
|
||||
# Save index
|
||||
vectorstore.save_local("faiss_index")
|
||||
|
||||
print(f"✅ Created FAISS index with {len(documents)} documents")
|
||||
```
|
||||
|
||||
### Query FAISS Index
|
||||
|
||||
```python
|
||||
from langchain.vectorstores import FAISS
|
||||
from langchain.embeddings import OpenAIEmbeddings
|
||||
|
||||
# Load index (note: only load indexes from trusted sources)
|
||||
embeddings = OpenAIEmbeddings(model="text-embedding-ada-002")
|
||||
vectorstore = FAISS.load_local("faiss_index", embeddings, allow_dangerous_deserialization=True)
|
||||
|
||||
# Similarity search
|
||||
results = vectorstore.similarity_search(
|
||||
query="How do I use React hooks?",
|
||||
k=3
|
||||
)
|
||||
|
||||
for i, doc in enumerate(results):
|
||||
print(f"\n{i+1}. Category: {doc.metadata['category']}")
|
||||
print(f" Source: {doc.metadata['source']}")
|
||||
print(f" Content: {doc.page_content[:200]}...")
|
||||
```
|
||||
|
||||
### Similarity Search with Scores
|
||||
|
||||
```python
|
||||
# Get similarity scores
|
||||
results = vectorstore.similarity_search_with_score(
|
||||
query="React state management",
|
||||
k=5
|
||||
)
|
||||
|
||||
for doc, score in results:
|
||||
print(f"Score: {score:.3f}")
|
||||
print(f"Category: {doc.metadata['category']}")
|
||||
print(f"Content: {doc.page_content[:150]}...")
|
||||
print()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📖 Detailed Setup Guide
|
||||
|
||||
### Step 1: Choose FAISS Index Type
|
||||
|
||||
**Option A: IndexFlatL2 (Exact Search, <100K vectors)**
|
||||
|
||||
```python
|
||||
import faiss
|
||||
|
||||
# Flat index: exact nearest neighbors (brute force)
|
||||
dimension = 1536 # OpenAI ada-002
|
||||
index = faiss.IndexFlatL2(dimension)
|
||||
|
||||
# Pros: 100% accuracy, simple
|
||||
# Cons: O(n) search time, slow for large datasets
|
||||
# Use when: <100K vectors, need perfect recall
|
||||
```
|
||||
|
||||
**Option B: IndexIVFFlat (Approximate Search, 100K-10M vectors)**
|
||||
|
||||
```python
|
||||
# IVF index: cluster-based approximate search
|
||||
quantizer = faiss.IndexFlatL2(dimension)
|
||||
nlist = 100 # Number of clusters
|
||||
index = faiss.IndexIVFFlat(quantizer, dimension, nlist)
|
||||
|
||||
# Train on sample data
|
||||
index.train(training_vectors) # Needs ~30*nlist training vectors
|
||||
index.add(vectors)
|
||||
|
||||
# Pros: Faster than flat, good accuracy
|
||||
# Cons: Requires training, 90-95% recall
|
||||
# Use when: 100K-10M vectors
|
||||
```
|
||||
|
||||
**Option C: IndexHNSWFlat (Graph-based, High Recall)**
|
||||
|
||||
```python
|
||||
# HNSW index: hierarchical navigable small world
|
||||
index = faiss.IndexHNSWFlat(dimension, 32) # 32 = M (graph connections)
|
||||
|
||||
# Pros: Fast, high recall (>95%), no training
|
||||
# Cons: High memory usage (3-4x flat)
|
||||
# Use when: Need speed + high recall, have memory
|
||||
```
|
||||
|
||||
**Option D: IndexIVFPQ (Product Quantization, 10M-1B vectors)**
|
||||
|
||||
```python
|
||||
# IVF + PQ: compressed vectors for massive scale
|
||||
quantizer = faiss.IndexFlatL2(dimension)
|
||||
nlist = 1000
|
||||
m = 8 # Number of subvectors
|
||||
nbits = 8 # Bits per subvector
|
||||
index = faiss.IndexIVFPQ(quantizer, dimension, nlist, m, nbits)
|
||||
|
||||
# Train then add
|
||||
index.train(training_vectors)
|
||||
index.add(vectors)
|
||||
|
||||
# Pros: 16-32x memory reduction, billion-scale
|
||||
# Cons: Lower recall (80-90%), complex
|
||||
# Use when: >10M vectors, memory constrained
|
||||
```
|
||||
|
||||
### Step 2: Generate Skill Seekers Documents
|
||||
|
||||
**Option A: Documentation Website**
|
||||
```bash
|
||||
skill-seekers create --config configs/django.json
|
||||
skill-seekers package output/django --target langchain
|
||||
```
|
||||
|
||||
**Option B: GitHub Repository**
|
||||
```bash
|
||||
skill-seekers create django/django --name django
|
||||
skill-seekers package output/django --target langchain
|
||||
```
|
||||
|
||||
**Option C: Local Codebase**
|
||||
```bash
|
||||
skill-seekers scan /path/to/repo
|
||||
skill-seekers package output/codebase --target langchain
|
||||
```
|
||||
|
||||
**Option D: RAG-Optimized Chunking**
|
||||
```bash
|
||||
skill-seekers create --config configs/fastapi.json --chunk-for-rag --chunk-tokens 512
|
||||
skill-seekers package output/fastapi --target langchain
|
||||
```
|
||||
|
||||
### Step 3: Create FAISS Index (LangChain Wrapper)
|
||||
|
||||
```python
|
||||
import json
|
||||
from langchain.vectorstores import FAISS
|
||||
from langchain.embeddings import OpenAIEmbeddings
|
||||
from langchain.schema import Document
|
||||
|
||||
# Load documents
|
||||
with open("output/django-langchain.json") as f:
|
||||
docs_data = json.load(f)
|
||||
|
||||
documents = [
|
||||
Document(page_content=doc["page_content"], metadata=doc["metadata"])
|
||||
for doc in docs_data
|
||||
]
|
||||
|
||||
# Create embeddings
|
||||
embeddings = OpenAIEmbeddings(model="text-embedding-ada-002")
|
||||
|
||||
# For small datasets (<100K): Use default (Flat)
|
||||
vectorstore = FAISS.from_documents(documents, embeddings)
|
||||
|
||||
# For large datasets (>100K): Use IVF
|
||||
# vectorstore = FAISS.from_documents(
|
||||
# documents,
|
||||
# embeddings,
|
||||
# index_factory_string="IVF100,Flat"
|
||||
# )
|
||||
|
||||
# Save index + docstore + metadata
|
||||
vectorstore.save_local("faiss_index")
|
||||
|
||||
print(f"✅ Created FAISS index with {len(documents)} vectors")
|
||||
```
|
||||
|
||||
### Step 4: Query with Filtering
|
||||
|
||||
```python
|
||||
# Load index (only from trusted sources!)
|
||||
vectorstore = FAISS.load_local("faiss_index", embeddings, allow_dangerous_deserialization=True)
|
||||
|
||||
# Basic similarity search
|
||||
results = vectorstore.similarity_search(
|
||||
query="Django models tutorial",
|
||||
k=5
|
||||
)
|
||||
|
||||
# Similarity search with score threshold
|
||||
results = vectorstore.similarity_search_with_relevance_scores(
|
||||
query="Django authentication",
|
||||
k=5,
|
||||
score_threshold=0.8 # Only return if relevance > 0.8
|
||||
)
|
||||
|
||||
# Maximum marginal relevance (diverse results)
|
||||
results = vectorstore.max_marginal_relevance_search(
|
||||
query="React components",
|
||||
k=5,
|
||||
fetch_k=20 # Fetch 20, return top 5 diverse
|
||||
)
|
||||
|
||||
# Custom filter function (post-search filtering)
|
||||
def filter_by_category(docs, category):
|
||||
return [doc for doc in docs if doc.metadata.get("category") == category]
|
||||
|
||||
results = vectorstore.similarity_search("hooks", k=20)
|
||||
filtered = filter_by_category(results, "state-management")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Advanced Usage
|
||||
|
||||
### 1. GPU Acceleration (Billion-Scale Search)
|
||||
|
||||
```python
|
||||
import faiss
|
||||
|
||||
# Check GPU availability
|
||||
ngpus = faiss.get_num_gpus()
|
||||
print(f"GPUs available: {ngpus}")
|
||||
|
||||
# Create GPU index
|
||||
dimension = 1536
|
||||
cpu_index = faiss.IndexFlatL2(dimension)
|
||||
|
||||
# Move to GPU
|
||||
gpu_index = faiss.index_cpu_to_gpu(
|
||||
faiss.StandardGpuResources(),
|
||||
0, # GPU ID
|
||||
cpu_index
|
||||
)
|
||||
|
||||
# Add vectors (on GPU)
|
||||
gpu_index.add(vectors)
|
||||
|
||||
# Search (on GPU, 10-100x faster)
|
||||
distances, indices = gpu_index.search(query_vectors, k=10)
|
||||
|
||||
# Move back to CPU for saving
|
||||
cpu_index = faiss.index_gpu_to_cpu(gpu_index)
|
||||
faiss.write_index(cpu_index, "index.faiss")
|
||||
```
|
||||
|
||||
### 2. Batch Processing for Large Datasets
|
||||
|
||||
```python
|
||||
import json
|
||||
from langchain.vectorstores import FAISS
|
||||
from langchain.embeddings import OpenAIEmbeddings
|
||||
from langchain.schema import Document
|
||||
|
||||
embeddings = OpenAIEmbeddings()
|
||||
|
||||
# Load documents
|
||||
with open("output/large-dataset-langchain.json") as f:
|
||||
all_docs = json.load(f)
|
||||
|
||||
# Create index with first batch
|
||||
batch_size = 10000
|
||||
first_batch = [
|
||||
Document(page_content=doc["page_content"], metadata=doc["metadata"])
|
||||
for doc in all_docs[:batch_size]
|
||||
]
|
||||
|
||||
vectorstore = FAISS.from_documents(first_batch, embeddings)
|
||||
print(f"Created index with {batch_size} documents")
|
||||
|
||||
# Add remaining batches
|
||||
for i in range(batch_size, len(all_docs), batch_size):
|
||||
batch = [
|
||||
Document(page_content=doc["page_content"], metadata=doc["metadata"])
|
||||
for doc in all_docs[i:i+batch_size]
|
||||
]
|
||||
|
||||
vectorstore.add_documents(batch)
|
||||
print(f"Added documents {i} to {i+len(batch)}")
|
||||
|
||||
# Save final index
|
||||
vectorstore.save_local("large_faiss_index")
|
||||
print(f"✅ Final index size: {len(all_docs)} documents")
|
||||
```
|
||||
|
||||
### 3. Index Merging for Multi-Source
|
||||
|
||||
```python
|
||||
# Create separate indexes for different sources
|
||||
vectorstore1 = FAISS.from_documents(docs1, embeddings)
|
||||
vectorstore2 = FAISS.from_documents(docs2, embeddings)
|
||||
vectorstore3 = FAISS.from_documents(docs3, embeddings)
|
||||
|
||||
# Merge indexes
|
||||
vectorstore1.merge_from(vectorstore2)
|
||||
vectorstore1.merge_from(vectorstore3)
|
||||
|
||||
# Save merged index
|
||||
vectorstore1.save_local("merged_index")
|
||||
|
||||
# Query combined index
|
||||
results = vectorstore1.similarity_search("query", k=10)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 Best Practices
|
||||
|
||||
### 1. Choose Index Type by Dataset Size
|
||||
|
||||
```python
|
||||
# <100K vectors: Flat (exact search)
|
||||
if num_vectors < 100_000:
|
||||
vectorstore = FAISS.from_documents(documents, embeddings)
|
||||
|
||||
# 100K-1M vectors: IVF
|
||||
elif num_vectors < 1_000_000:
|
||||
vectorstore = FAISS.from_documents(
|
||||
documents,
|
||||
embeddings,
|
||||
index_factory_string="IVF100,Flat"
|
||||
)
|
||||
|
||||
# 1M-10M vectors: IVF + PQ
|
||||
elif num_vectors < 10_000_000:
|
||||
vectorstore = FAISS.from_documents(
|
||||
documents,
|
||||
embeddings,
|
||||
index_factory_string="IVF1000,PQ8"
|
||||
)
|
||||
|
||||
# >10M vectors: GPU + IVF + PQ
|
||||
else:
|
||||
# Use GPU acceleration
|
||||
pass
|
||||
```
|
||||
|
||||
### 2. Only Load Indexes from Trusted Sources
|
||||
|
||||
```python
|
||||
# ⚠️ SECURITY: Only load indexes you trust!
|
||||
# The allow_dangerous_deserialization flag exists because
|
||||
# LangChain uses Python's serialization which can execute code
|
||||
|
||||
# ✅ Safe: Your own indexes
|
||||
vectorstore = FAISS.load_local("my_index", embeddings, allow_dangerous_deserialization=True)
|
||||
|
||||
# ❌ Dangerous: Unknown indexes from internet
|
||||
# vectorstore = FAISS.load_local("untrusted_index", ...) # DON'T DO THIS
|
||||
```
|
||||
|
||||
### 3. Use Batch Embedding Generation
|
||||
|
||||
```python
|
||||
from openai import OpenAI
|
||||
|
||||
client = OpenAI()
|
||||
|
||||
# ✅ Good: Batch API (2048 texts per call)
|
||||
texts = [doc["page_content"] for doc in documents]
|
||||
|
||||
embeddings = []
|
||||
batch_size = 2048
|
||||
|
||||
for i in range(0, len(texts), batch_size):
|
||||
batch = texts[i:i + batch_size]
|
||||
response = client.embeddings.create(
|
||||
model="text-embedding-ada-002",
|
||||
input=batch
|
||||
)
|
||||
embeddings.extend([e.embedding for e in response.data])
|
||||
|
||||
# ❌ Bad: One at a time (slow!)
|
||||
for text in texts:
|
||||
response = client.embeddings.create(model="text-embedding-ada-002", input=text)
|
||||
embeddings.append(response.data[0].embedding)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Issue: Index Too Large for Memory
|
||||
|
||||
**Problem:** "MemoryError" when loading index with 10M+ vectors
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. **Use Product Quantization:**
|
||||
```python
|
||||
# Compress vectors 32x
|
||||
vectorstore = FAISS.from_documents(
|
||||
documents,
|
||||
embeddings,
|
||||
index_factory_string="IVF1000,PQ8"
|
||||
)
|
||||
```
|
||||
|
||||
2. **Use GPU:**
|
||||
```python
|
||||
# Move to GPU memory
|
||||
gpu_index = faiss.index_cpu_to_gpu(faiss.StandardGpuResources(), 0, cpu_index)
|
||||
```
|
||||
|
||||
### Issue: Slow Search on Large Index
|
||||
|
||||
**Problem:** Search takes >1 second on 1M+ vectors
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. **Use IVF index:**
|
||||
```python
|
||||
vectorstore = FAISS.from_documents(
|
||||
documents,
|
||||
embeddings,
|
||||
index_factory_string="IVF100,Flat"
|
||||
)
|
||||
|
||||
# Tune nprobe
|
||||
vectorstore.index.nprobe = 10 # Balance speed/accuracy
|
||||
```
|
||||
|
||||
2. **GPU acceleration:**
|
||||
```python
|
||||
gpu_index = faiss.index_cpu_to_gpu(faiss.StandardGpuResources(), 0, index)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Before vs. After
|
||||
|
||||
| Aspect | Without Skill Seekers | With Skill Seekers |
|
||||
|--------|----------------------|-------------------|
|
||||
| **Data Preparation** | Custom scraping + embedding generation | One command: `skill-seekers create` |
|
||||
| **Index Creation** | Manual FAISS setup with numpy arrays | LangChain wrapper handles complexity |
|
||||
| **ID Tracking** | Manual mapping of IDs to documents | Automatic docstore integration |
|
||||
| **Metadata** | Separate storage required | Built into LangChain Documents |
|
||||
| **Scaling** | Complex index optimization required | Factory strings: `"IVF100,PQ8"` |
|
||||
| **Setup Time** | 4-6 hours | 10 minutes |
|
||||
| **Code Required** | 500+ lines | 30 lines with LangChain |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Next Steps
|
||||
|
||||
### Related Guides
|
||||
|
||||
- **[LangChain Integration](LANGCHAIN.md)** - Use FAISS as vector store in LangChain
|
||||
- **[LlamaIndex Integration](LLAMA_INDEX.md)** - Use FAISS with LlamaIndex
|
||||
- **[RAG Pipelines Guide](RAG_PIPELINES.md)** - Build complete RAG systems
|
||||
- **[INTEGRATIONS.md](INTEGRATIONS.md)** - See all integration options
|
||||
|
||||
### Resources
|
||||
|
||||
- **FAISS Wiki:** https://github.com/facebookresearch/faiss/wiki
|
||||
- **LangChain FAISS:** https://python.langchain.com/docs/integrations/vectorstores/faiss
|
||||
- **Support:** https://github.com/yusufkaraaslan/Skill_Seekers/discussions
|
||||
|
||||
---
|
||||
|
||||
**Questions?** Open an issue: https://github.com/yusufkaraaslan/Skill_Seekers/issues
|
||||
**Website:** https://skillseekersweb.com/
|
||||
**Last Updated:** February 7, 2026
|
||||
@@ -0,0 +1,435 @@
|
||||
# Google Gemini Integration Guide
|
||||
|
||||
Complete guide for creating and deploying skills to Google Gemini using Skill Seekers.
|
||||
|
||||
## Overview
|
||||
|
||||
Skill Seekers packages documentation into Gemini-compatible formats optimized for:
|
||||
- **Gemini 2.0 Flash** for enhancement
|
||||
- **Files API** for document upload
|
||||
- **Grounding** for accurate, source-based responses
|
||||
|
||||
## Setup
|
||||
|
||||
### 1. Install Gemini Support
|
||||
|
||||
```bash
|
||||
# Install with Gemini dependencies
|
||||
pip install skill-seekers[gemini]
|
||||
|
||||
# Verify installation
|
||||
pip list | grep google-generativeai
|
||||
```
|
||||
|
||||
### 2. Get Google API Key
|
||||
|
||||
1. Visit [Google AI Studio](https://aistudio.google.com/)
|
||||
2. Click "Get API Key"
|
||||
3. Create new API key or use existing
|
||||
4. Copy the key (starts with `AIza`)
|
||||
|
||||
### 3. Configure API Key
|
||||
|
||||
```bash
|
||||
# Set as environment variable (recommended)
|
||||
export GOOGLE_API_KEY=AIzaSy...
|
||||
|
||||
# Or pass directly to commands
|
||||
skill-seekers upload --target gemini --api-key AIzaSy...
|
||||
```
|
||||
|
||||
## Complete Workflow
|
||||
|
||||
### Step 1: Scrape Documentation
|
||||
|
||||
```bash
|
||||
# Use any config (scraping is platform-agnostic)
|
||||
skill-seekers create --config configs/react.json
|
||||
|
||||
# Or use a unified config for multi-source
|
||||
skill-seekers create --config configs/react_unified.json
|
||||
```
|
||||
|
||||
**Result:** `output/react/` skill directory with references
|
||||
|
||||
### Step 2: Enhance with Gemini (Optional but Recommended)
|
||||
|
||||
```bash
|
||||
# Enhance SKILL.md using Gemini 2.0 Flash
|
||||
skill-seekers enhance output/react/ --target gemini
|
||||
|
||||
# With API key specified
|
||||
skill-seekers enhance output/react/ --target gemini --api-key AIzaSy...
|
||||
```
|
||||
|
||||
**What it does:**
|
||||
- Analyzes all reference documentation
|
||||
- Extracts 5-10 best code examples
|
||||
- Creates comprehensive quick reference
|
||||
- Adds key concepts and usage guidance
|
||||
- Generates plain markdown (no YAML frontmatter)
|
||||
|
||||
**Time:** 20-40 seconds
|
||||
**Cost:** ~$0.01-0.05 (using Gemini 2.0 Flash)
|
||||
**Quality boost:** 3/10 → 9/10
|
||||
|
||||
### Step 3: Package for Gemini
|
||||
|
||||
```bash
|
||||
# Create tar.gz package for Gemini
|
||||
skill-seekers package output/react/ --target gemini
|
||||
|
||||
# Result: react-gemini.tar.gz
|
||||
```
|
||||
|
||||
**Package structure:**
|
||||
```
|
||||
react-gemini.tar.gz/
|
||||
├── system_instructions.md # Main documentation (plain markdown)
|
||||
├── references/ # Individual reference files
|
||||
│ ├── getting_started.md
|
||||
│ ├── hooks.md
|
||||
│ ├── components.md
|
||||
│ └── ...
|
||||
└── gemini_metadata.json # Platform metadata
|
||||
```
|
||||
|
||||
### Step 4: Upload to Gemini
|
||||
|
||||
```bash
|
||||
# Upload to Google AI Studio
|
||||
skill-seekers upload react-gemini.tar.gz --target gemini
|
||||
|
||||
# With API key
|
||||
skill-seekers upload react-gemini.tar.gz --target gemini --api-key AIzaSy...
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
✅ Upload successful!
|
||||
Skill ID: files/abc123xyz
|
||||
URL: https://aistudio.google.com/app/files/abc123xyz
|
||||
Files uploaded: 15 files
|
||||
```
|
||||
|
||||
### Step 5: Use in Gemini
|
||||
|
||||
Access your uploaded files in Google AI Studio:
|
||||
|
||||
1. Go to [Google AI Studio](https://aistudio.google.com/)
|
||||
2. Navigate to **Files** section
|
||||
3. Find your uploaded skill files
|
||||
4. Use with Gemini API or AI Studio
|
||||
|
||||
## What Makes Gemini Different?
|
||||
|
||||
### Format: Plain Markdown (No YAML)
|
||||
|
||||
**Claude format:**
|
||||
```markdown
|
||||
---
|
||||
name: react
|
||||
description: React framework
|
||||
---
|
||||
|
||||
# React Documentation
|
||||
...
|
||||
```
|
||||
|
||||
**Gemini format:**
|
||||
```markdown
|
||||
# React Documentation
|
||||
|
||||
**Description:** React framework for building user interfaces
|
||||
|
||||
## Quick Reference
|
||||
...
|
||||
```
|
||||
|
||||
No YAML frontmatter - Gemini uses plain markdown for better compatibility.
|
||||
|
||||
### Package: tar.gz Instead of ZIP
|
||||
|
||||
Gemini uses `.tar.gz` compression for better Unix compatibility and smaller file sizes.
|
||||
|
||||
### Upload: Files API + Grounding
|
||||
|
||||
Files are uploaded to Google's Files API and made available for grounding in Gemini responses.
|
||||
|
||||
## Using Your Gemini Skill
|
||||
|
||||
### Option 1: Google AI Studio (Web UI)
|
||||
|
||||
1. Go to [Google AI Studio](https://aistudio.google.com/)
|
||||
2. Create new chat or app
|
||||
3. Reference your uploaded files in prompts:
|
||||
```
|
||||
Using the React documentation files, explain hooks
|
||||
```
|
||||
|
||||
### Option 2: Gemini API (Python)
|
||||
|
||||
```python
|
||||
import google.generativeai as genai
|
||||
|
||||
# Configure with your API key
|
||||
genai.configure(api_key='AIzaSy...')
|
||||
|
||||
# Create model
|
||||
model = genai.GenerativeModel('gemini-2.0-flash-exp')
|
||||
|
||||
# Use with uploaded files (automatic grounding)
|
||||
response = model.generate_content(
|
||||
"How do I use React hooks?",
|
||||
# Files automatically available via grounding
|
||||
)
|
||||
|
||||
print(response.text)
|
||||
```
|
||||
|
||||
### Option 3: Gemini API with File Reference
|
||||
|
||||
```python
|
||||
import google.generativeai as genai
|
||||
|
||||
# Configure
|
||||
genai.configure(api_key='AIzaSy...')
|
||||
|
||||
# Get your uploaded file
|
||||
files = genai.list_files()
|
||||
react_file = next(f for f in files if 'react' in f.display_name.lower())
|
||||
|
||||
# Use file in generation
|
||||
model = genai.GenerativeModel('gemini-2.0-flash-exp')
|
||||
response = model.generate_content([
|
||||
"Explain React hooks in detail",
|
||||
react_file
|
||||
])
|
||||
|
||||
print(response.text)
|
||||
```
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Enhance with Custom Prompt
|
||||
|
||||
The enhancement process can be customized by modifying the adaptor:
|
||||
|
||||
```python
|
||||
from skill_seekers.cli.adaptors import get_adaptor
|
||||
from pathlib import Path
|
||||
|
||||
# Get Gemini adaptor
|
||||
adaptor = get_adaptor('gemini')
|
||||
|
||||
# Enhance with custom parameters
|
||||
success = adaptor.enhance(
|
||||
skill_dir=Path('output/react'),
|
||||
api_key='AIzaSy...'
|
||||
)
|
||||
```
|
||||
|
||||
### Programmatic Upload
|
||||
|
||||
```python
|
||||
from skill_seekers.cli.adaptors import get_adaptor
|
||||
from pathlib import Path
|
||||
|
||||
# Get adaptor
|
||||
gemini = get_adaptor('gemini')
|
||||
|
||||
# Package skill
|
||||
package_path = gemini.package(
|
||||
skill_dir=Path('output/react'),
|
||||
output_path=Path('output/react-gemini.tar.gz')
|
||||
)
|
||||
|
||||
# Upload
|
||||
result = gemini.upload(
|
||||
package_path=package_path,
|
||||
api_key='AIzaSy...'
|
||||
)
|
||||
|
||||
if result['success']:
|
||||
print(f"✅ Uploaded to: {result['url']}")
|
||||
print(f"Skill ID: {result['skill_id']}")
|
||||
else:
|
||||
print(f"❌ Upload failed: {result['message']}")
|
||||
```
|
||||
|
||||
### Manual Package Extraction
|
||||
|
||||
If you want to inspect or modify the package:
|
||||
|
||||
```bash
|
||||
# Extract tar.gz
|
||||
tar -xzf react-gemini.tar.gz -C extracted/
|
||||
|
||||
# View structure
|
||||
tree extracted/
|
||||
|
||||
# Modify files if needed
|
||||
nano extracted/system_instructions.md
|
||||
|
||||
# Re-package
|
||||
tar -czf react-gemini-modified.tar.gz -C extracted .
|
||||
```
|
||||
|
||||
## Gemini-Specific Features
|
||||
|
||||
### 1. Grounding Support
|
||||
|
||||
Gemini automatically grounds responses in your uploaded documentation files, providing:
|
||||
- Source attribution
|
||||
- Accurate citations
|
||||
- Reduced hallucination
|
||||
|
||||
### 2. Multimodal Capabilities
|
||||
|
||||
Gemini can process:
|
||||
- Text documentation
|
||||
- Code examples
|
||||
- Images (if included in PDFs)
|
||||
- Tables and diagrams
|
||||
|
||||
### 3. Long Context Window
|
||||
|
||||
Gemini 2.0 Flash supports:
|
||||
- Up to 1M token context
|
||||
- Entire documentation sets in single context
|
||||
- Better understanding of cross-references
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Issue: `google-generativeai not installed`
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
pip install skill-seekers[gemini]
|
||||
```
|
||||
|
||||
### Issue: `Invalid API key format`
|
||||
|
||||
**Error:** API key doesn't start with `AIza`
|
||||
|
||||
**Solution:**
|
||||
- Get new key from [Google AI Studio](https://aistudio.google.com/)
|
||||
- Verify you're using Google API key, not GCP service account
|
||||
|
||||
### Issue: `Not a tar.gz file`
|
||||
|
||||
**Error:** Wrong package format
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Use --target gemini for tar.gz format
|
||||
skill-seekers package output/react/ --target gemini
|
||||
|
||||
# NOT:
|
||||
skill-seekers package output/react/ # Creates .zip (Claude format)
|
||||
```
|
||||
|
||||
### Issue: `File upload failed`
|
||||
|
||||
**Possible causes:**
|
||||
- API key lacks permissions
|
||||
- File too large (check limits)
|
||||
- Network connectivity
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Verify API key works
|
||||
python3 -c "import google.generativeai as genai; genai.configure(api_key='AIza...'); print(list(genai.list_models())[:2])"
|
||||
|
||||
# Check file size
|
||||
ls -lh react-gemini.tar.gz
|
||||
|
||||
# Try with verbose output
|
||||
skill-seekers upload react-gemini.tar.gz --target gemini
|
||||
```
|
||||
|
||||
### Issue: Enhancement fails
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Check API quota
|
||||
# Visit: https://aistudio.google.com/apikey
|
||||
|
||||
# Try with smaller skill
|
||||
skill-seekers enhance output/react/ --target gemini
|
||||
|
||||
# Use without enhancement
|
||||
skill-seekers package output/react/ --target gemini
|
||||
# (Skip enhancement step)
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Organize Documentation
|
||||
|
||||
Structure your SKILL.md clearly:
|
||||
- Start with overview
|
||||
- Add quick reference section
|
||||
- Group related concepts
|
||||
- Include practical examples
|
||||
|
||||
### 2. Optimize File Count
|
||||
|
||||
- Combine related topics into single files
|
||||
- Use clear file naming
|
||||
- Keep total under 100 files for best performance
|
||||
|
||||
### 3. Test with Gemini
|
||||
|
||||
After upload, test with sample questions:
|
||||
```
|
||||
1. How do I get started with [topic]?
|
||||
2. What are the core concepts?
|
||||
3. Show me a practical example
|
||||
4. What are common pitfalls?
|
||||
```
|
||||
|
||||
### 4. Update Regularly
|
||||
|
||||
```bash
|
||||
# Re-scrape updated documentation
|
||||
skill-seekers create --config configs/react.json
|
||||
|
||||
# Re-enhance and upload
|
||||
skill-seekers enhance output/react/ --target gemini
|
||||
skill-seekers package output/react/ --target gemini
|
||||
skill-seekers upload react-gemini.tar.gz --target gemini
|
||||
```
|
||||
|
||||
## Cost Estimation
|
||||
|
||||
**Gemini 2.0 Flash pricing:**
|
||||
- Input: $0.075 per 1M tokens
|
||||
- Output: $0.30 per 1M tokens
|
||||
|
||||
**Typical skill enhancement:**
|
||||
- Input: ~50K-200K tokens (docs)
|
||||
- Output: ~5K-10K tokens (enhanced SKILL.md)
|
||||
- Cost: $0.01-0.05 per skill
|
||||
|
||||
**File upload:** Free (no per-file charges)
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. ✅ Install Gemini support: `pip install skill-seekers[gemini]`
|
||||
2. ✅ Get API key from Google AI Studio
|
||||
3. ✅ Scrape your documentation
|
||||
4. ✅ Enhance with Gemini
|
||||
5. ✅ Package for Gemini
|
||||
6. ✅ Upload and test
|
||||
|
||||
## Resources
|
||||
|
||||
- [Google AI Studio](https://aistudio.google.com/)
|
||||
- [Gemini API Documentation](https://ai.google.dev/docs)
|
||||
- [Gemini Pricing](https://ai.google.dev/pricing)
|
||||
- [Multi-LLM Support Guide](MULTI_LLM_SUPPORT.md)
|
||||
|
||||
## Feedback
|
||||
|
||||
Found an issue or have suggestions? [Open an issue](https://github.com/yusufkaraaslan/Skill_Seekers/issues)
|
||||
@@ -0,0 +1,822 @@
|
||||
# Using Skill Seekers with Haystack
|
||||
|
||||
**Last Updated:** February 7, 2026
|
||||
**Status:** Production Ready
|
||||
**Difficulty:** Easy ⭐
|
||||
|
||||
---
|
||||
|
||||
## 🎯 The Problem
|
||||
|
||||
Building RAG (Retrieval-Augmented Generation) applications with Haystack requires high-quality, structured documentation for your document stores and pipelines. Manually scraping and preparing documentation is:
|
||||
|
||||
- **Time-Consuming** - Hours spent scraping docs, formatting, and structuring
|
||||
- **Error-Prone** - Inconsistent formatting, missing metadata, broken references
|
||||
- **Not Scalable** - Multi-language docs and large frameworks are overwhelming
|
||||
|
||||
**Example:**
|
||||
> "When building an enterprise RAG system for FastAPI documentation with Haystack, you need to scrape 300+ pages, structure them with proper metadata, and prepare for multi-language search. This typically takes 6-8 hours of manual work."
|
||||
|
||||
---
|
||||
|
||||
## ✨ The Solution
|
||||
|
||||
Use Skill Seekers as **essential preprocessing** before Haystack:
|
||||
|
||||
1. **Generate Haystack Documents** from any documentation source
|
||||
2. **Pre-structured with metadata** following Haystack 2.x format
|
||||
3. **Ready for document stores** (InMemoryDocumentStore, Elasticsearch, Weaviate)
|
||||
4. **One command** - scrape, structure, format in minutes
|
||||
|
||||
**Result:**
|
||||
Skill Seekers outputs JSON files with Haystack Document format (`content` + `meta`), ready to load directly into your Haystack pipelines.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Start (5 Minutes)
|
||||
|
||||
### Prerequisites
|
||||
- Python 3.10+
|
||||
- Haystack 2.x installed: `pip install haystack-ai`
|
||||
- Optional: Embeddings library (e.g., `sentence-transformers`)
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
# Install Skill Seekers
|
||||
pip install skill-seekers
|
||||
|
||||
# Verify installation
|
||||
skill-seekers --version
|
||||
```
|
||||
|
||||
### Generate Haystack Documents
|
||||
|
||||
```bash
|
||||
# Example: Django framework documentation
|
||||
skill-seekers create --config configs/django.json
|
||||
|
||||
# Package as Haystack Documents
|
||||
skill-seekers package output/django --target haystack
|
||||
|
||||
# Output: output/django-haystack.json
|
||||
```
|
||||
|
||||
### Load into Haystack
|
||||
|
||||
```python
|
||||
from haystack import Document
|
||||
from haystack.document_stores.in_memory import InMemoryDocumentStore
|
||||
from haystack.components.retrievers.in_memory import InMemoryBM25Retriever
|
||||
import json
|
||||
|
||||
# Load documents
|
||||
with open("output/django-haystack.json") as f:
|
||||
docs_data = json.load(f)
|
||||
|
||||
# Convert to Haystack Documents
|
||||
documents = [
|
||||
Document(content=doc["content"], meta=doc["meta"])
|
||||
for doc in docs_data
|
||||
]
|
||||
|
||||
print(f"Loaded {len(documents)} documents")
|
||||
|
||||
# Create document store
|
||||
document_store = InMemoryDocumentStore()
|
||||
document_store.write_documents(documents)
|
||||
|
||||
# Create retriever
|
||||
retriever = InMemoryBM25Retriever(document_store=document_store)
|
||||
|
||||
# Query
|
||||
results = retriever.run(query="How do I create Django models?", top_k=3)
|
||||
for doc in results["documents"]:
|
||||
print(f"\n{doc.meta['category']}: {doc.content[:200]}...")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📖 Detailed Setup Guide
|
||||
|
||||
### Step 1: Choose Your Documentation Source
|
||||
|
||||
Skill Seekers supports multiple documentation sources:
|
||||
|
||||
```bash
|
||||
# Official framework documentation
|
||||
skill-seekers create --config configs/fastapi.json
|
||||
|
||||
# GitHub repository
|
||||
skill-seekers create tiangolo/fastapi
|
||||
|
||||
# PDF documentation
|
||||
skill-seekers create --pdf docs/manual.pdf
|
||||
|
||||
# Combine multiple sources via a unified config (sources array with docs + github)
|
||||
skill-seekers create --config configs/fastapi-unified.json \
|
||||
--output output/fastapi-complete
|
||||
```
|
||||
|
||||
### Step 2: Configure Scraping (Optional)
|
||||
|
||||
Create a custom config for your documentation:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "my-framework",
|
||||
"base_url": "https://docs.example.com/",
|
||||
"selectors": {
|
||||
"main_content": "article.documentation",
|
||||
"title": "h1.page-title",
|
||||
"code_blocks": "pre code"
|
||||
},
|
||||
"categories": {
|
||||
"getting_started": ["intro", "quickstart", "installation"],
|
||||
"guides": ["tutorial", "guide", "howto"],
|
||||
"api": ["api", "reference"]
|
||||
},
|
||||
"max_pages": 500,
|
||||
"rate_limit": 0.5
|
||||
}
|
||||
```
|
||||
|
||||
Save as `configs/my-framework.json` and use:
|
||||
|
||||
```bash
|
||||
skill-seekers create --config configs/my-framework.json
|
||||
```
|
||||
|
||||
### Step 3: Package for Haystack
|
||||
|
||||
```bash
|
||||
# Generate Haystack Documents
|
||||
skill-seekers package output/my-framework --target haystack
|
||||
|
||||
# With semantic chunking for better retrieval
|
||||
skill-seekers create --config configs/my-framework.json --chunk-for-rag
|
||||
skill-seekers package output/my-framework --target haystack
|
||||
|
||||
# Output files:
|
||||
# - output/my-framework-haystack.json (Haystack Documents)
|
||||
# - output/my-framework/rag_chunks.json (if chunking enabled)
|
||||
```
|
||||
|
||||
### Step 4: Load into Haystack Pipeline
|
||||
|
||||
**Option A: InMemoryDocumentStore (Development)**
|
||||
|
||||
```python
|
||||
from haystack import Document
|
||||
from haystack.document_stores.in_memory import InMemoryDocumentStore
|
||||
from haystack.components.retrievers.in_memory import InMemoryBM25Retriever
|
||||
import json
|
||||
|
||||
# Load documents
|
||||
with open("output/my-framework-haystack.json") as f:
|
||||
docs_data = json.load(f)
|
||||
|
||||
documents = [
|
||||
Document(content=doc["content"], meta=doc["meta"])
|
||||
for doc in docs_data
|
||||
]
|
||||
|
||||
# Create in-memory store
|
||||
document_store = InMemoryDocumentStore()
|
||||
document_store.write_documents(documents)
|
||||
|
||||
# Create BM25 retriever
|
||||
retriever = InMemoryBM25Retriever(document_store=document_store)
|
||||
|
||||
# Query
|
||||
results = retriever.run(query="your question", top_k=5)
|
||||
```
|
||||
|
||||
**Option B: Elasticsearch (Production)**
|
||||
|
||||
```python
|
||||
from haystack import Document
|
||||
from haystack.document_stores.elasticsearch import ElasticsearchDocumentStore
|
||||
from haystack.components.retrievers.elasticsearch import ElasticsearchBM25Retriever
|
||||
import json
|
||||
|
||||
# Connect to Elasticsearch
|
||||
document_store = ElasticsearchDocumentStore(
|
||||
hosts=["http://localhost:9200"],
|
||||
index="my-framework-docs"
|
||||
)
|
||||
|
||||
# Load and write documents
|
||||
with open("output/my-framework-haystack.json") as f:
|
||||
docs_data = json.load(f)
|
||||
|
||||
documents = [
|
||||
Document(content=doc["content"], meta=doc["meta"])
|
||||
for doc in docs_data
|
||||
]
|
||||
|
||||
document_store.write_documents(documents)
|
||||
|
||||
# Create retriever
|
||||
retriever = ElasticsearchBM25Retriever(document_store=document_store)
|
||||
```
|
||||
|
||||
**Option C: Weaviate (Hybrid Search)**
|
||||
|
||||
```python
|
||||
from haystack import Document
|
||||
from haystack.document_stores.weaviate import WeaviateDocumentStore
|
||||
from haystack.components.retrievers.weaviate import WeaviateHybridRetriever
|
||||
import json
|
||||
|
||||
# Connect to Weaviate
|
||||
document_store = WeaviateDocumentStore(
|
||||
host="http://localhost:8080",
|
||||
index="MyFrameworkDocs"
|
||||
)
|
||||
|
||||
# Load documents
|
||||
with open("output/my-framework-haystack.json") as f:
|
||||
docs_data = json.load(f)
|
||||
|
||||
documents = [
|
||||
Document(content=doc["content"], meta=doc["meta"])
|
||||
for doc in docs_data
|
||||
]
|
||||
|
||||
# Write with embeddings
|
||||
from haystack.components.embedders import SentenceTransformersDocumentEmbedder
|
||||
|
||||
embedder = SentenceTransformersDocumentEmbedder(
|
||||
model="sentence-transformers/all-MiniLM-L6-v2"
|
||||
)
|
||||
embedder.warm_up()
|
||||
|
||||
docs_with_embeddings = embedder.run(documents)
|
||||
document_store.write_documents(docs_with_embeddings["documents"])
|
||||
|
||||
# Create hybrid retriever (BM25 + vector)
|
||||
retriever = WeaviateHybridRetriever(document_store=document_store)
|
||||
```
|
||||
|
||||
### Step 5: Build RAG Pipeline
|
||||
|
||||
```python
|
||||
from haystack import Pipeline
|
||||
from haystack.components.builders import PromptBuilder
|
||||
from haystack.components.generators import OpenAIGenerator
|
||||
|
||||
# Create RAG pipeline
|
||||
rag_pipeline = Pipeline()
|
||||
|
||||
# Add components
|
||||
rag_pipeline.add_component("retriever", retriever)
|
||||
rag_pipeline.add_component(
|
||||
"prompt_builder",
|
||||
PromptBuilder(
|
||||
template="""
|
||||
Based on the following documentation, answer the question.
|
||||
|
||||
Documentation:
|
||||
{% for doc in documents %}
|
||||
{{ doc.content }}
|
||||
{% endfor %}
|
||||
|
||||
Question: {{ question }}
|
||||
|
||||
Answer:
|
||||
"""
|
||||
)
|
||||
)
|
||||
rag_pipeline.add_component(
|
||||
"llm",
|
||||
OpenAIGenerator(api_key=os.getenv("OPENAI_API_KEY"))
|
||||
)
|
||||
|
||||
# Connect components
|
||||
rag_pipeline.connect("retriever", "prompt_builder.documents")
|
||||
rag_pipeline.connect("prompt_builder", "llm")
|
||||
|
||||
# Run pipeline
|
||||
response = rag_pipeline.run({
|
||||
"retriever": {"query": "How do I deploy my app?"},
|
||||
"prompt_builder": {"question": "How do I deploy my app?"}
|
||||
})
|
||||
|
||||
print(response["llm"]["replies"][0])
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔥 Advanced Usage
|
||||
|
||||
### Semantic Chunking for Better Retrieval
|
||||
|
||||
```bash
|
||||
# Enable semantic chunking (preserves code blocks, respects paragraphs)
|
||||
skill-seekers create --config configs/django.json \
|
||||
--chunk-for-rag \
|
||||
--chunk-tokens 512 \
|
||||
--chunk-overlap-tokens 50
|
||||
|
||||
# Package chunked output
|
||||
skill-seekers package output/django --target haystack
|
||||
|
||||
# Result: Smaller, more focused documents for better retrieval
|
||||
```
|
||||
|
||||
### Multi-Source RAG System
|
||||
|
||||
```bash
|
||||
# Combine official docs + GitHub + PDF guides via a unified config
|
||||
# (sources array with documentation/github/pdf entries)
|
||||
skill-seekers create --config configs/complete-knowledge.json \
|
||||
--output output/complete-knowledge
|
||||
|
||||
skill-seekers package output/complete-knowledge --target haystack
|
||||
|
||||
# Conflicts between sources are detected automatically during the unified
|
||||
# scrape and written to the conflicts report in the skill directory.
|
||||
```
|
||||
|
||||
### Custom Metadata for Filtering
|
||||
|
||||
Haystack Documents include rich metadata for filtering:
|
||||
|
||||
```python
|
||||
# Query with metadata filters
|
||||
from haystack.dataclasses import Document
|
||||
from haystack.document_stores.in_memory import InMemoryDocumentStore
|
||||
|
||||
# Filter by category
|
||||
results = retriever.run(
|
||||
query="deployment",
|
||||
top_k=5,
|
||||
filters={"field": "category", "operator": "==", "value": "guides"}
|
||||
)
|
||||
|
||||
# Filter by version
|
||||
results = retriever.run(
|
||||
query="api reference",
|
||||
filters={"field": "version", "operator": "==", "value": "2.0"}
|
||||
)
|
||||
|
||||
# Multiple filters
|
||||
results = retriever.run(
|
||||
query="authentication",
|
||||
filters={
|
||||
"operator": "AND",
|
||||
"conditions": [
|
||||
{"field": "category", "operator": "==", "value": "api"},
|
||||
{"field": "type", "operator": "==", "value": "reference"}
|
||||
]
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
### Embedding-Based Retrieval
|
||||
|
||||
```python
|
||||
from haystack.components.embedders import (
|
||||
SentenceTransformersDocumentEmbedder,
|
||||
SentenceTransformersTextEmbedder
|
||||
)
|
||||
from haystack.components.retrievers.in_memory import InMemoryEmbeddingRetriever
|
||||
|
||||
# Embed documents
|
||||
doc_embedder = SentenceTransformersDocumentEmbedder(
|
||||
model="sentence-transformers/all-MiniLM-L6-v2"
|
||||
)
|
||||
doc_embedder.warm_up()
|
||||
|
||||
docs_with_embeddings = doc_embedder.run(documents)
|
||||
document_store.write_documents(docs_with_embeddings["documents"])
|
||||
|
||||
# Create embedding retriever
|
||||
text_embedder = SentenceTransformersTextEmbedder(
|
||||
model="sentence-transformers/all-MiniLM-L6-v2"
|
||||
)
|
||||
text_embedder.warm_up()
|
||||
|
||||
retriever = InMemoryEmbeddingRetriever(document_store=document_store)
|
||||
|
||||
# Query with embeddings
|
||||
query_embedding = text_embedder.run("How do I deploy?")
|
||||
results = retriever.run(
|
||||
query_embedding=query_embedding["embedding"],
|
||||
top_k=5
|
||||
)
|
||||
```
|
||||
|
||||
### Incremental Updates
|
||||
|
||||
```bash
|
||||
# Initial scrape
|
||||
skill-seekers create --config configs/fastapi.json
|
||||
|
||||
# Later: Update only changed pages
|
||||
skill-seekers update output/fastapi/ --check-changes
|
||||
|
||||
# Merge with existing documents
|
||||
python scripts/merge_documents.py \
|
||||
output/fastapi-haystack.json \
|
||||
output/fastapi-haystack-new.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Best Practices
|
||||
|
||||
### 1. Use Semantic Chunking for Large Docs
|
||||
|
||||
**Why:** Better retrieval quality, more focused results
|
||||
|
||||
```bash
|
||||
# Enable chunking for frameworks with long pages
|
||||
skill-seekers create --config configs/django.json \
|
||||
--chunk-for-rag \
|
||||
--chunk-tokens 512 \
|
||||
--chunk-overlap-tokens 50
|
||||
```
|
||||
|
||||
### 2. Choose Right Document Store
|
||||
|
||||
**Development:**
|
||||
- InMemoryDocumentStore - Fast, no setup
|
||||
|
||||
**Production:**
|
||||
- Elasticsearch - Full-text search, scalable
|
||||
- Weaviate - Hybrid search (BM25 + vector), multi-modal
|
||||
- Qdrant - High-performance vector search
|
||||
- Opensearch - AWS-managed, cost-effective
|
||||
|
||||
### 3. Add Metadata Filters
|
||||
|
||||
```python
|
||||
# Always include category in queries for faster results
|
||||
results = retriever.run(
|
||||
query="database models",
|
||||
filters={"field": "category", "operator": "==", "value": "guides"}
|
||||
)
|
||||
```
|
||||
|
||||
### 4. Monitor Retrieval Quality
|
||||
|
||||
```python
|
||||
# Test queries and verify relevance
|
||||
test_queries = [
|
||||
"How do I create a model?",
|
||||
"What is the deployment process?",
|
||||
"How to handle authentication?"
|
||||
]
|
||||
|
||||
for query in test_queries:
|
||||
results = retriever.run(query=query, top_k=3)
|
||||
print(f"\nQuery: {query}")
|
||||
for i, doc in enumerate(results["documents"], 1):
|
||||
print(f"{i}. {doc.meta['file']} - {doc.meta['category']}")
|
||||
```
|
||||
|
||||
### 5. Version Your Documentation
|
||||
|
||||
```bash
|
||||
# Include version in metadata (set "version" in the config JSON)
|
||||
skill-seekers create --config configs/django.json
|
||||
|
||||
# Query specific versions
|
||||
results = retriever.run(
|
||||
query="middleware",
|
||||
filters={"field": "version", "operator": "==", "value": "4.2"}
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💼 Real-World Example: FastAPI RAG Chatbot
|
||||
|
||||
Complete example of building a FastAPI documentation chatbot:
|
||||
|
||||
### Step 1: Generate Documentation
|
||||
|
||||
```bash
|
||||
# Scrape FastAPI docs with chunking
|
||||
skill-seekers create --config configs/fastapi.json \
|
||||
--chunk-for-rag \
|
||||
--chunk-tokens 512 \
|
||||
--chunk-overlap-tokens 50 \
|
||||
--max-pages 200
|
||||
|
||||
# Package for Haystack
|
||||
skill-seekers package output/fastapi --target haystack
|
||||
```
|
||||
|
||||
### Step 2: Setup Haystack Pipeline
|
||||
|
||||
```python
|
||||
from haystack import Pipeline, Document
|
||||
from haystack.document_stores.in_memory import InMemoryDocumentStore
|
||||
from haystack.components.retrievers.in_memory import InMemoryBM25Retriever
|
||||
from haystack.components.builders import PromptBuilder
|
||||
from haystack.components.generators import OpenAIGenerator
|
||||
import json
|
||||
import os
|
||||
|
||||
# Load documents
|
||||
with open("output/fastapi-haystack.json") as f:
|
||||
docs_data = json.load(f)
|
||||
|
||||
documents = [
|
||||
Document(content=doc["content"], meta=doc["meta"])
|
||||
for doc in docs_data
|
||||
]
|
||||
|
||||
print(f"Loaded {len(documents)} FastAPI documentation chunks")
|
||||
|
||||
# Create document store
|
||||
document_store = InMemoryDocumentStore()
|
||||
document_store.write_documents(documents)
|
||||
print(f"Indexed {document_store.count_documents()} documents")
|
||||
|
||||
# Build RAG pipeline
|
||||
rag = Pipeline()
|
||||
|
||||
# Add components
|
||||
rag.add_component(
|
||||
"retriever",
|
||||
InMemoryBM25Retriever(document_store=document_store)
|
||||
)
|
||||
|
||||
rag.add_component(
|
||||
"prompt",
|
||||
PromptBuilder(
|
||||
template="""
|
||||
You are a FastAPI expert assistant. Answer the question based on the documentation below.
|
||||
|
||||
Documentation:
|
||||
{% for doc in documents %}
|
||||
---
|
||||
Source: {{ doc.meta.file }}
|
||||
Category: {{ doc.meta.category }}
|
||||
|
||||
{{ doc.content }}
|
||||
{% endfor %}
|
||||
|
||||
Question: {{ question }}
|
||||
|
||||
Provide a clear, code-focused answer with examples when relevant.
|
||||
"""
|
||||
)
|
||||
)
|
||||
|
||||
rag.add_component(
|
||||
"llm",
|
||||
OpenAIGenerator(
|
||||
api_key=os.getenv("OPENAI_API_KEY"),
|
||||
model="gpt-4"
|
||||
)
|
||||
)
|
||||
|
||||
# Connect pipeline
|
||||
rag.connect("retriever.documents", "prompt.documents")
|
||||
rag.connect("prompt.prompt", "llm.prompt")
|
||||
|
||||
print("Pipeline ready!")
|
||||
```
|
||||
|
||||
### Step 3: Interactive Chat
|
||||
|
||||
```python
|
||||
def ask_fastapi(question: str, top_k: int = 5):
|
||||
"""Ask a question about FastAPI."""
|
||||
response = rag.run({
|
||||
"retriever": {"query": question, "top_k": top_k},
|
||||
"prompt": {"question": question}
|
||||
})
|
||||
|
||||
answer = response["llm"]["replies"][0]
|
||||
print(f"\nQuestion: {question}\n")
|
||||
print(f"Answer: {answer}\n")
|
||||
|
||||
# Show sources
|
||||
docs = response["retriever"]["documents"]
|
||||
print("Sources:")
|
||||
for doc in docs:
|
||||
print(f" - {doc.meta['file']} ({doc.meta['category']})")
|
||||
|
||||
# Example usage
|
||||
ask_fastapi("How do I create a REST API endpoint?")
|
||||
ask_fastapi("What is dependency injection in FastAPI?")
|
||||
ask_fastapi("How do I handle file uploads?")
|
||||
```
|
||||
|
||||
### Step 4: Deploy with FastAPI
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
class Question(BaseModel):
|
||||
text: str
|
||||
top_k: int = 5
|
||||
|
||||
@app.post("/ask")
|
||||
async def ask_question(question: Question):
|
||||
"""Ask a question about FastAPI documentation."""
|
||||
response = rag.run({
|
||||
"retriever": {"query": question.text, "top_k": question.top_k},
|
||||
"prompt": {"question": question.text}
|
||||
})
|
||||
|
||||
return {
|
||||
"question": question.text,
|
||||
"answer": response["llm"]["replies"][0],
|
||||
"sources": [
|
||||
{
|
||||
"file": doc.meta["file"],
|
||||
"category": doc.meta["category"],
|
||||
"content_preview": doc.content[:200]
|
||||
}
|
||||
for doc in response["retriever"]["documents"]
|
||||
]
|
||||
}
|
||||
|
||||
# Run: uvicorn chatbot:app --reload
|
||||
# Test: curl -X POST http://localhost:8000/ask \
|
||||
# -H "Content-Type: application/json" \
|
||||
# -d '{"text": "How do I use async functions?"}'
|
||||
```
|
||||
|
||||
**Result:**
|
||||
- ✅ 200 documentation pages → 450 optimized chunks
|
||||
- ✅ Sub-second retrieval with BM25
|
||||
- ✅ Context-aware answers from GPT-4
|
||||
- ✅ Source attribution for every answer
|
||||
- ✅ REST API for integration
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Troubleshooting
|
||||
|
||||
### Issue: Documents not loading correctly
|
||||
|
||||
**Symptoms:** Empty content, missing metadata
|
||||
|
||||
**Solutions:**
|
||||
```bash
|
||||
# Verify JSON structure
|
||||
jq '.[0]' output/fastapi-haystack.json
|
||||
|
||||
# Should show:
|
||||
# {
|
||||
# "content": "...",
|
||||
# "meta": {
|
||||
# "source": "fastapi",
|
||||
# "category": "...",
|
||||
# ...
|
||||
# }
|
||||
# }
|
||||
|
||||
# Regenerate if malformed
|
||||
skill-seekers package output/fastapi --target haystack
|
||||
```
|
||||
|
||||
### Issue: Poor retrieval quality
|
||||
|
||||
**Symptoms:** Irrelevant results, missed relevant docs
|
||||
|
||||
**Solutions:**
|
||||
```bash
|
||||
# 1. Enable semantic chunking
|
||||
skill-seekers create --config configs/fastapi.json --chunk-for-rag
|
||||
|
||||
# 2. Adjust chunk size
|
||||
skill-seekers create --config configs/fastapi.json \
|
||||
--chunk-for-rag \
|
||||
--chunk-tokens 768 \ # Larger chunks for more context
|
||||
--chunk-overlap-tokens 100 # More overlap for continuity
|
||||
|
||||
# 3. Use hybrid search (BM25 + embeddings)
|
||||
# See Advanced Usage section
|
||||
```
|
||||
|
||||
### Issue: OutOfMemoryError with large docs
|
||||
|
||||
**Symptoms:** Crash when loading thousands of documents
|
||||
|
||||
**Solutions:**
|
||||
```python
|
||||
# Load documents in batches
|
||||
import json
|
||||
|
||||
def load_documents_batched(file_path, batch_size=100):
|
||||
with open(file_path) as f:
|
||||
docs_data = json.load(f)
|
||||
|
||||
for i in range(0, len(docs_data), batch_size):
|
||||
batch = docs_data[i:i+batch_size]
|
||||
documents = [
|
||||
Document(content=doc["content"], meta=doc["meta"])
|
||||
for doc in batch
|
||||
]
|
||||
document_store.write_documents(documents)
|
||||
print(f"Loaded batch {i//batch_size + 1}")
|
||||
|
||||
load_documents_batched("output/large-framework-haystack.json")
|
||||
```
|
||||
|
||||
### Issue: Haystack version compatibility
|
||||
|
||||
**Symptoms:** Import errors, method not found
|
||||
|
||||
**Solutions:**
|
||||
```bash
|
||||
# Check Haystack version
|
||||
pip show haystack-ai
|
||||
|
||||
# Skill Seekers requires Haystack 2.x
|
||||
pip install --upgrade "haystack-ai>=2.0.0"
|
||||
|
||||
# For Haystack 1.x (legacy), use markdown export instead:
|
||||
skill-seekers package output/framework --target markdown
|
||||
```
|
||||
|
||||
### Issue: Slow query performance
|
||||
|
||||
**Symptoms:** Queries take >2 seconds
|
||||
|
||||
**Solutions:**
|
||||
```python
|
||||
# 1. Reduce top_k
|
||||
results = retriever.run(query="...", top_k=3) # Instead of 10
|
||||
|
||||
# 2. Add metadata filters
|
||||
results = retriever.run(
|
||||
query="...",
|
||||
filters={"field": "category", "operator": "==", "value": "api"}
|
||||
)
|
||||
|
||||
# 3. Use InMemoryDocumentStore for development
|
||||
# Switch to Elasticsearch for production scale
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Before vs After
|
||||
|
||||
| Aspect | Before Skill Seekers | After Skill Seekers |
|
||||
|--------|---------------------|-------------------|
|
||||
| **Setup Time** | 6-8 hours manual scraping | 5 minutes automated |
|
||||
| **Documentation Quality** | Inconsistent, missing metadata | Structured with rich metadata |
|
||||
| **Chunking** | Manual, error-prone | Semantic, code-preserving |
|
||||
| **Updates** | Re-scrape everything | Incremental updates |
|
||||
| **Multi-source** | Complex custom scripts | One unified command |
|
||||
| **Format** | Custom JSON hacking | Native Haystack Documents |
|
||||
| **Retrieval Quality** | Poor (large chunks, no metadata) | Excellent (optimized chunks, filters) |
|
||||
| **Maintenance** | High (scripts break) | Low (one tool, well-tested) |
|
||||
|
||||
---
|
||||
|
||||
## 🎓 Next Steps
|
||||
|
||||
### Try These Examples
|
||||
|
||||
1. **Build a chatbot** - Follow the FastAPI example above
|
||||
2. **Multi-language search** - Scrape docs in multiple languages
|
||||
3. **Hybrid retrieval** - Combine BM25 + embeddings (see Advanced Usage)
|
||||
4. **Production deployment** - Use Elasticsearch or Weaviate
|
||||
|
||||
### Explore More Integrations
|
||||
|
||||
- [LangChain Integration](LANGCHAIN.md) - Alternative RAG framework
|
||||
- [LlamaIndex Integration](LLAMA_INDEX.md) - Query engine approach
|
||||
- [Pinecone Integration](PINECONE.md) - Cloud vector database
|
||||
- [Cursor Integration](CURSOR.md) - AI coding assistant
|
||||
|
||||
### Learn More
|
||||
|
||||
- [RAG Pipelines Guide](RAG_PIPELINES.md) - Complete RAG overview
|
||||
- [Chunking Guide](../features/CHUNKING.md) - Semantic chunking details
|
||||
- [Haystack Documentation](https://docs.haystack.deepset.ai/)
|
||||
- [Example Repository](../../examples/haystack-pipeline/)
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Support
|
||||
|
||||
- **Questions:** [GitHub Discussions](https://github.com/yusufkaraaslan/Skill_Seekers/discussions)
|
||||
- **Issues:** [GitHub Issues](https://github.com/yusufkaraaslan/Skill_Seekers/issues)
|
||||
- **Haystack Help:** [Haystack Discord](https://discord.gg/haystack)
|
||||
|
||||
---
|
||||
|
||||
**Ready to build production RAG with Haystack?**
|
||||
|
||||
```bash
|
||||
pip install skill-seekers haystack-ai
|
||||
skill-seekers create --config configs/your-framework.json --chunk-for-rag
|
||||
skill-seekers package output/your-framework --target haystack
|
||||
```
|
||||
|
||||
Transform documentation into production-ready Haystack pipelines in minutes! 🚀
|
||||
@@ -0,0 +1,548 @@
|
||||
# AI System Integrations with Skill Seekers
|
||||
|
||||
**Universal Preprocessor:** Transform documentation into structured knowledge for any AI system
|
||||
|
||||
---
|
||||
|
||||
## 🤔 Which Integration Should I Use?
|
||||
|
||||
| Your Goal | Recommended Tool | Format | Setup Time | Guide |
|
||||
|-----------|-----------------|--------|------------|-------|
|
||||
| Build RAG with Python | LangChain | `--target langchain` | 5 min | [Guide](LANGCHAIN.md) |
|
||||
| Query engine from docs | LlamaIndex | `--target llama-index` | 5 min | [Guide](LLAMA_INDEX.md) |
|
||||
| Vector database only | Pinecone/Weaviate | `--target [db]` | 3 min | [Guide](PINECONE.md) |
|
||||
| AI coding (VS Code fork) | Cursor | `--target claude` | 5 min | [Guide](CURSOR.md) |
|
||||
| AI coding (Windsurf) | Windsurf | `--target markdown` | 5 min | [Guide](WINDSURF.md) |
|
||||
| AI coding (VS Code ext) | Cline (MCP) | `--target claude` | 10 min | [Guide](CLINE.md) |
|
||||
| AI coding (any IDE) | Continue.dev | `--target markdown` | 5 min | [Guide](CONTINUE_DEV.md) |
|
||||
| Claude AI chat | Claude | `--target claude` | 3 min | [Guide](CLAUDE.md) |
|
||||
| Chunked for RAG | Any + chunking | `--chunk-for-rag` | + 2 min | [RAG Guide](RAG_PIPELINES.md) |
|
||||
|
||||
---
|
||||
|
||||
## 📚 RAG & Vector Databases
|
||||
|
||||
### Production-Ready RAG Frameworks
|
||||
|
||||
Transform documentation into RAG-ready formats for AI-powered search and retrieval:
|
||||
|
||||
| Framework | Users | Format | Best For | Guide |
|
||||
|-----------|-------|--------|----------|-------|
|
||||
| **[LangChain](LANGCHAIN.md)** | 500K+ | Document | Python RAG, most popular | [Setup →](LANGCHAIN.md) |
|
||||
| **[LlamaIndex](LLAMA_INDEX.md)** | 200K+ | TextNode | Q&A focus, query engine | [Setup →](LLAMA_INDEX.md) |
|
||||
| **[Haystack](HAYSTACK.md)** | 50K+ | Document | Enterprise, multi-language | [Setup →](HAYSTACK.md) |
|
||||
|
||||
**Quick Example:**
|
||||
```bash
|
||||
# Generate LangChain documents
|
||||
skill-seekers create --config configs/react.json
|
||||
skill-seekers package output/react --target langchain
|
||||
|
||||
# Use in RAG pipeline
|
||||
python examples/langchain-rag-pipeline/quickstart.py
|
||||
```
|
||||
|
||||
### Vector Database Integrations
|
||||
|
||||
Direct upload to vector databases without RAG frameworks:
|
||||
|
||||
| Database | Type | Best For | Guide |
|
||||
|----------|------|----------|-------|
|
||||
| **[Pinecone](PINECONE.md)** | Cloud | Production, serverless | [Setup →](PINECONE.md) |
|
||||
| **[Weaviate](WEAVIATE.md)** | Self-hosted/Cloud | Enterprise, GraphQL | [Setup →](WEAVIATE.md) |
|
||||
| **[Chroma](CHROMA.md)** | Local | Development, embeddings included | [Setup →](CHROMA.md) |
|
||||
| **[FAISS](FAISS.md)** | Local | High performance, Facebook | [Setup →](FAISS.md) |
|
||||
| **[Qdrant](QDRANT.md)** | Self-hosted/Cloud | Rust engine, filtering | [Setup →](QDRANT.md) |
|
||||
|
||||
**Quick Example:**
|
||||
```bash
|
||||
# Generate Pinecone format
|
||||
skill-seekers create --config configs/fastapi.json
|
||||
skill-seekers package output/fastapi --target pinecone
|
||||
|
||||
# Upsert to Pinecone
|
||||
python examples/pinecone-upsert/quickstart.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💻 AI Coding Assistants
|
||||
|
||||
### IDE-Native AI Tools
|
||||
|
||||
Give AI coding assistants expert knowledge of your frameworks:
|
||||
|
||||
| Tool | Type | IDEs | Format | Setup | Guide |
|
||||
|------|------|------|--------|-------|-------|
|
||||
| **[Cursor](CURSOR.md)** | IDE (VS Code fork) | Cursor IDE | `.cursorrules` | 5 min | [Setup →](CURSOR.md) |
|
||||
| **[Windsurf](WINDSURF.md)** | IDE (Codeium) | Windsurf IDE | `.windsurfrules` | 5 min | [Setup →](WINDSURF.md) |
|
||||
| **[Cline](CLINE.md)** | VS Code Extension | VS Code | `.clinerules` + MCP | 10 min | [Setup →](CLINE.md) |
|
||||
| **[Continue.dev](CONTINUE_DEV.md)** | Plugin | VS Code, JetBrains, Vim | HTTP context | 5 min | [Setup →](CONTINUE_DEV.md) |
|
||||
|
||||
**Quick Example:**
|
||||
```bash
|
||||
# For any AI coding assistant (Cursor, Windsurf, Cline, Continue.dev)
|
||||
skill-seekers create --config configs/django.json
|
||||
skill-seekers package output/django --target markdown # or --target claude
|
||||
|
||||
# Copy to your project
|
||||
cp output/django-markdown/SKILL.md my-project/.cursorrules # or appropriate config
|
||||
```
|
||||
|
||||
**Comparison:**
|
||||
|
||||
| Feature | Cursor | Windsurf | Cline | Continue.dev |
|
||||
|---------|--------|----------|-------|--------------|
|
||||
| **IDE Type** | Fork (VS Code) | Native IDE | Extension | Plugin (multi-IDE) |
|
||||
| **Config File** | `.cursorrules` | `.windsurfrules` | `.clinerules` | HTTP context provider |
|
||||
| **Multi-IDE** | ❌ (Cursor only) | ❌ (Windsurf only) | ❌ (VS Code only) | ✅ (All IDEs) |
|
||||
| **MCP Support** | ✅ | ✅ | ✅ | ✅ |
|
||||
| **Character Limit** | No limit | 12K chars (6K per file) | No limit | No limit |
|
||||
| **Setup Complexity** | Easy ⭐ | Easy ⭐ | Medium ⭐⭐ | Easy ⭐ |
|
||||
| **Team Sharing** | Git-tracked file | Git-tracked files | Git-tracked file | HTTP server |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 AI Chat Platforms
|
||||
|
||||
Upload documentation as custom skills to AI chat platforms:
|
||||
|
||||
| Platform | Provider | Format | Best For | Guide |
|
||||
|----------|----------|--------|----------|-------|
|
||||
| **[Claude](CLAUDE.md)** | Anthropic | ZIP + YAML | Claude.ai Projects | [Setup →](CLAUDE.md) |
|
||||
| **[Gemini](GEMINI_INTEGRATION.md)** | Google | tar.gz | Gemini AI | [Setup →](GEMINI_INTEGRATION.md) |
|
||||
| **[ChatGPT](OPENAI_INTEGRATION.md)** | OpenAI | ZIP + Vector Store | GPT Actions | [Setup →](OPENAI_INTEGRATION.md) |
|
||||
| **[MiniMax](MINIMAX_INTEGRATION.md)** | MiniMax | ZIP | MiniMax AI Platform | [Setup →](MINIMAX_INTEGRATION.md) |
|
||||
|
||||
**Quick Example:**
|
||||
```bash
|
||||
# Generate Claude skill
|
||||
skill-seekers create --config configs/vue.json
|
||||
skill-seekers package output/vue --target claude
|
||||
|
||||
# Upload to Claude
|
||||
skill-seekers upload output/vue-claude.zip --target claude
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧠 Choosing the Right Integration
|
||||
|
||||
### By Use Case
|
||||
|
||||
| Your Goal | Best Integration | Why? | Setup Time |
|
||||
|-----------|-----------------|------|------------|
|
||||
| **Build Python RAG pipeline** | LangChain | Most popular, 500K+ users, extensive docs | 5 min |
|
||||
| **Query engine from docs** | LlamaIndex | Optimized for Q&A, built-in persistence | 5 min |
|
||||
| **Enterprise RAG system** | Haystack | Production-ready, multi-language support | 10 min |
|
||||
| **Vector DB only (no framework)** | Pinecone/Weaviate/Chroma | Direct upload, no framework overhead | 3 min |
|
||||
| **AI coding (VS Code fork)** | Cursor | Best integration, native `.cursorrules` | 5 min |
|
||||
| **AI coding (flow-based)** | Windsurf | Unique flow paradigm, Codeium AI | 5 min |
|
||||
| **AI coding (VS Code ext)** | Cline | Claude in VS Code, MCP integration | 10 min |
|
||||
| **AI coding (any IDE)** | Continue.dev | Works everywhere, open-source | 5 min |
|
||||
| **Chat with documentation** | Claude/Gemini/ChatGPT/MiniMax | Direct upload as custom skill | 3 min |
|
||||
|
||||
### By Technical Requirements
|
||||
|
||||
| Requirement | Compatible Integrations |
|
||||
|-------------|-------------------------|
|
||||
| **Python required** | LangChain, LlamaIndex, Haystack, all vector DBs |
|
||||
| **No dependencies** | Cursor, Windsurf, Cline, Continue.dev (markdown export) |
|
||||
| **Cloud-hosted** | Pinecone, Claude, Gemini, ChatGPT |
|
||||
| **Self-hosted** | Chroma, FAISS, Qdrant, Continue.dev |
|
||||
| **Multi-language** | Haystack, Continue.dev |
|
||||
| **VS Code specific** | Cursor, Cline, Continue.dev |
|
||||
| **IDE agnostic** | LangChain, LlamaIndex, Continue.dev |
|
||||
| **Real-time updates** | Continue.dev (HTTP server), MCP servers |
|
||||
|
||||
### By Team Size
|
||||
|
||||
| Team Size | Recommended Stack | Why? |
|
||||
|-----------|------------------|------|
|
||||
| **Solo developer** | Cursor + Claude + Chroma (local) | Simple setup, no infrastructure |
|
||||
| **Small team (2-5)** | Continue.dev + LangChain + Pinecone | IDE-agnostic, cloud vector DB |
|
||||
| **Medium team (5-20)** | Windsurf/Cursor + LlamaIndex + Weaviate | Good balance of features |
|
||||
| **Enterprise (20+)** | Continue.dev + Haystack + Qdrant/Weaviate | Production-ready, scalable |
|
||||
|
||||
### By Development Environment
|
||||
|
||||
| Environment | Recommended Tools | Setup |
|
||||
|-------------|------------------|-------|
|
||||
| **VS Code Only** | Cursor (fork) or Cline (extension) | `.cursorrules` or `.clinerules` |
|
||||
| **JetBrains Only** | Continue.dev | HTTP context provider |
|
||||
| **Mixed IDEs** | Continue.dev | Same config, all IDEs |
|
||||
| **Vim/Neovim** | Continue.dev | Plugin + HTTP server |
|
||||
| **Multiple Frameworks** | Continue.dev + RAG pipeline | HTTP server + vector search |
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Decision Tree
|
||||
|
||||
```
|
||||
Do you need RAG/search?
|
||||
├─ Yes → Use RAG framework (LangChain/LlamaIndex/Haystack)
|
||||
│ ├─ Beginner? → LangChain (most docs)
|
||||
│ ├─ Q&A focus? → LlamaIndex (optimized for queries)
|
||||
│ └─ Enterprise? → Haystack (production-ready)
|
||||
│
|
||||
└─ No → Use AI coding tool or chat platform
|
||||
├─ Need AI coding assistant?
|
||||
│ ├─ Use VS Code?
|
||||
│ │ ├─ Want native fork? → Cursor
|
||||
│ │ └─ Want extension? → Cline
|
||||
│ ├─ Use other IDE? → Continue.dev
|
||||
│ ├─ Use Windsurf? → Windsurf
|
||||
│ └─ Team uses mixed IDEs? → Continue.dev
|
||||
│
|
||||
└─ Just chat with docs? → Claude/Gemini/ChatGPT
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Common Patterns
|
||||
|
||||
### Pattern 1: RAG + AI Coding
|
||||
|
||||
**Best for:** Deep documentation search + context-aware coding
|
||||
|
||||
```bash
|
||||
# 1. Generate RAG pipeline (LangChain)
|
||||
skill-seekers create --config configs/django.json
|
||||
skill-seekers package output/django --target langchain --chunk-for-rag
|
||||
|
||||
# 2. Generate AI coding context (Cursor)
|
||||
skill-seekers package output/django --target claude
|
||||
|
||||
# 3. Use both:
|
||||
# - Cursor: Quick context for common patterns
|
||||
# - RAG: Deep search for complex questions
|
||||
|
||||
# Copy to project
|
||||
cp output/django-claude/SKILL.md my-project/.cursorrules
|
||||
|
||||
# Query RAG when needed
|
||||
python rag_search.py "How to implement custom Django middleware?"
|
||||
```
|
||||
|
||||
### Pattern 2: Multi-IDE Team Consistency
|
||||
|
||||
**Best for:** Teams using different IDEs
|
||||
|
||||
```bash
|
||||
# 1. Generate documentation
|
||||
skill-seekers create --config configs/react.json
|
||||
|
||||
# 2. Set up Continue.dev HTTP server (team server)
|
||||
python context_server.py --host 0.0.0.0 --port 8765
|
||||
|
||||
# 3. Team members configure Continue.dev:
|
||||
# ~/.continue/config.json (same for all IDEs)
|
||||
{
|
||||
"contextProviders": [{
|
||||
"name": "http",
|
||||
"params": {
|
||||
"url": "http://team-server:8765/docs/react",
|
||||
"title": "react-docs"
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
# Result: VS Code, IntelliJ, PyCharm all use same context!
|
||||
```
|
||||
|
||||
### Pattern 3: Full-Stack Development
|
||||
|
||||
**Best for:** Backend + Frontend with different frameworks
|
||||
|
||||
```bash
|
||||
# 1. Generate backend context (FastAPI)
|
||||
skill-seekers create --config configs/fastapi.json
|
||||
skill-seekers package output/fastapi --target markdown
|
||||
|
||||
# 2. Generate frontend context (Vue)
|
||||
skill-seekers create --config configs/vue.json
|
||||
skill-seekers package output/vue --target markdown
|
||||
|
||||
# 3. For Cursor (modular rules):
|
||||
cat output/fastapi-markdown/SKILL.md >> .cursorrules
|
||||
echo "\n\n# Frontend Framework\n" >> .cursorrules
|
||||
cat output/vue-markdown/SKILL.md >> .cursorrules
|
||||
|
||||
# 4. For Continue.dev (multiple providers):
|
||||
{
|
||||
"contextProviders": [
|
||||
{"name": "http", "params": {"url": "http://localhost:8765/docs/fastapi"}},
|
||||
{"name": "http", "params": {"url": "http://localhost:8765/docs/vue"}}
|
||||
]
|
||||
}
|
||||
|
||||
# Now AI knows BOTH backend AND frontend patterns!
|
||||
```
|
||||
|
||||
### Pattern 4: Documentation + Codebase Analysis
|
||||
|
||||
**Best for:** Custom internal frameworks
|
||||
|
||||
```bash
|
||||
# 1. Scrape public documentation
|
||||
skill-seekers create --config configs/custom-framework.json
|
||||
|
||||
# 2. Analyze internal codebase
|
||||
skill-seekers create /path/to/internal/repo --preset comprehensive
|
||||
|
||||
# 3. Merge both via a unified config (sources array with docs + local entries):
|
||||
skill-seekers create --config configs/complete-knowledge.json \
|
||||
--output output/complete-knowledge
|
||||
|
||||
# 4. Package for any platform
|
||||
skill-seekers package output/complete-knowledge --target [platform]
|
||||
|
||||
# Result: Documentation + Real-world code patterns!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 Best Practices
|
||||
|
||||
### 1. Start Simple, Scale Up
|
||||
|
||||
**Phase 1:** Single framework, single tool
|
||||
```bash
|
||||
# Week 1: Just Cursor + React
|
||||
skill-seekers create --config configs/react.json
|
||||
skill-seekers package output/react --target claude
|
||||
cp output/react-claude/SKILL.md .cursorrules
|
||||
```
|
||||
|
||||
**Phase 2:** Add RAG for deep search
|
||||
```bash
|
||||
# Week 2: Add LangChain for complex queries
|
||||
skill-seekers package output/react --target langchain --chunk-for-rag
|
||||
# Now you have: Cursor (quick) + RAG (deep)
|
||||
```
|
||||
|
||||
**Phase 3:** Scale to team
|
||||
```bash
|
||||
# Week 3: Continue.dev HTTP server for team
|
||||
python context_server.py --host 0.0.0.0
|
||||
# Team members configure Continue.dev
|
||||
```
|
||||
|
||||
### 2. Layer Your Context
|
||||
|
||||
**Priority order:**
|
||||
|
||||
1. **Project conventions** (highest priority)
|
||||
- Custom patterns
|
||||
- Team standards
|
||||
- Company guidelines
|
||||
|
||||
2. **Framework documentation** (medium priority)
|
||||
- Official best practices
|
||||
- Common patterns
|
||||
- API reference
|
||||
|
||||
3. **RAG search** (lowest priority)
|
||||
- Deep documentation search
|
||||
- Edge cases
|
||||
- Historical context
|
||||
|
||||
**Example (Cursor):**
|
||||
```bash
|
||||
# Layer 1: Project conventions (loaded first)
|
||||
cat > .cursorrules << 'EOF'
|
||||
# Project-Specific Patterns (HIGHEST PRIORITY)
|
||||
Always use async/await for database operations.
|
||||
Never use 'any' type in TypeScript.
|
||||
EOF
|
||||
|
||||
# Layer 2: Framework docs (loaded second)
|
||||
cat output/react-markdown/SKILL.md >> .cursorrules
|
||||
|
||||
# Layer 3: RAG search (when needed)
|
||||
# Query separately for deep questions
|
||||
```
|
||||
|
||||
### 3. Update Regularly
|
||||
|
||||
**Monthly:** Framework documentation
|
||||
```bash
|
||||
# Check for framework updates
|
||||
skill-seekers create --config configs/react.json
|
||||
# If new version, re-package
|
||||
skill-seekers package output/react --target [your-platform]
|
||||
```
|
||||
|
||||
**Quarterly:** Codebase analysis
|
||||
```bash
|
||||
# Re-analyze internal codebase for new patterns
|
||||
skill-seekers create . --preset comprehensive
|
||||
```
|
||||
|
||||
**Yearly:** Architecture review
|
||||
```bash
|
||||
# Review and update project conventions
|
||||
# Check if new integrations are available
|
||||
```
|
||||
|
||||
### 4. Measure Effectiveness
|
||||
|
||||
**Track these metrics:**
|
||||
|
||||
- **Context hit rate:** How often AI references your documentation
|
||||
- **Code quality:** Fewer pattern violations after adding context
|
||||
- **Development speed:** Time saved on common tasks
|
||||
- **Team consistency:** Similar code patterns across team members
|
||||
|
||||
**Example monitoring:**
|
||||
```python
|
||||
# Track Cursor suggestions quality
|
||||
# Compare before/after adding .cursorrules
|
||||
|
||||
# Before: 60% generic suggestions, 40% framework-specific
|
||||
# After: 20% generic suggestions, 80% framework-specific
|
||||
# Improvement: 2x better context awareness
|
||||
```
|
||||
|
||||
### 5. Share with Team
|
||||
|
||||
**Git-tracked configs:**
|
||||
```bash
|
||||
# Add to version control
|
||||
git add .cursorrules
|
||||
git add .clinerules
|
||||
git add .continue/config.json
|
||||
git commit -m "Add AI assistant configuration"
|
||||
|
||||
# Team benefits immediately
|
||||
git pull # New team member gets context
|
||||
```
|
||||
|
||||
**Documentation:**
|
||||
```markdown
|
||||
# README.md
|
||||
|
||||
## AI Assistant Setup
|
||||
|
||||
This project uses Cursor with custom rules:
|
||||
|
||||
1. Install Cursor: https://cursor.sh/
|
||||
2. Open project: `cursor .`
|
||||
3. Rules auto-load from `.cursorrules`
|
||||
4. Start coding with AI context!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📖 Complete Guides
|
||||
|
||||
### RAG & Vector Databases
|
||||
- **[LangChain Integration](LANGCHAIN.md)** - 500K+ users, Document format
|
||||
- **[LlamaIndex Integration](LLAMA_INDEX.md)** - 200K+ users, TextNode format
|
||||
- **[Pinecone Integration](PINECONE.md)** - Cloud-native vector database
|
||||
- **[Weaviate Integration](WEAVIATE.md)** - Enterprise-grade, GraphQL API
|
||||
- **[Chroma Integration](CHROMA.md)** - Local-first, embeddings included
|
||||
- **[RAG Pipelines Guide](RAG_PIPELINES.md)** - End-to-end RAG setup
|
||||
|
||||
### AI Coding Assistants
|
||||
- **[Cursor Integration](CURSOR.md)** - VS Code fork with AI (`.cursorrules`)
|
||||
- **[Windsurf Integration](WINDSURF.md)** - Codeium's IDE with AI flows
|
||||
- **[Cline Integration](CLINE.md)** - Claude in VS Code (MCP integration)
|
||||
- **[Continue.dev Integration](CONTINUE_DEV.md)** - Multi-platform, open-source
|
||||
|
||||
### AI Chat Platforms
|
||||
- **[Claude Integration](CLAUDE.md)** - Anthropic's AI assistant
|
||||
- **[Gemini Integration](GEMINI_INTEGRATION.md)** - Google's AI
|
||||
- **[ChatGPT Integration](OPENAI_INTEGRATION.md)** - OpenAI
|
||||
|
||||
### Advanced Topics
|
||||
- **[Multi-LLM Support](MULTI_LLM_SUPPORT.md)** - Platform comparison
|
||||
- **[MCP Setup Guide](../MCP_SETUP.md)** - Model Context Protocol
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Start Examples
|
||||
|
||||
### For RAG Pipelines:
|
||||
```bash
|
||||
# Generate LangChain documents
|
||||
skill-seekers create --config configs/react.json
|
||||
skill-seekers package output/react --target langchain
|
||||
|
||||
# Use in RAG pipeline
|
||||
python examples/langchain-rag-pipeline/quickstart.py
|
||||
```
|
||||
|
||||
### For AI Coding:
|
||||
```bash
|
||||
# Generate Cursor rules
|
||||
skill-seekers create --config configs/django.json
|
||||
skill-seekers package output/django --target claude
|
||||
|
||||
# Copy to project
|
||||
cp output/django-claude/SKILL.md my-project/.cursorrules
|
||||
```
|
||||
|
||||
### For Vector Databases:
|
||||
```bash
|
||||
# Generate Pinecone format
|
||||
skill-seekers create --config configs/fastapi.json
|
||||
skill-seekers package output/fastapi --target pinecone
|
||||
|
||||
# Upsert to Pinecone
|
||||
python examples/pinecone-upsert/quickstart.py
|
||||
```
|
||||
|
||||
### For Multi-IDE Teams:
|
||||
```bash
|
||||
# Generate documentation
|
||||
skill-seekers create --config configs/vue.json
|
||||
|
||||
# Start HTTP context server
|
||||
python examples/continue-dev-universal/context_server.py
|
||||
|
||||
# Configure Continue.dev (same config, all IDEs)
|
||||
# ~/.continue/config.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Platform Comparison Matrix
|
||||
|
||||
| Feature | LangChain | LlamaIndex | Cursor | Windsurf | Cline | Continue.dev | Claude Chat |
|
||||
|---------|-----------|------------|--------|----------|-------|--------------|-------------|
|
||||
| **Setup Time** | 5 min | 5 min | 5 min | 5 min | 10 min | 5 min | 3 min |
|
||||
| **Python Required** | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| **Works Offline** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| **Multi-IDE** | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ |
|
||||
| **Real-time Updates** | ✅ | ✅ | ❌ | ❌ | ✅ (MCP) | ✅ | ❌ |
|
||||
| **Team Sharing** | Git | Git | Git | Git | Git | HTTP server | Cloud |
|
||||
| **Context Limit** | No limit | No limit | No limit | 12K chars | No limit | No limit | 200K tokens |
|
||||
| **Custom Search** | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ |
|
||||
| **Best For** | RAG pipelines | Q&A engines | VS Code users | Windsurf users | Claude in VS Code | Multi-IDE teams | Quick chat |
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Community & Support
|
||||
|
||||
- **Questions:** [GitHub Discussions](https://github.com/yusufkaraaslan/Skill_Seekers/discussions)
|
||||
- **Issues:** [GitHub Issues](https://github.com/yusufkaraaslan/Skill_Seekers/issues)
|
||||
- **Website:** [skillseekersweb.com](https://skillseekersweb.com/)
|
||||
- **Examples:** [GitHub Examples](https://github.com/yusufkaraaslan/Skill_Seekers/tree/main/examples)
|
||||
|
||||
---
|
||||
|
||||
## 📖 What's Next?
|
||||
|
||||
1. **Choose your integration** from the table above
|
||||
2. **Follow the setup guide** (5-10 minutes)
|
||||
3. **Test with your framework** using provided examples
|
||||
4. **Customize for your project** with project-specific patterns
|
||||
5. **Share with your team** via Git or HTTP server
|
||||
|
||||
**Need help deciding?** Ask in [GitHub Discussions](https://github.com/yusufkaraaslan/Skill_Seekers/discussions)
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** February 7, 2026
|
||||
**Skill Seekers Version:** v3.6.0
|
||||
@@ -0,0 +1,518 @@
|
||||
# Using Skill Seekers with LangChain
|
||||
|
||||
**Last Updated:** February 5, 2026
|
||||
**Status:** Production Ready
|
||||
**Difficulty:** Easy ⭐
|
||||
|
||||
---
|
||||
|
||||
## 🎯 The Problem
|
||||
|
||||
Building RAG (Retrieval-Augmented Generation) applications with LangChain requires high-quality, structured documentation for your vector stores. Manually scraping and chunking documentation is:
|
||||
|
||||
- **Time-Consuming** - Hours spent scraping docs and formatting them
|
||||
- **Error-Prone** - Inconsistent chunking, missing metadata, broken references
|
||||
- **Not Maintainable** - Documentation updates require re-scraping everything
|
||||
|
||||
**Example:**
|
||||
> "When building a RAG chatbot for React documentation, you need to scrape 500+ pages, chunk them properly, add metadata, and load into a vector store. This typically takes 4-6 hours of manual work."
|
||||
|
||||
---
|
||||
|
||||
## ✨ The Solution
|
||||
|
||||
Use Skill Seekers as **essential preprocessing** before LangChain:
|
||||
|
||||
1. **Generate LangChain Documents** from any documentation source
|
||||
2. **Pre-chunked and structured** with proper metadata
|
||||
3. **Ready for vector stores** (Chroma, Pinecone, FAISS, etc.)
|
||||
4. **One command** - scrape, chunk, format in minutes
|
||||
|
||||
**Result:**
|
||||
Skill Seekers outputs JSON files with LangChain Document format, ready to load directly into your RAG pipeline.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Start (5 Minutes)
|
||||
|
||||
### Prerequisites
|
||||
- Python 3.10+
|
||||
- LangChain installed: `pip install langchain langchain-community`
|
||||
- OpenAI API key (for embeddings): `export OPENAI_API_KEY=sk-...`
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
# Install Skill Seekers
|
||||
pip install skill-seekers
|
||||
|
||||
# Verify installation
|
||||
skill-seekers --version
|
||||
```
|
||||
|
||||
### Generate LangChain Documents
|
||||
|
||||
```bash
|
||||
# Example: React framework documentation
|
||||
skill-seekers create --config configs/react.json
|
||||
|
||||
# Package as LangChain Documents
|
||||
skill-seekers package output/react --target langchain
|
||||
|
||||
# Output: output/react-langchain.json
|
||||
```
|
||||
|
||||
### Load into LangChain
|
||||
|
||||
```python
|
||||
from langchain.schema import Document
|
||||
from langchain.vectorstores import Chroma
|
||||
from langchain.embeddings import OpenAIEmbeddings
|
||||
import json
|
||||
|
||||
# Load documents
|
||||
with open("output/react-langchain.json") as f:
|
||||
docs_data = json.load(f)
|
||||
|
||||
# Convert to LangChain Documents
|
||||
documents = [
|
||||
Document(page_content=doc["page_content"], metadata=doc["metadata"])
|
||||
for doc in docs_data
|
||||
]
|
||||
|
||||
print(f"Loaded {len(documents)} documents")
|
||||
|
||||
# Create vector store
|
||||
embeddings = OpenAIEmbeddings()
|
||||
vectorstore = Chroma.from_documents(documents, embeddings)
|
||||
|
||||
# Query
|
||||
results = vectorstore.similarity_search("How do I use React hooks?", k=3)
|
||||
for doc in results:
|
||||
print(f"\n{doc.metadata['category']}: {doc.page_content[:200]}...")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📖 Detailed Setup Guide
|
||||
|
||||
### Step 1: Choose Your Documentation Source
|
||||
|
||||
**Option A: Use Preset Config (Fastest)**
|
||||
```bash
|
||||
# Available presets: react, vue, django, fastapi, etc.
|
||||
skill-seekers create --config configs/react.json
|
||||
```
|
||||
|
||||
**Option B: From GitHub Repository**
|
||||
```bash
|
||||
# Scrape from GitHub repo (includes code + docs)
|
||||
skill-seekers create facebook/react --name react-skill
|
||||
```
|
||||
|
||||
**Option C: Custom Documentation**
|
||||
```bash
|
||||
# Create custom config for your docs
|
||||
skill-seekers create --config configs/my-docs.json
|
||||
```
|
||||
|
||||
### Step 2: Generate LangChain Format
|
||||
|
||||
```bash
|
||||
# Convert to LangChain Documents
|
||||
skill-seekers package output/react --target langchain
|
||||
|
||||
# Output structure:
|
||||
# output/react-langchain.json
|
||||
# [
|
||||
# {
|
||||
# "page_content": "...",
|
||||
# "metadata": {
|
||||
# "source": "react",
|
||||
# "category": "hooks",
|
||||
# "file": "hooks.md",
|
||||
# "type": "reference"
|
||||
# }
|
||||
# }
|
||||
# ]
|
||||
```
|
||||
|
||||
**What You Get:**
|
||||
- ✅ Pre-chunked documents (semantic boundaries preserved)
|
||||
- ✅ Rich metadata (source, category, file, type)
|
||||
- ✅ Clean markdown (code blocks preserved)
|
||||
- ✅ Ready for embeddings
|
||||
|
||||
### Step 3: Load into Vector Store
|
||||
|
||||
**Option 1: Chroma (Local, Persistent)**
|
||||
```python
|
||||
from langchain.vectorstores import Chroma
|
||||
from langchain.embeddings import OpenAIEmbeddings
|
||||
from langchain.schema import Document
|
||||
import json
|
||||
|
||||
# Load documents
|
||||
with open("output/react-langchain.json") as f:
|
||||
docs_data = json.load(f)
|
||||
|
||||
documents = [
|
||||
Document(page_content=doc["page_content"], metadata=doc["metadata"])
|
||||
for doc in docs_data
|
||||
]
|
||||
|
||||
# Create persistent Chroma store
|
||||
embeddings = OpenAIEmbeddings()
|
||||
vectorstore = Chroma.from_documents(
|
||||
documents,
|
||||
embeddings,
|
||||
persist_directory="./chroma_db"
|
||||
)
|
||||
|
||||
print(f"✅ {len(documents)} documents loaded into Chroma")
|
||||
```
|
||||
|
||||
**Option 2: FAISS (Fast, In-Memory)**
|
||||
```python
|
||||
from langchain.vectorstores import FAISS
|
||||
from langchain.embeddings import OpenAIEmbeddings
|
||||
from langchain.schema import Document
|
||||
import json
|
||||
|
||||
with open("output/react-langchain.json") as f:
|
||||
docs_data = json.load(f)
|
||||
|
||||
documents = [
|
||||
Document(page_content=doc["page_content"], metadata=doc["metadata"])
|
||||
for doc in docs_data
|
||||
]
|
||||
|
||||
embeddings = OpenAIEmbeddings()
|
||||
vectorstore = FAISS.from_documents(documents, embeddings)
|
||||
|
||||
# Save for later use
|
||||
vectorstore.save_local("faiss_index")
|
||||
|
||||
print(f"✅ {len(documents)} documents loaded into FAISS")
|
||||
```
|
||||
|
||||
**Option 3: Pinecone (Cloud, Scalable)**
|
||||
```python
|
||||
from langchain.vectorstores import Pinecone as LangChainPinecone
|
||||
from langchain.embeddings import OpenAIEmbeddings
|
||||
from langchain.schema import Document
|
||||
import json
|
||||
import pinecone
|
||||
|
||||
# Initialize Pinecone
|
||||
pinecone.init(api_key="your-api-key", environment="us-west1-gcp")
|
||||
index_name = "react-docs"
|
||||
|
||||
if index_name not in pinecone.list_indexes():
|
||||
pinecone.create_index(index_name, dimension=1536)
|
||||
|
||||
# Load documents
|
||||
with open("output/react-langchain.json") as f:
|
||||
docs_data = json.load(f)
|
||||
|
||||
documents = [
|
||||
Document(page_content=doc["page_content"], metadata=doc["metadata"])
|
||||
for doc in docs_data
|
||||
]
|
||||
|
||||
# Upload to Pinecone
|
||||
embeddings = OpenAIEmbeddings()
|
||||
vectorstore = LangChainPinecone.from_documents(
|
||||
documents,
|
||||
embeddings,
|
||||
index_name=index_name
|
||||
)
|
||||
|
||||
print(f"✅ {len(documents)} documents uploaded to Pinecone")
|
||||
```
|
||||
|
||||
### Step 4: Build RAG Chain
|
||||
|
||||
```python
|
||||
from langchain.chains import RetrievalQA
|
||||
from langchain.chat_models import ChatOpenAI
|
||||
|
||||
# Create retriever from vector store
|
||||
retriever = vectorstore.as_retriever(
|
||||
search_type="similarity",
|
||||
search_kwargs={"k": 3}
|
||||
)
|
||||
|
||||
# Create RAG chain
|
||||
llm = ChatOpenAI(model_name="gpt-4", temperature=0)
|
||||
qa_chain = RetrievalQA.from_chain_type(
|
||||
llm=llm,
|
||||
chain_type="stuff",
|
||||
retriever=retriever,
|
||||
return_source_documents=True
|
||||
)
|
||||
|
||||
# Query
|
||||
query = "How do I use React hooks?"
|
||||
result = qa_chain({"query": query})
|
||||
|
||||
print(f"Answer: {result['result']}")
|
||||
print(f"\nSources:")
|
||||
for doc in result['source_documents']:
|
||||
print(f" - {doc.metadata['category']}: {doc.metadata['file']}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Advanced Usage
|
||||
|
||||
### Filter by Metadata
|
||||
|
||||
```python
|
||||
# Search only in specific categories
|
||||
retriever = vectorstore.as_retriever(
|
||||
search_type="similarity",
|
||||
search_kwargs={
|
||||
"k": 5,
|
||||
"filter": {"category": "hooks"}
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
### Custom Metadata Enrichment
|
||||
|
||||
```python
|
||||
# Add custom metadata before loading
|
||||
for doc_data in docs_data:
|
||||
doc_data["metadata"]["indexed_at"] = datetime.now().isoformat()
|
||||
doc_data["metadata"]["version"] = "18.2.0"
|
||||
|
||||
documents = [
|
||||
Document(page_content=doc["page_content"], metadata=doc["metadata"])
|
||||
for doc in docs_data
|
||||
]
|
||||
```
|
||||
|
||||
### Multi-Source Documentation
|
||||
|
||||
```python
|
||||
# Combine multiple documentation sources
|
||||
sources = ["react", "vue", "angular"]
|
||||
all_documents = []
|
||||
|
||||
for source in sources:
|
||||
with open(f"output/{source}-langchain.json") as f:
|
||||
docs_data = json.load(f)
|
||||
|
||||
documents = [
|
||||
Document(page_content=doc["page_content"], metadata=doc["metadata"])
|
||||
for doc in docs_data
|
||||
]
|
||||
all_documents.extend(documents)
|
||||
|
||||
# Create unified vector store
|
||||
vectorstore = Chroma.from_documents(all_documents, embeddings)
|
||||
print(f"✅ Loaded {len(all_documents)} documents from {len(sources)} sources")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 Best Practices
|
||||
|
||||
### 1. Start with Presets
|
||||
Use tested configurations to avoid scraping issues:
|
||||
```bash
|
||||
ls configs/ # See available presets
|
||||
skill-seekers create --config configs/django.json
|
||||
```
|
||||
|
||||
### 2. Test Queries Before Full Pipeline
|
||||
```python
|
||||
# Quick test with similarity search
|
||||
results = vectorstore.similarity_search("your query", k=3)
|
||||
for doc in results:
|
||||
print(f"{doc.metadata['category']}: {doc.page_content[:100]}")
|
||||
```
|
||||
|
||||
### 3. Use Persistent Storage
|
||||
```python
|
||||
# Save Chroma DB for reuse
|
||||
vectorstore = Chroma.from_documents(
|
||||
documents,
|
||||
embeddings,
|
||||
persist_directory="./chroma_db" # ← Persists to disk
|
||||
)
|
||||
|
||||
# Later: load existing DB
|
||||
vectorstore = Chroma(
|
||||
persist_directory="./chroma_db",
|
||||
embedding_function=embeddings
|
||||
)
|
||||
```
|
||||
|
||||
### 4. Monitor Token Usage
|
||||
```python
|
||||
# Check document sizes before embedding
|
||||
total_tokens = sum(len(doc["page_content"].split()) for doc in docs_data)
|
||||
print(f"Estimated tokens: {total_tokens * 1.3:.0f}") # Rough estimate
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔥 Real-World Example
|
||||
|
||||
### Building a React Documentation Chatbot
|
||||
|
||||
**Step 1: Generate Documents**
|
||||
```bash
|
||||
# Scrape React docs
|
||||
skill-seekers create --config configs/react.json
|
||||
|
||||
# Convert to LangChain format
|
||||
skill-seekers package output/react --target langchain
|
||||
```
|
||||
|
||||
**Step 2: Create Vector Store**
|
||||
```python
|
||||
from langchain.vectorstores import Chroma
|
||||
from langchain.embeddings import OpenAIEmbeddings
|
||||
from langchain.schema import Document
|
||||
from langchain.chains import ConversationalRetrievalChain
|
||||
from langchain.chat_models import ChatOpenAI
|
||||
from langchain.memory import ConversationBufferMemory
|
||||
import json
|
||||
|
||||
# Load documents
|
||||
with open("output/react-langchain.json") as f:
|
||||
docs_data = json.load(f)
|
||||
|
||||
documents = [
|
||||
Document(page_content=doc["page_content"], metadata=doc["metadata"])
|
||||
for doc in docs_data
|
||||
]
|
||||
|
||||
# Create vector store
|
||||
embeddings = OpenAIEmbeddings()
|
||||
vectorstore = Chroma.from_documents(
|
||||
documents,
|
||||
embeddings,
|
||||
persist_directory="./react_chroma"
|
||||
)
|
||||
|
||||
print(f"✅ Loaded {len(documents)} React documentation chunks")
|
||||
```
|
||||
|
||||
**Step 3: Build Conversational RAG**
|
||||
```python
|
||||
# Create conversational chain with memory
|
||||
memory = ConversationBufferMemory(
|
||||
memory_key="chat_history",
|
||||
return_messages=True
|
||||
)
|
||||
|
||||
qa_chain = ConversationalRetrievalChain.from_llm(
|
||||
llm=ChatOpenAI(model_name="gpt-4", temperature=0),
|
||||
retriever=vectorstore.as_retriever(search_kwargs={"k": 3}),
|
||||
memory=memory,
|
||||
return_source_documents=True
|
||||
)
|
||||
|
||||
# Chat loop
|
||||
while True:
|
||||
query = input("\nYou: ")
|
||||
if query.lower() in ['quit', 'exit']:
|
||||
break
|
||||
|
||||
result = qa_chain({"question": query})
|
||||
print(f"\nAssistant: {result['answer']}")
|
||||
|
||||
print(f"\nSources:")
|
||||
for doc in result['source_documents']:
|
||||
print(f" - {doc.metadata['category']}: {doc.metadata['file']}")
|
||||
```
|
||||
|
||||
**Result:**
|
||||
- Complete React documentation in 100-200 documents
|
||||
- Sub-second query responses
|
||||
- Source attribution for every answer
|
||||
- Conversational context maintained
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Issue: Too Many Documents
|
||||
**Solution:** Filter by category or split into multiple indexes
|
||||
```python
|
||||
# Filter specific categories
|
||||
hooks_docs = [
|
||||
doc for doc in docs_data
|
||||
if doc["metadata"]["category"] == "hooks"
|
||||
]
|
||||
```
|
||||
|
||||
### Issue: Large Documents
|
||||
**Solution:** Documents are already chunked, but you can re-chunk if needed
|
||||
```python
|
||||
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
||||
|
||||
text_splitter = RecursiveCharacterTextSplitter(
|
||||
chunk_size=1000,
|
||||
chunk_overlap=200
|
||||
)
|
||||
|
||||
split_documents = text_splitter.split_documents(documents)
|
||||
```
|
||||
|
||||
### Issue: Missing Dependencies
|
||||
**Solution:** Install LangChain components
|
||||
```bash
|
||||
pip install langchain langchain-community langchain-openai
|
||||
pip install chromadb # For Chroma
|
||||
pip install faiss-cpu # For FAISS
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Before vs After Comparison
|
||||
|
||||
| Aspect | Manual Process | With Skill Seekers |
|
||||
|--------|---------------|-------------------|
|
||||
| **Time to Setup** | 4-6 hours | 5 minutes |
|
||||
| **Documentation Coverage** | 50-70% (cherry-picked) | 95-100% (comprehensive) |
|
||||
| **Metadata Quality** | Manual, inconsistent | Automatic, structured |
|
||||
| **Maintenance** | Re-scrape everything | Re-run one command |
|
||||
| **Code Examples** | Often missing | Preserved with syntax |
|
||||
| **Updates** | Hours of work | 5 minutes |
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Community & Support
|
||||
|
||||
- **Questions:** [GitHub Discussions](https://github.com/yusufkaraaslan/Skill_Seekers/discussions)
|
||||
- **Issues:** [GitHub Issues](https://github.com/yusufkaraaslan/Skill_Seekers/issues)
|
||||
- **Documentation:** [https://skillseekersweb.com/](https://skillseekersweb.com/)
|
||||
- **Twitter:** [@_yUSyUS_](https://x.com/_yUSyUS_)
|
||||
|
||||
---
|
||||
|
||||
## 📚 Related Guides
|
||||
|
||||
- [LlamaIndex Integration](./LLAMA_INDEX.md)
|
||||
- [Pinecone Integration](./PINECONE.md)
|
||||
- [RAG Pipelines Overview](./RAG_PIPELINES.md)
|
||||
|
||||
---
|
||||
|
||||
## 📖 Next Steps
|
||||
|
||||
1. **Try the Quick Start** above
|
||||
2. **Explore other vector stores** (Pinecone, Weaviate, Qdrant)
|
||||
3. **Build your RAG application** with production-ready docs
|
||||
4. **Share your experience** - we'd love to hear how you use it!
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** February 5, 2026
|
||||
**Tested With:** LangChain v0.1.0+, OpenAI Embeddings
|
||||
**Skill Seekers Version:** v3.6.0
|
||||
@@ -0,0 +1,528 @@
|
||||
# Using Skill Seekers with LlamaIndex
|
||||
|
||||
**Last Updated:** February 5, 2026
|
||||
**Status:** Production Ready
|
||||
**Difficulty:** Easy ⭐
|
||||
|
||||
---
|
||||
|
||||
## 🎯 The Problem
|
||||
|
||||
Building knowledge bases and query engines with LlamaIndex requires well-structured documentation. Manually preparing documents is:
|
||||
|
||||
- **Labor-Intensive** - Scraping, chunking, and formatting takes hours
|
||||
- **Inconsistent** - Manual processes lead to quality variations
|
||||
- **Hard to Update** - Documentation changes require complete rework
|
||||
|
||||
**Example:**
|
||||
> "When building a LlamaIndex query engine for FastAPI documentation, you need to extract 300+ pages, structure them properly, and maintain consistent metadata. This typically takes 3-5 hours."
|
||||
|
||||
---
|
||||
|
||||
## ✨ The Solution
|
||||
|
||||
Use Skill Seekers as **essential preprocessing** before LlamaIndex:
|
||||
|
||||
1. **Generate LlamaIndex Nodes** from any documentation source
|
||||
2. **Pre-structured with IDs** and rich metadata
|
||||
3. **Ready for indexes** (VectorStoreIndex, TreeIndex, KeywordTableIndex)
|
||||
4. **One command** - complete documentation in minutes
|
||||
|
||||
**Result:**
|
||||
Skill Seekers outputs JSON files with LlamaIndex Node format, ready to build indexes and query engines.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Start (5 Minutes)
|
||||
|
||||
### Prerequisites
|
||||
- Python 3.10+
|
||||
- LlamaIndex installed: `pip install llama-index`
|
||||
- OpenAI API key (for embeddings): `export OPENAI_API_KEY=sk-...`
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
# Install Skill Seekers
|
||||
pip install skill-seekers
|
||||
|
||||
# Verify installation
|
||||
skill-seekers --version
|
||||
```
|
||||
|
||||
### Generate LlamaIndex Nodes
|
||||
|
||||
```bash
|
||||
# Example: Django framework documentation
|
||||
skill-seekers create --config configs/django.json
|
||||
|
||||
# Package as LlamaIndex Nodes
|
||||
skill-seekers package output/django --target llama-index
|
||||
|
||||
# Output: output/django-llama-index.json
|
||||
```
|
||||
|
||||
### Build Query Engine
|
||||
|
||||
```python
|
||||
from llama_index.core.schema import TextNode
|
||||
from llama_index.core import VectorStoreIndex
|
||||
import json
|
||||
|
||||
# Load nodes
|
||||
with open("output/django-llama-index.json") as f:
|
||||
nodes_data = json.load(f)
|
||||
|
||||
# Convert to LlamaIndex Nodes
|
||||
nodes = [
|
||||
TextNode(
|
||||
text=node["text"],
|
||||
metadata=node["metadata"],
|
||||
id_=node["id_"]
|
||||
)
|
||||
for node in nodes_data
|
||||
]
|
||||
|
||||
print(f"Loaded {len(nodes)} nodes")
|
||||
|
||||
# Create index
|
||||
index = VectorStoreIndex(nodes)
|
||||
|
||||
# Create query engine
|
||||
query_engine = index.as_query_engine()
|
||||
|
||||
# Query
|
||||
response = query_engine.query("How do I create a Django model?")
|
||||
print(response)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📖 Detailed Setup Guide
|
||||
|
||||
### Step 1: Choose Your Documentation Source
|
||||
|
||||
**Option A: Use Preset Config (Fastest)**
|
||||
```bash
|
||||
# Available presets: django, fastapi, vue, etc.
|
||||
skill-seekers create --config configs/django.json
|
||||
```
|
||||
|
||||
**Option B: From GitHub Repository**
|
||||
```bash
|
||||
# Scrape from GitHub repo
|
||||
skill-seekers create django/django --name django-skill
|
||||
```
|
||||
|
||||
**Option C: Custom Documentation**
|
||||
```bash
|
||||
# Create custom config
|
||||
skill-seekers create --config configs/my-docs.json
|
||||
```
|
||||
|
||||
### Step 2: Generate LlamaIndex Format
|
||||
|
||||
```bash
|
||||
# Convert to LlamaIndex Nodes
|
||||
skill-seekers package output/django --target llama-index
|
||||
|
||||
# Output structure:
|
||||
# output/django-llama-index.json
|
||||
# [
|
||||
# {
|
||||
# "text": "...",
|
||||
# "metadata": {
|
||||
# "source": "django",
|
||||
# "category": "models",
|
||||
# "file": "models.md"
|
||||
# },
|
||||
# "id_": "unique-hash-id",
|
||||
# "embedding": null
|
||||
# }
|
||||
# ]
|
||||
```
|
||||
|
||||
**What You Get:**
|
||||
- ✅ Pre-structured nodes with unique IDs
|
||||
- ✅ Rich metadata (source, category, file, type)
|
||||
- ✅ Clean text (code blocks preserved)
|
||||
- ✅ Ready for indexing
|
||||
|
||||
### Step 3: Create Vector Store Index
|
||||
|
||||
```python
|
||||
from llama_index.core.schema import TextNode
|
||||
from llama_index.core import VectorStoreIndex, StorageContext
|
||||
from llama_index.core.storage.docstore import SimpleDocumentStore
|
||||
from llama_index.core.storage.index_store import SimpleIndexStore
|
||||
from llama_index.core.vector_stores import SimpleVectorStore
|
||||
import json
|
||||
|
||||
# Load nodes
|
||||
with open("output/django-llama-index.json") as f:
|
||||
nodes_data = json.load(f)
|
||||
|
||||
nodes = [
|
||||
TextNode(
|
||||
text=node["text"],
|
||||
metadata=node["metadata"],
|
||||
id_=node["id_"]
|
||||
)
|
||||
for node in nodes_data
|
||||
]
|
||||
|
||||
# Create index
|
||||
index = VectorStoreIndex(nodes)
|
||||
|
||||
# Persist for later use
|
||||
index.storage_context.persist(persist_dir="./storage")
|
||||
|
||||
print(f"✅ Index created with {len(nodes)} nodes")
|
||||
```
|
||||
|
||||
**Load Persisted Index:**
|
||||
```python
|
||||
from llama_index.core import load_index_from_storage, StorageContext
|
||||
|
||||
# Load from disk
|
||||
storage_context = StorageContext.from_defaults(persist_dir="./storage")
|
||||
index = load_index_from_storage(storage_context)
|
||||
|
||||
print("✅ Index loaded from storage")
|
||||
```
|
||||
|
||||
### Step 4: Create Query Engine
|
||||
|
||||
**Basic Query Engine:**
|
||||
```python
|
||||
# Create query engine
|
||||
query_engine = index.as_query_engine(
|
||||
similarity_top_k=3, # Return top 3 relevant chunks
|
||||
response_mode="compact"
|
||||
)
|
||||
|
||||
# Query
|
||||
response = query_engine.query("How do I create a Django model?")
|
||||
print(response)
|
||||
```
|
||||
|
||||
**Chat Engine (Conversational):**
|
||||
```python
|
||||
from llama_index.core.chat_engine import CondenseQuestionChatEngine
|
||||
|
||||
# Create chat engine with memory
|
||||
chat_engine = index.as_chat_engine(
|
||||
chat_mode="condense_question",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Chat
|
||||
response = chat_engine.chat("Tell me about Django models")
|
||||
print(response)
|
||||
|
||||
# Follow-up (maintains context)
|
||||
response = chat_engine.chat("How do I add fields?")
|
||||
print(response)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Advanced Usage
|
||||
|
||||
### Custom Index Types
|
||||
|
||||
**Tree Index (For Summarization):**
|
||||
```python
|
||||
from llama_index.core import TreeIndex
|
||||
|
||||
tree_index = TreeIndex(nodes)
|
||||
query_engine = tree_index.as_query_engine()
|
||||
|
||||
# Better for summarization queries
|
||||
response = query_engine.query("Summarize Django's ORM capabilities")
|
||||
```
|
||||
|
||||
**Keyword Table Index (For Keyword Search):**
|
||||
```python
|
||||
from llama_index.core import KeywordTableIndex
|
||||
|
||||
keyword_index = KeywordTableIndex(nodes)
|
||||
query_engine = keyword_index.as_query_engine()
|
||||
|
||||
# Better for keyword-based queries
|
||||
response = query_engine.query("foreign key relationships")
|
||||
```
|
||||
|
||||
### Query with Filters
|
||||
|
||||
```python
|
||||
from llama_index.core.vector_stores import MetadataFilters, ExactMatchFilter
|
||||
|
||||
# Filter by category
|
||||
filters = MetadataFilters(
|
||||
filters=[
|
||||
ExactMatchFilter(key="category", value="models")
|
||||
]
|
||||
)
|
||||
|
||||
query_engine = index.as_query_engine(
|
||||
similarity_top_k=3,
|
||||
filters=filters
|
||||
)
|
||||
|
||||
# Only searches in "models" category
|
||||
response = query_engine.query("How do relationships work?")
|
||||
```
|
||||
|
||||
### Custom Retrieval
|
||||
|
||||
```python
|
||||
from llama_index.core.retrievers import VectorIndexRetriever
|
||||
|
||||
# Custom retriever with specific settings
|
||||
retriever = VectorIndexRetriever(
|
||||
index=index,
|
||||
similarity_top_k=5,
|
||||
)
|
||||
|
||||
# Get source nodes
|
||||
nodes = retriever.retrieve("django models")
|
||||
|
||||
for node in nodes:
|
||||
print(f"Score: {node.score:.3f}")
|
||||
print(f"Category: {node.metadata['category']}")
|
||||
print(f"Text: {node.text[:100]}...\n")
|
||||
```
|
||||
|
||||
### Multi-Source Knowledge Base
|
||||
|
||||
```python
|
||||
# Combine multiple documentation sources
|
||||
sources = ["django", "fastapi", "flask"]
|
||||
all_nodes = []
|
||||
|
||||
for source in sources:
|
||||
with open(f"output/{source}-llama-index.json") as f:
|
||||
nodes_data = json.load(f)
|
||||
|
||||
nodes = [
|
||||
TextNode(
|
||||
text=node["text"],
|
||||
metadata=node["metadata"],
|
||||
id_=node["id_"]
|
||||
)
|
||||
for node in nodes_data
|
||||
]
|
||||
all_nodes.extend(nodes)
|
||||
|
||||
# Create unified index
|
||||
index = VectorStoreIndex(all_nodes)
|
||||
print(f"✅ Created index with {len(all_nodes)} nodes from {len(sources)} sources")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 Best Practices
|
||||
|
||||
### 1. Persist Your Indexes
|
||||
```python
|
||||
# Save to avoid re-indexing
|
||||
index.storage_context.persist(persist_dir="./storage")
|
||||
|
||||
# Load when needed
|
||||
storage_context = StorageContext.from_defaults(persist_dir="./storage")
|
||||
index = load_index_from_storage(storage_context)
|
||||
```
|
||||
|
||||
### 2. Use Streaming for Long Responses
|
||||
```python
|
||||
query_engine = index.as_query_engine(
|
||||
streaming=True
|
||||
)
|
||||
|
||||
response = query_engine.query("Explain Django in detail")
|
||||
for text in response.response_gen:
|
||||
print(text, end="", flush=True)
|
||||
```
|
||||
|
||||
### 3. Add Response Synthesis
|
||||
```python
|
||||
from llama_index.core.response_synthesizers import ResponseMode
|
||||
|
||||
query_engine = index.as_query_engine(
|
||||
response_mode=ResponseMode.TREE_SUMMARIZE, # Better for long docs
|
||||
similarity_top_k=5
|
||||
)
|
||||
```
|
||||
|
||||
### 4. Monitor Performance
|
||||
```python
|
||||
import time
|
||||
|
||||
start = time.time()
|
||||
response = query_engine.query("your question")
|
||||
elapsed = time.time() - start
|
||||
|
||||
print(f"Query took {elapsed:.2f}s")
|
||||
print(f"Used {len(response.source_nodes)} source nodes")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔥 Real-World Example
|
||||
|
||||
### Building a FastAPI Documentation Assistant
|
||||
|
||||
**Step 1: Generate Nodes**
|
||||
```bash
|
||||
# Scrape FastAPI docs
|
||||
skill-seekers create --config configs/fastapi.json
|
||||
|
||||
# Convert to LlamaIndex format
|
||||
skill-seekers package output/fastapi --target llama-index
|
||||
```
|
||||
|
||||
**Step 2: Build Index and Query Engine**
|
||||
```python
|
||||
from llama_index.core.schema import TextNode
|
||||
from llama_index.core import VectorStoreIndex
|
||||
from llama_index.core.chat_engine import CondenseQuestionChatEngine
|
||||
import json
|
||||
|
||||
# Load nodes
|
||||
with open("output/fastapi-llama-index.json") as f:
|
||||
nodes_data = json.load(f)
|
||||
|
||||
nodes = [
|
||||
TextNode(
|
||||
text=node["text"],
|
||||
metadata=node["metadata"],
|
||||
id_=node["id_"]
|
||||
)
|
||||
for node in nodes_data
|
||||
]
|
||||
|
||||
# Create index
|
||||
index = VectorStoreIndex(nodes)
|
||||
index.storage_context.persist(persist_dir="./fastapi_index")
|
||||
|
||||
print(f"✅ FastAPI index created with {len(nodes)} nodes")
|
||||
|
||||
# Create chat engine
|
||||
chat_engine = index.as_chat_engine(
|
||||
chat_mode="condense_question",
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# Interactive loop
|
||||
print("\n🤖 FastAPI Documentation Assistant")
|
||||
print("Ask me anything about FastAPI (type 'quit' to exit)\n")
|
||||
|
||||
while True:
|
||||
user_input = input("You: ").strip()
|
||||
|
||||
if user_input.lower() in ['quit', 'exit', 'q']:
|
||||
print("👋 Goodbye!")
|
||||
break
|
||||
|
||||
if not user_input:
|
||||
continue
|
||||
|
||||
response = chat_engine.chat(user_input)
|
||||
print(f"\nAssistant: {response}\n")
|
||||
|
||||
# Show sources
|
||||
print("Sources:")
|
||||
for node in response.source_nodes:
|
||||
cat = node.metadata.get('category', 'unknown')
|
||||
file = node.metadata.get('file', 'unknown')
|
||||
print(f" - {cat} ({file})")
|
||||
print()
|
||||
```
|
||||
|
||||
**Result:**
|
||||
- Complete FastAPI documentation indexed
|
||||
- Conversational interface with memory
|
||||
- Source attribution for transparency
|
||||
- Instant responses (<1 second)
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Issue: Index Too Large
|
||||
**Solution:** Use hybrid indexing or split by category
|
||||
```python
|
||||
# Create separate indexes per category
|
||||
categories = set(node["metadata"]["category"] for node in nodes_data)
|
||||
|
||||
indexes = {}
|
||||
for category in categories:
|
||||
cat_nodes = [
|
||||
TextNode(**node)
|
||||
for node in nodes_data
|
||||
if node["metadata"]["category"] == category
|
||||
]
|
||||
indexes[category] = VectorStoreIndex(cat_nodes)
|
||||
```
|
||||
|
||||
### Issue: Slow Queries
|
||||
**Solution:** Reduce similarity_top_k or use caching
|
||||
```python
|
||||
query_engine = index.as_query_engine(
|
||||
similarity_top_k=2, # Reduce from 3 to 2
|
||||
)
|
||||
```
|
||||
|
||||
### Issue: Missing Dependencies
|
||||
**Solution:** Install LlamaIndex components
|
||||
```bash
|
||||
pip install llama-index llama-index-core
|
||||
pip install llama-index-llms-openai # For OpenAI LLM
|
||||
pip install llama-index-embeddings-openai # For OpenAI embeddings
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Before vs After Comparison
|
||||
|
||||
| Aspect | Manual Process | With Skill Seekers |
|
||||
|--------|---------------|-------------------|
|
||||
| **Time to Setup** | 3-5 hours | 5 minutes |
|
||||
| **Node Structure** | Manual, inconsistent | Automatic, structured |
|
||||
| **Metadata** | Often missing | Rich, comprehensive |
|
||||
| **IDs** | Manual generation | Auto-generated (stable) |
|
||||
| **Maintenance** | Re-process everything | Re-run one command |
|
||||
| **Updates** | Hours of work | 5 minutes |
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Community & Support
|
||||
|
||||
- **Questions:** [GitHub Discussions](https://github.com/yusufkaraaslan/Skill_Seekers/discussions)
|
||||
- **Issues:** [GitHub Issues](https://github.com/yusufkaraaslan/Skill_Seekers/issues)
|
||||
- **Documentation:** [https://skillseekersweb.com/](https://skillseekersweb.com/)
|
||||
- **Twitter:** [@_yUSyUS_](https://x.com/_yUSyUS_)
|
||||
|
||||
---
|
||||
|
||||
## 📚 Related Guides
|
||||
|
||||
- [LangChain Integration](./LANGCHAIN.md)
|
||||
- [Pinecone Integration](./PINECONE.md)
|
||||
- [RAG Pipelines Overview](./RAG_PIPELINES.md)
|
||||
|
||||
---
|
||||
|
||||
## 📖 Next Steps
|
||||
|
||||
1. **Try the Quick Start** above
|
||||
2. **Explore different index types** (Tree, Keyword, List)
|
||||
3. **Build your query engine** with production-ready docs
|
||||
4. **Share your experience** - we'd love feedback!
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** February 5, 2026
|
||||
**Tested With:** LlamaIndex v0.10.0+, OpenAI GPT-4
|
||||
**Skill Seekers Version:** v3.6.0
|
||||
@@ -0,0 +1,391 @@
|
||||
# MiniMax AI Integration Guide
|
||||
|
||||
Complete guide for using Skill Seekers with MiniMax AI platform.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
**MiniMax AI** is a Chinese AI company offering OpenAI-compatible APIs with their flagship M3 model (M2.7 is still selectable). Skill Seekers packages documentation for use with MiniMax's platform.
|
||||
|
||||
### Key Features
|
||||
|
||||
- **OpenAI-Compatible API**: Uses standard OpenAI client library
|
||||
- **MiniMax-M3 Model**: Powerful default LLM for enhancement and chat (M2.7 also supported via `--model`)
|
||||
- **Simple ZIP Format**: Easy packaging with system instructions
|
||||
- **Knowledge Files**: Reference documentation included in package
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### 1. Get MiniMax API Key
|
||||
|
||||
1. Visit [MiniMax Platform](https://platform.minimaxi.com/)
|
||||
2. Create an account and verify
|
||||
3. Navigate to API Keys section
|
||||
4. Generate a new API key
|
||||
5. Copy the key (starts with `eyJ` - JWT format)
|
||||
|
||||
### 2. Install Dependencies
|
||||
|
||||
```bash
|
||||
# Install MiniMax support (includes openai library)
|
||||
pip install skill-seekers[minimax]
|
||||
|
||||
# Or install all LLM platforms
|
||||
pip install skill-seekers[all-llms]
|
||||
```
|
||||
|
||||
### 3. Configure Environment
|
||||
|
||||
```bash
|
||||
export MINIMAX_API_KEY=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
```
|
||||
|
||||
Add to your `~/.bashrc`, `~/.zshrc`, or `.env` file for persistence.
|
||||
|
||||
---
|
||||
|
||||
## Complete Workflow
|
||||
|
||||
### Step 1: Scrape Documentation
|
||||
|
||||
```bash
|
||||
# Scrape documentation website
|
||||
skill-seekers create --config configs/react.json
|
||||
|
||||
# Or use quick preset
|
||||
skill-seekers create https://docs.python.org/3/ --preset quick
|
||||
```
|
||||
|
||||
### Step 2: Enhance with MiniMax-M3
|
||||
|
||||
```bash
|
||||
# Enhance SKILL.md using MiniMax AI
|
||||
skill-seekers enhance output/react/ --target minimax
|
||||
|
||||
# With custom model (e.g. pinning the previous-generation M2.7)
|
||||
skill-seekers enhance output/react/ --target minimax --model MiniMax-M2.7
|
||||
```
|
||||
|
||||
This step:
|
||||
- Reads reference documentation
|
||||
- Generates enhanced system instructions
|
||||
- Creates backup of original SKILL.md
|
||||
- Uses MiniMax-M3 for AI enhancement by default
|
||||
|
||||
### Step 3: Package for MiniMax
|
||||
|
||||
```bash
|
||||
# Package as MiniMax-compatible ZIP
|
||||
skill-seekers package output/react/ --target minimax
|
||||
|
||||
# Pin a specific model in the package metadata (default: MiniMax-M3)
|
||||
skill-seekers package output/react/ --target minimax --model MiniMax-M2.7
|
||||
```
|
||||
|
||||
**Output structure:**
|
||||
```
|
||||
react-minimax.zip
|
||||
├── system_instructions.txt # Main instructions (from SKILL.md)
|
||||
├── knowledge_files/ # Reference documentation
|
||||
│ ├── guide.md
|
||||
│ ├── api-reference.md
|
||||
│ └── examples.md
|
||||
└── minimax_metadata.json # Skill metadata
|
||||
```
|
||||
|
||||
### Step 4: Validate Package
|
||||
|
||||
```bash
|
||||
# Validate package with MiniMax API
|
||||
skill-seekers upload react-minimax.zip --target minimax
|
||||
```
|
||||
|
||||
This validates:
|
||||
- Package structure
|
||||
- API connectivity
|
||||
- System instructions format
|
||||
|
||||
**Note:** MiniMax doesn't have persistent skill storage like Claude. The upload validates your package but you'll use the ZIP file directly with MiniMax's API.
|
||||
|
||||
---
|
||||
|
||||
## Using Your Skill
|
||||
|
||||
### Direct API Usage
|
||||
|
||||
```python
|
||||
from openai import OpenAI
|
||||
import zipfile
|
||||
import json
|
||||
|
||||
# Extract package
|
||||
with zipfile.ZipFile('react-minimax.zip', 'r') as zf:
|
||||
with zf.open('system_instructions.txt') as f:
|
||||
system_instructions = f.read().decode('utf-8')
|
||||
|
||||
# Load metadata
|
||||
with zf.open('minimax_metadata.json') as f:
|
||||
metadata = json.load(f)
|
||||
|
||||
# Initialize MiniMax client (OpenAI-compatible)
|
||||
client = OpenAI(
|
||||
api_key="eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||||
base_url="https://api.minimax.io/v1"
|
||||
)
|
||||
|
||||
# Use with chat completions
|
||||
response = client.chat.completions.create(
|
||||
model="MiniMax-M3",
|
||||
messages=[
|
||||
{"role": "system", "content": system_instructions},
|
||||
{"role": "user", "content": "How do I create a React component?"}
|
||||
],
|
||||
temperature=0.3,
|
||||
max_tokens=2000
|
||||
)
|
||||
|
||||
print(response.choices[0].message.content)
|
||||
```
|
||||
|
||||
### With Knowledge Files
|
||||
|
||||
```python
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
# Extract knowledge files
|
||||
with zipfile.ZipFile('react-minimax.zip', 'r') as zf:
|
||||
zf.extractall('extracted_skill')
|
||||
|
||||
# Read all knowledge files
|
||||
knowledge_dir = Path('extracted_skill/knowledge_files')
|
||||
knowledge_files = []
|
||||
for md_file in knowledge_dir.glob('*.md'):
|
||||
knowledge_files.append({
|
||||
'name': md_file.name,
|
||||
'content': md_file.read_text()
|
||||
})
|
||||
|
||||
# Include in context (truncate if too long)
|
||||
context = "\n\n".join([f"## {kf['name']}\n{kf['content'][:5000]}"
|
||||
for kf in knowledge_files[:5]])
|
||||
|
||||
response = client.chat.completions.create(
|
||||
model="MiniMax-M3",
|
||||
messages=[
|
||||
{"role": "system", "content": system_instructions},
|
||||
{"role": "user", "content": f"Context: {context}\n\nQuestion: What are React hooks?"}
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Reference
|
||||
|
||||
### SkillAdaptor Methods
|
||||
|
||||
```python
|
||||
from skill_seekers.cli.adaptors import get_adaptor
|
||||
|
||||
# Get MiniMax adaptor
|
||||
adaptor = get_adaptor('minimax')
|
||||
|
||||
# Format SKILL.md as system instructions
|
||||
instructions = adaptor.format_skill_md(skill_dir, metadata)
|
||||
|
||||
# Package skill
|
||||
package_path = adaptor.package(skill_dir, output_path)
|
||||
|
||||
# Validate package with MiniMax API
|
||||
result = adaptor.upload(package_path, api_key)
|
||||
print(result['message']) # Validation result
|
||||
|
||||
# Enhance SKILL.md
|
||||
success = adaptor.enhance(skill_dir, api_key)
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Description | Required |
|
||||
|----------|-------------|----------|
|
||||
| `MINIMAX_API_KEY` | Your MiniMax API key (JWT format) | Yes |
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Invalid API Key Format
|
||||
|
||||
**Error:** `Invalid API key format`
|
||||
|
||||
**Solution:** MiniMax API keys use JWT format starting with `eyJ`. Check:
|
||||
```bash
|
||||
# Should start with 'eyJ'
|
||||
echo $MINIMAX_API_KEY | head -c 10
|
||||
# Output: eyJhbGciOi
|
||||
```
|
||||
|
||||
### OpenAI Library Not Installed
|
||||
|
||||
**Error:** `ModuleNotFoundError: No module named 'openai'`
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
pip install skill-seekers[minimax]
|
||||
# or
|
||||
pip install openai>=1.0.0
|
||||
```
|
||||
|
||||
### Upload Timeout
|
||||
|
||||
**Error:** `Upload timed out`
|
||||
|
||||
**Solution:**
|
||||
- Check internet connection
|
||||
- Try again (temporary network issue)
|
||||
- Verify API key is correct
|
||||
- Check MiniMax platform status
|
||||
|
||||
### Connection Error
|
||||
|
||||
**Error:** `Connection error`
|
||||
|
||||
**Solution:**
|
||||
- Verify internet connectivity
|
||||
- Check if MiniMax API endpoint is accessible:
|
||||
```bash
|
||||
curl https://api.minimax.io/v1/models
|
||||
```
|
||||
- Try with VPN if in restricted region
|
||||
|
||||
### Package Validation Failed
|
||||
|
||||
**Error:** `Invalid package: system_instructions.txt not found`
|
||||
|
||||
**Solution:**
|
||||
- Ensure SKILL.md exists before packaging
|
||||
- Check package contents:
|
||||
```bash
|
||||
unzip -l react-minimax.zip
|
||||
```
|
||||
- Re-package the skill
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Keep References Organized
|
||||
|
||||
Structure your documentation:
|
||||
```
|
||||
output/react/
|
||||
├── SKILL.md # Main instructions
|
||||
├── references/
|
||||
│ ├── 01-getting-started.md
|
||||
│ ├── 02-components.md
|
||||
│ ├── 03-hooks.md
|
||||
│ └── 04-api-reference.md
|
||||
└── assets/
|
||||
└── diagrams/
|
||||
```
|
||||
|
||||
### 2. Use Enhancement
|
||||
|
||||
Always enhance before packaging:
|
||||
```bash
|
||||
# Enhancement improves system instructions quality
|
||||
skill-seekers enhance output/react/ --target minimax
|
||||
```
|
||||
|
||||
### 3. Test Before Deployment
|
||||
|
||||
```bash
|
||||
# Validate package
|
||||
skill-seekers upload react-minimax.zip --target minimax
|
||||
|
||||
# If successful, package is ready to use
|
||||
```
|
||||
|
||||
### 4. Version Your Skills
|
||||
|
||||
```bash
|
||||
# Include version in output name
|
||||
skill-seekers package output/react/ --target minimax
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Comparison with Other Platforms
|
||||
|
||||
| Feature | MiniMax | Claude | Gemini | OpenAI |
|
||||
|---------|---------|--------|--------|--------|
|
||||
| **Format** | ZIP | ZIP | tar.gz | ZIP |
|
||||
| **Upload** | Validation | Full API | Full API | Full API |
|
||||
| **Enhancement** | MiniMax-M3 | Claude Sonnet | Gemini 2.0 | GPT-4o |
|
||||
| **API Type** | OpenAI-compatible | Anthropic | Google | OpenAI |
|
||||
| **Key Format** | JWT (eyJ...) | sk-ant... | AIza... | sk-... |
|
||||
| **Knowledge Files** | Included in ZIP | Included | Included | Vector Store |
|
||||
|
||||
---
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Custom Enhancement Prompt
|
||||
|
||||
Programmatically customize enhancement:
|
||||
|
||||
```python
|
||||
from skill_seekers.cli.adaptors import get_adaptor
|
||||
from pathlib import Path
|
||||
|
||||
adaptor = get_adaptor('minimax')
|
||||
skill_dir = Path('output/react')
|
||||
|
||||
# Build custom prompt
|
||||
references = adaptor._read_reference_files(skill_dir / 'references')
|
||||
prompt = adaptor._build_enhancement_prompt(
|
||||
skill_name='React',
|
||||
references=references,
|
||||
current_skill_md=(skill_dir / 'SKILL.md').read_text()
|
||||
)
|
||||
|
||||
# Customize prompt
|
||||
prompt += "\n\nADDITIONAL FOCUS: Emphasize React 18 concurrent features."
|
||||
|
||||
# Use with your own API call
|
||||
```
|
||||
|
||||
### Batch Processing
|
||||
|
||||
```bash
|
||||
# Process multiple frameworks
|
||||
for framework in react vue angular; do
|
||||
skill-seekers create --config configs/${framework}.json
|
||||
skill-seekers enhance output/${framework}/ --target minimax
|
||||
skill-seekers package output/${framework}/ --target minimax --output ${framework}-minimax.zip
|
||||
done
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Resources
|
||||
|
||||
- [MiniMax Platform](https://platform.minimaxi.com/)
|
||||
- [MiniMax API Documentation](https://platform.minimaxi.com/document)
|
||||
- [OpenAI Python Client](https://github.com/openai/openai-python)
|
||||
- [Multi-LLM Support Guide](MULTI_LLM_SUPPORT.md)
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Get your [MiniMax API key](https://platform.minimaxi.com/)
|
||||
2. Install dependencies: `pip install skill-seekers[minimax]`
|
||||
3. Try the [Quick Start example](#complete-workflow)
|
||||
4. Explore [advanced usage](#advanced-usage) patterns
|
||||
|
||||
For help, see [Troubleshooting](#troubleshooting) or open an issue on GitHub.
|
||||
@@ -0,0 +1,468 @@
|
||||
# Multi-LLM Platform Support Guide
|
||||
|
||||
Skill Seekers supports multiple LLM platforms through a clean adaptor system. The core scraping and content organization remains universal, while packaging and upload are platform-specific.
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
| Platform | Status | Format | Upload | Enhancement | API Key Required |
|
||||
|----------|--------|--------|--------|-------------|------------------|
|
||||
| **Claude AI** | ✅ Full Support | ZIP + YAML | ✅ Automatic | ✅ Yes | ANTHROPIC_API_KEY |
|
||||
| **Google Gemini** | ✅ Full Support | tar.gz | ✅ Automatic | ✅ Yes | GOOGLE_API_KEY |
|
||||
| **OpenAI ChatGPT** | ✅ Full Support | ZIP + Vector Store | ✅ Automatic | ✅ Yes | OPENAI_API_KEY |
|
||||
| **MiniMax AI** | ✅ Full Support | ZIP | ✅ Validation | ✅ Yes | MINIMAX_API_KEY |
|
||||
| **Atlas Cloud** | ✅ Full Support | ZIP | ✅ Validation | ✅ Yes | ATLAS_API_KEY |
|
||||
| **Generic Markdown** | ✅ Export Only | ZIP | ❌ Manual | ❌ No | None |
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Claude AI (Default)
|
||||
|
||||
No changes needed! All existing workflows continue to work:
|
||||
|
||||
```bash
|
||||
# Scrape documentation
|
||||
skill-seekers create --config configs/react.json
|
||||
|
||||
# Package for Claude (default)
|
||||
skill-seekers package output/react/
|
||||
|
||||
# Upload to Claude
|
||||
skill-seekers upload react.zip
|
||||
```
|
||||
|
||||
### Google Gemini
|
||||
|
||||
```bash
|
||||
# Install Gemini support
|
||||
pip install skill-seekers[gemini]
|
||||
|
||||
# Set API key
|
||||
export GOOGLE_API_KEY=AIzaSy...
|
||||
|
||||
# Scrape documentation (same as always)
|
||||
skill-seekers create --config configs/react.json
|
||||
|
||||
# Package for Gemini
|
||||
skill-seekers package output/react/ --target gemini
|
||||
|
||||
# Upload to Gemini
|
||||
skill-seekers upload react-gemini.tar.gz --target gemini
|
||||
|
||||
# Optional: Enhance with Gemini
|
||||
skill-seekers enhance output/react/ --target gemini
|
||||
```
|
||||
|
||||
**Output:** `react-gemini.tar.gz` ready for Google AI Studio
|
||||
|
||||
### OpenAI ChatGPT
|
||||
|
||||
```bash
|
||||
# Install OpenAI support
|
||||
pip install skill-seekers[openai]
|
||||
|
||||
# Set API key
|
||||
export OPENAI_API_KEY=sk-proj-...
|
||||
|
||||
# Scrape documentation (same as always)
|
||||
skill-seekers create --config configs/react.json
|
||||
|
||||
# Package for OpenAI
|
||||
skill-seekers package output/react/ --target openai
|
||||
|
||||
# Upload to OpenAI (creates Assistant + Vector Store)
|
||||
skill-seekers upload react-openai.zip --target openai
|
||||
|
||||
# Optional: Enhance with GPT-4o
|
||||
skill-seekers enhance output/react/ --target openai
|
||||
```
|
||||
|
||||
**Output:** OpenAI Assistant created with file search enabled
|
||||
|
||||
### Generic Markdown (Universal Export)
|
||||
|
||||
```bash
|
||||
# Package as generic markdown (no dependencies)
|
||||
skill-seekers package output/react/ --target markdown
|
||||
|
||||
# Output: react-markdown.zip with:
|
||||
# - README.md
|
||||
# - references/*.md
|
||||
# - DOCUMENTATION.md (combined)
|
||||
```
|
||||
|
||||
**Use case:** Export for any LLM, documentation hosting, or manual distribution
|
||||
|
||||
## Installation Options
|
||||
|
||||
### Install Core Package Only
|
||||
|
||||
```bash
|
||||
# Default installation (Claude support only)
|
||||
pip install skill-seekers
|
||||
```
|
||||
|
||||
### Install with Specific Platform Support
|
||||
|
||||
```bash
|
||||
# Google Gemini support
|
||||
pip install skill-seekers[gemini]
|
||||
|
||||
# OpenAI ChatGPT support
|
||||
pip install skill-seekers[openai]
|
||||
|
||||
# MiniMax AI support
|
||||
pip install skill-seekers[minimax]
|
||||
|
||||
# All LLM platforms
|
||||
pip install skill-seekers[all-llms]
|
||||
|
||||
# Development dependencies (includes testing)
|
||||
pip install skill-seekers[dev]
|
||||
```
|
||||
|
||||
### Install from Source
|
||||
|
||||
```bash
|
||||
git clone https://github.com/yusufkaraaslan/Skill_Seekers.git
|
||||
cd Skill_Seekers
|
||||
|
||||
# Editable install with all platforms
|
||||
pip install -e .[all-llms]
|
||||
```
|
||||
|
||||
## Platform Comparison
|
||||
|
||||
### Format Differences
|
||||
|
||||
**Claude AI:**
|
||||
- Format: ZIP archive
|
||||
- SKILL.md: YAML frontmatter + markdown
|
||||
- Structure: `SKILL.md`, `references/`, `scripts/`, `assets/`
|
||||
- API: Anthropic Skills API
|
||||
- Enhancement: Claude Sonnet 4
|
||||
|
||||
**Google Gemini:**
|
||||
- Format: tar.gz archive
|
||||
- SKILL.md → `system_instructions.md` (plain markdown, no frontmatter)
|
||||
- Structure: `system_instructions.md`, `references/`, `gemini_metadata.json`
|
||||
- API: Google Files API + grounding
|
||||
- Enhancement: Gemini 2.0 Flash
|
||||
|
||||
**OpenAI ChatGPT:**
|
||||
- Format: ZIP archive
|
||||
- SKILL.md → `assistant_instructions.txt` (plain text)
|
||||
- Structure: `assistant_instructions.txt`, `vector_store_files/`, `openai_metadata.json`
|
||||
- API: Assistants API + Vector Store
|
||||
- Enhancement: GPT-4o
|
||||
|
||||
**MiniMax AI:**
|
||||
- Format: ZIP archive
|
||||
- SKILL.md -> `system_instructions.txt` (plain text, no frontmatter)
|
||||
- Structure: `system_instructions.txt`, `knowledge_files/`, `minimax_metadata.json`
|
||||
- API: OpenAI-compatible chat completions
|
||||
- Enhancement: MiniMax-M3 (M2.7 still selectable)
|
||||
|
||||
**Generic Markdown:**
|
||||
- Format: ZIP archive
|
||||
- Structure: `README.md`, `references/`, `DOCUMENTATION.md` (combined)
|
||||
- No API integration
|
||||
- No enhancement support
|
||||
- Universal compatibility
|
||||
|
||||
### API Key Configuration
|
||||
|
||||
**Claude AI:**
|
||||
```bash
|
||||
export ANTHROPIC_API_KEY=sk-ant-...
|
||||
```
|
||||
|
||||
**Google Gemini:**
|
||||
```bash
|
||||
export GOOGLE_API_KEY=AIzaSy...
|
||||
```
|
||||
|
||||
**OpenAI ChatGPT:**
|
||||
```bash
|
||||
export OPENAI_API_KEY=sk-proj-...
|
||||
```
|
||||
|
||||
**MiniMax AI:**
|
||||
```bash
|
||||
export MINIMAX_API_KEY=your-key
|
||||
```
|
||||
|
||||
## Complete Workflow Examples
|
||||
|
||||
### Workflow 1: Claude AI (Default)
|
||||
|
||||
```bash
|
||||
# 1. Scrape
|
||||
skill-seekers create --config configs/react.json
|
||||
|
||||
# 2. Enhance (optional but recommended)
|
||||
skill-seekers enhance output/react/
|
||||
|
||||
# 3. Package
|
||||
skill-seekers package output/react/
|
||||
|
||||
# 4. Upload
|
||||
skill-seekers upload react.zip
|
||||
|
||||
# Access at: https://claude.ai/skills
|
||||
```
|
||||
|
||||
### Workflow 2: Google Gemini
|
||||
|
||||
```bash
|
||||
# Setup (one-time)
|
||||
pip install skill-seekers[gemini]
|
||||
export GOOGLE_API_KEY=AIzaSy...
|
||||
|
||||
# 1. Scrape (universal)
|
||||
skill-seekers create --config configs/react.json
|
||||
|
||||
# 2. Enhance for Gemini
|
||||
skill-seekers enhance output/react/ --target gemini
|
||||
|
||||
# 3. Package for Gemini
|
||||
skill-seekers package output/react/ --target gemini
|
||||
|
||||
# 4. Upload to Gemini
|
||||
skill-seekers upload react-gemini.tar.gz --target gemini
|
||||
|
||||
# Access at: https://aistudio.google.com/files/
|
||||
```
|
||||
|
||||
### Workflow 3: OpenAI ChatGPT
|
||||
|
||||
```bash
|
||||
# Setup (one-time)
|
||||
pip install skill-seekers[openai]
|
||||
export OPENAI_API_KEY=sk-proj-...
|
||||
|
||||
# 1. Scrape (universal)
|
||||
skill-seekers create --config configs/react.json
|
||||
|
||||
# 2. Enhance with GPT-4o
|
||||
skill-seekers enhance output/react/ --target openai
|
||||
|
||||
# 3. Package for OpenAI
|
||||
skill-seekers package output/react/ --target openai
|
||||
|
||||
# 4. Upload (creates Assistant + Vector Store)
|
||||
skill-seekers upload react-openai.zip --target openai
|
||||
|
||||
# Access at: https://platform.openai.com/assistants/
|
||||
```
|
||||
|
||||
### Workflow 4: MiniMax AI
|
||||
|
||||
```bash
|
||||
# Setup (one-time)
|
||||
pip install skill-seekers[minimax]
|
||||
export MINIMAX_API_KEY=your-key
|
||||
|
||||
# 1. Scrape (universal)
|
||||
skill-seekers create --config configs/react.json
|
||||
|
||||
# 2. Enhance with MiniMax-M3
|
||||
skill-seekers enhance output/react/ --target minimax
|
||||
|
||||
# 3. Package for MiniMax
|
||||
skill-seekers package output/react/ --target minimax
|
||||
|
||||
# 4. Upload to MiniMax (validates with API)
|
||||
skill-seekers upload react-minimax.zip --target minimax
|
||||
|
||||
# Access at: https://platform.minimaxi.com/
|
||||
```
|
||||
|
||||
### Workflow 5: Export to All Platforms
|
||||
|
||||
```bash
|
||||
# Install all platforms
|
||||
pip install skill-seekers[all-llms]
|
||||
|
||||
# Scrape once
|
||||
skill-seekers create --config configs/react.json
|
||||
|
||||
# Package for all platforms
|
||||
skill-seekers package output/react/ --target claude
|
||||
skill-seekers package output/react/ --target gemini
|
||||
skill-seekers package output/react/ --target openai
|
||||
skill-seekers package output/react/ --target minimax
|
||||
skill-seekers package output/react/ --target markdown
|
||||
|
||||
# Result:
|
||||
# - react.zip (Claude)
|
||||
# - react-gemini.tar.gz (Gemini)
|
||||
# - react-openai.zip (OpenAI)
|
||||
# - react-minimax.zip (MiniMax)
|
||||
# - react-markdown.zip (Universal)
|
||||
```
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Custom Enhancement Models
|
||||
|
||||
Each platform uses its default enhancement model, but you can customize:
|
||||
|
||||
```bash
|
||||
# Use specific model for enhancement (if supported)
|
||||
skill-seekers enhance output/react/ --target gemini --model gemini-2.0-flash-exp
|
||||
skill-seekers enhance output/react/ --target openai --model gpt-4o
|
||||
```
|
||||
|
||||
### Programmatic Usage
|
||||
|
||||
```python
|
||||
from skill_seekers.cli.adaptors import get_adaptor
|
||||
|
||||
# Get platform-specific adaptor
|
||||
gemini = get_adaptor('gemini')
|
||||
openai = get_adaptor('openai')
|
||||
claude = get_adaptor('claude')
|
||||
|
||||
# Package for specific platform
|
||||
gemini_package = gemini.package(skill_dir, output_path)
|
||||
openai_package = openai.package(skill_dir, output_path)
|
||||
|
||||
# Upload with API key
|
||||
result = gemini.upload(gemini_package, api_key)
|
||||
print(f"Uploaded to: {result['url']}")
|
||||
```
|
||||
|
||||
### Platform Detection
|
||||
|
||||
Check which platforms are available:
|
||||
|
||||
```python
|
||||
from skill_seekers.cli.adaptors import list_platforms, is_platform_available
|
||||
|
||||
# List all registered platforms
|
||||
platforms = list_platforms()
|
||||
print(platforms) # ['claude', 'gemini', 'minimax', 'openai', 'markdown']
|
||||
|
||||
# Check if platform is available
|
||||
if is_platform_available('gemini'):
|
||||
print("Gemini adaptor is available")
|
||||
```
|
||||
|
||||
## Backward Compatibility
|
||||
|
||||
**100% backward compatible** with existing workflows:
|
||||
|
||||
- All existing Claude commands work unchanged
|
||||
- Default behavior remains Claude-focused
|
||||
- Optional `--target` flag adds multi-platform support
|
||||
- No breaking changes to existing configs or workflows
|
||||
|
||||
## Platform-Specific Guides
|
||||
|
||||
For detailed platform-specific instructions, see:
|
||||
|
||||
- [Claude AI Integration](CLAUDE_INTEGRATION.md) (default)
|
||||
- [Google Gemini Integration](GEMINI_INTEGRATION.md)
|
||||
- [OpenAI ChatGPT Integration](OPENAI_INTEGRATION.md)
|
||||
- [MiniMax AI Integration](MINIMAX_INTEGRATION.md)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Missing Dependencies
|
||||
|
||||
**Error:** `ModuleNotFoundError: No module named 'google.generativeai'`
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
pip install skill-seekers[gemini]
|
||||
```
|
||||
|
||||
**Error:** `ModuleNotFoundError: No module named 'openai'`
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
pip install skill-seekers[openai]
|
||||
# or for MiniMax (also uses openai library)
|
||||
pip install skill-seekers[minimax]
|
||||
```
|
||||
|
||||
### API Key Issues
|
||||
|
||||
**Error:** `Invalid API key format`
|
||||
|
||||
**Solution:** Check your API key format:
|
||||
- Claude: `sk-ant-...`
|
||||
- Gemini: `AIza...`
|
||||
- OpenAI: `sk-proj-...` or `sk-...`
|
||||
- MiniMax: Any valid API key string
|
||||
|
||||
### Package Format Errors
|
||||
|
||||
**Error:** `Not a tar.gz file: react.zip`
|
||||
|
||||
**Solution:** Use correct --target flag:
|
||||
```bash
|
||||
# Gemini requires tar.gz
|
||||
skill-seekers package output/react/ --target gemini
|
||||
|
||||
# OpenAI and Claude use ZIP
|
||||
skill-seekers package output/react/ --target openai
|
||||
```
|
||||
|
||||
## FAQ
|
||||
|
||||
**Q: Can I use the same scraped data for all platforms?**
|
||||
|
||||
A: Yes! The scraping phase is universal. Only packaging and upload are platform-specific.
|
||||
|
||||
**Q: Do I need separate API keys for each platform?**
|
||||
|
||||
A: Yes, each platform requires its own API key. Set them as environment variables.
|
||||
|
||||
**Q: Can I enhance with different models?**
|
||||
|
||||
A: Yes. Each platform has a default enhancement model:
|
||||
- Claude: Claude Sonnet 4
|
||||
- Gemini: Gemini 2.0 Flash
|
||||
- OpenAI: GPT-4o
|
||||
- MiniMax: MiniMax-M3
|
||||
- Kimi / DeepSeek / Qwen / OpenRouter / Together / Fireworks: each platform's own default
|
||||
|
||||
Override the default for any platform with `--model`, e.g. to pin the
|
||||
previous-generation MiniMax model:
|
||||
|
||||
```bash
|
||||
skill-seekers enhance output/react/ --target minimax --model MiniMax-M2.7
|
||||
```
|
||||
|
||||
**Q: Which platforms can enhance SKILL.md?**
|
||||
|
||||
A: Any platform whose adaptor supports AI enhancement: `claude`, `gemini`,
|
||||
`openai`, `minimax`, `kimi`, `deepseek`, `qwen`, `openrouter`, `together`,
|
||||
`fireworks`. Pass one with `--target`; the valid list is also shown in
|
||||
`skill-seekers enhance --help`.
|
||||
|
||||
**Q: What if I don't want to upload automatically?**
|
||||
|
||||
A: Use the `package` command without `upload`. You'll get the packaged file to upload manually.
|
||||
|
||||
**Q: Is the markdown export compatible with all LLMs?**
|
||||
|
||||
A: Yes! The generic markdown export creates universal documentation that works with any LLM or documentation system.
|
||||
|
||||
**Q: Can I contribute a new platform adaptor?**
|
||||
|
||||
A: Absolutely! See the [Contributing Guide](../CONTRIBUTING.md) for how to add new platform adaptors.
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Choose your target platform
|
||||
2. Install optional dependencies if needed
|
||||
3. Set up API keys
|
||||
4. Follow the platform-specific workflow
|
||||
5. Upload and test your skill
|
||||
|
||||
For more help, see:
|
||||
- [Quick Start Guide](../docs/archive/legacy/QUICKSTART.md)
|
||||
- [Troubleshooting Guide](../TROUBLESHOOTING.md)
|
||||
- [Platform-Specific Guides](.)
|
||||
@@ -0,0 +1,515 @@
|
||||
# OpenAI ChatGPT Integration Guide
|
||||
|
||||
Complete guide for creating and deploying skills to OpenAI ChatGPT using Skill Seekers.
|
||||
|
||||
## Overview
|
||||
|
||||
Skill Seekers packages documentation into OpenAI-compatible formats optimized for:
|
||||
- **Assistants API** for custom AI assistants
|
||||
- **Vector Store + File Search** for accurate retrieval
|
||||
- **GPT-4o** for enhancement and responses
|
||||
|
||||
## Setup
|
||||
|
||||
### 1. Install OpenAI Support
|
||||
|
||||
```bash
|
||||
# Install with OpenAI dependencies
|
||||
pip install skill-seekers[openai]
|
||||
|
||||
# Verify installation
|
||||
pip list | grep openai
|
||||
```
|
||||
|
||||
### 2. Get OpenAI API Key
|
||||
|
||||
1. Visit [OpenAI Platform](https://platform.openai.com/)
|
||||
2. Navigate to **API keys** section
|
||||
3. Click "Create new secret key"
|
||||
4. Copy the key (starts with `sk-proj-` or `sk-`)
|
||||
|
||||
### 3. Configure API Key
|
||||
|
||||
```bash
|
||||
# Set as environment variable (recommended)
|
||||
export OPENAI_API_KEY=sk-proj-...
|
||||
|
||||
# Or pass directly to commands
|
||||
skill-seekers upload --target openai --api-key sk-proj-...
|
||||
```
|
||||
|
||||
## Complete Workflow
|
||||
|
||||
### Step 1: Scrape Documentation
|
||||
|
||||
```bash
|
||||
# Use any config (scraping is platform-agnostic)
|
||||
skill-seekers create --config configs/react.json
|
||||
|
||||
# Or use a unified config for multi-source
|
||||
skill-seekers create --config configs/react_unified.json
|
||||
```
|
||||
|
||||
**Result:** `output/react/` skill directory with references
|
||||
|
||||
### Step 2: Enhance with GPT-4o (Optional but Recommended)
|
||||
|
||||
```bash
|
||||
# Enhance SKILL.md using GPT-4o
|
||||
skill-seekers enhance output/react/ --target openai
|
||||
|
||||
# With API key specified
|
||||
skill-seekers enhance output/react/ --target openai --api-key sk-proj-...
|
||||
```
|
||||
|
||||
**What it does:**
|
||||
- Analyzes all reference documentation
|
||||
- Extracts 5-10 best code examples
|
||||
- Creates comprehensive assistant instructions
|
||||
- Adds response guidelines and search strategy
|
||||
- Formats as plain text (no YAML frontmatter)
|
||||
|
||||
**Time:** 20-40 seconds
|
||||
**Cost:** ~$0.15-0.30 (using GPT-4o)
|
||||
**Quality boost:** 3/10 → 9/10
|
||||
|
||||
### Step 3: Package for OpenAI
|
||||
|
||||
```bash
|
||||
# Create ZIP package for OpenAI Assistants
|
||||
skill-seekers package output/react/ --target openai
|
||||
|
||||
# Result: react-openai.zip
|
||||
```
|
||||
|
||||
**Package structure:**
|
||||
```
|
||||
react-openai.zip/
|
||||
├── assistant_instructions.txt # Main instructions for Assistant
|
||||
├── vector_store_files/ # Files for Vector Store + file_search
|
||||
│ ├── getting_started.md
|
||||
│ ├── hooks.md
|
||||
│ ├── components.md
|
||||
│ └── ...
|
||||
└── openai_metadata.json # Platform metadata
|
||||
```
|
||||
|
||||
### Step 4: Upload to OpenAI (Creates Assistant)
|
||||
|
||||
```bash
|
||||
# Upload and create Assistant with Vector Store
|
||||
skill-seekers upload react-openai.zip --target openai
|
||||
|
||||
# With API key
|
||||
skill-seekers upload react-openai.zip --target openai --api-key sk-proj-...
|
||||
```
|
||||
|
||||
**What it does:**
|
||||
1. Creates Vector Store for documentation
|
||||
2. Uploads reference files to Vector Store
|
||||
3. Creates Assistant with file_search tool
|
||||
4. Links Vector Store to Assistant
|
||||
|
||||
**Output:**
|
||||
```
|
||||
✅ Upload successful!
|
||||
Assistant ID: asst_abc123xyz
|
||||
URL: https://platform.openai.com/assistants/asst_abc123xyz
|
||||
Message: Assistant created with 15 knowledge files
|
||||
```
|
||||
|
||||
### Step 5: Use Your Assistant
|
||||
|
||||
Access your assistant in the OpenAI Platform:
|
||||
|
||||
1. Go to [OpenAI Platform](https://platform.openai.com/assistants)
|
||||
2. Find your assistant in the list
|
||||
3. Test in Playground or use via API
|
||||
|
||||
## What Makes OpenAI Different?
|
||||
|
||||
### Format: Assistant Instructions (Plain Text)
|
||||
|
||||
**Claude format:**
|
||||
```markdown
|
||||
---
|
||||
name: react
|
||||
---
|
||||
|
||||
# React Documentation
|
||||
...
|
||||
```
|
||||
|
||||
**OpenAI format:**
|
||||
```text
|
||||
You are an expert assistant for React.
|
||||
|
||||
Your Knowledge Base:
|
||||
- Getting started guide
|
||||
- React hooks reference
|
||||
- Component API
|
||||
|
||||
When users ask questions about React:
|
||||
1. Search the knowledge files
|
||||
2. Provide code examples
|
||||
...
|
||||
```
|
||||
|
||||
Plain text instructions optimized for Assistant API.
|
||||
|
||||
### Architecture: Assistant + Vector Store
|
||||
|
||||
OpenAI uses a two-part system:
|
||||
1. **Assistant** - The AI agent with instructions and tools
|
||||
2. **Vector Store** - Embedded documentation for semantic search
|
||||
|
||||
### Tool: file_search
|
||||
|
||||
The Assistant uses the `file_search` tool to:
|
||||
- Semantically search documentation
|
||||
- Find relevant code examples
|
||||
- Provide accurate, source-based answers
|
||||
|
||||
## Using Your OpenAI Assistant
|
||||
|
||||
### Option 1: OpenAI Playground (Web UI)
|
||||
|
||||
1. Go to [OpenAI Platform](https://platform.openai.com/assistants)
|
||||
2. Select your assistant
|
||||
3. Click "Test in Playground"
|
||||
4. Ask questions about your documentation
|
||||
|
||||
### Option 2: Assistants API (Python)
|
||||
|
||||
```python
|
||||
from openai import OpenAI
|
||||
|
||||
# Initialize client
|
||||
client = OpenAI(api_key='sk-proj-...')
|
||||
|
||||
# Create thread
|
||||
thread = client.beta.threads.create()
|
||||
|
||||
# Send message
|
||||
message = client.beta.threads.messages.create(
|
||||
thread_id=thread.id,
|
||||
role="user",
|
||||
content="How do I use React hooks?"
|
||||
)
|
||||
|
||||
# Run assistant
|
||||
run = client.beta.threads.runs.create(
|
||||
thread_id=thread.id,
|
||||
assistant_id='asst_abc123xyz' # Your assistant ID
|
||||
)
|
||||
|
||||
# Wait for completion
|
||||
while run.status != 'completed':
|
||||
run = client.beta.threads.runs.retrieve(thread_id=thread.id, run_id=run.id)
|
||||
|
||||
# Get response
|
||||
messages = client.beta.threads.messages.list(thread_id=thread.id)
|
||||
print(messages.data[0].content[0].text.value)
|
||||
```
|
||||
|
||||
### Option 3: Streaming Responses
|
||||
|
||||
```python
|
||||
from openai import OpenAI
|
||||
|
||||
client = OpenAI(api_key='sk-proj-...')
|
||||
|
||||
# Create thread and message
|
||||
thread = client.beta.threads.create()
|
||||
client.beta.threads.messages.create(
|
||||
thread_id=thread.id,
|
||||
role="user",
|
||||
content="Explain React hooks"
|
||||
)
|
||||
|
||||
# Stream response
|
||||
with client.beta.threads.runs.stream(
|
||||
thread_id=thread.id,
|
||||
assistant_id='asst_abc123xyz'
|
||||
) as stream:
|
||||
for event in stream:
|
||||
if event.event == 'thread.message.delta':
|
||||
print(event.data.delta.content[0].text.value, end='')
|
||||
```
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Update Assistant Instructions
|
||||
|
||||
```python
|
||||
from openai import OpenAI
|
||||
|
||||
client = OpenAI(api_key='sk-proj-...')
|
||||
|
||||
# Update assistant
|
||||
client.beta.assistants.update(
|
||||
assistant_id='asst_abc123xyz',
|
||||
instructions="""
|
||||
You are an expert React assistant.
|
||||
|
||||
Focus on modern best practices using:
|
||||
- React 18+ features
|
||||
- Functional components
|
||||
- Hooks-based patterns
|
||||
|
||||
When answering:
|
||||
1. Search knowledge files first
|
||||
2. Provide working code examples
|
||||
3. Explain the "why" not just the "what"
|
||||
"""
|
||||
)
|
||||
```
|
||||
|
||||
### Add More Files to Vector Store
|
||||
|
||||
```python
|
||||
from openai import OpenAI
|
||||
|
||||
client = OpenAI(api_key='sk-proj-...')
|
||||
|
||||
# Upload new file
|
||||
with open('new_guide.md', 'rb') as f:
|
||||
file = client.files.create(file=f, purpose='assistants')
|
||||
|
||||
# Add to vector store
|
||||
client.beta.vector_stores.files.create(
|
||||
vector_store_id='vs_abc123',
|
||||
file_id=file.id
|
||||
)
|
||||
```
|
||||
|
||||
### Programmatic Package and Upload
|
||||
|
||||
```python
|
||||
from skill_seekers.cli.adaptors import get_adaptor
|
||||
from pathlib import Path
|
||||
|
||||
# Get adaptor
|
||||
openai_adaptor = get_adaptor('openai')
|
||||
|
||||
# Package skill
|
||||
package_path = openai_adaptor.package(
|
||||
skill_dir=Path('output/react'),
|
||||
output_path=Path('output/react-openai.zip')
|
||||
)
|
||||
|
||||
# Upload (creates Assistant + Vector Store)
|
||||
result = openai_adaptor.upload(
|
||||
package_path=package_path,
|
||||
api_key='sk-proj-...'
|
||||
)
|
||||
|
||||
if result['success']:
|
||||
print(f"✅ Assistant created!")
|
||||
print(f"ID: {result['skill_id']}")
|
||||
print(f"URL: {result['url']}")
|
||||
else:
|
||||
print(f"❌ Upload failed: {result['message']}")
|
||||
```
|
||||
|
||||
## OpenAI-Specific Features
|
||||
|
||||
### 1. Semantic Search (file_search)
|
||||
|
||||
The Assistant uses embeddings to:
|
||||
- Find semantically similar content
|
||||
- Understand intent vs. keywords
|
||||
- Surface relevant examples automatically
|
||||
|
||||
### 2. Citations and Sources
|
||||
|
||||
Assistants can provide:
|
||||
- Source attribution
|
||||
- File references
|
||||
- Quote extraction
|
||||
|
||||
### 3. Function Calling (Optional)
|
||||
|
||||
Extend your assistant with custom tools:
|
||||
|
||||
```python
|
||||
client.beta.assistants.update(
|
||||
assistant_id='asst_abc123xyz',
|
||||
tools=[
|
||||
{"type": "file_search"},
|
||||
{"type": "function", "function": {
|
||||
"name": "run_code_example",
|
||||
"description": "Execute React code examples",
|
||||
"parameters": {...}
|
||||
}}
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
### 4. Multi-Modal Support
|
||||
|
||||
Include images in your documentation:
|
||||
- Screenshots
|
||||
- Diagrams
|
||||
- Architecture charts
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Issue: `openai not installed`
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
pip install skill-seekers[openai]
|
||||
```
|
||||
|
||||
### Issue: `Invalid API key format`
|
||||
|
||||
**Error:** API key doesn't start with `sk-`
|
||||
|
||||
**Solution:**
|
||||
- Get new key from [OpenAI Platform](https://platform.openai.com/api-keys)
|
||||
- Verify you're using API key, not organization ID
|
||||
|
||||
### Issue: `Not a ZIP file`
|
||||
|
||||
**Error:** Wrong package format
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Use --target openai for ZIP format
|
||||
skill-seekers package output/react/ --target openai
|
||||
|
||||
# NOT:
|
||||
skill-seekers package output/react/ --target gemini # Creates .tar.gz
|
||||
```
|
||||
|
||||
### Issue: `Assistant creation failed`
|
||||
|
||||
**Possible causes:**
|
||||
- API key lacks permissions
|
||||
- Rate limit exceeded
|
||||
- File too large
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Verify API key
|
||||
python3 -c "from openai import OpenAI; print(OpenAI(api_key='sk-proj-...').models.list())"
|
||||
|
||||
# Check rate limits
|
||||
# Visit: https://platform.openai.com/account/limits
|
||||
|
||||
# Reduce file count
|
||||
skill-seekers package output/react/ --target openai
|
||||
```
|
||||
|
||||
### Issue: Enhancement fails
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Check API quota and billing
|
||||
# Visit: https://platform.openai.com/account/billing
|
||||
|
||||
# Try with smaller skill
|
||||
skill-seekers enhance output/react/ --target openai
|
||||
|
||||
# Use without enhancement
|
||||
skill-seekers package output/react/ --target openai
|
||||
# (Skip enhancement step)
|
||||
```
|
||||
|
||||
### Issue: file_search not working
|
||||
|
||||
**Symptoms:** Assistant doesn't reference documentation
|
||||
|
||||
**Solution:**
|
||||
- Verify Vector Store has files
|
||||
- Check Assistant tool configuration
|
||||
- Test with explicit instructions: "Search the knowledge files for information about hooks"
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Write Clear Assistant Instructions
|
||||
|
||||
Focus on:
|
||||
- Role definition
|
||||
- Knowledge base description
|
||||
- Response guidelines
|
||||
- Search strategy
|
||||
|
||||
### 2. Organize Vector Store Files
|
||||
|
||||
- Keep files under 512KB each
|
||||
- Use clear, descriptive filenames
|
||||
- Structure content with headings
|
||||
- Include code examples
|
||||
|
||||
### 3. Test Assistant Behavior
|
||||
|
||||
Test with varied questions:
|
||||
```
|
||||
1. Simple facts: "What is React?"
|
||||
2. How-to questions: "How do I create a component?"
|
||||
3. Best practices: "What's the best way to manage state?"
|
||||
4. Troubleshooting: "Why isn't my hook working?"
|
||||
```
|
||||
|
||||
### 4. Monitor Token Usage
|
||||
|
||||
```python
|
||||
# Track tokens in API responses
|
||||
run = client.beta.threads.runs.retrieve(thread_id=thread.id, run_id=run.id)
|
||||
print(f"Input tokens: {run.usage.prompt_tokens}")
|
||||
print(f"Output tokens: {run.usage.completion_tokens}")
|
||||
```
|
||||
|
||||
### 5. Update Regularly
|
||||
|
||||
```bash
|
||||
# Re-scrape updated documentation
|
||||
skill-seekers create --config configs/react.json
|
||||
|
||||
# Re-enhance and upload (creates new Assistant)
|
||||
skill-seekers enhance output/react/ --target openai
|
||||
skill-seekers package output/react/ --target openai
|
||||
skill-seekers upload react-openai.zip --target openai
|
||||
```
|
||||
|
||||
## Cost Estimation
|
||||
|
||||
**GPT-4o pricing (as of 2024):**
|
||||
- Input: $2.50 per 1M tokens
|
||||
- Output: $10.00 per 1M tokens
|
||||
|
||||
**Typical skill enhancement:**
|
||||
- Input: ~50K-200K tokens (docs)
|
||||
- Output: ~5K-10K tokens (enhanced instructions)
|
||||
- Cost: $0.15-0.30 per skill
|
||||
|
||||
**Vector Store:**
|
||||
- $0.10 per GB per day (storage)
|
||||
- Typical skill: < 100MB = ~$0.01/day
|
||||
|
||||
**API usage:**
|
||||
- Varies by question volume
|
||||
- ~$0.01-0.05 per conversation
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. ✅ Install OpenAI support: `pip install skill-seekers[openai]`
|
||||
2. ✅ Get API key from OpenAI Platform
|
||||
3. ✅ Scrape your documentation
|
||||
4. ✅ Enhance with GPT-4o
|
||||
5. ✅ Package for OpenAI
|
||||
6. ✅ Upload and create Assistant
|
||||
7. ✅ Test in Playground
|
||||
|
||||
## Resources
|
||||
|
||||
- [OpenAI Platform](https://platform.openai.com/)
|
||||
- [Assistants API Documentation](https://platform.openai.com/docs/assistants/overview)
|
||||
- [OpenAI Pricing](https://openai.com/pricing)
|
||||
- [Multi-LLM Support Guide](MULTI_LLM_SUPPORT.md)
|
||||
|
||||
## Feedback
|
||||
|
||||
Found an issue or have suggestions? [Open an issue](https://github.com/yusufkaraaslan/Skill_Seekers/issues)
|
||||
@@ -0,0 +1,861 @@
|
||||
# Using Skill Seekers with Pinecone
|
||||
|
||||
**Last Updated:** February 5, 2026
|
||||
**Status:** Production Ready
|
||||
**Difficulty:** Easy ⭐
|
||||
|
||||
---
|
||||
|
||||
## 🎯 The Problem
|
||||
|
||||
Building production-grade vector search applications requires:
|
||||
|
||||
- **Scalable Vector Database** - Handle millions of embeddings efficiently
|
||||
- **Low Latency** - Sub-100ms query response times
|
||||
- **High Availability** - 99.9% uptime for production apps
|
||||
- **Easy Integration** - Works with any embedding model
|
||||
|
||||
**Example:**
|
||||
> "When building a customer support bot with RAG, you need to search across 500k+ documentation chunks in <50ms. Managing your own vector database means dealing with scaling, replication, and performance optimization."
|
||||
|
||||
---
|
||||
|
||||
## ✨ The Solution
|
||||
|
||||
Use Skill Seekers to **prepare documentation for Pinecone**:
|
||||
|
||||
1. **Generate structured documents** from any source
|
||||
2. **Create embeddings** with your preferred model (OpenAI, Cohere, etc.)
|
||||
3. **Upsert to Pinecone** with rich metadata for filtering
|
||||
4. **Query with context** - Full metadata preserved for filtering and routing
|
||||
|
||||
**Result:**
|
||||
Skill Seekers outputs JSON format ready for Pinecone upsert with all metadata intact.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Start (10 Minutes)
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Python 3.10+
|
||||
- Pinecone account (free tier available)
|
||||
- Embedding model API key (OpenAI or Cohere recommended)
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
# Install Skill Seekers
|
||||
pip install skill-seekers
|
||||
|
||||
# Install Pinecone client + embeddings
|
||||
pip install pinecone-client openai
|
||||
|
||||
# Or with Cohere embeddings
|
||||
pip install pinecone-client cohere
|
||||
```
|
||||
|
||||
### Setup Pinecone
|
||||
|
||||
```bash
|
||||
# Get API key from: https://app.pinecone.io/
|
||||
export PINECONE_API_KEY=your-api-key
|
||||
|
||||
# Get OpenAI key for embeddings
|
||||
export OPENAI_API_KEY=sk-...
|
||||
```
|
||||
|
||||
### Generate Documents
|
||||
|
||||
```bash
|
||||
# Example: React documentation
|
||||
skill-seekers create --config configs/react.json
|
||||
|
||||
# Package for Pinecone (uses LangChain format)
|
||||
skill-seekers package output/react --target langchain
|
||||
|
||||
# Output: output/react-langchain.json
|
||||
```
|
||||
|
||||
### Upsert to Pinecone
|
||||
|
||||
```python
|
||||
from pinecone import Pinecone, ServerlessSpec
|
||||
from openai import OpenAI
|
||||
import json
|
||||
|
||||
# Initialize clients
|
||||
pc = Pinecone(api_key="your-pinecone-api-key")
|
||||
openai_client = OpenAI()
|
||||
|
||||
# Create index (first time only)
|
||||
index_name = "react-docs"
|
||||
if index_name not in pc.list_indexes().names():
|
||||
pc.create_index(
|
||||
name=index_name,
|
||||
dimension=1536, # OpenAI ada-002 dimension
|
||||
metric="cosine",
|
||||
spec=ServerlessSpec(cloud="aws", region="us-east-1")
|
||||
)
|
||||
|
||||
# Connect to index
|
||||
index = pc.Index(index_name)
|
||||
|
||||
# Load documents
|
||||
with open("output/react-langchain.json") as f:
|
||||
documents = json.load(f)
|
||||
|
||||
# Create embeddings and upsert
|
||||
vectors = []
|
||||
for i, doc in enumerate(documents):
|
||||
# Generate embedding
|
||||
response = openai_client.embeddings.create(
|
||||
model="text-embedding-ada-002",
|
||||
input=doc["page_content"]
|
||||
)
|
||||
embedding = response.data[0].embedding
|
||||
|
||||
# Prepare vector with metadata
|
||||
vectors.append({
|
||||
"id": f"doc_{i}",
|
||||
"values": embedding,
|
||||
"metadata": {
|
||||
"text": doc["page_content"][:1000], # Store snippet
|
||||
"source": doc["metadata"]["source"],
|
||||
"category": doc["metadata"]["category"],
|
||||
"file": doc["metadata"]["file"],
|
||||
"type": doc["metadata"]["type"]
|
||||
}
|
||||
})
|
||||
|
||||
# Batch upsert every 100 vectors
|
||||
if len(vectors) >= 100:
|
||||
index.upsert(vectors=vectors)
|
||||
vectors = []
|
||||
print(f"Upserted {i + 1} documents...")
|
||||
|
||||
# Upsert remaining
|
||||
if vectors:
|
||||
index.upsert(vectors=vectors)
|
||||
|
||||
print(f"✅ Upserted {len(documents)} documents to Pinecone")
|
||||
```
|
||||
|
||||
### Query Pinecone
|
||||
|
||||
```python
|
||||
# Query with filters
|
||||
query = "How do I use hooks in React?"
|
||||
|
||||
# Generate query embedding
|
||||
response = openai_client.embeddings.create(
|
||||
model="text-embedding-ada-002",
|
||||
input=query
|
||||
)
|
||||
query_embedding = response.data[0].embedding
|
||||
|
||||
# Search with metadata filter
|
||||
results = index.query(
|
||||
vector=query_embedding,
|
||||
top_k=3,
|
||||
include_metadata=True,
|
||||
filter={"category": {"$eq": "hooks"}} # Filter by category
|
||||
)
|
||||
|
||||
# Display results
|
||||
for match in results["matches"]:
|
||||
print(f"Score: {match['score']:.3f}")
|
||||
print(f"Category: {match['metadata']['category']}")
|
||||
print(f"Text: {match['metadata']['text'][:200]}...")
|
||||
print()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📖 Detailed Setup Guide
|
||||
|
||||
### Step 1: Create Pinecone Index
|
||||
|
||||
```python
|
||||
from pinecone import Pinecone, ServerlessSpec
|
||||
|
||||
pc = Pinecone(api_key="your-api-key")
|
||||
|
||||
# Choose dimensions based on your embedding model:
|
||||
# - OpenAI ada-002: 1536
|
||||
# - OpenAI text-embedding-3-small: 1536
|
||||
# - OpenAI text-embedding-3-large: 3072
|
||||
# - Cohere embed-english-v3.0: 1024
|
||||
|
||||
pc.create_index(
|
||||
name="my-docs",
|
||||
dimension=1536, # Match your embedding model
|
||||
metric="cosine",
|
||||
spec=ServerlessSpec(
|
||||
cloud="aws",
|
||||
region="us-east-1" # Choose closest region
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
**Available regions:**
|
||||
- AWS: us-east-1, us-west-2, eu-west-1, ap-southeast-1
|
||||
- GCP: us-central1, europe-west1, asia-southeast1
|
||||
- Azure: eastus2, westeurope
|
||||
|
||||
### Step 2: Generate Skill Seekers Documents
|
||||
|
||||
**Option A: Documentation Website**
|
||||
```bash
|
||||
skill-seekers create --config configs/django.json
|
||||
skill-seekers package output/django --target langchain
|
||||
```
|
||||
|
||||
**Option B: GitHub Repository**
|
||||
```bash
|
||||
skill-seekers create django/django --name django
|
||||
skill-seekers package output/django --target langchain
|
||||
```
|
||||
|
||||
**Option C: Local Codebase**
|
||||
```bash
|
||||
skill-seekers scan /path/to/repo
|
||||
skill-seekers package output/codebase --target langchain
|
||||
```
|
||||
|
||||
### Step 3: Create Embeddings Strategy
|
||||
|
||||
**Strategy 1: OpenAI (Recommended)**
|
||||
```python
|
||||
from openai import OpenAI
|
||||
|
||||
client = OpenAI()
|
||||
|
||||
def create_embedding(text: str) -> list[float]:
|
||||
response = client.embeddings.create(
|
||||
model="text-embedding-ada-002",
|
||||
input=text
|
||||
)
|
||||
return response.data[0].embedding
|
||||
|
||||
# Cost: ~$0.0001 per 1K tokens
|
||||
# Speed: ~1000 docs/minute
|
||||
# Quality: Excellent for most use cases
|
||||
```
|
||||
|
||||
**Strategy 2: Cohere**
|
||||
```python
|
||||
import cohere
|
||||
|
||||
co = cohere.Client("your-cohere-api-key")
|
||||
|
||||
def create_embedding(text: str) -> list[float]:
|
||||
response = co.embed(
|
||||
texts=[text],
|
||||
model="embed-english-v3.0",
|
||||
input_type="search_document"
|
||||
)
|
||||
return response.embeddings[0]
|
||||
|
||||
# Cost: ~$0.0001 per 1K tokens
|
||||
# Speed: ~1000 docs/minute
|
||||
# Quality: Excellent, especially for semantic search
|
||||
```
|
||||
|
||||
**Strategy 3: Local Model (SentenceTransformers)**
|
||||
```python
|
||||
from sentence_transformers import SentenceTransformer
|
||||
|
||||
model = SentenceTransformer('all-MiniLM-L6-v2')
|
||||
|
||||
def create_embedding(text: str) -> list[float]:
|
||||
return model.encode(text).tolist()
|
||||
|
||||
# Cost: Free
|
||||
# Speed: ~500-1000 docs/minute (CPU)
|
||||
# Quality: Good for smaller datasets
|
||||
# Note: Dimension is 384 for all-MiniLM-L6-v2
|
||||
```
|
||||
|
||||
### Step 4: Batch Upsert Pattern
|
||||
|
||||
```python
|
||||
import json
|
||||
from typing import List, Dict
|
||||
from tqdm import tqdm
|
||||
|
||||
def batch_upsert_documents(
|
||||
index,
|
||||
documents_path: str,
|
||||
embedding_func,
|
||||
batch_size: int = 100
|
||||
):
|
||||
"""
|
||||
Efficiently upsert documents to Pinecone in batches.
|
||||
|
||||
Args:
|
||||
index: Pinecone index object
|
||||
documents_path: Path to Skill Seekers JSON output
|
||||
embedding_func: Function to create embeddings
|
||||
batch_size: Number of documents per batch
|
||||
"""
|
||||
# Load documents
|
||||
with open(documents_path) as f:
|
||||
documents = json.load(f)
|
||||
|
||||
vectors = []
|
||||
for i, doc in enumerate(tqdm(documents, desc="Upserting")):
|
||||
# Create embedding
|
||||
embedding = embedding_func(doc["page_content"])
|
||||
|
||||
# Prepare vector
|
||||
vectors.append({
|
||||
"id": f"doc_{i}",
|
||||
"values": embedding,
|
||||
"metadata": {
|
||||
"text": doc["page_content"][:1000], # Pinecone limit
|
||||
"full_text_id": str(i), # Reference to full text
|
||||
**doc["metadata"] # Preserve all Skill Seekers metadata
|
||||
}
|
||||
})
|
||||
|
||||
# Batch upsert
|
||||
if len(vectors) >= batch_size:
|
||||
index.upsert(vectors=vectors)
|
||||
vectors = []
|
||||
|
||||
# Upsert remaining
|
||||
if vectors:
|
||||
index.upsert(vectors=vectors)
|
||||
|
||||
print(f"✅ Upserted {len(documents)} documents")
|
||||
|
||||
# Verify index stats
|
||||
stats = index.describe_index_stats()
|
||||
print(f"Total vectors in index: {stats['total_vector_count']}")
|
||||
|
||||
# Usage
|
||||
batch_upsert_documents(
|
||||
index=pc.Index("my-docs"),
|
||||
documents_path="output/react-langchain.json",
|
||||
embedding_func=create_embedding,
|
||||
batch_size=100
|
||||
)
|
||||
```
|
||||
|
||||
### Step 5: Query with Filters
|
||||
|
||||
```python
|
||||
def semantic_search(
|
||||
index,
|
||||
query: str,
|
||||
embedding_func,
|
||||
top_k: int = 5,
|
||||
category: str = None,
|
||||
file: str = None
|
||||
):
|
||||
"""
|
||||
Semantic search with optional metadata filters.
|
||||
|
||||
Args:
|
||||
index: Pinecone index
|
||||
query: Search query
|
||||
embedding_func: Embedding function
|
||||
top_k: Number of results
|
||||
category: Filter by category
|
||||
file: Filter by file
|
||||
"""
|
||||
# Create query embedding
|
||||
query_embedding = embedding_func(query)
|
||||
|
||||
# Build filter
|
||||
filter_dict = {}
|
||||
if category:
|
||||
filter_dict["category"] = {"$eq": category}
|
||||
if file:
|
||||
filter_dict["file"] = {"$eq": file}
|
||||
|
||||
# Query
|
||||
results = index.query(
|
||||
vector=query_embedding,
|
||||
top_k=top_k,
|
||||
include_metadata=True,
|
||||
filter=filter_dict if filter_dict else None
|
||||
)
|
||||
|
||||
return results["matches"]
|
||||
|
||||
# Example queries
|
||||
results = semantic_search(
|
||||
index=pc.Index("react-docs"),
|
||||
query="How do I manage state?",
|
||||
embedding_func=create_embedding,
|
||||
category="hooks" # Only search in hooks category
|
||||
)
|
||||
|
||||
for match in results:
|
||||
print(f"Score: {match['score']:.3f}")
|
||||
print(f"Category: {match['metadata']['category']}")
|
||||
print(f"Text: {match['metadata']['text'][:200]}...")
|
||||
print()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Advanced Usage
|
||||
|
||||
### Hybrid Search (Keyword + Semantic)
|
||||
|
||||
```python
|
||||
# Pinecone sparse-dense hybrid search
|
||||
from pinecone_text.sparse import BM25Encoder
|
||||
|
||||
# Initialize BM25 encoder
|
||||
bm25 = BM25Encoder()
|
||||
bm25.fit(documents) # Fit on your corpus
|
||||
|
||||
def hybrid_search(query: str, top_k: int = 5):
|
||||
# Dense embedding
|
||||
dense_embedding = create_embedding(query)
|
||||
|
||||
# Sparse embedding (BM25)
|
||||
sparse_embedding = bm25.encode_queries(query)
|
||||
|
||||
# Hybrid query
|
||||
results = index.query(
|
||||
vector=dense_embedding,
|
||||
sparse_vector=sparse_embedding,
|
||||
top_k=top_k,
|
||||
include_metadata=True
|
||||
)
|
||||
|
||||
return results["matches"]
|
||||
```
|
||||
|
||||
### Namespace Management
|
||||
|
||||
```python
|
||||
# Organize documents by namespace
|
||||
namespaces = {
|
||||
"stable": documents_v1,
|
||||
"beta": documents_v2,
|
||||
"archived": old_documents
|
||||
}
|
||||
|
||||
for ns, docs in namespaces.items():
|
||||
vectors = prepare_vectors(docs)
|
||||
index.upsert(vectors=vectors, namespace=ns)
|
||||
|
||||
# Query specific namespace
|
||||
results = index.query(
|
||||
vector=query_embedding,
|
||||
top_k=5,
|
||||
namespace="stable" # Only query stable docs
|
||||
)
|
||||
```
|
||||
|
||||
### Metadata Filtering Patterns
|
||||
|
||||
```python
|
||||
# Exact match
|
||||
filter={"category": {"$eq": "api"}}
|
||||
|
||||
# Multiple values (OR)
|
||||
filter={"category": {"$in": ["api", "guides"]}}
|
||||
|
||||
# Exclude
|
||||
filter={"type": {"$ne": "deprecated"}}
|
||||
|
||||
# Range (for numeric metadata)
|
||||
filter={"version": {"$gte": 2.0}}
|
||||
|
||||
# Multiple conditions (AND)
|
||||
filter={
|
||||
"$and": [
|
||||
{"category": {"$eq": "api"}},
|
||||
{"version": {"$gte": 2.0}}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### RAG Pipeline Integration
|
||||
|
||||
```python
|
||||
from openai import OpenAI
|
||||
|
||||
openai_client = OpenAI()
|
||||
|
||||
def rag_query(question: str, top_k: int = 3):
|
||||
"""Complete RAG pipeline with Pinecone."""
|
||||
|
||||
# 1. Retrieve relevant documents
|
||||
query_embedding = create_embedding(question)
|
||||
results = index.query(
|
||||
vector=query_embedding,
|
||||
top_k=top_k,
|
||||
include_metadata=True
|
||||
)
|
||||
|
||||
# 2. Build context from results
|
||||
context_parts = []
|
||||
for match in results["matches"]:
|
||||
context_parts.append(
|
||||
f"[{match['metadata']['category']}] "
|
||||
f"{match['metadata']['text']}"
|
||||
)
|
||||
context = "\n\n".join(context_parts)
|
||||
|
||||
# 3. Generate answer with LLM
|
||||
response = openai_client.chat.completions.create(
|
||||
model="gpt-4",
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": "Answer based on the provided context."
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": f"Context:\n{context}\n\nQuestion: {question}"
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
return {
|
||||
"answer": response.choices[0].message.content,
|
||||
"sources": [
|
||||
{
|
||||
"category": m["metadata"]["category"],
|
||||
"file": m["metadata"]["file"],
|
||||
"score": m["score"]
|
||||
}
|
||||
for m in results["matches"]
|
||||
]
|
||||
}
|
||||
|
||||
# Usage
|
||||
result = rag_query("How do I create a React component?")
|
||||
print(f"Answer: {result['answer']}\n")
|
||||
print("Sources:")
|
||||
for source in result["sources"]:
|
||||
print(f" - {source['category']} ({source['file']}) - Score: {source['score']:.3f}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 Best Practices
|
||||
|
||||
### 1. Choose Right Index Configuration
|
||||
|
||||
```python
|
||||
# Serverless (recommended for most cases)
|
||||
spec=ServerlessSpec(
|
||||
cloud="aws",
|
||||
region="us-east-1" # Choose closest to your users
|
||||
)
|
||||
|
||||
# Pod-based (for high throughput, dedicated resources)
|
||||
spec=PodSpec(
|
||||
environment="us-east1-gcp",
|
||||
pod_type="p1.x1", # Small: p1.x1, Medium: p1.x2, Large: p2.x1
|
||||
pods=1,
|
||||
replicas=1
|
||||
)
|
||||
```
|
||||
|
||||
### 2. Optimize Metadata Storage
|
||||
|
||||
```python
|
||||
# Store only essential metadata in Pinecone (max 40KB per vector)
|
||||
# Keep full text elsewhere (database, object storage)
|
||||
|
||||
metadata = {
|
||||
"text": doc["page_content"][:1000], # Snippet only
|
||||
"full_text_id": str(i), # Reference to full text
|
||||
"category": doc["metadata"]["category"],
|
||||
"source": doc["metadata"]["source"],
|
||||
# Don't store: full page_content, images, binary data
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Use Namespaces for Multi-Tenancy
|
||||
|
||||
```python
|
||||
# Per-customer namespaces
|
||||
namespace = f"customer_{customer_id}"
|
||||
index.upsert(vectors=vectors, namespace=namespace)
|
||||
|
||||
# Query only customer's data
|
||||
results = index.query(
|
||||
vector=query_embedding,
|
||||
namespace=namespace,
|
||||
top_k=5
|
||||
)
|
||||
```
|
||||
|
||||
### 4. Monitor Index Performance
|
||||
|
||||
```python
|
||||
# Check index stats
|
||||
stats = index.describe_index_stats()
|
||||
print(f"Total vectors: {stats['total_vector_count']}")
|
||||
print(f"Dimension: {stats['dimension']}")
|
||||
print(f"Namespaces: {stats.get('namespaces', {})}")
|
||||
|
||||
# Monitor query latency
|
||||
import time
|
||||
start = time.time()
|
||||
results = index.query(vector=query_embedding, top_k=5)
|
||||
latency = time.time() - start
|
||||
print(f"Query latency: {latency*1000:.2f}ms")
|
||||
```
|
||||
|
||||
### 5. Handle Updates Efficiently
|
||||
|
||||
```python
|
||||
# Update existing vectors (upsert with same ID)
|
||||
index.upsert(vectors=[{
|
||||
"id": "doc_123",
|
||||
"values": new_embedding,
|
||||
"metadata": updated_metadata
|
||||
}])
|
||||
|
||||
# Delete obsolete vectors
|
||||
index.delete(ids=["doc_123", "doc_456"])
|
||||
|
||||
# Delete by metadata filter
|
||||
index.delete(filter={"category": {"$eq": "deprecated"}})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔥 Real-World Example: Customer Support Bot
|
||||
|
||||
```python
|
||||
import json
|
||||
from pinecone import Pinecone, ServerlessSpec
|
||||
from openai import OpenAI
|
||||
|
||||
class SupportBotRAG:
|
||||
def __init__(self, index_name: str):
|
||||
self.pc = Pinecone()
|
||||
self.index = self.pc.Index(index_name)
|
||||
self.openai = OpenAI()
|
||||
|
||||
def ingest_docs(self, docs_path: str):
|
||||
"""Ingest Skill Seekers documentation."""
|
||||
with open(docs_path) as f:
|
||||
documents = json.load(f)
|
||||
|
||||
vectors = []
|
||||
for i, doc in enumerate(documents):
|
||||
# Create embedding
|
||||
response = self.openai.embeddings.create(
|
||||
model="text-embedding-ada-002",
|
||||
input=doc["page_content"]
|
||||
)
|
||||
|
||||
vectors.append({
|
||||
"id": f"doc_{i}",
|
||||
"values": response.data[0].embedding,
|
||||
"metadata": {
|
||||
"text": doc["page_content"][:1000],
|
||||
**doc["metadata"]
|
||||
}
|
||||
})
|
||||
|
||||
if len(vectors) >= 100:
|
||||
self.index.upsert(vectors=vectors)
|
||||
vectors = []
|
||||
|
||||
if vectors:
|
||||
self.index.upsert(vectors=vectors)
|
||||
|
||||
print(f"✅ Ingested {len(documents)} documents")
|
||||
|
||||
def answer_question(self, question: str, category: str = None):
|
||||
"""Answer customer question with RAG."""
|
||||
# Create query embedding
|
||||
response = self.openai.embeddings.create(
|
||||
model="text-embedding-ada-002",
|
||||
input=question
|
||||
)
|
||||
query_embedding = response.data[0].embedding
|
||||
|
||||
# Retrieve relevant docs
|
||||
filter_dict = {"category": {"$eq": category}} if category else None
|
||||
results = self.index.query(
|
||||
vector=query_embedding,
|
||||
top_k=3,
|
||||
include_metadata=True,
|
||||
filter=filter_dict
|
||||
)
|
||||
|
||||
# Build context
|
||||
context = "\n\n".join([
|
||||
m["metadata"]["text"] for m in results["matches"]
|
||||
])
|
||||
|
||||
# Generate answer
|
||||
completion = self.openai.chat.completions.create(
|
||||
model="gpt-4",
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": "You are a helpful support bot. Answer based on the provided documentation."
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": f"Context:\n{context}\n\nQuestion: {question}"
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
return {
|
||||
"answer": completion.choices[0].message.content,
|
||||
"sources": [
|
||||
{
|
||||
"category": m["metadata"]["category"],
|
||||
"score": m["score"]
|
||||
}
|
||||
for m in results["matches"]
|
||||
]
|
||||
}
|
||||
|
||||
# Usage
|
||||
bot = SupportBotRAG("support-docs")
|
||||
bot.ingest_docs("output/product-docs-langchain.json")
|
||||
|
||||
result = bot.answer_question("How do I reset my password?", category="authentication")
|
||||
print(f"Answer: {result['answer']}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Issue: Dimension Mismatch Error
|
||||
|
||||
**Problem:** "Dimension mismatch: expected 1536, got 384"
|
||||
|
||||
**Solution:** Ensure embedding model dimension matches index
|
||||
```python
|
||||
# Check your embedding model dimension
|
||||
from sentence_transformers import SentenceTransformer
|
||||
model = SentenceTransformer('all-MiniLM-L6-v2')
|
||||
print(f"Model dimension: {model.get_sentence_embedding_dimension()}") # 384
|
||||
|
||||
# Create index with correct dimension
|
||||
pc.create_index(name="my-index", dimension=384, ...)
|
||||
```
|
||||
|
||||
### Issue: Rate Limit Errors
|
||||
|
||||
**Problem:** "Rate limit exceeded"
|
||||
|
||||
**Solution:** Add retry logic and batching
|
||||
```python
|
||||
import time
|
||||
from tenacity import retry, wait_exponential, stop_after_attempt
|
||||
|
||||
@retry(wait=wait_exponential(multiplier=1, min=2, max=10), stop=stop_after_attempt(3))
|
||||
def upsert_with_retry(index, vectors):
|
||||
return index.upsert(vectors=vectors)
|
||||
|
||||
# Use smaller batches
|
||||
batch_size = 50 # Reduce from 100
|
||||
```
|
||||
|
||||
### Issue: High Query Latency
|
||||
|
||||
**Solutions:**
|
||||
```python
|
||||
# 1. Reduce top_k
|
||||
results = index.query(vector=query_embedding, top_k=3) # Instead of 10
|
||||
|
||||
# 2. Use metadata filtering to reduce search space
|
||||
filter={"category": {"$eq": "api"}}
|
||||
|
||||
# 3. Use namespaces
|
||||
namespace="high_priority_docs"
|
||||
|
||||
# 4. Consider pod-based index for consistent low latency
|
||||
spec=PodSpec(environment="us-east1-gcp", pod_type="p1.x2")
|
||||
```
|
||||
|
||||
### Issue: Missing Metadata
|
||||
|
||||
**Problem:** Metadata not returned in results
|
||||
|
||||
**Solution:** Enable metadata in query
|
||||
```python
|
||||
results = index.query(
|
||||
vector=query_embedding,
|
||||
top_k=5,
|
||||
include_metadata=True # CRITICAL
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Cost Optimization
|
||||
|
||||
### Embedding Costs
|
||||
|
||||
| Provider | Model | Cost per 1M tokens | Speed |
|
||||
|----------|-------|-------------------|-------|
|
||||
| OpenAI | ada-002 | $0.10 | Fast |
|
||||
| OpenAI | text-embedding-3-small | $0.02 | Fast |
|
||||
| OpenAI | text-embedding-3-large | $0.13 | Fast |
|
||||
| Cohere | embed-english-v3.0 | $0.10 | Fast |
|
||||
| Local | SentenceTransformers | Free | Medium |
|
||||
|
||||
**Recommendation:** OpenAI text-embedding-3-small (best quality/cost ratio)
|
||||
|
||||
### Pinecone Costs
|
||||
|
||||
**Serverless (pay per use):**
|
||||
- Storage: $0.01 per GB/month
|
||||
- Reads: $0.025 per 100k read units
|
||||
- Writes: $0.50 per 100k write units
|
||||
|
||||
**Pod-based (fixed cost):**
|
||||
- p1.x1: ~$70/month (1GB storage, 100 QPS)
|
||||
- p1.x2: ~$140/month (2GB storage, 200 QPS)
|
||||
- p2.x1: ~$280/month (4GB storage, 400 QPS)
|
||||
|
||||
**Example costs for 100k documents:**
|
||||
- Storage: ~250MB = $0.0025/month
|
||||
- Writes: 100k = $0.50 one-time
|
||||
- Reads: 100k queries = $0.025/month
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Community & Support
|
||||
|
||||
- **Questions:** [GitHub Discussions](https://github.com/yusufkaraaslan/Skill_Seekers/discussions)
|
||||
- **Issues:** [GitHub Issues](https://github.com/yusufkaraaslan/Skill_Seekers/issues)
|
||||
- **Documentation:** [https://skillseekersweb.com/](https://skillseekersweb.com/)
|
||||
- **Pinecone Docs:** [https://docs.pinecone.io/](https://docs.pinecone.io/)
|
||||
|
||||
---
|
||||
|
||||
## 📚 Related Guides
|
||||
|
||||
- [LangChain Integration](./LANGCHAIN.md)
|
||||
- [LlamaIndex Integration](./LLAMA_INDEX.md)
|
||||
- [RAG Pipelines Overview](./RAG_PIPELINES.md)
|
||||
|
||||
---
|
||||
|
||||
## 📖 Next Steps
|
||||
|
||||
1. **Try the Quick Start** above
|
||||
2. **Experiment with different embedding models**
|
||||
3. **Build your RAG pipeline** with production-ready docs
|
||||
4. **Share your experience** - we'd love feedback!
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** February 5, 2026
|
||||
**Tested With:** Pinecone Serverless, OpenAI ada-002, GPT-4
|
||||
**Skill Seekers Version:** v3.6.0
|
||||
@@ -0,0 +1,904 @@
|
||||
# Qdrant Integration with Skill Seekers
|
||||
|
||||
**Status:** ✅ Production Ready
|
||||
**Difficulty:** Intermediate
|
||||
**Last Updated:** February 7, 2026
|
||||
|
||||
---
|
||||
|
||||
## ❌ The Problem
|
||||
|
||||
Building RAG applications with Qdrant involves several challenges:
|
||||
|
||||
1. **Collection Schema Complexity** - Defining vector configurations, payload schemas, and distance metrics requires understanding Qdrant's data model
|
||||
2. **Payload Filtering Setup** - Rich metadata filtering requires proper payload indexing and field types
|
||||
3. **Deployment Options** - Choosing between local, Docker, cloud, or cluster mode adds configuration overhead
|
||||
|
||||
**Example Pain Point:**
|
||||
|
||||
```python
|
||||
# Manual Qdrant setup for each framework
|
||||
from qdrant_client import QdrantClient
|
||||
from qdrant_client.models import Distance, VectorParams, PointStruct
|
||||
from openai import OpenAI
|
||||
|
||||
# Create client + collection
|
||||
client = QdrantClient(url="http://localhost:6333")
|
||||
client.create_collection(
|
||||
collection_name="react_docs",
|
||||
vectors_config=VectorParams(size=1536, distance=Distance.COSINE),
|
||||
)
|
||||
|
||||
# Generate embeddings manually
|
||||
openai_client = OpenAI()
|
||||
points = []
|
||||
for i, doc in enumerate(documents):
|
||||
response = openai_client.embeddings.create(
|
||||
model="text-embedding-ada-002",
|
||||
input=doc
|
||||
)
|
||||
points.append(PointStruct(
|
||||
id=i,
|
||||
vector=response.data[0].embedding,
|
||||
payload={"text": doc[:1000], "metadata": {...}} # Manual metadata
|
||||
))
|
||||
|
||||
# Upload points
|
||||
client.upsert(collection_name="react_docs", points=points)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ The Solution
|
||||
|
||||
Skill Seekers automates Qdrant integration with structured, production-ready data:
|
||||
|
||||
**Benefits:**
|
||||
- ✅ Auto-formatted documents with rich payload metadata
|
||||
- ✅ Consistent collection structure across all frameworks
|
||||
- ✅ Works with Qdrant Cloud, self-hosted, or Docker
|
||||
- ✅ Advanced filtering with indexed payloads
|
||||
- ✅ High-performance Rust engine (10K+ QPS)
|
||||
|
||||
**Result:** 10-minute setup, production-ready vector search with enterprise performance.
|
||||
|
||||
---
|
||||
|
||||
## ⚡ Quick Start (10 Minutes)
|
||||
|
||||
### Prerequisites
|
||||
|
||||
```bash
|
||||
# Install Qdrant client
|
||||
pip install qdrant-client>=1.7.0
|
||||
|
||||
# OpenAI for embeddings
|
||||
pip install openai>=1.0.0
|
||||
|
||||
# Or with Skill Seekers
|
||||
pip install skill-seekers[all-llms]
|
||||
```
|
||||
|
||||
**What you need:**
|
||||
- Qdrant instance (local, Docker, or Cloud)
|
||||
- OpenAI API key (for embeddings)
|
||||
|
||||
### Start Qdrant (Docker)
|
||||
|
||||
```bash
|
||||
# Start Qdrant locally
|
||||
docker run -p 6333:6333 qdrant/qdrant
|
||||
|
||||
# Or with persistence
|
||||
docker run -p 6333:6333 -v $(pwd)/qdrant_storage:/qdrant/storage qdrant/qdrant
|
||||
```
|
||||
|
||||
### Generate Qdrant-Ready Documents
|
||||
|
||||
```bash
|
||||
# Step 1: Scrape documentation
|
||||
skill-seekers create --config configs/react.json
|
||||
|
||||
# Step 2: Package for Qdrant (creates LangChain format)
|
||||
skill-seekers package output/react --target langchain
|
||||
|
||||
# Output: output/react-langchain.json (Qdrant-compatible)
|
||||
```
|
||||
|
||||
### Upload to Qdrant
|
||||
|
||||
```python
|
||||
import json
|
||||
from qdrant_client import QdrantClient
|
||||
from qdrant_client.models import Distance, VectorParams, PointStruct
|
||||
from openai import OpenAI
|
||||
|
||||
# Connect to Qdrant
|
||||
client = QdrantClient(url="http://localhost:6333")
|
||||
openai_client = OpenAI()
|
||||
|
||||
# Create collection
|
||||
collection_name = "react_docs"
|
||||
client.recreate_collection(
|
||||
collection_name=collection_name,
|
||||
vectors_config=VectorParams(size=1536, distance=Distance.COSINE),
|
||||
)
|
||||
|
||||
# Load documents
|
||||
with open("output/react-langchain.json") as f:
|
||||
documents = json.load(f)
|
||||
|
||||
# Generate embeddings and upload
|
||||
points = []
|
||||
for i, doc in enumerate(documents):
|
||||
# Generate embedding
|
||||
response = openai_client.embeddings.create(
|
||||
model="text-embedding-ada-002",
|
||||
input=doc["page_content"]
|
||||
)
|
||||
|
||||
# Create point with payload
|
||||
points.append(PointStruct(
|
||||
id=i,
|
||||
vector=response.data[0].embedding,
|
||||
payload={
|
||||
"content": doc["page_content"],
|
||||
"source": doc["metadata"]["source"],
|
||||
"category": doc["metadata"]["category"],
|
||||
"file": doc["metadata"]["file"],
|
||||
"type": doc["metadata"]["type"]
|
||||
}
|
||||
))
|
||||
|
||||
# Batch upload every 100 points
|
||||
if len(points) >= 100:
|
||||
client.upsert(collection_name=collection_name, points=points)
|
||||
points = []
|
||||
print(f"Uploaded {i + 1} documents...")
|
||||
|
||||
# Upload remaining
|
||||
if points:
|
||||
client.upsert(collection_name=collection_name, points=points)
|
||||
|
||||
print(f"✅ Uploaded {len(documents)} documents to Qdrant")
|
||||
```
|
||||
|
||||
### Query with Filters
|
||||
|
||||
```python
|
||||
# Search with metadata filter
|
||||
results = client.search(
|
||||
collection_name="react_docs",
|
||||
query_vector=query_embedding,
|
||||
limit=3,
|
||||
query_filter={
|
||||
"must": [
|
||||
{"key": "category", "match": {"value": "hooks"}}
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
for result in results:
|
||||
print(f"Score: {result.score:.3f}")
|
||||
print(f"Category: {result.payload['category']}")
|
||||
print(f"Content: {result.payload['content'][:200]}...")
|
||||
print()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📖 Detailed Setup Guide
|
||||
|
||||
### Step 1: Deploy Qdrant
|
||||
|
||||
**Option A: Docker (Local Development)**
|
||||
|
||||
```bash
|
||||
# Basic setup
|
||||
docker run -p 6333:6333 -p 6334:6334 qdrant/qdrant
|
||||
|
||||
# With persistent storage
|
||||
docker run -p 6333:6333 \
|
||||
-v $(pwd)/qdrant_storage:/qdrant/storage \
|
||||
qdrant/qdrant
|
||||
|
||||
# With configuration
|
||||
docker run -p 6333:6333 \
|
||||
-v $(pwd)/qdrant_storage:/qdrant/storage \
|
||||
-v $(pwd)/qdrant_config.yaml:/qdrant/config/production.yaml \
|
||||
qdrant/qdrant
|
||||
```
|
||||
|
||||
**Option B: Qdrant Cloud (Production)**
|
||||
|
||||
1. Sign up at [cloud.qdrant.io](https://cloud.qdrant.io)
|
||||
2. Create a cluster (free tier available)
|
||||
3. Get your API endpoint and API key
|
||||
4. Note your cluster URL: `https://your-cluster.qdrant.io`
|
||||
|
||||
```python
|
||||
from qdrant_client import QdrantClient
|
||||
|
||||
client = QdrantClient(
|
||||
url="https://your-cluster.qdrant.io",
|
||||
api_key="your-api-key"
|
||||
)
|
||||
```
|
||||
|
||||
**Option C: Self-Hosted Binary**
|
||||
|
||||
```bash
|
||||
# Download Qdrant
|
||||
wget https://github.com/qdrant/qdrant/releases/download/v1.7.0/qdrant-x86_64-unknown-linux-gnu.tar.gz
|
||||
tar -xzf qdrant-x86_64-unknown-linux-gnu.tar.gz
|
||||
|
||||
# Run Qdrant
|
||||
./qdrant
|
||||
|
||||
# Access at http://localhost:6333
|
||||
```
|
||||
|
||||
**Option D: Kubernetes (Production Cluster)**
|
||||
|
||||
```bash
|
||||
helm repo add qdrant https://qdrant.to/helm
|
||||
helm install qdrant qdrant/qdrant
|
||||
|
||||
# With custom values
|
||||
helm install qdrant qdrant/qdrant -f values.yaml
|
||||
```
|
||||
|
||||
### Step 2: Generate Skill Seekers Documents
|
||||
|
||||
**Option A: Documentation Website**
|
||||
```bash
|
||||
skill-seekers create --config configs/django.json
|
||||
skill-seekers package output/django --target langchain
|
||||
```
|
||||
|
||||
**Option B: GitHub Repository**
|
||||
```bash
|
||||
skill-seekers create django/django --name django
|
||||
skill-seekers package output/django --target langchain
|
||||
```
|
||||
|
||||
**Option C: Local Codebase**
|
||||
```bash
|
||||
skill-seekers scan /path/to/repo
|
||||
skill-seekers package output/codebase --target langchain
|
||||
```
|
||||
|
||||
**Option D: RAG-Optimized Chunking**
|
||||
```bash
|
||||
skill-seekers create --config configs/fastapi.json --chunk-for-rag --chunk-tokens 512
|
||||
skill-seekers package output/fastapi --target langchain
|
||||
```
|
||||
|
||||
### Step 3: Create Collection with Payload Schema
|
||||
|
||||
```python
|
||||
from qdrant_client import QdrantClient
|
||||
from qdrant_client.models import Distance, VectorParams, PayloadSchemaType
|
||||
|
||||
client = QdrantClient(url="http://localhost:6333")
|
||||
|
||||
# Create collection with vector config
|
||||
client.recreate_collection(
|
||||
collection_name="documentation",
|
||||
vectors_config=VectorParams(
|
||||
size=1536, # OpenAI ada-002 dimension
|
||||
distance=Distance.COSINE # or EUCLID, DOT
|
||||
)
|
||||
)
|
||||
|
||||
# Create payload indexes for filtering (optional but recommended)
|
||||
client.create_payload_index(
|
||||
collection_name="documentation",
|
||||
field_name="category",
|
||||
field_schema=PayloadSchemaType.KEYWORD
|
||||
)
|
||||
|
||||
client.create_payload_index(
|
||||
collection_name="documentation",
|
||||
field_name="source",
|
||||
field_schema=PayloadSchemaType.KEYWORD
|
||||
)
|
||||
|
||||
print("✅ Collection created with payload indexes")
|
||||
```
|
||||
|
||||
### Step 4: Batch Upload with Progress
|
||||
|
||||
```python
|
||||
import json
|
||||
from qdrant_client import QdrantClient
|
||||
from qdrant_client.models import PointStruct
|
||||
from openai import OpenAI
|
||||
|
||||
client = QdrantClient(url="http://localhost:6333")
|
||||
openai_client = OpenAI()
|
||||
|
||||
# Load documents
|
||||
with open("output/django-langchain.json") as f:
|
||||
documents = json.load(f)
|
||||
|
||||
# Batch upload with progress
|
||||
batch_size = 100
|
||||
collection_name = "documentation"
|
||||
|
||||
for i in range(0, len(documents), batch_size):
|
||||
batch = documents[i:i + batch_size]
|
||||
points = []
|
||||
|
||||
for j, doc in enumerate(batch):
|
||||
# Generate embedding
|
||||
response = openai_client.embeddings.create(
|
||||
model="text-embedding-ada-002",
|
||||
input=doc["page_content"]
|
||||
)
|
||||
|
||||
# Create point
|
||||
points.append(PointStruct(
|
||||
id=i + j,
|
||||
vector=response.data[0].embedding,
|
||||
payload={
|
||||
"content": doc["page_content"],
|
||||
"source": doc["metadata"]["source"],
|
||||
"category": doc["metadata"]["category"],
|
||||
"file": doc["metadata"]["file"],
|
||||
"type": doc["metadata"]["type"],
|
||||
"url": doc["metadata"].get("url", "")
|
||||
}
|
||||
))
|
||||
|
||||
# Upload batch
|
||||
client.upsert(collection_name=collection_name, points=points)
|
||||
print(f"Uploaded {min(i + batch_size, len(documents))}/{len(documents)}...")
|
||||
|
||||
print(f"✅ Uploaded {len(documents)} documents to Qdrant")
|
||||
|
||||
# Verify upload
|
||||
info = client.get_collection(collection_name)
|
||||
print(f"Collection size: {info.points_count}")
|
||||
```
|
||||
|
||||
### Step 5: Advanced Querying
|
||||
|
||||
```python
|
||||
from qdrant_client.models import Filter, FieldCondition, MatchValue
|
||||
from openai import OpenAI
|
||||
|
||||
openai_client = OpenAI()
|
||||
|
||||
# Generate query embedding
|
||||
query = "How do I use Django models?"
|
||||
response = openai_client.embeddings.create(
|
||||
model="text-embedding-ada-002",
|
||||
input=query
|
||||
)
|
||||
query_embedding = response.data[0].embedding
|
||||
|
||||
# Simple search
|
||||
results = client.search(
|
||||
collection_name="documentation",
|
||||
query_vector=query_embedding,
|
||||
limit=5
|
||||
)
|
||||
|
||||
# Search with single filter
|
||||
results = client.search(
|
||||
collection_name="documentation",
|
||||
query_vector=query_embedding,
|
||||
limit=5,
|
||||
query_filter=Filter(
|
||||
must=[
|
||||
FieldCondition(
|
||||
key="category",
|
||||
match=MatchValue(value="models")
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
# Search with multiple filters (AND logic)
|
||||
results = client.search(
|
||||
collection_name="documentation",
|
||||
query_vector=query_embedding,
|
||||
limit=5,
|
||||
query_filter=Filter(
|
||||
must=[
|
||||
FieldCondition(key="category", match=MatchValue(value="models")),
|
||||
FieldCondition(key="type", match=MatchValue(value="tutorial"))
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
# Search with OR logic
|
||||
results = client.search(
|
||||
collection_name="documentation",
|
||||
query_vector=query_embedding,
|
||||
limit=5,
|
||||
query_filter=Filter(
|
||||
should=[
|
||||
FieldCondition(key="category", match=MatchValue(value="models")),
|
||||
FieldCondition(key="category", match=MatchValue(value="views"))
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
# Extract results
|
||||
for result in results:
|
||||
print(f"Score: {result.score:.3f}")
|
||||
print(f"Category: {result.payload['category']}")
|
||||
print(f"Content: {result.payload['content'][:200]}...")
|
||||
print()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Advanced Usage
|
||||
|
||||
### 1. Named Vectors for Multi-Model Embeddings
|
||||
|
||||
```python
|
||||
from qdrant_client.models import VectorParams, Distance
|
||||
|
||||
# Create collection with multiple vector spaces
|
||||
client.recreate_collection(
|
||||
collection_name="documentation",
|
||||
vectors_config={
|
||||
"text-ada-002": VectorParams(size=1536, distance=Distance.COSINE),
|
||||
"cohere-v3": VectorParams(size=1024, distance=Distance.COSINE)
|
||||
}
|
||||
)
|
||||
|
||||
# Upload with multiple vectors
|
||||
point = PointStruct(
|
||||
id=1,
|
||||
vector={
|
||||
"text-ada-002": openai_embedding,
|
||||
"cohere-v3": cohere_embedding
|
||||
},
|
||||
payload={"content": "..."}
|
||||
)
|
||||
|
||||
# Search specific vector
|
||||
results = client.search(
|
||||
collection_name="documentation",
|
||||
query_vector=("text-ada-002", query_embedding),
|
||||
limit=5
|
||||
)
|
||||
```
|
||||
|
||||
### 2. Scroll API for Large Result Sets
|
||||
|
||||
```python
|
||||
# Retrieve all points matching filter (pagination)
|
||||
offset = None
|
||||
all_results = []
|
||||
|
||||
while True:
|
||||
results = client.scroll(
|
||||
collection_name="documentation",
|
||||
scroll_filter=Filter(
|
||||
must=[FieldCondition(key="category", match=MatchValue(value="api"))]
|
||||
),
|
||||
limit=100,
|
||||
offset=offset
|
||||
)
|
||||
|
||||
points, next_offset = results
|
||||
all_results.extend(points)
|
||||
|
||||
if next_offset is None:
|
||||
break
|
||||
offset = next_offset
|
||||
|
||||
print(f"Retrieved {len(all_results)} total points")
|
||||
```
|
||||
|
||||
### 3. Snapshot and Backup
|
||||
|
||||
```python
|
||||
# Create snapshot
|
||||
snapshot_info = client.create_snapshot(collection_name="documentation")
|
||||
snapshot_name = snapshot_info.name
|
||||
|
||||
print(f"Created snapshot: {snapshot_name}")
|
||||
|
||||
# Download snapshot
|
||||
client.download_snapshot(
|
||||
collection_name="documentation",
|
||||
snapshot_name=snapshot_name,
|
||||
output_path=f"./backups/{snapshot_name}"
|
||||
)
|
||||
|
||||
# Restore from snapshot
|
||||
client.restore_snapshot(
|
||||
collection_name="documentation",
|
||||
snapshot_path=f"./backups/{snapshot_name}"
|
||||
)
|
||||
```
|
||||
|
||||
### 4. Clustering and Sharding
|
||||
|
||||
```python
|
||||
# Create collection with sharding
|
||||
from qdrant_client.models import ShardingMethod
|
||||
|
||||
client.recreate_collection(
|
||||
collection_name="large_docs",
|
||||
vectors_config=VectorParams(size=1536, distance=Distance.COSINE),
|
||||
shard_number=4, # Distribute across 4 shards
|
||||
sharding_method=ShardingMethod.AUTO
|
||||
)
|
||||
|
||||
# Points automatically distributed across shards
|
||||
```
|
||||
|
||||
### 5. Recommendation API
|
||||
|
||||
```python
|
||||
# Find similar documents to existing ones
|
||||
results = client.recommend(
|
||||
collection_name="documentation",
|
||||
positive=[1, 5, 10], # Point IDs to find similar to
|
||||
negative=[15], # Point IDs to avoid
|
||||
limit=5
|
||||
)
|
||||
|
||||
# Recommend with filters
|
||||
results = client.recommend(
|
||||
collection_name="documentation",
|
||||
positive=[1, 5, 10],
|
||||
limit=5,
|
||||
query_filter=Filter(
|
||||
must=[FieldCondition(key="category", match=MatchValue(value="hooks"))]
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 Best Practices
|
||||
|
||||
### 1. Create Payload Indexes for Frequent Filters
|
||||
|
||||
```python
|
||||
# Index fields you filter on frequently
|
||||
client.create_payload_index(
|
||||
collection_name="documentation",
|
||||
field_name="category",
|
||||
field_schema=PayloadSchemaType.KEYWORD
|
||||
)
|
||||
|
||||
# Dramatically speeds up filtered search
|
||||
# Before: 500ms, After: 10ms
|
||||
```
|
||||
|
||||
### 2. Choose the Right Distance Metric
|
||||
|
||||
```python
|
||||
# Cosine: Best for normalized embeddings (OpenAI, Cohere)
|
||||
vectors_config=VectorParams(size=1536, distance=Distance.COSINE)
|
||||
|
||||
# Euclidean: For absolute distances
|
||||
vectors_config=VectorParams(size=1536, distance=Distance.EUCLID)
|
||||
|
||||
# Dot Product: For unnormalized vectors
|
||||
vectors_config=VectorParams(size=1536, distance=Distance.DOT)
|
||||
|
||||
# Recommendation: Use COSINE for most cases
|
||||
```
|
||||
|
||||
### 3. Use Batch Upsert for Performance
|
||||
|
||||
```python
|
||||
# ✅ Good: Batch upsert (100-1000 points)
|
||||
points = [...] # 100 points
|
||||
client.upsert(collection_name="docs", points=points)
|
||||
|
||||
# ❌ Bad: One at a time (slow!)
|
||||
for point in points:
|
||||
client.upsert(collection_name="docs", points=[point])
|
||||
|
||||
# Batch is 10-100x faster
|
||||
```
|
||||
|
||||
### 4. Monitor Collection Stats
|
||||
|
||||
```python
|
||||
# Get collection info
|
||||
info = client.get_collection("documentation")
|
||||
print(f"Points: {info.points_count}")
|
||||
print(f"Vectors: {info.vectors_count}")
|
||||
print(f"Indexed: {info.indexed_vectors_count}")
|
||||
print(f"Status: {info.status}")
|
||||
|
||||
# Check cluster info
|
||||
cluster_info = client.get_cluster_info()
|
||||
print(f"Peers: {len(cluster_info.peers)}")
|
||||
```
|
||||
|
||||
### 5. Use Wait Parameter for Consistency
|
||||
|
||||
```python
|
||||
# Ensure point is indexed before returning
|
||||
from qdrant_client.models import UpdateStatus
|
||||
|
||||
result = client.upsert(
|
||||
collection_name="documentation",
|
||||
points=points,
|
||||
wait=True # Wait until indexed
|
||||
)
|
||||
|
||||
assert result.status == UpdateStatus.COMPLETED
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔥 Real-World Example: Multi-Tenant Documentation System
|
||||
|
||||
```python
|
||||
import json
|
||||
from qdrant_client import QdrantClient
|
||||
from qdrant_client.models import Distance, VectorParams, PointStruct, Filter, FieldCondition, MatchValue
|
||||
from openai import OpenAI
|
||||
|
||||
class MultiTenantDocsSystem:
|
||||
def __init__(self, qdrant_url: str = "http://localhost:6333"):
|
||||
"""Initialize multi-tenant documentation system."""
|
||||
self.client = QdrantClient(url=qdrant_url)
|
||||
self.openai = OpenAI()
|
||||
|
||||
def create_tenant_collection(self, tenant: str):
|
||||
"""Create collection for a tenant."""
|
||||
collection_name = f"docs_{tenant}"
|
||||
|
||||
self.client.recreate_collection(
|
||||
collection_name=collection_name,
|
||||
vectors_config=VectorParams(size=1536, distance=Distance.COSINE)
|
||||
)
|
||||
|
||||
# Create indexes for common filters
|
||||
for field in ["category", "source", "type"]:
|
||||
self.client.create_payload_index(
|
||||
collection_name=collection_name,
|
||||
field_name=field,
|
||||
field_schema="keyword"
|
||||
)
|
||||
|
||||
print(f"✅ Created collection for tenant: {tenant}")
|
||||
|
||||
def ingest_tenant_docs(self, tenant: str, docs_path: str):
|
||||
"""Ingest documentation for a tenant."""
|
||||
collection_name = f"docs_{tenant}"
|
||||
|
||||
with open(docs_path) as f:
|
||||
documents = json.load(f)
|
||||
|
||||
# Batch upload
|
||||
batch_size = 100
|
||||
for i in range(0, len(documents), batch_size):
|
||||
batch = documents[i:i + batch_size]
|
||||
points = []
|
||||
|
||||
for j, doc in enumerate(batch):
|
||||
# Generate embedding
|
||||
response = self.openai.embeddings.create(
|
||||
model="text-embedding-ada-002",
|
||||
input=doc["page_content"]
|
||||
)
|
||||
|
||||
points.append(PointStruct(
|
||||
id=i + j,
|
||||
vector=response.data[0].embedding,
|
||||
payload={
|
||||
"content": doc["page_content"],
|
||||
"tenant": tenant,
|
||||
**doc["metadata"]
|
||||
}
|
||||
))
|
||||
|
||||
self.client.upsert(
|
||||
collection_name=collection_name,
|
||||
points=points,
|
||||
wait=True
|
||||
)
|
||||
|
||||
print(f"✅ Ingested {len(documents)} docs for {tenant}")
|
||||
|
||||
def query_tenant(self, tenant: str, question: str, category: str = None):
|
||||
"""Query specific tenant's documentation."""
|
||||
collection_name = f"docs_{tenant}"
|
||||
|
||||
# Generate query embedding
|
||||
response = self.openai.embeddings.create(
|
||||
model="text-embedding-ada-002",
|
||||
input=question
|
||||
)
|
||||
query_embedding = response.data[0].embedding
|
||||
|
||||
# Build filter
|
||||
query_filter = None
|
||||
if category:
|
||||
query_filter = Filter(
|
||||
must=[FieldCondition(key="category", match=MatchValue(value=category))]
|
||||
)
|
||||
|
||||
# Search
|
||||
results = self.client.search(
|
||||
collection_name=collection_name,
|
||||
query_vector=query_embedding,
|
||||
limit=5,
|
||||
query_filter=query_filter
|
||||
)
|
||||
|
||||
# Build context
|
||||
context = "\n\n".join([r.payload["content"][:500] for r in results])
|
||||
|
||||
# Generate answer
|
||||
completion = self.openai.chat.completions.create(
|
||||
model="gpt-4",
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": f"You are a helpful assistant for {tenant} documentation."
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": f"Context:\n{context}\n\nQuestion: {question}"
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
return {
|
||||
"answer": completion.choices[0].message.content,
|
||||
"sources": [
|
||||
{
|
||||
"category": r.payload["category"],
|
||||
"score": r.score
|
||||
}
|
||||
for r in results
|
||||
]
|
||||
}
|
||||
|
||||
def cross_tenant_search(self, question: str, tenants: list[str]):
|
||||
"""Search across multiple tenants."""
|
||||
all_results = {}
|
||||
|
||||
for tenant in tenants:
|
||||
try:
|
||||
result = self.query_tenant(tenant, question)
|
||||
all_results[tenant] = result["answer"]
|
||||
except Exception as e:
|
||||
all_results[tenant] = f"Error: {e}"
|
||||
|
||||
return all_results
|
||||
|
||||
# Usage
|
||||
system = MultiTenantDocsSystem()
|
||||
|
||||
# Set up tenants
|
||||
tenants = ["react", "vue", "angular"]
|
||||
for tenant in tenants:
|
||||
system.create_tenant_collection(tenant)
|
||||
system.ingest_tenant_docs(tenant, f"output/{tenant}-langchain.json")
|
||||
|
||||
# Query specific tenant
|
||||
result = system.query_tenant("react", "How do I use hooks?", category="hooks")
|
||||
print(f"React Answer: {result['answer']}")
|
||||
|
||||
# Cross-tenant search
|
||||
comparison = system.cross_tenant_search(
|
||||
question="How do I handle state?",
|
||||
tenants=["react", "vue", "angular"]
|
||||
)
|
||||
|
||||
for tenant, answer in comparison.items():
|
||||
print(f"\n{tenant.upper()}:")
|
||||
print(answer[:200] + "...")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Issue: Connection Refused
|
||||
|
||||
**Problem:** "Connection refused at http://localhost:6333"
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. **Check Qdrant is running:**
|
||||
```bash
|
||||
curl http://localhost:6333/healthz
|
||||
docker ps | grep qdrant
|
||||
```
|
||||
|
||||
2. **Verify ports:**
|
||||
```bash
|
||||
# API: 6333, gRPC: 6334
|
||||
lsof -i :6333
|
||||
```
|
||||
|
||||
3. **Check Docker logs:**
|
||||
```bash
|
||||
docker logs <qdrant-container-id>
|
||||
```
|
||||
|
||||
### Issue: Point Upload Failed
|
||||
|
||||
**Problem:** "Point with id X already exists"
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. **Use upsert instead of upload:**
|
||||
```python
|
||||
# Upsert replaces existing points
|
||||
client.upsert(collection_name="docs", points=points)
|
||||
```
|
||||
|
||||
2. **Delete and recreate:**
|
||||
```python
|
||||
client.delete_collection("docs")
|
||||
client.recreate_collection(...)
|
||||
```
|
||||
|
||||
### Issue: Slow Filtered Search
|
||||
|
||||
**Problem:** Filtered queries take >1 second
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. **Create payload index:**
|
||||
```python
|
||||
client.create_payload_index(
|
||||
collection_name="docs",
|
||||
field_name="category",
|
||||
field_schema="keyword"
|
||||
)
|
||||
```
|
||||
|
||||
2. **Check index status:**
|
||||
```python
|
||||
info = client.get_collection("docs")
|
||||
print(f"Indexed: {info.indexed_vectors_count}/{info.points_count}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Before vs. After
|
||||
|
||||
| Aspect | Without Skill Seekers | With Skill Seekers |
|
||||
|--------|----------------------|-------------------|
|
||||
| **Data Preparation** | Custom scraping + parsing logic | One command: `skill-seekers create` |
|
||||
| **Collection Setup** | Manual vector config + payload schema | Standard LangChain format |
|
||||
| **Metadata** | Manual extraction from docs | Auto-extracted (category, source, file, type) |
|
||||
| **Payload Filtering** | Complex filter construction | Consistent metadata keys |
|
||||
| **Performance** | 10K+ QPS (Rust engine) | 10K+ QPS (same, but easier setup) |
|
||||
| **Setup Time** | 3-5 hours | 10 minutes |
|
||||
| **Code Required** | 400+ lines | 30 lines upload script |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Next Steps
|
||||
|
||||
### Related Guides
|
||||
|
||||
- **[Weaviate Integration](WEAVIATE.md)** - Alternative vector database
|
||||
- **[RAG Pipelines Guide](RAG_PIPELINES.md)** - Build complete RAG systems
|
||||
- **[Multi-LLM Support](MULTI_LLM_SUPPORT.md)** - Use different embedding models
|
||||
- **[INTEGRATIONS.md](INTEGRATIONS.md)** - See all integration options
|
||||
|
||||
### Resources
|
||||
|
||||
- **Qdrant Docs:** https://qdrant.tech/documentation/
|
||||
- **Python Client:** https://qdrant.tech/documentation/quick-start/
|
||||
- **Support:** https://github.com/yusufkaraaslan/Skill_Seekers/discussions
|
||||
|
||||
---
|
||||
|
||||
**Questions?** Open an issue: https://github.com/yusufkaraaslan/Skill_Seekers/issues
|
||||
**Website:** https://skillseekersweb.com/
|
||||
**Last Updated:** February 7, 2026
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,993 @@
|
||||
# Weaviate Integration with Skill Seekers
|
||||
|
||||
**Status:** ✅ Production Ready
|
||||
**Difficulty:** Intermediate
|
||||
**Last Updated:** February 7, 2026
|
||||
|
||||
---
|
||||
|
||||
## ❌ The Problem
|
||||
|
||||
Building RAG applications with Weaviate involves several challenges:
|
||||
|
||||
1. **Manual Data Schema Design** - Need to define GraphQL schemas and object properties manually for each documentation project
|
||||
2. **Complex Hybrid Search** - Setting up both BM25 keyword search and vector search requires understanding Weaviate's query language
|
||||
3. **Multi-Tenancy Configuration** - Properly isolating different documentation sets requires tenant management
|
||||
|
||||
**Example Pain Point:**
|
||||
|
||||
```python
|
||||
# Manual schema creation for each framework
|
||||
client.schema.create_class({
|
||||
"class": "ReactDocs",
|
||||
"properties": [
|
||||
{"name": "content", "dataType": ["text"]},
|
||||
{"name": "category", "dataType": ["string"]},
|
||||
{"name": "source", "dataType": ["string"]},
|
||||
# ... 10+ more properties
|
||||
],
|
||||
"vectorizer": "text2vec-openai",
|
||||
"moduleConfig": {
|
||||
"text2vec-openai": {"model": "ada-002"}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ The Solution
|
||||
|
||||
Skill Seekers automates Weaviate integration with structured, production-ready data:
|
||||
|
||||
**Benefits:**
|
||||
- ✅ Auto-formatted objects with all metadata properties
|
||||
- ✅ Consistent schema across all frameworks
|
||||
- ✅ Compatible with hybrid search (BM25 + vector)
|
||||
- ✅ Works with Weaviate Cloud Services (WCS) and self-hosted
|
||||
- ✅ Supports multi-tenancy for documentation isolation
|
||||
|
||||
**Result:** 10-minute setup, production-ready vector search with enterprise features.
|
||||
|
||||
---
|
||||
|
||||
## ⚡ Quick Start (5 Minutes)
|
||||
|
||||
### Prerequisites
|
||||
|
||||
```bash
|
||||
# Install Weaviate Python client
|
||||
pip install weaviate-client>=3.25.0
|
||||
|
||||
# Or with Skill Seekers
|
||||
pip install skill-seekers[all-llms]
|
||||
```
|
||||
|
||||
**What you need:**
|
||||
- Weaviate instance (WCS or self-hosted)
|
||||
- Weaviate API key (if using WCS)
|
||||
- OpenAI API key (for embeddings)
|
||||
|
||||
### Generate Weaviate-Ready Documents
|
||||
|
||||
```bash
|
||||
# Step 1: Scrape documentation
|
||||
skill-seekers create --config configs/react.json
|
||||
|
||||
# Step 2: Package for Weaviate (creates LangChain format)
|
||||
skill-seekers package output/react --target langchain
|
||||
|
||||
# Output: output/react-langchain.json (Weaviate-compatible)
|
||||
```
|
||||
|
||||
### Upload to Weaviate
|
||||
|
||||
```python
|
||||
import weaviate
|
||||
import json
|
||||
|
||||
# Connect to Weaviate
|
||||
client = weaviate.Client(
|
||||
url="https://your-instance.weaviate.network",
|
||||
auth_client_secret=weaviate.AuthApiKey(api_key="your-api-key"),
|
||||
additional_headers={
|
||||
"X-OpenAI-Api-Key": "your-openai-key"
|
||||
}
|
||||
)
|
||||
|
||||
# Create schema (first time only)
|
||||
client.schema.create_class({
|
||||
"class": "Documentation",
|
||||
"vectorizer": "text2vec-openai",
|
||||
"moduleConfig": {
|
||||
"text2vec-openai": {"model": "ada-002"}
|
||||
}
|
||||
})
|
||||
|
||||
# Load documents
|
||||
with open("output/react-langchain.json") as f:
|
||||
documents = json.load(f)
|
||||
|
||||
# Batch upload
|
||||
with client.batch as batch:
|
||||
for i, doc in enumerate(documents):
|
||||
properties = {
|
||||
"content": doc["page_content"],
|
||||
"source": doc["metadata"]["source"],
|
||||
"category": doc["metadata"]["category"],
|
||||
"file": doc["metadata"]["file"],
|
||||
"type": doc["metadata"]["type"]
|
||||
}
|
||||
batch.add_data_object(properties, "Documentation")
|
||||
|
||||
if (i + 1) % 100 == 0:
|
||||
print(f"Uploaded {i + 1} documents...")
|
||||
|
||||
print(f"✅ Uploaded {len(documents)} documents to Weaviate")
|
||||
```
|
||||
|
||||
### Query with Hybrid Search
|
||||
|
||||
```python
|
||||
# Hybrid search: BM25 + vector similarity
|
||||
result = client.query.get("Documentation", ["content", "category"]) \
|
||||
.with_hybrid(
|
||||
query="How do I use React hooks?",
|
||||
alpha=0.75 # 0=BM25 only, 1=vector only, 0.5=balanced
|
||||
) \
|
||||
.with_limit(3) \
|
||||
.do()
|
||||
|
||||
for item in result["data"]["Get"]["Documentation"]:
|
||||
print(f"Category: {item['category']}")
|
||||
print(f"Content: {item['content'][:200]}...")
|
||||
print()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📖 Detailed Setup Guide
|
||||
|
||||
### Step 1: Set Up Weaviate Instance
|
||||
|
||||
**Option A: Weaviate Cloud Services (Recommended)**
|
||||
|
||||
1. Sign up at [console.weaviate.cloud](https://console.weaviate.cloud)
|
||||
2. Create a cluster (free tier available)
|
||||
3. Get your API endpoint and API key
|
||||
4. Note your cluster URL: `https://your-cluster.weaviate.network`
|
||||
|
||||
**Option B: Self-Hosted (Docker)**
|
||||
|
||||
```bash
|
||||
# docker-compose.yml
|
||||
version: '3.4'
|
||||
services:
|
||||
weaviate:
|
||||
image: semitechnologies/weaviate:latest
|
||||
ports:
|
||||
- "8080:8080"
|
||||
environment:
|
||||
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'true'
|
||||
PERSISTENCE_DATA_PATH: '/var/lib/weaviate'
|
||||
DEFAULT_VECTORIZER_MODULE: 'text2vec-openai'
|
||||
ENABLE_MODULES: 'text2vec-openai'
|
||||
OPENAI_APIKEY: 'your-openai-key'
|
||||
volumes:
|
||||
- ./weaviate-data:/var/lib/weaviate
|
||||
|
||||
# Start Weaviate
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
**Option C: Kubernetes (Production)**
|
||||
|
||||
```bash
|
||||
helm repo add weaviate https://weaviate.github.io/weaviate-helm
|
||||
helm install weaviate weaviate/weaviate \
|
||||
--set modules.text2vec-openai.enabled=true \
|
||||
--set env.OPENAI_APIKEY=your-key
|
||||
```
|
||||
|
||||
### Step 2: Generate Skill Seekers Documents
|
||||
|
||||
**Option A: Documentation Website**
|
||||
```bash
|
||||
skill-seekers create --config configs/django.json
|
||||
skill-seekers package output/django --target langchain
|
||||
```
|
||||
|
||||
**Option B: GitHub Repository**
|
||||
```bash
|
||||
skill-seekers create django/django --name django
|
||||
skill-seekers package output/django --target langchain
|
||||
```
|
||||
|
||||
**Option C: Local Codebase**
|
||||
```bash
|
||||
skill-seekers scan /path/to/repo
|
||||
skill-seekers package output/codebase --target langchain
|
||||
```
|
||||
|
||||
**Option D: RAG-Optimized Chunking**
|
||||
```bash
|
||||
skill-seekers create --config configs/fastapi.json --chunk-for-rag --chunk-tokens 512
|
||||
skill-seekers package output/fastapi --target langchain
|
||||
```
|
||||
|
||||
### Step 3: Create Weaviate Schema
|
||||
|
||||
```python
|
||||
import weaviate
|
||||
|
||||
client = weaviate.Client(
|
||||
url="https://your-instance.weaviate.network",
|
||||
auth_client_secret=weaviate.AuthApiKey(api_key="your-api-key"),
|
||||
additional_headers={
|
||||
"X-OpenAI-Api-Key": "your-openai-key"
|
||||
}
|
||||
)
|
||||
|
||||
# Define schema with all Skill Seekers metadata
|
||||
schema = {
|
||||
"class": "Documentation",
|
||||
"description": "Framework documentation from Skill Seekers",
|
||||
"vectorizer": "text2vec-openai",
|
||||
"moduleConfig": {
|
||||
"text2vec-openai": {
|
||||
"model": "ada-002",
|
||||
"vectorizeClassName": False
|
||||
}
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"name": "content",
|
||||
"dataType": ["text"],
|
||||
"description": "Documentation content",
|
||||
"moduleConfig": {
|
||||
"text2vec-openai": {"skip": False}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "source",
|
||||
"dataType": ["string"],
|
||||
"description": "Framework name"
|
||||
},
|
||||
{
|
||||
"name": "category",
|
||||
"dataType": ["string"],
|
||||
"description": "Documentation category"
|
||||
},
|
||||
{
|
||||
"name": "file",
|
||||
"dataType": ["string"],
|
||||
"description": "Source file"
|
||||
},
|
||||
{
|
||||
"name": "type",
|
||||
"dataType": ["string"],
|
||||
"description": "Document type"
|
||||
},
|
||||
{
|
||||
"name": "url",
|
||||
"dataType": ["string"],
|
||||
"description": "Original URL"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# Create class (idempotent)
|
||||
try:
|
||||
client.schema.create_class(schema)
|
||||
print("✅ Schema created")
|
||||
except Exception as e:
|
||||
print(f"Schema already exists or error: {e}")
|
||||
```
|
||||
|
||||
### Step 4: Batch Upload Documents
|
||||
|
||||
```python
|
||||
import json
|
||||
from weaviate.util import generate_uuid5
|
||||
|
||||
# Load documents
|
||||
with open("output/django-langchain.json") as f:
|
||||
documents = json.load(f)
|
||||
|
||||
# Configure batch
|
||||
client.batch.configure(
|
||||
batch_size=100,
|
||||
dynamic=True,
|
||||
timeout_retries=3,
|
||||
)
|
||||
|
||||
# Upload with batch
|
||||
with client.batch as batch:
|
||||
for i, doc in enumerate(documents):
|
||||
properties = {
|
||||
"content": doc["page_content"],
|
||||
"source": doc["metadata"]["source"],
|
||||
"category": doc["metadata"]["category"],
|
||||
"file": doc["metadata"]["file"],
|
||||
"type": doc["metadata"]["type"],
|
||||
"url": doc["metadata"].get("url", "")
|
||||
}
|
||||
|
||||
# Generate deterministic UUID
|
||||
uuid = generate_uuid5(properties["content"])
|
||||
|
||||
batch.add_data_object(
|
||||
data_object=properties,
|
||||
class_name="Documentation",
|
||||
uuid=uuid
|
||||
)
|
||||
|
||||
if (i + 1) % 100 == 0:
|
||||
print(f"Uploaded {i + 1}/{len(documents)} documents...")
|
||||
|
||||
print(f"✅ Uploaded {len(documents)} documents to Weaviate")
|
||||
|
||||
# Verify upload
|
||||
result = client.query.aggregate("Documentation").with_meta_count().do()
|
||||
count = result["data"]["Aggregate"]["Documentation"][0]["meta"]["count"]
|
||||
print(f"Total documents in Weaviate: {count}")
|
||||
```
|
||||
|
||||
### Step 5: Query with Filters
|
||||
|
||||
```python
|
||||
# Hybrid search with category filter
|
||||
result = client.query.get("Documentation", ["content", "category", "source"]) \
|
||||
.with_hybrid(
|
||||
query="How do I create a Django model?",
|
||||
alpha=0.75
|
||||
) \
|
||||
.with_where({
|
||||
"path": ["category"],
|
||||
"operator": "Equal",
|
||||
"valueString": "models"
|
||||
}) \
|
||||
.with_limit(5) \
|
||||
.do()
|
||||
|
||||
for item in result["data"]["Get"]["Documentation"]:
|
||||
print(f"Source: {item['source']}")
|
||||
print(f"Category: {item['category']}")
|
||||
print(f"Content: {item['content'][:200]}...")
|
||||
print()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Advanced Usage
|
||||
|
||||
### 1. Multi-Tenancy for Framework Isolation
|
||||
|
||||
```python
|
||||
# Enable multi-tenancy on schema
|
||||
client.schema.update_config("Documentation", {
|
||||
"multiTenancyConfig": {"enabled": True}
|
||||
})
|
||||
|
||||
# Add tenants
|
||||
client.schema.add_class_tenants(
|
||||
class_name="Documentation",
|
||||
tenants=[
|
||||
{"name": "react"},
|
||||
{"name": "django"},
|
||||
{"name": "fastapi"}
|
||||
]
|
||||
)
|
||||
|
||||
# Upload to specific tenant
|
||||
with client.batch as batch:
|
||||
batch.add_data_object(
|
||||
data_object={"content": "...", "category": "hooks"},
|
||||
class_name="Documentation",
|
||||
tenant="react"
|
||||
)
|
||||
|
||||
# Query specific tenant
|
||||
result = client.query.get("Documentation", ["content"]) \
|
||||
.with_tenant("react") \
|
||||
.with_hybrid(query="React hooks") \
|
||||
.do()
|
||||
```
|
||||
|
||||
### 2. Named Vectors for Multiple Embeddings
|
||||
|
||||
```python
|
||||
# Schema with multiple vector spaces
|
||||
schema = {
|
||||
"class": "Documentation",
|
||||
"vectorizer": "text2vec-openai",
|
||||
"vectorConfig": {
|
||||
"content": {
|
||||
"vectorizer": {
|
||||
"text2vec-openai": {"model": "ada-002"}
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"vectorizer": {
|
||||
"text2vec-openai": {"model": "ada-002"}
|
||||
}
|
||||
}
|
||||
},
|
||||
"properties": [
|
||||
{"name": "content", "dataType": ["text"]},
|
||||
{"name": "title", "dataType": ["string"]}
|
||||
]
|
||||
}
|
||||
|
||||
# Query specific vector
|
||||
result = client.query.get("Documentation", ["content", "title"]) \
|
||||
.with_near_text({"concepts": ["authentication"]}, target_vector="content") \
|
||||
.do()
|
||||
```
|
||||
|
||||
### 3. Generative Search (RAG in Weaviate)
|
||||
|
||||
```python
|
||||
# Answer questions using Weaviate's generative module
|
||||
result = client.query.get("Documentation", ["content", "category"]) \
|
||||
.with_hybrid(query="How do I use Django middleware?") \
|
||||
.with_generate(
|
||||
single_prompt="Explain this concept: {content}",
|
||||
grouped_task="Summarize Django middleware based on these docs"
|
||||
) \
|
||||
.with_limit(3) \
|
||||
.do()
|
||||
|
||||
# Access generated answer
|
||||
answer = result["data"]["Get"]["Documentation"][0]["_additional"]["generate"]["singleResult"]
|
||||
print(f"Generated Answer: {answer}")
|
||||
```
|
||||
|
||||
### 4. GraphQL Cross-References
|
||||
|
||||
```python
|
||||
# Create relationships between documentation
|
||||
schema = {
|
||||
"class": "Documentation",
|
||||
"properties": [
|
||||
{"name": "content", "dataType": ["text"]},
|
||||
{"name": "relatedTo", "dataType": ["Documentation"]} # Cross-reference
|
||||
]
|
||||
}
|
||||
|
||||
# Link related docs
|
||||
client.data_object.reference.add(
|
||||
from_class_name="Documentation",
|
||||
from_uuid=doc1_uuid,
|
||||
from_property_name="relatedTo",
|
||||
to_class_name="Documentation",
|
||||
to_uuid=doc2_uuid
|
||||
)
|
||||
|
||||
# Query with references
|
||||
result = client.query.get("Documentation", ["content", "relatedTo {... on Documentation {content}}"]) \
|
||||
.with_hybrid(query="React hooks") \
|
||||
.do()
|
||||
```
|
||||
|
||||
### 5. Backup and Restore
|
||||
|
||||
```python
|
||||
# Backup all data
|
||||
backup_name = "docs-backup-2026-02-07"
|
||||
result = client.backup.create(
|
||||
backup_id=backup_name,
|
||||
backend="filesystem",
|
||||
include_classes=["Documentation"]
|
||||
)
|
||||
|
||||
# Wait for completion
|
||||
status = client.backup.get_create_status(backup_id=backup_name, backend="filesystem")
|
||||
print(f"Backup status: {status['status']}")
|
||||
|
||||
# Restore from backup
|
||||
result = client.backup.restore(
|
||||
backup_id=backup_name,
|
||||
backend="filesystem",
|
||||
include_classes=["Documentation"]
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 Best Practices
|
||||
|
||||
### 1. Choose the Right Alpha Value
|
||||
|
||||
```python
|
||||
# Alpha controls BM25 vs vector balance
|
||||
# 0.0 = Pure BM25 (keyword matching)
|
||||
# 1.0 = Pure vector (semantic search)
|
||||
# 0.75 = Recommended (75% semantic, 25% keyword)
|
||||
|
||||
# For exact terms (API names, functions)
|
||||
result = client.query.get(...).with_hybrid(query="useState", alpha=0.3).do()
|
||||
|
||||
# For conceptual queries
|
||||
result = client.query.get(...).with_hybrid(query="state management", alpha=0.9).do()
|
||||
|
||||
# Balanced (recommended default)
|
||||
result = client.query.get(...).with_hybrid(query="React hooks", alpha=0.75).do()
|
||||
```
|
||||
|
||||
### 2. Use Tenant Isolation for Multi-Framework
|
||||
|
||||
```python
|
||||
# Separate tenants prevent cross-contamination
|
||||
tenants = ["react", "vue", "angular", "svelte"]
|
||||
|
||||
for tenant in tenants:
|
||||
client.schema.add_class_tenants("Documentation", [{"name": tenant}])
|
||||
|
||||
# Query only React docs
|
||||
result = client.query.get("Documentation", ["content"]) \
|
||||
.with_tenant("react") \
|
||||
.with_hybrid(query="components") \
|
||||
.do()
|
||||
```
|
||||
|
||||
### 3. Monitor Performance
|
||||
|
||||
```python
|
||||
# Check cluster health
|
||||
health = client.cluster.get_nodes_status()
|
||||
print(f"Nodes: {len(health)}")
|
||||
for node in health:
|
||||
print(f" {node['name']}: {node['status']}")
|
||||
|
||||
# Monitor query performance
|
||||
import time
|
||||
start = time.time()
|
||||
result = client.query.get("Documentation", ["content"]).with_limit(10).do()
|
||||
latency = time.time() - start
|
||||
print(f"Query latency: {latency*1000:.2f}ms")
|
||||
|
||||
# Check object count
|
||||
stats = client.query.aggregate("Documentation").with_meta_count().do()
|
||||
count = stats["data"]["Aggregate"]["Documentation"][0]["meta"]["count"]
|
||||
print(f"Total objects: {count}")
|
||||
```
|
||||
|
||||
### 4. Handle Updates Efficiently
|
||||
|
||||
```python
|
||||
from weaviate.util import generate_uuid5
|
||||
|
||||
# Update existing object (idempotent UUID)
|
||||
uuid = generate_uuid5("unique-content-identifier")
|
||||
client.data_object.replace(
|
||||
data_object={"content": "updated content", ...},
|
||||
class_name="Documentation",
|
||||
uuid=uuid
|
||||
)
|
||||
|
||||
# Delete obsolete objects
|
||||
client.data_object.delete(uuid=uuid, class_name="Documentation")
|
||||
|
||||
# Delete by filter
|
||||
client.batch.delete_objects(
|
||||
class_name="Documentation",
|
||||
where={
|
||||
"path": ["category"],
|
||||
"operator": "Equal",
|
||||
"valueString": "deprecated"
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
### 5. Use Async for Large Uploads
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from weaviate import Client
|
||||
|
||||
async def upload_batch(client, documents, start_idx, batch_size):
|
||||
"""Upload documents asynchronously."""
|
||||
with client.batch as batch:
|
||||
for i in range(start_idx, min(start_idx + batch_size, len(documents))):
|
||||
doc = documents[i]
|
||||
properties = {
|
||||
"content": doc["page_content"],
|
||||
**doc["metadata"]
|
||||
}
|
||||
batch.add_data_object(properties, "Documentation")
|
||||
|
||||
async def upload_all(documents, batch_size=100):
|
||||
client = Client(url="...", auth_client_secret=...)
|
||||
|
||||
tasks = []
|
||||
for i in range(0, len(documents), batch_size):
|
||||
tasks.append(upload_batch(client, documents, i, batch_size))
|
||||
|
||||
await asyncio.gather(*tasks)
|
||||
print(f"✅ Uploaded {len(documents)} documents")
|
||||
|
||||
# Usage
|
||||
asyncio.run(upload_all(documents))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔥 Real-World Example: Multi-Framework Documentation Bot
|
||||
|
||||
```python
|
||||
import weaviate
|
||||
import json
|
||||
from openai import OpenAI
|
||||
|
||||
class MultiFrameworkBot:
|
||||
def __init__(self, weaviate_url: str, weaviate_key: str, openai_key: str):
|
||||
self.weaviate = weaviate.Client(
|
||||
url=weaviate_url,
|
||||
auth_client_secret=weaviate.AuthApiKey(api_key=weaviate_key),
|
||||
additional_headers={"X-OpenAI-Api-Key": openai_key}
|
||||
)
|
||||
self.openai = OpenAI(api_key=openai_key)
|
||||
|
||||
def setup_tenants(self, frameworks: list[str]):
|
||||
"""Set up multi-tenancy for frameworks."""
|
||||
# Enable multi-tenancy
|
||||
self.weaviate.schema.update_config("Documentation", {
|
||||
"multiTenancyConfig": {"enabled": True}
|
||||
})
|
||||
|
||||
# Add tenants
|
||||
tenants = [{"name": fw} for fw in frameworks]
|
||||
self.weaviate.schema.add_class_tenants("Documentation", tenants)
|
||||
print(f"✅ Set up tenants: {frameworks}")
|
||||
|
||||
def ingest_framework(self, framework: str, docs_path: str):
|
||||
"""Ingest documentation for specific framework."""
|
||||
with open(docs_path) as f:
|
||||
documents = json.load(f)
|
||||
|
||||
with self.weaviate.batch as batch:
|
||||
batch.configure(batch_size=100)
|
||||
|
||||
for doc in documents:
|
||||
properties = {
|
||||
"content": doc["page_content"],
|
||||
"source": doc["metadata"]["source"],
|
||||
"category": doc["metadata"]["category"],
|
||||
"file": doc["metadata"]["file"],
|
||||
"type": doc["metadata"]["type"]
|
||||
}
|
||||
|
||||
batch.add_data_object(
|
||||
data_object=properties,
|
||||
class_name="Documentation",
|
||||
tenant=framework
|
||||
)
|
||||
|
||||
print(f"✅ Ingested {len(documents)} docs for {framework}")
|
||||
|
||||
def query_framework(self, framework: str, question: str, category: str = None):
|
||||
"""Query specific framework with hybrid search."""
|
||||
# Build query
|
||||
query = self.weaviate.query.get("Documentation", ["content", "category", "source"]) \
|
||||
.with_tenant(framework) \
|
||||
.with_hybrid(query=question, alpha=0.75)
|
||||
|
||||
# Add category filter if specified
|
||||
if category:
|
||||
query = query.with_where({
|
||||
"path": ["category"],
|
||||
"operator": "Equal",
|
||||
"valueString": category
|
||||
})
|
||||
|
||||
result = query.with_limit(3).do()
|
||||
|
||||
# Extract context
|
||||
docs = result["data"]["Get"]["Documentation"]
|
||||
context = "\n\n".join([doc["content"][:500] for doc in docs])
|
||||
|
||||
# Generate answer
|
||||
completion = self.openai.chat.completions.create(
|
||||
model="gpt-4",
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": f"You are an expert in {framework}. Answer based on the documentation."
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": f"Context:\n{context}\n\nQuestion: {question}"
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
return {
|
||||
"answer": completion.choices[0].message.content,
|
||||
"sources": [
|
||||
{
|
||||
"category": doc["category"],
|
||||
"source": doc["source"]
|
||||
}
|
||||
for doc in docs
|
||||
]
|
||||
}
|
||||
|
||||
def compare_frameworks(self, frameworks: list[str], question: str):
|
||||
"""Compare how different frameworks handle the same concept."""
|
||||
results = {}
|
||||
for framework in frameworks:
|
||||
try:
|
||||
result = self.query_framework(framework, question)
|
||||
results[framework] = result["answer"]
|
||||
except Exception as e:
|
||||
results[framework] = f"Error: {e}"
|
||||
|
||||
return results
|
||||
|
||||
# Usage
|
||||
bot = MultiFrameworkBot(
|
||||
weaviate_url="https://your-cluster.weaviate.network",
|
||||
weaviate_key="your-weaviate-key",
|
||||
openai_key="your-openai-key"
|
||||
)
|
||||
|
||||
# Set up tenants
|
||||
bot.setup_tenants(["react", "vue", "angular", "svelte"])
|
||||
|
||||
# Ingest documentation
|
||||
bot.ingest_framework("react", "output/react-langchain.json")
|
||||
bot.ingest_framework("vue", "output/vue-langchain.json")
|
||||
bot.ingest_framework("angular", "output/angular-langchain.json")
|
||||
bot.ingest_framework("svelte", "output/svelte-langchain.json")
|
||||
|
||||
# Query specific framework
|
||||
result = bot.query_framework("react", "How do I manage state?", category="hooks")
|
||||
print(f"React Answer: {result['answer']}")
|
||||
|
||||
# Compare frameworks
|
||||
comparison = bot.compare_frameworks(
|
||||
frameworks=["react", "vue", "angular", "svelte"],
|
||||
question="How do I handle user input?"
|
||||
)
|
||||
|
||||
for framework, answer in comparison.items():
|
||||
print(f"\n{framework.upper()}:")
|
||||
print(answer)
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
✅ Set up tenants: ['react', 'vue', 'angular', 'svelte']
|
||||
✅ Ingested 1247 docs for react
|
||||
✅ Ingested 892 docs for vue
|
||||
✅ Ingested 1534 docs for angular
|
||||
✅ Ingested 743 docs for svelte
|
||||
|
||||
React Answer: In React, you manage state using the useState hook...
|
||||
|
||||
REACT:
|
||||
Use the useState hook to create controlled components...
|
||||
|
||||
VUE:
|
||||
Vue provides v-model for two-way binding...
|
||||
|
||||
ANGULAR:
|
||||
Angular uses ngModel directive with FormsModule...
|
||||
|
||||
SVELTE:
|
||||
Svelte offers reactive declarations with bind:value...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Issue: Connection Failed
|
||||
|
||||
**Problem:** "Could not connect to Weaviate at http://localhost:8080"
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. **Check Weaviate is running:**
|
||||
```bash
|
||||
docker ps | grep weaviate
|
||||
curl http://localhost:8080/v1/meta
|
||||
```
|
||||
|
||||
2. **Verify URL format:**
|
||||
```python
|
||||
# Local: no https
|
||||
client = weaviate.Client("http://localhost:8080")
|
||||
|
||||
# WCS: use https
|
||||
client = weaviate.Client("https://your-cluster.weaviate.network")
|
||||
```
|
||||
|
||||
3. **Check authentication:**
|
||||
```python
|
||||
# WCS requires API key
|
||||
client = weaviate.Client(
|
||||
url="https://your-cluster.weaviate.network",
|
||||
auth_client_secret=weaviate.AuthApiKey(api_key="your-key")
|
||||
)
|
||||
```
|
||||
|
||||
### Issue: Schema Already Exists
|
||||
|
||||
**Problem:** "Class 'Documentation' already exists"
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. **Delete and recreate:**
|
||||
```python
|
||||
client.schema.delete_class("Documentation")
|
||||
client.schema.create_class(schema)
|
||||
```
|
||||
|
||||
2. **Update existing schema:**
|
||||
```python
|
||||
client.schema.add_class_properties("Documentation", new_properties)
|
||||
```
|
||||
|
||||
3. **Check existing schema:**
|
||||
```python
|
||||
existing = client.schema.get("Documentation")
|
||||
print(json.dumps(existing, indent=2))
|
||||
```
|
||||
|
||||
### Issue: Embedding API Key Not Set
|
||||
|
||||
**Problem:** "Vectorizer requires X-OpenAI-Api-Key header"
|
||||
|
||||
**Solution:**
|
||||
```python
|
||||
client = weaviate.Client(
|
||||
url="https://your-cluster.weaviate.network",
|
||||
additional_headers={
|
||||
"X-OpenAI-Api-Key": "sk-..." # OpenAI key
|
||||
# or "X-Cohere-Api-Key": "..."
|
||||
# or "X-HuggingFace-Api-Key": "..."
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
### Issue: Slow Batch Upload
|
||||
|
||||
**Problem:** Uploading 10,000 docs takes >10 minutes
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. **Enable dynamic batching:**
|
||||
```python
|
||||
client.batch.configure(
|
||||
batch_size=100,
|
||||
dynamic=True, # Auto-adjust batch size
|
||||
timeout_retries=3
|
||||
)
|
||||
```
|
||||
|
||||
2. **Use parallel batches:**
|
||||
```python
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
def upload_chunk(docs_chunk):
|
||||
with client.batch as batch:
|
||||
for doc in docs_chunk:
|
||||
batch.add_data_object(doc, "Documentation")
|
||||
|
||||
with ThreadPoolExecutor(max_workers=4) as executor:
|
||||
chunk_size = len(documents) // 4
|
||||
chunks = [documents[i:i+chunk_size] for i in range(0, len(documents), chunk_size)]
|
||||
executor.map(upload_chunk, chunks)
|
||||
```
|
||||
|
||||
### Issue: Hybrid Search Not Working
|
||||
|
||||
**Problem:** "with_hybrid() returns no results"
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. **Check vectorizer is enabled:**
|
||||
```python
|
||||
schema = client.schema.get("Documentation")
|
||||
print(schema["vectorizer"]) # Should be "text2vec-openai" or similar
|
||||
```
|
||||
|
||||
2. **Try pure vector search:**
|
||||
```python
|
||||
# Test vector search works
|
||||
result = client.query.get("Documentation", ["content"]) \
|
||||
.with_near_text({"concepts": ["test query"]}) \
|
||||
.do()
|
||||
```
|
||||
|
||||
3. **Verify BM25 index:**
|
||||
```python
|
||||
# BM25 requires inverted index
|
||||
schema["invertedIndexConfig"] = {"bm25": {"enabled": True}}
|
||||
client.schema.update_config("Documentation", schema)
|
||||
```
|
||||
|
||||
### Issue: Tenant Not Found
|
||||
|
||||
**Problem:** "Tenant 'react' does not exist"
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. **List existing tenants:**
|
||||
```python
|
||||
tenants = client.schema.get_class_tenants("Documentation")
|
||||
print([t["name"] for t in tenants])
|
||||
```
|
||||
|
||||
2. **Add missing tenant:**
|
||||
```python
|
||||
client.schema.add_class_tenants("Documentation", [{"name": "react"}])
|
||||
```
|
||||
|
||||
3. **Check multi-tenancy is enabled:**
|
||||
```python
|
||||
schema = client.schema.get("Documentation")
|
||||
print(schema.get("multiTenancyConfig", {}).get("enabled")) # Should be True
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Before vs. After
|
||||
|
||||
| Aspect | Without Skill Seekers | With Skill Seekers |
|
||||
|--------|----------------------|-------------------|
|
||||
| **Schema Design** | Manual property definition for each framework | Auto-formatted with consistent structure |
|
||||
| **Data Ingestion** | Custom scraping + parsing logic | One command: `skill-seekers create` |
|
||||
| **Metadata** | Manual extraction from docs | Auto-extracted (category, source, file, type) |
|
||||
| **Multi-Framework** | Separate schemas and databases | Single tenant-based schema |
|
||||
| **Hybrid Search** | Complex query construction | Pre-optimized for BM25 + vector |
|
||||
| **Setup Time** | 4-6 hours | 10 minutes |
|
||||
| **Code Required** | 500+ lines scraping logic | 30 lines upload script |
|
||||
| **Maintenance** | Update scrapers for each site | Update config once |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Next Steps
|
||||
|
||||
### Enhance Your Weaviate Integration
|
||||
|
||||
1. **Add Generative Search:**
|
||||
```bash
|
||||
# Enable qna-openai module in Weaviate
|
||||
# Then use with_generate() for RAG
|
||||
```
|
||||
|
||||
2. **Implement Semantic Chunking:**
|
||||
```bash
|
||||
skill-seekers create --config configs/fastapi.json --chunk-for-rag --chunk-tokens 512
|
||||
```
|
||||
|
||||
3. **Set Up Multi-Tenancy:**
|
||||
- Create tenant per framework
|
||||
- Query with `.with_tenant("framework-name")`
|
||||
- Isolate different documentation sets
|
||||
|
||||
4. **Monitor Performance:**
|
||||
- Track query latency
|
||||
- Monitor object count
|
||||
- Check cluster health
|
||||
|
||||
### Related Guides
|
||||
|
||||
- **[Haystack Integration](HAYSTACK.md)** - Use Weaviate as document store for Haystack
|
||||
- **[RAG Pipelines Guide](RAG_PIPELINES.md)** - Build complete RAG systems
|
||||
- **[Multi-LLM Support](MULTI_LLM_SUPPORT.md)** - Use different embedding models
|
||||
- **[INTEGRATIONS.md](INTEGRATIONS.md)** - See all integration options
|
||||
|
||||
### Resources
|
||||
|
||||
- **Weaviate Docs:** https://weaviate.io/developers/weaviate
|
||||
- **Python Client:** https://weaviate.io/developers/weaviate/client-libraries/python
|
||||
- **Support:** https://github.com/yusufkaraaslan/Skill_Seekers/discussions
|
||||
|
||||
---
|
||||
|
||||
**Questions?** Open an issue: https://github.com/yusufkaraaslan/Skill_Seekers/issues
|
||||
**Website:** https://skillseekersweb.com/
|
||||
**Last Updated:** February 7, 2026
|
||||
@@ -0,0 +1,978 @@
|
||||
# Using Skill Seekers with Windsurf IDE
|
||||
|
||||
**Last Updated:** February 7, 2026
|
||||
**Status:** Production Ready
|
||||
**Difficulty:** Easy ⭐
|
||||
|
||||
---
|
||||
|
||||
## 🎯 The Problem
|
||||
|
||||
Windsurf IDE (by Codeium) offers powerful AI flows and Cascade agent, but:
|
||||
|
||||
- **Generic Knowledge** - AI doesn't know your project-specific frameworks or internal patterns
|
||||
- **Manual Context** - Copy-pasting documentation into chat is tedious and breaks flow
|
||||
- **Limited Memory** - Memory feature requires manual teaching through conversations
|
||||
- **Context Limits** - Rules files are limited to 12,000 characters combined
|
||||
|
||||
**Example:**
|
||||
> "When building a FastAPI app in Windsurf, Cascade might suggest outdated patterns or miss framework-specific best practices. You want the AI to reference comprehensive documentation without hitting character limits."
|
||||
|
||||
---
|
||||
|
||||
## ✨ The Solution
|
||||
|
||||
Use Skill Seekers to create **custom rules** for Windsurf's Cascade agent:
|
||||
|
||||
1. **Generate structured docs** from any framework or codebase
|
||||
2. **Package as .windsurfrules** - Windsurf's markdown rules format
|
||||
3. **Automatic Context** - Cascade references your docs in AI flows
|
||||
4. **Modular Rules** - Split large docs into multiple rule files (6K chars each)
|
||||
|
||||
**Result:**
|
||||
Windsurf's Cascade becomes an expert in your frameworks with persistent, automatic context that fits within character limits.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Start (5 Minutes)
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Windsurf IDE installed (https://windsurf.com/)
|
||||
- Python 3.10+ (for Skill Seekers)
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
# Install Skill Seekers
|
||||
pip install skill-seekers
|
||||
|
||||
# Verify installation
|
||||
skill-seekers --version
|
||||
```
|
||||
|
||||
### Generate .windsurfrules
|
||||
|
||||
```bash
|
||||
# Example: FastAPI framework
|
||||
skill-seekers create --config configs/fastapi.json
|
||||
|
||||
# Package for Windsurf (markdown format)
|
||||
skill-seekers package output/fastapi --target markdown
|
||||
|
||||
# Extract SKILL.md
|
||||
# output/fastapi-markdown/SKILL.md
|
||||
```
|
||||
|
||||
### Setup in Windsurf
|
||||
|
||||
**Option 1: Project-Specific Rules** (recommended)
|
||||
|
||||
```bash
|
||||
# Create rules directory
|
||||
mkdir -p /path/to/your/project/.windsurf/rules
|
||||
|
||||
# Copy as rules.md
|
||||
cp output/fastapi-markdown/SKILL.md /path/to/your/project/.windsurf/rules/fastapi.md
|
||||
```
|
||||
|
||||
**Option 2: Legacy .windsurfrules** (single file)
|
||||
|
||||
```bash
|
||||
# Copy to project root (legacy format)
|
||||
cp output/fastapi-markdown/SKILL.md /path/to/your/project/.windsurfrules
|
||||
```
|
||||
|
||||
**Option 3: Split Large Documentation** (for >6K char files)
|
||||
|
||||
```bash
|
||||
# Skill Seekers automatically splits large files
|
||||
skill-seekers package output/react --target markdown
|
||||
|
||||
# This creates multiple rule files:
|
||||
# output/react-markdown/rules/
|
||||
# ├── core-concepts.md (5,800 chars)
|
||||
# ├── hooks-reference.md (5,400 chars)
|
||||
# ├── components-guide.md (5,900 chars)
|
||||
# └── best-practices.md (4,200 chars)
|
||||
|
||||
# Copy all rules
|
||||
cp -r output/react-markdown/rules/* /path/to/your/project/.windsurf/rules/
|
||||
```
|
||||
|
||||
### Test in Windsurf
|
||||
|
||||
1. Open your project in Windsurf
|
||||
2. Start Cascade (Cmd+L or Ctrl+L)
|
||||
3. Test knowledge:
|
||||
```
|
||||
"Create a FastAPI endpoint with async database queries using best practices"
|
||||
```
|
||||
4. Verify Cascade references your documentation
|
||||
|
||||
---
|
||||
|
||||
## 📖 Detailed Setup Guide
|
||||
|
||||
### Step 1: Choose Your Documentation Source
|
||||
|
||||
**Option A: Use Preset Configs** (24+ frameworks)
|
||||
|
||||
```bash
|
||||
# List available presets
|
||||
ls configs/
|
||||
|
||||
# Popular presets:
|
||||
# - react.json, vue.json, angular.json (Frontend)
|
||||
# - django.json, fastapi.json, flask.json (Backend)
|
||||
# - godot.json, unity.json (Game Development)
|
||||
# - kubernetes.json, docker.json (Infrastructure)
|
||||
```
|
||||
|
||||
**Option B: Custom Documentation**
|
||||
|
||||
Create `myframework-config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "myframework",
|
||||
"description": "Custom framework documentation for Windsurf",
|
||||
"base_url": "https://docs.myframework.com/",
|
||||
"selectors": {
|
||||
"main_content": "article",
|
||||
"title": "h1",
|
||||
"code_blocks": "pre code"
|
||||
},
|
||||
"categories": {
|
||||
"getting_started": ["intro", "quickstart", "installation"],
|
||||
"core_concepts": ["concepts", "architecture", "patterns"],
|
||||
"api": ["api", "reference", "methods"],
|
||||
"guides": ["guide", "tutorial", "how-to"],
|
||||
"best_practices": ["best-practices", "tips", "patterns"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Option C: GitHub Repository**
|
||||
|
||||
```bash
|
||||
# Analyze open-source codebase
|
||||
skill-seekers create facebook/react
|
||||
|
||||
# Or local codebase
|
||||
skill-seekers create /path/to/repo --preset comprehensive
|
||||
```
|
||||
|
||||
### Step 2: Optimize for Windsurf
|
||||
|
||||
**Character Limit Awareness**
|
||||
|
||||
Windsurf has strict limits:
|
||||
- **Per rule file:** 6,000 characters max
|
||||
- **Combined global + local:** 12,000 characters max
|
||||
|
||||
**Use automatic splitting:**
|
||||
```bash
|
||||
skill-seekers package output/react --target markdown
|
||||
```
|
||||
|
||||
**Rule Activation Modes**
|
||||
|
||||
Configure each rule file's activation mode in frontmatter:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: "FastAPI Core Concepts"
|
||||
activation: "always-on"
|
||||
priority: "high"
|
||||
---
|
||||
|
||||
# FastAPI Framework Expert
|
||||
|
||||
You are an expert in FastAPI...
|
||||
```
|
||||
|
||||
Activation modes:
|
||||
- **Always On** - Applied to every request (use for core concepts)
|
||||
- **Model Decision** - AI decides when to use (use for specialized topics)
|
||||
- **Manual** - Only when @mentioned (use for troubleshooting)
|
||||
- **Scheduled** - Time-based activation (use for context switching)
|
||||
|
||||
### Step 3: Configure Windsurf Settings
|
||||
|
||||
**Enable Rules**
|
||||
|
||||
1. Open Windsurf Settings (Cmd+, or Ctrl+,)
|
||||
2. Search for "rules"
|
||||
3. Enable "Use Custom Rules"
|
||||
4. Set rules directory: `.windsurf/rules`
|
||||
|
||||
**Memory Integration**
|
||||
|
||||
Combine rules with Windsurf's Memory feature:
|
||||
|
||||
```bash
|
||||
# Generate initial rules from docs
|
||||
skill-seekers package output/fastapi --target markdown
|
||||
|
||||
# Windsurf Memory learns from your usage:
|
||||
# - Coding patterns you use frequently
|
||||
# - Variable naming conventions
|
||||
# - Architecture decisions
|
||||
# - Team-specific practices
|
||||
|
||||
# Rules provide documentation, Memory provides personalization
|
||||
```
|
||||
|
||||
**MCP Server Integration**
|
||||
|
||||
For live documentation access:
|
||||
|
||||
```bash
|
||||
# Install Skill Seekers MCP server
|
||||
pip install skill-seekers[mcp]
|
||||
|
||||
# Configure in Windsurf's mcp_config.json
|
||||
{
|
||||
"mcpServers": {
|
||||
"skill-seekers": {
|
||||
"command": "python",
|
||||
"args": ["-m", "skill_seekers.mcp.server_fastmcp", "--transport", "stdio"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4: Test and Refine
|
||||
|
||||
**Test Cascade Knowledge**
|
||||
|
||||
```bash
|
||||
# Start Cascade (Cmd+L)
|
||||
# Ask framework-specific questions:
|
||||
|
||||
"Show me FastAPI async database patterns"
|
||||
"Create a React component with TypeScript best practices"
|
||||
"Implement Django REST framework viewset with pagination"
|
||||
```
|
||||
|
||||
**Refine Rules**
|
||||
|
||||
```bash
|
||||
# Add project-specific patterns
|
||||
cat >> .windsurf/rules/project-conventions.md << 'EOF'
|
||||
---
|
||||
name: "Project Conventions"
|
||||
activation: "always-on"
|
||||
priority: "highest"
|
||||
---
|
||||
|
||||
# Project-Specific Patterns
|
||||
|
||||
## Database Models
|
||||
- Always use async SQLAlchemy
|
||||
- Include created_at/updated_at timestamps
|
||||
- Add __repr__ for debugging
|
||||
|
||||
## API Endpoints
|
||||
- Use dependency injection for database sessions
|
||||
- Return Pydantic models, not ORM instances
|
||||
- Include OpenAPI documentation strings
|
||||
EOF
|
||||
|
||||
# Reload Windsurf window (Cmd+Shift+P → "Reload Window")
|
||||
```
|
||||
|
||||
**Monitor Character Usage**
|
||||
|
||||
```bash
|
||||
# Check rule file sizes
|
||||
find .windsurf/rules -name "*.md" -exec wc -c {} \;
|
||||
|
||||
# Ensure no file exceeds 6,000 characters
|
||||
# If too large, split further:
|
||||
skill-seekers package output/react --target markdown
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Advanced Usage
|
||||
|
||||
### Multi-Framework Projects
|
||||
|
||||
**Backend + Frontend Stack**
|
||||
|
||||
```bash
|
||||
# Generate backend rules (FastAPI)
|
||||
skill-seekers create --config configs/fastapi.json
|
||||
skill-seekers package output/fastapi --target markdown
|
||||
|
||||
# Generate frontend rules (React)
|
||||
skill-seekers create --config configs/react.json
|
||||
skill-seekers package output/react --target markdown
|
||||
|
||||
# Organize rules directory:
|
||||
.windsurf/rules/
|
||||
├── backend/
|
||||
│ ├── fastapi-core.md (Always On)
|
||||
│ ├── fastapi-database.md (Model Decision)
|
||||
│ └── fastapi-testing.md (Manual)
|
||||
├── frontend/
|
||||
│ ├── react-hooks.md (Always On)
|
||||
│ ├── react-components.md (Model Decision)
|
||||
│ └── react-performance.md (Manual)
|
||||
└── project/
|
||||
└── conventions.md (Always On, Highest Priority)
|
||||
```
|
||||
|
||||
### Dynamic Context per Workflow
|
||||
|
||||
**Context Switching Based on Task**
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: "Testing Context"
|
||||
activation: "model-decision"
|
||||
description: "Use when user is writing or debugging tests"
|
||||
keywords: ["test", "pytest", "unittest", "mock", "fixture"]
|
||||
---
|
||||
|
||||
# Testing Best Practices
|
||||
|
||||
When writing tests, follow these patterns...
|
||||
```
|
||||
|
||||
**Scheduled Rules for Time-Based Context**
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: "Code Review Mode"
|
||||
activation: "scheduled"
|
||||
schedule: "0 14 * * 1-5" # 2 PM on weekdays
|
||||
priority: "high"
|
||||
---
|
||||
|
||||
# Code Review Checklist
|
||||
|
||||
During code review, verify:
|
||||
- Type annotations are complete
|
||||
- Tests cover edge cases
|
||||
- Documentation is updated
|
||||
```
|
||||
|
||||
### Windsurf + RAG Pipeline
|
||||
|
||||
**Combine Rules with Vector Search**
|
||||
|
||||
```python
|
||||
# Use Skill Seekers to create both:
|
||||
# 1. Windsurf rules (for Cascade context)
|
||||
# 2. RAG chunks (for deep search)
|
||||
|
||||
from skill_seekers.cli.doc_scraper import main as scrape
|
||||
from skill_seekers.cli.package_skill import main as package
|
||||
from skill_seekers.cli.adaptors import get_adaptor
|
||||
|
||||
# Scrape documentation
|
||||
scrape(["--config", "configs/react.json"])
|
||||
|
||||
# Create Windsurf rules
|
||||
package(["output/react", "--target", "markdown", "--split-rules"])
|
||||
|
||||
# Also create RAG pipeline for deep search
|
||||
package(["output/react", "--target", "langchain", "--chunk-for-rag"])
|
||||
|
||||
# Now you have:
|
||||
# - .windsurf/rules/*.md (for Cascade)
|
||||
# - output/react-langchain/ (for custom RAG search)
|
||||
```
|
||||
|
||||
**MCP Tool for Dynamic Context**
|
||||
|
||||
Create custom MCP tool that queries RAG pipeline:
|
||||
|
||||
```python
|
||||
# mcp_custom_search.py
|
||||
from skill_seekers.mcp.tools import search_docs
|
||||
|
||||
@mcp.tool()
|
||||
def search_react_docs(query: str) -> str:
|
||||
"""Search React documentation for specific patterns."""
|
||||
# Query your RAG pipeline
|
||||
results = vector_store.similarity_search(query, k=5)
|
||||
return "\n\n".join([doc.page_content for doc in results])
|
||||
```
|
||||
|
||||
Register in `mcp_config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"custom-search": {
|
||||
"command": "python",
|
||||
"args": ["mcp_custom_search.py"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 Best Practices
|
||||
|
||||
### 1. Keep Rules Focused
|
||||
|
||||
**Bad: Single Monolithic Rule (15,000 chars - exceeds limit!)**
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: "Everything React"
|
||||
---
|
||||
# React Framework (Complete Guide)
|
||||
[... 15,000 characters of documentation ...]
|
||||
```
|
||||
|
||||
**Good: Modular Rules (5,000 chars each)**
|
||||
|
||||
```markdown
|
||||
<!-- react-core.md (5,200 chars) -->
|
||||
---
|
||||
name: "React Core Concepts"
|
||||
activation: "always-on"
|
||||
---
|
||||
# React Fundamentals
|
||||
[... focused on hooks, components, state ...]
|
||||
|
||||
<!-- react-performance.md (4,800 chars) -->
|
||||
---
|
||||
name: "React Performance"
|
||||
activation: "model-decision"
|
||||
description: "Use when optimizing React performance"
|
||||
---
|
||||
# Performance Optimization
|
||||
[... focused on memoization, lazy loading ...]
|
||||
|
||||
<!-- react-testing.md (5,100 chars) -->
|
||||
---
|
||||
name: "React Testing"
|
||||
activation: "manual"
|
||||
---
|
||||
# Testing React Components
|
||||
[... focused on testing patterns ...]
|
||||
```
|
||||
|
||||
### 2. Use Activation Modes Wisely
|
||||
|
||||
| Mode | Use Case | Example |
|
||||
|------|----------|---------|
|
||||
| **Always On** | Core concepts, common patterns | Framework fundamentals, project conventions |
|
||||
| **Model Decision** | Specialized topics | Performance optimization, advanced patterns |
|
||||
| **Manual** | Troubleshooting, rare tasks | Debugging guides, migration docs |
|
||||
| **Scheduled** | Time-based context | Code review checklists, release procedures |
|
||||
|
||||
### 3. Prioritize Rules
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: "Project Conventions"
|
||||
activation: "always-on"
|
||||
priority: "highest" # This overrides framework defaults
|
||||
---
|
||||
|
||||
# Project-Specific Rules
|
||||
|
||||
Always use:
|
||||
- Async/await for all database operations
|
||||
- Pydantic V2 (not V1)
|
||||
- pytest-asyncio for async tests
|
||||
```
|
||||
|
||||
### 4. Include Code Examples
|
||||
|
||||
**Don't just describe patterns:**
|
||||
|
||||
```markdown
|
||||
## Creating Database Models
|
||||
|
||||
Use SQLAlchemy with async patterns.
|
||||
```
|
||||
|
||||
**Show actual code:**
|
||||
|
||||
```markdown
|
||||
## Creating Database Models
|
||||
|
||||
```python
|
||||
from sqlalchemy import Column, Integer, String, DateTime
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from datetime import datetime
|
||||
|
||||
class User(Base):
|
||||
__tablename__ = "users"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
email = Column(String, unique=True, nullable=False)
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<User(email='{self.email}')>"
|
||||
|
||||
# Usage in endpoint
|
||||
async def create_user(email: str, db: AsyncSession):
|
||||
user = User(email=email)
|
||||
db.add(user)
|
||||
await db.commit()
|
||||
await db.refresh(user)
|
||||
return user
|
||||
```
|
||||
\```
|
||||
|
||||
Use this pattern in all endpoints.
|
||||
```
|
||||
|
||||
### 5. Update Rules Regularly
|
||||
|
||||
```bash
|
||||
# Framework updates quarterly
|
||||
skill-seekers create --config configs/react.json
|
||||
skill-seekers package output/react --target markdown
|
||||
|
||||
# Check what changed
|
||||
diff -r .windsurf/rules/react-old/ .windsurf/rules/react-new/
|
||||
|
||||
# Merge updates
|
||||
cp -r .windsurf/rules/react-new/* .windsurf/rules/
|
||||
|
||||
# Test with Cascade
|
||||
# Ask: "What's new in React 19?"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔥 Real-World Examples
|
||||
|
||||
### Example 1: FastAPI + PostgreSQL Microservice
|
||||
|
||||
**Project Structure:**
|
||||
|
||||
```
|
||||
my-api/
|
||||
├── .windsurf/
|
||||
│ └── rules/
|
||||
│ ├── fastapi-core.md (5,200 chars, Always On)
|
||||
│ ├── fastapi-database.md (5,800 chars, Always On)
|
||||
│ ├── fastapi-testing.md (4,100 chars, Manual)
|
||||
│ └── project-conventions.md (3,500 chars, Always On, Highest)
|
||||
├── app/
|
||||
│ ├── models.py
|
||||
│ ├── schemas.py
|
||||
│ └── routers/
|
||||
└── tests/
|
||||
```
|
||||
|
||||
**fastapi-core.md**
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: "FastAPI Core Patterns"
|
||||
activation: "always-on"
|
||||
priority: "high"
|
||||
---
|
||||
|
||||
# FastAPI Expert
|
||||
|
||||
You are an expert in FastAPI. Use these patterns:
|
||||
|
||||
## Endpoint Structure
|
||||
|
||||
Always use dependency injection:
|
||||
|
||||
\```python
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from app.database import get_db
|
||||
|
||||
router = APIRouter(prefix="/api/v1")
|
||||
|
||||
@router.post("/users/", response_model=UserResponse)
|
||||
async def create_user(
|
||||
user: UserCreate,
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""Create a new user."""
|
||||
# Implementation
|
||||
\```
|
||||
|
||||
## Error Handling
|
||||
|
||||
Use HTTPException with proper status codes:
|
||||
|
||||
\```python
|
||||
from fastapi import HTTPException
|
||||
|
||||
if not user:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="User not found"
|
||||
)
|
||||
\```
|
||||
```
|
||||
|
||||
**project-conventions.md**
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: "Project Conventions"
|
||||
activation: "always-on"
|
||||
priority: "highest"
|
||||
---
|
||||
|
||||
# Project-Specific Patterns
|
||||
|
||||
## Database Sessions
|
||||
|
||||
ALWAYS use async sessions with context managers:
|
||||
|
||||
\```python
|
||||
async with get_session() as db:
|
||||
result = await db.execute(query)
|
||||
\```
|
||||
|
||||
## Response Models
|
||||
|
||||
NEVER return ORM instances directly. Use Pydantic:
|
||||
|
||||
\```python
|
||||
# BAD
|
||||
return user # SQLAlchemy model
|
||||
|
||||
# GOOD
|
||||
return UserResponse.model_validate(user)
|
||||
\```
|
||||
|
||||
## Testing
|
||||
|
||||
All tests MUST use pytest-asyncio:
|
||||
|
||||
\```python
|
||||
import pytest
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_user():
|
||||
# Test implementation
|
||||
\```
|
||||
```
|
||||
|
||||
**Result:**
|
||||
|
||||
When you ask Cascade:
|
||||
> "Create an endpoint to list all users with pagination"
|
||||
|
||||
Cascade will:
|
||||
1. ✅ Use async/await (from project-conventions.md)
|
||||
2. ✅ Add dependency injection (from fastapi-core.md)
|
||||
3. ✅ Return Pydantic models (from project-conventions.md)
|
||||
4. ✅ Use proper database patterns (from fastapi-database.md)
|
||||
|
||||
### Example 2: Godot Game Engine
|
||||
|
||||
**Godot-Specific Rules**
|
||||
|
||||
```bash
|
||||
# Generate Godot documentation + codebase analysis
|
||||
skill-seekers create godotengine/godot-demo-projects
|
||||
skill-seekers package output/godot-demo-projects --target markdown
|
||||
|
||||
# Create rules structure:
|
||||
.windsurf/rules/
|
||||
├── godot-core.md (GDScript syntax, node system)
|
||||
├── godot-signals.md (Signal patterns, EventBus)
|
||||
├── godot-scenes.md (Scene tree, node access)
|
||||
└── project-patterns.md (Custom patterns from codebase)
|
||||
```
|
||||
|
||||
**godot-signals.md**
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: "Godot Signal Patterns"
|
||||
activation: "model-decision"
|
||||
description: "Use when working with signals and events"
|
||||
keywords: ["signal", "connect", "emit", "EventBus"]
|
||||
---
|
||||
|
||||
# Godot Signal Patterns
|
||||
|
||||
## Signal Declaration
|
||||
|
||||
\```gdscript
|
||||
signal health_changed(new_health: int, max_health: int)
|
||||
signal item_collected(item_type: String, quantity: int)
|
||||
\```
|
||||
|
||||
## Connection Pattern
|
||||
|
||||
\```gdscript
|
||||
func _ready():
|
||||
player.health_changed.connect(_on_health_changed)
|
||||
|
||||
func _on_health_changed(new_health: int, max_health: int):
|
||||
health_bar.value = (new_health / float(max_health)) * 100
|
||||
\```
|
||||
|
||||
## EventBus Pattern (from codebase analysis)
|
||||
|
||||
\```gdscript
|
||||
# EventBus.gd (autoload singleton)
|
||||
extends Node
|
||||
|
||||
signal game_started
|
||||
signal game_over(score: int)
|
||||
signal player_died
|
||||
|
||||
# Usage in game scenes:
|
||||
EventBus.game_started.emit()
|
||||
EventBus.game_over.emit(final_score)
|
||||
\```
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Issue: Rules Not Loading
|
||||
|
||||
**Symptoms:**
|
||||
- Cascade doesn't reference documentation
|
||||
- Rules directory exists but ignored
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. **Check rules directory location**
|
||||
```bash
|
||||
# Must be exactly:
|
||||
.windsurf/rules/
|
||||
|
||||
# Not:
|
||||
.windsurf/rule/ # Missing 's'
|
||||
windsurf/rules/ # Missing leading dot
|
||||
```
|
||||
|
||||
2. **Verify file extensions**
|
||||
```bash
|
||||
# Rules must be .md files
|
||||
ls .windsurf/rules/
|
||||
# Should show: fastapi.md, react.md, etc.
|
||||
# NOT: fastapi.txt, rules.json
|
||||
```
|
||||
|
||||
3. **Check Windsurf settings**
|
||||
```
|
||||
Cmd+, → Search "rules" → Enable "Use Custom Rules"
|
||||
```
|
||||
|
||||
4. **Reload Windsurf**
|
||||
```
|
||||
Cmd+Shift+P → "Reload Window"
|
||||
```
|
||||
|
||||
5. **Verify frontmatter syntax**
|
||||
```markdown
|
||||
---
|
||||
name: "Rule Name"
|
||||
activation: "always-on"
|
||||
---
|
||||
|
||||
# Content starts here
|
||||
```
|
||||
|
||||
### Issue: Rules Exceeding Character Limit
|
||||
|
||||
**Error:**
|
||||
> "Rule file exceeds 6,000 character limit"
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. **Use automatic splitting**
|
||||
```bash
|
||||
skill-seekers package output/react --target markdown
|
||||
```
|
||||
|
||||
2. **Set custom max-chars**
|
||||
```bash
|
||||
skill-seekers package output/django --target markdown
|
||||
```
|
||||
|
||||
3. **Manual splitting**
|
||||
```bash
|
||||
# Split SKILL.md by sections
|
||||
csplit SKILL.md '/^## /' '{*}'
|
||||
|
||||
# Rename files
|
||||
mv xx00 core-concepts.md
|
||||
mv xx01 api-reference.md
|
||||
mv xx02 best-practices.md
|
||||
```
|
||||
|
||||
4. **Use activation modes strategically**
|
||||
```markdown
|
||||
<!-- Keep core concepts Always On -->
|
||||
---
|
||||
name: "Core Concepts"
|
||||
activation: "always-on"
|
||||
---
|
||||
|
||||
<!-- Make specialized topics Manual -->
|
||||
---
|
||||
name: "Advanced Patterns"
|
||||
activation: "manual"
|
||||
---
|
||||
```
|
||||
|
||||
### Issue: Cascade Not Using Rules
|
||||
|
||||
**Symptoms:**
|
||||
- Rules loaded but AI doesn't reference them
|
||||
- Generic responses despite custom documentation
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. **Check activation mode**
|
||||
```markdown
|
||||
# Change from Model Decision to Always On
|
||||
---
|
||||
activation: "always-on" # Not "model-decision"
|
||||
---
|
||||
```
|
||||
|
||||
2. **Increase priority**
|
||||
```markdown
|
||||
---
|
||||
priority: "highest" # Override framework defaults
|
||||
---
|
||||
```
|
||||
|
||||
3. **Add explicit instructions**
|
||||
```markdown
|
||||
# FastAPI Expert
|
||||
|
||||
You MUST follow these patterns in all FastAPI code:
|
||||
- Use async/await
|
||||
- Dependency injection for database
|
||||
- Pydantic response models
|
||||
```
|
||||
|
||||
4. **Test with explicit mention**
|
||||
```
|
||||
In Cascade chat:
|
||||
"@fastapi Create an endpoint with async database access"
|
||||
```
|
||||
|
||||
5. **Combine with Memory**
|
||||
```
|
||||
Ask Cascade to remember:
|
||||
"Remember to always use the patterns from fastapi.md rules file"
|
||||
```
|
||||
|
||||
### Issue: Conflicting Rules
|
||||
|
||||
**Symptoms:**
|
||||
- AI mixes patterns from different frameworks
|
||||
- Inconsistent code suggestions
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. **Use priority levels**
|
||||
```markdown
|
||||
<!-- project-conventions.md -->
|
||||
---
|
||||
priority: "highest"
|
||||
---
|
||||
|
||||
<!-- framework-defaults.md -->
|
||||
---
|
||||
priority: "medium"
|
||||
---
|
||||
```
|
||||
|
||||
2. **Make project conventions always-on**
|
||||
```markdown
|
||||
---
|
||||
name: "Project Conventions"
|
||||
activation: "always-on"
|
||||
priority: "highest"
|
||||
---
|
||||
|
||||
These rules OVERRIDE all framework defaults:
|
||||
- [List project-specific patterns]
|
||||
```
|
||||
|
||||
3. **Use model-decision for conflicting patterns**
|
||||
```markdown
|
||||
<!-- rest-api.md -->
|
||||
---
|
||||
activation: "model-decision"
|
||||
description: "Use when creating REST APIs (not GraphQL)"
|
||||
---
|
||||
|
||||
<!-- graphql-api.md -->
|
||||
---
|
||||
activation: "model-decision"
|
||||
description: "Use when creating GraphQL APIs (not REST)"
|
||||
---
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Before vs After Comparison
|
||||
|
||||
| Aspect | Before Skill Seekers | After Skill Seekers |
|
||||
|--------|---------------------|---------------------|
|
||||
| **Context Source** | Copy-paste docs into chat | Automatic rules files |
|
||||
| **Character Limits** | Hit 12K limit easily | Modular rules fit perfectly |
|
||||
| **AI Knowledge** | Generic framework patterns | Project-specific best practices |
|
||||
| **Setup Time** | Manual doc curation (hours) | Automated scraping (5 min) |
|
||||
| **Consistency** | Varies per conversation | Persistent across all flows |
|
||||
| **Updates** | Manual doc editing | Re-run scraper for latest docs |
|
||||
| **Multi-Framework** | Context switching confusion | Separate rule files |
|
||||
| **Code Quality** | Hit-or-miss | Follows documented patterns |
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Community & Support
|
||||
|
||||
- **Questions:** [GitHub Discussions](https://github.com/yusufkaraaslan/Skill_Seekers/discussions)
|
||||
- **Issues:** [GitHub Issues](https://github.com/yusufkaraaslan/Skill_Seekers/issues)
|
||||
- **Website:** [skillseekersweb.com](https://skillseekersweb.com/)
|
||||
- **Windsurf Docs:** [docs.windsurf.com](https://docs.windsurf.com/)
|
||||
- **Windsurf Rules Directory:** [windsurf.com/editor/directory](https://windsurf.com/editor/directory)
|
||||
|
||||
---
|
||||
|
||||
## 📚 Related Guides
|
||||
|
||||
- [Cursor Integration](CURSOR.md) - Similar IDE, different rules format
|
||||
- [Cline Integration](CLINE.md) - VS Code extension with MCP
|
||||
- [Continue.dev Integration](CONTINUE_DEV.md) - IDE-agnostic AI assistant
|
||||
- [LangChain Integration](LANGCHAIN.md) - Build RAG pipelines
|
||||
- [RAG Pipelines Guide](RAG_PIPELINES.md) - End-to-end RAG setup
|
||||
|
||||
---
|
||||
|
||||
## 📖 Next Steps
|
||||
|
||||
1. **Try another framework:** `skill-seekers create --config configs/vue.json`
|
||||
2. **Combine multiple frameworks:** Create modular rules for full-stack projects
|
||||
3. **Integrate with MCP:** Add live documentation access via MCP servers
|
||||
4. **Build RAG pipeline:** Use `--target langchain` for deep search
|
||||
5. **Share your rules:** Contribute to [awesome-windsurfrules](https://github.com/SchneiderSam/awesome-windsurfrules)
|
||||
|
||||
---
|
||||
|
||||
**Sources:**
|
||||
- [Windsurf Official Site](https://windsurf.com/)
|
||||
- [Windsurf Documentation](https://docs.windsurf.com/windsurf/getting-started)
|
||||
- [Windsurf MCP Setup Guide](https://www.braingrid.ai/blog/windsurf-mcp)
|
||||
- [Awesome Windsurfrules Repository](https://github.com/SchneiderSam/awesome-windsurfrules)
|
||||
- [Windsurf Rules Directory](https://windsurf.com/editor/directory)
|
||||
- [Mastering .windsurfrules Guide](https://blog.stackademic.com/mastering-windsurfrules-react-typescript-projects-aee1e3fe4376)
|
||||
Reference in New Issue
Block a user