Arsitektur chatbot basis pengetahuan modern bawaan
Pencarian basis pengetahuan tradisional mengembalikan tautan; pengguna membacanya. RAG mengubahnya menjadi jawaban percakapan sekali kirim dengan sitasi. Jika dilakukan dengan baik, pengguna mendapat jawaban dalam 2 detik, bukan menggali 5 dokumen. Jika dilakukan dengan buruk, chatbot berhalusinasi dan CTO Anda melarang proyek tersebut selama setahun. Halaman ini menjelaskan perbedaannya.
Stack produksi minimum yang layak
- Vector store: pgvector jika Anda sudah memiliki Postgres, Pinecone atau Qdrant untuk layanan terkelola
- Embedding: text-embedding-3-large, dipanggil langsung ke OpenAI — Kunavo tidak menyediakan embedding, dan panggilan embedding tetap merupakan permintaan terpisah dari panggilan generasi
- Retrieval: hibrida (vektor + BM25 dengan reciprocal rank fusion)
- Generasi: Claude Sonnet 5 dengan cache_control pada system prompt
- UI: respons streaming, rendering sitasi, fallback "Saya tidak tahu"
from openai import OpenAI
client = OpenAI(api_key="sk-kn-...", base_url="https://api.kunavo.com/v1")
def chat(question: str, history: list[dict]) -> dict:
chunks = hybrid_retrieve(question, k=5) # vector + BM25
context = "\n\n---\n\n".join(
f"[doc:{c['id']}] {c['text']}" for c in chunks
)
resp = client.chat.completions.create(
model="claude-sonnet-5",
messages=[
{"role": "system", "content": [{
"type": "text",
"text": (
"Answer only from Context. Cite [doc:N] for each claim. "
"If Context doesn't answer, say 'I don't have that.' "
"Be concise, no throat-clearing."
),
"cache_control": {"type": "ephemeral"},
}]},
*history,
{"role": "user", "content": f"# Context\n{context}\n\n# Q\n{question}"},
],
max_tokens=600,
)
answer = resp.choices[0].message.content
cited_ids = parse_citations(answer) # extract [doc:N] references
return {"answer": answer, "sources": [c for c in chunks if c["id"] in cited_ids]}Biaya pada skala produksi
- Pengindeksan awal: ~$0,25 untuk 5.000 dokumen yang masing-masing terdiri dari 500 token
- 1.000 kueri/hari: ~$210/bulan dengan caching
- 10.000 kueri/hari: ~$2.100/bulan
- Jika menggunakan Haiku 4.5 alih-alih Sonnet: ~4x lebih murah, ~85% kualitas jawaban
Uraian arsitektur lengkap ada di panduan implementasi RAG. Catatan tuning khusus bahasa ada di pendalaman RAG bahasa Jepang dan panduan RAG bahasa Spanyol.
Tiga pola yang benar-benar mencegah halusinasi
- Sitasi setiap klaim: tag
[doc:42]dalam output model. Jika id yang disitasi tidak ada dalam set hasil retrieval, model berhalusinasi — blokir dan catat - Penolakan eksplisit dalam system prompt: "Jika Context tidak menjawab, katakan 'Saya tidak memiliki informasi itu.'" Tanpa ini, model mengisi jawaban dari pengetahuan umum
- Batas output 600 token: jawaban singkat biasanya merupakan jawaban yang akurat. Output yang lebih panjang adalah tempat penemuan tambahan menyelinap masuk
Apa yang dikirim pada minggu 1 vs minggu 4
| Minggu | Tonggak |
|---|---|
| 1 | 100 dokumen, satu strategi chunking, pencarian vektor dasar, set evaluasi 10 pertanyaan, recall@5 sekitar 70% |
| 2 | Korpus lengkap, retrieval hibrida, set evaluasi 100 pertanyaan, sitasi diwajibkan, beta internal |
| 3 | Sesuaikan chunking berdasarkan pertanyaan yang gagal, rilis ke pengguna internal, ukur CSAT |
| 4 | Pemantauan + dasbor biaya, batas pengeluaran harian, beta publik atau peluncuran produksi |
Mulai di /app/signup
Isi ulang $10 mencakup pengindeksan awal sekitar 100 ribu dokumen dan 1.500 kueri uji — lebih dari cukup untuk prototipe fungsional, dan saldo tidak pernah kedaluwarsa. Setelah itu, baca panduan RAG lengkap untuk pola produksi.
Pertanyaan umum
Berapa biaya satu kueri chatbot RAG?
Sekitar $0,007 per kueri dengan Claude Sonnet 4.6 dan prompt caching aktif, atau sekitar $0,001 dengan Claude Haiku 4.5 — yang menghasilkan sekitar 85% kualitas dengan biaya sepertujuhnya.
Bagaimana cara mencegah chatbot RAG berhalusinasi?
Tiga pola mencakup sebagian besar kebutuhan: wajibkan model mengutip ID [doc:N] untuk setiap klaim, berikan instruksi penolakan eksplisit di system prompt, dan batasi jawaban dengan max_tokens=600. Kemudian, sebelum menampilkan jawaban, verifikasi bahwa setiap ID yang dikutip terdapat dalam set hasil pengambilan.
Berapa ukuran potongan yang sebaiknya digunakan indeks RAG?
1.000–1.500 karakter per potongan dengan tumpang tindih 100–200 karakter, dibagi menggunakan RecursiveCharacterTextSplitter dan disematkan dengan text-embedding-3-large.
Apakah pencarian vektor saja cukup untuk retrieval RAG?
Tidak. Pengambilan hibrida menggabungkan kemiripan vektor dengan pencarian kata kunci BM25, lalu menggabungkan keduanya menggunakan reciprocal rank fusion dan mengambil 5 potongan teratas.