Skip to content

Add retry mechanism to LLMFactory and BaseLLM - #827

Open
Undertone0809 wants to merge 1 commit into
mainfrom
add-retry
Open

Add retry mechanism to LLMFactory and BaseLLM#827
Undertone0809 wants to merge 1 commit into
mainfrom
add-retry

Conversation

@Undertone0809

@Undertone0809 Undertone0809 commented Jul 29, 2024

Copy link
Copy Markdown
Owner

Related to #651

Add retry mechanism to LLMFactory and LiteLLM classes to increase robustness.

  • LLMFactory:

    • Add max_retry parameter to LLMFactory.build method in promptulate/llms/factory.py.
    • Pass max_retry parameter to LiteLLM constructor.
  • LiteLLM:

    • Add max_retry attribute to LiteLLM class in promptulate/llms/_litellm.py.
    • Modify _predict method to include retry logic.
  • AIChat:

    • Add max_retry parameter to AIChat constructor in promptulate/chat.py.
    • Pass max_retry parameter to LLMFactory.build method.
  • Tests:

    • Add tests in tests/llms/test_factory.py to verify retry mechanism.
    • Mock LiteLLM to simulate failure and retry behavior.

For more details, open the Copilot Workspace session.

Summary by CodeRabbit

  • New Features

    • Introduced a max_retry parameter across various functionalities, enhancing user control over retry attempts during LLM initialization and chat operations.
    • Improved error handling and robustness in the LiteLLM prediction process with a retry mechanism.
  • Bug Fixes

    • Enhanced resilience in LLM interactions by implementing a retry logic for failed attempts.
  • Tests

    • Added new tests to validate the retry mechanisms for the LiteLLM model, ensuring robust error handling.

Related to #651

Add retry mechanism to `LLMFactory` and `LiteLLM` classes to increase robustness.

* **LLMFactory**:
  - Add `max_retry` parameter to `LLMFactory.build` method in `promptulate/llms/factory.py`.
  - Pass `max_retry` parameter to `LiteLLM` constructor.

* **LiteLLM**:
  - Add `max_retry` attribute to `LiteLLM` class in `promptulate/llms/_litellm.py`.
  - Modify `_predict` method to include retry logic.

* **AIChat**:
  - Add `max_retry` parameter to `AIChat` constructor in `promptulate/chat.py`.
  - Pass `max_retry` parameter to `LLMFactory.build` method.

* **Tests**:
  - Add tests in `tests/llms/test_factory.py` to verify retry mechanism.
  - Mock `LiteLLM` to simulate failure and retry behavior.

---

For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/Undertone0809/promptulate/issues/651?shareId=XXXX-XXXX-XXXX-XXXX).
@coderabbitai

coderabbitai Bot commented Jul 29, 2024

Copy link
Copy Markdown

Walkthrough

The recent changes introduce a max_retry parameter across various components in the promptulate library, enhancing the robustness of language model instantiation and prediction processes. This parameter allows users to specify the maximum number of retry attempts for operations, promoting error resilience and improving control over the chat and model functionalities.

Changes

File Path Change Summary
promptulate/chat.py Added max_retry parameter to _get_llm, AIChat constructor, and chat method for enhanced retry logic.
promptulate/llms/_litellm.py Introduced max_retry in LiteLLM constructor; implemented retry mechanism in _predict method.
promptulate/llms/factory.py Updated LLMFactory.build method to include max_retry, ensuring consistent retry handling across models.
tests/llms/test_factory.py Added tests for retry mechanism in LiteLLM, validating functionality under exception scenarios.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant AIChat
    participant LiteLLM
    
    User->>AIChat: Initialize chat with max_retry
    AIChat->>LiteLLM: Create instance with max_retry
    LiteLLM->>LiteLLM: Call _predict with retries
    LiteLLM-->>LiteLLM: If success, return result
    LiteLLM-->>AIChat: Return prediction result
    AIChat-->>User: Provide response
Loading

🐰 In the garden, I hop and play,
With max_retry, come what may!
If things go wrong, I'll try again,
Until success, I'll not complain!
With every bounce and every cheer,
Robust chat, oh what a year! 🌼


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between a5a0874 and d1d8382.

