Lección 39 · 10 min · Gratis

Conectores, herramientas y agentes con las API de Completions

Usa conectores, herramientas integradas y agentes con la API de Chat Completions (/v1/chat/completions) y la API de Agent Completions (/v1/agents/completions).

Soporte del SDK: El SDK mistralai es compatible con herramientas tipo conector en chat.complete(). Ten en cuenta que las respuestas usan messages (array) en lugar de message (objeto) cuando se invocan herramientas.


Requisitos previos

Instalar

# Python
pip install mistralai
# or with uv
uv add mistralai
# TypeScript / Node.js
npm install @mistralai/mistralai

Variables de entorno requeridas

Para completar este manual, necesitarás una clave API de Mistral. En Studio, navega a la sección de claves API y crea una nueva clave API.

Crea un .env en la raíz de tu proyecto y agrega tu clave API de Mistral:

MISTRAL_API_KEY=your-mistral-api-key

Lo que necesitas antes de empezar

La mayoría de las recetas asumen:

  • Una MISTRAL_API_KEY válida
  • Un conector existente para recetas de conectores personalizados — consulta Crear un agente asesor de bases de datos para ver un ejemplo completo del ciclo de vida de un conector, o crea uno en Studio

Conversaciones vs. Completions — Cuándo usar cada una

Mistral ofrece dos API para interactuar con modelos:

Característica API de Conversaciones API de Chat Completions
Endpoint /v1/conversations /v1/chat/completions
Soporte del SDK client.beta.conversations client.chat.complete()
Formato de respuesta outputs[] con type: "message.output" choices[] con messages (array) cuando se usan herramientas
Estado de múltiples turnos Sin estado (envía el historial completo en cada llamada) Sin estado (envía el historial completo en cada llamada)
Ejecución de herramientas En el servidor (automática) En el servidor con formato multi_completion
Mejor para Nuevas integraciones, flujos de trabajo de agentes Aplicaciones compatibles con OpenAI, implementaciones de chat existentes

Usa Chat Completions cuando:

  • Estás migrando desde OpenAI y quieres un formato de respuesta familiar
  • Tu código existente usa la estructura choices[].message
  • Necesitas compatibilidad con SDKs estilo OpenAI

Usa Conversaciones cuando:

  • Estás creando nuevas integraciones desde cero
  • Quieres la superficie de API recomendada y más reciente
  • Estás usando las características beta del SDK

Lectura de respuestas de Completion

Las chat completions con herramientas devuelven respuestas en un formato multi_completion donde cada opción contiene un array messages en lugar de un solo message. El siguiente asistente maneja ambos formatos.

Python (SDK):

def display_response(response) -> None:
    """Display text content from SDK chat completion response.

    When using connector tools, responses use `messages` array instead of `message`.
    """
    for choice in response.choices:
        # Handle multi_completion format (messages array) - used with connector tools
        if hasattr(choice, 'messages') and choice.messages:
            for message in choice.messages:
                content = message.content
                if content:
                    if isinstance(content, str):
                        print(content[:500] if len(content) > 500 else content)
                    elif isinstance(content, list):
                        for chunk in content:
                            if hasattr(chunk, 'type'):
                                if chunk.type == "text":
                                    print(getattr(chunk, 'text', ''))
                                elif chunk.type == "image_url":
                                    print(f"[Image: {getattr(chunk, 'image_url', '')[:80]}...]")
                tool_calls = getattr(message, 'tool_calls', None)
                if tool_calls:
                    print(f"Tool calls: {len(tool_calls)}")
                    for tc in tool_calls:
                        func = tc.function
                        print(f"  - {func.name}: {func.arguments}")
        # Handle standard completion format (single message)
        elif hasattr(choice, 'message') and choice.message:
            message = choice.message
            content = message.content
            if content:
                print(content[:500] if len(content) > 500 else content)
            tool_calls = getattr(message, 'tool_calls', None)
            if tool_calls:
                print(f"Tool calls: {len(tool_calls)}")
                for tc in tool_calls:
                    func = tc.function
                    print(f"  - {func.name}: {func.arguments}")

TypeScript:

function displayResponse(data: any): void {
  for (const choice of data.choices ?? []) {
    // Handle multi_completion format (messages array)
    const messages = choice.messages ?? [];
    if (messages.length > 0) {
      for (const message of messages) {
        const content = message.content;
        if (content) {
          if (typeof content === "string") {
            console.log(content.length > 500 ? content.slice(0, 500) : content);
          } else if (Array.isArray(content)) {
            for (const chunk of content) {
              if (chunk.type === "text") {
                console.log(chunk.text ?? "");
              } else if (chunk.type === "image_url") {
                console.log(`[Image: ${(chunk.image_url ?? "").slice(0, 80)}...]`);
              }
            }
          }
        }
        const toolCalls = message.tool_calls ?? [];
        if (toolCalls.length > 0) {
          console.log(`Tool calls: ${toolCalls.length}`);
          for (const tc of toolCalls) {
            const func = tc.function ?? {};
            console.log(`  - ${func.name}: ${func.arguments}`);
          }
        }
      }
    // Handle standard completion format (single message)
    } else {
      const message = choice.message ?? {};
      const content = message.content;
      if (content) {
        console.log(typeof content === "string" && content.length > 500 ? content.slice(0, 500) : content);
      }
      const toolCalls = message.tool_calls ?? [];
      if (toolCalls.length > 0) {
        console.log(`Tool calls: ${toolCalls.length}`);
        for (const tc of toolCalls) {
          const func = tc.function ?? {};
          console.log(`  - ${func.name}: ${func.arguments}`);
        }
      }
    }
  }
}

Todas las recetas a continuación hacen referencia a este asistente. Cópialo en tu proyecto o integra la lógica.


Recetas


1. Hola Mundo — Chat Completion básica

Objetivo: Envía tu primera solicitud de chat completion — sin herramientas, sin conectores.

Cuándo usar:

  • Verificar que tu configuración del SDK funciona de principio a fin
  • Familiarizarte con la estructura de la respuesta antes de agregar conectores

Python:

import asyncio
from mistralai.client import Mistral

API_KEY = "your-api-key"


async def main() -> None:
    client = Mistral(api_key=API_KEY)

    response = await client.chat.complete_async(
        model="mistral-small-latest",
        messages=[
            {"role": "user", "content": "What is the capital of France?"}
        ],
    )

    # Standard completion uses choice.message
    print(response.choices[0].message.content)


asyncio.run(main())

TypeScript:

import { Mistral } from "@mistralai/mistralai";

const client = new Mistral({ apiKey: "your-api-key" });

async function main(): Promise<void> {
  const response = await client.chat.complete({
    model: "mistral-small-latest",
    messages: [
      { role: "user", content: "What is the capital of France?" },
    ],
  });

  console.log(response.choices[0].message.content);
}

main();

curl:

curl -X POST "https://api.mistral.ai/v1/chat/completions" \
  -H "Authorization: Bearer ${MISTRAL_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "mistral-small-latest",
    "messages": [{"role": "user", "content": "What is the capital of France?"}]
  }'

Ejemplo de salida:

The capital of France is Paris.

Cómo funciona:

  • /v1/chat/completions es el endpoint de chat estándar compatible con OpenAI
  • La respuesta contiene choices[] con cada opción teniendo un objeto message
  • No se requieren herramientas ni conectores para una completion básica

Errores comunes y soluciones:

Error Causa Solución
401 Unauthorized Clave API incorrecta Verifica MISTRAL_API_KEY
422 Unprocessable Entity Nombre de modelo inválido Usa un modelo válido como mistral-small-latest

2. Completion con generación de imágenes

Objetivo: Usa la herramienta integrada image_generation en una chat completion.

Cuándo usar:

  • Generar imágenes basadas en prompts de usuario
  • Integración rápida sin conectores personalizados

Python:

import asyncio
from mistralai.client import Mistral

API_KEY = "your-api-key"


async def main() -> None:
    client = Mistral(api_key=API_KEY)

    response = await client.chat.complete_async(
        model="mistral-small-latest",
        messages=[
            {
                "role": "user",
                "content": "Generate an image of a sunset over the ocean.",
            }
        ],
        tools=[
            {"type": "image_generation"},
        ],
    )

    # With tools, use choice.messages (array) instead of choice.message
    display_response(response)


