From d94aae9c5ed41389c98bf94b21aa926e14f50ebe Mon Sep 17 00:00:00 2001 From: Yasiru Rangana Date: Fri, 7 Nov 2025 09:55:06 +1100 Subject: [PATCH 01/10] Add dimensions parameter support to openai_embed() --- lightrag/llm/openai.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/lightrag/llm/openai.py b/lightrag/llm/openai.py index 66c3bfe4..155fd3e9 100644 --- a/lightrag/llm/openai.py +++ b/lightrag/llm/openai.py @@ -609,6 +609,7 @@ async def openai_embed( model: str = "text-embedding-3-small", base_url: str | None = None, api_key: str | None = None, + embedding_dim: int = None, client_configs: dict[str, Any] | None = None, token_tracker: Any | None = None, ) -> np.ndarray: @@ -619,6 +620,7 @@ async def openai_embed( model: The OpenAI embedding model to use. base_url: Optional base URL for the OpenAI API. api_key: Optional OpenAI API key. If None, uses the OPENAI_API_KEY environment variable. + embedding_dim: Optional embedding dimension. If None, uses the default embedding dimension for the model. (will be passed to API for dimension reduction). client_configs: Additional configuration options for the AsyncOpenAI client. These will override any default configurations but will be overridden by explicit parameters (api_key, base_url). @@ -638,9 +640,19 @@ async def openai_embed( ) async with openai_async_client: - response = await openai_async_client.embeddings.create( - model=model, input=texts, encoding_format="base64" - ) + # Prepare API call parameters + api_params = { + "model": model, + "input": texts, + "encoding_format": "base64", + } + + # Add dimensions parameter only if embedding_dim is provided + if embedding_dim is not None: + api_params["dimensions"] = embedding_dim + + # Make API call + response = await openai_async_client.embeddings.create(**api_params) if token_tracker and hasattr(response, "usage"): token_counts = { From 33a1482f7ff27e1992ac9fe05eb637312c7b8299 Mon Sep 17 00:00:00 2001 From: yangdx Date: Fri, 7 Nov 2025 20:46:40 +0800 Subject: [PATCH 02/10] Add optional embedding dimension parameter control via env var * Add EMBEDDING_SEND_DIM environment variable * Update Jina/OpenAI embed functions * Add send_dimensions to EmbeddingFunc * Auto-inject embedding_dim when enabled * Add parameter validation warnings --- env.example | 7 +++++ lightrag/api/lightrag_server.py | 49 +++++++++++++++++++++++++-------- lightrag/llm/jina.py | 13 ++++++--- lightrag/llm/openai.py | 9 ++++-- lightrag/utils.py | 16 +++++++++++ 5 files changed, 76 insertions(+), 18 deletions(-) diff --git a/env.example b/env.example index ce1eab0f..521021b8 100644 --- a/env.example +++ b/env.example @@ -241,6 +241,13 @@ OLLAMA_LLM_NUM_CTX=32768 ### EMBEDDING_BINDING_HOST: host only for Ollama, endpoint for other Embedding service ####################################################################################### # EMBEDDING_TIMEOUT=30 + +### Control whether to send embedding_dim parameter to embedding API +### Set to 'true' to enable dynamic dimension adjustment (only works for OpenAI and Jina) +### Set to 'false' (default) to disable sending dimension parameter +### Note: This is automatically ignored for backends that don't support dimension parameter +# EMBEDDING_SEND_DIM=false + EMBEDDING_BINDING=ollama EMBEDDING_MODEL=bge-m3:latest EMBEDDING_DIM=1024 diff --git a/lightrag/api/lightrag_server.py b/lightrag/api/lightrag_server.py index 70e17bb6..a66d5d3c 100644 --- a/lightrag/api/lightrag_server.py +++ b/lightrag/api/lightrag_server.py @@ -15,7 +15,6 @@ import logging.config import sys import uvicorn import pipmaster as pm -import inspect from fastapi.staticfiles import StaticFiles from fastapi.responses import RedirectResponse from pathlib import Path @@ -595,7 +594,7 @@ def create_app(args): return {} def create_optimized_embedding_function( - config_cache: LLMConfigCache, binding, model, host, api_key, dimensions, args + config_cache: LLMConfigCache, binding, model, host, api_key, args ): """ Create optimized embedding function with pre-processed configuration for applicable bindings. @@ -641,7 +640,7 @@ def create_app(args): from lightrag.llm.jina import jina_embed return await jina_embed( - texts, dimensions=dimensions, base_url=host, api_key=api_key + texts, base_url=host, api_key=api_key ) else: # openai and compatible from lightrag.llm.openai import openai_embed @@ -687,17 +686,43 @@ def create_app(args): ) # Create embedding function with optimized configuration + import inspect + + # Create the optimized embedding function + optimized_embedding_func = create_optimized_embedding_function( + config_cache=config_cache, + binding=args.embedding_binding, + model=args.embedding_model, + host=args.embedding_binding_host, + api_key=args.embedding_binding_api_key, + args=args, # Pass args object for fallback option generation + ) + + # Check environment variable for sending dimensions + embedding_send_dim = os.getenv("EMBEDDING_SEND_DIM", "false").lower() == "true" + + # Check if the function signature has embedding_dim parameter + # Note: Since optimized_embedding_func is an async function, inspect its signature + sig = inspect.signature(optimized_embedding_func) + has_embedding_dim_param = 'embedding_dim' in sig.parameters + + # Determine send_dimensions value + # Only send dimensions if both conditions are met: + # 1. EMBEDDING_SEND_DIM environment variable is true + # 2. The function has embedding_dim parameter + send_dimensions = embedding_send_dim and has_embedding_dim_param + + logger.info( + f"Embedding configuration: send_dimensions={send_dimensions} " + f"(env_var={embedding_send_dim}, has_param={has_embedding_dim_param}, " + f"binding={args.embedding_binding})" + ) + + # Create EmbeddingFunc with send_dimensions attribute embedding_func = EmbeddingFunc( embedding_dim=args.embedding_dim, - func=create_optimized_embedding_function( - config_cache=config_cache, - binding=args.embedding_binding, - model=args.embedding_model, - host=args.embedding_binding_host, - api_key=args.embedding_binding_api_key, - dimensions=args.embedding_dim, - args=args, # Pass args object for fallback option generation - ), + func=optimized_embedding_func, + send_dimensions=send_dimensions, ) # Configure rerank function based on args.rerank_bindingparameter diff --git a/lightrag/llm/jina.py b/lightrag/llm/jina.py index 5077ee25..70de5995 100644 --- a/lightrag/llm/jina.py +++ b/lightrag/llm/jina.py @@ -69,7 +69,7 @@ async def fetch_data(url, headers, data): ) async def jina_embed( texts: list[str], - dimensions: int = 2048, + embedding_dim: int = 2048, late_chunking: bool = False, base_url: str = None, api_key: str = None, @@ -78,7 +78,12 @@ async def jina_embed( Args: texts: List of texts to embed. - dimensions: The embedding dimensions (default: 2048 for jina-embeddings-v4). + embedding_dim: The embedding dimensions (default: 2048 for jina-embeddings-v4). + **IMPORTANT**: This parameter is automatically injected by the EmbeddingFunc wrapper. + Do NOT manually pass this parameter when calling the function directly. + The dimension is controlled by the @wrap_embedding_func_with_attrs decorator. + Manually passing a different value will trigger a warning and be ignored. + When provided (by EmbeddingFunc), it will be passed to the Jina API for dimension reduction. late_chunking: Whether to use late chunking. base_url: Optional base URL for the Jina API. api_key: Optional Jina API key. If None, uses the JINA_API_KEY environment variable. @@ -104,7 +109,7 @@ async def jina_embed( data = { "model": "jina-embeddings-v4", "task": "text-matching", - "dimensions": dimensions, + "dimensions": embedding_dim, "embedding_type": "base64", "input": texts, } @@ -114,7 +119,7 @@ async def jina_embed( data["late_chunking"] = late_chunking logger.debug( - f"Jina embedding request: {len(texts)} texts, dimensions: {dimensions}" + f"Jina embedding request: {len(texts)} texts, dimensions: {embedding_dim}" ) try: diff --git a/lightrag/llm/openai.py b/lightrag/llm/openai.py index 155fd3e9..fce33cac 100644 --- a/lightrag/llm/openai.py +++ b/lightrag/llm/openai.py @@ -609,7 +609,7 @@ async def openai_embed( model: str = "text-embedding-3-small", base_url: str | None = None, api_key: str | None = None, - embedding_dim: int = None, + embedding_dim: int | None = None, client_configs: dict[str, Any] | None = None, token_tracker: Any | None = None, ) -> np.ndarray: @@ -620,7 +620,12 @@ async def openai_embed( model: The OpenAI embedding model to use. base_url: Optional base URL for the OpenAI API. api_key: Optional OpenAI API key. If None, uses the OPENAI_API_KEY environment variable. - embedding_dim: Optional embedding dimension. If None, uses the default embedding dimension for the model. (will be passed to API for dimension reduction). + embedding_dim: Optional embedding dimension for dynamic dimension reduction. + **IMPORTANT**: This parameter is automatically injected by the EmbeddingFunc wrapper. + Do NOT manually pass this parameter when calling the function directly. + The dimension is controlled by the @wrap_embedding_func_with_attrs decorator. + Manually passing a different value will trigger a warning and be ignored. + When provided (by EmbeddingFunc), it will be passed to the OpenAI API for dimension reduction. client_configs: Additional configuration options for the AsyncOpenAI client. These will override any default configurations but will be overridden by explicit parameters (api_key, base_url). diff --git a/lightrag/utils.py b/lightrag/utils.py index 28559af5..9ac82b1c 100644 --- a/lightrag/utils.py +++ b/lightrag/utils.py @@ -353,8 +353,24 @@ class EmbeddingFunc: embedding_dim: int func: callable max_token_size: int | None = None # deprecated keep it for compatible only + send_dimensions: bool = False # Control whether to send embedding_dim to the function async def __call__(self, *args, **kwargs) -> np.ndarray: + # Only inject embedding_dim when send_dimensions is True + if self.send_dimensions: + # Check if user provided embedding_dim parameter + if 'embedding_dim' in kwargs: + user_provided_dim = kwargs['embedding_dim'] + # If user's value differs from class attribute, output warning + if user_provided_dim is not None and user_provided_dim != self.embedding_dim: + logger.warning( + f"Ignoring user-provided embedding_dim={user_provided_dim}, " + f"using declared embedding_dim={self.embedding_dim} from decorator" + ) + + # Inject embedding_dim from decorator + kwargs['embedding_dim'] = self.embedding_dim + return await self.func(*args, **kwargs) From c14f25b7f8e3a46e17c1815465b73fff0a090b40 Mon Sep 17 00:00:00 2001 From: yangdx Date: Fri, 7 Nov 2025 21:08:34 +0800 Subject: [PATCH 03/10] Add mandatory dimension parameter handling for Jina API compliance --- env.example | 7 ++++--- lightrag/api/lightrag_server.py | 36 ++++++++++++++++++--------------- lightrag/utils.py | 19 ++++++++++------- 3 files changed, 36 insertions(+), 26 deletions(-) diff --git a/env.example b/env.example index 84c1bbe7..534bd22a 100644 --- a/env.example +++ b/env.example @@ -244,9 +244,10 @@ OLLAMA_LLM_NUM_CTX=32768 # EMBEDDING_TIMEOUT=30 ### Control whether to send embedding_dim parameter to embedding API -### Set to 'true' to enable dynamic dimension adjustment (only works for OpenAI and Jina) -### Set to 'false' (default) to disable sending dimension parameter -### Note: This is automatically ignored for backends that don't support dimension parameter +### IMPORTANT: Jina ALWAYS sends dimension parameter (API requirement) - this setting is ignored for Jina +### For OpenAI: Set to 'true' to enable dynamic dimension adjustment +### For OpenAI: Set to 'false' (default) to disable sending dimension parameter +### Note: Automatically ignored for backends that don't support dimension parameter (e.g., Ollama) # EMBEDDING_SEND_DIM=false EMBEDDING_BINDING=ollama diff --git a/lightrag/api/lightrag_server.py b/lightrag/api/lightrag_server.py index d8bea386..f36d88df 100644 --- a/lightrag/api/lightrag_server.py +++ b/lightrag/api/lightrag_server.py @@ -643,9 +643,7 @@ def create_app(args): elif binding == "jina": from lightrag.llm.jina import jina_embed - return await jina_embed( - texts, base_url=host, api_key=api_key - ) + return await jina_embed(texts, base_url=host, api_key=api_key) else: # openai and compatible from lightrag.llm.openai import openai_embed @@ -691,7 +689,7 @@ def create_app(args): # Create embedding function with optimized configuration import inspect - + # Create the optimized embedding function optimized_embedding_func = create_optimized_embedding_function( config_cache=config_cache, @@ -701,27 +699,33 @@ def create_app(args): api_key=args.embedding_binding_api_key, args=args, # Pass args object for fallback option generation ) - + # Check environment variable for sending dimensions embedding_send_dim = os.getenv("EMBEDDING_SEND_DIM", "false").lower() == "true" - + # Check if the function signature has embedding_dim parameter # Note: Since optimized_embedding_func is an async function, inspect its signature sig = inspect.signature(optimized_embedding_func) - has_embedding_dim_param = 'embedding_dim' in sig.parameters - - # Determine send_dimensions value - # Only send dimensions if both conditions are met: - # 1. EMBEDDING_SEND_DIM environment variable is true - # 2. The function has embedding_dim parameter - send_dimensions = embedding_send_dim and has_embedding_dim_param - + has_embedding_dim_param = "embedding_dim" in sig.parameters + + # Determine send_dimensions value based on binding type + # Jina REQUIRES dimension parameter (forced to True) + # OpenAI and others: controlled by EMBEDDING_SEND_DIM environment variable + if args.embedding_binding == "jina": + # Jina API requires dimension parameter - always send it + send_dimensions = has_embedding_dim_param + dimension_control = "forced (Jina API requirement)" + else: + # For OpenAI and other bindings, respect EMBEDDING_SEND_DIM setting + send_dimensions = embedding_send_dim and has_embedding_dim_param + dimension_control = f"env_var={embedding_send_dim}" + logger.info( f"Embedding configuration: send_dimensions={send_dimensions} " - f"(env_var={embedding_send_dim}, has_param={has_embedding_dim_param}, " + f"({dimension_control}, has_param={has_embedding_dim_param}, " f"binding={args.embedding_binding})" ) - + # Create EmbeddingFunc with send_dimensions attribute embedding_func = EmbeddingFunc( embedding_dim=args.embedding_dim, diff --git a/lightrag/utils.py b/lightrag/utils.py index 9ac82b1c..460ede3c 100644 --- a/lightrag/utils.py +++ b/lightrag/utils.py @@ -353,24 +353,29 @@ class EmbeddingFunc: embedding_dim: int func: callable max_token_size: int | None = None # deprecated keep it for compatible only - send_dimensions: bool = False # Control whether to send embedding_dim to the function + send_dimensions: bool = ( + False # Control whether to send embedding_dim to the function + ) async def __call__(self, *args, **kwargs) -> np.ndarray: # Only inject embedding_dim when send_dimensions is True if self.send_dimensions: # Check if user provided embedding_dim parameter - if 'embedding_dim' in kwargs: - user_provided_dim = kwargs['embedding_dim'] + if "embedding_dim" in kwargs: + user_provided_dim = kwargs["embedding_dim"] # If user's value differs from class attribute, output warning - if user_provided_dim is not None and user_provided_dim != self.embedding_dim: + if ( + user_provided_dim is not None + and user_provided_dim != self.embedding_dim + ): logger.warning( f"Ignoring user-provided embedding_dim={user_provided_dim}, " f"using declared embedding_dim={self.embedding_dim} from decorator" ) - + # Inject embedding_dim from decorator - kwargs['embedding_dim'] = self.embedding_dim - + kwargs["embedding_dim"] = self.embedding_dim + return await self.func(*args, **kwargs) From ce28f30ca68a2e0469f14beb1b4d65a4633d211e Mon Sep 17 00:00:00 2001 From: yangdx Date: Fri, 7 Nov 2025 21:23:59 +0800 Subject: [PATCH 04/10] Add embedding_dim parameter support to embedding functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • Pass embedding_dim to jina_embed call • Pass embedding_dim to openai_embed call --- lightrag/api/lightrag_server.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lightrag/api/lightrag_server.py b/lightrag/api/lightrag_server.py index f36d88df..60fae05d 100644 --- a/lightrag/api/lightrag_server.py +++ b/lightrag/api/lightrag_server.py @@ -605,7 +605,7 @@ def create_app(args): Uses lazy imports for all bindings and avoids repeated configuration parsing. """ - async def optimized_embedding_function(texts): + async def optimized_embedding_function(texts, embedding_dim=None): try: if binding == "lollms": from lightrag.llm.lollms import lollms_embed @@ -643,12 +643,14 @@ def create_app(args): elif binding == "jina": from lightrag.llm.jina import jina_embed - return await jina_embed(texts, base_url=host, api_key=api_key) + return await jina_embed( + texts, embedding_dim=embedding_dim, base_url=host, api_key=api_key + ) else: # openai and compatible from lightrag.llm.openai import openai_embed return await openai_embed( - texts, model=model, base_url=host, api_key=api_key + texts, model=model, base_url=host, api_key=api_key, embedding_dim=embedding_dim ) except ImportError as e: raise Exception(f"Failed to import {binding} embedding: {e}") From d95efcb9ad641a05b3047be3ba75477405807e4b Mon Sep 17 00:00:00 2001 From: yangdx Date: Fri, 7 Nov 2025 21:27:54 +0800 Subject: [PATCH 05/10] Fix linting --- lightrag/api/lightrag_server.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lightrag/api/lightrag_server.py b/lightrag/api/lightrag_server.py index 60fae05d..0ed20a28 100644 --- a/lightrag/api/lightrag_server.py +++ b/lightrag/api/lightrag_server.py @@ -644,13 +644,20 @@ def create_app(args): from lightrag.llm.jina import jina_embed return await jina_embed( - texts, embedding_dim=embedding_dim, base_url=host, api_key=api_key + texts, + embedding_dim=embedding_dim, + base_url=host, + api_key=api_key, ) else: # openai and compatible from lightrag.llm.openai import openai_embed return await openai_embed( - texts, model=model, base_url=host, api_key=api_key, embedding_dim=embedding_dim + texts, + model=model, + base_url=host, + api_key=api_key, + embedding_dim=embedding_dim, ) except ImportError as e: raise Exception(f"Failed to import {binding} embedding: {e}") From 01b07b2be57446609c441045c5fa9ba04fef8703 Mon Sep 17 00:00:00 2001 From: yangdx Date: Fri, 7 Nov 2025 22:04:34 +0800 Subject: [PATCH 06/10] Refactor Jina embedding dimension by changing param to optional with default --- lightrag/llm/jina.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lightrag/llm/jina.py b/lightrag/llm/jina.py index 70de5995..f3c89228 100644 --- a/lightrag/llm/jina.py +++ b/lightrag/llm/jina.py @@ -1,4 +1,6 @@ import os +from typing import Final + import pipmaster as pm # Pipmaster for dynamic library install # install specific modules @@ -19,6 +21,9 @@ from tenacity import ( from lightrag.utils import wrap_embedding_func_with_attrs, logger +DEFAULT_JINA_EMBED_DIM: Final[int] = 2048 + + async def fetch_data(url, headers, data): async with aiohttp.ClientSession() as session: async with session.post(url, headers=headers, json=data) as response: @@ -58,7 +63,7 @@ async def fetch_data(url, headers, data): return data_list -@wrap_embedding_func_with_attrs(embedding_dim=2048) +@wrap_embedding_func_with_attrs(embedding_dim=DEFAULT_JINA_EMBED_DIM) @retry( stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=60), @@ -69,7 +74,7 @@ async def fetch_data(url, headers, data): ) async def jina_embed( texts: list[str], - embedding_dim: int = 2048, + embedding_dim: int | None = DEFAULT_JINA_EMBED_DIM, late_chunking: bool = False, base_url: str = None, api_key: str = None, @@ -95,6 +100,10 @@ async def jina_embed( aiohttp.ClientError: If there is a connection error with the Jina API. aiohttp.ClientResponseError: If the Jina API returns an error response. """ + resolved_embedding_dim = ( + embedding_dim if embedding_dim is not None else DEFAULT_JINA_EMBED_DIM + ) + if api_key: os.environ["JINA_API_KEY"] = api_key @@ -109,7 +118,7 @@ async def jina_embed( data = { "model": "jina-embeddings-v4", "task": "text-matching", - "dimensions": embedding_dim, + "dimensions": resolved_embedding_dim, "embedding_type": "base64", "input": texts, } @@ -119,7 +128,7 @@ async def jina_embed( data["late_chunking"] = late_chunking logger.debug( - f"Jina embedding request: {len(texts)} texts, dimensions: {embedding_dim}" + f"Jina embedding request: {len(texts)} texts, dimensions: {resolved_embedding_dim}" ) try: From ffeeae42080e806c51fc385c8f13f9da49e6ad4e Mon Sep 17 00:00:00 2001 From: yangdx Date: Fri, 7 Nov 2025 22:09:57 +0800 Subject: [PATCH 07/10] refactor: simplify jina embedding dimension handling --- lightrag/llm/jina.py | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/lightrag/llm/jina.py b/lightrag/llm/jina.py index f3c89228..70de5995 100644 --- a/lightrag/llm/jina.py +++ b/lightrag/llm/jina.py @@ -1,6 +1,4 @@ import os -from typing import Final - import pipmaster as pm # Pipmaster for dynamic library install # install specific modules @@ -21,9 +19,6 @@ from tenacity import ( from lightrag.utils import wrap_embedding_func_with_attrs, logger -DEFAULT_JINA_EMBED_DIM: Final[int] = 2048 - - async def fetch_data(url, headers, data): async with aiohttp.ClientSession() as session: async with session.post(url, headers=headers, json=data) as response: @@ -63,7 +58,7 @@ async def fetch_data(url, headers, data): return data_list -@wrap_embedding_func_with_attrs(embedding_dim=DEFAULT_JINA_EMBED_DIM) +@wrap_embedding_func_with_attrs(embedding_dim=2048) @retry( stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=60), @@ -74,7 +69,7 @@ async def fetch_data(url, headers, data): ) async def jina_embed( texts: list[str], - embedding_dim: int | None = DEFAULT_JINA_EMBED_DIM, + embedding_dim: int = 2048, late_chunking: bool = False, base_url: str = None, api_key: str = None, @@ -100,10 +95,6 @@ async def jina_embed( aiohttp.ClientError: If there is a connection error with the Jina API. aiohttp.ClientResponseError: If the Jina API returns an error response. """ - resolved_embedding_dim = ( - embedding_dim if embedding_dim is not None else DEFAULT_JINA_EMBED_DIM - ) - if api_key: os.environ["JINA_API_KEY"] = api_key @@ -118,7 +109,7 @@ async def jina_embed( data = { "model": "jina-embeddings-v4", "task": "text-matching", - "dimensions": resolved_embedding_dim, + "dimensions": embedding_dim, "embedding_type": "base64", "input": texts, } @@ -128,7 +119,7 @@ async def jina_embed( data["late_chunking"] = late_chunking logger.debug( - f"Jina embedding request: {len(texts)} texts, dimensions: {resolved_embedding_dim}" + f"Jina embedding request: {len(texts)} texts, dimensions: {embedding_dim}" ) try: From 03cc6262c4531260ac1425f5142b01afe0bcea63 Mon Sep 17 00:00:00 2001 From: yangdx Date: Sat, 8 Nov 2025 01:43:36 +0800 Subject: [PATCH 08/10] Prohibit direct access to internal functions of EmbeddingFunc. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • Fix similarity search error in query stage • Remove redundant null checks • Improve log readability --- lightrag/api/lightrag_server.py | 11 ++++--- lightrag/operate.py | 57 +++++++++++++++------------------ 2 files changed, 32 insertions(+), 36 deletions(-) diff --git a/lightrag/api/lightrag_server.py b/lightrag/api/lightrag_server.py index 0ed20a28..6da76f37 100644 --- a/lightrag/api/lightrag_server.py +++ b/lightrag/api/lightrag_server.py @@ -723,15 +723,18 @@ def create_app(args): if args.embedding_binding == "jina": # Jina API requires dimension parameter - always send it send_dimensions = has_embedding_dim_param - dimension_control = "forced (Jina API requirement)" + dimension_control = "forced by Jina API" else: # For OpenAI and other bindings, respect EMBEDDING_SEND_DIM setting send_dimensions = embedding_send_dim and has_embedding_dim_param - dimension_control = f"env_var={embedding_send_dim}" + if send_dimensions or not embedding_send_dim: + dimension_control = "by env var" + else: + dimension_control = "by not hasparam" logger.info( - f"Embedding configuration: send_dimensions={send_dimensions} " - f"({dimension_control}, has_param={has_embedding_dim_param}, " + f"Send embedding dimension: {send_dimensions} {dimension_control} " + f"(dimensions={args.embedding_dim}, has_param={has_embedding_dim_param}, " f"binding={args.embedding_binding})" ) diff --git a/lightrag/operate.py b/lightrag/operate.py index 5018ae0d..ae2be49e 100644 --- a/lightrag/operate.py +++ b/lightrag/operate.py @@ -3425,10 +3425,10 @@ async def _perform_kg_search( ) query_embedding = None if query and (kg_chunk_pick_method == "VECTOR" or chunks_vdb): - embedding_func_config = text_chunks_db.embedding_func - if embedding_func_config and embedding_func_config.func: + actual_embedding_func = text_chunks_db.embedding_func + if actual_embedding_func: try: - query_embedding = await embedding_func_config.func([query]) + query_embedding = await actual_embedding_func([query]) query_embedding = query_embedding[ 0 ] # Extract first embedding from batch result @@ -4336,25 +4336,21 @@ async def _find_related_text_unit_from_entities( num_of_chunks = int(max_related_chunks * len(entities_with_chunks) / 2) # Get embedding function from global config - embedding_func_config = text_chunks_db.embedding_func - if not embedding_func_config: + actual_embedding_func = text_chunks_db.embedding_func + if not actual_embedding_func: logger.warning("No embedding function found, falling back to WEIGHT method") kg_chunk_pick_method = "WEIGHT" else: try: - actual_embedding_func = embedding_func_config.func - - selected_chunk_ids = None - if actual_embedding_func: - selected_chunk_ids = await pick_by_vector_similarity( - query=query, - text_chunks_storage=text_chunks_db, - chunks_vdb=chunks_vdb, - num_of_chunks=num_of_chunks, - entity_info=entities_with_chunks, - embedding_func=actual_embedding_func, - query_embedding=query_embedding, - ) + selected_chunk_ids = await pick_by_vector_similarity( + query=query, + text_chunks_storage=text_chunks_db, + chunks_vdb=chunks_vdb, + num_of_chunks=num_of_chunks, + entity_info=entities_with_chunks, + embedding_func=actual_embedding_func, + query_embedding=query_embedding, + ) if selected_chunk_ids == []: kg_chunk_pick_method = "WEIGHT" @@ -4629,24 +4625,21 @@ async def _find_related_text_unit_from_relations( num_of_chunks = int(max_related_chunks * len(relations_with_chunks) / 2) # Get embedding function from global config - embedding_func_config = text_chunks_db.embedding_func - if not embedding_func_config: + actual_embedding_func = text_chunks_db.embedding_func + if not actual_embedding_func: logger.warning("No embedding function found, falling back to WEIGHT method") kg_chunk_pick_method = "WEIGHT" else: try: - actual_embedding_func = embedding_func_config.func - - if actual_embedding_func: - selected_chunk_ids = await pick_by_vector_similarity( - query=query, - text_chunks_storage=text_chunks_db, - chunks_vdb=chunks_vdb, - num_of_chunks=num_of_chunks, - entity_info=relations_with_chunks, - embedding_func=actual_embedding_func, - query_embedding=query_embedding, - ) + selected_chunk_ids = await pick_by_vector_similarity( + query=query, + text_chunks_storage=text_chunks_db, + chunks_vdb=chunks_vdb, + num_of_chunks=num_of_chunks, + entity_info=relations_with_chunks, + embedding_func=actual_embedding_func, + query_embedding=query_embedding, + ) if selected_chunk_ids == []: kg_chunk_pick_method = "WEIGHT" From 0b2a15c452689166c39e617b67043d1c0785cb97 Mon Sep 17 00:00:00 2001 From: yangdx Date: Sat, 8 Nov 2025 01:52:23 +0800 Subject: [PATCH 09/10] Centralize embedding_send_dim config through args instead of env var --- lightrag/api/config.py | 1 + lightrag/api/lightrag_server.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lightrag/api/config.py b/lightrag/api/config.py index 92e81253..baaf9c52 100644 --- a/lightrag/api/config.py +++ b/lightrag/api/config.py @@ -343,6 +343,7 @@ def parse_args() -> argparse.Namespace: args.llm_model = get_env_value("LLM_MODEL", "mistral-nemo:latest") args.embedding_model = get_env_value("EMBEDDING_MODEL", "bge-m3:latest") args.embedding_dim = get_env_value("EMBEDDING_DIM", 1024, int) + args.embedding_send_dim = get_env_value("EMBEDDING_SEND_DIM", False, bool) # Inject chunk configuration args.chunk_size = get_env_value("CHUNK_SIZE", 1200, int) diff --git a/lightrag/api/lightrag_server.py b/lightrag/api/lightrag_server.py index 6da76f37..b3a439e8 100644 --- a/lightrag/api/lightrag_server.py +++ b/lightrag/api/lightrag_server.py @@ -709,8 +709,8 @@ def create_app(args): args=args, # Pass args object for fallback option generation ) - # Check environment variable for sending dimensions - embedding_send_dim = os.getenv("EMBEDDING_SEND_DIM", "false").lower() == "true" + # Get embedding_send_dim from centralized configuration + embedding_send_dim = args.embedding_send_dim # Check if the function signature has embedding_dim parameter # Note: Since optimized_embedding_func is an async function, inspect its signature From f83ea3394e807630071648f91f0f71c00339187d Mon Sep 17 00:00:00 2001 From: yangdx Date: Sat, 8 Nov 2025 02:07:31 +0800 Subject: [PATCH 10/10] Add section header comment for Gemini binding options --- lightrag/llm/binding_options.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lightrag/llm/binding_options.py b/lightrag/llm/binding_options.py index b3affb37..8f69711a 100644 --- a/lightrag/llm/binding_options.py +++ b/lightrag/llm/binding_options.py @@ -472,6 +472,9 @@ class OllamaLLMOptions(_OllamaOptionsMixin, BindingOptions): _binding_name: ClassVar[str] = "ollama_llm" +# ============================================================================= +# Binding Options for Gemini +# ============================================================================= @dataclass class GeminiLLMOptions(BindingOptions): """Options for Google Gemini models."""