Hãy hỏi Claude về công ty của bạn, ghi chú của bạn, hoặc các tệp của bạn, và nó sẽ không biết gì cả. Nó chưa bao giờ thấy chúng. Nó chỉ biết những gì nó học được trong quá trình huấn luyện, và dữ liệu của bạn không nằm trong số đó.
Một hệ thống RAG sẽ khắc phục điều này. Thay vì trả lời từ trí nhớ, Claude trước tiên sẽ tra cứu trong tài liệu của bạn, lấy những phần có liên quan, và trả lời dựa trên những gì nó thực sự tìm thấy. Dữ liệu của bạn, nguồn của nó, không cần phải phỏng đoán.
Tại sao nó tốt hơn việc chỉ dán tệp vào cửa sổ chat:
Nó có khả năng mở rộng. Toàn bộ kiến thức của bạn sẽ không thể nhồi nhét vừa trong một cửa sổ chat. RAG lưu trữ mọi thứ và chỉ lấy những gì mỗi câu hỏi cần.
Nó rẻ hơn. Dán một tệp có nghĩa là Claude sẽ đọc lại toàn bộ tệp đó cho mỗi câu hỏi. RAG đọc nó một lần, sau đó chỉ lấy phần có liên quan. Thay vì gửi một tài liệu hướng dẫn dài 10.000 token mỗi lần, nó có thể chỉ gửi 500 token của đúng phần bạn cần. Các hệ thống thực tế có thể giảm 80% lượng token sử dụng hoặc hơn.
Nó sắc bén hơn. Cung cấp cho mô hình một khối văn bản khổng lồ và nó sẽ bỏ lỡ các chi tiết ở giữa. Đưa cho nó một vài đoạn nhỏ chính xác và câu trả lời sẽ chính xác hơn.
Nó luôn cập nhật. Cập nhật tệp của bạn một lần và hệ thống sẽ sử dụng phiên bản mới nhất. Không cần phải dán lại.
Kết thúc hướng dẫn này, bạn sẽ có một hệ thống chạy trên các tệp của riêng mình, từng bước một, không cần bằng tiến sĩ.
Những gì bạn cần
Trước khi chạm vào bất kỳ dòng code nào, đây là danh sách đầy đủ. Tin tốt: phiên bản này chỉ cần một API key, và mọi thứ khác đều chạy miễn phí trên máy tính của bạn.
1. Python 3.9 trở lên. Để kiểm tra xem bạn đã cài chưa, hãy mở terminal (Terminal trên Mac, Command Prompt trên Windows) và gõ python --version. Nếu bạn thấy đại loại như 3.11, thì bạn ổn. Nếu không, hãy tải xuống từ python.org và chạy trình cài đặt. Trên Windows, hãy đánh dấu chọn ô "Add Python to PATH" trong quá trình cài đặt, nếu không các lệnh bên dưới sẽ không hoạt động.
2. Một Claude API key, cùng với một số dư tín dụng nhỏ. Đây là key duy nhất và là khoản tiền duy nhất mà toàn bộ hướng dẫn này cần. Dưới đây là đường dẫn chính xác, từng bước một:
Truy cập platform.claude.com, và đăng nhập (hoặc đăng ký) tại đó.
API cần có số dư dương để hoạt động, vì vậy hãy nạp tiền trước. Khi được nhắc, hãy chọn tín dụng dành cho cá nhân bạn hay công ty, sau đó bạn sẽ đến màn hình thanh toán. Chọn tùy chọn $5 "Bắt đầu" (Starting out) . Thế là đủ: mọi thứ khác trong hướng dẫn này đều miễn phí và chạy trên máy cục bộ, vì vậy Claude là thứ duy nhất tốn tiền, và mỗi câu hỏi chỉ tốn một phần nhỏ của một xu. Tín dụng sẽ hết hạn sau một năm kể từ khi mua.
Sau khi thanh toán, bạn sẽ vào bảng điều khiển Console. Bạn sẽ thấy số dư của mình (ví dụ $5.00) ở góc trên cùng bên trái, dưới mục "Tín dụng tổ chức (Organization credits)".
Bây giờ hãy lấy key. Nhấp vào Lấy API key (Get API key) (góc trên cùng bên phải), sau đó Tạo Key (Create Key). Đặt cho nó bất kỳ tên nào bạn muốn (ví dụ: my-rag-key) và để workspace là Mặc định (Default). Nhấp vào tạo, sau đó sao chép chuỗi ký tự nó hiển thị cho bạn. Nó bắt đầu bằng sk-ant- và bạn chỉ thấy nó một lần, vì vậy hãy dán nó vào một nơi an toàn trong một phút.
Đó là toàn bộ phần thiết lập.
Bước 1: Thêm key của bạn và tải tệp của bạn
1. Tạo thư mục dự án. Tạo một thư mục mới trên Desktop và đặt tên là rag-project. Mọi thứ sẽ nằm ở đây.
2. Mở terminal của bạn. Trên Mac: Cmd+Space, gõ Terminal, Enter. Trên Windows: Start, gõ cmd, Enter.
3. Trỏ terminal vào thư mục của bạn. Gõ cd và một khoảng trắng, sau đó kéo thư mục rag-project vào cửa sổ terminal và nhấn Enter. Mọi lệnh bên dưới đều được chạy từ bên trong thư mục này.
1cd Desktop/rag-project
4. Cài đặt các công cụ. Dán dòng này vào terminal của bạn và nhấn Enter (lần chạy đầu tiên có thể mất một phút):
1pip install anthropic chromadb sentence-transformers pypdf python-dotenv
Nếu bạn gặp lỗi pip: command not found, hãy sử dụng pip3 thay vì pip. Khi terminal hiển thị một dòng mới và không có lỗi màu đỏ, nghĩa là đã hoàn tất.
5. Tạo tệp code của bạn. Bên trong rag-project, tạo một tệp trống và đặt tên chính xác là rag.py. Mở nó bằng bất kỳ trình soạn thảo văn bản nào.
6. Tạo tệp key của bạn. Trong cùng thư mục, tạo một tệp có tên chính xác là .env (bắt đầu bằng dấu chấm, không có tên nào trước nó). Dán nội dung này vào bên trong, với key thật bạn đã tạo trong quá trình thiết lập sau dấu =, không có dấu cách, không có dấu ngoặc kép:
1ANTHROPIC_API_KEY=sk-ant-paste-your-real-key-here
Việc giữ key trong .env thay vì trong code của bạn có nghĩa là nó sẽ không bị rò rỉ nếu bạn chia sẻ script hoặc đưa nó lên GitHub.
7. Tải key. Đặt đoạn này ở đầu rag.py:
1import os2from dotenv import load_dotenv34load_dotenv() # reads your .env file5api_key = os.getenv("ANTHROPIC_API_KEY")
8. Tạo cơ sở kiến thức của bạn. Bên trong rag-project, tạo một thư mục có tên là documents. Thả bất kỳ tệp .txt, .md, hoặc .pdf nào vào đó: ghi chú của bạn, tài liệu sản phẩm, biên bản cuộc họp, bất cứ thứ gì.
8.1. Nếu bạn chưa có tệp, hãy sử dụng tệp kiểm tra này. Tạo notes.txt bên trong thư mục documents và dán nội dung này vào:
Dự án Northstar là công cụ nội bộ của chúng tôi để theo dõi phản hồi của khách hàng. Nó được ra mắt vào tháng 3 năm 2026 và được duy trì bởi nhóm nền tảng. Kỹ sư trưởng là Dana Reyes. Phản hồi được xem xét vào mỗi thứ Sáu. Northstar đã thay thế hệ thống bảng tính cũ mà chúng tôi đã sử dụng cho đến năm 2025.
Cuối cùng, bạn sẽ hỏi Claude về Northstar và xem nó trả lời từ chính tệp này.
9. Thêm code đọc tệp của bạn. Bên dưới code từ bước 7, trong rag.py:
1from pathlib import Path2from pypdf import PdfReader34def load_documents(folder="documents"):5 docs = []6 for file in Path(folder).iterdir():7 if file.suffix in [".txt", ".md"]:8 text = file.read_text(encoding="utf-8")9 docs.append({"source": file.name, "text": text})10 elif file.suffix == ".pdf":11 reader = PdfReader(str(file))12 text = "\n".join(page.extract_text() or "" for page in reader.pages)13 docs.append({"source": file.name, "text": text})14 return docs1516documents = load_documents()17print(f"Đã tải {len(documents)} tài liệu.")
10. Chạy nó. Lưu rag.py, sau đó trong terminal của bạn:
1python rag.py
Bạn sẽ thấy:
Đã tải 1 tài liệu
Nếu bạn thấy Đã tải 0 tài liệu, nghĩa là thư mục documents trống hoặc không đúng vị trí. Nó phải nằm trực tiếp bên trong rag-project, bên cạnh rag.py.
Bước 2: Chia tệp của bạn thành các đoạn (chunks)
Hiện tại, mỗi tệp là một khối văn bản lớn. Trước khi chúng ta có thể tìm kiếm trong đó, chúng ta cần cắt nó thành các phần nhỏ hơn gọi là các đoạn (chunks). Đây là lý do: khi ai đó đặt câu hỏi, hệ thống sẽ tìm các đoạn phù hợp và chỉ gửi những đoạn đó cho Claude. Nếu các đoạn của bạn là toàn bộ tài liệu dài 50 trang, bạn sẽ gửi quá nhiều. Nếu chúng là các câu đơn lẻ, chúng sẽ mất ngữ cảnh. Các đoạn văn nhỏ là điểm tối ưu.
1. Thêm code chia đoạn. Bên dưới code từ bước 10, trong rag.py:
1def chunk_text(text, chunk_size=500, overlap=100):2 words = text.split()3 chunks = []4 start = 05 while start < len(words):6 end = start + chunk_size7 chunk = " ".join(words[start:end])8 chunks.append(chunk)9 start = end - overlap # lùi lại một chút để các đoạn chồng lên nhau10 return chunks
Hai con số cần hiểu ở đây, theo cách đơn giản:
- chunk_size=500 có nghĩa là mỗi đoạn dài khoảng 500 từ. Đủ lớn để chứa một ý hoàn chỉnh, đủ nhỏ để giữ được độ chính xác.
- overlap=100 có nghĩa là mỗi đoạn lặp lại 100 từ cuối cùng của đoạn trước nó. Điều này quan trọng vì câu trả lời có thể nằm ngay trên ranh giới nơi hai đoạn gặp nhau. Nếu không có sự chồng lấn, một câu bị cắt đôi có thể bị mất. Sự chồng lấn đảm bảo không có ý nào bị rơi qua khe hở.
2. Chuyển đổi mọi tài liệu thành các đoạn. Thêm đoạn này bên dưới:
1all_chunks = []2for doc in documents:3 for chunk in chunk_text(doc["text"]):4 all_chunks.append({"source": doc["source"], "text": chunk})56print(f"Đã tạo {len(all_chunks)} đoạn từ {len(documents)} tài liệu.")
Lưu ý rằng mỗi đoạn mang theo nguồn (source) của nó (tên tệp mà nó đến từ). Chúng ta giữ nó được gắn kết trong suốt quá trình, để khi Claude trả lời sau này, nó có thể cho bạn biết câu trả lời đến từ tệp nào.
3. Chạy nó. Lưu rag.py, sau đó trong terminal của bạn:
1python rag.py
Bạn sẽ thấy một cái gì đó như:
Đã tải 1 tài liệu.
Đã tạo 1 đoạn từ 1 tài liệu.
Tệp kiểm tra nhỏ chỉ trở thành một đoạn vì nó ngắn. Các tài liệu thực tế sẽ tạo ra nhiều đoạn. Nếu bạn thả một tệp PDF dài vào thư mục, bạn có thể thấy hàng chục hoặc hàng trăm đoạn, đó chính xác là những gì bạn muốn.
Bước 3: Chuyển đổi các đoạn của bạn thành embeddings
Đây là bước cho phép máy tính tìm kiếm theo ý nghĩa thay vì từ chính xác. Mỗi đoạn được chuyển đổi thành một danh sách các con số (một embedding) để nắm bắt nội dung của nó. Các đoạn có ý nghĩa tương tự sẽ kết thúc với các con số tương tự. Sau đó, khi một câu hỏi được đưa ra, chúng ta cũng chuyển đổi câu hỏi thành các con số và tìm các kết quả phù hợp nhất.
Mô hình thực hiện việc này chạy cục bộ trên máy tính của bạn. Nó tải xuống một lần, sau đó hoạt động ngoại tuyến và miễn phí, và các tệp của bạn không bao giờ rời khỏi máy tính.
1. Tải mô hình embedding. Bên dưới code từ bước 2, trong rag.py:
1from sentence_transformers import SentenceTransformer23print("Đang tải mô hình embedding (lần chạy đầu tiên sẽ tải xuống, khoảng 90 MB)...")4embedder = SentenceTransformer("all-MiniLM-L6-v2")
Lần đầu tiên bạn chạy cái này, nó sẽ tải xuống mô hình, vì vậy hãy chờ một chút. Mọi lần chạy sau đó sẽ ngay lập tức vì nó đã có sẵn trên máy của bạn.
2. Chuyển đổi mọi đoạn thành một embedding. Thêm đoạn này bên dưới:
1chunk_texts = [chunk["text"] for chunk in all_chunks]2embeddings = embedder.encode(chunk_texts)34print(f"Đã tạo {len(embeddings)} embedding(s).")5print(f"Mỗi embedding là một danh sách gồm {len(embeddings[0])} số.")
embedder.encode(...) nhận danh sách các văn bản đoạn của bạn và trả về một embedding cho mỗi đoạn. Chỉ có vậy thôi.
3. Chạy nó. Lưu rag.py, sau đó trong terminal của bạn:
1python rag.py
Lần chạy đầu tiên sẽ tạm dừng trong khi mô hình tải xuống, sau đó bạn sẽ thấy một cái gì đó như:
Đã tải 1 tài liệu.
Đã tạo 1 đoạn từ 1 tài liệu.
Đang tải mô hình embedding (lần chạy đầu tiên sẽ tải xuống, khoảng 90 MB)...
Đã tạo 1 embedding(s).
Mỗi embedding là một danh sách gồm 384 số.
Dòng "384 số" đó là toàn bộ ý tưởng được hiển thị rõ ràng: văn bản của bạn giờ đây là một hàng số mà máy tính có thể so sánh. Bạn không cần phải đọc hoặc hiểu những con số đó. Cơ sở dữ liệu trong bước tiếp theo sẽ xử lý tất cả việc so sánh cho bạn.
Nếu quá trình tải xuống thất bại với lỗi kết nối, chỉ cần chạy lại lệnh. Nó sẽ tiếp tục từ nơi nó bị gián đoạn.
Bước 4: Lưu trữ mọi thứ trong cơ sở dữ liệu vector của bạn
Bây giờ chúng ta đặt các đoạn và embeddings của chúng vào Chroma, cơ sở dữ liệu cục bộ của bạn. Đây là điều làm cho việc tìm kiếm trở nên nhanh chóng: thay vì so sánh câu hỏi của bạn với từng đoạn một theo cách thủ công mỗi lần, Chroma lưu trữ chúng sẵn sàng để sử dụng và thực hiện việc so khớp cho bạn. Nó lưu vào một thư mục trên máy tính của bạn, vì vậy bạn chỉ cần xây dựng nó một lần.
1. Thiết lập cơ sở dữ liệu. Bên dưới code từ bước 3, trong rag.py:
1import chromadb23client = chromadb.PersistentClient(path="chroma_db")4collection = client.get_or_create_collection("my_documents")
PersistentClient(path="chroma_db") yêu cầu Chroma lưu vào một thư mục có tên chroma_db (nó sẽ tự động tạo ra, ngay bên cạnh script của bạn). Bởi vì nó được lưu vào đĩa, dữ liệu của bạn tồn tại sau khi script kết thúc. Một collection chỉ đơn giản là cái hộp có tên mà các đoạn của bạn sống trong đó.
2. Thêm các đoạn của bạn vào cơ sở dữ liệu. Thêm đoạn này bên dưới:
1collection.add(2 ids=[str(i) for i in range(len(all_chunks))],3 embeddings=[emb.tolist() for emb in embeddings],4 documents=[chunk["text"] for chunk in all_chunks],5 metadatas=[{"source": chunk["source"]} for chunk in all_chunks],6)78print(f"Đã lưu trữ {collection.count()} đoạn trong cơ sở dữ liệu.")
Đây là những gì mỗi dòng cung cấp cho Chroma, theo cách đơn giản: ids cung cấp cho mỗi đoạn một nhãn duy nhất (0, 1, 2...), embeddings là các con số từ bước 3, documents là văn bản đoạn thực tế, và metadatas mang theo tên tệp để chúng ta có thể hiển thị nguồn sau này. Chroma giữ cả bốn thứ gắn kết với nhau.
3. Chạy nó. Lưu rag.py, sau đó trong terminal của bạn:
1python rag.py
Bạn sẽ thấy:
Đã lưu trữ 1 đoạn trong cơ sở dữ liệu.
Một điều cần biết cho sau này. Mỗi lần bạn chạy script ngay bây giờ, nó sẽ thêm các đoạn một lần nữa, vì vậy số lượng có thể tăng lên (1, rồi 2, rồi 3...) khi chạy nhiều lần. Điều đó không sao trong khi chúng ta đang xây dựng. Để bắt đầu sạch sẽ, hãy xóa thư mục chroma_db và chạy lại một lần nữa. Trong phiên bản cuối cùng, chúng ta sẽ xử lý vấn đề này đúng cách để nó không bị trùng lặp.
Bước 5: Tìm kiếm trong tài liệu của bạn
Đây là phần "truy xuất (retrieval)" của RAG, chữ R trong tên gọi. Chúng ta lấy một câu hỏi, chuyển nó thành một embedding giống như cách chúng ta đã làm với các đoạn, và yêu cầu Chroma tìm các đoạn có ý nghĩa gần nhất. Những đoạn phù hợp đó sẽ là thứ chúng ta chuyển cho Claude trong bước tiếp theo.
1. Thêm hàm tìm kiếm. Bên dưới code từ bước 4, trong rag.py:
1def search(question, n_results=3):2 question_embedding = embedder.encode([question])[0]3 results = collection.query(4 query_embeddings=[question_embedding.tolist()],5 n_results=n_results,6 )7 return results
Chức năng của đoạn code này, theo cách đơn giản từng dòng: nó chuyển đổi câu hỏi thành các con số bằng cùng một mô hình bạn đã sử dụng trên các đoạn của mình (điều này rất quan trọng, cả hai phải nói cùng một "ngôn ngữ số"), sau đó yêu cầu Chroma tìm các kết quả phù hợp nhất. n_results=3 có nghĩa là "trả về cho tôi 3 đoạn liên quan nhất." Ba là một giá trị mặc định tốt: đủ ngữ cảnh, không quá nhiều để lãng phí token.
2. Thử tìm kiếm. Thêm đoạn này bên dưới để kiểm tra:
1question = "Ai điều hành Northstar và khi nào phản hồi được xem xét?"2results = search(question)34for i, doc in enumerate(results["documents"][0]):5 source = results["metadatas"][0][i]["source"]6 print(f"\n--- Kết quả phù hợp {i+1} (từ {source}) ---")7 print(doc)
Đoạn code này chạy một câu hỏi thực tế với cơ sở dữ liệu của bạn và in ra các đoạn mà nó tìm thấy, mỗi đoạn kèm theo tên tệp nguồn.
3. Chạy nó. Lưu rag.py, sau đó trong terminal của bạn:
1python rag.py
Với tệp kiểm tra Northstar, bạn sẽ thấy nó lấy lại đoạn phù hợp, một cái gì đó như:
--- Kết quả phù hợp 1 (từ notes.txt) ---
Dự án Northstar là công cụ nội bộ của chúng tôi để theo dõi phản hồi của khách hàng. Nó được ra mắt vào tháng 3 năm 2026 và được duy trì bởi nhóm nền tảng. Kỹ sư trưởng là Dana Reyes. Phản hồi được xem xét vào mỗi thứ Sáu. Northstar đã thay thế hệ thống bảng tính cũ mà chúng tôi đã sử dụng cho đến năm 2025.
Hãy để ý điều vừa xảy ra: câu hỏi của bạn sử dụng các từ "ai điều hành" và "xem xét", nhưng tệp tin lại nói "kỹ sư trưởng" và "xem xét vào mỗi thứ Sáu". Nó vẫn khớp, bởi vì việc tìm kiếm hoạt động dựa trên ý nghĩa, không phải từ chính xác. Đó là toàn bộ mục đích của embeddings, và đó là lý do tại sao nó đánh bại một tìm kiếm từ khóa đơn thuần (Ctrl+F) trong các tệp của bạn.
Nếu bạn có nhiều tệp hơn, bạn sẽ thấy 3 đoạn hàng đầu từ tất cả chúng, được sắp xếp theo mức độ phù hợp.
Bước 6: Yêu cầu Claude trả lời từ những gì nó tìm thấy
Đây là phần "tạo sinh (generation)", chữ G trong RAG. Chúng ta lấy các đoạn từ bước 5, chuyển chúng cho Claude Opus 4.8 cùng với câu hỏi, và yêu cầu nó trả lời chỉ sử dụng ngữ cảnh đó. Đây là điều ngăn nó phỏng đoán: Claude trả lời từ các tệp của bạn, không phải từ trí nhớ của chính nó, và cho bạn biết nó đã sử dụng tệp nào.
1. Thêm hàm trả lời. Bên dưới code từ bước 5, trong rag.py:
1import anthropic23claude = anthropic.Anthropic(api_key=api_key)45def answer(question):6 results = search(question)7 chunks = results["documents"][0]8 sources = [m["source"] for m in results["metadatas"][0]]910 context = ""11 for i, chunk in enumerate(chunks):12 context += f"[Từ {sources[i]}]\n{chunk}\n\n"1314 message = claude.messages.create(15 model="claude-opus-4-8",16 max_tokens=1024,17 system=(18 "Bạn trả lời câu hỏi chỉ sử dụng ngữ cảnh được cung cấp. "19 "Nếu câu trả lời không có trong ngữ cảnh, hãy nói rằng bạn không biết. "20 "Luôn đề cập đến tệp nào đã cung cấp câu trả lời của bạn."21 ),22 messages=[23 {24 "role": "user",25 "content": f"Ngữ cảnh:\n{context}\nCâu hỏi: {question}",26 }27 ],28 )29 return message.content[0].text
Điều gì đang xảy ra ở đây, theo cách đơn giản: chúng ta tìm kiếm các đoạn liên quan, ghép chúng lại với nhau thành một khối ngữ cảnh (context) (mỗi đoạn được gắn nhãn với tên tệp của nó), sau đó gửi khối đó cùng với câu hỏi đến Claude. Chỉ thị system là phần quan trọng. Nó yêu cầu Claude ba điều: chỉ trả lời từ ngữ cảnh, thừa nhận khi câu trả lời không có ở đó, và nêu tên tệp nguồn. Ba quy tắc đó là những gì làm cho các câu trả lời trở nên đáng tin cậy thay vì bịa đặt.
model="claude-opus-4-8" là tên mô hình chính xác (dấu gạch ngang, không phải dấu chấm). max_tokens=1024 giới hạn độ dài câu trả lời.
2. Đặt một câu hỏi. Thêm đoạn này bên dưới:
1question = "Ai điều hành Northstar và khi nào phản hồi được xem xét?"2print(answer(question))
3. Chạy nó. Lưu rag.py, sau đó trong terminal của bạn:
1python rag.py
Bạn sẽ nhận được một câu trả lời thực tế được xây dựng từ tệp của bạn, một cái gì đó như:
Kỹ sư trưởng điều hành Dự án Northstar là Dana Reyes, và phản hồi được xem xét vào mỗi thứ Sáu. (Nguồn: notes.txt)
Đó là một hệ thống RAG hoàn chỉnh đang hoạt động. Claude chưa bao giờ thấy tệp này trong quá trình huấn luyện, nó không thể biết Dana Reyes là ai, nhưng nó đã trả lời chính xác và cho bạn biết chính xác câu trả lời đến từ đâu. Hãy hỏi nó một điều gì đó không có trong tệp của bạn và nó sẽ nói rằng nó không biết, thay vì bịa ra một câu trả lời. Câu trả lời "tôi không biết" đó là một tính năng, không phải lỗi: đó là sự khác biệt giữa một công cụ bạn có thể tin tưởng và một công cụ phỏng đoán.
Bước 7: Biến nó thành một thứ bạn thực sự có thể sử dụng
Hiện tại, bạn phải chỉnh sửa code và chạy lại toàn bộ script mỗi khi bạn muốn hỏi điều gì đó. Tệ hơn nữa, mỗi lần chạy đều đọc lại các tệp của bạn và thêm lại chúng vào cơ sở dữ liệu, vì vậy các đoạn sẽ chồng chất lên nhau. Hãy sửa cả hai: chỉ xây dựng cơ sở dữ liệu một lần, sau đó cho phép bạn đặt câu hỏi theo vòng lặp, gõ trực tiếp vào terminal.
1. Sửa lỗi thêm trùng lặp. Tìm khối code từ bước 4 thêm các đoạn (phần collection.add(...) ) và thay thế nó bằng phiên bản này, phiên bản chỉ xây dựng cơ sở dữ liệu nếu nó trống:
1if collection.count() == 0:2 collection.add(3 ids=[str(i) for i in range(len(all_chunks))],4 embeddings=[emb.tolist() for emb in embeddings],5 documents=[chunk["text"] for chunk in all_chunks],6 metadatas=[{"source": chunk["source"]} for chunk in all_chunks],7 )8 print(f"Đã lưu trữ {collection.count()} đoạn trong cơ sở dữ liệu.")9else:10 print(f"Cơ sở dữ liệu đã có {collection.count()} đoạn, bỏ qua xây dựng lại.")
Bây giờ công việc nặng nhọc (đọc tệp, tạo embeddings, điền vào cơ sở dữ liệu) chỉ xảy ra lần đầu tiên. Các lần chạy sau sẽ bỏ qua và chuyển thẳng đến phần trả lời.
2. Thêm vòng lặp câu hỏi. Ở cuối cùng của rag.py, thay thế câu hỏi kiểm tra duy nhất từ bước 6 bằng đoạn này:
1print("\nĐặt câu hỏi về tài liệu của bạn (hoặc gõ 'quit' để thoát).\n")23while True:4 question = input("Bạn: ")5 if question.lower() in ["quit", "exit"]:6 break7 print("\nClaude: " + answer(question) + "\n")
input("Bạn: ") đợi bạn gõ một câu hỏi và nhấn Enter. while True giữ cho nó tiếp tục để bạn có thể hỏi bao nhiêu tùy thích. Gõ quit sẽ dừng nó.
3. Chạy nó. Lưu rag.py, sau đó trong terminal của bạn:
1python rag.py
Bây giờ bạn có thể trò chuyện với các tệp của mình:
Đặt câu hỏi về tài liệu của bạn (hoặc gõ 'quit' để thoát).
Bạn: ai là kỹ sư trưởng của Northstar?
Claude: Kỹ sư trưởng của Dự án Northstar là Dana Reyes. (Nguồn: notes.txt)
Bạn: nó đã thay thế cái gì?
Claude: Northstar đã thay thế hệ thống bảng tính cũ được sử dụng cho đến năm 2025. (Nguồn: notes.txt)
Bạn: quit
Đó là hệ thống RAG hoàn chỉnh của bạn. Nó đọc các tệp của bạn một lần, ghi nhớ chúng, và trả lời các câu hỏi về chúng theo yêu cầu, luôn kèm theo nguồn.
Một điều cần biết khi bạn thêm tệp mới. Bởi vì cơ sở dữ liệu bây giờ chỉ được xây dựng một lần, việc thả các tệp mới vào documents sẽ không tự động hiển thị. Để tải các tệp mới, hãy xóa thư mục chroma_db và chạy script một lần. Nó sẽ xây dựng lại từ đầu với mọi thứ trong thư mục.
Tùy chọn: Cung cấp cho nó một cửa sổ chat trong trình duyệt của bạn
Terminal hoạt động tốt, nhưng nếu bạn muốn một cửa sổ chat thực sự, Streamlit sẽ thêm một cửa sổ chỉ với khoảng 20 dòng code.
1. Cài đặt nó. Trong terminal của bạn:
1pip install streamlit
2. Tạo app.py trong cùng thư mục và dán nội dung này vào. Nó sử dụng lại hàm trả lời từ rag.py của bạn:
1import streamlit as st2from rag import answer34st.title("Trò chuyện với tài liệu của bạn")56if "history" not in st.session_state:7 st.session_state.history = []89question = st.chat_input("Hỏi về tệp của bạn...")1011if question:12 reply = answer(question)13 st.session_state.history.append((question, reply))1415for q, a in st.session_state.history:16 st.chat_message("user").write(q)17 st.chat_message("assistant").write(a)
3. Chạy nó. Trong terminal của bạn (lưu ý: streamlit run, không phải python):
1streamlit run app.py
Nó sẽ tự động mở một cửa sổ chat trong trình duyệt của bạn. Gõ một câu hỏi, nhận câu trả lời kèm nguồn của nó, giống như terminal nhưng đẹp hơn để nhìn.
Một lưu ý: để điều này hoạt động, vòng lặp câu hỏi từ bước 7 không được chạy khi import. Hãy bọc vòng lặp đó ở cuối rag.py trong if __name__ == "__main__": để nó chỉ chạy khi bạn chạy trực tiếp rag.py, chứ không phải khi app.py import nó.
Cho phép nó trả lời các câu hỏi chung chung nữa
Nếu bạn muốn nó trả lời cả các câu hỏi chung chung. Hiện tại, hệ thống chỉ trả lời từ các tệp của bạn, vì vậy một câu hỏi như "thủ đô của Venezuela là gì?" sẽ nhận được câu trả lời "thông tin này không có trong tài liệu", mặc dù Claude biết câu trả lời. Nếu bạn muốn nó dựa vào kiến thức của chính nó, hãy mở rag.py, tìm khối system=(...) trong bước 6, và thay đổi dòng này:
1"Nếu câu trả lời không có trong ngữ cảnh, hãy nói rằng bạn không biết."
cho điều này:
1"Nếu câu trả lời không có trong ngữ cảnh, hãy trả lời từ kiến thức chung của bạn nhưng nói rõ rằng bạn đang làm vậy."
Lưu lại và chạy lại. Bây giờ nó sẽ trả lời từ tệp của bạn trước, và dùng kiến thức chung khi tệp không có đủ thông tin, đồng thời cho bạn biết nó đã dùng cái nào.
Tổng kết
Bạn vừa xây dựng một hệ thống RAG hoạt động được. Nó đọc các tệp của bạn, tìm ra những phần quan trọng, và yêu cầu Claude trả lời từ chúng kèm theo nguồn chính xác mỗi lần. Cùng một thiết lập này có thể mở rộng từ vài ghi chú đến toàn bộ cơ sở kiến thức của bạn.
Từ đây, bạn có thể hướng nó đến bất cứ đâu: kho Obsidian của bạn, tài liệu công việc, nghiên cứu đã lưu. Thả tệp vào, xây dựng lại một lần, và bắt đầu đặt câu hỏi. Mọi thứ bạn học được ở đây, các đoạn văn, embeddings, tìm kiếm, câu trả lời, đều là xương sống của mọi công cụ "trò chuyện với tài liệu" mà bạn đã thấy.
Nếu điều này hữu ích, hãy vào trang cá nhân của tôi và theo dõi. Tôi viết về công nghệ, AI, và các hệ thống thực sự hoạt động.
Tạm biệt,
[@undefinedKi](https://x.com/@undefinedKi)


![[Ghi chú] Sếp của bạn làm việc nhanh gấp 3 lần](/cdn-cgi/image/width=1920,quality=90,format=auto,metadata=none/https%3A%2F%2Fcms-assets.youmind.com%2Fmedia%2F1783963982361_vdddap_HNDtsxJbcAAoE0q.jpg)


