Skip to content
/

Prompts in YAML

Your first crewChapter 9 of 143 min read

Separate prompt definitions from Python code by moving agent personas and task specifications into declarative YAML configuration files.


Agents and tasks in YAML#

Create a config directory to house your YAML configurations. Define the agent personas in config/agents.yaml:

config/agents.yaml
# config/agents.yaml

reader:
  role: Contract analyst
  goal: Pull every commercially important term out of a contract, with its section number
  backstory: >
    You read contracts line by line for a procurement team. You quote the
    contract rather than paraphrase it, and you always note the section a
    term comes from.

risk_analyst:
  role: Commercial risk analyst
  goal: Spot the deadlines, costs, and one-sided terms that could hurt {customer}
  backstory: >
    You have reviewed hundreds of software agreements from the buyer's side.
    You know which clauses cost customers money: automatic renewals, price
    increases, short claim windows, and terms the vendor can change on its own.

fact_checker:
  role: Contract fact-checker
  goal: Make sure every claim in a contract memo matches the contract word for word
  backstory: >
    You are the last reviewer before a memo goes to the finance team. You
    check every number, date, and section reference against the source
    document and fix anything that does not match.

Define the corresponding task objectives and output formats in config/tasks.yaml:

config/tasks.yaml
# config/tasks.yaml

extract_terms:
  description: >
    Read the contract at {contract_path}. List its key terms: parties, dates,
    term and renewal, fees and payment, service levels, data handling,
    termination, liability, and any clause that lets one party change the
    deal on its own.
  expected_output: >
    A bulleted list of key terms. Each bullet quotes the contract and ends
    with its section number.

assess_risks:
  description: >
    Using the key terms, write a risk memo for {customer}. Pick the five terms
    most likely to cost them money or catch them out, and say what they
    should do about each one.
  expected_output: >
    A Markdown memo of no more than 350 words: a two-sentence summary, then a
    numbered list of five risks. Each risk has a section number, why it
    matters, and a recommended action.

fact_check:
  description: >
    Check every claim in the risk memo against the contract at {contract_path}.
    Fix any number, date, or section reference that does not match the
    contract, and remove anything the contract does not say.
  expected_output: >
    The corrected memo in Markdown, followed by a "Corrections" section that
    lists each change you made, or says "None".

Load the config#

Update review_crew.py to deserialize the YAML files dynamically and write output to output/review.md:

review_crew.py
# review_crew.py

from pathlib import Path

import yaml
from crewai import Agent, Crew, Process, Task
from crewai_tools import FileReadTool
from dotenv import load_dotenv

load_dotenv()

CONFIG_DIR = Path(__file__).parent / "config"


def load_config(name):
    with open(CONFIG_DIR / f"{name}.yaml") as f:
        return yaml.safe_load(f)


agents_config = load_config("agents")
tasks_config = load_config("tasks")

read_file = FileReadTool()

# agents

reader = Agent(**agents_config["reader"], tools=[read_file], verbose=True)
risk_analyst = Agent(**agents_config["risk_analyst"], verbose=True)
fact_checker = Agent(**agents_config["fact_checker"], tools=[read_file], verbose=True)

# tasks

extract_terms = Task(**tasks_config["extract_terms"], agent=reader)
assess_risks = Task(**tasks_config["assess_risks"], agent=risk_analyst)
fact_check = Task(**tasks_config["fact_check"], agent=fact_checker, output_file="output/review.md")

crew = Crew(
    agents=[reader, risk_analyst, fact_checker],
    tasks=[extract_terms, assess_risks, fact_check],
    process=Process.sequential,
    verbose=True,
)

if __name__ == "__main__":
    result = crew.kickoff(
        inputs={
            "contract_path": "contracts/acme-saas-agreement.md",
            "customer": "Northwind Traders",
        }
    )
    print(result.raw)

Key improvements:

  1. Configuration decoupling: Unpacking dictionaries with **agents_config[...] passes parameters without embedding prompt strings in application code.
  1. Automated artifact persistence: Setting output_file="output/review.md" saves the finalized memo directly to disk.

Execute the updated script:

Terminal
(env)$ python review_crew.py

The verified memo is displayed in your terminal and saved to output/review.md.