Commit 016fe161 authored by YaningGao's avatar YaningGao
Browse files

update docs

parent 1d6ca85f
Loading
Loading
Loading
Loading
+154 −85
Original line number Diff line number Diff line
# How to Create New Services
# How to Create New Environments
> NOTICE: Once you've implemented your environment following this guide, VAGEN can be used directly, with the service layer being optional for training acceleration.

This guide explains how to create new environment services for VAGEN's service-based architecture. The service architecture provides a standardized way to manage multiple environments for VLM agent training with enhanced scalability and flexibility.
This guide explains how to create new environments for VAGEN's architecture. Creating custom environments is the foundation for building specialized VLM agent training scenarios. 

## Service Architecture Overview
## Environment Structure Overview

VAGEN uses a client-server architecture for environment management:
VAGEN uses an object-oriented approach for environment management:
- 'BaseEnv': Abstract base class that defines the interface all environments must implement
- 'BaseEnvConfig': Configuration class for environment parameters
- 'Environment'-specific implementations (e.g., SvgEnv)

- `BaseService`: Abstract base class that defines the interface all services must implement
- `BatchEnvClient`: Client that communicates with environment servers (fixed)
- `BatchEnvServer`: Server implementation for hosting environments (fixed)

This architecture enables efficient parallel processing across distributed systems and seamless integration of both rule-based rewards and reward models.
This architecture enables standardized interaction patterns while allowing for customization across different domains and tasks.

## Directory Structure

```
vagen/
├── env/
│   ├── base_service.py        # Abstract base class defining the service interface
│   ├── client.py              # Client for interacting with environment server
│   ├── server.py              # Server implementation for hosting environments
│   └── REGISTERED_ENV         # Registry mapping environment names to services
├── utils/
│   ├── serial.py              # Handle observation serialization from service to client
```
## Component Hierarchy
|   ├── create_dataset.py         # Store train/test data configs, not real data
│   ├── base/
│   │   ├── base_env.py           # Abstract base class defining the 
│   │   └── base_env_config.py    # Base configuration class for environments
│   ├── [your_env]/               # Your environment implementation
│       ├── env.py                # Your environment class
│       ├── env_config.py         # Your environment configuration
│       └── data/                 # Environment-specific resources (Optional)
|   
├── examples/
|   ├── [your_env]/
│       ├── env_config.yaml       # Your data&env config for create_dataset.py
│       ├── run.sh                # Script for training
```
BaseService (ABC)
├── **Batch Methods**
    ├── create_environments_batch()
    ├── reset_batch()
    ├── step_batch()
    ├── compute_reward_batch()
    ├── get_system_prompts_batch()
    └── close_batch()

BatchEnvClient
├── **HTTP Communication**
├── **Batch Methods**
└── **Convenience Methods**

BatchEnvServer
├── **Service Management**
├── **Request Routing**
├── **Batch Method Implementation**
└── **Server Management**
```

## Creating a New Service Step by Step
## Creating a New Environment Step by Step

### Step 1: Inherit from BaseService
### Step 1: Create Environment Configuration

Create a new class that inherits from `BaseService`. This class must implement all required methods for interacting with environments:
Create a new class that inherits from BaseEnvConfig. This class will define all parameters specific to your environment in `create_dataset.py` by combining your unique requirements in `env_config.yaml` and default requirements in `env_config.py`:

```python
from vagen.env.base_service import BaseService

class MyNewService(BaseService):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        # Initialize your environment-specific components here
        
    def create_environments_batch(self, env_ids, **kwargs):
        # Initialize batch of environments
        # Return initialization status
        
    def reset_batch(self, env_ids, **kwargs):
        # Reset environments and return observations
        
    def step_batch(self, env_ids, actions, **kwargs):
        # Process actions and return (observations, dones)
        
    def compute_reward_batch(self, env_ids, **kwargs):
        # Calculate rewards for each environment
        # Return rewards and any additional info
@dataclass
class MyNewEnvConfig(BaseEnvConfig):
    """Configuration for My New Environment"""
    dataset_name: str = "path/to/dataset"
    data_dir: str = "vagen/env/my_new_env/data"
    seed: int = 42
    # Add your environment-specific parameters here
    
    def config_id(self) -> str:
        """Generate a unique identifier for this configuration"""
        return f"MyNewEnvConfig(dataset={self.dataset_name},seed={self.seed})"
```

    def get_system_prompts_batch(self, env_ids, **kwargs):
        # Return system prompts for each environment
