> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mka1.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Guía de primeros pasos de la plataforma MKA1

> Desde un enlace de invitación al clúster hasta crear aplicaciones con el SDK de MKA1. Acepte su invitación, configure su organización, genere una clave API y realice su primera solicitud.

<Note>
  **QUÉ DEBE TENER A MANO**

  1. **Un enlace de invitación al clúster** enviado por el administrador de su clúster. Le convierte en propietario de una organización completamente nueva.
  2. **Esta guía** todo lo que necesita para pasar de ese enlace a una integración funcional.
</Note>

**Enlaces rápidos**

* [Referencia de la API](https://docs.mka1.com/api-reference/introduction)
* [SDK de TypeScript en npm](https://www.npmjs.com/package/@meetkai/mka1)
* [SDK de Python en PyPI](https://pypi.org/project/meetkai-mka1/)
* [SDK de C# en NuGet](https://www.nuget.org/packages/MeetKai.MKA1/)
* [Instalación de la CLI](https://docs.mka1.com/docs/cli/introduction)

## Bienvenido a MKA1

MKA1 es una plataforma para crear aplicaciones de IA. Ofrece a su equipo una única puerta de enlace a grandes modelos de lenguaje además de los bloques de construcción de alto nivel que los productos reales necesitan: agentes, conversaciones almacenadas, memoria a largo plazo, recuperación de documentos (RAG), herramientas y servidores MCP, prompts, habilidades, guardrails, voz y evaluaciones.

Usted trabaja con MKA1 a través de dos superficies que comparten las mismas cuentas, equipos y recursos:

* **La Consola** - un panel web para crear e inspeccionar todo manualmente: ejecutar prompts en el Playground, guardar agentes, indexar archivos, generar claves API, gestionar su organización y sus equipos. La consola vive en la dirección de su clúster (por ejemplo platform.mka1.com).
* **La API y los SDK** - las mismas capacidades sobre HTTPS, llamadas desde su propio código mediante el SDK de TypeScript, Python o C#, la CLI `mka1` o curl a secas. Así es como su aplicación habla con MKA1 en producción.

Esta guía recorre todo el camino en orden. Los pasos 1–7 le llevan desde el enlace de invitación hasta su primera solicitud exitosa; las secciones posteriores recorren cada bloque de construcción con ejemplos listos para copiar y pegar.

## Antes de empezar

Solo necesita dos cosas para comenzar, y ya tiene ambas:

1. **Un enlace de invitación al clúster.** Su administrador creó una invitación en el clúster y le envió el enlace. Al abrirlo, se convierte en propietario de una nueva organización dentro de ese clúster.
2. **Esta guía.** Le lleva desde la invitación hasta una integración funcional con el SDK.

No hay nada que instalar de antemano. La consola se ejecuta en su navegador, y solo instala un SDK cuando esté listo para escribir código. El camino siguiente toma unos 15 minutos:

<Note>
  **Configuración en 15 minutos**

  * **Paso 1** Acepte su invitación al clúster y cree su organización.
  * **Paso 2** Oriéntese en la consola.
  * **Paso 3** Invite a compañeros y cree un equipo (las claves API viven en los equipos).
  * **Paso 4** Cree una clave API.
  * **Paso 5** Instale un SDK.
  * **Paso 6** Autentique sus solicitudes.
  * **Paso 7** Realice su primera solicitud.
</Note>

## Paso 1 · Acepte su invitación al clúster

Abra el enlace de invitación al clúster que le envió su administrador. Lleva un token de un solo uso y le deja en la página **Set up your organization**. Una invitación al clúster es una **invitación de propietario** - al aceptarla se crea una nueva organización y usted queda como propietario.

### Haga esto

1. **Abra el enlace de invitación.** La página valida el token y muestra una insignia de *Owner invite* (y una fecha de caducidad, si se configuró una). Si dice que la invitación no está disponible, el token de invitación ha caducado o ha sido revocado. Pida a su administrador un enlace nuevo.
2. **Nombre su organización.** Escriba un nombre como Acme Inc. Se genera automáticamente un slug de URL del espacio de trabajo (p. ej. acme-inc); expanda **Customize** si desea editarlo. Solo minúsculas, números y guiones.
3. **Elija cómo iniciar sesión.** Cree una cuenta con correo y contraseña, o continúe con Google. Si la invitación estaba vinculada a su dirección de correo, esa dirección aparece precargada y bloqueada.
4. **Verifique su correo.** Si se registró con contraseña, MKA1 le envía un correo de verificación. Haga clic en el enlace para confirmar; después entra directamente en su nueva organización.
5. **Ya está dentro.** Aterriza en la consola como **propietario** de su organización, listo para invitar a compañeros y crear claves.

<Note>
  **Ahora usted es el propietario de la organización**

  El propietario tiene control total. Uso, miembros, equipos y configuración. Todos los demás que incorpore serán administradores o miembros (se cubre en el Paso 3). Si ya había iniciado sesión en MKA1 con un correo distinto al de la invitación, cierre sesión primero: las invitaciones están vinculadas a una dirección específica.
</Note>

## Paso 2 · Recorra la consola

Tómese un minuto para orientarse. La barra lateral izquierda agrupa cada superficie en **Access**, **LLM**, **Agents** y **Admin**. Esto es para qué sirve cada sección. Usará varias de ellas en los pasos siguientes.

<img src="https://mintcdn.com/meetkaiinc/6LyFGcL-YnhBj_CK/images/platform-getting-started/console-organizations.png?fit=max&auto=format&n=6LyFGcL-YnhBj_CK&q=85&s=18e5508504a8d674c2e24b795fbf4d14" alt="Configuración de organizaciones en la consola de MKA1" width="1999" height="1173" data-path="images/platform-getting-started/console-organizations.png" />

### Access

| Sección              | Qué hace ahí                                                                    |
| :------------------- | :------------------------------------------------------------------------------ |
| **API Keys**         | Cree y gestione las claves de autenticación que usa su código (Paso 4).         |
| **Organizations**    | Gestione miembros, roles, equipos e invitaciones pendientes.                    |
| **Teams**            | Cree equipos y gestione su membresía. Cada clave API está limitada a un equipo. |
| **Service Accounts** | Cree identidades no humanas para producción y adjúntelas a equipos.             |

### LLM

| Sección            | Qué hace ahí                                                                                                                                                       |
| :----------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Playground**     | Chatee con modelos de forma interactiva. Transmita respuestas en tiempo real. Configure herramientas, habilidades y guardrails, con un panel de ajustes avanzados. |
| **Models**         | Explore los modelos disponibles a través de la puerta de enlace, agrupados por modalidad, con detalles del registro para administradores.                          |
| **Responses**      | Cree respuestas individuales e inspeccione el historial almacenado, la salida, las llamadas a herramientas y el uso de tokens.                                     |
| **Evals**          | Construya suites de evaluación y lance ejecuciones duraderas para medir y comparar la calidad de los modelos.                                                      |
| **Conversations**  | Cree e inspeccione el estado de conversaciones almacenadas, con búsqueda por metadatos.                                                                            |
| **Text to speech** | Sintetice voz a partir de texto e inspeccione el historial de generación.                                                                                          |
| **Speech to text** | Transcriba audio a texto e inspeccione el historial de transcripciones.                                                                                            |
| **Prompts**        | Cree, versione y revierta plantillas de prompts reutilizables con `{{variables}}`.                                                                                 |
| **Guardrails**     | Configure políticas de palabras prohibidas, inyección de prompts y filtraciones, y luego pruébelas.                                                                |
| **Files**          | Suba, inspeccione y elimine archivos usados por flujos de trabajo LLM.                                                                                             |
| **Vector Stores**  | Cree almacenes, adjunte archivos y busque fragmentos de documentos indexados para recuperación (RAG).                                                              |
| **Feedback**       | Registre y actualice retroalimentación humana sobre la salida del modelo; consulte registros o exporte una instantánea en parquet.                                 |
| **Skills**         | Suba, versione y gestione habilidades reutilizables, cada una empaquetada tras un manifiesto SKILL.md.                                                             |
| **MCP Servers**    | Registre definiciones de servidores MCP que los agentes guardados pueden adjuntar como herramientas; los secretos permanecen en Credentials.                       |
| **Credentials**    | Guarde los secretos que sus servidores MCP e integraciones necesitan, separados de sus definiciones.                                                               |

### Agents

| Sección           | Qué hace ahí                                                                                                               |
| :---------------- | :------------------------------------------------------------------------------------------------------------------------- |
| **Quickstart**    | Ponga en marcha un agente guardado rápidamente - elija un modelo, escriba instrucciones, adjunte herramientas y ejecútelo. |
| **Agents**        | Cree y ejecute agentes guardados que agrupan un modelo, instrucciones, herramientas y metadatos.                           |
| **Sessions**      | Rastree y depure ejecuciones de agentes. Reproduzca la transcripción y recorra los eventos sin procesar.                   |
| **Memory Stores** | Explore las memorias en markdown que los agentes leen y escriben entre ejecuciones.                                        |

### Admin

| Sección            | Qué hace ahí                                                                                                                                                                                                                 |
| :----------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Audit**          | Revise solicitudes de auditoría de la puerta de enlace, construya casos y exporte respuestas (los administradores del clúster ven todas las organizaciones; los administradores de organización ven la actividad de su org). |
| **Alerts**         | Registre endpoints de webhook que se disparan cuando fallan las respuestas, con alcance de clúster, organización o equipo.                                                                                                   |
| **Model Registry** | Añada y configure los modelos personalizados disponibles en el registro de su organización.                                                                                                                                  |
| **Pricing**        | Mantenga el libro de precios de modelos: moneda del clúster, precios por modelo y anulaciones por organización (solo administradores del clúster).                                                                           |
| **Budgets**        | Cree presupuestos de gasto de la org con umbrales de alerta/bloqueo y estado de gasto en vivo (los presupuestos de claves API los gestiona el administrador del clúster).                                                    |
| **Usage**          | Revise el uso de tokens, solicitudes y almacenamiento del org y equipo activos.                                                                                                                                              |
| **Fine-tuning**    | Lance y supervise ejecuciones de fine-tuning y checkpoints (próximamente).                                                                                                                                                   |
| **Serving**        | Despliegue modelos en el clúster: despliegues con escalado y reversión, registros de modelos, imágenes, trabajos de fine-tuning, aceleradores y secretos (administradores).                                                  |

## Paso 3 · Invite a su equipo y organice el acceso

<img src="https://mintcdn.com/meetkaiinc/6LyFGcL-YnhBj_CK/images/platform-getting-started/team-detail.png?fit=max&auto=format&n=6LyFGcL-YnhBj_CK&q=85&s=ee9ab4318584cf0bb683d6eefda81963" alt="Página de detalle de equipo en Access → Teams" width="1999" height="1173" data-path="images/platform-getting-started/team-detail.png" />

El acceso a MKA1 se organiza como una jerarquía simple: **organización → equipos → miembros**, con **roles** que controlan lo que cada persona puede hacer y **cuentas de servicio** que representan a los llamadores no humanos.

### La organización y su propietario

Cuando acepta la invitación al clúster, se convierte en **propietario** de su organización. El propietario tiene control total: métricas de uso, miembros, equipos y configuración. Todos los demás que incorpore son **administradores** o **miembros**:

| Rol               | Qué puede hacer                                                   |
| :---------------- | :---------------------------------------------------------------- |
| **Propietario**   | Control total de la organización - uso, miembros y configuración. |
| **Administrador** | Gestiona miembros, equipos y claves API en toda la organización.  |
| **Miembro**       | Accede a los modelos, archivos y claves API de su equipo.         |

### Equipos

Dentro de una organización usted crea **equipos**, y los miembros pertenecen a uno o más de ellos. Los equipos son donde realmente viven el trabajo y el acceso: **las claves API, los agentes y otros recursos están limitados a un solo equipo.** Una clave generada en un equipo concede acceso únicamente a los recursos de ese equipo. Sacar a alguien (o a una cuenta de servicio) de un equipo revoca el acceso que venía con él, y las claves ligadas a ese equipo dejan de funcionar. Esto convierte a los equipos en la frontera natural para separar proyectos, entornos o unidades de negocio. Gestiónelos en **Access → Teams**, donde puede crear un equipo y gestionar su lista plana de miembros.

### Invitar a compañeros

<img src="https://mintcdn.com/meetkaiinc/6LyFGcL-YnhBj_CK/images/platform-getting-started/invite-people.png?fit=max&auto=format&n=6LyFGcL-YnhBj_CK&q=85&s=6c07315e06afc45e5681cfdfef0e907b" alt="Diálogo de invitar personas con selección de rol y equipos" width="1999" height="1173" data-path="images/platform-getting-started/invite-people.png" />

Para añadir a una persona, envíele una **invitación a la organización** por correo. Puede hacerlo navegando a **Access → Organizations** y haciendo clic en **Invite people** en la esquina superior derecha. Comparta el enlace generado que abre la página **Accept invite**, que muestra la organización, quién le invitó, el rol que recibirá y cuándo caduca la invitación.

Lo que hacen para aceptar depende de su estado:

* **Sin cuenta todavía** (Este es el escenario más probable) - se registran (correo/contraseña o Google) con el correo invitado, lo verifican y vuelven a la invitación para terminar de unirse.
* **Ya con sesión iniciada con el correo invitado** - un clic en **Accept & join** los añade a la organización.
* **Con sesión iniciada con otro correo** - se les pide cambiar primero a la cuenta invitada, ya que las invitaciones están vinculadas a una dirección específica.

Las invitaciones pueden caducar o ser revocadas, así que envíe un enlace nuevo si alguien informa de uno muerto.

### Cuentas de servicio para producción

Para sistemas de producción, ejecutores de CI, servicios backend y trabajos programados, use una **cuenta de servicio** en lugar de las credenciales de una persona. Una cuenta de servicio es una identidad máquina no humana que usted adjunta a uno o más equipos, y para la que genera claves API. Puede crear una navegando a **Access → Service accounts** y haciendo clic en **New service account** en la esquina superior derecha. Como las claves heredan el alcance del equipo, separar una cuenta de servicio de un equipo (o eliminarla) detiene inmediatamente todas las claves generadas para ella en ese equipo, dándole un interruptor de apagado limpio para las credenciales de producción.

## Paso 4 · Cree una clave API

<img src="https://mintcdn.com/meetkaiinc/6LyFGcL-YnhBj_CK/images/platform-getting-started/create-api-key.png?fit=max&auto=format&n=6LyFGcL-YnhBj_CK&q=85&s=31359eac6502261378a6f4fac8acc238" alt="Formulario de nueva clave API con pasos de identidad, vinculación de alcance y permisos" width="1999" height="1173" data-path="images/platform-getting-started/create-api-key.png" />

Una clave API es la credencial que su código envía en cada solicitud. En la consola, abra **Access → API Keys** y haga clic en **Create API key**. El formulario recorre cuatro pasos.

### 1 · Identidad

Nombre la clave (p. ej. Production gateway) y elija el principal como el que actúa: **My user** (usa su rol de org y el equipo seleccionado) o una **Service account** (una identidad no humana dedicada. Las cuentas de servicio se recomiendan para casos de uso en producción).

### 2 · Vinculación de alcance

Elija la **organización** y el **equipo** a los que pertenece la clave. Una clave solo puede ver recursos dentro de ese único equipo en esa única org — así que elija el equipo cuyos modelos, archivos y agentes debe alcanzar esta clave. (Si aún no tiene equipo, cree uno primero en **Access → Teams**; las claves deben estar limitadas a un equipo.)

### 3 · Permisos (scopes)

Elija qué recursos puede **leer** y **escribir** la clave. Los scopes se comprueban en cada solicitud. Use un preajuste para avanzar rápido y luego afine:

* **Standard** - los scopes de lectura/escritura cotidianos para crear apps (respuestas, conversaciones, archivos, almacenes vectoriales, prompts, agentes y más).
* **Read-only** - todos los scopes `read:` y nada más.
* **All** - todos los scopes, incluidos los exclusivos de administrador. Disponible solo para propietarios y administradores de la org.

Algunos scopes son **solo de administrador** (fine-tuning, registro de modelos, guardrails, búsqueda, lotes, sandbox, autorización de grano fino) y aparecen solo si usted es propietario o administrador. Conceda el conjunto más estrecho que la clave realmente necesite.

### 4 · Limitación de tasa (opcional)

Opcionalmente limite la clave a un número máximo de solicitudes por minuto, hora o día. La puerta de enlace lo aplica y devuelve `429 Too Many Requests` antes de que la solicitud llegue a un modelo, así que las llamadas por encima del límite no cuestan nada.

<Warning>
  **Copie el secreto ahora — se muestra una sola vez**

  Cuando hace clic en **Create key**, el secreto completo se revela una **única vez**. Cópielo inmediatamente y guárdelo en un lugar seguro (un gestor de secretos o su .env). Si lo pierde, no puede volver a verlo. Regenere la clave para obtener un secreto nuevo. Trátelo como una contraseña: nunca lo suba al control de versiones ni lo exponga en código de navegador.
</Warning>

## Paso 5 · Instale un SDK

MKA1 ofrece SDK para TypeScript, Python y C#, además de una CLI `mka1` independiente. Cada cliente se autentica con su clave API como token Bearer y apunta a la puerta de enlace de la API. La puerta de enlace alojada por defecto es `https://apigw.mka1.com`.

<Note>
  **Clústeres privados**

  En un despliegue privado, sustituya `https://apigw.mka1.com` por el host de la puerta de enlace de su propio clúster en todo lo que sigue. Páselo como la opción `serverURL` / `server_url` / `serverUrl` del SDK, o configúrelo una vez para la CLI. Su administrador puede decirle la URL de la puerta de enlace (es la contraparte de API de su dirección de consola).
</Note>

### TypeScript - @meetkai/mka1

El SDK de TypeScript se instala desde el registro de paquetes npm:

```bash theme={null}
npm add @meetkai/mka1
```

```ts theme={null}
import { SDK } from '@meetkai/mka1';

const mka1 = new SDK({ bearerAuth: 'Bearer YOUR_API_KEY' });
```

### Python - [meetkai-mka1](https://pypi.org/project/meetkai-mka1/)

Requiere Python 3.10 o más reciente:

```bash theme={null}
pip install meetkai-mka1
```

```python theme={null}
from meetkai_mka1 import SDK

sdk = SDK(bearer_auth="Bearer YOUR_API_KEY")
```

### C# - [MeetKai.MKA1](https://www.nuget.org/packages/MeetKai.MKA1/)

```csharp theme={null}
using MeetKai.MKA1;

var sdk = new SDK(bearerAuth: "Bearer YOUR_API_KEY");
```

### CLI - [mka1](https://docs.mka1.com/docs/cli/introduction)

Los binarios precompilados se sirven desde downloads.mka1.com. En macOS (Apple silicon):

```bash theme={null}
curl -fsSL https://downloads.mka1.com/darwin/mka1_darwin_arm64-latest.tar.gz \
  | tar -xz -C /usr/local/bin mka1
mka1 version
```

Cambie arm64 por x86\_64 en Intel; los paquetes .deb/.rpm y un .zip para Windows están enlazados desde la [guía de la CLI](https://docs.mka1.com/docs/cli/introduction). Luego configure su clave y ejecute cualquier comando:

```bash theme={null}
export MKA1_BEARER_AUTH="Bearer YOUR_API_KEY"
mka1 llm models list
```

Para una configuración persistente que guarda los secretos en el llavero de su SO, vea [autenticar la CLI](https://docs.mka1.com/docs/cli/authentication).

## Paso 6 · Autentique sus solicitudes

Cada solicitud lleva su clave API como token bearer en el encabezado `Authorization`. Para apps multiusuario del lado del servidor también envía `X-On-Behalf-Of` para identificar para cuál de *sus* usuarios finales es la solicitud.

```http theme={null}
Authorization: Bearer YOUR_API_KEY
```

### Cuándo enviar X-On-Behalf-Of

Establezca `X-On-Behalf-Of` con un **identificador estable de su propio sistema** (p. ej. `user_123`) siempre que su servidor actúe para un usuario final específico. Esto mantiene las solicitudes, archivos, memoria y uso de ese usuario correctamente atribuidos. Use un ID que no cambie. Nunca use un correo ni un nombre visible.

* **Solo Authorization** - su propio flujo de trabajo backend, no ligado a ningún usuario final.
* **Authorization + X-On-Behalf-Of** - su servidor actuando para uno de sus usuarios finales; el uso y los recursos quedan asociados a él.

<CodeGroup>
  ```ts TypeScript theme={null}
  import type { ResponseObject } from '@meetkai/mka1/models/components';

  const result = await mka1.llm.responses.create({
    xOnBehalfOf: 'user_123',
    responsesCreateRequest: {
      model: 'meetkai:functionary-es-mini',
      input: 'Resuma este ticket de soporte.',
    },
  }) as ResponseObject;
  console.log(result.outputText);
  ```

  ```python Python theme={null}
  response = sdk.llm.responses.create(
      model="meetkai:functionary-es-mini",
      input="Resuma este ticket de soporte.",
      x_on_behalf_of="user_123",
  )
  ```
</CodeGroup>

### Emita tokens de corta duración (opcional)

Cuando un servicio descendente o un cliente de navegador necesita llamar a MKA1 sin poseer su clave API, intercambie la clave por un JWT de corta duración mediante `POST /api/v1/authentication/api-keys/exchange-token`, y luego use ese JWT como token bearer. Vea la [guía de autenticación](https://docs.mka1.com/docs/authentication) y el [análisis en profundidad](https://docs.mka1.com/docs/authentication-deep-dive).

<CodeGroup>
  ```bash bash theme={null}
  curl -X POST https://apigw.mka1.com/api/v1/authentication/api-keys/exchange-token \
    --header "Authorization: Bearer YOUR_API_KEY" \
    --header 'Content-Type: application/json' \
    --data '{ "audience": "https://your-app.example.com", "externalUserId": "user_123" }'
  # → { "token": "<jwt>" } — luego envíe Authorization: Bearer <jwt>
  ```

  ```ts TypeScript theme={null}
  const jwt = await mka1.auth.apiKeys.exchangeToken({
    requestBody: {
      audience: 'https://your-app.example.com',
      externalUserId: 'user_123',
    },
  });

  // jwt.token es el JWT de corta duración — úselo como bearer
  const asEndUser = new SDK({ bearerAuth: `Bearer ${jwt.token}` });
  ```

  ```python Python theme={null}
  jwt = sdk.auth.api_keys.exchange_token(body={
      "audience": "https://your-app.example.com",
      "external_user_id": "user_123",
  })

  # jwt.token es el JWT de corta duración — úselo como bearer
  as_end_user = SDK(bearer_auth=f"Bearer {jwt.token}")
  ```
</CodeGroup>

## Paso 7 · Realice su primera solicitud

Con una clave en mano, genere su primera respuesta. Usar `model: 'auto'` permite que la puerta de enlace elija el modelo adecuado para la solicitud.

<img src="https://mintcdn.com/meetkaiinc/6LyFGcL-YnhBj_CK/images/platform-getting-started/response-detail.png?fit=max&auto=format&n=6LyFGcL-YnhBj_CK&q=85&s=b7f8a1be0bd0a932fd79c8570778417c" alt="Una respuesta completada en la consola con entrada, razonamiento y salida" width="1999" height="1173" data-path="images/platform-getting-started/response-detail.png" />

<CodeGroup>
  ```bash CLI theme={null}
  mka1 llm responses create \
    --model meetkai:functionary-es-mini \
    --input '"¿Cuál es la capital de Francia?"' \
    -H 'X-On-Behalf-Of: <end-user-id>'
  ```

  ```ts TypeScript theme={null}
  import { SDK } from '@meetkai/mka1';
  import type { ResponseObject } from '@meetkai/mka1/models/components';

  const mka1 = new SDK({ bearerAuth: 'Bearer YOUR_API_KEY' });

  const result = await mka1.llm.responses.create({
    responsesCreateRequest: {
      model: 'meetkai:functionary-es-mini',
      input: '¿Cuál es la capital de Francia?',
    },
  }) as ResponseObject;
  console.log(result.outputText);
  ```

  ```python Python theme={null}
  from meetkai_mka1 import SDK

  sdk = SDK(bearer_auth="Bearer YOUR_API_KEY")

  res = sdk.llm.responses.create(
      model="meetkai:functionary-es-mini",
      input="¿Cuál es la capital de Francia?",
  )
  ```

  ```bash curl theme={null}
  curl https://apigw.mka1.com/api/v1/llm/responses \
    --request POST \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Bearer YOUR_API_KEY' \
    --data '{ "model": "meetkai:functionary-es-mini", "input": "¿Cuál es la capital de Francia?" }'
  ```
</CodeGroup>

Ese es el camino completo desde cero. Tiene una organización, un equipo, una clave API, un SDK y una solicitud funcionando. El resto de esta guía recorre los bloques de construcción que ensamblará en aplicaciones reales.

## Construya con la plataforma

Todo lo que sigue puede llamarse con la clave API que acaba de crear. Cada sección se apoya en las guías oficiales de docs.mka1.com. Siga los enlaces incorporados para la referencia completa.

## Generar respuestas (la llamada principal)

<img src="https://mintcdn.com/meetkaiinc/6LyFGcL-YnhBj_CK/images/platform-getting-started/playground-advanced-settings.png?fit=max&auto=format&n=6LyFGcL-YnhBj_CK&q=85&s=4508ba4961de54cf286ead2820124a69" alt="Playground con el panel de ajustes avanzados abierto" width="1999" height="1173" data-path="images/platform-getting-started/playground-advanced-settings.png" />

El recurso Responses es cómo genera texto con MKA1. Pase una cadena simple en `input` para un prompt de un solo turno; el resultado incluye el texto generado en `output_text`. Use `auto_routing: true` para que la puerta de enlace elija el modelo adecuado por usted.

### Llamada básica

<CodeGroup>
  ```ts TypeScript theme={null}
  import { SDK } from '@meetkai/mka1';

  const mka1 = new SDK({
    bearerAuth: `Bearer ${YOUR_API_KEY}`,
  });

  const result = await mka1.llm.responses.create({
    xOnBehalfOf: '<end-user-id>',
    responsesCreateRequest: {
      model: 'meetkai:functionary-es-mini',
      input: 'Escriba un resumen de una frase de la API de MKA1.',
    },
  });
  ```

  ```python Python theme={null}
  from meetkai_mka1 import SDK

  sdk = SDK(bearer_auth="Bearer YOUR_API_KEY")

  res = sdk.llm.responses.create(
      model="meetkai:functionary-es-mini",
      input="Escriba un resumen de una frase de la API de MKA1.",
      http_headers={"X-On-Behalf-Of": "<end-user-id>"},
  )
  ```
</CodeGroup>

Pase `X-On-Behalf-Of` cuando actúe para un usuario final; omítalo en caso contrario.

### Qué hace auto\_routing

`auto_routing` es un indicador de solicitud opcional, separado del alias de modelo `auto`. Cuando establece `auto_routing: true`, la puerta de enlace puntúa la complejidad de la solicitud y la enruta al mejor hermano **cuantizado**, **MoE** o **denso** *dentro de la familia de modelos que usted solicitó*. Nunca cambia a un modelo no relacionado, y recurre al modelo que pidió si esa familia no tiene un hermano compatible.

La puntuación es aditiva. Sube con la longitud del prompt, muchas herramientas o herramientas de alta agencia (p. ej. `code_interpreter`, `mcp`), `tool_choice: 'required'`, salida estructurada, un `max_output_tokens` grande, contexto multivuelta y señales de razonamiento complejo en el texto (debug, refactor, plan, incident, code); baja con prompts cortos y tareas simples reconocidas (traducir, resumir, clasificar, extraer). El total elige el nivel. Puntuaciones altas enrutan a `dense`, medias a `moe`, bajas a `quantized`. Se establece un `reasoning.effort` acorde (desde `minimal` hasta `xhigh`) a menos que usted mismo haya fijado el esfuerzo. Así, un breve "resuma esto" se enruta a `quantized` con esfuerzo `minimal`, mientras que un largo informe de incidente se enruta a `dense` con esfuerzo `high` (o `xhigh`).

Siempre que el enrutamiento se ejecuta, los metadatos de la respuesta registran `routed_model` - la variante realmente usada. Añada `auto_routing_debug: true` para obtener también un campo de metadatos `auto_routing_debug`: una cadena JSON compacta con el modelo solicitado y el enrutado, el nivel elegido, el esfuerzo de razonamiento, la puntuación y las razones detrás de la decisión. Se registra incluso cuando no hay variante hermana disponible, así que es útil para validar el comportamiento del despliegue. Deje este campo desactivado para el tráfico normal de producción.

### Transmita texto a medida que se genera

Establezca `stream: true` para recibir eventos enviados por el servidor en lugar de esperar la respuesta completa. Úselo para renderizar salida parcial a medida que llega.

<CodeGroup>
  ```ts TypeScript theme={null}
  import { CreateAcceptEnum } from '@meetkai/mka1/sdk/responses';
  import { EventStream } from '@meetkai/mka1/lib/event-streams';

  const stream = await mka1.llm.responses.create({
    responsesCreateRequest: {
      model: 'meetkai:functionary-es-mini',
      input: 'Escriba tres viñetas de notas de versión para nuestra actualización de docs.',
      stream: true,
    },
  }, { acceptHeaderOverride: CreateAcceptEnum.textEventStream });

  if (stream instanceof EventStream) {
    for await (const event of stream) {
      if (event.data.type === 'response.output_text.delta') {
        process.stdout.write(event.data.delta);
      }
    }
  }
  ```

  ```python Python theme={null}
  stream = sdk.llm.responses.create(
      model="meetkai:functionary-es-mini",
      input="Escriba tres viñetas de notas de versión para nuestra actualización de docs.",
      stream=True,
  )

  for event in stream:
      if event.data.type == "response.output_text.delta":
          print(event.data.delta, end="", flush=True)
  ```
</CodeGroup>

### Entrada multimodal (imagen + texto)

La API de Responses acepta texto, imágenes, audio y archivos en una sola solicitud. Use un arreglo `input` estructurado de elementos de mensaje, donde `content` es un arreglo que mezcla `input_text` e `input_image` (imagen por URL, URI de datos base64 o un `file_id` subido).

<CodeGroup>
  ```ts TypeScript theme={null}
  const result = await mka1.llm.responses.create({
    xOnBehalfOf: '<end-user-id>',
    responsesCreateRequest: {
      model: 'openai:gpt-4.1', // con visión — 'auto' descarta imágenes hoy
      input: [
        {
          type: 'message',
          role: 'user',
          content: [
            { type: 'input_text', text: 'Describa lo que ve en esta imagen.' },
            {
              type: 'input_image',
              imageUrl: 'https://upload.wikimedia.org/wikipedia/commons/3/3a/Cat03.jpg',
            },
          ],
        },
      ],
    },
  });
  ```

  ```python Python theme={null}
  res = sdk.llm.responses.create(
      model="openai:gpt-4.1",  # con visión — 'auto' descarta imágenes hoy
      input=[
          {
              "type": "message",
              "role": "user",
              "content": [
                  {"type": "input_text", "text": "Describa lo que ve en esta imagen."},
                  {
                      "type": "input_image",
                      "image_url": "https://upload.wikimedia.org/wikipedia/commons/3/3a/Cat03.jpg",
                  },
              ],
          },
      ],
      x_on_behalf_of="<end-user-id>",
  )
  ```
</CodeGroup>

### Respuestas en segundo plano

Para trabajo de larga duración, establezca `background: true` (con `stream: false`) para obtener de inmediato una respuesta en cola, y luego recupere el resultado más tarde sondeando con `mka1.llm.responses.get(...)` o mediante streaming. Vea la guía de [respuestas en segundo plano](https://docs.mka1.com/docs/background-responses).

<CodeGroup>
  ```ts TypeScript theme={null}
  import type { ResponseObject } from '@meetkai/mka1/models/components';

  const queued = await mka1.llm.responses.create({
    responsesCreateRequest: {
      model: 'meetkai:functionary-es-mini',
      input: 'Escriba una historia del fax en dos frases.',
      background: true,
      stream: false,
    },
  }) as ResponseObject;

  // queued.status === 'queued'

  let response = queued;
  while (response.status === 'queued' || response.status === 'in_progress') {
    await new Promise((r) => setTimeout(r, 2000));
    response = await mka1.llm.responses.get({ responseId: queued.id }) as ResponseObject;
  }
  console.log(response.outputText);
  ```

  ```python Python theme={null}
  import time

  queued = sdk.llm.responses.create(
      model="meetkai:functionary-es-mini",
      input="Escriba una historia del fax en dos frases.",
      background=True,
      stream=False,
  )  # queued.status == "queued"

  response = queued
  while response.status in ("queued", "in_progress"):
      time.sleep(2)
      response = sdk.llm.responses.get(response_id=queued.id)

  print(response.output_text)
  ```
</CodeGroup>

#### Webhooks en lugar de sondeo

En lugar de sondear, pase `webhook_url` (y opcionalmente `webhook_secret`) al crear una respuesta en segundo plano. La puerta de enlace envía por POST cada cambio de estado a su endpoint — `response.queued`, `response.in_progress`, `response.completed`, `response.failed`, `response.incomplete`, `response.cancelled` — como `{ event, resource_id, created_at, data }`, donde `data` es el objeto de evento completo.

Con un secreto configurado, cada entrega lleva `X-Webhook-Signature: sha256=<hex>`, un HMAC-SHA256 del cuerpo JSON sin procesar — verifíquelo antes de confiar en la carga útil. La entrega nunca bloquea la respuesta: tres intentos con retroceso exponencial y un tiempo límite de 10 segundos. El endpoint debe ser accesible públicamente — las direcciones privadas y localhost se rechazan. La puerta de enlace requiere que `webhook_secret` tenga al menos 16 caracteres.

<CodeGroup>
  ```ts TypeScript theme={null}
  const queued = await mka1.llm.responses.create({
    responsesCreateRequest: {
      model: 'meetkai:functionary-es-mini',
      input: 'Resuma este informe de 80 páginas…',
      background: true,
      stream: false,
      webhookUrl: 'https://your-app.example.com/hooks/mka1',
      webhookSecret: process.env.MKA1_WEBHOOK_SECRET,
    },
  }) as ResponseObject;
  ```

  ```python Python theme={null}
  import os

  queued = sdk.llm.responses.create(
      model="meetkai:functionary-es-mini",
      input="Resuma este informe de 80 páginas…",
      background=True,
      stream=False,
      webhook_url="https://your-app.example.com/hooks/mka1",
      webhook_secret=os.environ["MKA1_WEBHOOK_SECRET"],
  )
  ```
</CodeGroup>

Para su lado receptor:

```ts theme={null}
import crypto from 'node:crypto';

// En su manejador de webhook — verifique X-Webhook-Signature contra el cuerpo sin procesar de la solicitud
function isValidSignature(rawBody: string, signatureHeader: string, secret: string) {
  const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signatureHeader));
}
```

## Conversaciones y memoria

<img src="https://mintcdn.com/meetkaiinc/6LyFGcL-YnhBj_CK/images/platform-getting-started/conversation-detail.png?fit=max&auto=format&n=6LyFGcL-YnhBj_CK&q=85&s=78e6fd0f03347ab78f5e57bf0ac76804" alt="Detalle de conversación con elementos y metadatos" width="1999" height="1173" data-path="images/platform-getting-started/conversation-detail.png" />

MKA1 le ofrece dos formas complementarias de mantener el contexto entre turnos: **conversaciones con estado** (historial guardado para una sesión, en el servidor) y el **almacén de memoria a largo plazo** (la herramienta history, persistente entre sesiones y con alcance por usuario final).

### Conversaciones con estado

Una conversación es un contenedor del lado del servidor que la puerta de enlace usa para mantener el estado entre solicitudes de Responses, de modo que nunca reenvíe el historial completo. Cree una y luego pase su ID en cada respuesta de seguimiento.

<CodeGroup>
  ```ts TypeScript theme={null}
  import { SDK } from '@meetkai/mka1';

  const mka1 = new SDK({ bearerAuth: `Bearer ${YOUR_API_KEY}` });

  // 1. Cree una conversación (metadatos opcionales para su propio enrutamiento)
  const conv = await mka1.llm.conversations.create({
    xOnBehalfOf: '<end-user-id>',
    createConversationRequest: {
      metadata: { session_id: 'web-42', channel: 'support' },
    },
  });

  // 2. (Opcional) escriba historial explícitamente antes de llamar a Responses
  await mka1.llm.conversations.createItems({
    conversationId: conv.id,
    xOnBehalfOf: '<end-user-id>',
    createItemsRequest: {
      items: [
        { type: 'message', role: 'user', content: 'Resuma el último ticket de soporte.' },
      ],
    },
  });

  // 3. Continúe el flujo — adjunte la conversación para que el modelo tenga historial
  const result = await mka1.llm.responses.create({
    responsesCreateRequest: {
      model: 'meetkai:functionary-es-mini',
      conversation: conv.id,
      input: 'Convierta ese resumen en una respuesta lista para el cliente.',
    },
  });
  ```

  ```python Python theme={null}
  # 1. Cree una conversación (metadatos opcionales para su propio enrutamiento)
  conv = sdk.llm.conversations.create(
      metadata={"session_id": "web-42", "channel": "support"},
      x_on_behalf_of="<end-user-id>",
  )

  # 2. (Opcional) escriba historial explícitamente antes de llamar a Responses
  sdk.llm.conversations.create_items(
      conversation_id=conv.id,
      items=[
          {"type": "message", "role": "user", "content": "Resuma el último ticket de soporte."},
      ],
      x_on_behalf_of="<end-user-id>",
  )

  # 3. Continúe el flujo — adjunte la conversación para que el modelo tenga historial
  result = sdk.llm.responses.create(
      model="meetkai:functionary-es-mini",
      conversation=conv.id,
      input="Convierta ese resumen en una respuesta lista para el cliente.",
  )
  ```
</CodeGroup>

Pase `conversation` en cada solicitud; la puerta de enlace mantiene el hilo por usted. Use una conversación cuando quiera un contenedor reutilizable e inspeccionable para muchos turnos y la capacidad de listar, obtener o eliminar elementos después. Use `previous_response_id` en su lugar cuando solo necesite bifurcar desde una única respuesta anterior.

### Almacén de memoria a largo plazo

La herramienta history da al modelo memoria que persiste **entre** sesiones. Añada `{ type: 'history' }` a `tools` y establezca `store: true`; cada par solicitud/respuesta se indexa en segundo plano y se busca semánticamente (embeddings vectoriales) cuando el modelo decide que necesita recordar algo. La memoria está aislada por usuario final mediante el encabezado `X-On-Behalf-Of`.

<CodeGroup>
  ```ts TypeScript theme={null}
  // Sesión 1: guarde un dato
  await mka1.llm.responses.create({
    xOnBehalfOf: 'user-123',
    responsesCreateRequest: {
      model: 'meetkai:functionary-es-mini',
      input: 'Recuerda esto: mi color favorito es azul.',
      tools: [{ type: 'history' }],
      store: true,
    },
  });

  // Sesión 2 (minutos o días después — la indexación tarda ~1–2 min): recupérelo
  const recalled = await mka1.llm.responses.create({
    xOnBehalfOf: 'user-123',
    responsesCreateRequest: {
      model: 'meetkai:functionary-es-mini',
      input: '¿Cuál es mi color favorito?',
      tools: [{ type: 'history' }],
      store: true,
    },
  });
  // → "Tu color favorito es azul."
  ```

  ```python Python theme={null}
  # Sesión 1: guarde un dato
  sdk.llm.responses.create(
      model="meetkai:functionary-es-mini",
      input="Recuerda esto: mi color favorito es azul.",
      tools=[{"type": "history"}],
      store=True,
      x_on_behalf_of="user-123",
  )

  # Sesión 2 (minutos o días después — la indexación tarda ~1–2 min): recupérelo
  recalled = sdk.llm.responses.create(
      model="meetkai:functionary-es-mini",
      input="¿Cuál es mi color favorito?",
      tools=[{"type": "history"}],
      store=True,
      x_on_behalf_of="user-123",
  )
  ```
</CodeGroup>

**Regla general:** las conversaciones mantienen coherente una sesión; la herramienta history lleva preferencias, decisiones y contexto hacia adelante a través de muchas sesiones para el mismo usuario.

## Archivos, almacenes vectoriales y recuperación (RAG)

<img src="https://mintcdn.com/meetkaiinc/6LyFGcL-YnhBj_CK/images/platform-getting-started/vector-store-detail.png?fit=max&auto=format&n=6LyFGcL-YnhBj_CK&q=85&s=737c6a62cbd16dac3298a304d647e60a" alt="Un almacén vectorial con archivos adjuntos en indexación" width="1999" height="1173" data-path="images/platform-getting-started/vector-store-detail.png" />

MKA1 divide la recuperación en dos recursos: **Files** contiene sus documentos subidos, y **Vector Stores** indexa esos archivos para que pueda ejecutar búsqueda semántica sobre los fragmentos resultantes. Este es el patrón estándar para asistentes respaldados por documentos y respuestas fundamentadas. La indexación es automática. Usted sube, adjunta y busca; MKA1 se encarga del troceado y los embeddings.

Todos los fragmentos siguientes usan el SDK de MKA1 para TypeScript o Python. Inicialice el cliente una vez:

<CodeGroup>
  ```ts TypeScript theme={null}
  import { SDK } from '@meetkai/mka1';

  const mka1 = new SDK({ bearerAuth: 'Bearer <mka1-api-key>' });
  ```

  ```python Python theme={null}
  from meetkai_mka1 import SDK

  sdk = SDK(bearer_auth="Bearer <mka1-api-key>")
  ```
</CodeGroup>

### 1. Suba un archivo

Suba el documento una vez. La respuesta devuelve un objeto de archivo cuyo `id` se parece a `file_1783478060914_iemq10dh5h` — páselo a los almacenes vectoriales en el siguiente paso.

<CodeGroup>
  ```ts TypeScript theme={null}
  const file = Bun.file('./support-manual.pdf');

  const result = await mka1.llm.files.upload({
    xOnBehalfOf: '<end-user-id>',
    requestBody: { file, purpose: 'assistants' },
  });
  // result.id → p. ej. file_1783478060914_iemq10dh5h
  ```

  ```python Python theme={null}
  with open("support-manual.pdf", "rb") as fh:
      result = sdk.llm.files.upload(
          file={"file_name": "support-manual.pdf", "content": fh.read()},
          purpose="assistants",
          x_on_behalf_of="<end-user-id>",
      )
  # result.id → p. ej. file_1783481291595_r19s7ueog7o
  ```
</CodeGroup>

### 2. Cree un almacén vectorial y adjunte archivos

Cree un almacén vectorial, pasando uno o más ID de archivos subidos en `fileIds`. El almacén devuelve un ID como `vs_1783478061269_mptf5b93t0q`. Los archivos adjuntos se indexan automáticamente.

<CodeGroup>
  ```ts TypeScript theme={null}
  const vectorStore = await mka1.llm.vectorStores.create({
    xOnBehalfOf: '<end-user-id>',
    createVectorStoreRequest: {
      name: 'Base de conocimiento de soporte',
      description: 'Manuales de soporte y documentos del centro de ayuda indexados',
      fileIds: [result.id],
      expiresAfter: { anchor: 'last_active_at', days: 30 },
    },
  });
  ```

  ```python Python theme={null}
  vector_store = sdk.llm.vector_stores.create(
      name="Base de conocimiento de soporte",
      description="Manuales de soporte y documentos del centro de ayuda indexados",
      file_ids=[result.id],
      expires_after={"anchor": "last_active_at", "days": 30},
      x_on_behalf_of="<end-user-id>",
  )
  ```
</CodeGroup>

Para añadir más archivos después sin recrear el almacén, use `createFile`:

<CodeGroup>
  ```ts TypeScript theme={null}
  const second = await mka1.llm.files.upload({
    xOnBehalfOf: '<end-user-id>',
    requestBody: { file: Bun.file('./help-center-faq.pdf'), purpose: 'assistants' },
  });

  const vsFile = await mka1.llm.vectorStores.createFile({
    vectorStoreId: vectorStore.id,
    xOnBehalfOf: '<end-user-id>',
    createVectorStoreFileRequest: {
      fileId: second.id,
      attributes: { category: 'faq', version: '2.0' },
    },
  });
  ```

  ```python Python theme={null}
  with open("help-center-faq.pdf", "rb") as fh:
      second = sdk.llm.files.upload(
          file={"file_name": "help-center-faq.pdf", "content": fh.read()},
          purpose="assistants",
          x_on_behalf_of="<end-user-id>",
      )

  vs_file = sdk.llm.vector_stores.create_file(
      vector_store_id=vector_store.id,
      file_id=second.id,
      attributes={"category": "faq", "version": "2.0"},
      x_on_behalf_of="<end-user-id>",
  )
  ```
</CodeGroup>

Un archivo de almacén vectorial puede reportar `status: "in_progress"` mientras se ejecuta la indexación, así que espere a que el procesamiento termine antes de confiar en los resultados de búsqueda.

### 3. Busque fragmentos relevantes en el almacén

Ejecute una búsqueda semántica para recuperar los fragmentos más relevantes para la pregunta de un usuario. La respuesta devuelve coincidencias clasificadas con `file_id`, `filename`, datos de puntuación y el contenido del fragmento. Alimente ese texto a su propia lógica de aplicación o a una solicitud de Responses.

<CodeGroup>
  ```ts TypeScript theme={null}
  const results = await mka1.llm.vectorStores.search({
    vectorStoreId: vectorStore.id,
    xOnBehalfOf: '<end-user-id>',
    searchVectorStoreRequest: {
      query: '¿Cómo restablezco mi contraseña?',
      maxNumResults: 5,
    },
  });
  ```

  ```python Python theme={null}
  results = sdk.llm.vector_stores.search(
      vector_store_id=vector_store.id,
      query="¿Cómo restablezco mi contraseña?",
      max_num_results=5,
      x_on_behalf_of="<end-user-id>",
  )
  ```
</CodeGroup>

### Extra: extracción estructurada

Cuando necesita JSON tipado de un documento en lugar de fragmentos de texto libre, use el recurso Extract. Para trabajo puntual, llame a `extract` con un JSON Schema en línea — pasado como cadena JSON — y el archivo a leer. Para trabajos repetidos, guarde el esquema una vez con `createSchema` (aquí el esquema es un objeto simple) y ejecútelo contra muchos archivos con `extractWithSchema`, referenciando el id del esquema devuelto bajo `data.id`. Nombre un modelo explícitamente en cada llamada de extracción. Una respuesta exitosa devuelve `success`, un objeto `data` con los campos extraídos y `metadata` sobre la ejecución.

<CodeGroup>
  ```ts TypeScript theme={null}
  const schema = {
    type: 'object',
    properties: {
      document_title: { type: 'string' },
      reset_link_expiry_minutes: { type: 'number' },
      support_email: { type: 'string' },
    },
    required: ['document_title'],
  };

  // Extracción puntual — aquí el esquema es una cadena JSON
  const res = await mka1.llm.extract.extract({
    requestBody: {
      model: 'openai:gpt-4.1', // 'auto' actualmente devuelve 500 en este endpoint
      prompt: 'Extraiga el título del documento, la caducidad del enlace de restablecimiento y el correo de soporte.',
      schema: JSON.stringify(schema),
      file: Bun.file('./support-manual.txt'),
    },
  });
  // → { success, data: {…}, metadata: {…} }
  ```

  ```python Python theme={null}
  import json

  schema = {
      "type": "object",
      "properties": {
          "document_title": {"type": "string"},
          "reset_link_expiry_minutes": {"type": "number"},
          "support_email": {"type": "string"},
      },
      "required": ["document_title"],
  }

  # Extracción puntual — aquí el esquema es una cadena JSON
  with open("support-manual.txt", "rb") as fh:
      res = sdk.llm.extract.extract(
          model="openai:gpt-4.1",  # 'auto' actualmente devuelve 500 en este endpoint
          prompt="Extraiga el título del documento, la caducidad del enlace de restablecimiento y el correo de soporte.",
          schema=json.dumps(schema),
          file={"file_name": "support-manual.txt", "content": fh.read()},
      )
  # res.success, res.data, res.metadata
  ```
</CodeGroup>

<CodeGroup>
  ```ts TypeScript theme={null}
  // Plantilla reutilizable — aquí el esquema es un objeto; el id llega bajo data.id
  const created = await mka1.llm.extract.createSchema({
    extractionSchema: {
      name: 'support-manual',
      description: 'Extraer datos del manual de soporte',
      schema,
    },
  });

  const out = await mka1.llm.extract.extractWithSchema({
    schemaId: created.data.id,
    requestBody: {
      model: 'openai:gpt-4.1',
      prompt: 'Extraiga los campos.',
      file: Bun.file('./support-manual.txt'),
    },
  });
  ```

  ```python Python theme={null}
  # Plantilla reutilizable — aquí el esquema es un dict; el id llega bajo data.id
  created = sdk.llm.extract.create_schema(
      name="support-manual",
      description="Extraer datos del manual de soporte",
      schema=schema,
  )

  out = sdk.llm.extract.extract_with_schema(
      schema_id=created.data.id,
      model="openai:gpt-4.1",
      prompt="Extraiga los campos.",
      file={"file_name": "support-manual.txt", "content": open("support-manual.txt", "rb").read()},
  )
  ```
</CodeGroup>

## Agentes, herramientas y MCP

<img src="https://mintcdn.com/meetkaiinc/6LyFGcL-YnhBj_CK/images/platform-getting-started/agent-run.png?fit=max&auto=format&n=6LyFGcL-YnhBj_CK&q=85&s=9873202c75de301445f64edba6c99064" alt="Ejecutar un agente guardado desde la consola" width="1999" height="1173" data-path="images/platform-getting-started/agent-run.png" />

Un **agente guardado** es un objeto de agente reutilizable que almacena su propio comportamiento para que no reconstruya una solicitud de Responses cada vez. Cada agente persiste un modelo, instrucciones y una configuración de herramientas (`tools`, `tool_choice`, `parallel_tool_calls`, `max_tool_calls`, `text`, `reasoning`). Cuando lo ejecuta, el servicio combina su entrada por ejecución con la configuración guardada y la reenvía a la API de Responses a través de mkllm-gateway. Cada ejecución persiste la entrada más el resultado de Responses del upstream, así que también obtiene historial de ejecuciones gratis. Los agentes reciben un id estable como `agt_...`.

### Cree un agente

Cree un agente una vez con los SDK de MKA1 para Python, TypeScript o C#, incluyendo una herramienta integrada `web_search` para que las ejecuciones puedan incorporar información externa actual:

<CodeGroup>
  ```ts TypeScript theme={null}
  import { SDK } from '@meetkai/mka1';

  const mka1 = new SDK({ bearerAuth: 'Bearer YOUR_API_KEY' });

  const agent = await mka1.agents.createAgent({
    createAgentRequest: {
      name: 'release-research-agent',
      description: 'Busca información actual de versiones antes de responder.',
      model: 'meetkai:functionary-es-mini',
      instructions: 'Use la búsqueda web cuando la pregunta dependa de información externa actual.',
      tools: [{ type: 'web_search', searchContextSize: 'medium' }],
      metadata: { team: 'docs' },
    },
  });
  console.log(agent.id);
  ```

  ```python Python theme={null}
  from meetkai_mka1 import SDK

  sdk = SDK(bearer_auth="Bearer YOUR_API_KEY")

  agent = sdk.agents.create_agent(
      name="release-research-agent",
      description="Busca información actual de versiones antes de responder.",
      model="meetkai:functionary-es-mini",
      instructions="Use la búsqueda web cuando la pregunta dependa de información externa actual.",
      tools=[{"type": "web_search", "search_context_size": "medium"}],
      metadata={"team": "docs"},
  )

  print(agent.id)
  ```
</CodeGroup>

El arreglo `tools` completo (tal como se envía por HTTPS) configura la herramienta integrada:

```json theme={null}
"tools": [
  { "type": "web_search", "search_context_size": "medium" }
],
"tool_choice": "auto",
"parallel_tool_calls": true
```

### Ejecute un agente

Ejecute enviando solo la entrada por ejecución. La ejecución persiste `status`, el `gateway_response` almacenado y `gateway_response_id` de la llamada upstream. Si la ejecución usó `web_search`, el `gateway_response` persistido incluye las entradas de llamadas a herramientas.

<CodeGroup>
  ```ts TypeScript theme={null}
  const run = await mka1.agentRuns.createAgentRun({
    agentId: agent.id,
    createAgentRunRequest: {
      input: '¿Cuál es la versión estable actual de Bun? Use la búsqueda web antes de responder.',
      metadata: { request_source: 'docs' },
    },
  });

  console.log(run.gatewayResponseId);
  console.log(run.status);
  ```

  ```python Python theme={null}
  run = sdk.agent_runs.create_agent_run(
      agent_id="agt_123",
      input="¿Cuál es la versión estable actual de Bun? Use la búsqueda web antes de responder.",
      metadata={"request_source": "docs"},
  )

  print(run.gateway_response_id)
  print(run.status)
  ```
</CodeGroup>

Use `sdk.agents.list_agents(...)` / `sdk.agent_runs.list_agent_runs(agent_id=...)` para inspeccionar agentes guardados y ejecuciones anteriores.

<CodeGroup>
  ```ts TypeScript theme={null}
  const agents = await mka1.agents.listAgents({});
  const runs = await mka1.agentRuns.listAgentRuns({ agentId: agent.id });
  ```

  ```python Python theme={null}
  agents = sdk.agents.list_agents()
  runs = sdk.agent_runs.list_agent_runs(agent_id="agt_123")
  ```
</CodeGroup>

### Historial de versiones y reversión

Cada cambio confirmado en un agente guardado — crear, actualizar, revertir — añade una versión inmutable, así que el historial de configuración de un agente siempre es inspeccionable. Revertir no reescribe el historial: añade una nueva versión restaurada desde la de destino.

<CodeGroup>
  ```ts TypeScript theme={null}
  // Actualice el agente — esto confirma la versión 2
  await mka1.agents.updateAgent({
    agentId: agent.id,
    updateAgentRequest: { instructions: 'Responda con detalle exhaustivo.' },
  });

  // Inspeccione el historial
  const versions = await mka1.agentVersions.listAgentVersions({ agentId: agent.id });
  // versions.data → [ { version: 2, isCurrent: true, … }, { version: 1, … } ]

  // Obtenga una versión completa
  const v2 = await mka1.agentVersions.getAgentVersion({ agentId: agent.id, version: 2 });

  // Revierta a v1 — añade v3 con restoredFromVersion: 1
  await mka1.agentVersions.rollbackAgentVersion({ agentId: agent.id, version: 1 });
  ```

  ```python Python theme={null}
  sdk.agents.update_agent(agent_id=agent.id, instructions="Responda con detalle exhaustivo.")

  versions = sdk.agent_versions.list_agent_versions(agent_id=agent.id)
  # versions.data → [AgentVersion(version=2, is_current=True, …), AgentVersion(version=1, …)]

  v2 = sdk.agent_versions.get_agent_version(agent_id=agent.id, version=2)

  sdk.agent_versions.rollback_agent_version(agent_id=agent.id, version=1)
  # el historial ahora es v3 (actual, restored_from_version=1), v2, v1
  ```
</CodeGroup>

### Adjunte un servidor de herramientas MCP

Más allá de las herramientas integradas, puede permitir que el modelo llame a herramientas de un servidor MCP externo añadiendo una entrada `mcp` a `tools`. Establezca `require_approval` en `"never"` para ejecutar de inmediato, o `"always"` para pausar y pedir aprobación del usuario final. Limite las herramientas invocables con `allowed_tools`; pase credenciales upstream en `headers` (se enmascaran en las respuestas almacenadas).

<CodeGroup>
  ```ts TypeScript theme={null}
  import type { ResponseObject } from '@meetkai/mka1/models/components';

  const response = await mka1.llm.responses.create({
    responsesCreateRequest: {
      model: 'meetkai:functionary-es-mini',
      instructions: 'Use las herramientas de Linear cuando el usuario pregunte sobre tareas, errores o proyectos.',
      input: 'Liste mi issue de Linear más reciente asignado a mí.',
      tools: [
        {
          type: 'mcp',
          serverLabel: 'Linear MCP',
          serverUrl: 'https://mcp.linear.app/mcp',
          allowedTools: ['issues.list'],
          headers: { Authorization: `Bearer ${process.env.LINEAR_API_KEY}` },
          requireApproval: 'never',
        },
      ],
    },
  }) as ResponseObject;

  console.log(response.outputText);
  ```

  ```python Python theme={null}
  import os

  response = sdk.llm.responses.create(
      model="meetkai:functionary-es-mini",
      instructions="Use las herramientas de Linear cuando el usuario pregunte sobre tareas, errores o proyectos.",
      input="Liste mi issue de Linear más reciente asignado a mí.",
      tools=[
          {
              "type": "mcp",
              "server_label": "Linear MCP",
              "server_url": "https://mcp.linear.app/mcp",
              "allowed_tools": ["issues.list"],
              "headers": {"Authorization": f"Bearer {os.environ['LINEAR_API_KEY']}"},
              "require_approval": "never",
          },
      ],
  )

  print(response.output_text)
  ```
</CodeGroup>

El modelo llama a la herramienta MCP permitida y devuelve el mensaje final en una sola solicitud. Con `require_approval: "always"`, cree la respuesta en modo de segundo plano, sondéela y maneje el elemento `mcp_approval_request` devolviendo un `mcp_approval_response`.

## Prompts, habilidades y guardrails

<img src="https://mintcdn.com/meetkaiinc/6LyFGcL-YnhBj_CK/images/platform-getting-started/prompt-detail.png?fit=max&auto=format&n=6LyFGcL-YnhBj_CK&q=85&s=f940c3c74c8bd740787abbe6f6dd8346" alt="Una plantilla de prompt versionada en el repositorio de prompts" width="1999" height="1173" data-path="images/platform-getting-started/prompt-detail.png" />

MKA1 separa el *qué* de una llamada LLM (sus prompts), las *capacidades* que agrupa para ella (habilidades) y la *gobernanza* que mantiene el uso seguro y con rendición de cuentas (guardrails, limitación de tasa y auditoría).

### Repositorio de prompts

La API de Prompts almacena, versiona y renderiza plantillas de prompts de forma centralizada. Cada cambio de plantilla crea una versión inmutable, así que obtiene un historial de cambios completo y puede revertir a cualquier versión anterior en cualquier momento. Una reversión no es destructiva y solo cambia la versión activa. Las plantillas usan marcadores `{{variable}}` que se renderizan del lado del servidor cuando recupera un prompt, permitiéndole reutilizar una plantilla en distintos contextos. Los prompts están aislados por clave API.

<CodeGroup>
  ```ts TypeScript theme={null}
  import { SDK } from '@meetkai/mka1';

  const mka1 = new SDK({ bearerAuth: `Bearer ${YOUR_API_KEY}` });

  const prompt = await mka1.llm.prompts.create({
    createPromptRequest: {
      name: 'greeting',
      template: '¡Hola, {{name}}! Bienvenido a {{company}}.',
    },
  });

  const rendered = await mka1.llm.prompts.get({
    id: prompt.id,
    variables: JSON.stringify({ name: 'Alice', company: 'Acme' }),
  });
  console.log(rendered.renderedTemplate); // "¡Hola, Alice! Bienvenido a Acme."
  ```

  ```python Python theme={null}
  import json

  prompt = sdk.llm.prompts.create(
      name="greeting",
      template="¡Hola, {{name}}! Bienvenido a {{company}}.",
  )

  rendered = sdk.llm.prompts.get(
      id=prompt.id,
      variables=json.dumps({"name": "Alice", "company": "Acme"}),
  )
  print(rendered.rendered_template)  # "¡Hola, Alice! Bienvenido a Acme."
  ```
</CodeGroup>

### Habilidades

Las habilidades son paquetes de capacidades reutilizables y versionados que usted sube a la puerta de enlace. Cada habilidad empaqueta el comportamiento de herramientas tras un manifiesto SKILL.md. El nombre y la descripción de la habilidad se leen directamente de ese manifiesto. Puede subir un conjunto de archivos único o un paquete completo, gestionar versiones (cada habilidad rastrea una versión por defecto y la más reciente) y revisar cada archivo antes de crearla. Gestione las habilidades en el panel bajo **Skills**, o mediante la API de Skills.

### Guardrails, limitación de tasa y auditoría de uso

Estas tres funciones de gobernanza mantienen el tráfico delegado y multiusuario controlado y con rendición de cuentas:

* **Limitación de tasa** - Cada clave API puede llevar una cuota sobre una ventana configurable — por minuto, hora o día. Cuando una clave supera su límite, la puerta de enlace devuelve `429 Too Many Requests` antes de que la solicitud llegue al modelo, así que no se consumen tokens ni se factura uso. Maneje los 429 con reintentos de retroceso exponencial.
* **Auditoría de uso** - Revise el uso de tokens, solicitudes y almacenamiento por org y equipo en **Admin → Usage**, filtrable por usuario (miembros de la org). Para informes por usuario final, consulte la API de uso con su filtro `external_user_ids` — la identidad `X-On-Behalf-Of`. Cada respuesta también devuelve un `X-Request-ID` que puede guardar como clave de correlación.
* **Guardrails** - Las decisiones de política se registran en el mismo flujo de auditoría: resultados como `policy_violation` o `throttled` y valores de `policy_action` de `warn`, `block` o `escalate` fluyen a la página de Guardrails, dándole un camino consistente desde un informe de uso hasta la acción exacta que fue permitida, advertida, bloqueada o escalada.

Fuentes: [repositorios de prompts](https://docs.mka1.com/docs/prompt-repository), [limitación de tasa](https://docs.mka1.com/docs/rate-limiting), [auditoría de uso](https://docs.mka1.com/docs/usage-auditing) y [habilidades](https://reference.mka1.com/reference#tag/skills).

## Habla y voz

<img src="https://mintcdn.com/meetkaiinc/6LyFGcL-YnhBj_CK/images/platform-getting-started/text-to-speech-detail.png?fit=max&auto=format&n=6LyFGcL-YnhBj_CK&q=85&s=f28fa5329e249f122e48e5ac4a1d9de7" alt="Detalle de generación de texto a voz con salida de audio" width="1999" height="1173" data-path="images/platform-getting-started/text-to-speech-detail.png" />

MKA1 expone la voz basada en archivos a través del recurso `llm.speech` del SDK. Use `speak` para texto a voz y `transcribe` para voz a texto. Para conversaciones bidireccionales en tiempo real, use el modo de voz avanzado en su lugar. El modo de voz avanzado se cubre por separado.

### Texto a voz

`speak` devuelve un archivo WAV completo. El cuerpo de la respuesta es audio binario, y los encabezados de respuesta incluyen `X-Language-Code`.

<CodeGroup>
  ```ts TypeScript theme={null}
  import { SDK } from '@meetkai/mka1';
  import { writeFileSync } from 'node:fs';

  const mka1 = new SDK({ bearerAuth: 'Bearer <mka1-api-key>' });

  const { headers, result } = await mka1.llm.speech.speak({
    textToSpeechRequest: {
      text: 'Welcome to the MKA1 API speech guide.',
      language: 'en',
    },
  });
  // headers['x-language-code'] → ['en']

  const chunks = [];
  for await (const chunk of result) chunks.push(chunk);
  writeFileSync('speech.wav', Buffer.concat(chunks));
  ```

  ```python Python theme={null}
  res = sdk.llm.speech.speak(
      text="Welcome to the MKA1 API speech guide.",
      language="en",
  )
  # res.headers["x-language-code"] → ["en"]; res.result transmite los bytes WAV

  with open("speech.wav", "wb") as fh:
      fh.write(res.result.read())
  ```
</CodeGroup>

Para reproducción de baja latencia que comienza antes de que el archivo completo esté listo, use `speakStreaming` y elija `mp3` (más pequeño) o `pcm` (sin comprimir):

<CodeGroup>
  ```ts TypeScript theme={null}
  // Variante de baja latencia
  const streamed = await mka1.llm.speech.speakStreaming({
    textToSpeechStreamingRequest: {
      text: 'Start speaking this response as soon as audio is ready.',
      language: 'en',
      format: 'mp3',
    },
  });
  ```

  ```python Python theme={null}
  # Variante de baja latencia — note format_ con guion bajo final
  streamed = sdk.llm.speech.speak_streaming(
      text="Start speaking this response as soon as audio is ready.",
      language="en",
      format_="mp3",
  )
  ```
</CodeGroup>

### Voz a texto

`transcribe` acepta un archivo de audio (FLAC, MP3, MP4, M4A, OGG, WAV, WebM, PCM y más) y devuelve la transcripción junto con el idioma detectado y la confianza:

<CodeGroup>
  ```ts TypeScript theme={null}
  import { openAsBlob } from 'node:fs';

  const result = await mka1.llm.speech.transcribe({
    language: 'en',
    prompt: 'This is a technical podcast about machine learning.',
    temperature: 0.2,
    requestBody: { file: await openAsBlob('episode.wav') },
  });

  console.log(result.text);       // transcripción
  console.log(result.confidence); // confianza de la detección
  ```

  ```python Python theme={null}
  with open("episode.wav", "rb") as fh:
      result = sdk.llm.speech.transcribe(
          file={"file_name": "episode.wav", "content": fh.read()},
          language="en",
          prompt="This is a technical podcast about machine learning.",
          temperature=0.2,
      )

  print(result.text)        # transcripción
  print(result.confidence)  # confianza de la detección
  ```
</CodeGroup>

Para separación de múltiples hablantes, establezca `includeSpeakerData: true` (requiere audio WAV o PCM). La respuesta entonces incluye un arreglo `speakers` con segmentos etiquetados y tiempos `offset_ms` / `duration_ms`.

Archivos fuente: [voz](https://docs.mka1.com/docs/speech), [salida multimodal](https://docs.mka1.com/docs/multimodal-output).

## Evaluar y observar

Una vez que algo funciona, MKA1 le ayuda a medirlo y a vigilarlo en producción.

<img src="https://mintcdn.com/meetkaiinc/6LyFGcL-YnhBj_CK/images/platform-getting-started/eval-suite.png?fit=max&auto=format&n=6LyFGcL-YnhBj_CK&q=85&s=9f1dbcc0f00e950bddd7439c92319f27" alt="Una suite de evaluación con conjunto de datos, calificador y versiones" width="1999" height="1173" data-path="images/platform-getting-started/eval-suite.png" />

* **Evals** - Construya una suite de evaluación a partir de conjuntos de datos, prompts y calificadores, y luego lance ejecuciones duraderas contra uno o más modelos. Rastree la precisión y las puntuaciones por muestra, y compare modelos en una tabla de clasificación. Úselo para elegir un modelo y para detectar regresiones antes de que se publiquen.
* **Sessions** - Cada ejecución de agente se registra. Reproduzca la transcripción (mensajes, razonamiento, llamadas a herramientas) y recorra los eventos sin procesar para depurar exactamente qué hizo un agente.
* **Uso y auditoría** - Revise el uso de tokens, solicitudes y almacenamiento por org y equipo en **Admin → Usage**, y filtre por usuario final cuando envíe `X-On-Behalf-Of`. Cada respuesta también devuelve un `X-Request-ID` que puede guardar como clave de correlación.

### Auditoría

<img src="https://mintcdn.com/meetkaiinc/6LyFGcL-YnhBj_CK/images/platform-getting-started/audit.png?fit=max&auto=format&n=6LyFGcL-YnhBj_CK&q=85&s=158bbbbb22bf6fdd81521b5b022203ee" alt="La vista de Audit del tráfico de la puerta de enlace en Admin → Audit" width="1999" height="1013" data-path="images/platform-getting-started/audit.png" />

Audit (**Admin → Audit**) es la superficie de revisión del tráfico que pasó por la puerta de enlace. Los administradores del clúster ven solicitudes de todas las organizaciones y equipos; los administradores de organización ven la actividad de su propia org. Busque por ruta, path o usuario; filtre por servicio, método, estado, modelo o estado de revisión; o pegue un `X-Request-ID` — devuelto en cada respuesta de la API — para saltar a la solicitud exacta. Marque entradas para revisión, agrupe solicitudes relacionadas en casos y exporte datos de respuesta para análisis fuera de línea.

### Alertas

<img src="https://mintcdn.com/meetkaiinc/6LyFGcL-YnhBj_CK/images/platform-getting-started/alerts.png?fit=max&auto=format&n=6LyFGcL-YnhBj_CK&q=85&s=6d6922ef40c295457b2a0be3e5b4a25d" alt="Endpoints de webhook de alertas en Admin → Alerts" width="1999" height="1004" data-path="images/platform-getting-started/alerts.png" />

Las alertas convierten los fallos en webhooks. En **Admin → Alerts**, registre una URL de endpoint y elija su alcance: todo el clúster (administradores del clúster), su organización (propietarios y administradores de org) o un solo equipo — los administradores de org pueden apuntar a cualquier equipo, y los miembros de equipo pueden gestionar webhooks de su propio equipo activo. Suscriba el endpoint a uno o ambos tipos de evento — `response.failed` (una solicitud de respuesta falló en el proveedor del modelo) y `gateway.request.failed` (cualquier solicitud de la puerta de enlace devolvió un 5xx) — o deje la suscripción vacía para recibirlos todos. Los filtros opcionales limitan la entrega a claves API, códigos de error o modelos específicos.

Cada endpoint tiene una página de detalle que muestra su configuración, su secreto de firma (revelarlo, copiarlo o rotarlo) y las entregas recientes con cargas útiles y estado succeeded / failed / pending. Desde ahí puede reenviar una entrega, disparar una alerta de prueba mientras integra, y editar, deshabilitar o eliminar el endpoint — editar nunca cambia el secreto de firma.

## Precios, presupuestos y uso

Cada solicitud fluye por una tubería de facturación: el uso registra los volúmenes, el libro de precios de modelos los convierte en costos y los presupuestos aplican límites sobre el resultado. Esta sección cubre los tres.

### Precios

<img src="https://mintcdn.com/meetkaiinc/6LyFGcL-YnhBj_CK/images/platform-getting-started/pricing.png?fit=max&auto=format&n=6LyFGcL-YnhBj_CK&q=85&s=02fa4d0f64af96eaad31d93f0a7d67ba" alt="Formulario de añadir precio de modelo en Admin → Pricing" width="1999" height="1010" data-path="images/platform-getting-started/pricing.png" />

Cada solicitud se mide y se tarifica contra el libro de precios de modelos de su clúster. Los administradores del clúster mantienen el libro de precios en **Admin → Pricing**:

* **Moneda del clúster** - La moneda en la que se denominan todos los precios y presupuestos.
* **Precios de modelos** - La tarifa por defecto del clúster, un precio por modelo. Las dimensiones de tarifa siguen la modalidad del modelo: tokens de entrada, salida, entrada en caché y razonamiento para LLM; audio y caracteres para voz; tarifas por imagen con niveles opcionales por tamaño; búsqueda web.
* **Anulaciones por org** - Precios por organización para cuando una org factura distinto del valor por defecto del clúster.
* **Tarifas efectivas** - Una vista de resolución que muestra qué precio — por defecto del clúster, anulación de org o sin precio — resuelve cada modelo para una organización dada. Los modelos sin precio facturan a 0.

Los precios llevan fecha: guardar añade una nueva versión y nunca reescribe el costo pasado. El gasto aparece entonces en dos lugares:

* **Admin → Usage** - Gasto total tarificado desde el libro de precios, desglosado por organización, equipo, clave API y modelo — junto con los volúmenes subyacentes (vea Uso más abajo).
* **La API** - Consulte el gasto en cualquier rango de tiempo, agrupado por modelo, clave API, equipo, organización o usuario final (la identidad `X-On-Behalf-Of`). Este es el alimentador para sistemas de facturación; los Presupuestos (abajo) aplican límites contra el mismo gasto.

<CodeGroup>
  ```ts TypeScript theme={null}
  const now = Math.floor(Date.now() / 1000);

  const spend = await mka1.usage.costs({
    startTime: now - 7 * 24 * 60 * 60, // últimos 7 días (segundos unix)
    endTime: now,
    groupBy: 'model,api_key_id', // dimensiones separadas por comas
  });
  // spend.data → [{ model, apiKeyId, teamId, externalUserId, orgId, cost }, …]
  ```

  ```python Python theme={null}
  import time

  now = int(time.time())
  spend = sdk.usage.costs(
      start_time=now - 7 * 24 * 3600,  # últimos 7 días (segundos unix)
      end_time=now,
      group_by="model,api_key_id",  # dimensiones separadas por comas
  )
  # spend.data → filas con model, api_key_id, team_id, external_user_id, org_id, cost
  ```
</CodeGroup>

### Presupuestos

<img src="https://mintcdn.com/meetkaiinc/6LyFGcL-YnhBj_CK/images/platform-getting-started/budgets.png?fit=max&auto=format&n=6LyFGcL-YnhBj_CK&q=85&s=36094849ed0c62bf28bbccc30732211e" alt="Formulario de nuevo presupuesto de organización en Admin → Budgets" width="1999" height="1016" data-path="images/platform-getting-started/budgets.png" />

Los presupuestos limitan el gasto total por período en una organización o una clave API. Créelos y gestiónelos en **Admin → Budgets** — los administradores de organización gestionan los presupuestos de su org, mientras que los presupuestos de claves API hoy los gestiona el administrador del clúster. Un presupuesto tiene tres partes:

* **Período y límite** - Diario, semanal o mensual, con un límite en la moneda del clúster. Las ventanas de gasto se reinician en los límites del calendario UTC.
* **Umbrales** - Porcentajes únicos del límite, cada uno emparejado con una acción: `alert` (notificar) o `block` (rechazar más solicitudes). Un presupuesto que superó un umbral de bloqueo muestra Blocked en las columnas en vivo Spend y Status.
* **Webhook de alerta (opcional)** - Una URL más un secreto de firma HMAC que recibe las notificaciones de umbral.

Cada fila de presupuesto muestra el gasto en vivo contra su límite; abra el historial de un presupuesto para revisar los eventos de umbral del período, y edite o elimine presupuestos según cambien las necesidades. Los presupuestos tienen dos propietarios: los presupuestos de clúster son techos del operador (solo lectura para administradores de org), mientras que los presupuestos de org son autoimpuestos. La aplicación es de mejor esfuerzo y fail-open, así que dimensione los límites con margen.

Las mismas operaciones están disponibles por la API — conceda a la clave los scopes de Presupuestos exclusivos de administrador (`read:budgets` / `write:budgets`) en el asistente de claves del Paso 4.

<CodeGroup>
  ```ts TypeScript theme={null}
  // Presupuesto mensual propio en una clave API: advertir al 80%, bloquear al 100%
  await mka1.budgets.setApiKey({
    apiKeyId: 'ak_…',
    requestBody: {
      period: 'monthly',
      limit: 250, // en la moneda de su clúster — vea budgets.getCurrency()
      thresholds: [
        { pct: 80, action: 'alert' },
        { pct: 100, action: 'block' },
      ],
      webhookUrl: 'https://your-app.example.com/hooks/budget',
      webhookSecret: process.env.MKA1_WEBHOOK_SECRET,
    },
  });

  const budgets = await mka1.budgets.getApiKey({ apiKeyId: 'ak_…' });
  const events = await mka1.budgets.apiKeyEvents({ apiKeyId: 'ak_…' });
  await mka1.budgets.deleteApiKey({ apiKeyId: 'ak_…', owner: 'org' });

  // Variantes a nivel de org: budgets.setOrg / getOrg / deleteOrg / orgEvents ({ orgId, … })
  ```

  ```python Python theme={null}
  sdk.budgets.set_api_key(
      api_key_id="ak_…",
      period="monthly",
      limit=250,
      thresholds=[
          {"pct": 80, "action": "alert"},
          {"pct": 100, "action": "block"},
      ],
  )

  budgets = sdk.budgets.get_api_key(api_key_id="ak_…")
  events = sdk.budgets.api_key_events(api_key_id="ak_…")
  sdk.budgets.delete_api_key(api_key_id="ak_…", owner="org")

  # Variantes a nivel de org: set_org / get_org / delete_org / org_events (org_id=…)
  ```
</CodeGroup>

### Uso

<img src="https://mintcdn.com/meetkaiinc/6LyFGcL-YnhBj_CK/images/platform-getting-started/usage.png?fit=max&auto=format&n=6LyFGcL-YnhBj_CK&q=85&s=cbc37240ac560ee4186fc863d45db8ea" alt="El panel de Usage con tokens en el tiempo y desgloses por modelo en Admin → Usage" width="1999" height="1002" data-path="images/platform-getting-started/usage.png" />

El uso es el libro de volúmenes detrás de los precios y los presupuestos — los tokens, conteos de solicitudes y almacenamiento de cada solicitud se miden por organización, equipo, clave API y usuario final. Vive en dos lugares:

* **En la consola** - **Admin → Usage** muestra un gráfico de tokens en el tiempo (24h / 7d / 30d), desgloses por categoría (Responses, Completions, Embeddings, Classify, Extract) con tokens de entrada/salida y conteos de solicitudes por modelo, filas por usuario final, almacenamiento de archivos y vectores, y operaciones de sandbox — todo exportable como CSV. La sección de gasto tarifica estos volúmenes desde el libro de precios de modelos (vea **Precios** arriba).
* **Por la API** - Los endpoints por categoría (`llm.usage.responses`, `completions`, `conversations`, `embeddings`, `extract`, `classify`, `vectorStores`, `files`) devuelven series agrupadas en el tiempo. Elija un `bucket_width`, filtre por `models`, `user_ids` o `external_user_ids` (la identidad `X-On-Behalf-Of`) y agrupe por `model`, `api_key_id`, `user_id`, `org_id` o `background` para informes por dimensión.

<CodeGroup>
  ```ts TypeScript theme={null}
  const now = Math.floor(Date.now() / 1000);

  const usage = await mka1.llm.usage.responses({
    startTime: now - 7 * 24 * 60 * 60, // últimos 7 días (segundos unix)
    endTime: now,
    bucketWidth: '1d',
    groupBy: 'model',
  });
  // usage.data → un bucket por día, cada uno con resultados por modelo
  // (tokens de entrada/salida, conteos de solicitudes)
  ```

  ```python Python theme={null}
  import time

  now = int(time.time())
  usage = sdk.llm.usage.responses(
      start_time=now - 7 * 24 * 3600,  # últimos 7 días (segundos unix)
      end_time=now,
      bucket_width="1d",
      group_by="model",
  )
  # usage.data → un bucket por día, cada uno con resultados por modelo
  ```
</CodeGroup>

## Serving

Serving convierte los aceleradores de su clúster — GPU, NPU o TPU — en endpoints de inferencia con autoescalado para los modelos que usted elija. Vive en su propia sección Serving de la barra lateral (administradores de organización y de clúster), y su organización debe ser aprovisionada para serving por el operador del clúster antes del primer uso. Seis bloques de construcción:

* **Deployments** - Un modelo servido tras un endpoint de inferencia en aceleradores dedicados, respaldado por vLLM o SGLang. Los cambios de configuración generan una nueva revisión — vuelva a cualquier revisión anterior en cualquier momento — mientras que los cambios de escalado se aplican en el sitio. La URL del endpoint se asigna cuando el despliegue está listo, y la autenticación del endpoint requiere que los llamadores presenten una clave API válida. Cada despliegue expone estado, réplicas, revisiones, registros y métricas.
* **Models** - Registre un modelo servible por nombre y origen, opcionalmente fijando una rama, etiqueta o revisión de commit para despliegues reproducibles.
* **Images** - Construya imágenes de contenedor personalizadas (imagen OCI base, paquetes apt, comandos de build) para motores de serving y trabajos de fine-tuning; los despliegues usan por defecto la imagen estándar del motor.
* **Fine-tune jobs** - Entrene en los aceleradores del clúster: un modelo base, un conjunto de datos, una estrategia (LoRA por defecto, o fine-tuning completo) e hiperparámetros libres. Siga los registros y la línea de tiempo de eventos, recoja checkpoints y cancele en cualquier momento.
* **Accelerators** - Los tipos de aceleradores disponibles para su organización (p. ej. A100, H100) y sus límites por tipo.
* **Volumes & secrets** - Volúmenes persistentes (de tamaño fijo, o elásticos que crecen bajo demanda) y secretos como un hf-token, inyectados en los despliegues como variables de entorno.

El autoescalado es por despliegue: réplicas mínimas y máximas, réplicas de reserva listas para absorber ráfagas, un tope de solicitudes concurrentes enrutadas a una réplica antes de escalar hacia afuera, y una ventana de inactividad (2–1200 segundos) antes de reducir la escala.

<CodeGroup>
  ```ts TypeScript theme={null}
  // 1. Registre el modelo a servir (fije una revisión para despliegues reproducibles)
  await mka1.serving.models.register({
    modelRegister: { name: 'qwen-7b', source: 'Qwen/Qwen2.5-7B-Instruct' },
  });

  // 2. Despliéguelo tras un endpoint con autoescalado
  const deployment = await mka1.serving.deployments.create({
    deploymentCreate: {
      name: 'qwen-7b-prod',
      model: 'qwen-7b',
      engine: 'vllm',
      accelerator: { type: 'H100', count: 1, fallback: ['A100'] },
      scaling: { minContainers: 1, maxContainers: 4, maxConcurrentInputs: 32 },
      engineArgs: ['--max-model-len', '8192'],
      endpointAuth: true,
    },
  });
  // la URL del endpoint aparece en el despliegue cuando está listo

  // 3. Opérelo
  await mka1.serving.deployments.updateScaling({
    deploymentId: deployment.id,
    scaling: { minContainers: 2, maxContainers: 8 }, // se aplica en el sitio — sin nueva revisión
  });

  const logs = await mka1.serving.deployments.getLogs({ deploymentId: deployment.id, tail: 100 });

  await mka1.serving.deployments.rollback({
    deploymentId: deployment.id,
    deploymentRollbackRequest: { revision: 1 }, // los cambios de configuración generan revisiones
  });
  ```

  ```python Python theme={null}
  # 1. Registre el modelo a servir (fije una revisión para despliegues reproducibles)
  sdk.serving.models.register(name="qwen-7b", source="Qwen/Qwen2.5-7B-Instruct")

  # 2. Despliéguelo tras un endpoint con autoescalado
  deployment = sdk.serving.deployments.create(
      name="qwen-7b-prod",
      model="qwen-7b",
      engine="vllm",
      accelerator={"type": "H100", "count": 1, "fallback": ["A100"]},
      scaling={"min_containers": 1, "max_containers": 4, "max_concurrent_inputs": 32},
      engine_args=["--max-model-len", "8192"],
      endpoint_auth=True,
  )
  # la URL del endpoint aparece en el despliegue cuando está listo

  # 3. Opérelo
  sdk.serving.deployments.update_scaling(
      deployment_id=deployment.id,
      min_containers=2,
      max_containers=8,  # se aplica en el sitio — sin nueva revisión
  )

  logs = sdk.serving.deployments.get_logs(deployment_id=deployment.id, tail=100)

  sdk.serving.deployments.rollback(deployment_id=deployment.id, revision=1)
  ```
</CodeGroup>

## En conjunto: construya un agente de principio a fin

Los bloques de construcción se componen. Este es el flujo insignia de principio a fin: indexe conocimiento, conecte herramientas, empaquete una habilidad, ensamble un agente, ejecútelo y rastree el resultado.

<img src="https://mintcdn.com/meetkaiinc/6LyFGcL-YnhBj_CK/images/platform-getting-started/new-agent-tools.png?fit=max&auto=format&n=6LyFGcL-YnhBj_CK&q=85&s=ff3533965814ffdc566b67ce4f77c885" alt="Formulario de creación de agente con herramientas integradas" width="1999" height="1173" data-path="images/platform-getting-started/new-agent-tools.png" />

1. **Indexe conocimiento.** Suba sus documentos como Files y adjúntelos a un Vector Store para que el agente pueda fundamentar respuestas en su contenido (vea *Archivos, almacenes vectoriales y recuperación*).
2. **Conecte herramientas.** Registre un servidor MCP (o use herramientas integradas como `web_search`) para que el agente pueda actuar y obtener datos en vivo (vea *Agentes, herramientas y MCP*).
3. **Empaquete una habilidad.** Agrupe comportamiento reutilizable tras un SKILL.md y súbalo bajo **Skills**, luego adjúntelo.
4. **Ensamble el agente.** Cree un agente guardado con un modelo, instrucciones y ese conjunto de herramientas. Configura el agente una vez, así que no reconstruye la solicitud en cada llamada.
5. **Ejecútelo.** Ejecute el agente con entrada nueva desde la consola o `POST /api/v1/agents/{id}/runs`. Cada ejecución persiste su entrada y la respuesta de la puerta de enlace.
6. **Rastree la ejecución.** Abra **Sessions** para reproducir la transcripción y confirmar que el agente llamó a las herramientas correctas.

## Referencia y soporte

Tenga esto a mano mientras construye:

| Recurso                                            | Dónde                                                                                            |
| :------------------------------------------------- | :----------------------------------------------------------------------------------------------- |
| Referencia completa de la API (OpenAPI + "Try it") | [Referencia de la API](https://docs.mka1.com/api-reference/introduction)                         |
| Autenticación                                      | [docs.mka1.com/docs/authentication](https://docs.mka1.com/docs/authentication)                   |
| Generar una respuesta                              | [docs.mka1.com/docs/generate-a-response](https://docs.mka1.com/docs/generate-a-response)         |
| Archivos y almacenes vectoriales                   | [docs.mka1.com/docs/files-and-vector-stores](https://docs.mka1.com/docs/files-and-vector-stores) |
| Gestionar agentes                                  | [docs.mka1.com/docs/managing-agents](https://docs.mka1.com/docs/managing-agents)                 |
| Herramientas MCP                                   | [docs.mka1.com/docs/mcp-tools](https://docs.mka1.com/docs/mcp-tools)                             |
| CLI                                                | [docs.mka1.com/docs/cli/introduction](https://docs.mka1.com/docs/cli/introduction)               |
| SDK de Python                                      | [pypi.org/project/meetkai-mka1/](https://pypi.org/project/meetkai-mka1/)                         |
| SDK de C#                                          | [nuget.org/packages/MeetKai.MKA1/](https://www.nuget.org/packages/MeetKai.MKA1/)                 |
| SDK de TypeScript                                  | [npmjs.com/package/@meetkai/mka1](https://www.npmjs.com/package/@meetkai/mka1)                   |

<Note>
  **Resumen rápido**

  1. Acepte la invitación al clúster → es propietario de una nueva organización.
  2. Cree un equipo e invite a compañeros.
  3. Genere una clave API en ese equipo (copie el secreto una vez).
  4. Instale un SDK y autentíquese con `Authorization: Bearer`.
  5. Llame a `responses.create` — luego componga conversaciones, memoria, RAG, agentes, herramientas y voz en su app.
</Note>

Bienvenido a bordo. Ahora vaya a construir algo.
