Skip to content

Commit

Permalink
langchain[minor]: Adds create runnable chain functions (#3928)
Browse files Browse the repository at this point in the history
* langchain[minor]: Adds create runnable chain functions

* docs & tests

* cr

* chore: lint files

* fix docs build

* Updates

* Fix typing, docs

* Fix typo

* Format

---------

Co-authored-by: jacoblee93 <[email protected]>
  • Loading branch information
bracesproul and jacoblee93 authored Jan 8, 2024
1 parent 1ccf680 commit 14eb13a
Show file tree
Hide file tree
Showing 9 changed files with 633 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Using OpenAI functions

This walkthrough demonstrates how to incorporate OpenAI function-calling API's in a chain. We'll go over:

1. How to use functions to get structured outputs from ChatOpenAI
2. How to create a generic chain that uses (multiple) functions
3. How to create a chain that actually executes the chosen function

## Getting structured outputs

We can take advantage of OpenAI functions to try and force the model to return a particular kind of structured output.
We'll use `createStructuredOutputRunnable` to create our chain, which takes the desired structured output as a valid JSONSchema.

import JSONSchemaExample from "@examples/chains/openai_functions_json_schema.ts";
import CodeBlock from "@theme/CodeBlock";

<CodeBlock language="typescript">{JSONSchemaExample}</CodeBlock>

:::tip
You can see a LangSmith trace of this example [here](https://smith.langchain.com/public/c478790b-0b47-467f-894c-bc95b9b861a5/r).
:::

## Creating a generic OpenAI functions chain

To create a generic OpenAI functions chain, we can use the `createOpenaiFnRunnable` method.
This is the same as `createStructuredOutputRunnable` except that instead of taking a single output schema, it takes a sequence of function definitions.

import OpenAIFnExample from "@examples/chains/openai_functions_runnable.ts";

<CodeBlock language="typescript">{OpenAIFnExample}</CodeBlock>

:::tip
You can see a LangSmith trace of this example [here](https://smith.langchain.com/public/b042c342-da49-466c-afee-f5604b2fa232/r).
:::

## Multiple functions

import OpenAIMultiFnExample from "@examples/chains/openai_multi_functions_runnable.ts";

<CodeBlock language="typescript">{OpenAIMultiFnExample}</CodeBlock>

:::tip
You can see a LangSmith trace of this example [here](https://smith.langchain.com/public/06550907-1df5-4279-8ac5-00acb5e56ea7/r).
:::
2 changes: 2 additions & 0 deletions docs/core_docs/docs/modules/chains/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ Our commentary on when to use this chain.
| Chain Constructor | Function Calling | Other Tools | When to Use |
| ----------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [createStuffDocumentsChain](https://api.js.langchain.com/functions/langchain_chains_combine_documents.createStuffDocumentsChain.html) | | | This chain takes a list of documents and formats them all into a prompt, then passes that prompt to an LLM. It passes ALL documents, so you should make sure it fits within the context window the LLM you are using. |
| [createOpenAIFnRunnable](https://api.js.langchain.com/functions/langchain_chains_openai_functions.createOpenAIFnRunnable.html) | βœ… | | If you want to use OpenAI function calling to OPTIONALLY structure an output response. You may pass in multiple functions for the chain to call, but it does not have to call it. |
| [createStructuredOutputRunnable](https://api.js.langchain.com/functions/langchain_chains_openai_functions.createStructuredOutputRunnable.html) | βœ… | | If you want to use OpenAI function calling to FORCE the LLM to respond with a certain function. You may only pass in one function, and the chain will ALWAYS return this response. |
| [createHistoryAwareRetriever](https://api.js.langchain.com/functions/langchain_chains_history_aware_retriever.createHistoryAwareRetriever.html) | | Retriever | This chain takes in conversation history and then uses that to generate a search query which is passed to the underlying retriever. |
| [createRetrievalChain](https://api.js.langchain.com/functions/langchain_chains_retrieval.createRetrievalChain.html) | | Retriever | This chain takes in a user inquiry, which is then passed to the retriever to fetch relevant documents. Those documents (and original inputs) are then passed to an LLM to generate a response |

Expand Down
41 changes: 41 additions & 0 deletions examples/src/chains/openai_functions_json_schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { ChatOpenAI } from "@langchain/openai";
import { createStructuredOutputRunnable } from "langchain/chains/openai_functions";
import { JsonOutputFunctionsParser } from "langchain/output_parsers";

const jsonSchema = {
title: "Person",
description: "Identifying information about a person.",
type: "object",
properties: {
name: { title: "Name", description: "The person's name", type: "string" },
age: { title: "Age", description: "The person's age", type: "integer" },
fav_food: {
title: "Fav Food",
description: "The person's favorite food",
type: "string",
},
},
required: ["name", "age"],
};

const model = new ChatOpenAI();
const prompt = ChatPromptTemplate.fromMessages([
["human", "Human description: {description}"],
]);
const outputParser = new JsonOutputFunctionsParser();

const runnable = createStructuredOutputRunnable({
outputSchema: jsonSchema,
llm: model,
prompt,
outputParser,
});
const response = await runnable.invoke({
description:
"My name's John Doe and I'm 30 years old. My favorite kind of food are chocolate chip cookies.",
});
console.log(response);
/*
{ name: 'John Doe', age: 30, fav_food: 'chocolate chip cookies' }
*/
46 changes: 46 additions & 0 deletions examples/src/chains/openai_functions_runnable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { ChatOpenAI } from "@langchain/openai";
import { createOpenAIFnRunnable } from "langchain/chains/openai_functions";
import { JsonOutputFunctionsParser } from "langchain/output_parsers";

const openAIFunction = {
name: "get_person_details",
description: "Get details about a person",
parameters: {
title: "Person",
description: "Identifying information about a person.",
type: "object",
properties: {
name: { title: "Name", description: "The person's name", type: "string" },
age: { title: "Age", description: "The person's age", type: "integer" },
fav_food: {
title: "Fav Food",
description: "The person's favorite food",
type: "string",
},
},
required: ["name", "age"],
},
};

const model = new ChatOpenAI();
const prompt = ChatPromptTemplate.fromMessages([
["human", "Human description: {description}"],
]);
const outputParser = new JsonOutputFunctionsParser();

const runnable = createOpenAIFnRunnable({
functions: [openAIFunction],
llm: model,
prompt,
enforceSingleFunctionUsage: true, // Default is true
outputParser,
});
const response = await runnable.invoke({
description:
"My name's John Doe and I'm 30 years old. My favorite kind of food are chocolate chip cookies.",
});
console.log(response);
/*
{ name: 'John Doe', age: 30, fav_food: 'chocolate chip cookies' }
*/
73 changes: 73 additions & 0 deletions examples/src/chains/openai_multi_functions_runnable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { ChatOpenAI } from "@langchain/openai";
import { createOpenAIFnRunnable } from "langchain/chains/openai_functions";
import { JsonOutputFunctionsParser } from "langchain/output_parsers";

const personDetailsFunction = {
name: "get_person_details",
description: "Get details about a person",
parameters: {
title: "Person",
description: "Identifying information about a person.",
type: "object",
properties: {
name: { title: "Name", description: "The person's name", type: "string" },
age: { title: "Age", description: "The person's age", type: "integer" },
fav_food: {
title: "Fav Food",
description: "The person's favorite food",
type: "string",
},
},
required: ["name", "age"],
},
};

const weatherFunction = {
name: "get_weather",
description: "Get the weather for a location",
parameters: {
title: "Location",
description: "The location to get the weather for.",
type: "object",
properties: {
state: {
title: "State",
description: "The location's state",
type: "string",
},
city: {
title: "City",
description: "The location's city",
type: "string",
},
zip_code: {
title: "Zip Code",
description: "The locations's zip code",
type: "number",
},
},
required: ["state", "city"],
},
};

const model = new ChatOpenAI();
const prompt = ChatPromptTemplate.fromMessages([
["human", "Question: {question}"],
]);
const outputParser = new JsonOutputFunctionsParser();

const runnable = createOpenAIFnRunnable({
functions: [personDetailsFunction, weatherFunction],
llm: model,
prompt,
enforceSingleFunctionUsage: false, // Default is true
outputParser,
});
const response = await runnable.invoke({
question: "What's the weather like in Berkeley CA?",
});
console.log(response);
/*
{ state: 'CA', city: 'Berkeley' }
*/
Loading

2 comments on commit 14eb13a

@vercel
Copy link

@vercel vercel bot commented on 14eb13a Jan 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on 14eb13a Jan 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

langchainjs-docs – ./docs/core_docs/

langchainjs-docs-ruddy.vercel.app
langchainjs-docs-langchain.vercel.app
js.langchain.com
langchainjs-docs-git-main-langchain.vercel.app

Please sign in to comment.