框架调研 · 09

LangChain:最流行的 LLM 框架

LangChain 是目前 GitHub star 最多的 LLM 框架,几乎是 LLM 应用开发的代名词。但它也是被吐槽最多的框架之一——过度抽象、文档混乱、API 频繁变动。

这篇不是 LangChain 的完整教程,而是帮你快速判断:LangChain 能解决什么问题,什么时候换其他方案更好

GitHub:langchain-ai/langchain

安装

pip install langchain langchain-openai langchain-community

核心概念演进

LangChain 经历了两个时代:

v0.1 时代(Chain 为核心)

# 旧写法:显式链条
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate

chain = LLMChain(
    llm=ChatOpenAI(),
    prompt=PromptTemplate.from_template("翻译成英文:{text}"),
)
result = chain.run(text="你好世界")

v0.2+ 时代(LCEL 为核心)

# 新写法:LCEL 管道
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

llm = ChatOpenAI(model="gpt-4o-mini")
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个翻译助手"),
    ("human", "翻译成英文:{text}"),
])

chain = prompt | llm | StrOutputParser()
result = chain.invoke({"text": "你好世界"})
print(result)  # Hello World

| 是 LCEL(LangChain Expression Language)的管道操作符,把组件串联成链。

LCEL:管道组合

LCEL 的核心思路是函数组合

from langchain_core.runnables import RunnableLambda, RunnablePassthrough

# 每个 Runnable 都实现 .invoke() / .stream() / .batch()
step1 = RunnableLambda(lambda x: x.upper())
step2 = RunnableLambda(lambda x: f"结果:{x}")

chain = step1 | step2
print(chain.invoke("hello"))  # 结果:HELLO

# 并行执行
from langchain_core.runnables import RunnableParallel
parallel = RunnableParallel(
    upper=RunnableLambda(str.upper),
    lower=RunnableLambda(str.lower),
)
print(parallel.invoke("Hello"))  # {"upper": "HELLO", "lower": "hello"}

RAG:检索增强生成

LangChain 在 RAG 场景最成熟:

from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores import Chroma
from langchain_community.document_loaders import TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser

# 1. 加载文档
loader = TextLoader("knowledge.txt", encoding="utf-8")
docs = loader.load()

# 2. 切分
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = splitter.split_documents(docs)

# 3. 向量化存储
vectorstore = Chroma.from_documents(chunks, OpenAIEmbeddings())
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})

# 4. RAG Chain
prompt = ChatPromptTemplate.from_template("""
根据以下上下文回答问题:

上下文:{context}

问题:{question}

回答:""")

rag_chain = (
    {"context": retriever, "question": RunnablePassthrough()}
    | prompt
    | ChatOpenAI(model="gpt-4o-mini")
    | StrOutputParser()
)

result = rag_chain.invoke("什么是 LangGraph?")
print(result)

Agent(工具调用)

from langchain_openai import ChatOpenAI
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.tools import tool
from langchain_core.prompts import ChatPromptTemplate

@tool
def get_weather(city: str) -> str:
    """获取城市天气信息"""
    data = {"北京": "晴天 25°C", "上海": "多云 22°C"}
    return data.get(city, "暂无数据")

@tool
def calculate(expression: str) -> str:
    """计算数学表达式"""
    try:
        return str(eval(expression))
    except:
        return "计算错误"

llm = ChatOpenAI(model="gpt-4o-mini")
tools = [get_weather, calculate]

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个助手,可以查天气和做数学计算。"),
    ("human", "{input}"),
    ("placeholder", "{agent_scratchpad}"),  # Agent 的中间思考过程
])

agent = create_tool_calling_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

result = executor.invoke({"input": "北京天气怎样?另外 100 * 3.14 等于多少?"})
print(result["output"])

流式输出

for chunk in chain.stream({"text": "你好世界"}):
    print(chunk, end="", flush=True)
# Agent 流式
for event in executor.stream({"input": "北京天气?"}):
    if "output" in event:
        print(event["output"])

Memory(历史记忆)

from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationChain

memory = ConversationBufferMemory()
conversation = ConversationChain(
    llm=ChatOpenAI(model="gpt-4o-mini"),
    memory=memory,
    verbose=False,
)

conversation.predict(input="我叫张三")
response = conversation.predict(input="我叫什么名字?")
print(response)  # 应记得张三

LangSmith:可观测性

LangChain 的配套工具 LangSmith 提供 trace:

import os
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "your-langsmith-key"
os.environ["LANGCHAIN_PROJECT"] = "my-project"

# 之后所有 LangChain 调用都会自动记录到 LangSmith
result = rag_chain.invoke("问题")
# 在 LangSmith 控制台可以看到完整执行链路

LangChain 的问题

坦白说,LangChain 有几个真实存在的痛点:

1. 过度抽象

# 简单任务被包装得很重
# 实际上只是:response = llm.invoke(prompt)
# 但 LangChain 要写很多行

2. API 频繁变动

2023 年的代码在 2024 年版本里基本都要改写。

3. 调试困难

三层抽象之间的错误,stack trace 很难读。

4. 性能开销

轻量任务不需要这么重的框架。

什么时候用 LangChain

适合:

  • RAG 场景:文档加载、切分、向量化、检索有大量现成实现
  • 快速原型:大量预置 Loader、Splitter、Retriever
  • 社区工具丰富:需要某个特定 API 集成时,langchain-community 可能已经有了

不适合:

  • 生产环境的核心 Agent 逻辑(优先考虑原厂 SDK 或 LangGraph)
  • 简单的 LLM 调用(直接用 openai/anthropic 包更清晰)
  • 需要精细控制工具调用流程(用 Anthropic SDK 手动写更可控)

和 LangGraph 的关系

LangGraph 是 LangChain 团队开发的图执行框架,两者可以混用:

from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI

# LangGraph 直接支持 LangChain 的 Tool
agent = create_react_agent(
    model=ChatOpenAI(model="gpt-4o-mini"),
    tools=[get_weather, calculate],
)
result = agent.invoke({"messages": [("user", "北京天气")]})

建议: 用 LangGraph 做 Agent 控制流,用 LangChain 的工具/加载器/向量数据库做周边集成,不要用 LangChain 的 Agent 抽象。