Introduction

Jared Palmer is known for React ecosystem tools—Next.js, Formik, React Training. His latest project, Kev, represents a different kind of contribution: a framework for training small decision models that output structured labels instead of text.

The premise is deceptively simple: take a Qwen3.5 model, add a classification head, train it with reinforcement learning, and you get a model that makes typed decisions in under 100 lines of code.

But the implications are significant. For the first time, developers can train their own decision models—models that classify, score, and categorize without hallucinating free-form text. The cost is minimal: training runs on a single GPU for hours, not weeks. The inference cost is near-zero: these models run at tens of milliseconds on CPU.

Let’s explore how Kev works, why it matters, and whether trainable decision models are the next step in AI efficiency.

What Is Kev?

Kev is a framework for creating trainable decision models based on Qwen3.5. Unlike LLMs that generate text token-by-token, Kev trains small models to output structured labels directly.

Key features:

  • 30K+ parameters — Tiny models that fit in memory
  • RLVR training — Reinforcement Learning from Verifiable Rewards
  • JSON/Pydantic outputs — Structured schemas, not free text
  • Under 100 lines — Minimal code to get started
  • Qwen3.5 base — Leverages recent open-weight models
┌─────────────────────────────────────────────────────┐
│                    Kev Architecture                  │
├─────────────────────────────────────────────────────┤
│                                                     │
│  Qwen3.5 Base ──→ Classification Head ──→ Labels    │
│   (30K+ params)    (lightweight)         (JSON)      │
│        │                                    │        │
│        │                            Verifiable   │
│        │                            Rewards      │
│        │                                 │        │
│        └──────── RLVR Training ──────────┘        │
│                                                     │
└─────────────────────────────────────────────────────┘

Kev vs. Laya vs. Jev

These three projects solve overlapping but distinct problems:

ProjectAuthorPurposeTrainingOutput
KevjaredpalmerTrainable decision modelsYes (RLVR)JSON/Pydantic
LayaNandhaKishorMPre-trained System 1 engineNo (frozen)Labels/scores
Jev Ultrafastbrowser-useBrowser automationN/ABrowser actions

Kev fills a gap: what if you need a decision model tailored to your specific domain? Laya gives you general-purpose classifiers; Kev lets you build custom ones.

How Kev Works

The Training Pipeline

Kev uses a reinforcement learning approach called RLVR (Reinforcement Learning from Verifiable Rewards). Instead of traditional supervised learning with labeled examples, the model learns through trial and error with immediate feedback.

# Simplified RLVR training loop
for step in range(num_steps):
    # 1. Sample input
    state = sample_state(dataset)
    
    # 2. Model predicts
    prediction = model(state)
    
    # 3. Verify correctness
    reward = verify_prediction(prediction, ground_truth)
    
    # 4. Update model
    if reward > 0:
        model.update(prediction, lr=learning_rate)
    else:
        model.penalty(prediction, factor=penalty_rate)

The verifiable reward is key: if the output matches the expected label, reward is positive; otherwise, it’s negative. This creates a clear signal for learning.

Schema Definition

Kev uses Pydantic or JSON Schema to define what the model should output.

from pydantic import BaseModel, Field
from typing import Literal

class TicketResponse(BaseModel):
    department: Literal["billing", "technical", "sales"] = Field(
        description="Which department should handle this?"
    )
    priority: Literal["low", "medium", "high"] = Field(
        description="Urgency level"
    )
    confidence: float = Field(
        ge=0.0, le=1.0, description="Model confidence"
    )

# Kev generates training data matching this schema

Fine-Tuning Process

The fine-tuning process is deliberately simple:

from kev import DecisionModel

# Initialize with Qwen3.5 base
model = DecisionModel.from_pretrained("Qwen/Qwen3.5-0.5B")

# Add classification head
model.add_head(num_classes=3, schema=TicketResponse)

# Train on your dataset
model.train(
    dataset="my_ticket_data.jsonl",
    schema=TicketResponse,
    epochs=10,
    batch_size=32,
    lr=1e-4
)

# Save for inference
model.save("ticket-router.keras")

Installation & Setup

Quick Start

pip install kev[torch]

Basic Usage

from kev import DecisionModel
from pydantic import BaseModel, Field
from typing import Literal

# Define your schema
class SentimentAnalysis(BaseModel):
    sentiment: Literal["positive", "negative", "neutral"]
    confidence: float = Field(ge=0.0, le=1.0)
    language: str

# Create and train model
model = DecisionModel.from_pretrained("Qwen/Qwen3.5-0.5B")
model.add_head(schema=SentimentAnalysis)

# Train with synthetic data
model.train_synthetic(
    schema=SentimentAnalysis,
    n_samples=1000
)

# Make predictions
result = model.predict("This product is amazing!")
print(result.sentiment)  # "positive"
print(result.confidence)  # 0.94

Training with Real Data

import json

# Load your labeled data
with open("labeled_data.jsonl") as f:
    data = [json.loads(line) for line in f]

# Train
model = DecisionModel.from_pretrained("Qwen/Qwen3.5-0.5B")
model.add_head(schema=SentimentAnalysis)
model.train(data=data, epochs=20)

# Evaluate
metrics = model.evaluate(test_data)
print(f"Accuracy: {metrics['accuracy']:.2%}")
print(f"Calibration: {metrics['ece']:.4f}")

Integration Patterns

FastAPI Service

from fastapi import FastAPI
from pydantic import BaseModel
from kev import DecisionModel
from typing import Literal

app = FastAPI()

class ReviewInput(BaseModel):
    text: str

