Skip to content

Commit

Permalink
docs: Document sequential chain
Browse files Browse the repository at this point in the history
  • Loading branch information
davidmigloz committed Jul 23, 2023
1 parent a95b3e9 commit b9693a4
Show file tree
Hide file tree
Showing 6 changed files with 269 additions and 9 deletions.
3 changes: 3 additions & 0 deletions docs/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@
- [Loading from LangChainHub](/modules/chains/how_to/from_hub.md)
- [Adding memory](/modules/chains/how_to/memory.md)
- [Serialization](/modules/chains/how_to/serialization.md)
- Foundational
- [LLM](/modules/chains/foundational/llm.md)
- [Sequential](/modules/chains/foundational/sequential.md)
- [Memory](/modules/memory/memory.md)
- [Agents](/modules/agents/agents.md)
- [Agent types](/modules/agents/agent_types/agent_types.md)
Expand Down
23 changes: 23 additions & 0 deletions docs/modules/chains/foundational/llm.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# LLM

An `LLMChain` is a simple chain that adds some functionality around language
models. It is used widely throughout LangChain, including in other chains and
agents.

An `LLMChain` consists of a `PromptTemplate` and a language model (either an
LLM or chat model). It formats the prompt template using the input key values
provided (and also memory key values, if available), passes the formatted string
to LLM and returns the LLM output.

## Get started

```dart
final llm = OpenAI(apiKey: openaiApiKey, temperature: 0.9);
final prompt = PromptTemplate.fromTemplate(
'What is a good name for a company that makes {product}?',
);
final chain = LLMChain(llm: llm, prompt: prompt);
final res = await chain.run('colorful socks');
print(res);
// -> 'Colorful Toes Co.'
```
234 changes: 234 additions & 0 deletions docs/modules/chains/foundational/sequential.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
# Sequential

The next step after calling a language model is make a series of calls to a
language model. This is particularly useful when you want to take the output
from one call and use it as the input to another.

In this notebook we will walk through some examples for how to do this, using
sequential chains. Sequential chains allow you to connect multiple chains and
compose them into pipelines that execute some specific scenario.

## Types of Sequential Chains

There are two types of sequential chains:

- `SimpleSequentialChain`: the simplest form of sequential chains, where each
step has a singular input/output, and the output of one step is the input to
the next.
- `SequentialChain`: a more general form of sequential chains, allowing for
multiple inputs/outputs.

### SimpleSequentialChain

Let's see how we can use a `SimpleSequentialChain`:

```dart
final openAiApiKey = Platform.environment['OPENAI_API_KEY'];
final llm = ChatOpenAI(apiKey: openAiApiKey);
// This is an LLMChain to write a synopsis given a title of a play
const synopsisTemplate = '''
You are a playwright. Given the title of play, it is your job to write a synopsis for that title.
Title: {title}
Playwright: This is a synopsis for the above play:''';
final synopsisPromptTemplate = PromptTemplate.fromTemplate(synopsisTemplate);
final synopsisChain = LLMChain(llm: llm, prompt: synopsisPromptTemplate);
// This is an LLMChain to write a review of a play given a synopsis
const reviewTemplate = '''
You are a play critic from the New York Times. Given the synopsis of play, it is your job to write a review for that play.
Play Synopsis:
{synopsis}
Review from a New York Times play critic of the above play:''';
final reviewPromptTemplate = PromptTemplate.fromTemplate(reviewTemplate);
final reviewChain = LLMChain(llm: llm, prompt: reviewPromptTemplate);
// This is the overall chain where we run these two chains in sequence
final overallChain = SimpleSequentialChain(chains: [synopsisChain, reviewChain]);
final review = await overallChain.run('Tragedy at sunset on the beach');
print(review);
```

> In "Tragedy at Sunset on the Beach," playwright delivers a riveting and
> emotionally charged drama that captivates the audience from start to finish.
> Set against the breathtaking backdrop of a tranquil beach at dusk, this play
> explores the complexities of the human experience with depth and nuance...
### Sequential Chain

Of course, not all sequential chains will be as simple as passing a single
string as an argument and getting a single string as output for all steps in the
chain. In this next example, we will experiment with more complex chains that
involve multiple inputs, and where there also multiple final outputs.

Of particular importance is how we name the input/output variable names. In the
above example we didn't have to think about that because we were just passing
the output of one chain directly as input to the next, but here we do have worry
about that because we have multiple inputs.

