How to Add New Agents to the MathModelAgent Multi-Agent System: A Step-by-Step Guide

To add a new agent to the MathModelAgent system, subclass the Agent base class in app/core/agents/agent.py, register it in app/core/agents/__init__.py, and wire it into the MathModelWorkFlow.execute method in app/core/workflow.py.

The MathModelAgent repository (jihe520/mathmodelagent) orchestrates a pipeline of specialized agents including the Coordinator, Modeler, Coder, and Writer. Each agent inherits from a common base class that handles chat history, memory pruning, and LLM interaction. Adding new agents to this existing multi-agent system follows a standardized four-step procedure that maintains architectural consistency.

Step 1 – Subclass the Agent Base Class

All agents in the system inherit from the Agent base class located in app/core/agents/agent.py. This base provides essential infrastructure including self.chat_history for message tracking, self.append_chat_history for automatic memory pruning, self.clear_memory for history compression, and a run helper for LLM interaction.

Understanding the Agent Base Interface

The base class manages stateful conversations and memory constraints through the following key components:

  • max_chat_turns – Limits the number of conversation turns before termination
  • max_memory – Triggers automatic pruning when history exceeds this threshold
  • is_first_run – Boolean flag to handle system prompt initialization
  • append_chat_history – Method that adds messages and triggers memory management
  • model.chat – Coroutine for LLM inference with history context

Implementing a New Agent

Create a new file in app/core/agents/ and implement the required __init__ and run coroutine. The example below demonstrates an AnalyzerAgent that processes modeler output:


# backend/app/core/agents/analyzer_agent.py

from app.core.agents.agent import Agent
from app.core.llm.llm import LLM
from app.core.prompts import ANALYZER_PROMPT
from app.schemas.response import SystemMessage
from app.services.redis_manager import redis_manager

class AnalyzerAgent(Agent):
    """Analyzes modeler results and produces a concise summary."""

    def __init__(
        self,
        task_id: str,
        model: LLM,
        max_chat_turns: int = 20,
        max_memory: int = 15,
    ) -> None:
        super().__init__(task_id, model, max_chat_turns, max_memory)
        self.system_prompt = ANALYZER_PROMPT

    async def run(self, modeler_output: str) -> str:
        # Initialize system prompt on first call

        if self.is_first_run:
            self.is_first_run = False
            await self.append_chat_history(
                {"role": "system", "content": self.system_prompt}
            )

        await self.append_chat_history(
            {"role": "user", "content": f"请为下面的模型输出生成要点摘要:\n\n{modeler_output}"}
        )

        # Query the LLM

        response = await self.model.chat(
            history=self.chat_history,
            agent_name=self.__class__.__name__,
        )
        summary = response.choices[0].message.content

        # Store assistant response

        self.chat_history.append({"role": "assistant", "content": summary})

        # Broadcast via Redis for front-end monitoring

        await redis_manager.publish_message(
            self.task_id,
            SystemMessage(content=f"{self.__class__.__name__} 完成分析")
        )

        return summary

Key implementation details:

  • Always call super().__init__ to initialize inherited attributes including is_first_run, chat_history, and memory management
  • Use append_chat_history rather than direct list manipulation to ensure automatic memory pruning via clear_memory
  • Follow the established pattern of publishing status updates through redis_manager for real-time front-end visibility

Step 2 – Register the Agent in the Package

Expose the new class by importing it in app/core/agents/__init__.py and adding it to the __all__ list:


# backend/app/core/agents/__init__.py

from .coder_agent import CoderAgent
from .writer_agent import WriterAgent
from .coordinator_agent import CoordinatorAgent
from .modeler_agent import ModelerAgent
from .analyzer_agent import AnalyzerAgent   # New import

__all__ = [
    "CoderAgent",
    "WriterAgent",
    "CoordinatorAgent",
    "ModelerAgent",
    "AnalyzerAgent",   # New export

]

This registration makes the agent available for import throughout the backend, particularly in the workflow orchestrator.

Step 3 – Integrate the Agent into the Workflow

Instantiate and invoke the agent within MathModelWorkFlow.execute in app/core/workflow.py. The workflow orchestrator sequences agent execution and manages data flow between pipeline stages:


# Inside MathModelWorkFlow.execute (backend/app/core/workflow.py)

from app.core.agents import AnalyzerAgent   # Import new agent

