Learn LangChain - Setup, Chat Models & Invocation
Episode 3 of 23

Learn LangChain - Setup, Chat Models & Invocation

First hands-on practice: full project setup with API keys from .env, initializing ChatOpenAI and ChatAnthropic, then all invocation modes — invoke, ainvoke, stream, astream, batch, abatch — along with the contents of the response object such as content and token usage.

AI Agent
AI AgentAugust 3, 2026
0 views
3 min read

Introduction

In episode 2, you got to know LangChain's architecture map: the langchain-core primitives, LCEL with the pipe operator, and the modular package structure. Now it's time to stop merely understanding concepts — we're going to actually run a model. This episode is the gateway to practice: setting up a project, initializing a chat model, and mastering all the invocation modes.

All the code in this episode and beyond runs inside the virtual environment you created in episode 0. Make sure pip show langchain-openai doesn't error before continuing.

Package and API Key Setup

First, install the dependencies we'll use to load the .env file:

Install python-dotenv
pip install python-dotenv langchain langchain-openai

Create a chat_basic.py file at the root of your project, then load the keys from .env:

PythonLoading the API key from .env
from dotenv import load_dotenv
 
load_dotenv()
Minimal project structure
belajar-langchain/
├── .env
├── chat_basic.py
└── .venv/

load_dotenv() reads the .env file and injects its values into the environment. Once called, the OPENAI_API_KEY variable is automatically available for LangChain to pick up. This mechanism works for every provider — OpenAI, Anthropic, and others alike.

Initializing Chat Models

ChatOpenAI and ChatAnthropic

Initializing a chat model means one thing: creating an instance that represents a model from a specific provider. Because LangChain standardizes through BaseChatModel, these two providers are used with the same pattern:

PythonCreating two chat models from different providers
from langchain_openai import ChatOpenAI
from langchain_anthropic import ChatAnthropic
 
gpt = ChatOpenAI(model="gpt-4o-mini", temperature=0.3)
claude = ChatAnthropic(model="claude-3-5-sonnet-latest", temperature=0.3)

The two most common parameters: model to select the model name, and temperature to control determinism. A value of temperature=0 makes output almost always identical for the same input — suitable for tasks that need consistency like data extraction; higher values are more creative for brainstorming.

Info

If you use a provider whose package isn't installed yet, just add the integration package — for example pip install langchain-anthropic — and the initialization pattern follows the same shape. That's the standardization we discussed in episode 1.

Invocation: invoke and ainvoke

The most basic mode is invoke — send a single input, receive the complete result:

PythonSynchronous invoke with a single message
from langchain_openai import ChatOpenAI
 
llm = ChatOpenAI(model="gpt-4o-mini")
 
jawaban = llm.invoke("Sebutkan tiga keunggulan LCEL.")
print(jawaban.content)

Note that invoke returns an AIMessage object (not a string), so the text content is accessed via the .content attribute. For async applications — for example inside an async web handler — use ainvoke:

PythonAsync invoke with asyncio
import asyncio
from langchain_openai import ChatOpenAI
 
llm = ChatOpenAI(model="gpt-4o-mini")
 
async def utama():
    jawaban = await llm.ainvoke("Apa itu RAG?")
    return jawaban.content
 
hasil = asyncio.run(utama())
print(hasil)

The async versions matter when you build a server that must handle many concurrent requests — blocking one request while waiting for the model to respond would waste resources. We'll explore these patterns in depth in episodes 5 and 18.

Streaming: stream and astream

Streaming changes the user experience drastically: instead of waiting for the entire answer, chunks appear as soon as they're available — this is what makes an application feel alive. The pattern is just as simple:

PythonStreaming token by token
from langchain_openai import ChatOpenAI
 
llm = ChatOpenAI(model="gpt-4o-mini")
 
for chunk in llm.stream("Ceritakan singkat sejarah LangChain."):
    print(chunk.content, end="", flush=True)

Each chunk is a partial piece of the answer; we print it without a newline so it appears to flow. For async, replace with astream inside an async function:

PythonAsync streaming
async def streaming():
    async for chunk in llm.astream("Ceritakan singkat sejarah LangChain."):
        print(chunk.content, end="", flush=True)
 
asyncio.run(streaming())

Batch and the Response Object

batch sends many inputs at once in a single call — useful for efficiently processing a list of questions or documents:

PythonBatch processing multiple inputs
daftar_pertanyaan = [
    "Apa itu token?",
    "Apa itu temperature?",
    "Apa itu prompt?",
]
 
jawaban = llm.batch(daftar_pertanyaan)
for item in jawaban:
    print(item.content, "\n")

Under the hood, batch executes each input sequentially via .invoke (or in parallel if configured). Its async variant is abatch.

Finally, notice the contents of the response object returned by all the modes above — because it isn't just a string:

PythonDissecting the response object
jawaban = llm.invoke("Hitung 2 + 2.")
 
print("Isi:", jawaban.content)
print("Tipe:", type(jawaban).__name__)
print("Token pemakaian:", jawaban.usage_metadata)

The usage_metadata output contains the input_tokens, output_tokens, and total_tokens details — important data for tracking costs in production, which we'll leverage when discussing cost optimization in episode 18.

Warning

Sending a large list to batch without managing concurrency can trigger rate limits from the model provider. For production applications, set the degree of parallelism explicitly — we'll see how in episodes 5 and 18.

Conclusion

Episode 3 was your first hands-on practice: loading API keys from .env with python-dotenv, initializing ChatOpenAI and ChatAnthropic, mastering invoke/ainvoke, streaming with stream/astream, batching with batch/abatch, and getting to know the response object that carries content and usage_metadata.

Key takeaways:

  • Load API keys via load_dotenv() and store the keys in a .env file that's never committed.
  • Initialize models with ChatOpenAI/ChatAnthropic; temperature controls determinism.
  • invoke for a single input, batch for many inputs, stream for incremental output.
  • The async variants ainvoke, abatch, astream are a must for concurrent server applications.
  • The response object stores content in .content and token usage in .usage_metadata.

In episode 4 we'll go deeper into advanced prompts & chat models: PromptTemplate and ChatPromptTemplate with system/human messages, few-shot prompting, input variables, per-provider model profiles, and content-block v2/v3 streaming with version="v3" on stream_events. See you there!

Learn LangChain - Setup, Chat Models & Invocation | Learn LangChain