Harness Academy
Tài liệu gốc 17 15 phútTiếng Việt + English
docs/subagents.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.

Chất phụ

SubAgents cho phép một agent ủy thác các nhiệm vụ độc lập cho các agent con được đặt tên. Nó cần một chuỗi SubAgent các mục và hiển thị một delegate_task(agent_name, task) công cụ. Mỗi ủy quyền sẽ điều hành tổng đài viên phụ đã chọn theo cách riêng của mình -- với lịch sử tin nhắn riêng, do đó, nó không bao giờ nhìn thấy cuộc hội thoại chính -- và trả kết quả đầu ra của nó cho cấp trên.

Nguồn

Mặc dù Pydantic AI Harness có trên các bản phát hành 0.x nhưng API có thể thay đổi giữa các bản phát hành nhỏ; khi đó, cảnh báo ngừng sử dụng và hướng dẫn di chuyển ghi chú phát hành sẽ cho bạn (hoặc người đại diện của bạn) biết chính xác cách nâng cấp. Xem chính sách phiên bản.

vấn đề

Một agent duy nhất thực hiện mọi việc sẽ tích lũy được một bộ công cụ lớn và một bối cảnh dài. Việc phân chia công việc giữa các subagent chuyên biệt sẽ giúp mỗi bối cảnh tập trung, nhưng việc sắp xếp ủy quyền theo cách thủ công có nghĩa là viết một công cụ cho mỗi agent, chuyển tiếp các phần phụ, phân luồng giới hạn sử dụng và cho mô hình biết những gì nó có thể ủy quyền.

Giải pháp

SubAgents mất một chuỗi SubAgent các mục và hiển thị một delegate_task(agent_name, task) công cụ. Mỗi ủy quyền sẽ điều hành tổng đài viên phụ đã chọn theo cách riêng của mình -- với lịch sử tin nhắn riêng, do đó, nó không bao giờ nhìn thấy cuộc hội thoại chính -- và trả kết quả đầu ra của nó cho cấp trên. Các subagent khả dụng được liệt kê trong lời nhắc hệ thống dưới dạng lệnh tĩnh, do đó danh sách vẫn ở tiền tố được lưu trong bộ nhớ đệm.

from pydantic_ai import Agent
from pydantic_ai_harness import SubAgent, SubAgents

researcher = Agent('anthropic:claude-sonnet-4-6', name='researcher', description='Researches a topic and reports findings')
writer = Agent('anthropic:claude-sonnet-4-6', name='writer', description='Turns notes into polished prose')

orchestrator = Agent(
    'anthropic:claude-opus-4-7',
    capabilities=[SubAgents(agents=[SubAgent(researcher), SubAgent(writer)])],
)

result = orchestrator.run_sync('Research the history of TLS and write a one-paragraph summary.')
print(result.output)

Tên của đại biểu -- cách mô hình gốc đề cập đến nó và cách nó được liệt kê trong lời nhắc -- là tên riêng của đại diện name, hoặc một SubAgent(name=...) ghi đè. Hai đại diện giải quyết cùng tên là một lỗi và một đại diện không có tên và không có ghi đè sẽ bị từ chối.

công cụ

Công cụMục đích
delegate_task(agent_name, task)Chạy subagent được đặt tên trên một tác vụ độc lập và trả về kết quả đầu ra của nó.
  • subagent chạy với lịch sử tin nhắn của chính nó, vì vậy task phải có tính tự chủ.
  • Một ẩn số agent_name tăng lên ModelRetry, do đó mô hình có thể tự sửa.
  • Kết quả trả về cho cha mẹ là str(result.output).
  • Với một models menu được cấu hình, công cụ sẽ mất thêm model lập luận (xem bên dưới).

Deps, cách sử dụng, công cụ và khả năng

  • Deps được chuyển tiếp. Chạy gốc deps được chuyển đến từng subagent, vì vậy các subagent chia sẻ thông tin của agent mẹ AgentDepsT (được thực thi bằng chữ ký loại -- mỗi subagent là một AbstractAgent[AgentDepsT, Any]).
  • Việc sử dụng được chia sẻ theo mặc định. Của cha mẹ usage được chuyển cho mỗi lần chạy subagent, do đó việc tổng hợp mức sử dụng token và agent gốc usage_limits áp dụng trên toàn bộ cây agent. Đặt forward_usage=False giao cho mỗi agent phụ thực hiện công việc hạch toán riêng.
  • Các công cụ có thể được kế thừa. Với inherit_tools=True, công cụ riêng của agent mẹ (đăng ký trực tiếp hoặc qua toolsets) được thêm vào mỗi lần chạy của subagent, bên cạnh hoạt động của subagent. Các công cụ do khả năng của cấp độ gốc đóng góp không được kế thừa: chúng bị ràng buộc với các phiên bản khả năng được đăng ký trong lần chạy cấp độ gốc và sẽ đến mà không có các móc nối và hướng dẫn mà chúng phụ thuộc vào. sử dụng shared_capabilities để cung cấp cho các agent phụ một khả năng. Điều này cũng loại trừ chính công cụ ủy quyền, do đó, tổng đài viên phụ không thể tiếp tục ủy quyền nữa. Tắt theo mặc định.
  • Khả năng có thể được chia sẻ. shared_capabilities được áp dụng cho mọi hoạt động của subagent -- ví dụ: cung cấp cho tất cả các subagent một lan can bảo vệ, bộ nhớ hoặc khả năng lập kế hoạch chung mà không cần xây dựng lại từng agent Agent.
  • Các sự kiện của agent phụ có thể được phát trực tuyến. Vượt qua event_stream_handler và nó được chuyển tiếp tới mỗi lần chạy của subagent, do đó, các sự kiện công cụ và truyền phát mô hình của subagent sẽ hiển thị cho người gọi (trình xử lý sẽ nhận được thông tin riêng của subagent RunContext).

Điều khiển chạy cho mỗi đại biểu

Mỗi SubAgent có ngân sách riêng nên quyền kiểm soát của một đại biểu không ảnh hưởng đến những người khác. A SubAgent không có bộ điều khiển chạy với SubAgents mặc định.

from pydantic_ai import Agent
from pydantic_ai.usage import UsageLimits
from pydantic_ai_harness import SubAgent, SubAgents

reproducer = Agent('anthropic:claude-sonnet-4-6', instructions='Reproduce the reported bug from a minimal script.')
librarian = Agent('anthropic:claude-sonnet-4-6', instructions='Find relevant docs, issues, and prior art.')

orchestrator = Agent(
    'anthropic:claude-opus-4-7',
    capabilities=[
        SubAgents(
            agents=[
                SubAgent(reproducer, usage_limits=UsageLimits(request_limit=35), timeout_seconds=600, max_calls=1),
                SubAgent(librarian, usage_limits=UsageLimits(request_limit=18), timeout_seconds=300, max_calls=2),
            ]
        )
    ],
)
Lĩnh vựcHiệu ứng
modelsPhím nào của SubAgents menu mô hình mà đại biểu này có thể chạy trên đó và nó chạy trên trình đơn nào theo mặc định: khóa đầu tiên được liệt kê. Xem phần "Lựa chọn mô hình theo mỗi ủy quyền" bên dưới.
usage_limitsNgân sách yêu cầu/token cho một ủy quyền. Đứa trẻ chạy bằng cách tính toán sử dụng của riêng mình, vì vậy ngân sách chỉ tính các yêu cầu và token của đứa trẻ đó (không phải của cha mẹ hoặc anh chị em của con), ngay cả khi forward_usage=True. Sự đánh đổi: token của con đó không còn được tổng hợp vào token của cha mẹ nữa usage. Đạt được ngân sách là một kết quả nhẹ nhàng (xem bên dưới), không phải là một bước dừng UsageLimitExceeded.
timeout_secondsNgân sách đồng hồ treo tường cho một phái đoàn. Khi trẻ vượt quá giới hạn đó, hoạt động chạy của xe sẽ bị hủy và phụ huynh sẽ nhận được thông báo lái nhẹ thay vì bám chặt vào trẻ. Của đứa trẻ bị hủy bỏ event_stream_handler (nếu có) dừng nhận sự kiện mà không có sự kiện đầu cuối.
max_callsSố lần ủy quyền tối đa cho tổng đài viên phụ này trong mỗi lần chạy chính. Sau khi đạt được, các ủy quyền tiếp theo sẽ trả lại một thông báo đã cạn kiệt ngân sách mà không cần chạy con. Số lượng được giới hạn trong một Agent.run (a run_id) và bị xóa khi nó kết thúc, do đó, mỗi cấp độ gốc sẽ chạy và mỗi cấp độ của cây lồng nhau sẽ lập ngân sách một cách độc lập.
on_failureMột thông báo chỉ đạo được trả về cho phụ huynh về bất kỳ sự xuống cấp phần mềm nào của đại biểu này, thay cho mặc định tích hợp sẵn. Việc thiết lập nó cũng làm cho các lỗi ở trẻ em trở nên nhẹ nhàng hơn (xem bên dưới).
contain_errorsLiệu một sự cố không mong muốn trong đại biểu này có bị phát hiện và trả về cho thành phần mẹ dưới dạng giới hạn hay không ModelRetry thay vì hủy bỏ lần chạy gốc (xem bên dưới). Bỏ đặt kế thừa SubAgents(contain_errors=...) mặc định (tắt).

