Интеграция платежей Pydantic AI.
Нет пакета Pydantic AI, и он вам не нужен. Зарегистрируйте типизированную функцию с @agent.tool_plain, вызовите реальный клиент blockchain0x, и ваш агент сможет перемещать USDC на Base.
Специального пакета для Pydantic AI нет, и он вам не нужен. Pydantic AI превращает функцию в валидируемый tool с помощью , поэтому вы оборачиваете реальный Python client в типизированную функцию, и агент может отправлять USDC, закрывать invoices и читать wallets. Это работает с OpenAI, Anthropic, Google, Mistral, Groq и любым другим provider Pydantic AI, потому что tool вызывает HTTP API, а не model. Платежи завершаются в Base.
Типизация Pydantic AI выигрывает. Используйте ее и для платежей.
Основная идея Pydantic AI - это строгая типизация: входные данные агента типизированы, выходные данные типизированы, зависимости типизированы, повторные попытки типизированы. Фреймворк отклоняет неправильно сформированные данные на границе, вместо того чтобы позволять им распространяться через вызов LLM. Ваш инструмент кошелька основан именно на этом - объявите аргументы с типами, и Pydantic AI создаст проверенную схему из сигнатуры и документации до того, как модель получит разрешение на вызов.
Практическое преимущество: если модель пытается вызвать send_usdc с плавающей точкой вместо строки базовой единицы, сбой происходит на уровне валидации Pydantic до любого HTTP-вызова к нам. Вы видите четкую ValidationError с полезным сообщением, а не 422 от API с криптографическими путями полей. Это вся причина обернуть клиент самостоятельно здесь, а не использовать универсальный адаптер - вы сохраняете типизацию до самого конца.
Установите Pydantic AI и основной SDK. Два ключа.
Нет пакета blockchain0x Pydantic AI для добавления. Вы устанавливаете Pydantic AI (Python 3.10+) и реальный основной SDK blockchain0x, затем пишете функцию ниже. Это весь список зависимостей.
pip install pydantic-ai blockchain0xexport OPENAI_API_KEY=sk-... export BLOCKCHAIN0X_API_KEY=sk_test_... # sk_test_ = Base Sepolia, sk_live_ = Base mainnet
OPENAI_API_KEY (или аналогичный ключ для любого provider, который вы используете). BLOCKCHAIN0X_API_KEY - это ключ sk_test_ для testnet или sk_live_ для mainnet из вашего dashboard; client читает его из environment. Если ваш agent также получает деньги, обработчику webhook дополнительно нужен BLOCKCHAIN0X_WEBHOOK_SECRET.
Типизированная функция, которая оплачивает, зарегистрированная как инструмент.
Ниже приведена вся интеграция. send_usdc вызывает реальный клиент blockchain0x; @agent.tool_plain регистрирует его с схемой, построенной из подсказок типов и документации. Запустите его, и агент перемещает USDC на Base, при этом аргументы проверяются перед вызовом.
from pydantic_ai import Agent from blockchain0x import Client blockchain0x = Client() # reads BLOCKCHAIN0X_API_KEY from the environment agent = Agent( "openai:gpt-4o", system_prompt="You pay vendor invoices in USDC within owner-set limits.", ) # Register a plain function as a tool. No dedicated package needed. @agent.tool_plain def send_usdc(agent_id: str, to: str, amount_wei: str) -> str: """Send a USDC payment from an agent wallet. amount_wei is USDC base units (6 decimals), so "10000" is 0.01 USDC. """ return str( blockchain0x.payments.create(body={"agentId": agent_id, "to": to, "amountWei": amount_wei}) ) result = agent.run_sync( "Pay 0.01 USDC from agent agt_123 to 0xVendor for the dataset." ) print(result.output)
When the agent decides to pay, it calls send_usdc, the SDK submits the transfer, and you get a transaction hash back. amount_wei is base units, so 0.01 USDC is "10000". A sk_test_ key keeps it on Base Sepolia until you switch to sk_live_. Want a typed result object instead of a string? Set the agent's output_type to your own Pydantic model and return it from the tool. Add read and settle functions the same way.
Подтвердите входящие платежи с помощью подписанного webhook.
Если ваш агент также получает USDC, подтвердите это с помощью вебхука, а не опросом. Помощник проверки поставляется в Node SDK; в Python-сервисе вы проверяете вручную по документированному HMAC. Если вы хотите типизированные события, определите свою собственную модель Pydantic и выполните model_validate_json для необработанного тела после проверки подписи - типизация остается за вами. Пример FastAPI ниже.
import hmac, hashlib, os, time from fastapi import FastAPI, Request, HTTPException app = FastAPI() SECRET = os.environ["BLOCKCHAIN0X_WEBHOOK_SECRET"].encode() @app.post("/webhooks/payment") async def receive(request: Request): raw = await request.body() # RAW bytes - do not parse first sig = request.headers.get("X-Blockchain0x-Signature", "") ts = request.headers.get("X-Blockchain0x-Timestamp", "") parts = dict(p.split("=", 1) for p in sig.split(",") if "=" in p) t, v1 = parts.get("t", ts), parts.get("v1", sig) want = hmac.new(SECRET, t.encode() + b"." + raw, hashlib.sha256).hexdigest() if not hmac.compare_digest(want, v1) or abs(time.time() - int(t)) > 300: raise HTTPException(status_code=401) if request.headers.get("X-Blockchain0x-Event-Type") == "payment.received": await trigger_followup() # USDC landed - run the next step return {"ok": True}
Алгоритм - HMAC-SHA256 над строкой t.rawBody, сравнение с постоянным временем и окно повторного воспроизведения 300 секунд. Читайте необработанное тело через await request.body(), никогда не request.json() повторно сериализованное, потому что это изменяет байты, которые охватывает подпись. Отправленные события - payment.received, payment.sent, wallet.deployed и webhook.test; уточните по заголовку X-Blockchain0x-Event-Type для ветвления.
Клиент, который вы оборачиваете, открыт. Читайте его.
Нет starter package для Pydantic AI, который можно было бы клонировать - рецепт выше и есть интеграция. SDK Blockchain0x открыты в GitHub; этот рецепт оборачивает Python SDK (blockchain0x-python), а полный набор методов приведен в docs. Используйте его как reference для body функций.
github.com/tosh-labs/blockchain0x-pythonПолный набор методов SDK и scopes описаны в the docs. Начните с ключа sk_test_ в Base Sepolia, затем переключитесь на sk_live_, когда функция начнет работать так, как вы ожидаете.
Пять ловушек, специфичных для Pydantic AI, которых следует избегать.
Сильная типизация Pydantic AI ловит большинство ошибок интеграции на границе; это те немногие, которые проскальзывают.
Нет пакета Pydantic AI - вы регистрируете инструмент.
Blockchain0x поставляет адаптеры для LangChain и CrewAI, а также сервер MCP; нет отдельного пакета Pydantic AI. Рецепт выше - это путь: простая типизированная функция, декорированная @agent.tool_plain, которая вызывает реальный клиент blockchain0x. Pydantic AI читает сигнатуру и docstring, чтобы построить проверенную схему инструмента, что является именно тем выигрышем в типизации, за которым вы пришли в Pydantic AI.
Сохраняйте сумму в виде строки; позвольте Pydantic удерживать линию
payments.create takes amountWei: a string of USDC base units (6 decimals), so 0.01 USDC is "10000" and 5 USDC is "5000000". Type the tool argument as str and Pydantic AI rejects a float at the boundary with a clear ValidationError, before any HTTP call. That is the whole point of doing this in Pydantic AI - the malformed value never reaches the API.
send_payment может ответить 503 на раннем этапе
payments.create по умолчанию не повторяет и может вернуть 503, пока адаптер цепочки не подключен к вашей сети. Поймайте ошибку внутри вашего инструмента и верните четкое сообщение, на которое модель может реагировать, вместо того чтобы позволить агенту зациклиться. Автоматически созданный ключ идемпотентности означает, что ручная попытка не приведет к двойной оплате.
Строки моделей с префиксом провайдера
Pydantic AI использует строки моделей с префиксом провайдера: 'openai:gpt-4o', 'anthropic:claude-3-5-sonnet-latest', 'google-gla:gemini-1.5-pro'. Пропуск префикса дает загадочную ошибку 'неизвестная модель'. Ваш инструмент не зависит от провайдера, так как он вызывает HTTP API, а не модель - меняйте префикс свободно, и функция кошелька останется неизменной.
tool_plain против tool (RunContext)
Используйте @agent.tool_plain, когда функции ничего не нужно от выполнения, как выше. Если вы хотите, чтобы зависимости агента были внутри инструмента (идентификатор клиента за запрос, лимит расходов), используйте @agent.tool и объявите первый аргумент как ctx: RunContext[Deps], чтобы прочитать ctx.deps. Смешивание двух - объявление аргумента ctx в tool_plain - вызывает ошибку TypeError при регистрации.