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 swappable via environment variables.

Plugin Input Output Env Variable
Chunking text chunks LESTRADE_CHUNKING
Retrieval query + index ranked docs LESTRADE_RETRIEVAL
Response context + raw LLM output prompt + formatted text LESTRADE_RESPONSE
Ingestion data source texts 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.2.tar.gz (21.8 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.2-py3-none-any.whl (23.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: lestrade-0.1.2.tar.gz
  • Upload date:
  • Size: 21.8 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.2.tar.gz
Algorithm Hash digest
SHA256 1494c9cfdd0fdebe398e32bef64062ccc8b453c001ead48ce5487860963dfd0b
MD5 094511778f9d758d888dce6a676ec745
BLAKE2b-256 1d81046e6874971dc808df38b039511a93f93b56395cd323f84d00794e0bf13e

See more details on using hashes here.

File details

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

File metadata

  • Download URL: lestrade-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 23.2 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.2-py3-none-any.whl
Algorithm Hash digest
SHA256 f5b8757e43e6f42df020aec24f26d46c27e51bad0642c7da1c02bd2d857d0a1f
MD5 d86d1e7ab446d74de9671af1c86afcf9
BLAKE2b-256 692e2d3376e209e1c7813bdb5969c3966d5d81b63c7ee15377bebe3c84c2f076

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