Mastering LLM Output with ParseLM

In today’s digital age, large language models (LLMs) are emerging as powerful tools across various industries. However, integrating these LLMs into applications poses challenges for developers. ParseLM, a lightweight TypeScript library, provides an effective solution to bridge the gap between unstructured LLM outputs and structured data required for application logic. Below is a detailed introduction to ParseLM.

The Genesis of ParseLM

Traditional interactions with LLMs often rely on prompt engineering and fragile parsing techniques, which can lead to unstable applications. ParseLM was developed to address this issue. It enables reliable extraction and validation of structured information from LLM responses, allowing developers to integrate AI capabilities into their applications with greater confidence and type safety.

Key Features of ParseLM

  • Structured Data Extraction: Define your desired data structure using schemas, and ParseLM will handle the interaction with LLMs to extract matching, validated data.
  • Provider Agnostic: Configure ParseLM with different LLM providers (e.g., OpenAI, Google Gemini, Anthropic) through a simple ProviderConfig interface.
  • Type Safety: Ensures extracted data conforms to expected types at both runtime and compile time.
  • Built-in Retries: Handles transient LLM API errors with configurable retry logic and exponential backoff.
  • Utility Methods: Provides convenient helpers for common tasks such as boolean checks, single classifications (oneOf), list generation (toList, toListOf), and conditional function execution based on classification results (switch).

Installation and Basic Usage

Installation

# Using npm
npm install parselm

# Using yarn
yarn add parselm

Basic Usage

The core concept involves providing text context, defining a schema for the desired output using a library like Zod, and letting ParseLM orchestrate the LLM call and validation.

import { ParseLM, createOpenAICompatibleProvider } from "parselm";
import { z } from "zod";

const parselm = new ParseLM({
  provider: createOpenAICompatibleProvider("gemini-2.0-flash", "https://generativelanguage.googleapis.com/v1beta", process.env.API_KEY),
});

const context = "User: John Doe, Age: 30, Email: john.doe@example.com";

// Define the schema for the desired data
const userSchema = z.object({
  name: z.string().describe("User's full name"),
  age: z.number().int().positive().describe("User's age"),
  email: z.string().email().describe("User's email address"),
});

// Extract structured data
async function getUserData() {
  try {
    // 1. Provide context
    // 2. Define schema
    // 3. Retrieve value
    const userData = await parselm
      .context(context)
      .schema(userSchema)
      .value(); // Throws on error

    console.log("Extracted User Data:", userData);
  } catch (error) {
    console.error("An error occurred:", error);
  }
}

getUserData();

Advanced Usage

Error Handling with safeValue()

For cases where you wish to gracefully handle extraction failures without try/catch blocks:

async function getSafeUserData() {
  // Returns { success: true, value: ... } or { success: false, error: ..., value: null }
  const result = await parselm
    .context(context)
    .schema(userSchema)
    .safeValue();

  if (result.success) {
    console.log("Safely Extracted:", result.value);
    return result.value;
  } else {
    console.error("Extraction failed:", result.error);
    return null;
  }
}

Configuring Retries

Configure automatic retries to handle transient LLM API errors:

const parselm = new ParseLM({
  provider: createOpenAICompatibleProvider("gemini-2.0-flash", "https://generativelanguage.googleapis.com/v1beta", process.env.API_KEY),
  retryCount: 3, // Retry up to 3 times after the initial attempt
  backoffFactor: 2, // Exponential backoff, doubling the delay between retries
});

Image Analysis

Extract structured data from images by providing image data as part of the context:

import { ParseLM, createOpenAICompatibleProvider } from "parselm";
import { z } from "zod";
import fs from "fs/promises";

// Create a provider with vision capabilities
const parselm = new ParseLM({
  provider: createOpenAICompatibleProvider("gemini-2.0-flash", "https://generativelanguage.googleapis.com/v1beta", process.env.API_KEY),
});

// Define schema for product information
const productSchema = z.object({
  name: z.string().describe("Product name displayed on the packaging"),
  brand: z.string().describe("Brand name of the product"),
  price: z.string().optional().describe("Price if visible on the image"),
  keyFeatures: z.array(z.string()).describe("Key features or selling points of the product"),
  category: z.string().describe("Product category (e.g., electronics, food, clothing)"),
});

async function analyzeProductImage(imagePath) {
  // Read image as base64
  const imageBuffer = await fs.readFile(imagePath);
  const base64Image = imageBuffer.toString("base64");
  
  // Create image context with prompt
  const imageContext = {
    text: "Analyze this product image and extract detailed information about the item shown.",
    images: [base64Image]
  };
  
  try {
    const productData = await parselm
      .context(imageContext)
      .schema(productSchema)
      .value();
      
    console.log("Product Information:", productData);
    return productData;
  } catch (error) {
    console.error("Failed to analyze image:", error);
    return null;
  }
}

analyzeProductImage("./product-image.jpg");

API

new ParseLM(config: ParseLMConfig)

Creates a new instance of ParseLM.

Config:

  • provider: ProviderConfig – An object conforming to the provider interface, handling actual LLM API calls.
  • retryCount?: number (Default: 0) – The number of retries after the initial attempt if the LLM call fails.
  • backoffFactor?: number (Default: 2) – The factor by which the delay increases between retries (exponential backoff).

parselm.context(context: string)

Sets the text context for subsequent operations and returns an object with a schema method.

context(...).schema<T>(schema: z.ZodSchema<T>)

