Harness Academy
Tài liệu gốc 22 10 phútTiếng Việt + English
docs/tool-output-limits.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.

Giới hạn đầu ra của công cụ

ToolOutputLimits giảm output của tool đủ lớn để chiếm ưu thế trong bối cảnh cửa sổ. Công cụ trả về vẫn tồn tại trong lịch sử như ToolReturnParts, nên một cái quá khổ sẽ được gửi lại cho mỗi yêu cầu mô hình sau này, thanh toán chi phí token cho phần còn lại của quá trình chạy. Khả năng này chặn trả lại khi nó được tạo ra, giảm nó một lần và để dạng rút gọn tồn tại -- mức giảm không được tính toán lại theo yêu cầu.

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 công cụ có thể trả về một tải trọng đủ lớn để thống trị cửa sổ ngữ cảnh: một tệp lớn được đọc, một nhật ký dài dòng, một tài liệu JSON lớn. Bởi vì việc trả lại dụng cụ vẫn tồn tại trong lịch sử, một khoản trả lại có kích thước quá lớn được gửi lại theo mọi yêu cầu mô hình sau này, thanh toán chi phí token cho phần còn lại của quá trình chạy.

Đây là phần tiếp theo tràn vào tệp nén tên khả năng là hết về phạm vi: nó di chuyển các đầu ra công cụ lớn ra khỏi cửa sổ tại thời điểm sản xuất, thay vì nén hoặc thả bối cảnh đã có bên trong nó.

Ba chế độ

Chế độChi phíMất mát?model nhận được gì
Truncatekhông-LLMvângKẹp đầu/đuôi/đầu+đuôi của văn bản
Spillkhông-LLMkhôngMột tay cầm + xem trước + phác thảo hình dạng; đọc lại toàn bộ tải trọng theo yêu cầu
Summarizemột cuộc gọi LLMvângBản tóm tắt có giới hạn kích thước (kế thừa mô hình của lần chạy theo mặc định)

Spill không mất dữ liệu: toàn bộ tải trọng được giữ nguyên và mô hình đọc các phần của nó qua đã đăng ký read_tool_result(handle, offset, limit, from_end, pattern) công cụ (Claude Mẫu mã, lõi #4352 thiết kế). Công cụ đó bị giới hạn: offset >= 0, limit được kẹp vào nắp đường dây tích hợp, đầu ra được nối giới hạn, và pattern là một chuỗi con theo nghĩa đen (không phải biểu thức chính quy), vì vậy giá trị do mô hình cung cấp không thể treo cổ máy chủ bằng cách quay lại thảm khốc.

Cách sử dụng

Xây dựng một Agent với ToolOutputLimits() trong nó capabilities. Không có đối số nó sử dụng dải mặc định: trả về từ 10.000 ký tự trở lên, có giới hạn cắt ngắn dự phòng nếu cửa hàng không thể chấp nhận ghi.

from pydantic_ai import Agent
from pydantic_ai_harness import ToolOutputLimits

agent = Agent('openai:gpt-4o', capabilities=[ToolOutputLimits()])

Khả năng đăng ký một read_tool_result công cụ để mô hình có thể quay lại trang bất kỳ tải trọng bị đổ. Lợi nhuận của chính nó được miễn giảm.

Ban nhạc: kết hợp các chế độ

Định cấu hình danh sách kích thước theo thứ tự bands. Mỗi ban nhạc là một (over, action) cặp: khi một kích thước đo được của lợi nhuận đạt tới over, hành động của nó chạy. Dải có ngưỡng lớn nhất phù hợp sẽ thắng; bất cứ điều gì dưới ngưỡng nhỏ nhất đều đi qua.

from pydantic_ai import Agent
from pydantic_ai_harness import ToolOutputLimits
from pydantic_ai_harness.tool_output_limits import Band, Spill, Summarize, Truncate

agent = Agent(
    'openai:gpt-4o',
    capabilities=[
        ToolOutputLimits(
            bands=[
                Band(over=100_000, action=Spill()),      # huge: keep losslessly, read back on demand
                Band(over=20_000, action=Summarize()),    # large: compress with the run's model
                Band(over=5_000, action=Truncate()),      # medium: cheap clamp
            ],
            # below 5,000: passthrough
        )
    ],
)

Dải mặc định, khi bạn vượt qua không bands, là Spill(then=Truncate()) ở mức 10.000 ký tự ngưỡng: không mất dữ liệu khi cửa hàng chấp nhận ghi, nếu không thì cắt ngắn có giới hạn -- không LLM chi phí và không có sự sụt giảm im lặng.

Passthrough() là một hành động không hoạt động rõ ràng đối với bands hoặc per_tool danh sách, để lại kết quả phù hợp trở về nguyên vẹn.

Dự phòng với then

Mỗi hành động đều có một tùy chọn then, được áp dụng khi hành động không thể chạy: a Spill của ai lỗi lưu trữ, một Truncate / Summarize trên một tải trọng nhị phân, một Summarize cuộc gọi model của ai tăng lên. then dây chuyền, vì vậy Summarize(then=Spill(then=Truncate())) tóm tắt suy thoái -> tràn -> cắt ngắn.

Ghi đè và lọc theo từng công cụ

per_tool thay thế danh sách băng tần chung cho các công cụ được đặt tên (tệp được đọc thành head, đăng nhập vào tail); tool_filter (a ToolSelector) phạm vi những công cụ mà khả năng đó chạm tới.

from pydantic_ai import Agent
from pydantic_ai_harness import ToolOutputLimits
from pydantic_ai_harness.tool_output_limits import Band, Truncate, TruncationStrategy

agent = Agent(
    'openai:gpt-4o',
    capabilities=[
        ToolOutputLimits(
            per_tool={
                'read_file': [Band(over=8_000, action=Truncate(strategy=TruncationStrategy.head))],
                'run_shell': [Band(over=8_000, action=Truncate(strategy=TruncationStrategy.tail))],
            },
            tool_filter=['read_file', 'run_shell', 'search'],
        )
    ],
)

TruncationStrategy có ba thành viên: head (giữ các ký tự đầu tiên, tốt cho tiêu đề và lược đồ), tail (giữ các ký tự cuối cùng, tốt cho việc xây dựng và kiểm tra đầu ra khi có lỗi xảy ra cuối cùng) và head_tail (giữ cả hai đầu, bỏ bớt ở giữa - mặc định).

Cả hai return_value và content được giảm

A ToolReturn mang theo một return_value và một tùy chọn content lõi đó biểu hiện dưới dạng phần riêng biệt, có thể nhìn thấy được bằng mô hình và vẫn tồn tại trong lịch sử. Khả năng này đo lường và giảm cả hai với cùng một logic băng tần (chúng tràn vào các tay cầm riêng biệt). văn bản content là giảm tại chỗ; phi văn bản content (các phần đa phương thức) tràn ra không được giảm bớt với một warnings.warn, vì nó không thể được cắt bớt một cách an toàn.

Đơn vị kích thước

Ngưỡng được đo bằng ký tự theo mặc định. Đặt over_tokens=True để đo lường token ước tính (cùng phương pháp phỏng đoán ~4 ký tự cho mỗi token như nén); vượt qua một tokenizer có thể gọi được cho chính xác. Truncate.max_chars luôn là các ký tự -- việc cắt bớt là một hoạt động ký tự bất kể đơn vị ngưỡng. Đặt strip_ansi=True để loại bỏ ANSI chuỗi thoát khỏi văn bản trả về trước khi đo và giảm.

Sự cố tràn có cấu trúc có thể phân trang

Trả về có cấu trúc tràn được lưu trữ dưới dạng JSON nhỏ gọn: một dòng dài. read_tool_result trang theo dòng, do đó trang 1 trả về toàn bộ tải trọng và trang 2 trống. Cài đặt serializer thay vào đó, lưu trữ giá trị trong bố cục bằng các dòng thực:

from pydantic_ai_harness.tool_output_limits import ToolOutputLimits, indented_json, json_lines

ToolOutputLimits(serializer=indented_json)  # one field per line
ToolOutputLimits(serializer=json_lines)  # one record per line

sử dụng json_lines đối với các công cụ trả về danh sách bản ghi: dòng N là bản ghi N, do đó độ lệch trang và pattern các trận đấu xếp hàng với toàn bộ hồ sơ. Bất kỳ thứ gì không phải là một chuỗi giống như danh sách rơi trở lại indented_json -- bao gồm một danh sách được bao bọc trong một lệnh, vì vậy hãy trả về danh sách trực tiếp cho việc phân trang trên mỗi bản ghi. sử dụng indented_json cho mọi thứ khác.

bất kỳ (value) -> str có thể gọi được cũng hoạt động, nhưng thích các giá trị đặt trước hơn: chúng thoát khỏi Unicode dấu phân cách dòng (U+0085/U+2028/U+2029), nếu không sẽ loại bỏ các khoảng lệch đọc lại khỏi lưới đường. Văn bản được tuần tự hóa cũng là nội dung được đo lường, vì vậy bố cục thụt lề có thể vượt qua một dải kích thước mà JSON nhỏ gọn sẽ không làm được. Chuỗi và trả về nhị phân không bao giờ được tuần tự hóa, trở về dưới mức băng tần nhỏ nhất mà không bị ảnh hưởng và bộ nối tiếp tăng hoặc giảm trả về các cảnh báo không phải văn bản và quay lại JSON nhỏ gọn thay vì làm mất đầu ra của công cụ.

Cửa hàng tràn

Trọng tải tràn đi qua khe hẹp OverflowStore giao thức. Mặc định LocalFileStore ghi một tập tin mỗi (run_id, tool_call_id, retry) dưới một thư mục gốc ổn định và giữ nó sau khi chạy, nên sau đó read_tool_result -- trong lần chạy này hoặc agent/lần chạy tiếp theo -- có thể vẫn đạt được nó. Tay cầm có thể định địa chỉ phụ trợ (khóa tương đối), không phải cục bộ tuyệt đối đường dẫn, do đó, một chương trình phụ trợ bền vững (Tạm thời, cửa hàng blob hoặc lõi ExecutionEnvironment không gian làm việc khi #4352 xuất hiện) có thể giải quyết cùng một cách xử lý trong một quy trình khác. Cung cấp của riêng bạn phụ trợ với store=....

from typing import Protocol


class OverflowStore(Protocol):
    async def write(self, key: str, data: bytes) -> str: ...   # returns a handle
    async def read(self, handle: str) -> bytes: ...

Mô hình bảo mật (root chung, không cách ly)

Thư mục gốc của cửa hàng ổn định và có thể chia sẻ theo mục đích -- các tập tin bị tràn phải có thể đọc được sau này. agent hoặc chạy -- vì vậy bảo mật không đến từ sự cô lập theo từng phiên bản. Nó xuất phát từ hai cơ chế: root được tạo bằng 0700 quyền (chỉ dành cho chủ sở hữu) và read giải quyết target (theo các liên kết tượng trưng) và từ chối mọi thứ thoát khỏi gốc thông qua liên kết tượng trưng, ​​ ..hoặc một đường dẫn tuyệt đối Các đoạn tay cầm cũng được vệ sinh để tay cầm được chế tạo thủ công không thể đi ra ngoài.

Dọn dẹp: giữ mãi mãi theo mặc định, chọn tham gia cắt tỉa TTL

Theo mặc định, cửa hàng sẽ giữ các tập tin bị tràn vĩnh viễn -- việc xóa khi kết thúc quá trình sẽ bị hỏng sau đó agent vẫn muốn đọc thông tin tràn. Để giới hạn việc sử dụng đĩa, hãy chọn tham gia cắt bớt theo độ tuổi:

from datetime import timedelta

from pydantic_ai import Agent
from pydantic_ai_harness import ToolOutputLimits
from pydantic_ai_harness.tool_output_limits import LocalFileStore

store = LocalFileStore(cleanup_after=timedelta(hours=6))  # default: None = keep forever
agent = Agent('openai:gpt-4o', capabilities=[ToolOutputLimits(store=store)])

Khi được thiết lập, một write lên lịch cắt tỉa nền (một luồng daemon, ngoài đường dẫn nóng) xóa các tập tin có thời gian sửa đổi (st_mtime) cũ hơn cleanup_after. Cắt tỉa là không chặn và không có lỗi: mọi lỗi đều được phát hiện và hiển thị thông qua warnings.warn, không bao giờ được truyền vào quá trình chạy agent, do đó việc dọn dẹp không bao giờ có thể khiến quá trình chạy bị lỗi hoặc chặn đường dẫn nóng. Thời gian đọc lần cuối (st_atime) không đáng tin cậy trên noatime/relatime gắn kết và không được sử dụng.

Thích dọn dẹp bên ngoài (cron, trình quét) hơn TTL đang xử lý? Trỏ nó vào thư mục gốc của cửa hàng và xóa theo mtime:

import time
from pathlib import Path

root = Path('/tmp/pyai_harness_overflow')  # or your configured base_dir
cutoff = time.time() - 6 * 3600
for path in root.rglob('*'):
    if path.is_file() and path.stat().st_mtime < cutoff:
        path.unlink(missing_ok=True)

Kế toán sử dụng

Tích hợp sẵn Summarize cuộc gọi là một yêu cầu thực sự đối với mô hình, vì vậy việc sử dụng đầy đủ -- token và tự yêu cầu -- xếp vào phần chạy ctx.usage, giống hệt SummarizingCompaction. Nó lồng nhau run nhận được giới hạn gốc không thay đổi ngoại trừ giới hạn yêu cầu hữu hạn dành một yêu cầu cho yêu cầu cha mẹ đang chờ xử lý.

Theo mặc định Summarize kế thừa mô hình của agent đang chạy (ctx.model). Truyền id mẫu hoặc ví dụ để Summarize(model=...) để ghi đè hoặc summarize có thể gọi để bỏ qua lời nhắc tích hợp hoàn toàn. các summary_prompt mẫu về khả năng phải chứa cả hai {tool_name} và {output} giữ chỗ.

Vỏ cạnh

  • Trả về nhị phân đúng nguyên văn và không bao giờ bị cắt ngắn theo chuỗi; Truncate / Summarize trên hệ nhị phân rơi vào then.
  • Trả về có cấu trúc/lồng nhau tràn (hoặc tóm tắt) theo sở thích -- việc cắt bớt JSON sẽ tạo ra JSON không hợp lệ. Spill bao gồm một bản phác thảo hình dạng một dòng ở cấp cao nhất.
  • ModelRetry và lỗi công cụ không bao giờ chạm tới móc này (chúng được nâng lên chứ không được trả về), do đó mô hình luôn nhận được toàn bộ lỗi cần khắc phục.
  • Một cái lớn ToolReturn.content được giảm với các dải tương tự như return_value; phi văn bản nội dung tràn sẽ không bị giảm kèm theo cảnh báo.
  • Nhiều khoản trả về quá khổ trong một bước có các thẻ điều khiển riêng biệt (được khóa cho mỗi tool_call_id); lần thử lại cũng nhận được các thẻ điều khiển riêng biệt (được khóa cho mỗi retry), do đó cuộc gọi được thử lại không bao giờ làm tắc nghẽn sự cố tràn trước đó.

Mối quan hệ với các khả năng khác

  • Khác biệt với nén, nén hoặc bỏ ngữ cảnh đã có bên trong cửa sổ; khả năng này di chuyển các đầu ra công cụ lớn ra khỏi cửa sổ tại thời điểm sản xuất.
  • Tiêu thụ lõi #4352 (kinh điển nguyên thủy của tệp có thể truy vấn) thông qua OverflowStore đường may một khi nó hạ cánh.
  • Phân biệt với ClampOversizedMessages, kẹp các phản hồi của mô hình chạy trốn, không phải công cụ trở lại.

Tham chiếu API

::: pydantic_ai_harness.tool_output_limits.ToolOutputLimits

Mục lục nguồn