From d77430893058d4c69c10b4645ef887a1c1e64caf Mon Sep 17 00:00:00 2001 From: niteshver Date: Sat, 31 Jan 2026 17:51:31 +0530 Subject: [PATCH 1/6] add getting_started for mesa_llm --- docs/getting_started.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 docs/getting_started.md diff --git a/docs/getting_started.md b/docs/getting_started.md new file mode 100644 index 000000000..380f80caf --- /dev/null +++ b/docs/getting_started.md @@ -0,0 +1,31 @@ +# Getting Started +Mesa-llm is an extension of the Mesa agent-based modeling framework that enables language-model-based reasoning inside agents, while preserving Mesa’s execution model, scheduling, and environments. + +Mesa-llm allows agents to reason using natural language prompts, enabling more flexible, interpretable, and adaptive decision-making within structured simulations. + +Agents in mesa-llm are still standard Mesa agents. The only difference is how decisions are made, not how models run. + +## Overview +If you want a high-level understanding of mesa-llm structure and capabilities, start here: +- [Overview of Mesa-llm Library](https://github.com/mesa/mesa-llm/blob/main/docs/overview.md) + +## Tutorials +If you want to learn mesa-llm step by step, follow these tutorials: +- [Creating your First Mesa-llm Model](https://github.com/mesa/mesa-llm/blob/main/docs/first_model.md) +Learn how to define a minimal LLMAgent that reasons using an LLM while remaining a standard Mesa agent. + +- [Negotiation Model Tutorial](https://github.com/mesa/mesa-llm/blob/main/docs/negotiation_model_tutorial.md) +Learn how multiple LLM-powered agents reason, communicate, and negotiate within a shared model. + +## Examples +Mesa-llm ships with example models demonstrating how language-based reasoning integrates with classic agent-based modeling patterns. + +These examples are useful if you are already familiar with Mesa and want to see how LLM-powered agents behave in practice. You can find them here: +[Mesa-llm Examples](https://github.com/mesa/mesa-llm/tree/main/examples) + +## Source Code +- [Mesa-llm Github Repository](https://github.com/mesa/mesa-llm) + +## Community and Support +- [Mesa-llm Discussion](https://github.com/mesa/mesa-llm/discussions) +- [Matrix Chat Room](https://matrix.to/#/#mesa-llm:matrix.org) From e1d4167005518db620521b59a98137e2acc8b96e Mon Sep 17 00:00:00 2001 From: niteshver Date: Sun, 22 Mar 2026 18:05:36 +0530 Subject: [PATCH 2/6] add agriculture productivity model --- examples/agriculture_model/__init__.py | 1 + examples/agriculture_model/agent.py | 135 +++++++ examples/agriculture_model/app.py | 123 ++++++ examples/agriculture_model/model.py | 140 +++++++ examples/agriculture_model/readme.md | 515 +++++++++++++++++++++++++ examples/agriculture_model/tools.py | 88 +++++ 6 files changed, 1002 insertions(+) create mode 100644 examples/agriculture_model/__init__.py create mode 100644 examples/agriculture_model/agent.py create mode 100644 examples/agriculture_model/app.py create mode 100644 examples/agriculture_model/model.py create mode 100644 examples/agriculture_model/readme.md create mode 100644 examples/agriculture_model/tools.py diff --git a/examples/agriculture_model/__init__.py b/examples/agriculture_model/__init__.py new file mode 100644 index 000000000..a78585511 --- /dev/null +++ b/examples/agriculture_model/__init__.py @@ -0,0 +1 @@ +import examples.agriculture_model.tools \ No newline at end of file diff --git a/examples/agriculture_model/agent.py b/examples/agriculture_model/agent.py new file mode 100644 index 000000000..84706cbdb --- /dev/null +++ b/examples/agriculture_model/agent.py @@ -0,0 +1,135 @@ +import random +from enum import Enum + +from mesa_llm.llm_agent import LLMAgent +from mesa_llm.memory.st_lt_memory import STLTMemory +from mesa_llm.tools.tool_manager import ToolManager + +FARMER_TOOL_MANAGER = ToolManager() + + +class CropState(Enum): + IDLE = "IDLE" + PLANTED = "PLANTED" + GROWING = "GROWING" + READY = "READY" + + +class FarmerAgent(LLMAgent): + def __init__( + self, + model, + reasoning, + llm_model, + system_prompt, + vision, + internal_state, + step_prompt, + ): + super().__init__( + model=model, + reasoning=reasoning, + llm_model=llm_model, + system_prompt=system_prompt, + vision=vision, + internal_state=internal_state, + step_prompt=step_prompt, + ) + + self.tool_manager = FARMER_TOOL_MANAGER + self.land_size = random.randint(1, 5) + self.wealth = random.randint(1000, 50000) + self._base_internal_state = list(self.internal_state) + + self.crop_type = random.choice(["wheat", "rice", "maize"]) + self.crop_state = CropState.IDLE + + self.plant_date = None + self.harvest_date = None + self.fertilizer = 0.0 + + self.yield_output = 0.0 + self.profit = 0.0 + + self.memory = STLTMemory( + agent=self, + llm_model="ollama/llama3.1:latest", + display=False, + ) + + def observe_environment(self): + self.internal_state = [ + *self._base_internal_state, + f"My land size is {self.land_size}", + f"On a scale of 1000 - 50000, my wealth is {self.wealth}", + f"My crop type is {self.crop_type}", + f"My crop state is {self.crop_state.value}", + f"Rainfall condition is {self.model.rainfall}", + ] + + def update_crop_state(self): + if ( + self.crop_state in {CropState.PLANTED, CropState.GROWING} + and self.harvest_date is not None + and self.model.current_day >= self.harvest_date + ): + self.crop_state = CropState.READY + + def decide(self): + obs = self.generate_obs() + + prompt = f""" + You are a farmer. + + + wealth: {self.wealth} + Crop type: {self.crop_type} + Crop state: {self.crop_state} + land size: {self.land_size} + + Decide actions: + - plant_crop(days_to_harvest) + - apply_fertilizer(level) + - wait_action() + - harvest_crop() + + Use tools smartly. + """ + + plan = self.reasoning.plan( + prompt=prompt, + obs=obs, + selected_tools=[ + "plant_crop", + "apply_fertilizer", + "harvest_crop", + "speak_to", + ], + ) + + self.apply_plan(plan) + + def compute_yield(self): + base_yield = 1000 * self.land_size + + if self.model.rainfall == "LOW": + rain_factor = 0.7 + elif self.model.rainfall == "HIGH": + rain_factor = 1.3 + else: + rain_factor = 1.0 + + fert_factor = 1 + 0.3 * self.fertilizer + noise = random.uniform(0.9, 1.1) + + self.yield_output = base_yield * rain_factor * fert_factor * noise + price = self.model.market_price[self.crop_type] + self.profit = self.yield_output * price + + def step(self): + self.observe_environment() + self.update_crop_state() + self.decide() + self.update_crop_state() + + diff --git a/examples/agriculture_model/app.py b/examples/agriculture_model/app.py new file mode 100644 index 000000000..546f47247 --- /dev/null +++ b/examples/agriculture_model/app.py @@ -0,0 +1,123 @@ +import logging +import warnings + +from dotenv import load_dotenv +from mesa.visualization import SolaraViz, Slider, make_plot_component, make_space_component + +from mesa_llm.parallel_stepping import enable_automatic_parallel_stepping +from mesa_llm.reasoning.react import ReActReasoning + +from examples.agriculture_model.agent import CropState, FarmerAgent +from examples.agriculture_model.model import FarmerModel + + +warnings.filterwarnings( + "ignore", + category=UserWarning, + module="pydantic.main", + message=r".*Pydantic serializer warnings.*", +) +logging.getLogger("pydantic").setLevel(logging.ERROR) + +enable_automatic_parallel_stepping() +load_dotenv() + + +CROP_COLORS = { + CropState.IDLE: "#D7C7A3", + CropState.PLANTED: "#A3D977", + CropState.GROWING: "#6FBF73", + CropState.READY: "#FFBD66", +} + + +model_params = { + "initial_farmers": Slider("Number of Farmers", 10, 1, 50, 1), + "rainfall": Slider("Rainfall Level", 0.5, 0.0, 1.0, 0.1), + "seed": { + "type": "InputText", + "value": 42, + "label": "Random Seed", + }, + "width": 20, + "height": 20, + "reasoning": ReActReasoning, + "llm_model": "ollama/llama3.1:latest", + "vision": 3, + "parallel_stepping": False, +} + +model = FarmerModel( + initial_farmers=10, + rainfall=0.5, + width=model_params["width"], + height=model_params["height"], + reasoning=model_params["reasoning"], + llm_model=model_params["llm_model"], + vision=model_params["vision"], + seed=model_params["seed"]["value"], + parallel_stepping=model_params["parallel_stepping"], +) + + +def farmer_portrayal(agent): + if agent is None: + return None + + portrayal = {"size": 50} + + if isinstance(agent, FarmerAgent): + portrayal["color"] = CROP_COLORS.get(agent.crop_state, "#888888") + + return portrayal + + +def post_process(ax): + ax.set_aspect("equal") + ax.set_xticks([]) + ax.set_yticks([]) + ax.get_figure().set_size_inches(8, 8) + + +space_component = make_space_component( + farmer_portrayal, + post_process=post_process, + draw_grid=False, +) + +crop_chart = make_plot_component( + { + "Rice": "#4CAF50", + "Wheat": "#FFC107", + "Maize": "#FF5722", + } +) + +profit_chart = make_plot_component( + { + "Total Profit": "#2196F3", + "Average Profit": "#9C27B0", + } +) + +state_chart = make_plot_component( + { + "Planted": "#A3D977", + "Growing": "#6FBF73", + "Ready": "#FFBD66", + "Idle": "#D7C7A3", + } +) + + +page = SolaraViz( + model, + components=[ + space_component, + crop_chart, + profit_chart, + state_chart, + ], + model_params=model_params, + name="Agriculture Decision Model (Mesa-LLM)", +) diff --git a/examples/agriculture_model/model.py b/examples/agriculture_model/model.py new file mode 100644 index 000000000..6e2938d41 --- /dev/null +++ b/examples/agriculture_model/model.py @@ -0,0 +1,140 @@ +from datetime import datetime, timedelta +import random +from mesa import Model +from mesa.datacollection import DataCollector +from mesa.space import MultiGrid + +from mesa_llm.reasoning.reasoning import Reasoning +from mesa_llm.reasoning.react import ReActReasoning +from mesa_llm.recording.record_model import record_model + +from examples.agriculture_model.agent import CropState, FarmerAgent + + +@record_model(output_dir="recordings") +class FarmerModel(Model): + def __init__( + self, + initial_farmers: int, + rainfall: float, + width: int, + height: int, + reasoning: type[Reasoning], + llm_model: str, + vision: int, + parallel_stepping=True, + seed=None, + ): + normalized_seed = None if seed in (None, "") else int(seed) + super().__init__(seed=normalized_seed) + self.width = width + self.height = height + self.parallel_stepping = parallel_stepping + self.grid = MultiGrid(width, height, torus=False) + + self.start_date = datetime(2024, 6, 1) + self.current_day = self.start_date + + self.rainfall = self._normalize_rainfall(rainfall=rainfall) + self.market_price = { + "wheat": 2.0, + "rice": 3.0, + "maize": 1.5, + } + + for _ in range(initial_farmers): + agent = FarmerAgent( + model=self, + reasoning=reasoning, + llm_model=llm_model, + system_prompt="You are a smart farmer.", + step_prompt="Decide actions.", + vision=vision, + internal_state=["hardworking"], + ) + x = self.random.randrange(self.grid.width) + y = self.random.randrange(self.grid.height) + self.grid.place_agent(agent, (x, y)) + + self.datacollector = DataCollector( + model_reporters={ + "Rice": lambda m: sum( + 1 + for a in m.agents + if isinstance(a, FarmerAgent) and a.crop_type == "rice" + ), + "Wheat": lambda m: sum( + 1 + for a in m.agents + if isinstance(a, FarmerAgent) and a.crop_type == "wheat" + ), + "Maize": lambda m: sum( + 1 + for a in m.agents + if isinstance(a, FarmerAgent) and a.crop_type == "maize" + ), + "Total Profit": lambda m: sum( + a.profit for a in m.agents if isinstance(a, FarmerAgent) + ), + "Average Profit": lambda m: ( + sum(a.profit for a in m.agents if isinstance(a, FarmerAgent)) + / max( + 1, + sum(1 for a in m.agents if isinstance(a, FarmerAgent)), + ) + ), + "Planted": lambda m: sum( + 1 + for a in m.agents + if isinstance(a, FarmerAgent) and a.crop_state == CropState.PLANTED + ), + "Growing": lambda m: sum( + 1 + for a in m.agents + if isinstance(a, FarmerAgent) and a.crop_state == CropState.GROWING + ), + "Ready": lambda m: sum( + 1 + for a in m.agents + if isinstance(a, FarmerAgent) and a.crop_state == CropState.READY + ), + "Idle": lambda m: sum( + 1 + for a in m.agents + if isinstance(a, FarmerAgent) and a.crop_state == CropState.IDLE + ), + } + ) + + self.running = True + self.datacollector.collect(self) + + def _normalize_rainfall(self, rainfall: float | str | None) -> str: + if isinstance(rainfall, str): + rainfall_upper = rainfall.upper() + if rainfall_upper in {"LOW", "NORMAL", "HIGH"}: + return rainfall_upper + raise ValueError(f"Unsupported rainfall value: {rainfall}") + + if rainfall is None: + return "NORMAL" + if rainfall < 0.33: + return "LOW" + if rainfall > 0.66: + return "HIGH" + return "NORMAL" + + def step(self): + self.current_day += timedelta(days=1) + self.agents.shuffle_do("step") + self.datacollector.collect(self) + + if (self.current_day - self.start_date).days > 120: + self.running = False + + +if __name__ == "__main__": + from examples.agriculture_model.app import model + + for _ in range(5): + model.step() diff --git a/examples/agriculture_model/readme.md b/examples/agriculture_model/readme.md new file mode 100644 index 000000000..d7ce656d6 --- /dev/null +++ b/examples/agriculture_model/readme.md @@ -0,0 +1,515 @@ +πŸŒΎπŸš€ AgriCast-ABM +Farmer Decision & Crop Productivity Model (Mesa + Mesa-LLM) +🧠 1. Overview + +AgriCast-ABM is an agent-based simulation model that captures how farmers respond to weather forecasts, social information, and uncertainty to make agricultural decisions. + +The system models the full feedback loop: + +Weather Forecast β†’ Information Flow β†’ Farmer Decisions β†’ Crop Yield β†’ Learning β†’ Adoption + +It integrates: + +🌦 Environmental dynamics (rainfall variability) +πŸ‘¨β€πŸŒΎ Human decision-making (risk, trust, learning) +🌐 Social interactions (networks, diffusion) +🧠 Optional LLM-based reasoning (Mesa-LLM) +🧱 2. System Architecture +AgriCastModel +β”‚ +β”œβ”€β”€ FarmerAgent (Core) +β”‚ +β”œβ”€β”€ Environment +β”‚ β”œβ”€β”€ WeatherSystem +β”‚ β”œβ”€β”€ CropEngine +β”‚ +β”œβ”€β”€ Information Layer +β”‚ β”œβ”€β”€ Radio +β”‚ β”œβ”€β”€ Extension Agents +β”‚ β”œβ”€β”€ Farmer Network +β”‚ +β”œβ”€β”€ Decision Engine (LLM optional) +β”œβ”€β”€ Adoption Engine (LTA Model) +β”œβ”€β”€ Data Collector +πŸ‘¨β€πŸŒΎ 3. Agents +πŸ”Ή 3.1 FarmerAgent (Core Entity) +Attributes +unique_id +pos + +# socio-economic +land_size +wealth +education_level +risk_aversion + +# trust system +trust_radio +trust_neighbors +trust_extension + +# adoption +LTA # Learning–Trust–Adoption score (0–100) +adopt_forecast # Boolean + +# farming decisions +planting_time # early / normal / late +fertilizer +pesticide +tillage + +# outputs +yield_output +profit + +# memory +past_yields (list) +πŸ”„ Behavior (Step Flow) +1. Receive forecast +2. Interact with neighbors +3. Update trust +4. Update LTA +5. Decide adoption (probabilistic) +6. Choose farming strategy +7. Compute yield +8. Update memory +9. Learn (feedback) +πŸ”Ή 3.2 Information Sources +πŸ“» Radio +Global broadcast +Accuracy-dependent influence +πŸ‘¨β€πŸ”¬ Extension Agents +High-trust actors +Direct farmer interaction +🌐 Farmer Network +Graph-based (social diffusion) +Peer learning +🌦️ 4. Environment +WeatherSystem +rainfall ∈ {LOW, NORMAL, HIGH} +forecast_accuracy ∈ [0.6, 0.8] +Rainfall Values +LOW = 900 mm +NORMAL = 1300 mm +HIGH = 1900 mm +🌱 5. Crop Engine (Simplified DSSAT) +Yield Function +yield = +base_yield +Γ— rainfall_factor +Γ— planting_factor +Γ— fertilizer_factor +Γ— pesticide_factor +Γ— random(0.9, 1.1) +Factor Definitions +Rainfall +LOW = 0.7 +NORMAL = 1.0 +HIGH = 1.2 +Planting +early + high rain = 1.3 +late + low rain = 0.8 +else = 1.0 +Fertilizer +fertilizer_factor = 1 + 0.3 * fertilizer_level +Pesticide +pesticide_factor = 1 + 0.1 * pesticide_level +🧠 6. Adoption Model (LTA) +LTA Update Equation +LTA_new = +clip( + LTA_old + + Ξ± * ( + trust_neighbor * info_neighbor + + trust_network * info_network + + trust_extension * info_extension + + trust_radio * info_radio + ) + + Ξ² * forecast_accuracy + - Ξ³ * uncertainty +, 0, 100) +Feedback Learning +LTA_new = LTA_old + Ξ΄ * (yield - expected_yield) +Trust Update +if forecast_correct: + trust_radio += 0.05 +else: + trust_radio -= 0.1 +🎯 7. Adoption Decision +Probability Function +P_adopt = 1 / (1 + e^(-k*(LTA - threshold))) +Final Decision +if random.random() < P_adopt: + adopt = True +🌐 8. Interaction System +Neighbor Interaction +neighbors = grid.get_neighbors(pos, radius=r) +Network Interaction +network = nx.erdos_renyi_graph(n, p) +Information Aggregation +info = weighted average of sources +πŸ” 9. Simulation Loop +def step(): + + # 1. Weather update + update_weather() + + # 2. Information spread + for farmer: + gather_information() + + # 3. LTA update + for farmer: + update_LTA() + + # 4. Decision making + for farmer: + decide_adoption() + + # 5. Farming actions + for farmer: + choose_strategy() + + # 6. Crop simulation + for farmer: + compute_yield() + + # 7. Learning + for farmer: + update_memory() + + # 8. Data collection + collect_metrics() +πŸ“Š 10. Metrics +Core Metrics +average_yield +total_yield +adoption_rate +Advanced Metrics +food_security_index +information_spread_rate +trust_distribution +yield_variance +βš™οΈ 11. Parameters +Global Parameters +NUM_FARMERS +GRID_SIZE +FORECAST_ACCURACY +INTERACTION_RADIUS +NETWORK_PROB +Model Constants +Ξ± = 0.5 +Ξ² = 0.3 +Ξ³ = 0.2 +Ξ΄ = 0.1 +k = 0.1 +threshold = 50 +🧠 12. Mesa-LLM Integration (Advanced) +Farmer Reasoning Prompt +You are a farmer. + +Rain forecast: LOW +Neighbors suggest: plant early +Trust level: medium + +Decide: +- planting time +- fertilizer usage +- whether to follow forecast +Available Tools +listen_radio +talk_to_neighbor +apply_fertilizer +plant_crop +πŸš€ 13. Extensions +πŸ”Ή Policy Simulation +Subsidies β†’ increase adoption +Training β†’ increase trust +πŸ”Ή Climate Change +Increased rainfall variability +Forecast uncertainty +πŸ”Ή Economic Layer +profit = yield * price - cost +⚠️ 14. Assumptions +Single crop (maize) +Fixed land size +No market dynamics (optional) +Simplified crop model (DSSAT-inspired) +⭐ 15. Why This is GSoC-Level +βœ” Hybrid system (social + environmental) +βœ” Behaviorally realistic agents +βœ” Learning + feedback loops +βœ” Scalable architecture +i want a complete readme.md file + +Here’s a polished, complete README.md you can directly use for your repo / GSoC proposal: + +πŸŒΎπŸš€ AgriCast-ABM +Farmer Decision & Crop Productivity Model (Mesa + Mesa-LLM) +🧠 Overview + +AgriCast-ABM is an Agent-Based Model (ABM) that simulates how farmers make agricultural decisions under uncertain weather conditions. + +The system models the full decision pipeline: + +Weather Forecast β†’ Information Flow β†’ Farmer Decisions β†’ Crop Yield β†’ Learning β†’ Adoption + +It combines: + +🌦️ Environmental simulation (weather + crops) +πŸ‘¨β€πŸŒΎ Human decision-making (farmers) +🌐 Social interaction (networks, extension agents) +🧠 Learning & adaptation (trust + LTA) +πŸ€– Optional LLM-driven reasoning (Mesa-LLM) +🧱 Architecture +AgriCastModel +β”‚ +β”œβ”€β”€ FarmerAgent (core decision-maker) +β”‚ +β”œβ”€β”€ Environment +β”‚ β”œβ”€β”€ WeatherSystem +β”‚ β”œβ”€β”€ CropEngine +β”‚ +β”œβ”€β”€ Information Layer +β”‚ β”œβ”€β”€ Radio (global broadcast) +β”‚ β”œβ”€β”€ Extension Agents +β”‚ β”œβ”€β”€ Farmer Network (graph-based) +β”‚ +β”œβ”€β”€ Decision Engine (rule-based / LLM) +β”œβ”€β”€ Adoption Engine (LTA model) +β”œβ”€β”€ Data Collector +πŸ‘¨β€πŸŒΎ Agents +πŸ”Ή FarmerAgent (Core Entity) +Attributes +unique_id +pos + +# socio-economic +land_size +wealth +education_level +risk_aversion + +# trust system +trust_radio +trust_neighbors +trust_extension + +# adoption +LTA # Learning Trust Accumulation (0–100) +adopt_forecast # Boolean + +# farming decisions +planting_time # early / normal / late +fertilizer +pesticide +tillage + +# outputs +yield_output +profit + +# memory +past_yields (list) +πŸ”„ Behavior (Per Step) +1. Receive forecast +2. Interact with neighbors +3. Update trust +4. Update LTA +5. Decide adoption (probabilistic) +6. Choose farming strategy +7. Compute yield +8. Update memory +9. Learn (feedback) +πŸ“‘ Information Sources +πŸ“» Radio +Broadcasts weather forecast globally +Accuracy depends on system parameter +πŸ‘¨β€πŸ”¬ Extension Agents +High-trust advisory entities +Direct influence on farmers +🌐 Farmer Network +Graph-based (e.g., ErdΕ‘s–RΓ©nyi) +Enables peer-to-peer information diffusion +🌦️ Environment +WeatherSystem +rainfall ∈ {LOW, NORMAL, HIGH} +forecast_accuracy ∈ [0.6, 0.8] +Rainfall Values +LOW = 900 mm +NORMAL = 1300 mm +HIGH = 1900 mm +🌱 Crop Engine (Simplified DSSAT) +Yield Function +yield = +base_yield +Γ— rainfall_factor +Γ— planting_factor +Γ— fertilizer_factor +Γ— pesticide_factor +Γ— random(0.9, 1.1) +Factors +🌧️ Rainfall +LOW = 0.7 +NORMAL = 1.0 +HIGH = 1.2 +🌱 Planting Strategy +early + high rain = 1.3 +late + low rain = 0.8 +else = 1.0 +πŸ§ͺ Fertilizer +fertilizer_factor = 1 + 0.3 * fertilizer_level +πŸ› Pesticide +pesticide_factor = 1 + 0.1 * pesticide_level +🧠 Adoption Model (LTA) +πŸ”Ή LTA Update +LTA_new = +clip( + LTA_old + + Ξ± * ( + trust_neighbor * info_neighbor + + trust_network * info_network + + trust_extension * info_extension + + trust_radio * info_radio + ) + + Ξ² * forecast_accuracy + - Ξ³ * uncertainty +, 0, 100) +πŸ”Ή Feedback Learning +LTA_new = LTA_old + Ξ΄ * (yield - expected_yield) +πŸ”Ή Trust Update +if forecast_correct: + trust_radio += 0.05 +else: + trust_radio -= 0.1 +🎯 Adoption Decision +Probability Function +P_adopt = 1 / (1 + e^(-k*(LTA - threshold))) +Final Decision +if random.random() < P_adopt: + adopt = True +🌐 Interaction System +Neighbor Interaction +neighbors = grid.get_neighbors(pos, radius=r) +Network Interaction +network = nx.erdos_renyi_graph(n, p) +Information Aggregation +info = weighted average of all sources +πŸ” Simulation Loop +def step(): + + # 1. Weather update + update_weather() + + # 2. Information spread + for farmer: + gather_information() + + # 3. LTA update + for farmer: + update_LTA() + + # 4. Decision + for farmer: + decide_adoption() + + # 5. Farming actions + for farmer: + choose_strategy() + + # 6. Crop simulation + for farmer: + compute_yield() + + # 7. Learning + for farmer: + update_memory() + + # 8. Data collection + collect_metrics() +πŸ“Š Metrics +Core Metrics +average_yield +total_yield +adoption_rate +Advanced Metrics +food_security_index +information_spread_rate +trust_distribution +yield_variance +βš™οΈ Parameters +Global Parameters +NUM_FARMERS +GRID_SIZE +FORECAST_ACCURACY +INTERACTION_RADIUS +NETWORK_PROB +Model Constants +Ξ± = 0.5 +Ξ² = 0.3 +Ξ³ = 0.2 +Ξ΄ = 0.1 +k = 0.1 +threshold = 50 +πŸ€– Mesa-LLM Extension (Advanced) +Farmer Reasoning Prompt +You are a farmer. + +Rain forecast: LOW +Neighbors suggest: plant early +Trust level: medium + +Decide: +- planting time +- fertilizer usage +- whether to follow forecast +Tools +listen_radio +talk_to_neighbor +apply_fertilizer +plant_crop +πŸš€ Extensions +πŸ›οΈ Policy Simulation +subsidy β†’ increases adoption +training β†’ increases trust +🌍 Climate Change +increase rainfall variability +πŸ’° Economic Layer +profit = yield * price - cost +⚠️ Assumptions +- Single crop (maize) +- Fixed land size +- No market dynamics (optional) +- Simplified crop model +⭐ Why This is GSoC-Level +βœ” Hybrid system (social + environmental) +βœ” Incorporates learning & feedback loops +βœ” Realistic farmer behavior modeling +βœ” Scalable & modular architecture +βœ” Supports both rule-based and LLM-driven agents +🏁 Summary +Farmers receive information +β†’ interact socially +β†’ update beliefs (LTA) +β†’ make decisions +β†’ affect yield +β†’ learn from outcomes +β†’ system evolves +πŸš€ Next Steps + +You can extend this project by: + +Implementing Mesa simulation (model.py, agent.py) +Adding LLM agents (Mesa-LLM) +Building a UI with Solara +Running policy experiments +Publishing results + +If you want, I can now generate: + +πŸ‘‰ Full working code (agent.py, model.py, app.py) +πŸ‘‰ Or a GSoC proposal draft based on this README + +We use cookies + +We use cookies to help this site function, understand service usage, and support marketing efforts. Visit Manage Cookies to change preferences anytime. View our Cookie Policy for more info. \ No newline at end of file diff --git a/examples/agriculture_model/tools.py b/examples/agriculture_model/tools.py new file mode 100644 index 000000000..f1b5419b6 --- /dev/null +++ b/examples/agriculture_model/tools.py @@ -0,0 +1,88 @@ +from datetime import timedelta + +from mesa_llm.tools.tool_decorator import tool + +from examples.agriculture_model.agent import CropState, FARMER_TOOL_MANAGER + + +@tool(tool_manager=FARMER_TOOL_MANAGER) +def plant_crop(agent, days_to_harvest: int = 60): + """ + Plant a crop in the field. + + Args: + days_to_harvest: Number of days required for harvest. + + Returns: + A status message. + """ + try: + days_to_harvest = int(days_to_harvest) + except (TypeError, ValueError) as exc: + raise ValueError( + f"days_to_harvest must be an integer, got {days_to_harvest!r}" + ) from exc + if days_to_harvest <= 0: + raise ValueError("days_to_harvest must be greater than 0") + if agent.crop_state != CropState.IDLE: + return f"Cannot plant while crop is {agent.crop_state.value}" + + agent.crop_state = CropState.PLANTED + agent.plant_date = agent.model.current_day + agent.harvest_date = agent.model.current_day + timedelta(days=days_to_harvest) + agent.fertilizer = 0.0 + return "Crop planted" + + +@tool(tool_manager=FARMER_TOOL_MANAGER) +def apply_fertilizer(agent, level: float = 0.5): + """ + Apply fertilizer to the crop. + + Args: + level: Fertilizer intensity from 0 to 1. + + Returns: + A status message. + """ + try: + level = float(level) + except (TypeError, ValueError) as exc: + raise ValueError(f"level must be numeric, got {level!r}") from exc + if level < 0: + raise ValueError("level must be non-negative") + if agent.crop_state == CropState.IDLE: + return "No crop planted" + + agent.fertilizer += level + if agent.crop_state == CropState.PLANTED: + agent.crop_state = CropState.GROWING + return f"Fertilizer applied: {level}" + +@tool(tool_manager=FARMER_TOOL_MANAGER) +def harvest_crop(agent): + """ + Harvest the crop if ready. + + Args: + agent: Provided automatically. + + Returns: + A harvest status message. + """ + if ( + agent.harvest_date is not None + and agent.crop_state in {CropState.PLANTED, CropState.GROWING} + and agent.model.current_day >= agent.harvest_date + ): + agent.crop_state = CropState.READY + + if agent.crop_state != CropState.READY: + return "Not ready" + + agent.compute_yield() + agent.crop_state = CropState.IDLE + agent.plant_date = None + agent.harvest_date = None + agent.fertilizer = 0.0 + return "Harvested" From 0496aecffd8c12aff0a3868ea935d755a693ab50 Mon Sep 17 00:00:00 2001 From: niteshver Date: Mon, 23 Mar 2026 20:42:17 +0530 Subject: [PATCH 3/6] improve read me and agent.py --- examples/agriculture_model/agent.py | 10 +- examples/agriculture_model/model.py | 10 +- examples/agriculture_model/readme.md | 716 ++++++++------------------- 3 files changed, 210 insertions(+), 526 deletions(-) diff --git a/examples/agriculture_model/agent.py b/examples/agriculture_model/agent.py index 84706cbdb..ca5a74dea 100644 --- a/examples/agriculture_model/agent.py +++ b/examples/agriculture_model/agent.py @@ -54,7 +54,7 @@ def __init__( self.memory = STLTMemory( agent=self, llm_model="ollama/llama3.1:latest", - display=False, + display=True, ) def observe_environment(self): @@ -76,12 +76,10 @@ def update_crop_state(self): self.crop_state = CropState.READY def decide(self): - obs = self.generate_obs() + observation = self.generate_obs() prompt = f""" You are a farmer. - - wealth: {self.wealth} Crop type: {self.crop_type} Crop state: {self.crop_state} @@ -90,15 +88,15 @@ def decide(self): Decide actions: - plant_crop(days_to_harvest) - apply_fertilizer(level) - - wait_action() - harvest_crop() + - speak_to() Use tools smartly. """ plan = self.reasoning.plan( prompt=prompt, - obs=obs, + obs=observation, selected_tools=[ "plant_crop", "apply_fertilizer", diff --git a/examples/agriculture_model/model.py b/examples/agriculture_model/model.py index 6e2938d41..46291a1b1 100644 --- a/examples/agriculture_model/model.py +++ b/examples/agriculture_model/model.py @@ -16,7 +16,7 @@ class FarmerModel(Model): def __init__( self, initial_farmers: int, - rainfall: float, + rainfall: int, width: int, height: int, reasoning: type[Reasoning], @@ -106,8 +106,8 @@ def __init__( } ) - self.running = True - self.datacollector.collect(self) + # self.running = True + # self.datacollector.collect(self) def _normalize_rainfall(self, rainfall: float | str | None) -> str: if isinstance(rainfall, str): @@ -129,8 +129,8 @@ def step(self): self.agents.shuffle_do("step") self.datacollector.collect(self) - if (self.current_day - self.start_date).days > 120: - self.running = False + # if (self.current_day - self.start_date).days > 120: + # self.running = False if __name__ == "__main__": diff --git a/examples/agriculture_model/readme.md b/examples/agriculture_model/readme.md index d7ce656d6..ebceb7974 100644 --- a/examples/agriculture_model/readme.md +++ b/examples/agriculture_model/readme.md @@ -1,515 +1,201 @@ -πŸŒΎπŸš€ AgriCast-ABM -Farmer Decision & Crop Productivity Model (Mesa + Mesa-LLM) -🧠 1. Overview - -AgriCast-ABM is an agent-based simulation model that captures how farmers respond to weather forecasts, social information, and uncertainty to make agricultural decisions. - -The system models the full feedback loop: - -Weather Forecast β†’ Information Flow β†’ Farmer Decisions β†’ Crop Yield β†’ Learning β†’ Adoption - -It integrates: - -🌦 Environmental dynamics (rainfall variability) -πŸ‘¨β€πŸŒΎ Human decision-making (risk, trust, learning) -🌐 Social interactions (networks, diffusion) -🧠 Optional LLM-based reasoning (Mesa-LLM) -🧱 2. System Architecture -AgriCastModel -β”‚ -β”œβ”€β”€ FarmerAgent (Core) -β”‚ -β”œβ”€β”€ Environment -β”‚ β”œβ”€β”€ WeatherSystem -β”‚ β”œβ”€β”€ CropEngine -β”‚ -β”œβ”€β”€ Information Layer -β”‚ β”œβ”€β”€ Radio -β”‚ β”œβ”€β”€ Extension Agents -β”‚ β”œβ”€β”€ Farmer Network -β”‚ -β”œβ”€β”€ Decision Engine (LLM optional) -β”œβ”€β”€ Adoption Engine (LTA Model) -β”œβ”€β”€ Data Collector -πŸ‘¨β€πŸŒΎ 3. Agents -πŸ”Ή 3.1 FarmerAgent (Core Entity) -Attributes -unique_id -pos - -# socio-economic -land_size -wealth -education_level -risk_aversion - -# trust system -trust_radio -trust_neighbors -trust_extension - -# adoption -LTA # Learning–Trust–Adoption score (0–100) -adopt_forecast # Boolean - -# farming decisions -planting_time # early / normal / late -fertilizer -pesticide -tillage - -# outputs -yield_output -profit - -# memory -past_yields (list) -πŸ”„ Behavior (Step Flow) -1. Receive forecast -2. Interact with neighbors -3. Update trust -4. Update LTA -5. Decide adoption (probabilistic) -6. Choose farming strategy -7. Compute yield -8. Update memory -9. Learn (feedback) -πŸ”Ή 3.2 Information Sources -πŸ“» Radio -Global broadcast -Accuracy-dependent influence -πŸ‘¨β€πŸ”¬ Extension Agents -High-trust actors -Direct farmer interaction -🌐 Farmer Network -Graph-based (social diffusion) -Peer learning -🌦️ 4. Environment -WeatherSystem -rainfall ∈ {LOW, NORMAL, HIGH} -forecast_accuracy ∈ [0.6, 0.8] -Rainfall Values -LOW = 900 mm -NORMAL = 1300 mm -HIGH = 1900 mm -🌱 5. Crop Engine (Simplified DSSAT) -Yield Function -yield = -base_yield -Γ— rainfall_factor -Γ— planting_factor -Γ— fertilizer_factor -Γ— pesticide_factor -Γ— random(0.9, 1.1) -Factor Definitions -Rainfall -LOW = 0.7 -NORMAL = 1.0 -HIGH = 1.2 -Planting -early + high rain = 1.3 -late + low rain = 0.8 -else = 1.0 -Fertilizer -fertilizer_factor = 1 + 0.3 * fertilizer_level -Pesticide -pesticide_factor = 1 + 0.1 * pesticide_level -🧠 6. Adoption Model (LTA) -LTA Update Equation -LTA_new = -clip( - LTA_old - + Ξ± * ( - trust_neighbor * info_neighbor + - trust_network * info_network + - trust_extension * info_extension + - trust_radio * info_radio - ) - + Ξ² * forecast_accuracy - - Ξ³ * uncertainty -, 0, 100) -Feedback Learning -LTA_new = LTA_old + Ξ΄ * (yield - expected_yield) -Trust Update -if forecast_correct: - trust_radio += 0.05 -else: - trust_radio -= 0.1 -🎯 7. Adoption Decision -Probability Function -P_adopt = 1 / (1 + e^(-k*(LTA - threshold))) -Final Decision -if random.random() < P_adopt: - adopt = True -🌐 8. Interaction System -Neighbor Interaction -neighbors = grid.get_neighbors(pos, radius=r) -Network Interaction -network = nx.erdos_renyi_graph(n, p) -Information Aggregation -info = weighted average of sources -πŸ” 9. Simulation Loop -def step(): - - # 1. Weather update - update_weather() - - # 2. Information spread - for farmer: - gather_information() - - # 3. LTA update - for farmer: - update_LTA() - - # 4. Decision making - for farmer: - decide_adoption() - - # 5. Farming actions - for farmer: - choose_strategy() - - # 6. Crop simulation - for farmer: - compute_yield() - - # 7. Learning - for farmer: - update_memory() - - # 8. Data collection - collect_metrics() -πŸ“Š 10. Metrics -Core Metrics -average_yield -total_yield -adoption_rate -Advanced Metrics -food_security_index -information_spread_rate -trust_distribution -yield_variance -βš™οΈ 11. Parameters -Global Parameters -NUM_FARMERS -GRID_SIZE -FORECAST_ACCURACY -INTERACTION_RADIUS -NETWORK_PROB -Model Constants -Ξ± = 0.5 -Ξ² = 0.3 -Ξ³ = 0.2 -Ξ΄ = 0.1 -k = 0.1 -threshold = 50 -🧠 12. Mesa-LLM Integration (Advanced) -Farmer Reasoning Prompt -You are a farmer. - -Rain forecast: LOW -Neighbors suggest: plant early -Trust level: medium - -Decide: -- planting time -- fertilizer usage -- whether to follow forecast -Available Tools -listen_radio -talk_to_neighbor -apply_fertilizer -plant_crop -πŸš€ 13. Extensions -πŸ”Ή Policy Simulation -Subsidies β†’ increase adoption -Training β†’ increase trust -πŸ”Ή Climate Change -Increased rainfall variability -Forecast uncertainty -πŸ”Ή Economic Layer -profit = yield * price - cost -⚠️ 14. Assumptions -Single crop (maize) -Fixed land size -No market dynamics (optional) -Simplified crop model (DSSAT-inspired) -⭐ 15. Why This is GSoC-Level -βœ” Hybrid system (social + environmental) -βœ” Behaviorally realistic agents -βœ” Learning + feedback loops -βœ” Scalable architecture -i want a complete readme.md file - -Here’s a polished, complete README.md you can directly use for your repo / GSoC proposal: - -πŸŒΎπŸš€ AgriCast-ABM -Farmer Decision & Crop Productivity Model (Mesa + Mesa-LLM) -🧠 Overview - -AgriCast-ABM is an Agent-Based Model (ABM) that simulates how farmers make agricultural decisions under uncertain weather conditions. - -The system models the full decision pipeline: - -Weather Forecast β†’ Information Flow β†’ Farmer Decisions β†’ Crop Yield β†’ Learning β†’ Adoption - -It combines: - -🌦️ Environmental simulation (weather + crops) -πŸ‘¨β€πŸŒΎ Human decision-making (farmers) -🌐 Social interaction (networks, extension agents) -🧠 Learning & adaptation (trust + LTA) -πŸ€– Optional LLM-driven reasoning (Mesa-LLM) -🧱 Architecture -AgriCastModel -β”‚ -β”œβ”€β”€ FarmerAgent (core decision-maker) -β”‚ -β”œβ”€β”€ Environment -β”‚ β”œβ”€β”€ WeatherSystem -β”‚ β”œβ”€β”€ CropEngine -β”‚ -β”œβ”€β”€ Information Layer -β”‚ β”œβ”€β”€ Radio (global broadcast) -β”‚ β”œβ”€β”€ Extension Agents -β”‚ β”œβ”€β”€ Farmer Network (graph-based) -β”‚ -β”œβ”€β”€ Decision Engine (rule-based / LLM) -β”œβ”€β”€ Adoption Engine (LTA model) -β”œβ”€β”€ Data Collector -πŸ‘¨β€πŸŒΎ Agents -πŸ”Ή FarmerAgent (Core Entity) -Attributes -unique_id -pos - -# socio-economic -land_size -wealth -education_level -risk_aversion - -# trust system -trust_radio -trust_neighbors -trust_extension - -# adoption -LTA # Learning Trust Accumulation (0–100) -adopt_forecast # Boolean - -# farming decisions -planting_time # early / normal / late -fertilizer -pesticide -tillage - -# outputs -yield_output -profit - -# memory -past_yields (list) -πŸ”„ Behavior (Per Step) -1. Receive forecast -2. Interact with neighbors -3. Update trust -4. Update LTA -5. Decide adoption (probabilistic) -6. Choose farming strategy -7. Compute yield -8. Update memory -9. Learn (feedback) -πŸ“‘ Information Sources -πŸ“» Radio -Broadcasts weather forecast globally -Accuracy depends on system parameter -πŸ‘¨β€πŸ”¬ Extension Agents -High-trust advisory entities -Direct influence on farmers -🌐 Farmer Network -Graph-based (e.g., ErdΕ‘s–RΓ©nyi) -Enables peer-to-peer information diffusion -🌦️ Environment -WeatherSystem -rainfall ∈ {LOW, NORMAL, HIGH} -forecast_accuracy ∈ [0.6, 0.8] -Rainfall Values -LOW = 900 mm -NORMAL = 1300 mm -HIGH = 1900 mm -🌱 Crop Engine (Simplified DSSAT) -Yield Function -yield = -base_yield -Γ— rainfall_factor -Γ— planting_factor -Γ— fertilizer_factor -Γ— pesticide_factor -Γ— random(0.9, 1.1) -Factors -🌧️ Rainfall -LOW = 0.7 -NORMAL = 1.0 -HIGH = 1.2 -🌱 Planting Strategy -early + high rain = 1.3 -late + low rain = 0.8 -else = 1.0 -πŸ§ͺ Fertilizer -fertilizer_factor = 1 + 0.3 * fertilizer_level -πŸ› Pesticide -pesticide_factor = 1 + 0.1 * pesticide_level -🧠 Adoption Model (LTA) -πŸ”Ή LTA Update -LTA_new = -clip( - LTA_old - + Ξ± * ( - trust_neighbor * info_neighbor + - trust_network * info_network + - trust_extension * info_extension + - trust_radio * info_radio - ) - + Ξ² * forecast_accuracy - - Ξ³ * uncertainty -, 0, 100) -πŸ”Ή Feedback Learning -LTA_new = LTA_old + Ξ΄ * (yield - expected_yield) -πŸ”Ή Trust Update -if forecast_correct: - trust_radio += 0.05 -else: - trust_radio -= 0.1 -🎯 Adoption Decision -Probability Function -P_adopt = 1 / (1 + e^(-k*(LTA - threshold))) -Final Decision -if random.random() < P_adopt: - adopt = True -🌐 Interaction System -Neighbor Interaction -neighbors = grid.get_neighbors(pos, radius=r) -Network Interaction -network = nx.erdos_renyi_graph(n, p) -Information Aggregation -info = weighted average of all sources -πŸ” Simulation Loop -def step(): - - # 1. Weather update - update_weather() - - # 2. Information spread - for farmer: - gather_information() - - # 3. LTA update - for farmer: - update_LTA() - - # 4. Decision - for farmer: - decide_adoption() - - # 5. Farming actions - for farmer: - choose_strategy() - - # 6. Crop simulation - for farmer: - compute_yield() - - # 7. Learning - for farmer: - update_memory() - - # 8. Data collection - collect_metrics() -πŸ“Š Metrics -Core Metrics -average_yield -total_yield -adoption_rate -Advanced Metrics -food_security_index -information_spread_rate -trust_distribution -yield_variance -βš™οΈ Parameters -Global Parameters -NUM_FARMERS -GRID_SIZE -FORECAST_ACCURACY -INTERACTION_RADIUS -NETWORK_PROB -Model Constants -Ξ± = 0.5 -Ξ² = 0.3 -Ξ³ = 0.2 -Ξ΄ = 0.1 -k = 0.1 -threshold = 50 -πŸ€– Mesa-LLM Extension (Advanced) -Farmer Reasoning Prompt -You are a farmer. - -Rain forecast: LOW -Neighbors suggest: plant early -Trust level: medium - -Decide: -- planting time -- fertilizer usage -- whether to follow forecast -Tools -listen_radio -talk_to_neighbor -apply_fertilizer -plant_crop -πŸš€ Extensions -πŸ›οΈ Policy Simulation -subsidy β†’ increases adoption -training β†’ increases trust -🌍 Climate Change -increase rainfall variability -πŸ’° Economic Layer -profit = yield * price - cost -⚠️ Assumptions -- Single crop (maize) -- Fixed land size -- No market dynamics (optional) -- Simplified crop model -⭐ Why This is GSoC-Level -βœ” Hybrid system (social + environmental) -βœ” Incorporates learning & feedback loops -βœ” Realistic farmer behavior modeling -βœ” Scalable & modular architecture -βœ” Supports both rule-based and LLM-driven agents -🏁 Summary -Farmers receive information -β†’ interact socially -β†’ update beliefs (LTA) -β†’ make decisions -β†’ affect yield -β†’ learn from outcomes -β†’ system evolves -πŸš€ Next Steps - -You can extend this project by: - -Implementing Mesa simulation (model.py, agent.py) -Adding LLM agents (Mesa-LLM) -Building a UI with Solara -Running policy experiments -Publishing results - -If you want, I can now generate: - -πŸ‘‰ Full working code (agent.py, model.py, app.py) -πŸ‘‰ Or a GSoC proposal draft based on this README - -We use cookies - -We use cookies to help this site function, understand service usage, and support marketing efforts. Visit Manage Cookies to change preferences anytime. View our Cookie Policy for more info. \ No newline at end of file +## Summary + +This model simulates how farmers make agricultural decisions under uncertainty such as rainfall variability, market prices, and social influence. + +Farmer agents are placed on a grid and manage their land over a growing season. Each farmer decides when to plant, apply fertilizer, and harvest crops. These decisions directly impact yield and profit. + +The model incorporates environmental factors such as rainfall conditions (low, normal, high) and economic factors such as crop market prices. Additionally, farmers can observe neighboring agents, introducing social influence into decision-making. + +This model is implemented using **Mesa-LLM**, meaning agents are capable of reasoning and tool usage rather than relying purely on fixed rules. Farmers can dynamically decide actions like planting or waiting based on context. + +--- + +## Technical Details + +The **Agriculture Decision Model** simulates farming behavior using a population of **Farmer agents**. + +Each **FarmerAgent** is characterized by: + +- `land_size` +- `wealth` +- `education_level` +- `crop_type` (wheat, rice, maize) +- `fertilizer` level +- `crop_state` +- `yield_output` +- `profit` + +--- + +### Crop Lifecycle + +Each farmer follows a simplified crop lifecycle: +``` bash REST β†’ PLANTED β†’ READY β†’ HARVESTED β†’ REST +``` + +--- + +### Yield Function + +Crop yield depends on rainfall and fertilizer usage: +``` bash +yield = base_yield Γ— rainfall_factor Γ— fertilizer_factor + +Where: + +- `rainfall_factor` depends on environmental condition (LOW / NORMAL / HIGH) +- `fertilizer_factor` increases yield when fertilizer is applied + +``` + +### Profit Calculation +``` bash profit = yield Γ— market_price + +Where: + +- `market_price` depends on crop type + +``` + +### Environment + +- The model uses a **MultiGrid** environment +- Time progresses in **daily steps** +- Each simulation runs for ~120 days (one farming season) + +--- + +### Farmer Behavior + +Each Farmer agent: + +1. Observes: + - Rainfall condition + - Current crop state + - Neighbor behavior + +2. Decides: + - Plant crop + - Apply fertilizer + - Harvest + - Wait + +3. Executes actions using tools + +--- + +### Tools + +Farmer agents use tool-based actions: + +- `plant_crop` β†’ plants crop and sets harvest date +- `apply_fertilizer` β†’ increases yield potential +- `harvest_crop` β†’ harvests when ready + +--- + +### LLM-Powered Agents + +Farmers are implemented as **LLM agents**, meaning: + +- Decisions are generated via a reasoning module +- Agents use: + - Internal state (wealth, crop, etc.) + - Observations (environment + neighbors) + - Available tools + +This allows: + +- Context-aware decision making +- Adaptive strategies +- Non-deterministic behavior + +--- + +## How to Run + +If you have cloned the repo into your local machine, ensure you run the following command from the root of the library: +``` bash pip install -e . +``` + +Then, set up your LLM API key. + +### Setup Steps + +1. Install dotenv if not already installed: +pip install python-dotenv +Copy code + +2. Create a `.env` file in the root directory + +3. Add your API key: + +For OpenAI: +``` python OPENAI_API_KEY=your-api-key +``` + + +For Gemini: +``` python GEMINI_API_KEY=your-api-key +``` + +4. In `app.py`, set: +``` python +- `llm_model = "openai/gpt-4o-mini"` (or your model) +``` + +--- + +### Run the Model +``` python +solara run app.py +``` + + +Open in browser: +``` bash http://localhost:8765⁠� +``` +--- + +## Files + +- `model.py` β†’ Core simulation logic +- `agent.py` β†’ Farmer agent definition +- `tools.py` β†’ Actions available to agents +- `app.py` β†’ Visualization and UI + +--- + +## Metrics + +The model tracks: + +- **Total Yield** +- **Average Profit** +- **Crop Distribution** + +--- + +## Further Reading + +This model is inspired by: + +> [Agent-Based Modeling in Agricultural Productivity in Rural Area of Bahir Dar](https://www.mdpi.com/2571-9394/4/1/20) + +Related work on Agent-Based Modeling in agriculture: + +- Agent-based crop decision models +- Climate adaptation simulations +- Socio-environmental systems + +--- + +## Notes + +- This model simplifies crop growth dynamics +- Focus is on **decision-making behavior**, not full biological simulation +- Can be extended with: + - Climate models + - Policy interventions + - Multi-season dynamics + From 63f93fb3a1f95207fb38425644913454db815c0a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 23 Mar 2026 15:16:48 +0000 Subject: [PATCH 4/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- examples/agriculture_model/__init__.py | 2 +- examples/agriculture_model/agent.py | 2 -- examples/agriculture_model/app.py | 13 +++++--- examples/agriculture_model/model.py | 6 ++-- examples/agriculture_model/readme.md | 42 +++++++++++++------------- examples/agriculture_model/tools.py | 4 +-- 6 files changed, 34 insertions(+), 35 deletions(-) diff --git a/examples/agriculture_model/__init__.py b/examples/agriculture_model/__init__.py index a78585511..ec2ef8e0f 100644 --- a/examples/agriculture_model/__init__.py +++ b/examples/agriculture_model/__init__.py @@ -1 +1 @@ -import examples.agriculture_model.tools \ No newline at end of file +import examples.agriculture_model.tools diff --git a/examples/agriculture_model/agent.py b/examples/agriculture_model/agent.py index ca5a74dea..fbc7e7ee2 100644 --- a/examples/agriculture_model/agent.py +++ b/examples/agriculture_model/agent.py @@ -129,5 +129,3 @@ def step(self): self.update_crop_state() self.decide() self.update_crop_state() - - diff --git a/examples/agriculture_model/app.py b/examples/agriculture_model/app.py index 546f47247..fdbfbb590 100644 --- a/examples/agriculture_model/app.py +++ b/examples/agriculture_model/app.py @@ -2,14 +2,17 @@ import warnings from dotenv import load_dotenv -from mesa.visualization import SolaraViz, Slider, make_plot_component, make_space_component - -from mesa_llm.parallel_stepping import enable_automatic_parallel_stepping -from mesa_llm.reasoning.react import ReActReasoning +from mesa.visualization import ( + Slider, + SolaraViz, + make_plot_component, + make_space_component, +) from examples.agriculture_model.agent import CropState, FarmerAgent from examples.agriculture_model.model import FarmerModel - +from mesa_llm.parallel_stepping import enable_automatic_parallel_stepping +from mesa_llm.reasoning.react import ReActReasoning warnings.filterwarnings( "ignore", diff --git a/examples/agriculture_model/model.py b/examples/agriculture_model/model.py index 46291a1b1..579b994b1 100644 --- a/examples/agriculture_model/model.py +++ b/examples/agriculture_model/model.py @@ -1,15 +1,13 @@ from datetime import datetime, timedelta -import random + from mesa import Model from mesa.datacollection import DataCollector from mesa.space import MultiGrid +from examples.agriculture_model.agent import CropState, FarmerAgent from mesa_llm.reasoning.reasoning import Reasoning -from mesa_llm.reasoning.react import ReActReasoning from mesa_llm.recording.record_model import record_model -from examples.agriculture_model.agent import CropState, FarmerAgent - @record_model(output_dir="recordings") class FarmerModel(Model): diff --git a/examples/agriculture_model/readme.md b/examples/agriculture_model/readme.md index ebceb7974..0dc4ec040 100644 --- a/examples/agriculture_model/readme.md +++ b/examples/agriculture_model/readme.md @@ -38,7 +38,7 @@ Each farmer follows a simplified crop lifecycle: ### Yield Function Crop yield depends on rainfall and fertilizer usage: -``` bash +``` bash yield = base_yield Γ— rainfall_factor Γ— fertilizer_factor Where: @@ -88,10 +88,10 @@ Each Farmer agent: Farmer agents use tool-based actions: -- `plant_crop` β†’ plants crop and sets harvest date -- `apply_fertilizer` β†’ increases yield potential -- `harvest_crop` β†’ harvests when ready - +- `plant_crop` β†’ plants crop and sets harvest date +- `apply_fertilizer` β†’ increases yield potential +- `harvest_crop` β†’ harvests when ready + --- ### LLM-Powered Agents @@ -106,9 +106,9 @@ Farmers are implemented as **LLM agents**, meaning: This allows: -- Context-aware decision making -- Adaptive strategies -- Non-deterministic behavior +- Context-aware decision making +- Adaptive strategies +- Non-deterministic behavior --- @@ -147,7 +147,7 @@ For Gemini: --- ### Run the Model -``` python +``` python solara run app.py ``` @@ -159,10 +159,10 @@ Open in browser: ## Files -- `model.py` β†’ Core simulation logic -- `agent.py` β†’ Farmer agent definition -- `tools.py` β†’ Actions available to agents -- `app.py` β†’ Visualization and UI +- `model.py` β†’ Core simulation logic +- `agent.py` β†’ Farmer agent definition +- `tools.py` β†’ Actions available to agents +- `app.py` β†’ Visualization and UI --- @@ -184,18 +184,18 @@ This model is inspired by: Related work on Agent-Based Modeling in agriculture: -- Agent-based crop decision models -- Climate adaptation simulations -- Socio-environmental systems +- Agent-based crop decision models +- Climate adaptation simulations +- Socio-environmental systems --- ## Notes -- This model simplifies crop growth dynamics -- Focus is on **decision-making behavior**, not full biological simulation +- This model simplifies crop growth dynamics +- Focus is on **decision-making behavior**, not full biological simulation - Can be extended with: - - Climate models - - Policy interventions - - Multi-season dynamics + - Climate models + - Policy interventions + - Multi-season dynamics diff --git a/examples/agriculture_model/tools.py b/examples/agriculture_model/tools.py index f1b5419b6..63ffa8703 100644 --- a/examples/agriculture_model/tools.py +++ b/examples/agriculture_model/tools.py @@ -1,9 +1,8 @@ from datetime import timedelta +from examples.agriculture_model.agent import FARMER_TOOL_MANAGER, CropState from mesa_llm.tools.tool_decorator import tool -from examples.agriculture_model.agent import CropState, FARMER_TOOL_MANAGER - @tool(tool_manager=FARMER_TOOL_MANAGER) def plant_crop(agent, days_to_harvest: int = 60): @@ -59,6 +58,7 @@ def apply_fertilizer(agent, level: float = 0.5): agent.crop_state = CropState.GROWING return f"Fertilizer applied: {level}" + @tool(tool_manager=FARMER_TOOL_MANAGER) def harvest_crop(agent): """ From 27f4a08b048214c1ac742c05793371e2c67f6bf4 Mon Sep 17 00:00:00 2001 From: niteshver Date: Mon, 23 Mar 2026 21:25:44 +0530 Subject: [PATCH 5/6] fix model and finalize model --- examples/agriculture_model/agent.py | 14 ++++++++------ examples/agriculture_model/model.py | 6 ++---- examples/agriculture_model/tools.py | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/agriculture_model/agent.py b/examples/agriculture_model/agent.py index fbc7e7ee2..73e4c30ad 100644 --- a/examples/agriculture_model/agent.py +++ b/examples/agriculture_model/agent.py @@ -37,11 +37,11 @@ def __init__( ) self.tool_manager = FARMER_TOOL_MANAGER - self.land_size = random.randint(1, 5) - self.wealth = random.randint(1000, 50000) + self.land_size = self.random.randint(1, 5) + self.wealth = self.random.randint(1000, 50000) self._base_internal_state = list(self.internal_state) - self.crop_type = random.choice(["wheat", "rice", "maize"]) + self.crop_type = self.random.choice(["wheat", "rice", "maize"]) self.crop_state = CropState.IDLE self.plant_date = None @@ -53,7 +53,7 @@ def __init__( self.memory = STLTMemory( agent=self, - llm_model="ollama/llama3.1:latest", + llm_model=llm_model, display=True, ) @@ -118,11 +118,13 @@ def compute_yield(self): rain_factor = 1.0 fert_factor = 1 + 0.3 * self.fertilizer - noise = random.uniform(0.9, 1.1) + noise = self.random.uniform(0.9, 1.1) + + self.profit = 0 self.yield_output = base_yield * rain_factor * fert_factor * noise price = self.model.market_price[self.crop_type] - self.profit = self.yield_output * price + self.profit += self.yield_output * price def step(self): self.observe_environment() diff --git a/examples/agriculture_model/model.py b/examples/agriculture_model/model.py index 579b994b1..c99581815 100644 --- a/examples/agriculture_model/model.py +++ b/examples/agriculture_model/model.py @@ -104,8 +104,6 @@ def __init__( } ) - # self.running = True - # self.datacollector.collect(self) def _normalize_rainfall(self, rainfall: float | str | None) -> str: if isinstance(rainfall, str): @@ -127,8 +125,8 @@ def step(self): self.agents.shuffle_do("step") self.datacollector.collect(self) - # if (self.current_day - self.start_date).days > 120: - # self.running = False + if (self.current_day - self.start_date).days >= 120: + self.running = False if __name__ == "__main__": diff --git a/examples/agriculture_model/tools.py b/examples/agriculture_model/tools.py index 63ffa8703..167df3c3e 100644 --- a/examples/agriculture_model/tools.py +++ b/examples/agriculture_model/tools.py @@ -50,8 +50,8 @@ def apply_fertilizer(agent, level: float = 0.5): raise ValueError(f"level must be numeric, got {level!r}") from exc if level < 0: raise ValueError("level must be non-negative") - if agent.crop_state == CropState.IDLE: - return "No crop planted" + if agent.crop_state in [CropState.IDLE, CropState.READY]: + return "Cannot apply fertilizer at this stage" agent.fertilizer += level if agent.crop_state == CropState.PLANTED: From a53b830960baa7c225b2019dbde92d3ce2fdbd5b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 23 Mar 2026 15:56:01 +0000 Subject: [PATCH 6/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- examples/agriculture_model/agent.py | 1 - examples/agriculture_model/model.py | 3 +-- examples/agriculture_model/tools.py | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/agriculture_model/agent.py b/examples/agriculture_model/agent.py index 73e4c30ad..018070093 100644 --- a/examples/agriculture_model/agent.py +++ b/examples/agriculture_model/agent.py @@ -1,4 +1,3 @@ -import random from enum import Enum from mesa_llm.llm_agent import LLMAgent diff --git a/examples/agriculture_model/model.py b/examples/agriculture_model/model.py index c99581815..fc3d0201f 100644 --- a/examples/agriculture_model/model.py +++ b/examples/agriculture_model/model.py @@ -104,7 +104,6 @@ def __init__( } ) - def _normalize_rainfall(self, rainfall: float | str | None) -> str: if isinstance(rainfall, str): rainfall_upper = rainfall.upper() @@ -126,7 +125,7 @@ def step(self): self.datacollector.collect(self) if (self.current_day - self.start_date).days >= 120: - self.running = False + self.running = False if __name__ == "__main__": diff --git a/examples/agriculture_model/tools.py b/examples/agriculture_model/tools.py index 167df3c3e..0feca8610 100644 --- a/examples/agriculture_model/tools.py +++ b/examples/agriculture_model/tools.py @@ -51,7 +51,7 @@ def apply_fertilizer(agent, level: float = 0.5): if level < 0: raise ValueError("level must be non-negative") if agent.crop_state in [CropState.IDLE, CropState.READY]: - return "Cannot apply fertilizer at this stage" + return "Cannot apply fertilizer at this stage" agent.fertilizer += level if agent.crop_state == CropState.PLANTED: