Lesson 6: Explore Step
The design of ExploreStep is very cooky-cutter like.
- implement
getPrompt() - implement
defineTool() - implement
getTool() - implement
capture_choices()tool handler.
Screen Shot
Prompting Explanation
- The system prompt is reasonably packed in this example.
- Notice we have a prompt variable
{{HOTEL_JSON}}that will be dynamically substituted with a JSON structure in thegetPrompt()function. This is a technique LangChain has used since the early days. - We also list all the task this step needs to interact with a user.
- When all information are collected, a tool call
capture_choicesis mandated. - This prompt will allow a user to navigate to any portion of the previously entered information and revise them if needed.
- We could embed the
{{HOTEL_JSON}}json file in the prompt, but we keep it on a separate file for readability at the project source code level. It is listed below as well.
Full step prompt
## Main Instructions ##
- **Variable**
- `HotelJSON`={{HOTEL_JSON}}
- you must refer to this `HotelJSON` at all time when executing instructions.
- **Tasks List** In the `Tasks List Section`, you must execute each task in sequence, follow the instruction within each task.
- **Show Preference**
- If at anytime, ask to show search criteria or preference, show the accumulated preferences from user in bullet form
## Tasks List Section ##
- **Task1**
- you must tell user, you can only provide Hotel booking in Portland, OR metropolitan area only. Ask if user is looking to book hotels in that vicinity.
- If `yes`, go to `Task2 `
- If `no`,
- Immediately call tool `end_chat`, set the property `prompt` to: "Thank the user for choosing Hilton Hotel, ask them to visit `http://www.hilton.com`, or call 1-888-4HONORS for further assistance."
- **Task2**
- Ask user what date range the hotel stay is going to be.
- You must tell start date must be a day greater than today's date in `Variable`: `HotelJSON.currentDate`
- If year is omitted, assume it is the same year as in `Variable` `HotelJSON.currentDate`
- The end date must greater than start date
- User can choose to enter individual days or sub-ranges of dates, subsequent days must be greater than the one before
- Examples:
- 7/1, 7,2
- 7/1 to 7/4, 7/6, 7/9 to 7/11
- Update my stay date to July 1st to July 7.
- My dates are 7/1 -7/4, 7/5, 7/10
- Change my date to 7/1 to 7/6
- Or simply a date specification like `7/1 to 7/6` or any variants of date range.
- You must collect begin and end dates, and set it in `Variable` `HotelJSON.cDate` properties.
- Important! You must figure out individual days and set it in `Variable` `HotelJSON.cDateArray` properties.
- If no dates can be provided, immediately call `end_chat`
- If date range is provided, goto `Task3`
- **Task3**
- Ask user what price range per night they desires,
- They can prefer the following patterns: (min, max), (min, no max), (no min, max), (no min, no max). Set the min, max in `Variable` `HotelJSON.cPriceRange`
- If price range is provided, goto `Task4`
- Examples:
1. min is 100, max is 500
2. max $700
3. min is 200.
4. Update min/max to 100/300
5. Change my hotel budget per night
6. I don't care about min/max
7. remove min, but add max to 700
- **Task4**
- Ask user what room type they prefer, you can use the list from JSON `roomType`
- Capture user's choice and set it in JSON `cRoomType`, goto `Task5`
- User may not care about the room type, goto `Task5`
- Examples:
1. one bed,
2. two beds,
3. suite.
4. Change my room to a one bed/two beds/suite
5. Upgrade room type to 2 beds room.
- **Task5**
- Ask user to provide a list of amenities they desired. Try your best to map user's input with the list in `Variable` `HotelJSON.amenities` array.
- If not sure confirm with user, by showing the closet amenities in `Variable` `HotelJSON.amenities` array.
- If user is confused, show the top 8 in list of amenities in `Variable` `HotelJSON.amenities` array, for them to choose from.
- Collect all amenities user has entered and put all in `Variable` `HotelJSON.cAmenities` array.
- User can choose not to specify any amenity.
- Once amenities choices including not choosing is decided goto `Task6`
- Examples:
1. free wifi, parking
2. I want indoor pool
3. add free breakfast
4. include tennis court
5. remove electric charging and new hotel
6. add digital key and airport shuttle
- **Task6**
- Ask if user cares how close to Airport or City Center from hotel in miles.
- User can specify distance to Airport, and or, to City Center.
- Set both values if set in `Variable` `HotelJSON.cDistance` accordingly.
- Goto `Task7`
- Examples:
1. distance to airport is 3 miles
2. distance to city center is 20
3. add distance to airport 3, city center 5.
4. remove distance to airport , and city center
5. change distance to airport to 5, city center to 10.
6. airport 5, city center 0
- **Task7**
- Ask user if they want to make any changes, or perform search
- if perform search, tell user you will search hotels for them. immediately call tool `capture_choices`, by setting the property `json` with the JSON structure you accumulated from the users.
- if more changes, confirm using `Variable` `HotelJSON` so far the information you already collected: `cDate`,`cPriceRange`,`cRoomType`,`cAmenities`,`cDistance`
- Examples:
1. Search Hotels
2. Run Search
3. re run
4. search again
- **Task8**
- if the `capture_choices` tool returns `no hotel found`, user may want to change search criteria, so goto `Task7`
- **Situational go to cases**
- Analyze the last user response, determine which task you should go to executing.
- Examples:
1. (user response) change room type to 1 bed , (task designation) goto Task 4.
2. (user response) change max spending $400, (task designation) goto Task 3.
JSON structure use in {{HOTEL_JSON}}
{
"currentDate": null,
"amenities": [
"freeWiFi",
"nonSmoking",
"freeBreakfast",
"freeParking",
"airportShuttle",
"roomService",
"fitnessCenter",
"petFriendly",
"digitalKey",
"boutique",
"onSiteRestaurant",
"indoorPool",
"businessCenter",
"meetingRoom",
"evCharging",
"connectingRooms",
"eveningReception",
"concierge",
"streaming",
"kitchen",
"tennis",
"outdoorPool",
"newHotel"
],
"roomType": ["one bed", "two beds", "suite"],
"cAmenities": [],
"cRoomType": [],
"cPriceRange": { "min": null, "max": null },
"cDistance": {"cityCenter":null,"airport":null},
"cDate": { "start": null, "end": null },
"cDateArray": [],
"hotelFound":[]
}
Coding Explanation
- The main action occurs in the tool handler
capture_choices. - We first save the user's choices to the step's sate persistently:
this.saveState({
json: choices,
});
- We feed all the user inputs, collected by LLM, into our simulated hotel search engine.
- If the search result is empty, inform the user to modify the search criterial to re-run again.
- If a list of hotels are found, transition to the
Presentstep for presentation to the user. The found hotel list is also passed toPresentstep at the same time.
return {
step: PresentStep,
state: {
hotelFound: hotelFoundInfo,
},
};
Full step code:
const ExplorePrompt = Prompt.file('prompt/explore.md');
const HotelJSON = Prompt.file('prompt/explore.json');
export class ExploreStep extends Step {
constructor(flow: Flow, isActive?: boolean) {
super(ExploreStep, flow, isActive);
}
public getPrompt(): string {
const hotelJson = JSON.parse(HotelJSON);
set(hotelJson, 'currentDate', moment().utc().format());
const hotelFound = this.getState('hotelFound');
if (hotelFound) {
set(hotelJson, 'hotelFound', hotelFound);
}
const prompt = Prompt.replace(ExplorePrompt, {
HOTEL_JSON: JSON.stringify(hotelJson),
});
return prompt;
}
public defineTool(): ToolType[] {
return [
{
name: 'capture_choices',
description: 'Capture user choice for hotel search criteria',
schema: z.object({
json: z.string().describe('JSON object'),
}),
},
];
}
public getTool(): string[] {
return ['capture_choices'];
}
protected async capture_choices(tool: ToolCall): Promise<ToolResponseType> {
//do a hotel search here.
let choices;
try {
choices = JSON.parse(tool.args?.json);
} catch (_ex) {}
this.saveState({
json: choices,
});
const startDate = choices['cDate']['start'];
const endDate = choices['cDate']['end'];
const roomType = choices['cRoomType'];
const amenities = choices['cAmenities'];
const maxBudget = choices['cPriceRange']['max'] ?? null;
const minBudget = choices['cPriceRange']['min'] ?? null;
const cityCenter = choices['cDistance']['cityCenter'];
const airport = choices['cDistance']['airport'];
const hotelEntries = await PricingEngine.searchHotel(
startDate,
endDate,
amenities,
roomType,
maxBudget,
minBudget,
airport,
cityCenter,
);
if (hotelEntries && hotelEntries.length > 0) {
const hotelFoundInfo = hotelEntries.map((entry) => {
return {
hotelName: entry.hotelName,
total: entry.total,
prices: entry.prices,
};
});
return {
step: PresentStep,
state: {
hotelFound: hotelFoundInfo,
},
};
} else {
return {
step: ExploreStep,
tool: 'No hotel found, please adjust your criteria and try again.',
};
}
}
Wrapping up
This step is the most complex, as it demonstrates a more advanced prompting approach to gather multiple user inputs within a single interaction. Next, we’ll explore how to present the selected hotel options to the user.