Skip to main content

Lestrade

RAG knowledge engine with a pluggable architecture. Drop in documents, point at an LLM, and build domain-specific AI assistants.

Features

  • OpenAI-compatible API/v1/chat/completions and /v1/models endpoints
  • RAG with FAISS — Hybrid semantic + keyword search over your documents
  • Multi-backend LLM — Local (Ollama) or cloud (OpenAI / DeepSeek / any OpenAI-compatible API)
  • Bilingual — Auto-detects English / Chinese, with language-filtered retrieval
  • Auto-indexing — Watches knowledge base directories, re-indexes on changes
  • Rate limiting — Per-IP rate limit on chat completions
  • Streaming & JSON — Both SSE streaming and standard JSON responses
  • Pluggable architecture — Swap chunking, retrieval, response, and ingestion strategies via environment variables
  • Docker — One docker compose up to run everything

Quick Start

Prerequisites

  • Ollama installed and running (or use cloud API directly)
  • Python 3.9+

1. Install

pip install lestrade

Or for development:

cd source
pip install -e ".[dev]"

2. Prepare Knowledge Base

Put your .md or .txt files in data/kb/. Organize by language:

data/kb/
├── en/
│   ├── getting-started.md
│   └── faq.md
└── zh/
    ├── getting-started.md
    └── faq.md

3. Configure

Copy .env.example to .env and edit:

cp .env.example .env

Key settings:

Variable Description Default
CHAT_MODEL LLM model to use deepseek-chat
LLM_API_KEY API key for cloud LLM (empty)
LLM_BASE_URL OpenAI-compatible API base URL https://api.openai.com/v1
OLLAMA_BASE_URL Ollama server URL http://ollama:11434
EMBEDDING_MODEL Embedding model (Ollama) nomic-embed-text
KB_DIRS Comma-separated KB directories (empty)
RATE_LIMIT_MAX_REQUESTS Max requests per window 10

4. Run

uvicorn lestrade.main:app --reload

# or Docker
docker compose up -d

API

The service exposes an OpenAI-compatible API at http://localhost:8000:

Chat Completions

POST /v1/chat/completions
Content-Type: application/json

{
  "model": "deepseek-chat",
  "messages": [{"role": "user", "content": "What is your return policy?"}],
  "stream": false
}

List Models

GET /v1/models

Ingest Documents

POST /api/ingest
Content-Type: multipart/form-data

text=Document content here&source=my-doc.md
POST /api/ingest/file
Content-Type: multipart/form-data

file=@document.md

Health Check

GET /health

Pluggable Architecture

Lestrade provides four extension points. Each comes with a default implementation and can be swapped via environment variables.

┌──────────────┐
│  Chunking    │   text → chunks        (env: LESTRADE_CHUNKING)
├──────────────┤
│  Retrieval   │   query → ranked docs  (env: LESTRADE_RETRIEVAL)
├──────────────┤
│  Response    │   context → prompt     (env: LESTRADE_RESPONSE)
│              │   raw LLM → formatted  │
├──────────────┤
│  Ingestion   │   data source → texts  (env: LESTRADE_INGESTION)
└──────────────┘

Creating a Custom Plugin

Inherit from the base class in your own Python package, then point lestrade at it.

# my_legal_bot/plugins.py
from lestrade.plugins import ResponsePlugin
from lestrade.llm.base import ChatMessage

class LegalResponse(ResponsePlugin):
    def build_messages(self, contexts, user_message, lang):
        context_text = "\n\n".join(c[0] for c in contexts)
        prompt = (
            f"你是一位法律顾问。仅根据以下法律条文回答问题,"
            f"必须引用具体法条编号。回答末尾添加免责声明。\n\n"
            f"法律条文:\n{context_text}\n\n"
            f"问题:{user_message}"
        )
        return [ChatMessage(role="user", content=prompt)]

    def format_response(self, text):
        return text + "\n\n---\n以上回答仅供参考,不构成法律意见。"
# Install your plugin alongside lestrade
pip install lestrade my-legal-bot

# Point lestrade at your plugin
export LESTRADE_RESPONSE=my_legal_bot.plugins:LegalResponse
uvicorn lestrade.main:app

Extension Points

Plugin Base Class Method Purpose
Chunking ChunkingPlugin chunk(text, max_chars) -> list[str] Split documents into searchable chunks
Retrieval RetrievalPlugin search(query, k, lang, index, entries, embed_fn) -> list[tuple] Rank and return relevant chunks
Response ResponsePlugin build_messages(contexts, user_msg, lang) -> list[ChatMessage] Build the LLM prompt from context
Response ResponsePlugin format_response(text) -> str Post-process LLM output
Ingestion IngestionPlugin start(on_content) Connect external data sources

Vertical Domain Examples

lestrade                     # open-source base
└── my-legal-bot/           # vertical: legal Q&A
    └── plugins.py           #   LegalChunking (split by clause)
                             #   LegalRetrieval (cite article numbers)
                             #   LegalResponse (attach disclaimers)

└── my-medical-bot/         # vertical: medical triage
    └── plugins.py           #   MedicalChunking (split by diagnosis)
                             #   MedicalResponse (symptom → triage suggestion)

Vertical packages only declare lestrade as a dependency — no code fork needed. Upgrade lestrade without touching vertical logic.

Tech Stack

Component Technology
API Server FastAPI + Uvicorn
Vector Store FAISS (CPU)
Embeddings Ollama (nomic-embed-text / bge-m3)
LLM Ollama (local) or OpenAI-compatible API
Rate Limit Custom Starlette middleware

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lestrade-0.1.1.tar.gz (21.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lestrade-0.1.1-py3-none-any.whl (23.3 kB view details)

Uploaded Python 3

File details

Details for the file lestrade-0.1.1.tar.gz.

File metadata

  • Download URL: lestrade-0.1.1.tar.gz
  • Upload date:
  • Size: 21.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for lestrade-0.1.1.tar.gz
Algorithm Hash digest
SHA256 c2984b6d5ca702d0145d643030174401b54605ede8d290c171217285aadb4cb6
MD5 1bab4b4a7d10bb0ba9201e0942b18adb
BLAKE2b-256 d765ef66383514a6bb9cf4c5c02c98d2d3b6096db185de664d2e0a0b67b69dda

See more details on using hashes here.

File details

Details for the file lestrade-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: lestrade-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 23.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for lestrade-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 9ce9f5fd625625f4743a446b65ea400cc4c0c4a6a99525f4547e5316780b3221
MD5 7692a1f102ec31cdeeb65fe3346251dd
BLAKE2b-256 c092aeb318380fbd36f7c45f802eb486b5745c71cfd2b3283677dd006ee765d5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page