docs/code-mode.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.
Chế độ mã
CodeMode thay thế các lệnh gọi công cụ riêng lẻ bằng một môi trường thực thi Python có hộp cát duy nhất. Thay vì mô hình đưa ra một lệnh gọi công cụ cho mỗi hành động, mô hình này viết một chương trình Python gọi các công cụ của bạn dưới dạng hàm -- với các vòng lặp, điều kiện, biến và asyncio.gather -- tất cả đều nằm trong Monty được đóng hộp cát runtime.
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 đề
Việc gọi công cụ tiêu chuẩn thường cần một lượt mô hình khác cho từng đợt gọi công cụ phụ thuộc. Một agent cần tìm nạp 10 mục rồi xử lý kết quả của chúng có thể yêu cầu nhiều lượt mô hình, làm tăng độ trễ, chi phí và sử dụng ngữ cảnh. Kết quả trung gian cũng phát triển lịch sử hội thoại.
Giải pháp
CodeMode gói các công cụ đủ điều kiện thành một run_code công cụ. model viết mã điều phối hộp cát mà người hâm mộ gọi bằng asyncio.gather, lọc và chuyển đổi kết quả, đồng thời chỉ trả về những gì quan trọng. Các cuộc gọi từ mã đó được gửi thông qua Pydantic AI đến các công cụ máy chủ.
| Gọi công cụ chuẩn | Chế độ mã |
|---|---|
| Lô công cụ phụ thuộc trên các vòng quay mô hình | Nhiều cuộc gọi phụ thuộc trong một run_code |
| Chỉ song song khi mô hình phát ra một đợt | Tính song song được thể hiện bằng Python |
| Không tính toán cục bộ | Lọc, chuyển đổi, tổng hợp trong mã |
| Lịch sử hội thoại lớn | Nhỏ gọn -- ít tin nhắn hơn |
Tích hợp thực thi lâu dài có thể ghi lại các cuộc gọi lồng nhau để phát lại xác định.
Cài đặt
Chế độ mã yêu cầu hộp cát Monty, có sẵn thông qua codemode thêm (các code-mode extra là bí danh tương đương):
uv add "pydantic-ai-harness[codemode]"
Cách sử dụng
Xây dựng một Agent với CodeMode() trong nó capabilities, sau đó đăng ký công cụ như bình thường. Mọi công cụ thông thường đủ điều kiện đều có thể gọi được từ bên trong run_code:
from pydantic_ai import Agent
from pydantic_ai_harness import CodeMode
agent = Agent('anthropic:claude-sonnet-4-6', capabilities=[CodeMode()])
@agent.tool_plain
def get_weather(city: str) -> dict:
"""Get current weather for a city."""
return {'city': city, 'temp_f': 72, 'condition': 'sunny'}
result = agent.run_sync("What's the weather in Paris and Tokyo, in Celsius?")
print(result.output)
Bên trong một chiếc run_code gọi, mô hình sẽ viết mã như sau (minh họa -- mã chính xác mà mô hình phát ra sẽ khác nhau):
import asyncio
paris, tokyo = await asyncio.gather(
get_weather(city='Paris'),
get_weather(city='Tokyo'),
)
paris_c = round((paris['temp_f'] - 32) * 5 / 9, 1)
tokyo_c = round((tokyo['temp_f'] - 32) * 5 / 9, 1)
{'paris': paris_c, 'tokyo': tokyo_c}
Cả hai quá trình tra cứu thời tiết đều chạy song song và các quá trình chuyển đổi diễn ra bên trong Monty, tất cả đều nằm trong một run_code gọi.
Hộp cát công cụ chọn lọc
Theo mặc định, CodeMode(tools='all') hộp cát mọi công cụ thông thường đủ điều kiện. Các công cụ kiểm soát khung, công cụ trì hoãn chưa được khám phá, dự phòng gốc và các công cụ thực thi mã khác vẫn là công cụ gốc. Bề mặt vỏ được tính là công cụ thực thi mã: Shell's run_command và start_commandvà ModalSandbox's run_command, ngồi cạnh run_code thay vì bên trong nó, vì vậy mô hình không bao giờ phải trích dẫn lệnh shell bên trong chuỗi Python được tạo. CapabilityCreation's author_capability vẫn nguyên gốc vì lý do tương tự: đối số của nó là một mô-đun Python hoàn chỉnh. Công cụ phi lệnh của họ (read_file, check_command, v.v.) được gấp lại thành run_code giống như bất kỳ công cụ nào khác. các tools lĩnh vực này là AI Pydantic ToolSelector, để bạn có thể kiểm soát những công cụ đủ điều kiện nào đi qua hộp cát. Các công cụ phù hợp với bộ chọn sẽ có thể gọi được bên trong run_code; các công cụ không phù hợp vẫn hiển thị với mô hình như các lệnh gọi công cụ thông thường.
from pydantic_ai_harness import CodeMode
# By name -- only these tools are available inside run_code
CodeMode(tools=['search', 'fetch'])
# By predicate -- (ctx, tool_def) -> bool | Awaitable[bool]
CodeMode(tools=lambda ctx, td: td.name != 'dangerous_tool')
# By metadata -- combine with SetToolMetadata or a toolset's .with_metadata()
CodeMode(tools={'code_mode': True})
Lựa chọn dựa trên siêu dữ liệu
Sử dụng siêu dữ liệu khi quyết định phải được thực hiện bằng một công cụ hoặc bộ công cụ, thay vì bằng một công cụ CodeMode ví dụ. Điều này phù hợp với các bộ công cụ được chia sẻ: tác giả bộ công cụ gắn thẻ các công cụ an toàn và hữu ích để gọi từ mã được tạo và mỗi agent chọn tham gia thẻ đó với CodeMode(tools={...}).
CodeMode(tools={'code_mode': True}) sử dụng AI Pydantic tiêu chuẩn ToolSelector dạng siêu dữ liệu. Một công cụ được đóng hộp cát khi nó ToolDefinition.metadata chứa tất cả các cặp khóa-giá trị của bộ chọn. Siêu dữ liệu bổ sung trên công cụ này là ổn và các từ điển lồng nhau được khớp bằng cách đưa vào sâu.
Mẫu phổ biến là gắn thẻ toàn bộ bộ công cụ với .with_metadata(...):
from pydantic_ai import Agent
from pydantic_ai.toolsets import FunctionToolset
from pydantic_ai_harness import CodeMode
def search(query: str) -> str:
"""Search the web."""
return f'results for {query}'
def fetch(url: str) -> str:
"""Fetch a URL."""
return f'contents of {url}'
search_tools = FunctionToolset(tools=[search, fetch]).with_metadata(code_mode=True)
agent = Agent(
'anthropic:claude-sonnet-4-6',
toolsets=[search_tools],
capabilities=[CodeMode(tools={'code_mode': True})],
)
đây search và fetch được xóa khỏi danh sách công cụ đối mặt với mô hình và trở thành các hàm có thể gọi được bên trong run_code. Công cụ không có metadata['code_mode'] == True vẫn hiển thị như các lệnh gọi công cụ thông thường.
Công cụ tương tác Tìm kiếm
Khi bạn đánh dấu các công cụ hoặc toàn bộ bộ công cụ defer_loading=True (Tìm kiếm công cụ), CodeMode giữ họ ra khỏi run_code trong khi chúng chưa được khám phá -- chúng đi thẳng qua, do đó, Công cụ Tìm kiếm sẽ điều khiển chúng như bình thường (được gửi qua đường dây với defer_loading về các nhà cung cấp có tìm kiếm công cụ gốc; mặt khác bị loại bỏ cho đến khi được phát hiện, với một search_tools công cụ bên cạnh run_code). CodeMode công dụng RunContext.is_tool_available tuân theo trạng thái bộc lộ đó. Khi mô hình phát hiện ra một công cụ -- hoặc tải khả năng trì hoãn sở hữu nó -- CodeMode gấp nó thành run_code giống như bất kỳ công cụ nào khác kể từ đó trở đi, vì vậy nó có thể gọi được từ mã được tạo. (Công cụ này giữ defer_loading=True, ghi lại những gì tác giả của nó yêu cầu; những thay đổi là tính sẵn có của nó cho cuộc chạy.)
nếp gấp đó phát triển run_codemô tả của, nó làm mất hiệu lực tiền tố bộ nhớ đệm nhắc nhở một lần tại thời điểm phát hiện (chuyển sang trạng thái không có phát hiện nào, giữ nguyên bộ nhớ đệm ở chế độ ấm). Hai cách để tránh phá sản:
-
Vượt qua
dynamic_catalog=Trueđể giữrun_codemô tả của tĩnh trên các khám phá. Danh mục chữ ký công cụ hộp cát di chuyển vào hướng dẫn agent (dưới dạngInstructionPart) và các công cụ mới được phát hiện được công bố quactx.enqueuethay vì xây dựng lại mô tả:from pydantic_ai_harness import CodeMode CodeMode(dynamic_catalog=True)Điều này mang lại hiệu quả khi kết hợp với Tìm kiếm công cụ: khối định nghĩa công cụ vẫn ổn định theo byte để bộ nhớ đệm tiền tố vẫn tồn tại khi được khám phá, với chi phí là lời nhắc hệ thống lớn hơn (nhưng thân thiện với bộ nhớ đệm). Với bộ công cụ cố định và không có Tìm kiếm công cụ, cài đặt mặc định sẽ giữ cho lời nhắc hệ thống ngắn hơn và là lựa chọn tốt hơn.
-
Thay vào đó, để giữ cho kho dữ liệu Tìm kiếm Công cụ hoàn toàn nguyên bản -- không bao giờ được xếp vào
run_code, nhưng không thể gọi được từ bên trong nó -- loại trừ nó bằng mộttoolsbộ chọn; thành viên tập thể mang theowith_nativeđược đặt thành công cụ gốc quản lý:from pydantic_ai_harness import CodeMode CodeMode(tools=lambda ctx, td: td.with_native is None)
Giá trị trả về
Biểu thức cuối cùng trong đoạn mã được tự động ghi lại dưới dạng giá trị trả về -- mô hình không cần phải print(). Phép gán lưu trữ một giá trị trong REPL nhưng không trả về giá trị đó. Một biểu thức cuối cùng đánh giá None cũng được coi là không có kết quả. Nếu không cóNone biểu thức cuối cùng hoặc đầu ra in, run_code trả lại {}. Đặt tên được chỉ định ở dòng cuối cùng:
result = await get_weather(city='Paris')
result
Dự trữ print() để ghi nhật ký bổ sung: văn bản in được hiển thị riêng biệt, được bao bọc cùng với kết quả biểu thức cuối cùng.
| Kịch bản | Trở về |
|---|---|
KhôngNone biểu thức cuối cùng không có đầu ra in | Giá trị biểu thức cuối cùng |
Nhiệm vụ cuối cùng hoặc None kết quả không có đầu ra in | {} |
In kết quả không có biểu thức cuối cùng hoặc một None kết quả | {'output': '<printed text>'} |
Bản in đầu ra có màu trơn, khôngNone biểu thức cuối cùng | {'output': '<printed text>', 'result': <last expression>} |
| Biểu thức cuối cùng đa phương thức không có đầu ra in | Được trả về nguyên bản để xử lý mô hình |
| In đầu ra với biểu thức cuối cùng đa phương thức | Danh sách có văn bản in theo sau là nội dung đa phương thức gốc |
Đầu ra in được giới hạn ở 10 MiB. Vượt quá giới hạn khiến run_code trả lại một mô hình thử lại.
Việc thực thi hộp cát được giới hạn bởi resource_limits, mặc định là 30 giây thời gian thực hiện
và một đống 256 MiB. Điều này đảm bảo là mức trần cho mỗi đoạn: không có run_code đoạn mã chạy
dài hơn max_duration_secs về thời gian hộp cát, đó là yếu tố ngăn chặn vòng lặp chạy trốn. Thời gian dành
đang chờ một công cụ lồng nhau được loại trừ khỏi bộ đếm thời gian đó.
Đây không phải là ngân sách CPU cho toàn bộ hệ thống và không thể dựa vào đó. Monty áp dụng các giới hạn cho mỗi
phiên sandbox, quá liên tục run_code các cuộc gọi rút ra một khoản trợ cấp chung và mỗi phiên mới
bắt đầu với một cái đầy đủ. Phiên được thay thế bởi restart: true và bởi những thất bại đã thiết lập lại
REPL: lỗi công nhân, lỗi loại, lỗi phía máy chủ và lỗi cú pháp trước khi bất kỳ mã nào chạy.
Mỗi người trong số đó đều gia hạn trợ cấp mà không cần mô hình yêu cầu khởi động lại. Một ngoại lệ thông thường
bên trong một đoạn trích không phải là một trong số đó.
Sau khi sử dụng hết trợ cấp của một phiên, mỗi lần sau run_code cuộc gọi không thành công khi đến nơi, bao gồm cả
các đoạn mã gần như không mất phí vì chúng sử dụng lại cùng một phiên. Viết lại mã
không giúp được gì. restart: true là những gì phục hồi nó, với cái giá phải trả là trạng thái REPL mà phiên đó đã bị
đang giữ, vì vậy mọi biến, nội dung nhập và định nghĩa đều phải được tạo lại. run_code nói nhiều như vậy
trong lần thử lại, nó sẽ trả về và lần thử lại đó cũng báo cáo các lệnh gọi lồng nhau mà đoạn mã đã thực hiện, vì vậy
khởi động lại không loại bỏ bản ghi duy nhất của chúng. Hành vi này đáng được biết khi
lựa chọn max_duration_secs: đặt nó ở mức thấp và một thời gian dài hoạt động agent sẽ tiêu tốn nó vào công việc thông thường và
trả tiền khởi động lại để tiếp tục.
Các lệnh gọi công cụ lồng nhau được giới hạn riêng biệt bởi max_tool_calls, mặc định là 100 mỗi run_code
gọi. Ngân sách được đặt trước trước mỗi cuộc gọi được lên lịch, do đó, một đoạn mã không thể gửi thêm công việc
hơn nó cho phép. Cuộc gọi vượt quá ngân sách không thành công tại trang web cuộc gọi bên trong hộp cát. Một đoạn đó
bắt lỗi, lưu giữ kết quả của các cuộc gọi đã hoàn thành và có thể trả lại chúng. A
đoạn mã cho phép nó lan truyền sẽ thử lại mô hình báo cáo số lượng cuộc gọi lồng nhau đã bắt đầu,
theo sau là chi tiết mỗi cuộc gọi: mỗi cuộc gọi được gọi với mục đích gì và liệu nó có được trả về, tăng lên hay không
bị từ chối. Các cuộc gọi đã đưa ra sẽ được bao gồm thay vì lọc ra vì một công cụ có thể áp dụng thay đổi
trước khi thất bại. Chi tiết đó bị giới hạn -- các đối số và kết quả được xem trước và danh sách dừng lại
ở giới hạn kích thước và cho biết nó đã bỏ sót bao nhiêu mục nhập -- vì vậy tải trọng lớn không thể làm tăng kích thước
thử lại. Tổng số được báo cáo vẫn chính xác dù danh sách có bị cắt hay không, điều này cho biết
mô hình hóa một số cuộc gọi bị thiếu so với những gì nó có thể thấy. Danh sách này là bối cảnh cho mô hình, không phải là người bảo vệ:
không có gì ngăn nó gọi lại các công cụ đó, vì vậy hãy coi nó như thông báo cho lần thử tiếp theo
hơn là ngăn chặn sự lặp lại.
Ghi đè chúng bằng resource_limits={'max_duration_secs': 10, 'max_memory': 134_217_728} và
max_tool_calls=25. Vượt qua resource_limits='unlimited' chỉ khi ranh giới thực thi khác
cung cấp các giới hạn tương đương.
Khi nào CodeMode chạy bên trong quy trình làm việc tạm thời, nó sẽ vô hiệu hóa max_duration_secs, bao gồm một
ghi đè rõ ràng. run_code được phát lại trong mã quy trình công việc, do đó việc đo thời gian đã trôi qua có thể
thực hiện phát lại chọn một đường dẫn khác với quy trình làm việc đã ghi. Giới hạn bộ nhớ vẫn được áp dụng. đặt
thay vào đó, công việc có giới hạn thời gian đằng sau một hoạt động tạm thời.
trạng thái REPL
Trạng thái tồn tại giữa run_code các cuộc gọi trong cùng một lần chạy agent -- các biến, nội dung nhập và định nghĩa hàm sẽ được chuyển tiếp. Vượt qua restart: true trong lệnh gọi công cụ để thiết lập lại trạng thái. Nếu một nhân viên gặp sự cố hoặc lỗi thực thi phía máy chủ làm mất hiệu lực phiên, run_code trả về một lần thử lại mô hình báo cáo việc đặt lại; đoạn mã tiếp theo phải tạo lại bất kỳ trạng thái bắt buộc nào.
Độ bền tạm thời
Cài đặt cả hai tích hợp:
uv add "pydantic-ai-harness[codemode,temporal]"
Xây dựng agent được đặt tên và bộ công cụ ID ổn định của nó bên ngoài quy trình công việc, sau đó đính kèm
TemporalDurability bên cạnh CodeMode:
from pydantic_ai import Agent
from pydantic_ai.durable_exec.temporal import TemporalDurability
from pydantic_ai_harness import CodeMode
agent = Agent(
'openai:gpt-5.6-sol',
name='coding-agent',
capabilities=[CodeMode(), TemporalDurability()],
)
Thực hiện theo Hướng dẫn tạm thời của Pydantic AI để gọi
agent đơn giản từ một quy trình công việc và đăng ký các hoạt động của nó với PydanticAIPlugin và một trong hai
__pydantic_ai_agents__ hoặc AgentPlugin.
PydanticAIPlugin vượt qua pydantic_monty thông qua hộp cát quy trình làm việc của Temporal. Điều này khiến Monty
có thể chạy được ở đó, nhưng run_code vẫn thực thi trong mã quy trình làm việc và được thực thi lại trong quá trình phát lại.
Theo mặc định, các yêu cầu mô hình và các lệnh gọi công cụ lồng nhau vượt qua các ranh giới hoạt động tạm thời;
asyncio.gather có thể lên lịch đồng thời cho các hoạt động của công cụ lồng nhau. REPL là trạng thái cục bộ của quy trình
cho một agent chạy, lưu trữ không bền. Phát lại sẽ xây dựng lại nó bằng cách chạy các đoạn đã ghi
một lần nữa so với kết quả hoạt động được ghi lại.
Giữ mã phía quy trình công việc mang tính quyết định. mount đọc và viết, os_access cuộc gọi lại và
các cuộc gọi đồng hồ máy chủ lại xảy ra trong khi phát lại; việc thay đổi kết quả của họ có thể thay đổi những hoạt động nào
lịch trình công việc và gây ra NondeterminismError. Đặt các thao tác đọc, ghi, truy cập đồng hồ bên ngoài và
các tác dụng phụ khác trong các công cụ được bao bọc để Temporal ghi lại chúng dưới dạng hoạt động. Phát lại có thể không gắn cờ
đã thay đổi các đối số khi cùng một hoạt động vẫn ở cùng một vị trí lịch sử, vì vậy hãy phát lại xác thực
không phải là sự thay thế cho ranh giới này. Thời gian chờ hoạt động tạm thời áp dụng cho các công cụ lồng nhau, không phải thuần túy
tính toán bên trong run_code; di chuyển tính toán có giới hạn thời gian đằng sau một hoạt động.
Khả năng quan sát
Công cụ lồng nhau gọi bên trong run_code tạo ra các nhịp riêng của chúng khi được trang bị Logfire hoặc bất kỳ phần phụ trợ OpenTelemetry nào -- cách dễ nhất để hiểu chế độ mã thực sự đã làm gì, vì mỗi run_code kéo quạt ra ngoài công cụ gọi mô hình được tạo ra từ bên trong hộp cát. Xem Tài liệu về Pydantic AI Logfire để thiết lập.
các run_code công cụ trả về cũng mang siêu dữ liệu với mọi cuộc gọi lồng nhau, được khóa theo id cuộc gọi:
from pydantic_ai import Agent
from pydantic_ai.messages import ToolReturnPart
from pydantic_ai_harness import CodeMode
agent = Agent('anthropic:claude-sonnet-4-6', capabilities=[CodeMode()])
@agent.tool_plain
def get_weather(city: str) -> dict:
"""Get current weather for a city."""
return {'city': city, 'temp_f': 72}
result = agent.run_sync("What's the weather in Paris?")
for msg in result.all_messages():
for part in msg.parts:
if isinstance(part, ToolReturnPart) and part.tool_name == 'run_code':
metadata = part.metadata or {}
tool_calls = metadata['tool_calls'] # dict[str, ToolCallPart]
tool_returns = metadata['tool_returns'] # dict[str, ToolReturnPart]
Trong thực tế
Một đại diện chạy dây CodeMode đối đầu với máy chủ MCP và tìm kiếm trên web, đồng thời yêu cầu nó tìm câu chuyện Tin tức về hacker được thảo luận nhiều nhất trên ba nguồn cấp dữ liệu, lấy chuỗi nhận xét và hồ sơ của người gửi, đồng thời tìm kiếm trên web để biết nội dung tiếp theo. CodeMode chia nó thành hai run_code cuộc gọi: lần đầu tiên tìm nạp song song cả ba nguồn cấp dữ liệu thông qua asyncio.gather, loại trừ theo id, lọc theo điểm và xếp hạng theo số lượng nhận xét -- bằng Python đơn giản; đợt thứ hai ba cuộc gọi tiếp theo (hn_get_thread, hn_get_user, duckduckgo_search) cùng nhau.
Xem toàn bộ dấu vết Logfire -> Mỗi run_code kéo quạt ra ngoài công cụ gọi mô hình được tạo ra từ bên trong hộp cát.
Truy cập hệ thống tập tin và hệ điều hành
Mã hộp cát bắt đầu mà không có quyền truy cập vào tệp, môi trường hoặc đồng hồ của máy chủ. Hai tham số thêm hệ thống tập tin, môi trường hoặc hành vi đồng hồ được kiểm soát.
Cả hai tham số đều cố định khi khả năng được xây dựng, vì vậy hãy xây dựng CodeMode theo yêu cầu để xác định phạm vi quyền truy cập được định cấu hình cho yêu cầu đó.
mount -- chia sẻ thư mục máy chủ
Tiếp cận với mount khi agent làm việc với các tệp thực: phân tích tập dữ liệu bạn đã thả vào một thư mục và viết lại báo cáo, chỉnh sửa thanh toán hoặc xử lý một loạt tài liệu. Được đóng hộp cát pathlib mã đọc và ghi theo đường dẫn được gắn kết. (Đối với các biến môi trường hoặc đồng hồ, hãy sử dụng os_access thay vào đó.)
from pydantic_ai import Agent
from pydantic_monty import MountDir
from pydantic_ai_harness import CodeMode
# The agent can read /work/data.csv and write /work/summary.md back to the host:
agent = Agent(
'anthropic:claude-sonnet-4-6',
capabilities=[CodeMode(mount=MountDir(virtual_path='/work', host_path='/tmp/agent-workspace', mode='read-write'))],
)
A MountDir mặc định là sao chép khi ghi mode='overlay': hộp cát đọc các tập tin máy chủ và xem việc ghi được thực hiện trong quá trình hiện tại run_code gọi, nhưng Monty loại bỏ những nội dung ghi đó trước cuộc gọi tiếp theo và chúng không liên lạc được với máy chủ. Vượt qua mode='read-write' khi các cuộc gọi sau cần đọc bản ghi, hoặc mode='read-only' cấm viết. mount cũng chấp nhận một danh sách MountDir cho nhiều điểm gắn kết.
os_access -- hãy tự trả lời các cuộc gọi của hệ điều hành sandbox
Tiếp cận với os_access khi agent cần các biến môi trường, ngày và giờ hiện tại hoặc hành vi của hệ thống tệp mà bạn kiểm soát. Đưa cho nó một bản triển khai hệ điều hành đã sẵn sàng (AbstractOS) hoặc lệnh gọi lại quyết định từng cuộc gọi -- vì vậy, bạn có thể chỉ đưa vào những bí mật cần thiết, ghim "ngay bây giờ" cho các lần chạy có thể lặp lại hoặc định tuyến quyền truy cập tệp vào cửa hàng của riêng bạn.
from pydantic_ai import Agent
from pydantic_monty import OSAccess
from pydantic_ai_harness import CodeMode
# Give the agent a fixed set of environment values:
agent = Agent(
'anthropic:claude-sonnet-4-6',
capabilities=[CodeMode(os_access=OSAccess(environ={'API_BASE': 'https://api.example.com'}))],
)
Cuộc gọi lại nhận từng cuộc gọi hệ điều hành và quyết định số phận của nó:
from pydantic_ai import Agent
from pydantic_monty import NOT_HANDLED
from pydantic_ai_harness import CodeMode
allowed_env = {'API_KEY': 'sk-...'}
def my_os(fn, args, kwargs):
if fn == 'os.getenv':
# Answer the call: allow-listed keys resolve, every other key reads back
# as None -- absent, exactly like a real unset variable.
return allowed_env.get(args[0])
# Refuse everything else: NOT_HANDLED makes the call fail in the sandbox.
return NOT_HANDLED
agent = Agent('anthropic:claude-sonnet-4-6', capabilities=[CodeMode(os_access=my_os)])
Giá trị trả về của cuộc gọi lại quyết định số phận của cuộc gọi và hai kết quả rất dễ nhầm lẫn:
- Trả về bất kỳ giá trị nào -- bao gồm
None,''hoặc0-- và điều đó trở thành kết quả mà hộp cát nhìn thấy.os.getenvtrở vềNonetrông giống hệt như một biến chưa được đặt thông thường, do đó mã của agent vẫn tiếp tục chạy. Đây là cách bạn ẩn thứ gì đó: trả lời bằng một giá trị trống. - Trở về
NOT_HANDLEDvà lệnh gọi được coi là không được hỗ trợ: nó sẽ tăng lên bên trong hộp cát và mô hình sẽ được thử lại. Điều này từ chối một khả năng hoàn toàn -- sử dụng nó để chặn chứ không phải nói "không có giá trị". Trở vềNOT_HANDLEDđối với một khóa mà agent mong đợi một cách hợp lý sẽ ghi lại các lần thử lại.
!!! cảnh báo "Quyền truy cập máy chủ phụ thuộc vào cấu hình"
mount hiển thị các thư mục máy chủ đã chọn. Tích hợp sẵn OSAccess sử dụng môi trường và hệ thống tệp trong bộ nhớ bị cô lập nhưng đồng hồ máy chủ theo mặc định; một trình xử lý tùy chỉnh hoặc CallbackFile có thể làm lộ các tài nguyên máy chủ khác. Ưu tiên xây dựng CodeMode theo yêu cầu nên mọi quyền truy cập được cấp đều nằm trong phạm vi yêu cầu đó.
!!! lưu ý "Các loại cụ thể của Monty"
Các tham số này sử dụng Monty's AbstractOS/MountDir các loại từ pydantic_monty.
Hạn chế của hộp cát
Mã chạy bên trong Monty, một tập hợp con Python được đóng hộp cát. Hạn chế chính:
- Không nhập khẩu của bên thứ ba. Các mô-đun stdlib được phép:
sys,typing,asyncio,math,json,re,unicodedata,datetime,os,pathlib(mỗi cái phải được nhập trước khi sử dụng). asyncio.gather(...)chấp nhận các vị trí chờ đợi nhưng không có đối số từ khóa. Các API tạo tác vụ và chờ đợi khác không khả dụng.- Theo mặc định, không có đồng hồ treo tường hoặc thời gian nguyên thủy:
asyncio.sleep,datetime.datetime.now(),datetime.date.today(), vàtimemô-đun.datetime.datetime.now()/datetime.date.today()trở nên có sẵn khi mộtos_accesstrình xử lý thực hiện chúng (trình xử lý tích hợpOSAccesslàm);asyncio.sleepvàtimekhông bao giờ làm. - Không
import *. - I/O hệ thống tập tin cần một
os_accessngười xử lý hoặc mộtmount;os.getenv/os.environcần mộtos_accessngười xử lý. - Công cụ yêu cầu phê duyệt hoặc trì hoãn (
CallDeferred) việc thực thi được đóng hộp cát giống như bất kỳ công cụ nào khác; không cóHandleDeferredToolCalls(hoặc tương đương) trên agent để giải quyết chúng nội tuyến, gọi một từrun_codegây ra lỗi xuất hiện trên mô hình khi thử lại.
Thông số agent (YAML/JSON)
CodeMode hoạt động với thông số agent của Pydantic AI để xác định agent trong YAML hoặc JSON:
# agent.yaml
model: anthropic:claude-sonnet-4-6
capabilities:
- CodeMode: {}
from pydantic_ai import Agent
from pydantic_ai_harness import CodeMode
agent = Agent.from_file('agent.yaml', custom_capability_types=[CodeMode])
result = agent.run_sync('...')
print(result.output)
Vượt qua custom_capability_types để trình tải thông số kỹ thuật biết cách khởi tạo CodeMode. Các đối số cũng có thể được truyền trong YAML:
capabilities:
- CodeMode:
tools: ['search', 'fetch']
max_retries: 5
Đọc thêm
- Sử dụng công cụ qua mã (Nhân loại)
- Chế độ mã đang được sản xuất (Đám mây)
- Khả năng AI của Pydantic
Tham chiếu API
::: pydantic_ai_harness.CodeMode
