# Configuring Role-Specific LLM Parameters and Prompts in MetaGPT

> Customize MetaGPT agent behavior by configuring role-specific LLM parameters and prompts. Tailor assignments and define profiles for dynamic system prompts.

- Repository: [FoundationAgents/MetaGPT](https://github.com/FoundationAgents/MetaGPT)
- Tags: how-to-guide
- Published: 2026-03-04

---

**You can configure role-specific LLM parameters and prompts in MetaGPT by assigning a custom LLM instance to a Role's `llm` attribute and defining `profile`, `goal`, and `constraints` that dynamically generate the system prompt via the `_get_prefix()` method in [`metagpt/roles/role.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/roles/role.py).**

MetaGPT's role-based architecture allows developers to create autonomous agents with distinct personalities and capabilities. By configuring role-specific LLM parameters and prompts, you can fine-tune each agent's behavior, tone, and tool usage without modifying the core framework. This guide examines the implementation in the FoundationAgents/MetaGPT repository to show exactly how these customizations work under the hood.

## How Role-Specific LLM Configuration Works in MetaGPT

### The Role Class and Runtime Context

The foundation of agent customization lies in the `Role` class defined in [`metagpt/roles/role.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/roles/role.py). Each role maintains its own `RoleContext` instance that tracks the message buffer, memory, and react mode, while the `llm` attribute holds the language model instance used for inference.

When a role is instantiated, Pydantic's `model_validator` triggers `_process_role_extra`, which orchestrates the initialization of LLM parameters and prompt generation.

### The _process_role_extra Validation Hook

The `_process_role_extra` method (lines 61-79 in [`metagpt/roles/role.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/roles/role.py)) serves as the central configuration hub:

```python
def _process_role_extra(self):
    kwargs = self.model_extra or {}

    if self.is_human:
        self.llm = HumanProvider(None)

    self._check_actions()
    self.llm.system_prompt = self._get_prefix()      # ← inject role‑specific prompt

    self.llm.cost_manager = self.context.cost_manager
    if not self.observe_all_msg_from_buffer:
        self._watch(kwargs.pop("watch", [UserRequirement]))

```

This method performs three critical tasks:

- **LLM Selection** – Assigns a `HumanProvider` for human roles or uses the configured LLM instance
- **Prompt Injection** – Calls `_get_prefix()` to generate the system prompt and assigns it to `self.llm.system_prompt`
- **Context Binding** – Attaches the cost manager and initializes the watch list for message observation

## Setting Up Custom LLM Parameters for Individual Roles

To override the global LLM configuration for a specific role, instantiate a custom `LLM` object and assign it before the role processes messages. The following example demonstrates configuring a `TutorialAssistant` with GPT-4 Turbo:

```python
from metagpt.roles.tutorial_assistant import TutorialAssistant
from metagpt.configs.role_custom_config import RoleConfig
from metagpt.provider import LLM

# 1️⃣ Load a custom LLM (e.g. OpenAI gpt‑4‑turbo)

custom_llm = LLM(
    api_key="sk-********",           # <-- keep secret, do NOT commit

    model="gpt-4-turbo",
    # base_url="https://api.openai.com/v1"

)

# 2️⃣ Define role‑specific metadata

role_cfg = RoleConfig(
    name="Alice",
    profile="Software Engineer",
    goal="Explain Python decorators to a junior dev",
    constraints="Use no more than 200 words; avoid code execution"
)

# 3️⃣ Instantiate the role and inject the custom LLM

assistant = TutorialAssistant(config=role_cfg)
assistant.llm = custom_llm               # overrides the global config

assistant._process_role_extra()         # recompute system_prompt & watch list

# 4️⃣ Run the role (the system prompt now contains the custom goal & constraints)

reply = await assistant.run("How do decorators work?")
print(reply.content)

```

**Critical implementation details:**

