Harness Academy
Tài liệu gốc 28 9 phútTiếng Việt + English
docs/adr/0017-resilient-parallel-subagent-fanout.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.

0017. Linh hoạt, song song theo mặc định Khám phá phân xuất phân ra — một cuộc gọi tổng đài viên, N con đã được xác thực, một tập hợp được gắn nhãn

Trạng thái: Đã chấp nhận Ngày: 2026-07-13 Đã sửa đổi: 2026-07-14 — Phần bảo vệ chất của §3 được ghi là ĐÃ GIAO HÀNG: một từ trần (MIN_PROMPT_WORDS = 8), không kiểm tra ba tín hiệu đối với câu hỏi/phạm vi/báo cáo. Ba phần hình dạng đang được huấn luyện trong phần mô tả công cụ; làm cho nó trở thành một vị từ bác bỏ sai nhất tóm tắt thực tế. Mọi khía cạnh khác được vận chuyển như đã viết. Thay thế: Thay thế một phần ADR-0013 - cụ thể là §7 phân ra cơ chế ("N agent(...) các cuộc gọi trong một phản hồi chạy đồng thời… không có tùy chỉnh asyncio.gather" và agent(prompt) chữ ký một dấu nhắc mà nó ngụ ý) và kết quả * của §8 hình dạng* ("văn bản cuối cùng của trẻ — bị cắt ngắn thành subagent_result_max_bytes — được trả về dưới dạng kết quả công cụ"). Được giữ lại từ ADR-0013 và vẫn còn hiệu lực: §1 (ranh giới chạy lồng nhau trong quá trình), §2 (bộ công cụ con chỉ đọc), §3 (trục phụ), §4 (cấp), §5 (miễn phí quyền), §6 ( đường nối agent chính được đặt một lần), semaphore trên mỗi vòng lặp của §7 + subagent_max_parallel + theo từng trẻ UsageLimits + luồng không sử dụng, §8's truncate() thành ngữ + bảng điểm phù du + im lặng cho đến khi hoàn thành, §9 (không có vỏ bọc đặc biệt) và §10.

Bối cảnh

ADR-0013 đã được vận chuyển agent(prompt): một cuộc gọi, một đứa trẻ Khám phá chỉ đọc. Tính song song tồn tại nhưng là tự nguyện — điều này chỉ xảy ra nếu mô hình gốc chọn phát ra N lệnh gọi công cụ trong một phản hồi. Ba lỗ hổng nổi lên trong thực tế: (a) không có phân bổ mặc định - cha mẹ lười biếng khám phá một cách tuần tự; (b) không hợp đồng đầu vào - lời nhắc sinh ra một từ sẽ tạo ra một đứa trẻ vô dụng; (c) không xác nhận đầu ra - một báo cáo trống hoặc một đứa trẻ trả lời từ bộ nhớ mô hình mà không đọc bất kỳ mã nào, sẽ gập lại thành nếu đó là bằng chứng.

Phạm vi được cố tình thu hẹp (do con người khóa): khả năng phục hồi = hợp đồng đầu vào + xác thực đầu ra. Không có mục tiêu: làm cứng nhanh chóng bằng tiêm; thử lại/trở lại mô hình cấp độ vận chuyển.

Sự thật về khung đã được xác minh dựa trên cài đặt pydantic-ai-slim 1,95 (không phải tài liệu từ bộ nhớ):

  • ModelRetry được tạo ra từ một công cụ sẽ gửi lời nhắc thử lại tới mô hình (exceptions.py). các Ngân sách thử lại cho mỗi công cụ mặc định là 1 (Agent.__init__: eff_retries = thử lại nếu lần thử lại không phải là Không ai khác 1); exceeding it raises UnexpectedModelBehavior và hủy bỏ quá trình chạy — vì vậy một công cụ khiến bạn khó chịu ModelRetry phải đăng ký với số tiền lớn lên retries= ngân sách.
  • AgentRunResult.all_messages() trả về bảng điểm đầy đủ của trẻ (run.py:461); "cái trẻ không thực hiện cuộc gọi công cụ nào" = không ToolCallPart trong bất kỳ cái nào của nó ModelResponses.
  • Lồng nhau agent.run() nhập lại và UsageLimits(request_limit=…) hoạt động như ADR-0013 được ghi lại - không thay đổi.

Quyết định

Tất cả những điều sau đây là một thiết kế; mỗi mục được đánh số là một khía cạnh, không phải là một bản ghi quyết định riêng biệt.

  1. Chữ ký PHÁT HIỆN: agent(ctx, prompts: list[str]) -> str. MỘT lệnh gọi công cụ sẽ tạo ra N trẻ em; mô hình gốc tạo ra N góc riêng biệt (nó có câu hỏi); harness đảm bảo tính song song, tổng hợp và số lượng tối thiểu thông qua mô tả công cụ "ít nhất 3 góc độ KHÁC BIỆT cho một câu hỏi rộng". Khám phá một đứa trẻ là một thành phần danh sách. Fan-out không còn phụ thuộc vào mô hình N cuộc gọi công cụ tình nguyện.

  2. Bảo vệ cấu trúc (xác định, trước khi sinh sản). Danh sách trống → ModelRetry ("đưa ra ít nhất một nhắc"). len(prompts) > 6 → ModelRetry (hợp nhất). Giới hạn chiều rộng là hằng số mô-đun - cơ chế tối thiểu, không phải núm cấu hình; subagent_max_parallel (4) vẫn là riêng biệt Trần ĐỒNG HÀNH (một quạt ra rộng 6 chạy 4, rồi 2). Cho phép trùng lặp - chất lượng nhanh chóng vấn đề bảo vệ chất đã cằn nhằn.

  3. Hợp đồng đầu vào, không có cuộc gọi LLM bổ sung nào. Chuỗi dạng tự do trên mỗi góc (không có khe cắm cứng nhắc). chất lượng được thực thi bởi (i) phần mô tả công cụ cứng — mỗi lời nhắc chứa đựng câu hỏi, phạm vi cần thực hiện tìm kiếm và nội dung báo cáo phải chứa - và (ii) biện pháp bảo vệ chất rẻ tiền, mang tính quyết định nâng cao ModelRetry đặt tên cho lời nhắc vi phạm theo chỉ mục dựa trên 1 (khớp với ## Subagent i nhãn mà mô hình đã nhìn thấy) và nó có vấn đề gì. Bởi vì mặc định Ngân sách thử lại cho mỗi công cụ là 1, agent công cụ đăng ký với retries= ≥ 2 nên bảo vệ cằn nhằn huấn luyện viên mô hình thay vì hủy bỏ quá trình chạy (đã vận chuyển: AGENT_TOOL_RETRIES = 3).

    Bộ bảo vệ, như đã được vận chuyển (được sửa đổi 2026-07-14 để phù hợp với việc triển khai): nó có chính xác MỘT tiêu chí từ chối - tầng chất, số từ bên dưới MIN_PROMPT_WORDS (8). Đó là điều gì phát hiện ra sự thất bại mà nó tồn tại để ngăn chặn ("khám phá", "nhìn xung quanh"); không ai tóm tắt một đồng nghiệp trên một cơ sở mã trong sáu từ. Nó cố tình không là một người chấm điểm có chất lượng nhanh chóng, và hình dạng ba phần (câu hỏi + phạm vi + báo cáo) là huấn luyện trong phần mô tả công cụ, không phải vị ngữ bác bỏ. Việc triển khai đã thúc đẩy điều này: một cổng AND ba tín hiệu trước đó trên ba các phần bị từ chối sai 6 trên 8 tóm tắt thực tế (xác suất từ chối sai các hợp chất trên mờ kiểm tra từ khóa và mọi danh sách từ được mở rộng sẽ mời gọi người bỏ lỡ tiếp theo); một sự cho phép HOẶC trên cùng các tín hiệu vẫn bị từ chối sai một bản tóm tắt dài 17 từ. Cả hai đều bị rơi - sàn đứng một mình. Sự thiên vị là có chủ ý, bởi vì hai lỗi không đối xứng: CHẤP NHẬN sai chỉ khôi phục hiện trạng bảo vệ trước (một báo cáo trẻ yếu), trong khi một LỰA CHỌN sai sẽ chủ động phá vỡ đường chạy - nó đốt cháy một lượt mô hình và ăn ngân sách thử lại. Khi nghi ngờ, hãy chấp nhận. Sàn dừng lại Chơi trò chơi NGẮN, không phải trò chơi ĐỆM (từ khóa vượt qua sàn sẽ được thông qua) - giao dịch được chấp nhận, không phải là một sự giám sát. Do đó, người cằn nhằn nói rằng lời nhắc quá ngắn gọn; nó không bao giờ liệt kê các bộ phận bị thiếu riêng lẻ, điều này tạo ra sự cằn nhằn đã nói dối (yêu cầu mô hình thêm phạm vi vào đã đưa ra rồi).

  4. Đồng thời: khai thác asyncio.gather bên trong thân dụng cụ, giữ trật tự, từng con cố gắng thu được semaphore trên mỗi vòng lặp hiện có. (ADR-0013 dựa vào lịch trình pydantic-ai N các cuộc gọi công cụ riêng biệt; với một lệnh gọi mang danh sách, tập hợp sẽ chuyển sang công cụ — semaphore và mỗi đứa trẻ UsageLimits không thay đổi.)

  5. Tập hợp = ghép nối có nhãn, KHÔNG gọi LLM tổng hợp. Mỗi phần của trẻ đều có tiêu đề bằng lời nhắc riêng của nó - ## Subagent {i} — "{prompt}" - theo thứ tự nhanh chóng. Một đứa trẻ thất bại VẪN nhận được phần của nó, mang theo một ghi chú lỗi rõ ràng: các kết quả một phần đánh bại một ngoại lệ loại bỏ anh chị báo cáo. Mô hình gốc là bộ tổng hợp.

  6. Ngân sách ngữ cảnh được chia sẻ. Báo cáo của mỗi trẻ bị cắt bớt (được chia sẻ truncate() thành ngữ) đến subagent_result_max_bytes // len(prompts), do đó tổng nếp gấp vẫn ở mức ~16 KB bất kể chiều rộng - đây là lý do khiến "3 theo mặc định" trở thành mặc định miễn phí thay vì thuế ngữ cảnh.

  7. Xác thực đầu ra + chính xác một lần thử lại. Một báo cáo là BAD nếu nó (i) trống/chỉ có khoảng trắng, hoặc (ii) trẻ KHÔNG thực hiện cuộc gọi công cụ nào (all_messages() quét - thay vào đó nó đã trả lời từ bộ nhớ đọc mã). Một báo cáo xấu sẽ nhận được chính xác MỘT lần xuất hiện lại với một cú huých được thêm vào; một giây nỗ lực xấu sẽ gấp lại ghi chú thất bại ("subagent trả về không có báo cáo có thể sử dụng được."). Không bao giờ vô hạn thử lại. Phòng thủ DeferredToolRequests đầu ra được phân loại là BAD.

  8. Hợp đồng báo cáo trẻ em (persona). explore.mdnội dung được viết lại: báo cáo chặt chẽ tóm tắt có cấu trúc - phát hiện, tập tin:bằng chứng dòng, dấu vết theo sau - có chủ ý được nén cho ngân sách được chia sẻ giữa anh chị em. Một bản tóm tắt không có file:line bằng chứng là ảo giác kể (cặp với §7-ii).

  9. Chân trang tổng hợp. Phần khai thác gắn thêm một lệnh vào mỗi kết quả tổng hợp: biên dịch N báo cáo thành MỘT câu trả lời - văn xuôi CỘNG VỚI sơ đồ cấu trúc dựa trên văn bản được tìm thấy (ASCII/mặc định vẽ hộp; Nàng tiên cá chỉ dành cho đồ thị chính hãng - Rich TUI hiển thị Nàng tiên cá dưới dạng nguồn thô). Đúng lúc, một nơi, không bao giờ có sự nhắc nhở của cá nhân; nối thêm sau khi cắt bớt để nó không tốn ngân sách trẻ em.

  10. Kỷ luật (không thay đổi). TDD-đầu tiên, filterwarnings=["error"], chú thích đầy đủ, thư viện nhật ký mã, không có cài đặt mới, nhân bản kiểm tra src/ 1:1.

Sơ đồ

Bảo vệ → phân tán → xác thực → tổng hợp — một agent(prompts) gọi, N con kiên cường, một nếp gấp có nhãn.

flowchart TD
    model["parent model response:<br/>ONE agent(prompts=[p1..pN])"]:::call
    guards{"deterministic guards<br/>empty? · width > 6? · any prompt under 8 words?"}:::gate
    nag["ModelRetry — names the fix<br/>(tool registered with retries ≥ 2)"]:::retry
    gather["asyncio.gather (prompt order)<br/>each attempt under the per-loop Semaphore<br/>subagent_max_parallel"]:::tool

    model --> guards
    guards -- "bad input" --> nag --> model
    guards -- ok --> gather

    subgraph children["Explore children — fresh read-only deps, UsageLimits per child"]
        c1["child 1"]:::child
        c2["child 2"]:::child
        cn["child N"]:::child
    end
    gather --> c1 & c2 & cn

    validate{"report BAD?<br/>empty · zero tool calls<br/>(all_messages scan)"}:::gate
    c1 --> validate
    c2 --> validate
    cn --> validate
    validate -- "bad, 1st time" --> retry["ONE re-spawn<br/>same prompt + nudge"]:::retry --> validate
    validate -- "bad again" --> note["failure note<br/>'no usable report'"]:::fail
    validate -- good --> trunc["truncate() to<br/>subagent_result_max_bytes // N"]:::result

    trunc --> agg["labelled aggregate<br/>## Subagent i — &quot;prompt&quot; …"]:::result
    note --> agg
    agg --> footer["+ Synthesis Footer:<br/>one answer, prose + text diagram"]:::result
    footer --> model

    classDef call fill:#1e293b,stroke:#0ea5e9,color:#e2e8f0
    classDef gate fill:#713f12,stroke:#eab308,color:#fef9c3
    classDef retry fill:#4c1d95,stroke:#a855f7,color:#ede9fe
    classDef tool fill:#334155,stroke:#a855f7,color:#e9d5ff
    classDef child fill:#14532d,stroke:#22c55e,color:#dcfce7
    classDef fail fill:#7f1d1d,stroke:#ef4444,color:#fecaca
    classDef result fill:#334155,stroke:#38bdf8,color:#bae6fd

hậu quả

  • Phá vỡ, phá vỡ sạch sẽ. Mọi người gọi hình dạng cũ đều di chuyển: lược đồ công cụ, các bài kiểm tra đơn vị (tests/unit/decode/tools/test_agent.py), CẢ HAI viên đá (test_subagents_capstone.py, test_observability_capstone.py — cách sử dụng quạt ra của nó args={"prompt": …}) và hướng dẫn sử dụng-e2e-qa hàng vở kịch. KHÔNG agent(prompt) miếng chêm tương thích.
  • Tính song song hiện là sự đảm bảo về harness, không phải là phép lịch sự kiểu mẫu — và chi phí gấp là không phụ thuộc vào chiều rộng (phân chia ngân sách), do đó việc khám phá rộng sẽ ngừng đánh thuế vào bối cảnh của cấp độ gốc.
  • Con hỏng bị giới hạn: tối đa 2 lần sinh sản, sau đó là một nốt; anh chị em luôn sống sót. các ghi chú lỗi là UX trung thực - mô hình gốc (và con người đọc bản ghi) sẽ thấy cái nào góc không tạo ra gì cả.
  • Các lính canh dành lượt làm mẫu, không phải thẻ cho trẻ em: cằn nhằn là một lần thử lại rẻ tiền, và Ngân sách thử lại cho mỗi công cụ tăng lên là cái giá phải trả cho việc huấn luyện thay vì hủy bỏ.
  • Phát lại/headless không thay đổi (ADR-0013 §9 là viết tắt): toàn bộ quạt ra vẫn còn một lớp mờ đục lệnh gọi công cụ an toàn bộ đệm - bên trong phong phú hơn, hình dạng điểm kiểm tra giống nhau bên ngoài.
  • ADR-0013 lưu giữ bản ghi về ranh giới, bộ công cụ, đường nối, quyền và tính tạm thời; tiêu đề của nó có phần sửa đổi ghi ngày chỉ vào đây (phần nội dung không được chỉnh sửa, kiểu ADR-0011).
  • Các đường may còn hở: a subagent_type param khi nhân vật phụ thứ hai đến; bắc cầu các sự kiện con đối với TUI (tiến trình phụ trực tiếp); trình xác nhận báo cáo thích ứng (được tính điểm theo mô hình) nếu vị từ xác định tỏ ra quá thô - một giới hạn đo thực tế sẽ biện minh cho việc nâng cấp.
Mục lục nguồn