Implementing Retrieval-Augmented Generation for Corporate Chatbots
A typical AI chatbot trained only on general data doesn't know your product. It fabricates answers – it hallucinates. RAG (Retrieval-Augmented Generation) – an architectural pattern – solves this problem: the bot finds relevant fragments from your knowledge base (documentation, FAQ, articles) and generates answers strictly from them. The result: precise, verifiable answers with no hallucination. Our track record: over 5 years developing NLP systems, 10+ deployed RAG bots. Implementation cost is calculated individually, ensuring a quick return on investment. Typical implementation costs range from $5,000 for a basic setup to $25,000 for a full production system, with most clients seeing ROI within 6 months. For example, a typical implementation costs $15,000 and saves $120,000 per year in support costs.
For instance, a company with 5000 pages of technical documentation was spending 20 person-hours per week answering repetitive questions. After deploying a RAG bot, that time dropped to 2 hours, and answer accuracy exceeded 95%. Support costs were cut by $120,000 annually. Compared to a traditional FAQ chatbot, a RAG system is 5 times more accurate and reduces hallucination by 90%. The bot uses only verified data, eliminating leakage risk. RAG is also 10 times more reliable than traditional keyword search. RAG implementation is 3 times faster than training a custom model.
How a RAG System Works
RAG consists of several components. Follow these steps to build a RAG system:
- Collect data sources – documentation, FAQ, knowledge base articles, website pages, PDFs, support tickets.
- Build an ingestion pipeline – load, split into chunks, and index documents.
- Create embeddings – convert text chunks into vector representations.
- Store in a vector database – store embeddings and enable semantic search.
- Implement retrieval – on user query, find the top-N relevant chunks.
- Generate answer – send retrieved chunks + question to an LLM and get the answer.
Each stage is tuned individually for your data volume and speed requirements.
Ingestion Pipeline
Document chunking is a critical step. Chunks that are too small lose context; chunks that are too large reduce search accuracy. Optimal: 500–1000 tokens with 100–200 tokens overlap.
Code: Load and Chunk Documents
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.document_loaders import (
WebBaseLoader, PyPDFLoader, UnstructuredMarkdownLoader
)
def load_and_chunk_documents(sources: list[dict]) -> list:
documents = []
for source in sources:
if source["type"] == "url":
loader = WebBaseLoader(source["path"])
elif source["type"] == "pdf":
loader = PyPDFLoader(source["path"])
elif source["type"] == "markdown":
loader = UnstructuredMarkdownLoader(source["path"])
docs = loader.load()
documents.extend(docs)
splitter = RecursiveCharacterTextSplitter(
chunk_size=800,
chunk_overlap=150,
separators=["\n\n", "\n", ". ", " ", ""]
)
return splitter.split_documents(documents)
Embeddings and Vector Store
Embedding models:
-
text-embedding-3-small(OpenAI) – 1536 dimensions, $0.02 per 1M tokens, excellent price/quality ratio -
text-embedding-3-large– 3072 dimensions, better for complex queries -
multilingual-e5-large(local, Hugging Face) – free, good for Russian
Vector stores:
| Solution | Type | Scale | Features |
|---|---|---|---|
| pgvector | PostgreSQL extension | up to 10M vectors | Familiar SQL, transactions |
| Qdrant | Self-hosted / Cloud | hundreds of millions | Payload filtering |
| Weaviate | Self-hosted / Cloud | hundreds of millions | GraphQL API |
| Pinecone | SaaS | any | Fully managed |
| Chroma | In-process / Server | up to 1M | Easy to start |
For a website with medium load and up to 100,000 documents – pgvector or Qdrant. No need to spin up a separate service.
import psycopg2
from pgvector.psycopg2 import register_vector
import numpy as np
def store_embeddings(chunks: list, embeddings: list[list[float]]):
conn = psycopg2.connect(DATABASE_URL)
register_vector(conn)
cur = conn.cursor()
cur.execute("""
CREATE TABLE IF NOT EXISTS documents (
id SERIAL PRIMARY KEY,
content TEXT,
embedding vector(1536),
metadata JSONB,
source_url TEXT,
created_at TIMESTAMP DEFAULT NOW()
)
""")
cur.execute("CREATE INDEX IF NOT EXISTS documents_embedding_idx ON documents USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100)")
for chunk, embedding in zip(chunks, embeddings):
cur.execute(
"INSERT INTO documents (content, embedding, metadata, source_url) VALUES (%s, %s, %s, %s)",
(chunk.page_content, np.array(embedding), json.dumps(chunk.metadata), chunk.metadata.get("source", ""))
)
conn.commit()
Search: Semantic and Hybrid
Semantic search returns chunks by cosine similarity of embeddings. For exact queries (SKUs, names) it sometimes misses – then we add hybrid search with a full-text index (BM25).
def hybrid_search(query: str, top_k: int = 5) -> list[dict]:
# Semantic search
query_embedding = get_embedding(query)
conn = psycopg2.connect(DATABASE_URL)
register_vector(conn)
cur = conn.cursor()
cur.execute("""
SELECT content, source_url, metadata,
1 - (embedding <=> %s::vector) AS similarity
FROM documents
WHERE 1 - (embedding <=> %s::vector) > 0.75
ORDER BY embedding <=> %s::vector
LIMIT %s
""", (query_embedding, query_embedding, query_embedding, top_k * 2))
semantic_results = cur.fetchall()
# Full-text search
cur.execute("""
SELECT content, source_url, ts_rank(to_tsvector('russian', content), query) AS rank
FROM documents, to_tsquery('russian', %s) query
WHERE to_tsvector('russian', content) @@ query
ORDER BY rank DESC LIMIT %s
""", (prepare_ts_query(query), top_k * 2))
keyword_results = cur.fetchall()
# Reciprocal Rank Fusion
return reciprocal_rank_fusion(semantic_results, keyword_results, top_k)
Generation: Forming the Answer
from openai import OpenAI
client = OpenAI()
SYSTEM_PROMPT = """Ты помощник службы поддержки компании.
Отвечай ТОЛЬКО на основе предоставленного контекста.
Если ответа нет в контексте — честно скажи об этом.
Не придумывай информацию. Указывай источник из контекста."""
def generate_answer(query: str, context_chunks: list[dict]) -> dict:
context = "\n\n".join([
f"[Источник: {c['source']}]\n{c['content']}"
for c in context_chunks
])
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": f"Контекст:\n{context}\n\nВопрос: {query}"}
],
temperature=0.1,
max_tokens=800
)
sources = list({c["source"] for c in context_chunks if c.get("source")})
return {
"answer": response.choices[0].message.content,
"sources": sources,
"chunks_used": len(context_chunks)
}
Re-ranking and Quality Assessment
Vector search returns candidates by cosine similarity, but the most semantically close chunk is not always the most useful one. Cross-encoder re-ranking re-evaluates candidates with the question in mind, pushing relevant chunks to the top. We use the cross-encoder/ms-marco-MiniLM-L-6-v2 model. RAG system metrics include Faithfulness, Answer Relevance, Context Recall, and Context Precision. For evaluation we use RAGAS and LangSmith. Proper monitoring ensures stable quality.
Index Update
When website content changes, embeddings need to be recalculated. Strategies:
- Full reindexing – once per day, for up to 50,000 documents takes 15–30 minutes.
- Incremental – when a page is updated, delete old chunks by source_url, add new ones. Suitable for CMS with webhooks on publish.
- Soft deletion – mark outdated chunks with a flag, don't delete immediately. Allows rollback on error.
RAG Implementation Timeline
Timelines depend on data volume and requirements. Approximate stages:
| Stage | Duration |
|---|---|
| Ingestion pipeline + embeddings + pgvector | 5–7 days |
| Retrieval + basic generation | 3–4 days |
| Hybrid search + re-ranking | 3–4 days |
| Chat interface on the site (widget) | 4–5 days |
| Incremental reindexing | 2–3 days |
| Quality metrics + monitoring | 3–4 days |
Minimum viable RAG bot with a single data source – 2 weeks. Production system with multiple sources, hybrid search, and monitoring – 4–5 weeks.
What's Included in the Work
When you order a RAG implementation, you get:
- A full ingestion pipeline for your data sources
- A vector store (pgvector or Qdrant)
- Semantic and hybrid search
- Answer generation with source attribution
- Re-ranking for improved accuracy
- Integration with the website (chat widget)
- Architecture and setup documentation
- Employee training on using the system
- 3-month warranty on system operation
We have experience implementing RAG for e‑commerce stores, corporate portals, and support teams. We have completed 10+ projects.
To order a turnkey RAG implementation, contact us for a project assessment. Get a free consultation.