```dart
final openAiApiKey = Platform.environment['OPENAI_API_KEY'];
final llm = ChatOpenAI(apiKey: openAiApiKey);
// This is an LLMChain to write a synopsis given a title of a play
const synopsisTemplate = '''
You are a playwright. Given the title of play, it is your job to write a synopsis for that title.
Title: {title}
Era: {era}
Playwright: This is a synopsis for the above play:''';
final synopsisPromptTemplate = PromptTemplate.fromTemplate(synopsisTemplate);
final synopsisChain = LLMChain(
llm: llm,
prompt: synopsisPromptTemplate,
outputKey: 'synopsis',
);
// This is an LLMChain to write a review of a play given a synopsis
const reviewTemplate = '''
You are a play critic from the New York Times. Given the synopsis of play, it is your job to write a review for that play.
Play Synopsis:
{synopsis}
Review from a New York Times play critic of the above play:''';
final reviewPromptTemplate = PromptTemplate.fromTemplate(reviewTemplate);
final reviewChain = LLMChain(
llm: llm,
prompt: reviewPromptTemplate,
outputKey: 'review',
);
// This is the overall chain where we run these two chains in sequence
final overallChain = SequentialChain(chains: [synopsisChain, reviewChain]);
final review = await overallChain.run({
'title': 'Tragedy at sunset on the beach',
'era': 'Victorian England',
});
print(review);
```

> Tragedy at Sunset on the Beach: A Captivating Tale of Love and Sacrifice
>
> In the enchanting coastal town of Victorian England, Tragedy at Sunset on the
> Beach transports its audience to a world where societal expectations and
> forbidden love collide. This tragic play, set against the backdrop of a
> breathtaking sunset on the beach, delves into the complexities of a society
> bound by rigid rules and the heart-wrenching consequences of defying them...
## Memory in Sequential Chains

Sometimes you may want to pass along some context to use in each step of the
chain or in a later part of the chain, but maintaining and chaining together the
input/output variables can quickly get messy. Using `SimpleMemory` is a
convenient way to do manage this and clean up your chains.

For example, using the previous playwright `SequentialChain`, lets say you
wanted to include some context about date, time and location of the play, and
using the generated synopsis and review, create some social media post text. You
could add these new context variables as input variables, or we can add
a `SimpleMemory` to the chain to manage this context:

```dart
final openAiApiKey = Platform.environment['OPENAI_API_KEY'];
final llm = ChatOpenAI(apiKey: openAiApiKey);
// This is an LLMChain to write a synopsis given a title of a play
const synopsisTemplate = '''
You are a playwright. Given the title of play, it is your job to write a synopsis for that title.
Title: {title}
Era: {era}
Playwright: This is a synopsis for the above play:''';
final synopsisPromptTemplate = PromptTemplate.fromTemplate(synopsisTemplate);
final synopsisChain = LLMChain(
llm: llm,
prompt: synopsisPromptTemplate,
outputKey: 'synopsis',
);
// This is an LLMChain to write a review of a play given a synopsis
const reviewTemplate = '''
You are a play critic from the New York Times. Given the synopsis of play, it is your job to write a review for that play.
Play Synopsis:
{synopsis}
Review from a New York Times play critic of the above play:''';
final reviewPromptTemplate = PromptTemplate.fromTemplate(reviewTemplate);
final reviewChain = LLMChain(
llm: llm,
prompt: reviewPromptTemplate,
outputKey: 'review',
);
// This is an LLMChain to write a social post
const socialTemplate = '''
You are a social media manager for a theater company. Given the title of play, the era it is set in, the date,time and location, the synopsis of the play, and the review of the play, it is your job to write a social media post for that play.
Here is some context about the time and location of the play:
Date and Time: {time}
Location: {location}
Play Synopsis:
{synopsis}
Review from a New York Times play critic of the above play:
{review}
Social Media Post:''';
final socialPromptTemplate = PromptTemplate.fromTemplate(socialTemplate);
final socialChain = LLMChain(
llm: llm,
prompt: socialPromptTemplate,
outputKey: 'social_post_text',
);
// This is the overall chain where we run these three chains in sequence
final overallChain = SequentialChain(
memory: const SimpleMemory(
memories: {
'time': 'December 25th, 8pm PST',
'location': 'Theater in the Park'
},
),
chains: [synopsisChain, reviewChain, socialChain],
);
final review = await overallChain.run({
'title': 'Tragedy at sunset on the beach',
'era': 'Victorian England',
});
print(review);
```

