AgentSkillsCN

edsl-survey-rules

添加跳过逻辑、导航规则与停止规则,灵活掌控调查问卷的流程。

SKILL.md
--- frontmatter
name: edsl-survey-rules
description: Add skip logic, navigation rules, and stop rules to control survey flow
allowed-tools: Read, Glob, Bash(python:*)

Survey Rules and Flow Control

Rules define conditional navigation through surveys using Jinja2 template expressions.

Rule Types

TypeWhen EvaluatedPurpose
Skip RuleBEFORE questionSkip question entirely if condition is True
Navigation RuleAFTER questionJump to specific question based on answer
Stop RuleAFTER questionEnd survey if condition is True

Skip Rules (Before Rules)

Skip a question entirely based on previous answers:

python
from edsl import Survey, QuestionMultipleChoice, QuestionFreeText

q1 = QuestionMultipleChoice(
    question_name="has_pet",
    question_text="Do you have a pet?",
    question_options=["Yes", "No"]
)
q2 = QuestionFreeText(
    question_name="pet_name",
    question_text="What is your pet's name?"
)
q3 = QuestionFreeText(
    question_name="conclusion",
    question_text="Any final thoughts?"
)

survey = Survey([q1, q2, q3])

# Skip pet_name if no pet
survey = survey.add_skip_rule(
    "pet_name",
    "{{ has_pet.answer }} == 'No'"
)

Navigation Rules (After Rules)

Jump to a different question based on the answer:

python
q1 = QuestionMultipleChoice(
    question_name="preference",
    question_text="Which do you prefer?",
    question_options=["A", "B", "C"]
)
q2a = QuestionFreeText(question_name="section_a", question_text="Section A questions...")
q2b = QuestionFreeText(question_name="section_b", question_text="Section B questions...")
q2c = QuestionFreeText(question_name="section_c", question_text="Section C questions...")
q3 = QuestionFreeText(question_name="conclusion", question_text="Final question...")

survey = Survey([q1, q2a, q2b, q2c, q3])

# Add navigation rules (chain them)
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'"))

Stop Rules (Early Termination)

End the survey when a condition is met:

python
q1 = QuestionMultipleChoice(
    question_name="eligibility",
    question_text="Are you 18 or older?",
    question_options=["Yes", "No"]
)

survey = Survey([q1, q2, q3])

# End survey if not eligible
survey = survey.add_stop_rule(
    "eligibility",
    "{{ eligibility.answer }} == 'No'"
)

Expression Syntax

Expressions use Jinja2 template syntax:

python
# Reference answers
"{{ question_name.answer }} == 'value'"
"{{ age.answer }} > 18"
"{{ score.answer }} >= 50 and {{ score.answer }} <= 100"

# String comparisons
"{{ color.answer }} == 'Red'"
"{{ color.answer }} != 'Blue'"
"{{ color.answer }} in ['Red', 'Green', 'Blue']"

# Numeric comparisons
"{{ age.answer }} > 25"
"{{ age.answer }} >= 18 and {{ age.answer }} <= 65"

# Logical operators
"{{ q1.answer }} == 'yes' and {{ q2.answer }} != 'no'"
"{{ q1.answer }} == 'yes' or {{ q2.answer }} == 'yes'"

# Reference agent traits
"{{ agent.persona }} == 'expert'"

# Reference scenario parameters
"{{ scenario.condition }} == 'treatment'"

# Random functions
"randint(1, 10) > 5"

Rule Priority

When multiple rules apply, higher priority wins:

python
# Default rules have priority -1
# Custom rules default to priority 0

# High priority rule takes precedence
survey = survey.add_rule("q1", "{{ q1.answer }} == 'special'", "special_section", priority=1)
survey = survey.add_rule("q1", "{{ q1.answer }} != ''", "normal_section", priority=0)

EndOfSurvey Marker

Navigate directly to end of survey:

python
from edsl.surveys.navigation_markers import EndOfSurvey

# Jump to end on certain answer
survey = survey.add_rule("screening", "{{ screening.answer }} == 'disqualified'", EndOfSurvey)

View Rules

python
# Show all rules in the survey
survey.show_rules()

# Access rule collection
rules = survey.rule_collection
print(rules.non_default_rules)

Common Patterns

Branching Survey

python
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

python
survey = (Survey([screener, main_q1, main_q2, main_q3])
    .add_stop_rule("screener", "{{ screener.answer }} == 'No'"))

Conditional Follow-up

python
survey = (Survey([main_q, followup, next_q])
    .add_skip_rule("followup", "{{ main_q.answer }} != 'Yes'"))

Quick Reference

TaskMethod
Add skip rulesurvey.add_skip_rule(question, expression)
Add navigation rulesurvey.add_rule(question, expression, next_question)
Add stop rulesurvey.add_stop_rule(question, expression)
Set prioritysurvey.add_rule(q, expr, next_q, priority=1)
View rulessurvey.show_rules()
Jump to endsurvey.add_rule(q, expr, EndOfSurvey)