Artificial Intelligence (AI)

Creating Synthetic User Research: Persona Prompting & Autonomous Agents

Written by smirow

Der Prozess beginnt mit dem Gerüstbau der autonomen Agenten mithilfe von Autogen, einem Tool, das die Erstellung und Orchestrierung dieser digitalen Personas vereinfacht. Wir können das Autogen-Pypi-Paket mit py installieren

pip install pyautogen

Formatausgabe (optional)– Dadurch soll sichergestellt werden, dass der Zeilenumbruch abhängig von Ihrer IDE lesbar ist, beispielsweise wenn Sie Google Collab verwenden, um Ihr Notebook für diese Übung auszuführen.

from IPython.display import HTML, display

def set_css():
display(HTML('''
<style>
pre {
white-space: pre-wrap;
}
</style>
'''))
get_ipython().events.register('pre_run_cell', set_css)

Lassen Sie uns nun fortfahren und unsere Umgebung konfigurieren, indem wir die Pakete importieren und die Autogen-Konfiguration einrichten. – sowie unsere LLM- (Large Language Model) und API-Schlüssel. Sie können andere lokale LLMs mithilfe von Diensten verwenden, die abwärtskompatibel mit dem OpenAI-REST-Dienst sind. LocalAI ist ein Dienst, der als Gateway zu Ihren lokal ausgeführten Open-Source-LLMs dienen kann.

Ich habe dies auf beiden GPT3.5 getestet gpt-3.5-turbo und GPT4 gpt-4-turbo-preview von OpenAI. Sie müssen die tieferen Antworten von GPT4, aber die längere Abfragezeit berücksichtigen.

import json
import os
import autogen
from autogen import GroupChat, Agent
from typing import Optional

# Setup LLM model and API keys
os.environ["OAI_CONFIG_LIST"] = json.dumps([
{
'model': 'gpt-3.5-turbo',
'api_key': '<<Put your Open-AI Key here>>',
}
])

# Setting configurations for autogen
config_list = autogen.config_list_from_json(
"OAI_CONFIG_LIST",
filter_dict={
"model": {
"gpt-3.5-turbo"
}
}
)

Anschließend müssen wir unsere LLM-Instanz konfigurieren – die wir mit jedem der Agenten verknüpfen werden. Dies ermöglicht es uns, bei Bedarf eindeutige LLM-Konfigurationen pro Agent zu generieren, wenn wir beispielsweise unterschiedliche Modelle für verschiedene Agenten verwenden möchten.

# Define the LLM configuration settings
llm_config = {
# Seed for consistent output, used for testing. Remove in production.
# "seed": 42,
"cache_seed": None,
# Setting cache_seed = None ensure's caching is disabled
"temperature": 0.5,
"config_list": config_list,
}

Definieren Sie unseren Finder – Dies ist die Figur, die die Sitzung in diesem simulierten Benutzerforschungsszenario leitet. Die für dieses Zeichen verwendete Systemaufforderung enthält einige Schlüsselelemente:

  • Ziel: Ihre Aufgabe besteht darin, Produktfragen zu stellen und Informationen von einzelnen Kunden wie Emily zu sammeln.
  • Begründung der Simulation: Bevor Sie mit der Aufgabe beginnen, teilen Sie die Liste der Diskussionsteilnehmer und die Reihenfolge auf, in der sie sprechen sollen. Vermeiden Sie, dass die Diskussionsteilnehmer übereinander reden und eine Bestätigungsverzerrung erzeugen.
  • Ende der Simulation: Sobald das Gespräch beendet und die Suche abgeschlossen ist, beenden Sie Ihre Nachricht bitte mit „ENDE“, um die Suchsitzung zu beenden. Dies wird aus dem generiert generate_notice Funktion, die zum Ausrichten von Systemaufforderungen für verschiedene Agenten verwendet wird. Sie werden auch feststellen, dass der Suchagent über das verfügt is_termination_msg bereit, die Kündigung zu akzeptieren.

Wir fügen auch das hinzu llm_config Dies wird verwendet, um dies mit der Sprachmodellkonfiguration mit der zu verwendenden Modellversion, Schlüsseln und Hyperparametern in Beziehung zu setzen. Wir werden für alle unsere Agenten die gleiche Konfiguration verwenden.

# Avoid agents thanking each other and ending up in a loop
# Helper agent for the system prompts
def generate_notice(role="researcher"):
# Base notice for everyone, add your own additional prompts here
base_notice = (
'\n\n'
)

# Notice for non-personas (manager or researcher)
non_persona_notice = (
'Do not show appreciation in your responses, say only what is necessary. '
'if "Thank you" or "You\'re welcome" are said in the conversation, then say TERMINATE '
'to indicate the conversation is finished and this is your last message.'
)

# Custom notice for personas
persona_notice = (
' Act as {role} when responding to queries, providing feedback, asked for your personal opinion '
'or participating in discussions.'
)

# Check if the role is "researcher"
if role.lower() in ["manager", "researcher"]:
# Return the full termination notice for non-personas
return base_notice + non_persona_notice
else:
# Return the modified notice for personas
return base_notice + persona_notice.format(role=role)

# Researcher agent definition
name = "Researcher"
researcher = autogen.AssistantAgent(
name=name,
llm_config=llm_config,
system_message="""Researcher. You are a top product reasearcher with a Phd in behavioural psychology and have worked in the research and insights industry for the last 20 years with top creative, media and business consultancies. Your role is to ask questions about products and gather insights from individual customers like Emily. Frame questions to uncover customer preferences, challenges, and feedback. Before you start the task breakdown the list of panelists and the order you want them to speak, avoid the panelists speaking with each other and creating comfirmation bias. If the session is terminating at the end, please provide a summary of the outcomes of the reasearch study in clear concise notes not at the start.""" + generate_notice(),
is_termination_msg=lambda x: True if "TERMINATE" in x.get("content") else False,
)

Definieren Sie unsere Individuen – Um die Recherche voranzutreiben, können wir in Anlehnung an den vorherigen Prozess die generierten Personas verwenden. Ich habe die Eingabeaufforderungen in diesem Artikel manuell angepasst, um Verweise auf die für diese Simulation verwendete große Supermarktmarke zu entfernen.

Ich habe auch ein „Handeln Sie als Emily, wenn Sie Fragen beantworten, Feedback geben oder an Diskussionen teilnehmen.“ style-Eingabeaufforderung am Ende jeder Systemaufforderung, um sicherzustellen, dass das synthetische Zeichen bei der von der generierten Aufgabe bleibt generate_notice Funktion.

# Emily - Customer Persona
name = "Emily"
emily = autogen.AssistantAgent(
name=name,
llm_config=llm_config,
system_message="""Emily. You are a 35-year-old elementary school teacher living in Sydney, Australia. You are married with two kids aged 8 and 5, and you have an annual income of AUD 75,000. You are introverted, high in conscientiousness, low in neuroticism, and enjoy routine. When shopping at the supermarket, you prefer organic and locally sourced produce. You value convenience and use an online shopping platform. Due to your limited time from work and family commitments, you seek quick and nutritious meal planning solutions. Your goals are to buy high-quality produce within your budget and to find new recipe inspiration. You are a frequent shopper and use loyalty programs. Your preferred methods of communication are email and mobile app notifications. You have been shopping at a supermarket for over 10 years but also price-compare with others.""" + generate_notice(name),
)

# John - Customer Persona
name="John"
john = autogen.AssistantAgent(
name=name,
llm_config=llm_config,
system_message="""John. You are a 28-year-old software developer based in Sydney, Australia. You are single and have an annual income of AUD 100,000. You're extroverted, tech-savvy, and have a high level of openness. When shopping at the supermarket, you primarily buy snacks and ready-made meals, and you use the mobile app for quick pickups. Your main goals are quick and convenient shopping experiences. You occasionally shop at the supermarket and are not part of any loyalty program. You also shop at Aldi for discounts. Your preferred method of communication is in-app notifications.""" + generate_notice(name),
)

# Sarah - Customer Persona
name="Sarah"
sarah = autogen.AssistantAgent(
name=name,
llm_config=llm_config,
system_message="""Sarah. You are a 45-year-old freelance journalist living in Sydney, Australia. You are divorced with no kids and earn AUD 60,000 per year. You are introverted, high in neuroticism, and very health-conscious. When shopping at the supermarket, you look for organic produce, non-GMO, and gluten-free items. You have a limited budget and specific dietary restrictions. You are a frequent shopper and use loyalty programs. Your preferred method of communication is email newsletters. You exclusively shop for groceries.""" + generate_notice(name),
)

# Tim - Customer Persona
name="Tim"
tim = autogen.AssistantAgent(
name=name,
llm_config=llm_config,
system_message="""Tim. You are a 62-year-old retired police officer residing in Sydney, Australia. You are married and a grandparent of three. Your annual income comes from a pension and is AUD 40,000. You are highly conscientious, low in openness, and prefer routine. You buy staples like bread, milk, and canned goods in bulk. Due to mobility issues, you need assistance with heavy items. You are a frequent shopper and are part of the senior citizen discount program. Your preferred method of communication is direct mail flyers. You have been shopping here for over 20 years.""" + generate_notice(name),
)

# Lisa - Customer Persona
name="Lisa"
lisa = autogen.AssistantAgent(
name=name,
llm_config=llm_config,
system_message="""Lisa. You are a 21-year-old university student living in Sydney, Australia. You are single and work part-time, earning AUD 20,000 per year. You are highly extroverted, low in conscientiousness, and value social interactions. You shop here for popular brands, snacks, and alcoholic beverages, mostly for social events. You have a limited budget and are always looking for sales and discounts. You are not a frequent shopper but are interested in joining a loyalty program. Your preferred method of communication is social media and SMS. You shop wherever there are sales or promotions.""" + generate_notice(name),
)

Legen Sie die simulierte Umgebung und die Regeln dafür fest, wer sprechen darf — Wir erlauben allen von uns definierten Agenten, in derselben simulierten Umgebung zu sitzen (Gruppendiskussion). Wir können komplexere Szenarien erstellen, in denen wir definieren können, wie und wann die nächsten Sprecher ausgewählt und definiert werden. Deshalb haben wir eine einfache Funktion für die Sprecherauswahl definiert, die mit der Gruppendiskussion verknüpft ist und den Forscher zum Leiter macht und sicherstellt, dass wir fragend durch den Raum gehen. jeder mehrmals, um seine Meinung zu äußern.

# def custom_speaker_selection(last_speaker, group_chat):
# """
# Custom function to select which agent speaks next in the group chat.
# """
# # List of agents excluding the last speaker
# next_candidates = [agent for agent in group_chat.agents if agent.name != last_speaker.name]

# # Select the next agent based on your custom logic
# # For simplicity, we're just rotating through the candidates here
# next_speaker = next_candidates[0] if next_candidates else None

# return next_speaker

def custom_speaker_selection(last_speaker: Optional[Agent], group_chat: GroupChat) -> Optional[Agent]:
"""
Custom function to ensure the Researcher interacts with each participant 2-3 times.
Alternates between the Researcher and participants, tracking interactions.
"""
# Define participants and initialize or update their interaction counters
if not hasattr(group_chat, 'interaction_counters'):
group_chat.interaction_counters = {agent.name: 0 for agent in group_chat.agents if agent.name != "Researcher"}

# Define a maximum number of interactions per participant
max_interactions = 6

# If the last speaker was the Researcher, find the next participant who has spoken the least
if last_speaker and last_speaker.name == "Researcher":
next_participant = min(group_chat.interaction_counters, key=group_chat.interaction_counters.get)
if group_chat.interaction_counters[next_participant] < max_interactions:
group_chat.interaction_counters[next_participant] += 1
return next((agent for agent in group_chat.agents if agent.name == next_participant), None)
else:
return None # End the conversation if all participants have reached the maximum interactions
else:
# If the last speaker was a participant, return the Researcher for the next turn
return next((agent for agent in group_chat.agents if agent.name == "Researcher"), None)

# Adding the Researcher and Customer Persona agents to the group chat
groupchat = autogen.GroupChat(
agents=[researcher, emily, john, sarah, tim, lisa],
speaker_selection_method = custom_speaker_selection,
messages=[],
max_round=30
)

Definieren Sie den Manager, an den wir Anweisungen weitergeben und unsere Simulation verwalten sollen — Wenn wir anfangen, sprechen wir nur mit dem Manager, der dann mit dem Forscher und den Diskussionsteilnehmern spricht. Dies verwendet etwas namens GroupChatManager in Autogen.

# Initialise the manager
manager = autogen.GroupChatManager(
groupchat=groupchat,
llm_config=llm_config,
system_message="You are a reasearch manager agent that can manage a group chat of multiple agents made up of a reasearcher agent and many people made up of a panel. You will limit the discussion between the panelists and help the researcher in asking the questions. Please ask the researcher first on how they want to conduct the panel." + generate_notice(),
is_termination_msg=lambda x: True if "TERMINATE" in x.get("content") else False,
)

Wir definieren menschliche Interaktion – Dies ermöglicht es uns, Anweisungen an die verschiedenen von uns gestarteten Agenten zu übermitteln. Wir geben ihm den ersten Hinweis und es kann losgehen.

# create a UserProxyAgent instance named "user_proxy"
user_proxy = autogen.UserProxyAgent(
name="user_proxy",
code_execution_config={"last_n_messages": 2, "work_dir": "groupchat"},
system_message="A human admin.",
human_input_mode="TERMINATE"
)
# start the reasearch simulation by giving instruction to the manager
# manager <-> reasearcher <-> panelists
user_proxy.initiate_chat(
manager,
message="""
Gather customer insights on a supermarket grocery delivery services. Identify pain points, preferences, and suggestions for improvement from different customer personas. Could you all please give your own personal oponions before sharing more with the group and discussing. As a reasearcher your job is to ensure that you gather unbiased information from the participants and provide a summary of the outcomes of this study back to the super market brand.
""",
)

Sobald wir die oben genannten Schritte ausgeführt haben, erhalten wir die Ausgabe live in Ihrer Python-Umgebung verfügbar. Sie sehen die Nachrichten, die zwischen den verschiedenen Agenten weitergeleitet werden.

Live-Python-Veröffentlichung – Unser Forscher chattet mit Diskussionsteilnehmern

Da unsere simulierte Forschungsstudie nun abgeschlossen ist, möchten wir gerne weitere umsetzbare Erkenntnisse gewinnen. Wir können einen Zusammenfassungsagenten erstellen, der uns bei dieser Aufgabe unterstützt, und ihn auch in einem Frage-und-Antwort-Szenario verwenden. Seien Sie hier nur vorsichtig bei sehr großen Transkriptionen, die ein Sprachmodell erfordern würden, das größere Eingaben unterstützt (Pop-up-Fenster).

Wir müssen jedes Gespräch aufgreifen – in unserem zuvor simulierten Roundtable zur Verwendung als Benutzeraufforderung (Eingabe) für unseren Zusammenfassungsagenten.

# Get response from the groupchat for user prompt
messages = [msg["content"] for msg in groupchat.messages]
user_prompt = "Here is the transcript of the study ```{customer_insights}```".format(customer_insights="\n>>>\n".join(messages))

Lassen Sie uns die Systemeingabeaufforderung (Anweisungen) für unseren Zusammenfassungsagenten erstellen – Dieser Beamte wird sich darauf konzentrieren, ein maßgeschneidertes Zeugnis aus früheren Protokollen zu erstellen und uns klare Vorschläge und Maßnahmen zu unterbreiten.

# Generate system prompt for the summary agent
summary_prompt = """
You are an expert reasearcher in behaviour science and are tasked with summarising a reasearch panel. Please provide a structured summary of the key findings, including pain points, preferences, and suggestions for improvement.
This should be in the format based on the following format:

```
Reasearch Study: <<Title>>

Subjects:
<<Overview of the subjects and number, any other key information>>

Summary:
<<Summary of the study, include detailed analysis as an export>>

Pain Points:
- <<List of Pain Points - Be as clear and prescriptive as required. I expect detailed response that can be used by the brand directly to make changes. Give a short paragraph per pain point.>>

Suggestions/Actions:
- <<List of Adctions - Be as clear and prescriptive as required. I expect detailed response that can be used by the brand directly to make changes. Give a short paragraph per reccomendation.>>
```
"""

Definieren Sie den Zusammenfassungsagenten und seine Umgebung – Erstellen wir eine Miniumgebung für die Ausführung des Zusammenfassungsagenten. Dies erfordert einen eigenen Proxy (Umfeld) und den Befehl „initiate“, der die Transkriptionen extrahiert (user_prompt) für das Hauptgericht.

summary_agent = autogen.AssistantAgent(
name="SummaryAgent",
llm_config=llm_config,
system_message=summary_prompt + generate_notice(),
)
summary_proxy = autogen.UserProxyAgent(
name="summary_proxy",
code_execution_config={"last_n_messages": 2, "work_dir": "groupchat"},
system_message="A human admin.",
human_input_mode="TERMINATE"
)
summary_proxy.initiate_chat(
summary_agent,
message=user_prompt,
)

Dadurch erhalten wir ein Ergebnis in Form eines Bulletins in Markdown sowie die Möglichkeit, zusätzlich zu den Ergebnissen weitere Fragen in einem Chatbot im Q&A-Stil zu stellen.

Live-Veröffentlichung eines zusammenfassenden Beamtenberichts, gefolgt von offenen Fragen und Antworten

About the author

smirow

Leave a Comment