> 🌅 Don't miss out on the mesmerizing production of "Tragedy at Sunset on the
> Beach" at Theater in the Park on December 25th at 8pm PST! 🎭✨ Transporting
> audiences to the captivating world of a Victorian beach resort in England,
> this gripping melodrama delves into the depths of human emotions, societal
> constraints, and the consequences of choices made in the face of desire.
>
> 💔 Follow the lives of three prominent families as their idyllic holiday
> takes a dark turn. Lady Adelaide, torn between duty and love; Lord Reginald,
> embodying societal expectations; and the enigmatic artist, Mr. Theodore, who
> radiates charm and mystery. Witness their intricate relationships unravel
> against the backdrop of a breathtaking sunset on the beach.
>
> 🤫 Secrets, hidden desires, and forbidden love abound in this riveting tale.
> The young and naive Miss Charlotte falls madly in love with a penniless poet,
> Mr. Edmund, leading to a ticking time bomb of societal expectations and
> fervent desires. And with the arrival of the mysterious Baron, disruption and
> suspense only escalate, pushing the families to the brink of destruction.
>
> ✨ "Tragedy at Sunset on the Beach" is a thought-provoking exploration of
> love, betrayal, and the consequences of choices made. This Victorian
> melodrama will captivate you from the moment the curtains rise, leaving you
> breathless until the shocking climax.
>
> ⭐️ The New York Times calls it a "mesmerizing production" that delves into
> the complexities of human emotions, societal constraints, and the devastating
> consequences of choices made in the face of desire.
>
> 🎟️ Get your tickets now for an unforgettable evening of theater that will
> leave you contemplating the power of love, societal expectations, and the
> fragility of happiness. Don't miss out on this captivating portrayal of
> tragedy at its most poignant. Book your seats today! #TragedyAtSunset
> #TheaterInthePark #VictorianMelodrama
8 changes: 4 additions & 4 deletions packages/langchain/lib/src/chains/llm_chain.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,21 @@ class LLMChain<LLMInput extends Object, LLMOptions extends LanguageModelOptions,
LLMOutput extends Object, ParserOutput extends Object> extends BaseChain {
/// {@macro llm_chain}
const LLMChain({
required this.prompt,
required this.llm,
required this.prompt,
this.outputKey = defaultOutputKey,
this.outputParser,
this.returnFinalOnly = true,
this.llmOptions,
super.memory,
});

/// Prompt object to use.
final BasePromptTemplate prompt;

/// Language model to call.
final BaseLanguageModel<LLMInput, LLMOptions, LLMOutput> llm;

/// Prompt object to use.
final BasePromptTemplate prompt;

/// Key to use for output.
final String outputKey;

Expand Down
8 changes: 4 additions & 4 deletions packages/langchain/lib/src/chains/sequential.dart
Original file line number Diff line number Diff line change
Expand Up @@ -182,11 +182,11 @@ class SequentialChain extends BaseChain {
class SimpleSequentialChain extends BaseChain {
/// {@macro simple_sequential_chain}
SimpleSequentialChain({
super.memory,
required this.chains,
this.trimOutputs = false,
super.memory,
final String inputKey = defaultInputKey,
final String outputKey = defaultOutputKey,
this.trimOutputs = false,
}) : inputKeys = {inputKey},
outputKeys = {outputKey} {
assert(_isChainValid());
Expand Down Expand Up @@ -236,10 +236,10 @@ class SimpleSequentialChain extends BaseChain {

@override
Future<ChainValues> callInternal(final ChainValues inputs) async {
String input = inputs[inputKeys.first];
dynamic input = inputs[inputKeys.first];
for (final chain in chains) {
input = await chain.run(input);
if (trimOutputs) {
if (trimOutputs && input is String) {
input = input.trim();
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/langchain/lib/src/documents/loaders/base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ abstract class BaseDocumentLoader {
Future<List<Document>> loadAndSplit({
final TextSplitter splitter = const RecursiveCharacterTextSplitter(),
}) async {
final docs = await lazyLoad().toList();
final docs = await load();
return splitter.splitDocuments(docs);
}
}

0 comments on commit b9693a4

Please sign in to comment.