Intégration de paiement Pydantic AI.
Il n'y a pas de package Pydantic AI, et vous n'en avez pas besoin. Enregistrez une fonction typée avec @agent.tool_plain, appelez le vrai client blockchain0x, et votre agent peut déplacer USDC sur Base.
Il n'existe pas de package spécifique à Pydantic AI, et vous n'en avez pas besoin. Pydantic AI transforme une fonction en outil validé avec , donc vous encapsulez le vrai client Python dans une fonction typée et l'agent peut envoyer des USDC, régler des factures et lire des wallets. Cela fonctionne avec OpenAI, Anthropic, Google, Mistral, Groq et tous les autres fournisseurs Pydantic AI, car l'outil appelle l'API HTTP, pas le modèle. Les paiements sont réglés sur Base.
Le typage de Pydantic AI gagne. Utilisez-le aussi pour les paiements.
Le but de Pydantic AI est le typage fort : les entrées de l'agent sont typées, les sorties sont typées, les dépendances sont typées, les réessais sont typés. Le cadre rejette les données malformées à la frontière au lieu de les laisser se propager à travers l'appel LLM. Votre outil de portefeuille repose exactement sur cela - déclarez les arguments avec des types, et Pydantic AI construit un schéma validé à partir de la signature et de la docstring avant que le modèle ne soit jamais autorisé à l'appeler.
Le bénéfice pratique : si le modèle essaie d'appeler send_usdc avec un float au lieu d'une chaîne d'unités de base, l'échec se produit au niveau de validation de Pydantic avant tout appel HTTP vers nous. Vous voyez une ValidationError claire avec un message utile plutôt qu'un 422 de l'API avec des chemins de champ cryptiques. C'est la raison principale d'envelopper le client vous-même ici plutôt que de recourir à un adaptateur générique - vous conservez le typage jusqu'au fil.
Installez Pydantic AI et le SDK de base. Deux clés.
Il n'y a pas de package blockchain0x Pydantic AI à ajouter. Vous installez Pydantic AI (Python 3.10+) et le vrai SDK de base blockchain0x, puis écrivez la fonction ci-dessous. C'est toute la liste des dépendances.
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 (ou l'équivalent pour le fournisseur que vous utilisez). BLOCKCHAIN0X_API_KEY est une clé sk_test_ testnet ou sk_live_ mainnet de votre tableau de bord ; le client la lit depuis l'environnement. Si votre agent reçoit également de l'argent, le gestionnaire de webhook a également besoin de BLOCKCHAIN0X_WEBHOOK_SECRET.
Une fonction typée qui paie, enregistrée en tant qu'outil.
Voici l'intégration complète. send_usdc appelle le véritable client blockchain0x ; @agent.tool_plain l'enregistre avec un schéma construit à partir des indications de type et de la docstring. Exécutez-le et l'agent déplace USDC sur Base, avec les arguments validés avant l'appel.
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.
Confirmer les paiements entrants avec un webhook signé.
Si votre agent reçoit également des USDC, confirmez-le avec le webhook plutôt que par sondage. L'assistant de vérification est inclus dans le SDK Node ; dans un service Python, vous vérifiez manuellement contre le HMAC documenté. Si vous souhaitez des événements typés, définissez votre propre modèle Pydantic et utilisez model_validate_json sur le corps brut après que la signature soit vérifiée - la typage est à ajouter par vos soins. Exemple FastAPI ci-dessous.
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}
L'algorithme est HMAC-SHA256 sur la chaîne t.rawBody, une comparaison en temps constant, et une fenêtre de répétition de 300 secondes. Lisez le corps brut via await request.body(), jamais request.json() re-sérialisé, car cela change les octets que la signature couvre. Les événements expédiés sont payment.received, payment.sent, wallet.deployed, et webhook.test ; affinez sur l'en-tête X-Blockchain0x-Event-Type pour ramifier.
Le client que vous enveloppez est ouvert. Lisez-le.
Il n'y a pas de package de démarrage Pydantic AI à cloner - la recette ci-dessus est l'intégration. Les SDK blockchain0x sont open source sur GitHub ; cette recette encapsule le SDK Python (blockchain0x-python), avec la surface complète des méthodes dans la documentation. Lisez-le pour une référence sur les corps de fonction.
github.com/tosh-labs/blockchain0x-pythonLa surface complète des méthodes SDK et les portées sont documentées dans la documentation. Commencez avec une clé sk_test_ sur Base Sepolia, puis passez à sk_live_ lorsque la fonction fonctionne comme vous l'attendez.
Cinq pièges spécifiques à Pydantic AI à éviter.
Le typage fort de Pydantic AI attrape la plupart des bugs d'intégration à la frontière ; voici ceux qui glissent à travers.
Il n'y a pas de package Pydantic AI - vous enregistrez un outil
Blockchain0x expédie des adaptateurs pour LangChain et CrewAI ainsi que le serveur MCP ; il n'y a pas de package Pydantic AI dédié. La recette ci-dessus est le chemin : une fonction typée ordinaire décorée avec @agent.tool_plain qui appelle le véritable client blockchain0x. Pydantic AI lit la signature et la docstring pour construire un schéma d'outil validé, qui est exactement le gain de typage pour lequel vous êtes venu à Pydantic AI.
Gardez le montant sous forme de chaîne ; laissez Pydantic maintenir la ligne
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 peut répondre 503 tôt
payments.create ne réessaie pas par défaut et peut renvoyer 503 jusqu'à ce que l'adaptateur de chaîne soit câblé pour votre réseau. Attrapez l'erreur à l'intérieur de votre outil et renvoyez un message clair sur lequel le modèle peut agir, plutôt que de laisser l'agent boucler. La clé d'idempotence générée automatiquement signifie qu'un réessai manuel ne paiera pas deux fois.
Chaînes de modèles préfixées par le fournisseur
Pydantic AI utilise des chaînes de modèles préfixées par le fournisseur : 'openai:gpt-4o', 'anthropic:claude-3-5-sonnet-latest', 'google-gla:gemini-1.5-pro'. Omettre le préfixe donne une erreur cryptique 'modèle inconnu'. Votre outil est agnostique au fournisseur car il appelle l'API HTTP, pas le modèle - échangez le préfixe librement et la fonction de portefeuille reste inchangée.
tool_plain vs tool (RunContext)
Utilisez @agent.tool_plain lorsque la fonction n'a besoin de rien de l'exécution, comme ci-dessus. Si vous voulez que les dépendances de l'agent soient à l'intérieur de l'outil (un identifiant client par demande, un plafond de dépense), utilisez @agent.tool et déclarez le premier argument comme ctx: RunContext[Deps] pour lire ctx.deps. Mélanger les deux - déclarer un argument ctx sur tool_plain - soulève une TypeError à l'enregistrement.