Tất cả bài viết

Vấn đề Recrawl: Giữ cho các Pipeline RAG luôn mới

Cơ sở tri thức RAG của bạn sẽ trở nên lỗi thời ngay trong tuần bạn triển khai nó. Dưới đây là cách các đội ngũ recrawl hàng trăm nguồn vertical mà không làm vượt quá ngân sách kỹ thuật.

Thách thức

Các startup AI chuyên biệt (vertical AI) đều vấp phải cùng một bức tường vào khoảng tháng thứ hai. Họ triển khai một trợ lý hỗ trợ (support copilot), một trợ lý nghiên cứu pháp lý, hoặc một bot tuân thủ. Bản demo đầu tiên thu hút được khách hàng. Sau đó, dữ liệu trở nên lỗi thời, và các câu trả lời bắt đầu lệch khỏi thực tế.

Chúng tôi đã chứng kiến nhiều đội ngũ xây dựng phần AI rất gọn gàng nhưng lại xem phần dữ liệu như một yếu tố phụ. Pipeline nạp dữ liệu (ingestion pipeline) chỉ là một script Python chạy trên máy tính cá nhân của ai đó. Nó cào 200 URL nguồn một lần, đổ Markdown sạch vào một vector store, và mọi người ăn mừng. Sáu tuần sau, một nửa số câu trả lời trích dẫn các trang đã bị xóa, các API đã lỗi thời, hoặc các tính năng sản phẩm được ra mắt vào tháng Ba rồi lại được thay đổi vào tháng Năm.

Giải pháp nghe có vẻ đơn giản: thu thập lại dữ liệu từ mọi nguồn hàng tuần. Thực tế thì phũ phàng hơn. Đến năm 2026, khoảng 60% các trang web uy tín chặn các AI crawler (tăng từ 23% vào cuối năm 2023), và các biện pháp bảo vệ không còn là những bước kiểm tra User-Agent đơn giản nữa. Chúng xem xét hành vi phiên (session), nhịp độ request, và các tín hiệu ở cấp độ bắt tay (handshake-level). Một script đơn giản hoạt động tốt vào tháng Một có thể âm thầm trả về các trang trống vào tháng Ba.

Tệ hơn nữa, một số trang web hiện nay cung cấp nội dung bẫy (tarpit content), là những đoạn văn bản vô nghĩa được tạo ra bởi mô hình Markov trông giống như văn xuôi thật, cho đến khi nó làm hỏng các embedding của bạn. Vì vậy, các kỹ sư của bạn phải dành nửa tuần để vá lỗi scraper thay vì phát triển sản phẩm. Chất lượng truy xuất giảm sút, khách hàng nhận ra, và đội ngũ bạn thuê để xây dựng AI trở thành một xưởng bảo trì scraper.

Giải pháp

Vấn đề thu thập lại dữ liệu được chia thành ba quyết định cụ thể cần phải thực hiện trên mỗi request:

  1. Render hay không? Hầu hết các cổng tài liệu đều cung cấp HTML sạch. Một tỷ lệ ngày càng tăng (bất kỳ thứ gì được xây dựng trên Next.js, bất kỳ thứ gì có client-side rendering) cần render trình duyệt đầy đủ để trả về nội dung hữu ích.
  2. Sử dụng proxy nào? Dân cư (residential), trung tâm dữ liệu (datacenter), di động (mobile), định vị địa lý (geo-pinned), hoặc đặc thù theo ISP. Lựa chọn phù hợp sẽ thay đổi tùy theo mục tiêu.
  3. Nó có thực sự hoạt động không? Một phản hồi 200 với body trống, hoặc một trang HTML CAPTCHA, là một HTTP request thành công nhưng lại là một lượt crawl thất bại.

Một nền tảng như FourA xử lý từng vấn đề này như một mối quan tâm hàng đầu.

Đối với quyết định render, bạn gọi Single cho trường hợp rẻ và nhanh, và gọi Browser cho các mục tiêu nặng về JS. Body của lệnh gọi có cùng cấu trúc, vì vậy code nạp dữ liệu của bạn chỉ cần rẽ nhánh một lần dựa trên cờ (flag) của từng nguồn thay vì phải xử lý hàng trăm đặc điểm riêng biệt của từng trang web.

Đối với việc chọn proxy, Proxy Finder chạy như một phần của mỗi lệnh gọi Single, Browser, và Auto. Nền tảng sẽ chọn một cổng ra (exit) hoạt động cho mỗi request, trả về id ẩn danh của nó trong response meta.proxy, và bạn tái sử dụng id đó trong các lệnh gọi tiếp theo khi cần giữ nguyên cổng ra đó. Crawler của bạn không cần tự chạy thuật toán xếp hạng proxy riêng. (Chúng tôi đã viết về lý do tại sao kích thước pool không còn là yếu tố khác biệt trong bài viết Why Proxy Pool Size Stopped Mattering in 2026.)

