Using Prompt Engineering to Create Tailored AEM Content Fragments
Before, we explained how AEM can use ChatGPT in authoring tasks or back-end processes. Today, we will show how Prompt Engineering can help authors write accurate prompts. These prompts will be used to generate HTML content. Then, the HTML content will be converted into Content Fragments that can be included in several pages.
We will create prompts to design a tailored vacation package for the Smith Family. This family includes father James (age 45), mother Mary (age 45), daughter Karen (age 15), and their dog Cinnamon. They want to visit picturesque Colombian towns.
The article has six parts. The first part will introduce the Prompt Engineering tactics that helped us write our prompts. The second part will describe the prompts used to generate HTML content. The third part will specify the structure of the needed Content Fragment Models. In the fourth part, we will create the necessary OSGi components for our City Info Process. In the fifth part, we will create and configure a Workflow. Finally, we will run the workflow to test our prompts and code.
The article skips topics explored in our previous work. For example, the Chat Completions endpoint and configuration of the Postman platform. It also omits AEM technologies such as Content Fragments, Content Fragment Models, or Workflows.
Prompt Engineering
Brex’s Prompt Engineering Guide defines a prompt as:
A prompt, sometimes referred to as context, is the text provided to a model before it begins generating output. It guides the model to explore a particular area of what it has learned so that the output is relevant to your goals. As an analogy, if you think of the language model as a source code interpreter, then a prompt is the source code to be interpreted.
OpenAI shares, in its Prompt Engineering Guide, a set of strategies and tactics to improve our prompts and get better answers from ChatGPT. We can combine several tactics in the same prompt to improve ChatGPT’s responses.
In our case, we explored how the tactics defined in the Write Clear Instructions strategy help us write complex requests to ChatGPT. These are some of the tactics used to write the prompts utilized in this article:
- Include details in your query to get more relevant answers.
- Ask the model to adopt a persona.
- Use delimiters to clearly indicate distinct parts of the input.
- Specify the steps required to complete a task.
- Specify the desired length of the output.
We encourage you to review the guide to identify what other tactics can be used in your prompts.
We also utilized the Chain of Thought technique to inquire about ChatGPT’s reasoning.
Define Prompts
Let’s specify the prompts to be used in our conversation with ChatGPT. These prompts were written following the guidelines outlined by the tactics listed above.
System Message
We use the System Message to share context, rules, and output guidelines:
The Context section includes relevant details to guide the conversation:
- It asks ChatGPT to personate a tourism expert who is creating a pet-friendly vacation package (lines 2 and 3).
- It also presents the Smith Family and gives information about each family member. (line 4).
The Task Rules section specifies a set of guidelines for the tasks defined in the prompts:
- It defines the expected length of short sentences and paragraphs (lines 8 and 9).
- It stipulates the desired readability level for the task output (line 10).
- It also instructs to omit footnotes and delimiters for formats, tasks, and outputs (lines 11 to 14). These guidelines were introduced to avoid non-HTML content in the ChatGPT’s responses.
The Format section delineates the formatting requirements for HTML outputs:
- It assigns the
h3
tag to the main title, theh4
tag to the subtitles and thea
tag to links (lines 18 to 20). - It utilizes the
target
attribute to indicate that links must be opened in a new window or tab (line 20). - It asks ChatGPT to wrap paragraphs within the
p
tag, keywords within thestrong
tag, and the family within theem
tag (lines 21 to 24).
Description Prompt
After defining the general format and rules, we must describe the city to be visited. The next prompt instructs ChatGPT to write a captivating city description. The description should include the city’s history, location, climate, and gastronomy:
The Task section defines the subtasks to be performed by ChatGPT:
- It asks ChatGPT to write a city description and specifies the desired output length (line 1).
- It defines the topics that should be part of the description (lines 3 to 7).
- It tells ChatGPT to suggest things to do and places to go good for families and pets (line 9).
- It asks ChatGPT to incorporate SEO best practices (line 10).
- It instructs ChatGPT to obey the rules defined in the System Message (line 10).
The Output section asks ChatGPT to respect the formatting guidelines defined in the System Message (line 13). It also instructs ChatGPT to include links to official or reputable websites (line 14).
Restaurants Prompt
Another important aspect of a trip is the food. The next prompt asks ChatGPT to select the city's top three restaurants and display the selection on a table:
The Task section lists the subtasks to be executed to create the table:
- It specifies the selection criteria and the columns that compose the table (lines 2 to 6).
- It instructs ChatGPT to justify the inclusion of each restaurant. The reason will be displayed in the Special Features column (line 7).
- It defines the contact information to be displayed in the Contact column (line 8).
- It indicates ChatGPT to incorporate SEO best practices (line 9).
- It asks ChatGPT to adhere to the rules established in the System Message (line 10).
The Output section defines the output format for the response:
- It asks ChatGPT to obey the rules defined in the System Message (line 13).
- It stipulates that the selection should be represented by the
table
tag and styled with therestaurants__table
CSS class (line 14). - It defines which CSS classes should be applied to the
th
andtd
tags. The classes are assigned adhering to the patternrestaurants__[columnname]
(line 15). For example, ChatGPT assigns therestaurants__special-features
CSS class to the Special Features column. - Besides, it instructs ChatGPT to include links to official or reputable websites (line 16).
Activity List Prompt
Activities are an essential component of a trip. The following prompt calls ChatGPT to list the names of the top three activities in a city:
The Task section asks ChapGPT to create a list of the names of the top three activities in the city.
In this prompt, the Output section is different from the previous ones:
- It specifies that the output must be in plain text format with each activity name on its line (lines 1 to 2).
- It also instructs ChatGPT to exclude titles and item markers (lines 7 to 8).
These particular guidelines were not defined in the System Message. Since they only apply to the Activity List Prompt.
Activity Prompt
After identifying the top activities in the city, we must provide detailed information about them. The next prompt asks ChatGPT to write an activity description:
The Task 1 section lists the subtasks to be performed to create a description of the activity:
- It asks ChatGPT to write an activity description. It specifies the desired output length too (line 1).
- It outlines the topics to be included in the activity description (lines 3 to 7).
- It tells ChatGPT to suggest activities and places good for families and pets (line 8).
- It asks ChatGPT to incorporate SEO best practices (line 9).
- Finally, it asks ChatGPT to adhere to the rules defined in the System Message (line 10).
The Task 2 section inquires ChatGPT if the activity is relevant for each family member. Besides, it adds the Let’s think step by step sentence to use the Chain of Thought technique.
The Output section defines the instructions to format the response:
- It asks ChatGPT to adhere to the formatting rules defined in the System Message (line 16).
- It instructs ChatGPT to merge Task 1 and Task 2 responses (line 17).
- Finally, it asks ChatGPT to include links to official or reputable websites (line 18).
Define the Content Fragment Models
We created two Content Fragment Models in our implementation. The first one is the City Info Prompts model. This model defines the prompts to be processed by ChatGPT using plain text properties (all properties are required):
- System Prompt (
systemPrompt
). - Description Prompt (
descriptionPrompt
). - Restaurants Prompt (
restaurantsPrompt
). - Activity List Prompt (
activityListPrompt
). - Activity Prompt (
activityPrompt
).
The second is the HTML Content model. This model defines a rich text property called Content (content
). This property is required.
Create the City Info Process
Let’s see how our City Info Process was implemented step by step.
Create model classes
We reused the POJO classes created in our previous work to map the Chat Completions endpoint’s request and response bodies.
Besides, we created two new POJO classes: ActivityInfo
and CityInfo
. The ActivityInfo
class represents an activity. It declares the name
and description
properties:
The CityInfo
, for its part, represents a city. It declares the name
, description
, restaurants
properties, and a list of activities
:
We also created a Java interface and a Sling model class to represent the previous prompts. The CityInfoPrompts
interface defines the methods to create the prompts:
The CityInfoPromptsImpl
class is a Sling model that implements the CityInfoPrompts
interface:
Let’s explore the structure of the CityInfoPromptsImpl
class:
- It uses the
@Model
annotation to mark the class as a Sling model (lines 13 to 15). - It utilizes the
@Self
annotation to inject the current resource into theresource
variable (lines 20 to 21). - It uses the
@PostConstruct
annotation to ask the Sling framework to invoke theinit
method to initialize the class variables (lines 29 to 37). - It implements the methods defined in the
CityInfoPrompts
interface. These methods set values for the${cityName}
and${activityName}
placeholders (lines 39 to 62).
Create an OSGi service
We created an OSGi service to retrieve and save information about a city. The CityInfoService
interface defines the methods that the OSGi service must implement:
The CityInfoServiceImpl
class implements the methods defined in the CityInfoService
interface:
The CityInfoServiceImpl
class:
- It uses the
@Component
annotation to define an OSGi service that implements theCityInfoService
interface (line 3). - It declares a configuration class using the
@Designate
annotation (line 4). - It defines an inner class for the configurable properties via the
@ObjectClassDefinition
annotation (lines 7 to 9). A description of the inner class properties is available in our previous work - It injects a
ResourceResolverFactory
instance through the@Reference
annotation (lines 11 and 12). - It uses the
@Activate
annotation to declare a method to be invoked during the activation phase (lines 14 to 16). - It implements the
createCityInfo
method. This method is defined in theCityInfoService
interface (lines 18 to 29). - It implements the
saveCityInfo
method. This method is defined in theCityInfoService
interface (lines 31 to 41).
Let’s explore the implementation of the methods defined in the CityInfoService
interface. The first implemented method is the createCityInfo
:
The implementation of the createCityInfo
method:
- It receives two parameters:
cityName
andpromptsPath
. ThecityName
represents the city to be portrayed. ThepromptsPath
parameter contains the path of the prompts to be used. - It creates an instance of the
ResourceResolver
interface. It uses theResourceResolver
instance to adapt thepromptsPath
resource into aCityInfoPrompts
object (lines 3 to 13). - It creates an instance of the
CloseableHttpClient
interface (line 15). - It invokes the
createBasicInfo
andcreateActivities
methods to create aCityInfo
object (lines 16 to 17). - Finally, it returns the
CityInfo
object (line 19).
The createCityInfo
method relies on three private methods:
- The
createBasicInfo
method asks ChatGPT to generate HTML content that portrays a city. It returns aCityInfo
object. - The
createActivities
method instructs ChatGPT to select the top activities in a city. It also asks ChatGPT to create HTML content for each activity. It returns a list ofActivityInfo
objects. - The
createBasicInfo
andcreateActivities
methods rely on theexecute
method. Theexecute
method sends a request to the OpenAI endpoint and processes the response. Finally, it returns the ChatGPT’s answer. Check our previous work for a detailed description of this method.
The second method is the saveCityInfo
method:
The implementation of the saveCityInfo
method:
- It receives three parameters:
cityInfo
,parentPath
, andtemplatePath
. ThecityInfo
object encloses the HTML content to be converted into Content Fragments. TheparentPath
parameter defines the path of the folder for the new JCR nodes. ThetemplatePath
parameter specifies the Fragment Template used to create the Content Fragments. - It creates an instance of the
ResourceResolver
interface (lines 3 to 5). It uses theResourceResolver
object to validate the parent resource (lines 6 to 11). It uses theResourceResolver
object to adapt thetemplatePath
resource into aFragmentTemplate
object (lines 13 to 20). - It invokes the
createCityFolder
method to make a folder to store the Content Fragments (line 21). - It calls the
createContentFragment
method many times to create Content Fragments. The Content Fragments include the city description (lines 22 to 23), the selected restaurants (lines 24 to 25), and the top activities (lines 27 to 31). - It uses the
ResourceResolver
object to commit the changes made in the JCR repository (line 33). - Finally, it returns the path of the new folder (line 34).
The saveCityInfo
method relies on two private methods:
- The
createCityFolder
method creates asling:OrderedFolder
node in the JCR repository. It returns theResource
that represents the node. - The
createContentFragment
method converts HTML content into a Content Fragment. It returns aContentFragment
object compatible with the HTML Content model.
A complete implementation of the CityInfoServiceImpl
class is available here.
Create a Custom Workflow Process
The CityInfoProcess
class uses the functionality defined in the CityInfoService
interface. This class implements the WorkflowProcess
interface:
Let’s explore the code of the CityInfoProcess
class:
- It uses the
@Component
annotation to declare an OSGi component (line 16). - It injects an instance of the
ContentFragmentService
interface (lines 28 and 29). - It implements the
execute
method (lines 24 to 55).
The execute
method is defined in the WorkflowProcess
interface. In this method the ContentFragmentProcessor
class:
- It retrieves the
PROCESS_ARGS
variable from its metadata and validates its value (lines 27 to 37). - It sets the
cityName
variable’s value from the workflow payloads (line 39). - It parses the
PROCESS_ARGS
variable to set thepromptsPath
,parentPath
, andtemplatePath
variables (lines 40 to 42). - It creates a
CityInfo
object using theContentFragmentService
instance (line 43). - It saves the
CityInfo
object’s content using theContentFragmentService
instance (line 50).
Create a Workflow Model
Check our previous work for a detailed description of creating, configuring, and running a Workflow Model. We designed and ran a Workflow Model called Create Pet-friendly Package Processor. This Workflow Model only contains one Process Step component with the next configuration:
- Common/Title:
Create a pet-friendly package
- Process/Process:
Create City Info Process
- Process/Handler Advance:
True
- Arguments:
/content/dam/cities/en/city-info/prompts/pet-friendly-prompts
/content/dam/cities/en/city-info/cities
/conf/cities/settings/dam/cfm/models/html-content
Every line in the Arguments property contains one argument:
- The first line defines the path of the Content Fragment with the prompts. The Content Fragment must be compatible with the City Info Prompts model.
- The second line specifies the path of the folder to store the Content Fragments.
- The last line defines the path of the Content Fragment Model used to create the Content Fragments. The Content Fragment Model must be compatible with the HTML Content model.
Our example Workflow Model looks like this:
Test the City Info Process
This section shows the HTML content created for La Calera, Cundinamarca, using the prompts explained before. The resulting Content Fragments were stored in the La Calera, Cundinamarca folder:
The first Content Fragment is the Description of La Calera, Cundinamarca. It was generated using the Description Prompt:
This is the HTML content of the previous image:
The second Content Fragment is the Restaurants in La Calera, Cundinamarca. It was generated using the Restaurants Prompt:
This HTML content corresponds to the image mentioned earlier:
Finally, the City Info Process generated three Content Fragments for the top activities:
- Nature Walk in Chingaza National Park,
- Visit to the La Calera Market, and
- Day at the El Sisga Dam.
This is the Content Fragment for the Nature Walk in Chingaza National Park activity:
This is the HTML content of the previous image:
Conclusions
This article illustrates how Prompt Engineering can help us write accurate prompts. We wrote prompts that provide context information for ChatGPT requests. These prompts also define the structure, length, and format of the ChatGPT’s responses.
Besides, we explained how AEM authors can write and improve their prompts using AEM tools. These tools include Content Fragments and Workflows.
Finally, we described the construction of OSGi components to generate HTML content. Besides, we explained how to convert HTML content into Content Fragments.