Cloud agent cá nhân

Đưa agent cá nhân lên cloud mà không viết lại nó

Một agent chạy trên laptop thì tắt máy là mất: job theo lịch bị lỡ, điện thoại không gọi được, approval nằm chờ trong một tab đã đóng. Tài liệu này kể cách đặt nguyên engine đó vào một container trên Cloudflare: container ngủ khi rảnh, thức dậy khi có tin nhắn, job hoặc một nút Duyệt.

~0,074 USDmỗi giờ container thức (standard-1, giá niêm yết)
12–26 scold start đo được: restore snapshot rồi khởi động engine
0 dòngengine bị sửa để chạy trên cloud; mọi thay đổi đi upstream
0 cổngmở trên máy cá nhân; edge chỉ poll ra ngoài

Bài toán: agent tốt trên laptop, nhưng laptop không thức 24/7

Agent cá nhân ở đây là một crew: một master agent bạn nói chuyện cùng, giao việc cho các agent chuyên trách, dùng tool, nhớ sự kiện, chạy job theo lịch và luôn hỏi trước khi làm việc làm thay đổi dữ liệu.

Chạy trên laptop

  • Gập máy là job 7 giờ sáng không chạy, không ai báo.
  • Ra đường không gọi được agent, trừ khi mở cổng hay dựng tunnel.
  • Approval chờ trong một tab; tab đóng thì việc đứng.
  • Dữ liệu, cookie, token rải trong thư mục home của máy.

Điều muốn có trên cloud

  • Luôn gọi được từ điện thoại; job chạy đúng giờ dù máy tắt.
  • Chỉ trả tiền compute khi agent thực sự làm việc.
  • Dữ liệu cá nhân nằm trong tài khoản cloud của chính mình.
  • Giữ nguyên approval, memory, tool và cách cấu hình quen thuộc.

Hai lớp, hai repository

Điểm mấu chốt của cả thiết kế: engine không biết mình đang chạy trên cloud. Nó vẫn là một process Python nghe ở 127.0.0.1:8765, y như trên laptop. Mọi thứ cloud-specific nằm ở lớp platform bao quanh.

Engine Python · public

  • FastAPI + uvicorn, một process; agent loop với max_steps.
  • Crew: master agent điều phối, các agent chuyên trách.
  • Tool: file trong workspace, shell, web fetch/search, browser (Playwright), memory, scripts, MCP (OAuth).
  • Approval có TTL, lưu trong SQLite; run chờ duyệt có status awaiting_approval.
  • Memory là các fact có basis (operator / said / inferred / extracted) và khoảng hiệu lực.
  • Provider: anthropic, openrouter, ollama; route chain fallback; prompt cache 1h.
  • Kênh: web UI (cả phone inbox, Web Push), Telegram long-poll hoặc webhook.

Platform Cloudflare

  • Worker: proxy web UI sau lớp đăng nhập, Telegram webhook, API cho edge, console; cron mỗi phút; outbound handler cho egress.
  • Durable Object: một cho mỗi home, giữ handle của container, đánh thức nó và chuyển tiếp request kèm control key.
  • Container (standard-1: ½ vCPU, 4 GiB): sidecar Starlette ở :8080 đứng trước engine đã pin version; shell của engine chạy trong bubblewrap.
  • D1: jobs, job runs, sessions, edge tasks. R2: snapshot, backup 30 ngày, drops.
  • Secrets: Worker secrets thành env var của container lúc khởi động.

Engine changes go upstream. Khi cloud cần engine làm khác đi (một config key, một hook, chế độ webhook, cờ --no-schedule), thay đổi được viết như một feature trong repo engine, có test, phát hành version mới. Platform chỉ bump version đã pin.

Nhờ vậy hai bên deploy độc lập: version engine nào cũng chạy được với commit platform nào, và engine vẫn chạy được trên laptop mà không cần platform.

Kiến trúc tổng thể

Kéo để di chuyển, cuộn để phóng to. Mở viewer đầy đủ để tìm node, focus một nhánh hay trace một đường đi.

