Inovacc Desarrolladores

Referencia de la API

Embeddings de IA

Convierte texto en vectores para búsqueda y similitud.

URL base https://ai.inovacc.dev

Descripción general

Los embeddings de IA convierten texto en vectores: listas de números cuya distancia entre sí sigue el significado del texto. Dos pasajes sobre lo mismo quedan cerca aunque no compartan palabras. El endpoint, POST /v1/embeddings, usa el formato de red de embeddings de OpenAI, por lo que un cliente de OpenAI existente puede llamarlo con la URL base https://ai.inovacc.dev/v1 y dos encabezados adicionales.

El problema que resuelve es la comparación semántica dentro de tus propios sistemas. Con vectores puedes buscar por significado, agrupar elementos similares, encontrar casi duplicados o dirigir un mensaje a la categoría más cercana, con la base de datos o el índice que ya uses.

Usa los embeddings de IA cuando tú guardas los vectores. Si prefieres que Inovacc los guarde, los busque y devuelva los pasajes coincidentes, usa la base de datos vectorial administrada de Conocimiento y búsqueda vectorial, que genera los embeddings de tus documentos por ti. Cuando necesites texto generado en lugar de vectores, usa el Chat con IA.

Conceptos

Rutas. Igual que con el chat, nunca nombras un modelo. A tu organización se le asignan rutas de embeddings, ids opacos configurados por Inovacc. GET /v1/models las lista: una entrada cuyo endpoint es /v1/embeddings es una ruta de embeddings. Envía su id como model, o envía "auto" (o ningún model) para usar la ruta predeterminada de tu organización. Una ruta sirve un solo endpoint; una ruta de chat invocada aquí se rechaza.

Entrada. input es una cadena no vacía, o un arreglo de cadenas; dentro de un arreglo se acepta una cadena vacía. La respuesta contiene un vector por entrada, en data[], cada uno con el index de la entrada a la que pertenece.

Los vectores de una ruta van juntos. Un vector solo es comparable con vectores producidos por la misma ruta. Guarda el id de la ruta junto a cada vector que conserves, y genera los embeddings de tus documentos y de tus consultas con la misma ruta.

Campos opcionales. encoding_format y dimensions se pasan al modelo cuando el modelo de la ruta los admite, y se ignoran en caso contrario. user se acepta como cadena y, antes de salir de Inovacc, se reemplaza por un valor derivado de tu organización, de modo que dos organizaciones que envían el mismo valor nunca colisionan.

Uso. El usage de la respuesta contiene prompt_tokens y total_tokens. Este endpoint no lleva encabezados x-usage-*; la ruta que respondió está en x-route-id.

Cómo funciona

Toda llamada lleva Authorization: Bearer <key> y un X-Operation-Id. Tu organización se obtiene de la clave. El servicio verifica el id de operación y la clave, luego si ese id de operación ya se usó, y después el cuerpo: solo se aceptan model, input, encoding_format, dimensions y user, y cualquier otro campo se rechaza por su nombre. Resuelve la ruta, verifica que la ruta sirva embeddings, valida input, estima el tamaño de la entrada (una cuarta parte de los caracteres de cada cadena de entrada) frente al tope por solicitud de tu organización, y reserva la llamada contra las cuotas de tu organización. Entonces se llama al modelo.

La respuesta es {"object":"list","data":[{"object":"embedding","index":0,"embedding":[...]}],"model":"<route id>","usage":{...}}. model es siempre el id de la ruta.

No hay streaming. Una respuesta exitosa se almacena durante 24 horas bajo su id de operación: el mismo id enviado de nuevo devuelve los mismos vectores con x-idempotent-replay: true, sin una segunda llamada ni cobro. Un error nunca se almacena, así que una llamada fallida puede reintentarse con el mismo id. Lo que se mide son los tokens de entrada.

Primeros pasos

Necesitas una clave de API y una ruta de embeddings habilitada para tu organización (Autenticación).

  1. Encuentra tu ruta de embeddings. Llama a GET /v1/models y elige una entrada cuyo endpoint sea /v1/embeddings.
  2. Genera los embeddings de dos pasajes. Llama a POST /v1/embeddings con esa ruta como model, un arreglo input de dos cadenas y un X-Operation-Id nuevo (consulta los ejemplos). La respuesta tiene dos entradas en data, con index 0 y 1, y model es el id de tu ruta.
  3. Compáralos. Calcula la similitud coseno de los dos vectores en tu código. Genera el embedding de un tercer pasaje sobre otro tema y compara de nuevo: su puntuación frente al primero es menor.
  4. Repite. Envía de nuevo el paso 2 con el mismo id de operación; los vectores son idénticos y la respuesta lleva x-idempotent-replay: true.

Casos de uso

Búsqueda en tu propia base de datos. Un catálogo de productos guarda un vector por cada descripción de producto en la base de datos que ya usa. La pregunta de un comprador se convierte en embedding con la misma ruta al momento de la consulta, y se muestran los productos más cercanos, incluidos aquellos cuya descripción usa otras palabras.

Detección de casi duplicados. Un sistema de tickets genera el embedding de cada ticket nuevo y lo compara con los abiertos; una puntuación por encima de un umbral que tú calibras vincula el ticket con el caso existente en lugar de abrir un segundo caso.

Enrutamiento por similitud. Un conjunto pequeño de mensajes de ejemplo por equipo se convierte en embeddings una sola vez. De cada mensaje entrante se genera el embedding y se envía al equipo cuyos ejemplos estén más cerca, sin ninguna llamada a un modelo por mensaje aparte del embedding.

Límites y precios

LímiteValor
Cuerpo de la solicitud1 MiB por defecto; tu organización puede configurarse entre 1 KiB y 20 MiB
Tokens de entrada por solicitudel tope de tu organización (400 input_too_large por encima de él)
Tiempo hasta la primera respuesta del modelo60 segundos
Respuesta almacenada para una repetición24 horas
Solicitudes, tokens, costo, concurrencia, presupuestos diariossegún lo configurado para tu organización

Precios: a consultar. La unidad de precio son los tokens.

Errores

EstadoCódigoQué significa y qué hacer
400missing_operation_id, invalid_operation_idEnvía un X-Operation-Id válido.
400unsupported_fieldUn campo distinto de model, input, encoding_format, dimensions, user; quítalo.
400invalid_bodyJSON mal formado, input con una forma incorrecta, o un user que no es cadena.
400model_not_allowedmodel no es un id de ruta válido.
400input_too_largeLa entrada supera tu tope por solicitud; divídela en varias llamadas.
401missing_credentials, invalid_credentialsEnvía una clave válida.
403route_forbiddenLa ruta no es tuya, está deshabilitada o no sirve embeddings.
403key_disabled, organization_disabledRevisa la clave.
409operation_in_progressEse id de operación sigue en ejecución; espera y reintenta.
413request_too_largeEl cuerpo supera tu tope de tamaño.
429rate_limited, budget_exhaustedEspera los segundos de Retry-After.
429quota_exceeded, concurrency_limitedSe agotó una asignación; sin Retry-After.
502, 503, 504upstream_error, service_unavailable, timeout_errorReintenta con el mismo id de operación y espera creciente.

Consulta Errores para el envoltorio.

Buenas prácticas

  • Agrupa las entradas en lotes: envía muchos pasajes en un solo arreglo input, dentro de tus topes de tamaño y de tokens, en lugar de una llamada por pasaje.
  • Conserva el id de la ruta junto con el vector, y vuelve a generar todos los embeddings si cambias de ruta: los vectores de dos rutas no son comparables.
  • Divide los documentos largos en fragmentos de unos pocos párrafos antes de generar los embeddings; un solo vector para un documento completo difumina su significado.
  • Deriva el id de operación del contenido (por ejemplo, un hash del lote) para que un trabajo reiniciado repita la respuesta en lugar de volver a pagar.
  • Reintenta 502, 503 y 504 con el mismo id de operación; espera Retry-After en 429 rate_limited.
  • Calibra los umbrales con tus propios datos: las puntuaciones de similitud son relativas, no probabilidades.

Autenticación

Toda llamada lleva tu clave; tu organización viene de ella. Consulta la guía de autenticación.

EncabezadoAuthorizationBearer <clave de API>
EncabezadoX-Operation-Idun id único que tú eliges, en toda llamada excepto GET

