Using Prompt Engineering to Create Tailored AEM Content Fragments

Victor Serrato
Globant
Published in
12 min readMay 3, 2024
Image generated by Microsoft Copilot for “A robot family on vacation in a picturesque Colombian town”.

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:

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, the h4 tag to the subtitles and the a 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 the strong tag, and the family within the em 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 the restaurants__table CSS class (line 14).
  • It defines which CSS classes should be applied to the th and td tags. The classes are assigned adhering to the pattern restaurants__[columnname](line 15). For example, ChatGPT assigns the restaurants__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 the resource variable (lines 20 to 21).
  • It uses the @PostConstruct annotation to ask the Sling framework to invoke the init 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 the CityInfoService 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 the CityInfoService interface (lines 18 to 29).
  • It implements the saveCityInfo method. This method is defined in the CityInfoService 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 and promptsPath. The cityName represents the city to be portrayed. The promptsPath parameter contains the path of the prompts to be used.
  • It creates an instance of the ResourceResolver interface. It uses the ResourceResolver instance to adapt the promptsPath resource into a CityInfoPrompts object (lines 3 to 13).
  • It creates an instance of the CloseableHttpClient interface (line 15).
  • It invokes the createBasicInfo and createActivities methods to create a CityInfo 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 a CityInfo 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 of ActivityInfo objects.
  • The createBasicInfo and createActivities methods rely on the execute method. The execute 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, and templatePath. The cityInfo object encloses the HTML content to be converted into Content Fragments. The parentPath parameter defines the path of the folder for the new JCR nodes. The templatePath 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 the ResourceResolver object to validate the parent resource (lines 6 to 11). It uses the ResourceResolver object to adapt the templatePath resource into a FragmentTemplate 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 a sling:OrderedFolder node in the JCR repository. It returns the Resource that represents the node.
  • The createContentFragment method converts HTML content into a Content Fragment. It returns a ContentFragment 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 the promptsPath, parentPath, and templatePath variables (lines 40 to 42).
  • It creates a CityInfo object using the ContentFragmentService instance (line 43).
  • It saves the CityInfo object’s content using the ContentFragmentService 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:

Pet-friendly Vacation Package Processor’s structure.

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:

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.

--

--