Skip to main content
EDSL is an open-source library for simulating surveys, experiments and other research with AI agents and large language models. Before running the code below, please ensure that you have installed the EDSL library and either activated remote inference from your Coop account or stored API keys for the language models that you want to use with EDSL. Please also see our documentation page for tips and tutorials on getting started using EDSL.

Importing the data

Persona Hub: https://github.com/tencent-ailab/persona-hub
! pip install datasets
Collecting datasets
  Downloading datasets-3.5.0-py3-none-any.whl.metadata (19 kB)
Requirement already satisfied: filelock in /Users/johnhorton/Library/Caches/pypoetry/virtualenvs/edsl-EZo3_VAr-py3.11/lib/python3.11/site-packages (from datasets) (3.18.0)
Requirement already satisfied: numpy>=1.17 in /Users/johnhorton/Library/Caches/pypoetry/virtualenvs/edsl-EZo3_VAr-py3.11/lib/python3.11/site-packages (from datasets) (1.26.4)
Collecting pyarrow>=15.0.0 (from datasets)
  Using cached pyarrow-19.0.1-cp311-cp311-macosx_12_0_arm64.whl.metadata (3.3 kB)
Collecting dill<0.3.9,>=0.3.0 (from datasets)
  Downloading dill-0.3.8-py3-none-any.whl.metadata (10 kB)
Requirement already satisfied: pandas in /Users/johnhorton/Library/Caches/pypoetry/virtualenvs/edsl-EZo3_VAr-py3.11/lib/python3.11/site-packages (from datasets) (2.2.3)
Requirement already satisfied: requests>=2.32.2 in /Users/johnhorton/Library/Caches/pypoetry/virtualenvs/edsl-EZo3_VAr-py3.11/lib/python3.11/site-packages (from datasets) (2.32.3)
Requirement already satisfied: tqdm>=4.66.3 in /Users/johnhorton/Library/Caches/pypoetry/virtualenvs/edsl-EZo3_VAr-py3.11/lib/python3.11/site-packages (from datasets) (4.67.1)
Collecting xxhash (from datasets)
  Downloading xxhash-3.5.0-cp311-cp311-macosx_11_0_arm64.whl.metadata (12 kB)
Collecting multiprocess<0.70.17 (from datasets)
  Downloading multiprocess-0.70.16-py311-none-any.whl.metadata (7.2 kB)
Collecting fsspec<=2024.12.0,>=2023.1.0 (from fsspec[http]<=2024.12.0,>=2023.1.0->datasets)
  Downloading fsspec-2024.12.0-py3-none-any.whl.metadata (11 kB)
Requirement already satisfied: aiohttp in /Users/johnhorton/Library/Caches/pypoetry/virtualenvs/edsl-EZo3_VAr-py3.11/lib/python3.11/site-packages (from datasets) (3.11.16)
Collecting huggingface-hub>=0.24.0 (from datasets)
  Downloading huggingface_hub-0.30.2-py3-none-any.whl.metadata (13 kB)