Endpoints

POST /v1/embeddings

Ejemplo

Lenguaje

⋮
POST /v1/embeddingsEjemplo

cURL

curl -X POST "https://ai.inovacc.dev/v1/embeddings" \
  -H "Authorization: Bearer $INOVACC_API_KEY" \
  -H "X-Operation-Id: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "input": [
    "first passage",
    "second passage"
  ],
  "model": "r-embed"
}'

TypeScript

import crypto from "node:crypto";

const body: Record<string, unknown> = {
  "input": [
    "first passage",
    "second passage"
  ],
  "model": "r-embed"
};

const url = "https://ai.inovacc.dev/v1/embeddings";

const response = await fetch(url, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.INOVACC_API_KEY}`,
    "X-Operation-Id": crypto.randomUUID(),
    "Content-Type": "application/json",
  },
  body: JSON.stringify(body),
});

console.log(response.status, await response.text());

Python

import json
import os
import urllib.request
import uuid

body = {
    "input": [
        "first passage",
        "second passage",
    ],
    "model": "r-embed",
}

request = urllib.request.Request(
    "https://ai.inovacc.dev/v1/embeddings",
    data=json.dumps(body).encode(),
    method="POST",
    headers={
        "User-Agent": "inovacc-python-sample",
        "Authorization": "Bearer " + os.environ["INOVACC_API_KEY"],
        "X-Operation-Id": str(uuid.uuid4()),
        "Content-Type": "application/json",
    },
)

with urllib.request.urlopen(request) as response:
    print(response.status, response.read().decode())

Go

package main

import (
	"crypto/rand"
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
)

const url = "https://ai.inovacc.dev/v1/embeddings"

const body = `{
  "input": [
    "first passage",
    "second passage"
  ],
  "model": "r-embed"
}`

// newUUID returns a random (version 4) UUID, from the standard library alone.
func newUUID() string {
	b := make([]byte, 16)
	if _, err := rand.Read(b); err != nil {
		panic(err)
	}
	b[6] = b[6]&0x0f | 0x40
	b[8] = b[8]&0x3f | 0x80
	return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
}

func main() {
	req, err := http.NewRequest("POST", url, strings.NewReader(body))
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("INOVACC_API_KEY"))
	req.Header.Set("X-Operation-Id", newUUID())
	req.Header.Set("Content-Type", "application/json")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	out, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	fmt.Println(res.Status, string(out))
}

Rust

// Cargo.toml: reqwest = { version = "0.12", features = ["blocking", "json"] }
// Cargo.toml: serde_json = "1"
// Cargo.toml: uuid = { version = "1", features = ["v4"] }

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api_key = std::env::var("INOVACC_API_KEY")?;
    let body = serde_json::json!({
        "input": [
            "first passage",
            "second passage"
        ],
        "model": "r-embed"
    });
    let response = reqwest::blocking::Client::new()
        .post("https://ai.inovacc.dev/v1/embeddings")
        .bearer_auth(api_key)
        .header("X-Operation-Id", uuid::Uuid::new_v4().to_string())
        .json(&body)
        .send()?;
    println!("{} {}", response.status(), response.text()?);
    Ok(())
}

JavaScript

import crypto from "node:crypto";

const body = {
  "input": [
    "first passage",
    "second passage"
  ],
  "model": "r-embed"
};

const url = "https://ai.inovacc.dev/v1/embeddings";

const response = await fetch(url, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.INOVACC_API_KEY}`,
    "X-Operation-Id": crypto.randomUUID(),
    "Content-Type": "application/json",
  },
  body: JSON.stringify(body),
});

console.log(response.status, await response.text());

PHP

<?php

$body = <<<'JSON'
{
  "input": [
    "first passage",
    "second passage"
  ],
  "model": "r-embed"
}
JSON;

function uuid4(): string
{
    $bytes = random_bytes(16);
    $bytes[6] = chr(ord($bytes[6]) & 0x0f | 0x40);
    $bytes[8] = chr(ord($bytes[8]) & 0x3f | 0x80);
    return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($bytes), 4));
}

$curl = curl_init('https://ai.inovacc.dev/v1/embeddings');
curl_setopt_array($curl, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('INOVACC_API_KEY'),
        'X-Operation-Id: ' . uuid4(),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => $body,
]);

$response = curl_exec($curl);
echo curl_getinfo($curl, CURLINFO_HTTP_CODE), ' ', $response, "\n";
curl_close($curl);

Ruby

require "net/http"
require "securerandom"
require "uri"

uri = URI('https://ai.inovacc.dev/v1/embeddings')
body = <<~'JSON'
{
  "input": [
    "first passage",
    "second passage"
  ],
  "model": "r-embed"
}
JSON

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch('INOVACC_API_KEY')}"
request["X-Operation-Id"] = SecureRandom.uuid
request["Content-Type"] = "application/json"
request.body = body

response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") do |http|
  http.request(request)
end

puts "#{response.code} #{response.body}"

Java

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.UUID;

public class Main {
    public static void main(String[] args) throws Exception {
        String apiKey = System.getenv("INOVACC_API_KEY");
        String body = "{" +
                "\"input\": [" +
                "\"first passage\"," +
                "\"second passage\"" +
                "]," +
                "\"model\": \"r-embed\"" +
                "}";

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://ai.inovacc.dev/v1/embeddings"))
                .header("Authorization", "Bearer " + apiKey)
                .header("X-Operation-Id", UUID.randomUUID().toString())
                .header("Content-Type", "application/json")
                .method("POST", HttpRequest.BodyPublishers.ofString(body))
                .build();

        HttpResponse<String> response = HttpClient.newHttpClient()
                .send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.statusCode() + " " + response.body());
    }
}

C#

using System.Text;

var body = "{" +
    "\"input\": [" +
    "\"first passage\"," +
    "\"second passage\"" +
    "]," +
    "\"model\": \"r-embed\"" +
    "}";

var url = "https://ai.inovacc.dev/v1/embeddings";
var apiKey = Environment.GetEnvironmentVariable("INOVACC_API_KEY");

using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Post, url);
request.Headers.Add("Authorization", $"Bearer {apiKey}");
request.Headers.Add("X-Operation-Id", Guid.NewGuid().ToString());
request.Content = new StringContent(body, Encoding.UTF8, "application/json");

using var response = await client.SendAsync(request);
Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");

Kotlin

import java.net.URI
import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse
import java.util.UUID

fun main() {
    val apiKey = System.getenv("INOVACC_API_KEY")
    val body = "{" +
        "\"input\": [" +
        "\"first passage\"," +
        "\"second passage\"" +
        "]," +
        "\"model\": \"r-embed\"" +
        "}"

    val request = HttpRequest.newBuilder()
        .uri(URI.create("https://ai.inovacc.dev/v1/embeddings"))
        .header("Authorization", "Bearer " + apiKey)
        .header("X-Operation-Id", UUID.randomUUID().toString())
        .header("Content-Type", "application/json")
        .method("POST", HttpRequest.BodyPublishers.ofString(body))
        .build()

    val response = HttpClient.newHttpClient()
        .send(request, HttpResponse.BodyHandlers.ofString())
    println("${response.statusCode()} ${response.body()}")
}

Swift

import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

let body = #"""
{
  "input": [
    "first passage",
    "second passage"
  ],
  "model": "r-embed"
}
"""#

let apiKey = ProcessInfo.processInfo.environment["INOVACC_API_KEY"] ?? ""

let url = URL(string: "https://ai.inovacc.dev/v1/embeddings")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
request.setValue(UUID().uuidString, forHTTPHeaderField: "X-Operation-Id")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = Data(body.utf8)

let (data, response) = try await URLSession.shared.data(for: request)
let status = (response as? HTTPURLResponse)?.statusCode ?? 0
print(status, String(decoding: data, as: UTF8.self))
Detalles de la fuente

Entrada del catálogo

Id
identity/component-taxonomy/capabilities#ai.embeddings
Repositorio
identity
Ruta
contracts/component-taxonomy/catalog/capabilities.json
Commit
08ef3cd75d82

Ejemplo

Id
identity/component-taxonomy/quickstart#ai.embeddings
Repositorio
identity
Ruta
contracts/component-taxonomy/catalog/capabilities.json
Commit
08ef3cd75d82
Actualizado el 2026-10-10.