Day 51 of 80

LangChain Fundamentals

Phase 6: Frameworks & Agents

What You'll Build Today

Welcome to Day 51! You have spent the last several weeks interacting with Large Language Models (LLMs) by sending raw text to an API and getting raw text back. You have built loops, managed history lists, and likely spent a lot of time fixing errors where you forgot a quotation mark in a formatted string.

Today, we introduce LangChain.

LangChain is a framework designed to simplify the creation of applications using LLMs. Think of it as a set of power tools that replaces your manual hand tools.

Today, you will rebuild your standard chatbot, but you will do it using the "LangChain Expression Language" (LCEL). By the end of this session, you will understand:

* PromptTemplates: Why hard-coding strings inside your Python logic is a bad idea and how to separate instructions from data.

* Output Parsers: Why dealing with raw API response objects is tedious and how to automatically extract just the text you need.

* LCEL (LangChain Expression Language): Why writing nested functions is hard to read and how to use the "pipe" syntax to create clean, readable data flows.

* Chains: How to link multiple AI actions together (like translating, then summarizing) without writing spaghetti code.

Let's clean up your workflow.

The Problem

To understand why LangChain exists, we need to look at the pain of writing "raw" code.

In previous lessons, when you wanted to build a specific tool—say, a bot that extracts a comma-separated list of groceries from a paragraph—you probably wrote code that looked like this:

import os

from openai import OpenAI

client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

user_input = "I need to buy apples, three jugs of milk, and a loaf of bread."

# 1. The Pain of Prompt Formatting # You have to manually concatenate strings. It's prone to spacing errors. # If you want to change the "system" behavior, you have to dig into this logic.

messages = [

{"role": "system", "content": "You are a helpful assistant. Extract items from the text. Return them as a comma-separated list ONLY. No other text."},

{"role": "user", "content": user_input}

]

# 2. The Pain of API Complexity # You have to remember exactly which model version to use and the specific parameter names.

response = client.chat.completions.create(

model="gpt-4o",

messages=messages,

temperature=0

)

# 3. The Pain of Parsing # The response is a complex object. You have to dig deep to find the content.

raw_content = response.choices[0].message.content

# 4. The Pain of Post-Processing # Even with good prompting, the model might return "Here is your list: apples, milk, bread" # forcing you to write cleanup code.

clean_list = raw_content.replace("Here is your list:", "").strip().split(",")

print(clean_list)

Why this hurts:
  • Fragility: If OpenAI changes their API structure (which they do), your code breaks.
  • Verbosity: It took us about 15 lines of code just to ask a simple question.
  • Hard to Chain: Imagine if you wanted to take that list of groceries, translate it to Spanish, and then sort it alphabetically. You would need three separate API calls, three separate message lists, and three separate parsing blocks. It becomes a mess of variables very quickly.
  • There has to be a way to treat an LLM interaction like a simple function: Input goes in, processed result comes out.

    Let's Build It

    We are going to replicate the logic above, but we will do it the LangChain way. We will break this down into three components: The Prompt, The Model, and The Parser. Then, we will chain them together.

    Prerequisites

    You will need to install the LangChain libraries.

    pip install langchain langchain-openai

    Step 1: The Model

    First, we create an object that represents our LLM. In LangChain, this is standardized. Whether you use OpenAI, Anthropic, or an open-source model, the commands you use to talk to it will look exactly the same.

    import os
    

    from langchain_openai import ChatOpenAI

    # Ensure your API Key is set in your environment variables # os.environ["OPENAI_API_KEY"] = "sk-..." # Initialize the model # We set temperature to 0 for consistent results

    model = ChatOpenAI(model="gpt-4o", temperature=0)

    # We can invoke it directly, but we usually don't. # response = model.invoke("Hello!") # print(response)

    Step 2: The Prompt Template

    Instead of using f-strings or manual string concatenation, LangChain uses PromptTemplates. This treats your prompt like a reusable form letter. You define the structure once, and fill in the blanks (variables) later.

    from langchain_core.prompts import ChatPromptTemplate
    
    # Create a template with placeholders
    # {topic} is a variable we will fill in later
    

    template = ChatPromptTemplate.from_template(

    "Tell me a short, one-sentence joke about {topic}."

    )

    # Let's see what this looks like when we fill it in

    formatted_prompt = template.invoke({"topic": "ice cream"})

    print("--- Formatted Prompt ---")

    print(formatted_prompt)

    Why this matters: This separates your instructions from your user input. You can change the prompt wording without touching the code that runs the prompt.

    Step 3: The Output Parser

    When an LLM responds, it gives us a AIMessage object containing metadata (token usage, finish reason, etc.). Usually, we just want the string text. The StrOutputParser handles this cleanup automatically.

    from langchain_core.output_parsers import StrOutputParser
    
    

    parser = StrOutputParser()

    Step 4: The Chain (LCEL)

    This is the most important concept of the day. LangChain Expression Language (LCEL) allows us to chain these components together using the pipe operator (|).

    Think of it like a factory assembly line:

  • Raw data enters the Prompt Template.
  • Formatted prompt moves to the Model.
  • Raw model response moves to the Parser.
  • Clean string comes out the end.
  • # The syntax is: source | step1 | step2 | step3
    

    chain = template | model | parser

    # Now we invoke the whole chain with our input dictionary

    result = chain.invoke({"topic": "chickens"})

    print("--- Final Result ---")

    print(result)

    Output:
    --- Final Result ---
    

    Why did the chicken join the band? Because it had the drumsticks!

    Look how clean that is! No response.choices[0].message.content. Just chain.invoke.

    Step 5: A More Complex Example

    Let's rebuild the grocery list extractor from "The Problem" section using this new method.

    from langchain_openai import ChatOpenAI
    

    from langchain_core.prompts import ChatPromptTemplate

    from langchain_core.output_parsers import StrOutputParser

    # 1. Define the Model

    model = ChatOpenAI(model="gpt-4o", temperature=0)

    # 2. Define the Prompt # We use 'system' and 'user' tuples to be specific about roles

    prompt = ChatPromptTemplate.from_messages([

    ("system", "You are a helpful assistant. Extract items from the text. Return them as a comma-separated list ONLY. No other text."),

    ("user", "{text_input}")

    ])

    # 3. Define the Parser

    parser = StrOutputParser()

    # 4. Create the Chain

    grocery_chain = prompt | model | parser

    # 5. Run it

    user_text = "I need to buy apples, three jugs of milk, and a loaf of bread."

    result = grocery_chain.invoke({"text_input": user_text})

    print(result)

    # Output: apples, milk, bread

    Step 6: Common Mistakes

  • Missing Keys: If your prompt expects {topic} but you invoke the chain with {"subject": "cats"}, it will crash. The dictionary keys must match the template variables.
  • API Key Issues: LangChain still needs your OpenAI API key. Ensure it is in your environment variables.
  • Object vs String: If you forget the parser in your chain (chain = prompt | model), your result will be an AIMessage object, not a string.
  • Now You Try

    It is time to get your hands dirty. Take the "Complex Example" code above (Step 5) and modify it to complete the following tasks.

    1. The Translator

    Modify the prompt template so that instead of extracting groceries, it acts as a translator.

    * System: "You are a professional translator. Translate the user's text into French."

    * Input: "I love learning about Artificial Intelligence."

    * Goal: The output should be the French translation.

    2. The Code Fixer

    Change the model to gpt-3.5-turbo (or keep gpt-4o if you prefer). Change the prompt to take a snippet of broken Python code and return a fixed version.

    * Input: print "Hello World" (This is Python 2 syntax, invalid in Python 3).

    * Goal: The model should return print("Hello World").

    3. Multi-Variable Prompt

    Create a prompt template that takes two variables: {style} and {topic}.

    * Template: "Write a {style} poem about {topic}."

    * Invoke: Pass a dictionary with both keys: {"style": "haiku", "topic": "databases"}.

    Challenge Project: The Sequential Processor

    Your challenge is to build a processing pipeline that performs three distinct operations on a single piece of text. In raw Python, this would be a nightmare of nested calls. In LangChain, it should be elegant.

    The Scenario:

    You are building a tool for an international news agency. You receive raw news blurbs in various languages. You need to standardize them.

    Requirements:
  • Create Chain A: Takes raw text -> Translates it to English.
  • Create Chain B: Takes English text -> Summarizes it into one sentence.
  • Create Chain C: Takes a summary -> Extracts 3 key tags/topics (comma separated).
  • Combine them into a single master_chain using the pipe | operator.
  • Run the master chain on this input: "La inteligencia artificial está transformando la industria tecnológica a un ritmo sin precedentes."
  • Hint:

    You can pipe chains into other chains!

    master_chain = chain_a | chain_b | chain_c Example Output:
    AI, Technology, Transformation
    

    (Note: The intermediate steps—translation and summary—won't be printed, only the final result of the last link in the chain. This is expected.)

    What You Learned

    Today you moved from "scripting" to "engineering" your AI interactions.

    * LCEL (LangChain Expression Language): You learned that | allows you to compose complex logic linearly.

    * Abstraction: You learned that ChatOpenAI hides the messy API details, and StrOutputParser cleans up the response automatically.

    * Templates: You learned to treat prompts as dynamic templates rather than hard-coded strings.

    Why This Matters:

    In the real world, AI applications aren't just one question and answer. They are pipelines: Retrieve data -> Format it -> Ask AI -> Parse Answer -> Save to Database. Doing this with raw API calls results in code that is impossible to maintain. LangChain gives you the structure to build massive, complex applications that remain readable.

    Tomorrow: We tackle the biggest buzzword in AI right now: RAG (Retrieval Augmented Generation). You will learn how to make your chatbot read your own PDF documents and answer questions about them.