You will build a pipeline that analyses your support ticket history and documentation, identifies the most frequently asked questions, generates clear answers grounded in your knowledge base, and outputs a formatted FAQ page. The end result: your FAQ stays current automatically — when new question patterns emerge in support tickets, the pipeline surfaces them and drafts answers for review. Here is the complete system on dedicated GPU infrastructure.
Pipeline Architecture
| Stage | Tool | Purpose |
|---|---|---|
| 1. Ticket analysis | LLaMA 3.1 8B | Extract questions from tickets |
| 2. Clustering | Embeddings + HDBSCAN | Group similar questions |
| 3. Answer generation | LLM + RAG (ChromaDB) | Generate grounded answers |
| 4. Quality check | LLM | Verify answer accuracy |
Stage 1: Question Extraction from Tickets
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="none")
def extract_questions(ticket_text: str) -> list:
response = client.chat.completions.create(
model="meta-llama/Llama-3.1-8B-Instruct",
messages=[{
"role": "system",
"content": "Extract the core customer question(s) from this support ticket. "
"Rephrase as clear, standalone questions. Return JSON: "
"{\"questions\": [\"question 1\", \"question 2\"]}"
}, {"role": "user", "content": ticket_text}],
max_tokens=200, temperature=0.1
)
return parse_json(response.choices[0].message.content)["questions"]
The vLLM server processes ticket batches. Each ticket may contain multiple implicit questions buried in narrative text — the LLM extracts them as clean, searchable questions.
Stage 2: Question Clustering
from sentence_transformers import SentenceTransformer
import hdbscan
embedder = SentenceTransformer("BAAI/bge-large-en-v1.5", device="cuda")
def cluster_questions(questions: list) -> dict:
embeddings = embedder.encode(questions, normalize_embeddings=True)
clusterer = hdbscan.HDBSCAN(min_cluster_size=5)
labels = clusterer.fit_predict(embeddings)
clusters = {}
for idx, label in enumerate(labels):
if label == -1:
continue
if label not in clusters:
clusters[label] = []
clusters[label].append(questions[idx])
# Sort by frequency (cluster size)
return dict(sorted(clusters.items(), key=lambda x: -len(x[1])))
Stage 3: RAG-Grounded Answer Generation
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import HuggingFaceEmbeddings
# Knowledge base loaded from documentation
kb = Chroma(persist_directory="/data/docs_kb",
embedding_function=HuggingFaceEmbeddings(model_name="BAAI/bge-large-en-v1.5"))
def generate_faq_entry(question_cluster: list) -> dict:
representative_q = question_cluster[0]
context_docs = kb.similarity_search(representative_q, k=3)
context = "\n".join([doc.page_content for doc in context_docs])
response = client.chat.completions.create(
model="meta-llama/Llama-3.1-8B-Instruct",
messages=[{
"role": "system",
"content": "Generate an FAQ entry. Write a clear, canonical question and "
"a concise answer (2-4 sentences) based ONLY on the provided context. "
"Return JSON: {\"question\": \"\", \"answer\": \"\", \"category\": \"\"}"
}, {
"role": "user",
"content": f"Common customer questions about this topic:\n"
+ "\n".join(question_cluster[:5])
+ f"\n\nKnowledge base context:\n{context}"
}],
max_tokens=300, temperature=0.2
)
entry = parse_json(response.choices[0].message.content)
entry["frequency"] = len(question_cluster)
return entry
Using RAG retrieval from ChromaDB ensures answers are grounded in actual documentation rather than hallucinated. The LangChain integration handles the retrieval layer.
FAQ Page Generation
def generate_faq_page(entries: list) -> str:
grouped = {}
for entry in entries:
cat = entry["category"]
if cat not in grouped:
grouped[cat] = []
grouped[cat].append(entry)
html = "Frequently Asked Questions
"
for category, items in grouped.items():
html += f"{category}
"
for item in sorted(items, key=lambda x: -x["frequency"]):
html += f"{item['question']}
"
html += f"{item['answer']}
"
return html
Automated Maintenance
Schedule the pipeline weekly. Compare new FAQ entries against existing ones — flag genuinely new questions for human review before publishing. Track which FAQ entries reduce support ticket volume (measure before/after publication). Remove entries that no longer receive queries. Deploy on private infrastructure for data protection. See model options, chatbot hosting for interactive FAQ, more tutorials, and support use cases.
Support AI GPU Servers
Dedicated GPU servers for FAQ generation and support automation. Process ticket data on isolated UK infrastructure.
Browse GPU Servers