Harness Academy
Tài liệu gốc 35 10 phútTiếng Việt + English
docs/notes/parallelization-via-sandboxes.mdXem bản gốc
Ngôn ngữ bài đọc
Bản dịch tiếng Việt

Bản dịch đầy đủ theo đúng cấu trúc tài liệu; code, liên kết và định danh kỹ thuật được giữ nguyên.

Song song hóa thông qua hộp cát

Câu hỏi: Một harness đơn có thể quản lý nhiều công việc song song bằng cách điều khiển nhiều công việc không? hộp cát - thay vì mô hình một hộp cát mỗi phiên hiện tại?

Câu trả lời ngắn gọn: Về mặt cơ học là có. Hộp cát nguyên thủy đã hỗ trợ N bị cô lập hộp cát. Kết nối thì không - người thực thi là một đơn vị toàn cầu quy trình và Không gian làm việc đường dẫn đã được cố định, vì vậy ngày nay một quy trình = một hộp cát, về mặt cấu trúc. Hai con đường đưa bạn đến sự song song công việc: A) sắp xếp các hoạt động thực thi N Kitaru (với trình tự thiết kế, trình tái cấu trúc hộp cát bằng 0) hoặc B) tái cấu trúc trình thực thi vào AgentDeps và loại bỏ N hộp cát trong một quy trình (chống lại hạt, kiểm soát nhiều hơn).


Ngày nay mọi thứ đang ở đâu

Đường may có một làn do thi công

bash và các công cụ tìm kiếm/tập tin chạy qua one CommandExecutor, được chọn một lần cho mỗi quá trình và được ghi nhớ trong một mô-đun toàn cầu:

src/decode/tools/bash.py
  43   _EXECUTOR: CommandExecutor = LocalExecutor()   # module-global singleton
  44   _executor_selected = False
  63   _get_executor()      # memoizes exactly ONE executor for the whole process
 158   active_backend(cwd)  # file tools bridge to the SAME memo

SandboxExecutor và cả hai chương trình phụ trợ rõ ràng không an toàn cho việc sử dụng đồng thời exec/run trên một ví dụ (sandbox/executor.py:116, docker_backend.py:77, modal_backend.py:107). Một phiên = một container/một sandbox từ xa = một làn nối tiếp.

Một nơi đã thành công — và chia sẻ hộp cát duy nhất

các agent công cụ (tools/agent.py:375) đã chạy đồng thời N phần tử con thông qua một harness: asyncio.gather trên N lần sinh sản, được giới hạn bởi một đèn hiệu trên mỗi vòng lặp (subagent_max_parallel). Nhưng mỗi đứa trẻ nhận được phạm vi của cha mẹ:

src/decode/tools/agent.py
 475   cwd=ctx.deps.cwd,               # SAME as parent
 476   harness_home=ctx.deps.harness_home,

Trẻ em chỉ đọc (read/glob/grep/lsp, không bash), tất cả đều đọc hộp cát phiên một. Vì vậy, số lượng người hâm mộ ra ngày hôm nay = N đồng thời người đọc, MỘT không gian làm việc. Không phải N công việc bị cô lập.

Ba khối bê tông chặn tới N hộp cát cách ly trong một quy trình

  1. Người thực thi là một đơn vị toàn cầu quy trình (bash.py:43). Mỗi bash + tập tin op tuyến đường thông qua một bản ghi nhớ. Một quy trình ⇒ một hộp cát.
  2. Đường dẫn vùng làm việc đã được sửa (workspace.py:27): workspace_dir(harness_home) = harness_home/.decode/sandbox, một đường đi duy nhất N công việc liên kết gắn kết cùng một thư mục máy chủ xung đột.
  3. Chế độ áp dụng cho toàn bộ quy trình: settings.sandbox_mode được đọc một lần và áp dụng cho mọi thứ.

Nhưng những người nguyên thủy đã hỗ trợ N hộp cát

  • Phần cuối là các đối tượng đơn giản theo từng phiên bản; kết cấu trơ, không có trạng thái chia sẻ giữa trường hợp (executor.py:121, docker_backend.py:80). SandboxExecutor(DockerBackend()) × N là ổn.
  • Mỗi .create() là của riêng nó docker run container/hộp cát Modal từ xa của riêng mình — cách ly thực sự.
  • Quy tắc "không an toàn cho việc thực thi đồng thời trên MỘT phiên bản" được thỏa mãn bằng cách giao cho mỗi công việc của nó ví dụ riêng: tuần tự hóa trong một công việc, song song hóa trên các công việc - chính xác là gather hình dạng agent.py đã sử dụng rồi.
  • Tiền lệ: active_executor() (bash.py:83) tồn tại đặc biệt nên harness eval có thể làm ấm và điều khiển một trình thực thi mỗi lần chạy từ bên ngoài đường dẫn công cụ (mặc dù vẫn thông qua toàn cầu, vì vậy nó tuần tự hóa).

Mô hình hiện tại so với mục tiêu

 TODAY — one sandbox per harness process
 ┌──────────────────────────── harness process ────────────────────────────┐
 │                                                                          │
 │   agent loop ──▶ bash / files / lsp ──▶ _get_executor()  (module global) │
 │                                              │                           │
 │                                              ▼                           │
 │                                    ONE SandboxExecutor                    │
 │                                              │                           │
 │                                              ▼                           │
 │                                   ONE Workspace  (.decode/sandbox)        │
 │                                              │                           │
 │                                              ▼                           │
 │                                   ONE container / remote sandbox          │
 └──────────────────────────────────────────────────────────────────────────┘


 TARGET — one harness, N isolated jobs
 ┌──────────────────────────── harness process ────────────────────────────┐
 │                          orchestrator / gather                            │
 │            ┌───────────────────┼───────────────────┐                     │
 │            ▼                   ▼                   ▼                      │
 │        job A deps          job B deps          job C deps                 │
 │      (own executor)      (own executor)      (own executor)               │
 │            │                   │                   │                      │
 │            ▼                   ▼                   ▼                      │
 │      Workspace A           Workspace B          Workspace C               │
 │   .decode/sandbox/A     .decode/sandbox/B     .decode/sandbox/C           │
 │            │                   │                   │                      │
 │            ▼                   ▼                   ▼                      │
 │      container A           container B          container C               │
 └──────────────────────────────────────────────────────────────────────────┘

Khoảng cách giữa hai hình ảnh chính xác là các phần chặn 1–2: di chuyển người thực thi ra khỏi mô-đun toàn cầu vào trạng thái của mỗi công việc và cung cấp cho mỗi công việc một thư mục Workspace riêng biệt.


Đường A — sắp xếp N hành quyết Kitaru (bằng hạt)

Mỗi decode run đã là một quá trình thực thi luồng bền vững khép kín (runtime/flow.py:298 run_agent_task) sẽ tạo ra hộp cát của chính nó và bản sao Workspace. Song song hóa = một bộ điều khiển gửi N lần thực thi và thu thập kết quả. Không có công cụ tái cấu trúc hộp cát nào cả.

                        ┌─────────────────────────┐
                        │   controller / harness  │
                        │   (submit + gather)     │
                        └────────────┬────────────┘
             ┌───────────────────────┼───────────────────────┐
             ▼                       ▼                       ▼
      ┌────────────┐          ┌────────────┐          ┌────────────┐
      │  flow exec │          │  flow exec │          │  flow exec │
      │  (proc /   │          │  (proc /   │          │  (proc /   │
      │  Modal ctr)│          │  Modal ctr)│          │  Modal ctr)│
      │            │          │            │          │            │
      │  sandbox A │          │  sandbox B │          │  sandbox C │
      │  ws clone  │          │  ws clone  │          │  ws clone  │
      └─────┬──────┘          └─────┬──────┘          └─────┬──────┘
            │  checkpoints           │  checkpoints           │
            ▼                        ▼                        ▼
        durable state            durable state            durable state
        (replay / fork)          (replay / fork)          (replay / fork)

Trên một ngăn xếp từ xa, đây đã là hai lớp Ứng dụng Modal lồng nhau (runtime/modal_app.py:32): decode-<env> cho các thùng chứa dòng chảy, decode-sandbox-<env> cho các hộp cát bash mỗi luồng sinh ra bên trong chính nó.