Requirement already satisfied: packaging in /Users/johnhorton/Library/Caches/pypoetry/virtualenvs/edsl-EZo3_VAr-py3.11/lib/python3.11/site-packages (from datasets) (24.2)
Requirement already satisfied: pyyaml>=5.1 in /Users/johnhorton/Library/Caches/pypoetry/virtualenvs/edsl-EZo3_VAr-py3.11/lib/python3.11/site-packages (from datasets) (6.0.2)
Requirement already satisfied: aiohappyeyeballs>=2.3.0 in /Users/johnhorton/Library/Caches/pypoetry/virtualenvs/edsl-EZo3_VAr-py3.11/lib/python3.11/site-packages (from aiohttp->datasets) (2.6.1)
Requirement already satisfied: aiosignal>=1.1.2 in /Users/johnhorton/Library/Caches/pypoetry/virtualenvs/edsl-EZo3_VAr-py3.11/lib/python3.11/site-packages (from aiohttp->datasets) (1.3.2)
Requirement already satisfied: attrs>=17.3.0 in /Users/johnhorton/Library/Caches/pypoetry/virtualenvs/edsl-EZo3_VAr-py3.11/lib/python3.11/site-packages (from aiohttp->datasets) (25.3.0)
Requirement already satisfied: frozenlist>=1.1.1 in /Users/johnhorton/Library/Caches/pypoetry/virtualenvs/edsl-EZo3_VAr-py3.11/lib/python3.11/site-packages (from aiohttp->datasets) (1.5.0)
Requirement already satisfied: multidict<7.0,>=4.5 in /Users/johnhorton/Library/Caches/pypoetry/virtualenvs/edsl-EZo3_VAr-py3.11/lib/python3.11/site-packages (from aiohttp->datasets) (6.3.1)
Requirement already satisfied: propcache>=0.2.0 in /Users/johnhorton/Library/Caches/pypoetry/virtualenvs/edsl-EZo3_VAr-py3.11/lib/python3.11/site-packages (from aiohttp->datasets) (0.3.1)
Requirement already satisfied: yarl<2.0,>=1.17.0 in /Users/johnhorton/Library/Caches/pypoetry/virtualenvs/edsl-EZo3_VAr-py3.11/lib/python3.11/site-packages (from aiohttp->datasets) (1.18.3)
Requirement already satisfied: typing-extensions>=3.7.4.3 in /Users/johnhorton/Library/Caches/pypoetry/virtualenvs/edsl-EZo3_VAr-py3.11/lib/python3.11/site-packages (from huggingface-hub>=0.24.0->datasets) (4.13.0)
Requirement already satisfied: charset-normalizer<4,>=2 in /Users/johnhorton/Library/Caches/pypoetry/virtualenvs/edsl-EZo3_VAr-py3.11/lib/python3.11/site-packages (from requests>=2.32.2->datasets) (3.4.1)
Requirement already satisfied: idna<4,>=2.5 in /Users/johnhorton/Library/Caches/pypoetry/virtualenvs/edsl-EZo3_VAr-py3.11/lib/python3.11/site-packages (from requests>=2.32.2->datasets) (3.10)
Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/johnhorton/Library/Caches/pypoetry/virtualenvs/edsl-EZo3_VAr-py3.11/lib/python3.11/site-packages (from requests>=2.32.2->datasets) (1.26.20)
Requirement already satisfied: certifi>=2017.4.17 in /Users/johnhorton/Library/Caches/pypoetry/virtualenvs/edsl-EZo3_VAr-py3.11/lib/python3.11/site-packages (from requests>=2.32.2->datasets) (2025.1.31)
Requirement already satisfied: python-dateutil>=2.8.2 in /Users/johnhorton/Library/Caches/pypoetry/virtualenvs/edsl-EZo3_VAr-py3.11/lib/python3.11/site-packages (from pandas->datasets) (2.9.0.post0)
Requirement already satisfied: pytz>=2020.1 in /Users/johnhorton/Library/Caches/pypoetry/virtualenvs/edsl-EZo3_VAr-py3.11/lib/python3.11/site-packages (from pandas->datasets) (2025.2)
Requirement already satisfied: tzdata>=2022.7 in /Users/johnhorton/Library/Caches/pypoetry/virtualenvs/edsl-EZo3_VAr-py3.11/lib/python3.11/site-packages (from pandas->datasets) (2025.2)
Requirement already satisfied: six>=1.5 in /Users/johnhorton/Library/Caches/pypoetry/virtualenvs/edsl-EZo3_VAr-py3.11/lib/python3.11/site-packages (from python-dateutil>=2.8.2->pandas->datasets) (1.17.0)
Downloading datasets-3.5.0-py3-none-any.whl (491 kB)
Downloading dill-0.3.8-py3-none-any.whl (116 kB)
Downloading fsspec-2024.12.0-py3-none-any.whl (183 kB)
Downloading huggingface_hub-0.30.2-py3-none-any.whl (481 kB)
Downloading multiprocess-0.70.16-py311-none-any.whl (143 kB)
Using cached pyarrow-19.0.1-cp311-cp311-macosx_12_0_arm64.whl (30.7 MB)
Downloading xxhash-3.5.0-cp311-cp311-macosx_11_0_arm64.whl (30 kB)
Installing collected packages: xxhash, pyarrow, fsspec, dill, multiprocess, huggingface-hub, datasets
  Attempting uninstall: dill
    Found existing installation: dill 0.3.9
    Uninstalling dill-0.3.9:
      Successfully uninstalled dill-0.3.9
