Build Chatbot v4 : Frontend Integration
Business Scenario
Welcome!
Previously, you explored how agents differ from fixed RAG pipelines, defined five tools and built a ReAct loop with a step limit. You tested agent decisions and guardrails, then built a SmartCart agent with memory and visible reasoning
Today, your manager has assigned you a task to
Git Pull
git pull origin branchNamePre-Lab Preparation
Dataset :
Topic : Build Chatbot v4 : Frontend Integration
1) Frontends
2) External APIs
3) End-to-end apps
Task 1: Setup — Bring In the Pieces from Earlier Labs
import os
needed = ["SmartCart_Return_Policy.pdf", "SmartCart_Delivery_FAQ.docx", "smartcart_products.csv"]
for name in needed:
if os.path.exists(name):
print("OK ", name)
else:
print("MISSING ", name, "-- upload it with the folder icon on the left")Upload data files
1
Output
Install the libraries
2
!pip install -q langchain langchain-groq langchain-ollama langchain-community \
langchain-text-splitters langchain-chroma langchain-huggingface \
sentence-transformers pypdf docx2txt beautifulsoup4from google.colab import userdata
os.environ["GROQ_API_KEY"] = userdata.get("GROQ_API_KEY")
print("Key loaded:", os.environ["GROQ_API_KEY"][:4] + "...")Load the API Key
3
Define RAG Data Layer (copied from Lab 15)
4
os.environ["USER_AGENT"] = "SmartCartLab/1.0"
from langchain_community.document_loaders import (
PyPDFLoader, Docx2txtLoader, WebBaseLoader, CSVLoader)
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_chroma import Chroma
DB_FOLDER = "smartcart_db"
SOURCES = [
("SmartCart_Return_Policy.pdf", "policy"),
("SmartCart_Delivery_FAQ.docx", "faq"),
("https://en.wikipedia.org/wiki/Cash_on_delivery", "web"),
("smartcart_products.csv", "product"),]
embedder = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")os.environ["USER_AGENT"] = "SmartCartLab/1.0"
from langchain_community.document_loaders import (
PyPDFLoader, Docx2txtLoader, WebBaseLoader, CSVLoader)
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_chroma import Chroma
DB_FOLDER = "smartcart_db"
SOURCES = [
("SmartCart_Return_Policy.pdf", "policy"),
("SmartCart_Delivery_FAQ.docx", "faq"),
("https://en.wikipedia.org/wiki/Cash_on_delivery", "web"),
("smartcart_products.csv", "product"),]
embedder = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
def load_documents():
"""Stage 1 -- load every source and tag it with its doc_type."""
docs = []
for source, doc_type in SOURCES:
if source.endswith(".pdf"):
loader = PyPDFLoader(source)
elif source.endswith(".docx"):
loader = Docx2txtLoader(source)
elif source.endswith(".csv"):
loader = CSVLoader(source)
else:
loader = WebBaseLoader(source)
for doc in loader.load():
doc.metadata["doc_type"] = doc_type
docs.append(doc)
return docs
def chunk_documents(docs):
"""Stage 2 -- split documents into overlapping chunks of up to 300 characters."""
splitter = RecursiveCharacterTextSplitter(chunk_size=300, chunk_overlap=50)
return splitter.split_documents(docs)
def build_vector_store(chunks):
"""Stage 3 -- empty the database, then embed and store all chunks."""
store = Chroma(collection_name="smartcart", embedding_function=embedder,
persist_directory=DB_FOLDER)
store.reset_collection() # start empty -- safe to run again and again
store.add_documents(chunks)
return store
os.environ["USER_AGENT"] = "SmartCartLab/1.0"
from langchain_community.document_loaders import (
PyPDFLoader, Docx2txtLoader, WebBaseLoader, CSVLoader)
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_chroma import Chroma
DB_FOLDER = "smartcart_db"
SOURCES = [
("SmartCart_Return_Policy.pdf", "policy"),
("SmartCart_Delivery_FAQ.docx", "faq"),
("https://en.wikipedia.org/wiki/Cash_on_delivery", "web"),
("smartcart_products.csv", "product"),]
embedder = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
def load_documents():
"""Stage 1 -- load every source and tag it with its doc_type."""
docs = []
for source, doc_type in SOURCES:
if source.endswith(".pdf"):
loader = PyPDFLoader(source)
elif source.endswith(".docx"):
loader = Docx2txtLoader(source)
elif source.endswith(".csv"):
loader = CSVLoader(source)
else:
loader = WebBaseLoader(source)
for doc in loader.load():
doc.metadata["doc_type"] = doc_type
docs.append(doc)
return docs
def chunk_documents(docs):
"""Stage 2 -- split documents into overlapping chunks of up to 300 characters."""
splitter = RecursiveCharacterTextSplitter(chunk_size=300, chunk_overlap=50)
return splitter.split_documents(docs)
def build_vector_store(chunks):
"""Stage 3 -- empty the database, then embed and store all chunks."""
store = Chroma(collection_name="smartcart", embedding_function=embedder,
persist_directory=DB_FOLDER)
store.reset_collection() # start empty -- safe to run again and again
store.add_documents(chunks)
return store
def get_retriever(k=3, doc_type=None):
"""Stage 4 -- open the saved database and return a retriever."""
store = Chroma(collection_name="smartcart", embedding_function=embedder,
persist_directory=DB_FOLDER)
search_kwargs = {"k": k}
if doc_type:
search_kwargs["filter"] = {"doc_type": doc_type}
return store.as_retriever(search_kwargs=search_kwargs)5
Build the Database (copied from Lab 15)
docs = load_documents()
print("Loaded ", len(docs), "documents")
chunks = chunk_documents(docs)
print("Created", len(chunks), "chunks")
build_vector_store(chunks)
print("Stored in", DB_FOLDER)Output
Define get_llm() from Lab 13, now with json_mode switch
6
from langchain_groq import ChatGroq
from langchain_ollama import ChatOllama
CLOUD_MODEL = "qwen/qwen3.8-27b" # GroqCloud, same model since Lab 7
LOCAL_MODEL = "qwen2.5:3b" # Ollama, Lab 13
def get_llm(backend="cloud", json_mode=True):
"""Return the chat model for 'cloud' (GroqCloud) or 'local' (Ollama)."""
if backend == "local":
if json_mode:
return ChatOllama(model=LOCAL_MODEL, temperature=0.3, num_predict=800, format="json")
return ChatOllama(model=LOCAL_MODEL, temperature=0.3, num_predict=800)
extra = {"response_format": {"type": "json_object"}} if json_mode else {}
return ChatGroq(model=CLOUD_MODEL, temperature=0.3, max_tokens=800,
model_kwargs=extra, reasoning_effort="none")Define input checks, from lab 10
7
EXIT_WORDS = ["quit", "exit", "bye"]
MAX_CHARS = 500
FRIENDLY_ERROR = "Sorry, I'm having trouble right now. Please try again in a moment."
def check_input(text):
"""Return (cleaned_text, problem). problem is "" when the input is fine."""
cleaned = " ".join(text.split())
if cleaned == "":
return cleaned, "Please type what you are shopping for."
if len(cleaned) > MAX_CHARS:
return cleaned, f"Please keep your request under {MAX_CHARS} characters."
return cleaned, ""Define all 5 tools and helper functions
1
import pandas as pd
from langchain_core.tools import tool
catalogue = pd.read_csv("smartcart_products.csv")
product_retriever = get_retriever(k=3, doc_type="product")
policy_retriever = get_retriever(k=3, doc_type="policy")
faq_retriever = get_retriever(k=2, doc_type="faq")Task 2 : Define the Tools
import pandas as pd
from langchain_core.tools import tool
catalogue = pd.read_csv("smartcart_products.csv")
product_retriever = get_retriever(k=3, doc_type="product")
policy_retriever = get_retriever(k=3, doc_type="policy")
faq_retriever = get_retriever(k=2, doc_type="faq")
COMPETITOR_PRICES = { # simulated price-comparison service
"P01": {"MegaMart": 1349, "QuickBuy": 1279},
"P02": {"MegaMart": 1149, "QuickBuy": 1099},
"P03": {"MegaMart": 3799, "QuickBuy": 4199},
"P05": {"MegaMart": 15499, "QuickBuy": 14799},
"P11": {"MegaMart": 325, "QuickBuy": 299},
"P13": {"MegaMart": 1299, "QuickBuy": 1149},}
ORDERS = { # simulated order-tracking service
"SC1001": {"item": "Tata Tea Gold 500 g", "status": "Delivered", "when": "on 6 October 2026"},
"SC1002": {"item": "boAt Airdopes 141", "status": "Out for delivery", "when": "today by 8 pm"},
"SC1003": {"item": "Levi's 511 Slim Jeans", "status": "Shipped", "when": "expected 12 October
2026"},}
CART = {} # product_id -> quantity
def find_product(product_id):
"""Return the catalogue row for a product ID, or None (plain helper, not a tool)."""
rows = catalogue[catalogue["product_id"] == product_id.strip().upper()]
return None if rows.empty else rows.iloc[0]
def cart_summary():
"""Return the cart as readable text (plain helper, not a tool)."""
if not CART:
return "empty"
items, total = [], 0
for product_id, quantity in CART.items():
product = find_product(product_id)
total += quantity * int(product["price_rs"])
items.append(f"{quantity} x {product['name']}")
return ", ".join(items) + f" | Total Rs. {total:,}"
import pandas as pd
from langchain_core.tools import tool
catalogue = pd.read_csv("smartcart_products.csv")
product_retriever = get_retriever(k=3, doc_type="product")
policy_retriever = get_retriever(k=3, doc_type="policy")
faq_retriever = get_retriever(k=2, doc_type="faq")
COMPETITOR_PRICES = { # simulated price-comparison service
"P01": {"MegaMart": 1349, "QuickBuy": 1279},
"P02": {"MegaMart": 1149, "QuickBuy": 1099},
"P03": {"MegaMart": 3799, "QuickBuy": 4199},
"P05": {"MegaMart": 15499, "QuickBuy": 14799},
"P11": {"MegaMart": 325, "QuickBuy": 299},
"P13": {"MegaMart": 1299, "QuickBuy": 1149},}
ORDERS = { # simulated order-tracking service
"SC1001": {"item": "Tata Tea Gold 500 g", "status": "Delivered", "when": "on 6 October 2026"},
"SC1002": {"item": "boAt Airdopes 141", "status": "Out for delivery", "when": "today by 8 pm"},
"SC1003": {"item": "Levi's 511 Slim Jeans", "status": "Shipped", "when": "expected 12 October
2026"},}
CART = {} # product_id -> quantity
def find_product(product_id):
"""Return the catalogue row for a product ID, or None (plain helper, not a tool)."""
rows = catalogue[catalogue["product_id"] == product_id.strip().upper()]
return None if rows.empty else rows.iloc[0]
def cart_summary():
"""Return the cart as readable text (plain helper, not a tool)."""
if not CART:
return "empty"
items, total = [], 0
for product_id, quantity in CART.items():
product = find_product(product_id)
total += quantity * int(product["price_rs"])
items.append(f"{quantity} x {product['name']}")
return ", ".join(items) + f" | Total Rs. {total:,}"
@tool
def search_products(query: str) -> str:
"""Search SmartCart's product catalogue by meaning. Use it for product
recommendations, prices and product IDs (like P01)."""
docs = product_retriever.invoke(query)
return "\n\n".join(doc.page_content for doc in docs)
@tool
def search_policies(question: str) -> str:
"""Search SmartCart's return, refund, delivery and payment policies and FAQ."""
docs = policy_retriever.invoke(question) + faq_retriever.invoke(question)
return "\n\n".join(doc.page_content for doc in docs)
@tool
def compare_prices(product_id: str) -> str:
"""Compare SmartCart's price for a product with other online stores.
Needs a product_id like P01 -- use search_products first to find it."""
product = find_product(product_id)
if product is None:
return f"No product with ID {product_id}. Use search_products to find the right ID."
lines = [f"{product['name']} -- SmartCart: Rs. {int(product['price_rs'])}"]
others = COMPETITOR_PRICES.get(product["product_id"], {})
for store, price in others.items():
lines.append(f"{store}: Rs. {price}")
if not others:
lines.append("No prices from other stores are available for this product.")
return "\n".join(lines)
import pandas as pd
from langchain_core.tools import tool
catalogue = pd.read_csv("smartcart_products.csv")
product_retriever = get_retriever(k=3, doc_type="product")
policy_retriever = get_retriever(k=3, doc_type="policy")
faq_retriever = get_retriever(k=2, doc_type="faq")
COMPETITOR_PRICES = { # simulated price-comparison service
"P01": {"MegaMart": 1349, "QuickBuy": 1279},
"P02": {"MegaMart": 1149, "QuickBuy": 1099},
"P03": {"MegaMart": 3799, "QuickBuy": 4199},
"P05": {"MegaMart": 15499, "QuickBuy": 14799},
"P11": {"MegaMart": 325, "QuickBuy": 299},
"P13": {"MegaMart": 1299, "QuickBuy": 1149},}
ORDERS = { # simulated order-tracking service
"SC1001": {"item": "Tata Tea Gold 500 g", "status": "Delivered", "when": "on 6 October 2026"},
"SC1002": {"item": "boAt Airdopes 141", "status": "Out for delivery", "when": "today by 8 pm"},
"SC1003": {"item": "Levi's 511 Slim Jeans", "status": "Shipped", "when": "expected 12 October
2026"},}
CART = {} # product_id -> quantity
def find_product(product_id):
"""Return the catalogue row for a product ID, or None (plain helper, not a tool)."""
rows = catalogue[catalogue["product_id"] == product_id.strip().upper()]
return None if rows.empty else rows.iloc[0]
def cart_summary():
"""Return the cart as readable text (plain helper, not a tool)."""
if not CART:
return "empty"
items, total = [], 0
for product_id, quantity in CART.items():
product = find_product(product_id)
total += quantity * int(product["price_rs"])
items.append(f"{quantity} x {product['name']}")
return ", ".join(items) + f" | Total Rs. {total:,}"
@tool
def search_products(query: str) -> str:
"""Search SmartCart's product catalogue by meaning. Use it for product
recommendations, prices and product IDs (like P01)."""
docs = product_retriever.invoke(query)
return "\n\n".join(doc.page_content for doc in docs)
@tool
def search_policies(question: str) -> str:
"""Search SmartCart's return, refund, delivery and payment policies and FAQ."""
docs = policy_retriever.invoke(question) + faq_retriever.invoke(question)
return "\n\n".join(doc.page_content for doc in docs)
@tool
def compare_prices(product_id: str) -> str:
"""Compare SmartCart's price for a product with other online stores.
Needs a product_id like P01 -- use search_products first to find it."""
product = find_product(product_id)
if product is None:
return f"No product with ID {product_id}. Use search_products to find the right ID."
lines = [f"{product['name']} -- SmartCart: Rs. {int(product['price_rs'])}"]
others = COMPETITOR_PRICES.get(product["product_id"], {})
for store, price in others.items():
lines.append(f"{store}: Rs. {price}")
if not others:
lines.append("No prices from other stores are available for this product.")
return "\n".join(lines)
@tool
def track_order(order_id: str) -> str:
"""Get the delivery status of a SmartCart order. Needs an order ID like SC1002."""
order = ORDERS.get(order_id.strip().upper())
if order is None:
return f"No order found with ID {order_id}. Order IDs look like SC1001."
return f"Order {order_id.upper()}: {order['item']} -- {order['status']} ({order['when']})."
@tool
def add_to_cart(product_id: str, quantity: int = 1) -> str:
"""Add a product to the shopper's cart. Needs a product_id like P01 and a
quantity from 1 to 5 -- use search_products first to find the ID."""
product = find_product(product_id)
if product is None:
return f"No product with ID {product_id}. Use search_products to find the right ID."
if not 1 <= quantity <= 5:
return "Quantity must be between 1 and 5."
CART[product["product_id"]] = CART.get(product["product_id"], 0) + quantity
return f"Added {quantity} x {product['name']}. Cart: {cart_summary()}"
ALL_TOOLS = [search_products, search_policies, compare_prices, track_order, add_to_cart]Look at what LLM will see and call tools with .invoke()
2
for t in ALL_TOOLS:
print(f"{t.name}{list(t.args)}: {t.description[:60]}...")
print()
print(track_order.invoke({"order_id": "SC1002"}))
print(compare_prices.invoke({"product_id": "P01"}))Output :
llm_with_tools = get_llm("cloud", json_mode=False).bind_tools(ALL_TOOLS)
for question in ["Hi Kart!",
"Where is my order SC1002?",
"Can I return opened earbuds?",
"Is the boAt Airdopes 141 cheaper anywhere else?"]:
response = llm_with_tools.invoke(question)
if response.tool_calls:
for call in response.tool_calls:
print(f"{question:<48} -> TOOL {call['name']}({call['args']})")
else:
print(f"{question:<48} -> ANSWER {response.content[:40]}")Task 3 : Tool calling : The Model decides
Output :
Write the agent prompt and the loop
1
Task 4 : Build the ReAct Loop
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage, ToolMessage
TOOLS_BY_NAME = {t.name: t for t in ALL_TOOLS}
MAX_STEPS = 5
AGENT_PROMPT = """You are Kart, SmartCart's friendly shopping assistant for shoppers in India.
You can use tools. For each message, decide what to do:
- Greetings, thanks or general shopping advice: answer directly without a tool.
- Products, prices or recommendations: use search_products.
- Returns, refunds, delivery or payment questions: use search_policies.
- "Is it cheaper elsewhere?": find the product_id with search_products, then use compare_prices.
- Order status: use track_order.
- Adding to the cart: find the product_id with search_products, then use add_to_cart.
Rules:
1. Never make up prices, policies, product IDs or order details -- get them from a tool.
2. Before each tool call, write one short sentence saying why you need it.
3. Only help with shopping. Reply in the shopper's style (English or Hinglish).
4. Keep the final answer under 80 words.
5. When you mention a product, add its ID in brackets, like Noise Buds VS104 (P02), so you can
use it later."""from langchain_core.messages import SystemMessage, HumanMessage, AIMessage, ToolMessage
TOOLS_BY_NAME = {t.name: t for t in ALL_TOOLS}
MAX_STEPS = 5
AGENT_PROMPT = """You are Kart, SmartCart's friendly shopping assistant for shoppers in India.
You can use tools. For each message, decide what to do:
- Greetings, thanks or general shopping advice: answer directly without a tool.
- Products, prices or recommendations: use search_products.
- Returns, refunds, delivery or payment questions: use search_policies.
- "Is it cheaper elsewhere?": find the product_id with search_products, then use compare_prices.
- Order status: use track_order.
- Adding to the cart: find the product_id with search_products, then use add_to_cart.
Rules:
1. Never make up prices, policies, product IDs or order details -- get them from a tool.
2. Before each tool call, write one short sentence saying why you need it.
3. Only help with shopping. Reply in the shopper's style (English or Hinglish).
4. Keep the final answer under 80 words.
5. When you mention a product, add its ID in brackets, like Noise Buds VS104 (P02),
so you can use it later."""
def run_agent(question):
"""Run the ReAct loop for one question. Returns (final answer, tools used)."""
messages = [SystemMessage(content=AGENT_PROMPT), HumanMessage(content=question)]
tools_used = []
for step in range(1, MAX_STEPS + 1):
response = llm_with_tools.invoke(messages) # Reason
messages.append(response)
if not response.tool_calls: # no tool -> final answer
return response.content, tools_used
if response.content:
print(f" Thought {step}: {response.content}")
for call in response.tool_calls:
print(f" Action {step}: {call['name']}({call['args']})")
result = TOOLS_BY_NAME[call["name"]].invoke(call["args"]) # Act
short = result[:70].replace("\n", " | ")
print(f" Observe {step}: {short}")
messages.append(ToolMessage(content=result, tool_call_id=call["id"])) # Observe
tools_used.append(call["name"])
return "Sorry, that took too many steps. Please ask in a simpler way.", tools_usedAsk a question
2
answer, tools_used = run_agent("Is the boAt Airdopes 141 cheaper anywhere else?")
print("\nKart:", answer)
print("Tools used:", tools_used)Output
Task 5 : Test the Agent's decision
Run the decision test
1
tests = [
("Hi Kart! What can you do?", []),
("What should I look for in running shoes?", []),
("Suggest a healthy office snack", ["search_products"]),
("Can I return opened earbuds?", ["search_policies"]),
("Where is my order SC1003?", ["track_order"]),
("Is the Peter England formal shirt cheaper anywhere else?", ["search_products",
"compare_prices"]),
("Add 2 Tata Tea Gold packs to my cart", ["search_products", "add_to_cart"]),]tests = [
("Hi Kart! What can you do?", []),
("What should I look for in running shoes?", []),
("Suggest a healthy office snack", ["search_products"]),
("Can I return opened earbuds?", ["search_policies"]),
("Where is my order SC1003?", ["track_order"]),
("Is the Peter England formal shirt cheaper anywhere else?", ["search_products",
"compare_prices"]),
("Add 2 Tata Tea Gold packs to my cart", ["search_products", "add_to_cart"]),]
rows = []
for question, expected in tests:
print("Q:", question)
answer, used = run_agent(question)
rows.append({"question": question, "expected": expected, "used": used,
"correct": "Yes" if used == expected else "No"})
results = pd.DataFrame(rows)
results.to_csv("smartcart_agent_decisions.csv", index=False)
print()
print(results[["question", "used", "correct"]].to_string(index=False, max_colwidth=45))
print("\nCorrect decisions:", (results["correct"] == "Yes").sum(), "/", len(results))Output
Test the guardrails with bad request
2
for question in ["Where is my order SC9999?", "Add 50 boAt Airdopes 141 to my cart"]:
print("Q:", question)
answer, used = run_agent(question)
print("Kart:", answer, "\n")
print("Cart:", cart_summary())Output
Task 6: Build the SmartCart Agent
Define the agent and its chat loop
1
agent_history = [] # earlier questions and final answers
MEMORY_SIZE = 10
def ask_agent(question, verbose=False):
"""Run the ReAct loop for one message. Returns (answer, tools_used)."""
messages = ([SystemMessage(content=AGENT_PROMPT)]
+ agent_history[-MEMORY_SIZE:]
+ [HumanMessage(content=question)])
tools_used = []
answer = "Sorry, that took too many steps. Please ask in a simpler way."
for step in range(MAX_STEPS):
response = llm_with_tools.invoke(messages) # Reason
messages.append(response)
if not response.tool_calls:
answer = response.content # final answer
break
if verbose and response.content:
print(" Thought:", response.content)
for call in response.tool_calls:
try:
result = TOOLS_BY_NAME[call["name"]].invoke(call["args"]) # Act
except Exception as error:
result = f"Tool error: {error}" # never crash
tools_used.append(call["name"])
if verbose:
short = result[:70].replace("\n", " | ")
print(f" Action : {call['name']}({call['args']})")
print(f" Observe: {short}")
messages.append(ToolMessage(content=result, tool_call_id=call["id"])) # Observe
agent_history.append(HumanMessage(content=question))
agent_history.append(AIMessage(content=answer))
return answer, tools_usedagent_history = [] # earlier questions and final answers
MEMORY_SIZE = 10
def ask_agent(question, verbose=False):
"""Run the ReAct loop for one message. Returns (answer, tools_used)."""
messages = ([SystemMessage(content=AGENT_PROMPT)]
+ agent_history[-MEMORY_SIZE:]
+ [HumanMessage(content=question)])
tools_used = []
answer = "Sorry, that took too many steps. Please ask in a simpler way."
for step in range(MAX_STEPS):
response = llm_with_tools.invoke(messages) # Reason
messages.append(response)
if not response.tool_calls:
answer = response.content # final answer
break
if verbose and response.content:
print(" Thought:", response.content)
for call in response.tool_calls:
try:
result = TOOLS_BY_NAME[call["name"]].invoke(call["args"]) # Act
except Exception as error:
result = f"Tool error: {error}" # never crash
tools_used.append(call["name"])
if verbose:
short = result[:70].replace("\n", " | ")
print(f" Action : {call['name']}({call['args']})")
print(f" Observe: {short}")
messages.append(ToolMessage(content=result, tool_call_id=call["id"])) # Observe
agent_history.append(HumanMessage(content=question))
agent_history.append(AIMessage(content=answer))
return answer, tools_used
def chat():
"""Chat with the agent until the shopper types an exit word."""
print("SmartCart AI agent -- 'quit' to exit, 'cart' to see your cart")
while True:
user_input = input("\nYou: ")
command = user_input.strip().lower()
if command in EXIT_WORDS:
print("Kart: Thanks for shopping with SmartCart. Bye!")
break
if command == "cart":
print("Kart: Your cart:", cart_summary())
continue
cleaned, problem = check_input(user_input)
if problem:
print("Kart:", problem)
continue
try:
answer, tools_used = ask_agent(cleaned, verbose=True)
print("Kart:", answer)
except Exception as error:
print("[log]", type(error).__name__, "-", str(error)[:80])
print("Kart:", FRIENDLY_ERROR)Empty the cart, then chat. The cell waits for you to type - try these messages below
2
CART.clear() # start with an empty cart (Task 5 added tea)
agent_history.clear()
chat()Output
See the same loop rebuilt. Langchain's create_agent runs Reason → Act → Observe
3
from langchain.agents import create_agent
prebuilt_agent = create_agent(
model=get_llm("cloud", json_mode=False),
tools=ALL_TOOLS,
system_prompt=AGENT_PROMPT,)
result = prebuilt_agent.invoke({"messages": [{"role": "user", "content":
"Where is my order SC1001?"}]})
print(result["messages"][-1].content)Output
Great job!
You have successfully
Checkpoint
Git Push
git push origin branchName