asyncio.run(main())

TypeScript:

import { Mistral } from "@mistralai/mistralai";

const client = new Mistral({ apiKey: "your-api-key" });

async function main(): Promise<void> {
  const response = await client.chat.complete({
    model: "mistral-small-latest",
    messages: [
      {
        role: "user",
        content: "Generate an image of a sunset over the ocean.",
      },
    ],
    tools: [
      { type: "image_generation" },
    ],
  });

  displayResponse(response);
}

main();

curl:

curl -X POST "https://api.mistral.ai/v1/chat/completions" \
  -H "Authorization: Bearer ${MISTRAL_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "mistral-small-latest",
    "messages": [{"role": "user", "content": "Generate an image of a sunset over the ocean."}],
    "tools": [{"type": "image_generation"}]
  }'

Ejemplo de salida:

[Image: https://files.mistral.ai/generated/abc123...]
Here's a beautiful sunset over the ocean as requested.

Cómo funciona:

  • image_generation es un tipo de herramienta integrada — no se requiere la creación de conectores
  • El modelo decide invocar la herramienta basándose en la solicitud del usuario
  • Las imágenes generadas se devuelven como URLs en el contenido de la respuesta
  • Cuando se invocan herramientas, las respuestas usan choice.messages (array) en lugar de choice.message

Errores comunes y soluciones:

Error Causa Solución
422 Unprocessable Entity Tipo de herramienta inválido Asegúrate de que el tipo sea exactamente "image_generation"

3. Completion con un conector personalizado

Objetivo: Usar un Conector en una chat completion para que el modelo pueda llamar a herramientas externas.

Cuándo usar:

  • Has registrado un conector (por ejemplo, DeepWiki) y quieres que el modelo use sus herramientas
  • Conectar capacidades específicas del dominio al modelo en un contexto de chat completion

Requisitos previos:

Python:

import asyncio
from mistralai.client import Mistral

API_KEY = "your-api-key"


async def main() -> None:
    client = Mistral(api_key=API_KEY)

    response = await client.chat.complete_async(
        model="mistral-small-latest",
        messages=[
            {
                "role": "user",
                "content": "Using deepwiki, tell me about the structure of the sqlite/sqlite repository.",
            }
        ],
        tools=[
            {
                "type": "connector",
                "connector_id": "my_deepwiki",  # name or UUID
            },
        ],
    )

    # With connector tools, use choice.messages (array)
    display_response(response)


asyncio.run(main())

TypeScript:

import { Mistral } from "@mistralai/mistralai";

const client = new Mistral({ apiKey: "your-api-key" });

async function main(): Promise<void> {
  const response = await client.chat.complete({
    model: "mistral-small-latest",
    messages: [
      {
        role: "user",
        content:
          "Using deepwiki, tell me about the structure of the sqlite/sqlite repository.",
      },
    ],
    tools: [
      {
        type: "connector",
        connectorId: "my_deepwiki", // name or UUID
      },
    ],
  });

  displayResponse(response);
}

main();

curl:

curl -X POST "https://api.mistral.ai/v1/chat/completions" \
  -H "Authorization: Bearer ${MISTRAL_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "mistral-small-latest",
    "messages": [{"role": "user", "content": "Using deepwiki, tell me about the structure of the sqlite/sqlite repository."}],
    "tools": [{"type": "connector", "connector_id": "my_deepwiki"}]
  }'

Ejemplo de salida:

The sqlite/sqlite repository is organized into several key directories:
- src/ — core SQLite source code
- ext/ — extensions
- test/ — test suite
...

Cómo funciona:

  • El campo connector_id acepta el nombre o UUID del conector
  • El modelo descubre las herramientas expuestas por el servidor MCP y decide cuáles llamar
  • Las llamadas a herramientas y los resultados se manejan en el servidor — tú solo ves la respuesta final
  • Las respuestas usan choice.messages (array) cuando se invocan herramientas

Errores comunes y soluciones:

Error Causa Solución
404 Not Found El nombre/ID del conector no existe Verifica con la API de lista/obtener conector
422 Unprocessable Entity El conector está inactivo o el servidor MCP es inalcanzable Verifica la URL del servidor MCP

