Giới thiệu AI Subroutines: Tự động hóa tác vụ trình duyệt trực tiếp trong tab

17 tháng 4, 2026·8 phút đọc

AI Subroutines là công cụ mới cho phép ghi lại tác vụ trình duyệt một lần và chạy lại như một script có thể gọi, giúp loại bỏ chi phí token và độ trễ của LLM. Điểm đột phá là script chạy ngay trong ngữ cảnh trang web, tự động xử lý xác thực và bảo mật mà không cần cấu hình phức tạp.

Giới thiệu AI Subroutines: Tự động hóa tác vụ trình duyệt trực tiếp trong tab

Hầu hết các tác nhân web (web agents) hiện nay đang giải quyết sai một nửa vấn đề. Bạn có thể sử dụng Mô hình ngôn ngữ lớn (LLM) để đăng bài lên X, gửi tin nhắn trực tiếp (DM) trên Instagram hay kết nối LinkedIn — nhưng chỉ được một lần. Khi cần thực hiện hành động đó hàng nghìn lần, bài toán kinh tế sẽ phá sản: chi phí token cho mỗi lần gọi, độ trễ cho mỗi lần thực thi và tính không xác định (non-determinism) liên tục. Trong các tác vụ như tiếp cận khách hàng, cập nhật CRM hay đăng bài hàng loạt, việc "tác nhân nhấn nút sai" không phải là một đặc điểm lạ, mà là một chế độ thất bại.

Giải pháp hiển nhiên là bỏ qua giao diện người dùng (UI) và gọi trực tiếp API nội bộ của trang web. Điều này đúng, nhưng cũng là nơi hầu hết các dự án "chỉ cần gọi API" chết yểu. Bởi vì vấn đề khó thực sự không phải là điểm cuối API (endpoint), mà là xác thực (Authentication).

Xác thực là bài toán thực sự khó khăn

Các yêu cầu web đã được xác thực thường mang theo sự kết hợp của cookie, token CSRF xoay vòng, token phiên, header bearer, nonce chống phát lại, các tham số bị ràng buộc bởi dấu vân tay và các băm chữ ký request được tính toán bằng JavaScript của trang web tại thời điểm yêu cầu. Một số do máy chủ đặt ra, một số được suy ra trong trình duyệt, và một số thay đổi theo từng yêu cầu.

Các bộ thu thập dữ liệu ngoài quy trình (out-of-process) như Node worker, Playwright worker hay cloud function phải xây dựng lại tất cả những thứ này một cách thủ công. Đây chính là điểm gãy đổ ngay khi một trang web thay đổi header hoặc triển khai cơ chế ký mới. Hầu hết các công cụ phát lại HAR (HTTP Archive) đều kết thúc vòng đời hữu ích ngay tại đây.

Mẹo: Ghi lại trong tiện ích mở rộng, phát lại ngay trong trang web

Trong rtrvr, cả quá trình ghi lại và phát lại đều diễn ra bên trong trình duyệt của người dùng, ngay từ chính trang web đó.

Tiện ích mở rộng sẽ chặn các yêu cầu mạng mà tab tạo ra trong khi bạn thực hiện tác vụ. Nó sử dụng hai lớp: một bản vá fetch/XHR trong MAIN-world được cài đặt trước khi bất kỳ script trang nào chạy, kết hợp với API webRequest của Chrome làm phương án dự phòng cho các đường dẫn CORS và service-worker mà bản vá trong trang không nhìn thấy. Nội dung yêu cầu — bao gồm FormData, Blob, byte thô, không chỉ JSON — cũng bị bắt giữ.

Khi script chạy sau đó, các yêu cầu đó được gửi đi từ ngữ cảnh thực thi của chính trang web — cùng nguồn gốc (origin), cùng cookie, cùng phiên TLS, cùng đoạn JS tính toán các header đã ký.

Không cần trình điều khiển Puppeteer. Không cần worker headless. Không cần ngăn xếp TLS riêng biệt. Trình duyệt sẽ làm những gì nó luôn làm: đính kèm cookie, chạy JS của trang web để tính toán header và gửi yêu cầu.

Xác thực, CSRF, ký và dấu vân tay đều được truyền đi tự động. Tác nhân không cần chạm vào bất kỳ thứ nào trong số đó. Không cần trích xuất khóa, không cần xây dựng lại phiên, không cần xoay vòng proxy.

Xếp hạng và tinh gọn dữ liệu ghi nhận

Có một vấn đề thứ hai ẩn giấu trong "chỉ cần ghi lại mạng". Một phút duyệt web điển hình kích hoạt hàng chục đến hàng trăm yêu cầu mỗi tab — tín hiệu phân tích, ping RUM, thăm dò tính năng, pixel của bên thứ ba, v.v. Lệnh gọi API thực sự bạn cần thường chỉ là 3 yêu cầu trong số 300.

Bạn không thể đưa tất cả những thứ đó cho LLM để tìm ra cái nào là công cụ. Nó không vừa với cửa sổ ngữ cảnh, và ngay cả khi bạn trả tiền để mở rộng, tín hiệu hữu ích sẽ bị chìm trong tiếng ồn.