Successfully installed datasets-3.5.0 dill-0.3.8 fsspec-2024.12.0 huggingface-hub-0.30.2 multiprocess-0.70.16 pyarrow-19.0.1 xxhash-3.5.0

[notice] A new release of pip is available: 24.3.1 -> 25.0.1
[notice] To update, run: pip install --upgrade pip
try:
    from datasets import load_dataset
    ds = load_dataset("proj-persona/PersonaHub", "instruction")
    num_agents = 10
    personas_list = ds['train']['input persona'][:num_agents]
    personas_list
except ImportError:
    personas_list = ['A theater manager or events coordinator interested in understanding the operational aspects, facilities, and programming of performing arts centers, such as the Broward Center.',
 'An urban planner looking to understand the distribution and organization of public services in the Halifax Regional Municipality.',
 "A high school literature teacher looking for supplementary materials to enrich their curriculum and provide students with a deeper understanding of their state's cultural heritage.",
 'A science fiction writer, exploring the use of secret trials as a theme in stories that examine surveillance, privacy, and power dynamics in society.',
 'A financial analyst specializing in Asian markets and wealthy individuals, interested in tracking the investments and philanthropic activities of billionaires like Gerald Chan.',
 'A high school physics teacher who enjoys applying physics concepts to various sports, curious about the effects of water resistance and body positioning in Paralympic swimming.',
 'A high school physical education teacher seeking to incorporate Paralympic history and achievements into the curriculum to inspire and educate students about inclusivity in sports.',
 'A high school history teacher creating lesson plans on South American civilizations and their regional diversity.',
 'A cultural anthropologist studying the representation and adaptation of traditional folklore in contemporary media, particularly in television and film.',
 'A high school earth science teacher looking for real-world examples to explain climate zones, soil types, and human-environment interactions.']

Selecting data

Here we select some personas to use.

Creating agents

We create an agent in EDSL by passing a dictionary of traits (such as a persona) to an Agent object. Here we use a method for generating a set of agents from a list of traits at once (a list of the personas). Learn more about designing agents in EDSL.
from edsl import AgentList

agents = AgentList.from_list("persona", personas_list)

Using agents to answer a survey

Here we construct some questions and administer them to the agents. EDSL comes with many common question types that we can choose from based on the form of the response that we want to get back from a model. Learn more about constructing surveys with different question types, logic and rules.
from edsl import QuestionMultipleChoice, QuestionLinearScale, Survey

q1 = QuestionMultipleChoice(
    question_name = "preferred_mode_commute",
    question_text = "What is your preferred mode of commuting to work?",
    question_options = [ "Car", "Public transportation", "Bike", "Walk", "Work from home", "Other" ]
)

q2 = QuestionLinearScale(
    question_name = "work_from_home",
    question_text = "On a scale from 1 to 5, how easy is it for you to work from home?",
    question_options = [1,2,3,4,5],
    option_labels = {1:"Not at all easy", 5:"Very easy"}
)

survey = Survey([q1, q2])

Selecting language models

EDSL works with many popular language models that we can select to generate the responses for the agents. To see a list of all services:
from edsl import Model

Model.services()
Service Name
0anthropic
1azure
2bedrock
3deep_infra
4deepseek
5google
6groq
7mistral
8ollama
9openai
10perplexity
11together
12xai
To see a list of all available models:
\# Model.available()

To select models to use with a survey:

from edsl import ModelList, Model

models = ModelList(
    Model(m) for m in ["gemini-1.5-flash", "gpt-4o"]
)
We run a survey by adding the agents and models, and then calling the run() method. This generates a formatted dataset of Results:
results = survey.by(agents).by(models).run()

Analyzing results

EDSL comes with built-in methods for analysis. Here we inspect the responses in a table:
results.select("model", "persona", "preferred_mode_commute", "work_from_home")
model.modelagent.personaanswer.preferred_mode_commuteanswer.work_from_home
0gemini-1.5-flashA theater manager or events coordinator interested in understanding the operational aspects, facilities, and programming of performing arts centers, such as the Broward Center.Car1
1gpt-4oA theater manager or events coordinator interested in understanding the operational aspects, facilities, and programming of performing arts centers, such as the Broward Center.Car2
2gemini-1.5-flashAn urban planner looking to understand the distribution and organization of public services in the Halifax Regional Municipality.Public transportation3
3gpt-4oAn urban planner looking to understand the distribution and organization of public services in the Halifax Regional Municipality.Public transportation4
4gemini-1.5-flashA high school literature teacher looking for supplementary materials to enrich their curriculum and provide students with a deeper understanding of their state’s cultural heritage.Car3
5gpt-4oA high school literature teacher looking for supplementary materials to enrich their curriculum and provide students with a deeper understanding of their state’s cultural heritage.Car3
6gemini-1.5-flashA science fiction writer, exploring the use of secret trials as a theme in stories that examine surveillance, privacy, and power dynamics in society.Work from home5
7gpt-4oA science fiction writer, exploring the use of secret trials as a theme in stories that examine surveillance, privacy, and power dynamics in society.Work from home5
8gemini-1.5-flashA financial analyst specializing in Asian markets and wealthy individuals, interested in tracking the investments and philanthropic activities of billionaires like Gerald Chan.Work from home4
9gpt-4oA financial analyst specializing in Asian markets and wealthy individuals, interested in tracking the investments and philanthropic activities of billionaires like Gerald Chan.Work from home5
10gemini-1.5-flashA high school physics teacher who enjoys applying physics concepts to various sports, curious about the effects of water resistance and body positioning in Paralympic swimming.Car3
11gpt-4oA high school physics teacher who enjoys applying physics concepts to various sports, curious about the effects of water resistance and body positioning in Paralympic swimming.Bike2
12gemini-1.5-flashA high school physical education teacher seeking to incorporate Paralympic history and achievements into the curriculum to inspire and educate students about inclusivity in sports.Car1
13gpt-4oA high school physical education teacher seeking to incorporate Paralympic history and achievements into the curriculum to inspire and educate students about inclusivity in sports.Bike1
14gemini-1.5-flashA high school history teacher creating lesson plans on South American civilizations and their regional diversity.Car3
15gpt-4oA high school history teacher creating lesson plans on South American civilizations and their regional diversity.Car4
16gemini-1.5-flashA cultural anthropologist studying the representation and adaptation of traditional folklore in contemporary media, particularly in television and film.Work from home4
17gpt-4oA cultural anthropologist studying the representation and adaptation of traditional folklore in contemporary media, particularly in television and film.Work from home4
18gemini-1.5-flashA high school earth science teacher looking for real-world examples to explain climate zones, soil types, and human-environment interactions.Car2
19gpt-4oA high school earth science teacher looking for real-world examples to explain climate zones, soil types, and human-environment interactions.Car3

Constructing traits

In comparing model responses it can be convenient to include shortnames for traits in addition to narrative personas–e.g., just the name of the agent’s occupation, age, etc. Here we run a question to extract the occupation from each persona in order to store it as a separate trait of each agent. We use Scenario objects to represent the data (personas) that we add to the question when we run it. Learn more about using scenarios to parameterize questions with data and context.
from edsl import QuestionExtract

