Khi Naive RAG “đầu hàng” trước thực tế
2 giờ sáng, sếp nhắn tin: “Sao con bot trả lời sai bét về sự kiện Apple tối qua vậy em?”. Anh em làm AI chắc không lạ gì cảnh này. Dù bạn đã index dữ liệu vào Vector Database từ tuần trước, nhưng với những thông tin thay đổi theo từng giờ, hệ thống RAG truyền thống hoàn toàn bất lực và bắt đầu “bốc phét” (hallucination) một cách tự tin.
Vấn đề nằm ở chỗ: Naive RAG là một quy trình tuyến tính, thụ động. Để giải quyết, chúng ta cần nâng cấp lên Agentic RAG. Nếu Naive RAG là một cái máy tra từ điển, thì Agentic RAG giống như một cộng sự biết tư duy. Nó sẽ tự hỏi: “Dữ liệu nội bộ có đủ không? Có cần lên mạng kiểm tra lại không?” trước khi trả lời người dùng.
Lên bàn cân: Naive RAG và Agentic RAG
Tại sao chúng ta phải làm phức tạp hóa vấn đề? Hãy nhìn vào sự khác biệt thực tế giữa hai hướng tiếp cận này.
1. Naive RAG (Truyền thống)
- Luồng xử lý: Query → Vector Search → LLM → Answer.
- Ưu điểm: Phản hồi cực nhanh (thường < 2 giây), chi phí vận hành rẻ.
- Gót chân Achilles: Không có khả năng tự kiểm chứng. Nếu dữ liệu trong DB bị out-date, AI sẽ trả về kết quả sai mà không hề hay biết.
2. Agentic RAG (Thế hệ mới)
- Luồng xử lý: Query → LLM suy luận → Chọn công cụ (Search DB/Web) → Kiểm tra kết quả → Lặp lại nếu cần → Trả lời.
- Ưu điểm: Có khả năng tự sửa lỗi và tích hợp tri thức thế giới thời gian thực.
- Đánh đổi: Latency cao hơn (có thể từ 5-15 giây tùy độ phức tạp) và tốn token hơn do LLM phải “suy nghĩ” qua nhiều bước.
Tại sao bộ đôi LangGraph và Tavily lại là “chân á”?
Trước đây, dùng LangChain để build agent thường khiến code dễ trở thành một mớ “spaghetti” khó kiểm soát. LangGraph xuất hiện để dọn dẹp đống hỗn độn đó. Nó coi toàn bộ quy trình là một State Machine (máy trạng thái). Bạn có thể kiểm soát chính xác node nào chạy sau node nào, khi nào cần quay lại bước trước để tìm thêm dữ liệu.
Về phần tìm kiếm, mình chọn Tavily thay vì Google Search. Tavily được tối ưu riêng cho AI. Thay vì trả về đống HTML rác, nó trả về text sạch và các đoạn snippet cô đọng. Điều này giúp tiết kiệm tới 40% context window và giảm đáng kể nhiễu cho mô hình LLM.
Hướng dẫn triển khai chi tiết
Bước 1: Thiết lập môi trường
Cài đặt các thư viện lõi. Lưu ý nên sử dụng Python 3.9+ để đảm bảo tính ổn định cho LangGraph.
pip install langchain-openai langgraph tavily-python chromadb langchain-community
Hãy chuẩn bị sẵn OpenAI API Key và Tavily API Key (Tavily cho phép 1.000 lượt search miễn phí mỗi tháng, quá đủ để anh em test).
Bước 2: Xây dựng kho tri thức nội bộ
Chúng ta sẽ giả lập một Vector Database chứa các quy định của công ty bằng ChromaDB.
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_core.documents import Document
# Giả lập dữ liệu nội bộ
docs = [
Document(page_content="Chính sách 2024: Nhân viên có 12 ngày phép và 3 ngày nghỉ chế độ.", metadata={"source": "HR"}),
Document(page_content="Thưởng KPI được thanh toán vào kỳ lương tháng 3 hàng năm.", metadata={"source": "Finance"})
]
vectorstore = Chroma.from_documents(documents=docs, embedding=OpenAIEmbeddings())
retriever = vectorstore.as_retriever()
Bước 3: Định nghĩa “vũ khí” cho Agent
Agent cần hai công cụ: Một để đào bới dữ liệu nội bộ, một để tra cứu thế giới bên ngoài.
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain.tools import tool
web_search_tool = TavilySearchResults(k=3)
@tool
def retrieve_internal_info(query: str):
"""Tra cứu các quy định, chính sách và tài liệu nội bộ công ty."""
docs = retriever.get_relevant_documents(query)
return "\n".join([d.page_content for d in docs])
tools = [retrieve_internal_info, web_search_tool]
Bước 4: Thiết lập luồng tư duy với LangGraph
Đây là lúc chúng ta thiết kế bộ não cho AI. Node agent sẽ quyết định hành động, node action sẽ thực thi công cụ.
from langgraph.prebuilt import ToolNode
from langgraph.graph import StateGraph, END
class AgentState(TypedDict):
messages: Annotated[Sequence[BaseMessage], operator.add]
model = ChatOpenAI(model="gpt-4o").bind_tools(tools)
def agent(state):
return {"messages": [model.invoke(state['messages'])]}
workflow = StateGraph(AgentState)
workflow.add_node("agent", agent)
workflow.add_node("action", ToolNode(tools))
workflow.set_entry_point("agent")
def should_continue(state):
last_message = state['messages'][-1]
return "continue" if last_message.tool_calls else "end"
workflow.add_conditional_edges("agent", should_continue, {"continue": "action", "end": END})
workflow.add_edge("action", "agent")
app = workflow.compile()
Sức mạnh thực tế: Vượt xa mong đợi
Hãy thử hỏi: “Chính sách nghỉ phép của tôi là gì và giá vàng hôm nay biến động thế nào?”.
Với RAG thông thường, AI sẽ đứng hình hoặc trả lời sai vế thứ hai. Nhưng với Agentic RAG, nó sẽ kích hoạt retrieve_internal_info để lấy số ngày phép, sau đó gọi web_search_tool để check giá vàng. Cuối cùng, nó tổng hợp lại thành một câu trả lời duy nhất, chính xác và đầy đủ.
Vài lưu ý “xương máu” khi triển khai
Sau nhiều dự án thực tế, mình rút ra 3 điều quan trọng anh em cần nhớ:
- Chặn đứng vòng lặp vô tận: Luôn set
recursion_limit(khoảng 10-15) khi chạy app. Agent có thể bị “ngáo” và gọi tool liên tục nếu không tìm thấy câu trả lời thỏa đáng. - Mô tả Tool là chìa khóa: LLM chọn công cụ dựa trên mô tả của bạn. Thay vì viết “Search tool”, hãy viết cụ thể: “Dùng để cập nhật giá chứng khoán hoặc tin tức thời sự mới nhất”.
- Tối ưu chi phí: GPT-4o rất thông minh nhưng đắt. Bạn có thể dùng
gpt-4o-miniđể xử lý các task suy luận đơn giản nhằm tiết kiệm tới 80% chi phí token.
Lời kết
Agentic RAG không chỉ là một kỹ thuật code, nó là cách chúng ta dạy AI biết sử dụng công cụ và kiểm chứng thông tin. Sự kết hợp giữa LangGraph và Tavily giúp chatbot của bạn thoát khỏi cái mác “vẹt học vẹt” để trở thành một trợ lý thực thụ. Nếu bạn đã thành thạo RAG cơ bản, hãy bắt tay vào nâng cấp lên Agentic RAG ngay hôm nay. Cảm giác nhìn con bot tự đi tìm dữ liệu để hoàn thiện câu trả lời thực sự rất tuyệt vời!

