Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Simple AI Workflow with Reflection, Structured Output and Validation

Authored by Dr. Tiziana Ligorio for AI Agents - CSCI 395.32 taught at Hunter College of The City University of New York

In this version, we augment the single-round reflection workflow with structured outputs, validation, and bounded retries so that only valid outputs are passed from one step to the next; everything else remains the same.

workflow

Our workflow consists of three steps, each handled by an LLM with a distinct role:

  1. Report Writer (think journalist): Generates an initial report based on a user-provided topic

  2. Critic (think editor): Provides detailed critique and improvement suggestions

  3. Reviser (think senior reporter): Takes the original report and critique to produce a final version

The purpose is to see how outputs from multiple LLM calls can be connected. A reflection workflow is more elaborate than a single call, but it is not automatically better. We will inspect the draft, critique, and revision to decide what changed and whether the change helped.

We use the OpenAI SDK directly, with OpenRouter as our provider, to keep the implementation transparent: no orchestration framework, just API calls that can be followed step by step.

Installs and Imports

%%capture
%pip install -q "openai>=2.0.0" "python-dotenv>=1.0.0"

%%capture hides installation output to keep the notebook readable. %pip installs packages into the Python environment used by the current notebook kernel.

# OpenAI SDK: provides a clean interface for calling LLMs
# We'll use it with OpenRouter, which is OpenAI API-compatible
from openai import OpenAI

# Standard library
import json
import os

OpenRouter provides access to models from multiple providers through one API. Model availability, pricing, and free-model options can change, so check the current OpenRouter model list before choosing a model.

This notebook follows OpenRouter’s documented integration with the OpenAI SDK. Other services may also describe themselves as OpenAI-compatible, but their supported endpoints and parameters can differ.

Setup your API Key

Step 1: Get an OpenRouter API key

For this demo we will use an LLM via OpenRouter, which requires an API key.

  1. Go to https://openrouter.ai

  2. Sign in (or create an account if you don’t have one)

  3. Once logged in, navigate to https://openrouter.ai/settings/keys

  4. Click Create Key

  5. Give the key a name, e.g. colab-reflection-workflow

  6. Copy the key immediately (you won’t be able to see it again)

Important: Treat this key like a password. Do not share it, paste it into notebooks, or commit it to GitHub.

Step 2: Store the API key

If running in Google Colab:

  1. On the left sidebar, click 🔑 Secrets

  2. Add a new secret:

    • Name: OPENROUTER_API_KEY

    • Value: your actual API key

  3. Toggle the switch to give notebook access (you should see a checkmark)

If running locally:

  1. Create a .env file in the project root:

    touch .env
  2. Add the following (replace with your own key):

    OPENROUTER_API_KEY=your_openrouter_key_here

Important: Never paste API keys directly into code cells.

Load the API Key

In Colab:

Uncomment and run the cell below if you’re using Google Colab.

# # Uncomment the lines below if running in Google Colab
# from google.colab import userdata
# os.environ["OPENROUTER_API_KEY"] = userdata.get("OPENROUTER_API_KEY")
# print("API key loaded from Colab Secrets")

Locally:

Run the cell below if you’re running locally with a .env file.

# Load a local .env file when one is present.
# This does not replace a key already loaded from Colab Secrets.
from dotenv import load_dotenv

env_file_found = load_dotenv(dotenv_path=".env")
print("Local .env file found:", env_file_found)
Local .env file found: True
# Sanity check: verify that a non-empty API key is available.
api_key = os.getenv("OPENROUTER_API_KEY")
assert api_key, "OPENROUTER_API_KEY not found. Please check your setup."
print("OPENROUTER_API_KEY present:", bool(api_key))
OPENROUTER_API_KEY present: True

Initialize the LLM Client

We use the OpenAI SDK to communicate with OpenRouter. OpenRouter documents this SDK integration and provides an OpenAI-compatible Chat Completions endpoint.

This demo uses gpt-5.6-luna, a current OpenAI model that is cost-sensitive. It is not a source of verified facts: generated factual claims should still be checked, especially for changing topics.

Models do not all support the same request settings. OpenRouter’s current model information lists reasoning_effort for this model but does not list temperature, so this notebook does not send a temperature setting. If you choose another model, check its supported parameters in the OpenRouter model list.

