行业动态
dev.to ·
@Daniel Castillo
Jev TypeSafe AI 与 LangChain、Vercel AI Gateway 集成实践
文章介绍 jev 这一专用于分类、优先级排序和路由等决策任务的模型:它不生成文本,而是评估状态并返回带类型的决策及各选项概率。文中演示如何通过 Vercel AI Gateway 将 jev 与 LangChain 结合使用,并提供可安装的 jev-ai-gateway-langchain skill。作者引用 TypeSafe 发布的评测称 jev 速度最高提升 193.6 倍、成本降低 444.6 倍,但该数据为厂商自测,未获独立验证。
AI推荐理由 介绍 jev 这一面向分类/路由/优先级决策的类型化决策模型,并给出与 LangChain、Vercel AI Gateway 的集成方式及可安装的 skill。文中引用的 193.6 倍速度、444.6 倍成本优势来自 TypeSafe 自发布的评测,缺乏第三方验证,需谨慎看待;集成教程本身对开发者有参考价值。
62
正文
La mayoría de sistemas usan un LLM para decidir cosas como clasificar, priorizar o enrutar.
jev está diseñado específicamente para tomar esas decisiones. En lugar de generar texto, evalúa un estado y devuelve una decisión tipada junto con las probabilidades de cada opción.
En las evaluaciones publicadas por TypeSafe, jev alcanzó hasta 193,6× mayor velocidad y 444,6× menor costo que los modelos de referencia.
En este artículo vas a ver cómo usar jev con LangChain a través de Vercel AI Gateway.
Dale esta skill a tu agente de código
Si quieres que tu agente de código conozca esta integración, puedes instalar la skill jev-ai-gateway-langchain.
La skill incluye la configuración de AI Gateway y ejemplos de los primitives y middlewares utilizados en este artículo.
En Claude Code:
claude plugin marketplace add dcastillogi/skills
claude plugin install jev-ai-gateway-langchain@dcastillogi
Enter fullscreen mode
Exit fullscreen mode
Para otros agentes compatibles con skills.sh:
npx skills add dcastillogi/skills --skill jev-ai-gateway-langchain
Enter fullscreen mode
Exit fullscreen mode
Después de instalarla, puedes pedirle al agente que configure la conexión, cree classifiers con los primitives adecuados o incorpore los middlewares en tu aplicación de LangChain.
Paso 1: entender la entrada y la salida
Una solicitud a jev tiene dos partes principales:
State: los datos que quieres evaluar. Puede ser un ticket, un documento, un registro o el historial de un agente.
Questions: las decisiones que jev debe tomar sobre esos datos.
state + questions → jev → respuestas tipadas + probabilidades
Enter fullscreen mode
Exit fullscreen mode
Puedes enviar varias preguntas sobre el mismo estado. Jev las evalúa en paralelo y devuelve cada respuesta bajo el identificador que definiste.
Las preguntas de una misma solicitud son independientes. Si una decisión necesita el resultado de otra para formularse, debes hacer una segunda solicitud.
Paso 2: elegir el primitive adecuado
Antes de construir tu classifier, define qué forma debe tener cada respuesta. TypeSafe ofrece tres primitives: Noul, Choice y Score.
Primitive
Tipo de decisión
Resultado
Noul
Evaluar una condición binaria
Probabilidad entre 0 y 1
Choice
Elegir una categoría
Opción, distribución y confianza
Score
Medir una escala ordenada
Puntaje, distribución, leyenda y confianza
Noul: evaluar una condición
Noul responde qué tan probable es que una condición sea verdadera. En un sistema de soporte puedes utilizarlo para representar la urgencia de un ticket:
from langchain_typesafe import Noul, NoulCriteria
urgent_question = Noul(
instructions="¿El ticket requiere atención inmediata?",
criteria=NoulCriteria(
true="El cliente está bloqueado o existe una interrupción crítica.",
false="La solicitud puede esperar sin producir un impacto importante.",
),
)
Enter fullscreen mode
Exit fullscreen mode
La respuesta contiene el campo noul:
probability = result.nouls["urgent"].noul
Enter fullscreen mode
Exit fullscreen mode
Un valor cercano a 1 favorece true; uno cercano a 0, false. Los valores próximos a 0.5 no favorecen claramente ninguna respuesta.
Noul no incluye un campo confidence separado.
NoulCriteria es opcional. Puedes utilizarlo cuando la condición necesita límites más precisos que una pregunta breve.
Choice: elegir una opción
Choice clasifica el estado dentro de un conjunto definido por tu aplicación. Las claves son los valores que utilizará tu código y las descripciones explican cuándo corresponde cada opción.
from langchain_typesafe import Choice
department_question = Choice(
instructions="¿Qué equipo debe atender el ticket?",
criteria={
"billing": "Cobros, facturas y reembolsos.",
"technical": "Errores e interrupciones del servicio.",
"account": "Acceso, permisos y datos de la cuenta.",
"other": "Ninguna de las categorías anteriores.",
},
)
Enter fullscreen mode
Exit fullscreen mode
La respuesta contiene tres campos principales:
answer = result.choices["department"]
answer.choice
answer.probabilities
answer.confidence
Enter fullscreen mode
Exit fullscreen mode
choice es la opción seleccionada.
probabilities contiene la distribución entre todas las opciones.
confidence resume qué tan concentrada está esa distribución.
Si tu lista no cubre todos los casos posibles, conviene incluir una opción como other o none_of_the_above.
Score: medir una escala
Score se utiliza cuando las respuestas tienen un orden. Por ejemplo, puedes utilizarlo para medir la frustración de un cliente:
from langchain_typesafe import Score
frustration_question = Score(
instructions="¿Cuál es el nivel de frustración del cliente?",
criteria=[
"Tono neutral.",
"Molestia expresada de forma moderada.",
"Enojo explícito o lenguaje hostil.",
],
)
Enter fullscreen mode
Exit fullscreen mode
La respuesta incluye:
answer = result.scores["frustration"]
answer.score
answer.probabilities
answer.legend
answer.confidence
Enter fullscreen mode
Exit fullscreen mode
Los niveles se numeran desde 0. score es una media ponderada de sus probabilidades, por lo que puede ser fraccionario.
En una escala de 0 a 2, un resultado de 1.4 representa una distribución entre los niveles existentes.
Las descripciones deberían representar situaciones observables. Una escala como “sin impacto”, “función degradada” y “operación bloqueada” aporta más información que “bajo”, “medio” y “alto”.
Paso 3: conocer los cinco límites principales
Estos son los límites relevantes que publica actualmente la documentación de TypeSafe:
Área
Límite
Opciones de Choice
Máximo de 255
Niveles de Score
Entre 2 y 10
Espacio de respuesta de Noul
Binario; devuelve P(verdadero) entre 0 y 1
Contexto total
64k tokens por solicitud
state + pregunta más larga
Máximo de 32k tokens
Un Choice puede manejar taxonomías amplias. Si tienes más de 255 categorías, puedes dividir la clasificación en niveles o resolverla mediante una jerarquía.
Un Score debería incluir únicamente niveles que puedan distinguirse mediante sus descripciones. Agregar niveles similares puede distribuir la probabilidad entre alternativas poco claras.
Los 64k tokens cubren el estado y todas las preguntas de la solicitud. Además, el estado combinado con la pregunta individual más larga debe permanecer dentro de 32k tokens.
Estos valores pueden cambiar, así que si vas a diseñar cargas cercanas al límite, revisa la documentación antes de hacerlo.
Paso 4: instalar la integración de LangChain
pip install "langchain-typesafe[experimental]" python-dotenv
Enter fullscreen mode
Exit fullscreen mode
langchain-typesafe incluye TypeSafeClassifier. El extra experimental incorpora ModelRouterMiddleware y AutoModeMiddleware.
La versión utilizada en este proyecto es alfa. El classifier está marcado como beta y los middlewares son experimentales.
Paso 5: conectar LangChain con jev mediante AI Gateway
Por defecto, langchain-typesafe utiliza la API de TypeSafe y busca una credencial en TYPESAFE_API_KEY.
En este proyecto queremos consumir jev mediante Vercel AI Gateway. Vercel expone una API compatible con el formato de TypeSafe:
https://ai-gateway.vercel.sh/typesafe/v1/systemone
Enter fullscreen mode
Exit fullscreen mode
Solo necesitas indicarle al paquete dos datos:
Utilizar la credencial de Vercel como TYPESAFE_API_KEY.
Utilizar https://ai-gateway.vercel.sh/typesafe como TYPESAFE_BASE_URL.
El cliente añade /v1/systemone a esa URL base. No necesitas transformar preguntas o respuestas ni intervenir el transporte HTTP.
Creamos gateway.py:
import os
from dotenv import load_dotenv
load_dotenv()
token = os.getenv("AI_GATEWAY_API_KEY") or os.getenv("VERCEL_OIDC_TOKEN")
if not token:
raise RuntimeError("No se encontró una credencial para Vercel AI Gateway.")
os.environ["TYPESAFE_API_KEY"] = token
os.environ["TYPESAFE_BASE_URL"] = "https://ai-gateway.vercel.sh/typesafe"
Enter fullscreen mode
Exit fullscreen mode
La credencial local se guarda en .env:
AI_GATEWAY_API_KEY=...
Enter fullscreen mode
Exit fullscreen mode
Esta capa de configuración también se aplica a los classifiers que los middlewares construyen internamente.
Con esta configuración, langchain-typesafe queda listo para enviar solicitudes a jev mediante AI Gateway.
Ejemplo: clasificar un ticket
Ahora agrupamos los tres primitives definidos anteriormente:
import gateway # Configura la API TypeSafe-compatible
from langchain_typesafe import TypeSafeClassifier
classifier = TypeSafeClassifier(
questions={
"urgent": urgent_question,
"department": department_question,
"frustration": frustration_question,
}
)
Enter fullscreen mode
Exit fullscreen mode
Luego enviamos el ticket como estado:
ticket = {
"message": (
"El sistema de pagos sigue fallando y no podemos completar ventas. "
"Necesitamos una solución hoy."
),
"customer_plan": "enterprise",
}
result = classifier.invoke(ticket)
Enter fullscreen mode
Exit fullscreen mode
Las tres preguntas se envían en una sola solicitud. Puedes incorporar el resultado a una regla de negocio común:
department = result.choices["department"]
urgent = result.nouls["urgent"].noul
frustration = result.scores["frustration"]
if department.confidence = 0.8 or frustration.score >= 1.5:
route_to_senior_agent(ticket, department.choice)
else:
assign(ticket, department.choice)
Enter fullscreen mode
Exit fullscreen mode
Los umbrales son ilustrativos. Deberías evaluarlos con tickets representativos y definir qué hacer cuando el resultado sea incierto.
TypeSafeClassifier implementa la interfaz Runnable, por lo que también puedes utilizarlo con ainvoke, batch y dentro de otros flujos de LangChain.
Más ejemplos con LangChain
Además del classifier general, langchain-typesafe incluye middlewares para decisiones frecuentes dentro de un agente.
Seleccionar un modelo
ModelRouterMiddleware utiliza un Choice para seleccionar entre modelos ya configurados. Evalúa el último mensaje humano al inicio de la ejecución y guarda la respuesta en model_route.
from langchain.agents import create_agent
from langchain_typesafe.experimental.middleware import (
ModelChoice,
ModelRouterMiddleware,
)
router = ModelRouterMiddleware(
choices={
"fast": ModelChoice(
model=fast_model,
criteria="Consultas directas y cambios acotados.",
),
"capable": ModelChoice(
model=capable_model,
criteria="Arquitectura y decisiones de alto impacto.",
),
},
instructions="Seleccione el modelo adecuado para completar la tarea.",
)
agent = create_agent(fast_model, middleware=[router])
Enter fullscreen mode
Exit fullscreen mode
Evaluar una herramienta
AutoModeMiddleware evalúa una llamada inmediatamente antes de ejecutar una herramienta.
from langchain_typesafe import NoulCriteria
from langchain_typesafe.experimental.middleware import AutoModeMiddleware
guardrail = AutoModeMiddleware(
tools=["bash"],
instructions=(
"¿La llamada propuesta es destructiva, irreversible o excede la "
"autorización concedida para este sistema?"
),
criteria=NoulCriteria(
true="Elimina datos, interrumpe servicios o produce un efecto no aprobado.",
false="Consulta información o realiza un cambio reversible y autorizado.",
),
)
Enter fullscreen mode
Exit fullscreen mode
La política debe indicar qué operaciones requieren aprobación. Esta evaluación complementa los controles de acceso y aislamiento de la aplicación.
Supervisar el ciclo del agente
También puedes ejecutar un classifier después de cada respuesta:
from langchain.agents.middleware import after_model
@after_model
def supervise(state, runtime) -> None:
result = supervisor.invoke(state["messages"])
if result.nouls["escalate"].noul >= 0.8:
record_handoff(result)
Enter fullscreen mode
Exit fullscreen mode
La integración acepta mensajes de LangChain como state, por lo que puedes evaluar el historial sin conversión manual.
Referencias
TypeSafe: Primitives
TypeSafe: Choice
TypeSafe: Score
TypeSafe: Models and limits
TypeSafe API reference
TypeSafe: Introducing System One Models & Jev
LangChain: Building a Harness with Jev
Vercel: TypeSafe API with AI Gateway