- Assign `assistant.llm` **before** calling `_process_role_extra()` to ensure the system prompt is generated using the correct LLM instance
- The `RoleConfig` class (defined in [`metagpt/config2.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/config2.py)) validates the metadata schema
- Global configurations reside in YAML files like [`config/examples/openai-gpt-4-turbo.yaml`](https://github.com/FoundationAgents/MetaGPT/blob/main/config/examples/openai-gpt-4-turbo.yaml), but per-role instances override these

## Customizing System Prompts for Tailored Agent Behavior

MetaGPT generates role-specific system prompts dynamically using templates defined in [`metagpt/roles/role.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/roles/role.py).

### Prompt Template Structure

The system prompt construction relies on two key templates:

```python
PREFIX_TEMPLATE = """You are a {profile}, named {name}, your goal is {goal}."""

CONSTRAINT_TEMPLATE = """\nConstraints:\n{constraints}"""

```

These templates are combined in the `_get_prefix()` method to create a coherent identity for the agent.

### Dynamic Prompt Generation with _get_prefix

The `_get_prefix()` method (lines 71-84 in [`metagpt/roles/role.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/roles/role.py)) assembles the final system prompt:

```python
def _get_prefix(self):
    if self.desc:
        return self.desc

    prefix = PREFIX_TEMPLATE.format(**{
        "profile": self.profile,
        "name": self.name,
        "goal": self.goal,
    })

    if self.constraints:
        prefix += CONSTRAINT_TEMPLATE.format(**{"constraints": self.constraints})

    if self.rc.env and self.rc.env.desc:
        # add environment context

        all_roles = self.rc.env.role_names()
        other_role_names = ", ".join([r for r in all_roles if r != self.name])
        env_desc = f"You are in {self.rc.env.desc} with roles({other_role_names})."
        prefix += env_desc
    return prefix

```

**Key behaviors:**

- If `desc` is explicitly provided, it overrides the template entirely
- The `profile`, `name`, and `goal` fields form the core identity statement
- Optional `constraints` append specific behavioral limitations
- When operating within an `Environment`, the prompt automatically includes context about other available roles

## Per-Action LLM Overrides

While role-level configuration sets the default model, individual actions can override this to use specialized models for specific tasks. This is implemented in the `_init_action` method of [`metagpt/roles/role.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/roles/role.py):

```python
def _init_action(self, action: Action):
    action.set_context(self.context)
    override = not action.private_config
    action.set_llm(self.llm, override=override)   # ← shares the role’s LLM

    action.set_prefix(self._get_prefix())

```

To use a different model for a specific action, instantiate the action with its own LLM before adding it to the role:

```python
from metagpt.actions import WriteCode
from metagpt.provider import LLM

# A cheap model for general chat

chat_llm = LLM(api_key="...", model="gpt-3.5-turbo")

# A powerful model for code generation

code_llm = LLM(api_key="...", model="gpt-4")

# Action that uses the heavyweight model

write_code = WriteCode()
write_code.set_llm(code_llm, override=True)

assistant = TutorialAssistant()
assistant.set_actions([write_code])   # the action keeps its own LLM

```

Only `WriteCode` will invoke `gpt-4`; other actions in the role continue using the default `chat_llm`. This pattern enables cost-effective heterogeneous inference where expensive models handle complex generation tasks while cheaper models manage routine interactions.

## Summary

- **Role-level LLM assignment** occurs through the `llm` attribute in [`metagpt/roles/role.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/roles/role.py), validated during `_process_role_extra()` which injects the system prompt and cost manager.
- **System prompts** are dynamically assembled from `profile`, `name`, `goal`, and optional `constraints` using `PREFIX_TEMPLATE` and `CONSTRAINT_TEMPLATE`, with automatic environment context appended when applicable.
- **Action-level overrides** allow specific tasks to use different models by calling `set_llm()` with `override=True` before adding the action to the role via `set_actions()`.
- **Configuration hierarchy** flows from global YAML files (e.g., [`config/examples/openai-gpt-4-turbo.yaml`](https://github.com/FoundationAgents/MetaGPT/blob/main/config/examples/openai-gpt-4-turbo.yaml)) to runtime `RoleConfig` objects to direct `LLM` instance assignment.

## Frequently Asked Questions

### How do I assign a different LLM model to a specific role?

Assign a custom `LLM` instance to the role's `llm` attribute and call `_process_role_extra()` to recompute the system prompt. This overrides the global configuration defined in YAML files like [`config/examples/openai-gpt-4-turbo.yaml`](https://github.com/FoundationAgents/MetaGPT/blob/main/config/examples/openai-gpt-4-turbo.yaml). Ensure you set the LLM before the role processes its first message to guarantee the correct model handles all subsequent inference calls.

### Can I customize the system prompt template for a role?

Yes, the system prompt is generated dynamically in [`metagpt/roles/role.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/roles/role.py) using `PREFIX_TEMPLATE` and optional `CONSTRAINT_TEMPLATE`. You can customize the output by setting the `profile`, `name`, `goal`, and `constraints` attributes on your role instance, or override the `_get_prefix()` method entirely to return a custom `desc` string that bypasses the template system.

### Is it possible to use different LLMs for different actions within the same role?

Absolutely. Instantiate actions with their own `LLM` instances and call `set_llm(model, override=True)` before adding them to the role via `set_actions()`. According to the `_init_action` implementation in [`metagpt/roles/role.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/roles/role.py), actions with `private_config` set will retain their specific LLM while other actions inherit the role's default model, enabling cost-effective routing such as using GPT-4 for coding and GPT-3.5 for chat.

### Where are LLM configurations stored in MetaGPT?

MetaGPT supports hierarchical configuration through YAML files in the `config/` directory (such as [`config/examples/openai-gpt-4-turbo.yaml`](https://github.com/FoundationAgents/MetaGPT/blob/main/config/examples/openai-gpt-4-turbo.yaml)), runtime `LLMConfig` objects defined in [`metagpt/config2.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/config2.py), and direct instantiation of the `LLM` class from [`metagpt/provider/llm.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/provider/llm.py). The global configuration singleton loads settings from environment variables and YAML, but per-role overrides take precedence when explicitly assigned to the `llm` attribute before `_process_role_extra()` executes.