How to Customize Standard Operating Procedures (SOP) for Agent Workflows in MetaGPT
To customize SOPs in MetaGPT, toggle the use_fixed_sop flag in RoleZero-based classes to switch between dynamic LLM-driven planning and static, predefined action pipelines.
MetaGPT treats Standard Operating Procedures (SOP) as configurable behavioral rules that govern how each role (agent) reacts to inputs, selects tools, and executes actions. By customizing the SOP configuration in the MetaGPT framework, you can shape deterministic workflows with explicit step-by-step logic or enable adaptive, LLM-generated execution strategies. This guide covers the architectural mechanics, source code references, and practical implementations for both fixed and dynamic SOP modes.
SOP Architecture and the use_fixed_sop Switch
The MetaGPT architecture centers on the RoleZero base class in metagpt/roles/di/role_zero.py, which implements the core SOP logic. Every role inherits from this class and respects the use_fixed_sop boolean flag (default False) stored in the instance.
When use_fixed_sop is False, the role enters dynamic SOP mode. In this mode, the _think() method builds an execution plan, queries the LLM for decisions, and uses the ToolRecommender to suggest relevant tools based on the current task context. This creates an adaptive "think-act" loop where the agent iteratively plans and executes until completion or budget exhaustion.
When use_fixed_sop is True, the role enters fixed SOP mode. The _think() method returns early, bypassing LLM-driven planning entirely. Instead, the role executes a static list of predefined actions set during initialization via set_actions(). This mode also typically disables memory tracking to ensure deterministic execution.
The Team class in metagpt/team.py (lines 34-36) aggregates these roles and stores the overall SOP description in its docstring, serving as the high-level container that orchestrates multi-agent workflows.
Implementing Fixed SOP Workflows
Fixed SOPs provide deterministic, repeatable workflows ideal for structured tasks like requirements gathering or architectural design. To implement a fixed SOP, you must override the role's __init__ method to set use_fixed_sop=True, disable memory, and define a static action pipeline.
Fixed SOP Implementation Pattern
The ProductManager role in metagpt/roles/product_manager.py (lines 43-48) demonstrates the canonical pattern:
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.use_fixed_sop = True
self.enable_memory = False
self.set_actions([PrepareDocuments, WritePRD])
Key configuration points for fixed SOPs include:
use_fixed_sop = True– Forces the role to skip the LLM planning phase inRoleZero._think().enable_memory = False– Disables conversation memory to ensure the role follows the exact script without historical context interference.set_actions([...])– Accepts a list of action classes or callables that execute sequentially in the order provided.
The Architect role in metagpt/roles/architect.py (lines 46-48) extends this pattern by additionally mapping custom tool execution logic through _update_tool_execution(), allowing specific tool calls like Terminal.run_command within the fixed workflow.
Configuring Dynamic SOP Behavior
Dynamic SOPs leverage the LLM's reasoning capabilities for adaptive problem-solving. When use_fixed_sop remains False (the default), RoleZero._think() executes its full logic:
- Builds a plan based on the current task and context.
- Queries the
ToolRecommenderto suggest a subset of available tools relevant to the task. - Generates a command string for the LLM to decide the next action.
_act()parses the command string, executes the selected tool(s), and loops until task completion.
This mode is ideal for complex, exploratory tasks where the solution path cannot be predetermined. The dynamic behavior is implemented in metagpt/roles/di/role_zero.py (lines 19-22) where tools = await self.tool_recommender.recommend_tools() populates the context-aware tool selection.
Practical Customization Examples
Creating a Custom Fixed-SOP Role
The following example creates a DataAnalyst role with a hardcoded analysis pipeline:
from metagpt.roles.di.role_zero import RoleZero
from metagpt.prompts.di.role_zero import ROLE_INSTRUCTION
class DataAnalyst(RoleZero):
name = "Dana"
profile = "Data Analyst"
instruction = ROLE_INSTRUCTION
tools = ["Editor:write,read", "Browser:search"]
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.use_fixed_sop = True
self.enable_memory = False
self.set_actions([self._load_data, self._run_analysis])
async def _load_data(self):
return "Data loaded from source."
async def _run_analysis(self):
return "Analysis complete."
In this configuration, the tools attribute restricts the available toolbox, preventing the LLM from recommending unrelated utilities even if the role were temporarily switched to dynamic mode. The set_actions() method injects the static pipeline [self._load_data, self._run_analysis].
Switching SOP Modes at Runtime
You can dynamically alter SOP behavior after instantiation by modifying the flag before adding the role to a team:
from metagpt.roles.architect import Architect
from metagpt.team import Team
arch = Architect()
arch.use_fixed_sop = False # Enable dynamic LLM planning
team = Team()
team.hire([arch])
team.run_project("Design a micro-service architecture")
await team.run()
When use_fixed_sop=False, the Architect will use the tool recommendation engine and iterative planning rather than the fixed action sequence defined in its class.
Integrating with Team Workflows
To deploy a fixed-SOP agent within a multi-agent team:
from metagpt.roles.product_manager import ProductManager
from metagpt.team import Team
pm = ProductManager(use_fixed_sop=True)
team = Team()
team.hire([pm])
team.run_project("Create a PRD for a todo-list app")
await team.run(n_round=3)
The Team.run() coroutine iterates over hired roles, respecting their individual SOP modes, and terminates when all roles are idle or the budget is exhausted.
Key Source Files for SOP Customization
When customizing Standard Operating Procedures, consult these specific files and line ranges:
metagpt/roles/di/role_zero.py(lines 98-104) – Contains theuse_fixed_sopflag definition and the_think()method logic that branches between fixed and dynamic execution paths.metagpt/roles/product_manager.py(lines 43-48) – Reference implementation of a fixed-SOP role with disabled memory and static actions.metagpt/roles/architect.py(lines 46-48) – Demonstrates fixed-SOP configuration with custom tool execution mapping.metagpt/team.py(lines 34-36) – Defines theTeamcontainer and documents the overall SOP concept for multi-agent orchestration.metagpt/strategy/task_type.py(lines 73-75) – Contains theTaskType.DEVELOP_SOFTWARESOP description used for task-type routing and pipeline selection.
Summary
- MetaGPT SOPs are controlled by the
use_fixed_sopboolean inRoleZero-derived classes, defaulting to dynamic LLM-driven behavior. - Fixed SOPs bypass LLM planning by setting
use_fixed_sop=True, disabling memory, and usingset_actions()to define explicit execution pipelines. - Dynamic SOPs leverage
RoleZero._think()to generate plans, recommend tools viaToolRecommender, and iteratively refine actions. - Source code locations: Core logic resides in
metagpt/roles/di/role_zero.py, with implementation examples inmetagpt/roles/product_manager.pyandmetagpt/roles/architect.py.
Frequently Asked Questions
What is the difference between fixed and dynamic SOP in MetaGPT?
Fixed SOP disables LLM-driven planning and executes a predefined list of actions sequentially, making it ideal for deterministic workflows. Dynamic SOP (the default) uses the _think() method to generate plans on-the-fly, recommends tools dynamically, and allows the agent to adapt its strategy based on intermediate results. The mode is controlled by the use_fixed_sop flag in RoleZero.
How do I disable memory when using fixed SOP?
Set self.enable_memory = False in the role's __init__ method, as demonstrated in ProductManager (metagpt/roles/product_manager.py, lines 43-48). This prevents the role from accessing conversation history, ensuring it follows the static action pipeline without context interference.
Can I switch SOP modes after initializing a role?
Yes. The use_fixed_sop attribute is a public instance variable that can be toggled at runtime before the role joins a team workflow. For example, you can instantiate an Architect, then set arch.use_fixed_sop = False to enable dynamic planning for a specific project without modifying the class definition.
Which source file contains the main SOP logic?
The primary SOP logic resides in metagpt/roles/di/role_zero.py, specifically lines 98-104 where the use_fixed_sop flag is defined and checked, and lines 19-22 where the dynamic tool recommendation occurs. This file serves as the base class for all customizable agent roles in MetaGPT.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →