How to Build RAG Chatbot with Pinecone - A Full-Stack Walkthrough A developer published a full-stack walkthrough for building a production-ready retrieval-augmented generation (RAG) chatbot that retrieves relevant passages from internal SOP documents and passes them to OpenAI's GPT-4 for citation-ready answers. The pipeline uses LangChain for orchestration, Pinecone as the vector database, FastAPI for an HTTP chat endpoint, and Docker Compose for deployment, with an estimated build time of six to eight hours for developers comfortable with Python and Docker. Result: By the end of this guide you will have a production-ready chatbot that pulls the most relevant passages from your internal SOP Standard Operating Procedure documents, runs them through OpenAI's GPT-4, and returns precise, citation-ready answers. The whole pipeline lives in a Docker-compose stack, uses LangChain for orchestration, and stores embeddings in Pinecone's vector database. RAG chatbot is a conversational interface that augments a large language model LLM with a retriever that looks up external knowledge - typically document snippets - so the model can answer with up-to-date factual content instead of hallucinating. What is RAG? Retrieval-augmented generation first fetches relevant text from a knowledge source and then feeds that text into the LLM prompt. | Tool | Plan / Price | Role | |---|---|---| | OpenAI API gpt-4-turbo | Pay-as-you-go ≈ $0.03 / 1 k prompt, $0.06 / 1 k completion see official pricing | LLM for answer generation | | Pinecone hosted vector DB | Managed cloud plan - check Pinecone's current pricing page for up-to-date costs | Store and query embeddings | | LangChain Python library | Free open-source | Orchestrate retrieval, prompting, and chat flow | | Docker + Docker-compose | Free community edition | Run all services locally or on a VM | | FastAPI web framework | Free open-source | Expose a simple HTTP chat endpoint | | Git source control | Free | Version your code | | SOP PDFs or markdown files | Free your internal docs | Knowledge source to embed | All prices are current as of August 2026; cloud providers may adjust rates, so always verify on the official pricing pages. Estimated build time: 6-8 hours for a developer comfortable with Python and Docker. Below is a concrete, numbered recipe. Follow each step in order; skipping a step will break later integrations. git clone https://github.com/aria-automation/rag-pinecone-starter.git cd rag-pinecone-starter python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt The requirements.txt pins LangChain 0.2.x, openai , pinecone-client , and fastapi . This guarantees reproducibility across machines. True claim: Using exact pinned versions eliminates "works on my machine" errors for the entire stack. sop-vectors . text-embedding-ada-002 vector size True claim: The text-embedding-ada-002 model outputs 1536-dimensional vectors, so the index dimension must match exactly. Store all SOP files in the data/ folder as plain .txt or .pdf . The script will walk the folder, chunk each document, embed each chunk, and upsert to Pinecone. Create a file embed documents.py with the following content the code block shows the core logic; the rest of the script contains argument parsing and logging : python embed documents.py - creates embeddings and pushes them to Pinecone import os, glob, json from pathlib import Path from langchain.text splitter import RecursiveCharacterTextSplitter from langchain.embeddings import OpenAIEmbeddings import pinecone === configuration === PINECONE API KEY = os.getenv "PINECONE API KEY" PINECONE ENV = os.getenv "PINECONE ENV" INDEX NAME = "sop-vectors" DOCS PATH = Path "./data" initialize clients pinecone.init api key=PINECONE API KEY, environment=PINECONE ENV index = pinecone.Index INDEX NAME embeder = OpenAIEmbeddings model="text-embedding-ada-002" splitter: 500-char chunks with 200-char overlap splitter = RecursiveCharacterTextSplitter chunk size=500, chunk overlap=200, separators= "\n\n", "\n", " " , def process file filepath: Path : raw = filepath.read text encoding="utf-8" chunks = splitter.split text raw ids, vectors, metadatas = , , for i, chunk in enumerate chunks : vec = embeder.embed query chunk ids.append f"{filepath.stem} {i}" vectors.append vec metadatas.append {"source": str filepath , "text": chunk} upsert in batches of 100 for start in range 0, len ids , 100 : end = start + 100 index.upsert vectors=list zip ids start:end , vectors start:end , metadatas start:end if name == " main ": for file in glob.glob str DOCS PATH / " . " : process file Path file print "Embedding complete." What this does: Walks every file under data/ , splits into overlapping chunks, creates embeddings with OpenAI, and upserts them to the Pinecone index in batches of 100. Run the script: export PINECONE API KEY=your-pinecone-key export PINECONE ENV=your-pinecone-env export OPENAI API KEY=your-openai-key python embed documents.py If the script finishes without errors, the index now holds a searchable vector representation of all SOP content. Create app.py that wires LangChain's Retriever to Pinecone and calls OpenAI's chat model: python app.py - FastAPI wrapper for RAG chat import os from fastapi import FastAPI, HTTPException from pydantic import BaseModel import pinecone from langchain.embeddings import OpenAIEmbeddings from langchain.vectorstores import Pinecone from langchain.chat models import ChatOpenAI from langchain.chains import RetrievalQA app = FastAPI Load env vars PINECONE API KEY = os.getenv "PINECONE API KEY" PINECONE ENV = os.getenv "PINECONE ENV" INDEX NAME = "sop-vectors" OPENAI API KEY = os.getenv "OPENAI API KEY" Initialize Pinecone and LangChain components pinecone.init api key=PINECONE API KEY, environment=PINECONE ENV vector store = Pinecone.from existing index index name=INDEX NAME, embedding=OpenAIEmbeddings model="text-embedding-ada-002" retriever = vector store.as retriever search kwargs={"k": 5} llm = ChatOpenAI model name="gpt-4-turbo", temperature=0 qa chain = RetrievalQA.from chain type llm=llm, retriever=retriever, return source documents=True class Query BaseModel : question: str @app.post "/chat" async def chat endpoint query: Query : try: result = qa chain {"query": query.question} answer = result "result" sources = {"source": doc.metadata "source" , "snippet": doc.page content :200 } for doc in result "source documents" return {"answer": answer, "sources": sources} except Exception as e: raise HTTPException status code=500, detail=str e What this does: Exposes a /chat POST endpoint that receives a JSON payload {"question":"..."} , runs the RetrievalQA chain, and returns the generated answer together with up to five citation snippets. Run locally to verify: uvicorn app:app --host 0.0.0.0 --port 8000 Test with curl : curl -X POST http://127.0.0.1:8000/chat \ -H "Content-Type: application/json" \ -d '{"question":"How do I reset a failed batch job according to the SOP?"}' You should see a JSON response containing an answer and a list of source documents. Create docker-compose.yml so the API, Pinecone optional local mock , and a reverse proxy run together: version: "3.9" services: api: build: . container name: rag api environment: - OPENAI API KEY=${OPENAI API KEY} - PINECONE API KEY=${PINECONE API KEY} - PINECONE ENV=${PINECONE ENV} ports: - "8000:8000" depends on: - vector-db vector-db: image: pinecone/pinecone:latest container name: pinecone mock environment: - PINECONE API KEY=${PINECONE API KEY} ports: - "8100:8100" NOTE: This is a local mock for offline dev; in prod you point to the hosted service. What this does: Builds the Python app into a Docker image Dockerfile uses python:3.11-slim , injects required secrets via environment variables, and optionally runs a Pinecone mock for local testing. Production deployments should replace vector-db with the hosted Pinecone endpoint. Build and launch: docker compose up --build -d The API is now reachable at http://localhost:8000/chat . If you want a quick front-end, create ui.html that posts to the API: < DOCTYPE html