Lựa chọn mô hình cho mỗi ủy quyền

Người điều phối biết nhiệm vụ đó khó khăn như thế nào vào thời điểm họ viết bản tóm tắt, vì vậy đây là nơi thích hợp để quyết định mô hình nào sẽ thực hiện nhiệm vụ đó. Cấu hình một models menu và công cụ đại biểu đạt được model đối số đặt tên cho một trong các khóa của nó.

from pydantic_ai import Agent
from pydantic_ai.settings import ModelSettings
from pydantic_ai_harness import SubAgent, SubAgents
from pydantic_ai_harness.subagents import ModelOption

reviewer = Agent('anthropic:claude-sonnet-4-6', name='reviewer', description='Reviews a diff')
linter = Agent('anthropic:claude-sonnet-4-6', name='linter', description='Runs the linter and reports failures')

orchestrator = Agent(
    'anthropic:claude-opus-4-7',
    capabilities=[
        SubAgents(
            agents=[SubAgent(reviewer), SubAgent(linter, models=['fast'])],
            models={
                'fast': 'anthropic:claude-haiku-4-5',
                'standard': 'anthropic:claude-sonnet-4-6',
                'deep': ModelOption(
                    'anthropic:claude-opus-4-7',
                    description='hard reasoning, multi-file changes',
                    settings=ModelSettings(thinking='xhigh'),
                ),
            },
        )
    ],
)
  • Tắt theo mặc định. Không có models thực đơn model đối số hoàn toàn không có trong lược đồ công cụ và mọi ủy quyền đều chạy chính xác như trước đây.
  • Các phím là giao diện. Chúng được liệt kê trong lời nhắc hệ thống cùng với mô hình và mô tả của từng mục nhập, đồng thời lược đồ công cụ cung cấp chúng dưới dạng enum, do đó, mô hình sẽ chọn từ menu thay vì tạo tên mô hình. Đặt tên cho công việc ('fast', 'deep'), không dành cho nhà cung cấp.
  • Mục nhập là mô hình hoặc ModelOption. ModelOption(model, description=..., settings=...) thêm gợi ý định tuyến và mỗi tùy chọn ModelSettings, vì vậy một phím có thể có nghĩa là "cùng một mô hình, nhiều suy nghĩ hơn". Các cài đặt đó hợp nhất với chính subagent model_settings, giữ các phần mà tùy chọn không được đặt.
  • Thứ tự giải quyết. Khóa cấp trên được chuyển, nếu không thì khóa được phép đầu tiên của đại biểu (xem bên dưới), nếu không thì mô hình của chính đại biểu, nếu không thì mô hình của cấp trên chạy.
  • Một đại biểu có thể bị hạn chế. SubAgent(linter, models=['fast']) chân ủy quyền cho fast: khóa được liệt kê đầu tiên là khóa mà nó chạy khi khóa cha vượt qua không model, và những người khác bị từ chối với một ModelRetry. Hạn chế được hiển thị trong danh sách nhắc nhở (- linter: Runs the linter (models: fast)). Việc giới hạn một phím mà menu không xác định là một ValueError lúc xây dựng.
  • Khóa bị từ chối không mất phí. Khóa không xác định hoặc không có sẵn sẽ xuất hiện dưới dạng ModelRetry liệt kê các tùy chọn hợp lệ, trước đại biểu max_calls ngân sách được tính phí.

Xử lý lỗi

kết quả mềm trả về thông báo chỉ đạo cho cấp độ gốc dưới dạng kết quả của công cụ thông thường, do đó, mô hình của nó sẽ đọc thông báo và quyết định việc cần làm tiếp theo (thay vì ủy quyền lại ngay lập tức, điều này ModelRetry lời mời). Đã hết thời gian chờ, đã đạt đến usage_limits ngân sách và cạn kiệt max_calls ngân sách luôn mềm mại. Khi nào on_failure được đặt, thông báo mà nó mang theo sẽ thay thế mặc định tích hợp cho những kết quả này.

Chạy subagent không thành công với lỗi mô hình mềm (ModelRetry, UnexpectedModelBehavior, ví dụ: nó đã hết số lần thử lại), theo mặc định, được chuyển đổi thành ModelRetry cho cha mẹ -- để mô hình của cha mẹ thấy Sub-agent '<name>' failed: ... và có thể phản ứng bằng cách ủy quyền lại. Công cụ ủy quyền mặc định là tool_retries=2, do đó cha mẹ chỉ hủy bỏ sau nhiều lần đại biểu liên tiếp thất bại; bộ đếm sẽ đặt lại sau khi ủy quyền thành công. Tăng tool_retries để chịu đựng một subagent dễ bong tróc hơn, hoặc thiết lập None để kế thừa các lần thử lại công cụ mặc định của agent gốc. Đặt on_failure để một đại biểu làm cho các lỗi của nó trở nên nhẹ nhàng hơn: lỗi con trả về on_failure tin nhắn như một kết quả công cụ bình thường.

Lỗi cứng lan truyền để dừng toàn bộ quá trình chạy. A UsageLimitExceeded từ một đứa trẻ có no mỗi đại biểu usage_limits (do đó nó chia sẻ kế toán của cha mẹ) nghĩa là toàn bộ cây hết ngân sách và nhân giống; một đứa trẻ đạt được của riêng mình usage_limits mềm như trên.

Một sự cố bất ngờ -- bất kỳ ngoại lệ nào khác mà trẻ đưa ra, chẳng hạn như nhà cung cấp ModelAPIError/FallbackExceptionGroup hoặc đồng bằng ValueError từ một đối số công cụ xấu -- truyền bá theo mặc định và hủy bỏ quá trình chạy gốc. Đặt contain_errors=True (theo đại biểu, hoặc theo SubAgents mặc định) để bắt nó và trả lại cho cha mẹ dưới dạng giới hạn ModelRetry thay vào đó, do đó một sự cố của đại biểu không thể hủy bỏ toàn bộ quá trình chạy. Ngăn chặn vẫn ồn ào: ngoại lệ gửi thông báo thử lại (Sub-agent '<name>' crashed: ...), nó được ghi lại thông qua tiêu chuẩn logging mô-đun và tool_retries vẫn còn giới hạn liên tiếp đâm vào một vụ phá thai. Điều này trực giao với on_failure -- một sự cố được ngăn chặn luôn tạo ra âm thanh thử lại lớn, không bao giờ là âm thanh nhỏ on_failure return, do đó lỗi thực sự không bao giờ được coi là thành công. Hủy bỏ, chia sẻ UsageLimitExceeded, tín hiệu điều khiển luồng pydantic-ai (CallDeferred, ApprovalRequired, cái Skip* tín hiệu) và UserError luôn lan truyền bất kể contain_errors.

khám phá

Các agent phụ được liệt kê trong lời nhắc hệ thống thông qua get_instructions, sử dụng của mỗi agent description (hoặc một SubAgent(description=...) ghi đè). Một agent phụ không có mô tả chỉ được liệt kê theo tên.

Đang tải subagent từ đĩa

Các định nghĩa agent đánh dấu của repo trở thành đại biểu mà không cần viết bất kỳ Agent mã. Theo mặc định mỗi *.md tệp trong các thư mục thông thường được tải dưới dạng subagent, cùng với thông tin được chuyển rõ ràng agents.

from pydantic_ai import Agent
from pydantic_ai_harness import SubAgents

orchestrator = Agent(
    'anthropic:claude-opus-4-7',
    capabilities=[SubAgents(inherit_tools=True)],  # auto-loads ./.agents/agents/ and ~/.agents/agents/
)

agent_folders kiểm soát các định nghĩa đến từ đâu. Nó mặc định là 'agents', cách bố trí thông thường:

  • Tên thư mục str (mặc định 'agents'): đối với gốc dự án (cwd) thì gốc gốc, tải từ <root>/.agents/<name>/, rơi trở lại <root>/.claude/<name>/ khi nào <root>/.agents/ vắng mặt.
  • Một chuỗi các đường dẫn tải từ chính xác các thư mục đó theo thứ tự.
  • None vô hiệu hóa việc tải đĩa, chỉ hiển thị thông tin được thông qua một cách rõ ràng agents.

định dạng định nghĩa

Một định nghĩa là một tệp đánh dấu với phần đầu tùy chọn:

---
name: researcher
description: Researches a topic and reports findings
tools: Read, Grep
---
You research topics. Report your findings, each with a source.
  • name là tên đại biểu (cách cấp trên đề cập đến nó và cách nó được liệt kê). Nó rơi trở lại gốc tên tập tin khi vắng mặt.
  • description thúc đẩy danh sách nhắc nhở.
  • Phần thân markdown trở thành hướng dẫn của agent.
  • tools (hoặc allowed-tools) là một chuỗi được phân tách bằng dấu phẩy hoặc danh sách chặn YAML. Xem phần "Công cụ" bên dưới.
  • model và color bị bỏ qua: mô hình được kế thừa từ cha mẹ (xem bên dưới) và color không có pyai tương đương.

Frontmatter được đọc bởi một trình phân tích cú pháp nhỏ, không phụ thuộc, giới hạn ở các khóa đó (pyyaml không phải là sự phụ thuộc khai thác). Frontmatter YAML đầy đủ không được hỗ trợ.

Những mô hình và nỗ lực

Các agent đĩa kế thừa mô hình của lần chạy gốc theo mặc định. Mỗi tổng đài viên, người gọi có thể ghi đè mô hình và đặt mức suy nghĩ/nỗ lực thông qua agent_overrides, được khóa theo tên của agent:

from pydantic_ai_harness import SubAgents
from pydantic_ai_harness.subagents import AgentOverride

SubAgents(
    agent_folders='agents',
    agent_overrides={'researcher': AgentOverride(model='anthropic:claude-sonnet-4-6', effort='high')},
)

Mọi agent được xây dựng năng lực đều hoạt động ở mức nỗ lực tư duy tối thiểu. MINIMUM_EFFORT_FLOOR và clamp_effort(level, floor=...) người trợ giúp được xuất để người điều phối có thể áp dụng cùng một tầng cho các agent của chính mình (ứng dụng phía người điều phối đó là trách nhiệm của người gọi). clamp_effort bản đồ None/False xuống sàn, lá True (nỗ lực mặc định của nhà cung cấp) không thay đổi và nâng mức cụ thể dưới mức sàn lên tới mức đó. Nỗ lực được áp dụng thông qua pyai's ModelSettings.thinking.

Công cụ