### Step 2: Implement Environment Class

    def close_batch(self, env_ids, **kwargs):
        # Clean up resources for environments
```
### Step 2: Observation Serialization
When passing observations between the service and client, ensure proper serialization:
Create a new class that inherits from BaseEnv. This class must implement all required methods:
```python
from vagen.env.base.base_env import BaseEnv
from typing import Dict, Tuple
import random

class MyNewEnv(BaseEnv):
    def __init__(self, config):
        self.config = config
        self.done = False
        
    def step(self, llm_raw_response) -> Tuple[Dict, float, bool, Dict]:
        """Process an action from the LLM and return the next state"""
        parsed_action = parse_llm_raw_response(llm_raw_response)
        action_valid = parsed_action['is_valid']
        action_effective = action_valid  # Simplification for example
        
        # Update environment state based on action
        
        obs = {
            'obs_str': "Observation after action",
            'multi_modal_data': {}  # Add any images or audio here
        }
        
        reward = 0.0 if not action_valid else 0.5
        self.done = False  # Update based on task completion
        
        info = {
            "metrics": {
                'success': False,
                'action_is_effective': action_effective,
                'action_is_valid': action_valid,
            },
            "llm_raw_response": llm_raw_response,
            "llm_response": parsed_action,
        }
        
        return obs, reward, self.done, info
    
    def reset(self, seed=None) -> Tuple[Dict, Dict]:
        """Reset the environment to initial state"""
        if seed is not None:
            random.seed(seed)
            
        self.done = False
        
        obs = {
            'obs_str': "Initial observation text",
            'multi_modal_data': {}
        }
                
        return obs, info #(Optional, could be empty)
    
    def system_prompt(self) -> str:
        """Define the system prompt for the LLM"""
        return "You are an agent in the MyNewEnv environment. Your goal is to [describe task]."
    
    def compute_reward(self) -> float:
        """Calculate final episode reward"""
        return 0.0  # Calculate based on task completion
        
    def close(self):
        """Clean up any resources"""
        pass
```
from vagen.utils.serial import serialize_observation, deserialize_observation
### Step 3: Make Sure Input/Output Format Details

# On the service side
## at the end of reset_batch()
serialized_obs = serialize_observation(original_observation)
## at the end of step_batch()
serialized_step = serialize_step_result(observation, reward, done, info)
#### Environment Observations
Step Observations must follow this structure:
```python
{
    'obs_str': "Text observation with <image> or <audio> placeholders",
    'multi_modal_data': {
        '<image>': [image_data_1, image_data_2, ...],
        '<audio>': [audio_data_1, audio_data_2, ...],
    }
}
```
**Notice**: number of `image_place_holder(<image>)` in `obs_str` must match with number of `image_data` in `multi_modal_data`

### Step 3: Register your Environment
Register your env in `env/__init__.py`
```
from vagen.env.NEW_service import MyNewService
# Register your service
REGISTERED_ENV["my_new_env"] = MyNewService
#### Environment Info Dictionary
The info dictionary provides additional context and metrics:
```python
{
    "metrics": {
        'success': bool,  # Did the agent complete the task?
        'action_is_effective': bool,  # Was the action meaningful?
        'action_is_valid': bool,  # Was the action syntactically correct?
        # Add additional custom metrics
    },
    "llm_raw_response": str,  # Original response from LLM
    "llm_response": dict,  # Parsed response with structured format
}
```

### Step 4: Define your env config and script
> Please refer to `[Configuration](config.md)`
Define your env config and running script in `examples/`
### Step 4: Testing Your Environment

Create a basic script below your `env.py` to test your environment:
```python
# Create environment
config = MyNewEnvConfig()
env = MyNewEnv(config)

# Reset environment
obs, info = env.reset(seed=42)
print("Initial observation:", obs['obs_str'])

# Test step with mock LLM response
mock_llm_response = "Action1, Action2, Action3"
next_obs, reward, done, info = env.step(mock_llm_response)

print("Next observation:", next_obs['obs_str'])
print("Reward:", reward)
print("Done:", done)
print("Action valid:", info['metrics']['action_is_valid'])
print("Action effective:", info['metrics']['action_is_effective'])

# Clean up
env.close()
```