# Initialize the OpenAI client pointing to OpenRouter.
client = OpenAI(
    base_url="https://openrouter.ai/api/v1",
    api_key=api_key,
)

# Use one model and one reasoning setting for all three roles.
MODEL = "openai/gpt-5.6-luna"
REASONING_EFFORT = "none"

print(f"Client initialized. Using model: {MODEL}")
print(f"Reasoning effort: {REASONING_EFFORT}")
Client initialized. Using model: openai/gpt-5.6-luna
Reasoning effort: none

Structured Outputs and Validation

A structured output schema defines the exact shape and data types an LLM’s response should follow. Instead of returning free-form text, the model is instructed to produce predictable fields. For example, a Writer returns a title, a list of sections, and a conclusion. This makes the output easier for code to validate and safely pass to the next workflow step. If required fields are missing, empty, or malformed, the workflow can detect the problem, request a corrected response, and avoid silently propagating invalid data.

Each LLM call is expected to return a small JSON object with a known schema. Before an output is passed to the next step, we programmatically check that it has the required fields and basic content.

If validation fails, the same step is retried with specific feedback about what was missing. Retries are bounded by MAX_ATTEMPTS. A malformed response is never silently passed forward.

# A small, predefined bound keeps retries predictable.
MAX_ATTEMPTS = 2

WRITER_SCHEMA = {
    "type": "object",
    "properties": {
        "title": {"type": "string"},
        "sections": {"type": "array", "items": {"type": "string"}},
        "conclusion": {"type": "string"},
    },
    "required": ["title", "sections", "conclusion"],
    "additionalProperties": False,
}

CRITIC_SCHEMA = {
    "type": "object",
    "properties": {
        "strengths": {"type": "array", "items": {"type": "string"}},
        "problems": {"type": "array", "items": {"type": "string"}},
        "suggestions": {"type": "array", "items": {"type": "string"}},
    },
    "required": ["strengths", "problems", "suggestions"],
    "additionalProperties": False,
}

REVISER_SCHEMA = {
    "type": "object",
    "properties": {"revised_report": {"type": "string"}},
    "required": ["revised_report"],
    "additionalProperties": False,
}
def validate_writer(data):
    errors = []
    for field in ("title", "sections", "conclusion"):
        if field not in data:
            errors.append(f"missing required field: {field}")
    return errors


def validate_critic(data):
    errors = []
    for field in ("strengths", "problems", "suggestions"):
        if field not in data:
            errors.append(f"missing required field: {field}")
        elif not isinstance(data[field], list) or not data[field]:
            errors.append(f"{field} must be a non-empty list")
    return errors


def validate_reviser(data):
    if "revised_report" not in data:
        return ["missing required field: revised_report"]
    if not isinstance(data["revised_report"], str) or not data["revised_report"].strip():
        return ["revised_report must contain non-empty text"]
    return []


def call_structured_step(messages, schema_name, schema, validator, model=MODEL):
    """Call one workflow step, validate it, and retry with specific feedback."""
    feedback = None

    for attempt in range(1, MAX_ATTEMPTS + 1):
        attempt_messages = list(messages)
        if feedback:
            attempt_messages.append({
                "role": "user",
                "content": f"Your previous output was invalid. Fix these issues: {feedback}",
            })

        response = client.chat.completions.create(
            model=model,
            messages=attempt_messages,
            reasoning_effort=REASONING_EFFORT,
            response_format={
                "type": "json_schema",
                "json_schema": {"name": schema_name, "strict": True, "schema": schema},
            },
        )

        raw_output = response.choices[0].message.content or ""
        try:
            data = json.loads(raw_output)
            errors = validator(data) if isinstance(data, dict) else ["output must be a JSON object"]
        except json.JSONDecodeError as error:
            data = None
            errors = [f"output was not valid JSON: {error.msg}"]

        if not errors:
            return data, response

        feedback = "; ".join(errors)
        print(f"{schema_name} attempt {attempt} failed validation: {feedback}")

    raise RuntimeError(
        f"{schema_name} failed validation after {MAX_ATTEMPTS} attempts: {feedback}"
    )


def format_writer_output(data):
    """Turn the validated Writer object into readable report text."""
    return "\n\n".join([data["title"], *data["sections"], data["conclusion"]])


def format_critique(data):
    """Turn the validated Critic object into readable feedback."""
    blocks = []
    for label, field in (("Strengths", "strengths"), ("Problems", "problems"), ("Suggestions", "suggestions")):
        blocks.append(label + ":\n- " + "\n- ".join(data[field]))
    return "\n\n".join(blocks)

Step 1: The Report Writer

Our workflow begins with the Report Writer, an LLM instructed to act as a journalist who writes an initial report on a given topic.

Giving the model a role

The system message supplies instructions that should guide the model when it responds to the user message. It is part of the list of messages sent in the API request.

The OpenAI SDK uses a message format like this:

messages = [
    {"role": "system", "content": "You are a..."},  # Instructions for the model
    {"role": "user", "content": "..."},             # The request and its context
]

For our Report Writer:

  • System message: Instructs the LLM to behave as a journalist writing informative reports

  • User message: Supplies the topic and asks for a concise, well-structured report

The user message does not have to be the raw topic by itself. We can add context or instructions around it, for example, Write a concise, well-structured report on the following topic: {topic}.

# System prompt that defines the Report Writer persona
WRITER_SYSTEM_PROMPT = """You are a journalist who writes clear, informative reports.

When given a topic, write a short report that:
- Provides a balanced overview of the topic
- Includes relevant context and background
- Is written in a professional, accessible style

Return the report using the required structured output schema."""
def generate_initial_report(topic: str, system_prompt: str = WRITER_SYSTEM_PROMPT, model: str = MODEL, return_response=False):
    """Generate and validate the Writer's structured output."""
    data, response = call_structured_step(
        messages=[
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": f"Write a concise report on: {topic}"},
        ],
        schema_name="writer_output",
        schema=WRITER_SCHEMA,
        validator=validate_writer,
        model=model,
    )
    return (data, response) if return_response else data

The function above requests the Writer schema, validates the required fields, and retries at most MAX_ATTEMPTS times with concrete feedback. If all attempts fail, it raises an error and the workflow stops before an invalid draft can reach the Critic.

For this demonstration, we keep the complete response object for inspection and reuse the same validated output in the workflow.

Pedagogical note

The SDK returns more than the generated text. We will keep the complete response object so we can inspect its fields before extracting the report.

# Make one validated Writer call and keep the complete response object.
topic = "The impact of artificial intelligence on healthcare"

writer_output, response = generate_initial_report(topic, return_response=True)
response.model_dump()
{'id': 'gen-1789455144-Ivsbq3ArfgByXYaLseg7', 'choices': [{'finish_reason': 'stop', 'index': 0, 'logprobs': None, 'message': {'content': '{"title":"Artificial Intelligence’s Impact on Healthcare","sections":["Artificial intelligence (AI) is increasingly used in healthcare to analyze medical images, support diagnosis, predict patient risks, and personalize treatment. Machine-learning systems can identify patterns in scans and laboratory results, while administrative tools can automate scheduling, documentation, and billing. These applications may improve efficiency, expand access to expertise, and help clinicians detect disease earlier.","AI also presents important challenges. Systems trained on incomplete or unrepresentative data can produce biased results, potentially worsening health disparities. Errors, cybersecurity threats, unclear accountability, and privacy concerns are significant risks, particularly when sensitive patient information is involved. Overreliance on automated recommendations could also weaken clinical judgment if tools are poorly validated or used without adequate oversight.","The technology’s benefits therefore depend on responsible implementation. Effective safeguards include rigorous testing across diverse populations, transparent performance standards, human review, strong data protection, and clear regulation. AI is most likely to have a positive impact when it supports—not replaces—health professionals and when patients are informed about how it is used."],"conclusion":"AI has the potential to make healthcare more accurate, efficient, and accessible, but its value is not automatic. Continued evaluation, ethical governance, and clinical oversight will be essential to ensure that innovation improves outcomes while protecting patient safety, privacy, and equity."}', 'refusal': None, 'role': 'assistant', 'annotations': None, 'audio': None, 'function_call': None, 'tool_calls': None, 'reasoning': None}, 'native_finish_reason': 'completed'}], 'created': 1789455144, 'model': 'openai/gpt-5.6-luna', 'object': 'chat.completion', 'moderation': None, 'service_tier': 'default', 'system_fingerprint': None, 'usage': {'completion_tokens': 276, 'prompt_tokens': 124, 'total_tokens': 400, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None, 'image_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cache_write_tokens': 0, 'cached_tokens': 0, 'video_tokens': 0}, 'cost': 0.000356, 'is_byok': False, 'cost_details': {'upstream_inference_cost': 0.000356, 'upstream_inference_prompt_cost': 2.48e-05, 'upstream_inference_completions_cost': 0.0003312}}, 'provider': 'OpenAI'}