4. Combinando múltiples herramientas

Objetivo: Dar al modelo acceso a herramientas integradas y conectores personalizados simultáneamente en una chat completion.

Cuándo usar:

  • Quieres que el modelo elija la mejor herramienta para la tarea entre varias opciones
  • Construir un asistente con múltiples capacidades

Requisitos previos:

  • Un conector existente

Python:

import asyncio
from mistralai.client import Mistral

API_KEY = "your-api-key"


async def main() -> None:
    client = Mistral(api_key=API_KEY)

    response = await client.chat.complete_async(
        model="mistral-small-latest",
        messages=[
            {
                "role": "user",
                "content": "What tools do you have access to? List them briefly.",
            }
        ],
        tools=[
            {"type": "image_generation"},
            {
                "type": "connector",
                "connector_id": "my_deepwiki",
            },
        ],
    )

    display_response(response)


asyncio.run(main())

TypeScript:

import { Mistral } from "@mistralai/mistralai";

const client = new Mistral({ apiKey: "your-api-key" });

async function main(): Promise<void> {
  const response = await client.chat.complete({
    model: "mistral-small-latest",
    messages: [
      {
        role: "user",
        content: "What tools do you have access to? List them briefly.",
      },
    ],
    tools: [
      { type: "image_generation" },
      {
        type: "connector",
        connectorId: "my_deepwiki",
      },
    ],
  });

  displayResponse(response);
}

main();

curl:

curl -X POST "https://api.mistral.ai/v1/chat/completions" \
  -H "Authorization: Bearer ${MISTRAL_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "mistral-small-latest",
    "messages": [{"role": "user", "content": "What tools do you have access to? List them briefly."}],
    "tools": [
      {"type": "image_generation"},
      {"type": "connector", "connector_id": "my_deepwiki"}
    ]
  }'

Ejemplo de salida:

I have access to the following tools:
1. Image Generation — create images from text descriptions
2. read_wiki_structure — explore repository wiki structure
3. read_wiki_contents — read specific wiki pages
4. ask_question — ask questions about a repository

Cómo funciona:

  • El array tools acepta cualquier combinación de herramientas integradas (image_generation) y conectores personalizados
  • Cada conector expone su propio conjunto de herramientas MCP; el modelo las ve todas
  • El modelo decide qué herramienta(s) invocar basándose en la pregunta del usuario

Errores comunes y soluciones:

Error Causa Solución
422 Unprocessable Entity IDs de conector duplicados en el array de herramientas Cada conector debe aparecer solo una vez

5. Creación de un agente con conectores

Objetivo: Crear un agente persistente preconfigurado con conectores e instrucciones personalizadas para usar con la API de Agent Completions.

Cuándo usar:

  • Quieres un agente reutilizable que siempre tenga acceso a herramientas específicas
  • Construir una característica de producto donde los usuarios interactúan con un asistente especializado
  • Simplificar las llamadas a la API preconfigurando el modelo, las instrucciones y las herramientas

Requisitos previos:

  • Un conector existente

Python:

import asyncio
from mistralai.client import Mistral

API_KEY = "your-api-key"


async def main() -> None:
    client = Mistral(api_key=API_KEY)
    agent_id: str | None = None

    try:
        # Create the agent
        agent = await client.beta.agents.create_async(
            name="deepwiki_completion_agent",
            description="Agent with DeepWiki access for code repository exploration",
            model="mistral-small-latest",
            instructions="You are a helpful assistant that can explore code repositories using DeepWiki. Be concise.",
            tools=[
                {
                    "type": "connector",
                    "connector_id": "my_deepwiki",
                },
            ],
        )
        agent_id = str(agent.id)
        print(f"Created agent: {agent.name} ({agent_id})")

    finally:
        # Clean up
        if agent_id:
            await client.beta.agents.delete_async(agent_id=agent_id)
            print(f"Deleted agent: {agent_id}")


asyncio.run(main())

TypeScript:

import { Mistral } from "@mistralai/mistralai";

const client = new Mistral({ apiKey: "your-api-key" });

