Hướng dẫn đầy đủ cách xây dựng chatbot RAG để tìm kiếm cơ sở tri thức nội bộ bằng Claude, triển khai ở quy mô 5.000 tài liệu tiếng Nhật. Công bố cả mã khoảng 30 dòng và ước tính chi phí vận hành hàng tháng.
Tổng quan
- Chuyển tài liệu thành vector embedding (text-embedding-3-large)
- Chuyển câu hỏi của người dùng thành vector bằng cùng mô hình, tìm kiếm 5 kết quả hàng đầu
- Gửi context đã truy xuất đến Claude Sonnet 4.6 để tạo câu trả lời
- Giảm 90% chi phí gọi lại bằng prompt caching
1) Nhúng tài liệu (chỉ một lần)
# 1) 5,000 件の社内文書を埋め込みベクトル化
from openai import OpenAI
# 埋め込みは Kunavo では提供していません(/v1/embeddings は実装済みの
# ワイヤフォーマットですが、有効なモデルがないため呼ぶと失敗します)。
# 埋め込みは OpenAI に直接、生成は Kunavo に — クライアントは 2 つ持ちます。
embedder = OpenAI(api_key="sk-...") # OpenAI 本家
kunavo = OpenAI(
api_key="sk-kn-...",
base_url="https://api.kunavo.com/v1",
)
documents = load_documents() # [{id, text, metadata}, ...]
# バッチ 100 件ずつで埋め込みを呼ぶ
batches = [documents[i:i+100] for i in range(0, len(documents), 100)]
all_vectors = []
for batch in batches:
resp = embedder.embeddings.create(
model="text-embedding-3-large",
input=[d["text"] for d in batch],
)
all_vectors.extend(resp.data)
# Postgres + pgvector に保存(または Pinecone, Qdrant など)
save_to_vector_db(documents, all_vectors)5.000 tài liệu × trung bình 500 token = 2,5 triệu token. Vì Kunavo không cung cấp embedding nên chỉ bước này do OpenAI trực tiếp tính phí—— hãy kiểm tra đơn giá trên trang giá của OpenAI. Tôi không ghi con số ở đây vì nếu ghi giá của thứ mình không bán, sẽ không ai nhận ra khi giá đó trở nên lỗi thời. Chạy quy trình này một lần rồi lưu kết quả vào pgvector.
2) Tìm kiếm và tạo câu trả lời khi truy vấn
# 2) ユーザー質問 → 関連文書を検索 → Claude に投げて回答
def answer(question: str) -> str:
# 質問を埋め込み化
q_embed = embedder.embeddings.create( # 埋め込みは OpenAI 直
model="text-embedding-3-large",
input=[question],
).data[0].embedding
# 上位 5 件を検索
relevant = vector_search(q_embed, top_k=5)
# Claude に context + question を渡す
context = "\n\n---\n\n".join(d["text"] for d in relevant)
resp = kunavo.chat.completions.create( # 生成は Kunavo
model="claude-sonnet-4-6",
messages=[
{
"role": "system",
"content": (
"あなたは社内ナレッジ ベースをもとに正確に答えるアシスタントです。"
"提供された context にない情報については「情報がありません」と答えてください。"
),
},
{"role": "user", "content": f"# Context\n{context}\n\n# 質問\n{question}"},
],
max_tokens=800,
)
return resp.choices[0].message.contentToken sử dụng cho mỗi truy vấn: embedding của câu hỏi (~$0,000005) + khoảng 5K token đầu vào của Claude Sonnet 4.6 (context) × $1,20/1M = $0,006 + khoảng 500 token đầu ra × $6,00/1M = $0,003. Khoảng $0,009 mỗi truy vấn (khoảng 1,4 yên).
3) Tiết kiệm thêm bằng prompt caching
Vì cùng một system prompt được gửi mỗi lần, Anthropic prompt caching sẽ phát huy tác dụng:
# 3) Cache_control で再呼び出しコストを 90% 削減
# 同じ context(社内ドキュメント)を何度も使うので、Anthropic prompt caching が効く
resp = client.chat.completions.create(
model="claude-sonnet-4-6",
messages=[
{
"role": "system",
"content": [{
"type": "text",
"text": SYSTEM_PROMPT_AND_GUIDELINES, # 安定したシステムプロンプト
"cache_control": {"type": "ephemeral"},
}],
},
{"role": "user", "content": f"# Context\n{context}\n\n# 質問\n{question}"},
],
)
# 2回目以降の同じシステムプロンプトはキャッシュヒット → 入力料金の 10%Nếu system prompt ổn định ở mức 3.000 token và không thay đổi, từ lần thứ hai trở đi phần đó được tính bằng 10% mức phí. Theo đo lường thực tế, chi phí giảm xuống khoảng $0,004 mỗi truy vấn (khoảng 0,6 yên).
Ước tính chi phí vận hành hàng tháng
| Mức sử dụng | Chi phí | Ghi chú |
|---|---|---|
| Embedding ban đầu | $0,25 | Một lần |
| 1.000 truy vấn/ngày | Khoảng $270/tháng | Không có caching |
| 1.000 truy vấn/ngày | Khoảng $110/tháng | Có caching |
| 10.000 truy vấn/ngày | Khoảng $1.100/tháng | Có caching, quy mô bot Slack |
Các điểm cần lưu ý riêng với tiếng Nhật
- Mức tiêu thụ token: tiếng Nhật đôi khi tiêu thụ lượng token gấp 2-3 lần tiếng Anh (do cách mã hóa kanji và kana). Hãy thu hẹp context từ 5K → 3K và cạnh tranh bằng độ chính xác tìm kiếm
- Mô hình embedding: text-embedding-3-large hỗ trợ đa ngôn ngữ và độ chính xác tiếng Nhật đủ tốt. Nếu có nhiều thuật ngữ nội bộ, nên duy trì thêm một từ điển từ đồng nghĩa
- Claude so với Gemini 2.5 Pro: Claude nghiêm ngặt hơn với việc tóm tắt dài và trích dẫn, còn Gemini 2.5 Pro có phạm vi tìm kiếm rộng hơn. Cách làm tiêu chuẩn là bắt đầu với Sonnet 4.6 và nâng cấp lên Opus 4.7 khi cần
- Chống ảo giác: ghi rõ trong system prompt rằng “nếu không có trong context thì trả lời ‘không có thông tin’”. Nếu vẫn để lọt, hãy giới hạn max_tokens và yêu cầu trả về ID tài liệu nguồn để hiển thị liên kết trích dẫn trong UI
Danh sách kiểm tra trước khi đưa vào production
- Quy trình cập nhật chỉ mục embedding (tái xây dựng hàng ngày/hàng tuần bằng cron)
- Fallback khi thất bại (Claude → Gemini 2.5 Flash, v.v., theo hai tầng)
- Giới hạn tốc độ và trần chi phí (đặt giới hạn như $50 mỗi ngày cho từng khóa tại /app/keys)
- Nhật ký và giám sát (theo dõi chi phí hàng ngày bằng bảng điều khiển usage)
- Luật giao dịch thương mại đặc định (dành cho khách hàng Nhật Bản) — /legal/tokutei-shoutorihiki
Để bắt đầu, hãy đăng ký miễn phí. Nạp từ $10 và bắt đầu sử dụng theo hình thức thanh toán theo mức dùng, xem /docs/quickstart hoặc /docs/caching để biết chi tiết.