Do đó, trước khi trình tạo nhìn thấy bất kỳ thứ gì, hệ thống sẽ xếp hạng và tinh gọn dữ liệu đã bắt. Các yêu cầu được chấm điểm dựa trên một số tín hiệu có trọng số:

  • Nguồn gốc bên thứ nhất so với bên thứ ba: (+20 / -15). Một máy chủ telemetry đã biết như Sentry, Segment, Hotjar... bị trừ -80 điểm.
  • Tương quan thời gian với sự kiện DOM: (+28 trong 800ms, +16 trong 2.5s). Một lệnh POST kích hoạt 40ms sau khi bạn bấm "Gửi" gần như chắc chắn là lệnh gửi.
  • Phương thức và hình dạng payload: (POST/PUT/PATCH/DELETE thay đổi dữ liệu: +35; GET: +5; có nội dung yêu cầu: +8).
  • Chất lượng phản hồi: (2xx: +12; 4xx+: -25; nội dung không rỗng: +4).
  • Bộ định danh hoạt động dễ thay đổi (Volatile operation IDs): (-18). Các yêu cầu mang queryId, doc_id của GraphQL sẽ bị trừ điểm vì chúng có vẻ đúng hôm nay nhưng sẽ bị lỗi khi trang web triển khai bản mới.

Sau khi xếp hạng, 5 yêu cầu hàng đầu cùng với các tương tác DOM xung quanh chúng được hiển thị cho trình tạo. Nếu ứng viên hàng đầu chứa ID dễ thay đổi, trình quy hoạch sẽ ép buộc sử dụng công cụ chỉ dùng DOM để tránh lỗi âm thầm sau này.

Subroutines là các lệnh gọi công cụ, không phải macro

Một tác vụ đã ghi lại — một Subroutine — được đăng ký như một công cụ có thể gọi trong bộ công cụ của tác nhân, bên cạnh tìm kiếm và tìm nạp:

  • Danh sách URL Instagram -> sendInstagramDirectMessage({ url, message })
  • Hàng đợi nội dung hàng ngày -> createXPost({ text, mediaUrl })
  • Danh sách hồ sơ -> sendLinkedInConnectionRequest({ url, note })

Bạn chỉ cần trỏ tác nhân vào một bảng tính 500 hàng. Nó sẽ chọn tham số cho từng hàng. Subroutine chạy. LLM chỉ được gọi một lần cho mỗi hàng — để chọn tham số — và hành động thực tế là một script.

  • Chi phí token bằng không trên đường dẫn chính.
  • Tính xác định cao (Deterministic). Cùng đầu vào, cùng đầu ra, mỗi lần.
  • Bề mặt phát hiện thấp. Yêu cầu đến từ cùng nguồn gốc, cùng header, cùng phiên người dùng đã gửi yêu cầu gốc.

Bên trong một Subroutine: Các trình trợ giúp rtrvr

Một Subroutine là một hàm JavaScript async nhỏ chạy trong tab. Các tham số mà tác nhân truyền đi được chèn dưới dạng khai báo const phía trên mã của bạn. Bên trong phần thân, không gian tên trợ giúp rtrvr.* bao gồm các thao tác phổ biến cần thiết trên các trang web thực mà không cần dùng đến bộ chọn mong manh:

  • rtrvr.find({ role, name, text, placeholder }): Tìm mục tiêu trang ngữ nghĩa.
  • rtrvr.click(handleOrTarget): Nhấp vào mục tiêu.
  • rtrvr.type(handleOrTarget, value, { clear, submit }): Nhập văn bản vào ô nhập liệu.
  • rtrvr.request(url, init): Thực hiện các yêu cầu đã xác thực trong trang.
  • rtrvr.getCsrfToken(): Đọc token CSRF hiện tại.

Ví dụ tối giản cho Subroutine kết nối LinkedIn:

const button = await rtrvr.find({
  role: "button",
  name: /Connect/i,
});
if (!button) {
  return { success: false, error: "Connect button not found." };
}
await rtrvr.click(button);
const csrfToken = rtrvr.getCsrfToken();
return await rtrvr.requestJson("/voyager/api/example", {
  method: "POST",
  headers: {
    "content-type": "application/json",
    "x-csrf-token": csrfToken,
  },
  body: JSON.stringify({ ok: true }),
});

Sự khác biệt so với các giải pháp khác

Browser-Use và Stagehand giữ LLM trong đường dẫn hành động thời gian chạy. Tuyệt vời cho các tác vụ một lần, nhưng đắt đỏ và không xác định khi mở rộng quy mô.

Libretto (phát hành tháng trước) chuyển LLM sang thời điểm tạo mã và phát ra script Playwright. Đây là bước đi đúng hướng, nhưng Playwright chạy ngoài quy trình, nên vấn đề xác thực quay trở lại — bạn kế thừa phiên của Playwright, không phải của người dùng.

Điểm mới mẻ ở đây không phải là "tạo trước script thay vì quyết định tại thời gian chạy". Mà là tạo trước một script chạy trong cùng ngữ cảnh trình duyệt với người dùng, để xác thực không bao giờ là một vấn đề riêng biệt.

Mục tiêu cuối cùng: Một thư viện cho không gian hành động của web

Một Subroutine là một công cụ. Một thư viện các Subroutine là phạm vi bao phủ. Đội ngũ phát triển đang hướng tới việc xây dựng một thư viện công cộng được cộng đồng duy trì, cùng với các mẫu và tập dữ liệu, mở rộng không gian hành động của web cho các tác nhân. Các Subroutine được cài đặt sẵn cho Instagram, X và LinkedIn được đóng gói trong tiện ích mở rộng làm hạt giống ban đầu.

Nếu bạn đã từng viết một script kết dính (glue script) làm một việc hữu ích trên một trang web và sau đó bị lỗi khi trang web thay đổi header — đó chính là một Subroutine đang chờ được ghi lại trong trang để nó có thể tồn tại mãi mãi.

Bài viết được tổng hợp và biên soạn bằng AI từ các nguồn tin tức công nghệ. Nội dung mang tính tham khảo. Xem bài gốc ↗