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 branchName

Pre-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 beautifulsoup4
from 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_used

Ask 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_used
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_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

GenAI - 19

By Content ITV

GenAI - 19

  • 5