How to Create a Client-Facing Knowledge Base with RAG
Build a customer-facing knowledge base powered by RAG for accurate answers.
Jay Banlasan
The AI Systems Guy
A client facing knowledge base with rag and ai search delivers accurate, conversational answers instead of forcing customers to browse through article lists. I build these as the public-facing version of internal RAG systems. Same technology, different audience. The key difference is tone, simplicity, and making sure the AI never exposes internal information.
Customers ask questions in plain language and get the answer they need in one response.
What You Need Before Starting
- Customer-facing help content (articles, guides, FAQs)
- Python 3.8+ with chromadb, anthropic, Flask
- A content review process (never auto-publish internal docs externally)
- A web frontend for the search experience
Step 1: Curate External Content
Only index content approved for customer access:
def prepare_external_content(articles):
external = []
for article in articles:
if article.get("visibility") != "public":
continue
if contains_internal_info(article["content"]):
flag_for_review(article["id"])
continue
external.append(article)
return external
def contains_internal_info(text):
internal_markers = ["INTERNAL ONLY", "CONFIDENTIAL", "internal use", "@company.slack.com"]
return any(marker.lower() in text.lower() for marker in internal_markers)
Step 2: Index with Customer-Friendly Metadata
from sentence_transformers import SentenceTransformer
import chromadb
model = SentenceTransformer("all-MiniLM-L6-v2")
chroma = chromadb.PersistentClient(path="./client_kb")
collection = chroma.get_or_create_collection("help_center")
def index_help_articles(articles):
for article in articles:
embedding = model.encode(f"{article['title']} {article['content']}").tolist()
collection.add(
ids=[article["id"]],
embeddings=[embedding],
documents=[article["content"]],
metadatas=[{
"title": article["title"],
"url": article["url"],
"category": article["category"],
"last_updated": article["updated_at"]
}]
)
Step 3: Build the Customer-Facing Q&A
import anthropic
client = anthropic.Anthropic()
CUSTOMER_PROMPT = """You are a helpful assistant for [Product Name].
Answer customer questions using only the provided help articles.
Rules:
- Be friendly and clear. Use simple language.
- Always link to the full article for more details
- Never mention internal processes, employee names, or internal tools
- If you cannot answer from the provided articles, say: "I could not find a specific answer. You can reach our support team at [email protected]."
- Never speculate or make up features"""
@app.route("/api/help/ask", methods=["POST"])
def customer_ask():
question = request.json["question"]
query_embedding = model.encode(question).tolist()
results = collection.query(query_embeddings=[query_embedding], n_results=3)
context = "\n\n".join([
f"Article: {results['metadatas'][0][i]['title']}\nURL: {results['metadatas'][0][i]['url']}\n{results['documents'][0][i]}"
for i in range(len(results["ids"][0]))
])
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=400,
system=CUSTOMER_PROMPT,
messages=[{"role": "user", "content": f"Help articles:\n{context}\n\nCustomer question: {question}"}]
)
return jsonify({
"answer": response.content[0].text,
"related_articles": [{"title": results["metadatas"][0][i]["title"], "url": results["metadatas"][0][i]["url"]} for i in range(len(results["ids"][0]))]
})
Step 4: Add Safety Filters
Prevent the AI from leaking anything it should not:
def filter_response(response_text):
blocked_patterns = ["internal", "employee", "slack channel", "jira", "confluence"]
for pattern in blocked_patterns:
if pattern.lower() in response_text.lower():
return "I could not generate a safe response. Please contact [email protected]."
return response_text
Step 5: Track Customer Search Behavior
def log_customer_search(question, answer, helpful=None):
conn = sqlite3.connect("help_analytics.db")
conn.execute("""
INSERT INTO searches (question, answer, helpful, searched_at)
VALUES (?, ?, ?, datetime('now'))
""", (question, answer, helpful))
conn.commit()
def get_content_gaps():
conn = sqlite3.connect("help_analytics.db")
return conn.execute("""
SELECT question, COUNT(*) as freq FROM searches
WHERE answer LIKE '%could not find%'
GROUP BY question ORDER BY freq DESC LIMIT 20
""").fetchall()
What to Build Next
Add personalized answers based on the customer's plan tier or product version. A free-tier customer asking about a premium feature should get a different response than an enterprise customer asking the same question.
Related Reading
- AI in Customer Service - knowledge bases as the first line of customer support
- The Centralized Brain Concept - external knowledge base as the customer-facing brain
- Build vs Buy: The AI Framework - building custom help experiences vs using existing platforms
Want this system built for your business?
Get a free assessment. We will map every system your business needs and show you the ROI.
Get Your Free Assessment