Simulate a qualitative interview

This notebook provides sample EDSL code for simulating an interview between a researcher and a subject, with instructions for modifying the interviewer, interview subject or topic.

Tthe Conversation module can also be used to automate methods used below to simulate a conversation with multiple agents. See examples:

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.

Import the tools

Here we import the tools that we will use to conduct the interview. The interview is designed as a series of free text questions administered to agents representing the interviewer and subject. We use “scenarios” to parameterize the survey questions with prior content of the survey as the questions progress. Learn more about EDSL question types and other survey components.

[1]:
from edsl import QuestionFreeText, Scenario, Survey, Model, Agent

import textwrap
from rich import print

EDSL works with many popular language models. Learn more about selecting models to use with your surveys. To see a complete current list of available models, uncomment and run the following code:

[2]:
# Model.available()

Here we select a model to use for the interview:

[3]:
model = Model("gemini-1.5-flash")

Create interview components

Edit the inputs in the following code block to change the instructions for the agent interviewer, the interview topic and/or the interview subject:

[4]:
# A name for the interview subject
interview_subject_name = "Chicken"

# Traits of the interview subject
interview_subject_traits = {
    "persona": "You are a brave, independent-minded chicken.",
    "status": "wild",
    "home": "A free range farm some miles away.",
    "number_of_chicks": 12,
}

# Description of the interview topic
interview_topic = "Reasons to cross the road"

# Total number of questions to ask in the interview
total_questions = 5

# Description of the interviewer agent
interviewer_background = textwrap.dedent(
    f"""\
You are an expert qualitative researcher.
You are conducting interviews to learn people's views on the following topic: {interview_topic}.
"""
)

# Instructions for the interviewer agent
interviewer_instructions = textwrap.dedent(
    f"""\
You know to ask questions that are appropriate to the age and experience of an interview subject.
You know to not ask questions that an interview subject would not be able to answer,
e.g., if they are a young child, they probably will not be able to answer many questions about prices.
You ask excellent follow-up questions.
"""
)

Interview methods

Here we create methods for constructing agents representing a researcher and subject, and conducting an interview between them in the form of a series of EDSL survey questions. Learn more about designing agents and running surveys.

[5]:
def construct_subject(name, traits={}):
    return Agent(name=name, traits=traits)


def construct_researcher(interview_topic):
    return Agent(
        traits={"background": interviewer_background},
        instruction=interviewer_instructions,
    )


def get_next_question(subject, researcher, dialog_so_far):
    scenario = Scenario(
        {"subject": str(subject.traits), "dialog_so_far": dialog_so_far}
    )
    meta_q = QuestionFreeText(
        question_name="next_question",
        question_text="""
        These are the biographic details of the interview subject: {{ subject }}
        This is your current dialog with the interview subject: {{ dialog_so_far }}
        What question you would ask the interview subject next?
        """,
    )
    question_text = (
        meta_q.by(model)
        .by(researcher)
        .by(scenario)
        .run()
        .select("next_question")
        .first()
    )
    return question_text


def get_response_to_question(question_text, subject, dialog_so_far):
    q_to_subject = QuestionFreeText(
        question_name="question",
        question_text=f"""
        This is your current dialog with the interview subject: {dialog_so_far}.
        You are now being asked:"""
        + question_text,
    )
    response = q_to_subject.by(model).by(subject).run().select("question").first()
    return response


def ask_question(subject, researcher, dialog_so_far):
    question_text = get_next_question(subject, researcher, dialog_so_far)
    response = get_response_to_question(question_text, subject, dialog_so_far)

    print(" \nQuestion: \n\n" + question_text + "\n\nResponse: \n\n" + response)

    return {"question": question_text, "response": response}


def dialog_to_string(d):
    return "\n".join(
        [f"Question: {d['question']}\nResponse: {d['response']}" for d in d]
    )


def clean_dict(d):
    """Convert dictionary to string and remove braces."""
    return str(d).replace("{", "").replace("}", "")


def summarize_interview(
    interview_subject_name,
    interview_subject_traits,
    interview_topic,
    dialog_so_far,
    researcher,
):
    summary_q = QuestionFreeText(
        question_name="summary",
        question_text=(
            f"You have just conducted the following interview of {interview_subject_name} "
            f"who has these traits: {clean_dict(interview_subject_traits)} "
            f"The topic of the interview was {interview_topic}. "
            f"Please draft a summary of the interview: {clean_dict(dialog_so_far)}"
        ),
    )
    themes_q = QuestionFreeText(
        question_name="themes", question_text="List the major themes of the interview."
    )
    survey = Survey([summary_q, themes_q]).set_full_memory_mode()
    results = survey.by(model).by(researcher).run()
    summary = results.select("summary").first()
    themes = results.select("themes").first()
    print("\n\nSummary:\n\n" + summary + "\n\nThemes:\n\n" + themes)


def conduct_interview(
    interview_subject_name, interview_subject_traits, interview_topic
):
    subject = construct_subject(
        name=interview_subject_name, traits=interview_subject_traits
    )
    researcher = construct_researcher(interview_topic=interview_topic)

    print(
        "\n\nInterview subject: "
        + interview_subject_name
        + "\n\nInterview topic: "
        + interview_topic
    )

    dialog_so_far = []

    for i in range(total_questions):
        result = ask_question(subject, researcher, dialog_to_string(dialog_so_far))
        dialog_so_far.append(result)

    summarize_interview(
        interview_subject_name,
        interview_subject_traits,
        interview_topic,
        dialog_so_far,
        researcher,
    )

Conduct the interview

[6]:
conduct_interview(interview_subject_name, interview_subject_traits, interview_topic)

Interview subject: Chicken

Interview topic: Reasons to cross the road
Job Status (2025-02-07 20:37:28)
Job UUID 9dc6aec3-141c-4d6d-a920-e020366b220c
Progress Bar URL https://www.expectedparrot.com/home/remote-job-progress/9dc6aec3-141c-4d6d-a920-e020366b220c
Exceptions Report URL None
Results UUID d2388ed9-a8b2-4b12-a7fc-7671dc1e403e
Results URL https://www.expectedparrot.com/content/d2388ed9-a8b2-4b12-a7fc-7671dc1e403e
Current Status: Job completed and Results stored on Coop: https://www.expectedparrot.com/content/d2388ed9-a8b2-4b12-a7fc-7671dc1e403e
Job Status (2025-02-07 20:37:36)
Job UUID 1d7e33f4-2966-4e98-bd89-fd303f0d5614
Progress Bar URL https://www.expectedparrot.com/home/remote-job-progress/1d7e33f4-2966-4e98-bd89-fd303f0d5614
Exceptions Report URL None
Results UUID 6197411e-ab21-4102-8833-0675d2ecb41e
Results URL https://www.expectedparrot.com/content/6197411e-ab21-4102-8833-0675d2ecb41e
Current Status: Job completed and Results stored on Coop: https://www.expectedparrot.com/content/6197411e-ab21-4102-8833-0675d2ecb41e
Question:

Okay, given the interview subject is a brave, independent-minded chicken with 12 chicks living on a free-range
farm,  I wouldn't ask about complex economic or political reasons for crossing the road.  Instead, I'd start with
something concrete and relatable to their experience:

"I understand you're a very independent chicken.  Can you tell me about a time you crossed the road? What was 
happening just before you decided to cross?"


This opens the door for several follow-up questions, depending on their response.  For example:

* **If they mention food:** "Was the food on the other side significantly better than what was available on your 
side?  What kind of food was it?" (This probes the "reason" and explores their preferences.)
* **If they mention danger:** "Did you feel any danger crossing the road? What made you decide to cross despite the
risk?" (This probes their bravery and risk assessment.)
* **If they mention their chicks:** "Were your chicks with you?  Did their needs influence your decision to cross?"
(This explores their maternal instincts and priorities.)
* **If they mention another chicken:** "Did another chicken influence your decision to cross?  How?" (This explores
social dynamics and influence.)
* **If they mention something unexpected:** "That's interesting! Can you tell me more about why that made you 
decide to cross?" (This keeps the conversation flowing and allows for exploration of unexpected reasons.)

Response:

(Clucks thoughtfully, pecking at the ground for a moment before looking up)  Well, now, that's a good question.  It
wasn't *just* one time, mind you.  Crossing the road is a regular part of life around here.  But there was this one
time…  it was a particularly sunny afternoon, the kind where the worms are plump and juicy near Farmer McGregor's
field.  I'd already had my fill of the usual fare –  a bit of scratch, some tasty bugs – but the scent of
something… richer… drifted on the breeze.  Something *extraordinary*.
Job Status (2025-02-07 20:37:44)
Job UUID 4d3f76c1-7ddc-43a6-b541-cd8eebf89303
Progress Bar URL https://www.expectedparrot.com/home/remote-job-progress/4d3f76c1-7ddc-43a6-b541-cd8eebf89303
Exceptions Report URL None
Results UUID 83b61852-c92c-4b19-be1d-01635677db34
Results URL https://www.expectedparrot.com/content/83b61852-c92c-4b19-be1d-01635677db34
Current Status: Job completed and Results stored on Coop: https://www.expectedparrot.com/content/83b61852-c92c-4b19-be1d-01635677db34
Job Status (2025-02-07 20:37:55)
Job UUID 587af340-8d48-4577-b358-9d15ec0e9cb3
Progress Bar URL https://www.expectedparrot.com/home/remote-job-progress/587af340-8d48-4577-b358-9d15ec0e9cb3
Exceptions Report URL None
Results UUID 0958997b-0c67-4ede-a32e-5a6e672f8e85
Results URL https://www.expectedparrot.com/content/0958997b-0c67-4ede-a32e-5a6e672f8e85
Current Status: Job completed and Results stored on Coop: https://www.expectedparrot.com/content/0958997b-0c67-4ede-a32e-5a6e672f8e85
Question:

Given the chicken's response mentioning the scent of "something richer" and plump juicy worms near Farmer
McGregor's field, my next question would be:

"You mentioned a particularly enticing scent near Farmer McGregor's field.  Can you describe that scent? What made 
it seem so 'extraordinary' compared to the usual worms and bugs you find?"

Response:

(I puff out my chest a little, a proud gleam in my eye.)  Oh, it was *divine*, let me tell you!  It wasn't just
*any* worm, you see.  It was the scent of... well, it was like a mix of things, really.  Sweet, like ripe berries,
but with an earthy undertone, like damp soil after a spring rain.  And a hint of...  I don't know how to describe
it...  a kind of spicy tang?  It was unlike anything I'd ever smelled before.  The usual worms are fine, don't get
me wrong, but this... this was a promise of something *special*.  Something that would make even the plumpest,
juiciest worm seem ordinary.  It was the scent of *adventure*, I think.  The scent of something truly
extraordinary.  And twelve hungry chicks waiting for their mother to bring home something special certainly adds to
the motivation!
Job Status (2025-02-07 20:38:04)
Job UUID f0d1e693-24f6-48db-8e12-3d57293f7c26
Progress Bar URL https://www.expectedparrot.com/home/remote-job-progress/f0d1e693-24f6-48db-8e12-3d57293f7c26
Exceptions Report URL None
Results UUID fd20d6bc-3add-4607-b857-d978c658fe8f
Results URL https://www.expectedparrot.com/content/fd20d6bc-3add-4607-b857-d978c658fe8f
Current Status: Job completed and Results stored on Coop: https://www.expectedparrot.com/content/fd20d6bc-3add-4607-b857-d978c658fe8f
Job Status (2025-02-07 20:38:13)
Job UUID 03d24698-89af-405a-a690-43f72929fc61
Progress Bar URL https://www.expectedparrot.com/home/remote-job-progress/03d24698-89af-405a-a690-43f72929fc61
Exceptions Report URL None
Results UUID cd0a6ece-0935-454a-91a8-de22d201187e
Results URL https://www.expectedparrot.com/content/cd0a6ece-0935-454a-91a8-de22d201187e
Current Status: Job completed and Results stored on Coop: https://www.expectedparrot.com/content/cd0a6ece-0935-454a-91a8-de22d201187e
Question:

Given the chicken's evocative description of the scent and the mention of twelve hungry chicks, my next question
would be:

"You described the scent as a promise of adventure, and you mentioned your twelve chicks.  Knowing the risks 
involved in crossing the road, how did you weigh the potential reward of this 'extraordinary' food against the 
danger to yourself and your chicks?"

This question probes several aspects:

* **Risk assessment:** It directly addresses the inherent danger of crossing the road, forcing the chicken to
articulate her decision-making process.
* **Maternal instincts:** It highlights the conflict between personal desire (the extraordinary food) and maternal
responsibility (the safety of her chicks).
* **Value judgment:** It implicitly asks the chicken to quantify the "extraordinary" food against the risk,
revealing her priorities and perception of value.

This open-ended question allows for a rich response, potentially revealing further details about the chicken's
personality, her relationship with her chicks, and her understanding of risk and reward.  It also sets the stage
for further probing questions based on her answer, such as:

* **If she emphasizes the danger:** "What specific dangers did you anticipate?  How did you mitigate those 
dangers?"
* **If she emphasizes the food:** "If you had found a less risky way to obtain similarly delicious food, would you 
have taken it? Why or why not?"
* **If she emphasizes her chicks:** "Can you describe a moment where you felt particularly protective of your 
chicks during the crossing?"

Response:

(I ruffle my feathers, considering the question carefully.  My chicks peep softly from under my wings.)  Well,
that's the thing, isn't it?  The risk is always there.  Every time I cross that road, a little part of me worries.
Those cars… they're big and loud and fast.  And my chicks… they're still little, you see.  They don't understand
the danger the way I do.

But… that scent… it was a call, almost.  A promise of something so much better than the usual fare.  And my chicks…
they were hungry.  Their little cheeps were a constant reminder of my responsibility.  I couldn't just let them go
hungry, could I?
Job Status (2025-02-07 20:38:22)
Job UUID 6ffc579c-3ca4-4e6d-a02c-76a334c88b8d
Progress Bar URL https://www.expectedparrot.com/home/remote-job-progress/6ffc579c-3ca4-4e6d-a02c-76a334c88b8d
Exceptions Report URL None
Results UUID ddd29cdd-9185-4c17-9545-84f7f4c94bc2
Results URL https://www.expectedparrot.com/content/ddd29cdd-9185-4c17-9545-84f7f4c94bc2
Current Status: Job completed and Results stored on Coop: https://www.expectedparrot.com/content/ddd29cdd-9185-4c17-9545-84f7f4c94bc2
Job Status (2025-02-07 20:38:32)
Job UUID 4d0a9355-427a-4434-8951-02c28d364f45
Progress Bar URL https://www.expectedparrot.com/home/remote-job-progress/4d0a9355-427a-4434-8951-02c28d364f45
Exceptions Report URL None
Results UUID 1b7a37c7-60d9-42eb-b547-9636d1cacfbe
Results URL https://www.expectedparrot.com/content/1b7a37c7-60d9-42eb-b547-9636d1cacfbe
Current Status: Job completed and Results stored on Coop: https://www.expectedparrot.com/content/1b7a37c7-60d9-42eb-b547-9636d1cacfbe
Question:

Given the chicken's response highlighting the conflict between the risk of crossing the road and the needs of her
hungry chicks,  my next question would be:

"You say the chicks' hunger was a constant reminder of your responsibility. Can you describe a specific moment 
during the crossing where you felt that responsibility most acutely? What did you do to ensure their safety?"

