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

Truyền thông bên ngoài

Cuộc trò chuyện mang hình ảnh, âm thanh hoặc các nội dung khác BinaryContent nội tuyến các byte đó vào mỗi tin nhắn và một phần văn bản lớn (chẳng hạn như một chuỗi trả về công cụ lớn) cũng nặng như vậy. Duy trì lịch sử đó và mỗi ảnh chụp nhanh sẽ tuần tự hóa lại các tải trọng; cùng một hình ảnh được tham chiếu bởi mười tin nhắn là mười bản sao của byte. Việc ngoại hóa phương tiện giải quyết vấn đề đó: các cửa hàng có địa chỉ nội dung ghi mỗi tải trọng một lần, được khóa bằng hàm băm của chính nó và để lại một đoạn ngắn media+sha256:// URI ở vị trí của nó. Hãy tiếp cận nó bất cứ khi nào tải trọng văn bản hoặc nhị phân lớn sẽ làm nổi bật những gì bạn lưu trữ hoặc gửi.

!!! lưu ý "Đường dẫn nhập" Nhập những trình trợ giúp này từ mô-đun con của chúng -- không có cấp độ cao nhất pydantic_ai_harness tái xuất:

```python
from pydantic_ai_harness.media import (
    DiskMediaStore,
    S3MediaStore,
    SqliteMediaStore,
    externalize_media,
    restore_media,
)
```

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.

Khối xây dựng, không phải là khả năng

Đây là những khối xây dựng. Không có lớp nào bạn thêm vào Agent(capabilities=[...]) chưa. StepPersistence đã sử dụng chúng để giữ cho ảnh chụp nhanh nhỏ khi có tin nhắn mang theo BinaryContent hoặc văn bản lớn (ví dụ: chuỗi trả về công cụ lớn) và sắp tới MediaExternalizer khả năng (#254) sẽ sử dụng lại các cửa hàng tương tự để viết lại BinaryContent vào các phần URL trước khi mô hình nhìn thấy chúng.

Tại sao phải định địa chỉ nội dung

URI được lấy từ hàm băm tải trọng, do đó các byte giống hệt nhau sẽ tự động được loại bỏ trùng lặp. Các byte giống nhau được lưu trữ một lần cho dù có bao nhiêu thông báo hoặc ảnh chụp nhanh tham chiếu đến chúng và việc di chuyển bộ nhớ cơ bản là thao tác hoán đổi một dòng vì URI không thay đổi.

Cửa hàng

Mỗi cửa hàng đều thực hiện MediaStore giao thức -- put, get, exists, public_urlvà get_metadata, tất cả đều không đồng bộ và có địa chỉ nội dung.

Cửa hàngĐược hỗ trợ bởiSử dụng khi
DiskMediaStore(directory=...)Một thư mục trên đĩaChạy và kiểm tra cục bộ
SqliteMediaStore(database=...)Cơ sở dữ liệu SQLiteMột repository một tệp di chuyển cùng với dữ liệu
S3MediaStore(bucket=, endpoint=, region=, ...)S3 hoặc bộ chứa tương thích với S3Lưu trữ chia sẻ hoặc sản xuất
MongoMediaStore(client= or db_url=, database=, ...)MongoDB (phân đoạn thủ công theo địa chỉ sha256)Triển khai MongoDB; các đốm màu lớn hơn một tài liệu BSON

S3MediaStore sử dụng các URL kiểu đường dẫn cộng với SigV4 được quản lý bằng tay, do đó nó tương thích với AWS S3, Cloudflare R2 (region='auto'), MinIO và các nhà cung cấp tương thích với S3 khác. SqliteMediaStore cũng chấp nhận connection= thay vì database= để chia sẻ một sqlite3.Connection.

MongoMediaStore cần mongodb thêm (pip install pydantic-ai-harness[mongodb], cài đặt nào pymongo>=4.17.0). Vượt qua một chia sẻ AsyncMongoClient như client=hoặc một chuỗi kết nối như db_url= (khi đó cửa hàng sẽ sở hữu khách hàng -- hãy gọi await store.aclose() để phát hành nó); database= luôn luôn được yêu cầu. Mỗi đốm màu được lưu trữ dưới dạng các khối có địa chỉ sha256 trong một media_chunks bộ sưu tập, với một media tài liệu kê khai trên mỗi đốm màu (_id = <digest>). Phân đoạn giới hạn từng tài liệu BSON, do đó, một blob lớn hơn giới hạn tài liệu 16 MiB của MongoDB vẫn lưu trữ và đọc lại. Nó không ràng buộc bộ nhớ: put lấy toàn bộ tải trọng như bytes và get tập hợp lại từng đoạn thành một bytearray, do đó, một blob phải vừa với bộ nhớ xử lý theo cả hai hướng -- không có API phát trực tuyến. Bản kê khai giữ MediaContext.metadata nội tuyến và không bị phân đoạn, vì vậy hãy giữ siêu dữ liệu trên mỗi blob ở mức nhỏ. Việc phân chia thủ công được sử dụng thay vì trình điều khiển GridFS nhằm mục đích: thông báo là bảng kê khai _id, do đó các byte giống hệt nhau sẽ được loại bỏ trùng lặp (các tệp khóa GridFS bằng ObjectId và không khấu trừ) và bề mặt bộ sưu tập đơn giản vẫn hoàn toàn có thể kiểm tra được trong bộ nhớ.

Hai nút xây dựng định hình bố cục đó. collection= (mặc định 'media') đặt tên cho bộ sưu tập bảng kê khai và lấy bộ sưu tập chunk là <collection>_chunks; tên bên ngoài [A-Za-z_][A-Za-z0-9_]* bị từ chối. chunk_size_bytes= (mặc định 8 MiB) đặt kích thước phân chia và bị từ chối dưới 1 byte hoặc trên 16 MiB trừ đi 64 KiB khoảng trống cho các trường riêng của tài liệu chunk, vì một đoạn lớn hơn sẽ tạo ra một tài liệu mà MongoDB từ chối chèn.

Vào lần đầu tiên put hoặc get, các vấn đề về cửa hàng createIndex cho một hợp chất (files_id, n) lập chỉ mục trên bộ sưu tập chunk, nếu không có việc tập hợp lại sẽ là quét bộ sưu tập. Do đó, người dùng kết nối cần có đặc quyền để tạo chỉ mục -- vai trò Atlas bị hạn chế có thể không có đặc quyền đó -- và việc trỏ cửa hàng vào một bộ sưu tập đã được điền sẵn sẽ trả tiền cho việc xây dựng chỉ mục trong lệnh gọi đầu tiên đó.

from pymongo import AsyncMongoClient

from pydantic_ai_harness.media import MongoMediaStore

client = AsyncMongoClient('mongodb://localhost:27017')
store = MongoMediaStore(client=client, database='agent_media')

Người trợ giúp đi bộ

externalize_media và restore_media đi qua nút tin nhắn và trao đổi tải trọng cho URI và ngược lại:

from pydantic_ai_harness.media import DiskMediaStore, externalize_media, restore_media

store = DiskMediaStore(directory='./media')

# Replace binary and text payloads at or above the threshold with media+sha256:// URIs.
lean = await externalize_media(message, media_store=store, threshold_bytes=32_000)

# Later, rehydrate the URIs back into the original parts.
full = await restore_media(lean, media_store=store)

externalize_media bên ngoài cả lớn BinaryContent và văn bản lớn: bất kỳ phần tin nhắn nào có chuỗi content đạt tới threshold_bytes byte UTF-8 (TextPart, ThinkingPart, một chuỗi trả về ToolReturnPart, một chuỗi có giá trị UserPromptPart), cộng với bất kỳ TextContent phần tử di chuyển bên trong một UserPromptPart.content trình tự hoặc một ToolReturn. giống nhau threshold_bytes quản lý hệ nhị phân và văn bản, đồng thời các tải trọng bên dưới nó vẫn nằm trong dòng. Chuyến đi khứ hồi minh bạch -- restore_media sắp xếp lại các byte nhị phân và văn bản một cách đối xứng. Nếu bạn cần tự mình khóa phương tiện, media_uri_for và parse_media_uri cung cấp cho bạn chuyến đi khứ hồi URI thô.

Trình đọc hiện tại khôi phục các dấu nhị phân được viết trước khi hiển thị văn bản. Khả năng tương thích đó chỉ dành cho bản nâng cấp: một bản phát hành có trước quá trình ngoại hóa văn bản sẽ coi mọi điểm đánh dấu là nhị phân, do đó, nó không thể xác thực ảnh chụp nhanh có chứa điểm đánh dấu văn bản bên ngoài. Giữ một trình đọc hiện tại để biết các ảnh chụp nhanh liên tục có chứa các điểm đánh dấu đó.

URL công khai

Khi cửa hàng có CDN, máy chủ HTTP cục bộ hoặc dịch vụ URL đã ký, hãy chuyển public_url= trình giải quyết (hoặc sử dụng make_static_public_url) để biến một lưu trữ media+sha256:// URI thành URL mà mô hình có thể tìm nạp trực tiếp. Không có người giải quyết, public_url(...) trả lại None.

URL cơ sở tĩnh, dành cho nhóm công khai hoặc CDN:

from pydantic_ai_harness.media import S3MediaStore, make_static_public_url

store = S3MediaStore(
    bucket='my-bucket',
    endpoint='https://<acc>.r2.cloudflarestorage.com',
    region='auto',
    access_key_id=..., secret_access_key=...,
    key_prefix='media/',
    public_url=make_static_public_url('https://pub-abc.r2.dev', key_prefix='media/'),
)

URL có chữ ký luân phiên hoặc được chỉ định -- chuyển bất kỳ lệnh gọi không đồng bộ nào cần (uri, MediaContext):

from pydantic_ai_harness.media import MediaContext, S3MediaStore


async def presign(uri: str, ctx: MediaContext) -> str:
    key = 'media/' + uri.removeprefix('media+sha256://') + '.bin'
    return await my_signer.generate(key, ttl=3600, content_type=ctx.media_type)


store = S3MediaStore(..., public_url=presign)

Đây là điều sắp tới MediaExternalizer sẽ sử dụng để trao đổi BinaryContent các bộ phận cho ImageUrl / AudioUrl / các phần URL khác trước khi mô hình nhìn thấy thông báo, cho phép nhà cung cấp tìm nạp phương tiện lớn qua mạng mà không cần mã hóa lại byte vào nội dung yêu cầu. Việc phát ra URL luôn an toàn: các nhà cung cấp pydantic-ai tải xuống các byte một cách minh bạch khi mô hình mục tiêu về cơ bản không chấp nhận loại URL đó, do đó bạn chỉ mất khoản tiết kiệm dây chứ không bao giờ chính xác.

MediaContext

Mọi phương thức lưu trữ và cả các lệnh gọi do người dùng cung cấp (PublicUrlResolver, KeyStrategy) chấp nhận một MediaContext -- một túi có thể mở rộng cho mỗi lần phẫu thuật:

from collections.abc import Mapping
from dataclasses import dataclass, field


@dataclass(frozen=True, kw_only=True)
class MediaContext:
    media_type: str | None = None                    # e.g. 'image/png'
    filename: str | None = None                      # original filename, when known
    metadata: Mapping[str, str] = field(default_factory=dict)  # user-supplied tags

Tất cả các trường đều mặc định, vì vậy bạn chuyển những gì bạn có và bỏ qua phần còn lại; các trường mới được thêm vào liên tục khi các trường hợp sử dụng xuất hiện. get_metadata(uri) chuyến đi khứ hồi do người dùng cung cấp metadata lập bản đồ trên cả bốn cửa hàng; media_type được duy trì riêng biệt (dưới dạng tải trọng byte Content-Type).

KeyStrategy

Bố cục khóa trên cửa hàng mặc định là <sha256>.bin. DiskMediaStore và S3MediaStore chấp nhận một key_strategy= ghi đè để phù hợp với bố cục hiện có. SqliteMediaStore và MongoMediaStore thì không, vì bản tóm tắt là khóa chính của họ -- hãy sử dụng table= / collection= để di chuyển các hàng hoặc tài liệu thay thế:

from pydantic_ai_harness.media import DiskMediaStore, MediaContext


def by_media_type(uri: str, ctx: MediaContext) -> str:
    digest = uri.removeprefix('media+sha256://')
    ext = {'image/png': '.png', 'image/jpeg': '.jpg'}.get(ctx.media_type or '', '.bin')
    return f'images/{digest}{ext}'


store = DiskMediaStore('runs', key_strategy=by_media_type)

Nếu chiến lược của bạn phụ thuộc vào ctx.media_type, ngữ cảnh tương tự phải được cung cấp tại thời điểm đọc cho get/exists để tìm đốm màu. DiskMediaStore từ chối các chiến lược tạo ra đường dẫn tuyệt đối hoặc .. phân đoạn, để giữ ghi bên trong thư mục cửa hàng. default_key_strategy được xuất nếu bạn muốn xây dựng trên đó.

API

Biểu tượngMục đích
MediaStoreGiao thức lưu trữ địa chỉ nội dung không đồng bộ (put / get / exists / public_url / get_metadata)
DiskMediaStore, SqliteMediaStore, S3MediaStore, MongoMediaStoreCửa hàng bê tông (MongoMediaStore cần mongodb thêm)
MediaContextNgữ cảnh của mỗi hoạt động (loại phương tiện, tên tệp, thẻ) được xâu chuỗi qua các hoạt động của cửa hàng
KeyStrategy, default_key_strategyBố trí chìa khóa tại cửa hàng
PublicUrlResolver, make_static_public_urlGiải quyết URI được lưu trữ thành URL công khai
externalize_media, restore_mediaĐi qua nút tin nhắn để ngoại hóa / bù nước cho tải trọng văn bản và nhị phân lớn
media_uri_for, parse_media_uriTính toán và phân tích một media+sha256:// URI

Nguồn: pydantic_ai_harness/media/.

Liên quan

  • Bền bỉ từng bước -- người tiêu dùng đầu tiên của các cửa hàng này, tiếp cận các khách hàng lớn BinaryContent và các phần văn bản trong ảnh chụp nhanh đang chạy.
Mục lục nguồn