Vue d’ensemble
Multi-agent permet à un modèle de créer et de coordonner des sous-agents en parallèle, puis de synthétiser leur travail pour fournir une réponse finale. Cette fonctionnalité est particulièrement efficace pour les applications dont les tâches complexes gagnent à être déléguées en parallèle, comme l’exploration du code source, la documentation et l’implémentation.
Multi-agent est disponible en version bêta avec tous les modèles GPT-5.6. Consultez la page du modèle avant d’activer Multi-agent dans votre application.
Quand utiliser Multi-agent
Les tâches peuvent souvent être divisées en parties indépendantes qu’un seul agent traiterait successivement, mais que plusieurs agents peuvent traiter en parallèle. Multi-agent permet à un agent racine de déléguer du travail à plusieurs sous-agents qui l’exécutent simultanément. Cette approche peut offrir plusieurs avantages :
- Exécution parallèle. Des tâches indépendantes de recherche, d’analyse ou d’implémentation peuvent avancer simultanément, ce qui peut accélérer l’exécution.
- Contexte ciblé. Chaque sous-agent reçoit une tâche bien délimitée et conserve son propre contexte, ce qui réduit les interférences entre les contextes de travaux sans rapport entre eux et améliore les performances.
- Coordination pilotée par le modèle. L’agent racine peut créer des sous-agents, leur envoyer des informations supplémentaires, attendre leurs résultats et en faire la synthèse pour fournir une réponse finale, sans que votre application ait à implémenter l’orchestration.
L’orchestration Multi-agent est surtout utile lorsqu’une tâche peut être divisée en travaux concrets et indépendants, par exemple :
- L’exploration de différentes parties d’une vaste base de code
- La comparaison de plusieurs propositions, documents ou hypothèses
- La recherche dans plusieurs sources en parallèle
- L’implémentation de composants indépendants ou l’écriture de suites de tests indépendantes
- L’étude en parallèle de différentes causes possibles d’une défaillance
- L’exploration simultanée de différentes approches d’un problème
L’ajout de sous-agents peut augmenter la consommation de tokens et s’avérer moins avantageux pour les tâches qui reposent sur une seule séquence ordonnée de raisonnement, nécessitent des écritures fréquentes dans un état partagé modifiable ou dont la durée est déjà dominée par une seule opération externe lente.
| Utilisez Multi-agent lorsque | Privilégiez un seul agent lorsque |
|---|---|
| Le travail peut être réparti en tâches indépendantes et bien délimitées | Chaque étape dépend directement de la précédente |
| Des contextes distincts aident les agents à rester concentrés sur leur tâche | La tâche est assez limitée pour être accomplie en une seule exécution courte |
| L’exploration parallèle peut réduire le temps total écoulé | Les agents se disputeraient l’accès à une même ressource modifiable |
| La comparaison de résultats indépendants permet de couvrir davantage d’aspects | Vous avez besoin d’un graphe d’exécution fixe et déterministe |
Démarrage rapide
Les exemples Python et JavaScript utilisent le SDK Responses en version bêta. Pour les requêtes
HTTP, utilisez client.beta.responses et passez responses_multi_agent=v1 dans
l’argument betas. Pour les requêtes HTTP brutes et les connexions WebSocket, passez
OpenAI-Beta: responses_multi_agent=v1 dans les en-têtes de la requête ou de la connexion.
Les schémas des éléments peuvent évoluer tant que Multi-agent est en version bêta.
Activez Multi-agent dans votre requête à l’API Responses avec multi_agent.enabled. Lorsque multi_agent.enabled vaut true, l’agent racine peut créer une arborescence de sous-agents. Les sous-agents partagent le modèle et les outils disponibles de la requête. Les agents se coordonnent à l’aide de primitives de collaboration telles que la création de sous-agents, la messagerie et l’attente (voir Fonctionnement de Multi-agent). L’agent racine se charge de synthétiser les réponses des sous-agents et de fournir la réponse finale.
from openai import OpenAI
client = OpenAI()
def review_pull_request(diff: str) -> str:
response = client.beta.responses.create(
model="gpt-5.6-sol",
input=(
"Review the pull-request diff below with three agents: one for "
"correctness, one for security, and one for missing tests. "
"Reconcile duplicate or conflicting findings, then return a "
"prioritized review with file and line references.\n\n"
f"<diff>\n{diff}\n</diff>"
),
multi_agent={
"enabled": True,
"max_concurrent_subagents": 3,
},
betas=["responses_multi_agent=v1"],
)
return "".join(
part.text
for item in response.output
if (
item.type == "message"
and item.agent is not None
and item.agent.agent_name == "/root"
and item.phase == "final_answer"
)
for part in item.content
if part.type == "output_text"
)max_concurrent_subagents définit le nombre maximal de sous-agents pouvant être actifs simultanément dans l’ensemble de l’arborescence des agents. Ce nombre inclut tous les descendants, enfants, petits-enfants et sous-agents de niveaux plus profonds, mais exclut l’agent racine.
L’API n’impose pas de limite supérieure fixe à ce paramètre. Sa valeur par défaut est 3, ce qui est recommandé pour la plupart des charges de travail. Les exécutions Multi-agent n’imposent pas non plus de limite fixe à la profondeur de l’arborescence ni au nombre total de sous-agents créés au cours d’une exécution.
Ajoutez un message développeur pour préciser dans quels cas le modèle racine doit créer des sous-agents. Ce message s’ajoute aux instructions injectées pour l’agent racine et les sous-agents.
Voici quelques exemples de messages développeur :
- « Ne créez pas de sous-agents à moins que l’utilisateur ne demande explicitement des sous-agents, une délégation ou un travail parallèle entre agents. »
- « La délégation proactive Multi-agent est active. Utilisez des sous-agents lorsque le travail parallèle améliorerait sensiblement la rapidité ou la qualité. »
Fonctionnement de Multi-agent
L’API Responses fournit au modèle de l’agent racine et à ceux des sous-agents des actions d’orchestration hébergées ainsi que des instructions pour les utiliser. L’agent racine se nomme /root. Les sous-agents créés utilisent des chemins hiérarchiques tels que :
/root
├── /root/researcher
├── /root/reviewer
└── /root/reviewer/tester
Multi-agent n’impose aucune limite fixe au nombre total de sous-agents ni à la profondeur de l’arborescence. Pour la plupart des tâches, utilisez la valeur par défaut de max_concurrent_subagents, soit 3. Ce paramètre limite le nombre de tours actifs des sous-agents dans l’ensemble de l’arborescence, y compris les enfants et les descendants de niveaux plus profonds.
Lorsque le mode Multi-agent est activé, l’API Responses fournit six actions de collaboration hébergées. Elles peuvent apparaître sous forme d’éléments multi_agent_call. Votre application ne doit ni les exécuter ni soumettre de sorties pour ces actions.
| Action | Fonction |
|---|---|
spawn_agent | Créez un sous-agent et attribuez-lui sa tâche initiale. |
send_message | Mettez un message en file d’attente pour un agent existant sans démarrer un nouveau tour. |
followup_task | Attribuez du travail supplémentaire à un agent existant autre que l’agent racine, puis démarrez ou reprenez son tour. |
wait_agent | Attendez une mise à jour dans la boîte de réception de l’agent appelant. |
interrupt_agent | Interrompez le tour actif d’un autre agent sans supprimer son contexte. |
list_agents | Renvoyez l’arborescence actuelle des agents, leurs états et la valeur de last_task_message de chaque agent. |
Le traitement des appels aux outils définis par le développeur fonctionne de la même manière que lorsque Multi-agent est désactivé. N’importe quel agent de l’arborescence peut émettre un function_call. Votre application doit exécuter cet appel et soumettre le function_call_output correspondant.
Tous les agents de l’arborescence ont accès aux outils configurés pour l’appel au modèle dans la requête API.
Utilisation de Multi-agent dans l’API Responses
Comparaison des performances HTTP et WebSocket
HTTP et WebSocket prennent en charge les mêmes capacités Multi-agent, mais WebSocket est recommandé pour les workflows qui font un usage intensif des outils ou qui durent longtemps. Sa connexion persistante permet à votre application de renvoyer les sorties des fonctions dès qu’elles sont disponibles, ce qui réduit le surcoût lié aux requêtes de continuation et le temps d’attente des agents.
Avec HTTP, la réponse se termine lorsque chaque agent actif a soit terminé, soit suspendu son travail pour attendre un appel de fonction exécuté côté client. Votre application exécute alors tous les appels de fonction en attente et soumet leurs sorties dans une nouvelle requête à l’API Responses, ce qui permet aux agents en pause de reprendre leur travail.
Avec WebSocket, votre application peut injecter chaque sortie de fonction dans la réponse dès qu’elle est disponible, sans attendre la fin de la réponse active. L’agent en attente peut reprendre immédiatement pendant que les autres continuent leur travail. Cela réduit les délais de coordination et évite des allers-retours de requêtes supplémentaires lorsque les agents terminent ou sollicitent des outils à des moments différents.
HTTP peut suffire pour les workflows qui nécessitent d’appeler plusieurs outils hébergés, comme des recherches web en parallèle, ou pour les workflows à requête unique comportant peu d’appels de fonction. Pour la plupart des workflows Multi-agent, WebSocket devrait offrir une latence plus faible et de meilleures performances de bout en bout.
Exécution des appels de fonction via HTTP

Exécution des appels de fonction via WebSocket

HTTP
Ces exemples nécessitent des versions bêta des SDK qui donnent accès à l’API Responses en bêta. Pour le streaming HTTP, appelez client.beta.responses.create et transmettez responses_multi_agent=v1 via l’argument betas ; cela active les types bêta et l’autocomplétion. En Python, importez les types bêta des éléments de réponse depuis openai.types.beta lorsque vous ajoutez des annotations de type.
Exemple de code côté client :
from __future__ import annotations
import json
import sys
from openai import OpenAI
from openai.types.beta import BetaResponseOutputItem
client = OpenAI()
ROOT = "/root"
PROPOSALS = {
"alpha": {"estimated_weeks": 6, "risk": "medium"},
"beta": {"estimated_weeks": 8, "risk": "low"},
}
tools = [
{
"type": "function",
"name": "get_proposal",
"description": "Return details for a proposal that the agents should compare.",
"parameters": {
"type": "object",
"properties": {
"proposal": {
"type": "string",
"enum": ["alpha", "beta"],
}
},
"required": ["proposal"],
"additionalProperties": False,
},
"strict": True,
}
]
history = [
{
"role": "user",
"content": "Compare proposal alpha and proposal beta.",
}
]
def agent_name(item: BetaResponseOutputItem) -> str:
return item.agent.agent_name if item.agent else ROOT
def render_to_user(delta: str) -> None:
print(delta, end="", flush=True)
def log_subagent_text(agent: str, delta: str) -> None:
print(f"[{agent}] {delta}", end="", file=sys.stderr, flush=True)
def process_tool_call(name: str, arguments: str) -> str:
if name != "get_proposal":
raise ValueError(f"Unknown tool: {name}")
parsed_arguments = json.loads(arguments)
return json.dumps(PROPOSALS[parsed_arguments["proposal"]])
while True:
output_items = []
pending_calls = []
item_agents: dict[int, str] = {}
stream = client.beta.responses.create(
model="gpt-5.6-sol",
input=history,
tools=tools,
store=False,
multi_agent={
"enabled": True,
"max_concurrent_subagents": 3,
},
stream=True,
betas=["responses_multi_agent=v1"],
)
for event in stream:
if event.type == "response.output_item.added":
item_agents[event.output_index] = agent_name(event.item)
elif event.type == "response.output_text.delta":
agent = item_agents.get(event.output_index, ROOT)
if agent == ROOT:
render_to_user(event.delta)
else:
log_subagent_text(agent, event.delta)
elif event.type == "response.output_item.done":
output_items.append(event.item)
if event.item.type == "function_call":
# Handle function calls from both the root agent and subagents.
pending_calls.append(event.item)
elif event.type == "response.completed":
print(f"\nUsage: {event.response.usage}", file=sys.stderr)
break
elif event.type in {
"error",
"response.failed",
"response.incomplete",
}:
raise RuntimeError(event)
history.extend(output_items)
for call in pending_calls:
history.append(
{
"type": "function_call_output",
"call_id": call.call_id,
"output": process_tool_call(call.name, call.arguments),
}
)
if not pending_calls:
breakSi un ou plusieurs agents appellent des fonctions définies par le développeur, exécutez tous les appels en attente et créez une requête de continuation contenant leurs résultats.
WebSocket
En mode WebSocket, lorsqu’un agent appelle une fonction définie par le développeur, exécutez-la dans votre application et envoyez son résultat à la réponse active avec un événement response.inject. L’agent en attente peut alors reprendre son travail sans attendre que la réponse Multi-agent soit entièrement terminée.
{
"type": "response.inject",
"response_id": "resp_123",
"input": [
{
"type": "function_call_output",
"call_id": "call_123",
"output": "{\"temperature\":72}"
}
]
}
Pour une requête response.inject valide, le serveur renvoie l’un des deux événements suivants :
response.inject.created: les données d’entrée ont été validées et acceptées pour injectionresponse.inject.failed: les données d’entrée n’ont pas été injectées ; examinezerror.code
{
"type": "response.inject.created",
"sequence_number": 42,
"response_id": "resp_123"
}
{
"type": "response.inject.failed",
"sequence_number": 43,
"response_id": "resp_123",
"input": [
{
"type": "function_call_output",
"call_id": "call_123",
"output": "{\"temperature\":72}"
}
],
"error": {
"code": "response_already_completed",
"message": "Response 'resp_123' has already completed."
}
}
Si une requête ne respecte pas le schéma response.inject, le serveur envoie une erreur générique avec le code d’état 400 et ferme la connexion WebSocket. Corrigez la requête et ouvrez une nouvelle connexion WebSocket avant d’envoyer un autre événement.
Le SDK Python en bêta donne accès au mode WebSocket via client.beta.responses.connect. Le SDK TypeScript en bêta y donne accès via ResponsesWS. Transmettez OpenAI-Beta: responses_multi_agent=v1 dans les en-têtes de connexion ; contrairement au streaming HTTP, les connecteurs WebSocket n’acceptent pas encore l’argument betas.
Enregistrez l’identifiant de réponse fourni par l’événement response.created et incluez-le dans chaque événement response.inject que vous envoyez pour cette réponse. Après avoir envoyé un élément à injecter, continuez à lire les événements de la connexion WebSocket jusqu’à ce que la réponse soit terminée et que chaque injection ait produit un événement response.inject.created ou response.inject.failed.
from __future__ import annotations
import json
from openai import OpenAI
client = OpenAI()
PROPOSALS = {
"alpha": {"estimated_weeks": 6, "risk": "medium"},
"beta": {"estimated_weeks": 8, "risk": "low"},
}
tools = [
{
"type": "function",
"name": "get_proposal",
"description": "Return details for a proposal that the agents should compare.",
"parameters": {
"type": "object",
"properties": {
"proposal": {
"type": "string",
"enum": ["alpha", "beta"],
}
},
"required": ["proposal"],
"additionalProperties": False,
},
"strict": True,
}
]
def process_tool_call(name: str, arguments: str) -> str:
if name != "get_proposal":
raise ValueError(f"Unknown tool: {name}")
parsed_arguments = json.loads(arguments)
return json.dumps(PROPOSALS[parsed_arguments["proposal"]])
def run_multi_agent(connection):
previous_response_id: str | None = None
pending_input: list[dict[str, object]] = [{"role": "user", "content": input()}]
while pending_input:
request = {
"type": "response.create",
"model": "gpt-5.6-sol",
"store": True,
"multi_agent": {"enabled": True},
"tools": tools,
"input": pending_input,
}
if previous_response_id is not None:
request["previous_response_id"] = previous_response_id
connection.send(request)
next_input: list[dict[str, object]] = []
completed_response = None
response_id: str | None = None
pending_injections = 0
for event in connection:
event_type = event.type
if event_type == "response.created":
response_id = event.response.id
elif event_type == "response.output_item.done":
item = event.item
if item.type == "function_call":
if response_id is None:
raise RuntimeError(
"Received a function call before response.created"
)
output = {
"type": "function_call_output",
"call_id": item.call_id,
"output": process_tool_call(item.name, item.arguments),
}
pending_injections += 1
connection.send(
{
"type": "response.inject",
"response_id": response_id,
"input": [output],
}
)
elif event_type == "response.inject.created":
pending_injections -= 1
elif event_type == "response.inject.failed":
pending_injections -= 1
if event.error.code != "response_already_completed":
raise RuntimeError(event.error)
next_input.extend(item.model_dump(mode="json") for item in event.input)
elif event_type == "response.completed":
completed_response = event.response
elif event_type in {
"error",
"response.failed",
"response.incomplete",
}:
raise RuntimeError(event)
if completed_response is not None and pending_injections == 0:
break
if completed_response is None:
raise RuntimeError("Connection ended before response.completed")
if not next_input:
return completed_response
previous_response_id = completed_response.id
pending_input = next_input
with client.beta.responses.connect(
extra_headers={"OpenAI-Beta": "responses_multi_agent=v1"},
) as connection:
run_multi_agent(connection)Après avoir envoyé un événement response.inject, continuez à lire les événements de la connexion WebSocket et traitez l’accusé de réception :
response.inject.created: le résultat de la fonction a été ajouté à la réponse active. Continuez à lire les événements de cette réponse.response.inject.failedavecresponse_already_completed: la réponse s’est terminée avant que le résultat de la fonction puisse être ajouté. Récupérez la valeur deinputrenvoyée dans l’événement d’échec et envoyez-la dans une nouvelle requêteresponse.createqui poursuit l’exécution à partir de la réponse terminée.response.inject.failedavecresponse_not_found: le serveur n’a pas trouvé la réponse correspondant àresponse_id. Vérifiez que vous utilisez l’identifiant reçu dansresponse.created.
Une même exécution Multi-agent peut s’étendre sur plusieurs requêtes à l’API Responses. Avec HTTP, lorsqu’un agent appelle une fonction définie par le développeur, votre application exécute la fonction et transmet son résultat dans un nouvel appel response.create. Avec WebSocket, votre application injecte directement le résultat de la fonction dans la réponse active.
Nouveaux éléments de sortie Multi-agent
Les réponses Multi-agent peuvent inclure trois types d’éléments de sortie supplémentaires :
multi_agent_call: consigne une action Multi-agent hébergée, telle quespawn_agent.multi_agent_call_output: contient le résultat de l’exécution d’une action hébergée.agent_message: transmet un message chiffré d’un agent à un autre.
Le champ call_id relie chaque multi_agent_call au multi_agent_call_output correspondant.
Chaque élément inclut également un attribut agent. Pour un élément agent_message, agent.agent_name identifie l’agent destinataire. Utilisez author et recipient pour déterminer le sens de transmission du message.
Lorsque votre application reçoit un élément multi_agent_call, ne l’exécutez pas comme un appel de fonction et ne renvoyez pas de résultat. L’API Responses exécute l’action hébergée et renvoie le multi_agent_call_output correspondant. Conservez les deux éléments si votre application en a besoin pour rejouer l’exécution ou en assurer le traçage.
[
{
"type": "multi_agent_call",
"id": "mac_123",
"call_id": "call_spawn_a",
"action": "spawn_agent",
"arguments": "{\"task_name\":\"agent_a\",\"fork_turns\":\"all\",\"message\":\"enc_...\"}",
"agent": { "agent_name": "/root" }
},
{
"type": "multi_agent_call_output",
"id": "maco_123",
"call_id": "call_spawn_a",
"action": "spawn_agent",
"output": [
{
"type": "output_text",
"text": "{\"task_name\":\"/root/agent_a\"}",
"annotations": [],
"logprobs": []
}
],
"agent": { "agent_name": "/root" }
},
{
"type": "agent_message",
"id": "amsg_123",
"author": "/root/agent_a",
"recipient": "/root",
"content": [
{
"type": "encrypted_content",
"encrypted_content": "enc_..."
}
],
"agent": { "agent_name": "/root" }
}
]
Les événements SSE attribués à un agent incluent un attribut agent au premier niveau. Pour un événement agent_message, agent.agent_name identifie l’agent destinataire. Les événements du cycle de vie de la réponse, tels que response.created et response.completed, décrivent la réponse dans son ensemble plutôt qu’un agent particulier ; ils n’incluent donc pas d’attribut agent.
{
"type": "response.output_item.done",
"agent": { "agent_name": "/root" },
"item": {
"type": "agent_message",
"id": "amsg_123",
"author": "/root/agent_a",
"recipient": "/root",
"content": [
{
"type": "encrypted_content",
"encrypted_content": "enc_..."
}
],
"agent": { "agent_name": "/root" }
}
}
Limites
- Compactage :
- Le point de terminaison
/responses/compactn’est pas pris en charge lorsque Multi-agent est activé. - Lorsque
multi_agent.enabledest défini surtrue, le compactage automatique côté serveur est activé implicitement, même si la requête ne configure pascontext_management. Le compactage s’applique indépendamment à l’agent racine et à chaque sous-agent, en préservant leurs contextes distincts. Les utilisateurs peuvent toujours modifiercompact_thresholden définissant explicitementcontext_management.compact_thresholddans la requête.
- Le point de terminaison
reasoning.summaryn’est pas pris en charge lorsque Multi-agent est activé.max_tool_callsn’est pas pris en charge lorsque Multi-agent est activé.- La valeur par défaut de
max_concurrent_subagentsest3, qui est la valeur recommandée.
Conseils pour les prompts
Lorsque Multi-agent est activé, nos systèmes ajoutent automatiquement ces instructions à l’agent racine et aux sous-agents sous la forme d’un nouveau message développeur. Vous ne pouvez ni modifier ni supprimer ces instructions. Rédigez vos propres instructions développeur de manière à compléter celles qui sont injectées automatiquement.
Agent racine
You are `/root`, the primary agent in a team of agents collaborating to fulfill the user's goals.
At the start of your turn, you are the active agent.
You can spawn sub-agents to handle subtasks, and those sub-agents can spawn their own sub-agents.
All agents in the team, including the agents that you can assign tasks to, are equally intelligent and capable, and have access to the same set of tools.
You can use `spawn_agent` to create a new agent, `followup_task` to give an existing agent a new task and trigger a turn, and `send_message` to pass a message to a running agent without triggering a turn.
Child agents can also spawn their own sub-agents.
You can decide how much context you want to propagate to your sub-agents with the `fork_turns` parameter.
You will receive messages in the form:
```
Message Type: MESSAGE | FINAL_ANSWER
Task name: <recipient>
Sender: <author>
Payload:
<payload text>
```
They may be addressed as to=/root
There are {max_concurrent_subagents + 1} available concurrency slots, meaning that up to {max_concurrent_subagents + 1} agents can be active at once, including you.
Sous-agent
You are an agent in a team of agents collaborating to complete a task.
You can spawn sub-agents to handle subtasks, and those sub-agents can spawn their own sub-agents. All agents in the team, including the agents that you can assign tasks to, are equally intelligent and capable, and have access to the same set of tools.
You can use `spawn_agent` to create a new agent, `followup_task` to give an existing agent a new task and trigger a turn, and `send_message` to pass a message to a running agent.
Child agents can also spawn their own sub-agents.
When you provide a response in the final channel, that content is immediately delivered back to your parent agent.
You will receive messages in the form:
```
Message Type: NEW_TASK | MESSAGE | FINAL_ANSWER
Task name: <recipient>
Sender: <author>
Payload:
<payload text>
```
You may also see them addressed as to=/root/..., which indicates your identity is /root/...
There are {max_concurrent_subagents + 1} available concurrency slots, meaning that up to {max_concurrent_subagents + 1} agents can be active at once, including you.