Your AI Agents Are Only as Good as Your Database: Stop Upserting Messy JSON

typescript dev.to

Why raw LLM payloads wreck your backend pipeline, and the exact Zod validation layer we use at SpaceAI360 to keep production databases clean.

Let’s be completely honest.

Building an AI agent that extracts leads, parses PDFs, or automates customer data is actually the easy part. You write a prompt, configure a structured output schema, call the Gemini or Claude API, and things look great on your local terminal.

But then you check your production database a week later.

One record has the company size stored as "10-50". Another has it as "50+ employees". A third one is completely empty because the LLM decided to hallucinate the JSON key as companySize instead of the expected snake_case company_size.

If you are running automated n8n pipelines, dynamic frontends, or CRM syncing on top of this data, your system is already silently failing.

As the founder of SpaceAI360, I see this bottleneck constantly. If you don't build a strict validation and normalization layer right before your data hits the database, you aren't building "intelligent automation"—you're just automating the generation of technical debt.

The Reality of Non-Deterministic Outputs
No matter how much you optimize your system prompts or turn on JSON-mode, LLMs are inherently non-deterministic. In production, they will eventually:

Return inconsistent date formats (e.g., 15-07-2026 instead of standardized ISO strings).

Fail to output arrays, returning comma-separated strings instead.

Hallucinate empty fields as "N/A", "null", or physical empty strings.

If you let these payloads write directly to your PostgreSQL or MongoDB collections, you will spend more time writing database cleanup scripts than shipping features.

Our Production Blueprint: The Sanity Middleware
To prevent this at SpaceAI360, we implement a strict, runtime-validated "Sanity Layer" using Zod and TypeScript before any DB write operations are executed.

Here is the exact architectural helper utility we use to clean, parse, and normalize LLM-generated payloads:

import { z } from 'zod';

// 1. Define the strict schema contract your database actually expects
export const LeadValidationSchema = z.object({
  company_name: z.string().trim().min(1, "Company name cannot be empty"),

  // Force emails to stay lowercased and clean of stray spaces
  contact_email: z.string().email().toLowerCase().trim(),

  // Standardize categories to match database ENUM strings
  industry: z.string().transform((val) => 
    val.toLowerCase().replace(/[^a-z0-9]/g, '_')
  ),

  // Ensure we fall back to a safe integer if the LLM fails to output a number
  estimated_employees: z.preprocess(
    (val) => Number(val) || 10, 
    z.number().int().positive()
  )
});

// 2. The middleware that processes the raw AI response
export async function sanitizeAIPayload(rawLLMResponse: unknown) {
  try {
    // Parse forces validation and strips out any undeclared keys
    const sanitizedData = LeadValidationSchema.parse(rawLLMResponse);
    return { success: true, data: sanitizedData, error: null };
  } catch (error) {
    if (error instanceof z.ZodError) {
      // Capture the exact path that failed without crashing the engine
      console.error("❌ Data normalization rejected:", error.errors);
      return { success: false, data: null, error: error.errors };
    }
    return { success: false, data: null, error: "Unknown parsing error" };
  }
}

Enter fullscreen mode Exit fullscreen mode

Why This Approach Saves Your Architecture
By introducing this simple processing block:

Indexed Speed: Your database engines run faster because columns receive uniform datatypes rather than raw, index-breaking strings.

Safer Automation: Your downstream email sequencers (like n8n or custom nodemailer scripts) never send out broken templates containing "Hello [object Object]".

Isolated Failures: If an LLM completely scrambles a payload, the parse catcher flags it instantly—allowing your systems to retry the generation step instead of writing corrupt logs.

How Are You Handling Unstructured Data?
If you are running systems at scale, relying on the hope that your AI prompt won't break is a major liability. You have to build code that assumes the AI will send junk data, and gracefully handle those edge cases.

We build exactly these kinds of fail-safe, high-performance web systems and automation pipelines over at SpaceAI360. If you're looking to upgrade your digital products or build resilient infrastructure that actually handles production loads, check out what we are building at SpaceAI360.

Drop a comment below: What is the weirdest hallucinated payload an LLM has ever tried to insert into your database?

Source: dev.to

arrow_back Back to Tutorials