一键导入
edsl-survey-reference
EDSL survey reference - question types, templating, rules, memory, helpers, and visualization
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
EDSL survey reference - question types, templating, rules, memory, helpers, and visualization
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Analyze EDSL Results objects - load by UUID or file path, export survey documentation, and generate analysis reports
Answer questions about a generated analysis report - reads report artifacts, performs additional analysis if needed, and saves the answer with metadata
Design complete surveys from free text requirements - generates a Python script with Survey, ScenarioList, and AgentList definitions
Design a detailed experimental plan from a research question - includes literature review, randomization plan, survey design, power analysis, and sample size recommendation
EDSL agent reference - AgentList operations, trait manipulation, templates, codebooks, and instructions
Save/load Surveys, Agents, and AgentLists locally, push/pull to Expected Parrot cloud, git versioning
| name | edsl-survey-reference |
| description | EDSL survey reference - question types, templating, rules, memory, helpers, and visualization |
| allowed-tools | Read, Glob, Bash(python:*) |
Consolidated reference for building surveys with EDSL: question types, Jinja2 templating, skip/navigation rules, memory modes, helper utilities, and visualization.
EDSL provides a comprehensive set of question types for surveys. All questions require question_name (a valid Python identifier) and question_text.
Open-ended text responses without constraints.
from edsl import QuestionFreeText
q = QuestionFreeText(
question_name="feedback",
question_text="What do you think about our service?"
)
Single selection from a predefined list of options.
from edsl import QuestionMultipleChoice
q = QuestionMultipleChoice(
question_name="color",
question_text="What is your favorite color?",
question_options=["Red", "Blue", "Green", "Yellow"]
)
Multiple selections from a predefined list (checkbox-style).
from edsl import QuestionCheckBox
q = QuestionCheckBox(
question_name="features",
question_text="Which features do you use? (Select all that apply)",
question_options=["Feature A", "Feature B", "Feature C", "Feature D"],
min_selections=1, # Optional: minimum selections required
max_selections=3 # Optional: maximum selections allowed
)
Numeric responses with optional min/max bounds.
from edsl import QuestionNumerical
q = QuestionNumerical(
question_name="age",
question_text="How old are you?",
min_value=0, # Optional: minimum allowed value
max_value=120 # Optional: maximum allowed value
)
Simple binary yes/no question (derived from MultipleChoice).
from edsl import QuestionYesNo
q = QuestionYesNo(
question_name="consent",
question_text="Do you agree to participate in this survey?"
)
# Options are automatically ["Yes", "No"]
Linear scale with customizable range and endpoint labels.
from edsl import QuestionLinearScale
q = QuestionLinearScale(
question_name="satisfaction",
question_text="How satisfied are you with our service?",
question_options=[1, 2, 3, 4, 5], # Scale values
option_labels={1: "Very Unsatisfied", 5: "Very Satisfied"} # Endpoint labels
)
Standard 5-point Likert scale (agree/disagree).
from edsl import QuestionLikertFive
q = QuestionLikertFive(
question_name="statement_agree",
question_text="I find the product easy to use."
)
# Options: Strongly disagree, Disagree, Neutral, Agree, Strongly agree
Response as a list of items.
from edsl import QuestionList
q = QuestionList(
question_name="top_movies",
question_text="List your top 3 favorite movies.",
max_list_items=3 # Optional: maximum items allowed
)
Ranking/ordering items by preference.
from edsl import QuestionRank
q = QuestionRank(
question_name="priority",
question_text="Rank these features by importance (1 = most important):",
question_options=["Speed", "Security", "Price", "Support"],
num_selections=4 # How many items to rank
)
Grid-based responses with rows (items) and columns (options).
from edsl import QuestionMatrix
q = QuestionMatrix(
question_name="product_ratings",
question_text="Rate each product on the following attributes:",
question_items=["Product A", "Product B", "Product C"], # Rows
question_options=["Poor", "Fair", "Good", "Excellent"], # Columns
option_labels=None # Optional labels for options
)
Allocating a fixed budget across multiple options.
from edsl import QuestionBudget
q = QuestionBudget(
question_name="time_allocation",
question_text="How would you allocate 100 hours across these activities?",
question_options=["Work", "Exercise", "Leisure", "Sleep"],
budget_sum=100 # Total that allocations must sum to
)
Response as key-value pairs (structured data).
from edsl import QuestionDict
q = QuestionDict(
question_name="contact_info",
question_text="Provide your contact information:",
answer_keys=["name", "email", "phone"] # Required keys in response
)
Extracting specific information from text.
from edsl import QuestionExtract
q = QuestionExtract(
question_name="entities",
question_text="Extract all company names from the following text: {{ text }}",
answer_template={"companies": "List of company names"}
)
BM25-powered search through large option sets.
from edsl import QuestionDropdown
q = QuestionDropdown(
question_name="country",
question_text="Select your country:",
question_options=["Afghanistan", "Albania", ..., "Zimbabwe"] # Large list
)
Multiple choice with an "Other" option for custom responses.
from edsl import QuestionMultipleChoiceWithOther
q = QuestionMultipleChoiceWithOther(
question_name="source",
question_text="How did you hear about us?",
question_options=["Google", "Friend", "Advertisement"],
other_option_label="Other (please specify)"
)
Checkbox with an "Other" option for custom responses.
from edsl import QuestionCheckboxWithOther
q = QuestionCheckboxWithOther(
question_name="interests",
question_text="What are your interests?",
question_options=["Sports", "Music", "Reading"],
other_option_label="Other"
)
Select top K items from a list.
from edsl import QuestionTopK
q = QuestionTopK(
question_name="favorites",
question_text="Select your top 3 favorite items:",
question_options=["A", "B", "C", "D", "E"],
k=3
)
Python function-based question (not sent to LLM - computed locally).
from edsl import QuestionFunctional
def compute_sum(scenario, agent):
numbers = scenario.get("numbers", [])
return sum(numbers)
q = QuestionFunctional(
question_name="total",
question_text="Calculate the sum",
func=compute_sum
)
Use custom Pydantic models as response schemas.
from edsl import QuestionPydantic
from pydantic import BaseModel
class PersonInfo(BaseModel):
name: str
age: int
occupation: str
q = QuestionPydantic(
question_name="person",
question_text="Describe a person:",
pydantic_model=PersonInfo
)
Responses with markdown formatting.
from edsl import QuestionMarkdown
q = QuestionMarkdown(
question_name="formatted_response",
question_text="Write a formatted response with headers and lists."
)
All questions support these common parameters:
| Parameter | Description |
|---|---|
question_name | Unique identifier (valid Python identifier) |
question_text | The question text (supports Jinja2 templating) |
answering_instructions | Optional custom instructions for the LLM |
question_presentation | Optional custom presentation template |
| Type | Use Case | Key Parameter |
|---|---|---|
QuestionFreeText | Open-ended responses | - |
QuestionMultipleChoice | Single selection | question_options |
QuestionCheckBox | Multiple selections | question_options |
QuestionNumerical | Numbers | min_value, max_value |
QuestionYesNo | Binary yes/no | - |
QuestionLinearScale | Numeric scale | question_options, option_labels |
QuestionLikertFive | 5-point agree/disagree | - |
QuestionList | List of items | max_list_items |
QuestionRank | Ordering | question_options, num_selections |
QuestionMatrix | Grid/table | question_items, question_options |
QuestionBudget | Budget allocation | question_options, budget_sum |
QuestionDict | Key-value pairs | answer_keys |
QuestionExtract | Extract from text | answer_template |
QuestionDropdown | Large option sets | question_options |
EDSL uses Jinja2 templating to create dynamic questions. Template variables are enclosed in {{ }} and are rendered at runtime with values from scenarios, agents, or previous answers.
Scenarios provide key-value data that gets substituted into questions:
from edsl import QuestionFreeText, Scenario
q = QuestionFreeText(
question_name="opinion",
question_text="What do you think about {{ scenario.fruit }}?"
)
scenarios = [
Scenario({"fruit": "apples"}),
Scenario({"fruit": "oranges"}),
Scenario({"fruit": "bananas"})
]
results = q.by(scenarios).run()
q = QuestionFreeText(
question_name="review",
question_text="Review the {{ scenario.product }} priced at ${{ scenario.price }}."
)
scenario = Scenario({"product": "Widget X", "price": 29.99})
q = QuestionFreeText(
question_name="address",
question_text="Describe the location: {{ scenario.location.city }}, {{ scenario.location.country }}"
)
scenario = Scenario({
"location": {
"city": "Paris",
"country": "France"
}
})
q = QuestionFreeText(
question_name="summary",
question_text="Given this data: {{ scenario }}, provide a summary."
)
Reference agent traits in questions:
from edsl import QuestionFreeText, Agent
q = QuestionFreeText(
question_name="perspective",
question_text="As a {{ agent.occupation }}, what do you think about remote work?"
)
agent = Agent(traits={"occupation": "software engineer", "age": 35})
results = q.by(agent).run()
Reference previous answers within a survey:
from edsl import Survey, QuestionFreeText, QuestionMultipleChoice
q1 = QuestionFreeText(
question_name="name",
question_text="What is your name?"
)
q2 = QuestionFreeText(
question_name="greeting",
question_text="Hello {{ name.answer }}! How are you today?"
)
survey = Survey([q1, q2])
q = QuestionMultipleChoice(
question_name="preference",
question_text="Which {{ scenario.category }} do you prefer?",
question_options=[
"{{ scenario.option_a }}",
"{{ scenario.option_b }}",
"{{ scenario.option_c }}"
]
)
q = QuestionFreeText(
question_name="advice",
question_text="""
{% if scenario.age < 18 %}
As a young person, what advice would you give your peers?
{% else %}
As an adult, what advice would you give young people?
{% endif %}
"""
)
| Variable | Access Pattern | Example |
|---|---|---|
| Scenario value | {{ scenario.key }} | {{ scenario.fruit }} |
| Nested scenario | {{ scenario.obj.key }} | {{ scenario.location.city }} |
| Full scenario | {{ scenario }} | Converts to string |
| Agent trait | {{ agent.trait }} | {{ agent.occupation }} |
| Prior answer | {{ question_name.answer }} | {{ q1.answer }} |
{{ scenario.product_name }} over {{ scenario.p }}question.render(scenario_dict) to test rendering"{{ scenario.name | default('Unknown') }}"Rules define conditional navigation through surveys using Jinja2 template expressions.
| Type | When Evaluated | Purpose |
|---|---|---|
| Skip Rule | BEFORE question | Skip question entirely if condition is True |
| Navigation Rule | AFTER question | Jump to specific question based on answer |
| Stop Rule | AFTER question | End survey if condition is True |
survey = Survey([q1, q2, q3])
# Skip pet_name if no pet
survey = survey.add_skip_rule(
"pet_name",
"{{ has_pet.answer }} == 'No'"
)
survey = (survey
.add_rule("preference", "{{ preference.answer }} == 'A'", "section_a")
.add_rule("preference", "{{ preference.answer }} == 'B'", "section_b")
.add_rule("preference", "{{ preference.answer }} == 'C'", "section_c"))
# Also skip sections that shouldn't be shown
survey = (survey
.add_skip_rule("section_a", "{{ preference.answer }} != 'A'")
.add_skip_rule("section_b", "{{ preference.answer }} != 'B'")
.add_skip_rule("section_c", "{{ preference.answer }} != 'C'"))
survey = survey.add_stop_rule(
"eligibility",
"{{ eligibility.answer }} == 'No'"
)
"{{ question_name.answer }} == 'value'"
"{{ age.answer }} > 18"
"{{ q1.answer }} == 'yes' and {{ q2.answer }} != 'no'"
"{{ agent.persona }} == 'expert'"
"{{ scenario.condition }} == 'treatment'"
"randint(1, 10) > 5"
survey = survey.add_rule("q1", "{{ q1.answer }} == 'special'", "special_section", priority=1)
survey = survey.add_rule("q1", "{{ q1.answer }} != ''", "normal_section", priority=0)
from edsl.surveys.navigation_markers import EndOfSurvey
survey = survey.add_rule("screening", "{{ screening.answer }} == 'disqualified'", EndOfSurvey)
# Branching survey
survey = (Survey([q1, section_a, section_b, conclusion])
.add_rule("q1", "{{ q1.answer }} == 'A'", "section_a")
.add_rule("q1", "{{ q1.answer }} == 'B'", "section_b")
.add_skip_rule("section_a", "{{ q1.answer }} != 'A'")
.add_skip_rule("section_b", "{{ q1.answer }} != 'B'"))
# Screening with early exit
survey = (Survey([screener, main_q1, main_q2, main_q3])
.add_stop_rule("screener", "{{ screener.answer }} == 'No'"))
# Conditional follow-up
survey = (Survey([main_q, followup, next_q])
.add_skip_rule("followup", "{{ main_q.answer }} != 'Yes'"))
| Task | Method |
|---|---|
| Add skip rule | survey.add_skip_rule(question, expression) |
| Add navigation rule | survey.add_rule(question, expression, next_question) |
| Add stop rule | survey.add_stop_rule(question, expression) |
| Set priority | survey.add_rule(q, expr, next_q, priority=1) |
| View rules | survey.show_rules() |
| Jump to end | survey.add_rule(q, expr, EndOfSurvey) |
Memory controls which previous question-answer pairs an agent sees when answering each question.
| Mode | Description | Use Case |
|---|---|---|
| No Memory | Agent sees no prior answers | Independent questions |
| Full Memory | Agent sees ALL prior answers | Conversational surveys |
| Lagged Memory | Agent sees last N answers | Recent context only |
| Targeted Memory | Specific questions see specific priors | Precise control |
survey = Survey([q1, q2, q3, q4, q5])
survey = survey.set_full_memory_mode()
survey = Survey([q1, q2, q3, q4, q5])
survey = survey.set_lagged_memory(lags=2)
survey = survey.add_targeted_memory("q3", "q1")
survey = survey.add_memory_collection("summary", ["q1", "q2", "q3"])
# Chain multiple targeted memories
survey = (survey
.add_targeted_memory("q3", "q1")
.add_targeted_memory("q4", "q2")
.add_memory_collection("summary", ["q1", "q2", "q3", "q4"]))
survey = (Survey([intro, q1, q2, q3, q4, summary])
.set_lagged_memory(lags=1)
.add_memory_collection("summary", ["q1", "q2", "q3", "q4"]))
| Task | Method |
|---|---|
| Full memory | survey.set_full_memory_mode() |
| Lagged memory | survey.set_lagged_memory(lags=N) |
| Single targeted | survey.add_targeted_memory(focal, prior) |
| Multiple targeted | survey.add_memory_collection(focal, [priors]) |
| View memory plan | survey.memory_plan |
# Rename and auto-update ALL references (rules, memory, piping)
new_survey = survey.with_renamed_question("q1", "intro_question")
Combine multiple MC questions with same options into a matrix:
from edsl.surveys.survey_helpers.matrix_combiner import combine_multiple_choice_to_matrix
new_survey = combine_multiple_choice_to_matrix(
survey=survey,
question_names=["trust_freelancer", "trust_ai", "trust_agency"],
matrix_question_name="trust_matrix"
)
Auto-generate conditional follow-ups for each MC option:
q_restaurant = QuestionMultipleChoice(
question_name="restaurants",
question_text="Which restaurant do you prefer?",
question_options=["Italian", "Chinese", "Mexican"]
)
q_followup = QuestionFreeText(
question_name="why_restaurant",
question_text="Why do you like {{ restaurants.answer }}?"
)
survey = Survey([q_restaurant])
survey = survey.add_followup_questions("restaurants", q_followup)
survey = survey.delete_question("question_name")
survey = survey.move_question("question_name", new_index=0)
| Task | Method |
|---|---|
| Rename question | survey.with_renamed_question(old, new) |
| Combine to matrix | combine_multiple_choice_to_matrix(survey, names, new_name) |
| Add follow-ups | survey.add_followup_questions(ref_q, template) |
| Delete question | survey.delete_question(name) |
| Move question | survey.move_question(name, new_index) |
Visualize survey structure using Mermaid diagrams.
from edsl.surveys.survey_helpers.survey_mermaid import SurveyMermaidVisualization
viz = SurveyMermaidVisualization(survey)
mermaid_code = viz.to_mermaid()
print(mermaid_code)
viz = SurveyMermaidVisualization(
survey,
max_text_length=40,
show_options=True,
show_piping=True,
show_default_flow=True
)
| Element | Meaning |
|---|---|
Solid arrow --> | Sequential flow |
Dashed arrow -.-> | Skip rule |
| Solid arrow with label | Navigation rule |
| Dotted arrow | Piping dependency |
survey.show_rules() # Text-based rule table
dag = survey.dag # Dependency graph
| Task | Method |
|---|---|
| Create visualization | SurveyMermaidVisualization(survey) |
| Get Mermaid code | viz.to_mermaid() |
| Display in Jupyter | viz (auto-renders) |
| Show rules (text) | survey.show_rules() |
| Get DAG | survey.dag |