Langchain : Chains

What is a Chain ?
Chains are like a series of steps or actions. These steps could involve using an AI model, a tool, or processing some data. The main method for creating these chains is called LCEL. LCEL is awesome for making your own chains of steps, but sometimes you just want to use ready-made chains. LangChain supports two kinds of ready-made chains:
- Chains made with LCEL: These chains use LCEL to put the steps together, and LangChain has an easy way to make them.
- [Old-fashioned] Chains: These chains are made using an older method that doesn't use LCEL. They are standalone and not built with the new
system. The chains constructed in the "ChatGPT and LangChain: The Complete Developer's Masterclass" training are considered outdated.
We're not going to work on them.
Example of chain in the first Jupyter notebook.
from langchain_openai import AzureChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
import os
# SECURE THIS KEY!
os.environ["AZURE_OPENAI_API_KEY"] = ""
os.environ["AZURE_OPENAI_ENDPOINT"] = "https://azqoreai.openai.azure.com/"
os.environ["AZURE_OPENAI_CHAT_DEPLOYMENT_NAME"] = "gpt-35-turbo-16k_azqore_ai"
os.environ["AZURE_OPENAI_API_VERSION"] = "2024-02-01"
model = AzureChatOpenAI(
openai_api_version=os.environ["AZURE_OPENAI_API_VERSION"],
azure_deployment=os.environ["AZURE_OPENAI_CHAT_DEPLOYMENT_NAME"],
)
code_prompt_template = ChatPromptTemplate.from_messages([
("system", "Your are a software developer specialized in {language} "),
("human", "Write a very short function that will {task}. Make sure the code compiles !")
])
output_parser= StrOutputParser()
chain = code_prompt_template | model |output_parser
chain.invoke({
"language": "python",
"task": "return a fibonacci sequence using recursion",
})
--------------------------------
'Here is a short function that returns a Fibonacci sequence using recursion in Python:\n\n```python\ndef
fibonacci(n):\n
if n <= 1:\n
return n\n
else:\n
return fibonacci(n-1) + fibonacci(n-2)
\n```\n\nIn this code, the base case is when `n` is less than or equal to 1, where we simply return `n`. For
any other value of `n`, we recursively call the `fibonacci` function with `n-1` and `n-2`, and return the sum
of the two recursive calls.\n\nTo use this function, simply call it with the desired index of the Fibonacci
sequence:\n\n```python\nprint(fibonacci(5)) # Output: 5\nprint(fibonacci(10)) # Output: 55\nprint(fibonacci
(15)) # Output: 610\n```\n\nNote that since this implementation uses recursion, it may become inefficient for
large values of `n` due to repeated calculations. To optimize it, you can use memoization or dynamic
programming techniques.'Imagine a chain like a series of steps you follow to get a job done. Each step in this chain talks to the next one. It could be asking a computer program to do something, using a tool, or dealing with some data.The most important part of this chain is the model. The model takes what the previous step gave it, does its job, and then passes its result on to the next step. A chain uses a PromptTemplate, which is like a guide or template to help each step know what to do. Sometimes, this guide even comes with a default setting, like in the SQL chain. Good to know: Langchain lets you run different component in parallel. We are not going to discuss it here, but you can find examples in their documentation
You can try running the example in the training folder on your own. There are many interesting points to discuss.
- First, we're using AzureChatOpenAI and ChatPromptTemplate. As we learned before, this means the way we send and receive messages will follow a specific format (system, human, and AI). This is visible line 18 & 19.
- We're using the LCEL format to build a series of steps, one after another. You can see this on line 25 where the | (pipe) operator is used. This operator takes the result from one step and sends it to the next step in the chain
- If you look carefully line 18 & 19, you'll see that the chain requires specific information - the language and the task. If you forget to provide these when you invoke the chain (line 26), you'll get an error message.
- Each component of the chain needs a certain type of input and gives back a different type of output. We'll talk more about this in the next section
Input and Output
LangChain provides an easy-to-understand diagram that shows what each part does. For example in the following table, you can see that a "Prompt" creates something called a "PromptValue." Then you can also see that a "ChatModel" needs a "PromptValue" to work. The ChatModel produce a ChatMessage, that OutputParser requires as an input. This makes everything flow smoothly.

All components show what kind of data they need to start (input_schema) and what kind of data they give back when done (output_schema):
- input_schema: It's like a template created automatically based on what information the program needs to work.
- output_schema: It's like a template created automatically based on what information the program gives you after it's done.
If you run the code below, you will see the template for the PromptInput:
schema_representation = code_prompt_template.input_schema.schema()
print(schema_representation)
{
"title": "PromptInput",
"type": "object",
"properties": {
"language": {
"title": "Language",
"type": "string"
},
"task": {
"title": "Task",
"type": "string"
}
}
}Predefined Chains
LCEL is super flexible, but LangChain has some handy built-in chains you can use. Here's a quick table that explains all LCEL chain creators:
- Chain Constructor: This is the name of the function that creates the chain. These are methods that give you LCEL Runnables. There are also links to more details in the API docs.
- Function Calling: This tells you if you need to use OpenAI's function calling for this chain (more on this later).
- Other Tools: Any additional tools you might need for the chain are listed here (more on this later).
- When to Use: Langchain's advice on the best times to use each chain

Combining predefined chains
You can link different chains together. Let's look at an example in the second Jupyter notebook. First, Langchain will gather information from Wikipedia using a "retriever" . Then, it will send the info returned by the retriever to another chain that uses a language model (llm). Don't worry if you don't know what a retriever is yet – we'll explain it in another lesson.
The key thing to understand is that when you check out the create_retrieval_chain instructions (or the table above), you'll see it needs a retriever to work. This retriever will pull data from Wikipedia and return it as a list of Documents. These documents will then go to the second chain, created with create_stuff_documents_chain. This chain uses the LLM. You can see in the table above that this type of chain takes a list of documents, turns them into a prompt, and sends the prompt to the llm. Finally, the StrOutputParser changes the LLM's output, which is usually in complex formats like JSON, into simple strings
This explains how linking things together can create a final result. Usually, the last step involves calling the llm, which tends to be slower than the other steps
model = AzureChatOpenAI(
openai_api_version=os.environ["AZURE_OPENAI_API_VERSION"],
azure_deployment=os.environ["AZURE_OPENAI_CHAT_DEPLOYMENT_NAME"],
)
output_parser= StrOutputParser()
#this retriever (more on this later) let us access Wikipedia
retriever = WikipediaRetriever()
prompt_template = ChatPromptTemplate.from_messages([
("system", "You are a highly efficient assistant that excels at creating concise and comprehensive
summaries."),
("human", "Create a summary in 10 lines about this topic {input} using only the data provided here :
{context}")
])
#this chain will invoke the llm passing the documents retrieved from from wikipedia as input in the "context"
variable
llm_chain = create_stuff_documents_chain(model, prompt_template)
#this chain will invoke the wikipedia retriever then pass the result to llm_chain
chain = create_retrieval_chain(retriever, llm_chain)
output = chain.invoke({
"input": "euro 2024",
})
output_parser.invoke(output['answer'])
----------------------------------------------------
'The 2024 UEFA European Football Championship, also known as Euro 2024, is the 17th edition of the tournament
and is being held in Germany from 14 June to 14 July 2024. The tournament features 24 teams, including Georgia
making their debut in the European Championship finals. This is the third time matches are played on German
territory, with Leipzig hosting for the first time in what was formerly East Germany. Germany is the solo host
nation for the first time since the 2006 FIFA World Cup. The tournament returned to its regular four-year cycle
after being postponed in 2020 due to the COVID-19 pandemic. Italy, the defending champions, were eliminated in
the round of 16 by Switzerland. The tournament follows a knockout format, with extra time and penalty shootouts
used to determine winners in case of a tie. The final will be held at Olympiastadion in Berlin. The qualifying
tournament for Euro 2024 took place from March 2023 to March 2024, with the top two teams from each group and
the four best third-placed teams joining host nation Germany in the final tournament.'If you run the following code you will print the list of documents that is passed down through the chain by the retriever. Here’s something to keep in mind about documents that will be helpful later when we talk about RAG: they have two important parts. One part is called metadata, and it’s like a little library of extra details about the document, such as the page number, the book it’s from, or who’s allowed to see it. The other part is the content of the document, which is basically what’s written in it (here it's called page_content)
prompt_template = ChatPromptTemplate.from_messages([
("system", "You are a highly efficient assistant that excels at creating concise and comprehensive
summaries."),
("human", "Create a summary in 10 lines about this topic {input} using only the data provided here :
{context}")
])
#this chain will invoke the llm passing the documents retrieved from from wikipedia as input in the "context"
variable
chain = create_retrieval_chain(retriever, prompt_template)
output = chain.invoke({
"input": "euro 2024",
})
output["context"]
------------------------------------------
[Document(metadata={'title': 'UEFA Euro 2024', 'summary': "The 2024 UEFA European Football Championship,
commonly referred to as UEFA Euro 2024 (stylised as UEFA EURO 2024), or simply Euro 2024, is the ongoing 17th
edition of the UEFA European Championship, the quadrennial international football championship organised by
UEFA for the European men's national teams of its member associations. Germany is hosting the tournament, which
is taking place from 14 June to 14 July 2024. The tournament comprises 24 teams, with Georgia being the only
team making their European Championship finals debut. \nIt is the third time that European Championship matches
are played on German territory and the second time in reunified Germany, as West Germany hosted the
tournament's 1988 edition, and four matches of the multi-national Euro 2020 were played in Munich. It is the
first time the competition is held in what was formerly East Germany, with Leipzig as a host city, as well as
the first major tournament since the 2006 FIFA World Cup that Germany serves as a solo host nation. The
tournament returned to its usual four-year cycle after the 2020 edition was postponed to 2021 due to the COVID-
19 pandemic.\nItaly were the defending champions, having won the 2020 final against England on penalties, but
were eliminated in the round of 16 by Switzerland.", 'source': 'https://en.wikipedia.org/wiki/UEFA_Euro_2024'},
page_content='The 2024 UEFA European Football Championship, commonly referred to as UEFA Euro 2024 (stylised as
UEFA EURO 2024), or simply Euro 2024, is the ongoing 17th edition of the UEFA European Championship, the
quadrennial international football championship organised by UEFA for the European men\'s national teams of
its member associations. Germany is hosting the tournament, which is taking place from 14 June to 14 July 2024.
The tournament comprises 24 teams, with Georgia being the only team making their European Championship finals
debut. \nIt is the third time that European Championship matches are played on German territory and the second
time in reunified Germany, as West Germany hosted the tournament\'s 1988 edition, and four matches of the multi-
national Euro 2020 were played in Munich. It is the first time the competition is held in what was formerly
East Germany, with Leipzig as a host city, as well as the first major tournament since the 2006 FIFA World Cup
that Germany serves as a solo host nation. The tournament returned to its usual four-year cycle after the 2020
edition was postponed to 2021 due to the COVID-19 pandemic.\nItaly were the defending champions, having won the
2020 final against England on penalties, but were eliminated in the round of 16 by Switzerland.\n\n\n== Host
selection ==\n\nOn 8 March 2017, UEFA announced that two countries, Germany and Turkey, had announced their
intentions to host the tournament before the deadline of 3 March 2017.\nThe host was chosen by the UEFA
Executive Committee in a confidential ballot, needing only a simple majority of votes to win. If the votes were
equal, the final decision rested with UEFA president Aleksander eferin. Out of the 20 members on the UEFA
Executive Committee, Reinhard Grindel (Germany) and Servet Yardmc (Turkey) could not vote because they were
ineligible. Lars-Christer Olsson (Sweden) was also absent due to illness. In total, 17 members were able to
vote.\nThe host was selected on 27 September 2018 in Nyon, Switzerland. Germany initially planned to fully host
Euro 2020, although had not announced any firm interest by May 2012.\n\n\n== Venues ==\nGermany had a wide
choice of stadiums that satisfied UEFA\'s minimum capacity requirement of 30,000 seats for European
Championship matches.\nOf the ten venues selected for Euro 2024, nine were used for the 2006 FIFA World Cup:Berlin, Dortmund, Munich, Cologne, Stuttgart, Hamburg, Leipzig, Frankfurt, and Gelsenkirchen. Düsseldorf, which
was not used in 2006 but had previously been used for the 1974 FIFA World Cup and UEFA Euro 1988, will serve as
the tenth venue; conversely, Hanover, Nuremberg and Kaiserslautern, host cities in 2006 (in addition to 1974
and 1988 in Hanover\'s case), will not be used for this championship. Munich, the site of the first game of
UEFA Euro 2024, was also a host city at the multi-national UEFA Euro 2020 tournament, hosting four matches
(three involving Germany) in front of a greatly reduced number of spectators due to COVID-19 restrictions.
\nVarious other stadiums, such as those in Bremen and Mönchengladbach, were not selected. The area with the
highest number of venues at UEFA Euro 2024 is the Rhine-Ruhr metropolitan region in the state of North Rhine-
Westphalia, with four of the ten host cities (Dortmund, Düsseldorf, Gelsenkirchen and Cologne).\n\n\n=== Team
base camps ===\nEach team chose a "team base camp" for its stay between the matches. The teams will train and
reside in these locations throughout the tournament, travelling to games staged away from their bases. The
"team base camp" needs to be in Germany.\n\n\n=== Ticketing ===\nTickets for the venues were sold directly by
UEFA via its website, or distributed by the football associations of the 24 finalists. Ticket sales started on
3 October 2023. More than 80% of 2.7 million tickets for the 51 tournament matches were available for the fans
of the participating teams and the general public. Fans of each participating team allocated 10,000 tickets
for'),
Document(metadata={'title': 'UEFA Euro 2024 knockout stage', 'summary': 'The knockout stage of UEFA Euro 2024
began on 29 June 2024 with the round of 16 and will end on 14 July 2024 with the final at Olympiastadion in
Berlin, Germany.\nAll times listed are Central European Summer Time (UTC+2)\n\n', 'source': 'https://en.
wikipedia.org/wiki/UEFA_Euro_2024_knockout_stage'}, page_content='The knockout stage of UEFA Euro 2024 began on
29 June 2024 with the round of 16 and will end on 14 July 2024 with the final at Olympiastadion in Berlin,
Germany.\nAll times listed are Central European Summer Time (UTC+2)\n\n\n== Format ==\nIn the knockout stage,
if a match is level at the end of normal playing time, extra time is played (two periods of 15 minutes each).
If still tied after extra time, the match is decided by a penalty shoot-out.\nUEFA set out the following
schedule for the round of 16:\n\nMatch 1: Winner Group B vs 3rd Group A/D/E/F\nMatch 2: Winner Group A vs
Runner-up Group C\nMatch 3: Winner Group F vs 3rd Group A/B/C\nMatch 4: Runner-up Group D vs Runner-up Group
E\nMatch 5: Winner Group E vs 3rd Group A/B/C/D\nMatch 6: Winner Group D vs Runner-up Group F\nMatch 7: Winner
Group C vs 3rd Group D/E/F\nMatch 8: Runner-up Group A vs Runner-up Group B\nAs with every tournament since
UEFA Euro 1984, there will be no third place play-off.\n\n\n=== Combinations of matches in the round of 16
===\nThe specific match-ups involving the third-placed teams depended on which four third-placed teams
qualified for the round of 16:\n\n\n== Qualified teams ==\nThe top two placed teams from each of the six
groups, along with the four best-placed third teams, qualified for the knockout stage.\n\n\n== Bracket
==\n\n\n== Round of 16 ==\n\n\n=== Switzerland vs Italy ===\n\n\n=== Germany vs Denmark ===\nThis was a rematch
of the UEFA Euro 1992 final, which Denmark won 2–0.\nIn the 35th minute, the match was suspended due to adverse
weather conditions (thunderstorms and heavy rain) in the vicinity of the stadium. Play was suspended for about
25 minutes before resuming at 21:59.\n\n\n=== England vs Slovakia ===\n\n\n=== Spain vs Georgia ===\n\n\n===
France vs Belgium ===\n\n\n=== Portugal vs Slovenia ===\n\n\n=== Romania vs Netherlands ===\n\n\n=== Austria vs
Turkey ===\n\n\n== Quarter-finals ==\n\n\n=== Spain vs Germany ===\nThe sides previously met in the UEFA Euro
2008 final, which Spain won 1–0.\n\n\n=== Portugal vs France ===\nThe sides previously met in the UEFA Euro
2016 final, where Portugal prevailed against the hosts 1–0 on extra time.\n\n\n=== England vs Switzerland
===\n\n\n=== Netherlands vs Turkey ===\n\n\n== Semi-finals ==\n\n\n=== Winner Match 45 vs Winner Match 46
===\n\n\n=== Winner Match 47 vs Winner Match 48 ===\n\n\n== Final ==\n\n\n== References ==\n\n\n== External
links ==\nOfficial website'),
Document(metadata={'title': 'UEFA Euro 2024 qualifying', 'summary': "The UEFA Euro 2024 qualifying tournament
was a football competition that was played from March 2023 to March 2024 to determine the 23 UEFA member men's
national teams that would join the automatically qualified host team Germany in the UEFA Euro 2024 final
tournament. The competition was linked with the 2022–23 UEFA Nations League, which gave countries a secondary
route to qualify for the final tournament.\nA total of 53 UEFA member associations entered the qualifying
process. The draw for the qualifying group stage took place at the Festhalle in Frankfurt on 9 October 2022.",
'source': 'https://en.wikipedia.org/wiki/UEFA_Euro_2024_qualifying'}, page_content="The UEFA Euro 2024
qualifying tournament was a football competition that was played from March 2023 to March 2024 to determine the
23 UEFA member men's national teams that would join the automatically qualified host team Germany in the UEFA
Euro 2024 final tournament. The competition was linked with the 2022–23 UEFA Nations League, which gave
countries a secondary route to qualify for the final tournament.\nA total of 53 UEFA member associations
entered the qualifying process. The draw for the qualifying group stage took place at the Festhalle in
Frankfurt on 9 October 2022.\n\n\n== Qualified teams ==\n\n\n== Format ==\nThe format was similar to the UEFA
Euro 2020 qualifying competition: the group stage decided 20 of the 23 teams that would advance to the final
tournament to join host Germany. The 53 UEFA member associations were divided into ten groups, with seven
groups containing five teams and three containing six teams. The draw for the qualifying group stage took place
on 9 October 2022, after conclusion of the league phase of the 2022–23 UEFA Nations League. The four UEFA
Nations League Finals participants were drawn into groups of five teams (so they were able to compete in the
Nations League Finals in June 2023). The qualifying group stage was played in a home-and-away, round-robin
format on double matchdays in March, June, September, October, and November 2023. The winners and runners-up
from the ten groups qualified directly to the final tournament.\nFollowing the qualifying group stage, the
remaining three teams were decided through the play-offs, held in March 2024. Twelve teams were selected based
entirely on their performance in the 2022–23 UEFA Nations League. These teams were divided into three paths,
each containing four teams, with one team from each path qualifying for the final tournament. The group winners
of Nations Leagues A, B, and C automatically qualified for the play-off path of their league, unless they
qualified for the final tournament via the qualifying group stage. If a group winner had already qualified
through the qualifying group stage, they would be replaced by the next best-ranked team in the same league.
However, if there were not enough non-qualified teams in the same league, then the spot would go first to thebest-ranked group winner of League D, unless that team had already qualified for the final tournament. The
remaining slots were then allocated to the next best team in the Nations League overall ranking. However, group
winners of Leagues B and C could not face teams from a higher league.\nThe three play-off paths each featured
two single-leg semi-finals, and one single-leg final. In the semi-finals, the best-ranked team hosted the
lowest-ranked team, and the second-ranked team hosted the third-ranked team. The host of the final was drawn
between the winners of the semi-final pairings. The three play-off path winners joined the twenty teams that
already qualified for the final tournament through the group stage.\n\n\n=== Tiebreakers for group ranking
===\nIf two or more teams were equal on points on completion of the group matches, the following tie-breaking
criteria were applied:\n\nHigher number of points obtained in the matches played among the teams in question;
\nSuperior goal difference in matches played among the teams in question;\nHigher number of goals scored in the
matches played among the teams in question;\nIf, after having applied criteria 1 to 3, teams still had an equal
ranking, criteria 1 to 3 were reapplied exclusively to the matches between the teams in question to determine
their final rankings. If this procedure did not lead to a decision, criteria 5 to 11 applied;\nSuperior goal
difference in all group matches;\nHigher number of goals scored in all group matches;\nHigher number of away
goals scored in all group matches;\nHigher number of wins in all group matches;\nHigher number of away wins in
all group matches;\nFair play conduct in all group matches (1 point for a single yellow card")]Combining components using LCEL
The same result can be obtained using LCEL instead of predefined chains :
prompt_template = ChatPromptTemplate.from_messages([
("system", "You are a highly efficient assistant that excels at creating concise and comprehensive
summaries."),
("human", "Create a summary in 10 lines about this topic {input} using only the data provided here :
{context}")
])
chain = (
{"context": retriever, "input": RunnablePassthrough()}
| prompt_template
| model
| output_parser
)
chain.invoke("euro 2024")
-------------------------------------------
'UEFA Euro 2024 is the 17th edition of the UEFA European Championship, hosted by Germany from 14 June to 14
July 2024. The tournament features 24 teams, with Georgia making their European Championship finals debut. This
is the third time European Championship matches are played in Germany and the first time in what was formerly
East Germany. Leipzig is one of the host cities. It is the first major tournament since the 2006 FIFA World Cup
that Germany serves as a solo host nation. Italy, the defending champions, were eliminated in the round of 16
by Switzerland. The knockout stage of Euro 2024 began on 29 June 2024 and will end with the final at
Olympiastadion in Berlin on 14 July 2024. The qualifying tournament for Euro 2024 was played from March 2023 to
March 2024, with 23 teams joining host Germany in the final tournament. The competition was linked with the
2022–23 UEFA Nations League.'The RunnablePassthrough() method makes sure that any info you provide when invoking the chain gets passed along correctly to the PromptTemplate and then to the model. Think of it like this: when you run the chain, the input (like "euro 2024") gets stored in a special map with a key called "input," which all other parts of the process can use. In the next section, we'll talk about how Lanchain keeps track of these variables
Variable management in LangChain
Each component takes in data as input (input_data), and gives out data output_data). The data is saved in a map as a key/value pair, like a word and its definition in a dictionary. When a component starts working, it first looks in the map to find the info it needs by its name. If the map doesn't have the info (key), an error pops up, and everything stops. Once the needed info is found, the part does its job and then saves the new info in the map with a specific key for its output.

In our example, the prompt template has a variable called input_variable that contains the key to the data expected. The associated schema displays the
types.
print("Input variables :\t{}\n".format(prompt_template.input_variables))
print("Input schema :\t{}\n".format(prompt_template.input_schema.schema_json()))
-----------------------------------
Input variables : ['context', 'input']
Input schema : {"title": "PromptInput", "type": "object", "properties": {"context": {"title": "Context",
"type": "string"}, "input": {"title": "Input", "type": "string"}}}The same idea applies to what comes out of this. The output we're looking for is called AzureChatOpenAIOutput, and it can be any type of message under 'AIMessage', 'HumanMessage', or 'ChatMessage'. We talked about this in the last lesson, and it's because we're using AzureChatOpenAI and ChatPromptTemplate
model.output_schema.schema_json()
----------------------------------------
'{"title": "AzureChatOpenAIOutput", "anyOf": [{"$ref": "#/definitions/AIMessage"}, {"$ref": "#/definitions
/HumanMessage"}, {"$ref": "#/definitions/ChatMessage"}, {"$ref": "#/definitions/SystemMessage"}, {"$ref": "#
/definitions/FunctionMessage"}, {"$ref": "#/definitions/ToolMessage"}], ....Exercices
- Adapt the example to connect to OpenAI API instead of Azure.
- Try to combine two chains to create a unit test for the function that produces a Fibonacci sequence, as shown in the first example
- Try to implement the ChatPerplexity
- Tweak the input variables names and see how it reacts
Code