Exécutez des commandes shell dans des conteneurs hébergés ou dans votre propre environnement d’exécution local.
L’outil shell permet aux modèles de travailler dans un environnement de terminal complet. L’API Responses prend en charge l’exécution de commandes shell en local ou à distance.
Avec l’outil shell, les modèles peuvent exécuter des commandes dans l’un des environnements suivants :
L’outil shell est disponible via l’API Responses. L’API Chat Completions ne le prend pas en charge.
L’exécution de commandes shell arbitraires peut être dangereuse. Exécutez toujours les commandes dans un bac à sable. Dans la mesure du possible, autorisez ou bloquez des commandes précises. Journalisez l’activité de l’outil à des fins d’audit.
Démarrage rapide avec le shell distant
Le shell distant offre une solution native simple à utiliser pour les tâches qui nécessitent des traitements avancés et déterministes, qu’il s’agisse d’effectuer des calculs ou de manipuler des fichiers multimédias.
Utilisez container_auto pour qu’OpenAI crée et gère un conteneur pour votre requête.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15require "openai"client = OpenAI::Client.newresponse = client.responses.create( model: "gpt-6-astra", input: "Run ls -lah /mnt/data, then show the Python and Node.js versions.", tools: [ { type: :shell, environment: { type: :container_auto } } ])puts(response.output_text)
Caractéristiques de l’environnement d’exécution hébergé
L’environnement d’exécution repose actuellement sur Debian 12 et peut évoluer.
Le répertoire de travail par défaut est /mnt/data.
/mnt/data est toujours présent. C’est le répertoire pris en charge pour les fichiers que les utilisateurs peuvent télécharger.
Le shell distant ne prend pas en charge les sessions TTY interactives.
Les commandes du shell distant s’exécutent sans sudo.
Vous pouvez exécuter des services dans le conteneur si votre workflow en a besoin.
Parmi les langages actuellement préinstallés figurent :
Python 3.11
Node.js 22.16
Java 17.0
PHP 8.2
Ruby 3.1
Go 1.23
Réutilisez un conteneur pour plusieurs requêtes
Si vos workflows itératifs nécessitent un environnement qui reste actif sur la durée, créez un conteneur, puis faites-y référence dans vos appels suivants à l’API Responses.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18require "openai"client = OpenAI::Client.newresponse = client.responses.create( model: "gpt-6-astra", input: "List files in the container and show disk usage.", tools: [ { type: :shell, environment: { type: :container_reference, container_id: "cntr_08f3d96c87a585390069118b594f7481a088b16cda7d9415fe" } } ])puts(response.output_text)
Associez des Skills
Les Skills sont des ensembles de ressources réutilisables et versionnés que vous pouvez monter dans un environnement de shell distant. Vous déterminez ainsi les Skills disponibles. Au moment d’exécuter les commandes shell, le modèle décide de les utiliser ou non.
Consultez le guide des Skills pour savoir comment importer des Skills et gérer leurs versions.
Autoriser des domaines présente des risques de sécurité, notamment l’exfiltration de données à la suite d’une attaque par injection de prompt. Autorisez uniquement des domaines de confiance que des attaquants ne peuvent pas utiliser pour recevoir des données volées. Lisez attentivement la section Risques et sécurité ci-dessous avant d’utiliser cet outil.
Ordre de priorité des règles d’accès réseau
Lorsque plusieurs règles s’appliquent :
La liste d’autorisation de votre organisation définit l’ensemble des domaines que peut contenir allowed_domains.
Le paramètre network_policy de la requête restreint davantage l’accès.
La requête échoue si allowed_domains contient des domaines absents de la liste d’autorisation de votre organisation.
Conservation des données et cycle de vie des conteneurs
Tant qu’un conteneur hébergé utilisé par le shell distant ou l’Interpréteur de code est actif, l’application peut enregistrer son état temporaire dans le système de fichiers du conteneur, qui repose sur un stockage par blocs éphémère. Les données du conteneur sont supprimées à son expiration ou lorsque vous le supprimez explicitement.
Le shell distant peut produire des fichiers téléchargeables. Utilisez les mêmes API de gestion des conteneurs et des fichiers que pour l’Interpréteur de code afin de récupérer les fichiers écrits dans /mnt/data.
Contrôles supplémentaires des données
Pour limiter la durée de vie des contenus et des fichiers à celle du conteneur hébergé, vous pouvez inclure les fichiers directement dans la requête et monter dans le conteneur des Skills fournis de la même manière.
Utilisation de fichiers et de Skills inclus directement dans la requête
Pour les requêtes suivantes, transmettez le même container_id avec container_reference. Les Skills montés et les fichiers déjà présents dans le conteneur restent disponibles tant que celui-ci est actif.
Supprimez un conteneur dès la fin du travail
Une fois le travail terminé, vous pouvez supprimer explicitement le conteneur sans attendre qu’il expire pour cause d’inactivité.
import OpenAI from "openai";const client = new OpenAI();await client.containers.delete("container_id");console.log("Container deleted");
# Replace the illustrative IDs and URLs below with your own resource values.from openai import OpenAIclient = OpenAI()container_id = "cntr_123"client.containers.delete(container_id)print("Container deleted")
Utilisez domain_secrets lorsqu’un domaine de votre liste allowed_domains exige des en-têtes d’autorisation confidentiels, comme Authorization: Bearer <token>.
Chaque entrée comprend :
Le domaine cible
Un nom explicite pour le secret
La valeur du secret
Lors de l’exécution :
Le modèle et l’environnement d’exécution voient des noms de substitution (par exemple $API_KEY) à la place des identifiants réels.
Le composant auxiliaire chargé de l’authentification remplace ces noms par les valeurs réelles des secrets uniquement pour les destinations approuvées.
Les valeurs réelles des secrets ne sont pas conservées sur les serveurs de l’API et n’apparaissent pas dans le contexte accessible au modèle.
L’assistant peut ainsi appeler des services protégés tout en limitant le risque de fuite de données.
Outil shell avec domain_secrets
curl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32curl-L'https://api.openai.com/v1/responses'\-H"Authorization: Bearer $OPENAI_API_KEY"\-H"Content-Type: application/json"\-d'{ "model": "gpt-6-astra", "input": [ { "role": "user", "content": "Use curl to call https://httpbin.org/headers with header Authorization: Bearer $API_KEY. Tell me what you see in the final text response." } ], "tool_choice": "required", "tools": [ { "type": "shell", "environment": { "type": "container_auto", "network_policy": { "type": "allowlist", "allowed_domains": ["httpbin.org"], "domain_secrets": [ { "domain": "httpbin.org", "name": "API_KEY", "value": "debug-secret-123" } ] } } } ] }'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36import OpenAI from "openai";const client = new OpenAI();const response = await client.responses.create({ model: "gpt-6-astra", input: [ { role: "user", content: "Use curl to call https://httpbin.org/headers with header Authorization: Bearer $API_KEY. Tell me what you see in the final text response.", }, ], tool_choice: "required", tools: [ { type: "shell", environment: { type: "container_auto", network_policy: { type: "allowlist", allowed_domains: ["httpbin.org"], domain_secrets: [ { domain: "httpbin.org", name: "API_KEY", value: "debug-secret-123", }, ], }, }, }, ],});console.log(response.output_text);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35from openai import OpenAIclient = OpenAI()response = client.responses.create( model="gpt-6-astra", input=[ { "role": "user", "content": "Use curl to call https://httpbin.org/headers with header Authorization: Bearer $API_KEY. Tell me what you see in the final text response.", } ], tool_choice="required", tools=[ { "type": "shell", "environment": { "type": "container_auto", "network_policy": { "type": "allowlist", "allowed_domains": ["httpbin.org"], "domain_secrets": [ { "domain": "httpbin.org", "name": "API_KEY", "value": "debug-secret-123", } ], }, }, } ],)print(response.output_text)
Le shell distant et le shell local utilisent les mêmes types d’éléments de sortie. Chaque exécution du shell est représentée par une paire d’éléments de sortie :
shell_call : commandes demandées par le modèle.
shell_call_output : sortie des commandes et état de fin d’exécution.
Vous pouvez également lancer des commandes shell dans votre propre environnement d’exécution local en exécutant les actions shell_call, puis en renvoyant shell_call_output au modèle.
Utilisez ce mode si vous devez garder le contrôle du système de fichiers ou accéder à des outils internes. Choisissez shell comme type d’outil et local comme type d’environnement. Si vous migrez depuis l’ancien outil local_shell, désormais retiré, mettez à jour votre requête et traitez shell_call et shell_call_output dans votre boucle d’exécution.
Requête utilisant le shell local
curl
1
2
3
4
5
6
7
8
9curl-L'https://api.openai.com/v1/responses'\-H"Content-Type: application/json"\-H"Authorization: Bearer $OPENAI_API_KEY"\-d'{ "model": "gpt-6-astra", "instructions": "The local bash shell environment is on Mac.", "input": "find me the largest pdf file in ~/Documents", "tools": [{ "type": "shell", "environment": { "type": "local" } }] }'
1
2
3
4
5
6
7
8
9
10
11
12import OpenAI from "openai";const client = new OpenAI();const response = await client.responses.create({ model: "gpt-6-astra", instructions: "The local bash shell environment is on Mac.", input: "find me the largest pdf file in ~/Documents", tools: [{ type: "shell", environment: { type: "local" } }],});console.log(response);
1
2
3
4
5
6
7
8
9
10
11
12from openai import OpenAIclient = OpenAI()response = client.responses.create( model="gpt-6-astra", instructions="The local bash shell environment is on Mac.", input="find me the largest pdf file in ~/Documents", tools=[{"type": "shell", "environment": {"type": "local"}}],)print(response)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26package mainimport ( "context" "fmt" "github.com/openai/openai-go/v3" "github.com/openai/openai-go/v3/responses")func main() { client := openai.NewClient() tool := responses.ToolUnionParam{OfShell: &responses.FunctionShellToolParam{ Environment: responses.FunctionShellToolEnvironmentUnionParam{OfLocal: &responses.LocalEnvironmentParam{}}, }} response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{ Model: "gpt-6-astra", Instructions: openai.String("The local bash shell environment is on Mac."), Input: responses.ResponseNewParamsInputUnion{OfString: openai.String("find me the largest pdf file in ~/Documents")}, Tools: []responses.ToolUnionParam{tool}, }) if err != nil { panic(err) } fmt.Println(response.Output)}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22import com.openai.client.OpenAIClient;import com.openai.client.okhttp.OpenAIOkHttpClient;import com.openai.core.JsonValue;import com.openai.models.responses.ResponseCreateParams;import java.util.List;import java.util.Map;ResponseCreateParams params = ResponseCreateParams.builder() .model("gpt-6-astra") .input("Find the largest PDF in ~/Documents.") .instructions("The local shell environment is macOS.") .putAdditionalBodyProperty( "tools", JsonValue.from( List.of(Map.of("type", "shell", "environment", Map.of("type", "local"))))) .build();client.responses().create(params).output().stream() .flatMap(item -> item.shellCall().stream()) .flatMap(call -> call.action().commands().stream()) .forEach(System.out::println);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16require "openai"client = OpenAI::Client.newresponse = client.responses.create( model: "gpt-6-astra", instructions: "The local shell environment is macOS.", input: "Find the largest PDF in ~/Documents.", tools: [ { type: :shell, environment: { type: :local } } ])puts(response.output)
Lorsque vous recevez des éléments de sortie shell_call :
Examinez chaque commande avant de l’exécuter. Utilisez une liste de commandes autorisées et exigez une approbation pour les commandes destructrices ou celles qui accèdent à des données sensibles.
Exécutez les commandes approuvées dans un bac à sable. Limitez explicitement l’accès au système de fichiers et au réseau, la quantité de mémoire utilisable et la durée d’exécution. Appliquez votre propre délai d’expiration, même si le modèle en suggère un.
Consignez les commandes et leurs résultats à des fins d’audit.
Recueillez stdout, stderr et l’état de fin d’exécution.
Renvoyez les résultats sous la forme d’un élément shell_call_output dans la requête suivante.
Ces exemples nécessitent Linux ou macOS. À l’expiration du délai d’exécution d’une commande, ils arrêtent tout le groupe de processus de cette commande.
Si une commande échoue ou dépasse le délai d’exécution, renvoyez son état de fin d’exécution pour que le modèle puisse décider de réessayer ou non. Consultez l’avis de retrait de l’ancien outil.
Utilisez le shell local avec le SDK Agents
Si vous utilisez le SDK Agents, vous pouvez fournir votre propre implémentation de l’exécuteur de commandes shell à la fonction utilitaire de l’outil shell.
Si une commande dépasse le délai d’exécution fixé, signalez l’expiration du délai et joignez la sortie partielle recueillie.
Si max_output_length figure dans shell_call, incluez-le dans shell_call_output.
Évitez les commandes interactives. Les commandes de l’outil shell doivent pouvoir s’exécuter sans intervention.
Conservez la sortie des commandes qui se terminent avec un code de sortie non nul afin que le modèle puisse déterminer comment reprendre l’exécution.
Risques et sécurité
Activer l’accès réseau dans l’API Containers élargit considérablement les possibilités des conteneurs, mais présente des risques importants pour la sécurité et la gouvernance des données. L’accès réseau est désactivé par défaut. Si vous l’activez, limitez strictement l’accès sortant aux domaines de confiance nécessaires à la tâche.
Les conteneurs disposant d’un accès réseau peuvent interagir avec des services tiers et des registres de paquets. Ils sont ainsi exposés à des fuites de données, à un détournement des outils à la suite d’une attaque par injection de prompt ou à un accès accidentel à des ressources hors du périmètre prévu. Ces risques augmentent lorsque les règles sont trop larges, restent figées ou sont appliquées de manière inégale.
Identifiez les risques d’attaque par injection de prompt dans les contenus récupérés sur le réseau
Tout contenu externe récupéré sur le réseau peut renfermer des instructions dissimulées visant à manipuler le comportement du modèle. Traitez les contenus réseau provenant de sources non fiables comme potentiellement malveillants et redoublez de prudence pour les actions susceptibles de modifier des données ou des systèmes.
Connectez-vous uniquement à des destinations de confiance
Autorisez uniquement les domaines auxquels vous faites confiance et que vous maintenez activement. Faites preuve de prudence avec les intermédiaires et les agrégateurs qui relaient les requêtes vers d’autres services. Avant de les ajouter à votre liste de domaines autorisés, examinez leurs pratiques de traitement et de conservation des données.
Prévoyez des vérifications avant et après l’exécution des requêtes
Examinez la commande de l’outil shell et sa sortie, toutes deux fournies dans la réponse de l’API Responses. Pour chaque session, consignez les hôtes demandés et les destinations réelles des connexions sortantes. Examinez régulièrement les journaux pour vérifier que les accès correspondent à vos attentes, repérer les écarts au fil du temps et détecter les comportements suspects.
Vérifiez le respect des exigences de résidence et de conservation des données
Les contrôles des données d’OpenAI s’appliquent dans le périmètre d’OpenAI. Les données transmises à des services tiers via le réseau sont toutefois soumises aux politiques de conservation de ces services. Vérifiez que les points de terminaison externes répondent à vos exigences en matière de résidence des données, de conservation et de conformité.