
Xây dựng RAG độc lập bằng Kizuna OCR/Embedding + Qdrant để tích hợp với bất kỳ AI Agent nào
Nguyen Dang Duc Linh
Author
Khi xây dựng AI Agent cho một team hoặc một solo dev/tester base skill, một trong những vấn đề lớn nhất là: làm sao để agent hiểu được tài liệu nội bộ, spec, workflow, rule nghiệp vụ… mà không cần fine-tune model?
Câu trả lời phổ biến là RAG — Retrieval-Augmented Generation.
Nhưng RAG không nhất thiết phải là một hệ thống chatbot hoàn chỉnh. Trong nhiều trường hợp, ta chỉ cần một RAG backend độc lập:
- nhận tài liệu
- trích xuất text/markdown
- chunk nội dung
- tạo embedding
- lưu vector
- semantic search
- trả về context liên quan cho AI Agent bất kỳ
Bài này mô tả cách setup một RAG backend nhẹ bằng:
- Kizuna OCR Markdown API
- Kizuna Embedding API
- Qdrant
- Python + FastAPI
Mục tiêu là xây một service RAG độc lập, có thể tích hợp với OpenAI Agent, Claude, Gemini, LangChain agent, custom workflow engine, hay bất kỳ AI Agent nào.
1. RAG là gì?
RAG là viết tắt của Retrieval-Augmented Generation.
Thay vì yêu cầu LLM “biết hết mọi thứ”, ta cho nó khả năng truy xuất thông tin liên quan từ kho dữ liệu riêng trước khi trả lời.
Flow cơ bản:
Điểm quan trọng:
LLM không tự nhớ tài liệu của bạn. Nó chỉ trả lời tốt hơn vì được cung cấp đúng context tại thời điểm hỏi.
2. Embedding là gì?
Embedding là cách biến text thành vector số.
Ví dụ: "請求書の支払い期限" có thể được biến thành một vector như: [0.012, -0.044, 0.087, ...]
Vector này đại diện cho “ý nghĩa” của câu, không chỉ là từ khóa. Nhờ embedding, hệ thống có thể tìm được những nội dung gần nghĩa nhau, kể cả khi query và tài liệu dùng ngôn ngữ khác nhau.
Ví dụ:
Query tiếng Việt:
"quy trình thanh toán invoice"Tài liệu tiếng Nhật:
"請求書 支払い フロー"
Nếu embedding model đủ tốt, semantic search vẫn có thể tìm đúng đoạn liên quan.
Trong PoC này, ta dùng Kizuna Embedding API với model: bge-m3
3. Kiến trúc tổng thể
Trong kiến trúc này:
Kizuna chỉ dùng cho:
- OCR markdown extraction
- embedding generation
Qdrant chỉ dùng cho:
- vector storage
- semantic search
AI Agent sẽ nằm ngoài RAG backend. RAG backend chỉ trả về context liên quan. Đây là model tách biệt rõ ràng, dễ debug, dễ tích hợp với các nền tảng custom.
Ngoài ra, tách thành RAG độc lập sẽ giúp nhiều lợi ích mà sau khi đã thử qua các plugin RAG cho AI Agent, mình nhận thấy gần như không đáp ứng tốt tiêu chí tùy chỉnh cho mỗi nhu cầu. Bên cạnh đó là khả năng đọc được nhiều định dạng và cấu hình RAG được Kizunax Platform cung cấp đầy đủ qua API document. Từ hệ thống RAG tự build và embedding API được cung cấp, mình đánh giá, debug được: chunk có đúng không? embedding dimension đúng không? search trả về chunk hợp lý không? score có ổn không? query tiếng Việt có tìm được tài liệu tiếng Nhật không? Từ đó tách được lỗi: OCR sai, chunk sai, Embedding sai hay retrieval sai? (các plugin RAG/Embedding tích hợp trong AI Agent mình gần như không thể làm việc này được hoặc phải check trong tool call của agent để hiểu rõ)
4. Bắt tay xào nấu
PoC này mình có thể chạy trên 1 VPS hoặc 1 máy tính siêu yếu cũng được (thậm chí là android TV box cài armbian với chip ARM64 2 lõi, 2GB RAM). Và vì cấu hình như vậy nên sẽ không cài qua docker cho Qdrant vectorDB (có thể dùng ChromaDB cũng được, nhưng mình đã có kinh nghiệm vọc Qdrant nên chọn nó)
Yêu cầu:
1 vCPU
2GB RAM
Ubuntu 22.04
No Docker
No Kubernetes
No local LLM
No local embedding model
Các bước ngắn gọn:
1. Cài Qdrant native, không cài qua Docker với cấu hình như trên
2. Chuẩn bị môi trường Python
pip install --no-cache-dir \
requests \
qdrant-client \
fastapi \
uvicorn \
jinja2 \
python-multipartNote: có thể cài thêm langchain (nhưng mà PoC và dùng cá nhân nên mình chunk thủ công)
3. Các API bên Kizuna sẽ cần bao gồm
- List RAG Collections
- List documents trong collections
- Download markdown
- Generate embedding
Tham khảo thêm tại: https://kizunax.io/api-docs
Trong API docs Kizuna đã cung cấp sẵn API RAG chat (streaming), nhưng lúc này Kizuna đã trở thành 1 chatbot hoàn chỉnh (tự thân Kizuna đã OCR → embedding → vector search → LLM gen anwser), trong khi mình cần AI Agent của mình là reasoning và trả lời.
4. Chunking strategy (vì chunking thủ công nên mình config chunk_size = 800, có set thêm chunk_overlap khoảng 150 - 200. Vừa tạm đủ giữ context, vừa tránh mất ý nghĩa nếu bị chunk ở giữa ranh giới. Thêm metadata giữ lại thông tin document. Trong markdown trả về của Kizuna nếu có OCR cần thêm clear markdown để loại bỏ nhiễu thông tin ([Image OCR], [End OCR])
{
"document_id": "hidden-marked",
"filename": "IMG_2824.pdf",
"markdown": "## Page 1\n\n*[Image OCR]\nMàn hình Convert data Soufuri 『総合振込データ変換』\n① Change/Add menu như image bên dưới:\noneplat\n名称変更:「請求額」→「今回御請求額」\nメニュー追加:「繰越金額」\n② Giải thích cho requirement ①\nChange text : 「請求額」 → 「今回御請求金額」\n⇒ Chỉ change text hiển thị\nAdd cột : 「繰越金額」\n⇒ Hiển thị Tiền Kurikoshi đợt này 今回繰越金額 đã nhập tại màn hình Approve invoice-report 請求書承認 (Không cho edit)\nỞ image trên không mô tả nhưng nhờ change text bên dưới:\nChange text : 「合計」 → 「支払金額」\n⇒ Hiển thị kết quả của tính toán: 『「今回御請求金額」 - 「繰越金額」』\n* Tóm lại là: cột 「振込額」 hiển thị kết quả của tính toán: 『「今回御請求金額」 - 「繰越金額」 - 「振込手数料」』\n③ Màn hình:\n総合振込データ変換処理 ご利用マニュアル\n繰越金①備考欄に関して 繰越金CSV 繰越金CSVサンプル\n[End OCR]*"
}5. Ingestion và Semantic search. Với Qdrant version cũ có thể method query_points() thay vì search()
6. FastAPI backend đơn giản
GET /
POST /collections
POST /documents
POST /ocr
POST /ingest
POST /search
POST /chatTrong đó /chat ở đây không phải chatbot generation. Nó chỉ là “mini retrieval test”.
7. Tích hợp với AI Agent bất kỳ nào với RAG backend đã có thì việc tích hợp với AI Agent để gọi semantic search là đơn giản:
Ví dụ agent flow:
User:
"Remark khi bulk payment hoạt động thế nào?"
Agent:
1. Call RAG backend /search
2. Nhận top chunks
3. Đưa chunks vào prompt
4. Generate answerRAG backend trả về
[
{
"score": 0.704,
"filename": "remark-all-roles.md",
"chunk_index": 2,
"content": "Bulk create data payment..."
}
]
Agent sau đó tự quyết định cách trả lời.
Điểm hay là RAG backend không phụ thuộc agent nào.
8. Kết quả PoC thực tế
Với document remark-all-roles.md, pipeline chạy được:
OCR markdown fetch: OK
Chunk count: 5
Embedding model: bge-m3
Embedding dimension: 1024
Qdrant collection: rag_chunks
Inserted points: 5
Search query:
invoice payment workflow
Top result score khoảng:
0.63
Query:
Remark bulk payment invoice
Top scores:
0.704
0.697
0.696
Kết quả trả về đúng các chunk liên quan đến:
- create data payment
- bulk payment
- invoice report
- remark input behavior
Toàn bộ PoC đã được push lên github tại đây: https://github.com/Linh-NDD/semantic_search_kizunax-plaform
Build theo hướng dẫn trên file README.md
Tài liệu tham khảo:
- KizunaX Platform document: https://kizunax.io/api-docs
- Qdrant document: https://qdrant.tech/documentation/
Comments
🗣️ Join the conversation
Sign in to leave a comment and join the discussion