{"id":14155599,"url":"https://github.com/instructor-ai/instructor-js","last_synced_at":"2025-04-14T23:15:53.909Z","repository":{"id":215013042,"uuid":"737903080","full_name":"instructor-ai/instructor-js","owner":"instructor-ai","description":"structured extraction for llms","archived":false,"fork":false,"pushed_at":"2025-01-27T23:44:58.000Z","size":2804,"stargazers_count":700,"open_issues_count":11,"forks_count":64,"subscribers_count":13,"default_branch":"main","last_synced_at":"2025-04-14T23:15:48.944Z","etag":null,"topics":["llm","openai","zod"],"latest_commit_sha":null,"homepage":"https://js.useinstructor.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/instructor-ai.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"docs/contributing.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-01-01T22:52:25.000Z","updated_at":"2025-04-14T10:34:32.000Z","dependencies_parsed_at":"2024-02-10T22:29:08.624Z","dependency_job_id":"3680d7f9-5fd0-4f11-89ee-2174bc02fd49","html_url":"https://github.com/instructor-ai/instructor-js","commit_stats":null,"previous_names":["jxnl/instructor-js","instructor-ai/instructor-js"],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/instructor-ai%2Finstructor-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/instructor-ai%2Finstructor-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/instructor-ai%2Finstructor-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/instructor-ai%2Finstructor-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/instructor-ai","download_url":"https://codeload.github.com/instructor-ai/instructor-js/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248975329,"owners_count":21192210,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["llm","openai","zod"],"created_at":"2024-08-17T08:04:16.722Z","updated_at":"2025-04-14T23:15:53.875Z","avatar_url":"https://github.com/instructor-ai.png","language":"TypeScript","funding_links":[],"categories":["openai"],"sub_categories":[],"readme":"# instructor-js\n\n_Structured extraction in Typescript, powered by llms, designed for simplicity, transparency, and control._\n\n---\n\n[![Twitter Follow](https://img.shields.io/twitter/follow/jxnlco?style=social)](https://twitter.com/jxnlco)\n[![Twitter Follow](https://img.shields.io/twitter/follow/dimitrikennedy?style=social)](https://twitter.com/dimitrikennedy)\n[![NPM Version](https://img.shields.io/npm/v/@instructor-ai/instructor.svg)](https://www.npmjs.com/package/@instructor-ai/instructor)\n[![Documentation](https://img.shields.io/badge/docs-available-brightgreen)](https://jxnl.github.io/instructor-js)\n[![GitHub issues](https://img.shields.io/github/issues/instructor-ai/instructor-js.svg)](https://github.com/instructor-ai/instructor-js/issues)\n[![Discord](https://img.shields.io/discord/1192334452110659664?label=discord)](https://discord.gg/CV8sPM5k5Y)\n\nDive into the world of Typescript-based structured extraction, by OpenAI's function calling API and Zod, typeScript-first schema validation with static type inference. Instructor stands out for its simplicity, transparency, and user-centric design. Whether you're a seasoned developer or just starting out, you'll find Instructor's approach intuitive and steerable.\n\n\n## Installation\n\n```bash\nbun add @instructor-ai/instructor zod openai\n```\n\n```bash\nnpm i @instructor-ai/instructor zod openai\n```\n\n```bash\npnpm add @instructor-ai/instructor zod openai\n```\n\n## Basic Usage\nTo check out all the tips and tricks to prompt and extract data, check out the [documentation](https://instructor-ai.github.io/instructor-js/tips/prompting/).\n\n\n```typescript\n\nimport Instructor from \"@instructor-ai/instructor\";\nimport OpenAI from \"openai\"\nimport { z } from \"zod\"\n\nconst oai = new OpenAI({\n  apiKey: process.env.OPENAI_API_KEY ?? undefined,\n  organization: process.env.OPENAI_ORG_ID ?? undefined\n})\n\nconst client = Instructor({\n  client: oai,\n  mode: \"TOOLS\"\n})\n\nconst UserSchema = z.object({\n  // Description will be used in the prompt\n  age: z.number().describe(\"The age of the user\"), \n  name: z.string()\n})\n\n\n// User will be of type z.infer\u003ctypeof UserSchema\u003e\nconst user = await client.chat.completions.create({\n  messages: [{ role: \"user\", content: \"Jason Liu is 30 years old\" }],\n  model: \"gpt-3.5-turbo\",\n  response_model: { \n    schema: UserSchema, \n    name: \"User\"\n  }\n})\n\nconsole.log(user)\n// { age: 30, name: \"Jason Liu\" }\n```\n\n\n## API Reference\n\n### Instructor Class\nThe main class for creating an Instructor client.\n\n**createInstructor**\n```typescript\nfunction createInstructor\u003cC extends GenericClient | OpenAI\u003e(args: {\n  client: OpenAILikeClient\u003cC\u003e;\n  mode: Mode;\n  debug?: boolean;\n}): InstructorClient\u003cC\u003e\n```\n\nCreates an instance of the Instructor class.\n\n- client: An OpenAI-like client.\n- mode: The mode of operation.\n- debug: Whether to log debug messages.\n\nReturns the extended OpenAI-Like client.\n\n\n**chat.completions.create**\n```typescript\nchat.completions.create\u003c\n        T extends z.AnyZodObject,\n        P extends T extends z.AnyZodObject ? ChatCompletionCreateParamsWithModel\u003cT\u003e\n        : ClientTypeChatCompletionParams\u003cOpenAILikeClient\u003cC\u003e\u003e \u0026 { response_model: never }\n      \u003e(\n        params: P\n      ): Promise\u003cReturnTypeBasedOnParams\u003ctypeof this.client, P\u003e\u003e\n```\nWhen response_model is present in the params, creates a chat completion with structured extraction based on the provided schema - otherwise will proxy back to the provided client.\n\n- params: Chat completion parameters including the response model schema.\n- Returns a promise resolving to the extracted data based on the schema.\n\n\n### Modes\n\nInstructor supports different modes for defining the structure and format of the response from the language model. These modes are defined in the `zod-stream` package and are as follows:\n\n- `FUNCTIONS` (*DEPRECATED*): Generates a response using OpenAI's function calling API. It maps to the necessary parameters for the function calling API, including the `function_call` and `functions` properties. \n\n- `TOOLS`: Generates a response using OpenAI's tool specification. It constructs the required parameters for the tool specification, including the `tool_choice` and `tools` properties.\n\n- `JSON`: It sets the `response_format` to `json_object` and includes the JSON schema in the system message to guide the response generation. (Together \u0026 Anyscale)\n\n- `MD_JSON`: Generates a response in JSON format embedded within a Markdown code block. It includes the JSON schema in the system message and expects the response to be a valid JSON object wrapped in a Markdown code block.\n\n- `JSON_SCHEMA`: Generates a response using \"JSON mode\" that conforms to a provided JSON schema. It sets the `response_format` to `json_object` with the provided schema and includes the schema description in the system message.\n\n\n\n## Examples\n\n\n### Streaming Completions\nInstructor supports partial streaming completions, allowing you to receive extracted data in real-time as the model generates its response. This can be useful for providing a more interactive user experience or processing large amounts of data incrementally.\n\n```typescript\nimport Instructor from \"@instructor-ai/instructor\"\nimport OpenAI from \"openai\"\nimport { z } from \"zod\"\n\nconst textBlock = `\n  In our recent online meeting, participants from various backgrounds joined to discuss the upcoming tech conference. \n  The names and contact details of the participants were as follows:\n\n  - Name: John Doe, Email: johndoe@email.com, Twitter: @TechGuru44\n  - Name: Jane Smith, Email: janesmith@email.com, Twitter: @DigitalDiva88\n  - Name: Alex Johnson, Email: alexj@email.com, Twitter: @CodeMaster2023\n\n  During the meeting, we agreed on several key points. The conference will be held on March 15th, 2024, at the Grand Tech Arena located at 4521 Innovation Drive. Dr. Emily Johnson, a renowned AI researcher, will be our keynote speaker. The budget for the event is set at $50,000, covering venue costs, speaker fees, and promotional activities. \n\n  Each participant is expected to contribute an article to the conference blog by February 20th. A follow-up meeting is scheduled for January 25th at 3 PM GMT to finalize the agenda and confirm the list of speakers.\n`\n\nasync function extractData() {\n  const ExtractionSchema = z.object({\n    users: z.array(\n      z.object({\n        name: z.string(),\n        handle: z.string(),\n        twitter: z.string()\n      })\n    ).min(3),\n    location: z.string(),\n    budget: z.number()\n  })\n\n  const oai = new OpenAI({\n    apiKey: process.env.OPENAI_API_KEY ?? undefined,\n    organization: process.env.OPENAI_ORG_ID ?? undefined\n  })\n\n  const client = Instructor({\n    client: oai,\n    mode: \"TOOLS\"\n  })\n\n  const extractionStream = await client.chat.completions.create({\n    messages: [{ role: \"user\", content: textBlock }],\n    model: \"gpt-3.5-turbo\",\n    response_model: {\n      schema: ExtractionSchema,\n      name: \"Extraction\"\n    },\n    max_retries: 3,\n    stream: true\n  })\n\n  let extractedData = {}\n  for await (const result of extractionStream) {\n    extractedData = result\n    console.log(\"Partial extraction:\", result)\n  }\n  \n  console.log(\"Final extraction:\", extractedData)\n}\n\nextractData()\n```\n\nIn this example, we define an ExtractionSchema using Zod to specify the structure of the data we want to extract. We then create an Instructor client with streaming enabled and pass the schema to the response_model parameter.\n\nThe extractionStream variable holds an async generator that yields partial extraction results as they become available. We iterate over the stream using a for await...of loop, updating the extractedData object with each partial result and logging it to the console.\n\nFinally, we log the complete extracted data once the stream is exhausted.\n\n\n### Using Different Providers via proxy\nInstructor supports various providers that adhere to the OpenAI API specification. You can easily switch between providers by configuring the appropriate client and specifying the desired model and mode.\n\n**Anyscale**\n```typescript\nimport Instructor from \"@instructor-ai/instructor\"\nimport OpenAI from \"openai\"\nimport { z } from \"zod\"\n\nconst UserSchema = z.object({\n  age: z.number(),\n  name: z.string().refine(name =\u003e name.includes(\" \"), {\n    message: \"Name must contain a space\"\n  })\n})\n\nasync function extractUser() {\n  const client = new OpenAI({\n    baseURL: \"https://api.endpoints.anyscale.com/v1\",\n    apiKey: process.env.ANYSCALE_API_KEY\n  })\n\n  const instructor = Instructor({\n    client: client,\n    mode: \"TOOLS\"\n  })\n\n  const user = await instructor.chat.completions.create({\n    messages: [{ role: \"user\", content: \"Jason Liu is 30 years old\" }],\n    model: \"mistralai/Mixtral-8x7B-Instruct-v0.1\",\n    response_model: {\n      schema: UserSchema,\n      name: \"User\"\n    },\n    max_retries: 4\n  })\n\n  return user\n}\n\nconst anyscaleUser = await extractUser()\nconsole.log(\"Anyscale user:\", anyscaleUser)\n```\n\n**Together**\n```typescript\nimport Instructor from \"@instructor-ai/instructor\"\nimport OpenAI from \"openai\"\nimport { z } from \"zod\"\n\nconst UserSchema = z.object({\n  age: z.number(),\n  name: z.string().refine(name =\u003e name.includes(\" \"), {\n    message: \"Name must contain a space\"\n  })\n})\n\nasync function extractUser() {\n  const client = new OpenAI({\n    baseURL: \"https://api.together.xyz/v1\",\n    apiKey: process.env.TOGETHER_API_KEY\n  })\n\n  const instructor = Instructor({\n    client: client,\n    mode: \"TOOLS\"\n  })\n\n  const user = await instructor.chat.completions.create({\n    messages: [{ role: \"user\", content: \"Jason Liu is 30 years old\" }],\n    model: \"mistralai/Mixtral-8x7B-Instruct-v0.1\",\n    response_model: {\n      schema: UserSchema,\n      name: \"User\"\n    },\n    max_retries: 4\n  })\n\n  return user\n}\n\nconst togetherUser = await extractUser()\nconsole.log(\"Together user:\", togetherUser)\n```\n\nIn these examples, we specify a specific base URL and API key from Anyscale, and Together..\n\nThe extractUser function takes the model, mode, and provider as parameters. It retrieves the corresponding provider configuration, creates an OpenAI client, and initializes an Instructor instance with the specified mode.\n\nWe then call instructor.chat.completions.create with the desired model, response schema, and other parameters to extract the user information.\n\nBy varying the provider, model, and mode arguments when calling extractUser, you can easily switch between different providers and configurations.\n\n\n### Using Non-OpenAI Providers with llm-polyglot\n\nInstructor supports integration with providers that don't adhere to the OpenAI SDK, such as Anthropic, Azure, and Cohere, through the [`llm-polyglot`](https://github.com/hack-dance/island-ai/tree/main/public-packages/llm-client) library maintained by @dimitrikennedy. This library provides a unified interface for interacting with various language models across different providers.\n\n```typescript\nimport { createLLMClient } from \"llm-polyglot\"\nimport Instructor from \"@instructor-ai/instructor\"\nimport { z } from \"zod\"\n\nconst anthropicClient = createLLMClient({\n  provider: \"anthropic\",\n  apiKey: process.env.ANTHROPIC_API_KEY\n})\n\nconst UserSchema = z.object({\n  age: z.number(),\n  name: z.string()\n})\n\nconst instructor = Instructor\u003ctypeof anthropicClient\u003e({\n  client: anthropicClient,\n  mode: \"TOOLS\"\n})\n\nasync function extractUser() {\n  const user = await instructor.chat.completions.create({\n    model: \"claude-3-opus-20240229\",\n    max_tokens: 1000,\n    messages: [\n      {\n        role: \"user\",\n        content: \"My name is Dimitri Kennedy.\"\n      }\n    ],\n    response_model: {\n      name: \"extract_name\",\n      schema: UserSchema\n    }\n  })\n\n  return user\n}\n\n// Example usage\nconst extractedUser = await extractUser()\nconsole.log(\"Extracted user:\", extractedUser)\n```\n\nIn this example, we use the createLLMClient function from the llm-polyglot library to create a client for the Anthropic provider. We pass the provider name (\"anthropic\") and the corresponding API key to the function.\n\nNext, we define a UserSchema using Zod to specify the structure of the user data we want to extract.\n\nWe create an Instructor instance by passing the Anthropic client and the desired mode to the Instructor function. Note that we use Instructor\u003ctypeof anthropicClient\u003e to specify the client type explicitly.\n\nThe extractUser function demonstrates how to use the Instructor instance to extract user information from a given input. We call instructor.chat.completions.create with the appropriate model (\"claude-3-opus-20240229\" in this case), parameters, and the response_model that includes our UserSchema.\n\nFinally, we log the extracted user information.\n\nBy leveraging the llm-polyglot library, Instructor enables seamless integration with a wide range of providers beyond those that follow the OpenAI SDK. This allows you to take advantage of the unique capabilities and models offered by different providers while still benefiting from the structured extraction and validation features of Instructor.\n\nFor additional support and information on using other providers with [llm-polyglot](https://github.com/hack-dance/island-ai/tree/main/public-packages/llm-client), please refer to the library's documentation and examples.\n\n\n## More Examples\n\nIf you'd like to see more check out our [cookbook](docs/examples/index.md).\n\n[Installing Instructor](docs/installation.md) is a breeze.\n\n\n## Built on Island AI\n\nInstructor is built on top of several powerful packages from the [Island AI](https://github.com/hack-dance/island-ai) toolkit, developed and maintained by [Dimitri Kennedy](https://twitter.com/dimitrikennedy). These packages provide essential functionality for structured data handling and streaming with Large Language Models.\n\n### zod-stream\n\n[zod-stream](https://github.com/hack-dance/island-ai/tree/main/public-packages/zod-stream) is a client module that interfaces directly with LLM streams. It utilizes Schema-Stream for efficient parsing and is equipped with tools for processing raw responses from OpenAI, categorizing them by mode (function, tools, JSON, etc.), and ensuring proper error handling and stream conversion. It's ideal for API integration delivering structured LLM response streams.\n\n### schema-stream\n\n[schema-stream](https://github.com/hack-dance/island-ai/tree/main/public-packages/schema-stream) is a JSON streaming parser that incrementally constructs and updates response models based on Zod schemas. It's designed for real-time data processing and incremental model hydration.\n\n\n### llm-polyglot\n\n[llm-polyglot](https://github.com/hack-dance/island-ai/tree/main/public-packages/llm-client) is a library that provides a unified interface for interacting with various language models across different providers, such as OpenAI, Anthropic, Azure, and Cohere. It simplifies the process of working with multiple LLM providers and enables seamless integration with Instructor.\n\nInstructor leverages the power of these Island AI packages to deliver a seamless and efficient experience for structured data extraction and streaming with LLMs. The collaboration between Dimitri Kennedy, the creator of Island AI, and Jason Liu, the author of the original Instructor Python package, has led to the development of the TypeScript version of Instructor, which introduces the concept of partial JSON streaming from LLM's.\n\nFor more information about Island AI and its packages, please refer to the [Island AI repository](https://github.com/hack-dance/island-ai).\n\n\n## Why use Instructor?\n\nThe question of using Instructor is fundamentally a question of why to use zod.\n\n1. **Works with the OpenAI SDK** — Instructor follows OpenAI's API. This means you can use the same API for both prompting and extraction across multiple providers that support the OpenAI API.\n\n2. **Customizable** — Zod is highly customizable. You can define your own validators, custom error messages, and more.\n\n3. **Ecosystem** Zod is the most widely used data validation library for Typescript.\n\n4. **Battle Tested** — Zod is downloaded over 24M times per month, and supported by a large community of contributors.\n\n\n\n\n## Contributing\n\nIf you want to help out, checkout some of the issues marked as `good-first-issue` or `help-wanted`. Found [here](https://github.com/instructor-ai/instructor-js/labels/good%20first%20issue). They could be anything from code improvements, a guest blog post, or a new cook book.\n\nCheckout the [contribution guide]() for details on how to set things up, testing, changesets and guidelines.\n\n\u003e ℹ️ **Tip:**  Support in other languages\n\n    Check out ports to other languages below:\n\n    - [Python](https://www.github.com/jxnl/instructor)\n    - [Elixir](https://github.com/thmsmlr/instructor_ex/)\n\n    If you want to port Instructor to another language, please reach out to us on [Twitter](https://twitter.com/jxnlco) we'd love to help you get started!\n\n## License\n\nThis project is licensed under the terms of the MIT License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finstructor-ai%2Finstructor-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Finstructor-ai%2Finstructor-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finstructor-ai%2Finstructor-js/lists"}