n4nAI

E-commerce chatbot: from search to checkout with LangChain

Hands-on ecommerce chatbot search to checkout langchain tutorial: build semantic search, tool-calling agent, cart and checkout with runnable Python code.

n4n Team2 min read495 words

Audio narration

Coming soon — every post will get a voice note here.

Building a conversational shopping assistant that actually completes purchases is harder than demoing a Q&A bot. This tutorial walks through an ecommerce chatbot search to checkout langchain implementation that uses LangChain’s tool-calling agent to move a user from natural-language product discovery all the way to a mock order confirmation.

Prerequisites

  • Python 3.10 or newer
  • langchain, langchain-openai, langchain-community, faiss-cpu
  • An OpenAI API key (or any OpenAI-compatible endpoint)
  • A minimal product catalog in memory

Install dependencies:

pip install langchain langchain-openai langchain-community faiss-cpu python-dotenv

Semantic search beats keyword matching when users say “something for cold feet” instead of “socks”. We embed a small catalog and use FAISS for similarity lookup. For a production catalog with millions of SKUs you’d swap FAISS for a managed vector database, but the interface stays identical.

import os
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings

products = [
    {"id": "p1", "name": "Trailrunner Shoes", "description": "Lightweight hiking shoes with grip soles", "price": 89.99, "category": "footwear"},
    {"id": "p2", "name": "Summit Backpack 30L", "description": "Water-resistant backpack for day hikes", "price": 59.50, "category": "bags"},
    {"id": "p3", "name": "Merino Wool Socks", "description": "Breathable socks for cold weather", "price": 14.00, "category": "apparel"},
]

texts = [f"{p['name']}: {p['description']} (${p['price']})" for p in products]
metadatas = [{"id": p["id"], "price": p["price"]} for p in products]

embeddings = OpenAIEmbeddings(api_key=os.environ["OPENAI_API_KEY"])
vectorstore = FAISS.from_texts(texts, embeddings, metadatas=metadatas)

Checkpoint — confirm retrieval works before wiring the agent:

hits = vectorstore.similarity_search("hiking shoes", k=1)
print(hits[0].page_content)
# Trailrunner Shoes: Lightweight hiking shoes with grip soles ($89.99)

Tools for cart and checkout

LangChain tools are just decorated functions with docstrings the model reads to decide when to call them. The agent decides when to call them. We keep cart state in a module-level dict for the tutorial; in production use a session-backed store keyed by user ID.

from langchain.tools import tool

cart = {}

@tool
def search_products(query: str) -> str:
    """Search the catalog by semantic query. Returns top matches with IDs."""
    docs = vectorstore.similarity_search(query, k=2)
    return "\n".join(f"{d.metadata['id']}: {d.page_content}" for d in docs)

@tool
def add_to_cart(product_id: str, quantity: int = 1) -> str:
    """Add a product to the cart by its ID. Returns current cart."""
    if product_id not in [p["id"] for p in products]:
        return f"Unknown product {product_id}"
    cart[product_id] = cart.get(product_id, 0) + quantity
    return f"Added {quantity} x {product_id}. Cart: {cart}"

@tool
def checkout() -> str:
    """Compute total and place the order. Returns confirmation with total."""
    if not cart:
        return "Cart is empty."
    total = sum(next(p["price"] for p in products if p["id"] == pid) * qty for pid, qty in cart.items())
    order_id = "ORD-" + str(hash(frozenset(cart.items())) % 10000)
    cart.clear()
    return f"Order {order_id} placed. Total ${total:.2f}."

Test the search tool directly to verify formatting:

print(search_products.invoke({"query": "cold weather gear"}))
# p3: Merino Wool Socks: Breathable socks for cold weather ($14.0)
# p1: Trailrunner Shoes: Lightweight hiking shoes with grip soles ($89.99)

Agent assembly

We use the standard openai-tools-agent prompt from the LangChain hub. For production resilience, point ChatOpenAI at n4n.ai’s OpenAI-compatible endpoint: it honors client routing directives and provides automatic fallback when a provider is degraded, which keeps an ecommerce chatbot search to checkout langchain flow online under rate limits.

from langchain_openai import ChatOpenAI
from langchain.agents import create_openai_tools_agent, AgentExecutor
from langchain import hub

prompt = hub.pull("hwchase17/openai-tools-agent")
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
tools = [search_products, add_to_cart, checkout]
agent = create_openai_tools_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

Running from search to checkout

A single user turn can trigger the full pipeline. The agent searches, adds items, then checks out.

result = executor.invoke({
    "input": "I need shoes for hiking and a pair of wool socks. Then check out."
})
print(result["output"])

Expected trimmed output:

> Entering agent executor...
Call: search_products("hiking shoes")
Call: add_to_cart("p1", 1)
Call: add_to_cart("p3", 1)
Call: checkout()
Order ORD-1234 placed. Total $103.99.

The agent inferred two product IDs from the search results and completed the purchase without explicit UI steps. That is the core value of the ecommerce chatbot search to checkout langchain pattern: the LLM maps intent to existing backend operations.

Multi-turn conversations

AgentExecutor is stateless per call. Pass chat_history to maintain context across turns:

from langchain_core.messages import HumanMessage, AIMessage

history = []
def chat(user_msg: str) -> str:
    resp = executor.invoke({"input": user_msg, "chat_history": history})
    history.append(HumanMessage(content=user_msg))
    history.append(AIMessage(content=resp["output"]))
    return resp["output"]

chat("Show me bags under $60")
chat("Add the backpack to my cart")
chat("Now check out")

In a real deployment you’d persist history in the same session store as the cart and load it per request.

Hardening the flow

  • Validate tool inputs. The add_to_cart tool already rejects unknown IDs, but you should also enforce quantity limits and price sanity from the server, not trust the LLM’s arithmetic.
  • Isolate cart state. Replace the global cart dict with Redis or a database row keyed by session ID. The tool closures should read/write that store.
  • Make checkout idempotent. Real orders need an idempotency key; if the agent retries checkout() after a network blip you must not double-charge.
  • Stream tokens. Wrap the executor in RunnableWithMessageHistory and use .stream() so the user sees progress while the agent thinks.
  • Log tool calls. Keep an audit trail of which products were added and when, for dispute resolution and analytics.

The ecommerce chatbot search to checkout langchain pattern is fundamentally an agentic wrapper around three primitives: retrieval, state mutation, and transactional action. Get those right and the LLM is just the router that translates messy human text into clean function calls.

Tagslangchainecommercechatbotcheckout

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All framework tutorials: e-commerce search & recommendations posts →