Skip to content

Ralph loop reflect module#749

Merged
rainsonGain merged 2 commits intomainfrom
feature/ralph_reflector
Feb 6, 2026
Merged

Ralph loop reflect module#749
rainsonGain merged 2 commits intomainfrom
feature/ralph_reflector

Conversation

@rainsonGain
Copy link
Collaborator

Add related structure;
Add LLM-based general reflector;
Add Reflection API

add related structure;
add LLM-based general reflector;
add Reflection API
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @rainsonGain, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a robust reflection framework designed to enhance the system's ability to learn from its own task executions. By providing a structured way to analyze outcomes, identify underlying issues, and generate improvement strategies, this module aims to make the ralph_loop more adaptive and efficient. The core components facilitate the integration of various reflection mechanisms, including an LLM-powered general reflector for comprehensive insights.

Highlights

  • New Reflection Module: Introduced a new reflect module within aworld/ralph_loop to enable systematic analysis and improvement of task execution.
  • Reflection API: Added the Reflection class, which acts as a central coordinator for various Reflector instances, managing their execution and maintaining a history of reflection results.
  • LLM-based General Reflector: Implemented a GeneralReflector that leverages Large Language Models (LLMs) to perform deep analysis, identify root causes, and generate actionable suggestions based on task inputs and outputs.
  • Structured Reflection Types and Levels: Defined enums for ReflectionType (e.g., SUCCESS, FAILURE, OPTIMIZATION) and ReflectionLevel (e.g., SHALLOW, MEDIUM, DEEP) to categorize and control the depth of reflection.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • aworld/ralph_loop/reflect/init.py
    • Initializes the reflect package, importing key components like Reflector, GeneralReflector, and Reflection.
  • aworld/ralph_loop/reflect/reflection.py
    • Adds the Reflection class to coordinate multiple Reflector instances.
    • Includes methods for adding reflectors, asynchronously running reflections, and selecting appropriate reflectors based on input and type.
    • Implements history tracking for reflection results and provides summary statistics.
  • aworld/ralph_loop/reflect/reflectors.py
    • Introduces an abstract Reflector base class defining a template for analysis, insight, and suggestion generation.
    • Adds GeneralReflector, an LLM-powered implementation that builds detailed system prompts and parses structured JSON responses from LLMs for comprehensive task analysis.
  • aworld/ralph_loop/reflect/types.py
    • Defines ReflectionType and ReflectionLevel enums for categorizing reflections.
    • Introduces dataclasses for ReflectionInput, ReflectionResult, and ReflectionHistory to standardize data flow and storage within the reflection framework.
Activity
  • The pull request introduces a new reflect module, including core structures, an LLM-based general reflector, and a Reflection API.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new reflection module for analyzing task executions using LLMs. The overall structure is well-defined with Reflection, Reflector, and GeneralReflector classes. However, I've identified several critical issues that need to be addressed. These include a synchronous LLM call within an async method which will block the event loop, a bug that will cause an AttributeError when building the LLM prompt, and incorrect error handling for JSON parsing. Additionally, there's a significant performance improvement opportunity by running reflectors concurrently. I've also pointed out some inconsistencies in the LLM prompt.

self._llm = get_llm_model(self.model_config)

analysis_input = self._build_analysis_input(reflection_input)
response = call_llm_model(self._llm, messages=analysis_input)
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

The analyze method is async, but it uses the synchronous call_llm_model. This will block the asyncio event loop, negating the benefits of using async. You should use the asynchronous version, acall_llm_model.

You'll also need to update the import on line 11 to include acall_llm_model from aworld.models.llm.

Suggested change
response = call_llm_model(self._llm, messages=analysis_input)
response = await acall_llm_model(self._llm, messages=analysis_input)

{reflection_input.input_data}

Output:
{reflection_input.output_data.answer}
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

You are trying to access reflection_input.output_data.answer. However, output_data is likely a ModelResponse object, which does not have an answer attribute but a content attribute. Using .answer will raise an AttributeError.

