Generative AI: LangChain

Learning Hub

A structured curriculum for mastering Generative AI with LangChain

This site helps learners master Generative AI with strong foundations and practical building approaches. From LangChain basics to enterprise RAG systems - your journey to AI expertise starts here.

Home

Lesson 3: LangChain Components & Setup

Lesson 3 of 5
From concepts to code

We now translate the architecture from Lesson 2 into working practice—installing LangChain, invoking models, composing runnables, and adding structure.

Learning Objectives

  • Environment Readiness: Install LangChain + provider packages with clean API key handling.
  • Primitive Literacy: Know when to choose a direct model call vs. a chain vs. an agent.
  • Composable Pipelines: Build LCEL (`|`) pipelines that remain inspectable and testable.
  • Structured Outputs: Leverage parsers (e.g., Pydantic) early to enforce schema guarantees.
  • Abstraction Trade‑offs: Articulate benefits vs. overhead compared to raw provider SDKs.

1. Core Architecture Snapshot

LangChain centers around composable primitives:

Primitive Purpose Typical Examples
LLM / Chat Model Core text generation interface ChatOpenAI, ChatAnthropic
Prompt / PromptTemplate Parameterized input formatting System + user message templates
Chain / Runnable Execution pipeline (can branch/compose) Prompt → LLM, multi-step workflows
Agent Dynamic decision-maker that selects tools Tool-using conversational assistant
Tool External capability invoked by an agent Web search, DB query, calculator
Memory Persists conversational or contextual state Buffer, summary, vector store memory
Output Parser Structures raw model text into objects Pydantic parser, JSON schema parser

The mental model: Inputs → (Prompt Formatting) → LLM Call(s) → (Parsing / Post-processing) → Output.


2. Installation & Environment

Python Version

Use Python 3.9+ (3.10–3.12 recommended for ecosystem compatibility).

Install Core Packages

1
2
3
4
5
pip install langchain
pip install langchain-openai langchain-anthropic langchain-community
# Optional extras
pip install langchain-experimental
pip install python-dotenv pydantic

Environment Variables

Create a .env file (never commit real keys):

1
2
OPENAI_API_KEY=your_openai_api_key_here
ANTHROPIC_API_KEY=your_anthropic_api_key_here

Load them in Python:

1
2
from dotenv import load_dotenv
load_dotenv()

3. First Minimal Chat Invocation

1
2
3
4
5
6
7
8
9
10
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain.schema import HumanMessage

load_dotenv()

llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.7)
response = llm.invoke([HumanMessage(content="Explain quantum computing in one sentence.")])
print(response.content)

Key Idea: invoke() accepts a list of messages for chat models; behind the scenes LangChain normalizes provider differences.


4. Prompt Templates and Chaining

LangChain encourages separating template from model:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from langchain.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI

prompt = ChatPromptTemplate.from_template(
    "Summarize the following text in {word_count} words or less:\n\n{text}" )

llm = ChatOpenAI(model="gpt-3.5-turbo")
chain = prompt | llm  # Runnable composition

text_to_summarize = """
Artificial intelligence (AI) has transformed numerous industries by enabling
machines to perform tasks that typically require human intelligence..."""

result = chain.invoke({"text": text_to_summarize, "word_count": 40})
print(result.content)

Why |? In LangChain v0.3 the runnable protocol standardizes synchronous / async execution and streaming across composable steps.


5. Structured Output with Pydantic

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from langchain.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field

class Summary(BaseModel):
    summary: str = Field(description="Brief summary of the text")
    key_points: list[str] = Field(description="List of 3-5 key points")
    word_count: int = Field(description="Word count of summary")

parser = PydanticOutputParser(pydantic_object=Summary)

prompt = ChatPromptTemplate.from_template(
    "Summarize the following text and return JSON with fields: summary, key_points, word_count.\n\n{text}\n\n{format_instructions}"
)

llm = ChatOpenAI(model="gpt-3.5-turbo")
chain = prompt | llm | parser

result = chain.invoke({
    "text": text_to_summarize,
    "format_instructions": parser.get_format_instructions()
})
print(result.summary)
print(result.key_points)
print(result.word_count)

6. Expanding to Multi-step Chains

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from langchain.prompts import PromptTemplate, ChatPromptTemplate
from langchain.chains import LLMChain, SimpleSequentialChain
from langchain_openai import ChatOpenAI

facts_chain = LLMChain(
    llm=ChatOpenAI(),
    prompt=PromptTemplate(input_variables=["topic"], template="Generate 5 concise facts about {topic}.")
)
quiz_chain = LLMChain(
    llm=ChatOpenAI(),
    prompt=PromptTemplate(input_variables=["facts"], template="Turn these facts into a short quiz:\n{facts}")
)
workflow = SimpleSequentialChain(chains=[facts_chain, quiz_chain])
quiz = workflow.run("artificial intelligence")
print(quiz)

Takeaway: Higher-order chains let you encapsulate logic while retaining transparency.


7. Direct API vs. LangChain Abstraction

Direct OpenAI call (manual formatting):

1
2
3
4
5
6
7
8
import openai, os
openai.api_key = os.getenv("OPENAI_API_KEY")
resp = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=[{"role": "system", "content": "You are a helpful assistant."},
              {"role": "user", "content": "Explain machine learning."}]
)
print(resp.choices[0].message.content)

LangChain version:

1
2
3
4
5
6
7
8
9
from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant."),
    ("user", "Explain {topic}."),
])
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.7)
chain = prompt | llm
print(chain.invoke({"topic": "machine learning"}).content)

Benefits: Swappable models, reusable prompts, richer tooling (retries, caching, tracing via LangSmith).


8. Ecosystem Snapshot

Category Examples
Vector Stores Pinecone, Chroma, FAISS, Weaviate
Document Loaders PDF, HTML, Web, CSV, Notion
Memory Buffer, Summary, Vector store-backed
Monitoring LangSmith, W&B
Embeddings OpenAI, HuggingFace, Instructor, Cohere

9. Best Practices Starter

  1. Use environment variables for keys (never hard-code).
  2. Keep prompts versioned when iterating (treat like code).
  3. Add output parsers early if you expect structured responses.
  4. Start small: Validate each stage (prompt → model → parser) incrementally.
  5. Instrument with tracing (e.g., LangSmith) before scaling.

Practice Exercises

  1. Modify the summarization chain to return both a short and extended summary.
  2. Build a chain that generates brainstorm ideas and then turns them into an action plan.
  3. Add error handling around the Pydantic parser (simulate malformed output).
  4. Swap the LLM provider (Anthropic or an open-source model) without changing downstream logic.

What’s Next?

In Lesson 4 we will dive specifically into LLM model selection and prompt engineering fundamentals, then move toward parsing, runnables/LCEL, and memory patterns.