Administración de sesiones del agente hospedado

En este artículo se muestra cómo administrar sesiones para agentes hospedados en el servicio de agente Foundry. Una sesión es un espacio aislado con estado asociado a una sola carga de trabajo lógica (por ejemplo, el chat de un usuario). La plataforma conserva el sistema de archivos de la sesión ($HOME y los archivos cargados) entre turnos y períodos inactivos, por lo que el agente puede reanudar dónde se dejó. Las sesiones se conservan durante un máximo de 30 días, con un tiempo de espera de inactividad de 15 minutos que desaprovisiona el cómputo y guarda el estado hasta que se vuelva a referenciar la sesión. Para obtener más información, consulte Agentes hospedados en el servicio de agente Foundry.

Sesiones versus conversaciones

Las sesiones y las conversaciones son conceptos distintos en el servicio Foundry Agent.

Aspecto Sesión Conversación
Lo que representa Computación de espacio aislado y sistema de archivos persistente ($HOME, /files) Historial de mensajes, llamadas a herramientas y respuestas
Identificador agent_session_id previous_response_id o conversation (solo protocolo de respuestas)
Se utiliza para Cargas de archivos, estado de trabajo entre turnos Integración de los turnos de chat
Administrado por La plataforma, a través de la /sessions API La plataforma (Respuestas); el código de contenedor (invocaciones)

La /sessions API de este artículo funciona de la misma manera para los agentes de protocolo de respuestas y protocolo de invocaciones. Lo que difiere es cómo se enlaza una invocación por llamada a una sesión y si la plataforma almacena el historial de conversaciones:

  • Protocolo de respuestas. La continuidad de la conversación no procede del identificador de sesión, sino de previous_response_id o de un ID de conversation. Reutilizar el mismo agent_session_id no reproduce automáticamente los mensajes previos al modelo. Tiene dos formas de encadenar las respuestas por turnos:

    • previous_response_id. Encadene cada nueva respuesta al identificador de la respuesta anterior. Sin estado en el cliente. Cada llamada sin un agent_session_id explícito cae en un nuevo espacio aislado, así que incluya agent_session_id también cuando necesite reutilizar los archivos cargados o el estado $HOME.
    • conversation. Cree un objeto de conversación una vez a través de POST .../endpoint/protocols/openai/conversations, y a continuación, pase su id en cada llamada responses.create. La plataforma almacena el historial de mensajes bajo ese identificador de conversación, y un agent_session_id persistente se asocia automáticamente a la conversación. Las llamadas posteriores reutilizan el mismo espacio aislado sin tener que realizar un seguimiento del identificador de sesión.
  • Protocolo de invocaciones. La plataforma no almacena el historial de conversaciones; el contenedor administra cualquier estado que el agente necesite durante las interacciones. Las sesiones siguen siendo útiles para la persistencia de /uploaded-file y como un identificador estable que el código puede usar para buscar su propio estado por sesión.

Propina

El reenvío de agent_session_id en las llamadas de seguimiento los vincula al mismo espacio aislado. Los puntos de conexión de invocación no deducen la sesión solo de previous_response_id. Solo necesita ese enlace cuando, en etapas posteriores, deba ver los archivos cargados a través del punto de conexión de la sesión /files o el estado al que escribió el agente $HOME. En el caso de invocaciones completamente sin estado, puede dejar que cada llamada reciba una sesión nueva.

Cómo enlaza cada protocolo una invocación a una sesión

Los dos puntos finales de invocación aceptan el ID de sesión en ubicaciones diferentes. Utilice el mecanismo que se muestra para el protocolo que está utilizando.

Protocolo Punto de conexión Dónde colocar agent_session_id
Respuestas POST .../endpoint/protocols/openai/responses Campo de cuerpo agent_session_id de la solicitud (o use el campo conversation, que se une automáticamente a una sesión)
Invocaciones POST .../endpoint/protocols/invocations Parámetro de cadena de consulta ?agent_session_id=<id>

En Invocaciones, la plataforma solo lee el parámetro de consulta. Los campos denominados agent_session_id o session_id en el cuerpo de la solicitud y los encabezados como x-agent-session-id se pasan al contenedor sin modificar, pero no influyen en el espacio aislado al que se enruta la plataforma.

Requisitos previos

  • CLI de Azure versión 2.80 o posterior, autenticado con az login.
  • SDK de Python: azure-ai-projects>=2.1.0 y azure-identity.

Configurar variables

En los ejemplos de la API REST de este artículo se usa az rest para llamar directamente a los puntos de conexión del Servicio de Agente Foundry. Establezca las siguientes variables antes de ejecutar los comandos:

ACCOUNT_NAME="<your-foundry-account-name>"
PROJECT_NAME="<your-project-name>"
BASE_URL="https://${ACCOUNT_NAME}.services.ai.azure.com/api/projects/${PROJECT_NAME}"
API_VERSION="v1"
RESOURCE="https://ai.azure.com"

Importante

El --resource parámetro es necesario para todas las llamadas a los az rest puntos de conexión del plano de datos del servicio Foundry Agent. Sin ella, az rest no puede derivar la audiencia de Microsoft Entra correcta de la dirección URL y se produce un error en la autenticación.

Nota

Las operaciones de sesión son una característica en versión preliminar. Incluya el Foundry-Features: HostedAgents=V1Preview encabezado en cada solicitud REST.

Configuración del cliente

Todos los ejemplos de Python de este artículo usan la siguiente configuración de cliente:

from azure.identity import DefaultAzureCredential
from azure.ai.projects import AIProjectClient

project = AIProjectClient(
    endpoint="<your-project-endpoint>",
    credential=DefaultAzureCredential(),
    allow_preview=True,
)

Nota

Las operaciones de sesión se exponen en el project.beta.agents subclient. Las llamadas a project.beta.agents funcionan sin allow_preview=True, pero project.get_openai_client(agent_name=...), que se usan en este artículo para invocar agentes de protocolo de respuestas, requiere allow_preview=True y genera ValueError sin él.

Invoque un agente y permita que la plataforma cree la sesión

Para la mayoría de los agentes, no es necesario crear una sesión de antemano. Cuando se invoca al agente sin agent_session_id, el servicio crea uno y lo devuelve en la respuesta. Capture ese identificador y páselo en llamadas posteriores cuando desee que las invocaciones posteriores compartan el mismo estado de espacio aislado; por ejemplo, los archivos que cargue a través del /files punto de conexión.

Nota

La continuidad de la sesión no es la misma que la continuidad de la conversación. En Respuestas, conserve el historial de mensajes a través de turnos pasando previous_response_id o un conversation identificador. Para las invocaciones, la plataforma no almacena el historial, así que el código del contenedor es responsable de realizar el seguimiento de cualquier estado por sesión. En ambos casos, agent_session_id solo vincula las llamadas al mismo sandbox.

Protocolo de respuestas

El punto de conexión de Respuestas devuelve una sola carga útil JSON o una secuencia de eventos Server-Sent Events (SSE), en función del campo stream del cuerpo de la solicitud. El valor predeterminado es false. Configúrelo "stream": true para recibir eventos incrementales.

AGENT_NAME="my-agent"

az rest --method POST \
    --url "${BASE_URL}/agents/${AGENT_NAME}/endpoint/protocols/openai/responses?api-version=${API_VERSION}" \
    --resource "${RESOURCE}" \
    --headers "Foundry-Features=HostedAgents=V1Preview" \
    --body '{
        "input": "Find me hotels in Seattle under $200 per night",
        "stream": false
    }'

La carga de respuesta incluye la agent_session_id plataforma creada. Para seguir usando esa sesión en una llamada posterior cuando se manejen subprocesos con previous_response_id, incluya agent_session_id en el cuerpo de la solicitud.

az rest --method POST \
    --url "${BASE_URL}/agents/${AGENT_NAME}/endpoint/protocols/openai/responses?api-version=${API_VERSION}" \
    --resource "${RESOURCE}" \
    --headers "Foundry-Features=HostedAgents=V1Preview" \
    --body '{
        "input": "Recommend one of those hotels",
        "stream": false,
        "agent_session_id": "<session-id-from-first-response>",
        "previous_response_id": "<id-from-first-response>"
    }'

Si convierte el hilo en un identificador conversation en su lugar, la plataforma enruta automáticamente cada llamada de esa conversación a la misma agent_session_id. No necesitas pasar agent_session_id tú mismo.

Cuando llamas a get_openai_client con un agent_name, el cliente de OpenAI devuelto se enruta al punto de conexión del agente. La primera llamada crea la sesión; la respuesta incluye el nuevo agent_session_id en model_extra.

openai_client = project.get_openai_client(agent_name="my-agent")

response = openai_client.responses.create(
    input="Find me hotels in Seattle under $200 per night",
)
session_id = response.model_extra.get("agent_session_id")
print(f"Session: {session_id}")
print(f"Response: {response.output_text}")

# Reuse the session and thread the conversation on a later turn.
follow_up = openai_client.responses.create(
    input="Recommend one of those hotels",
    previous_response_id=response.id,
    extra_body={"agent_session_id": session_id},
)
print(follow_up.output_text)

Si el subproceso gira con un conversation identificador en lugar de previous_response_id, la plataforma enruta automáticamente cada llamada de esa conversación a la misma agent_session_id, puede omitir extra_body={"agent_session_id": ...}:

conversation = openai_client.conversations.create()

first = openai_client.responses.create(
    input="Find me hotels in Seattle under $200 per night",
    extra_body={"conversation": conversation.id},
)
follow_up = openai_client.responses.create(
    input="Recommend one of those hotels",
    extra_body={"conversation": conversation.id},
)
azd ai agent invoke --input "Find me hotels in Seattle under $200 per night"

Protocolo de invocaciones

Los agentes de invocaciones aceptan cuerpos de solicitud JSON arbitrarios que coinciden con el esquema que define el contenedor. La plataforma enruta la llamada a una sesión y reenvía el contenido a tu contenedor; el formato de respuesta se corresponde con lo que emite el contenedor. Los agentes de ejemplo y los contenedores creados con el azure-ai-agentserver-invocations SDK devuelven una secuencia SSE por defecto, con un evento terminal done que lleva el session_id (el mismo valor que agent_session_id) y un invocation_id. Su propio contenedor puede devolver JSON, NDJSON, SSE o cualquier otro tipo de contenido.

La primera llamada sin un agent_session_id parámetro de consulta crea una nueva sesión. Para reutilizar el sandbox en una llamada posterior, pase el identificador de sesión como parámetro de consulta agent_session_id.

AGENT_NAME="my-agent"

# First call — platform creates a new session.
az rest --method POST \
    --url "${BASE_URL}/agents/${AGENT_NAME}/endpoint/protocols/invocations?api-version=${API_VERSION}" \
    --resource "${RESOURCE}" \
    --headers "Foundry-Features=HostedAgents=V1Preview" \
    --body '{"input": "Hello"}'

En el caso de un contenedor emisor de SSE como los ejemplos de Agent Service, el evento final done lleva session_id y invocation_id. Para reutilizar ese espacio aislado en una llamada posterior, pase el identificador de sesión como el parámetro de consulta agent_session_id:

SESSION_ID="<session_id-from-first-response>"

az rest --method POST \
    --url "${BASE_URL}/agents/${AGENT_NAME}/endpoint/protocols/invocations?api-version=${API_VERSION}&agent_session_id=${SESSION_ID}" \
    --resource "${RESOURCE}" \
    --headers "Foundry-Features=HostedAgents=V1Preview" \
    --body '{"input": "Continue our previous discussion"}'

Importante

El punto de conexión Invocations lee el identificador de sesión de la cadena de consulta. Los campos denominados agent_session_id o session_id en el cuerpo de la solicitud y los encabezados, como x-agent-session-id, se reenvían al contenedor sin modificaciones, pero no cambian a qué espacio aislado se enruta la plataforma.

El SDK de Python no proporciona un cliente de invocaciones tipado. Llame al punto de conexión con requests (o cualquier biblioteca HTTP) y autentíquese con un token de portador desde azure-identity:

import json
import requests
from azure.identity import DefaultAzureCredential

credential = DefaultAzureCredential()
token = credential.get_token("https://ai.azure.com/.default").token
headers = {
    "Authorization": f"Bearer {token}",
    "Foundry-Features": "HostedAgents=V1Preview",
    "Content-Type": "application/json",
}

base = "<your-project-endpoint>/agents/my-agent/endpoint/protocols/invocations?api-version=v1"

# First call — platform creates a new session.
response = requests.post(base, headers=headers, data=json.dumps({"input": "Hello"}))
for line in response.iter_lines(decode_unicode=True):
    if line.startswith("data:"):
        event = json.loads(line[len("data:"):].strip())
        if event.get("type") == "done":
            session_id = event["session_id"]

# Reuse the session on a later call.
requests.post(
    f"{base}&agent_session_id={session_id}",
    headers=headers,
    data=json.dumps({"input": "Continue our previous discussion"}),
)
azd ai agent invoke --input '{"input": "Hello"}'

Claves de aislamiento

La clave de aislamiento es un valor de delimitación asociado a cada sesión. Cada sesión pertenece exactamente a una clave de aislamiento y la plataforma enruta las solicitudes de sesión para que un llamante solo vea y opere en sesiones etiquetadas con la clave que proporciona la solicitud. La misma clave se aplica de forma coherente en todos los puntos de conexión relacionados con la sesión, independientemente del protocolo que use el agente:

  • POST/GET/DELETE .../endpoint/sessions[/{id}]
  • POST .../endpoint/protocols/openai/responses (Agentes de respuesta)
  • POST .../endpoint/protocols/invocations (Agentes de invocaciones)
  • PUT/GET/DELETE .../endpoint/sessions/{id}/files[/content]

La clave de aislamiento es un valor de creación de particiones, no un mecanismo de autenticación o autorización. El token de Microsoft Entra en la solicitud autentica al llamante y autoriza la llamada según las asignaciones de roles del proyecto. La clave de aislamiento solo limita las sesiones en las que actúa el llamante autenticado. Aplique los propios controles de acceso de la aplicación en una capa superior al punto de conexión del agente cuando necesite decidir qué usuarios pueden actuar en qué claves.

La forma en que se establece la clave depende del esquema de autorización del punto de conexión del agente, que se configura al configurar el agente (consulte Configuración de un agente):

  • Entra (valor predeterminado). La plataforma deriva la clave de aislamiento desde el token de Microsoft Entra del emisor de la llamada. El x-ms-user-isolation-key encabezado se acepta pero se omite. Cada llamador autenticado obtiene automáticamente su propio ámbito.
  • Header. La plataforma lee la clave de aislamiento del encabezado de solicitud x-ms-user-isolation-key . Envíe una cadena estable por propietario de sesión (por ejemplo, un identificador de usuario final o de inquilino) en cada solicitud de sesión, incluidas las invocaciones y las operaciones de archivo. Se produce un error en las solicitudes sin el encabezado. La plataforma no valida el valor, por lo que el cliente es responsable de elegir la clave adecuada para cada llamada.

Crear una sesión explícitamente (avanzada)

Cree una sesión de antemano solo cuando necesite:

  • Suba los archivos a la caja de arena (/files) antes de la primera intervención del agente.
  • Asignar previamente una sesión a la que puede hacer referencia desde el código de cliente antes de la primera invocación.
  • Fije la sesión a una versión específica del agente con version_indicator. Cada sesión está enlazada a una sola versión en el momento de la creación. De forma predeterminada, la plataforma resuelve la versión mediante las reglas de enrutamiento de tráfico del punto de conexión del agente—por ejemplo, version_selector@latest. Pase version_indicator para invalidar eso y enlazar la sesión a una versión concreta (como "2") para que más adelante siga usando esa versión incluso si publica una más reciente. El valor debe ser un identificador de versión concreto devuelto por la API de versiones del agente; los alias como @latest no se aceptan aquí.
AGENT_NAME="my-agent"

az rest --method POST \
    --url "${BASE_URL}/agents/${AGENT_NAME}/endpoint/sessions?api-version=${API_VERSION}" \
    --resource "${RESOURCE}" \
    --headers "x-ms-user-isolation-key=user-123" "Foundry-Features=HostedAgents=V1Preview" \
    --body '{
        "version_indicator": {
            "type": "version_ref",
            "agent_version": "2"
        }
    }'

Omita el cuerpo (o envíe {}) para permitir que la plataforma seleccione la versión utilizando las reglas de enrutamiento de tráfico del punto de conexión del agente.

session = project.beta.agents.create_session(
    agent_name="my-agent",
    body={},
    isolation_key="user-123",
)
print(f"Session created (ID: {session.agent_session_id}, status: {session.status})")

El SDK requiere la isolation_key palabra clave en create_session y delete_session. El servidor solo lo aplica cuando el punto de conexión del agente está configurado para leer las claves de los encabezados; consulte Claves de aislamiento.

Para anclar la sesión a una versión específica del agente, incluya version_indicator en el cuerpo:

session = project.beta.agents.create_session(
    agent_name="my-agent",
    body={
        "version_indicator": {"type": "version_ref", "agent_version": "2"},
    },
    isolation_key="user-123",
)

Las sesiones se crean automáticamente al invocar un agente a través de azd. La creación manual de sesiones no está disponible actualmente como comando independiente.

Enumerar sesiones

az rest --method GET \
    --url "${BASE_URL}/agents/my-agent/endpoint/sessions?api-version=${API_VERSION}" \
    --resource "${RESOURCE}" \
    --headers "Foundry-Features=HostedAgents=V1Preview"
sessions = project.beta.agents.list_sessions(agent_name="my-agent")
for item in sessions:
    print(f"Session: {item.agent_session_id} (status: {item.status})")

La lista de sesiones no está disponible actualmente como comando independiente. Use la API REST o el SDK.

Obtención de los detalles de la sesión

SESSION_ID="<session-id>"

az rest --method GET \
    --url "${BASE_URL}/agents/my-agent/endpoint/sessions/${SESSION_ID}?api-version=${API_VERSION}" \
    --resource "${RESOURCE}" \
    --headers "Foundry-Features=HostedAgents=V1Preview"
session = project.beta.agents.get_session(
    agent_name="my-agent",
    session_id="<session-id>",
)
print(f"Session ID: {session.agent_session_id}, Status: {session.status}")

La administración de sesiones no está disponible actualmente como comando independiente. Use la API REST o el SDK.

Eliminación de una sesión

Al eliminar una sesión, se finaliza el espacio aislado y se liberan sus recursos. Cuando el punto de conexión del agente usa Header aislamiento, la clave de aislamiento debe coincidir con el valor usado cuando se creó la sesión. Cuando el punto de conexión usa Entra aislamiento, la plataforma limita la eliminación a la identidad que realiza la llamada.

SESSION_ID="<session-id>"
ISOLATION_KEY="user-123"

az rest --method DELETE \
    --url "${BASE_URL}/agents/my-agent/endpoint/sessions/${SESSION_ID}?api-version=${API_VERSION}" \
    --resource "${RESOURCE}" \
    --headers "x-ms-user-isolation-key=${ISOLATION_KEY}" "Foundry-Features=HostedAgents=V1Preview"
project.beta.agents.delete_session(
    agent_name="my-agent",
    session_id="<session-id>",
    isolation_key="user-123",
)

La administración de sesiones no está disponible actualmente como comando independiente. Use la API REST o el SDK.

Operaciones de archivos de sesión

Cargue y descargue archivos en espacios aislados de sesión del agente. Cada archivo está asignado a una sesión específica. El tamaño máximo de archivo para la carga es de 50 MB.

Nota

El SDK de Python usa session_id como palabra clave para upload_session_file y agent_session_id para get_session_files, download_session_file y delete_session_file. Use el nombre de palabra clave que se muestra en cada ejemplo.

Carga de un archivo

SESSION_ID="<session-id>"

az rest --method PUT \
    --url "${BASE_URL}/agents/my-agent/endpoint/sessions/${SESSION_ID}/files/content?api-version=${API_VERSION}&path=data.csv" \
    --resource "${RESOURCE}" \
    --body @data.csv \
    --headers "Content-Type=application/octet-stream" "Foundry-Features=HostedAgents=V1Preview"
project.beta.agents.upload_session_file(
    agent_name="my-agent",
    session_id="<session-id>",
    content_or_file_path="./data.csv",
    path="data.csv",
)

El content_or_file_path parámetro acepta una cadena de ruta de acceso de archivo. El SDK lee y carga automáticamente el contenido del archivo.

azd ai agent files upload --file ./data.csv --target-path data.csv

Enumerar archivos en una sesión

SESSION_ID="<session-id>"

az rest --method GET \
    --url "${BASE_URL}/agents/my-agent/endpoint/sessions/${SESSION_ID}/files?api-version=${API_VERSION}&path=." \
    --resource "${RESOURCE}" \
    --headers "Foundry-Features=HostedAgents=V1Preview"
files = project.beta.agents.get_session_files(
    agent_name="my-agent",
    agent_session_id="<session-id>",
    path=".",
)
for entry in files.entries:
    print(f"  {entry['name']} (size: {entry['size']}, directory: {entry['is_directory']})")
azd ai agent files list .

Descargar un archivo

SESSION_ID="<session-id>"

az rest --method GET \
    --url "${BASE_URL}/agents/my-agent/endpoint/sessions/${SESSION_ID}/files/content?api-version=${API_VERSION}&path=data.csv" \
    --resource "${RESOURCE}" \
    --headers "Foundry-Features=HostedAgents=V1Preview" \
    --output-file output.csv
content_bytes = b"".join(
    project.beta.agents.download_session_file(
        agent_name="my-agent",
        agent_session_id="<session-id>",
        path="data.csv",
    )
)
with open("./output.csv", "wb") as f:
    f.write(content_bytes)
azd ai agent files download --file data.csv --target-path ./output.csv

Eliminar un archivo

SESSION_ID="<session-id>"

az rest --method DELETE \
    --url "${BASE_URL}/agents/my-agent/endpoint/sessions/${SESSION_ID}/files?api-version=${API_VERSION}&path=data.csv" \
    --resource "${RESOURCE}" \
    --headers "Foundry-Features=HostedAgents=V1Preview"
project.beta.agents.delete_session_file(
    agent_name="my-agent",
    agent_session_id="<session-id>",
    path="data.csv",
)
azd ai agent files remove --file data.csv

Pasos siguientes