Files selected for processing (4)
  • promptulate/chat.py (7 hunks)
  • promptulate/llms/_litellm.py (1 hunks)
  • promptulate/llms/factory.py (2 hunks)
  • tests/llms/test_factory.py (2 hunks)
Additional context used
Ruff
promptulate/llms/factory.py

10-10: Line too long (108 > 88)

(E501)


20-20: Line too long (102 > 88)

(E501)


24-24: Line too long (104 > 88)

(E501)


28-28: Line too long (98 > 88)

(E501)

tests/llms/test_factory.py

65-65: Line too long (101 > 88)

(E501)


73-73: Line too long (101 > 88)

(E501)

promptulate/llms/_litellm.py

34-34: Line too long (102 > 88)

(E501)


69-69: Line too long (94 > 88)

(E501)

Additional comments not posted (9)
promptulate/chat.py (9)

47-47: Parameter Addition: max_retry

The max_retry parameter has been added to the _get_llm function, which enhances the function's flexibility by allowing users to specify the maximum number of retries.


55-55: Docstring Update: max_retry

The docstring has been updated to include the max_retry parameter, ensuring that the function documentation is accurate and complete.


86-86: Parameter Addition: max_retry

The max_retry parameter has been added to the AIChat.__init__ method, which enhances the class's flexibility by allowing users to specify the maximum number of retries.


98-98: Docstring Update: max_retry

The docstring has been updated to include the max_retry parameter, ensuring that the class documentation is accurate and complete.


214-214: Parameter Addition: max_retry

The max_retry parameter has been added to the chat function, which enhances the function's flexibility by allowing users to specify the maximum number of retries.


234-234: Docstring Update: max_retry

The docstring has been updated to include the max_retry parameter, ensuring that the function documentation is accurate and complete.


74-74: Verify max_retry usage in LLMFactory.build

Ensure that the max_retry parameter is correctly utilized in the LLMFactory.build method.

Verification successful

The max_retry parameter is correctly utilized in the LLMFactory.build method.

  • The parameter is passed to the constructors of ZhiPu, QianFan, and LiteLLM classes within the build method.
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the `max_retry` parameter is correctly utilized in the `LLMFactory.build` method.

# Test: Search for the `LLMFactory.build` method implementation. Expect: Usage of `max_retry` parameter.
rg --type python 'def build' -A 10

Length of output: 67


Script:

#!/bin/bash
# Correcting the previous command to search for the `build` method implementation in Python files and check the usage of `max_retry`.

# Search for the `build` method in Python files within the `LLMFactory` class.
rg 'def build' -t py -A 20

# Use `ast-grep` to locate the exact implementation of the `build` method in the `LLMFactory` class.
ast-grep --lang python --pattern $'class LLMFactory:\n  $$$\n  def build($_, $_, model_config, max_retry):\n    $$$\n  $$$'

Length of output: 3294


100-100: Verify max_retry usage in _get_llm

Ensure that the max_retry parameter is correctly utilized in the _get_llm function.

Verification successful

max_retry is correctly utilized in the _get_llm function.

  • The max_retry parameter is passed to the LLMFactory.build method within the _get_llm function.
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the `max_retry` parameter is correctly utilized in the `_get_llm` function.

# Test: Search for the `_get_llm` function implementation. Expect: Usage of `max_retry` parameter.
rg --type python 'def _get_llm' -A 10

Length of output: 70


Script:

#!/bin/bash
# Description: Verify that the `max_retry` parameter is correctly utilized in the `_get_llm` function.

# Test: Search for the `_get_llm` function implementation. Expect: Usage of `max_retry` parameter.
rg --type py 'def _get_llm' -A 20

Length of output: 1022


Script:

#!/bin/bash
# Description: Verify that the `max_retry` parameter is correctly utilized in the `_get_llm` function.

# Test: Search for the `_get_llm` function implementation. Expect: Usage of `max_retry` parameter.
rg --type py 'def _get_llm' -A 50

Length of output: 2579


249-249: Verify max_retry usage in AIChat constructor

Ensure that the max_retry parameter is correctly utilized in the AIChat constructor.

Verification successful

The max_retry parameter is correctly utilized in the AIChat constructor.

  • The max_retry parameter is passed from the AIChat constructor to the _get_llm function.
  • The _get_llm function then passes max_retry to the LLMFactory.build method, which uses it to initialize various LLM instances.
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the `max_retry` parameter is correctly utilized in the `AIChat` constructor.

# Test: Search for the `AIChat` class implementation. Expect: Usage of `max_retry` parameter.
rg --type python 'class AIChat' -A 10

Length of output: 70


Script:

#!/bin/bash
# Description: Verify that the `max_retry` parameter is correctly utilized in the `AIChat` constructor.

# Step 1: Locate the `AIChat` class definition.
rg 'class AIChat' -A 20

# Step 2: Locate the constructor of the `AIChat` class and check for `max_retry` usage.
rg 'def __init__' -A 20

Length of output: 72708


Script:

#!/bin/bash
# Description: Verify that the `max_retry` parameter is correctly utilized in the `AIChat` class.

# Step 1: Locate the `AIChat` class definition and its methods.
rg 'class AIChat' -A 50

# Step 2: Search for `max_retry` usage within the `promptulate/chat.py` file.
rg 'max_retry' promptulate/chat.py

Length of output: 3571


Script:

#!/bin/bash
# Description: Verify that the `max_retry` parameter is correctly utilized in the `_get_llm` function and `LLMFactory.build` method.

# Step 1: Locate the `_get_llm` function definition.
rg 'def _get_llm' -A 20

# Step 2: Locate the `LLMFactory.build` method definition.
rg 'def build' -A 20

Length of output: 4180

from promptulate.llms import ZhiPu

return ZhiPu(model=model_id, model_config=model_config, **kwargs)
return ZhiPu(model=model_id, model_config=model_config, max_retry=max_retry, **kwargs)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor long line.

The line is too long (102 > 88 characters). Consider breaking it into multiple lines for better readability.

-                return ZhiPu(model=model_id, model_config=model_config, max_retry=max_retry, **kwargs)
+                return ZhiPu(
+                    model=model_id, 
+                    model_config=model_config, 
+                    max_retry=max_retry, 
+                    **kwargs
+                )
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return ZhiPu(model=model_id, model_config=model_config, max_retry=max_retry, **kwargs)
return ZhiPu(
model=model_id,
model_config=model_config,
max_retry=max_retry,
**kwargs
)
Tools
Ruff

20-20: Line too long (102 > 88)

(E501)

pass

return LiteLLM(model=model_name, model_config=model_config, **kwargs)
return LiteLLM(model=model_name, model_config=model_config, max_retry=max_retry, **kwargs)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor long line.

The line is too long (98 > 88 characters). Consider breaking it into multiple lines for better readability.

-        return LiteLLM(model=model_name, model_config=model_config, max_retry=max_retry, **kwargs)
+        return LiteLLM(
+            model=model_name, 
+            model_config=model_config, 
+            max_retry=max_retry, 
+            **kwargs
+        )
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return LiteLLM(model=model_name, model_config=model_config, max_retry=max_retry, **kwargs)
return LiteLLM(
model=model_name,
model_config=model_config,
max_retry=max_retry,
**kwargs
)
Tools
Ruff

28-28: Line too long (98 > 88)

(E501)

@classmethod
def build(
cls, model_name: str, *, model_config: Optional[Dict[str, Any]] = None, **kwargs
cls, model_name: str, *, model_config: Optional[Dict[str, Any]] = None, max_retry: int = 5, **kwargs

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor long line.

The line is too long (108 > 88 characters). Consider breaking it into multiple lines for better readability.

-        cls, model_name: str, *, model_config: Optional[Dict[str, Any]] = None, max_retry: int = 5, **kwargs
+        cls, 
+        model_name: str, 
+        *, 
+        model_config: Optional[Dict[str, Any]] = None, 
+        max_retry: int = 5, 
+        **kwargs
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
cls, model_name: str, *, model_config: Optional[Dict[str, Any]] = None, max_retry: int = 5, **kwargs
cls,
model_name: str,
*,
model_config: Optional[Dict[str, Any]] = None,
max_retry: int = 5,
**kwargs
Tools
Ruff

10-10: Line too long (108 > 88)

(E501)

from promptulate.llms import QianFan

return QianFan(model=model_id, model_config=model_config, **kwargs)
return QianFan(model=model_id, model_config=model_config, max_retry=max_retry, **kwargs)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor long line.

The line is too long (104 > 88 characters). Consider breaking it into multiple lines for better readability.

-                return QianFan(model=model_id, model_config=model_config, max_retry=max_retry, **kwargs)
+                return QianFan(
+                    model=model_id, 
+                    model_config=model_config, 
+                    max_retry=max_retry, 
+                    **kwargs
+                )
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return QianFan(model=model_id, model_config=model_config, max_retry=max_retry, **kwargs)
return QianFan(
model=model_id,
model_config=model_config,
max_retry=max_retry,
**kwargs
)
Tools
Ruff

24-24: Line too long (104 > 88)

(E501)



def test_litellm_retry():
with mock.patch.object(LiteLLM, "_predict", side_effect=Exception("Test error")) as mock_predict:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor long line.

The line is too long (101 > 88 characters). Consider breaking it into multiple lines for better readability.

-    with mock.patch.object(LiteLLM, "_predict", side_effect=Exception("Test error")) as mock_predict:
+    with mock.patch.object(
+        LiteLLM, 
+        "_predict", 
+        side_effect=Exception("Test error")
+    ) as mock_predict:
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
with mock.patch.object(LiteLLM, "_predict", side_effect=Exception("Test error")) as mock_predict:
with mock.patch.object(
LiteLLM,
"_predict",
side_effect=Exception("Test error")
) as mock_predict:
Tools
Ruff

73-73: Line too long (101 > 88)

(E501)



def test_retry_mechanism():
with mock.patch.object(LiteLLM, "_predict", side_effect=Exception("Test error")) as mock_predict:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor long line.

The line is too long (101 > 88 characters). Consider breaking it into multiple lines for better readability.

-    with mock.patch.object(LiteLLM, "_predict", side_effect=Exception("Test error")) as mock_predict:
+    with mock.patch.object(
+        LiteLLM, 
+        "_predict", 
+        side_effect=Exception("Test error")
+    ) as mock_predict:
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
with mock.patch.object(LiteLLM, "_predict", side_effect=Exception("Test error")) as mock_predict:
with mock.patch.object(
LiteLLM,
"_predict",
side_effect=Exception("Test error")
) as mock_predict:
Tools
Ruff

65-65: Line too long (101 > 88)

(E501)

else json.loads(temp_response.json()),
)
logger.debug(
f"[pne chat] response: {json.dumps(response.additional_kwargs, indent=2)}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor long line.

The line is too long (94 > 88 characters). Consider breaking it into multiple lines for better readability.

-                    f"[pne chat] response: {json.dumps(response.additional_kwargs, indent=2)}"
+                    f"[pne chat] response: {json.dumps(
+                        response.additional_kwargs, 
+                        indent=2
+                    )}"
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
f"[pne chat] response: {json.dumps(response.additional_kwargs, indent=2)}"
f"[pne chat] response: {json.dumps(
response.additional_kwargs,
indent=2
)}"
Tools
Ruff

69-69: Line too long (94 > 88)

(E501)


class LiteLLM(BaseLLM):
def __init__(self, model: str, model_config: Optional[dict] = None, **kwargs):
def __init__(self, model: str, model_config: Optional[dict] = None, max_retry: int = 5, **kwargs):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor long line.

The line is too long (102 > 88 characters). Consider breaking it into multiple lines for better readability.

-    def __init__(self, model: str, model_config: Optional[dict] = None, max_retry: int = 5, **kwargs):
+    def __init__(
+        self, 
+        model: str, 
+        model_config: Optional[dict] = None, 
+        max_retry: int = 5, 
+        **kwargs
+    ):
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def __init__(self, model: str, model_config: Optional[dict] = None, max_retry: int = 5, **kwargs):
def __init__(
self,
model: str,
model_config: Optional[dict] = None,
max_retry: int = 5,
**kwargs
):
Tools
Ruff

34-34: Line too long (102 > 88)

(E501)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant