Agent guard : des règles en mots simples pour votre agent IA
Vérifiez les appels d’outils de votre agent, leurs résultats et ses réponses avec des règles que vous écrivez sous forme de phrases.
Un agent IA décide seul quels outils appeler et quoi répondre à l’utilisateur. La plupart du temps, c’est ce que vous voulez. Mais parfois, il rembourse trop, transmet des données qu’il ne devrait pas, ou promet quelque chose que personne n’a accepté. Agent guard vous donne des hooks à trois endroits de la boucle de l’agent, où chaque étape est vérifiée par rapport à vos règles avant de prendre effet.
Comment ça marche
Les règles. Vous écrivez chaque règle sous forme de phrase, par exemple « Block refunds above 500 unless the user's role is manager. » Vous indiquez les outils concernés, et si elle doit bloquer ou seulement signaler pour l’instant. Les règles sont enregistrées sur votre compte : vous pouvez donc les modifier sans changer ni redéployer l’agent.
Les vérifications. Votre agent envoie ce qu’il s’apprête à faire, ou ce qu’il vient de recevoir, à un seul endpoint : POST /v1/guard/check. Pour chaque règle concernée, Strom indique la probabilité qu’elle soit enfreinte, et vous dit si vous pouvez continuer. Il y a trois endroits de la boucle de l’agent où vous pouvez vérifier :
- avant qu’un outil s’exécute (
before_tool), - après l’exécution d’un outil, avant que l’agent voie le résultat (
after_tool), - avant qu’une réponse parte vers l’utilisateur (
before_reply).
Chaque règle appartient à l’une de ces étapes. Une règle en mode enforce bloque quand elle s’applique. Une règle en mode observe ne bloque jamais ; elle signale seulement would_block, pour que vous voyiez d’abord ce qu’elle intercepterait.
Un exemple
Un agent de support d’une boutique en ligne a deux outils : lookup_order et refund. Nous lui donnons trois règles :
| Règle | Étape | Outils | Mode |
|---|---|---|---|
refund-limit : « Block refunds above 500 unless the user's role is manager. » |
before_tool | refund | enforce |
no-card-numbers : « Block results that contain a full card number. » |
after_tool | lookup_order | enforce |
no-promised-dates : « Block replies that promise the customer a date for a refund or delivery. » |
before_reply | observe |
Une règle se crée avec une seule requête :
curl https://api.uprelic.com/v1/guard/rules \
-H "Authorization: Bearer $UPRELIC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"id": "refund-limit",
"text": "Block refunds above 500 unless the user’s role is manager.",
"stage": "before_tool",
"tools": ["refund"],
"mode": "enforce"
}'
L’équipe support de la boutique répond aux clients avec l’agent. Une employée, connectée avec le rôle support_agent, lui transmet le message d’un client : « I want a refund for order A1. » Les réponses ci-dessous sont de vraies réponses de l’API, raccourcies.
1. L’agent consulte la commande
Avant que lookup_order s’exécute, l’agent vérifie l’appel :
{"action": "lookup_order", "params": {"order_id": "A1"}, "context": {"role": "support_agent"}}
Aucune règle before_tool ne concerne lookup_order : la réponse est allow, sans aucune règle évaluée. Une vérification de ce type est gratuite.
2. La commande revient avec un numéro de carte
Le système de commandes renvoie plus qu’il ne devrait :
{"order_id": "A1", "total": 800, "status": "delivered", "card": "4111 1111 1111 1111"}
Avant que l’agent le voie, le résultat est vérifié. Il est envoyé dans result, avec la même action et les mêmes params :
{
"decision": "block",
"rules": [
{"id": "no-card-numbers", "probability": 0.92, "threshold": 0.9,
"mode": "enforce", "matched": true}
]
}
L’agent ne reçoit pas le résultat. Il reçoit à la place le texte de la règle : « Block results that contain a full card number. » La même commande, avec seulement les quatre derniers chiffres de la carte, obtient une probabilité de 0,07 et passe.
L’outil s’est quand même exécuté. Une vérification après un outil peut empêcher son résultat d’arriver à l’agent, mais elle ne peut pas annuler ce que l’outil a fait. Les outils qui modifient quelque chose se vérifient donc avant leur exécution.
3. L’agent tente de rembourser 800
{"action": "refund", "params": {"order_id": "A1", "amount": 800}, "context": {"role": "support_agent"}}
{
"decision": "block",
"rules": [
{"id": "refund-limit", "probability": 0.94, "threshold": 0.9,
"mode": "enforce", "matched": true}
]
}
Le remboursement n’a pas lieu, et l’agent sait pourquoi. Le même appel avec "role": "manager" obtient une probabilité de 0,02 et passe.
Le rôle se trouve dans context. Votre application le remplit à partir de l’utilisateur connecté, pas à partir de ce que le modèle a écrit. Si le modèle pouvait choisir le rôle, il pourrait aussi se déclarer manager.
4. L’agent rédige une réponse
L’agent prépare : « Refunds above 500 need a manager's approval. I've passed your request on, and you'll have your money back by Friday. »
Personne n’a promis vendredi. La réponse est vérifiée avec response (et le message de l’utilisateur dans request) :
{
"decision": "would_block",
"rules": [
{"id": "no-promised-dates", "probability": 0.94, "threshold": 0.9,
"mode": "observe", "matched": true}
]
}
La règle est encore en mode observe, donc la réponse est envoyée. La même réponse sans « by Friday » obtient 0,02.
5. Activer la règle
Après quelques jours, nous listons ce que la règle sur les réponses aurait bloqué :
curl "https://api.uprelic.com/v1/guard/checks?decision=would_block" \
-H "Authorization: Bearer $UPRELIC_API_KEY"
Chaque vérification revient avec la réponse, le message de l’utilisateur et la probabilité de chaque règle. Si les cas détectés sont les bons, nous passons la règle en enforce avec PUT /v1/guard/rules/no-promised-dates. Sinon, nous reformulons la règle ou relevons son seuil, et nous observons à nouveau.
Ce que cela a coûté
Quatre vérifications, dont trois avec une règle chacune : 3 règles évaluées à 0,01 $ les 1 000, soit 0,00003 $. Chaque vérification a pris 30 à 40 ms sur le serveur.
En Python
Avec le SDK Python, un décorateur fait les vérifications pour vous :
import uprelic
client = uprelic.Uprelic()
@client.guard("refund", context=lambda: {"role": current_user.role})
def refund(order_id, amount):
...
@client.guard("lookup_order", check_result=True)
def lookup_order(order_id):
...
try:
refund("A1", amount=800)
except uprelic.Blocked as blocked:
tool_result = str(blocked) # give this to the agent instead
Points forts
- Les règles sont des phrases. Quelqu’un qui connaît la politique, mais pas le code, peut les écrire et les modifier, sans déploiement.
- Ça marche avec n’importe quel agent. C’est un appel HTTP à trois endroits de la boucle, quel que soit le framework ou le modèle qui fait tourner l’agent.
- Vous pouvez tester une règle avant qu’elle bloque. Le mode
observeapplique une règle au trafic réel et enregistre ce qu’elle aurait bloqué. - C’est rapide et peu cher. Une vérification prend quelques dizaines de millisecondes et coûte 0,01 $ les 1 000 règles.
Points faibles
- C’est un modèle, il peut donc se tromper. Il manquera parfois un cas ou bloquera un cas sans risque. Les limites exactes, comme « montant supérieur à 500 », sont plus sûres dans votre propre code. Les règles servent surtout pour ce que le code vérifie mal, comme ce qu’une réponse promet.
- Une vérification ne voit que ce que vous envoyez. Elle ne se souvient pas des appels précédents : une règle comme « trois remboursements par jour au maximum » a besoin du compte dans
context. - Chaque vérification ajoute un aller-retour, à chaque endroit où vous vérifiez. Dans une longue suite d’appels d’outils, cela s’additionne.
Essayer
- La démo Agent guard fait passer un agent simulé par ces vérifications dans la console, sans code.
- La documentation décrit chaque champ et chaque erreur.
- Le SDK Python :
pip install uprelic.
Questions et retours : support@uprelic.com.