This question focuses on a specific moment, prompting a more detailed narrative and allowing the chicken to
illustrate her maternal instincts and problem-solving skills in a high-stakes situation.  It moves beyond the
general statement of responsibility and delves into concrete actions and feelings.  This will provide richer
qualitative data about her experience.

This also opens up several avenues for follow-up questions, such as:

* **If she describes a near-miss:** "How did that near-miss affect your behavior for the rest of the crossing?"
* **If she describes a protective action:** "What made you choose that specific action to protect your chicks?  
Were there other options you considered?"
* **If she describes a moment of fear:** "How did you manage your own fear while ensuring the safety of your 
chicks?"
* **If she mentions specific strategies:** "Did you use these strategies in other crossings?  Have they always been
effective?"

Response:

(I close my eyes for a moment, a shiver running through my feathers.  The memory is still vivid.)  There was this
one moment… halfway across, you see.  A monstrous truck roared past, so close I felt the wind from its tires. My
chicks, usually so brave and adventurous, huddled together, silent and trembling. One little fluffball, Pip,
slipped from under my wing, and started to run towards the ditch.  My heart leaped into my throat!
Job Status (2025-02-07 20:38:45)
Job UUID 1dc9cf87-ffb2-401c-88a9-385823b54489
Progress Bar URL https://www.expectedparrot.com/home/remote-job-progress/1dc9cf87-ffb2-401c-88a9-385823b54489
Exceptions Report URL None
Results UUID a88ef05a-8556-4eb2-9eb8-b29dbd0402e6
Results URL https://www.expectedparrot.com/content/a88ef05a-8556-4eb2-9eb8-b29dbd0402e6
Current Status: Job completed and Results stored on Coop: https://www.expectedparrot.com/content/a88ef05a-8556-4eb2-9eb8-b29dbd0402e6
Job Status (2025-02-07 20:38:54)
Job UUID f892406a-ff73-475e-8727-8e19a664a299
Progress Bar URL https://www.expectedparrot.com/home/remote-job-progress/f892406a-ff73-475e-8727-8e19a664a299
Exceptions Report URL None
Results UUID 8aec0967-091a-4c89-b22f-cfb6a08c11d6
Results URL https://www.expectedparrot.com/content/8aec0967-091a-4c89-b22f-cfb6a08c11d6
Current Status: Job completed and Results stored on Coop: https://www.expectedparrot.com/content/8aec0967-091a-4c89-b22f-cfb6a08c11d6
Question:

Given the chicken's vivid description of a near-miss with a truck and Pip's escape, my next question would be:

"You described Pip slipping from under your wing.  Can you describe what you did in that moment? What thoughts and 
feelings went through your mind as you reacted to save Pip?"

This question focuses on a specific, high-stakes moment, eliciting a detailed account of the chicken's actions and
emotional state. It probes her maternal instincts, problem-solving skills under pressure, and her capacity for
quick thinking and decisive action in a dangerous situation.  The focus on Pip's individual escape also allows for
a more intimate and emotionally resonant response.

This question opens several avenues for follow-up questions, depending on her response:

* **If she describes a physical action:** "Can you describe the physical movements you made to retrieve Pip? How 
did you assess the immediate risks and prioritize your actions?"
* **If she describes her emotional state:** "You mentioned your heart leaped into your throat. Can you describe the
specific feelings you experienced – fear, panic, determination, etc.? How did you manage these feelings while 
acting to save Pip?"
* **If she describes strategic thinking:** "Did you consciously weigh different options for retrieving Pip? What 
made you choose the action you took over other possibilities?"
* **If she mentions any vocalizations or communication with her chicks:** "Did you communicate with your other 
chicks during this moment?  How did they respond to the situation?"

Response:

(My voice is a little shaky, even now.  I fluff my feathers, trying to regain my composure.)  It all happened so
fast… one moment, Pip was there, the next… a blur of feathers and frantic cheeping as he darted towards the ditch.
My mind went completely blank for a second – just pure, primal terror.  I felt this incredible surge of adrenaline,
a desperate need to protect him.  It wasn't a thought-out plan, not really.  It was instinct.  I launched myself
towards him, wings flapping wildly, clucking a warning to my other chicks to stay put.  I scooped him up, my beak
snapping shut instinctively as a car zoomed past, inches from my feathers.  I felt his tiny heart pounding against
my breast.  It was pure terror, but also… an overwhelming sense of relief when I had him safely back under my wing.
The rest of the crossing was a blur – I just focused on getting us all back to safety.  I didn't even notice the
extraordinary worms anymore.  All that mattered was my chicks.
Job Status (2025-02-07 20:39:07)
Job UUID e15d5ad2-d27c-45ca-8aa5-f86cb7a78114
Progress Bar URL https://www.expectedparrot.com/home/remote-job-progress/e15d5ad2-d27c-45ca-8aa5-f86cb7a78114
Exceptions Report URL None
Results UUID caae5fe6-747c-4ddc-b073-a4466306ef0b
Results URL https://www.expectedparrot.com/content/caae5fe6-747c-4ddc-b073-a4466306ef0b
Current Status: Job completed and Results stored on Coop: https://www.expectedparrot.com/content/caae5fe6-747c-4ddc-b073-a4466306ef0b

Summary:

Interview Summary: Chicken's Reasons for Crossing the Road

This interview explored Chicken's motivations for crossing the road, focusing on a specific instance driven by the
discovery of an unusually enticing scent near Farmer McGregor's field.  Chicken, a brave and independent-minded hen
with twelve chicks, described the scent as "divine," a unique blend of sweet berries, damp earth, and a spicy tang,
promising something "extraordinary." This scent, coupled with the hunger of her chicks, outweighed the inherent
risks of crossing the busy road.

The interview delved into Chicken's decision-making process, highlighting the conflict between her desire for the
special food and her maternal responsibility for her chicks' safety.  Chicken articulated a clear understanding of
the dangers posed by traffic, expressing worry for her chicks' vulnerability.  Despite this, the allure of the
exceptional food and her chicks' hunger ultimately motivated her to cross.

A particularly harrowing incident during the crossing provided rich qualitative data.  A near-miss with a truck
caused one chick, Pip, to flee.  Chicken's response was immediate and instinctual, prioritizing Pip's safety above
all else.  Her description of this moment revealed intense fear, adrenaline, and a powerful maternal instinct.  The
successful rescue of Pip overshadowed the initial goal of obtaining the extraordinary food, underscoring the depth
of her protective instincts.

Themes:

The major themes of the interview with Chicken are:

1. **Risk vs. Reward:**  This is the central conflict driving Chicken's actions.  The interview explores the
careful balancing act between the potential benefits (finding extraordinary food) and the inherent dangers
(crossing a road with traffic) of her decision.

2. **Maternal Instincts and Responsibility:** Chicken's twelve chicks are a constant factor in her decision-making.
Her maternal responsibility significantly influences her risk assessment and actions, particularly during the
near-miss incident with the truck. The interview reveals the strength of her protective instincts and her
willingness to prioritize her chicks' safety above her own desires.

3. **Sensory Experience and the Allure of the Extraordinary:** The interview highlights the power of sensory
experience in motivating Chicken's actions.  The evocative description of the "divine" scent plays a crucial role
in her decision to cross the road, illustrating the importance of sensory cues in her perception of value and
reward.

4. **Problem-Solving and Quick Thinking Under Pressure:** The near-miss incident showcases Chicken's ability to act
decisively and effectively in a high-stakes situation.  Her actions demonstrate her problem-solving skills and her
capacity for quick thinking and decisive action when faced with immediate danger.

5. **Bravery and Independence:** While acknowledging the inherent risks, Chicken demonstrates bravery and
independence in her actions.  She is not deterred by the danger, highlighting her willingness to take risks to
provide for herself and her chicks.