LangChain LangGraph
Module 1 Module 2 Module 3
Module 1 · Basic abilities
1 1.1a Foundation Model
2 1.1b Prompting
3 1.2a Tools
4 1.2b Web Search
5 1.3 Memory
6 1.4 Multimodal
7 1.5 Personal Chef
SUM Module Summary
HomeLangChainModule 1 · Basic capabilities1.1a Basic Model
📓 Notebook 📖 Explained
LANGCHAIN MODULE 1 · LESSON 1.1a

LangChain basic model
init_chat_model · create_agent · Streaming output

use init_chat_model To initialize any chat model, use create_agent Build an Agent and use streaming output to display responses in real time.

1What is the LangChain base model layer? Overview of core concepts

LangChain’s Module 1 starts with the most basic capabilities:How to call a large language model (LLM)? How to build an Agent that can remember conversations and call tools?

This section (1.1_foundational_models) focuses on the three most basic things:

Module 1 overall architecture: from model to agent

init_chat_model
Initialize LLM
create_agent
Build Agent
invoke / stream
Execute / stream output
Course background

This course usesDeepSeekAs primary LLM (also supports Gemini, etc.). DeepSeek provides an interface compatible with the OpenAI API format, so it is used in LangChainmodel_provider="openai"Plus customizationbase_urlYou can access it. This "compatibility layer" design allows you to use the same set of LangChain code to switch models from different manufacturers.

2init_chat_model: unified model initialization interface

Provided by LangChaininit_chat_modelFunction that unifies the initialization methods of different LLM providers. You just need to pass in the model name, provider identifier, and API key, and you'll get a standard chat model object.

Basic usage: Directly initialize Google Gemini

The simplest usage is to directly use the model class officially integrated by LangChain:

from langchain_google_genai import ChatGoogleGenerativeAI

# 直接初始化 Gemini 模型
model = ChatGoogleGenerativeAI(model="gemini-2.5-flash-lite")

# 直接调用:注意这是 model.invoke,不是 agent.invoke
response = model.invoke("What's the capital of the Moon?")
print(response.content)
note the difference

model.invoke()Call the original model directly and returnAIMessageobject, through.contentGet the text content. andagent.invoke()Returns a dictionary containing the complete message history{"messages": [...]}. The interfaces of the two are different.

Factory function that encapsulates DeepSeek

One is defined in the notebookdeepseek_model()Factory function encapsulates all DeepSeek related initialization details:

from dotenv import load_dotenv
load_dotenv()  # 从 .env 文件加载 DEEPSEEK_API_KEY 等环境变量

import os
from langchain.chat_models import init_chat_model

DEEPSEEK_MODEL = "deepseek-v4-flash"
DEEPSEEK_BASE_URL = "https://api.deepseek.com"

def deepseek_model(model: str = DEEPSEEK_MODEL, max_tokens=200, **kwargs):
    return init_chat_model(
        model=model,
        model_provider="deepseek",   # 或 "openai"(DeepSeek 兼容 OpenAI 格式)
        max_tokens=max_tokens,
        base_url=DEEPSEEK_BASE_URL,
        api_key=os.environ["DEEPSEEK_API_KEY"],
        **kwargs
    )

Initialize the model using a factory function:

model = deepseek_model(temperature=1)
print(model)  # 打印模型对象,确认配置

# 直接调用模型(不经过 Agent)
response = model.invoke("what is 1+1?")
print(response.content)  # → "The answer is 2."
Execution output
ChatDeepSeek(model_name='deepseek-v4-flash', temperature=1.0, ...)

The answer is 2.

Key parameters of init_chat_model

parameterillustrateExample value
model Model ID string "deepseek-v4-flash"
model_provider LangChain routes to which provider's adapter "deepseek" / "openai" / "google-genai"
max_tokens Maximum number of output tokens 200 / 1000
temperature Output randomness (0=deterministic, 1=most random) 0 / 1
base_url Custom API endpoint (for DeepSeek/local models) "https://api.deepseek.com"

3create_agent: Build Agent with model

create_agentIt is a high-level API provided by LangChain, which packages a chat model into a completeLangGraph Agent(The bottom layer is a StateGraph with a checkpointer).

What does Agent have compared to the original model?

from langchain.agents import create_agent

# 最基础的用法:只传入模型
agent = create_agent(model=deepseek_model())
The underlying principle of create_agent

create_agentBuilt a LangGraph under the hoodStateGraph, contains amodelnode (calling LLM) and atoolsNode (which performs tool calls). They are connected by conditional edges: the model output goes to the tools node when a tool is called, otherwise it ends. This is the implementation of the ReAct (Reasoning + Acting) pattern.

4Agent's invoke: synchronous call and response structure

Used to call Agentagent.invoke({"messages": [...]}), the input is a containingmessagesA dictionary of keys, messages can be usedHumanMessagePass in object or dictionary format.

Using the HumanMessage object

from langchain.messages import HumanMessage

