# How ModelerAgent Analyzes Problems and Constructs Mathematical Models in jihe520/mathmodelagent

> Discover how ModelerAgent analyzes problems and constructs mathematical models by transforming user questions into structured plans via a three-stage LLM workflow. Learn more.

- Repository: [Sanjin/mathmodelagent](https://github.com/jihe520/mathmodelagent)
- Tags: deep-dive
- Published: 2026-03-04

---

**The ModelerAgent translates free-form problem descriptions into structured mathematical modeling plans by orchestrating a three-stage LLM workflow that receives user questions, applies a specialized system prompt, and outputs machine-readable JSON specifications.**

The `jihe520/mathmodelagent` repository implements a multi-agent system for automated mathematical modeling. At its core, the **ModelerAgent** serves as the architectural bridge between natural language problem statements and executable code, converting ambiguous requirements into concrete analytical specifications that drive downstream implementation.

## Understanding the ModelerAgent Architecture

The ModelerAgent operates as a specialized async component within the agent-to-agent (A2A) pipeline. Located in [`backend/app/core/agents/modeler_agent.py`](https://github.com/jihe520/mathmodelagent/blob/main/backend/app/core/agents/modeler_agent.py), this class inherits from a base agent implementation and exposes a single public entry point: the `run()` method. This method accepts a `CoordinatorToModeler` schema object containing user questions and returns a `ModelerToCoder` schema that downstream agents consume for implementation.

The agent maintains internal state through a `chat_history` list and relies on the **MODELER_PROMPT** constant defined in [`backend/app/core/prompts.py`](https://github.com/jihe520/mathmodelagent/blob/main/backend/app/core/prompts.py) (lines 31-57) to constrain the LLM's behavior. The prompt instructs the model to act as an "experienced modeling hand" and enforce strict JSON output requirements.

## The Three-Stage Analysis Workflow

The ModelerAgent processes problem descriptions through a deterministic three-stage pipeline that transforms unstructured input into executable modeling specifications.

### Stage 1: Receiving Problem Descriptions via CoordinatorToModeler

The workflow initiates when the coordinating service transmits user questions through the `CoordinatorToModeler` Pydantic schema. The `run()` method appends these questions to the conversation history alongside the system prompt:

```python
await self.append_chat_history({"role": "system", "content": self.system_prompt})
await self.append_chat_history({"role": "user", "content": json.dumps(coordinator_to_modeler.questions)})

```

*(source: [`backend/app/core/agents/modeler_agent.py`](https://github.com/jihe520/mathmodelagent/blob/main/backend/app/core/agents/modeler_agent.py), lines 23-31)*

This initialization establishes the context for the LLM, ensuring the model understands its role as a mathematical modeling specialist before processing the specific problem constraints.

### Stage 2: Generating Mathematical Models with the LLM

With the conversation primed, the agent invokes the underlying language model through `self.model.chat()`:

```python
response = await self.model.chat(history=self.chat_history, agent_name=self.__class__.__name__)

```

The LLM receives the full chat history including the **MODELER_PROMPT**, which mandates a specific output structure. According to [`backend/app/core/prompts.py`](https://github.com/jihe520/mathmodelagent/blob/main/backend/app/core/prompts.py) (lines 31-57), the prompt requires the model to generate a flat JSON object containing:

- **`eda`**: Exploratory data analysis suggestions
- **`ques1` through `quesN`**: Individual model specifications for each user question
- **`sensitivity_analysis`**: Sensitivity testing recommendations

This strict schema ensures downstream agents can parse the output deterministically without ambiguity.

### Stage 3: Parsing and Delivering the ModelingPlan

The raw LLM response undergoes preprocessing to extract valid JSON. The implementation strips markdown code fences and parses the content:

```python
json_str = response.choices[0].message.content
json_str = json_str.replace("```json", "").replace("```", "").strip()
questions_solution = json.loads(json_str)
return ModelerToCoder(questions_solution=questions_solution)

```

*(source: [`backend/app/core/agents/modeler_agent.py`](https://github.com/jihe520/mathmodelagent/blob/main/backend/app/core/agents/modeler_agent.py), lines 38-48)*

If JSON parsing fails, the agent raises a clear `ValueError`, preventing corrupted plans from propagating to the **Coder Agent**. The resulting `ModelerToCoder` object contains the complete modeling specification ready for implementation.

## Deep Dive into the MODELER_PROMPT System Instructions

The efficacy of the mathematical model construction depends on the `MODELER_PROMPT` defined in [`backend/app/core/prompts.py`](https://github.com/jihe520/mathmodelagent/blob/main/backend/app/core/prompts.py). This system prompt constrains the LLM to:

- **Role**: Act as an experienced mathematical modeling specialist
- **Task**: Build comprehensive models and visualization plans for each submitted question
- **Format**: Output strictly valid JSON without nested structures or markdown formatting

The prompt specifically enumerates the required JSON keys (`eda`, `ques1`, `quesN`, `sensitivity_analysis`), ensuring the LLM addresses every dimension of the mathematical modeling process, from initial data exploration through final sensitivity testing.

## Implementation Example

The following async workflow demonstrates how to instantiate and execute the ModelerAgent within the mathmodelagent ecosystem:

```python
import asyncio
from app.core.agents.modeler_agent import ModelerAgent
from app.core.llm.llm import LLM
from app.schemas.A2A import CoordinatorToModeler

async def get_modeling_plan():
    # Initialize the LLM backend

    llm = LLM(model_name="gpt-4o-mini")
    
    # Instantiate the ModelerAgent

    agent = ModelerAgent(task_id="task-1234", model=llm)
    
    # Prepare user questions via the coordinator schema

    coordinator_msg = CoordinatorToModeler(
        questions=[
            "How does temperature affect battery discharge rate?",
            "What is the optimal scheduling algorithm for given resource constraints?"
        ]
    )
    
    # Execute the analysis workflow

    modeling_plan = await agent.run(coordinator_msg)
    
    # Access the structured JSON plan

    print(modeling_plan.questions_solution)

asyncio.run(get_modeling_plan())

```

This example illustrates the complete pipeline: LLM initialization, agent instantiation, schema-compliant input preparation, and retrieval of the JSON modeling plan suitable for transmission to the Coder Agent.

## Summary

- **The ModelerAgent** in `jihe520/mathmodelagent` serves as the critical intermediary between natural language problem descriptions and executable mathematical specifications.
- **Three-stage workflow**: Receives `CoordinatorToModeler` input, processes through LLM with `MODELER_PROMPT` constraints, and returns `ModelerToCoder` JSON output.
- **Strict JSON schema**: The system prompt enforces flat JSON structures with mandatory keys for EDA, individual question models, and sensitivity analysis.
- **Error handling**: Implements robust markdown fence stripping and JSON parsing with explicit `ValueError` exceptions for malformed outputs.
- **A2A integration**: Seamlessly fits into the broader agent architecture, consuming coordinator messages and producing coder-ready specifications.

## Frequently Asked Questions

### What input format does the ModelerAgent require?

The ModelerAgent expects a `CoordinatorToModeler` Pydantic schema object containing a list of user questions. The agent serializes these questions to JSON and appends them to the chat history alongside the system prompt before invoking the LLM.

### How does the ModelerAgent ensure valid JSON output from the LLM?

The agent applies the `MODELER_PROMPT` defined in [`backend/app/core/prompts.py`](https://github.com/jihe520/mathmodelagent/blob/main/backend/app/core/prompts.py), which explicitly instructs the LLM to output only flat JSON without markdown formatting. Additionally, the parsing logic strips potential markdown code fences (```json and ```) before attempting JSON deserialization, raising a `ValueError` if parsing fails.

### What specific keys must the LLM include in its JSON response?

According to the source code in [`prompts.py`](https://github.com/jihe520/mathmodelagent/blob/main/prompts.py) (lines 31-57), the LLM must generate a JSON object containing: `eda` for exploratory data analysis recommendations, numbered keys (`ques1`, `ques2`, etc.) for each question's model specification, and `sensitivity_analysis` for testing recommendations.

### Which downstream agent consumes the ModelerAgent's output?

The `ModelerToCoder` schema output feeds directly into the **Coder Agent**, which interprets the JSON modeling plan and implements the actual Python code for data analysis, model construction, and visualization based on the specifications provided.