From 41876bdbfb682c725e9068430740edd7906bf6a5 Mon Sep 17 00:00:00 2001 From: "jinli.yl" Date: Fri, 13 Feb 2026 10:58:52 +0800 Subject: [PATCH] refactor(core): implement lazy initialization for OpenAI clients --- reme/__init__.py | 2 +- reme/core/embedding/openai_embedding_model.py | 17 +++++++++++++---- .../embedding/openai_embedding_model_sync.py | 6 ++++-- reme/core/llm/openai_llm.py | 17 +++++++++++++---- reme/core/llm/openai_llm_sync.py | 6 ++++-- 5 files changed, 35 insertions(+), 13 deletions(-) diff --git a/reme/__init__.py b/reme/__init__.py index e403ca94..4ab6f36a 100644 --- a/reme/__init__.py +++ b/reme/__init__.py @@ -20,7 +20,7 @@ __all__ = [ "ReMeFs", ] -__version__ = "0.3.0.0a8" +__version__ = "0.3.0.0a9" """ diff --git a/reme/core/embedding/openai_embedding_model.py b/reme/core/embedding/openai_embedding_model.py index ccd59104..2fb0f8c1 100644 --- a/reme/core/embedding/openai_embedding_model.py +++ b/reme/core/embedding/openai_embedding_model.py @@ -15,16 +15,23 @@ class OpenAIEmbeddingModel(BaseEmbeddingModel): super().__init__(**kwargs) self.encoding_format: Literal["float", "base64"] = encoding_format - # Create client using factory method - self._client = self._create_client() + # Lazy client initialization + self._client = None def _create_client(self): """Create and return an internal AsyncOpenAI client instance.""" return AsyncOpenAI(api_key=self.api_key, base_url=self.base_url) + @property + def client(self): + """Lazily create and return the AsyncOpenAI client.""" + if self._client is None: + self._client = self._create_client() + return self._client + async def _get_embeddings(self, input_text: list[str], **kwargs) -> list[list[float]]: """Fetch embeddings from the API for a batch of strings.""" - completion = await self._client.embeddings.create( + completion = await self.client.embeddings.create( model=self.model_name, input=input_text, dimensions=self.dimensions, @@ -40,4 +47,6 @@ class OpenAIEmbeddingModel(BaseEmbeddingModel): async def close(self): """Close the asynchronous OpenAI client and release network resources.""" - await self._client.close() + if self._client is not None: + await self._client.close() + self._client = None diff --git a/reme/core/embedding/openai_embedding_model_sync.py b/reme/core/embedding/openai_embedding_model_sync.py index cf3aac14..25242b06 100644 --- a/reme/core/embedding/openai_embedding_model_sync.py +++ b/reme/core/embedding/openai_embedding_model_sync.py @@ -14,7 +14,7 @@ class OpenAIEmbeddingModelSync(OpenAIEmbeddingModel): def _get_embeddings_sync(self, input_text: list[str], **kwargs) -> list[list[float]]: """Fetch embeddings synchronously from the API for a batch of strings.""" - completion = self._client.embeddings.create( + completion = self.client.embeddings.create( model=self.model_name, input=input_text, dimensions=self.dimensions, @@ -30,4 +30,6 @@ class OpenAIEmbeddingModelSync(OpenAIEmbeddingModel): def close_sync(self): """Close the synchronous OpenAI client and release network resources.""" - self._client.close() + if self._client is not None: + self._client.close() + self._client = None diff --git a/reme/core/llm/openai_llm.py b/reme/core/llm/openai_llm.py index e7fc65fe..c757ed50 100644 --- a/reme/core/llm/openai_llm.py +++ b/reme/core/llm/openai_llm.py @@ -19,13 +19,20 @@ class OpenAILLM(BaseLLM): """Initialize the OpenAI async client with API credentials and model configuration.""" super().__init__(**kwargs) - # Create client using factory method - self._client = self._create_client() + # Lazy client initialization + self._client = None def _create_client(self): """Create and return an instance of the AsyncOpenAI client.""" return AsyncOpenAI(api_key=self.api_key, base_url=self.base_url) + @property + def client(self): + """Lazily create and return the AsyncOpenAI client.""" + if self._client is None: + self._client = self._create_client() + return self._client + def _build_stream_kwargs( self, messages: list[Message], @@ -76,7 +83,7 @@ class OpenAILLM(BaseLLM): ) -> AsyncGenerator[StreamChunk, None]: """Generate a stream of chat completion chunks including text, reasoning content, and tool calls.""" stream_kwargs = stream_kwargs or {} - completion = await self._client.chat.completions.create(**stream_kwargs) + completion = await self.client.chat.completions.create(**stream_kwargs) ret_tool_calls: list[ToolCall] = [] async for chunk in completion: @@ -102,4 +109,6 @@ class OpenAILLM(BaseLLM): async def close(self): """Asynchronously close the OpenAI client and release network resources.""" - await self._client.close() + if self._client is not None: + await self._client.close() + self._client = None diff --git a/reme/core/llm/openai_llm_sync.py b/reme/core/llm/openai_llm_sync.py index e7e0291b..1cdce427 100644 --- a/reme/core/llm/openai_llm_sync.py +++ b/reme/core/llm/openai_llm_sync.py @@ -26,7 +26,7 @@ class OpenAILLMSync(OpenAILLM): ) -> Generator[StreamChunk, None, None]: """Synchronously generate a stream of chat completion chunks including text, reasoning, and tool calls.""" stream_kwargs = stream_kwargs or {} - completion = self._client.chat.completions.create(**stream_kwargs) + completion = self.client.chat.completions.create(**stream_kwargs) ret_tool_calls: list[ToolCall] = [] for chunk in completion: @@ -52,4 +52,6 @@ class OpenAILLMSync(OpenAILLM): def close_sync(self): """Close the synchronous OpenAI client and release network resources.""" - self._client.close() + if self._client is not None: + self._client.close() + self._client = None