q = QuestionExtract(
    question_name = "occupation",
    question_text = "{{ scenario.persona }}",
    answer_template = {"occupation":"artist"}
)
Creating scenarios for the personas in order to add them to the question:
from edsl import ScenarioList

scenarios = ScenarioList.from_list("persona", personas_list)
results = q.by(scenarios).run()
results.select("persona", "occupation")
scenario.personaanswer.occupation
0A theater manager or events coordinator interested in understanding the operational aspects, facilities, and programming of performing arts centers, such as the Broward Center.{'occupation': 'theater manager or events coordinator'}
1An urban planner looking to understand the distribution and organization of public services in the Halifax Regional Municipality.{'occupation': 'urban planner'}
2A high school literature teacher looking for supplementary materials to enrich their curriculum and provide students with a deeper understanding of their state’s cultural heritage.{'occupation': 'high school literature teacher'}
3A science fiction writer, exploring the use of secret trials as a theme in stories that examine surveillance, privacy, and power dynamics in society.{'occupation': 'science fiction writer'}
4A financial analyst specializing in Asian markets and wealthy individuals, interested in tracking the investments and philanthropic activities of billionaires like Gerald Chan.{'occupation': 'financial analyst'}
5A high school physics teacher who enjoys applying physics concepts to various sports, curious about the effects of water resistance and body positioning in Paralympic swimming.{'occupation': 'high school physics teacher'}
6A high school physical education teacher seeking to incorporate Paralympic history and achievements into the curriculum to inspire and educate students about inclusivity in sports.{'occupation': 'high school physical education teacher'}
7A high school history teacher creating lesson plans on South American civilizations and their regional diversity.{'occupation': 'high school history teacher'}
8A cultural anthropologist studying the representation and adaptation of traditional folklore in contemporary media, particularly in television and film.{'occupation': 'cultural anthropologist'}
9A high school earth science teacher looking for real-world examples to explain climate zones, soil types, and human-environment interactions.{'occupation': 'high school earth science teacher'}

Designing agents

Here we recreate agents with both the personas and occupations as traits:
occupations_list = [o['occupation'] for o in results.select("occupation").to_list()]
occupations_list


['theater manager or events coordinator',
 'urban planner',
 'high school literature teacher',
 'science fiction writer',
 'financial analyst',
 'high school physics teacher',
 'high school physical education teacher',
 'high school history teacher',
 'cultural anthropologist',
 'high school earth science teacher']

t = list(zip(personas_list, occupations_list))

from edsl import AgentList, Agent

agents = AgentList(
    Agent(traits = {"persona":p, "occupation":o}) for p,o in t
)

Running a survey

Here we rerun the survey and then filter and sort results by agent traits:
results = survey.by(agents).by(models).run()
(
    results
    .filter("model.model == 'gpt-4o'")
    .sort_by("work_from_home", reverse=True)
    .select("model", "occupation", "preferred_mode_commute", "work_from_home")
)
model.modelagent.occupationanswer.preferred_mode_commuteanswer.work_from_home
0gpt-4oscience fiction writerWork from home5
1gpt-4ofinancial analystWork from home5
2gpt-4ocultural anthropologistWork from home5
3gpt-4ourban plannerPublic transportation4
4gpt-4ohigh school literature teacherCar3
5gpt-4ohigh school physics teacherBike3
6gpt-4ohigh school history teacherCar3
7gpt-4ohigh school earth science teacherCar3
8gpt-4otheater manager or events coordinatorCar2
9gpt-4ohigh school physical education teacherBike1

Posting to the Coop

The Coop is a platform for creating, storing and sharing LLM-based research. It is fully integrated with EDSL and accessible from your workspace or Coop account page. Learn more about creating an account and using the Coop. Here we demonstrate how to post this notebook:
from edsl import Notebook

nb = Notebook(path = "import_agents.ipynb")

if refresh := False:
    nb.push(
        description = "Importing agents",
        alias = "importing-agents-notebook",
        visibility = "public"
    )
else:
    nb.patch('e0f3c111-328e-417b-b2ad-aec527adad49', value = nb)
I