Ưu điểm

  • Công cụ tái cấu trúc hộp cát bằng không — tính năng cách ly, Không gian làm việc cho mỗi công việc và bản sao đã có sẵn.
  • Độ bền miễn phí — mỗi điểm kiểm tra công việc, do đó một sự cố sẽ phát lại các lượt đã hoàn thành (flow.py:325); fork/replay/cohort đã là một bề mặt vận hành (flow.py:558, kỹ năng kitaru-replay-ops).
  • Cách ly cứng — các quy trình/thùng chứa riêng biệt; một công việc gặp sự cố hoặc OOM không thể chạm vào anh chị em (ZenML chấm dứt hộp cát theo id, không bao giờ chấm dứt Ứng dụng được chia sẻ — modal_app.py:14).
  • Quy mô qua một máy — quạt ngăn xếp từ xa đến Modal; không bị giới hạn bởi lõi/RAM của một máy chủ.
  • HITL, chuyển giao, các bí mật đã được nối dây mỗi lần thực hiện (flow.py:190, ADR-0016).

Nhược điểm

  • Không có trạng thái chia sẻ trong quá trình — công việc không thể chia sẻ ứng dụng khách mô hình ấm, bộ đệm trong bộ nhớ hoặc Biểu đồ đối tượng Python. Sự phối hợp nằm ngoài phạm vi (hiện vật, cửa hàng Kitaru).
  • Chi phí cho mỗi công việc — mỗi lần thực thi sẽ trả tiền cho việc khởi động luồng + xây dựng/tái sử dụng hình ảnh + hộp cát mới tạo (cài đặt git+gh, ~ 20 giây trên docker mỗi phiên - docker_backend.py:290).
  • Bề mặt hoạt động nặng hơn — bạn đang chạy ngăn xếp Kitaru/Modal (DECODE_ENV != local), không phải là một quá trình máy tính xách tay duy nhất; nhiều bộ phận chuyển động hơn để đứng lên và xem.
  • Độ chi tiết thô — đơn vị của tính song song là toàn bộ quá trình chạy, không phải là một nhiệm vụ bên trong một lần chạy. Tốt cho "chạy 20 nhiệm vụ", gây khó xử cho "một agent phân chia nội bộ 3 công nhân và hợp nhất họ".

Tốt nhất cho: công việc hàng loạt/độc lập — đánh giá, xếp hàng nhiệm vụ, nhóm những gì-nếu-nếu — mỗi công việc nằm ở đâu vận hành toàn bộ agent và bạn muốn độ bền + cân trên nhiều máy.


Đường B — thi hành trên AgentDeps, quạt ra bên trong một quy trình (ngược lại với hạt)

Di chuyển người thi hành ra khỏi mô-đun toàn cầu và vào AgentDeps (ở đâu cwd, gate, đã có giải pháp rồi live), đặt cho mỗi công việc một thư mục Workspace riêng biệt, sau đó gather agent N chạy trong một vòng lặp sự kiện.

Phác thảo sự thay đổi

# tools/exec.py / agent/deps.py — carry the executor as per-job state
@dataclass
class AgentDeps:
    cwd: Path
    harness_home: Path
    executor: CommandExecutor          # NEW: per-job, not a module global
    workspace: Path                    # NEW: per-job .decode/sandbox/<job-id>
    ...

# tools/bash.py — read the executor from deps, not the memo
async def bash(ctx, command, timeout=None):
    ...
    result = await ctx.deps.executor.run(command, cwd=ctx.deps.cwd, timeout_s=timeout_s)

# workspace.py — parametrize the path per job
def workspace_dir(harness_home: Path, job_id: str) -> Path:
    return (harness_home / settings.sandbox_workspace_dir / job_id)

Một cuộc chạy trông như thế nào

  one asyncio event loop
  ────────────────────────────────────────────────────────────
   gather([ run(job A), run(job B), run(job C) ])
        │            │            │
        ▼            ▼            ▼
   deps.executor  deps.executor  deps.executor     ← three distinct instances
        │            │            │
        ▼            ▼            ▼
   Workspace/A    Workspace/B    Workspace/C        ← distinct paths, no collision
        │            │            │
        ▼            ▼            ▼
   container A    container B    container C         ← "not safe concurrent on ONE
                                                        instance" holds: each job has
                                                        its own instance, serial inside

Bộ máy xử lý đồng thời đã được chứng minh trong agent.py - semaphore trên mỗi vòng lặp, gather, dep tươi mỗi đứa trẻ. Sự thay đổi là người thực hiện mà những đứa trẻ đó tiếp cận: của chính chúng chứ không phải của toàn cầu chung.

