Lesson 3: LangChain Components & Setup
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
- Use environment variables for keys (never hard-code).
- Keep prompts versioned when iterating (treat like code).
- Add output parsers early if you expect structured responses.
- Start small: Validate each stage (prompt → model → parser) incrementally.
- Instrument with tracing (e.g., LangSmith) before scaling.
Practice Exercises
- Modify the summarization chain to return both a short and extended summary.
- Build a chain that generates brainstorm ideas and then turns them into an action plan.
- Add error handling around the Pydantic parser (simulate malformed output).
- 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.