### Step 5: Integration with Service Layer (Optional)

Please refer to `Frozenlake/service.py` for better service structure understanding
 No newline at end of file
For training acceleration and distributed processing, you can integrate your environment with the VAGEN service layer. This step is optional but recommended for large-scale training. See the "[Create your Own Service](create-service.md)" section for details.

docs/create-service.md

0 → 100644
+109 −0
Original line number Diff line number Diff line
# How to Create New Services

This guide explains how to create new environment services for VAGEN's service-based architecture. The service architecture provides a standardized way to manage multiple environments for VLM agent training with enhanced scalability and flexibility.

## Service Architecture Overview

VAGEN uses a client-server architecture for environment management:

- `BaseService`: Abstract base class that defines the interface all services must implement
- `BatchEnvClient`: Client that communicates with environment servers (fixed)
- `BatchEnvServer`: Server implementation for hosting environments (fixed)

This architecture enables efficient parallel processing across distributed systems and seamless integration of both rule-based rewards and reward models.

## Directory Structure

```
vagen/
├── env/
│   ├── base_service.py        # Abstract base class defining the service interface
│   ├── client.py              # Client for interacting with environment server
│   ├── server.py              # Server implementation for hosting environments
│   └── REGISTERED_ENV         # Registry mapping environment names to services
├── utils/
│   ├── serial.py              # Handle observation serialization from service to client
```
## Component Hierarchy
```
BaseService (ABC)
├── **Batch Methods**
    ├── create_environments_batch()
    ├── reset_batch()
    ├── step_batch()
    ├── compute_reward_batch()
    ├── get_system_prompts_batch()
    └── close_batch()

BatchEnvClient
├── **HTTP Communication**
├── **Batch Methods**
└── **Convenience Methods**

BatchEnvServer
├── **Service Management**
├── **Request Routing**
├── **Batch Method Implementation**
└── **Server Management**
```

## Creating a New Service Step by Step

### Step 1: Inherit from BaseService

Create a new class that inherits from `BaseService`. This class must implement all required methods for interacting with environments:

```python
from vagen.env.base_service import BaseService

class MyNewService(BaseService):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        # Initialize your environment-specific components here
        
    def create_environments_batch(self, env_ids, **kwargs):
        # Initialize batch of environments
        # Return initialization status
        
    def reset_batch(self, env_ids, **kwargs):
        # Reset environments and return observations
        
    def step_batch(self, env_ids, actions, **kwargs):
        # Process actions and return (observations, dones)
        
    def compute_reward_batch(self, env_ids, **kwargs):
        # Calculate rewards for each environment
        # Return rewards and any additional info
        
    def get_system_prompts_batch(self, env_ids, **kwargs):
        # Return system prompts for each environment
        
    def close_batch(self, env_ids, **kwargs):
        # Clean up resources for environments
```
### Step 2: Observation Serialization
When passing observations between the service and client, ensure proper serialization:
```
from vagen.utils.serial import serialize_observation, deserialize_observation

# On the service side
## at the end of reset_batch()
serialized_obs = serialize_observation(original_observation)
## at the end of step_batch()
serialized_step = serialize_step_result(observation, reward, done, info)
```

### Step 3: Register your Environment
Register your env in `env/__init__.py`
```
from vagen.env.NEW_service import MyNewService
# Register your service
REGISTERED_ENV["my_new_env"] = MyNewService
```

### Step 4: Define your env config and script
> Please refer to `[Configuration](config.md)`
Define your env config and running script in `examples/`


Please refer to `Frozenlake/service.py` for better service structure understanding
 No newline at end of file
+1 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@ VAGEN is a multi-turn reinforcement learning framework designed for training Vis

- [Run Experiment](run-exp.md)
- [Create your Own Environment](create-env.md)
- [Create your Own Service](create-service.md)
- [Configuration](config.md)

Use the links above to explore the core functionalities of the project.
+1 −1
Original line number Diff line number Diff line
@@ -59,4 +59,4 @@ The following environments are currently registered:
- SVG: An environment that generate svg code fot provided image. Supports reward model integration
- Navigation: An environment of visual navigation task for embodied AI

For information on creating new environment services, please refer to our "[Create your Own Environment](create-env.md)" guide.
 No newline at end of file
For information on creating new environment, please refer to our "[Create your Own Environment](create-env.md)" guide.
 No newline at end of file