Defines the Zod schema for data extraction from the context and returns an object with methods to retrieve the value.

  • .value(): Promise<T>: Executes the LLM call (if not already done) and returns parsed, validated data according to the schema. Throws an error if parsing, validation, or the LLM call fails.
  • .safeValue(): Promise<{ success: true; value: T } | { success: false; error: string; value: null }>: Executes the LLM call and returns a result object indicating success or failure, avoiding thrown exceptions.
  • .raw(): Promise<{ structured: T | null, raw: string, valid: boolean, attempts: number, errors?: any }>: Executes the LLM call and returns an object containing the parsed data (or null on failure), the raw text response from the LLM, validation status, number of attempts, and any validation errors.

Utility Methods

isTrue

Determines if the context represents a logically true statement. Useful for simple yes/no checks.

const text = `The system is operational based on these metrics: ${metrics}`;
const isOperational: boolean = await parselm.isTrue(text);
console.log(`System operational: ${isOperational}`); // Likely true

oneOf

Classifies the context into exactly one of the provided string options. Throws an error if the LLM’s classification does not match any of the options.

const inputText = "This feedback is highly positive and encouraging!";
const sentiment: string = await parselm.oneOf(inputText, ["positive", "negative", "neutral"]);
console.log(`Detected sentiment: ${sentiment}`); // Likely "positive"

toList

Extracts a list of strings from the context.

const listText = "Items needed: apples, bananas, oranges.";
const items: string[] = await parselm.toList(listText);
console.log("Shopping list:", items); // Likely ["apples", "bananas", "oranges"]

toListOf

Extracts a list where each item conforms to the provided Zod itemSchema.

const taskSchema = z.object({ description: z.string(), priority: z.number() });
const tasksText = "Task 1: Write report (Priority 1). Task 2: Schedule meeting (Priority 3).";
const tasks: z.infer<typeof taskSchema>[] = await parselm.toListOf(tasksText, taskSchema);
console.log("Parsed tasks:", tasks);
// Likely:
// [
//   { description: 'Write report', priority: 1 },
//   { description: 'Schedule meeting', priority: 3 }
// ]

switch

Classifies the context based on the keys (names) provided in the fns object map. It then executes the function associated with the chosen key, passing the original context to that function. Returns the result of the executed function.

async function handleBug(ctx: string) {
  console.log("Handling bug report:", ctx);
  // ... logic to file bug ticket
  return { status: "Bug Filed" };
}

async function handleFeature(ctx: string) {
  console.log("Handling feature request:", ctx);
  // ... logic to add to backlog
  return { status: "Feature Added to Backlog" };
}

async function handleQuestion(ctx: string) {
    console.log("Handling question:", ctx);
    // ... logic to route to support
    return { status: "Question Routed" };
}

const ticketText = "The login button isn't working on the staging server.";

const result = await parselm.switch(ticketText, {
  reportBug: () => handleBug(ticketText),
  requestFeature: () => handleFeature(ticketText),
  askQuestion: () => handleQuestion(ticketText),
});

console.log("Switch result:", result);
// Likely Output:
// Handling bug report: The login button isn't working on the staging server.
// Switch result: { status: 'Bug Filed' }

Why Choose ParseLM Over Other LLM Structured Output Methods?

ParseLM employs a minimal schema and prompting strategy to achieve structured outputs from models that lack native support for structured outputs. This approach reduces the amount of input tokens transmitted, saving bandwidth. Additionally, ParseLM abstracts away the complexities of prompt engineering for structured outputs, eliminating the need for developers to focus on intricate prompt design.

Use Cases for ParseLM

ParseLM is applicable in various scenarios requiring LLM integration:

  • Data Extraction and Transformation: Extract specific information from large volumes of text data and convert it into structured formats, such as processing customer feedback, market research reports, and news articles.
  • Smart Form Filling: Analyze user-provided text descriptions or uploaded documents to auto-fill form fields, enhancing user experience and minimizing manual input errors.
  • Content Classification and Filtering: Classify and filter large volumes of text content, such as news categorization and email filtering.
  • Smart Customer Service and Chatbots: Parse user queries in natural language, extract key information, and trigger corresponding business logic. For example, route user issues to appropriate departments or generate tickets.
  • Image Information Extraction: Extract key information from images, such as product names, brands, and prices, to enrich product databases and improve search and recommendation accuracy.

The Future of ParseLM

As LLM technology evolves, ParseLM continues to advance:

  • Support for More LLM Providers: As the LLM market grows, ParseLM will expand its list of supported providers, giving developers more options.
  • Intelligent Prompt Optimization: Continuously refine internal prompt design and adaptation mechanisms to improve data extraction accuracy and efficiency.
  • Enhanced Error Handling and Recovery: Strengthen error handling and recovery capabilities to ensure stable application operation.
  • Improved Developer Experience: Simplify APIs, enrich documentation and examples, and enhance tool integration for a more seamless development process.
  • Integration with Other Technologies: Deepen integration with machine learning, knowledge graphs, and natural language processing to unlock greater potential.

In summary, ParseLM is a powerful TypeScript library for structuring LLM outputs. Its advantages—such as ease of use, type safety, and provider agnosticism—make it an ideal tool for integrating LLM capabilities into applications. Whether for data extraction, content classification, image analysis, or other scenarios, ParseLM can become a reliable assistant for developers. As it continues to evolve, ParseLM will bring more efficient and reliable LLM integration solutions to developers, helping them navigate the digital wave and develop innovative and competitive applications.

– END –