CopilotKit v1.50 is coming soon!

Back
By Bonnie and Nathan Tarbert

TL;DR

In this guide, you will learn how to build a RAG(Retrieval-Augmented Generation)-powered e-commerce platform using LangGraph, MongoDB Vector Search, and CopilotKit. The e-commerce platform helps users find products and get tailored product recommendations using LLMs.

Before we jump in, here is what we will cover:

  • What is RAG(Retrieval-Augmented Generation )?
  • What is MongoDB Atlas Vector Search, and what makes it stand out?
  • Implementing RAG using LangGraph and MongoDB Atlas Vector Search
  • Building a frontend UI to query the RAG-powered e-commerce AI agent using MongoDB LeafyGreen Design System and CopilotKit.

Here’s a preview of the application we’ll be building.

What is RAG (Retrieval-Augmented Generation)?

Imagine you’re using a language model (like ChatGPT) to answer questions. These models are trained on massive datasets and can generate human-like text, but they have limitations:

  1. Limited Knowledge: They only know what’s in their training data, which might be outdated or incomplete.
  2. Hallucination: Sometimes, they make up answers that sound convincing but are wrong because they don’t have the right information.
  3. Context-Specific Answers: If you ask about something very specific (like internal company docs or recent news), the model might not have that info.

That is where RAG comes in.

It solves these problems by giving the model access to external information (like a database, documents, or web pages).

Instead of the AI guessing answers based on what it remembers, it can look for the right information and then explain it in a way that makes sense.

You can learn more about Retrieval-Augmented Generation (RAG) here.

__wf_reserved_inherit

What is MongoDB Atlas Vector Search, and what makes it stand out?

MongoDB Atlas Vector Search is a platform used to create vector indexes and perform vector searches, including approximate nearest neighbor (ANN) and exact nearest neighbor (ENN) searches, on vector embeddings representing data such as text, images, or audio.

This enables applications to retrieve results based on contextual similarity rather than exact keyword matches, making it useful for AI-driven applications like recommendation systems, chatbots, and image recognition.

Here is what makes MongoDB Atlas Vector Search stand out from the rest:

  • Native Integration: Atlas Vector Search is built into MongoDB, which means there is no need to sync data between your operational database and vector database, hence saving time, reducing complexity, and preventing errors.
  • Powerful query capabilities: Atlas Vector Search allows you to easily combine vector queries with filters on meta-data, graph lookups, aggregation pipelines, geo-spatial search, and lexical search for powerful hybrid search use cases within a single database.
  • Scalability and Performance: Unlike other solutions, MongoDB’s distributed architecture scales vector search independently from the core database. This enables workload isolation and optimization for vector queries, resulting in superior performance at scale.
  • Enterprise-Grade Security: Atlas Vector Search inherits MongoDB Atlas’s robust security features, including encryption, high availability, and compliance with industry standards, which makes it suitable for sensitive and regulated workloads.

You can learn more about MongoDB Atlas Vector Search here.

__wf_reserved_inherit

Prerequisites

To fully understand this tutorial, you need to have a basic understanding of React or Next.js.

We'll also make use of the following:

  • Python - a popular programming language for building AI agents with LangGraph—make sure it is installed on your computer.
  • LangGraph - a framework for creating and deploying AI agents. It also helps to define the control flows and actions to be performed by the agent.
  • OpenAI API Key - to enable us to perform various tasks using the GPT models; for this tutorial, ensure you have access to the GPT-4 model.
  • MongoDB Atlas Vector Search - a platform used to create vector indexes and perform vector search, including semantic search and hybrid search, on your vector embeddings
  • LeafyGreen Design System - MongoDB’s open-source design system for building intuitive, and beautiful UI
  • CopilotKit - an open-source copilot framework for building custom AI chatbots, in-app AI agents, and text areas.

Implementing RAG using LangGraph and MongoDB Atlas Vector Search

In this section, you will learn how to build and run a RAG-powered e-commerce AI agent using LangGraph, MongoDB Atlas Vector Search, and OpenAI LLMs.

After that, you will learn how to deploy the e-commerce AI agent to a cloud application platform known as Render.

Before we get started, let us talk about how RAG is implemented using MongoDB Atlas Vector Search.

First, you store your custom data as vector embeddings in a vector database such as MongoDB Atlas.

Then retrieve semantically similar data based on the user’s query using a search solution such as MongoDB Atlas Vector Search.

Finally, feed your LLM with the retrieved data as context to generate a more accurate and relevant response, reducing hallucinations.

Here is a diagram that explains RAG implementation using MongoDB better.

__wf_reserved_inherit

You can also learn more about implementing RAG with Atlas Vector Search on MongoDB docs.

__wf_reserved_inherit

Now that you have a clear idea of how RAG is implemented using MongoDB, let us jump into building the RAG-powered e-commerce AI agent.

Step 1: Building the RAG-powered e-commerce AI agent

First, start by cloning the ecommerce-rag-agent repository, which contains code for a Python-based LangGraph agent:

git clone <https://github.com/TheGreatBonnie/ecommerce-rag-agent.git>

‍The repository contains a RAG-powered e-commerce AI agent with the following structure:

__wf_reserved_inherit

Next, create a .env file in the ecommerce-rag-agent folder. Then add OpenAI, LangSmith, and MongoDB Atlas credentials into the environment variables

OPENAI_API_KEY=your_openai_api_key
LANGSMITH_API_KEY=your_langsmith_api_key
MONGODB_USERNAME=your_mongodb_username
MONGODB_PASSWORD=your_mongodb_password
MONGODB_CLUSTER=your_cluster_address
MONGODB_OPTIONS=retryWrites=true&w=majority&appName=Cluster0
EMBEDDING_MODEL=text-embedding-3-small
PYTHON_VERSION="3.12.2"
PORT="8000"

Then install all packages and dependencies using Poetry.

poetry install

Once all packages and dependencies have been installed, let us now see how to run the RAG-powered e-commerce AI agent.

Step 2: Running and testing the RAG-powered e-commerce AI agent

To run the e-commerce AI agent, execute the following command in the command line.

poetry run langgraph dev

Once the AI agent has started, it will open in the browser on the LangGraph studio, and you can visualize it, as shown below.

__wf_reserved_inherit

To test the e-commerce AI agent, add the “Find me a good laptop for programming under $1500” query to the messages state variable and click the Submit button.

__wf_reserved_inherit

The e-commerce AI agent will start searching for programming laptops under $1500. Once done, the agent will provide tailored recommendations, as shown below.

__wf_reserved_inherit

Now that you have learned how to run and test the e-commerce AI agent, let us see how to deploy it.

Step 3: Deploying the RAG-powered e-commerce AI agent

To deploy the e-commerce AI agent, push the AI agent code to a GitHub repository, as shown below.

__wf_reserved_inherit

After that, sign up to Render.com and select Web Services as your resource type on your Render dashboard.

__wf_reserved_inherit

Then connect GitHub as your Git provider to deploy the e-commerce AI agent repository.

__wf_reserved_inherit

Next, select the e-commerce AI agent repository and add a unique name for the web service, as shown below.

__wf_reserved_inherit

Then scroll down to add “poetry run demo” as the start command and select the instance type, as shown below.

__wf_reserved_inherit

Finally, add all the environment variables you added in the .env file, and click the Deploy Web Service button, as shown below.

__wf_reserved_inherit

Once the AI agent has been deployed, grab its URL. The URL will be used to register the e-commerce agent with Copilot Cloud.

__wf_reserved_inherit

Now that we have learned how to build, run, and deploy the e-commerce AI agent, let’s see how we can add a frontend UI to chat with it.

Building a Frontend UI to Query the RAG-powered E-commerce AI Agent

In this section, you will learn how to build a frontend UI to query the RAG-powered e-commerce AI agent using Copilot Cloud and CopilotKit.

Let’s get started.

Step 1: Registering the RAG-powered e-commerce AI agent with Copilot Cloud

To register the RAG-powered e-commerce AI agent, go to Copilot Cloud, sign in, and click the Get Started button.

Then add your OpenAI API key to the "Provide OpenAI API Key" section, as shown below.

Next, scroll down to the remote endpoints section and click the Add New button.

Then select the remote endpoint from the modal that pops up. After that, add your AI agent endpoint URL from Render.com and click the Save Endpoint button, as shown below.

__wf_reserved_inherit

Once the AI agent endpoint is saved, copy the Copilot Cloud Public API Key, as shown below.

Step 2: Adding the RAG-powered e-commerce AI agent UI

To build the e-commerce AI agent UI, start by cloning the e-commerce AI agent UI repository, which contains code for a Next.js project:

git clone <https://github.com/TheGreatBonnie/ecommerce-ui.git>

‍Next, create a .env file in the root directory. Then add your Copilot Cloud Public API Key into the environment variables.

NEXT_PUBLIC_CPK_PUBLIC_API_KEY=your-copilot-cloud-api-key

After that, install the frontend dependencies using pnpm.

pnpm install

Then start the app using the command below.

pnpm run dev

Navigate to http://localhost:3000/ and you should see the e-commerce AI agent frontend up and running.

__wf_reserved_inherit

Let’s now see how to build the frontend UI for the e-commerce AI agent using CopilotKit.

Step 2: Setup CopilotKit Provider

To set up the CopilotKit Provider, the <CopilotKit> component should wrap the Copilot-aware parts of your application. For most use cases, it's appropriate to wrap the CopilotKit provider around the entire app, e.g., in your layout.tsx, as shown below in the app/layout.tsx file

import type React from "react";
import { ReactNode } from "react";
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import Navigation from "@/components/navigation";
import { ThemeProvider } from "@/components/theme-provider";
import { Toaster } from "@/components/ui/toaster";
import { CartProvider } from "@/context/cart-context";
import { CopilotKit } from "@copilotkit/react-core";
import "@copilotkit/react-ui/styles.css";
const inter = Inter({ subsets: ["latin"] });
//...
export default function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html lang="en">
      <body className={inter.className}>
        {/* CopilotKit wrapper provides AI capabilities throughout the app */}
        <CopilotKit
          publicApiKey={process.env.NEXT_PUBLIC_CPK_PUBLIC_API_KEY}
          agent="ecommerce_agent"
        >
          {/* ThemeProvider manages light/dark mode for the application */}
          <ThemeProvider
            attribute="class"
            defaultTheme="light"
            enableSystem
            disableTransitionOnChange
          >
            {/* CartProvider manages the shopping cart state globally */}
            <CartProvider>
              {/* Main navigation bar component */} <Navigation />
              {/* Main content area with minimum height calculation to ensure footer positioning */}
              <div className="min-h-[calc(100vh-73px)]">{children}</div>
              {/* Toast notifications component for displaying messages */}
              <Toaster />
            </CartProvider>
          </ThemeProvider>
        </CopilotKit>
      </body>
    </html>
  );
}

Step 3: Choose a Copilot UI

To set up your Copilot UI, first import the default styles in your root component (typically layout.tsx).

import "@copilotkit/react-ui/styles.css";

Copilot UI ships with a number of built-in UI patterns; choose whichever one you like from CopilotPopup, CopilotSidebar, CopilotChat, to Headless UI.

In this case, we will use Copilot Sidebar as shown in the app/page.tsx file.

"use client";
import ProductGrid from "@/components/product-grid";
import SearchBar from "@/components/search-bar";
import { products } from "@/lib/mock-data";
import { CopilotSidebar } from "@copilotkit/react-ui";
import { Progress } from "@/components/Progress";
export default function Home() {
  return (
    <CopilotSidebar
      defaultOpen={false}
      instructions={
        "You are assisting the user as best as you can. Answer in the best way possible given the data you have."
      }
      onSubmitMessage={async (message) => {
        // clear the logs before starting the new research
        setState({ ...state, logs: [] });
        await new Promise((resolve) => setTimeout(resolve, 30));
      }}
      labels={{
        title: "Sidebar Assistant",
        initial: "How can I help you today?",
      }}
    >
      <main className="container mx-auto px-4 py-8">
        {" "}
        <div className="mb-8">
          <SearchBar />{" "}
        </div>
        <h1 className="text-3xl font-bold mb-6">Featured Products</h1>{" "}
        <ProductGrid products={products} />{" "}
      </main>{" "}
    </CopilotSidebar>
  );
}

The sidebar is then rendered on the frontend UI, as shown below.

__wf_reserved_inherit

Step 4: Creating a shared state between the UI and the RAG-poered e-commerce AI agent

In CopilotKit, AI agents maintain a shared state that seamlessly connects your UI with the agent's execution. This shared state system allows you to:

  • Display the agent's current progress and intermediate results
  • Update the agent's state through UI interactions
  • React to state changes in real-time across your application

You can learn more about CoAgents’ shared state on CopilotKit docs.

To create a shared state between the frontend UI and the RAG-powered e-commerce AI agent, first, you need to define the agent state and emit it to the front end, as shown in the ecommerce_agent/agent.py file.

class ToolNode:  
    """Node for executing tools in a workflow graph."""
    def __init__(self, tools):
        self.tools = tools
    async def __call__(self, state, config):
        # Initialize or retrieve logs list
        state["logs"] = state.get("logs", [])
    # Update processing status
    state["processing_status"] = "processing"
    
    # Initialize additional state properties for tracking
    state["current_query"] = AgentState.current_query
    state["search_stage"] = AgentState.search_stage
    state["progress_percentage"] = AgentState.progress_percentage
    state["active_filters"] = AgentState.active_filters
    state["matched_products_count"] = AgentState.matched_products_count
    state["filtered_products_count"] = AgentState.filtered_products_count
    state["processing_time"] = AgentState.processing_time
    state["search_history"] = AgentState.search_history
    state["error_message"] = AgentState.error_message
    
    # Initial state emission to show we're starting
    await copilotkit_emit_state(config, state)
    
    # Get the tool call from the last message if it exists
    last_message = state["messages"][-1]
    if not isinstance(last_message, AIMessage) or "tool_calls" not in last_message.additional_kwargs:
        return state
    tool_calls = last_message.additional_kwargs["tool_calls"]
    
    # Execute each tool call
    for tool_call in tool_calls:
        tool_name = tool_call["function"]["name"]
        tool_args = json.loads(tool_call["function"]["arguments"])
        tool_call_id = tool_call["id"]
        
        # Add a log entry for this tool call
        log_entry = {
            "message": f"Processing {tool_name} with query: {tool_args.get('query', '')}",
            "done": False
        }      
        state["logs"].append(log_entry)
        
        # Emit state to update frontend about the tool execution starting
        await copilotkit_emit_state(config, state)

        # Find and execute the matching tool
        for i, tool in enumerate(self.tools):
            if tool.name == tool_name:
                try:
                    # Pass arguments as the input parameter dictionary
                    result = await tool.ainvoke(input=tool_args["query"])
                    
                    # Add a proper tool message with the tool_call_id
                    tool_message = ToolMessage(
                        content=str(result),
                        tool_call_id=tool_call_id
                    )
                    state["messages"].append(tool_message)

                    # Update state with the latest status from AgentState
                    state["current_query"] = AgentState.current_query
                    state["search_stage"] = AgentState.search_stage
                    state["progress_percentage"] = AgentState.progress_percentage
                    state["active_filters"] = AgentState.active_filters
                    state["matched_products_count"] = AgentState.matched_products_count
                    state["filtered_products_count"] = AgentState.filtered_products_count
                    state["processing_time"] = AgentState.processing_time
                    state["search_history"] = AgentState.search_history
                    state["error_message"] = AgentState.error_message
                    # Mark the log entry as complete
                    state["logs"][-1]["done"] = True
                    # Emit intermediate state after tool execution
                    await copilotkit_emit_state(config, state)
                    except Exception as e:
                        # Update log with error
                        state["logs"][-1]["message"] = f"Error in {tool_name}: {str(e)}"
                        state["logs"][-1]["done"] = True
                        # Update error state
                        state["error_message"] = f"Error in {tool_name}: {str(e)}"
                        state["search_stage"] = "error"
                        state["progress_percentage"] = 0
                        # Emit error state
                        await copilotkit_emit_state(config, state)
                        # Add error message to messages
                        error_message = ToolMessage(
                            content=f"Error executing {tool_name}: {str(e)}",
                            tool_call_id=tool_call_id
                        )
                        state["messages"].append(error_message)
        
                    break
        
        # Clear logs after processing is complete but keep other state data
        state["logs"] = []
        state["processing_status"] = "completed"
        
        # Final state emission
        await copilotkit_emit_state(config, state)

        return state</span>

Then use the CopilotKit useCoAgent hook to share the RAG-powered e-commerce AI agent state with your frontend UI, as shown in the app/page.tsx file

"use client";
import ProductGrid from "@/components/product-grid";
import SearchBar from "@/components/search-bar";
import { products } from "@/lib/mock-data";
import { CopilotSidebar } from "@copilotkit/react-ui";
import { AgentState } from "@/lib/types";
import {
  useCoAgent,
  useCoAgentStateRender,
  useCopilotAction,
} from "@copilotkit/react-core";
import { Progress } from "@/components/Progress";
export default function Home() {
  /**
   * Initialize and manage the AI assistant agent state  * useCoAgent hook creates and manages state for the CopilotKit assistant
   * @property {string} name - Unique identifier for this agent instance
   * @property {AgentState} initialState - Initial values for all agent state properties
   * */
  const { state, setState } =
    useCoAgent <AgentState>{
      name: "ecommerce_agent",
      initialState: {
        logs: [],
        // Logs of agent actions for displaying progress
        processing_status: "idle",
        // Current processing status of the agent
        current_query: "",
        // The user's current search query
        search_stage: "",
        // Current stage of the search process
        progress_percentage: 0,
        // Progress indicator for current operation
        active_filters: {},
        // Applied filters for product search
        matched_products_count: 0,
        // Number of products matching the search criteria
        filtered_products_count: 0,
        // Number of products after applying filters
        processing_time: 0,
        // Time taken to process the request
        search_history: [],
        // History of previous searches
        error_message: "",
        // Error message if something goes wrong
      },
    };
  return (
    <CopilotSidebar
      defaultOpen={false}
      instructions={
        "You are assisting the user as best as you can. Answer in the best way possible given the data you have."
      }
      onSubmitMessage={async (message) => {
        // clear the logs before starting the new research
        setState({ ...state, logs: [] });
        await new Promise((resolve) => setTimeout(resolve, 30));
      }}
      labels={{
        title: "Sidebar Assistant",
        initial: "How can I help you today?",
      }}
    >
      {/*....*/}
    </CopilotSidebar>
  );
}

Next, render the agent's state in the sidebar UI. This is useful for informing the user about the agent's state in a more in-context way. To do this, you can use the useCoAgentStateRender hook, as shown in the app/page.tsx file.

"use client";
import ProductGrid from "@/components/product-grid";
import SearchBar from "@/components/search-bar";
import { products } from "@/lib/mock-data";
import { CopilotSidebar } from "@copilotkit/react-ui";
import { AgentState } from "@/lib/types";
import {
  useCoAgent,
  useCoAgentStateRender,
  useCopilotAction,
} from "@copilotkit/react-core";
import { Progress } from "@/components/Progress";
export default function Home() {
  /**
   * Configure how the agent state should be rendered in the UI
   * This callback determines when and how to show the Progress component
   *  @property {string} name - Must match the agent name from useCoAgent
   * @property {Function} render - Callback that returns JSX based on agent state
   */
  useCoAgentStateRender({
    name: "ecommerce_agent",
    render: ({ state, nodeName, status }) => {
      // Only show progress if there are logs or progress has started
      if (
        !state.logs ||
        (state.logs.length === 0 && state.progress_percentage === 0)
      ) {
        return null;
      }
      return <Progress logs={state.logs} state={state} />;
    },
  });
  return (
    <CopilotSidebar
      defaultOpen={false}
      instructions={
        "You are assisting the user as best as you can. Answer in the best way possible given the data you have."
      }
      onSubmitMessage={async (message) => {
        // clear the logs before starting the new research
        setState({ ...state, logs: [] });
        await new Promise((resolve) => setTimeout(resolve, 30));
      }}
      labels={{
        title: "Sidebar Assistant",
        initial: "How can I help you today?",
      }}
    >
      {/*...*/}
    </CopilotSidebar>
  );
}

Then navigate to http://localhost:3000/, add “Find me a good laptop for programming under $1500” to the sidebar chat, and press “Enter.” You should see the RAG-powered e-commerce AI agent state rendered in the chat UI and tailored product recommendations, as shown below.

Congratulations! You have successfully built a RAG-powered e-commerce platform using LangGraph, MongoDB Vector Search, and CopilotKit.

Conclusion

In this guide, we have walked through the steps of building a RAG-powered e-commerce platform using LangGraph, MongoDB Atlas Vector Search, and CopilotKit.

While we’ve explored a couple of features, we have barely scratched the surface of the countless use cases for CopilotKit, ranging from building interactive AI chatbots to building agentic solutions—in essence, CopilotKit lets you add a ton of useful AI capabilities to your products in minutes.

Hopefully, this guide makes it easier for you to integrate AI-powered Copilots into your existing application.

Follow CopilotKit on Twitter and say hi, and if you'd like to build something cool, join the Discord community.

Top posts

See All
AG-UI and A2UI Explained: How the Emerging Agentic Stack Fits Together
Nathan Tarbert November 19, 2025
AG-UI and A2UI Explained: How the Emerging Agentic Stack Fits TogetherThe agentic ecosystem is evolving fast — and with new standards appearing almost weekly, it’s easy to get lost in the terminology. Two names that often get mixed up are AG-UI and A2UI. They sound similar, but they actually serve very different purposes. Even better: they complement each other beautifully.CopilotKit has been working closely with Google on A2UI, and we’ll be shipping full support when the A2UI spec launches. But before that happens, let’s break down how these pieces fit into the broader agentic landscape.
Build a Frontend for your Microsoft Agent Framework Agents with AG-UI
Bonnie and Nathan TarbertNovember 11, 2025
Build a Frontend for your Microsoft Agent Framework Agents with AG-UIIn this guide, you will learn how to build a frontend for your Microsoft Agent Framework Agents using AG-UI Protocol and CopilotKit. Microsoft Agent Framework will power the AI agents backend, while CopilotKit powers the frontend, and then AG-UI creates a bridge that enables the frontend to communicate with the backend.
Microsoft Agent Framework is now AG-UI Compatible!
Uli Barkai and Nathan TarbertNovember 11, 2025
Microsoft Agent Framework is now AG-UI Compatible!We’re excited to announce that Microsoft’s Agent Framework is now fully compatible with the AG-UI protocol - the open standard powering frontend-agent communication across the ecosystem. This integration means you can now connect Microsoft’s powerful reasoning and orchestration layer directly to rich, real-time user interfaces - without custom socket code, polling loops, or one-off APIs.
Are you ready?

Stay in the know

Subscribe to our blog and get updates on CopilotKit in your inbox.