Skip to content

Commit 8455f78

Browse files
authored
Merge pull request #221 from xrc10/develop/v0.2.4
add RAP workflow and example
2 parents a4876c2 + b2696fc commit 8455f78

File tree

20 files changed

+948
-0
lines changed

20 files changed

+948
-0
lines changed

examples/rap/README.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Reasoning via Planning (RAP) Example
2+
3+
This example demonstrates how to use the RAP (Reasoning via Planning) operator for complex reasoning tasks. The RAP operator treats reasoning as a planning problem and uses Monte Carlo Tree Search (MCTS) to explore reasoning paths.
4+
5+
> **Note**: RAP currently only supports the lite version because Conductor cannot handle nested loops (loops inside loops) which are required for the MCTS algorithm.
6+
7+
## Overview
8+
9+
The example implements a RAP workflow with three main components:
10+
11+
1. **Input Interface**
12+
- Handles user input for math problems
13+
- Provides a simple CLI interface
14+
15+
2. **RAP Workflow**
16+
- Uses MCTS to explore reasoning paths
17+
- Leverages a language model for reasoning
18+
- Finds optimal solution paths
19+
20+
3. **Conclude Task**
21+
- Extracts and formats the final answer
22+
- Presents results to the user
23+
24+
## Prerequisites
25+
26+
- Access to OpenAI API or compatible endpoint
27+
28+
## Setup
29+
30+
Configure environment variables:
31+
```bash
32+
export custom_openai_key="your_openai_api_key"
33+
export custom_openai_endpoint="your_openai_endpoint" # Optional: defaults to https://api.openai.com/v1
34+
```
35+
36+
## Running the Example
37+
38+
Only the lightweight version is supported:
39+
```bash
40+
python run_cli_lite.py
41+
```
42+
43+
The CLI will prompt you to:
44+
1. Select a task type (currently supports 'math')
45+
2. Enter your problem/question
46+
47+
## Configuration Files
48+
49+
- `configs/llms/gpt.yml`: LLM settings
50+
```yaml
51+
name: OpenaiGPTLLM
52+
model_id: gpt-4o-mini
53+
api_key: ${env| custom_openai_key}
54+
endpoint: ${env| custom_openai_endpoint, https://api.openai.com/v1}
55+
temperature: 0.0
56+
vision: false
57+
```
58+
59+
- `configs/workers/rap_workflow.yml`: Worker configurations for the RAP pipeline
60+
61+
## Example Usage in Code
62+
63+
```python
64+
from omagent_core.advanced_components.workflow.rap import RAPWorkflow
65+
66+
# Initialize RAP workflow
67+
workflow = RAPWorkflow()
68+
69+
# Set input query
70+
workflow.set_input(query="If 4 friends share 7 pizzas equally, and each pizza has 8 slices, how many slices does each friend get?")
71+
72+
# Get results
73+
final_answer = workflow.final_answer
74+
```
75+
76+
## Troubleshooting
77+
78+
Common issues:
79+
- Invalid API key: Verify your OpenAI API key is set correctly
80+
- Connection errors: Check your internet connection and API endpoint
81+
- Import errors: Ensure all dependencies are installed
82+
83+
For more detailed documentation, visit the [OmAgent documentation](https://docs.omagent.ai).
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from pathlib import Path
2+
from omagent_core.engine.worker.base import BaseWorker
3+
from omagent_core.utils.registry import registry
4+
import re
5+
6+
@registry.register_worker()
7+
class Conclude(BaseWorker):
8+
"""Worker that formats and presents the final reasoning output"""
9+
10+
def _run(self, final_answer: str, *args, **kwargs):
11+
"""Format and present the final reasoning results.
12+
13+
Args:
14+
final_answer: The final answer from RAP
15+
16+
Returns:
17+
dict: Contains the extracted short answer
18+
"""
19+
20+
# Extract the short answer using regex pattern
21+
matches = re.findall(r'the answer is\s+([^.]+)\.', final_answer.lower())
22+
short_answer = matches[-1] if matches else final_answer
23+
24+
# Send formatted answer through callback
25+
self.callback.send_answer(
26+
agent_id=self.workflow_instance_id,
27+
msg=f"Final conclusion: {short_answer}"
28+
)
29+
30+
return {"short_answer": short_answer}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from omagent_core.engine.worker.base import BaseWorker
2+
from omagent_core.utils.registry import registry
3+
4+
# Define supported tasks
5+
SUPPORTED_TASKS = {
6+
'math': "Please input your math problem:"
7+
}
8+
9+
@registry.register_worker()
10+
class InputInterface(BaseWorker):
11+
"""Input interface processor that handles user queries."""
12+
13+
def _run(self, query=None, *args, **kwargs):
14+
# Get task selection from user
15+
task = input(f'\nWelcome to OmAgent RAP! Please select a task type: {list(SUPPORTED_TASKS.keys())} ')
16+
17+
if task not in SUPPORTED_TASKS:
18+
raise ValueError(f"Unsupported task type: {task}. Must be one of {list(SUPPORTED_TASKS.keys())}")
19+
20+
self.stm(self.workflow_instance_id)['task'] = task
21+
22+
# Use query parameter if provided, otherwise get user input
23+
data_input = query if query else input(SUPPORTED_TASKS[task])
24+
25+
# Store input in STM and return
26+
self.stm(self.workflow_instance_id)['data_input'] = data_input
27+
return {"query": data_input}

examples/rap/configs/llms/gpt.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
name: OpenaiGPTLLM
2+
model_id: gpt-4o-mini
3+
api_key: ${env| custom_openai_key}
4+
endpoint: ${env| custom_openai_endpoint, https://api.openai.com/v1}
5+
temperature: 0.0
6+
vision: false
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
- name: InputInterface
2+
- name: Selection
3+
- name: Expansion
4+
llm: ${sub|gpt}
5+
- name: SimulationPreProcess
6+
- name: SimulationPostProcess
7+
- name: BackPropagation
8+
- name: MCTSCompletionCheck
9+
- name: OutputInterface

examples/rap/run_cli_lite.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Import required modules and components
2+
from pathlib import Path
3+
from omagent_core.utils.container import container
4+
from omagent_core.engine.workflow.conductor_workflow import ConductorWorkflow
5+
from omagent_core.engine.workflow.task.simple_task import simple_task
6+
from omagent_core.advanced_components.workflow.rap import RAPWorkflow
7+
from omagent_core.clients.devices.cli import DefaultClient
8+
from omagent_core.utils.registry import registry
9+
from omagent_core.utils.logger import logging
10+
from agent.conclude.conclude import Conclude
11+
from agent.input_interface.input_interface import InputInterface
12+
13+
import os
14+
os.environ["OMAGENT_MODE"] = "lite"
15+
16+
# Initialize logging
17+
logging.init_logger("omagent", "omagent", level="INFO")
18+
19+
# Set current working directory path
20+
CURRENT_PATH = Path(__file__).parents[0]
21+
22+
# Import registered modules
23+
registry.import_module(CURRENT_PATH.joinpath("agent"))
24+
25+
# Load container configuration and set STM
26+
container.register_stm("SharedMemSTM")
27+
28+
# Initialize RAP workflow with lite_version=True
29+
workflow = ConductorWorkflow(name="rap_workflow", lite_version=True)
30+
31+
# Configure workflow tasks:
32+
# 1. Input interface for user interaction
33+
client_input_task = simple_task(
34+
task_def_name=InputInterface,
35+
task_reference_name="input_interface"
36+
)
37+
38+
# 2. RAP workflow for reasoning
39+
rap_workflow = RAPWorkflow()
40+
rap_workflow.set_input(query=client_input_task.output("query"))
41+
42+
# 3. Conclude task for final answer
43+
conclude_task = simple_task(
44+
task_def_name=Conclude,
45+
task_reference_name="task_conclude",
46+
inputs={
47+
"final_answer": rap_workflow.final_answer,
48+
},
49+
)
50+
51+
# Configure workflow execution flow: Input -> RAP -> Conclude
52+
workflow >> client_input_task >> rap_workflow >> conclude_task
53+
54+
# Register workflow with overwrite=True for lite version
55+
workflow.register(overwrite=True)
56+
57+
# Initialize and start CLI client
58+
config_path = CURRENT_PATH.joinpath("configs")
59+
cli_client = DefaultClient(
60+
interactor=workflow,
61+
config_path=config_path,
62+
workers=[InputInterface(), Conclude()]
63+
)
64+
cli_client.start_interactor()
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Reasoning via Planning (RAP) Operator
2+
3+
RAP is a workflow operator that performs reasoning by treating it as a planning problem with a world model. It uses Monte Carlo Tree Search (MCTS) to explore the reasoning space and find high-reward reasoning paths.
4+
5+
Refer to the example in the `examples/rap` directory to understand how to use this operator.
6+
7+
## Overview
8+
9+
RAP repurposes the language model as both:
10+
1. A world model - to predict states and simulate outcomes
11+
2. A reasoning agent - to explore and evaluate reasoning paths
12+
13+
The algorithm uses MCTS to strategically explore the vast reasoning space with a proper balance between exploration and exploitation.
14+
15+
## Inputs, Outputs and Configs
16+
17+
### Inputs:
18+
| Name | Type | Required | Description |
19+
| ---- | ---- | -------- | ----------- |
20+
| query | str | true | The reasoning query/problem to solve |
21+
22+
### Outputs:
23+
| Name | Type | Description |
24+
| ---- | ---- | ----------- |
25+
| final_answer | str | The final answer/solution to the query |
26+
27+
### Configs:
28+
The config of the RAP operator should be defined in a `rap_workflow.yml` file:
29+
30+
```yml
31+
- name: InputInterface
32+
- name: Selection
33+
- name: Expansion
34+
llm: ${sub|gpt}
35+
- name: SimulationPreProcess
36+
- name: SimulationPostProcess
37+
- name: BackPropagation
38+
- name: MCTSCompletionCheck
39+
```
40+
41+
## References
42+
43+
[1] Hao, S., Gu, Y., Ma, H., Hong, J. J., Wang, Z., Wang, D. Z., & Hu, Z. (2023). Reasoning with Language Model is Planning with World Model. arXiv preprint arXiv:2305.14992.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .workflow import RAPWorkflow
2+
3+
__all__ = ["RAPWorkflow"]
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from pathlib import Path
2+
from typing import List
3+
import math
4+
from omagent_core.models.llms.base import BaseLLMBackend
5+
from omagent_core.engine.worker.base import BaseWorker
6+
from omagent_core.models.llms.prompt import PromptTemplate
7+
from omagent_core.utils.registry import registry
8+
from pydantic import Field
9+
10+
CURRENT_PATH = Path(__file__).parents[0]
11+
12+
@registry.register_worker()
13+
class BackPropagation(BaseWorker):
14+
"""Back propagation worker that updates node values"""
15+
16+
def _run(self, *args, **kwargs):
17+
path = self.stm(self.workflow_instance_id)['selected_path']
18+
rewards = []
19+
cum_reward = -math.inf
20+
21+
# Update rewards for each node in path
22+
for node in reversed(path):
23+
rewards.append(node.reward)
24+
cum_reward = self.cum_reward(rewards[::-1])
25+
node.cum_rewards.append(cum_reward)
26+
27+
return {}
28+
29+
def cum_reward(self, rewards):
30+
"""Calculate cumulative reward"""
31+
return sum(rewards)

0 commit comments

Comments
 (0)