async function main(): Promise<void> {
  let agentId: string | undefined;

  try {
    // Create the agent
    const agent = await client.beta.agents.create({
      name: "deepwiki_completion_agent",
      description: "Agent with DeepWiki access for code repository exploration",
      model: "mistral-small-latest",
      instructions:
        "You are a helpful assistant that can explore code repositories using DeepWiki. Be concise.",
      tools: [
        {
          type: "connector",
          connectorId: "my_deepwiki",
        },
      ],
    });
    agentId = agent.id;
    console.log(`Created agent: ${agent.name} (${agentId})`);
  } finally {
    // Clean up
    if (agentId) {
      await client.beta.agents.delete({ agentId });
      console.log(`Deleted agent: ${agentId}`);
    }
  }
}

main();

curl:

# Create agent
curl -X POST "https://api.mistral.ai/v1/agents" \
  -H "Authorization: Bearer ${MISTRAL_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "deepwiki_completion_agent",
    "description": "Agent with DeepWiki access",
    "model": "mistral-small-latest",
    "instructions": "You are a helpful assistant that can explore code repositories using DeepWiki. Be concise.",
    "tools": [{"type": "connector", "connector_id": "my_deepwiki"}]
  }'

# Delete agent when done (use the agent ID from the response above)
curl -X DELETE "https://api.mistral.ai/v1/agents/<agent-id>" \
  -H "Authorization: Bearer ${MISTRAL_API_KEY}"

Ejemplo de salida:

Created agent: deepwiki_completion_agent (b2c3d4e5-6789-01ab-cdef-234567890abc)
Deleted agent: b2c3d4e5-6789-01ab-cdef-234567890abc

Cómo funciona:

  • Los agentes son configuraciones persistentes: modelo + instrucciones + herramientas
  • Una vez creado, usa el ID del agente con /v1/agents/completions para chatear
  • El array tools del agente usa el mismo formato que el parámetro tools en las completions
  • Elimina los agentes cuando ya no sean necesarios

Errores comunes y soluciones:

Error Causa Solución
404 Not Found El conector referenciado en las herramientas del agente no existe Crea el conector primero
409 Conflict Ya existe un agente con este nombre Elige un nombre diferente o elimina el agente existente

6. Agent Completions

Objetivo: Chatear con un agente preconfigurado usando la API de Agent Completions.

Cuándo usar:

  • Tienes un agente existente con herramientas configuradas
  • Quieres evitar pasar el modelo, las instrucciones y las herramientas en cada solicitud
  • Construir flujos conversacionales con un asistente especializado

Requisitos previos:

  • Un ID de agente existente (consulta Receta 5)

Python:

import asyncio
from mistralai.client import Mistral

API_KEY = "your-api-key"


async def main() -> None:
    client = Mistral(api_key=API_KEY)
    agent_id = "your-agent-id"  # From agent creation

    response = await client.agents.complete_async(
        agent_id=agent_id,
        messages=[
            {
                "role": "user",
                "content": "What is the main purpose of the sqlite repository?",
            }
        ],
    )

    display_response(response)


asyncio.run(main())

TypeScript:

import { Mistral } from "@mistralai/mistralai";

const client = new Mistral({ apiKey: "your-api-key" });

async function main(): Promise<void> {
  const agentId = "your-agent-id"; // From agent creation

  const response = await client.agents.complete({
    agentId,
    messages: [
      {
        role: "user",
        content: "What is the main purpose of the sqlite repository?",
      },
    ],
  });

  displayResponse(response);
}

main();

curl:

curl -X POST "https://api.mistral.ai/v1/agents/completions" \
  -H "Authorization: Bearer ${MISTRAL_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "<agent-id>",
    "messages": [{"role": "user", "content": "What is the main purpose of the sqlite repository?"}]
  }'

Ejemplo de salida:

SQLite is a self-contained, serverless, zero-configuration SQL database engine. It is the most widely deployed database in the world, embedded in countless applications including web browsers, mobile phones, and operating systems.

Cómo funciona:

  • /v1/agents/completions usa el modelo, las instrucciones y las herramientas preconfiguradas del agente
  • Solo necesitas proporcionar agent_id y messages — no es necesario repetir la configuración
  • El formato de respuesta es el mismo que /v1/chat/completions
  • Para conversaciones de múltiples turnos, incluye el historial completo de mensajes en el array messages

Errores comunes y soluciones:

Error Causa Solución
404 Not Found ID de agente inválido El agente puede haber sido eliminado
422 Unprocessable Entity Falta agent_id o formato de mensaje inválido Asegúrate de que se proporcione agent_id

7. Conectores autenticados con OAuth (Gmail)

Objetivo: Usar un conector que requiere autenticación OAuth2 en una chat completion.

Cuándo usar:

  • Integrar con servicios que requieren tokens OAuth a nivel de usuario (Gmail, Google Drive, Slack, etc.)
  • Construir características donde el modelo accede a datos específicos del usuario

Requisitos previos:

  • Un token de acceso OAuth2 válido para el servicio de destino

Python:

import asyncio
from mistralai.client import Mistral

API_KEY = "your-api-key"


async def main() -> None:
    client = Mistral(api_key=API_KEY)
    google_oauth_token = "your-google-oauth-token"

    response = await client.chat.complete_async(
        model="mistral-small-latest",
        messages=[
            {
                "role": "user",
                "content": "What's the latest email I received?",
            }
        ],
        tools=[
            {
                "type": "connector",
                "connector_id": "gmail",
                "authorization": {
                    "type": "oauth2-token",
                    "value": google_oauth_token,
                },
            },
        ],
    )

    display_response(response)


asyncio.run(main())

TypeScript:

import { Mistral } from "@mistralai/mistralai";

const client = new Mistral({ apiKey: "your-api-key" });

async function main(): Promise<void> {
  const googleOauthToken = "your-google-oauth-token";

  const response = await client.chat.complete({
    model: "mistral-small-latest",
    messages: [
      {
        role: "user",
        content: "What's the latest email I received?",
      },
    ],
    tools: [
      {
        type: "connector",
        connector_id: "gmail",
        authorization: {
          type: "oauth2-token",
          value: googleOauthToken,
        },
      },
    ],
  });

  displayResponse(response);
}

main();

curl:

curl -X POST "https://api.mistral.ai/v1/chat/completions" \
  -H "Authorization: Bearer ${MISTRAL_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "mistral-small-latest",
    "messages": [{"role": "user", "content": "What is the latest email I received?"}],
    "tools": [{
      "type": "connector",
      "connector_id": "gmail",
      "authorization": {
        "type": "oauth2-token",
        "value": "<your-google-oauth-token>"
      }
    }]
  }'

Ejemplo de salida:

Your latest email is from John Doe with the subject "Q1 Report Review" received at 2:30 PM today...

Cómo funciona:

  • El campo authorization se pasa por herramienta, no globalmente — diferentes conectores pueden usar diferentes tokens
  • type: "oauth2-token" le indica al backend que reenvíe el token al servidor MCP
  • El token no es almacenado por Mistral — se usa solo durante la duración de la solicitud
  • Los conectores integrados como gmail están preregistrados; no necesitas crearlos

Errores comunes y soluciones:

Error Causa Solución
401 Unauthorized El token OAuth ha expirado Actualiza el token y vuelve a intentarlo
403 Forbidden El token no tiene los scopes requeridos Solicita los scopes correctos (por ejemplo, gmail.readonly)

8. Ejemplo completo — Crear, completar y limpiar

Objetivo: Flujo de trabajo de principio a fin: crear un conector, usarlo en chat completions y con un agente, luego limpiar.

Cuándo usar:

  • Pruebas de integración
  • Conectores efímeros para tareas únicas
  • Plantilla para flujos de trabajo de producción

Python:

import asyncio
from mistralai.client import Mistral

API_KEY = "your-api-key"


async def main() -> None:
    client = Mistral(api_key=API_KEY)
    connector_id: str | None = None
    agent_id: str | None = None

    try:
        # 1. Create a connector
        connector = await client.beta.connectors.create_async(
            name="completions_deepwiki",
            description="DeepWiki connector for completion testing",
            server="https://mcp.deepwiki.com/mcp",
            visibility="private",
        )
        connector_id = str(connector.id)
        print(f"Created connector: {connector.name} ({connector_id})")

        # 2. Use it in a chat completion
        response = await client.chat.complete_async(
            model="mistral-small-latest",
            messages=[
                {
                    "role": "user",
                    "content": "Using deepwiki, summarize the sqlite/sqlite repo in one sentence.",
                }
            ],
            tools=[
                {"type": "connector", "connector_id": "completions_deepwiki"},
            ],
        )
        print("\nChat completion response:")
        display_response(response)

        # 3. Create an agent with the connector
        agent = await client.beta.agents.create_async(
            name="completions_test_agent",
            description="Test agent for completion cookbook",
            model="mistral-small-latest",
            instructions="You are a helpful assistant. Be concise.",
            tools=[
                {"type": "connector", "connector_id": connector_id},
            ],
        )
        agent_id = str(agent.id)
        print(f"\nCreated agent: {agent.name} ({agent_id})")

        # 4. Use agent completions
        response = await client.agents.complete_async(
            agent_id=agent_id,
            messages=[
                {
                    "role": "user",
                    "content": "What programming language is SQLite written in?",
                }
            ],
        )
        print("\nAgent completion response:")
        display_response(response)

        print("\n" + "=" * 60)
        print("  SUCCESS")
        print("=" * 60)

    finally:
        # Clean up
        print("\nCleaning up...")
        if agent_id:
            try:
                await client.beta.agents.delete_async(agent_id=agent_id)
                print(f"Deleted agent: {agent_id}")
            except Exception:
                pass

        if connector_id:
            try:
                await client.beta.connectors.delete_async(
                    connector_id=connector_id,
                )
                print(f"Deleted connector: {connector_id}")
            except Exception:
                pass


asyncio.run(main())

TypeScript:

import { Mistral } from "@mistralai/mistralai";

const client = new Mistral({ apiKey: "your-api-key" });

async function main(): Promise<void> {
  let connectorId: string | undefined;
  let agentId: string | undefined;

  try {
    // 1. Create a connector
    const connector = await client.beta.connectors.create({
      name: "completions_deepwiki",
      description: "DeepWiki connector for completion testing",
      server: "https://mcp.deepwiki.com/mcp",
      visibility: "private",
    });
    connectorId = connector.id;
    console.log(`Created connector: ${connector.name} (${connectorId})`);

    // 2. Use it in a chat completion
    let response = await client.chat.complete({
      model: "mistral-small-latest",
      messages: [
        {
          role: "user",
          content: "Using deepwiki, summarize the sqlite/sqlite repo in one sentence.",
        },
      ],
      tools: [
        { type: "connector", connectorId: "completions_deepwiki" },
      ],
    });
    console.log("\nChat completion response:");
    displayResponse(response);

    // 3. Create an agent with the connector
    const agent = await client.beta.agents.create({
      name: "completions_test_agent",
      description: "Test agent for completion cookbook",
      model: "mistral-small-latest",
      instructions: "You are a helpful assistant. Be concise.",
      tools: [
        { type: "connector", connectorId },
      ],
    });
    agentId = agent.id;
    console.log(`\nCreated agent: ${agent.name} (${agentId})`);

    // 4. Use agent completions
    response = await client.agents.complete({
      agentId,
      messages: [
        {
          role: "user",
          content: "What programming language is SQLite written in?",
        },
      ],
    });
    console.log("\nAgent completion response:");
    displayResponse(response);

    console.log("\n" + "=".repeat(60));
    console.log("  SUCCESS");
    console.log("=".repeat(60));
  } finally {
    // Clean up
    console.log("\nCleaning up...");
    if (agentId) {
      try {
        await client.beta.agents.delete({ agentId });
        console.log(`Deleted agent: ${agentId}`);
      } catch {
        // ignore
      }
    }
    if (connectorId) {
      try {
        await client.beta.connectors.delete({ connectorId });
        console.log(`Deleted connector: ${connectorId}`);
      } catch {
        // ignore
      }
    }
  }
}

main();

Salida:

Created connector: completions_deepwiki (c3d4e5f6-...)

Chat completion response:
SQLite is a self-contained, serverless SQL database engine used worldwide.

Created agent: completions_test_agent (d4e5f6a7-...)

Agent completion response:
SQLite is primarily written in C.

============================================================
  SUCCESS
============================================================

Cleaning up...
Deleted agent: d4e5f6a7-...
Deleted connector: c3d4e5f6-...

