Adding Flexibility
Overview
In the previous section you created your first workflow. It works well for two movie descriptions, however if you want to expand to more movies it could be a bit difficult for a few reasons.
- We're creating the tasks and adding them to the workflow one at a time.
- In the comparison task we target the specific ids of the movie tasks.
- We're repeating our prompt "What movie is this? Return only the name" over and over again.
So in this section, we'll make our application more flexible by defining a list of movie descriptions, and then iterate through that list to create PromptTasks and add them to the workflow.
Movie Description List
Locate the section of your code where you create the list of movie tasks:
# ...
# Create movie tasks
movie_1_task = PromptTask(
"What movie is this? Return only the movie name: A boy discovers an alien in his back yard",
id="movie_1")
movie_2_task = PromptTask(
"What movie is this? Return only the movie name: a shark attacks a beach.",
id="movie_2")
# ...
We're going to replace this entire section with a descriptions
list instead. This will be a list of python dictionaries with an "id" and a "description".
It should look something like:
# Create a list of movie descriptions
movie_descriptions = [
"A boy discovers an alien in his back yard",
"A shark attacks a beach"
]
Iterate through list
Now to create our PromptTasks, we'll iterate through the list of movie_descriptions.
Locate the insert_task
code where we inserted the tasks into the workflow:
We will replace this with a for loop where we create the PromptTask then insert it.
# ...
# Iterate through the movie descriptions
for description in movie_descriptions:
movie_task = PromptTask(
"What movie title is this? Return only the movie name: {{ description }}",
context = {
"description": description
})
workflow.insert_tasks(start_task, [movie_task], end_task)
# ...
As you can see, we:
- Iterate through each
description
in the list ofmovie_descriptions
. - Create a
PromptTask
and pass thatdescription
to thecontext
into a variable also calleddescription
. - Use that variable via Jinja2 templates in the prompt itself:
{{ description }}
. - Once the
PromptTask
is created, we insert it to the workflow using theinsert_tasks
method.
Update End Task
There's one final step we need to take before we can run this. In our end_task
, we're specifically identifying movie_1
and movie_2
in the prompt:
end_task = PromptTask("""
How are these movies the same:
{{parent_outputs['movie_1']}}
{{parent_outputs['movie_2']}}
""",
id="compare")
This will no longer work because we are not defining the ids when we create the PromptTask - we just let it come up with it's own unique identifiers. Also, we don't know exactly how many movies we might be comparing, so it doesn't make much sense to define and add each one individually.
Luckily, instead of specifically specifying the items via id, we can just say "hey - give me all the input items" using {{ parent_outputs }}
. This will return the entire python dictionary
of items that are input to the task.
Replace the two lines:
with:
The end_task
section should now look like:
Test
Let's run the code and see what we get.
[08/13/23 10:08:28] INFO Task END
Input:
How are these movies the same:{'74bd46cfd17a4ccaa92308029b508751': 'E.T. the
Extra-Terrestrial', '90ed4594b9af4ad9ac2fe45cd53c7889': 'Jaws'}
[08/13/23 10:08:31] INFO Task END
Output: Both 'E.T. the Extra-Terrestrial' and 'Jaws' are iconic movies directed by Steven Spielberg. They are known for their
memorable storylines and have had a significant impact on popular culture.
We get the proper output for our task - it compares ET and Jaws as we expect. But notice the input.
Input:
How are these movies the same:
{'74bd46cfd17a4ccaa92308029b508751': 'E.T. the Extra-Terrestrial', '90ed4594b9af4ad9ac2fe45cd53c7889': 'Jaws'}
Instead of passing just the names of the movies, it's passing the entire dictionary of items. It works but it's extra data. Don't worry, there's a way to clean this up using Jinja2 for loops.
Iterate through item values
Jinja2 has a for loop structure that looks like:
We can use this inside our PromptTask to iterate through the items and just output the names.
Replace the {{ parent_outputs }}
section of the PromptTask
with a for loop that will get the key/value pairs (id, movie name) and output just the value.
Tip
For Jinja2 to iterate through the values of dict, you need to use parent_outputs.values()
.
# ...
end_task = PromptTask("""
How are these movies the same:
{% for value in parent_outputs.values() %}
{{ value }}
{% endfor %}
""",
id="END")
# ...
Test
Run the script again and let's see how it looks.
Much better. Go ahead and add a third movie to the structure and run it again. Everything should work as expected. I added "A princess and a man named Wesley" (from the movie The Princess Bride) and got the following result:
Result
All three movies, E.T. the Extra-Terrestrial, Jaws, and The Princess Bride, are iconic films
from the late 20th century. They all fall under the genre of adventure and have elements of fantasy.
Additionally, they have been highly influential in popular culture and have received critical acclaim.
Code Review
There was not as much work in this section, but we did cover some important concepts.
- We made our code more flexible by using a list of descriptions to create PromptTasks instead of creating them one at a time.
- We used a Jinja2 template for loop to iterate through each incoming item.
Review your code with the current state to make sure everything is working as expected.
Next Step
Our code works, but the descriptions of the movies aren't as detailed as they could be. It would be better if we could search the web for detailed information about the movies, and use those results for a more comprehensive comparison.
In the next section, we will add to our workflow by adding a ToolkitTask that uses the WebScraper
tool to get more detailed information. Jump to Using Tools when you're ready to continue.