Now extract readable report text from the same validated structured output. This avoids paying for a second Writer call and ensures the inspected response corresponds to the report used below.

# Convert the validated Writer object to text for display and for the Critic.
initial_report = format_writer_output(writer_output)
initial_report
'Artificial Intelligence’s Impact on Healthcare\n\nArtificial intelligence (AI) is increasingly used in healthcare to analyze medical images, support diagnosis, predict patient risks, and personalize treatment. Machine-learning systems can identify patterns in scans and laboratory results, while administrative tools can automate scheduling, documentation, and billing. These applications may improve efficiency, expand access to expertise, and help clinicians detect disease earlier.\n\nAI also presents important challenges. Systems trained on incomplete or unrepresentative data can produce biased results, potentially worsening health disparities. Errors, cybersecurity threats, unclear accountability, and privacy concerns are significant risks, particularly when sensitive patient information is involved. Overreliance on automated recommendations could also weaken clinical judgment if tools are poorly validated or used without adequate oversight.\n\nThe technology’s benefits therefore depend on responsible implementation. Effective safeguards include rigorous testing across diverse populations, transparent performance standards, human review, strong data protection, and clear regulation. AI is most likely to have a positive impact when it supports—not replaces—health professionals and when patients are informed about how it is used.\n\nAI has the potential to make healthcare more accurate, efficient, and accessible, but its value is not automatic. Continued evaluation, ethical governance, and clinical oversight will be essential to ensure that innovation improves outcomes while protecting patient safety, privacy, and equity.'

Step 2: The Critic

Now that we have an initial report, we pass it to the Critic, an LLM prompted to act as an editor who reviews the work and provides constructive feedback.

The Critic doesn’t rewrite the report. Instead, it identifies:

  • Areas that need clarification or more detail

  • Structural or logical issues

  • Missing perspectives or context

  • Ways to improve clarity and impact

This separation of concerns (writing vs. critiquing) is key to the reflection pattern. By having a dedicated critic, we get focused, actionable feedback rather than a muddled attempt to both evaluate and fix at once.

# System prompt that defines the Critic persona
CRITIC_SYSTEM_PROMPT = """You are an editor who provides constructive feedback on reports.

Identify strengths, problems, and specific suggestions for improvement. Do not rewrite the report.
Return the critique using the required structured output schema."""
def generate_critique(report: str, system_prompt: str = CRITIC_SYSTEM_PROMPT, model: str = MODEL):
    """Generate and validate the Critic's structured output."""
    data, _ = call_structured_step(
        messages=[
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": f"Please critique this report:\n\n{report}"},
        ],
        schema_name="critic_output",
        schema=CRITIC_SCHEMA,
        validator=validate_critic,
        model=model,
    )
    return data

The validated output of Step 1 becomes the input to Step 2. The Critic must return three non-empty lists. If it cannot do so within the attempt limit, the workflow stops and reports that the draft was not evaluated.

# Generate and validate the critique. Critic failure stops the workflow.
try:
    critic_output = generate_critique(initial_report)
    critique = format_critique(critic_output)
except RuntimeError as error:
    raise RuntimeError("Workflow stopped: the draft was not evaluated.") from error