Cómo funciona:

  • El patrón try/finally asegura que los recursos siempre se limpien, incluso si las solicitudes fallan
  • Esta receta demuestra el flujo de trabajo completo: creación de conector → chat completion → creación de agente → agent completion
  • Tanto /v1/chat/completions como /v1/agents/completions admiten los mismos formatos de herramienta

Convenciones de nombres de Python / TypeScript

Concepto SDK de Python SDK de TypeScript
ID de conector connector_id connectorId
ID de agente agent_id agentId
Tipo de herramienta type type
Autorización OAuth authorization.type, authorization.value authorization.type, authorization.value

Solución de problemas

Error "Conector no encontrado"

  • Verifica que el conector existe listando los conectores u obteniéndolos por nombre/ID
  • Comprueba que el nombre/ID del conector esté escrito correctamente
  • Asegúrate de que el conector fue creado en el mismo espacio de trabajo

"Las llamadas a herramientas no aparecen en la respuesta"

  • El modelo decide si llamar a las herramientas basándose en el mensaje del usuario
  • Intenta ser más explícito en tu prompt (por ejemplo, "Usa deepwiki para...")
  • Asegúrate de que el tipo de herramienta sea válido (connector, image_generation, etc.)

"Errores de tiempo de espera"

  • Los servidores MCP pueden tardar en responder — aumenta el tiempo de espera
  • Verifica si la URL del servidor MCP es accesible
  • Intenta primero con una consulta más simple

"Token OAuth expirado"

  • Los tokens OAuth tienen una vida útil limitada
  • Implementa la lógica de actualización de tokens en tu aplicación
  • Verifica la expiración del token antes de realizar solicitudes

"AttributeError: el objeto 'Unset' no tiene el atributo 'content'"

  • Al usar herramientas de conector, las respuestas usan choice.messages (array) en lugar de choice.message
  • Usa la función auxiliar display_response o verifica ambos formatos
  • Accede al contenido a través de response.choices[0].messages[0].content

Referencia de códigos de error

Estado HTTP Error Causas comunes
400 Solicitud incorrecta JSON inválido, campos requeridos faltantes
401 No autorizado Clave API inválida o faltante, token OAuth expirado
403 Prohibido Permisos insuficientes, scopes OAuth inválidos
404 No encontrado El conector/agente no existe, ID incorrecto
409 Conflicto Ya existe un recurso con el mismo nombre
422 Entidad no procesable Nombre de modelo inválido, formato de herramienta inválido, servidor MCP inalcanzable
429 Demasiadas solicitudes Límite de tasa excedido
500 Error interno del servidor Problema del lado del servidor, reintenta con retroceso exponencial
502 Bad Gateway Servidor MCP inalcanzable o devolvió un error
504 Gateway Timeout El servidor MCP tardó demasiado en responder

Resumen

Este manual cubrió ocho recetas para usar Conectores, herramientas integradas y agentes con las API de Chat Completions y Agent Completions — desde una completion básica hasta Conectores autenticados con OAuth y un ejemplo completo del ciclo de vida de creación, completion y limpieza.

Lo que cubre este manual:

  • Completion de chat básica
  • Completion con generación de imágenes
  • Completion con un Conector personalizado
  • Combinar múltiples herramientas en una completion
  • Crear un agente con Conectores para usar con completions
  • Agent completions
  • Conectores autenticados con OAuth (Gmail)
  • Ciclo de vida completo: crear un Conector, completar y limpiar

Características de Mistral usadas:

  • API de Chat Completions
  • API de Agent Completions
  • API de Agentes (beta)
  • Conectores (beta)
  • Herramienta integrada de generación de imágenes

Otros servicios:

  • DeepWiki — Servidor MCP para exploración de repositorios de GitHub
  • Gmail — Conector autenticado con OAuth2

Consulta tus Conectores en Studio.

Lección del curso «Mistral Cookbook» de Mistral AI, publicado con licencia MIT. Traducción y adaptación al español de IA con Clase. IA con Clase no está afiliado a Mistral AI. Ver el original · Licencia
Esta lección es gratuita. El resto del curso se abre con la Membresía de IA con Clase, que incluye todos los cursos del catálogo. Ver precios