Đường đi: kênh chat, Worker, Durable Object rồi tới container (sidecar + engine); xung quanh là D1, R2, egress và edge. JSON nguồn

Mô phỏng: container thức dậy, làm việc, rồi ngủ

Bấm một kịch bản và xem từng bước đi qua hệ thống. Thời gian được nén: vài giây trên màn hình là vài chục giây thật, 15 phút chờ ngủ chỉ còn vài giây. Đồng hồ chi phí chỉ chạy khi container thức.

Điện thoạiTelegram / web
Workerroutes · cron
Durable Object1 / home
Containersidecar + engine
ngủ
Model APIprompt cache 1h
Cronmỗi phút · D1
R2snapshot home
Đồng hồ mô phỏng00:00
Thời gian thức0 s
Chi phí container$0.0000
Run chờ duyệt0
Nhật kýContainer đang ngủ, không tốn compute
  1. Chọn một kịch bản ở trên để bắt đầu.

Mô phỏng dùng số đo tham khảo: cold start 12–26 s (lấy 15 s), resume sau khi duyệt 17,7 s, snapshot cuối khoảng 1,35 s, sleepAfter 15 phút, giá standard-1 khoảng 0,074 USD/giờ. Kịch bản là việc chung chung, không phải dữ liệu thật.

Sequence: tin nhắn khi container đang ngủ. JSON

Một tin nhắn đi qua hệ thống

Telegram gọi webhook của Worker, kèm secret token. Worker không chờ engine: nó trả 200 ngay cho Telegram rồi xử lý tiếp, vì cold start có thể dài hơn timeout của webhook.

Durable Object của home kiểm tra container. Đang ngủ thì nó start container; sidecar kéo snapshot từ R2, mở engine, đợi engine báo sẵn sàng rồi mới nhận request. Mọi request vào container đều mang control key, và sidecar từ chối request thiếu key.

Engine chạy turn như trên laptop: master agent, tool loop, gọi model với prompt cache. Câu trả lời đi ngược về Telegram. Sau đó container ở lại 15 phút, rồi ngủ nếu không còn request.

Vòng đời container

Mô hình chi phí xoay quanh một ý: container chỉ tốn tiền khi thức. Muốn ngủ được thì không gì trong container phải tự thức theo giờ. Vì vậy scheduler và Telegram chuyển ra Worker: engine chạy với --no-schedule, và cron của Worker gọi POST /api/jobs/{id}/run khi đến hạn.

Một run đang chờ duyệt không giữ container thức. Trạng thái awaiting_approval nằm trong SQLite của engine, được snapshot lên R2 khi container ngủ. Bấm Duyệt sẽ đánh thức container, và turn chạy tiếp từ chỗ dừng.

Đo tham khảoGiá trị
Cold start (restore + engine ready)12–26 s
Resume turn sau khi duyệt lúc đang ngủ17,7 s
Snapshot cuối trước SIGTERM~1,35 s
Restore từ một bản backup36 s
sleepAfter15 phút
Lifecycle: sleeping, waking, ready, idle, rồi quay về sleeping. JSON

R2 là nguồn sự thật, cấu hình đồng bộ kiểu git

Disk của container chỉ là cache. Chỉ container được ghi vào home trên R2; mỗi lần ghi tăng generation trong manifest, nên một bản cũ không thể đè bản mới.

Dataflow: working copy trên máy ↔ snapshot home trên R2. JSON nguồn

Sửa trên máy, đẩy lên cloud

Home là một git repo. Lệnh update chỉ ghi commit mới nhất lên snapshot khi đó là fast-forward so với ref refs/cloud/home. Nó từ chối khi còn thay đổi chưa commit, khi có xung đột, hoặc khi cloud có commit mà máy chưa có.

Sửa trên cloud, kéo về máy

Khi bạn hay agent sửa cấu hình qua web UI, sidecar tự commit (author riêng cho cloud) trước mỗi lần đẩy home lên R2. Lệnh pull kéo về và fast-forward, hoặc merge nếu hai bên cùng sửa.

Trí nhớ: tệp Markdown, viết lại có cổng

