Skip to content

Commit

Permalink
Chore: update SQL popular chain docs to use runnables (langchain-ai#2877
Browse files Browse the repository at this point in the history
)

* fix: added legacy files and updated base sql example to use runables

* del

* feat: added with sql output example

* fix: removed unnecessary examples

* fix: comment

* fix: added info cards explaining lcel vs non lcel

* fix: removed references to typeorm

* fix: create legacy page and update copy on non legacy

* fix: remove mention of default props on lcel docs

* fix: add comments

* chore: added comments to code examples

* chore: lint files

* fix: mention default prompts

* chore: lint files

* fix: typeorm install doc

* fix: example import

* fix: remove ?

* chore: lint files

* fix: remove unused imports

* chore: eslint no unused imports to examples, ran lint w/ fix
  • Loading branch information
bracesproul authored Oct 13, 2023
1 parent 1b98cdb commit 2e54f1a
Show file tree
Hide file tree
Showing 19 changed files with 442 additions and 44 deletions.
2 changes: 1 addition & 1 deletion docs/docs_skeleton/docs/modules/chains/popular/sqlite.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# SQL

This example demonstrates the use of the `SQLDatabaseChain` for answering questions over a SQL database.
This example demonstrates the use of `Runnables` with questions and more on a SQL database.

import Example from "@snippets/modules/chains/popular/sqlite.mdx"

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# SQL

This example demonstrates the use of the `SQLDatabaseChain` for answering questions over a SQL database.

import Example from "@snippets/modules/chains/popular/sqlite_legacy.mdx"

<Example/>
23 changes: 6 additions & 17 deletions docs/snippets/modules/chains/popular/sqlite.mdx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import CodeBlock from "@theme/CodeBlock";
import SqlDBExample from "@examples/chains/sql_db.ts";
import SqlDBSqlOutputExample from "@examples/chains/sql_db_sql_output.ts";
import SqlDBSAPHANAExample from "@examples/chains/sql_db_saphana.ts";
import SqlDBSqlCustomPromptExample from "@examples/chains/sql_db_custom_prompt.ts";

This example uses Chinook database, which is a sample database available for SQL Server, Oracle, MySQL, etc.

:::info
Looking for the older, non-LCEL version? Click [here](/docs/modules/chains/popular/sqlite_legacy).
:::

## Set up

First install `typeorm`:
Expand All @@ -14,14 +16,13 @@ First install `typeorm`:
npm install typeorm
```

Then install the dependencies needed for your database. For example, for SQLite:
Then, install the dependencies needed for your database. For example, for SQLite:

```bash npm2yarn
npm install sqlite3
```

For other databases see https://typeorm.io/#installation. Currently, LangChain.js has default prompts for
Postgres, SQLite, Microsoft SQL Server, MySQL, and SAP HANA.
LangChain offers default prompts for: default SQL, Postgres, SQLite, Microsoft SQL Server, MySQL, and SAP HANA.

Finally follow the instructions on https://database.guide/2-sample-databases-sqlite/ to get the sample database for this example.

Expand All @@ -40,15 +41,3 @@ const db = await SqlDatabase.fromDataSourceParams({
If desired, you can return the used SQL command when calling the chain.

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

## SAP Hana

Here's an example of using the chain with a SAP HANA database:

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

## Custom prompt

You can also customize the prompt that is used. Here is an example prompting the model to understand that "foobar" is the same as the Employee table:

<CodeBlock language="typescript">{SqlDBSqlCustomPromptExample}</CodeBlock>
60 changes: 60 additions & 0 deletions docs/snippets/modules/chains/popular/sqlite_legacy.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import CodeBlock from "@theme/CodeBlock";
import SqlDBExample from "@examples/chains/sql_db_legacy.ts";
import SqlDBSqlOutputExample from "@examples/chains/sql_db_sql_output_legacy.ts";
import SqlDBSAPHANAExample from "@examples/chains/sql_db_saphana_legacy.ts";
import SqlDBSqlCustomPromptExample from "@examples/chains/sql_db_custom_prompt_legacy.ts";

This example uses Chinook database, which is a sample database available for SQL Server, Oracle, MySQL, etc.

:::info
These are legacy docs. It is now recommended to use LCEL over legacy implementations.

Looking for the LCEL docs? Click [here](/docs/modules/chains/popular/sqlite).
:::

## Set up

First install `typeorm`:

```bash npm2yarn
npm install typeorm
```

Then install the dependencies needed for your database. For example, for SQLite:

```bash npm2yarn
npm install sqlite3
```

Currently, LangChain.js has default prompts for
Postgres, SQLite, Microsoft SQL Server, MySQL, and SAP HANA.

Finally follow the instructions on https://database.guide/2-sample-databases-sqlite/ to get the sample database for this example.

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

You can include or exclude tables when creating the `SqlDatabase` object to help the chain focus on the tables you want.
It can also reduce the number of tokens used in the chain.

```typescript
const db = await SqlDatabase.fromDataSourceParams({
appDataSource: datasource,
includesTables: ["Track"],
});
```

If desired, you can return the used SQL command when calling the chain.

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

## SAP Hana

Here's an example of using the chain with a SAP HANA database:

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

## Custom prompt

You can also customize the prompt that is used. Here is an example prompting the model to understand that "foobar" is the same as the Employee table:

<CodeBlock language="typescript">{SqlDBSqlCustomPromptExample}</CodeBlock>
3 changes: 2 additions & 1 deletion examples/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module.exports = {
parser: "@typescript-eslint/parser",
sourceType: "module",
},
plugins: ["@typescript-eslint"],
plugins: ["@typescript-eslint", "unused-imports"],
rules: {
"@typescript-eslint/explicit-module-boundary-types": 0,
"@typescript-eslint/no-empty-function": 0,
Expand Down Expand Up @@ -41,5 +41,6 @@ module.exports = {
"no-useless-constructor": 0,
"no-else-return": 0,
semi: ["error", "always"],
"unused-imports/no-unused-imports": "error",
},
};
1 change: 1 addition & 0 deletions examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-unused-imports": "^3.0.0",
"prettier": "^2.8.3",
"tsx": "^3.12.3",
"typescript": "^5.0.0"
Expand Down
1 change: 0 additions & 1 deletion examples/src/agents/custom_llm_agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
import { LLMChain } from "langchain/chains";
import { OpenAI } from "langchain/llms/openai";
import {
BasePromptTemplate,
BaseStringPromptTemplate,
SerializedBasePromptTemplate,
renderTemplate,
Expand Down
1 change: 0 additions & 1 deletion examples/src/agents/custom_llm_agent_chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { LLMChain } from "langchain/chains";
import { ChatOpenAI } from "langchain/chat_models/openai";
import {
BaseChatPromptTemplate,
BasePromptTemplate,
SerializedBasePromptTemplate,
renderTemplate,
} from "langchain/prompts";
Expand Down
1 change: 0 additions & 1 deletion examples/src/chains/advanced_subclass.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { CallbackManagerForChainRun } from "langchain/callbacks";
import { BaseChain as _ } from "langchain/chains";
import { BaseMemory } from "langchain/memory";
import { ChainValues } from "langchain/schema";

Expand Down
1 change: 0 additions & 1 deletion examples/src/chains/retrieval_qa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { StringOutputParser } from "langchain/schema/output_parser";
import {
ChatPromptTemplate,
HumanMessagePromptTemplate,
PromptTemplate,
SystemMessagePromptTemplate,
} from "langchain/prompts";
import { ChatOpenAI } from "langchain/chat_models/openai";
Expand Down
108 changes: 100 additions & 8 deletions examples/src/chains/sql_db.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { DataSource } from "typeorm";
import { OpenAI } from "langchain/llms/openai";
import { SqlDatabase } from "langchain/sql_db";
import { SqlDatabaseChain } from "langchain/chains/sql_db";
import { PromptTemplate } from "langchain/prompts";
import { RunnableSequence } from "langchain/schema/runnable";
import { ChatOpenAI } from "langchain/chat_models/openai";
import { StringOutputParser } from "langchain/schema/output_parser";

/**
* This example uses Chinook database, which is a sample database available for SQL Server, Oracle, MySQL, etc.
Expand All @@ -17,11 +19,101 @@ const db = await SqlDatabase.fromDataSourceParams({
appDataSource: datasource,
});

const chain = new SqlDatabaseChain({
llm: new OpenAI({ temperature: 0 }),
database: db,
const llm = new ChatOpenAI();

/**
* Create the first prompt template used for getting the SQL query.
*/
const prompt =
PromptTemplate.fromTemplate(`Based on the provided SQL table schema below, write a SQL query that would answer the user's question.
------------
SCHEMA: {schema}
------------
QUESTION: {question}
------------
SQL QUERY:`);
/**
* You can also load a default prompt by importing from "langchain/sql_db"
*
* import {
* DEFAULT_SQL_DATABASE_PROMPT
* SQL_POSTGRES_PROMPT
* SQL_SQLITE_PROMPT
* SQL_MSSQL_PROMPT
* SQL_MYSQL_PROMPT
* SQL_SAP_HANA_PROMPT
* } from "langchain/sql_db";
*
*/

/**
* Create a new RunnableSequence where we pipe the output from `db.getTableInfo()`
* and the users question, into the prompt template, and then into the llm.
* We're also applying a stop condition to the llm, so that it stops when it
* sees the `\nSQLResult:` token.
*/
const sqlQueryChain = RunnableSequence.from([
{
schema: async () => db.getTableInfo(),
question: (input: { question: string }) => input.question,
},
prompt,
llm.bind({ stop: ["\nSQLResult:"] }),
new StringOutputParser(),
]);

const res = await sqlQueryChain.invoke({
question: "How many employees are there?",
});
console.log({ res });

/**
* { res: 'SELECT COUNT(*) FROM tracks;' }
*/

const res = await chain.run("How many tracks are there?");
console.log(res);
// There are 3503 tracks.
/**
* Create the final prompt template which is tasked with getting the natural language response.
*/
const finalResponsePrompt =
PromptTemplate.fromTemplate(`Based on the table schema below, question, SQL query, and SQL response, write a natural language response:
------------
SCHEMA: {schema}
------------
QUESTION: {question}
------------
SQL QUERY: {query}
------------
SQL RESPONSE: {response}
------------
NATURAL LANGUAGE RESPONSE:`);

/**
* Create a new RunnableSequence where we pipe the output from the previous chain, the users question,
* and the SQL query, into the prompt template, and then into the llm.
* Using the result from the `sqlQueryChain` we can run the SQL query via `db.run(input.query)`.
*/
const finalChain = RunnableSequence.from([
{
question: (input) => input.question,
query: sqlQueryChain,
},
{
schema: async () => db.getTableInfo(),
question: (input) => input.question,
query: (input) => input.query,
response: (input) => db.run(input.query),
},
finalResponsePrompt,
llm,
new StringOutputParser(),
]);

const finalResponse = await finalChain.invoke({
question: "How many employees are there?",
});

console.log({ finalResponse });

/**
* { finalResponse: 'There are 8 employees.' }
*/
56 changes: 56 additions & 0 deletions examples/src/chains/sql_db_custom_prompt_legacy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { DataSource } from "typeorm";
import { OpenAI } from "langchain/llms/openai";
import { SqlDatabase } from "langchain/sql_db";
import { SqlDatabaseChain } from "langchain/chains/sql_db";
import { PromptTemplate } from "langchain/prompts";

const template = `Given an input question, first create a syntactically correct {dialect} query to run, then look at the results of the query and return the answer.
Use the following format:
Question: "Question here"
SQLQuery: "SQL Query to run"
SQLResult: "Result of the SQLQuery"
Answer: "Final answer here"
Only use the following tables:
{table_info}
If someone asks for the table foobar, they really mean the employee table.
Question: {input}`;

const prompt = PromptTemplate.fromTemplate(template);

/**
* This example uses Chinook database, which is a sample database available for SQL Server, Oracle, MySQL, etc.
* To set it up follow the instructions on https://database.guide/2-sample-databases-sqlite/, placing the .db file
* in the examples folder.
*/
const datasource = new DataSource({
type: "sqlite",
database: "data/Chinook.db",
});

const db = await SqlDatabase.fromDataSourceParams({
appDataSource: datasource,
});

const chain = new SqlDatabaseChain({
llm: new OpenAI({ temperature: 0 }),
database: db,
sqlOutputKey: "sql",
prompt,
});

const res = await chain.call({
query: "How many employees are there in the foobar table?",
});
console.log(res);

/*
{
result: ' There are 8 employees in the foobar table.',
sql: ' SELECT COUNT(*) FROM Employee;'
}
*/
27 changes: 27 additions & 0 deletions examples/src/chains/sql_db_legacy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { DataSource } from "typeorm";
import { OpenAI } from "langchain/llms/openai";
import { SqlDatabase } from "langchain/sql_db";
import { SqlDatabaseChain } from "langchain/chains/sql_db";

/**
* This example uses Chinook database, which is a sample database available for SQL Server, Oracle, MySQL, etc.
* To set it up follow the instructions on https://database.guide/2-sample-databases-sqlite/, placing the .db file
* in the examples folder.
*/
const datasource = new DataSource({
type: "sqlite",
database: "Chinook.db",
});

const db = await SqlDatabase.fromDataSourceParams({
appDataSource: datasource,
});

const chain = new SqlDatabaseChain({
llm: new OpenAI({ temperature: 0 }),
database: db,
});

const res = await chain.run("How many tracks are there?");
console.log(res);
// There are 3503 tracks.
Loading

0 comments on commit 2e54f1a

Please sign in to comment.