Ants GPT: OpenAI LLM and rule based agents
Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)
CREDITS AND REFERENCES
If you mention this model in a publication, we ask that you include these citations for the model itself and for the NetLogo software:
Cristian Jimenez-Romero, Alper Yegenoglu, Christian Blum Multi-Agent Systems Powered By Large Language Models: Applications In Swarm Intelligence. In ArXiv Pre-print, March 2025.
Wilensky, U. (1999). NetLogo. http://ccl.northwestern.edu/netlogo/. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
Comments and Questions
;; AntGPT Colony - Hybrid LLM - Rule-based agents ;; Author: Cristian Jimenez Romero - 2025 extensions [ py ] patches-own [ chemical ;; amount of chemical on this patch food ;; amount of food on this patch (0, 1, or 2) nest? ;; true on nest patches, false elsewhere nest-scent ;; number that is higher closer to the nest food-source-number ;; number (1, 2, or 3) to identify the food sources ] globals [ is-stopped? ; flag to specify if the model is stopped food_collected all-food-amounts activate_llm ] breed [ants ant] ants-own [ ant-id action-move_forward ;; amount of chemical on this patch action-rotate ;; amount of food on this patch (0, 1, or 2) action-pick_up_food ;; true on nest patches, false elsewhere action-drop_pheromone ;; number that is higher closer to the nest action-drop_food ;; number (1, 2, or 3) to identify the food sources action-status-ok action-status-code sense-pheromone-left sense-pheromone-front sense-pheromone-right sense-on-nest sense-nest-left sense-nest-front sense-nest-right sense-food-quantity sense-carrying-food recovered_ant_data_move recovered_ant_data_rotate_r recovered_ant_data_rotate_l recovered_ant_data_random_l recovered_ant_data_random_r recovered_ant_data_pick_up_food recovered_ant_data_drop_pheromone recovered_ant_data_drop_food food_pickup_time food_drop_time food_from_source steps_searching ] to setup-patches ask patches [ setup-nest setup-food recolor-patch ] end to setup-nest ;; patch procedure ;; set nest? variable to true inside the nest, false elsewhere set nest? (distancexy 0 0) < 5 ;; spread a nest-scent over the whole world -- stronger near the nest set nest-scent 200 - distancexy 0 0 end to setup-food-test ;; patch procedure set food_collected 0 ;; setup food source one on the right if (distancexy (0.6 * max-pxcor) 9) < 4 [ set food-source-number 1 ] ;; setup food source two on the lower-left if (distancexy (-0.6 * max-pxcor) (-0.6 * max-pycor)) < 4 [ set food-source-number 2 ] ;; setup food source three on the upper-left if (distancexy (-0.8 * max-pxcor) (0.8 * max-pycor)) < 4 [ set food-source-number 3 ] ;; set "food" at sources to either 1 or 2, randomly if food-source-number > 0 [ set food one-of [1 2] ] end to setup-food ;; patch procedure ;; setup food source one on the right if (distancexy (0.6 * max-pxcor) 0) < 5 [ set food-source-number 1 ] ;; setup food source two on the lower-left if (distancexy (-0.6 * max-pxcor) (-0.6 * max-pycor)) < 5 [ set food-source-number 2 ] ;; setup food source three on the upper-left if (distancexy (-0.8 * max-pxcor) (0.8 * max-pycor)) < 5 [ set food-source-number 3 ] ;; set "food" at sources to either 1 or 2, randomly if food-source-number > 0 [ set food one-of [1 2] ] end to recolor-patch ;; patch procedure ;; give color to nest and food sources ifelse nest? [ set pcolor violet ] [ ifelse food > 0 [ if food-source-number = 1 [ set pcolor cyan ] if food-source-number = 2 [ set pcolor sky ] if food-source-number = 3 [ set pcolor blue ] ] ;; scale color to show chemical concentration [ set pcolor scale-color green chemical 0.1 5 ] ] end to setup_ants clear-all set activate_llm true random-seed read-from-string used_seed; 21504; 6890;351973;19562;47822 set-default-shape turtles "bug" create-ants 10 [ set ant-id who set sense-carrying-food "False" set size 2 set color red set food_pickup_time 0 set food_drop_time 0 set food_from_source 0 ] setup-patches set all-food-amounts [] reset-ticks end to export-food-collected-to-csv [filename] ; Open the file for writing. The file will be saved in the current directory. file-open filename ; Write header row to the CSV file file-print "step_number,food_amount" ; Iterate over each step in all-distances let step-count length all-food-amounts let step-number 0 repeat step-count [ let step-data item step-number all-food-amounts file-print (word step-number "," step-data) set step-number step-number + 1 ] ; Close the file after writing is done file-close end to setup setup_ants py:setup py:python py:run "import math" py:run "import sys" py:run "import json" py:run "from openai import OpenAI" py:run "client = OpenAI(api_key='Insert your API key here')" py:run "elements_list = []" (py:run "def parse_response(response):" " text = response" " text = text.lower()" " text = text.strip()" " text = text.replace(chr(39), chr(34))" " text = text.replace('_', '-')" " parse_ok = 'True'" " error_code = 'None'" " try:" " index = text.find('{')" " text = text[index:]" " index = text.find('}')" " text = text[:index + 1]" " print ('pre-processed-text: *****', text, '*****')" " text = json.loads(text)" " move_forward = text['move-forward']" " move_forward = str(move_forward)" " rotate = text['rotate']" " rotate = str(rotate)" " pick_up_food = text['pick-up-food']" " pick_up_food = str(pick_up_food)" " drop_pheromone = text['drop-pheromone']" " drop_pheromone = str(drop_pheromone)" " drop_food = text['drop-food']" " drop_food = str(drop_food)" " elements_list.append(parse_ok)" " elements_list.append(error_code)" " elements_list.append(move_forward.lower())" " elements_list.append(rotate.lower())" " elements_list.append(pick_up_food.lower())" " elements_list.append(drop_pheromone.lower())" " elements_list.append(drop_food.lower())" " print('Parsed ok: ', elements_list)" " except json.JSONDecodeError as e:" " error_code = str(e)" " parse_ok = 'False'" " elements_list.append(parse_ok)" " elements_list.append(error_code)" " print ('Error: ', error_code)" " except Exception as e:" " error_code = str(e)" " parse_ok = 'False'" " elements_list.append(parse_ok)" " elements_list.append(error_code)" " print ('Error: ', error_code)" "def create_prompt(sense_pheromone_left, sense_pheromone_front, sense_pheromone_right, sense_on_nest, sense_nest_left, sense_nest_front, sense_nest_right, sense_food_quantity, sense_carrying_food):" " sense_pheromone_left = float(sense_pheromone_left)" " sense_pheromone_front = float(sense_pheromone_front)" " sense_pheromone_right = float(sense_pheromone_right)" " sense_nest_left = float(sense_nest_left)" " sense_nest_front = float(sense_nest_front)" " sense_nest_right = float(sense_nest_right)" " if sense_on_nest.lower() == 'false':" " on_nest_text = '**False** (You are not currently at the nest)'" " else:" " on_nest_text = '**True** (You are currently at the nest)'" " if sense_carrying_food.lower() == 'false':" " carrying_food_text = '**False** (You are not currently carrying food)'" " else:" " carrying_food_text = '**True** (You are currently carrying food)'" " if sense_pheromone_left > sense_pheromone_front and sense_pheromone_left > sense_pheromone_right:" " pheromone_text = 'Left'" " elif sense_pheromone_right > sense_pheromone_front and sense_pheromone_right > sense_pheromone_left:" " pheromone_text = 'Right'" " elif sense_pheromone_front > 0 and (sense_pheromone_front >= sense_pheromone_right or sense_pheromone_front >= sense_pheromone_left):" " pheromone_text = 'Front'" " else:" " pheromone_text = 'None'" " if sense_nest_left > sense_nest_front and sense_nest_left > sense_nest_right:" " nest_text = 'Left'" " elif sense_nest_right > sense_nest_front and sense_nest_right > sense_nest_left:" " nest_text = 'Right'" " else:" " nest_text = 'Front'" " system_text = 'You are an ant in a 2D simulation. Your task is to pick up food and release it at the nest. Release pheromone on food source and while you are carrying food. Use nest scent to navigate back to the nest only when carrying food, prioritizing nest scent over pheromones. Use highest pheromone scent to navigate to food when not carrying any. Move away from nest and rotate randomly if you are not carrying any food and you are not sensing any pheromone. Format your actions as a Python dictionary with these keys and options: ' + chr(34) + 'move-forward' + chr(34) + ' (options: True, False), ' + chr(34) + 'rotate' + chr(34) + ' (options: ' + chr(34) + 'left'+ chr(34) + ', '+ chr(34) + 'right' + chr(34)+ ', ' + chr(34) + 'none' + chr(34) + ', ' + chr(34) + 'random' + chr(34) + ' ), ' + chr(34) + 'pick-up-food' + chr(34) + ' (options: True, False), ' + chr(34) + 'drop-pheromone' + chr(34) + ' (options: True, False), ' + chr(34) + 'drop-food' + chr(34) + ' (options: True, False). You will be provided with environment information. Keep your response concise, under 45 tokens.'" " prompt_text = 'This is your current environment: -Highest Pheromone Concentration: ' + pheromone_text + ', -Nest Presence: ' + on_nest_text + ', -Stronger Nest Scent: ' + nest_text + ', -Food Concentration at your location: ' + sense_food_quantity + ', -Carrying Food Status ' + carrying_food_text " " return prompt_text, system_text" "def process_step(file_name, step):" " # Open the text file" " with open(file_name, 'r') as file:" " lines = file.readlines()" " # Initialize variables" " in_step_section = False" " in_ant_section = False" " actions_list = []" " ant_info = {}" " # Iterate through the lines" " for line in lines:" " # Check for the start of the step section" " if line.strip() == f'step: {step}':" " in_step_section = True" " continue" " # Check for the end of the step section" " if line.strip() == 'end step':" " if in_step_section:" " break" " else:" " continue" " # If we are in the correct step section, look for ant sections" " if in_step_section:" " if line.startswith('Start-AntID:'):" " in_ant_section = True" " ant_id = line.split(':')[1].strip()" " # Initialize variables for the new ant" " ant_info = {" " 'AntID': ant_id," " 'move': False," " 'rotate_right': False," " 'rotate_left': False," " 'rotate_random_l': False," " 'rotate_random_r': False," " 'pick_up_food': False," " 'drop_pheromone': False," " 'drop_food': False," " 'action_ok': False" " }" " continue" " if line.startswith('End-AntID:'):" " end_ant_id = line.split(':')[1].strip()" " if in_ant_section and end_ant_id == ant_info['AntID']:" " in_ant_section = False" " # Add the ant_info to actions_list as a list of its values" " actions_list.append([" " ant_info['AntID']," " ant_info['action_ok']," " ant_info['move']," " ant_info['rotate_right']," " ant_info['rotate_left']," " ant_info['rotate_random_l']," " ant_info['rotate_random_r']," " ant_info['pick_up_food']," " ant_info['drop_pheromone']," " ant_info['drop_food']" " ])" " continue" " # If we are in the correct ant section, check for the required texts" " if in_ant_section:" " if 'Parser ok' in line:" " ant_info['action_ok'] = True" " if '--- action move' in line:" " ant_info['move'] = True" " if '--- action rotate-right' in line:" " ant_info['rotate_right'] = True" " if '--- action rotate-left' in line:" " ant_info['rotate_left'] = True" " if '--- action rotate-random-l' in line:" " ant_info['rotate_random_l'] = True" " if '--- action rotate-random-r' in line:" " ant_info['rotate_random_r'] = True" " if '--- action pick-up-food' in line:" " ant_info['pick_up_food'] = True" " if '--- action drop-pheromone' in line:" " ant_info['drop_pheromone'] = True" " if '--- action drop-food' in line:" " ant_info['drop_food'] = True" " # Return the actions list" " return actions_list " ) end to-report get_llm_data let llm_data py:runresult "elements_list" report llm_data end to-report populate_ant_with_llm_data [ llm_data ] let parse_ok item 0 llm_data let return_ok true ifelse parse_ok = "True" [ print "Parser ok" set action-move_forward item 2 llm_data set action-rotate item 3 llm_data set action-pick_up_food item 4 llm_data set action-drop_pheromone item 5 llm_data set action-drop_food item 6 llm_data set action-status-ok true set action-status-code 0 if action-pick_up_food = "true" [ print "--- action pick-up-food" if food > 0 and sense-carrying-food != "True" [ set food food - 1 set sense-carrying-food "True" set color green ] ] if action-move_forward = "true" [ print "--- action move" ifelse not can-move? ant_speed [ rt 180 ][fd ant_speed] ] ifelse action-rotate != "none" [ ifelse action-rotate = "right" [ rt rotation-ang print "--- action rotate-right" ] [ ifelse action-rotate = "left" [ rt -1 * rotation-ang print "--- action rotate-left" ] [ ifelse action-rotate = "180deg" [ rt -180 print "--- action rotate-180deg" ] [ ifelse ( random 10 ) > 4 [ rt rotation-ang / 2 fd 0 print "--- action rotate-random-r" ][ rt -1 * rotation-ang / 2 fd 0 print "--- action rotate-random-l" ] ] ] ] ] [ print "--- action rotate-none" ] if action-drop_pheromone = "true" [ print "--- action drop-pheromone" set chemical chemical + 60 ] if action-drop_food = "true" [ print "--- action drop-food" if sense-carrying-food = "True" and nest? [ set sense-carrying-food "False" set food_collected food_collected + 1 set color red ] ] ] [ print "Parser error" set action-status-ok false set action-status-code 1 set return_ok false ] print "end parser" report return_ok end to run_llm print (word "Start-AntID: " ant-id) let populate_prompt (word "prepared_prompt, system_prompt = create_prompt('" sense-pheromone-left "', '" sense-pheromone-front "','" sense-pheromone-right "','" sense-on-nest "','" sense-nest-left "','" sense-nest-front "','" sense-nest-right "','" sense-food-quantity "','" sense-carrying-food "')" ) py:run populate_prompt py:run "elements_list = []" py:run "print('User prompt: ' + prepared_prompt)" py:run "print('Complete prompt: ' + system_prompt + prepared_prompt)" py:run "response = client.chat.completions.create(model= 'gpt-4o-2024-08-06', timeout=15, max_tokens=500, messages=[ {'role': 'system', 'content': system_prompt}, {'role': 'user', 'content': prepared_prompt}], temperature=0.1)" py:run "response = response.choices[0].message.content" py:run "parse_response(response)" print "--------------- llm data: ----------------" let llm_data get_llm_data let populate_ok populate_ant_with_llm_data llm_data print (word "End-AntID: " ant-id) end to-report nest-scent-at-angle-llm [angle] let p patch-right-and-ahead angle 2 ;2 if p = nobody [ report 0 ] report [nest-scent] of p end to-report nest-scent-at-angle [angle] let p patch-right-and-ahead angle 1 if p = nobody [ report 0 ] report [nest-scent] of p end to-report chemical-scent-at-angle [angle] let p patch-right-and-ahead angle 1 if p = nobody [ report 0 ] report [chemical] of p end to wiggle rt random 40 lt random 40 if not can-move? 1 [ rt 180 ] end to-report chemical-scent-at-angle-llm [angle] let p patch-right-and-ahead angle 1 ;1 if p = nobody [ report 0 ] let pchem [chemical] of p ifelse pchem > 5.0 [ set pchem 5.0 ] [ if pchem < 0.001 [ set pchem 0 ] ] report pchem end to-report food-in-front let p patch-ahead 1 if p = nobody [ report 0 ] report [food] of p end to sense-world ifelse nest? [ set sense-on-nest "True" ][ set sense-on-nest "False" ] set sense-pheromone-front ( word precision (chemical-scent-at-angle-llm 0) 2 ) set sense-pheromone-right ( word precision (chemical-scent-at-angle-llm 45) 2 ) set sense-pheromone-left ( word precision (chemical-scent-at-angle-llm -45) 2 ) set sense-nest-front ( word precision (nest-scent-at-angle-llm 0) 2 ) set sense-nest-right ( word precision (nest-scent-at-angle-llm 45) 2 ) set sense-nest-left ( word precision (nest-scent-at-angle-llm -45) 2 ) set sense-food-quantity (word food) ;food-in-front end to go_ants ;; forever button let step_text ( word "step: " ticks ) ask ants [ ifelse ant-id < 5 [ ;Ants 0 to 4 are steered by LLM ifelse activate_llm [ sense-world run_llm ] [ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if recovered_ant_data_pick_up_food = true [ if food > 0 and sense-carrying-food != "True" [ set food food - 1 set sense-carrying-food "True" set color green set food_pickup_time ticks set food_from_source food-source-number let food_text ( word food_from_source ", " steps_searching ) print food_text set steps_searching 0 ] ] if sense-carrying-food = "False" [ set steps_searching steps_searching + 1 ] if recovered_ant_data_move = true [ ifelse not can-move? ant_speed [ rt 180 ][fd ant_speed] ] if recovered_ant_data_rotate_r = true [ rt rotation-ang ] if recovered_ant_data_rotate_l = true [ rt -1 * rotation-ang ] if recovered_ant_data_random_l = true [ rt -1 * rotation-ang / 2 ; fd 2 let x ( random 10 ) ] if recovered_ant_data_random_r = true [ rt rotation-ang / 2 ; fd 2 let x ( random 10 ) ] if recovered_ant_data_drop_pheromone = true [ set chemical chemical + 60 ] if recovered_ant_data_drop_food = true [ if sense-carrying-food = "True" and nest? [ set sense-carrying-food "False" set food_collected food_collected + 1 set color red set food_drop_time ticks let food_return_duration food_drop_time - food_pickup_time ] ] ] ] [ ifelse color = red [ look-for-food ] ;; not carrying food? look for it [ return-to-nest ] ;; carrying food? take it back to nest wiggle fd 1 ] ] diffuse chemical (diffusion-rate / 100) ask patches [ set chemical chemical * (100 - evaporation-rate) / 100 ;; slowly evaporate chemical recolor-patch ] set all-food-amounts lput food_collected all-food-amounts tick end to return-to-nest ;; turtle procedure ifelse nest? [ ;; drop food and head out again set food_collected food_collected + 1 set color red rt 180 set food_drop_time ticks let food_return_duration food_drop_time - food_pickup_time ] [ set chemical chemical + 60 ;; drop some chemical uphill-nest-scent ] ;; head toward the greatest value of nest-scent end to look-for-food ;; turtle procedure if food > 0 [ set color orange + 1 ;; pick up food set food food - 1 ;; and reduce the food source rt 180 ;; and turn around set food_pickup_time ticks set food_from_source food-source-number let food_text ( word food_from_source ", " steps_searching ) print food_text set steps_searching 0 stop ] set steps_searching steps_searching + 1 ;; go in the direction where the chemical smell is strongest if (chemical >= 0.05) and (chemical < 2) [ uphill-chemical ] end ;; sniff left and right, and go where the strongest smell is to uphill-nest-scent ;; turtle procedure let scent-ahead nest-scent-at-angle 0 let scent-right nest-scent-at-angle 45 let scent-left nest-scent-at-angle -45 if (scent-right > scent-ahead) or (scent-left > scent-ahead) [ ifelse scent-right > scent-left [ rt 45 ] [ lt 45 ] ] end ;; sniff left and right, and go where the strongest smell is to uphill-chemical ;; turtle procedure let scent-ahead chemical-scent-at-angle 0 let scent-right chemical-scent-at-angle 45 let scent-left chemical-scent-at-angle -45 if (scent-right > scent-ahead) or (scent-left > scent-ahead) [ ifelse scent-right > scent-left [ rt 45 ] [ lt 45 ] ] end
There is only one version of this model, created 5 days ago by Cristian Jimenez Romero.
Attached files
File | Type | Description | Last updated | |
---|---|---|---|---|
Ants GPT: OpenAI LLM and rule based agents.png | preview | Preview for 'Ants GPT: OpenAI LLM and rule based agents' | 5 days ago, by Cristian Jimenez Romero | Download |
This model does not have any ancestors.
This model does not have any descendants.
Cristian Jimenez Romero
About Ants GPT:
This work examines the integration of large language models (LLMs) into multi-agent simulations by replacing the hard-coded programs of agents with LLM-driven prompts. The proposed approach is showcased in the context of two examples of complex systems from the field of swarm intelligence: ant colony foraging and bird flocking. Central to this study is a toolchain that integrates LLMs with the NetLogo simulation platform, leveraging its Python extension to enable communication with GPT-4o via the OpenAI API. This toolchain facilitates prompt-driven behavior generation, allowing agents to respond adaptively to environmental data. For both example applications mentioned above, we employ both structured, rule-based prompts and autonomous, knowledge-driven prompts. Our work demonstrates how this toolchain enables LLMs to study self-organizing processes and induce emergent behaviors within multi-agent environments, paving the way for new approaches to exploring intelligent systems and modeling swarm intelligence inspired by natural phenomena. We provide the code, including simulation files and data at: https://github.com/crjimene/swarm_gpt
Posted 5 days ago