Leçon 02 · Base

Le cycle n’a pas changé, c’est juste qu’il y a plus d’outils

"La boucle n'a pas changé du tout, j'ai juste ajouté des éléments au tableau TOOLS." - s02_tool_use.py Mots originaux.

⏱ ~10 min · 📝 3 widgets interactifs · 🧑‍💻 Basé sur shareAI-lab · s02_tool_use.py

De combien d’endroits faut-il se déplacer pour ajouter un outil ?

L'agent de S01 ne connaît que bash. Comment le modifieriez-vous pour activer également read_file / write_file / edit_file ?

La première réaction de beaucoup de gens est : changer de boucle. faux. Ne touchez pas une seule ligne de boucle. Seulement trois éléments sont nécessaires :

  1. Écrivez une fonction de gestionnaire Python (run_read(path, limit)).
  2. Enregistrez-le dans la table de mappage TOOL_HANDLERS ("read_file": lambda **kw: run_read(...)).
  3. Ajoutez une instruction de schéma JSON au tableau TOOLS (indiquant au modèle comment s'appelle l'outil et quels paramètres il accepte).

Lorsque la boucle voit un bloc tool_use, appuyez sur block.name pour rechercher la fonction dans la carte de répartition, exécutez-la et remettez la sortie dans tool_result. Il suit exactement le même chemin que bash.

# Carte de répartition : nom → gestionnaire lambda
OUTIL_HANDLERS = {
    "bash" : lambda **kw : run_bash(kw["command"]),
    "read_file" : lambda **kw : run_read(kw["path"], kw.get("limit")),
    "write_file" : lambda **kw : run_write(kw["path"], kw["content"]),
    "edit_file" : lambda **kw : run_edit(kw["path"], kw["old_text"], kw["new_text"]),

Voir comment l'expédition est acheminée

Le widget suivant vous permet de cliquer sur une requête tool_use qui peut être envoyée par un modèle pour voir comment elle est acheminée vers une fonction Python spécifique. Remarque : block.name détermine la ligne à prendre.

safe_path : une ligne de défense incontournable

Donnez à l'agent les droits d'accès aux fichiers. L'échec de sécurité le plus probable est l'path escape : le modèle aurait dû fonctionner dans /home/user/project/, mais il a fini par envoyer un read_file("../../etc/passwd").

Il y a une petite fonction dans s02 qui traite de ceci :

def safe_path(p : str) -> Chemin :
    path = (WORKDIR / p).resolve() # Normaliser, résoudre .. et liens symboliques
    si pas path.is_relative_to(WORKDIR) :
        raise ValueError(f"Le chemin échappe à l'espace de travail : {p}")
    chemin de retour

La clé réside dans les deux étapes .resolve() + .is_relative_to() - analyser le chemin absolu, puis vérifier s'il est toujours dans le bac à sable. Sans le premier, foo/../../etc peut passer ; sans ce dernier, aucun contrôle n'est même effectué.

Identifier la sécurité du chemin

Les 5 chemins suivants sont tous des paramètres read_file qui peuvent être envoyés par le modèle. Lesquels seront autorisés par safe_path et lesquels seront rejetés ? Supposons que WORKDIR = /home/user/project.

N'ajoutez pas d'outils dangereux à l'agent

Il est facile d'ajouter des outils, mais n'oubliez pas : Chaque outil que vous ajoutez constitue une nouvelle limite de capacités du modèle. Dans s02, bash a déjà une liste noire (rm -rf /, sudo, shutdown), et write_file a des restrictions safe_path. Posez-vous trois questions avant d'ajouter des outils à la production :

  • Cet outil peut-il permettre au modèle de faire des choses irréversibles ? (rm, envoyer un email, git push)
  • Qu'est-ce qui peutfuir ? (vars d'environnement, .ssh, cookies)
  • Les résultats d'erreur seront-ils traités comme un retour de commande ? (injection rapide via la sortie de l'outil)

Le cours s07 ajoutera une "couche d'autorisation" pour extraire ces décisions du code et les rendre déclaratives.

Interactif

Widget 1 · Répartition des outils · Comment tool_use est acheminé vers le gestionnaire

Cliquez sur une requête tool_use et voyez comment block.name dans la boucle trouve la fonction correspondante, l'exécute et remet la sortie dans le bloc tool_result.

模型发来的 tool_use 块
TOOL_HANDLERS 映射表

        
执行结果 · tool_result 块
(点上面任意一条 tool_use 触发路由)
Interactif

Widget 2 · Safe Path · Détection d'évasion pour 5 chemins

Chaque chemin sera traité par safe_path(). Supposons que WORKDIR = /home/user/project, cliquez sur "Libérer" ou "Rejeter" - cela dépend si votre intuition concernant l'échappement du chemin est exacte.

答对 0 / 5
Interactif

Widget 3 · Ajouter un outil · Que faut-il modifier pour ajouter un outil global à l'agent ?

Supposons que vous souhaitiez ajouter un nouvel outil glob(pattern) pour permettre à l'agent de rechercher des fichiers par lots. Remplissez les espaces vides : tous les trois doivent être modifiés, aucun d’entre eux ne peut manquer.

第 1 处 · 写一个 handler 函数
def run_glob(pattern: str) -> str:
    import glob
    return "\n".join(glob.glob(pattern))
第 2 处 · 注册到 dispatch map(选正确一行)
第 3 处 · 在 TOOLS 数组里加 schema(选正确一组)