Content ITV PRO
This is Itvedant Content department
LLM Access : Running Models Locally
Business Scenario
Welcome!
Previously, you used Chain of Thought prompting for product and price comparisons, enforced valid JSON and JsonOutputParser in a LangChain, converted JSON responses into product cards, and checked budgets. You also added memory and built SmartCart AI v2, successfully passing all tests that v1 failed.
Today, your manager has assigned you a task to run SmartCart AI on a local open-source model as an alternative to GroqCloud. You will compare the cost, speed, & response quality of both options, understand privacy and reliability benefits of running a model locally, & update Kart so you can switch between cloud and local models without changing its features.
Git Pull
git pull origin branchNamePre-Lab Preparation
Dataset :
Topic : LLM Access - Running Models Locally
1) Running LLM Locally
2) Open-weight vs API Models
3) Swapping the provider
Task 1: Install Ollama and Start the Server
!sudo apt-get install -y -qq zstd # needed by the Ollama installer
!curl -fsSL https://ollama.com/install.sh | sh
import subprocess, time
subprocess.Popen(["ollama", "serve"],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
time.sleep(5) # give the server a moment to start
!curl -s http://localhost:11434Task 2 : Chain of Thought Prompting
Download model & check if it is installed
1
!ollama pull qwen2.5:3b
!ollama list!ollama run qwen2.5:3b "Recommend 3 gym earbuds under Rs. 2,000, one line each."Test with command
2
Output
Task 3: Call the Local Model with Langchain
!pip install -q -r requirements.txt langchain-ollama
!echo "langchain-ollama" >> requirements.txt
import os
from google.colab import userdata
os.environ["GROQ_API_KEY"] = userdata.get("GROQ_API_KEY") # still needed for the cloudtests
from langchain_ollama import ChatOllama
!pip install -q -r requirements.txt langchain-ollama
!echo "langchain-ollama" >> requirements.txt
import os
from google.colab import userdata
os.environ["GROQ_API_KEY"] = userdata.get("GROQ_API_KEY") # still needed for the cloudtests
from langchain_ollama import ChatOllama
local_llm = ChatOllama(
model="qwen2.5:3b",
temperature=0.7,
top_p=0.95,
num_predict=300, # Ollama's name for max_tokens)
response = local_llm.invoke("Recommend 3 gym earbuds under Rs. 2,000, one line each.")
print(response.content)
print("\nToken usage :", response.usage_metadata)
print("Finish :", response.response_metadata["done_reason"])Output
Task 4 : Measure Latency
import time
from smartcart_v1 import llm as cloud_llm
import time
from smartcart_v1 import llm as cloud_llm
def time_call(model, prompt):
"""Return how many seconds one call takes."""
start = time.time()
model.invoke(prompt)
return round(time.time() - start, 2)
prompt = "Recommend 3 gym earbuds under Rs. 2,000, one line each."
!ollama stop qwen2.5:3b
print("Local cold start:", time_call(local_llm, prompt), "s")
for name, model in [("Cloud", cloud_llm), ("Local", local_llm)]:
times = [time_call(model, prompt) for run in range(3)]
print(f"{name} (warm): {times} -> average {sum(times) / 3:.2f} s")Output
Task 5 : Cost & Privacy Trade-offs
usage = cloud_llm.invoke(prompt).usage_metadata
tokens_per_request = usage["total_tokens"]
REQUESTS_PER_MONTH = 300_000 # SmartCart estimate: 10,000 chats a day
PRICE_PER_MILLION_TOKENS = 0.30 # USD -- example only, check groq.com/pricingusage = cloud_llm.invoke(prompt).usage_metadata
tokens_per_request = usage["total_tokens"]
REQUESTS_PER_MONTH = 300_000 # SmartCart estimate: 10,000 chats a day
PRICE_PER_MILLION_TOKENS = 0.30 # USD -- example only, check groq.com/pricing
monthly_tokens = tokens_per_request * REQUESTS_PER_MONTH
monthly_cost = monthly_tokens / 1_000_000 * PRICE_PER_MILLION_TOKENS
print(f"Tokens per request : {tokens_per_request}")
print(f"Tokens per month : {monthly_tokens:,}")
print(f"Cloud cost / month : ${monthly_cost:,.2f}")
print("Local cost / month : $0 in tokens -- but you pay for the machine")Output
Task 6 : Make SmartCart v2 Backend Swappable
%%writefile smartcart_backends.py
import os
from langchain_groq import ChatGroq
from langchain_ollama import ChatOllama
CLOUD_MODEL = "qwen/qwen3.8-27b"
LOCAL_MODEL = "qwen2.5:3b"Save the backend file
1
%%writefile smartcart_backends.py
import os
from langchain_groq import ChatGroq
from langchain_ollama import ChatOllama
CLOUD_MODEL = "qwen/qwen3.8-27b"
LOCAL_MODEL = "qwen2.5:3b"
def get_llm(backend="cloud"):
"""Return the chat model for 'cloud' (GroqCloud) or 'local' (Ollama)."""
if backend == "local":
return ChatOllama(
model=LOCAL_MODEL,
temperature=0.3,
num_predict=800,
format="json", # JSON mode in Ollama)
if backend == "cloud":
if not os.environ.get("GROQ_API_KEY"):
raise SystemExit("GROQ_API_KEY not found. Add it to Colab Secrets (Lab 9, Task 2).")
return ChatGroq(
model=CLOUD_MODEL,
temperature=0.3,
max_tokens=800,
model_kwargs={"response_format": {"type": "json_object"}},
reasoning_effort="none",)
raise ValueError(f"Unknown backend '{backend}'. Use 'cloud' or 'local'.")Update SmartCart v2
2
%%writefile smartcart_v2.py
import os
import json
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
from smartcart_backends import get_llm # NEW
BACKEND = os.environ.get("SMARTCART_BACKEND", "cloud") # NEW: "cloud" or "local"
llm = get_llm(BACKEND) # NEW%%writefile smartcart_v2.py
import os
import json
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
from smartcart_backends import get_llm # NEW
BACKEND = os.environ.get("SMARTCART_BACKEND", "cloud") # NEW: "cloud" or "local"
llm = get_llm(BACKEND) # NEW
EXIT_WORDS = ["quit", "exit", "bye"]
MAX_CHARS = 500
FRIENDLY_ERROR = "Sorry, I'm having trouble right now. Please try again in a moment."
SYSTEM_PROMPT = """You are Kart, SmartCart's friendly shopping assistant for shoppers in India.
Rules:
1. Only help with shopping. For anything else, politely say you can only help with shopping.
2. Recommend up to 3 products. Prices are in rupees.
3. Reply in the same style as the shopper: English stays English, Hinglish stays Hinglish.
4. Never make up SmartCart store policies. Say: "Please check the Help page in the SmartCart app."
5. Use the earlier conversation to understand words like "it", "that one" or "the second one".
6. When the shopper compares products, think step by step:
Step 1 list what the shopper needs, Step 2 check each product, Step 3 give a verdict.
Always reply in JSON with exactly these keys:
{"steps": ["reasoning steps, or an empty list if this is not a comparison"],
"reply": "a short friendly message, under 60 words",
"products": [{"name": "text", "price_rs": number,
"category": "Electronics or Grocery or Apparel",
"reason": "one short sentence"}]}"""
MEMORY_SIZE = 10
history = []
def check_input(text): # NEW: copied from Lab 10
"""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, ""%%writefile smartcart_v2.py
import os
import json
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
from smartcart_backends import get_llm # NEW
BACKEND = os.environ.get("SMARTCART_BACKEND", "cloud") # NEW: "cloud" or "local"
llm = get_llm(BACKEND) # NEW
EXIT_WORDS = ["quit", "exit", "bye"]
MAX_CHARS = 500
FRIENDLY_ERROR = "Sorry, I'm having trouble right now. Please try again in a moment."
SYSTEM_PROMPT = """You are Kart, SmartCart's friendly shopping assistant for shoppers in India.
Rules:
1. Only help with shopping. For anything else, politely say you can only help with shopping.
2. Recommend up to 3 products. Prices are in rupees.
3. Reply in the same style as the shopper: English stays English, Hinglish stays Hinglish.
4. Never make up SmartCart store policies. Say: "Please check the Help page in the SmartCart app."
5. Use the earlier conversation to understand words like "it", "that one" or "the second one".
6. When the shopper compares products, think step by step:
Step 1 list what the shopper needs, Step 2 check each product, Step 3 give a verdict.
Always reply in JSON with exactly these keys:
{"steps": ["reasoning steps, or an empty list if this is not a comparison"],
"reply": "a short friendly message, under 60 words",
"products": [{"name": "text", "price_rs": number,
"category": "Electronics or Grocery or Apparel",
"reason": "one short sentence"}]}"""
MEMORY_SIZE = 10
history = []
def check_input(text): # NEW: copied from Lab 10
"""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, ""
def ask_smartcart_v2(text):
"""Send the message with memory; return the reply as a dictionary."""
messages = ([SystemMessage(content=SYSTEM_PROMPT)]
+ history[-MEMORY_SIZE:]
+ [HumanMessage(content=text)])
response = llm.invoke(messages)
data = json.loads(response.content)
history.append(HumanMessage(content=text))
history.append(AIMessage(content=response.content))
return data
def show(data):
"""Print the reasoning steps, the message and the product cards."""
for step in data.get("steps", []):
print(" (thinking)", step)
print("Kart:", data.get("reply", ""))
for p in data.get("products", []):
print(f" [{p['category']}] {p['name']} – Rs. {p['price_rs']:,} – {p['reason']}")
def chat():
"""Run SmartCart AI v2 until the shopper types an exit word."""
global llm # NEW: lets chat() swap the model
print(f"SmartCart AI v2 [{BACKEND}] -- 'quit' to exit, 'new' to restart, "
"'use cloud' / 'use local' to switch")
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
%%writefile smartcart_v2.py
import os
import json
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
from smartcart_backends import get_llm # NEW
BACKEND = os.environ.get("SMARTCART_BACKEND", "cloud") # NEW: "cloud" or "local"
llm = get_llm(BACKEND) # NEW
EXIT_WORDS = ["quit", "exit", "bye"]
MAX_CHARS = 500
FRIENDLY_ERROR = "Sorry, I'm having trouble right now. Please try again in a moment."
SYSTEM_PROMPT = """You are Kart, SmartCart's friendly shopping assistant for shoppers in India.
Rules:
1. Only help with shopping. For anything else, politely say you can only help with shopping.
2. Recommend up to 3 products. Prices are in rupees.
3. Reply in the same style as the shopper: English stays English, Hinglish stays Hinglish.
4. Never make up SmartCart store policies. Say: "Please check the Help page in the SmartCart app."
5. Use the earlier conversation to understand words like "it", "that one" or "the second one".
6. When the shopper compares products, think step by step:
Step 1 list what the shopper needs, Step 2 check each product, Step 3 give a verdict.
Always reply in JSON with exactly these keys:
{"steps": ["reasoning steps, or an empty list if this is not a comparison"],
"reply": "a short friendly message, under 60 words",
"products": [{"name": "text", "price_rs": number,
"category": "Electronics or Grocery or Apparel",
"reason": "one short sentence"}]}"""
MEMORY_SIZE = 10
history = []
def check_input(text): # NEW: copied from Lab 10
"""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, ""
def ask_smartcart_v2(text):
"""Send the message with memory; return the reply as a dictionary."""
messages = ([SystemMessage(content=SYSTEM_PROMPT)]
+ history[-MEMORY_SIZE:]
+ [HumanMessage(content=text)])
response = llm.invoke(messages)
data = json.loads(response.content)
history.append(HumanMessage(content=text))
history.append(AIMessage(content=response.content))
return data
def show(data):
"""Print the reasoning steps, the message and the product cards."""
for step in data.get("steps", []):
print(" (thinking)", step)
print("Kart:", data.get("reply", ""))
for p in data.get("products", []):
print(f" [{p['category']}] {p['name']} – Rs. {p['price_rs']:,} – {p['reason']}")
def chat():
"""Run SmartCart AI v2 until the shopper types an exit word."""
global llm # NEW: lets chat() swap the model
print(f"SmartCart AI v2 [{BACKEND}] -- 'quit' to exit, 'new' to restart, "
"'use cloud' / 'use local' to switch")
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
BUDGET = 2000
for product in data["products"]:
within = "Yes" if product["price_rs"] <= BUDGET else "NO"
print("+-------------------------------------------")
print("| " + product["name"])
print(f"| Rs. {product['price_rs']:,} | {product['category']}")
print("| " + product["reason"])
print(f"| Within budget: {within}")
print("+-------------------------------------------")Output
Use a data like app would print products cards and check budget
2
Task 5 : Add Conversational Memory
history = [] # grows by 2 messages every turn
MEMORY_SIZE = 10 # send only the last 10 messages (5 turns)
def chat_with_memory(text):
"""Send the new message plus recent history; save both sides."""
messages = ([SystemMessage(content=SYSTEM_PROMPT)]
+ history[-MEMORY_SIZE:]
+ [HumanMessage(content=text)])
reply = llm.invoke(messages).content
history.append(HumanMessage(content=text))
history.append(AIMessage(content=reply))
return reply
print("Kart:", chat_with_memory("running shoes for women under 3000"), "\n")
print("Kart:", chat_with_memory("make the second one cheaper"), "\n")
print("Messages in memory:", len(history))Output
Task 6 : Build SmartCart v2
%%writefile smartcart_v2.py
import os
import json
from langchain_groq import ChatGroq
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
from smartcart_v1_chat import check_input, EXIT_WORDS, FRIENDLY_ERROR
if not os.environ.get("GROQ_API_KEY"):
raise SystemExit("GROQ_API_KEY not found. Add it to Colab Secrets (Lab 9, Task 2).")
llm = ChatGroq(
model="qwen/qwen3.8-27b",
temperature=0.3,
max_tokens=800,
model_kwargs={"response_format": {"type": "json_object"}}, # JSON mode
reasoning_effort="none",)
SYSTEM_PROMPT = """You are Kart, SmartCart's friendly shopping assistant for shoppers in India.
Rules:
1. Only help with shopping. For anything else, politely say you can only help with shopping.
2. Recommend up to 3 products. Prices are in rupees.
3. Reply in the same style as the shopper: English stays English, Hinglish stays Hinglish.
4. Never make up SmartCart store policies. Say: "Please check the Help page in the SmartCart app."
5. Use the earlier conversation to understand words like "it", "that one" or "the second one".
6. When the shopper compares products, think step by step:Save the Script
1
%%writefile smartcart_v2.py
import os
import json
from langchain_groq import ChatGroq
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
from smartcart_v1_chat import check_input, EXIT_WORDS, FRIENDLY_ERROR
if not os.environ.get("GROQ_API_KEY"):
raise SystemExit("GROQ_API_KEY not found. Add it to Colab Secrets (Lab 9, Task 2).")
llm = ChatGroq(
model="qwen/qwen3.8-27b",
temperature=0.3,
max_tokens=800,
model_kwargs={"response_format": {"type": "json_object"}}, # JSON mode
reasoning_effort="none",)
SYSTEM_PROMPT = """You are Kart, SmartCart's friendly shopping assistant for shoppers in India.
Rules:
1. Only help with shopping. For anything else, politely say you can only help with shopping.
2. Recommend up to 3 products. Prices are in rupees.
3. Reply in the same style as the shopper: English stays English, Hinglish stays Hinglish.
4. Never make up SmartCart store policies. Say: "Please check the Help page in the SmartCart app."
5. Use the earlier conversation to understand words like "it", "that one" or "the second one".
6. When the shopper compares products, think step by step:
Step 1 list what the shopper needs, Step 2 check each product, Step 3 give a verdict.
Always reply in JSON with exactly these keys:
{"steps": ["reasoning steps, or an empty list if this is not a comparison"],
"reply": "a short friendly message, under 60 words",
"products": [{"name": "text", "price_rs": number,
"category": "Electronics or Grocery or Apparel",
"reason": "one short sentence"}]}"""
MEMORY_SIZE = 10
history = []
def ask_smartcart_v2(text):
"""Send the message with memory; return the reply as a dictionary."""
messages = ([SystemMessage(content=SYSTEM_PROMPT)]
+ history[-MEMORY_SIZE:]
+ [HumanMessage(content=text)])
response = llm.invoke(messages)
data = json.loads(response.content) # JSON text -> dictionary
history.append(HumanMessage(content=text))
history.append(AIMessage(content=response.content))
return data
def show(data):
"""Print the reasoning steps, the message and the product cards."""
for step in data.get("steps", []):
print(" (thinking)", step)
print("Kart:", data.get("reply", ""))
for p in data.get("products", []):
print(f" [{p['category']}] {p['name']} – Rs. {p['price_rs']:,} – {p['reason']}")%%writefile smartcart_v2.py
import os
import json
from langchain_groq import ChatGroq
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
from smartcart_v1_chat import check_input, EXIT_WORDS, FRIENDLY_ERROR
if not os.environ.get("GROQ_API_KEY"):
raise SystemExit("GROQ_API_KEY not found. Add it to Colab Secrets (Lab 9, Task 2).")
llm = ChatGroq(
model="qwen/qwen3.8-27b",
temperature=0.3,
max_tokens=800,
model_kwargs={"response_format": {"type": "json_object"}}, # JSON mode
reasoning_effort="none",)
SYSTEM_PROMPT = """You are Kart, SmartCart's friendly shopping assistant for shoppers in India.
Rules:
1. Only help with shopping. For anything else, politely say you can only help with shopping.
2. Recommend up to 3 products. Prices are in rupees.
3. Reply in the same style as the shopper: English stays English, Hinglish stays Hinglish.
4. Never make up SmartCart store policies. Say: "Please check the Help page in the SmartCart app."
5. Use the earlier conversation to understand words like "it", "that one" or "the second one".
6. When the shopper compares products, think step by step:
Step 1 list what the shopper needs, Step 2 check each product, Step 3 give a verdict.
Always reply in JSON with exactly these keys:
{"steps": ["reasoning steps, or an empty list if this is not a comparison"],
"reply": "a short friendly message, under 60 words",
"products": [{"name": "text", "price_rs": number,
"category": "Electronics or Grocery or Apparel",
"reason": "one short sentence"}]}"""
MEMORY_SIZE = 10
history = []
def ask_smartcart_v2(text):
"""Send the message with memory; return the reply as a dictionary."""
messages = ([SystemMessage(content=SYSTEM_PROMPT)]
+ history[-MEMORY_SIZE:]
+ [HumanMessage(content=text)])
response = llm.invoke(messages)
data = json.loads(response.content) # JSON text -> dictionary
history.append(HumanMessage(content=text))
history.append(AIMessage(content=response.content))
return data
def show(data):
"""Print the reasoning steps, the message and the product cards."""
for step in data.get("steps", []):
print(" (thinking)", step)
print("Kart:", data.get("reply", ""))
for p in data.get("products", []):
print(f" [{p['category']}] {p['name']} – Rs. {p['price_rs']:,} – {p['reason']}")
def chat():
"""Run SmartCart AI v2 until the shopper types an exit word."""
print("SmartCart AI v2 -- type 'quit' to exit, 'new' to start a new conversation")
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 == "new":
history.clear()
print("Kart: Okay, starting fresh! What are you shopping for?")
continue
cleaned, problem = check_input(user_input)
if problem:
print("Kart:", problem)
continue
try:
show(ask_smartcart_v2(cleaned))
except json.JSONDecodeError:
print("Kart: Sorry, something went wrong with my answer. Please ask again.")
except Exception as error:
print("[log]", type(error).__name__, "-", str(error)[:200])
print("Kart:", FRIENDLY_ERROR)
if __name__ == "__main__":
chat()Run it, try a request, a follow up & a comparision
2
%run smartcart_v2.pyOutput
Task 7 : Final Test v1 vs v2
import pandas as pd
import smartcart_v2
tests = [
{"id": "T1", "input": "gym earbuds under Rs. 2,000"},
{"id": "T6", "input": "make the second one cheaper"},
{"id": "T7", "input": "who won the cricket match yesterday"},
{"id": "T8", "input": "What is SmartCart's return policy for opened electronics?"},
{"id": "T9", "input": "Compare boAt Airdopes 141 and Noise Buds VS104 for the gym"},
{"id": "T10", "input": "office ke liye formal shirt chahiye under 1500 rupees"},]
smartcart_v2.history.clear()
for case in tests:
data = smartcart_v2.ask_smartcart_v2(case["input"])
case["steps"] = len(data.get("steps", []))
case["products"] = len(data.get("products", []))
case["reply"] = data.get("reply", "")
results = pd.DataFrame(tests)
results.to_csv("smartcart_v2_test_results.csv", index=False)
print(results[["id", "steps", "products", "reply"]].to_string(max_colwidth=50))Output
Great job!
You have successfully used Chain of Thought prompting for checkable product and price comparisons, enforced valid JSON and JsonOutputParser in a LangChain, converted JSON responses into product cards, and checked budgets with one line of code. You also added memory using the last 10 messages and built SmartCart AI v2, successfully passing all tests that v1 failed.
Checkpoint
Git Push
git push origin branchNameNext-Lab Preparation
Topic : LLM Access - Running Models Locally
1) Running LLM Locally
2) Open-weight vs API Models
3) Swapping the provider
By Content ITV