/forge-ml

The Fastest Way to Build Bulletproof AI Products

Primary LanguageTypeScript

๐Ÿš… Forge: The Fastest Way to Build Bulletproof AI Products ๐Ÿƒ๐Ÿ’จ

npm version License: MIT Downloads

A developer toolkit for making AI product development easy and reliable, starting with structured data.

Installation โ€ข Quickstart โ€ข Forge Online โ€ข Forge Docs

๐Ÿš€ Installation

Install Forge globally:

npm install -g forge-ml

And you're live!

forge --help

Get started now ->

๐Ÿ› ๏ธ What is Forge?

Features

  • Fully typesafe Typescript SDK, auto-generated from your zod schemas
  • AI-powered schema creation and editing (save time and get better results with mini-prompts optimized for each key)
  • Guaranteed response structure (no more parsing JSON)
  • Auto-generated documentation for endpoints (get reliable structured responses in any language)
  • Caching and cache-management for queries (don't burn tokens on repeat extractions)
  • Multiple LLM Providers: Anthropic and OpenAI - Groq coming soon (avoid vendor lock-in)

Forge uses a combination of tools like Zod and Instructor to create and deploy endpoints that can be used to extract structured data from LLMs. It's the easiest way to build AI products.

You define a Zod schema, test it locally, and run forge deploy. From there you can access it from any application with a fetch request or the auto-generated SDK, and it's guaranteed to have the expected response structure.

// Define your schema
const whois = z.object({
  name: z.string(),
  occupation: z.string(),
  hobbies: z.array(z.string()),
});
# deploy
forge deploy
// endpoint: https://api.forge-ml.com/q/jakezegil/whois
// prompt: Jake Zegil is a Software Engineer who likes ripping code and driving boats
// Your endpoint response -
{
  name: "Jake Zegil",
  occupation: "Software Engineer",
  hobbies: ["ripping code", "driving boats"],
}

For more information on Forge, checkout the Forge Docs.

๐Ÿ“ˆ Quickstart

Run the following shell commands in the root directory of your project.

# Sign up for a forge account
forge signup

## Install zod
npm install zod

## Initialize your forge project
forge init

## Create a forge schema
forge create

# Test your endpoint
forge test ./forge/schema/<your_schema>.ts

# Deploy your schema as an endpoint
forge deploy

โ—๏ธ Note โ—๏ธ In order to deploy, your schema file must have a zod object as the default export and a named config export containing the path.

export default z
  .object({
    // your schema here
  })
  .describe("my schema");

export const config: EndpointConfig = {
  // "path" determines the url path for the endpoint you'll deploy
  path: "my-schema", // one word, no special characters
  public: true || false, // determines if the endpoint is available for public access
  name: "My Schema", // name of the endpoint
  description: "My schema description",
  cache: "Individual" | "Common" | "None", // cache determines how the schema is cached.
  contentType: "text" | "image", // contentType determines the type of content the endpoint will receive
  model:
    "gpt-4o-mini" | "gpt-4o" | "gpt-4" | "gpt-3.5-turbo" | "<custom-model-id>", // model determines the model used to generate and query the endpoint
};

Once you're authenticated and have deployed an endpoint, you can view and test out all of your live endpoints on your swagger docs page:

forge docs   # https://api.forge-ml.com/docs/jakezegil

You can see my openAPI spec here.

๐Ÿ” Authentication

Auth lives at forge auth. When you log in or sign up, you'll get a fresh api key (this will not invalidate your old key). Your credentials are stored at ~/.forge/key.json.

forge auth signup         # Sign up for a forge account
forge auth login          # Log in to your account
forge auth logout         # Log out of your account

For simplicity you can also just use forge login and forge signup to login and signup.

If you don't like your username, you can always update it, but beware! It will also update your deployed endpoints. Your swagger docs are dynamic, and will reflect your latest username and endpoints.

forge auth update    # update your forge username

๐Ÿ”‘ Managing API Keys

Your api keys live in ~/.forge/key.json. You can manage them using some of the utility functions forge provides out of the box:

  # List API key status (are keys set?)
  forge key list

  # Copy a key from the local forge credential cache to your clipboard
  # You'll need this once you're ready to hit a deployed endpoint
  forge key copy <provider>

  # Set a key (defaults to setting your openAI key, in case it isn't valid anymore or you want to change it)
  forge key set <API_KEY> --provider <provider>

๐Ÿ”จ Building your Schemas

Forge can create new schemas for you using forge create. After using the command, you'll be met with a series of prompts to set up your endpoint configuration. Finally you'll be asked for a prompt to generate a schema:

forge> Enter a prompt for your schema? (ex. Generate a Person schema with attributes like a job, name, age, etc.)

user> Make me a superhero schema with attributes like name, sidekick, and abilities, etc. Add a lot of attributes and be very detailed.

forge> Creating schema...

Once the schema is generated, a new forge schema file <endpoint-path>.ts will be created in ./forge/schema for you to test and deploy.

To learn more about creating schemas and how to use them, check out our docs here.

๐Ÿ›œ Forge Online

Forge partners with lsd.so for live data from the web.

The LSD bicycle allows you to easily and precisely access structured data from the internet, fast. You can then pipe that data into your prompt context, which gives forge realtime access to any website when building structured AI workflows.

As an example, we built an app that allows you to filter and sort live hacker news articles by vibes:

๐Ÿค– Using the Forge SDK

forge init and forge deploy will generate a client for you, allowing you to interact with your endpoints programatically.

Lets walk through an example of how to use the Forge SDK

After forge init you'll have a client.ts file in your forge folder that looks like this:

import Forge from "@forge-ml/client";

const keyGuard = () => {
  throw new Error("set FORGE_KEY in your .env");
};

const forgeKey = process.env.FORGE_KEY || keyGuard();

const forge = Forge({
  forgeKey: forgeKey,
});

export default forge;

Feel free to edit this, it's only regenerated when you run forge init.

In the root of your project add a .env file with your forge key. You can get your forge key after logging in by running forge key copy forge.

FORGE_KEY=your-forge-key

Then, import your forge client and make a request:

import forge from "./forge/client";

const response = await forge.person.get({
  q: "Who is Mark Twain?",
});

// a typesafe response!
const firstName = response.name.firstName; // "Mark"
console.log(firstName);

And you'll get a typesafe response from your endpoint:

{
  "name": {
    "full": "Mark Twain",
    "firstName": "Mark",
    "lastName": "Twain"
  },
  ...
  "_meta": {
    "usage": {
      "prompt_tokens": 211,
      "completion_tokens": 220,
      "total_tokens": 431
    },
    "cacheHit": false
  }
}

Learn more about the Forge SDK here.

๐Ÿ“„ RAG over your documents

Forge allows you upload documents and query them using RAG. To get started, head over to forge-ml.com and sign in. Once you're logged in, upload your document and copy the key. You can now use the forge client to upload your documents.

const result = await forge.$withContext("<your-prompt>", {
  collectionKey: "<your-collection-key>",
  chunkCount: 10,
});

result.context.forEach((chunk) => {
  console.log(chunk.text);
  console.log(chunk.score);
});

console.log(result.response);

If you want query multiple documents, go to collections section and create a new collection with the documents you want to query. You can now use the collection key to query the documents.

To find out more about Forge RAG, check out our docs here.

โšก๏ธ Creating your first endpoint

  1. Create a typescript file with a zod schema as the default export

    // ./forge/schema/endpointSchema.ts
    import z from "zod";
    
    const PersonCategory = z.enum([
      "historical",
      "celebrity",
      "politician",
      "scientist",
      "artist",
      "other",
    ]);
    
    // Define the main person schema
    const PersonSchema = z.object({
      name: z.object({
        full: z.string(),
        firstName: z.string(),
        lastName: z.string(),
      }),
      birthDate: z.date(),
      deathDate: z.date().optional(),
      nationality: z.string().optional(),
      occupation: z.array(z.string()).min(1),
      category: PersonCategory,
      knownFor: z.array(z.string()),
      briefBio: z.string().max(500),
      imageUrl: z.string().url(),
      sources: z.array(z.string().url()),
      lastUpdated: z.date().default(() => new Date()),
    });
    
    export default PersonSchema;
  2. Add a config export to the schema typescript file. The path for the endpoint should be one word with no special characters

    /*
     *   forge/schema/endpointSchema.ts
     */
    
    export const config: EndpointConfig = {
      /** path to the endpoint. one word, no special characters */
      path: "the_path",
      /**
       * determines if the endpoint is available for public access.
       * users will always use their own OpenAI API key (you won't be dinged for others using your endpoint)
       */
      public: true,
      /** name of the endpoint */
      name: "Person",
      /** description of the endpoint */
      description: "A person in history or the present day",
      /** cache setting **/
      cache: "Individual", // this means it's set to be unique to each user
      contentType: "text", // this means the endpoint will process text
      provider: "openai", // this means the endpoint will use the openai provider
      model: "gpt-4o-mini", // this means the endpoint will use the gpt-4o-mini model
    };
  3. Test the endpoint

    forge test ./forge/schema/endpointSchema.ts
    
    ## Enter your prompt: Who is Mark Twain?
    // Your response should look something like this:
    {
      "name": "Mark Twain",
      "fullName": {
        "firstName": "Mark",
        "lastName": "Twain"
      },
      "birthDate": "1920-03-01",
      "deathDate": "1961-04-21",
      "nationality": "American",
      "occupation": ["writer", "illustrator"],
      "knownFor": [
        "The Adventures of Tom Sawyer",
        "Adventures of Huckleberry Finn"
      ],
      "briefBio": "Mark Twain, whose real name was Samuel Langhorne Clemens, was an American writer and humorist. He is best known for his novels 'The Adventures of Tom Sawyer' and 'Adventures of Huckleberry Finn,' which are considered classics of American literature.",
      "sources": ["https://en.wikipedia.org/wiki/Mark_Twain"],
      "_meta": {
        "usage": {
          "prompt_tokens": 75,
          "completion_tokens": 79,
          "total_tokens": 154
        }
      }
    }
  4. Deploy the endpoint, and check it out in your swagger docs

    forge deploy  ## Deploy your endpoints
    forge docs    ## Check out your swagger docs
  5. Grab your forge key

    forge key copy forge  ## Copy your forge key to your clipboard
  6. Make your first request!

    # Make a request to your endpoint
    # If this seems like a lot, just use your forge client!
    # The only required header is `Authorization`
    curl -X POST https://api.forge-ml.com/q/your_username/the_path   -H "Authorization: Bearer <your-forge-key>" -d '{"q": "Who is Mark Twain?"}'
    # You can also pass -H "cache-behavior: <bust | evade | none>" and -H "model: <model-id>" to override the default behaviors

โš™๏ธ Endpoint Config

The exported config is used for deployment. It must be a const config exported from the schema file.

export type EndpointConfig = {
  /** path to the endpoint. one word, no special characters */
  path: string;
  /** name of the endpoint */
  name?: string;
  /** description of the endpoint */
  description?: string;
  /** cache setting
   * Individual - cache is unique to each user
   * Common - cache is shared amongst all users
   * None - no caching
   * **/
  cache: "Individual" | "Common" | "None";
  /** contentType setting
   * text - the endpoint will process text
   * image - the endpoint will process images
   * **/
  contentType: "text" | "image";
  /** model setting
   * gpt-4o-mini - the endpoint will use the gpt-4o-mini model
   * gpt-4o - the endpoint will use the gpt-4o model
   * gpt-4 - the endpoint will use the gpt-4 model
   * gpt-3.5-turbo - the endpoint will use the gpt-3.5-turbo model
   * <custom-model-id> - the endpoint will use a OpenAI custom model id - as of right now we only support OPENAI as a model provider
   * if no model is included we use gpt-4o-mini by default
   * **/
  model: "gpt-4o-mini" | "gpt-4o" | "gpt-4" | "gpt-3.5-turbo" | "<custom-model-id>";
  /** provider setting
   * openai - the endpoint will use the openai provider
   * groq - the endpoint will use the groq provider
   * anthropic - the endpoint will use the anthropic provider
   * **/
  provider: "openai" | "groq" | "anthropic";
};

export const config: EndpointConfig = {
  ...
}

๐Ÿ“ Editing a schema

You can edit a schema by running forge edit in root directory of your project. You will then be prompted for a schema to edit and the changes you would like to make.

forge> Let's edit your schema! Which file would you like to edit?

user>   superhero.ts    student.ts    recipe.ts  * book.ts    example.ts    test.ts    vegetables.ts

forge> What edits would you like to make?

user> Make genre an array and add a new attribute "pageCount"

forge> Editing schema...

๐Ÿงช Testing an endpoint

Endpoint schemas can be tested locally using:

forge test <path-to-schema>

๐Ÿ‘† Deploying a schema

Example schemas can be found in the ./forge/schema folder of this project.

forge deploy deploys all schemas in the ./forge/schema folder by default. Files with a .ignore.ts extension are ignored.

forge deploy    ## Deploy all schemas in the ./forge folder