Suggested change
{reflection_input.output_data.answer}
{reflection_input.output_data.content}

Comment on lines +53 to +66
for reflector in valid_reflectors:
if aworld.debug_mode:
logger.info(f"Running reflector: {reflector.name}")

try:
# Each reflector performs its reflection asynchronously
result = await reflector.reflect(reflect_input)
results.append(result)
# Add result to history
self.history.add_reflection(result)
except Exception as e:
logger.error(f"Reflector {reflector.name} failed: {e}")
if aworld.debug_mode:
logger.error(f"Reflector {reflector.name} failed: {traceback.format_exc()}")
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The current implementation runs reflectors sequentially in a for loop. Since reflectors can be I/O-bound (e.g., GeneralReflector making network calls), running them concurrently would significantly improve performance. You can use asyncio.gather to parallelize their execution.

Note: This change requires import asyncio at the top of the file, and from typing import Optional if not already present.

            async def _run_reflector(reflector: Reflector) -> Optional[ReflectionResult]:
                if aworld.debug_mode:
                    logger.info(f"Running reflector: {reflector.name}")
                try:
                    result = await reflector.reflect(reflect_input)
                    self.history.add_reflection(result)
                    return result
                except Exception as e:
                    logger.error(f"Reflector {reflector.name} failed: {e}")
                    if aworld.debug_mode:
                        logger.error(f"Reflector {reflector.name} failed: {traceback.format_exc()}")
                    return None

            tasks = [_run_reflector(reflector) for reflector in valid_reflectors]
            gathered_results = await asyncio.gather(*tasks)
            results.extend([res for res in gathered_results if res is not None])

"string: Observation 1",
"string: Observation 2"
],
"root_cause": [
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The JSON schema in the system prompt specifies "root_cause" (singular), but the Reflector.reflect method expects to extract "root_causes" (plural) from the analysis result. This mismatch will cause result.root_causes to always be an empty list. Please correct the schema to use "root_causes".

Suggested change
"root_cause": [
"root_causes": [

logger.error(
f"Failed to parse reflection response {response.raw_response} \n{traceback.format_exc()}")
return {
"summary": response,
Copy link
Contributor

Choose a reason for hiding this comment

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

high

In the except block of _parse_response, if JSON parsing fails, you are setting "summary": response. Here, response is a ModelResponse object, not a string. This will likely cause type errors downstream. You should probably use response.content or a specific error message as the summary.

Suggested change
"summary": response,
"summary": response.content,

Comment on lines +186 to +190
key_findings, root_cause,insights, suggestions do not necessarily have values, but if there are values, they must ensure logical, correctness and authenticity.

# Output Format
You must strictly output a **single valid JSON object**. Do not include markdown fencing (like ```json) or preamble text.
root_cause, insights, suggestions
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

There are a couple of small issues in the system prompt:

  • On line 186, root_cause should be root_causes to be consistent with the JSON schema and the rest of the code.
  • Line 190 appears to be stray text and should be removed.
Suggested change
key_findings, root_cause,insights, suggestions do not necessarily have values, but if there are values, they must ensure logical, correctness and authenticity.
# Output Format
You must strictly output a **single valid JSON object**. Do not include markdown fencing (like ```json) or preamble text.
root_cause, insights, suggestions
key_findings, root_causes, insights, suggestions do not necessarily have values, but if there are values, they must ensure logical, correctness and authenticity.
# Output Format
You must strictly output a **single valid JSON object**. Do not include markdown fencing (like ```json) or preamble text.

if not data:
content = response.content
try:
import re
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The import re statement is inside the _parse_response method. According to PEP 8, imports should be at the top of the file. This improves readability and avoids re-importing the module on every call. Please move this import to the top of the file.

@rainsonGain rainsonGain merged commit bd90d3f into main Feb 6, 2026
1 check passed
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