### All configurable environment variable must show up in this sample file in active or comment out status ### Setup tool `make env-*` uses this file to generate final .env file ### Target environment of this env file: host/compose (compose is for Docker or Kubernetes) # LIGHTRAG_RUNTIME_TARGET=host ########################### ### Server Configuration ########################### ### HOST binds to all network interfaces (0.0.0.0) by default. ### SECURITY: only expose 0.0.0.0 together with LIGHTRAG_API_KEY or AUTH_ACCOUNTS ### (see "Login and API-Key Configuration" below). Without authentication, a ### server on 0.0.0.0 grants anyone on the network full access to your documents ### and knowledge graph. Bind to 127.0.0.1 for local-only access. HOST=0.0.0.0 PORT=9621 ### Deployment name shown in WebUI headers, on the login page, and as the browser tab title. ### Leave unset to keep the default 'LightRAG'. WEBUI_TITLE='My Graph KB' WEBUI_DESCRIPTION='Simple and Fast Graph Based RAG System' ### Show an "AI-generated content" notice on every answer in the WebUI ### retrieval panel (/webui) and the query entry (/workspace). It is appended ### to the response-time line below the answer, not given a line of its own. ### Enable it where machine-generated output must be labelled. The notice is a ### UI element only: it is never added to the API response or to the stored ### chat history, and its wording follows the interface language. # ENABLE_AI_CONTENT_NOTICE=false # WORKERS=2 ### gunicorn worker timeout(as default LLM request timeout if LLM_TIMEOUT is not set) # TIMEOUT=150 ### Ceiling on how long one knowledge-graph admin edit (entity/relation ### create, edit, delete, merge; custom KG insert) may hold the workspace ### admin lock and the pipeline busy reservation. Applies only with ### LIGHTRAG_GRAPH_STORAGE=NetworkXStorage, where such an edit defers a ### pipeline start for its duration; server-backed graph stores are not ### gated. On expiry the edit fails with HTTP 500 and both are released. ### The failure does not mean the edit was undone: a commit already in flight ### is allowed to finish, so re-read the object before retrying. ### Defaults to max(180, 6 x EMBEDDING_TIMEOUT) -- 180 at the default ### embedding timeout of 30. Derived rather than fixed because the embedding ### round-trip runs inside the hold: raising EMBEDDING_TIMEOUT alone would ### otherwise leave a ceiling sized for the old value, killing every retry. ### One hold has to cover an embedding retry storm (3 x EMBEDDING_TIMEOUT plus ### 8s of backoff = 98s at the default) plus a whole-graph GraphML commit ### (~17s at 200k nodes -- the entire graph is rewritten however small the edit ### was), so ~115s, with the rest as headroom for the edges an edit touches. ### Resolved per LightRAG instance from its own embedding timeout, so a ### direct LightRAG(default_embedding_timeout=...) caller is followed without ### setting anything here. Setting this BELOW the embedding timeout is refused ### at startup. ### Prefer raising it over lowering it: too high only defers ingestion, which ### self-heals through the sticky rescan request, while too low kills edits ### whose commit may already have landed. # LIGHTRAG_ADMIN_WRITE_MAX_HOLD_SECONDS=180 ### How long a second concurrent knowledge-graph admin edit waits behind the ### first before giving up with HTTP 409 ("Another knowledge graph edit is in ### progress"). Same NetworkXStorage-only scope as the ceiling above. This is ### the only bound on that wait, and it is a responsiveness knob, NOT a ### derivative of the ceiling: it asks how long a caller should wait before ### being told to retry, so when the edit ahead runs long the queue is meant ### to fail fast rather than to wait longer. A value above ### LIGHTRAG_ADMIN_WRITE_MAX_HOLD_SECONDS is NOT pointless: the admin lock is ### taken before the ceiling starts and released after it ends, and an ### in-flight commit runs past the expiry, so the lock is always held longer ### than the ceiling and a longer wait can still be rewarded. # LIGHTRAG_ADMIN_WRITE_LOCK_ACQUIRE_TIMEOUT=30 ### CORS allowed origins for browser cross-origin requests. Defaults to "*" ### (any origin). The bundled WebUI is served same-origin and does not need ### this; set an explicit allowlist only when a different-origin web app calls ### the API from a browser. Credentialed (cookie) cross-origin requests are ### only enabled for an explicit allowlist, never for the "*" wildcard. # CORS_ORIGINS=http://localhost:3000,http://localhost:8080 ### Interactive API documentation (Swagger UI /docs, ReDoc /redoc and the ### /openapi.json schema). Set to false to disable all of them (each returns ### 404) — recommended for hardened production deployments. The WebUI hides ### its API-docs entry point automatically based on /health. # ENABLE_API_DOCS=true ### Default UI entry for the root path '/'. ### The server hosts two WebUI entries: /webui (admin: documents, knowledge ### graph, query debugging) and /workspace (query-only entry for everyday ### users). This variable controls EXACTLY ONE behavior — which entry '/' ### redirects to. Both entries stay mounted regardless. Allowed values: ### webui (default) or workspace; anything else fails startup. ### Query parameters on /workspace are inherited, not editable: each query ### uses the settings that /webui saved in the SAME BROWSER (frontend ### defaults when none were saved). This is per-browser local state, not a ### server-wide policy — an end user opening /workspace on their own device ### gets the frontend defaults, not the parameters an admin saved elsewhere. # LIGHTRAG_DEFAULT_UI=webui ### Path Prefix Configuration (Optional) ### Used to host multiple LightRAG instances on one host behind a reverse ### proxy that routes by site prefix. Leave unset (or empty) for a ### single-instance deployment. ### ### - LIGHTRAG_API_PREFIX : reverse-proxy prefix the upstream proxy strips ### before forwarding (passed to FastAPI as root_path). ### ### See docs/MultiSiteDeployment.md for end-to-end examples. # LIGHTRAG_API_PREFIX=/site01 ### Optional read-only UI customization bundle: the welcome page, the query ### empty state, the login-page text and user agreement, the copyright line, ### and the brand logo (multi-language). Unset means "no customization": the ### frontend shows its built-in branding. A directory that holds no ### manifest.json yet means the same thing (logged as a warning at startup). ### Once manifest.json is there, the bundle must be complete and valid ### (manifest.json + locales/ + assets/) or the server refuses to start. This ### value is for host/source runs: the compose files set the container path in ### their environment: block, which overrides the value here, so one .env ### serves both deployments. Changes require a restart of all workers. See ### docs/UserDefinedUI.md for the full guide, and docs/ui_templates_example/ ### for a ready-to-copy example bundle. # UI_TEMPLATES_DIR=./lightrag_webui/ui_templates ### Optional SSL Configuration ### Docker note: generated compose files mount staged certs at /app/data/certs/ inside the container # SSL=true # SSL_CERTFILE=/path/to/cert.pem # SSL_KEYFILE=/path/to/key.pem ### Directory Configuration (defaults to current working directory) ### Default value is: ./inputs ./rag_storage # INPUT_DIR= # WORKING_DIR= ### Tiktoken cache directory (Store cached files in this folder for offline deployment) # TIKTOKEN_CACHE_DIR=/app/data/tiktoken ### Ollama Emulating Model and Tag # OLLAMA_EMULATING_MODEL_NAME=lightrag OLLAMA_EMULATING_MODEL_TAG=latest ### Max nodes for graph retrieval (Ensure WebUI local settings are also updated, which is limited to this value) # MAX_GRAPH_NODES=1000 ### Logging level # LOG_LEVEL=INFO # VERBOSE=False # LOG_MAX_BYTES=10485760 # LOG_BACKUP_COUNT=5 ### Logfile location (defaults to current working directory) # LOG_DIR=/path/to/log/directory # LIGHTRAG_PERFORMANCE_TIMING_LOGS=false ##################################### ### Login and API-Key Configuration ##################################### ### SECURITY: If neither AUTH_ACCOUNTS nor LIGHTRAG_API_KEY is set, the server ### runs with NO authentication and every endpoint is publicly accessible. ### This is only safe on a loopback bind (HOST=127.0.0.1). Before exposing the ### server to a network (HOST=0.0.0.0), configure at least one of the two below. ### NOTE: AUTH_ACCOUNTS additionally requires TOKEN_SECRET to be set to a ### non-default value, otherwise the server refuses to start. ### NOTE: even with authentication enabled, the default WHITELIST_PATHS below ### exempts /api/* so the Ollama-compatible endpoints (/api/chat, /api/generate, ### ...) stay open by default, matching Ollama's own unauthenticated behavior. ### Those routes invoke the LLM and read your knowledge base, so if you expose ### the server to a network and want them protected, set WHITELIST_PATHS=/health ### (and have your Ollama clients send the API key). See WHITELIST_PATHS below. # AUTH_ACCOUNTS='admin:admin123,user1:{bcrypt}$2b$12$S8Yu.gCbuAbNTJFB.231gegTwr5pgrFxc8H9kXQ4/sduFBHkhM8Ka' # TOKEN_SECRET=lightrag-jwt-default-secret-key! # JWT_ALGORITHM=HS256 # TOKEN_EXPIRE_HOURS=48 # GUEST_TOKEN_EXPIRE_HOURS=24 ### Login brute-force protection (POST /login). ### After LOGIN_MAX_FAILED_ATTEMPTS failed attempts from the same client IP for ### the same username within LOGIN_LOCKOUT_WINDOW_SECONDS, further attempts are ### rejected with HTTP 429 until the window passes; a successful login resets it. ### Set LOGIN_MAX_FAILED_ATTEMPTS=0 to disable. Counters are per server process ### (in-memory): under gunicorn with N workers the effective limit is N x the ### value below; use a reverse-proxy / WAF rate limit for strict enforcement. # LOGIN_MAX_FAILED_ATTEMPTS=5 # LOGIN_LOCKOUT_WINDOW_SECONDS=300 ### Token Auto-Renewal Configuration (Sliding Window Expiration) ### Enable automatic token renewal to prevent active users from being logged out ### When enabled, tokens will be automatically renewed when remaining time < threshold # TOKEN_AUTO_RENEW=true ### Token renewal threshold (0.0 - 1.0) ### Renew token when remaining time < (total time * threshold) ### Default: 0.5 (renew when 50% time remaining) ### Examples: ### 0.5 = renew when 24h token has 12h left ### 0.25 = renew when 24h token has 6h left # TOKEN_RENEW_THRESHOLD=0.5 ### Note: Token renewal is automatically skipped for certain endpoints: ### - /health: Health check endpoint (no authentication required) ### - /documents/paginated: Frequently polled by client (5-30s interval) ### - /documents/pipeline_status: Very frequently polled by client (2s interval) ### - Rate limit: Minimum 60 seconds between renewals for same user ### API-Key to access LightRAG Server API ### Use this key in HTTP requests with the 'X-API-Key' header ### Example: curl -H "X-API-Key: your-secure-api-key-here" http://localhost:9621/query # LIGHTRAG_API_KEY=your-secure-api-key-here ### WHITELIST_PATHS: paths exempt from authentication. A /* suffix matches on ### path-segment boundaries, so /api/* covers /api and everything under /api/ ### (it does NOT match a sibling like /apikeys). ### Entries are internal route paths and must NOT include LIGHTRAG_API_PREFIX: ### the mount prefix is removed before matching, so /health here exempts ### /site01/health as the browser sees it (see docs/MultiSiteDeployment.md). ### Default keeps /api/* open for Ollama-client compatibility (Ollama is ### unauthenticated by default). To require auth on the Ollama routes too when ### the server is network-exposed, narrow this to /health. ### NOTE: /health stays whitelisted as a liveness probe, but it no longer leaks ### configuration to unauthenticated callers: anonymous requests get only ### liveness signals (status/versions/auth_mode/pipeline_busy), while the full ### runtime configuration is returned only to authenticated callers (valid JWT ### or X-API-Key). # WHITELIST_PATHS=/health,/api/* ###################################################################################### ### Query Configuration ### ### How to control the context length sent to LLM: ### MAX_ENTITY_TOKENS + MAX_RELATION_TOKENS < MAX_TOTAL_TOKENS ### Chunk_Tokens = MAX_TOTAL_TOKENS - Actual_Entity_Tokens - Actual_Relation_Tokens ###################################################################################### # LLM response cache for query (default=true,permanently disabled for streaming response) ENABLE_LLM_CACHE=false # COSINE_THRESHOLD=0.2 ### Number of entities or relations retrieved from KG # TOP_K=40 ### Maximum number or chunks for naive vector search # CHUNK_TOP_K=20 ### control the actual entities send to LLM # MAX_ENTITY_TOKENS=6000 ### control the actual relations send to LLM # MAX_RELATION_TOKENS=8000 ### control the maximum tokens send to LLM (include entities, relations and chunks) # MAX_TOTAL_TOKENS=30000 ### chunk selection strategies ### VECTOR: Pick KG chunks by vector similarity, delivered chunks to the LLM aligning more closely with naive retrieval ### WEIGHT: Pick KG chunks by entity and chunk weight, delivered more solely KG related chunks to the LLM ### If reranking is enabled, the impact of chunk selection strategies will be diminished. # KG_CHUNK_PICK_METHOD=VECTOR ### maximum number of related chunks per source entity or relation ### The chunk picker uses this value to determine the total number of chunks selected from KG(knowledge graph) ### Higher values increase re-ranking time # RELATED_CHUNK_NUMBER=5 ### Append each chunk's heading path (parent headings joined by " → ") as a ### `content_headings` field in the chunk JSON sent to the LLM. Costs extra tokens. ENABLE_CONTENT_HEADINGS=true ### Global instructions prepended to every request's user_prompt (the ### "Additional Instructions" section of the answer prompt). Empty by default. ### A request can opt out with the API field `disable_user_prompt_prefix`. ### - If a request's user_prompt is empty, this prefix alone becomes the ### instructions sent to the LLM. Only the API field above suppresses it. ### - Concatenated VERBATIM, with no separator inserted. End the value with ### \n\n yourself so it does not run into the request's own prompt. ### - Single line only. Use DOUBLE quotes with \n for line breaks; inside ### single quotes a \n stays literal. ### - `${...}` is substituted from the environment in BOTH quote styles and ### cannot be escaped. If your text contains `${`, use the file below. # USER_PROMPT_PREFIX="Please use Mermaid format for diagrams; the delimiter for LaTeX is $$. For inline citations, use the footnote marker syntax `[^1]`, where the `^` preceding the identifier indicates a footnote reference. When multiple citations are required at a single location, each ID should be enclosed in separate footnote markers (e.g., `[^1][^2][^3]`).\n" ### Read the global prefix from PROMPT_DIR/user_prompt/ instead ### (.md or .txt, UTF-8). Takes precedence over USER_PROMPT_PREFIX, and is the ### way to configure a long or multi-paragraph prefix. ### File name only, no directory separators. PROMPT_DIR defaults to ./prompts # USER_PROMPT_PREFIX_FILE=user_prompt_prefix.md ######################################################### ### Reranking configuration ### RERANK_BINDING type: null, cohere, jina, aliyun ### For rerank model deployed by vLLM use cohere binding ### If LightRAG deployed in Docker: ### uses host.docker.internal instead of localhost in RERANK_BINDING_HOST ######################################################### RERANK_BINDING=null # RERANK_MODEL=BAAI/bge-reranker-v2-m3 # RERANK_BINDING_HOST=http://localhost:8000/rerank # RERANK_BINDING_API_KEY=your_rerank_api_key_here ### rerank score chunk filter(set to 0.0 to keep all chunks, 0.6 or above if LLM is not strong enough) # MIN_RERANK_SCORE=0.0 ### Enable rerank by default in query params when RERANK_BINDING is not null # RERANK_BY_DEFAULT=True ### Rerank concurrency and timeout (independent from base LLM settings) ### MAX_ASYNC_RERANK falls back to MAX_ASYNC_LLM when unset. ### RERANK_TIMEOUT has its own default (30s) since reranker calls are ### typically much shorter than full LLM generation. # MAX_ASYNC_RERANK=4 # RERANK_TIMEOUT=30 ### Cohere AI # # RERANK_MODEL=rerank-v3.5 # # RERANK_BINDING_HOST=https://api.cohere.com/v2/rerank # # RERANK_BINDING_API_KEY=your_rerank_api_key_here ### Cohere rerank chunking configuration (useful for models with token limits like ColBERT) ### RERANK_MAX_TOKENS_PER_DOC must be an integer >= 1; the server refuses to start otherwise. ### Defaults to 4096 (Cohere rerank-v3.5) when unset; 480 shown below suits 512-token models. # RERANK_ENABLE_CHUNKING=true # RERANK_MAX_TOKENS_PER_DOC=480 ### Aliyun Dashscope (gte-rerank-*, qwen3-vl-rerank) — nested input/parameters format # # RERANK_BINDING=aliyun # # RERANK_MODEL=gte-rerank-v2 # # RERANK_BINDING_HOST=https://dashscope.aliyuncs.com/api/v1/services/rerank/text-rerank/text-rerank # # RERANK_BINDING_API_KEY=your_rerank_api_key_here ### Aliyun Dashscope qwen3-rerank series — flat (Cohere-style) payload format ### The qwen3-rerank models expect a flat body {"model", "query", "documents", "top_n", ...} ### and return top-level "results", identical to the standard Cohere format. They are also served ### from a DIFFERENT, Cohere-compatible endpoint (/compatible-api/v1/reranks) — NOT the ### .../text-rerank/text-rerank path used by gte-rerank-*/qwen3-vl-rerank above. ### So use RERANK_BINDING=cohere (NOT aliyun) and point RERANK_BINDING_HOST at that endpoint. ### Replace {WorkspaceId} and the region with your own; see the Aliyun Text Rerank API docs: ### https://help.aliyun.com/zh/model-studio/text-rerank-api # # RERANK_BINDING=cohere # # RERANK_MODEL=qwen3-rerank # # RERANK_BINDING_HOST=https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/compatible-api/v1/reranks # # RERANK_BINDING_API_KEY=your_rerank_api_key_here ### Jina AI # # RERANK_MODEL=jina-reranker-v2-base-multilingual # # RERANK_BINDING_HOST=https://api.jina.ai/v1/rerank # # RERANK_BINDING_API_KEY=your_rerank_api_key_here ### For local deployment Embedding and Reranker with vLLM (OpenAI-compatible API) ### Wizard metadata used to preserve the chosen deployment provider across setup reruns # LIGHTRAG_SETUP_EMBEDDING_PROVIDER=vllm # LIGHTRAG_SETUP_RERANK_PROVIDER=vllm # VLLM_EMBED_MODEL=BAAI/bge-m3 # VLLM_EMBED_PORT=8001 # VLLM_EMBED_DEVICE=cpu ### VLLM_EMBED_API_KEY is passed as --api-key to vLLM; synced to EMBEDDING_BINDING_API_KEY; auto-generated if blank # VLLM_EMBED_API_KEY= # VLLM_EMBED_EXTRA_ARGS= # VLLM_RERANK_MODEL=BAAI/bge-reranker-v2-m3 # VLLM_RERANK_PORT=8000 # VLLM_RERANK_DEVICE=cuda ### VLLM_RERANK_API_KEY is passed as --api-key to vLLM; synced to RERANK_BINDING_API_KEY; auto-generated if blank # VLLM_RERANK_API_KEY= ### Use float16 for GPU mode. CPU mode uses the official vLLM CPU image. # VLLM_USE_CPU=1 ### Set to 1 for CPU mode, unset for GPU mode # CUDA_VISIBLE_DEVICES=-1 ### Set to -1 to disable CUDA (CPU mode), or specific GPU IDs for GPU mode # NVIDIA_VISIBLE_DEVICES=0 ### Optional Docker runtime equivalent; generated GPU compose honors either variable. # VLLM_RERANK_EXTRA_ARGS= ######################################## ### Document processing configuration ######################################## ### Document processing output language: English, Chinese, French, German ... SUMMARY_LANGUAGE=English ### Enable JSON-structured output for entity extraction ### Default behavior: JSON output is disabled when ENTITY_EXTRACTION_USE_JSON is unset ### JSON output incurs higher latency but delivers improved reliability ENTITY_EXTRACTION_USE_JSON=true ### Optional external YAML profile for entity type guidance and extraction examples ### Profiles are loaded from PROMPT_DIR/entity_type (PROMPT_DIR defaults to ./prompts). ### A reference template is shipped at prompts/samples/entity_type_prompt.sample.yml; # ENTITY_TYPE_PROMPT_FILE=entity_type_prompt.yml # PROMPT_DIR= ### Multimodal parsing/analyze integration ### Optional parser routing rules. Example for VLM & MinerU enabled configuration: ### LIGHTRAG_PARSER=*:native-iteP(drop_rf),xlsx:legacy-R,*:mineru-iteP(drop_rf),*:legacy-R ### Rules are separated with semicolons ';' or commas ','; ### Rules match file suffixes (pdf) are checked left-to-right. ### If mineru/docling appears in LIGHTRAG_PARSER, the corresponding endpoint ### below must be configured before server startup. ### ### Per-strategy chunk parameters may be attached in parentheses to a chunk ### selector (F/R/V/P/C). Inside the parentheses a comma only separates parameters. ### Supported parameters (alias in brackets): ### chunk_token_size [chunk_ts] F/R/V/P/C e.g. R(chunk_ts=800) ### chunk_overlap_token_size [chunk_ol] F/R/P/C (V has no overlap) ### LIGHTRAG_PARSER=pdf:legacy-R(chunk_ts=800,chunk_ol=80);*:legacy-R ### The same syntax works in a filename hint, e.g. notes.[-R(chunk_ts=800)].md ### Boolean parameters may be written bare as a flag, on a chunk selector as ### well as on an engine token: P(drop_rf) means drop_rf=true, and ### docx:native(smart_heading) means native(smart_heading=true). ### See docs/FileProcessingPipeline.md for detail LIGHTRAG_PARSER=*:native-teP,*:legacy-R ### Decompression budget for the native DOCX engine (advanced). A .docx is a ### ZIP, so what parsing costs is its UNCOMPRESSED size — MAX_UPLOAD_SIZE ### bounds the compressed file on disk and MAX_REQUEST_BODY_BYTES bounds the ### request body, so neither of them bounds this. Both quantities are read ### from the ZIP central directory before anything is decompressed; a .docx ### over either limit is rejected and the document is recorded FAILED. ### The same budget also bounds the legacy engine's .pptx and .xlsx (both are ### the identical OPC/ZIP bomb class), enforced before those parse locally. ### The ratio gate is applied archive-wide and to the cumulative expansion by ### which individual members exceed their own ratio budgets, so member ### splitting cannot dilute it. That excess receives a fixed ### DOCX_RATIO_FLOOR_BYTES allowance plus a 1:1 allowance for archive bytes ### outside those members. This permits repetitive XML backed by real stored ### media without letting padding buy another ratio-cap multiple. Raise the ### three gates ### (DOCX_MAX_UNCOMPRESSED_BYTES / DOCX_MAX_COMPRESSION_RATIO / DOCX_MAX_ENTRIES) ### only if a legitimate document is being refused; a non-positive value ### disables that gate. DOCX_RATIO_FLOOR_BYTES is the opposite — it is the ### small-file EXEMPTION threshold, so a non-positive value does NOT disable ### the ratio gate, it removes the exemption and makes the ratio gate strictest. # DOCX_MAX_UNCOMPRESSED_BYTES=536870912 # DOCX_MAX_COMPRESSION_RATIO=100 # DOCX_RATIO_FLOOR_BYTES=16777216 # DOCX_MAX_ENTRIES=10000 ### Native DOCX embedded-image export budgets. Images are copied from the ### archive in 1 MiB chunks, with a 25 MiB ceiling for one image and a 64 MiB ### cumulative ceiling for one document. An over-budget image is skipped with ### a parse warning; document text continues. Defaults are sized against the ### five native parse workers so attacker-controlled output remains bounded. ### Raise these only when retaining unusually large embedded images matters ### more than the memory/disk ceiling. A zero or negative value is NOT ### unlimited; it falls back to the safe default. # NATIVE_DOCX_IMAGE_MAX_BYTES=26214400 # NATIVE_DOCX_IMAGE_MAX_TOTAL_BYTES=67108864 ### Zip-bomb budget for the result BUNDLE an external parser engine (docling, ### mineru) returns — a zip fetched from the configured server and extracted ### locally. Defense-in-depth against a compromised/misbehaving endpoint. The ### bundle size scales with your source document and the engine's rendering ### settings, so raise (or disable) these if a legitimate result is refused. ### A non-positive value disables that gate. Both are read live per parse. # PARSER_RESULT_BUNDLE_MAX_ENTRIES=10000 # PARSER_RESULT_BUNDLE_MAX_TOTAL_BYTES=536870912 ### Overall wall-clock budget (seconds) for downloading that result bundle, ### on top of the per-read timeout each client already sets. A per-read ### timeout only bounds a single socket operation, so a peer trickling one ### byte per interval can reset it indefinitely; this bounds the whole ### download regardless of how it stalls. A non-positive value disables the ### deadline. Read live per parse. # PARSER_RESULT_BUNDLE_DOWNLOAD_TIMEOUT=300 ### Cap on the raw response bytes received while streaming that download, ### checked before the bytes ever reach the zip-bomb checks above. Separate ### from PARSER_RESULT_BUNDLE_MAX_TOTAL_BYTES: that one bounds the ### *uncompressed* size a zip declares, this bounds the *compressed* bytes ### actually transferred — tune independently. A non-positive value ### disables this gate. Read live per parse. # PARSER_RESULT_BUNDLE_DOWNLOAD_MAX_BYTES=536870912 ### Global default for the native docx smart_heading engine parameter. ### When true, .docx files routed to the native engine get smart_heading ### enabled without per-file declaration; opt out per file/rule with an ### explicit native(smart_heading=false). Enabling this (or carrying ### native(smart_heading=true) in a LIGHTRAG_PARSER rule) makes the server ### verify the pinned spaCy models at startup and fail fast if missing ### (install: lightrag-download-cache --spacy-install; the main ### Docker image ships them). Applies to new uploads only — already-ingested ### documents keep their persisted engine parameters on re-parse. # DOCX_SMART_HEADING=true ### smart_heading tuning (advanced). These apply only when smart_heading is ### active (DOCX_SMART_HEADING above, or a per-file/rule opt-in). The defaults ### suit most documents — the values shown ARE the defaults; uncomment to change. ### Skip smart_heading for WHOLE documents shorter than this many tokens; they ### keep the plain outline-based headings. Kept below CHUNK_P_SIZE (2000): a ### document that fits inside one paragraph-chunk needs no heading splitting. ### Lower it to run the extra analysis on short documents (e.g. 红头 notices). # DOCX_SMART_MIN_TOKENS=1800 ### Once a document clears the gate above, a single SUB-document shorter than ### this many tokens falls back to outline-only levels instead of size-based ### leveling. Defaults to min(1000, DOCX_SMART_MIN_TOKENS): lowering the ### whole-document gate to run smart on short documents also pulls this floor ### down, so their sub-documents are not silently left on outline-only. Set it ### explicitly to override (e.g. level only big sections of a long document). # DOCX_SMART_SUBDOC_MIN_TOKENS=1000 ### Heading-detection sensitivity. The engine drops a line from the heading set ### when it looks like body text; these tune how strict that is. ### DENSITY_MAX largest share of paragraphs allowed to be headings ### (0-1) before the engine decides it over-detected ### and recomputes the body font size. ### DENSITY_BASELINE_MARGIN for a document with a rich built-in outline, the ### ceiling rises by this much above the document's own ### outline ratio (percentage points). ### MIN_INTER_HEADING_CHARS fewest body characters expected between two adjacent ### headings (a Chinese char counts as 3); a denser run ### also triggers the recompute. ### HEADING_MAX_CHARS a line longer than this (Chinese char = 3) is body, ### never a heading. Also caps the merged main+sub doc ### title. FATAL if non-integer or < 3 (too small to ### hold the "..." truncation marker): startup and ### parsing both reject it; a value below the title-line ### width (90) is accepted but warns (most headings ### would be demoted to body). ### Raise the ceiling / lower the minimums if real headings are being dropped; ### do the reverse if body text is leaking in as headings. # DOCX_SMART_DENSITY_MAX=0.40 # DOCX_SMART_DENSITY_BASELINE_MARGIN=0.10 # DOCX_SMART_MIN_INTER_HEADING_CHARS=200 # DOCX_SMART_HEADING_MAX_CHARS=180 ### Table of contents (TOC) retention. A detected TOC keeps its first N visible ### lines as body text (so a 目录 heading is not orphaned from its entries) and ### collapses the remainder to a single "……". Counted globally by visible line ### (a soft-break line counts as one). 0 keeps none (one "……" replaces the whole ### TOC); a negative value is treated as 0; a very large value keeps it all. # DOCX_SMART_TOC_KEEP_LINES=5 ### Lines starting with one of these words (followed by a number) are figure / ### table captions, never headings. Comma-separated; localize for your corpus. # DOCX_SMART_CAPTION_PREFIXES=图,表,公式,Figure,Table,Fig.,Eq.,Chart ### 公文版记 (imprint) ANCHORS — openers like 抄送:/ 主题词:(colon class) start a ### 版记 region: they are body, never headings, and veto title-block membership ### for themselves and the 2 preceding non-blank paragraphs. An anchor may also ### be middle content of another anchor's region (主题词 then 抄送). Comma- ### separated; localize for your corpus. # DOCX_SMART_IMPRINT_COLON_PREFIXES=抄送,主题词 ### 版记 region CLOSERS (印发-family — the issuing-organ / print line that ENDS a ### 版记), recognized ONLY within FORWARD_PARAS non-blank paragraphs after an ### anchor above (so a body line ending in 印发 cannot false-fire alone). Prefix ### form: 印发:XX / 印发 XX / 印发机关 XX (印发机关 is a closer, not an anchor — the ### old DOCX_SMART_IMPRINT_SPACE_PREFIXES knob is gone); trailing form: a line ### ENDING with 印发 (某某办公室 2026年6月30日 印发, the GB/T layout). A found 抄送…印发 ### span (middle lines included) is barred from title blocks; when a valid title ### block immediately follows it (a 公文汇编 boundary), the span is force-demoted ### to body. Comma-separated; localize for your corpus. # DOCX_SMART_IMPRINT_CLOSER_PREFIXES=印发,印发机关 # DOCX_SMART_IMPRINT_CLOSER_TRAILING=印发 # DOCX_SMART_IMPRINT_FORWARD_PARAS=3 ### Document-title detection and its LLM cost. Only the first eligible paragraph ### can be a single-line title candidate; it must be at least this many points ### larger than the body font. The LLM input remains bounded by a token window. # DOCX_SMART_TITLE_BLOCK_MIN_DELTA=2.0 # DOCX_SMART_LLM_WINDOW_TOKENS=1000 ### Mid-document title-window gate: a multi/table window may open freely only ### in the document head zone — fewer than this many content records before it ### AND before the first body signal (a sentence-punctuated paragraph, a real ### outline/numbered heading, or a data table that cannot be cover material). ### Past the zone it needs a 版记 tail or 附件 marker as boundary evidence. # DOCX_SMART_TITLE_HEAD_ZONE_RECORDS=8 ### Further DOCX_SMART_* thresholds exist (circuit-breaker ratios, confidence ### ratio, numbering sequence break, TOC detection minimum). They are algorithm ### internals rather than a supported tuning surface: see lightrag/constants.py ### for their names and defaults, and prefer reporting a misclassification over ### tuning them. ### Native Markdown (.md / .textpack) remote image handling ### External http(s) images in markdown are downloaded and embedded into the ### sidecar assets by default (SSRF-guarded: private/loopback/link-local hosts ### are refused; the socket is pinned to the validated IP so a DNS rebind cannot ### redirect it to an internal host, and any ambient HTTP(S)_PROXY is ignored). ### Set ENABLED=false to instead DROP external images (no sidecar entry), in ### which case a doc whose only images are external links produces no drawings.json. NATIVE_MD_IMAGE_DOWNLOAD_ENABLED=true ### When downloading is enabled, REQUIRED=true fails the document on a download ### error; false (default) keeps the image as an external link and warns. ### (Base64 and .textpack file-reference images are always embedded regardless ### of this switch; SVG images are rasterized to PNG via cairosvg.) # NATIVE_MD_IMAGE_DOWNLOAD_REQUIRED=false ### Wall-clock deadline for ONE image request, covering connect, TLS, headers, ### body and every redirect hop (DNS resolution is the one phase outside it). # NATIVE_MD_IMAGE_DOWNLOAD_TIMEOUT=30 ### Per-image size ceiling: caps a remote download AND a single bundled ### (.textpack) asset, so one oversized image cannot be read into memory. # NATIVE_MD_IMAGE_MAX_BYTES=26214400 ### SVG render budget: an SVG whose declared canvas (width*height or viewBox) ### exceeds this pixel count is skipped BEFORE rasterization # NATIVE_MD_IMAGE_MAX_SVG_PIXELS=16000000 ### Per-DOCUMENT image ceilings. The three above bound ONE image; these bound ### a whole document, and they are what stops a small upload referencing a ### large number of images from exhausting the host. ### Over-budget images do NOT fail the document: a remote one degrades to an ### external link and a base64 / .textpack one is dropped, both with a parse ### warning. DOWNLOAD_REQUIRED=true turns an over-budget REMOTE image into a ### document failure, matching how it treats any other failed download; base64 ### and .textpack images are outside that switch, as they always have been. ### 0 or a negative value is NOT "unlimited" — it falls back to the default. ### For effectively unlimited, set a very large number. ### ### Total image bytes RETAINED for one document, across every source (base64, ### .textpack file, download, and cache reuse). This is the memory bound; the ### default is derived from MAX_PARALLEL_PARSE_NATIVE (5), so all parse workers ### together hold at most ~320 MiB of retained image data. ### Live image data peaks a little higher while one image is in flight, since ### assembling a download into one immutable buffer holds the pieces and the ### result together for a moment. The bound on live image ALLOCATIONS is this ### value plus min(MAX_BYTES, this value) — ~89 MiB at the defaults — plus a ### small constant for the read buffer. Lowering MAX_BYTES lowers it. Process ### RSS follows the allocator's high-water mark and can sit above that. # NATIVE_MD_IMAGE_MAX_TOTAL_BYTES=67108864 ### Remote image fetch ATTEMPTS per document. Counts every redirect hop, and ### counts attempts that fail in DNS or the SSRF guard without a packet leaving ### the host, so it is an upper bound on outbound HTTP requests rather than an ### exact count. A `.native_raw/` cache hit issues no request and is not ### counted. Base64 and .textpack file references are not counted either. # NATIVE_MD_IMAGE_MAX_REQUESTS=100 ### Wall-clock budget for ALL image downloads in one document, in seconds ### (DOWNLOAD_TIMEOUT above is per request). Starts at the first download. ### Once spent, the remaining external images degrade to links with no request ### issued. Successful downloads are cached, so a re-parse resumes where the ### previous one stopped rather than starting over. # NATIVE_MD_IMAGE_DOWNLOAD_TOTAL_TIMEOUT=120 ### Escape hatch for the SSRF guard: only globally-routable IPs are allowed by ### default. To permit specific non-public ranges (e.g. an internal image host), ### list comma-separated CIDRs/IPs. Applies to DNS-resolved IPs and redirects. # NATIVE_MD_IMAGE_ALLOWED_NON_PUBLIC_CIDRS=10.0.0.0/8,192.168.1.5 ### Downloaded external images are cached in a `.native_raw/` sidecar dir ### so a re-parse of an unchanged file reuses them instead of re-downloading. ### Set the following env var true to force a re-download (discard the cache) # LIGHTRAG_FORCE_REPARSE_NATIVE=false ### Async parser service protocol (optional) ### Configure these when using remote MinerU/Docling async services ### ---- MinerU shared parameters (both local and official modes) ---- ### MinerU API protocol. Choose one active mode. ### - official: MinerU precision API v4. Requires MINERU_API_TOKEN. ### - local: self-hosted mineru-api / mineru-router base URL. MINERU_API_MODE=local # MINERU_POLL_INTERVAL_SECONDS=2 # MINERU_MAX_POLLS=600 # MINERU_LANGUAGE=ch # MINERU_ENABLE_TABLE=true # MINERU_ENABLE_FORMULA=true # MINERU_PAGE_RANGES= ### MINERU_PAGE_RANGES semantics differ by mode: ### - official: forwarded verbatim, supports e.g. "1-3,5,7-9". ### - local: only a single page ("3") or simple range ("1-10"); comma ### lists are rejected at startup. ### When switching modes, double-check this constraint. ### Per-file override: a hint / rule may set page_range on the engine token, ### e.g. notes.[mineru(page_range=1-3,page_range=5)].pdf — inside the parens a ### comma only separates parameters, so a multi-segment list REPEATS the key ### (and requires MINERU_API_MODE=official). Likewise language / local_parse_method. # MINERU_ADDITIONAL_SUFFIXES=doc,xls,ppt ### MINERU_ADDITIONAL_SUFFIXES: suffixes your MinerU endpoint can handle on top ### of the baseline set (pdf docx pptx xlsx png jpg jpeg jp2 webp gif bmp). ### MinerU converts legacy Office formats through LibreOffice on its own side, ### so which of them work is a property of your deployment, not of LightRAG. ### Format: bare lowercase suffixes separated by ',' — a leading dot and ### surrounding whitespace are tolerated (" .DOC " = doc); anything else ### ('*.doc' written out of glob habit, or a ';'-separated list) is rejected at ### startup rather than silently ignored. ### Semantics differ by mode: this describes the endpoint of the CURRENTLY ### selected MINERU_API_MODE — official coverage is fixed by the service, local ### coverage depends on your container. When switching modes, re-check it. ### NOTE: this only makes a suffix *routable to mineru*; it does not by itself ### make a bare 'x.doc' uploadable. Pair it with a routing rule ### (LIGHTRAG_PARSER=doc:mineru) or a per-file hint (x.[mineru].doc), otherwise ### such files still fall through to the default legacy engine and are rejected ### as unsupported. Conversely, a 'doc:mineru' rule without this variable fails ### startup validation, since doc is not among mineru's capabilities. ### ---- MinerU local-only (MINERU_API_MODE=local) ---- MINERU_LOCAL_ENDPOINT=http://127.0.0.1:8000 ### MINERU_LOCAL_BACKEND: which mineru-api backend handles the parse. ### Accepted values (per mineru-api POST /tasks form parameter `backend`): ### hybrid-auto-engine - pipeline + VLM combo with auto-selected local ### engine (mineru-api's default). GPU required. ### pipeline - CPU-friendly traditional pipeline; no VLM step. ### vlm-auto-engine - VLM with auto-selected local inference engine ### (sglang-engine / vllm-engine if GPU is available); ### requires the matching engine extra preinstalled ### on the mineru-api side, plus model weights. ### We ship `hybrid-auto-engine` -- requires the target mineru-api ### deployment to have a GPU plus the matching inference engine ### (sglang / vllm) and model weights installed. Switch to `pipeline` ### for CPU-only deployments without those dependencies. MINERU_LOCAL_BACKEND=hybrid-auto-engine ### MINERU_LOCAL_PARSE_METHOD: parsing strategy for the pipeline component. ### Accepted values: ### auto - auto-detect embedded text-layer vs OCR per page (default). ### txt - extract text from the embedded text layer only; fastest, ### but yields empty output on scanned PDFs without a text layer. ### ocr - force OCR on every page regardless of text-layer quality; ### slowest, reliable on scanned or low-quality PDFs. ### Only consumed when MINERU_LOCAL_BACKEND is `pipeline` or ### `hybrid-auto-engine` (the pipeline arm of the hybrid pipeline). ### Pure VLM backends (`vlm-auto-engine`, `vlm-http-client`) ignore this ### parameter -- the VLM model handles layout/OCR natively. MINERU_LOCAL_PARSE_METHOD=auto ### MINERU_LOCAL_IMAGE_ANALYSIS: enable VLM image/chart analysis pass for ### better caption an footnote recognition. ### Only consumed by `vlm-auto-engine`, `vlm-http-client`, ### `hybrid-auto-engine`, `hybrid-http-client`. The `pipeline` backend ### silently drops this flag -- its `_process_pipeline` does not accept ### the kwarg, so setting `false` under pipeline does NOT speed parsing ### up; pipeline never invokes the VLM image pass to begin with. ### Disable (`false`) on VLM / hybrid backends to skip the extra VLM ### round, trading image / chart semantic descriptions for faster parsing ### and lower GPU cost. MINERU_LOCAL_IMAGE_ANALYSIS=false # MINERU_LOCAL_START_PAGE_ID=0 # MINERU_LOCAL_END_PAGE_ID=99999 ### ---- MinerU official-only (MINERU_API_MODE=official) ---- # MINERU_API_TOKEN=your-api-key # MINERU_OFFICIAL_ENDPOINT=https://mineru.net # MINERU_MODEL_VERSION=vlm # MINERU_IS_OCR=false ### Force re-upload of file to MinerU on every retry after failure ### Disables caching of result outcomes # LIGHTRAG_FORCE_REPARSE_MINERU=false ### ---- MinerU raw-bundle cache (.mineru_raw/) ---- ### Engine version recorded in the bundle manifest; changing it invalidates the ### cache. Leave empty to skip the version check. # MINERU_ENGINE_VERSION= ### Default coordinate system for MinerU layout boxes, written into the ### sidecar meta. NOTE the default differs from DOCLING_BBOX_ATTRIBUTES. # MINERU_BBOX_ATTRIBUTES={"origin":"LEFTTOP","max":1000} ### Docling parser (docling-serve v1 / async API). ### ### Endpoint: base URL only — the client appends /v1/convert/file/async, ### /v1/status/poll/{task_id}?wait=, ### /v1/result/{task_id} itself. ### Pipeline shape (pipeline=standard, target_type=zip, ### to_formats=[json,md], image_export_mode=referenced) is fixed in ### code so the sidecar flow stays self-consistent — flipping any of ### these would break the adapter and is therefore not exposed as env. ### ### Optional formats: ### - DOCLING_ADDITIONAL_SUFFIXES: comma-separated suffixes your ### docling-serve deployment can actually handle on top of the baseline ### set (pdf docx pptx xlsx md html xhtml png jpg jpeg tiff webp bmp). ### Docling's legacy Office support (doc/xls/ppt) needs LibreOffice on ### the docling-serve side, so it is opted in per deployment rather than ### advertised globally. Bare lowercase suffixes only — 'doc,ppt,xls', ### not '*.doc' or 'doc;ppt' (the server refuses to start otherwise). ### NOTE: this only makes the suffix *routable to docling*; it does not ### by itself make bare 'x.doc' uploadable. Pair it with a routing rule ### (LIGHTRAG_PARSER=doc:docling) or a per-file hint (x.[docling].doc), ### otherwise such files still fall through to the default legacy engine ### and are rejected as unsupported. ### ### OCR tunables: ### - DOCLING_DO_OCR: master switch; when false the engine relies only on ### text-layer extraction. ### - DOCLING_FORCE_OCR: when true, OCR every page regardless of text-layer ### quality (slower, useful for scanned PDFs with bad text layers). ### - DOCLING_OCR_ENGINE: explicit engine selection (DEPRECATED in the ### docling-serve OpenAPI but still honored for older deployments). ### - DOCLING_OCR_PRESET: recommended replacement for DOCLING_OCR_ENGINE. ### - DOCLING_OCR_LANG: JSON array (e.g. ["en","zh"]) or comma-separated ### list. Empty (default) lets the OCR engine pick its default. ### - DOCLING_DO_FORMULA_ENRICHMENT: when true, the code-formula model runs ### and `texts[*].label="formula"` items carry LaTeX in `text`. Default ### false because the model may not be present on every deployment; ### adapter falls back to plain-text formulas when disabled. ### ### Polling budget (server-side long-poll; client does NOT add extra sleep): ### - DOCLING_POLL_INTERVAL_SECONDS: ``?wait=N`` value sent to ### /v1/status/poll/{task_id}. Larger N = fewer round trips per parse; ### bound by your reverse-proxy idle timeout. Default 5. ### - DOCLING_MAX_POLLS: max polling rounds before raising TimeoutError. ### Worst-case wall-clock budget ≈ ### DOCLING_POLL_INTERVAL_SECONDS × DOCLING_MAX_POLLS. Default 240 ### (≈ 20 minutes at wait=5s); raise for very large PDFs. ### ### Bundle cache controls: ### - DOCLING_ENGINE_VERSION: recorded in .docling_raw/_manifest.json. ### Mismatch with the recorded value forces a cache miss → re-download. ### Leave empty to skip this check. ### - LIGHTRAG_FORCE_REPARSE_DOCLING: when truthy ("1"/"true"), bypass the ### docling raw cache and re-upload on every parse_docling call. ### - DOCLING_BBOX_ATTRIBUTES: override the doc-level bbox_attributes ### written into .blocks.jsonl meta. Default ### {"origin":"LEFTBOTTOM"} matches docling's default coordinate system. DOCLING_ENDPOINT=http://localhost:5001 DOCLING_DO_OCR=true ### DOCLING_FORCE_OCR can be overridden per file via a hint / rule on the engine ### token, e.g. scan.[docling(force_ocr=true)].pdf DOCLING_FORCE_OCR=true DOCLING_DO_FORMULA_ENRICHMENT=false # DOCLING_ADDITIONAL_SUFFIXES=doc,ppt,xls # DOCLING_OCR_ENGINE=auto # DOCLING_OCR_PRESET=auto # DOCLING_OCR_LANG= # DOCLING_POLL_INTERVAL_SECONDS=5 # DOCLING_MAX_POLLS=240 # DOCLING_BBOX_ATTRIBUTES={"origin":"LEFTBOTTOM"} # DOCLING_ENGINE_VERSION= ### Force re-upload of file to Docling on every retry after failure ### Disables caching of result outcomes # LIGHTRAG_FORCE_REPARSE_DOCLING=false ### File upload size limit (in bytes) ### Default: 104857600 (100MB) ### Set to 0 or None for unlimited upload size ### Examples: ### 52428800 = 50MB ### 104857600 = 100MB (default) ### 209715200 = 200MB ### Note: If using Nginx as reverse proxy, also configure client_max_body_size ### Note: /documents/upload derives its raw request-body ceiling from this value ### (plus 1 MiB of multipart overhead), so 0/None leaves that route with no ### body ceiling at all and the server warns about it at startup. # MAX_UPLOAD_SIZE=104857600 ### Global chunk size, 500~1500 is recommended. ### Chunker inherits the global value here only when its own var is unset. ### Exception: P never inherits CHUNK_SIZE — it uses CHUNK_P_SIZE (default 2000). # CHUNK_SIZE=1200 # CHUNK_OVERLAP_SIZE=100 ### Optional installed third-party chunker (lightrag.chunkers entry points). ### Bare registered name only, not module:func or a file path. CLI: --custom-chunker. ### Unset preserves the built-in callback. Selection serves C AND no-selector ### inserts instance-wide; explicit F/R/V/P still use their built-in strategies. ### No-selector inserts then lose source-span sidecar backfill, exactly as a ### constructor-supplied chunking_func does -- this changes default ingestion. ### Unknown/duplicate selected name or invalid implementation fails startup. ### Authoring, diagnostics and executor opt-in: docs/ThirdPartyChunker.md # CUSTOM_CHUNKER= ### Overlap (in tokens) borrowed from the previous chunk's tail when the ### embedding hard fallback still has to token-window-split a chunk that ### remains over the embedding model's context limit after chunking. ### Independent of CHUNK_OVERLAP_SIZE above (which some chunker strategies, ### e.g. V, deliberately zero out for unrelated reasons) — 0 disables this ### fallback's overlap; negative values are rejected at startup. # EMBEDDING_CHUNK_OVERLAP_TOKEN_SIZE=100 ### Fixed-token chunker (process_options=F, default) settings ### CHUNK_F_SIZE: per-strategy chunk_token_size override; falls back to CHUNK_SIZE when unset ### CHUNK_F_OVERLAP_SIZE: token overlap; falls back to CHUNK_OVERLAP_SIZE when unset ### CHUNK_F_SPLIT_BY_CHARACTER: optional separator string; pre-segment before token windowing ### CHUNK_F_SPLIT_BY_CHARACTER_ONLY: when true, raise on oversize segment instead of token re-split # CHUNK_F_SIZE=1200 # CHUNK_F_OVERLAP_SIZE=100 # CHUNK_F_SPLIT_BY_CHARACTER= # CHUNK_F_SPLIT_BY_CHARACTER_ONLY=false ### Recursive character chunker (process_options=R) settings ### CHUNK_R_SIZE: per-strategy chunk_token_size override; falls back to CHUNK_SIZE when unset ### CHUNK_R_OVERLAP_SIZE: token overlap between adjacent chunks; falls back to CHUNK_OVERLAP_SIZE when unset ### CHUNK_R_SEPARATORS: JSON array of cascaded separators tried by RecursiveCharacterTextSplitter. ### Default includes CJK sentence-ending punctuation so Chinese / mixed-language ### documents split at semantic boundaries. Order: paragraph (\n\n) > line (\n) > ### Chinese sentence-end (。!?) > Chinese semi-clause (;,) > space > char. ### English ".?!" are intentionally omitted (literal match would split "0.95" / ### "e.g."); the English path falls through space / char as before. ### Bounded at 64 entries of at most 256 characters each. The splitter ### re-scans the whole text once per remaining separator, so an oversized ### cascade costs O(len(separators) x len(text)) for no extra splitting. ### The two limits do NOT behave the same way: ### - an entry longer than 256 characters is DROPPED, not shortened. A ### lone 300-character separator disappears; it does not fall back to ### matching its first 256 characters. ### - a list longer than 64 entries is TRUNCATED to 64, keeping the ### trailing char-level "" sentinel when the original had one. ### If nothing survives, the fallback differs by consumer and is NOT this ### variable's default: the R chunker uses the splitter's own four-entry ### cascade ("\n\n", "\n", " ", ""), while multimodal surrounding-context ### extraction uses the CJK-aware default above minus the sentinel. ### A valid-but-out-of-bounds configured value is corrected and logged once ### when its configuration is loaded/cached, rather than once per document. ### A value that is not a JSON array of strings falls back to the default ### cascade above instead of being bounded, so a bare string can never ### become 64 single-character separators. # CHUNK_R_SIZE=1200 # CHUNK_R_OVERLAP_SIZE=100 # CHUNK_R_SEPARATORS=["\n\n","\n","。","!","?",";",","," ",""] ### Semantic vector chunker (process_options=V) settings ### CHUNK_V_SIZE: per-strategy chunk_token_size hard cap (oversized pieces are ### re-split via R before being emitted); falls back to CHUNK_SIZE when unset ### CHUNK_V_BREAKPOINT_THRESHOLD_TYPE: percentile | standard_deviation | interquartile | gradient ### CHUNK_V_BREAKPOINT_THRESHOLD_AMOUNT: leave empty to use the LangChain per-type default (e.g. 95 for percentile) ### CHUNK_V_BUFFER_SIZE: number of adjacent sentences combined when computing distances ### CHUNK_V_SENTENCE_SPLIT_REGEX: regex fed to LangChain SemanticChunker for the ### initial sentence split. Default extends the upstream English-only pattern ### with CJK sentence-end punctuation (。?!). Override if you need a ### different language mix. Note: env value is the raw regex string, no JSON ### quoting. ### This env var (or the SDK addon_params) is the ONLY way to set the ### pattern: /documents/text and /documents/texts reject a ### "sentence_split_regex" key in the chunking params with HTTP 422. An ### attacker-supplied pattern is a ReDoS vector — it is applied to the ### request's own text and CPython's regex engine holds the GIL while ### backtracking, so one request can freeze the worker process ### (GHSA-32jh-39m7-8x84). Keep this value under operator control and ### prefer anchored, non-ambiguous patterns. ### V embeds one item per sentence window while chunking, so the size of ### those requests is governed by EMBEDDING_BATCH_NUM (see the Embedding ### section), not by CHUNK_V_SIZE. Per-window token length is capped on ### a best-effort basis at the embedding function's declared token limit: ### EMBEDDING_TOKEN_LIMIT when set, otherwise the binding's own default ### (8192 for openai/azure_openai/ollama/jina/bedrock/lollms, 32000 for ### voyageai, 2048 for gemini) — every built-in binding declares one, so ### on the API server path CHUNK_V_SIZE is never the budget. It becomes ### the fallback only for an SDK caller whose EmbeddingFunc declares no ### max_token_size (or 0). Truncation there only affects boundary ### detection, never chunk content. # CHUNK_V_SIZE=1200 # CHUNK_V_BREAKPOINT_THRESHOLD_TYPE=percentile # CHUNK_V_BREAKPOINT_THRESHOLD_AMOUNT= # CHUNK_V_BUFFER_SIZE=1 # CHUNK_V_SENTENCE_SPLIT_REGEX=(?<=[.?!])\s+|(?<=[。?!]) ### Paragraph semantic chunker (process_options=P) settings ### CHUNK_P_SIZE: per-strategy chunk_token_size override; defaults to 2000 when unset ### (does NOT fall back to CHUNK_SIZE — paragraph-semantic merging needs more ### headroom than the global default to keep related paragraphs together). ### CHUNK_P_OVERLAP_SIZE: overlap for prose fallback and table-bridge context; ### falls back to CHUNK_OVERLAP_SIZE when unset ### CHUNK_P_DROP_REFERENCES: drop matching reference blocks before chunking. ### Global default switch; overridable per-file via the hint param ### drop_references (alias drop_rf), e.g. paper.[-P(drop_rf=true)].pdf. Frozen ### into the document's chunk_options at enqueue and recorded in ### doc_status.metadata['chunk_opts']. ### CHUNK_P_REFERENCES_TAIL_N: 0 scans all content blocks for reference ### headings (default); a positive value scans only the last N blocks. ### CHUNK_P_REFERENCES_HEADINGS: pipe-separated reference heading prefixes ### (default References|Bibliography|参考文献). English words match ### case-insensitively at a word boundary; 参考文献 matches as a prefix. ### NOTE: TAIL_N / HEADINGS are read live by the chunker at run time (NOT ### snapshotted) — editing them changes the behaviour of re-runs. # CHUNK_P_SIZE=2000 # CHUNK_P_OVERLAP_SIZE=100 # CHUNK_P_DROP_REFERENCES=false # CHUNK_P_REFERENCES_TAIL_N=0 # CHUNK_P_REFERENCES_HEADINGS=References|Bibliography|参考文献 ### Number of summary segments or tokens to trigger LLM summary on entity/relation merge (at least 3 is recommended) # FORCE_LLM_SUMMARY_ON_MERGE=8 ### Max description token size to trigger LLM summary # SUMMARY_MAX_TOKENS = 1200 ### Recommended LLM summary output length in tokens # SUMMARY_LENGTH_RECOMMENDED=600 ### Maximum context size sent to LLM for description summary # SUMMARY_CONTEXT_SIZE=12000 ### Maximum token size allowed for entity extraction input context # MAX_EXTRACT_INPUT_TOKENS=20480 ### Multimodal surrounding-context budget (per-half token cap for the ### `leading` / `trailing` text injected into VLM and extract prompts). ### Computed at analyze_multimodal entry; the two halves are independent ### so deployments can bias context forward or backward as needed. # SURROUNDING_LEADING_MAX_TOKENS=2000 # SURROUNDING_TRAILING_MAX_TOKENS=2000 ### Floor on the multimodal item's own content budget. If the surrounding ### budgets above leave less than this for the item itself, startup warns and ### names this variable as the knob to raise (or lower SURROUNDING_* instead). # MM_EXTRACT_CONTENT_MIN_TOKENS=100 ### Per-response cap on total entity+relationship rows/records emitted by the LLM # MAX_EXTRACTION_RECORDS=100 ### Per-response cap on entity rows/objects emitted by the LLM # MAX_EXTRACTION_ENTITIES=40 ### Control the maximum chunk_ids stored in vector and graph db ### Addresses the hard-coded 64KB size constraint for Milvus dynamic field ($meta) # MAX_SOURCE_IDS_PER_ENTITY=200 # MAX_SOURCE_IDS_PER_RELATION=200 ### control chunk_ids limitation method: KEEP, FIFO, ### KEEP: Keep oldest (default, less merge action and faster) ### do not change entity/release description after max_source_ids reached ### FIFO: First in first out # SOURCE_IDS_LIMIT_METHOD=KEEP ### Maximum number of file paths stored in entity/relation file_path field ### For displayed only, does not affect query performance # MAX_FILE_PATHS=75 ### PDF decryption password for protected PDF files # PDF_DECRYPT_PASSWORD=your_pdf_password_here ######################################## ### Pipeline Concurrency Configuration ######################################## ### Number of parallel processing documents (between 2~10, MAX_ASYNC_LLM/3 is recommended). ### This does not set per-document chunk extraction or graph-merge task limits. MAX_PARALLEL_INSERT=3 ### For each document, MAX_ASYNC_LLM caps chunk entity/relation extraction tasks; ### each entity-merge or relation-merge phase caps tasks at 2 * MAX_ASYNC_LLM. ### EXTRACT_MAX_ASYNC_LLM limits the actual Extract-role LLM requests and does ### not change those pipeline task limits. ### Optional per-stage document pipeline concurrency # MAX_PARALLEL_PARSE_NATIVE=5 # MAX_PARALLEL_PARSE_MINERU=1 # MAX_PARALLEL_PARSE_DOCLING=1 # MAX_PARALLEL_ANALYZE=5 ### Optional queue sizes for staged pipeline workers # QUEUE_SIZE_PARSE=20 # QUEUE_SIZE_ANALYZE=100 # QUEUE_SIZE_INSERT=4 ### Bounded scheduling page size: the scheduler sweeps the doc_status backlog ### through keyset pages of this many records so memory grows with page-size + ### inflight instead of the whole backlog. 0 disables paging (legacy single ### scan). Default 500. # PIPELINE_SCHEDULING_PAGE_SIZE=500 ### /documents/scan discovery is a single streaming pass; this bounds how many ### newly claimed files one batch holds before it is written to doc_status, so ### scan memory grows with the batch instead of with the input directory. Must be ### positive (there is no "disabled" value — the server refuses to start on 0). ### Default 100. # SCAN_ENQUEUE_BATCH_SIZE=100 ### Directory for /documents/scan's disposable candidate spool — the disk-backed ### index that orders discovered files oldest-first without holding them in RAM. ### One fixed-name database per workspace subdirectory, deleted when the scan ### ends and reclaimed by the next scan after a crash. Default: an empty value ### means WORKING_DIR/scan_spool. Set it when WORKING_DIR is a network volume. ### It must be writable local disk — if it cannot be used the scan FAILS rather ### than relocating to the OS temp dir, which is a RAM-backed tmpfs on many ### hosts and would defeat the memory bound. Never point it at INPUT_DIR. # SCAN_SPOOL_DIR= ### Refuse to start when the configured doc_status backend is missing a strict ### capability (active count / source-conflict listing / source-conflict repair / ### strict point reads). Default false: the gaps are logged loudly at startup and ### reported by /health under "capabilities", and the affected features fail closed ### (admission 503, conflicts 501). Set true if you would rather not start at all. # PIPELINE_REQUIRE_STRICT_STORAGE_READS=false ### Admission capacity: refuse new uploads / text inserts with HTTP 429 once this ### many documents are already active (PENDING/PARSING/ANALYZING/PROCESSING) or ### reserved by an in-flight request. Manual retries and /documents/scan may ### exceed it on purpose; the rows they create make ordinary uploads wait. ### 0 disables admission control (default). # MAX_PENDING_DOCUMENTS=0 ### Ceiling on how many texts ONE /documents/texts request may carry, refused ### with 413 before any per-text storage lookup. Bounds the fan-out of a single ### request, unlike MAX_PENDING_DOCUMENTS which bounds the whole backlog and says ### "retry later" — no amount of waiting makes an oversized batch fit. ### 0 disables (default). # MAX_TEXTS_PER_REQUEST=0 ### Per-workspace ceiling on manual retry requests (/documents/reprocess_failed, ### /documents/scan) that have been published but not yet acknowledged by their ### exclusive FAILED->PENDING reset. The channel is sticky, so an over-capacity ### publish is refused with 429 rather than dropped. Default 64. # MAX_UNACKED_MANUAL_RETRIES=64 ### Hard ceiling on the raw request body, counted as it streams through ASGI (so ### a body that lies about or omits Content-Length is still cut off with 413). ### Applies to EVERY route, and is layered because routes differ by orders of ### magnitude in what they legitimately carry: ### - ordinary routes (/query, /api/chat, ...): this value, default 1 MiB ### - /documents/text and /documents/texts: 50 MiB built in, ONLY while ### this variable is left unset ### - /documents/upload: MAX_UPLOAD_SIZE + 1 MiB of ### multipart overhead ### Setting this at all makes it govern every non-upload route, ingestion ### included; there is no separate knob for the ingestion tier. That holds even ### when the value equals the 1 MiB default, so uncommenting the line below as-is ### does change behaviour: it drops /documents/text(s) from 50 MiB to 1 MiB. ### Setting it to 0 turns off every ceiling, including the derived upload one. ### Distinct from MAX_UPLOAD_SIZE, which bounds one uploaded FILE after multipart ### parsing: this bounds the bytes the server agrees to read at all. # MAX_REQUEST_BODY_BYTES=1048576 ########################################################################### ### Gloabal LLM Configuration ### LLM_BINDING type: openai, ollama, lollms, azure_openai, bedrock, gemini ### LLM_BINDING_HOST: Service endpoint (left empty if using the provider SDK default endpoint) ### LLM_BINDING_API_KEY: api key ### If LightRAG deployed in Docker: ### uses host.docker.internal instead of localhost in LLM_BINDING_HOST ########################################################################### ### LLM request timeout setting for all llm (0 means no timeout for Ollma) # LLM_TIMEOUT=240 LLM_BINDING=openai LLM_BINDING_HOST=https://api.openai.com/v1 LLM_BINDING_API_KEY=your_api_key LLM_MODEL=gpt-5.4-mini ### Base maximum concurrency for LLM roles and file-pipeline task scheduling. ### Per document, it caps chunk entity/relation extraction tasks; each entity ### or relation merge phase uses twice this task limit. EXTRACT_MAX_ASYNC_LLM ### can separately limit actual Extract-role requests without changing them. ### MAX_ASYNC is still accepted as a deprecated alias ### NOTE: with gunicorn multi-worker (lightrag-gunicorn --workers N) every ### MAX_ASYNC_* / *_MAX_ASYNC_* setting (LLM roles, embedding, rerank) ### is enforced BOTH per worker process AND as a cross-worker global ### cap. Under normal operation this keeps total in-process provider ### calls clamped to MAX_ASYNC, similar to single-process mode. Slots ### held by crashed workers (kill -9 / OOM) are reclaimed automatically ### via lease heartbeats; if a worker is terminated externally while its ### provider request is still pending, replacement work may briefly make ### provider-side concurrency exceed the cap until the abandoned request ### times out or closes. ### Runtime caveat: changing a role's max_async through the API ### updates only that worker's local limit — the cross-worker cap ### keeps the value read at startup. MAX_ASYNC_LLM=4 ########################################################################### ### Role-specific LLM/VLM overrides ### Available roles: EXTRACT, KEYWORD, QUERY, VLM ### If unset, each role falls back to global LLM configuration above. ### For detail information, refer to: ### docs/RoleSpecificLLMConfiguration.md ### docs/RoleSpecificLLMConfiguration-zh.md ########################################################################### # EXTRACT_LLM_MODEL=gpt-5.4-mini ### Overrides only the actual Extract-role LLM request limit; file-pipeline ### chunk and merge task limits above still use MAX_ASYNC_LLM. # EXTRACT_MAX_ASYNC_LLM=4 # EXTRACT_LLM_TIMEOUT=240 # EXTRACT_LLM_BINDING=openai # EXTRACT_LLM_BINDING_HOST=https://api.openai.com/v1 # EXTRACT_LLM_BINDING_API_KEY=your_api_key # KEYWORD_LLM_MODEL=gpt-5.4-nano KEYWORD_MAX_ASYNC_LLM=4 # KEYWORD_LLM_TIMEOUT=60 # KEYWORD_LLM_BINDING=openai # KEYWORD_LLM_BINDING_HOST=https://api.openai.com/v1 # KEYWORD_LLM_BINDING_API_KEY=your_api_key # QUERY_LLM_MODEL=gpt-5.4 QUERY_MAX_ASYNC_LLM=4 # QUERY_LLM_TIMEOUT=240 # QUERY_LLM_BINDING=openai # QUERY_LLM_BINDING_HOST=https://api.openai.com/v1 # QUERY_LLM_BINDING_API_KEY=your_api_key # VLM_LLM_MODEL=gpt-5.4-mini # VLM_MAX_ASYNC_LLM=4 # VLM_LLM_TIMEOUT=300 # VLM_LLM_BINDING=openai # VLM_LLM_BINDING_HOST=https://api.example.com/v1 # VLM_LLM_BINDING_API_KEY=your_vlm_api_key ### Master switch for VLM analysis of IMAGE items (the `i` process option). ### Table (`t`) and equation (`e`) items are analyzed by the EXTRACT role and ### are NOT affected by this switch. ### ### This switch is only ever consulted for a document whose process_options ### include `i`. A document without `i` never enters image analysis, so ### leaving this false is the normal setup for e.g. LIGHTRAG_PARSER=*:native-teP ### -- such documents keep processing regardless of how many images they carry. ### ### For a document WITH `i` and this set to false: the first image that ### survives the pre-filters (file present, raster format, both sides >= ### VLM_MIN_IMAGE_PIXEL) FAILS that document rather than being skipped -- ### analysis raises and the document lands in FAILED with "VLM analysis ### required but VLM role is not available". Images dropped by those ### pre-filters, and documents whose drawings sidecar is absent, are ### unaffected and keep processing. ### ### When true, VLM_LLM_BINDING (or the base LLM_BINDING) must be vision-capable ### lollms is rejected at startup VLM_PROCESS_ENABLE=false ### Maximum image bytes sent to VLM (5242880=5MB) VLM_MAX_IMAGE_BYTES=5242880 ### Minimum image side (width or height) in pixels accepted for VLM analysis. ### Images with a smaller width or height are treated as decorative (icons, ### separators, etc.) and skipped instead of sent to the VLM. VLM_MIN_IMAGE_PIXEL=64 ########################################################################### ### Provider sepecific LLM options ### Increasing the temperature setting may help mitigate infinite inference ### loops during entity/elation extraction, particularly when using ### models with more limited capabilities, such as Qwen3-30B ### Set a max output token limit to prevent endless output from certain LLMs, ### which may trigger timeout errors during entity and relation extraction. ### max_output_token < LLM_TIMEOUT * llm_tokens_per_second ### i.e. max_output_token = 9000 < 240s * 50 tokens/s ### Sample commands to list all supported options specific LLM_BINDING: ### lightrag-server --llm-binding openai --help ### lightrag-server --llm-binding bedrock --help ### lightrag-server --llm-binding gemini --help ########################################################################### ### OpenAI Specific Parameters (Openrouter of other OpenAI compatible API): ### LLM_BINDING=openai ### LLM_BINDING_HOST=https://openrouter.ai/api/v1 ### LLM_MODEL=google/gemini-2.5-flash ### OrcaRouter (OpenRouter-style AI gateway, OpenAI-compatible API): ### LLM_BINDING=openai ### LLM_BINDING_HOST=https://api.orcarouter.ai/v1 ### LLM_BINDING_API_KEY=sk-orca-... ### LLM_MODEL=your-model # OPENAI_LLM_TEMPERATURE=0.9 ### For vLLM/SGLang and most of OpenAI compatible API provider # OPENAI_LLM_MAX_TOKENS=9000 ### For OpenAI o1-mini or newer modles utilizes max_completion_tokens instead of max_tokens # OPENAI_LLM_MAX_COMPLETION_TOKENS=9000 ### For OpenAI reason control # OPENAI_LLM_REASONING_EFFORT=minimal ### For OpenRouter reasoning control # OPENAI_LLM_EXTRA_BODY='{"reasoning": {"enabled": false}}' ### For Qwen3 reasoning control deploy by vLLM # OPENAI_LLM_EXTRA_BODY='{"chat_template_kwargs": {"enable_thinking": false}}' ### Role-specific + Provider-sepecific LLM options # VLM_OPENAI_LLM_MAX_TOKENS=20000 ### Azure OpenAI Specific Parameters: ### LLM_BINDING=azure_openai ### LLM_BINDING_HOST=https://xxxx.openai.azure.com/ ### LLM_BINDING_API_KEY=your_api_key ### LLM_MODEL=my-gpt-mini-deployment ### You may use deployment name for LLM_MODEL or set AZURE_OPENAI_DEPLOYMENT instead # AZURE_OPENAI_DEPLOYMEN=my—deplyment-name # AZURE_OPENAI_API_VERSION=2024-08-01-preview ### Google AI Studio Gemini Specific Parameters: ### DEFAULT_GEMINI_ENDPOINT means selecting endpoit by SDK automatically ### LLM_BINDING=gemini ### LLM_BINDING_HOST=DEFAULT_GEMINI_ENDPOINT ### LLM_BINDING_API_KEY=your_gemini_api_key ### LLM_MODEL=gemini-flash-latest # GEMINI_LLM_TEMPERATURE=0.7 # GEMINI_LLM_MAX_OUTPUT_TOKENS=9000 ### Enable or disable thinking ### GEMINI_LLM_THINKING_CONFIG='{"thinking_budget": -1, "include_thoughts": true}' ### GEMINI_LLM_THINKING_CONFIG='{"thinking_budget": 0, "include_thoughts": false}' # GEMINI_LLM_THINKING_CONFIG='{"thinking_budget": 0, "include_thoughts": false}' ### Google Vertex AI Gemini Specific Parameters: ### Vertex AI use GOOGLE_APPLICATION_CREDENTIALS instead of API-KEY for authentication # GOOGLE_GENAI_USE_VERTEXAI=true # GOOGLE_CLOUD_PROJECT='your-project-id' # GOOGLE_CLOUD_LOCATION='us-central1' # GOOGLE_APPLICATION_CREDENTIALS='/Users/xxxxx/your-service-account-credentials-file.json' ### Bedrock Specific Parameters: ### LLM_BINDING=bedrock ### LLM_BINDING_HOST=DEFAULT_BEDROCK_ENDPOINT ### LLM_MODEL=us.amazon.nova-lite-v1:0 ### Region is required for all three modes (Bedrock endpoints are regional). # AWS_REGION=us-west-1 ### Bedrock Authentication (choose ONE of the following three approaches): ### Bedrock API key (bearer token). Bedrock ignores LLM_BINDING_API_KEY; ### set AWS_BEARER_TOKEN_BEDROCK directly before startup. This is a ### process-level AWS SDK setting and cannot be overridden per role. # AWS_BEARER_TOKEN_BEDROCK=your_bedrock_api_key ### SigV4 credentials (classic IAM user / STS / instance profile). # AWS_ACCESS_KEY_ID=your_aws_access_key_id # AWS_SECRET_ACCESS_KEY=your_aws_secret_access_key # AWS_SESSION_TOKEN=your_optional_aws_session_token ### Ambient credentials (AWS SDK default credential chain). ### To use this mode, leave AWS_BEARER_TOKEN_BEDROCK, AWS_ACCESS_KEY_ID, ### AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN above commented out — the ### AWS SDK will then resolve credentials from ~/.aws/credentials, IAM role, ### instance profile, SSO, or environment variables outside .env. ### Activating any of the lines above forces that explicit mode and bypasses ### the credential chain. # BEDROCK_LLM_TEMPERATURE=1.0 # BEDROCK_LLM_MAX_TOKENS=9000 # BEDROCK_LLM_TOP_P=1.0 # BEDROCK_LLM_STOP_SEQUENCES='[""]' ### Bedrock model reasoning control # BEDROCK_LLM_EXTRA_FIELDS='{"reasoningConfig": {"type": "enabled", "maxReasoningEffort": "low"}}' ### Ollama Specific Parameters: ### LLM_BINDING=ollama ### LLM_BINDING_HOST=http://localhost:11434 ### LLM_MODEL=qwen3.5:9b ### OLLAMA_LLM_NUM_CTX must be provided, and should at least larger than MAX_TOTAL_TOKENS + 2000 OLLAMA_LLM_NUM_CTX=32768 ### OLLAMA_LLM_NUM_PREDICT caps the OUTPUT budget. A response cut off by it is ### kept (and reported in doc_status.metadata.llm_truncation); one cut off ### before emitting any content fails the document instead of indexing an empty ### graph — raise this value, or disable thinking mode, if that happens. # OLLAMA_LLM_NUM_PREDICT=9000 # OLLAMA_LLM_TEMPERATURE=0.85 # OLLAMA_LLM_STOP='["", "<|EOT|>"]' ### OLLAMA_LLM_THINK also accepts a reasoning level (low/medium/high, requires ### an Ollama server that supports levels). Leave it unset entirely to ### follow the model's own default -- an empty value means false, not unset, and ### setting true for a model without thinking support is rejected by Ollama. # OLLAMA_LLM_THINK=low ### If a thinking-capable model silently returns empty entities/relations during ### extraction (issue #3597), it spent its whole budget on hidden reasoning -- ### turn thinking off for the roles that need deterministic output: # EXTRACT_OLLAMA_LLM_THINK=false # KEYWORD_OLLAMA_LLM_THINK=false ####################################################################################### ### Embedding Configuration (Should not be changed after the first file processed) ### EMBEDDING_MODEL is REQUIRED: the server refuses to start without it. Every ### vector storage records the model's name beside its vectors, and that is ### the only thing that detects a later switch to a different model of the ### same dimension. Changing it means stopping the server, running ### lightrag-rebuild-vdb and starting again -- a rolling change is not ### supported. ### EMBEDDING_BINDING: ollama, openai, azure_openai, jina, lollms, bedrock ### EMBEDDING_BINDING_HOST: Service endpoint (left empty if using default endpoint provided by openai or gemini SDK) ### EMBEDDING_BINDING_API_KEY: api key ### If LightRAG deployed in Docker: ### uses host.docker.internal instead of localhost in EMBEDDING_BINDING_HOST ### Control whether to send embedding_dim parameter to embedding API ### For OpenAI: Set EMBEDDING_SEND_DIM=true to enable dynamic dimension adjustment ### For OpenAI: Set EMBEDDING_SEND_DIM=false (default) to disable sending dimension parameter ### For Gemini: Allways set EMBEDDING_SEND_DIM=true ### Control whether to use base64 encoding format for embeddings (improves performance for OpenAI) ### For OpenAI: Set EMBEDDING_USE_BASE64=true (default) to use base64 encoding ### For Yandex Cloud and other providers that don't support it: Set EMBEDDING_USE_BASE64=false ####################################################################################### # EMBEDDING_TIMEOUT=30 ### OpenAI compatible embedding EMBEDDING_BINDING=openai EMBEDDING_BINDING_HOST=https://api.openai.com/v1 EMBEDDING_BINDING_API_KEY=your_api_key EMBEDDING_MODEL=text-embedding-3-large EMBEDDING_DIM=3072 EMBEDDING_TOKEN_LIMIT=8192 EMBEDDING_SEND_DIM=false EMBEDDING_USE_BASE64=true ### Max concurrency requests for Embedding # EMBEDDING_FUNC_MAX_ASYNC=8 ### Num of chunks send to Embedding in single request (default is 10) ### Also caps the items per request when the V chunker embeds sentence windows EMBEDDING_BATCH_NUM=32 ### Optional: asymmetric embeddings (query/document behavior split) ### Leave EMBEDDING_ASYMMETRIC unset or set false to keep symmetric behavior. ### Set true only when the selected embedding backend supports asymmetric mode. # EMBEDDING_ASYMMETRIC=true ### Provider-task bindings such as Jina/Gemini/VoyageAI use provider parameters ### and should not configure the prefix variables below. ### Prefix-based models such as BGE/E5/GTE require both prefix variables. ### Wrap non-empty values with quotes if there are trailing spaces. # EMBEDDING_DOCUMENT_PREFIX="search_document: " ### Use NO_PREFIX for a side that should intentionally have no prefix. ### EMBEDDING_DOCUMENT_PREFIX=NO_PREFIX # EMBEDDING_QUERY_PREFIX="search_query: " ########################################################################### ### Provider sepecific Embedding options ### Increasing the temperature setting may help mitigate infinite inference ### loops during entity/elation extraction, particularly when using ### models with more limited capabilities, such as Qwen3-30B ### Set a max output token limit to prevent endless output from certain LLMs, ### which may trigger timeout errors during entity and relation extraction. ### max_output_token < LLM_TIMEOUT * llm_tokens_per_second ### i.e. max_output_token = 9000 < 240s * 50 tokens/s ### Sample commands to list all supported options specific EMBEDDING_BINDING: ### lightrag-server --embedding-binding openai --help ### lightrag-server --embedding-binding ollama --help ### lightrag-server --embedding-binding bedrock --help ########################################################################### ### Azure Embedding Specific Parameters: ### Use deployment name as model name or set AZURE_EMBEDDING_DEPLOYMENT instead ### EMBEDDING_BINDING=azure_openai ### EMBEDDING_BINDING_HOST=https://xxxx.openai.azure.com/ ### EMBEDDING_API_KEY=your_api_key ### EMBEDDING_MODEL==my-text-embedding-3-large-deployment ### EMBEDDING_DIM=3072 # AZURE_EMBEDDING_API_VERSION=2024-08-01-preview ### Ollama Embedding Specific Parameters: ### EMBEDDING_BINDING=ollama ### EMBEDDING_BINDING_HOST=http://localhost:11434 ### EMBEDDING_BINDING_API_KEY=your_api_key ### EMBEDDING_MODEL=qwen3-embedding:4b ### EMBEDDING_DIM=2560 ### Ollama should set num_ctx option inaddition to EMBEDDING_TOKEN_LIMIT OLLAMA_EMBEDDING_NUM_CTX=8192 ### Gemini Embedding Specific Parameters: ### DEFAULT_GEMINI_ENDPOINT means selecting endpoit by SDK automatically ### Gemini embedding requires sending dimension to server ### EMBEDDING_BINDING=gemini ### EMBEDDING_BINDING_HOST=DEFAULT_GEMINI_ENDPOINT ### EMBEDDING_BINDING_API_KEY=your_api_key ### EMBEDDING_MODEL=gemini-embedding-001 ### EMBEDDING_DIM=1536 ### EMBEDDING_TOKEN_LIMIT=2048 ### EMBEDDING_SEND_DIM=true ### Bedrock Embedding Specific Parameters: ### EMBEDDING_BINDING=bedrock ### EMBEDDING_BINDING_HOST=DEFAULT_BEDROCK_ENDPOINT ### EMBEDDING_MODEL=amazon.titan-embed-text-v2:0 ### EMBEDDING_DIM=1024 ### Share the same region and authentication settings as LLMs, no reconfiguration here ### AWS_REGION=us-west-1 ### AWS_BEARER_TOKEN_BEDROCK=your_bedrock_api_key ### AWS_ACCESS_KEY_ID=your_aws_access_key_id ### AWS_SECRET_ACCESS_KEY=your_aws_secret_access_key ### AWS_SESSION_TOKEN=your_optional_aws_session_token ### Jina AI Embedding Specific Parameters: ### EMBEDDING_BINDING=jina ### EMBEDDING_BINDING_HOST=https://api.jina.ai/v1/embeddings ### EMBEDDING_MODEL=jina-embeddings-v4 ### EMBEDDING_DIM=2048 ### EMBEDDING_BINDING_API_KEY=your_api_key #################################################################### ### WORKSPACE sets workspace name for all storage types ### for the purpose of isolating data from LightRAG instances. ### Valid workspace name constraints: a-z, A-Z, 0-9, and _ #################################################################### # WORKSPACE= ############################ ### Data storage selection ############################ ### Default storage: JSON/Nano/NetworkX (Recommended for test deployment) ### LIGHTRAG_GRAPH_STORAGE options: NetworkXStorage, Neo4JStorage, PGGraphStorage, ### PGTableGraphStorage, MongoGraphStorage, MemgraphStorage, OpenSearchGraphStorage ### PGTableGraphStorage runs the graph on plain PostgreSQL 14+ tables with no ### Apache AGE and no extensions, so it works on managed PostgreSQL ### (RDS / Cloud SQL / Supabase / Neon), and in Docker the official ### pgvector/pgvector:pg18 image is sufficient. Use PGGraphStorage only if you ### need AGE — that is the only option requiring the AGE-bundled image ### gzdaniel/postgres-for-rag:pg18-age-pgvector. LIGHTRAG_KV_STORAGE=JsonKVStorage LIGHTRAG_DOC_STATUS_STORAGE=JsonDocStatusStorage LIGHTRAG_GRAPH_STORAGE=NetworkXStorage LIGHTRAG_VECTOR_STORAGE=NanoVectorDBStorage ### Wizard metadata used to preserve env-storage Docker deployment defaults across setup reruns # LIGHTRAG_SETUP_POSTGRES_DEPLOYMENT=docker # LIGHTRAG_SETUP_NEO4J_DEPLOYMENT=docker # LIGHTRAG_SETUP_MONGODB_DEPLOYMENT=docker # LIGHTRAG_SETUP_MONGODB_DEPLOYMENT=atlas-capable # LIGHTRAG_SETUP_REDIS_DEPLOYMENT=docker # LIGHTRAG_SETUP_MILVUS_DEPLOYMENT=docker # LIGHTRAG_SETUP_QDRANT_DEPLOYMENT=docker # LIGHTRAG_SETUP_MEMGRAPH_DEPLOYMENT=docker # LIGHTRAG_SETUP_OPENSEARCH_DEPLOYMENT=docker ### PostgreSQL Configuration POSTGRES_HOST=localhost POSTGRES_PORT=5432 POSTGRES_USER=your_username POSTGRES_PASSWORD='your_password' POSTGRES_DATABASE=rag POSTGRES_MAX_CONNECTIONS=25 ### DB specific workspace should not be set, keep for compatible only # POSTGRES_WORKSPACE=forced_workspace_name ### Use HNSW_HALFVEC for large embeddings (2000+ dim). ### Requires pgvector extension >= 0.7.0. ### Vector storage type: HNSW, HNSW_HALFVEC, IVFFlat, VCHORDRQ POSTGRES_VECTOR_INDEX_TYPE=HNSW POSTGRES_HNSW_M=16 POSTGRES_HNSW_EF=200 POSTGRES_IVFFLAT_LISTS=100 POSTGRES_VCHORDRQ_BUILD_OPTIONS= POSTGRES_VCHORDRQ_PROBES= POSTGRES_VCHORDRQ_EPSILON=1.9 ### Batch write limits for KV/Vector/DocStatus (split a single executemany / ANY($2) delete; non-positive disables that dimension) # POSTGRES_UPSERT_MAX_PAYLOAD_BYTES=16777216 # POSTGRES_UPSERT_MAX_RECORDS_PER_BATCH=200 # POSTGRES_DELETE_MAX_RECORDS_PER_BATCH=1000 ### PostgreSQL Connection Retry Configuration (Network Robustness) ### NEW DEFAULTS (v1.4.10+): Optimized for HA deployments with ~30s switchover time ### These defaults provide out-of-the-box support for PostgreSQL High Availability setups ### ### Number of retry attempts (1-100, default: 10) ### - Default 10 attempts allows ~225s total retry time (sufficient for most HA scenarios) ### - For extreme cases: increase up to 20-50 ### Initial retry backoff in seconds (0.1-300.0, default: 3.0) ### - Default 3.0s provides reasonable initial delay for switchover detection ### - For faster recovery: decrease to 1.0-2.0 ### Maximum retry backoff in seconds (must be >= backoff, max: 600.0, default: 30.0) ### - Default 30.0s matches typical switchover completion time ### - For longer switchovers: increase to 60-90 ### Connection pool close timeout in seconds (1.0-30.0, default: 5.0) # POSTGRES_CONNECTION_RETRIES=10 # POSTGRES_CONNECTION_RETRY_BACKOFF=3.0 # POSTGRES_CONNECTION_RETRY_BACKOFF_MAX=30.0 # POSTGRES_POOL_CLOSE_TIMEOUT=5.0 ### PostgreSQL SSL Configuration (Optional) # POSTGRES_SSL_MODE=require # POSTGRES_SSL_CERT=/path/to/client-cert.pem # POSTGRES_SSL_KEY=/path/to/client-key.pem # POSTGRES_SSL_ROOT_CERT=/path/to/ca-cert.pem # POSTGRES_SSL_CRL=/path/to/crl.pem ### PostgreSQL Server Settings (for Supabase Supavisor) # Use this to pass extra options to the PostgreSQL connection string. # For Supabase, you might need to set it like this: # POSTGRES_SERVER_SETTINGS='options=reference%3D[project-ref]' # Default is 100 set to 0 to disable # POSTGRES_STATEMENT_CACHE_SIZE=100 ### Apache AGE version (PGGraphStorage only) # PGGraphStorage refuses to start on Apache AGE 1.8.0 and newer: id() began # returning graphid there, which breaks get_knowledge_graph and can terminate the # PostgreSQL backend with SIGSEGV, taking the whole instance through crash # recovery. See https://github.com/apache/age/issues/2500 # Verified good: AGE 1.7.0. Verified bad: AGE 1.8.0, and AGE master. # AGE reports its version per release rather than per commit, so a source build # that fixes the crash still reports an unsupported number; set this to skip the # check for such a build, at your own risk. Default is false. # POSTGRES_AGE_ALLOW_UNSUPPORTED_VERSION=false ### Neo4j Configuration ### Use neo4j:// or neo4j+s:// for Aura and clusters (routing); use bolt:// for a single ### instance or a single Docker container to avoid "Unable to retrieve routing information" NEO4J_URI=neo4j+s://xxxxxxxx.databases.neo4j.io NEO4J_USERNAME=neo4j NEO4J_PASSWORD='your_password' NEO4J_DATABASE=neo4j NEO4J_MAX_CONNECTION_POOL_SIZE=100 NEO4J_CONNECTION_TIMEOUT=30 NEO4J_CONNECTION_ACQUISITION_TIMEOUT=30 NEO4J_MAX_TRANSACTION_RETRY_TIME=30 NEO4J_MAX_CONNECTION_LIFETIME=300 NEO4J_LIVENESS_CHECK_TIMEOUT=30 NEO4J_KEEP_ALIVE=true ### DB specific workspace should not be set, keep for compatible only # NEO4J_WORKSPACE=forced_workspace_name ### MongoDB Configuration # For MongoVectorDBStorage, MONGO_URI must point to a MongoDB endpoint with # Atlas Search / Vector Search support, such as MongoDB Atlas or Atlas local. MONGO_URI=mongodb://localhost:27017/ MONGO_DATABASE=LightRAG ### DB specific workspace should not be set, keep for compatible only # MONGODB_WORKSPACE=forced_workspace_name # Flush-time bulk_write batching limits for MongoDB upsert paths (KV, vector, graph). # (non-positive disables that dimension; DELETE cap applies to MongoVectorDBStorage) # MONGO_UPSERT_MAX_PAYLOAD_BYTES=16777216 # MONGO_UPSERT_MAX_RECORDS_PER_BATCH=128 # MONGO_DELETE_MAX_RECORDS_PER_BATCH=1000 # Community/local Docker MongoDB example for KV, graph, or doc-status storage only: # MONGO_URI=mongodb://localhost:27017/ ### OpenSearch Configuration ### OpenSearch can be used for all storage types: KV, Vector, Graph, DocStatus ### Connection settings (comma-separated host:port entries; do not include http:// or https://) ### This setup wizard supports authenticated OpenSearch clusters only. ### OPENSEARCH_USE_SSL controls whether those hosts are reached over TLS. OPENSEARCH_HOSTS=localhost:9200 OPENSEARCH_USER=admin OPENSEARCH_PASSWORD=LightRAG2026_!@ OPENSEARCH_USE_SSL=true OPENSEARCH_VERIFY_CERTS=false # OPENSEARCH_TIMEOUT=30 # OPENSEARCH_MAX_RETRIES=3 ### Index Settings (for 3-AZ Amazon OpenSearch Service, set replicas to 2) # OPENSEARCH_NUMBER_OF_SHARDS=1 # OPENSEARCH_NUMBER_OF_REPLICAS=0 ### k-NN Settings for Vector Storage (HNSW algorithm) # OPENSEARCH_KNN_EF_CONSTRUCTION=200 # OPENSEARCH_KNN_M=16 # OPENSEARCH_KNN_EF_SEARCH=100 ### PPL graphlookup for server-side graph traversal (auto-detected if not set) # OPENSEARCH_USE_PPL_GRAPHLOOKUP=true ### Bulk batching limits (split a single async_bulk request; non-positive disables that dimension) # OPENSEARCH_UPSERT_MAX_PAYLOAD_BYTES=104857600 # OPENSEARCH_UPSERT_MAX_RECORDS_PER_BATCH=128 # OPENSEARCH_DELETE_MAX_RECORDS_PER_BATCH=1000 ### DB specific workspace should not be set, keep for compatible only # OPENSEARCH_WORKSPACE=forced_workspace_name ### NOTE: OpenSearch index names must be lowercase, so the workspace is ### lowercased (and any character outside [a-z0-9_-] folded to '_') when the ### index name is built. Two workspaces that differ only in case or ### punctuation therefore map to the SAME indexes. When several LightRAG ### deployments share one OpenSearch cluster, give them workspace names that ### differ by more than case -- a colliding deployment refuses to start. ### Milvus Configuration MILVUS_URI=http://localhost:19530 MILVUS_DB_NAME=lightrag # MILVUS_DEVICE=cpu # MILVUS_USER=root # MILVUS_PASSWORD=your_password # MILVUS_TOKEN=your_token # Required for the bundled Docker Milvus stack; may come from .env or exported shell variables. # MINIO_ACCESS_KEY_ID=minioadmin # MINIO_SECRET_ACCESS_KEY=minioadmin ### DB specific workspace should not be set, keep for compatible only # MILVUS_WORKSPACE=forced_workspace_name ### Milvus upsert/delete batching (enabled by default) ### Split large flushes by estimated JSON payload size and record count to stay ### under the server-side 64MB gRPC message limit. A single record larger than the ### byte budget is sent as its own batch instead of failing. # MILVUS_UPSERT_MAX_PAYLOAD_BYTES=33554432 # MILVUS_UPSERT_MAX_RECORDS_PER_BATCH=128 # MILVUS_DELETE_MAX_RECORDS_PER_BATCH=1000 ### Milvus schema-migration resilience (enabled by default) ### On a transient connection failure the migration is retried from scratch with ### a rebuilt client and exponential backoff. Set MAX_RETRIES=0 to fail fast. ### Lower the iterator batch size to reduce write pressure on a small server. # MILVUS_MIGRATION_MAX_RETRIES=5 # MILVUS_MIGRATION_RETRY_BACKOFF=5 # MILVUS_MIGRATION_RETRY_MAX_BACKOFF=60 # MILVUS_MIGRATION_ITERATOR_BATCH_SIZE=2000 ### Milvus Vector Index Configuration ### Index type: AUTOINDEX (default), HNSW, HNSW_SQ, HNSW_PQ, IVF_FLAT, IVF_SQ8, DISKANN # MILVUS_INDEX_TYPE=AUTOINDEX ### Metric type: COSINE (default), L2, IP # MILVUS_METRIC_TYPE=COSINE ### HNSW / HNSW_SQ / HNSW_PQ Parameters (aligned with Milvus 2.4+ defaults) ### M: Maximum number of connections per node [2-2048], default 16 # MILVUS_HNSW_M=16 ### efConstruction: Size of dynamic candidate list during build [8-512], default 360 # MILVUS_HNSW_EF_CONSTRUCTION=360 ### ef: Size of dynamic candidate list during search, default 200 # MILVUS_HNSW_EF=200 ### HNSW_SQ Specific Parameters (requires Milvus 2.6.8+) ### sq_type: Scalar quantization type - SQ4U, SQ6, SQ8 (default), BF16, FP16 # MILVUS_HNSW_SQ_TYPE=SQ8 ### refine: Enable refinement step for higher precision, default false # MILVUS_HNSW_SQ_REFINE=false ### refine_type: Refinement precision (must be higher than sq_type) - SQ6, SQ8, BF16, FP16, FP32 # MILVUS_HNSW_SQ_REFINE_TYPE=FP32 ### refine_k: Refinement expansion factor, default 10 # MILVUS_HNSW_SQ_REFINE_K=10 ### IVF_FLAT / IVF_SQ8 Parameters ### nlist: Number of cluster units [1-65536], recommended sqrt(n) for n>1M, default 1024 # MILVUS_IVF_NLIST=1024 ### nprobe: Number of units to query [1-nlist], default 16 # MILVUS_IVF_NPROBE=16 ### Qdrant QDRANT_URL=http://localhost:6333 # QDRANT_DEVICE=cpu # QDRANT_API_KEY=your-api-key ### Qdrant upsert/delete batching (enabled by default) ### Split large upserts by estimated JSON payload size and point count, and ### large deletes by point count, to stay under the server/gateway request limit. ### Default 16MB keeps safe headroom below common 32MB gateway/request limits. ### A single point larger than the byte budget is sent as its own batch instead of failing. # QDRANT_UPSERT_MAX_PAYLOAD_BYTES=16777216 # QDRANT_UPSERT_MAX_POINTS_PER_BATCH=128 # QDRANT_DELETE_MAX_POINTS_PER_BATCH=1000 ### DB specific workspace should not be set, keep for compatible only # QDRANT_WORKSPACE=forced_workspace_name ### Redis REDIS_URI=redis://localhost:6379 REDIS_SOCKET_TIMEOUT=30 REDIS_CONNECT_TIMEOUT=10 REDIS_MAX_CONNECTIONS=100 REDIS_RETRY_ATTEMPTS=3 ### LightRAG keeps doc_status / full_docs / the scheduling index in Redis as a ### system of record, and none of those keys carry a TTL. Startup therefore ### REFUSES an instance with maxmemory>0 plus an `allkeys-*` maxmemory-policy, ### because eviction there drops documents and scheduling state silently and ### undetectably. Use `noeviction` (or a `volatile-*` policy), or give LightRAG ### its own instance/db. Set this to true only to accept that data loss. # REDIS_ALLOW_EVICTION_POLICY=false ### DB specific workspace should not be set, keep for compatible only # REDIS_WORKSPACE=forced_workspace_name ### Memgraph Configuration MEMGRAPH_URI=bolt://localhost:7687 MEMGRAPH_USERNAME= MEMGRAPH_PASSWORD= MEMGRAPH_DATABASE=memgraph ### DB specific workspace should not be set, keep for compatible only # MEMGRAPH_WORKSPACE=forced_workspace_name ########################################################### ### Langfuse Observability Configuration ### Only works with LLM provided by OpenAI compatible API ### Install with: pip install lightrag-hku[observability] ### Sign up at: https://cloud.langfuse.com or self-host ########################################################### # LANGFUSE_SECRET_KEY='' # LANGFUSE_PUBLIC_KEY='' # LANGFUSE_HOST='https://cloud.langfuse.com' # LANGFUSE_ENABLE_TRACE=true ############################ ### Evaluation Configuration ############################ ### RAGAS evaluation models (used for RAG quality assessment) ### ⚠️ IMPORTANT: Both LLM and Embedding endpoints MUST be OpenAI-compatible ### Default uses OpenAI models for evaluation ### LLM Configuration for Evaluation # EVAL_LLM_MODEL=gpt-4o-mini ### API key for LLM evaluation (fallback to OPENAI_API_KEY if not set) # EVAL_LLM_BINDING_API_KEY=your_api_key ### Custom OpenAI-compatible endpoint for LLM evaluation (optional) # EVAL_LLM_BINDING_HOST=https://api.openai.com/v1 ### Embedding Configuration for Evaluation # EVAL_EMBEDDING_MODEL=text-embedding-3-large ### API key for embeddings (fallback: EVAL_LLM_BINDING_API_KEY -> OPENAI_API_KEY) # EVAL_EMBEDDING_BINDING_API_KEY=your_embedding_api_key ### Custom OpenAI-compatible endpoint for embeddings (fallback: EVAL_LLM_BINDING_HOST) # EVAL_EMBEDDING_BINDING_HOST=https://api.openai.com/v1 ### Performance Tuning ### Number of concurrent test case evaluations ### Lower values reduce API rate limit issues but increase evaluation time # EVAL_MAX_CONCURRENT=2 ### TOP_K query parameter of LightRAG (default: 10) ### Number of entities or relations retrieved from KG # EVAL_QUERY_TOP_K=10 ### LLM request retry and timeout settings for evaluation # EVAL_LLM_MAX_RETRIES=5 # EVAL_LLM_TIMEOUT=180 ########################################################################## ### ----- Preserved custom environment variables from previous .env ----- ### ----- Comments in this session will persist across regenerations ----- ### (This must be the final session; ensure the preceding lines unchanged) ########################################################################## ### The "make env*" wizard will leave the following lines unchanged ### You may add additional env vars or commnets here for your own purpose ########################################################################## ### AWS Bedrock # LLM_BINDING=bedrock # LLM_BINDING_HOST=DEFAULT_BEDROCK_ENDPOINT # LLM_MODEL=us.anthropic.claude-haiku-4-5-20251001-v1:0 # KEYWORD_LLM_MODEL=us.anthropic.claude-haiku-4-5-20251001-v1:0 # QUERY_LLM_MODEL=us.anthropic.claude-haiku-4-5-20251001-v1:0 # VLM_LLM_MODEL=us.anthropic.claude-haiku-4-5-20251001-v1:0 ### ----- Extra setting from previous .env -----