docs/tool-output-limits.mdXem bản gốc 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.
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ì |
|---|---|---|---|
Truncate | không-LLM | vâng | Kẹp đầu/đuôi/đầu+đuôi của văn bản |
Spill | không-LLM | không | Mộ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 |
Summarize | một cuộc gọi LLM | vâng | Bả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/Summarizetrên hệ nhị phân rơi vàothen. - 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ệ.
Spillbao gồm một bản phác thảo hình dạng một dòng ở cấp cao nhất. ModelRetryvà 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ỗiretry), 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