OpenAlpha_Evolve

repository·main·Indexed 21 days ago

https://github.com/shyamsaktawat/openalpha_evolve

An open-source Python framework that utilizes Large Language Models (LLMs) to autonomously discover, test, and evolve algorithmic solutions. It employs a modular, agent-based architecture—including PromptDesignerAgent, CodeGeneratorAgent, and EvaluatorAgent—to iteratively improve code through an evolutionary cycle. The framework features sandboxed code execution via Docker, support for multiple LLM providers through LiteLLM, and a Gradio web interface for interactive task definition and evolution management.

Tokens
3.7K
Snippets
10
Records
14
Agent score
76%

What's inside OpenAlpha_Evolve

  1. How the OpenAlpha_Evolve evolutionary cycle works

    main

    OpenAlpha_Evolve uses a modular, agent-based architecture to iteratively improve code through an evolutionary process. The cycle consists of the following stages:

    1. Task Definition: The user defines an algorithmic 'quest' with problem descriptions and input/output examples.
    2. Prompt Engineering (PromptDesignerAgent): Crafts initial prompts for code generation, mutation prompts (requesting changes in 'diff' format), and bug-fix prompts.
    3. Code Generation (CodeGeneratorAgent): Uses an LLM (via LiteLLM) to generate Python code or apply 'diff' changes to existing code.
    4. Evaluation (EvaluatorAgent): Performs syntax checks and executes code in a sandboxed Docker container against user-provided examples. It calculates a Fitness Score based on correctness and efficiency.
    5. Database (DatabaseAgent): Stores programs, fitness scores, and evolutionary lineage (currently in-memory).
    6. Selection (SelectionControllerAgent): Applies 'survival of the fittest' by selecting Parents (for offspring) and Survivors (to advance to the next generation).
    7. Iteration: The cycle repeats for a set number of generations.
    8. Orchestration (TaskManagerAgent): Coordinates all agents and manages the overall loop.
  2. Define algorithmic quests using YAML files

    main

    The recommended way to define new tasks (algorithmic quests) for OpenAlpha_Evolve is by creating a YAML file in the examples directory. This allows you to specify the problem description, the target function name, allowed imports, and a suite of test cases.

    Each task definition supports:

    • task_id: A unique identifier for the task.
    • task_description: A detailed explanation of the problem, including constraints and expected behavior.
    • function_name: The name of the function the agent should evolve.
    • allowed_imports: A list of Python modules the agent is permitted to use.
    • tests: A list of test groups, where each group contains test_cases.

    Test cases can be validated in two ways:

    1. Direct Comparison: Using the output key to match the expected result.
    2. Custom Validation: Using the validation_func key to provide a Python function string that performs complex logic on the output.
    task_id: "your_task_id"
    task_description: |
      Your detailed problem description here.
      Be specific about function names, expected behavior, and constraints.
    function_name: "your_function_name"
    allowed_imports: ["module1", "module2"]
    
    tests:
      - description: "Test group description"
        name: "Test group name"
        test_cases:
          - input: [arg1, arg2]
            output: expected_output
          - input: [arg_for_validation_func_1, arg_for_validation_func_2]
            validation_func: |
              def validate(output_from_function):
                  # Custom validation logic
                  return isinstance(output_from_function, bool) and output_from_function is True
  3. Authenticate with Google Cloud (Vertex AI / AI Studio)

    main

    When using Google Cloud services like Vertex AI or AI Studio, you must authenticate using one of the following methods:

    Option 1: Application Default Credentials (ADC)

    Ensure you have authenticated via the gcloud CLI:

    gcloud auth application-default login

    Option 2: Environment Variable

    Set the GOOGLE_APPLICATION_CREDENTIALS environment variable pointing to your service account key file.

  4. Install and set up OpenAlpha_Evolve

    main

    Follow these steps to set up the environment for OpenAlpha_Evolve:

    1. Prerequisites

    • Python 3.10+
    • pip
    • git
    • Docker: Required for sandboxed code evaluation. Ensure Docker Desktop or Docker Engine is running.

    2. Installation

    # Clone the repository
    git clone https://github.com/shyamsaktawat/OpenAlpha_Evolve.git
    cd OpenAlpha_Evolve
    
    # Set up a virtual environment
    python -m venv venv
    source venv/bin/activate  # On Windows: venv\Scripts\activate
    
    # Install dependencies
    pip install -r requirements.txt

    3. Environment Configuration

    Create a .env file from the example to store your API keys:

    cp .env_example .env

    Edit the .env file to include your LLM provider credentials. For example:

    • Google Cloud (Vertex AI / AI Studio):
      • Use Application Default Credentials (ADC): gcloud auth application-default login
      • Or set GOOGLE_APPLICATION_CREDENTIALS="/path/to/your/service-account-key.json"
      • Or use a direct API key: GEMINI_API_KEY="your_gemini_api_key"
    • Other Providers (via LiteLLM):
      • OPENAI_API_KEY="your_openai_api_key"
      • ANTHROPIC_API_KEY="your_anthropic_api_key"
    git clone https://github.com/shyamsaktawat/OpenAlpha_Evolve.git
    cd OpenAlpha_Evolve
    python -m venv venv
    source venv/bin/activate
    pip install -r requirements.txt
    cp .env_example .env
  5. Run OpenAlpha_Evolve via CLI or Web UI

    main

    Run an evolutionary task via CLI

    To run a predefined task (e.g., Dijkstra's algorithm) using a YAML configuration file:

    python -m main examples/shortest_path.yaml

    Logs are printed to the terminal and saved to alpha_evolve.log by default.

    Launch the Gradio Web Interface

    To interact with the system through a browser, where you can define custom tasks and run evolution interactively:

    python app.py

    Once started, open the local URL provided (e.g., http://127.0.0.1:7860) in your browser.

    # Run a specific task
    python -m main examples/shortest_path.yaml
    
    # Launch the web UI
    python app.py
  6. Best practices for task definition

    main

    To guide OpenAlpha_Evolve effectively, follow these best practices when crafting task definitions:

    • Be Clear and Unambiguous: Write descriptions as if explaining to another developer; avoid or explain jargon.
    • Provide Diverse and Comprehensive Examples: Use test cases to cover typical use cases, edge cases (empty inputs, boundary values), and different logical paths.
    • Use Validation Functions: For complex checks that cannot be solved by simple equality, use validation_func.
    • Start Simple: Break complex problems into smaller, simpler versions first.
    • Specify Constraints: Explicitly mention constraints and edge cases in the task_description.
    • Define Function Signatures: Clearly state the expected function name and its parameters.
  7. Configure the evolutionary task via JSON examples

    main

    When defining a task, the examples_json must follow a specific schema. Each example must be an object containing an input key and an output key. The input can be a list of arguments for the function being evolved.

    Required JSON Format:

    [
        {"input": [arg1, arg2], "output": expected_result},
        {"input": [arg1], "output": expected_result}
    ]
    [
        {"input": [0], "output": 0},
        {"input": [1], "output": 1},
        {"input": [10], "output": 55}
    ]
  8. Use the Gradio web interface for OpenAlpha_Evolve

    main

    OpenAlpha_Evolve provides a Gradio-based web UI to interact with the evolutionary engine without writing code.

    UI Components

    1. Task Definition Section:

      • Task ID: Unique name for your experiment.
      • Task Description: Detailed instructions for the AI to follow.
      • Function Name to Evolve: The target function signature.
      • Input/Output Examples (JSON): A code editor for providing test cases.
      • Allowed Imports: A text box for comma-separated module names (e.g., math, numpy).
    2. Evolutionary Budget Section:

      • Population Size: Slider to set the number of individuals.
      • Generations: Slider to set the number of evolutionary cycles.
      • Number of Islands: Slider to set the number of independent populations.
      • Migration Frequency: How often islands exchange individuals.
      • Migration Rate: The proportion of the population that migrates.
    3. Controls:

      • 📘 Fibonacci Example: A quick-start button that populates the fields with a standard Fibonacci task.
      • 🚀 Run Evolution: The primary button to start the process.
    4. Results Tab:

      • Displays the markdown output of the evolution, including fitness scores and the final evolved Python code blocks.
  9. Define algorithmic quests using TaskDefinition (Legacy)

    main

    You can programmatically define tasks using the TaskDefinition class from core.task_definition. Note that this is considered a legacy method compared to the YAML approach.

    from core.task_definition import TaskDefinition
    
    task = TaskDefinition(
        id="your_task_id",
        description="Your detailed problem description",
        function_name_to_evolve="your_function_name",
        input_output_examples=[
            {"input": [arg1, arg2], "output": expected_output},
            # More examples...
        ],
        allowed_imports=["module1", "module2"]
    )
  10. Run the evolutionary process with `run_evolution()`

    main

    The run_evolution function is the primary entrypoint for triggering the autonomous algorithm evolution process. It accepts task definitions and evolutionary parameters, executes the cycle via a TaskManagerAgent, and returns a formatted markdown string containing the successful solutions found.

    Parameters

    ParameterTypeDescription
    task_idstrUnique identifier for the task
    descriptionstrClear description of the problem to solve
    function_namestrThe name of the Python function to be evolved
    examples_jsonstrA JSON string representing a list of objects with input and output keys
    allowed_imports_textstrA comma-separated string of Python modules allowed in the evolved code
    population_sizeintNumber of individuals in each island
    generationsintTotal number of evolutionary cycles
    num_islandsintNumber of independent evolutionary islands
    migration_frequencyintHow often (in generations) individuals migrate between islands
    migration_ratefloatThe rate of migration between islands

    Returns

    A markdown string containing either a success message with solution details (ID, Fitness, Generation, Island ID, and Python code) or an error message describing the failure.

    # Example conceptual usage of the run_evolution function
    results = await run_evolution(
        task_id="fibonacci_task",
        description="Write a Python function that computes the nth Fibonacci number.",
        function_name="fibonacci",
        examples_json='[{"input": [5], "output": 5}]',
        allowed_imports_text="math, itertools",
        population_size=10,
        generations=5,
        num_islands=3,
        migration_frequency=2,
        migration_rate=0.2
    )
    print(results)
  11. Load task configuration with load_task_from_yaml()

    main

    The load_task_from_yaml(yaml_path: str) function parses a YAML file to extract task metadata and test cases. It converts the YAML structure into a format compatible with TaskDefinition.

    Returns: A tuple containing (input_output_examples, task_id, task_description, function_name, allowed_imports).

    YAML Schema Requirements: To be successfully parsed, the YAML file should contain:

    • task_id: Unique identifier for the task.
    • task_description: Description of the algorithmic goal.
    • function_name: The name of the function to be evolved.
    • allowed_imports: (Optional) A list of Python modules the agent is permitted to use.
    • tests: A list of test groups, where each group contains test_cases.

    Test Case Formats: The function supports two types of test cases within the tests list:

    1. Input/Output: {'input': ..., 'output': ...}
    2. Validation Function: {'input': ..., 'validation_func': ...}
    from main import load_task_from_yaml
    
    test_cases, task_id, task_description, function_name, allowed_imports = load_task_from_yaml("config.yaml")
  12. Retrieve evolved code with `get_code()`

    main

    The get_code(solution_index) function allows you to retrieve the raw Python source code for a specific solution from the most recently completed evolution run.

    • solution_index: An integer representing the index of the solution in the current_results list.
    • Returns: The Python code as a string if the index is valid; otherwise, returns an error message or a placeholder string.
    # Retrieve the code for the first solution found in the last run
    code = get_code(0)
    print(code)