Theo mặc định, agent đĩa không có công cụ nào (inherit_tools là False); đặt inherit_tools=True để cho các công cụ của cha mẹ tiếp cận với nó thông qua inherit_tools cơ chế, trong trường hợp đó tools vấn đề phía trước bị bỏ qua. Thay vào đó, để ánh xạ tên công cụ frontmatter tới các bộ công cụ cụ thể, hãy chuyển một tool_resolver: nó nhận từng tên công cụ (vì vậy nó có thể tôn trọng các mục như Bash(git:*)) và trả về các bộ công cụ cung cấp nó, hoặc None đối với một tên không xác định, tên này sẽ bị bỏ qua kèm theo một cảnh báo.

from pydantic_ai_harness import SubAgents

def resolve(tool_name: str):
    return TOOLSETS.get(tool_name)  # -> Sequence[AgentToolset[object]] | None

SubAgents(agent_folders='agents', tool_resolver=resolve)

Ưu tiên

Khi cùng một tên xuất hiện trong nhiều nguồn, tên nào có mức độ ưu tiên cao hơn sẽ thắng và những tên khác bị bỏ qua kèm theo cảnh báo: đã được thông qua một cách rõ ràng agents đầu tiên, sau đó là thư mục dự án, sau đó là thư mục chính (và, đối với một chuỗi đường dẫn rõ ràng, các đường dẫn trước đó trước các đường dẫn sau). Tên trùng lặp trong phạm vi được thông qua rõ ràng agents danh sách vẫn bị lỗi.

Cấu hình

SubAgents(
    agents=(),             # Sequence[SubAgent[AgentDepsT]] -- each pairs an agent with its run controls
    models={},             # Mapping[str, Model | str | ModelOption] -- per-delegation model menu (off when empty)
    agent_folders='agents',# folder-name str (convention) | Sequence[Path] | None (disable)
    agent_overrides={},    # Mapping[str, AgentOverride] -- per-disk-agent model/effort override
    tool_resolver=None,    # Callable[[str], Sequence[AgentToolset[object]] | None] -- disk-agent tool mapping
    forward_usage=True,    # share the parent's usage with sub-agent runs
    inherit_tools=False,   # expose the parent's own tools to sub-agents (capability tools excluded)
    shared_capabilities=(),# capabilities applied to every sub-agent run
    event_stream_handler=None,  # forwarded to each sub-agent run to stream its events
    tool_name='delegate_task',
    tool_retries=2,        # extra delegate-tool attempts after a sub-agent error before aborting (None inherits the agent default)
    contain_errors=False,  # default for SubAgent.contain_errors: contain an unexpected crash as a bounded retry
)
SubAgent(
    agent,                 # AbstractAgent[AgentDepsT, Any] -- the child agent to run
    name=None,             # delegate name; defaults to the agent's own `name`
    description=None,      # prompt-listing description; defaults to the agent's own `description`
    models=None,           # Sequence[str] -- menu keys this delegate may run on; the first is its default
    usage_limits=None,     # per-delegation request/token budget (isolated accounting)
    timeout_seconds=None,  # per-delegation wall-clock budget
    max_calls=None,        # max delegations to this sub-agent per parent run
    on_failure=None,       # steering message for soft degradations of this delegate
    contain_errors=None,   # contain an unexpected crash as a bounded retry; None inherits the SubAgents default
)

SubAgents không thể tuần tự hóa thông qua thông số agent (nó vẫn tồn tại Agent trường hợp), vì vậy get_serialization_name() trả lại None.

Ghi chú

  • agent phụ có thể tự mình có SubAgents, tạo thành cây Chia sẻ usage (mặc định) và đặt usage_limits ở cấp cao nhất để ràng buộc toàn bộ cây.
  • Phân quyền các vấn đề của mô hình chạy song song dưới dạng subagent độc lập chạy.

Đọc thêm

Tham chiếu API

::: pydantic_ai_harness.subagents.SubAgents

::: pydantic_ai_harness.subagents.SubAgent

::: pydantic_ai_harness.subagents.ModelOption

::: pydantic_ai_harness.subagents.AgentOverride

Mục lục nguồn