Trí nhớ của agent là các tệp Markdown trên đĩa: không embedding, không vector DB. Bạn mở ra đọc và sửa được từng dòng. Thư mục này nằm trong home, nên được snapshot lên R2 cùng mọi thứ khác và vẫn còn nguyên sau mỗi lần container ngủ.

Hai phạm vi

Facts về bạn dùng chung cho mọi agent. Mỗi fact là một tệp, và mục lục của chúng vào prompt ở mỗi lượt. Mỗi agent có thêm MEMORY.md riêng, nằm trong system prompt, và ghi chú theo ngày. Ghi chú hôm nay và hôm qua được đặt trước tin nhắn mở lượt, nên không làm hỏng prompt cache.

Fact biết mình dựa trên gì

Mỗi fact ghi lại nó đến từ đâu: basis (operator › said › inferred › extracted), khoảng hiệu lực valid_from / valid_until, các nguồn và số phiên bản. Khi một fact được thay, bản cũ không mất mà chuyển vào lịch sử, kèm ngày kết thúc.

Tìm lại bằng grep

Phần không có trong prompt chỉ tìm được qua memory_search. Ở đây một mục là một gạch đầu dòng cùng các dòng thụt vào bên dưới. Khi so khớp, dấu tiếng Việt được bỏ qua. Facts dùng chung xếp trước, rồi đến tệp mới hơn. Kho nhỏ nên grep đủ nhanh, và kết quả là chữ người đọc được.

Dataflow: lúc trò chuyện thì ghi ngay; job chạy không ai trông chỉ được đề xuất; cuối tuần model viết lại, code quyết định có áp dụng hay không. JSON nguồn

Hoà giải bằng code, không hỏi model

Khi một fact được ghi trong lúc trò chuyện, engine so nó với bản đang có theo một bảng luật cố định. Model chỉ đưa ra nội dung, còn code quyết định nội dung đó đi vào đâu.

Khi ghi một factKết quả
Trùng nội dung với bản đang cóThêm nguồn, đánh dấu confirmed
Nội dung mới, nguồn ngang hoặc cao hơnThay bản cũ; bản cũ vào lịch sử với ngày kết thúc
Agent suy ra điều trái với lời bạnThành đề xuất, kèm lý do
Ghi từ job theo lịchThành đề xuất
Rút lại / xoá hẳnRút lại giữ lịch sử; xoá hẳn xoá cả lịch sử

Cô đọng hằng tuần

Một cron đọc tối đa 7 ngày ghi chú cùng tóm tắt các cuộc trò chuyện do bạn mở, rồi để model viết lại MEMORY.md. Mỗi dòng trong tệp mang ngày (YYYY-MM-DD) của lần gần nhất nó được xác nhận.

  • Dòng không có ngày, hoặc có ngày cũ hơn 90 ngày, được đưa lại cho model xem xét.
  • Dòng có ngày kết thúc (… → ngày) tự rời prompt sau ngày đó.
  • Nếu agent có ngân sách ký tự, mỗi dòng mới phải qua thêm một lượt sàng ngắn. Model chỉ được trả lời NHẬN hoặc BỎ: lý do.

Cùng job này cũng biên dịch wiki của agent, và mỗi trang wiki phải liệt kê nguồn của nó.

Model viết, code quyết. Một bản viết lại chỉ được tự áp dụng khi code so bản cũ với bản mới và thấy không có gì bị mất. Nếu bản viết lại có thể làm mất một điều bạn đã nói, nó chờ bạn duyệt. Kênh nhận một thông báo, còn hộp thư có link tới trang duyệt.

Lúc bạn bấm duyệt, nếu MEMORY.md đã đổi kể từ khi có đề xuất, lệnh duyệt trả 409 thay vì đè lên. Facts dùng chung do agent quản trị dọn dẹp luôn chờ duyệt, kể cả với agent tự chủ.

Thử cổng tự áp dụng

Chọn những gì bản viết lại tuần này làm với MEMORY.md. Trong ví dụ, hôm nay là 08/11/2026.

MEMORY.md · bản viết lại

      Credential ở egress, approval ở engine

      Agent đọc web, đọc email, đọc tài liệu do người khác viết, tức là luôn có nguy cơ prompt injection. Thiết kế giả định agent có thể bị lừa, và giới hạn thiệt hại bằng cấu trúc thay vì bằng lời dặn.

      Request ra ngoài của container đi qua outbound handler của Worker. JSON nguồn

      Token không vào container

      Với API nhạy cảm (ví dụ Google), container chỉ giữ một token giả. Outbound handler của Worker thay bằng access token thật và chỉ cho qua một danh sách đóng các cặp method + path.

      Approval là feature

      Mọi hành động thay đổi dữ liệu đều hỏi trước, trừ lệnh bạn đã đánh dấu là quen (shell_ask_patterns). Platform chỉ phản chiếu và chuyển tiếp approval, không có công tắc “bỏ qua duyệt”.

      Engine không public

      Không route nào đi thẳng vào container. Chỉ Durable Object gọi được nó, kèm control key. Shell của agent chạy trong bubblewrap; HTTPS bị chặn ở egress dùng CA bundle do sidecar dựng.

      Máy cá nhân là edge, không phải node thứ hai

      Vẫn có vài việc cloud không làm thay được: đăng nhập trình duyệt cần màn hình, file chỉ có trên máy. Máy cá nhân phục vụ những việc đó như một edge, và không bao giờ chạy engine song song với cloud.

      Chỉ poll ra ngoài

      Edge agent hỏi Worker xem có việc không, chỉ chạy những loại task có trong allowlist, rồi trả output. Máy không mở cổng nào, Worker không gọi được vào máy.

      Drops

      Những file máy giữ cho tươi (ví dụ cookie một extension làm mới) được đẩy lên R2 thành drop, và sidecar nhặt về khi container thức. Đăng nhập một site: login trên máy, export cookie dạng Playwright storage state, gửi như một drop.

      Standby và failback

      Mỗi giờ máy chép snapshot về. Nếu cloud hỏng, có thể đưa crew chạy lại trên máy từ bản chép đó. Đây là đường lui, không phải chế độ chạy song song.

      Một script vận hành

      Deploy, update, pull, logs, cost, sessions, restore đều đi qua một script duy nhất. Số liệu chi phí và session lấy từ script đó, không ước lượng.

      Chi phí: trả cho giờ thức, không phải giờ treo

      Kéo thanh trượt để xem chi phí tháng thay đổi theo thói quen dùng. Phần lớn chênh lệch đến từ một câu hỏi: container thức bao nhiêu giờ mỗi ngày.

      Mỗi lần thức tối thiểu 15 phút (sleepAfter). Vài job và vài cuộc trò chuyện một ngày thường dưới 3 giờ.
      Mỗi bước của tool loop là một lượt; một câu hỏi thường tốn vài lượt.
      Prompt cache 1h hết hạn thì lượt đầu phải ghi lại cache cho prefix khoảng 25k token.
      $0mỗi tháng, ước tính
      Container
      $0
      Prompt cache
      $0
      Workers + R2
      $0
      So với luôn bật
      $0

      Giá niêm yết tháng 10/2026: standard-1 khoảng 0,074 USD/giờ thức, Workers Paid 5 USD/tháng, R2 vài cent. Phần model chỉ tính prefix cache (đọc khoảng 0,006 USD/lượt, ghi khoảng 0,10 USD/lần với model hạng Sonnet), chưa gồm token đầu vào mới và output. Dùng để so sánh thứ bậc, không phải hoá đơn.

      Mười quyết định định hình hệ thống

      Mỗi quyết định đều có cái giá. Mở từng mục để xem lý do và thứ phải đánh đổi.

      Bài học khi vận hành thật

      Những lỗi không thấy trong bản thiết kế, chỉ lộ ra khi hệ thống đã chạy hằng ngày.

      Tự dựng: checklist

      Thứ tự gợi ý nếu bạn muốn đưa agent của mình lên cloud theo cách này. Tiến độ được lưu trong trình duyệt của bạn.

      0 / 0
      Sơ đồ Mở tab mới