Given an overview of prompt engineering, the next step is to dive deeper into the principles and tactics of prompt engineering.
The two fundamental principles for AI prompt engineering are:
- Writing clear and specific instructions
- Giving time for the model to think
Writing Clear and Specific Instructions
You should express what you want a model to do by providing instructions that are as clear and specific as possible. This practice will guide the model toward the desired output and reduce the chances of receiving irrelevant or incorrect responses. Make sure to distinguish writing a clear prompt from writing a short prompt. Because, in many cases, longer prompts provide more clarity and context for the model, which can lead to more detailed and relevant outputs.
Tactics to write clear and specific instructions include using delimiters, asking for structured output, asking the model to check whether conditions are satisfied, and few-shot prompting.
Tactic 1: Using Delimiters
You can use delimiters to indicate distinct parts of the input. These could be things such as:
- Triple quotes: “””
- Triple backticks: “`
- Triple dashes: —
- Angle brackets: < >
- XML tags: <tag> </tag>
Delimiters can be any clear punctuation separating specific text pieces from the rest of the prompt.
For example, let’s say you had a body of text on George Washington from Wikipedia you wanted to summarize into a single sentence.
You could use the following code snippet, specifying the model should summarize the text enclosed by triple backticks (“`). Please note I am not showing all the text included in the Wikipedia page in this example.
text = f"""
George Washington (February 22, 1732 – December 14, 1799) was an American military officer, statesman, and Founding Father who served as the first president of the United States from 1789 to 1797. Appointed by the Second Continental Congress as commander of the Continental Army in June 1775, Washington led Patriot forces to victory in the American Revolutionary War and then served as president of the Constitutional Convention of 1787, which created and ratified the Constitution of the United States and the American federal government. Washington has been called the "Father of his Country" for his manifold leadership in the nation's founding.[9]Washington's first public office, from 1749 to 1750, was as surveyor of Culpeper County, Virginia. He subsequently received his first military training and was assigned command of the Virginia Regiment during the French and Indian War. He was later elected to the Virginia House of Burgesses and was named a delegate to the Continental Congress, where he was appointed Commanding General of the Continental Army and led American forces allied with France to a decisive victory over the British at the siege of Yorktown in 1781 during the Revolutionary War, paving the way for American independence. He resigned his commission in 1783 after the Treaty of Paris was signed.Washington played an indispensable role in adopting and ratifying the Constitution of the United States, which replaced the Articles of Confederation in 1789 and remains the world's longest-standing written and codified national constitution to this day.[10][c] He was then twice elected president by the Electoral College unanimously. As the first U.S. president, Washington implemented a strong, well-financed national government while remaining impartial in a fierce rivalry that emerged between cabinet members Thomas Jefferson and Alexander Hamilton. During the French Revolution, he proclaimed a policy of neutrality while sanctioning the Jay Treaty. He set enduring precedents for the office of president, including use of the title "Mr. President" and taking an Oath of Office with his hand on a Bible. His Farewell Address on September 19, 1796, is a preeminent statement on republicanism in which he writes about the importance of national unity and the dangers regionalism, partisanship and foreign influence pose to it.[11]Washington was a slave owner who had a complicated relationship with slavery. During his lifetime, he owned a cumulative total of over 577 slaves, who were forced to work on his farms and wherever he lived, including the President's House in Philadelphia. Yet, as president, he also signed laws passed by Congress that both protected and curtailed slavery. His will stated that his enslaved valet, William Lee, should be freed upon his death and that his remaining 123 slaves should be freed on his wife's death, though she freed them earlier during her lifetime.[12]Washington endeavored to assimilate Native Americans into the Anglo-American culture. He also waged military campaigns against Native American nations during the Revolutionary War and the Northwest Indian War. He was a member of the Anglican Church and the Freemasons and supported broad religious freedom as the Continental Army commanding general and nation's first president. Upon his death, Washington was eulogized by Henry Lee as "first in war, first in peace, and first in the hearts of his countrymen".[13]Washington has been memorialized by monuments, a federal holiday, various media depictions, geographical locations including the national capital, the State of Washington, stamps, and currency. Many scholars and ordinary Americans alike rank him among the greatest U.S. presidents. In 1976, Washington was posthumously promoted to the rank of General of the Armies, the highest rank in the U.S. Army.
"""
prompt = f"""
Summarize the text delimited by triple backticks \
into a single sentence.
```{text}```
"""
response = get_completion(prompt)
print(response)
Running this code will return the sentence:
George Washington was an American military officer, statesman,
and Founding Father who served as the first president of the
United States, leading Patriot forces to victory in the
American Revolutionary War, playing a crucial role in the
creation and ratification of the Constitution, implementing
a strong national government, and leaving a lasting legacy
as one of the greatest U.S. presidents.
Delimiters can also help avoid prompt injections. Prompt injections allow users to add some input into the prompt that creates conflicting instructions to the model. The injection can lead the model to follow malicious instructions rather than doing what you want the model to do.
Tactic 2: Ask for a Structured Output
This makes parsing the model output easier. You could ask for output in a format such as HTML or JSON.
For example, you could run a command such as:
prompt = f"""
Generate a list of three made-up book titles along \
with their authors and genres.
Provide them in JSON format with the following keys:
book_id, title, author, genre.
"""
response = get_completion(prompt)
print(response)
Which would produce the output:
{
"books": [
{
"book_id": 1,
"title": "The Enigma of Elysium",
"author": "Evelyn Sinclair",
"genre": "Mystery"
},
{
"book_id": 2,
"title": "Whispers in the Wind",
"author": "Nathaniel Blackwood",
"genre": "Fantasy"
},
{
"book_id": 3,
"title": "Echoes of the Past",
"author": "Amelia Hart",
"genre": "Romance"
}
]
}
One advantage of doing this is that you could take the output from this command and read it into a dictionary or list.
Tactic 3: Ask the Model to Check Whether Conditions are Satisfied
If the task makes assumptions that aren’t necessarily satisfied, we can tell the model to check them first and then stop short of a whole task completion attempt if they’re not satisfied. This technique could also be utilized to consider edge cases and how the model should handle them to prevent unexpected errors or results.
For example, I enjoy cooking using recipes from Cooks Illustrated, but their recipes are notorious for having run-on instructions. Instead, I could use ChatGPT to break them apart into steps that are easy to follow.
I’ll take the instructions for one of my favorite recipes for Shrimp Fra Diavolo and put it into a variable:
text_1 = f"""
Toss shrimp with ½ teaspoon salt and set aside. Pour tomatoes into colander set over large bowl. Pierce tomatoes with edge of rubber spatula and stir briefly to release juice. Transfer drained tomatoes to small bowl and reserve juice. Do not wash colander.
Heat 1 tablespoon vegetable oil in 12-inch skillet over high heat until shimmering. Add shrimp shells and cook, stirring frequently, until they begin to turn spotty brown and skillet starts to brown, 2 to 4 minutes. Remove skillet from heat and carefully add wine. When bubbling subsides, return skillet to heat and simmer until wine is reduced to about 2 tablespoons, 2 to 4 minutes. Add reserved tomato juice and simmer to meld flavors, 5 minutes. Pour contents of skillet into colander set over bowl. Discard shells and reserve liquid. Wipe out skillet with paper towels.
Heat remaining 2 tablespoons vegetable oil, garlic, pepper flakes, and oregano in now-empty skillet over medium heat, stirring occasionally, until garlic is straw-colored and fragrant, 1 to 2 minutes. Add anchovies and stir until fragrant, about 30 seconds. Remove from heat. Add drained tomatoes and mash with potato masher until coarsely pureed. Return to heat and stir in reserved tomato juice mixture. Increase heat to medium-high and simmer until mixture has thickened, about 5 minutes.
Add shrimp to skillet and simmer gently, stirring and turning shrimp frequently, until they are just cooked through, 4 to 5 minutes. Remove pan from heat. Stir in basil, parsley, and pepperoncini and brine and season with salt to taste. Drizzle with olive oil and serve.
"""
And then, create a command to parse delimited with triple quotes and containing a sequence of instructions into steps.
prompt = f"""
You will be provided with text delimited by triple quotes.
If it contains a sequence of instructions, \
re-write those instructions in the following format:
Step 1 - ...
Step 2 - …
…
Step N - …
If the text does not contain a sequence of instructions, \
then simply write \"No steps provided.\"
\"\"\"{text_1}\"\"\"
"""
response = get_completion(prompt)
print("Completion for Text 1:")
print(response)
Which returns nicely formatted instructions.
Completion for Text 1:
Step 1 - Toss shrimp with ½ teaspoon salt and set aside.
Step 2 - Pour tomatoes into colander set over large bowl. Pierce tomatoes with edge of rubber spatula and stir briefly to release juice. Transfer drained tomatoes to small bowl and reserve juice. Do not wash colander.
Step 3 - Heat 1 tablespoon vegetable oil in 12-inch skillet over high heat until shimmering. Add shrimp shells and cook, stirring frequently, until they begin to turn spotty brown and skillet starts to brown, 2 to 4 minutes.
Step 4 - Remove skillet from heat and carefully add wine. When bubbling subsides, return skillet to heat and simmer until wine is reduced to about 2 tablespoons, 2 to 4 minutes.
Step 5 - Add reserved tomato juice and simmer to meld flavors, 5 minutes. Pour contents of skillet into colander set over bowl. Discard shells and reserve liquid. Wipe out skillet with paper towels.
Step 6 - Heat remaining 2 tablespoons vegetable oil, garlic, pepper flakes, and oregano in now-empty skillet over medium heat, stirring occasionally, until garlic is straw-colored and fragrant, 1 to 2 minutes.
Step 7 - Add anchovies and stir until fragrant, about 30 seconds. Remove from heat.
Step 8 - Add drained tomatoes and mash with potato masher until coarsely pureed. Return to heat and stir in reserved tomato juice mixture. Increase heat to medium-high and simmer until mixture has thickened, about 5 minutes.
Step 9 - Add shrimp to skillet and simmer gently, stirring and turning shrimp frequently, until they are just cooked through, 4 to 5 minutes.
Step 10 - Remove pan from heat. Stir in basil, parsley, and pepperoncini and brine and season with salt to taste. Drizzle with olive oil and serve.
But if I try a command that does not satisfy the conditions, such as:
text_2 = f"""
The sun is shining brightly today, and the birds are \
singing. It's a beautiful day to go for a \
walk in the park. The flowers are blooming, and the \
trees are swaying gently in the breeze. People \
are out and about, enjoying the lovely weather. \
Some are having picnics, while others are playing \
games or simply relaxing on the grass. It's a \
perfect day to spend time outdoors and appreciate the \
beauty of nature.
"""
I’ll get the response:
Completion for Text 2:
No steps provided.
Tactic 4: Few-Shot Prompting
Few-shot prompting provides successful examples of completing the task to perform to the model before asking it to perform the task.
For example, we could provide an example of a conversation between a child and a grandparent. The successful example provided to the model is having the child ask, “Teach me about patience”, and the grandparent responds. The model can then understand what to do when the child asks, “Teach me about resilience.”
prompt = f"""
Your task is to answer in a consistent style.
: Teach me about patience.
: The river that carves the deepest \
valley flows from a modest spring; the \
grandest symphony originates from a single note; \
the most intricate tapestry begins with a solitary thread.
: Teach me about resilience.
"""
response = get_completion(prompt)
print(response)
: Resilience is the unwavering strength that
emerges from facing adversity. It is the ability to bounce
back, to rise above challenges, and to persevere in the face
of setbacks. Like a mighty oak tree that withstands the
fiercest storms, resilience allows us to weather the storms of
life and come out stronger on the other side.