Content
# Tool List
[](https://github.com/JIEAO-re/ragx/actions/workflows/ci.yml)
[](LICENSE)


**A retrieval-augmented system for agents: strong parsing + hybrid retrieval + reranking + agentic answering with citations**,
providing **core engine (Python library) + MCP server + REST API (including OpenAI compatible `/v1/chat/completions`)**.
## Design Philosophy
| Layer | Inspired by | Implementation |
|---|---|---|
| Parsing | RAGFlow DeepDoc | PyMuPDF + python-docx/pptx + openpyxl + trafilatura + code awareness, block-level chunking |
| Chunking | LlamaIndex | Recursive character chunking + Markdown header awareness + code tree-sitter AST boundaries; overlap exit unified application |
| Vectorization | BGE-M3 | A single model producing dense + sparse embeddings, foundation for hybrid retrieval |
| Vector Store | Qdrant | Local embedded (no Docker) + dense/sparse named vectors |
| Hybrid Retrieval | R2R / Weaviate | Vector recall + sparse recall → RRF fusion |
| Reranking | bge-reranker-v2-m3 | Cross-encoder precise ranking |
| Agentic | Self-RAG / LangGraph | Multi-query rewriting → retrieval → reranking → optional relevance filtering → answer generation with citations |
| Generation | Claude | Opus 4.8 for answer generation, Haiku 4.5 for rewriting/scoring (cost-effective) |
**Model Roadmap**: embedding/rerank local execution (BGE, cost-effective, offline indexing), generation using Claude API (best results).
## Installation
```bash
pip install -e .
# Optional enhancements:
pip install -e ".[web,code]" # Better webpage content extraction + code AST chunking
pip install -e ".[graph]" # GraphRAG multi-hop (LightRAG)
pip install -e ".[vision]" # Enhanced table extraction (image processing with PyMuPDF + Claude vision)
pip install -e ".[eval]" # Evaluation (optional ragas)
```
Configure (copy `.env.example` to `.env`): `ANTHROPIC_API_KEY` is required, others optional.
Initial run will download BGE-M3 (approximately 2GB) and reranker models.
### Using OpenAI Compatible Endpoint / Relay Station (Optional)
Generation layer defaults to Claude, but can be switched to any **OpenAI format** `/v1/chat/completions` endpoint
(true OpenAI, Azure, API relay, vLLM, Ollama, DeepSeek, etc.):
```bash
pip install -e ".[openai]"
# .env:
RAGX_LLM_PROVIDER=openai
RAGX_OPENAI_BASE_URL=https://your-relay/v1
RAGX_OPENAI_API_KEY=sk-xxx # or leave blank to use environment variable OPENAI_API_KEY
RAGX_ANSWER_MODEL=... # fill with endpoint-supported model name
RAGX_UTILITY_MODEL=...
```
embedding/rerank still uses local BGE (cost-effective, offline), only generation/rewrite/scoring/vision use the endpoint.
Structured output prioritizes `response_format=json_object`, automatically falls back to prompt constraints + validation
for robust compatibility with various relays.
## Quick Start
```bash
# 1. Ingest documents (support PDF / Word / PPT / Excel / CSV / Markdown / webpage / code)
ragx ingest ./docs
ragx ingest --url https://example.com/article
# 2. Search (recall only, no generation)
ragx search "vector store selection"
# 3. Question answering (streaming output + citations)
ragx ask "What is the hybrid retrieval scheme used in this project?"
# 4. Status
ragx stats
```
### As a Python Library
```python
from ragx import RAGEngine
engine = RAGEngine()
engine.ingest_path("./docs")
ans = engine.answer("What vector store does the project use?")
print(ans.text)
for c in ans.citations:
print(c.marker, c.source, c.metadata)
```
### As MCP Server (for Claude Code / Desktop / Cursor)
```bash
ragx serve-mcp
```
Claude Desktop configuration:
```json
{ "mcpServers": { "ragx": { "command": "ragx", "args": ["serve-mcp"] } } }
```
Exposed tools: `rag_answer`, `rag_graph_answer` (requires GraphRAG), `rag_search`, `rag_ingest`, `rag_stats`.
### As REST API
```bash
ragx serve-rest --port 8000 # open http://localhost:8000/docs
```
- `POST /ingest` `{path | url | text(+source)}`
- `POST /search` `{query, top_k?, top_n?, use_hybrid?}`
- `POST /answer` `{query, reflect?, route?}` → answer + citations
- `POST /answer/stream` `{query, ...}` → SSE streaming (token / reflection / final events)
- `POST /graph/answer` `{query}` → GraphRAG fusion QA (requires `RAGX_ENABLE_GRAPH=true`)
- `POST /eval` `{cases:[...]}` → batch evaluation
- `GET /stats`、`GET /health`
> `route` values: `auto|vector|graph|hybrid`, invalid values return 422.
#### OpenAI Compatible Endpoint
`POST /v1/chat/completions` (+ `GET /v1/models`) allows ragx to be used as a "knowledge-aware model",
directly accessible from any OpenAI client (OpenAI SDK / ChatBox / Cherry Studio / LangChain, etc.):
```python
from openai import OpenAI
client = OpenAI(base_url="https://your-host/v1", api_key="<RAGX_API_KEYS entry>")
print(client.chat.completions.create(model="ragx",
messages=[{"role":"user","content":"..."}]).choices[0].message.content)
```
Takes the last user message as the retrieval query, appends `[n] sources` to the answer; supports `stream`.
## Architecture
```
parsing → chunking → embedding(BGE-M3) → store(Qdrant: dense+sparse)
│
query ─► rewrite ─► retrieve(hybrid+RRF) ─► rerank(BGE) ─► [grade] ─► answer(Claude, with citations)
│
RAGEngine ── core engine
├── server_mcp.py (MCP)
└── server_rest.py (REST)
```
Module overview:
- Core: `config` · `types` · `parsing` · `chunking` · `embedding` · `reranking` · `store` · `retrieval` · `agent` · `engine` · `llm` · `prompts`
- v2 foundation: `logging` · `errors` · `registry` (deduplication + vision caching)
- v2 features: `eval` (evaluation) · `media` + `vision` (multimodal) · `graph_index` + `router` + `graph_agent` (GraphRAG)
- Interfaces: `cli` · `server_mcp` · `server_rest`
## Concurrency Notes
Default local embedded Qdrant single-process exclusive directory. For concurrent REST/MCP and background ingestion,
use Docker to run Qdrant:
```bash
docker run -p 6333:6333 qdrant/qdrant
export RAGX_QDRANT_URL=http://localhost:6333
```
## Advanced Features (v2, disabled by default, enable as needed)
All advanced features are **disabled** by default, behaving like v1 core path; enable through `.env` switches or command-line arguments.
### Incremental Deduplication (enabled by default)
Content hash registry (SQLite), automatically skips unchanged files during ingestion; `--force` forces re-ingestion.
### Self-RAG Reflection
Self-evaluation, rewriting queries to supplement retrieval (bounded iteration):
```bash
ragx ask --reflect "questions requiring multi-hop reasoning"
# or globally enable: RAGX_ENABLE_REFLECTION=true
```
### Multimodal (tables + images + formulas)
Structured table extraction (no cost), images/charts/formulas transcribed by Claude vision and cached by content hash:
```bash
pip install -e ".[vision]"
ragx ingest ./report.pdf --vision # or RAGX_ENABLE_VISION=true
```
### GraphRAG Multi-Hop (integrates LightRAG)
Global/relational questions use knowledge graph + vector evidence fusion; query routing (including "relation/overall/between" signals to graph):
```bash
pip install -e ".[graph]"
export RAGX_ENABLE_GRAPH=true
ragx ingest ./docs # build graph during ingestion
ragx ask --route hybrid "outline relationships between modules"
ragx graph-stats
```
LightRAG reuses this project's BGE embedding and Claude, storing in `.ragx/lightrag/`; graph features degrade to vector retrieval if `[graph]` is not installed.
### Evaluation Framework (RAGAS-style)
```bash
ragx eval examples/eval_cases.jsonl --out report.json
# metrics: recall / faithfulness / answer correctness / citation accuracy + average latency (LLM-as-judge)
```
## Engineering Foundation (v2)
Structured logging (`RAGX_LOG_LEVEL`), typed exceptions, lazy model loading with thread safety (double-checked locking),
per-request overrides (`top_k/top_n/use_hybrid/reflect/route` can be overridden in CLI/REST/MCP single calls),
embedding dimension validation, input safeguards, and timeouts. 57 tests cover chunking/deduplication/hybrid retrieval/citations/reflection/multimodal/routing/authentication/OpenAI backend.
## External Deployment (Docker: Caddy auto-HTTPS + Qdrant + authentication)
Repository includes `Dockerfile` / `docker-compose.yml` / `Caddyfile`. Architecture: **only Caddy exposes public network (443)**,
reverse-proxying to internal ragx (with Bearer authentication), ragx connects to internal Qdrant; relay station/Anthropic key exists only in ragx container.
```bash
cp .env.example .env # fill RAGX_LLM_PROVIDER / RAGX_OPENAI_* / RAGX_API_KEYS (required for external access)
# Caddyfile replace rag.example.com with a domain resolving to this machine (pure IP cannot obtain Let's Encrypt certificate)
mkdir -p docs # documents to ingest placed here
docker compose up -d --build # initial build takes longer; models downloaded and cached during first ingest
docker compose exec ragx ragx ingest /data/docs # ingest (management operations via container CLI, not through public network)
```
External calls (with key):
```bash
curl -X POST https://rag.example.com/answer \
-H "Authorization: Bearer <RAGX_API_KEYS entry>" \
-H "Content-Type: application/json" -d '{"query":"..."}'
```
**Authentication and Authorization**: `RAGX_API_KEYS`=read-only (`/answer` `/search` `/stats`); `RAGX_ADMIN_API_KEYS`=write access (`/ingest` `/eval`),
leaving blank allows any read key to write. `/health` is not authenticated (for liveness probe). **No key = no authentication, only for local/internal networks**.
## Roadmap
- [ ] LightRAG end-to-end testing (requires `[graph]` + API key)
- [ ] Evaluation integration with ragas official metrics
- [ ] Asynchronous ingestion and multi-process concurrency (with Docker Qdrant)
- [ ] Graph incremental rebuild command `graph-rebuild`
## License
MIT