Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Code smell]: _extract_reasoning_step should have returned current_reasoning as an Optional[...] instead of a List[...] #10568

Closed
tslmy opened this issue Feb 11, 2024 · 3 comments
Labels
bug Something isn't working triage Issue needs to be triaged/prioritized

Comments

@tslmy
Copy link
Contributor

tslmy commented Feb 11, 2024

Bug Description

Seeing this line:

reasoning_step = cast(ActionReasoningStep, current_reasoning[-1])

I thought 1) _extract_reasoning_step was capable of extracting multiple reasoning steps from the output: ChatResponse, and 2) we are ruthlessly discarding everything before that. It's only after I read through _extract_reasoning_step did I realize that current_reasoning: List[...] is either an empty list or a singleton list.

I kinda consider this a code smell. _extract_reasoning_step should have returned an current_reasoning: Optional[...] instead.

...u nless there are some portability considerations?

Version

e3a169b

Steps to Reproduce

Not a bug.

Relevant Logs/Tracbacks

No response

@tslmy tslmy added bug Something isn't working triage Issue needs to be triaged/prioritized labels Feb 11, 2024
Copy link

dosubot bot commented Feb 11, 2024

🤖

Hey @tslmy, great to see you diving into the intricacies of our code again! 🚀

Thank you for your feedback on the _extract_reasoning_step function. I understand your concern about the function returning a List[...] instead of an Optional[...]. However, the current_reasoning variable is designed to store multiple reasoning steps, which is why it is a list. Each reasoning step is appended to this list as the program progresses. If current_reasoning were an Optional[...], it could only store one reasoning step or none, which would not be sufficient for the program's needs.

The _extract_reasoning_step function is part of the ReActAgentWorker class and is used in the process of handling actions and generating responses in the LlamaIndex framework. It parses the output of a chat response and extracts the reasoning step from it. The reasoning step is then appended to the current_reasoning list.

Here is the relevant code snippet:

def _extract_reasoning_step(
    self, output: ChatResponse, is_streaming: bool = False
) -> Tuple[str, List[BaseReasoningStep], bool]:
    """
    Extracts the reasoning step from the given output.

    This method parses the message content from the output,
    extracts the reasoning step, and determines whether the processing is
    complete. It also performs validation checks on the output and
    handles possible errors.
    """
    if output.message.content is None:
        raise ValueError("Got empty message.")
    message_content = output.message.content
    current_reasoning = []
    try:
        reasoning_step = self._output_parser.parse(message_content, is_streaming)
    except BaseException as exc:
        raise ValueError(f"Could not parse output: {message_content}") from exc
    if self._verbose:
        print_text(f"{reasoning_step.get_content()}\n", color="pink")
    current_reasoning.append(reasoning_step)

    if reasoning_step.is_done:
        return message_content, current_reasoning, True

    reasoning_step = cast(ActionReasoningStep, reasoning_step)
    if not isinstance(reasoning_step, ActionReasoningStep):
        raise ValueError(f"Expected ActionReasoningStep, got {reasoning_step}")

    return message_content, current_reasoning, False

You can find this function in the llama_index/agent/react/step.py file.

I hope this clarifies the design choice for the current_reasoning variable. If you have any other questions or concerns, feel free to ask.

Sources

About Dosu

This response is meant to be useful and save you time. It is not meant to be a precise solution, but rather a starting point for your own research.

Help me be more useful! Please leave a 👍 if this is helpful and 👎 if it is irrelevant.

If you want to continue the conversation, start your reply with @dosu-bot.

@tslmy
Copy link
Contributor Author

tslmy commented Feb 11, 2024

@dosu-bot , I think it's more readable to declare that list in outer functions. It's kinda too much responsibility to have one function declare a container that to be used in later stages as well as constructing its initial step.

On the other hand, if _extract_reasoning_step had been named _prepare_current_reasoning_container, I wouldn't have complained.

Copy link

dosubot bot commented Feb 11, 2024

🤖

Thank you for your suggestion to improve the readability of the LlamaIndex framework. I agree that the _extract_reasoning_step function in the ReActAgentWorker class could be made more readable by either declaring the current_reasoning list in outer functions or renaming the function to _prepare_current_reasoning_container.

The current_reasoning list is used in multiple places in the ReActAgentWorker class, including the initialize_step, _extract_reasoning_step, _process_actions, _aprocess_actions, _get_response, _run_step, _arun_step, and _run_step_stream methods. Declaring it in an outer function could improve readability and maintainability by reducing the need to declare it in multiple places.

Here is an example of how you might declare the current_reasoning list in an outer function:

def initialize_current_reasoning() -> List[BaseReasoningStep]:
    """Initialize the current reasoning list."""
    return []

You would then replace all occurrences of current_reasoning = [] with current_reasoning = initialize_current_reasoning() in the ReActAgentWorker class.

As for renaming the _extract_reasoning_step function to _prepare_current_reasoning_container, this could also improve readability by making the function's purpose more clear. The current name, _extract_reasoning_step, suggests that the function is extracting a reasoning step from some input, but the function is actually preparing a container for the current reasoning steps, which is more accurately reflected in the suggested name, _prepare_current_reasoning_container.

Here is an example of how you might rename the _extract_reasoning_step function:

def _prepare_current_reasoning_container(
    self, output: ChatResponse, is_streaming: bool = False
) -> Tuple[str, List[BaseReasoningStep], bool]:
    """Prepare the current reasoning container."""
    # function body...

You would then replace all occurrences of _extract_reasoning_step with _prepare_current_reasoning_container in the ReActAgentWorker class.

However, these changes should be made carefully to ensure that they do not introduce any bugs or unexpected behavior. It's also important to update any references to these variables or functions throughout the codebase.

I hope this helps! If you have any further questions or suggestions, please don't hesitate to ask.

Sources

About Dosu

This response is meant to be useful and save you time. It is not meant to be a precise solution, but rather a starting point for your own research.

Help me be more useful! Please leave a 👍 if this is helpful and 👎 if it is irrelevant.

If you want to continue the conversation, start your reply with @dosu-bot.

@dosubot dosubot bot added the stale Issue has not had recent activity or appears to be solved. Stale issues will be automatically closed label May 12, 2024
@dosubot dosubot bot closed this as not planned Won't fix, can't repro, duplicate, stale May 19, 2024
@dosubot dosubot bot removed the stale Issue has not had recent activity or appears to be solved. Stale issues will be automatically closed label May 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working triage Issue needs to be triaged/prioritized
Projects
None yet
Development

No branches or pull requests

1 participant