pi-rag is a read-only Retrieval-Augmented Generation (RAG) extension for Pi.
It lets Pi search one or more configured knowledge bases, retrieve bounded passages from a vector database, and return those passages with source metadata so the agent can use them in grounded answers.
The repository also contains a separate Python ingestion CLI for parsing documents with Docling, creating embeddings, and loading vectors and metadata into Qdrant.
At query time:
- Pi calls
rag_search. pi-ragembeds the user query using the configured embedding provider.- The extension searches the configured vector store.
- Matching chunks are returned with source metadata such as title, path, page, section, and business metadata.
- Pi uses those retrieved passages as context for its answer.
At ingestion time, the Python CLI:
- discovers supported documents;
- parses them with Docling;
- splits them into chunks;
- creates embeddings through an OpenAI-compatible endpoint or Ollama;
- creates or validates the Qdrant collection;
- writes vectors and metadata to Qdrant;
- records an ingestion report.
For Qdrant, the ingestion CLI and the Pi extension use the same rag.json configuration so that the embedding model, collection, vector name, payload mapping, and search settings remain consistent. The extension also reads pgvector and ChromaDB knowledge bases from this file, but the bundled Python CLI does not ingest into those backends.
The read-only Pi extension supports:
- Qdrant through its REST API;
- PostgreSQL with the pgvector extension through the PostgreSQL protocol;
- ChromaDB through its v2 HTTP API.
All three adapters share knowledge-base, embedding, payload mapping, filter allow-list, score threshold, and context-budget configuration. The Python ingestion CLI remains Qdrant-only by design; use your existing ingestion pipeline for pgvector or ChromaDB.
The extension currently supports:
- OpenAI-compatible embedding endpoints;
- Ollama.
This means the actual embedding model can be OpenAI, Jina, Qwen, BGE, or another model as long as the endpoint implements the expected API contract.
For an OpenAI-compatible provider, pi-rag sends:
POST <baseUrl>/embeddings
Authorization: Bearer <token>
Content-Type: application/jsonwith a JSON body similar to:
{
"model": "your-embedding-model",
"input": "text to embed"
}The token is read from an environment variable referenced by apiKeyEnv.
- Node.js
>=22.19.0 - Pi
- a reachable Qdrant, PostgreSQL/pgvector, or ChromaDB instance
- an embedding endpoint compatible with OpenAI
/embeddingsor Ollama
- Python 3.11+
- the Python dependencies from
scripts/requirements-ingest.txt - Qdrant
- the same embedding provider used by the knowledge base
Docling can download model artifacts at first use. In restricted or offline enterprise environments, those artifacts may need to be preloaded in the local Hugging Face cache or otherwise made available offline.
The package is published as:
@raguets/pi-rag
Install it in Pi with:
pi install npm:@raguets/pi-ragTo test it without permanently installing it:
pi -e npm:@raguets/pi-ragpi install git:github.com/raguets/pi-ragA tagged version can be pinned explicitly:
pi install git:github.com/raguets/pi-rag@v0.1.0Clone the repository:
git clone https://github.com/raguets/pi-rag.git
cd pi-ragInstall and build the Node.js extension:
npm install
npm run buildThen install the local package in Pi.
pi install .pi.cmd install .If the PowerShell execution policy blocks pi.ps1, use pi.cmd.
After a local installation, Pi keeps the project path. When the TypeScript source changes, rebuild it:
npm run buildThen restart Pi. You normally do not need to run pi install . again.
Create a virtual environment:
python3 -m venv .venvActivate it:
source .venv/bin/activateInstall the ingestion dependencies:
python -m pip install --upgrade pip
python -m pip install -r scripts/requirements-ingest.txtDeactivate later with:
deactivateCreate the environment:
python -m venv .venvActivate it:
.\.venv\Scripts\Activate.ps1Install dependencies:
python -m pip install --upgrade pip
python -m pip install -r scripts/requirements-ingest.txtIf PowerShell activation is restricted, the Python executable can be called directly:
.\.venv\Scripts\python.exe -m pip install -r scripts/requirements-ingest.txtA local Docker instance is convenient for development.
docker volume create qdrant-storage
docker run -d \
--name qdrant \
-p 127.0.0.1:6333:6333 \
-p 127.0.0.1:6334:6334 \
-v qdrant-storage:/qdrant/storage \
qdrant/qdrant:latestOnce created, the container can be restarted with:
docker start qdrantCheck it:
curl http://localhost:6333The local dashboard is usually available at:
http://localhost:6333/dashboard
For reproducible production deployments, prefer pinning a specific Qdrant version instead of using latest.
Copy the example configuration:
mkdir -p .pi
cp examples/rag.json .pi/rag.jsonpi-rag searches for configuration in the following ways:
- project configuration:
.pi/rag.json; - global configuration:
~/.pi/agent/rag.json; - explicit configuration selected with
PI_RAG_CONFIG.
Example:
export PI_RAG_CONFIG="$HOME/.pi/agent/rag.json"$env:PI_RAG_CONFIG = "$HOME\.pi\agent\rag.json"Secrets must not be written directly into rag.json. apiKeyEnv contains the name of an environment variable, not the secret itself.
A typical configuration looks like this:
{
"version": 1,
"embeddingProviders": {
"local": {
"type": "openai-compatible",
"baseUrl": "http://localhost:11434/v1",
"model": "qwen3-embedding:0.6b",
"expectedDimensions": 1024,
"queryTemplate": "Instruct: Given a user question in French or English, retrieve relevant passages from enterprise documents that answer the question\nQuery: {{query}}"
}
},
"vectorStores": {
"qdrant-local": {
"type": "qdrant",
"url": "http://localhost:6333",
"apiKeyEnv": "QDRANT_API_KEY"
}
},
"knowledgeBases": {
"contract-library": {
"description": "Contracts and contractual precedents",
"vectorStore": "qdrant-local",
"embeddingProvider": "local",
"collection": "contracts",
"vectorName": "text",
"dimensions": 1024,
"distance": "cosine",
"payload": {
"content": "content",
"title": "document_title",
"source": "source_path",
"page": "page",
"section": "section",
"metadata": ["customer", "contract_type", "year", "business_domain"]
},
"filterableFields": ["customer", "contract_type", "year", "business_domain", "document_type"],
"search": {
"topK": 8,
"maxTopK": 30,
"scoreThreshold": 0.45,
"maxCharsPerChunk": 4000,
"maxTotalChars": 20000
},
"ingestion": {
"inputDirectory": "./data/contracts",
"recursive": true,
"chunking": {
"strategy": "docling-hybrid",
"maxTokens": 700
},
"embeddingText": {
"includeTitle": true,
"includeHeadings": true
},
"batchSize": 32,
"timeoutSeconds": 60,
"maxRetries": 3,
"distance": "cosine"
}
}
}
}"version": 1The current schema accepts version 1.
embeddingProviders is a dictionary of named embedding configurations. A knowledge base refers to one of these names through embeddingProvider.
"embeddingProviders": {
"enterprise": {
"type": "openai-compatible",
"baseUrl": "https://gateway.example.com/v1",
"model": "my-embedding-model",
"apiKeyEnv": "EMBEDDING_API_KEY",
"expectedDimensions": 1024,
"queryTemplate": "{{query}}",
"timeoutSeconds": 60,
"maxRetries": 3
}
}| Property | Required | Meaning |
|---|---|---|
type |
yes | openai-compatible or ollama |
baseUrl |
yes | Provider base URL |
model |
yes | Model name sent to the provider |
apiKeyEnv |
no | Environment variable containing the API key/token |
expectedDimensions |
no | Expected query-vector size; retrieval fails if the provider returns another dimension |
queryTemplate |
no | Template applied to retrieval queries; {{query}} is replaced with the user's query |
timeoutSeconds |
no | Provider timeout, default 60 |
maxRetries |
no | Retry count, default 3 |
queryTemplate affects query embeddings generated by the Pi extension. It can be useful for models that expect an instruction or a query-specific prefix.
Example:
"queryTemplate": "Represent this sentence for searching relevant passages: {{query}}"The text embedded during ingestion must remain compatible with the same embedding model and retrieval strategy.
export EMBEDDING_API_KEY='your-token'$env:EMBEDDING_API_KEY = "your-token"The environment variable must be present in the environment from which Pi or the ingestion process is launched.
"embeddingProviders": {
"ollama": {
"type": "ollama",
"baseUrl": "http://localhost:11434",
"model": "qwen3-embedding:0.6b",
"expectedDimensions": 1024,
"queryTemplate": "{{query}}"
}
}Choose the adapter with type. Connection secrets are always referenced by environment-variable name.
"vectorStores": {
"qdrant-local": {
"type": "qdrant",
"url": "http://localhost:6333"
}
}Authenticated Qdrant:
"vectorStores": {
"qdrant-prod": {
"type": "qdrant",
"url": "https://qdrant.example.com",
"apiKeyEnv": "QDRANT_API_KEY"
}
}Set the secret outside the JSON.
export QDRANT_API_KEY='your-key'$env:QDRANT_API_KEY = "your-key"| Property | Required | Meaning |
|---|---|---|
type |
yes | qdrant |
url |
yes | Qdrant REST endpoint |
apiKeyEnv |
no | environment variable containing the Qdrant API key |
"vectorStores": {
"postgres": {
"type": "pgvector",
"connectionStringEnv": "PI_RAG_DATABASE_URL",
"ssl": true,
"schema": "rag",
"idColumn": "id",
"maxConnections": 10,
"idleTimeoutSeconds": 30
}
}Set PI_RAG_DATABASE_URL=postgresql://user:password@host/database outside JSON. Instead of connectionStringEnv, you may configure host, port, database, user, and passwordEnv. schema defaults to public, idColumn to id, and the vector column is selected by the knowledge base's vectorName (default embedding). The PostgreSQL role needs read-only access to the selected schema/table. The vector extension and a compatible vector index must already exist.
"vectorStores": {
"chroma": {
"type": "chroma",
"url": "http://localhost:8000",
"tenant": "default_tenant",
"database": "default_database",
"apiKeyEnv": "CHROMA_API_KEY",
"apiKeyHeader": "x-chroma-token"
}
}tenant and database use the shown defaults. Omit both authentication properties for a local unauthenticated server. For hosted or proxied deployments, apiKeyHeader lets you select the header expected by the service. Chroma's native documents value is used as chunk content; payload maps title/source/page/section and extra fields from Chroma metadata.
Complete ready-to-copy configurations are provided in examples/rag.json, examples/rag-pgvector.json, and examples/rag-chroma.json.
Each entry in knowledgeBases is a logical knowledge base exposed to Pi.
Example:
"knowledgeBases": {
"contract-library": {
"description": "Contracts and precedents",
"vectorStore": "qdrant-local",
"embeddingProvider": "local",
"collection": "contracts"
}
}The key (contract-library) is the logical name used by rag_search, rag_status, and --knowledge-base. It is not a filesystem path.
| Property | Required | Meaning |
|---|---|---|
description |
no | Human-readable description exposed to the agent |
vectorStore |
yes | Name of an entry in vectorStores |
embeddingProvider |
yes | Name of an entry in embeddingProviders |
collection |
yes | Qdrant/Chroma collection or pgvector table |
vectorName |
no | Qdrant named vector or pgvector column (default embedding for pgvector; unused by Chroma) |
dimensions |
Chroma: yes | Vector dimensions; also a fallback for unconstrained pgvector columns |
distance |
no | cosine (default), dot, euclid, or manhattan |
payload |
no | Maps generic RAG fields to payload, metadata, or SQL columns |
filterableFields |
no | Fields allowed in search filters |
search |
no | Retrieval limits and thresholds |
ingestion |
no | Settings used by the Python Qdrant ingestion CLI |
The payload mapping tells pi-rag which backend fields contain the returned text and source information. With pgvector these are column names; with Qdrant they are payload keys; with Chroma all except content are metadata keys (content comes from the native document).
"payload": {
"content": "content",
"title": "document_title",
"source": "source_path",
"page": "page",
"section": "section",
"metadata": ["customer", "contract_type", "year"]
}Properties:
content: field containing the chunk text. Defaults tocontent.title: optional document title field.source: optional source path or source identifier.page: optional page number field.section: optional section field.metadata: additional payload fields returned with search hits.
This mapping is especially important when querying a collection or table created by another ingestion pipeline.
Only fields explicitly declared here can be used as RAG filters:
"filterableFields": ["customer", "contract_type", "year", "business_domain", "document_type"]Example agent filter:
{
"and": [
{"field": "contract_type", "op": "eq", "value": "customer"},
{"field": "year", "op": "gte", "value": 2022}
]
}Filters are compiled into the backend-native syntax and values are parameterized for PostgreSQL. Declaring a field as filterable also lets the Qdrant ingestion script create appropriate payload indexes.
"search": {
"topK": 8,
"maxTopK": 30,
"scoreThreshold": 0.45,
"maxCharsPerChunk": 4000,
"maxTotalChars": 20000
}| Property | Default | Meaning |
|---|---|---|
topK |
8 |
Default number of retrieved chunks |
maxTopK |
30 |
Maximum value accepted for a requested top_k |
scoreThreshold |
none | Optional minimum similarity score |
maxCharsPerChunk |
4000 |
Maximum chunk text returned to Pi |
maxTotalChars |
20000 |
Maximum combined text returned by one search |
These limits keep RAG results bounded before they are inserted into the agent context.
The ingestion object is consumed by scripts/ingest_qdrant.py.
"ingestion": {
"inputDirectory": "./data/contracts",
"recursive": true,
"chunking": {
"strategy": "docling-hybrid",
"maxTokens": 700
},
"embeddingText": {
"includeTitle": true,
"includeHeadings": true
},
"batchSize": 32,
"timeoutSeconds": 60,
"maxRetries": 3,
"distance": "cosine"
}Default directory containing the corpus. It can be overridden with --input.
When true, subdirectories are traversed recursively.
The current GitHub ingestion script uses Docling's HybridChunker.
"chunking": {
"strategy": "docling-hybrid",
"maxTokens": 700,
"tokenizer": "Qwen/Qwen3-Embedding-0.6B"
}tokenizer is optional in the current script. If omitted, the current script defaults to Qwen/Qwen3-Embedding-0.6B.
The tokenizer is used for chunk-size accounting. It is separate from the remote embedding request itself.
In restricted/offline environments, the tokenizer and Docling model artifacts may need to be available locally.
Controls the text sent to the embedding provider for each chunk:
"embeddingText": {
"includeTitle": true,
"includeHeadings": true
}When enabled, the script prefixes the chunk with the document title and/or section headings before embedding it. The original chunk content stored in the Qdrant payload remains available separately.
Number of chunk texts sent in one embedding request. The command-line --batch-size option overrides it.
Embedding HTTP timeout.
Number of retries for transient embedding errors.
Qdrant vector distance, for example cosine. The existing collection must use a compatible vector dimension and distance.
The ingestion script can use explicit Qdrant payload index types:
"filterFields": {
"customer": "keyword",
"contract_type": "keyword",
"year": "integer"
}If not specified, common numeric fields such as year, page, and chunk_index are treated as integer fields; other filterable fields default to keyword indexes.
The current ingestion script discovers:
.pdf
.docx
.pptx
.xlsx
.html
.htm
.md
.txt
.doc
.ppt
.xls
.odt
.ods
.odp
.png
.jpg
.jpeg
.tiff
Actual parsing support can also depend on the installed Docling stack and system/model availability.
Temporary Microsoft Office files beginning with ~$ are ignored. Hidden files and directories are ignored by default.
A corpus can include an optional metadata.csv or metadata.json next to the documents.
The CSV must contain a source_path column.
source_path,customer,contract_type,year,business_domain
01-contract.pdf,ACME,customer,2026,naval
02-framework.docx,ExampleCo,supplier,2025,engineeringsource_path must match the path relative to the ingestion root. Simple CSV values are automatically converted to booleans, integers, or floats when possible.
[
{
"source_path": "01-contract.pdf",
"customer": "ACME",
"contract_type": "customer",
"year": 2026
}
]{
"01-contract.pdf": {
"customer": "ACME",
"year": 2026
}
}The logical knowledge-base name is mandatory.
Using the input directory from rag.json:
python scripts/ingest_qdrant.py \
--config .pi/rag.json \
--knowledge-base contract-libraryUsing a global config:
python scripts/ingest_qdrant.py \
--config "$HOME/.pi/agent/rag.json" \
--knowledge-base contract-libraryOverride the corpus directory:
python scripts/ingest_qdrant.py \
--config "$HOME/.pi/agent/rag.json" \
--knowledge-base contract-library \
--input ./test-docs \
--verboseDry run:
python scripts/ingest_qdrant.py \
--config .pi/rag.json \
--knowledge-base contract-library \
--dry-run.\.venv\Scripts\python.exe scripts\ingest_qdrant.py `
--config "$HOME\.pi\agent\rag.json" `
--knowledge-base contract-library `
--input .\test-docs `
--verboseDry run:
.\.venv\Scripts\python.exe scripts\ingest_qdrant.py `
--config .pi\rag.json `
--knowledge-base contract-library `
--dry-runConfiguration file. Default: .pi/rag.json.
Required logical name under knowledgeBases.
--knowledge-base contract-libraryOverrides ingestion.inputDirectory. It can point to a directory or one supported file.
Repeatable include glob pattern.
--include "*.pdf" --include "*.docx"Patterns are matched against both the relative path and filename.
Repeatable exclude glob pattern.
--exclude "*draft*" --exclude "archive/*"Overrides ingestion.batchSize.
--batch-size 8Use a smaller batch if an embedding gateway imposes payload limits.
Parses and chunks documents without creating embeddings or writing vectors to Qdrant.
Normally, a document whose current content version is already present is skipped. --force processes it again.
After ingestion, deletes Qdrant documents whose document_id is no longer present in the current input corpus.
Use this carefully: the input corpus becomes the source of truth for that collection.
Deletes and recreates the configured Qdrant collection before ingestion. This is destructive and normally asks for confirmation.
Automatically confirms destructive prompts, especially with --recreate.
--recreate --yesStops on the first file error instead of continuing.
--include-hidden
Includes hidden files and directories that are ignored by default.
Prints individual ingestion errors to stderr.
The ingestion script computes SHA-256 based identifiers.
A document version is derived from the file contents. If the same source path and document version already exist in Qdrant, the file is skipped unless --force is used.
When an updated document is successfully written, obsolete versions of the same document_id are removed.
This lets repeated ingestion runs avoid re-embedding unchanged files while keeping updated documents synchronized.
Each execution writes a JSON report under .ingestion/ relative to the configuration location.
For example, with:
~/.pi/agent/rag.json
reports are written under:
~/.pi/.ingestion/
A report includes selected knowledge base, collection, files discovered/processed/skipped/failed, chunks created, vectors inserted, embedding model, detected dimension, distance, errors, and duration.
Inspect a report on macOS/Linux without jq:
python -m json.tool ~/.pi/.ingestion/contract-library-YYYYMMDD-HHMMSS.jsonrag.json:
{
"apiKeyEnv": "EMBEDDING_API_KEY"
}macOS / Linux:
export EMBEDDING_API_KEY='secret'Windows PowerShell:
$env:EMBEDDING_API_KEY = "secret"macOS / Linux:
export QDRANT_API_KEY='secret'Windows PowerShell:
$env:QDRANT_API_KEY = "secret"Do not commit secrets to rag.json.
The current code does not automatically load a .env file.
Internal API gateways may use a private corporate CA.
For Python/httpx ingestion, configure the trusted CA instead of disabling TLS verification:
export SSL_CERT_FILE=/path/to/company-ca-bundle.pemFor the Node.js Pi extension, an additional enterprise CA can commonly be provided with:
export NODE_EXTRA_CA_CERTS=/path/to/company-ca-bundle.pemWindows PowerShell:
$env:SSL_CERT_FILE = "C:\path\company-ca-bundle.pem"
$env:NODE_EXTRA_CA_CERTS = "C:\path\company-ca-bundle.pem"Avoid permanently disabling certificate verification.
Docling may require model artifacts for document layout, table structure, OCR, or other processing steps.
In restricted environments, pre-populate the required Hugging Face cache and run with:
HF_HUB_OFFLINE=1 python scripts/ingest_qdrant.py \
--config "$HOME/.pi/agent/rag.json" \
--knowledge-base contract-libraryor:
export HF_HUB_OFFLINE=1$env:HF_HUB_OFFLINE = "1"Offline mode only works when all required model artifacts and revision references are already present in the local cache.
Restart Pi after installation or after rebuilding the local extension.
pipi.cmdList configured knowledge bases:
/rag
Ask Pi to search a knowledge base:
/rag What obligations apply to the supplier?
The command instructs the agent to use rag_search and preserve source citations in its answer.
The extension does not add a dedicated RAG panel to the UI.
Lists configured logical knowledge bases and their descriptions.
Embeds a query, searches the configured vector collection or table, and returns bounded chunks with source metadata.
Main arguments include query, knowledge_base, top_k, and optional filters.
Checks knowledge-base configuration and connectivity, including the embedding provider and vector index information, without exposing secrets.
Only fields listed under filterableFields may be used.
Example:
{
"and": [
{"field": "contract_type", "op": "eq", "value": "customer"},
{"field": "year", "op": "gte", "value": 2022}
]
}Use metadata and payload indexes for frequently filtered fields.
The embedding model used by the Pi extension must be compatible with the model used to create the vectors stored in Qdrant.
Keep these aligned:
- model semantics;
- vector dimension;
- normalization/distance assumptions;
- query/document instruction strategy;
- collection;
- vector name.
For example, if documents were embedded as 1024-dimensional vectors, a 768-dimensional query embedding cannot be searched against the same dense-vector field.
expectedDimensions can be used to detect an unexpected query-vector size before sending it to Qdrant.
The Python ingestion script is optional.
You can point pi-rag at an existing Qdrant collection produced by another system as long as:
- the query embedding provider is compatible with the stored vectors;
collectionandvectorNameare correct;- the configured payload mapping matches the existing Qdrant payload fields;
- any filter fields are declared in
filterableFields.
Example:
{
"knowledgeBases": {
"existing-corpus": {
"description": "Existing enterprise vector corpus",
"vectorStore": "qdrant-prod",
"embeddingProvider": "enterprise-embedding",
"collection": "enterprise-documents",
"vectorName": "dense",
"payload": {
"content": "text",
"title": "title",
"source": "uri",
"page": "page_number",
"section": "heading",
"metadata": ["department", "classification"]
},
"filterableFields": ["department", "classification"]
}
}
}A single rag.json can declare several knowledge bases. They may mix Qdrant, pgvector, and ChromaDB stores, collections or tables, vector fields, embedding providers, search thresholds, payload mappings, and metadata filters.
{
"version": 1,
"embeddingProviders": {
"local": {
"type": "openai-compatible",
"baseUrl": "http://localhost:11434/v1",
"model": "qwen3-embedding:0.6b",
"expectedDimensions": 1024
}
},
"vectorStores": {
"local-qdrant": {
"type": "qdrant",
"url": "http://localhost:6333"
}
},
"knowledgeBases": {
"contracts": {
"description": "Contracts",
"vectorStore": "local-qdrant",
"embeddingProvider": "local",
"collection": "contracts",
"vectorName": "text"
},
"technical-docs": {
"description": "Technical documentation",
"vectorStore": "local-qdrant",
"embeddingProvider": "local",
"collection": "technical-docs",
"vectorName": "text"
}
}
}npm ci
npm run check
npm test
npm run buildPython tests on macOS/Linux:
python -m unittest discover -s test/pythonWindows:
.\.venv\Scripts\python.exe -m unittest discover -s test\pythonThe source tree separates generic interfaces from implementations:
src/
├── config/
├── core/
├── embeddings/
├── stores/
│ ├── vector-store-adapter.ts
│ └── qdrant/
├── tools/
└── index.ts
VectorStoreAdapter defines the generic retrieval contract:
healthCheck(...)describe(...)search(...)- optional
close()
This makes additional vector databases technically possible, but each backend still requires:
- a concrete adapter implementation;
- adapter registration/factory wiring;
- configuration-schema support;
- mapping of filters and metadata semantics;
- tests.
Qdrant, pgvector, and ChromaDB are implemented. A new backend only needs another VectorStoreAdapter, its configuration-schema variant, factory registration, and native filter translation; the service, tools, embedding providers, result formatting, and budgets remain shared.
The npm package is:
@raguets/pi-rag
Validate before publishing:
npm ci
npm run check
npm test
npm run build
npm pack --dry-runCreate and inspect a real tarball:
npm packPublish a public scoped package:
npm publish --access publicVerify:
npm view @raguets/pi-ragTest directly through Pi:
pi -e npm:@raguets/pi-ragInstall:
pi install npm:@raguets/pi-ragFor a new release:
npm version patch
git push origin main --follow-tags
npm publish --access publicDo not overwrite an existing npm release.
The query embedding dimension does not match expectedDimensions. Check the embedding model, gateway model alias, configured dimension, and Qdrant vector-field dimension.
Check the environment variable referenced by apiKeyEnv.
macOS / Linux:
echo "${EMBEDDING_API_KEY:+set}"Windows PowerShell:
if ($env:EMBEDDING_API_KEY) { "set" } else { "missing" }Do not print production tokens into shared logs.
Configure your corporate CA using SSL_CERT_FILE for Python and, where applicable, NODE_EXTRA_CA_CERTS for Node.js.
curl http://localhost:6333
docker ps
docker logs qdrantThis is normal idempotent behavior. Use --force to process them again.
Use:
--recreateor non-interactively:
--recreate --yesThis deletes the configured collection.
Preload all required model artifacts and revisions, then use:
export HF_HUB_OFFLINE=1The exact required models depend on the installed Docling version and document-processing pipeline.
- Do not store API keys or tokens directly in
rag.json. - Use
apiKeyEnv. - Do not commit
.envfiles, enterprise documents, local ingestion reports, or private certificates. - Keep Qdrant and embedding endpoints restricted according to your deployment requirements.
- Prefer trusted CA bundles over disabling TLS verification.
- Treat retrieved documents and metadata according to their classification and access-control requirements.
MIT