agent = create_agent(deepseek_model())

messages = [
    {"role": "user",      "content": "what is 1+1?"},
    {"role": "assistant", "content": "2"},
    {"role": "user",      "content": "how about times 5?"}
]

response = agent.invoke({"messages": messages})
print(response['messages'][-1].content)
Execution output
If you take the result of 1+1 (which is 2) and multiply it by 5, you get 10.

Structural analysis of response

The Agent's response is a dictionary, and the core keys aremessages, which is a message list containing the complete conversation history:

print(len(response['messages']))  # → 4(3 条输入 + 1 条 AI 响应)

for msg in response['messages']:
    print(msg.content)
Execution output
what is 1+1?
2
how about times 5?
If you take the result of 1+1 (which is 2) and multiply it by 5, you get 10.
Commonly used value methods

Usually only the last AI message is needed:response['messages'][-1].content. This is the most common value pattern - take the last item in the message list, and then take.contentProperty gets the text content.

5Streaming output (stream_mode="messages"): real-time printing by Token

use agent.invoke()You need to wait until all models are generated before you can see the results.agent.stream()Then let the model push it immediately every time it generates a token to achieve the "typewriter effect" - which is a much better experience in UI interaction and long response scenarios.

Basic streaming usage

messages = [{"role": "user", "content": "Tell me all about Luna City, the capital of the Moon"}]

for token, metadata in agent.stream(
    {"messages": messages},
    stream_mode="messages"   # 关键:按消息/token 流式推送
):
    if token.content:          # 过滤空 token(工具调用消息没有 content)
        print(token.content, end="", flush=True)  # 不换行,实时打印
Streaming output effects
Luna City is a fictional lunar capital featured in sci-fi.

stream_mode parameter description

stream_modePush timingSuitable for the scene
"messages" Push every time a token/message fragment is generated UI typewriter effect, real-time response display
"values" Push the complete State every time a LangGraph node is completed Monitor Agent internal step status
"updates" Push the State changes of each node after completion Debug node output

6metadata metadata: understand the internal execution information of Agent

In a streaming loop,agent.stream()Return at the same timetoken(message content) andmetadata(execution metadata).metadataContains LangGraph internal runtime information, useful for debugging and tracing.

for token, metadata in agent.stream(
    {"messages": messages},
    stream_mode="messages"
):
    # 第一个 token 时打印 metadata
    print(metadata)
    break
metadata content example
{
  'langgraph_step': 1,
  'langgraph_node': 'model',
  'langgraph_triggers': ('branch:to:model',),
  'ls_provider': 'deepseek',
  'ls_model_name': 'deepseek-v4-flash',
  'ls_model_type': 'chat',
  'ls_max_tokens': 500
}

Interpretation of metadata key fields

Fieldmeaning
langgraph_step The current step of LangGraph execution (starting from 1)
langgraph_node The name of the currently executing node (e.g.'model'or'tools'
langgraph_triggers The source that triggered the execution of the current node (edge/event name)
ls_provider Actual LLM providers used
ls_model_name The actual model ID used
Practical application

In a production environment, metadata is commonly used for: ① logging and monitoring (tracking which model is used for each call); ② debugging (checking which node the Agent executes to have problems); ③ billing analysis (throughls_model_nameStatistics of usage of each model).

7Complete code and quick review of key concepts

Complete example from scratch

from dotenv import load_dotenv
load_dotenv()

import os
from langchain.chat_models import init_chat_model
from langchain.agents import create_agent
from langchain.messages import HumanMessage

# 1. 初始化模型
def deepseek_model(**kwargs):
    return init_chat_model(
        model="deepseek-v4-flash",
        model_provider="deepseek",
        api_key=os.environ["DEEPSEEK_API_KEY"],
        base_url="https://api.deepseek.com",
        max_tokens=500,
        **kwargs
    )

# 2. 构建 Agent
agent = create_agent(deepseek_model())

# 3. 同步调用
response = agent.invoke({"messages": [HumanMessage(content="Hello!")]})
print(response['messages'][-1].content)

# 4. 流式调用
for token, _ in agent.stream(
    {"messages": [{"role": "user", "content": "Tell me a joke"}]},
    stream_mode="messages"
):
    if token.content:
        print(token.content, end="", flush=True)

Summary of knowledge panorama in this section

Module 1 Lesson 1.1a Core Concept Map
init_chat_model
  • • Unify the initialization interfaces of different manufacturers’ models
  • • passmodel_providerSpecify adapter
  • • Support DeepSeek, OpenAI, Google, etc.
create_agent
  • • Wrap the model as LangGraph Agent
  • • Built-in message history management
  • • Support tool invocation (ReAct mode)
invoke vs stream
  • invoke: Wait for a complete response and return the message list
  • stream: Push token by token, typewriter effect
  • • usetoken.contentFilter empty messages
response structure
  • response['messages']: Complete message history
  • response['messages'][-1].content:AI latest reply
  • • metadata contains node/model execution information