LangChain 基础
LangChain 的核心是把模型、提示词、工具和调用流程包装成可以组合的 Python 应用代码,让 AI 能力从“调用一次模型”变成“组织一条链路”。
LangChain 是什么
LangChain 是 Python 生态里常用的 LLM 应用开发框架。
LLM,中文一般叫“大语言模型”。
如果直接调用模型 API,代码通常是:
准备 messages
调用模型接口
拿到回答
返回给用户
LangChain 在这个基础上继续包装:
模型
提示词
工具
记忆
检索
工作流
Agent
本节先不要把它想复杂。
本节只记住一句话:
LangChain 是把模型调用和应用逻辑组织起来的工具箱。
为什么要学 LangChain
前面已经学过:
直接调用 LLM API
Prompt 基础
JSON 结构化输出
流式输出
Tool Calling
FastAPI
这些能力都可以手写。
但项目变复杂以后,会遇到几个问题:
提示词越来越多
模型切换不方便
工具越来越多
调用步骤越来越长
RAG 需要加载、切片、检索、生成
Agent 需要循环调用模型和工具
LangChain 的价值是帮你把这些步骤拆成可组合的组件。
比如:
Prompt Template
-> Chat Model
-> Tool
-> Agent
它不是替代大模型。
它是让你更方便地组织大模型应用。
安装依赖
学习阶段先安装最小依赖:
python -m pip install langchain langchain-openai python-dotenv
如果后面要做文本切片,再安装:
python -m pip install langchain-text-splitters
如果后面要用社区文档加载器,再安装:
python -m pip install langchain-community
建议 .env 保持和前面 Python 学习一致:
DASHSCOPE_API_KEY=你的百炼 API Key
DASHSCOPE_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
QWEN_MODEL=qwen-plus
Chat Model
Chat Model,中文可以理解为“聊天模型”。
它对应前面直接调用 API 时的模型客户端。
使用 DashScope 的 OpenAI 兼容接口时,可以用 ChatOpenAI:
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
load_dotenv()
model = ChatOpenAI(
model=os.getenv("QWEN_MODEL", "qwen-plus"),
api_key=os.environ["DASHSCOPE_API_KEY"],
base_url=os.getenv(
"DASHSCOPE_BASE_URL",
"https://dashscope.aliyuncs.com/compatible-mode/v1",
),
temperature=0.3,
)
response = model.invoke("用一句话解释 LangChain 是什么。")
print(response.content)
这里的 invoke 可以理解为“执行一次调用”。
返回值不是普通字符串,而是一个消息对象。
常用字段是:
content:模型回答文本
response_metadata:响应元信息
usage_metadata:token 用量信息
Messages
前面调用 OpenAI 兼容接口时,已经见过 messages:
messages = [
{"role": "system", "content": "你是一个严谨的 AI 学习助手。"},
{"role": "user", "content": "什么是 LangChain?"},
]
LangChain 也支持这种字典格式:
response = model.invoke([
{
"role": "system",
"content": "你是一个严谨的 AI 学习助手。",
},
{
"role": "user",
"content": "什么是 LangChain?",
},
])
print(response.content)
也可以使用消息对象:
from langchain_core.messages import HumanMessage, SystemMessage
response = model.invoke([
SystemMessage(content="你是一个严谨的 AI 学习助手。"),
HumanMessage(content="什么是 LangChain?"),
])
print(response.content)
学习阶段先用字典格式就够了。
它和前面的 LLM API 更像。
Prompt Template
Prompt Template,中文可以理解为“提示词模板”。
它的作用是把固定提示词和变量分开。
不要这样到处拼字符串:
role = "Java 后端工程师"
question = "怎么理解 Tool Calling?"
prompt = "你是" + role + ",请回答:" + question
用模板更清楚:
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages([
(
"system",
"你是一个{role},回答要清楚、直接、适合初学者。",
),
(
"user",
"{question}",
),
])
messages = prompt.invoke({
"role": "Java 后端工程师",
"question": "怎么理解 Tool Calling?",
})
response = model.invoke(messages)
print(response.content)
模板的好处是:
变量更明确
提示词更容易复用
后面能组合成 Chain
错误更容易定位
Chain
Chain,中文可以理解为“链”。
它表示把多个步骤串起来。
最小 Chain:
Prompt Template
-> Chat Model
代码:
chain = prompt | model
response = chain.invoke({
"role": "Java 后端工程师",
"question": "怎么理解 RAG?",
})
print(response.content)
这里的 | 可以理解为管道。
左边的输出会交给右边。
流程是:
输入变量
-> 渲染 prompt
-> 调用模型
-> 返回 AIMessage
这就是 LangChain 的基本组合方式。
加一个输出解析
如果只想要字符串,可以加一个输出解析器。
from langchain_core.output_parsers import StrOutputParser
chain = prompt | model | StrOutputParser()
answer = chain.invoke({
"role": "Java 后端工程师",
"question": "LangChain 的 Chain 是什么?",
})
print(answer)
流程变成:
Prompt Template
-> Chat Model
-> StrOutputParser
-> string
这样 Controller 或 FastAPI 返回时更方便。
Tools 入门
Tools,中文就是“工具”。
前面已经学过 Tool Calling。
在 LangChain 里,可以用 @tool 把 Python 函数声明成工具:
from langchain.tools import tool
@tool
def query_order(order_id: str) -> str:
"""根据订单号查询订单状态。只用于订单发货、物流和售后进度查询。"""
mock_orders = {
"A10001": "订单 A10001 已发货,物流单号 SF123456。",
"A10002": "订单 A10002 待发货,预计很快出库。",
}
return mock_orders.get(order_id, f"没有查询到订单 {order_id}。")
注意这个 docstring 很重要。
模型会根据它判断什么时候调用工具。
工具函数要尽量做到:
函数名清楚
参数类型明确
docstring 写明用途
返回值稳定
不要直接做高风险操作
创建一个 Agent
Agent,中文可以理解为“代理”或“智能体”。
在本节里,先把 Agent 理解为:
模型 + 工具 + 循环决策
最小示例:
from langchain.agents import create_agent
agent = create_agent(
model=model,
tools=[query_order],
system_prompt="""
你是一个售后客服助手。
用户询问订单状态时,优先使用 query_order 工具。
不要编造订单结果。
""",
)
result = agent.invoke({
"messages": [
{
"role": "user",
"content": "帮我查一下订单 A10001 发货了吗?",
}
]
})
print(result["messages"][-1].content)
这段代码里,模型可能会做这些事:
理解用户问题
判断需要查订单
生成工具参数 order_id=A10001
调用 query_order
拿到工具结果
生成最终回答
这和前面 Java Tool Calling 是同一个思想。
区别是这里放在 Python LangChain 里。
LangChain 和 LangGraph 的关系
先记一个简单区别:
LangChain:快速组合模型、提示词、工具、Agent
LangGraph:更底层地控制状态、节点、边和工作流
LangChain 适合先把应用跑起来。
LangGraph 适合工作流变复杂以后:
多步骤流程
条件分支
循环
人工确认
持久化状态
可观测执行路径
下一节会单独学习 LangGraph。
一个完整 demo
可以新建 langchain_basic_demo.py:
import os
from dotenv import load_dotenv
from langchain.agents import create_agent
from langchain.tools import tool
from langchain_openai import ChatOpenAI
load_dotenv()
@tool
def query_order(order_id: str) -> str:
"""根据订单号查询订单状态。只用于订单发货、物流和售后进度查询。"""
mock_orders = {
"A10001": "订单 A10001 已发货,物流单号 SF123456。",
"A10002": "订单 A10002 待发货,预计很快出库。",
}
return mock_orders.get(order_id, f"没有查询到订单 {order_id}。")
model = ChatOpenAI(
model=os.getenv("QWEN_MODEL", "qwen-plus"),
api_key=os.environ["DASHSCOPE_API_KEY"],
base_url=os.getenv(
"DASHSCOPE_BASE_URL",
"https://dashscope.aliyuncs.com/compatible-mode/v1",
),
temperature=0.3,
)
agent = create_agent(
model=model,
tools=[query_order],
system_prompt="""
你是一个售后客服助手。
用户询问订单状态时,优先使用 query_order 工具。
不要编造订单结果。
""",
)
result = agent.invoke({
"messages": [
{
"role": "user",
"content": "帮我查一下订单 A10001 发货了吗?",
}
]
})
print(result["messages"][-1].content)
运行:
python langchain_basic_demo.py
常见问题
LangChain 会不会替代 OpenAI SDK
不会。
LangChain 底层仍然会调用模型供应商的 SDK 或 HTTP 接口。
它是更高一层的应用组织方式。
是不是所有 AI 项目都要用 LangChain
不是。
简单聊天接口,用 OpenAI SDK 或 Spring AI 就够。
当你需要 RAG、Agent、工具编排、链路追踪时,再引入 LangChain 更自然。
为什么工具描述很重要
因为模型看不到工具内部代码。
它主要根据工具名称、参数和描述来决定是否调用。
描述太模糊,模型就容易选错工具。
Chain 和 Agent 有什么区别
Chain 更像固定流程。
Agent 更像模型自己决定下一步。
简单理解:
Chain:你安排步骤
Agent:模型决定是否调用工具和怎么继续
练习清单
完成几件事情:
安装 langchain 和 langchain-openai
用 ChatOpenAI 调通 qwen-plus
用 messages 调用一次模型
用 ChatPromptTemplate 写一个模板
用 prompt | model 组成一个 Chain
加 StrOutputParser 返回字符串
用 @tool 定义 query_order
用 create_agent 创建一个带工具的 Agent
能解释 LangChain 和 LangGraph 的区别
建议目录:
ai-agent-study
├── python
│ └── langchain-basic
│ ├── langchain_basic_demo.py
│ ├── requirements.txt
│ └── README.md
└── docs
└── langchain-basic.md
小结
本节的结论:
LangChain 先从 Chat Model、Prompt Template、Chain、Tool、Agent 这五个概念入手,不要一开始陷入复杂生态。
最小链路:
输入变量
-> Prompt Template
-> Chat Model
-> Output Parser
-> 返回结果
带工具链路:
用户问题
-> Agent
-> 模型判断是否需要工具
-> Python 工具函数执行
-> 模型生成最终回答
import argparse
import os
from collections.abc import Callable
from dotenv import load_dotenv
from langchain.agents import create_agent
from langchain.tools import tool
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
DEFAULT_BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1"
DEFAULT_MODEL = "qwen3.5-flash"
DEFAULT_ROLE = "Java 后端工程师"
DEFAULT_QUESTION = "LangChain 的 Chain 是什么?"
DEFAULT_AGENT_QUESTION = "帮我查一下订单 A10001 发货了吗?"
load_dotenv()
@tool
def query_order(order_id: str) -> str:
"""根据订单号查询订单状态。只用于订单发货、物流和售后进度查询。"""
mock_orders = {
"A10001": "订单 A10001 已发货,物流单号 SF123456。",
"A10002": "订单 A10002 待发货,预计很快出库。",
"A10003": "订单 A10003 已签收,如需售后可以提交工单。",
}
return mock_orders.get(order_id, f"没有查询到订单 {order_id}。")
def build_model() -> ChatOpenAI:
"""创建 LangChain Chat Model,对接 DashScope OpenAI 兼容接口。"""
return ChatOpenAI(
model=os.getenv("QWEN_MODEL", DEFAULT_MODEL),
api_key=required_env("DASHSCOPE_API_KEY"),
base_url=os.getenv("DASHSCOPE_BASE_URL", DEFAULT_BASE_URL),
temperature=0.3,
max_completion_tokens=1024,
extra_body={"enable_thinking": bool_env("QWEN_ENABLE_THINKING", False)},
)
def run_chat_model(question: str) -> str:
"""Chat Model:直接把字符串交给模型。"""
model = build_model()
response = model.invoke(question)
return response.content
def run_messages(question: str) -> str:
"""Messages:使用 system/user 消息调用模型。"""
model = build_model()
response = model.invoke(
[
{
"role": "system",
"content": "你是一个严谨的 AI 学习助手,用中文回答,回答要清楚、直接。",
},
{
"role": "user",
"content": question,
},
]
)
return response.content
def build_prompt() -> ChatPromptTemplate:
"""Prompt Template:把固定提示词和变量分开。"""
return ChatPromptTemplate.from_messages(
[
(
"system",
"你是一个{role},用中文回答,回答要清楚、直接、适合初学者。",
),
(
"user",
"{question}",
),
]
)
def run_prompt_template(question: str, role: str) -> str:
"""Prompt Template:先渲染模板,再调用模型。"""
model = build_model()
prompt = build_prompt()
messages = prompt.invoke(
{
"role": role,
"question": question,
}
)
response = model.invoke(messages)
return response.content
def run_chain(question: str, role: str) -> str:
"""Chain:用 prompt | model | parser 组成固定流程。"""
model = build_model()
prompt = build_prompt()
chain = prompt | model | StrOutputParser()
return chain.invoke(
{
"role": role,
"question": question,
}
)
def run_agent(question: str) -> str:
"""Agent:让模型判断是否需要调用 query_order 工具。"""
model = build_model()
agent = create_agent(
model=model,
tools=[query_order],
system_prompt=(
"你是一个售后客服助手。"
"用户询问订单状态时,优先使用 query_order 工具。"
"不要编造订单结果。"
),
)
result = agent.invoke(
{
"messages": [
{
"role": "user",
"content": question,
}
]
}
)
return result["messages"][-1].content
def required_env(name: str) -> str:
value = os.getenv(name)
if value:
return value
raise RuntimeError(f"请先在 .env 文件中配置 {name}")
def bool_env(name: str, default: bool) -> bool:
value = os.getenv(name)
if value is None:
return default
return value.strip().lower() in {"1", "true", "yes", "on"}
def print_section(title: str, value: str) -> None:
print(f"\n=== {title} ===")
print(value)
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Day11 LangChain 基础示例")
parser.add_argument(
"--mode",
choices=["chat", "messages", "prompt", "chain", "agent", "all"],
default="chain",
help="选择要运行的 LangChain 示例",
)
parser.add_argument(
"--question",
default=DEFAULT_QUESTION,
help="传给模型的问题",
)
parser.add_argument(
"--role",
default=DEFAULT_ROLE,
help="Prompt Template 中的角色变量",
)
return parser.parse_args()
def main() -> None:
args = parse_args()
runners: dict[str, Callable[[], str]] = {
"chat": lambda: run_chat_model(args.question),
"messages": lambda: run_messages(args.question),
"prompt": lambda: run_prompt_template(args.question, args.role),
"chain": lambda: run_chain(args.question, args.role),
"agent": lambda: run_agent(
args.question if args.question != DEFAULT_QUESTION else DEFAULT_AGENT_QUESTION
),
}
if args.mode == "all":
print_section("Chat Model", runners["chat"]())
print_section("Messages", runners["messages"]())
print_section("Prompt Template", runners["prompt"]())
print_section("Chain", runners["chain"]())
print_section("Agent + Tool", run_agent(DEFAULT_AGENT_QUESTION))
return
print(runners[args.mode]())
if __name__ == "__main__":
main()



Comments | 0 条评论