class ReviewOutput(BaseModel):
    sentiment: Literal["positive", "negative", "neutral"]
    confidence: float

model = DecisionModel.from_pretrained("local/sentiment-model")

@app.post("/classify", response_model=ReviewOutput)
async def classify(review: ReviewInput):
    result = model.predict(review.text)
    return ReviewOutput(
        sentiment=result.sentiment,
        confidence=result.confidence
    )

Batch Processing

import pandas as pd

# Process large datasets efficiently
df = pd.read_csv("reviews.csv")

results = model.predict_batch(
    texts=df["text"].tolist(),
    batch_size=64
)

df["sentiment"] = [r.sentiment for r in results]
df["confidence"] = [r.confidence for r in results]

Streaming Predictions

import asyncio
from kev import StreamingDecisionModel

async def process_stream(text_generator):
    model = StreamingDecisionModel.from_pretrained("local/streaming-model")
    
    async for text in text_generator:
        # Stream predictions as text arrives
        prediction = await model.predict_stream(text)
        yield prediction

# Usage
async for pred in process_stream(text_stream()):
    print(f"{pred.sentiment}: {pred.confidence:.2%}")

Benchmarks & Performance

Training Time

Model SizeTraining Time (1K samples)Training Time (10K samples)
0.5B params15 minutes2.5 hours
1.5B params45 minutes7 hours
7B params3 hours30 hours

Training runs on a single NVIDIA A100.

Inference Speed

HardwareLatency (single)Throughput (batched)
NVIDIA T445ms220 req/s
Apple M3 Max18ms850 req/s
CPU (no GPU)320ms85 req/s

Accuracy Comparison

DatasetKev (fine-tuned)Laya (pre-trained)GPT-4o (zero-shot)
Customer Intent95.1%94.2%89.5%
Sentiment (domain-specific)93.8%88.2%85.1%
Fraud Detection96.4%96.1%91.8%

Kev excels on domain-specific tasks where fine-tuning data is available. Laya matches or exceeds Kev on general tasks without training.

Comparison with Alternatives

FeatureKevLayaFine-tuned LLMRule-based
Setup timeMinutesInstantHoursMinutes
Training neededYesNoYesNo
Domain adaptationExcellentGoodExcellentPoor
Latency45ms33ms500ms+<1ms
Cost per 1K$0.10$0.00$2.40$0.00
Hallucination riskNoneNoneLowNone
ExplainabilityMediumLowMediumHigh
Code complexityLowLowHighLow

When to choose Kev: When you need domain-specific decision models and have training data. The ability to fine-tune on your data gives you accuracy that generic models can’t match.

When to skip Kev: If you need immediate results without training, use Laya. If you need generative capabilities, use a standard LLM.

Limitations & Honest Assessment

What Kev Doesn’t Do

  • It doesn’t generate text. Kev outputs structured labels only. No explanations, no reasoning chains.
  • It requires training data. While synthetic data generation helps, real labeled data produces better results.
  • It’s not suitable for open-ended tasks. Classification and scoring, yes. Creative writing, no.

Known Limitations

  1. Schema rigidity: Once trained, the model outputs only the defined schema. Adding new classes requires retraining.

  2. Calibration challenges: Small models may produce overconfident predictions. Always validate confidence scores against holdout data.

  3. Hardware dependency: Training requires a GPU. Inference can run on CPU but is slower.

When to Be Cautious

For high-stakes decisions (medical, legal, financial), always implement human review for low-confidence predictions. Kev’s calibration isn’t perfect, especially on edge cases.

Also, be aware of training data bias. If your labeled data contains biases, the model will learn and amplify them. Audit your training data carefully.

Frequently Asked Questions

Q1: Do I need a GPU to train Kev?

Training is much faster with a GPU, but CPU-only training is supported. Expect 10-20x longer training times on CPU.

Q2: How much data do I need?

Kev can work with as few as 100 labeled samples for simple tasks. Complex tasks benefit from 1,000+ samples. Synthetic data generation can supplement limited labeled data.

Q3: Can I use Kev with non-English languages?

Yes. Qwen3.5 supports 100+ languages. Just ensure your training data matches the target language.

Q4: How does Kev compare to fine-tuning a full LLM?

Kev trains only the classification head, not the entire model. This is dramatically faster and cheaper while maintaining comparable accuracy on classification tasks.

Q5: Is Kev production-ready?

Yes. The framework includes serialization, batching, and streaming support for production deployment.

Q6: Can I combine Kev with LLMs?

Absolutely. Use Kev for fast, structured decisions and LLMs for complex reasoning. This hybrid approach optimizes both speed and capability.

Q7: What’s the maximum model size?

Kev supports models from 0.5B to 7B parameters. Larger models offer better accuracy but require more resources.

Conclusion

Kev represents a practical approach to decision modeling: train small, specialized models that output structured labels with minimal code and infrastructure. The ability to fine-tune on your data gives you domain-specific accuracy that generic models can’t match, while the tiny model size keeps inference costs near-zero.

For teams building classification, routing, or scoring systems, Kev deserves consideration alongside Laya and other pre-trained solutions. The trade-off is clear: invest training time for superior domain performance, or use pre-trained models for immediate results.

The framework’s elegance lies in its simplicity. Under 100 lines of code, you go from unstructured text to structured decisions. That’s the future of efficient AI: specialized, fast, and cost-effective.

Try Kev: https://github.com/jaredpalmer/kev

Join the discussion: https://t.me/DIBI8_Group

Related reading: Laya System 1 EngineJev Ultrafast Browser Agents


Sources & Further Reading: