Model Serving plugin
Model Serving plugin
Proporciona un proxy autenticado hacia los endpoints de Databricks Model Serving, con soporte para invocación y streaming.
Características principales:
- Alias con nombre para múltiples endpoints de serving
- Invocación sin streaming (
invoke) y con streaming SSE (stream) - Generación automática de tipos OpenAPI para los esquemas de solicitud y respuesta
- Filtrado del cuerpo de la solicitud según el esquema del endpoint
- Ejecución en nombre del usuario (OBO, on-behalf-of)
Uso básico
import { createApp, server, serving } from "@databricks/appkit";
await createApp({
plugins: [
server(),
serving(),
],
});Si no se define ninguna configuración, el plugin lee DATABRICKS_SERVING_ENDPOINT_NAME del entorno y lo registra con el alias default.
Opciones de configuración
| Opción | Tipo | Valor predeterminado | Descripción |
|---|---|---|---|
endpoints | Record<string, EndpointConfig> | { default: { env: "DATABRICKS_SERVING_ENDPOINT_NAME" } } | Mapa de alias a configuraciones de endpoint |
timeout | number | 120000 | Tiempo de espera de la solicitud en ms |
Alias de endpoints
Los alias de endpoints te permiten hacer referencia a varios endpoints de serving por nombre:
serving({
endpoints: {
llm: { env: "DATABRICKS_SERVING_ENDPOINT_NAME" },
classifier: { env: "DATABRICKS_SERVING_ENDPOINT_CLASSIFIER" },
},
})Cada alias se corresponde con una variable de entorno que contiene el nombre real del endpoint. Si un endpoint sirve varios modelos, puedes usar servedModel para omitir el enrutamiento de tráfico y dirigirte directamente a un modelo concreto:
serving({
endpoints: {
llm: { env: "DATABRICKS_SERVING_ENDPOINT_NAME", servedModel: "llama-v2" },
},
})Generación de tipos
El plugin de Vite appKitServingTypesPlugin() genera tipos de TypeScript a partir de los esquemas OpenAPI de tus endpoints de serving. No requiere configuración manual: el servidor de desarrollo de AppKit incluye este plugin automáticamente.
El plugin detecta automáticamente la configuración de los endpoints en tu archivo de servidor (server/index.ts o server/server.ts).
Los tipos generados ofrecen:
- Autocompletado de alias tanto en el backend (
AppKit.serving("alias")) como en los hooks del frontend (useServingStream,useServingInvoke) - Tipado de request/response/chunk por endpoint según los esquemas OpenAPI
Si el esquema OpenAPI de un endpoint no está disponible (no se ha hecho deploy, la variable de entorno no está definida), el plugin genera tipos genéricos de respaldo. El endpoint se puede seguir usando, solo que sin request/response tipados.
Los endpoints que no definen un esquema de respuesta en streaming en su especificación OpenAPI tendrán chunk: unknown. Para esos endpoints, usa useServingInvoke en lugar de useServingStream: el tipo de response seguirá estando correctamente tipado.
Variables de entorno
| Variable | Descripción |
|---|---|
DATABRICKS_SERVING_ENDPOINT_NAME | Nombre del endpoint predeterminado (se usa cuando se omite la configuración endpoints) |
Al usar endpoints con nombre, define una variable de entorno personalizada para cada alias (por ejemplo, DATABRICKS_SERVING_ENDPOINT_CLASSIFIER).
Contexto de ejecución
De forma predeterminada, todas las rutas de serving se ejecutan en nombre del usuario autenticado (OBO), igual que en los plugins de Genie y Files. Así se garantiza que los permisos CAN_QUERY de cada usuario se apliquen en el endpoint de serving.
Para el acceso programático mediante exports(), usa .asUser(req) para ejecutar en el contexto del usuario:
// Contexto del service principal (predeterminado)
const result = await AppKit.serving("llm").invoke({ messages });
// Contexto de usuario (recomendado en los handlers de rutas)
const result = await AppKit.serving("llm").asUser(req).invoke({ messages });Endpoints HTTP
Modo con nombre (con configuración de endpoints)
POST /api/serving/:alias/invoke— Invocación sin streamingPOST /api/serving/:alias/stream— Invocación con streaming SSE
Modo predeterminado (sin configuración de endpoints)
POST /api/serving/invoke— Invocación sin streamingPOST /api/serving/stream— Invocación con streaming SSE
Formato de la solicitud
POST /api/serving/:alias/invoke
Content-Type: application/json
{
"messages": [
{ "role": "user", "content": "Hello" }
]
}Acceso programático
El plugin exporta los métodos invoke y stream para uso del lado del servidor:
const AppKit = await createApp({
plugins: [
server(),
serving({
endpoints: {
llm: { env: "DATABRICKS_SERVING_ENDPOINT_NAME" },
},
}),
],
});
// Sin streaming
const result = await AppKit.serving("llm").invoke({
messages: [{ role: "user", content: "Hello" }],
});
// Con streaming
for await (const chunk of AppKit.serving("llm").stream({
messages: [{ role: "user", content: "Hello" }],
})) {
console.log(chunk);
}Hooks de frontend
El paquete @databricks/appkit-ui proporciona hooks de React para los endpoints de serving:
useServingStream
Invocación en streaming mediante SSE:
import { useServingStream } from "@databricks/appkit-ui/react";
function ChatStream() {
const { stream, chunks, streaming, error, reset } = useServingStream(
{ messages: [{ role: "user", content: "Hello" }] },
{
alias: "llm",
onComplete: (finalChunks) => {
// Se invoca con todos los chunks acumulados cuando finaliza el stream
console.log("Stream done, got", finalChunks.length, "chunks");
},
},
);
return (
<>
<button onClick={stream} disabled={streaming}>Send</button>
<button onClick={reset}>Reset</button>
{chunks.map((chunk, i) => <pre key={i}>{JSON.stringify(chunk)}</pre>)}
{error && <p>{error}</p>}
</>
);
}useServingInvoke
Invocación sin streaming. invoke() devuelve una promesa con los datos de la respuesta (o null en caso de error):
import { useServingInvoke } from "@databricks/appkit-ui/react";
function Classify() {
const { invoke, data, loading, error } = useServingInvoke(
{ inputs: ["sample text"] },
{ alias: "classifier" },
);
async function handleClick() {
const result = await invoke();
if (result) {
console.log("Classification result:", result);
}
}
return (
<>
<button onClick={handleClick} disabled={loading}>Classify</button>
{data && <pre>{JSON.stringify(data)}</pre>}
{error && <p>{error}</p>}
</>
);
}Ambos hooks aceptan autoStart: true para invocarse automáticamente al montarse.