Ưu điểm

  • Fine-grained — tính song song trong một lần chạy. Một agent có thể phân nhánh N công nhân trên N hộp cát và hợp nhất chúng trong quá trình ("yêu cầu" khai thác đơn, nhiều công việc "thực sự).
  • Trạng thái quy trình được chia sẻ — một ứng dụng khách mô hình ấm/nhóm HTTP, một vòng lặp sự kiện, trong bộ nhớ phối hợp giữa các công việc; không có các chuyến đi khứ hồi giả tạo để truyền dữ liệu.
  • Nhẹ để bắt đầu — không cần ngăn xếp Kitaru/Modal; chạy trên máy tính xách tay trong DECODE_ENV=local.
  • Kiến trúc sạch hơn bất kể — treo người thực thi lên AgentDeps loại bỏ một mô-đun toàn cầu điều đó đã làm phức tạp các bài kiểm tra (reset_executor, close_executor) và khai thác eval.

Nhược điểm

  • Bạn sở hữu tính năng cách ly và phục hồi sau sự cố — không có điểm kiểm tra/phát lại; nếu quá trình chết, tất cả N công việc chết với nó. Mọi thứ Kitaru cho miễn phí, bạn sẽ xây dựng lại hoặc từ bỏ.
  • Được giới hạn bởi một máy chủ — N vùng chứa dùng chung lõi/RAM/daemon Docker của một máy; không quy mô chéo máy mà không cần thêm bộ điều phối.
  • Công cụ tái cấu trúc thực với bán kính vụ nổ — toàn cầu được giả định trên toàn bộ bash.py, files.py, lsp.py, cộng với các móc vòng đời ấm/đóng/xuất và khởi động TUI (tui/app.py:788). Mỗi người đọc phải chuyển sang ctx.deps.executor.
  • Chống lại một bất biến đã nêu — AGENTS.md: "Chế độ hộp cát = một Không gian làm việc biệt lập đằng sau một Không gian làm việc đường may." Thiết kế đã cố ý đẩy trục song song về phía Kitaru; điều này thêm một trục thứ hai kiến trúc có chủ ý tránh né.
  • Tranh chấp tài nguyên khi dọn dẹp — N đồng thời docker run + lượt cài đặt git/gh đạt được một daemon; Việc phá bỏ/trả lại phải được phối hợp để một công việc thất bại không làm mắc kẹt một thùng chứa ( --rm và Việc dừng lại thời gian chờ theo phương thức vẫn được áp dụng, nhưng việc xử lý lại theo từng công việc trở nên phức tạp hơn).

Tốt nhất cho: một phiên tương tác muốn tạo ra một vài cây công việc/hộp cát riêng biệt, so sánh chúng và hợp nhất các kết quả mà không cần rời khỏi quy trình — nơi bộ nhớ dùng chung và độ trễ thấp quan trọng hơn độ bền và quy mô máy chéo.


Khuyến nghị

  • Muốn nhiều công việc độc lập, bền bỉ, quy mô → Đường A. Đó chính là kiến trúc được xây dựng cho; công việc duy nhất là lặp lại việc phối hợp run_agent_task.
  • Muốn phân tách trong quá trình với trạng thái được chia sẻ và độ chi tiết tốt → Đường B và xử lý AgentDeps.executor tái cấu trúc như một cách dọn dẹp chung (tắt mô-đun toàn cầu) thay vì một lần.

Chúng không phải là độc quyền: Người thực thi theo từng cấp độ của Đường B là nền tảng sạch hơn và người kiểm soát có thể vẫn gửi các bản thực thi Road-A cho các lô máy nặng, bền bỉ.


Câu hỏi mở/câu hỏi tiếp theo

  • Trần song song: có bao nhiêu song song docker run hộp cát mà một máy chủ có thể chịu đựng được trước daemon/đĩa (mỗi Workspace là một bản sao đầy đủ) có trở thành nút thắt cổ chai không? Cần một thước đo thực tế.
  • Giới hạn vùng chứa phương thức: có bao nhiêu lần thực thi đồng thời decode-<env> Ứng dụng thực sự cho phép (Đường A trần thật) — chưa có dấu vết cho đến nay.
  • Chi phí gieo trồng kỹ năng tại N hộp cát (workspace.py:189 sao chép các kỹ năng vào mọi Không gian làm việc).
  • Handback theo chiều rộng: N công việc, mỗi công việc đẩy một decode/<session-id> nhánh - đặt tên và giới hạn tỷ lệ.
  • Chồng chéo khai thác đánh giá: nó đã thúc đẩy người thực thi mỗi lần chạy; một công cụ tái cấu trúc Road-B có thể thay thế nó con đường riêng.
Mục lục nguồn