Và đối với câu hỏi "nó có thực sự hoạt động không", mỗi request đều hỗ trợ một block validate. Bạn khai báo những gì được tính là thành công: các status code được chấp nhận, các giá trị header bắt buộc, các chuỗi ký tự trong body phải xuất hiện hoặc không được xuất hiện. FourA trả về một trong bảy kết quả, và chỉ có success mới bị tính phí. Một phản hồi 200 không vượt qua các quy tắc nội dung của bạn sẽ được đánh dấu là application_fail và không bao giờ đi vào tập dữ liệu của bạn.

Dưới đây là cấu trúc của một lệnh gọi thu thập lại dữ liệu cho một cổng tài liệu cần render JS. Chúng tôi để Auto điều phối, nó sẽ chọn sản phẩm phù hợp (Single, Proxy, hoặc Browser), xử lý các hệ thống phòng thủ bot, và trả về bộ ba phiên (session triple) để lần thu thập lại tiếp theo có thể giữ nguyên cổng ra đó:

import requests

r = requests.post(
    "https://api.foura.ai/api/auto",
    headers={"Authorization": "Bearer pk_live_..."},
    json={
        "url": "https://docs.example.com/changelog",
        "validate": {
            "status": {"accept": [200]},
            "data":   {"accept": ["<article"], "fail": ["captcha", "Just a moment"]},
        },
    },
).json()

# r["data"]    — rendered body
# r["meta"]    — { "proxy": "<base36 id>", "cookies": [...], "userAgent": "..." }
# On the next recrawl, pass r["meta"]["proxy"] back as `ignoreProxies: [<id>]` to avoid
# the same exit, or via /api/single with `proxy: <id>` to stick to it.

Nếu mục tiêu kích hoạt màn hình chờ của Cloudflare, quy tắc validate.data.fail sẽ phát hiện ra nó. Kết quả được ghi nhận cho mức sử dụng của bạn là application_fail. Bạn không phải trả phí cho lượt này, và code nạp dữ liệu của bạn sẽ biết để thử lại với một proxy khác thay vì đưa trang "Just a moment..." vào các embedding.

Đối với tập dữ liệu rộng hơn, bạn có thể tích hợp mô hình tương tự vào job queue hiện tại của mình. Các đội ngũ mà chúng tôi đã trao đổi thường chạy so sánh khác biệt (diff) hàng đêm với lần crawl trước đó, chỉ tạo lại embedding cho các tài liệu thực sự thay đổi, và cập nhật mới tập dữ liệu 500 nguồn chỉ trong vài giờ đồng hồ. Job queue vẫn do bạn quản lý. Việc luân chuyển proxy, quyết định render, và xác định kết quả thành công là việc của chúng tôi.

Kết quả

Quy trình cập nhật dữ liệu sẽ trông như thế nào khi cơ sở hạ tầng không còn là nút thắt cổ chai (kịch bản minh họa dựa trên các mô hình chúng tôi thấy ở các đội ngũ AI chuyên biệt):

  • 500 URL nguồn được thu thập lại hàng tuần, thay vì chỉ chạy một lần duy nhất với 200 URL khi ra mắt
  • Thời gian kỹ thuật dành cho scraper: dưới 2 giờ mỗi tuần, giảm từ 1-2 ngày
  • Độ trễ của dữ liệu truy xuất (staleness window): 5-7 ngày, thay vì không có giới hạn
  • Tỷ lệ dữ liệu rác trong vector store gần như bằng không, vì các màn hình chờ Cloudflare và các trang bẫy (tarpit) bị từ chối ở lớp validate trước khi chúng tiếp cận mô hình embedding của bạn
  • Chi phí có thể dự đoán được trên mỗi nguồn, vì các lượt crawl thất bại không xuất hiện trong hóa đơn thanh toán

Vấn đề không phải là những điều này có gì kỳ diệu. Vấn đề là chúng rất tẻ nhạt. Và sự tẻ nhạt chính là điều mà AI trong môi trường production cần. (Để biết thêm về việc khi nào các phép tính chi phí không còn hiệu quả với việc trích xuất bằng LLM được lưu trữ, hãy xem When LLM Extraction Stops Paying for Itself.)

Kết luận chính

Hầu hết các đội ngũ xây dựng AI chuyên biệt đều nghĩ rằng lợi thế cạnh tranh (moat) nằm ở prompt, việc lựa chọn mô hình, hoặc thuật toán truy xuất. Thực tế không phải vậy. Lợi thế cạnh tranh chính là quy trình cập nhật dữ liệu (freshness loop): cơ sở hạ tầng thầm lặng giúp giữ cho cơ sở tri thức luôn chính xác tuần này qua tuần khác.

Những đội ngũ chiến thắng trong lĩnh vực AI chuyên biệt tính đến năm 2026 sẽ không phải là những bên có các prompt thông minh nhất. Đó sẽ là những bên mà người dùng của họ không bao giờ phải bận tâm xem dữ liệu có mới hay không, bởi vì nó luôn luôn mới.