# ... after existing agent execution

coder_response = await coder_agent.run(...)

# Instantiate new agent with task context

analyzer_agent = AnalyzerAgent(
    task_id=problem.task_id,
    model=writer_llm,  # Reuse existing LLM or instantiate dedicated model

)

# Execute analysis on previous agent output

analysis = await analyzer_agent.run(coder_response.code_response)

# Store results for downstream consumption

user_output.set_res(f"{key}_analysis", analysis)

Integration best practices:

  • Pass the task_id to maintain conversation isolation across concurrent tasks
  • Reuse existing LLM instances from LLMFactory unless the agent requires specific model capabilities
  • Store results in UserOutput using set_res to preserve data for subsequent pipeline stages or final output generation

Step 4 – Define Prompts and Schemas (Optional)

Adding Custom Prompts

If the agent requires specialized system instructions, define them in app/core/prompts.py and reference them in the agent class:


# backend/app/core/prompts.py

ANALYZER_PROMPT = """
你是一个数学建模结果分析助手。请根据提供的模型输出,提取关键结论、重要数值和潜在风险点,输出条理清晰的要点列表。返回的文字应简洁明了,适合作为论文或报告的摘要。
"""

Creating Structured Output Schemas

For agents returning structured data rather than plain strings, define Pydantic models in app/schemas/A2A.py:


# backend/app/schemas/A2A.py

from pydantic import BaseModel

class AnalyzerResult(BaseModel):
    summary: str
    key_metrics: list[str] = []

Update the agent's type hints to return AnalyzerResult and parse the LLM output accordingly. This pattern is consistent with existing schemas like CoderToWriter and WriterResponse.

Testing Your New Agent

Verify integration by running the backend test suite or executing a minimal async script:

cd backend
uv run pytest   # Run existing test suite

For manual verification:

python -c "
import asyncio
from app.core.agents import AnalyzerAgent
from app.core.llm.llm_factory import LLMFactory

async def demo():
    llm = (await LLMFactory('demo').get_all_llms())[0]
    agent = AnalyzerAgent('demo', llm)
    result = await agent.run('示例模型输出')
    print(result)

asyncio.run(demo())

Summary

Adding new agents to the MathModelAgent multi-agent system requires four specific actions:

  • Subclass Agent in a new file under app/core/agents/, implementing __init__ and an async run method that handles chat history via append_chat_history
  • Register the class in app/core/agents/__init__.py by importing it and adding it to __all__
  • Wire into workflow by instantiating the agent in app/core/workflow.py within MathModelWorkFlow.execute and calling its run coroutine
  • Define supporting assets such as prompts in app/core/prompts.py and Pydantic schemas in app/schemas/A2A.py when structured I/O is required

This procedure ensures new agents leverage the existing memory management, Redis notification, and LLM abstraction layers while maintaining consistency with the established Coordinator-Modeler-Coder-Writer pipeline.

Frequently Asked Questions

What base class should new agents inherit from?

All agents must inherit from the Agent class defined in app/core/agents/agent.py. This base class provides the chat_history management, automatic memory pruning through clear_memory, and the is_first_run flag for system prompt initialization. Inheriting from this class ensures your agent integrates seamlessly with the existing memory-aware chat infrastructure.

Where should I instantiate new agents in the codebase?

Instantiate new agents within the MathModelWorkFlow.execute method in app/core/workflow.py. This orchestrator coordinates the multi-agent pipeline and manages the flow of data between specialized agents. Create the instance using the current task_id and an LLM instance, then call the run method with the appropriate input from the previous pipeline stage.

How does memory management work for custom agents?

The base class automatically handles memory through the max_memory parameter passed to __init__. When append_chat_history is called and the history exceeds max_memory entries, the system invokes simple_chat to compress older messages. Agents should always use append_chat_history (which triggers this pruning) rather than directly appending to self.chat_history to ensure memory constraints are respected.

Can I use a dedicated LLM configuration for a specific agent?

Yes. While you can reuse existing LLM instances passed to other agents, you may configure a dedicated model by extending LLMFactory in app/core/llm/llm_factory.py. Create a new factory method or configuration profile that returns a specialized LLM instance, then pass this to your agent's model parameter during instantiation in the workflow. This is useful when an agent requires specific capabilities like extended context windows or particular API endpoints.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →