AgentSkillsCN

edsl-templating

在问题中运用Jinja2模板引擎,支持场景、代理、管道传输以及动态内容的嵌入。

SKILL.md
--- frontmatter
name: edsl-templating
description: Jinja2 templating in questions for scenarios, agents, piping, and dynamic content
allowed-tools: Read, Glob, Bash(python:*)

Jinja2 Templating in Questions

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.

Scenario Templating

Scenarios provide key-value data that gets substituted into questions:

python
from edsl import QuestionFreeText, Scenario

# Question with scenario variable
q = QuestionFreeText(
    question_name="opinion",
    question_text="What do you think about {{ scenario.fruit }}?"
)

# Create scenarios
scenarios = [
    Scenario({"fruit": "apples"}),
    Scenario({"fruit": "oranges"}),
    Scenario({"fruit": "bananas"})
]

# Run survey with scenarios - each generates a separate response
results = q.by(scenarios).run()

Multiple Variables

python
q = QuestionFreeText(
    question_name="review",
    question_text="Review the {{ scenario.product }} priced at ${{ scenario.price }}."
)

scenario = Scenario({"product": "Widget X", "price": 29.99})

Nested Scenario Data

python
q = QuestionFreeText(
    question_name="address",
    question_text="Describe the location: {{ scenario.location.city }}, {{ scenario.location.country }}"
)

scenario = Scenario({
    "location": {
        "city": "Paris",
        "country": "France"
    }
})

Full Scenario Access

python
# Access entire scenario as string
q = QuestionFreeText(
    question_name="summary",
    question_text="Given this data: {{ scenario }}, provide a summary."
)

Agent Templating

Reference agent traits in questions:

python
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()

Multiple Agent Traits

python
q = QuestionFreeText(
    question_name="intro",
    question_text="You are {{ agent.name }}, a {{ agent.age }}-year-old {{ agent.occupation }}. Introduce yourself."
)

agent = Agent(traits={"name": "Alice", "age": 28, "occupation": "teacher"})

Piping (Answer References)

Reference previous answers within a survey:

python
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?"
)

q3 = QuestionMultipleChoice(
    question_name="mood",
    question_text="{{ name.answer }}, which best describes your current mood?",
    question_options=["Happy", "Neutral", "Sad"]
)

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

Piping in Options

python
q1 = QuestionFreeText(
    question_name="hobby",
    question_text="What is your favorite hobby?"
)

q2 = QuestionMultipleChoice(
    question_name="frequency",
    question_text="How often do you engage in {{ hobby.answer }}?",
    question_options=["Daily", "Weekly", "Monthly", "Rarely"]
)

Combining Sources

You can combine scenario, agent, and piping references:

python
q = QuestionFreeText(
    question_name="comprehensive",
    question_text="""
    {{ agent.name }} ({{ agent.occupation }}),
    regarding {{ scenario.topic }}:
    You previously said "{{ prior_question.answer }}".
    Please elaborate on your thoughts.
    """
)

Templating in Question Options

Options can also use templates:

python
q = QuestionMultipleChoice(
    question_name="preference",
    question_text="Which {{ scenario.category }} do you prefer?",
    question_options=[
        "{{ scenario.option_a }}",
        "{{ scenario.option_b }}",
        "{{ scenario.option_c }}"
    ]
)

scenario = Scenario({
    "category": "fruit",
    "option_a": "Apples",
    "option_b": "Oranges",
    "option_c": "Bananas"
})

Conditional Logic in Templates

Jinja2 supports conditionals and loops:

python
# Conditional text
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 %}
    """
)

# Loop in text
q = QuestionFreeText(
    question_name="items_review",
    question_text="""
    Review these items:
    {% for item in scenario.items %}
    - {{ item }}
    {% endfor %}
    """
)

Template Variables Reference

VariableAccess PatternExample
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 }}

Best Practices

  1. Use descriptive scenario keys: {{ scenario.product_name }} over {{ scenario.p }}

  2. Test templates: Use question.render(scenario_dict) to test rendering:

    python
    q = QuestionFreeText(
        question_name="test",
        question_text="Opinion on {{ scenario.topic }}?"
    )
    rendered = q.render({"topic": "AI"})
    print(rendered.question_text)  # "Opinion on AI?"
    
  3. Handle missing values: Provide defaults with Jinja2 filters:

    python
    "{{ scenario.name | default('Unknown') }}"
    
  4. Avoid forward references: In piping, only reference questions that come BEFORE the current question in the survey.

Common Patterns

Survey with Scenarios

python
from edsl import Survey, QuestionFreeText, Scenario, ScenarioList

q = QuestionFreeText(
    question_name="opinion",
    question_text="What do you think of {{ scenario.item }}?"
)

survey = Survey([q])
scenarios = ScenarioList([
    Scenario({"item": "electric cars"}),
    Scenario({"item": "solar panels"}),
    Scenario({"item": "wind turbines"})
])

results = survey.by(scenarios).run()

Personalized Questions with Agents

python
from edsl import Survey, QuestionFreeText, Agent, AgentList

q = QuestionFreeText(
    question_name="view",
    question_text="As a {{ agent.role }}, what's your view on automation?"
)

agents = AgentList([
    Agent(traits={"role": "factory worker"}),
    Agent(traits={"role": "CEO"}),
    Agent(traits={"role": "software developer"})
])

results = Survey([q]).by(agents).run()

Dynamic Follow-up with Piping

python
q1 = QuestionMultipleChoice(
    question_name="preference",
    question_text="Which do you prefer?",
    question_options=["Option A", "Option B", "Option C"]
)

q2 = QuestionFreeText(
    question_name="why",
    question_text="You chose {{ preference.answer }}. Why do you prefer it?"
)

survey = Survey([q1, q2])