01
LangChain 是什么:LLM 应用开发框架
直接用 OpenAI、Anthropic 的官方 SDK,你能完成「发一段话、拿回一段回答」。但真实的应用要做的远不止这些:让模型调用你的函数查库存、检索文档再回答、记住前几轮对话、按步骤走完一个多环节流程。LangChain 把这些通用件做成了标准组件——你负责拼装,而不是手写循环、解析工具调用、管理状态。
2025 年 10 月发布的 v1.0 是一次大重写:核心入口收敛到 create_agent(构建智能体)和 init_chat_model(初始化任意厂商的模型),旧版的 LLMChain、AgentExecutor 等全部退场。如果你看过 0.x 时代的老教程,先默认它过时,以官方文档为准。
落到场景上:客服与文档问答(RAG)、让模型调用内部接口干活的自动化流、从非结构化文本里抽取字段(结构化输出)、给已有产品加一个「会查资料的助手」——这些是 LangChain 的主场。反过来,如果只是一次性问答或文本处理,直接调 SDK 反而更轻。
- 当前主线
- langchain 1.x(写本页时最新 1.4.9,2026-11 查 PyPI)
- 1.0 发布
- 2025-10(API 大版本重写)
- 语言
- Python / JavaScript(本页讲 Python)
- 协议
- MIT
- Python 要求
- ≥ 3.10
- 核心入口
- create_agent / init_chat_model
- 智能体运行时
- LangGraph(持久化、流式、human-in-the-loop)
- 0.x 旧 API
- 已移出主包,搬进 langchain-classic
langchain 是编排主包(create_agent、中间件);langchain-core 是抽象层(消息、向量库接口等基础类型);langgraph 负责复杂状态图与多智能体;各厂商模型走独立集成包 langchain-openai、langchain-anthropic 等。装主包时这些依赖会自动带上,但你得知道谁是谁,报错才好定位。02
安装:两个包 + 一把钥匙
主包和模型集成包一起装,再把 API 密钥配进环境变量,就绪。建议先建一个干净的虚拟环境。
# 主包 + OpenAI 集成一起装(会自动带上 langchain-core、langgraph) pip install -U langchain langchain-openai # 把密钥写进环境变量(当前终端生效) export OPENAI_API_KEY=sk-... # macOS / Linux setx OPENAI_API_KEY "sk-..." # Windows(新开终端生效)
# 换 Anthropic / Google,就换对应的集成包 pip install -U langchain langchain-anthropic pip install -U langchain langchain-google-genai # 本地跑开源模型(Ollama) pip install -U langchain langchain-ollama # 用 uv 的话,也可以用 extras 一条装完 uv add "langchain[openai]"
# 版本对不对? pip show langchain # 导入不报错就 OK python -c "import langchain, langchain_openai; print('imports ok')"
.env 文件(配 python-dotenv 的 load_dotenv()),并把 .env 加进 .gitignore。泄露的 key 会被扫库脚本秒捡,账单是真的。03
快速上手:先调通模型,再让它动手
# 第一步:用 init_chat_model 拿到模型,「厂商:模型名」一个字符串就够 # 模型名换成你账号可用的任何型号即可,以各服务商控制台为准 from langchain.chat_models import init_chat_model model = init_chat_model("openai:gpt-5.5", temperature=0) print(model.invoke("用一句话说明什么是 LLM 应用编排").text)
能跑通上面三行,说明包和密钥都没问题。第二步,把一个会调工具的智能体立起来——这是 LangChain 1.x 的主角 create_agent:
from langchain.agents import create_agent
def get_word_count(text: str) -> int:
"""统计一段文本去掉空格后的字数。"""
return len(text.replace(" ", ""))
agent = create_agent(
model="openai:gpt-5.5", # 也能传 init_chat_model 的返回值
tools=[get_word_count], # 函数列表,模型自己决定何时调用
system_prompt="你是文字助手,需要统计字数时调用工具。",
)
result = agent.invoke(
{"messages": [{"role": "user", "content": "数一数这句有多少字:大模型应用落地"}]}
)
print(result["messages"][-1].text) # 取最后一条消息,就是最终回答
-
01
配好密钥再跑
首次运行最常见的报错就是没读到 API key。先
export(或写 .env),确认当前终端能echo $OPENAI_API_KEY打印出来。 -
02
用「厂商:模型名」换模型
init_chat_model("anthropic:claude-sonnet-4-6")、"ollama:llama3.3"——换厂商只换字符串和对应集成包,业务代码不动。 -
03
工具就是带 docstring 的函数
模型靠 docstring 判断这个工具干什么、什么时候用。描述写得越清楚,调用越准。
-
04
结果从 messages 里取
agent.invoke返回完整消息历史,最后一条是回答;想看过程就把整个列表打出来,能看到模型的工具调用记录。
04
核心概念:消息、工具、RAG 与记忆
消息与角色:对话的通用语言
一切交互都是消息列表,角色只有几种:system(设定人设与规则)、user(用户输入)、assistant / AI(模型回答)、tool(工具执行结果)。1.x 里消息类统一从 langchain.messages 导入,也支持直接传 OpenAI 风格的字典。
from langchain.messages import SystemMessage, HumanMessage, AIMessage, ToolMessage
messages = [
SystemMessage("你是一名严谨的技术编辑。"),
HumanMessage("用一句话解释什么是 RAG。"),
]
reply = model.invoke(messages) # 返回 AIMessage
print(reply.text) # .text 是纯文本
print(reply.content_blocks) # 标准化内容块,兼容各厂商的推理/引用等信息
结构化输出与工具调用
两个高频需求:让模型返回程序能用的对象(接数据库、接表单),以及让模型决定调用你的函数。前者用 with_structured_output 套一个 Pydantic 模型;后者最低层是 bind_tools,最高层就是 create_agent 帮你把「调用—执行—回填」的循环全包了。
from pydantic import BaseModel
class BookReview(BaseModel):
title: str
score: int # 1-10
reason: str
review = model.with_structured_output(BookReview).invoke(
"给《三体》写一条 30 字短评"
)
print(review.title, review.score) # 已经是 Python 对象,不是字符串
from langchain.tools import tool
@tool
def get_weather(city: str) -> str:
"""查询一个城市今天的天气。"""
return f"{city}:晴,26°C" # 真实项目里换成调用天气 API
resp = model.bind_tools([get_weather]).invoke("北京天气怎么样?")
print(resp.tool_calls) # 模型说:想调 get_weather,参数是……执行权在你手上
RAG 三件套:加载、切分、检索
模型不知道你的私有资料,RAG 的思路是「先检索、后生成」:把文档加载进来,切分成小块并向量化存进向量库,提问时按相似度捞出最相关的几段,塞进提示词交给模型。组件全部可替换——换 loader 不动切分,换向量库不动业务逻辑。
from langchain_community.document_loaders import TextLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_openai import OpenAIEmbeddings from langchain_core.vectorstores import InMemoryVectorStore docs = TextLoader("notes.txt", encoding="utf-8").load() chunks = RecursiveCharacterTextSplitter( chunk_size=500, chunk_overlap=50, ).split_documents(docs) store = InMemoryVectorStore.from_documents(chunks, OpenAIEmbeddings()) print(store.similarity_search("部署要点", k=3)) # 直接检索试一下 retriever = store.as_retriever(search_kwargs={"k": 3}) # 或包成检索器接进链里
记忆、会话与 LangSmith 观测
默认情况下每次 invoke 都是失忆的。给 agent 配一个 checkpointer(存档器),再用 thread_id 区分会话,它就能记住同一会话里说过的内容——这是 LangGraph 提供的能力,1.x 的 create_agent 直接暴露了参数。调试阶段强烈建议打开 LangSmith:官方观测平台,每次调用的提示词、工具轨迹、token 花费全部可查。
from langgraph.checkpoint.memory import InMemorySaver
agent = create_agent(
model="openai:gpt-5.5",
tools=[get_weather],
system_prompt="你是可靠的助手。",
checkpointer=InMemorySaver(), # 生产可换持久化实现
)
cfg = {"configurable": {"thread_id": "user-42"}} # 同一个 id = 同一个会话
agent.invoke({"messages": [{"role": "user", "content": "我叫小林"}]}, cfg)
agent.invoke({"messages": [{"role": "user", "content": "我叫什么?"}]}, cfg)
export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY=lsv2_...
# 之后所有调用自动上报到 smith.langchain.com,先注册拿 key
05
速查表:1.x 高频 API 与生态包
下面这块表格能搜。忘了某个 API 叫什么,直接搜 agent、检索、结构化 之类的词。
| API | 作用 |
|---|---|
| init_chat_model("openai:gpt-5.5") | 按「厂商:模型名」字符串初始化对话模型,参数如 temperature 透传 |
| init_chat_model(m, model_provider="google-genai") | 模型名不带前缀时,显式指定厂商 |
| from langchain.chat_models | init_chat_model 所在模块 |
| model.invoke(messages) | 单次调用,传字符串、字典列表或消息对象都行 |
| model.stream(...) | 流式输出,逐段拿结果 |
| model.bind_tools([fn]) | 低层工具绑定:模型返回 tool_calls,执行循环自己写 |
| model.with_structured_output(Schema) | 按 Pydantic 模型返回结构化对象 |
| create_agent(model=, tools=) | 1.x 核心入口:构建会自动调工具的智能体,另支持 system_prompt、checkpointer、middleware |
| from langchain.agents | create_agent 所在模块 |
| agent.invoke({"messages": [...]}) | 运行智能体,返回完整消息历史 |
| result["messages"][-1] | 取最后一条消息即最终回答,.text 拿纯文本 |
| agent.stream(...) | 流式执行,逐步产出中间与最终状态 |
| @tool | 把普通函数变成工具,docstring 就是给模型看的说明书 |
| create_agent(checkpointer=...) | 接入会话记忆,配合 thread_id 区分会话 |
| 写法 | 说明 |
|---|---|
| from langchain.messages import … | 1.x 的消息导入路径(HumanMessage、SystemMessage 等) |
| SystemMessage("…") | 系统消息:人设、规则,一般放列表开头 |
| HumanMessage("…") | 用户输入 |
| AIMessage | 模型回答;.text 取纯文本,.tool_calls 看工具调用 |
| ToolMessage(content, tool_call_id) | 回填工具执行结果,id 必须对上模型的调用请求 |
| {"role": "user", "content": "…"} | OpenAI 风格字典,等价写法,invoke 直接收 |
| response.content_blocks | 1.x 标准化内容块,统一各厂商的文本/推理等类型 |
| model.invoke("一句话") | 只发一句的快捷方式,内部转成 HumanMessage |
| response.tool_calls | 模型想调的工具列表:name、args、id |
| response.response_metadata / usage_metadata | 厂商原始返回信息 / token 用量统计 |
| result["messages"] | 完整消息轨迹,遍历可复盘模型每一步做了什么 |
| RemoveMessage | 在历史中删除指定消息(管理长会话用) |
| 组件 | 来源与作用 |
|---|---|
| TextLoader | langchain_community.document_loaders:读本地文本文件 |
| WebBaseLoader | langchain_community.document_loaders:抓网页正文 |
| PyPDFLoader | langchain_community.document_loaders:读 PDF |
| RecursiveCharacterTextSplitter | langchain_text_splitters:按段落/句子递归切分,chunk_size + chunk_overlap |
| CharacterTextSplitter | 同包的另一常用切分器:按指定分隔符切块 |
| OpenAIEmbeddings | langchain_openai:文本向量化,检索的基础 |
| InMemoryVectorStore | langchain_core.vectorstores:内存向量库,原型期最省事 |
| store.add_documents(docs) | 向量化并入库 |
| store.similarity_search(q, k=3) | 按相似度检索,返回 Document 列表 |
| store.as_retriever(search_kwargs={"k": 3}) | 包装成检索器,可直接接进链或工具 |
| retriever.invoke("问题") | 检索器的统一调用入口 |
| Chroma / PGVector 等 | 生产向量库走对应集成包(langchain-chroma、langchain-postgres…) |
| d.page_content / d.metadata | Document 的正文与元数据(来源页码、文件名等) |
| 包 | 定位 |
|---|---|
| langchain | 编排主包:create_agent、中间件、业务层抽象 |
| langchain-core | 抽象基础层:消息、向量库接口、Runnable 协议 |
| langgraph | 复杂状态图与多智能体:持久化、human-in-the-loop、自定义工作流 |
| langchain-openai | OpenAI 模型与嵌入的集成 |
| langchain-anthropic 等 | 其他厂商集成包,命名规律 langchain-厂商 |
| langchain-ollama | 本地跑开源模型的集成,模型字符串用 "ollama:模型名" |
| langchain-community | 社区贡献的 loader、工具大合集 |
| langchain-text-splitters | 文档切分器独立包 |
| langchain-classic | 0.x 旧 API(LLMChain、AgentExecutor)收容所,新项目别用 |
| langsmith | 官方观测与评估平台,LANGSMITH_TRACING=true 开启 |
| deepagents | 官方扩展:内置规划、文件系统工具与子智能体的 deep agent |
没有匹配的 API。换个词试试,比如「智能体」「检索」「消息」。
06
实战:30 行的最小 RAG 问答
不建数据库、不跑服务:知识库就是几段文本,向量库用内存版,检索出来的片段拼进提示词再调模型。整个脚本 30 多行,跑通后把它换成真实文档就是能用的原型。需要有效的 OPENAI_API_KEY,会产生少量调用费用。
第 1 步:建知识库并入库
# 运行前:pip install -U langchain langchain-openai # 密钥:export OPENAI_API_KEY=sk-... from langchain_core.vectorstores import InMemoryVectorStore from langchain_openai import OpenAIEmbeddings texts = [ "LangChain 1.x 的核心入口是 create_agent,智能体底层由 LangGraph 驱动。", "init_chat_model 用「厂商:模型名」字符串初始化任意厂商的对话模型。", "RAG 三件套:文档加载、切分、向量库与检索器,检索结果作为上下文交给模型。", "LangSmith 是官方观测平台,设置 LANGSMITH_TRACING=true 即可记录每次调用。", ] # 向量化并写入内存向量库;真实项目里 texts 换成 loader 读出的文档切分结果 store = InMemoryVectorStore.from_texts(texts, embedding=OpenAIEmbeddings())
第 2 步:组装「检索 → 填模板 → 生成」的链
from langchain.chat_models import init_chat_model
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
retriever = store.as_retriever(search_kwargs={"k": 2}) # 每次取最相关的 2 段
llm = init_chat_model("openai:gpt-5.5", temperature=0)
prompt = ChatPromptTemplate.from_template(
"仅根据下面的资料回答问题;资料里没有的就直说不知道。\n\n"
"资料:\n{context}\n\n问题:{question}"
)
def format_docs(docs):
return "\n\n".join(d.page_content for d in docs)
chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
)
这条链的读法:输入的问题一路透传;同时 retriever 拿回文档、format_docs 拼成一段文本;两路汇进模板填空,最后交给模型。LCEL 用 | 把组件串成管道,每一段都能单独测试。
第 3 步:提问运行
if __name__ == "__main__": while True: q = input("\n问题(直接回车退出)> ").strip() if not q: break print(chain.invoke(q).text)
$ python rag_demo.py 问题(直接回车退出)> 1.x 用什么构建智能体? 1.x 通过 create_agent() 构建智能体,底层由 LangGraph 驱动,支持持久化与流式。
第 4 步:把原型换成真实知识库
骨架不动,只换两处:texts 换成 loader 读出的切分结果,内存库换成可持久化的向量库:
# pip install langchain-community langchain-chroma from langchain_community.document_loaders import PyPDFLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_chroma import Chroma docs = PyPDFLoader("handbook.pdf").load() # 换 loader chunks = RecursiveCharacterTextSplitter( chunk_size=500, chunk_overlap=50, ).split_documents(docs) store = Chroma.from_documents( # 换向量库,落盘 chunks, OpenAIEmbeddings(), persist_directory="./db" ) retriever = store.as_retriever(search_kwargs={"k": 2}) # 下面的 prompt、chain 原样复用——组件可替换正是分层的好处
07
避坑:四个最常见的坑
坑一:照 0.x 老教程写,import 直接报错
v1 是破坏性重写。from langchain.chains import LLMChain、AgentExecutor、initialize_agent 在主包里都没有了;网上 2024 年及更早的教程基本全是旧写法。对照检查:create_agent(替代 create_react_agent / AgentExecutor)在 langchain.agents,消息从 langchain.messages 导入。确需维护旧项目,官方提供了 langchain-classic 包收容旧 API。
坑二:AuthenticationError / model not found
九成是密钥没配对或模型名写错。排查顺序:当前终端 echo $OPENAI_API_KEY 有值吗?key 是不是对应厂商的?模型字符串里的厂商前缀和型号在服务商控制台存在吗?
echo $OPENAI_API_KEY # 有输出才算配上了 pip show langchain langchain-openai | grep -E 'Name|Version' python -c "from dotenv import load_dotenv; load_dotenv(); import os; print(bool(os.getenv('OPENAI_API_KEY')))"
用 .env 文件时,load_dotenv() 必须在构造模型之前执行;export 只对当前终端会话生效,换窗口要重配。
坑三:RAG 答非所问,先怪检索再怪模型
检索增强类应用不准,问题大多出在检索端:切分太大(一片塞进多个主题)、没有 overlap(句子被拦腰切断)、取的 k 太小。先脱离模型单独测,人眼看捞回来的片段对不对——检索不对,调提示词是白费劲。中文语料记得给切分器留意标点,必要时换按句子切分的策略。
hits = store.similarity_search("1.x 用什么构建智能体?", k=2) for d in hits: print("---") print(d.page_content[:120]) # 捞回来的片段对不对,肉眼判断
坑四:什么时候不该上框架
LangChain 是编排工具,不是必需品。判断标准很简单:只是一次问答——用 init_chat_model 甚至厂商官方 SDK 就够;要模型反复调工具、走多步流程——用 create_agent;多个角色协作、复杂状态机、要人工审批节点——上 LangGraph。给 hello world 套全家桶,只会让调试链路变长。
08
进阶方向与资源
- LangChain 官方文档(Python)——1.x 的权威入口,本页所有写法以这里为准。
- Python API 参考——按类与函数查参数细节。
- langchain-ai/langchain——源码仓库,issue 区能查到大量报错的先例。
- LangGraph 文档——多智能体、持久化、human-in-the-loop 的下一站。
- LangSmith——调试与评估平台,跑复杂 agent 前先把追踪打开。
- LangChain Academy——官方免费课程,含 LangGraph 系统课。
09
收尾:照着勾一遍
0 / 5