Welcome to the lesson on metacognition in AI agents! This chapter is designed for beginners who are curious about how AI agents can think about their own thinking processes. By the end of this lesson, you'll understand key concepts and be equipped with practical examples to apply metacognition in AI agent design.
After completing this lesson, you'll be able to:
- Understand the implications of reasoning loops in agent definitions.
- Use planning and evaluation techniques to help self-correcting agents.
- Create your own agents capable of manipulating code to accomplish tasks.
Metacognition refers to the higher-order cognitive processes that involve thinking about one’s own thinking. For AI agents, this means being able to evaluate and adjust their actions based on self-awareness and past experiences. Metacognition, or "thinking about thinking," is an important concept in the development of agentic AI systems. It involves AI systems being aware of their own internal processes and being able to monitor, regulate, and adapt their behavior accordingly. Much like we do when we read the room or look at a problem. This self-awareness can help AI systems make better decisions, identify errors, and improve their performance over time- again linking back to the Turing test and the debate over whether AI is going to take over.
In the context of agentic AI systems, metacognition can help address several challenges, such as:
- Transparency: Ensuring that AI systems can explain their reasoning and decisions.
- Reasoning: Enhancing the ability of AI systems to synthesize information and make sound decisions.
- Adaptation: Allowing AI systems to adjust to new environments and changing conditions.
- Perception: Improving the accuracy of AI systems in recognizing and interpreting data from their environment.
Metacognition, or "thinking about thinking," is a higher-order cognitive process that involves self-awareness and self-regulation of one's cognitive processes. In the realm of AI, metacognition empowers agents to evaluate and adapt their strategies and actions, leading to improved problem-solving and decision-making capabilities. By understanding metacognition, you can design AI agents that are not only more intelligent but also more adaptable and efficient. In true metacognition, you’d see the AI explicitly reasoning about its own reasoning.
Example: “I prioritized cheaper flights because… I might be missing out on direct flights, so let me re-check.”. Keeping track of how or why it chose a certain route.
- Noting that it made mistakes because it over-relied on user preferences from last time, so it modifies its decision-making strategy not just the final recommendation.
- Diagnosing patterns like, “Whenever I see the user mention ‘too crowded,’ I should not only remove certain attractions but also reflect that my method of picking ‘top attractions’ is flawed if I always rank by popularity.”
Metacognition plays a crucial role in AI agent design for several reasons:
- Self-Reflection: Agents can assess their own performance and identify areas for improvement.
- Adaptability: Agents can modify their strategies based on past experiences and changing environments.
- Error Correction: Agents can detect and correct errors autonomously, leading to more accurate outcomes.
- Resource Management: Agents can optimize the use of resources, such as time and computational power, by planning and evaluating their actions.
Before diving into metacognitive processes, it's essential to understand the basic components of an AI agent. An AI agent typically consists of:
- Persona: The personality and characteristics of the agent, which define how it interacts with users.
- Tools: The capabilities and functions that the agent can perform.
- Skills: The knowledge and expertise that the agent possesses.
These components work together to create an "expertise unit" that can perform specific tasks.
Example: Consider a travel agent, agent services that not only plans your holiday but also adjusts its path based on real-time data and past customer journey experiences.
Imagine you're designing a travel agent service powered by AI. This agent, "Travel Agent," assists users with planning their vacations. To incorporate metacognition, Travel Agents needs to evaluate and adjust its actions based on self-awareness and past experiences. Here's how metacognition could play a role:
The current task is to help a user plan a trip to Paris.
- Gather User Preferences: Ask the user about their travel dates, budget, interests (e.g., museums, cuisine, shopping), and any specific requirements.
- Retrieve Information: Search for flight options, accommodations, attractions, and restaurants that match the user's preferences.
- Generate Recommendations: Provide a personalized itinerary with flight details, hotel reservations, and suggested activities.
- Adjust Based on Feedback: Ask the user for feedback on the recommendations and make necessary adjustments.
- Access to flight and hotel booking databases.
- Information on Parisian attractions and restaurants.
- User feedback data from previous interactions.
Travel Agent uses metacognition to evaluate its performance and learn from past experiences. For example:
- Analyzing User Feedback: Travel Agent reviews user feedback to determine which recommendations were well-received and which were not. It adjusts its future suggestions accordingly.
- Adaptability: If a user has previously mentioned a dislike for crowded places, Travel Agent will avoid recommending popular tourist spots during peak hours in the future.
- Error Correction: If Travel Agent made an error in a past booking, such as suggesting a hotel that was fully booked, it learns to check availability more rigorously before making recommendations.
Here's a simplified example of how Travel Agents code might look when incorporating metacognition:
class Travel_Agent:
def __init__(self):
self.user_preferences = {}
self.experience_data = []
def gather_preferences(self, preferences):
self.user_preferences = preferences
def retrieve_information(self):
# Search for flights, hotels, and attractions based on preferences
flights = search_flights(self.user_preferences)
hotels = search_hotels(self.user_preferences)
attractions = search_attractions(self.user_preferences)
return flights, hotels, attractions
def generate_recommendations(self):
flights, hotels, attractions = self.retrieve_information()
itinerary = create_itinerary(flights, hotels, attractions)
return itinerary
def adjust_based_on_feedback(self, feedback):
self.experience_data.append(feedback)
# Analyze feedback and adjust future recommendations
self.user_preferences = adjust_preferences(self.user_preferences, feedback)
# Example usage
travel_agent = Travel_Agent()
preferences = {
"destination": "Paris",
"dates": "2025-04-01 to 2025-04-10",
"budget": "moderate",
"interests": ["museums", "cuisine"]
}
travel_agent.gather_preferences(preferences)
itinerary = travel_agent.generate_recommendations()
print("Suggested Itinerary:", itinerary)
feedback = {"liked": ["Louvre Museum"], "disliked": ["Eiffel Tower (too crowded)"]}
travel_agent.adjust_based_on_feedback(feedback)
- Self-Reflection: Agents can analyze their performance and identify areas for improvement.
- Adaptability: Agents can modify strategies based on feedback and changing conditions.
- Error Correction: Agents can autonomously detect and correct mistakes.
- Resource Management: Agents can optimize resource usage, such as time and computational power.
By incorporating metacognition, Travel Agent can provide more personalized and accurate travel recommendations, enhancing the overall user experience.
Planning is a critical component of AI agent behavior. It involves outlining the steps needed to achieve a goal, considering the current state, resources, and possible obstacles.
- Current Task: Define the task clearly.
- Steps to Complete the Task: Break down the task into manageable steps.
- Required Resources: Identify necessary resources.
- Experience: Utilize past experiences to inform planning.
Example: Here are the steps Travel Agent needs to take to assist a user in planning their trip effectively:
-
Gather User Preferences
- Ask the user for details about their travel dates, budget, interests, and any specific requirements.
- Examples: "When are you planning to travel?" "What is your budget range?" "What activities do you enjoy on vacation?"
-
Retrieve Information
- Search for relevant travel options based on user preferences.
- Flights: Look for available flights within the user's budget and preferred travel dates.
- Accommodations: Find hotels or rental properties that match the user's preferences for location, price, and amenities.
- Attractions and Restaurants: Identify popular attractions, activities, and dining options that align with the user's interests.
-
Generate Recommendations
- Compile the retrieved information into a personalized itinerary.
- Provide details such as flight options, hotel reservations, and suggested activities, making sure to tailor the recommendations to the user's preferences.
-
Present Itinerary to User
- Share the proposed itinerary with the user for their review.
- Example: "Here's a suggested itinerary for your trip to Paris. It includes flight details, hotel bookings, and a list of recommended activities and restaurants. Let me know your thoughts!"
-
Collect Feedback
- Ask the user for feedback on the proposed itinerary.
- Examples: "Do you like the flight options?" "Is the hotel suitable for your needs?" "Are there any activities you would like to add or remove?"
-
Adjust Based on Feedback
- Modify the itinerary based on the user's feedback.
- Make necessary changes to flight, accommodation, and activity recommendations to better match the user's preferences.
-
Final Confirmation
- Present the updated itinerary to the user for final confirmation.
- Example: "I've made the adjustments based on your feedback. Here's the updated itinerary. Does everything look good to you?"
-
Book and Confirm Reservations
- Once the user approves the itinerary, proceed with booking flights, accommodations, and any pre-planned activities.
- Send confirmation details to the user.
-
Provide Ongoing Support
- Remain available to assist the user with any changes or additional requests before and during their trip.
- Example: "If you need any further assistance during your trip, feel free to reach out to me anytime!"
class Travel_Agent:
def __init__(self):
self.user_preferences = {}
self.experience_data = []
def gather_preferences(self, preferences):
self.user_preferences = preferences
def retrieve_information(self):
flights = search_flights(self.user_preferences)
hotels = search_hotels(self.user_preferences)
attractions = search_attractions(self.user_preferences)
return flights, hotels, attractions
def generate_recommendations(self):
flights, hotels, attractions = self.retrieve_information()
itinerary = create_itinerary(flights, hotels, attractions)
return itinerary
def adjust_based_on_feedback(self, feedback):
self.experience_data.append(feedback)
self.user_preferences = adjust_preferences(self.user_preferences, feedback)
# Example usage within a booing request
travel_agent = Travel_Agent()
preferences = {
"destination": "Paris",
"dates": "2025-04-01 to 2025-04-10",
"budget": "moderate",
"interests": ["museums", "cuisine"]
}
travel_agent.gather_preferences(preferences)
itinerary = travel_agent.generate_recommendations()
print("Suggested Itinerary:", itinerary)
feedback = {"liked": ["Louvre Museum"], "disliked": ["Eiffel Tower (too crowded)"]}
travel_agent.adjust_based_on_feedback(feedback)
Firstly let's start by understanding the difference between RAG Tool and Pre-emptive Context Load
RAG combines a retrieval system with a generative model. When a query is made, the retrieval system fetches relevant documents or data from an external source, and this retrieved information is used to augment the input to the generative model. This helps the model generate more accurate and contextually relevant responses.
In a RAG system, the agent retrieves relevant information from a knowledge base and uses it to generate appropriate responses or actions.
The Corrective RAG approach focuses on using RAG techniques to correct errors and improve the accuracy of AI agents. This involves:
- Prompting Technique: Using specific prompts to guide the agent in retrieving relevant information.
- Tool: Implementing algorithms and mechanisms that enable the agent to evaluate the relevance of the retrieved information and generate accurate responses.
- Evaluation: Continuously assessing the agent's performance and making adjustments to improve its accuracy and efficiency.
Consider a search agent that retrieves information from the web to answer user queries. The Corrective RAG approach might involve:
- Prompting Technique: Formulating search queries based on the user's input.
- Tool: Using natural language processing and machine learning algorithms to rank and filter search results.
- Evaluation: Analyzing user feedback to identify and correct inaccuracies in the retrieved information.
Corrective RAG (Retrieval-Augmented Generation) enhances an AI's ability to retrieve and generate information while correcting any inaccuracies. Let's see how Travel Agent can use the Corrective RAG approach to provide more accurate and relevant travel recommendations.
This involves:
- Prompting Technique: Using specific prompts to guide the agent in retrieving relevant information.
- Tool: Implementing algorithms and mechanisms that enable the agent to evaluate the relevance of the retrieved information and generate accurate responses.
- Evaluation: Continuously assessing the agent's performance and making adjustments to improve its accuracy and efficiency.
-
Initial User Interaction
-
Travel Agent gathers initial preferences from the user, such as destination, travel dates, budget, and interests.
-
Example:
preferences = { "destination": "Paris", "dates": "2025-04-01 to 2025-04-10", "budget": "moderate", "interests": ["museums", "cuisine"] }
-
-
Retrieval of Information
-
Travel Agent retrieves information about flights, accommodations, attractions, and restaurants based on user preferences.
-
Example:
flights = search_flights(preferences) hotels = search_hotels(preferences) attractions = search_attractions(preferences)
-
-
Generating Initial Recommendations
-
Travel Agent uses the retrieved information to generate a personalized itinerary.
-
Example:
itinerary = create_itinerary(flights, hotels, attractions) print("Suggested Itinerary:", itinerary)
-
-
Collecting User Feedback
-
Travel Agent asks the user for feedback on the initial recommendations.
-
Example:
feedback = { "liked": ["Louvre Museum"], "disliked": ["Eiffel Tower (too crowded)"] }
-
-
Corrective RAG Process
-
Prompting Technique: Travel Agent formulates new search queries based on user feedback.
-
Example:
if "disliked" in feedback: preferences["avoid"] = feedback["disliked"]
-
-
Tool: Travel Agent uses algorithms to rank and filter new search results, emphasizing the relevance based on user feedback.
-
Example:
new_attractions = search_attractions(preferences) new_itinerary = create_itinerary(flights, hotels, new_attractions) print("Updated Itinerary:", new_itinerary)
-
-
Evaluation: Travel Agent continuously assesses the relevance and accuracy of its recommendations by analyzing user feedback and making necessary adjustments.
-
Example:
def adjust_preferences(preferences, feedback): if "liked" in feedback: preferences["favorites"] = feedback["liked"] if "disliked" in feedback: preferences["avoid"] = feedback["disliked"] return preferences preferences = adjust_preferences(preferences, feedback)
-
-
Here's a simplified Python code example incorporating the Corrective RAG approach in Travel Agent:
class Travel_Agent:
def __init__(self):
self.user_preferences = {}
self.experience_data = []
def gather_preferences(self, preferences):
self.user_preferences = preferences
def retrieve_information(self):
flights = search_flights(self.user_preferences)
hotels = search_hotels(self.user_preferences)
attractions = search_attractions(self.user_preferences)
return flights, hotels, attractions
def generate_recommendations(self):
flights, hotels, attractions = self.retrieve_information()
itinerary = create_itinerary(flights, hotels, attractions)
return itinerary
def adjust_based_on_feedback(self, feedback):
self.experience_data.append(feedback)
self.user_preferences = adjust_preferences(self.user_preferences, feedback)
new_itinerary = self.generate_recommendations()
return new_itinerary
# Example usage
travel_agent = Travel_Agent()
preferences = {
"destination": "Paris",
"dates": "2025-04-01 to 2025-04-10",
"budget": "moderate",
"interests": ["museums", "cuisine"]
}
travel_agent.gather_preferences(preferences)
itinerary = travel_agent.generate_recommendations()
print("Suggested Itinerary:", itinerary)
feedback = {"liked": ["Louvre Museum"], "disliked": ["Eiffel Tower (too crowded)"]}
new_itinerary = travel_agent.adjust_based_on_feedback(feedback)
print("Updated Itinerary:", new_itinerary)
Pre-emptive Context Load involves loading relevant context or background information into the model before processing a query. This means the model has access to this information from the start, which can help it generate more informed responses without needing to retrieve additional data during the process.
Here's a simplified example of how a pre-emptive context load might look for a travel agent application in Python:
class TravelAgent:
def __init__(self):
# Pre-load popular destinations and their information
self.context = {
"Paris": {"country": "France", "currency": "Euro", "language": "French", "attractions": ["Eiffel Tower", "Louvre Museum"]},
"Tokyo": {"country": "Japan", "currency": "Yen", "language": "Japanese", "attractions": ["Tokyo Tower", "Shibuya Crossing"]},
"New York": {"country": "USA", "currency": "Dollar", "language": "English", "attractions": ["Statue of Liberty", "Times Square"]},
"Sydney": {"country": "Australia", "currency": "Dollar", "language": "English", "attractions": ["Sydney Opera House", "Bondi Beach"]}
}
def get_destination_info(self, destination):
# Fetch destination information from pre-loaded context
info = self.context.get(destination)
if info:
return f"{destination}:\nCountry: {info['country']}\nCurrency: {info['currency']}\nLanguage: {info['language']}\nAttractions: {', '.join(info['attractions'])}"
else:
return f"Sorry, we don't have information on {destination}."
# Example usage
travel_agent = TravelAgent()
print(travel_agent.get_destination_info("Paris"))
print(travel_agent.get_destination_info("Tokyo"))
-
Initialization (
__init__
method): TheTravelAgent
class pre-loads a dictionary containing information about popular destinations such as Paris, Tokyo, New York, and Sydney. This dictionary includes details like the country, currency, language, and major attractions for each destination. -
Retrieving Information (
get_destination_info
method): When a user queries about a specific destination, theget_destination_info
method fetches the relevant information from the pre-loaded context dictionary.
By pre-loading the context, the travel agent application can quickly respond to user queries without having to retrieve this information from an external source in real-time. This makes the application more efficient and responsive.
Bootstrapping a plan with a goal involves starting with a clear objective or target outcome in mind. By defining this goal upfront, the model can use it as a guiding principle throughout the iterative process. This helps ensure that each iteration moves closer to achieving the desired outcome, making the process more efficient and focused.
Here's an example of how you might bootstrap a travel plan with a goal before iterating for a travel agent in Python:
A travel agent wants to plan a customized vacation for a client. The goal is to create a travel itinerary that maximizes the client's satisfaction based on their preferences and budget.
- Define the client's preferences and budget.
- Bootstrap the initial plan based on these preferences.
- Iterate to refine the plan, optimizing for the client's satisfaction.
class TravelAgent:
def __init__(self, destinations):
self.destinations = destinations
def bootstrap_plan(self, preferences, budget):
plan = []
total_cost = 0
for destination in self.destinations:
if total_cost + destination['cost'] <= budget and self.match_preferences(destination, preferences):
plan.append(destination)
total_cost += destination['cost']
return plan
def match_preferences(self, destination, preferences):
for key, value in preferences.items():
if destination.get(key) != value:
return False
return True
def iterate_plan(self, plan, preferences, budget):
for i in range(len(plan)):
for destination in self.destinations:
if destination not in plan and self.match_preferences(destination, preferences) and self.calculate_cost(plan, destination) <= budget:
plan[i] = destination
break
return plan
def calculate_cost(self, plan, new_destination):
return sum(destination['cost'] for destination in plan) + new_destination['cost']
# Example usage
destinations = [
{"name": "Paris", "cost": 1000, "activity": "sightseeing"},
{"name": "Tokyo", "cost": 1200, "activity": "shopping"},
{"name": "New York", "cost": 900, "activity": "sightseeing"},
{"name": "Sydney", "cost": 1100, "activity": "beach"},
]
preferences = {"activity": "sightseeing"}
budget = 2000
travel_agent = TravelAgent(destinations)
initial_plan = travel_agent.bootstrap_plan(preferences, budget)
print("Initial Plan:", initial_plan)
refined_plan = travel_agent.iterate_plan(initial_plan, preferences, budget)
print("Refined Plan:", refined_plan)
-
Initialization (
__init__
method): TheTravelAgent
class is initialized with a list of potential destinations, each having attributes like name, cost, and activity type. -
Bootstrapping the Plan (
bootstrap_plan
method): This method creates an initial travel plan based on the client's preferences and budget. It iterates through the list of destinations and adds them to the plan if they match the client's preferences and fit within the budget. -
Matching Preferences (
match_preferences
method): This method checks if a destination matches the client's preferences. -
Iterating the Plan (
iterate_plan
method): This method refines the initial plan by trying to replace each destination in the plan with a better match, considering the client's preferences and budget constraints. -
Calculating Cost (
calculate_cost
method): This method calculates the total cost of the current plan, including a potential new destination.
- Initial Plan: The travel agent creates an initial plan based on the client's preferences for sightseeing and a budget of $2000.
- Refined Plan: The travel agent iterates the plan, optimizing for the client's preferences and budget.
By bootstrapping the plan with a clear goal (e.g., maximizing client satisfaction) and iterating to refine the plan, the travel agent can create a customized and optimized travel itinerary for the client. This approach ensures that the travel plan aligns with the client's preferences and budget from the start and improves with each iteration.
Large Language Models (LLMs) can be used for re-ranking and scoring by evaluating the relevance and quality of retrieved documents or generated responses. Here's how it works:
Retrieval: The initial retrieval step fetches a set of candidate documents or responses based on the query.
Re-ranking: The LLM evaluates these candidates and re-ranks them based on their relevance and quality. This step ensures that the most relevant and high-quality information is presented first.
Scoring: The LLM assigns scores to each candidate, reflecting their relevance and quality. This helps in selecting the best response or document for the user.
By leveraging LLMs for re-ranking and scoring, the system can provide more accurate and contextually relevant information, improving the overall user experience.
Here's an example of how a travel agent might use a Large Language Model (LLM) for re-ranking and scoring travel destinations based on user preferences in Python:
A travel agent wants to recommend the best travel destinations to a client based on their preferences. The LLM will help re-rank and score the destinations to ensure the most relevant options are presented.
- Collect user preferences.
- Retrieve a list of potential travel destinations.
- Use the LLM to re-rank and score the destinations based on user preferences.
Here’s how you can update the previous example to use Azure OpenAI Services:
- You need to have an Azure subscription.
- Create an Azure OpenAI resource and get your API key.
import requests
import json
class TravelAgent:
def __init__(self, destinations):
self.destinations = destinations
def get_recommendations(self, preferences, api_key, endpoint):
# Generate a prompt for the Azure OpenAI
prompt = self.generate_prompt(preferences)
# Define headers and payload for the request
headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {api_key}'
}
payload = {
"prompt": prompt,
"max_tokens": 150,
"temperature": 0.7
}
# Call the Azure OpenAI API to get the re-ranked and scored destinations
response = requests.post(endpoint, headers=headers, json=payload)
response_data = response.json()
# Extract and return the recommendations
recommendations = response_data['choices'][0]['text'].strip().split('\n')
return recommendations
def generate_prompt(self, preferences):
prompt = "Here are the travel destinations ranked and scored based on the following user preferences:\n"
for key, value in preferences.items():
prompt += f"{key}: {value}\n"
prompt += "\nDestinations:\n"
for destination in self.destinations:
prompt += f"- {destination['name']}: {destination['description']}\n"
return prompt
# Example usage
destinations = [
{"name": "Paris", "description": "City of lights, known for its art, fashion, and culture."},
{"name": "Tokyo", "description": "Vibrant city, famous for its modernity and traditional temples."},
{"name": "New York", "description": "The city that never sleeps, with iconic landmarks and diverse culture."},
{"name": "Sydney", "description": "Beautiful harbour city, known for its opera house and stunning beaches."},
]
preferences = {"activity": "sightseeing", "culture": "diverse"}
api_key = 'your_azure_openai_api_key'
endpoint = 'https://your-endpoint.com/openai/deployments/your-deployment-name/completions?api-version=2022-12-01'
travel_agent = TravelAgent(destinations)
recommendations = travel_agent.get_recommendations(preferences, api_key, endpoint)
print("Recommended Destinations:")
for rec in recommendations:
print(rec)
-
Initialization: The
TravelAgent
class is initialized with a list of potential travel destinations, each having attributes like name and description. -
Getting Recommendations (
get_recommendations
method): This method generates a prompt for the Azure OpenAI service based on the user's preferences and makes an HTTP POST request to the Azure OpenAI API to get re-ranked and scored destinations. -
Generating Prompt (
generate_prompt
method): This method constructs a prompt for the Azure OpenAI, including the user's preferences and the list of destinations. The prompt guides the model to re-rank and score the destinations based on the provided preferences. -
API Call: The
requests
library is used to make an HTTP POST request to the Azure OpenAI API endpoint. The response contains the re-ranked and scored destinations. -
Example Usage: The travel agent collects user preferences (e.g., interest in sightseeing and diverse culture) and uses the Azure OpenAI service to get re-ranked and scored recommendations for travel destinations.
Make sure to replace your_azure_openai_api_key
with your actual Azure OpenAI API key and https://your-endpoint.com/...
with the actual endpoint URL of your Azure OpenAI deployment.
By leveraging the LLM for re-ranking and scoring, the travel agent can provide more personalized and relevant travel recommendations to clients, enhancing their overall experience.
Retrieval-Augmented Generation (RAG) can be both a prompting technique and a tool in the development of AI agents. Understanding the distinction between the two can help you leverage RAG more effectively in your projects.
What is it?
- As a prompting technique, RAG involves formulating specific queries or prompts to guide the retrieval of relevant information from a large corpus or database. This information is then used to generate responses or actions.
How it works:
- Formulate Prompts: Create well-structured prompts or queries based on the task at hand or the user's input.
- Retrieve Information: Use the prompts to search for relevant data from a pre-existing knowledge base or dataset.
- Generate Response: Combine the retrieved information with generative AI models to produce a comprehensive and coherent response.
Example in Travel Agent:
- User Input: "I want to visit museums in Paris."
- Prompt: "Find top museums in Paris."
- Retrieved Information: Details about Louvre Museum, Musée d'Orsay, etc.
- Generated Response: "Here are some top museums in Paris: Louvre Museum, Musée d'Orsay, and Centre Pompidou."
What is it?
- As a tool, RAG is an integrated system that automates the retrieval and generation process, making it easier for developers to implement complex AI functionalities without manually crafting prompts for each query.
How it works:
- Integration: Embed RAG within the AI agent's architecture, allowing it to automatically handle the retrieval and generation tasks.
- Automation: The tool manages the entire process, from receiving user input to generating the final response, without requiring explicit prompts for each step.
- Efficiency: Enhances the agent's performance by streamlining the retrieval and generation process, enabling quicker and more accurate responses.
Example in Travel Agent:
- User Input: "I want to visit museums in Paris."
- RAG Tool: Automatically retrieves information about museums and generates a response.
- Generated Response: "Here are some top museums in Paris: Louvre Museum, Musée d'Orsay, and Centre Pompidou."
Aspect | Prompting Technique | Tool |
---|---|---|
Manual vs Automatic | Manual formulation of prompts for each query. | Automated process for retrieval and generation. |
Control | Offers more control over the retrieval process. | Streamlines and automates the retrieval and generation. |
Flexibility | Allows for customized prompts based on specific needs. | More efficient for large-scale implementations. |
Complexity | Requires crafting and tweaking of prompts. | Easier to integrate within an AI agent's architecture. |
Prompting Technique Example:
def search_museums_in_paris():
prompt = "Find top museums in Paris"
search_results = search_web(prompt)
return search_results
museums = search_museums_in_paris()
print("Top Museums in Paris:", museums)
Tool Example:
class Travel_Agent:
def __init__(self):
self.rag_tool = RAGTool()
def get_museums_in_paris(self):
user_input = "I want to visit museums in Paris."
response = self.rag_tool.retrieve_and_generate(user_input)
return response
travel_agent = Travel_Agent()
museums = travel_agent.get_museums_in_paris()
print("Top Museums in Paris:", museums)
Evaluating relevancy is a crucial aspect of AI agent performance. It ensures that the information retrieved and generated by the agent is appropriate, accurate, and useful to the user. Let's explore how to evaluate relevancy in AI agents, including practical examples and techniques.
-
Context Awareness:
- The agent must understand the context of the user's query to retrieve and generate relevant information.
- Example: If a user asks for "best restaurants in Paris," the agent should consider the user's preferences, such as cuisine type and budget.
-
Accuracy:
- The information provided by the agent should be factually correct and up-to-date.
- Example: Recommending currently open restaurants with good reviews rather than outdated or closed options.
-
User Intent:
- The agent should infer the user's intent behind the query to provide the most relevant information.
- Example: If a user asks for "budget-friendly hotels," the agent should prioritize affordable options.
-
Feedback Loop:
- Continuously collecting and analyzing user feedback helps the agent refine its relevancy evaluation process.
- Example: Incorporating user ratings and feedback on previous recommendations to improve future responses.
-
Relevance Scoring:
-
Assign a relevance score to each retrieved item based on how well it matches the user's query and preferences.
-
Example:
def relevance_score(item, query): score = 0 if item['category'] in query['interests']: score += 1 if item['price'] <= query['budget']: score += 1 if item['location'] == query['destination']: score += 1 return score
-
-
Filtering and Ranking:
-
Filter out irrelevant items and rank the remaining ones based on their relevance scores.
-
Example:
def filter_and_rank(items, query): ranked_items = sorted(items, key=lambda item: relevance_score(item, query), reverse=True) return ranked_items[:10] # Return top 10 relevant items
-
-
Natural Language Processing (NLP):
-
Use NLP techniques to understand the user's query and retrieve relevant information.
-
Example:
def process_query(query): # Use NLP to extract key information from the user's query processed_query = nlp(query) return processed_query
-
-
User Feedback Integration:
-
Collect user feedback on the provided recommendations and use it to adjust future relevance evaluations.
-
Example:
def adjust_based_on_feedback(feedback, items): for item in items: if item['name'] in feedback['liked']: item['relevance'] += 1 if item['name'] in feedback['disliked']: item['relevance'] -= 1 return items
-
Here's a practical example of how Travel Agent can evaluate the relevancy of travel recommendations:
class Travel_Agent:
def __init__(self):
self.user_preferences = {}
self.experience_data = []
def gather_preferences(self, preferences):
self.user_preferences = preferences
def retrieve_information(self):
flights = search_flights(self.user_preferences)
hotels = search_hotels(self.user_preferences)
attractions = search_attractions(self.user_preferences)
return flights, hotels, attractions
def generate_recommendations(self):
flights, hotels, attractions = self.retrieve_information()
ranked_hotels = self.filter_and_rank(hotels, self.user_preferences)
itinerary = create_itinerary(flights, ranked_hotels, attractions)
return itinerary
def filter_and_rank(self, items, query):
ranked_items = sorted(items, key=lambda item: self.relevance_score(item, query), reverse=True)
return ranked_items[:10] # Return top 10 relevant items
def relevance_score(self, item, query):
score = 0
if item['category'] in query['interests']:
score += 1
if item['price'] <= query['budget']:
score += 1
if item['location'] == query['destination']:
score += 1
return score
def adjust_based_on_feedback(self, feedback, items):
for item in items:
if item['name'] in feedback['liked']:
item['relevance'] += 1
if item['name'] in feedback['disliked']:
item['relevance'] -= 1
return items
# Example usage
travel_agent = Travel_Agent()
preferences = {
"destination": "Paris",
"dates": "2025-04-01 to 2025-04-10",
"budget": "moderate",
"interests": ["museums", "cuisine"]
}
travel_agent.gather_preferences(preferences)
itinerary = travel_agent.generate_recommendations()
print("Suggested Itinerary:", itinerary)
feedback = {"liked": ["Louvre Museum"], "disliked": ["Eiffel Tower (too crowded)"]}
updated_items = travel_agent.adjust_based_on_feedback(feedback, itinerary['hotels'])
print("Updated Itinerary with Feedback:", updated_items)
Searching with intent involves understanding and interpreting the underlying purpose or goal behind a user's query to retrieve and generate the most relevant and useful information. This approach goes beyond simply matching keywords and focuses on grasping the user's actual needs and context.
-
Understanding User Intent:
- User intent can be categorized into three main types: informational, navigational, and transactional.
- Informational Intent: The user seeks information about a topic (e.g., "What are the best museums in Paris?").
- Navigational Intent: The user wants to navigate to a specific website or page (e.g., "Louvre Museum official website").
- Transactional Intent: The user aims to perform a transaction, such as booking a flight or making a purchase (e.g., "Book a flight to Paris").
- User intent can be categorized into three main types: informational, navigational, and transactional.
-
Context Awareness:
- Analyzing the context of the user's query helps in accurately identifying their intent. This includes considering previous interactions, user preferences, and the specific details of the current query.
-
Natural Language Processing (NLP):
- NLP techniques are employed to understand and interpret the natural language queries provided by users. This includes tasks like entity recognition, sentiment analysis, and query parsing.
-
Personalization:
- Personalizing the search results based on the user's history, preferences, and feedback enhances the relevancy of the information retrieved.
Let's take Travel Agent as an example to see how searching with intent can be implemented.
-
Gathering User Preferences
class Travel_Agent: def __init__(self): self.user_preferences = {} def gather_preferences(self, preferences): self.user_preferences = preferences
-
Understanding User Intent
def identify_intent(query): if "book" in query or "purchase" in query: return "transactional" elif "website" in query or "official" in query: return "navigational" else: return "informational"
-
Context Awareness
def analyze_context(query, user_history): # Combine current query with user history to understand context context = { "current_query": query, "user_history": user_history } return context
-
Search and Personalize Results
def search_with_intent(query, preferences, user_history): intent = identify_intent(query) context = analyze_context(query, user_history) if intent == "informational": search_results = search_information(query, preferences) elif intent == "navigational": search_results = search_navigation(query) elif intent == "transactional": search_results = search_transaction(query, preferences) personalized_results = personalize_results(search_results, user_history) return personalized_results def search_information(query, preferences): # Example search logic for informational intent results = search_web(f"best {preferences['interests']} in {preferences['destination']}") return results def search_navigation(query): # Example search logic for navigational intent results = search_web(query) return results def search_transaction(query, preferences): # Example search logic for transactional intent results = search_web(f"book {query} to {preferences['destination']}") return results def personalize_results(results, user_history): # Example personalization logic personalized = [result for result in results if result not in user_history] return personalized[:10] # Return top 10 personalized results
-
Example Usage
travel_agent = Travel_Agent() preferences = { "destination": "Paris", "interests": ["museums", "cuisine"] } travel_agent.gather_preferences(preferences) user_history = ["Louvre Museum website", "Book flight to Paris"] query = "best museums in Paris" results = search_with_intent(query, preferences, user_history) print("Search Results:", results)
Code generating agents use AI models to write and execute code, solving complex problems and automating tasks.
Code generating agents use generative AI models to write and execute code. These agents can solve complex problems, automate tasks, and provide valuable insights by generating and running code in various programming languages.
- Automated Code Generation: Generate code snippets for specific tasks, such as data analysis, web scraping, or machine learning.
- SQL as a RAG: Use SQL queries to retrieve and manipulate data from databases.
- Problem Solving: Create and execute code to solve specific problems, such as optimizing algorithms or analyzing data.
Imagine you're designing a code generating agent. Here's how it might work:
- Task: Analyze a dataset to identify trends and patterns.
- Steps:
- Load the dataset into a data analysis tool.
- Generate SQL queries to filter and aggregate the data.
- Execute the queries and retrieve the results.
- Use the results to generate visualizations and insights.
- Required Resources: Access to the dataset, data analysis tools, and SQL capabilities.
- Experience: Use past analysis results to improve the accuracy and relevance of future analyses.
In this example, we'll design a code generating agent, Travel Agent, to assist users in planning their travel by generating and executing code. This agent can handle tasks such as fetching travel options, filtering results, and compiling an itinerary using generative AI.
- Gathering User Preferences: Collects user input such as destination, travel dates, budget, and interests.
- Generating Code to Fetch Data: Generates code snippets to retrieve data about flights, hotels, and attractions.
- Executing Generated Code: Runs the generated code to fetch real-time information.
- Generating Itinerary: Compiles the fetched data into a personalized travel plan.
- Adjusting Based on Feedback: Receives user feedback and regenerates code if necessary to refine the results.
-
Gathering User Preferences
class Travel_Agent: def __init__(self): self.user_preferences = {} def gather_preferences(self, preferences): self.user_preferences = preferences
-
Generating Code to Fetch Data
def generate_code_to_fetch_data(preferences): # Example: Generate code to search for flights based on user preferences code = f""" def search_flights(): import requests response = requests.get('https://api.example.com/flights', params={preferences}) return response.json() """ return code def generate_code_to_fetch_hotels(preferences): # Example: Generate code to search for hotels code = f""" def search_hotels(): import requests response = requests.get('https://api.example.com/hotels', params={preferences}) return response.json() """ return code
-
Executing Generated Code
def execute_code(code): # Execute the generated code using exec exec(code) result = locals() return result travel_agent = Travel_Agent() preferences = { "destination": "Paris", "dates": "2025-04-01 to 2025-04-10", "budget": "moderate", "interests": ["museums", "cuisine"] } travel_agent.gather_preferences(preferences) flight_code = generate_code_to_fetch_data(preferences) hotel_code = generate_code_to_fetch_hotels(preferences) flights = execute_code(flight_code) hotels = execute_code(hotel_code) print("Flight Options:", flights) print("Hotel Options:", hotels)
-
Generating Itinerary
def generate_itinerary(flights, hotels, attractions): itinerary = { "flights": flights, "hotels": hotels, "attractions": attractions } return itinerary attractions = search_attractions(preferences) itinerary = generate_itinerary(flights, hotels, attractions) print("Suggested Itinerary:", itinerary)
-
Adjusting Based on Feedback
def adjust_based_on_feedback(feedback, preferences): # Adjust preferences based on user feedback if "liked" in feedback: preferences["favorites"] = feedback["liked"] if "disliked" in feedback: preferences["avoid"] = feedback["disliked"] return preferences feedback = {"liked": ["Louvre Museum"], "disliked": ["Eiffel Tower (too crowded)"]} updated_preferences = adjust_based_on_feedback(feedback, preferences) # Regenerate and execute code with updated preferences updated_flight_code = generate_code_to_fetch_data(updated_preferences) updated_hotel_code = generate_code_to_fetch_hotels(updated_preferences) updated_flights = execute_code(updated_flight_code) updated_hotels = execute_code(updated_hotel_code) updated_itinerary = generate_itinerary(updated_flights, updated_hotels, attractions) print("Updated Itinerary:", updated_itinerary)
Based on the schema of the table can indeed enhance the query generation process by leveraging environmental awareness and reasoning.
Here's an example of how this can be done:
- Understanding the Schema: The system will understand the schema of the table and use this information to ground the query generation.
- Adjusting Based on Feedback: The system will adjust user preferences based on feedback and reason about which fields in the schema need to be updated.
- Generating and Executing Queries: The system will generate and execute queries to fetch updated flight and hotel data based on the new preferences.
Here is an updated Python code example that incorporates these concepts:
def adjust_based_on_feedback(feedback, preferences, schema):
# Adjust preferences based on user feedback
if "liked" in feedback:
preferences["favorites"] = feedback["liked"]
if "disliked" in feedback:
preferences["avoid"] = feedback["disliked"]
# Reasoning based on schema to adjust other related preferences
for field in schema:
if field in preferences:
preferences[field] = adjust_based_on_environment(feedback, field, schema)
return preferences
def adjust_based_on_environment(feedback, field, schema):
# Custom logic to adjust preferences based on schema and feedback
if field in feedback["liked"]:
return schema[field]["positive_adjustment"]
elif field in feedback["disliked"]:
return schema[field]["negative_adjustment"]
return schema[field]["default"]
def generate_code_to_fetch_data(preferences):
# Generate code to fetch flight data based on updated preferences
return f"fetch_flights(preferences={preferences})"
def generate_code_to_fetch_hotels(preferences):
# Generate code to fetch hotel data based on updated preferences
return f"fetch_hotels(preferences={preferences})"
def execute_code(code):
# Simulate execution of code and return mock data
return {"data": f"Executed: {code}"}
def generate_itinerary(flights, hotels, attractions):
# Generate itinerary based on flights, hotels, and attractions
return {"flights": flights, "hotels": hotels, "attractions": attractions}
# Example schema
schema = {
"favorites": {"positive_adjustment": "increase", "negative_adjustment": "decrease", "default": "neutral"},
"avoid": {"positive_adjustment": "decrease", "negative_adjustment": "increase", "default": "neutral"}
}
# Example usage
preferences = {"favorites": "sightseeing", "avoid": "crowded places"}
feedback = {"liked": ["Louvre Museum"], "disliked": ["Eiffel Tower (too crowded)"]}
updated_preferences = adjust_based_on_feedback(feedback, preferences, schema)
# Regenerate and execute code with updated preferences
updated_flight_code = generate_code_to_fetch_data(updated_preferences)
updated_hotel_code = generate_code_to_fetch_hotels(updated_preferences)
updated_flights = execute_code(updated_flight_code)
updated_hotels = execute_code(updated_hotel_code)
updated_itinerary = generate_itinerary(updated_flights, updated_hotels, feedback["liked"])
print("Updated Itinerary:", updated_itinerary)
- Schema Awareness: The
schema
dictionary defines how preferences should be adjusted based on feedback. It includes fields likefavorites
andavoid
, with corresponding adjustments. - Adjusting Preferences (
adjust_based_on_feedback
method): This method adjusts preferences based on user feedback and the schema. - Environment-Based Adjustments (
adjust_based_on_environment
method): This method customizes the adjustments based on the schema and feedback. - Generating and Executing Queries: The system generates code to fetch updated flight and hotel data based on the adjusted preferences and simulates the execution of these queries.
- Generating Itinerary: The system creates an updated itinerary based on the new flight, hotel, and attraction data.
By making the system environment-aware and reasoning based on the schema, it can generate more accurate and relevant queries, leading to better travel recommendations and a more personalized user experience.
SQL (Structured Query Language) is a powerful tool for interacting with databases. When used as part of a Retrieval-Augmented Generation (RAG) approach, SQL can retrieve relevant data from databases to inform and generate responses or actions in AI agents. Let's explore how SQL can be used as a RAG technique in the context of Travel Agent.
-
Database Interaction:
- SQL is used to query databases, retrieve relevant information, and manipulate data.
- Example: Fetching flight details, hotel information, and attractions from a travel database.
-
Integration with RAG:
- SQL queries are generated based on user input and preferences.
- The retrieved data is then used to generate personalized recommendations or actions.
-
Dynamic Query Generation:
- The AI agent generates dynamic SQL queries based on the context and user needs.
- Example: Customizing SQL queries to filter results based on budget, dates, and interests.
- Automated Code Generation: Generate code snippets for specific tasks.
- SQL as a RAG: Use SQL queries to manipulate data.
- Problem Solving: Create and execute code to solve problems.
Example: A data analysis agent:
- Task: Analyze a dataset to find trends.
- Steps:
- Load the dataset.
- Generate SQL queries to filter data.
- Execute queries and retrieve results.
- Generate visualizations and insights.
- Resources: Dataset access, SQL capabilities.
- Experience: Use past results to improve future analyses.
-
Gathering User Preferences
class Travel_Agent: def __init__(self): self.user_preferences = {} def gather_preferences(self, preferences): self.user_preferences = preferences
-
Generating SQL Queries
def generate_sql_query(table, preferences): query = f"SELECT * FROM {table} WHERE " conditions = [] for key, value in preferences.items(): conditions.append(f"{key}='{value}'") query += " AND ".join(conditions) return query
-
Executing SQL Queries
import sqlite3 def execute_sql_query(query, database="travel.db"): connection = sqlite3.connect(database) cursor = connection.cursor() cursor.execute(query) results = cursor.fetchall() connection.close() return results
-
Generating Recommendations
def generate_recommendations(preferences): flight_query = generate_sql_query("flights", preferences) hotel_query = generate_sql_query("hotels", preferences) attraction_query = generate_sql_query("attractions", preferences) flights = execute_sql_query(flight_query) hotels = execute_sql_query(hotel_query) attractions = execute_sql_query(attraction_query) itinerary = { "flights": flights, "hotels": hotels, "attractions": attractions } return itinerary travel_agent = Travel_Agent() preferences = { "destination": "Paris", "dates": "2025-04-01 to 2025-04-10", "budget": "moderate", "interests": ["museums", "cuisine"] } travel_agent.gather_preferences(preferences) itinerary = generate_recommendations(preferences) print("Suggested Itinerary:", itinerary)
-
Flight Query
SELECT * FROM flights WHERE destination='Paris' AND dates='2025-04-01 to 2025-04-10' AND budget='moderate';
-
Hotel Query
SELECT * FROM hotels WHERE destination='Paris' AND budget='moderate';
-
Attraction Query
SELECT * FROM attractions WHERE destination='Paris' AND interests='museums, cuisine';
By leveraging SQL as part of the Retrieval-Augmented Generation (RAG) technique, AI agents like Travel Agent can dynamically retrieve and utilize relevant data to provide accurate and personalized recommendations.
So to demonstrate an implementation of metacongition, let's create a simple agent that reflects on its decision-making process while solving a problem. For this example, we'll build a system where an agent tries to optimize the choice of a hotel, but then evaluates its own reasoning and adjusts its strategy when it makes errors or suboptimal choices.
We'll simulate this using a basic example where the agent selects hotels based on a combination of price and quality, but it will "reflect" on its decisions and adjust accordingly.
- Initial Decision: The agent will pick the cheapest hotel, without understanding the quality impact.
- Reflection and Evaluation: After the initial choice, the agent will check whether the hotel is a "bad" choice using user feedback. If it finds that the hotel’s quality was too low, it reflects on its reasoning.
- Adjusting Strategy: The agent adjusts its strategy based on its reflection switches from "cheapest" to "highest_quality", thus improving its decision-making process in future iterations.
Here's an example:
class HotelRecommendationAgent:
def __init__(self):
self.previous_choices = [] # Stores the hotels chosen previously
self.corrected_choices = [] # Stores the corrected choices
self.recommendation_strategies = ['cheapest', 'highest_quality'] # Available strategies
def recommend_hotel(self, hotels, strategy):
"""
Recommend a hotel based on the chosen strategy.
The strategy can either be 'cheapest' or 'highest_quality'.
"""
if strategy == 'cheapest':
recommended = min(hotels, key=lambda x: x['price'])
elif strategy == 'highest_quality':
recommended = max(hotels, key=lambda x: x['quality'])
else:
recommended = None
self.previous_choices.append((strategy, recommended))
return recommended
def reflect_on_choice(self):
"""
Reflect on the last choice made and decide if the agent should adjust its strategy.
The agent considers if the previous choice led to a poor outcome.
"""
if not self.previous_choices:
return "No choices made yet."
last_choice_strategy, last_choice = self.previous_choices[-1]
# Let's assume we have some user feedback that tells us whether the last choice was good or not
user_feedback = self.get_user_feedback(last_choice)
if user_feedback == "bad":
# Adjust strategy if the previous choice was unsatisfactory
new_strategy = 'highest_quality' if last_choice_strategy == 'cheapest' else 'cheapest'
self.corrected_choices.append((new_strategy, last_choice))
return f"Reflecting on choice. Adjusting strategy to {new_strategy}."
else:
return "The choice was good. No need to adjust."
def get_user_feedback(self, hotel):
"""
Simulate user feedback based on hotel attributes.
For simplicity, assume if the hotel is too cheap, the feedback is "bad".
If the hotel has quality less than 7, feedback is "bad".
"""
if hotel['price'] < 100 or hotel['quality'] < 7:
return "bad"
return "good"
# Simulate a list of hotels (price and quality)
hotels = [
{'name': 'Budget Inn', 'price': 80, 'quality': 6},
{'name': 'Comfort Suites', 'price': 120, 'quality': 8},
{'name': 'Luxury Stay', 'price': 200, 'quality': 9}
]
# Create an agent
agent = HotelRecommendationAgent()
# Step 1: The agent recommends a hotel using the "cheapest" strategy
recommended_hotel = agent.recommend_hotel(hotels, 'cheapest')
print(f"Recommended hotel (cheapest): {recommended_hotel['name']}")
# Step 2: The agent reflects on the choice and adjusts strategy if necessary
reflection_result = agent.reflect_on_choice()
print(reflection_result)
# Step 3: The agent recommends again, this time using the adjusted strategy
adjusted_recommendation = agent.recommend_hotel(hotels, 'highest_quality')
print(f"Adjusted hotel recommendation (highest_quality): {adjusted_recommendation['name']}")
The key here is the agent's ability to:
- Evaluate its previous choices and decision-making process.
- Adjust its strategy based on that reflection i.e., metacognition in action.
This is a simple form of metacognition where the system is capable of adjusting its reasoning process based on internal feedback.
Metacognition is a powerful tool that can significantly enhance the capabilities of AI agents. By incorporating metacognitive processes, you can design agents that are more intelligent, adaptable, and efficient. Use the additional resources to further explore the fascinating world of metacognition in AI agents.