critique
'Strengths:\n- Clearly identifies major healthcare applications of AI, including medical imaging, diagnosis, risk prediction, treatment personalization, and administrative automation.\n- Presents a balanced discussion by addressing both potential benefits and significant risks rather than portraying AI as universally beneficial or harmful.\n- Recognizes important ethical and practical concerns, including bias, privacy, cybersecurity, accountability, validation, and overreliance on automated recommendations.\n- Offers appropriate safeguards, such as testing across diverse populations, transparency, human oversight, data protection, regulation, and patient notification.\n- The report is concise, coherent, and logically organized, moving from applications to challenges, safeguards, and an overall conclusion.\n- Uses appropriately cautious language and avoids unsupported numerical claims or exaggerated conclusions.\n\nProblems:\n- The discussion remains general and would be more persuasive with specific examples, evidence, or citations to studies, healthcare systems, or documented AI applications.\n- The report does not distinguish clearly between different types of AI tools, such as diagnostic systems, predictive models, generative AI, and administrative automation, even though their risks and evaluation requirements differ.\n- Several benefits—such as improved access, earlier detection, and greater accuracy—are asserted without explaining when or how they occur or acknowledging limitations such as false positives, implementation costs, and uneven access to technology.\n- The treatment of bias is accurate but brief; it does not explain how bias can enter through data collection, labeling, model design, deployment settings, or unequal healthcare access.\n- The report mentions regulation and accountability without identifying who should be responsible when an AI-supported decision causes harm, such as developers, healthcare organizations, clinicians, or regulators.\n- Patient perspectives are underdeveloped. The report briefly mentions informing patients but does not address consent, the right to challenge automated decisions, trust, or the accessibility of explanations.\n- The conclusion largely repeats earlier points and could provide a more precise judgment about the conditions under which AI is most beneficial.\n\nSuggestions:\n- Add two or three concrete examples, such as AI-assisted radiology, sepsis-risk prediction, or automated clinical documentation, and explain both their demonstrated benefits and limitations.\n- Include credible sources or statistics to support claims about accuracy, efficiency, access, health disparities, and patient outcomes.\n- Differentiate applications by risk level and explain why diagnostic and treatment systems require stricter validation than scheduling or billing tools.\n- Expand the bias discussion by describing representative data, subgroup performance testing, ongoing monitoring, and procedures for correcting unequal outcomes.\n- Clarify accountability by outlining the respective responsibilities of developers, healthcare institutions, clinicians, and regulators.\n- Discuss implementation requirements, including staff training, integration with clinical workflows, cost, interoperability, and mechanisms for reporting errors.\n- Strengthen the patient-centered perspective by addressing informed consent, privacy protections, communication of AI involvement, and patients’ ability to seek human review.\n- End with a more specific evaluative claim—for example, that AI should be adopted selectively where evidence of improved patient outcomes outweighs risks and where continuous oversight is feasible.'
print("Critique word count:", len(critique.split()))
Critique word count: 477

Step 3: The Reviser

The Reviser receives both the original report and the critique, then produces another version.

The Reviser has:

  • The initial draft

  • The critic’s comments

This gives it an opportunity to make targeted changes while preserving useful parts of the draft. However, the critic may miss a problem or suggest an unhelpful change, and the reviser may not follow good advice. We therefore need to inspect the final version rather than assume it improved.

# System prompt that defines the Reviser persona
REVISER_SYSTEM_PROMPT = """You are a senior reporter who produces polished final reports.

Revise the original report by addressing the critique while preserving its useful content and voice.
Return the revision using the required structured output schema."""
def generate_revised_report(report: str, critique: str, system_prompt: str = REVISER_SYSTEM_PROMPT, model: str = MODEL):
    """Generate and validate the Reviser's structured output."""
    user_message = f"""Revise the report using the editorial feedback.

ORIGINAL REPORT:
{report}

EDITORIAL FEEDBACK:
{critique}"""

    data, _ = call_structured_step(
        messages=[
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": user_message},
        ],
        schema_name="reviser_output",
        schema=REVISER_SCHEMA,
        validator=validate_reviser,
        model=model,
    )
    return data

The Reviser receives only validated inputs. Its output must contain non-empty revised_report text. If all attempts fail, the predefined fallback preserves the original draft and critique instead of silently passing malformed output forward.

# Generate and validate the revision. On failure, preserve prior valid work.
try:
    reviser_output = generate_revised_report(initial_report, critique)
    final_report = reviser_output["revised_report"]
except RuntimeError as error:
    final_report = initial_report
    print("Revision failed; preserving the original draft and critique.")
    print(error)

final_report
'# Artificial Intelligence’s Impact on Healthcare\n\nArtificial intelligence (AI) is moving from research settings into everyday healthcare, but its effects depend heavily on the type of tool and how it is implemented. Diagnostic systems analyze medical images, predictive models estimate risks such as hospital deterioration, generative AI drafts clinical notes or patient communications, and administrative systems assist with scheduling, coding, and billing. These applications do not carry the same level of risk: an erroneous appointment reminder is usually less dangerous than a flawed cancer-screening result or treatment recommendation. Diagnostic and treatment tools therefore require especially rigorous clinical validation, subgroup testing, and human review.\n\nSome applications show practical promise. AI-assisted radiology tools can flag abnormalities and help prioritize scans for review, potentially supporting earlier detection and reducing workloads. However, they may produce false positives, miss unusual cases, or perform less reliably when images differ from those used in training. Predictive models for conditions such as sepsis may help clinicians identify high-risk patients sooner, but sepsis definitions vary, alerts can be inaccurate, and excessive warnings may contribute to alert fatigue. Generative AI can reduce the time clinicians spend drafting documentation, yet it may invent details, omit important information, or expose confidential data if deployed through insecure systems. Administrative automation may offer efficiency with comparatively lower clinical risk, but it can still create access problems if scheduling or billing systems are inaccurate or difficult for patients to use.\n\nClaims of improved accuracy, access, or efficiency should therefore be understood as conditional rather than automatic. Benefits depend on representative training data, reliable integration with electronic health records, interoperable systems, staff training, adequate funding, and workflows that allow clinicians to verify outputs. Implementation costs may disadvantage smaller or under-resourced hospitals, while uneven broadband access, language support, and digital literacy can widen disparities rather than expand access. AI may also increase testing or referrals through false positives, producing financial and emotional costs for patients.\n\nBias can enter at several stages. Data may underrepresent particular racial, ethnic, age, gender, disability, or socioeconomic groups; labels may reflect existing disparities or inconsistent clinical judgments; model design may optimize overall accuracy while masking poor performance for smaller subgroups; and deployment in a setting different from the training environment can change results. Unequal access to follow-up care can further worsen the consequences of an inaccurate prediction. Responsible use requires representative data, performance testing across relevant subgroups, public reporting of limitations, continuous monitoring after deployment, and procedures for investigating and correcting unequal outcomes. Models should be reevaluated when populations, clinical practices, or data systems change.\n\nAccountability must be shared but clearly assigned. Developers should document training data, intended uses, known limitations, security protections, and model updates. Healthcare organizations should conduct local validation, oversee procurement, train staff, protect patient information, monitor outcomes, and provide mechanisms for reporting errors. Clinicians should use AI within their professional judgment, verify consequential recommendations, and explain uncertainty to patients. Regulators should establish risk-based standards for safety, transparency, cybersecurity, post-market monitoring, and auditing. When an AI-supported decision causes harm, responsibility should not be shifted to the algorithm alone; investigators should examine the roles of the developer, institution, clinician, and governance systems involved.\n\nPatients also need a meaningful role. They should be told when AI materially contributes to diagnosis, treatment, triage, or documentation, in language they can understand. Depending on the application and applicable law, consent may be appropriate, especially when data are reused for model development or when decisions have significant consequences. Patients should know how their information is protected, how to question an AI-supported decision, and how to request human review. Explanations must be accessible to people with different languages, disabilities, and levels of health literacy. Trust is more likely when AI is presented as a support tool rather than an unquestionable authority.\n\nAI should therefore be adopted selectively, not simply because it is new or efficient. Lower-risk administrative uses may be introduced with routine safeguards, while systems that influence diagnosis, treatment, or access to care should be used only when credible evidence shows that they improve patient outcomes or safety in the settings where they are deployed. Continuous clinical oversight, subgroup monitoring, error reporting, privacy protection, and the ability to suspend a system are essential. Under these conditions, AI can complement health professionals and improve some aspects of care; without them, it may reproduce inequities, create new errors, and weaken accountability.'
print("Initial report word count:", len(initial_report.split()))
print("Revised report word count:", len(final_report.split()))
Initial report word count: 208
Revised report word count: 724

Comparing the Results

Compare the initial report, critique, and revised report. Which comments were useful? Which changes helped? Did the revision introduce a new problem or leave an important issue unresolved?

from IPython.display import Markdown

comparison = f"""
## Initial Report

{initial_report}

---

## Critique

{critique}

---

## Final Report (After Reflection)

{final_report}
"""

Markdown(comparison)
Loading...