LangChain入门:用Python构建LLM应用
当你第一次用 OpenAI SDK 调通一个大模型,那种“AI 真的能听懂我说话”的兴奋感会持续好几天。但兴奋过后,真正的工程问题随之而来:如何复用提示词?如何让模型记住上下文?如何让模型调用外部工具?如何把私有文档喂给模型?这些问题单靠一个 chat.completions.create 是解决不了的。
这就是 LangChain 出现的原因。它是目前最流行的 LLM 应用开发框架,把“模型调用、提示词管理、记忆、工具、检索”抽象成可组合的组件,让你像搭积木一样构建复杂的 AI 应用。本文将从零开始,带你用 Python 跑通 LangChain 的核心能力,并在最后展示如何通过 EnlyAI 统一 API 接入多种模型。
一、LangChain 是什么
LangChain 最初由 Harrison Chase 在 2022 年底开源,定位是“面向大语言模型的应用开发框架”。它的核心理念是:把 LLM 应用拆解成可组合的模块,而不是把所有逻辑塞进一个巨大的 prompt 字符串里。
LangChain 的核心模块包括:
- Models:统一封装各类模型的调用接口(聊天模型、文本模型、嵌入模型)。
- Prompts:提示词模板,支持变量插值和 Few-shot 示例。
- Chains:把多个组件串联成一条处理流水线。
- Memory:跨轮次的对话记忆。
- Retrievers:从向量数据库检索相关文档,支撑 RAG。
- Agents:让模型自主决定调用哪些工具来完成任务。
理解这六个模块,就理解了 LangChain 的全部骨架。下面我们逐一上手。
二、环境搭建与安装
LangChain 在 0.2 版本之后做了模块化拆分,主包只包含核心抽象,具体模型的集成需要单独安装。对于大多数开发者,推荐直接安装 langchain 和 langchain-openai。
# 安装 LangChain 核心包与 OpenAI 集成
pip install langchain langchain-openai
# 如果需要 RAG,再装向量库和文本分割器
pip install langchain-community faiss-cpu
安装完成后,建议把 API 密钥放到环境变量里,而不是硬编码在脚本中:
# Linux / macOS
export OPENAI_API_KEY="sk-your-api-key"
export OPENAI_BASE_URL="https://enlyai.com/v1"
# Windows PowerShell
# $env:OPENAI_API_KEY="sk-your-api-key"
# $env:OPENAI_BASE_URL="https://enlyai.com/v1"
提示:把
OPENAI_BASE_URL指向https://enlyai.com/v1,LangChain 就会通过 EnlyAI 聚合平台调用模型,一套密钥即可访问 GPT、Claude、Gemini 等数十种模型。
三、第一次调用:ChatOpenAI
LangChain 中最常用的模型类是 ChatOpenAI,它封装了 OpenAI 兼容的聊天接口。由于 EnlyAI 完全兼容 OpenAI API 格式,所以可以直接用这个类接入。
from langchain_openai import ChatOpenAI
# 通过 EnlyAI 统一接入,可随时切换底层模型
llm = ChatOpenAI(
model="gpt-4o-mini",
api_key="sk-your-api-key",
base_url="https://enlyai.com/v1",
temperature=0.3
)
# 直接传入字符串即可调用
response = llm.invoke("用一句话解释什么是向量数据库")
print(response.content)
这里有几个关键参数需要理解:
model:模型名称。通过 EnlyAI 接入时,可以填gpt-4o-mini、claude-3-5-sonnet、gemini-2.0-flash等。temperature:取值 0 到 1,越低越确定,越高越有创造力。技术问答建议 0.2-0.3,创意写作建议 0.7-0.9。base_url:API 地址。指向 EnlyAI 后,所有调用都走聚合通道。
四、提示词模板:PromptTemplate
真实应用中,提示词往往很长,而且包含动态变量。直接用 f-string 拼接会让代码很难维护。LangChain 提供了 ChatPromptTemplate 来管理提示词结构。
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages([
("system", "你是一位资深 {role},请用专业但易懂的语言回答。"),
("user", "{question}")
])
# 渲染模板
messages = prompt.invoke({
"role": "数据库工程师",
"question": "为什么 PostgreSQL 比 MySQL 更适合复杂查询?"
})
print(messages)
from_messages 接收一个消息列表,每条消息是 (角色, 内容) 元组。花括号里的 {role} 和 {question} 是变量,调用 invoke 时传入字典即可填充。
五、链(Chains):LCEL 表达式
LangChain 0.2 之后推荐使用 LCEL(LangChain Expression Language) 来构建链。它的语法非常优雅:用管道符 | 把组件串联起来,就像 Unix 管道一样。
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
llm = ChatOpenAI(
model="gpt-4o-mini",
api_key="sk-your-api-key",
base_url="https://enlyai.com/v1"
)
prompt = ChatPromptTemplate.from_template("请把以下文本翻译成{language}:\n{text}")
# 用管道符串联:prompt -> llm -> 输出解析器
chain = prompt | llm | StrOutputParser()
result = chain.invoke({
"language": "英文",
"text": "大模型让软件开发变得更有趣了"
})
print(result)
这条链的执行流程是:prompt 把输入字典渲染成消息 → llm 调用模型生成回复 → StrOutputParser 把回复对象转成纯字符串。LCEL 的好处是每个组件都支持 invoke / stream / batch,切换流式输出只需把 invoke 换成 stream:
# 流式输出
for chunk in chain.stream({
"language": "日文",
"text": "今天天气真好"
}):
print(chunk, end="", flush=True)
六、记忆(Memory):多轮对话
LLM 本身是无状态的,每次调用都是独立的。要实现“记得上一轮说了什么”的多轮对话,需要把历史消息拼到当前请求里。LangChain 提供了 ChatMessageHistory 来管理对话历史。
from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
llm = ChatOpenAI(
model="gpt-4o-mini",
api_key="sk-your-api-key",
base_url="https://enlyai.com/v1"
)
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个友好的助手,记住之前的对话内容。"),
"placeholder", # 这里会自动插入历史消息
("user", "{input}")
])
chain = prompt | llm
# 用 session_id 区分不同用户的会话
store = {}
def get_history(session_id):
if session_id not in store:
store[session_id] = InMemoryChatMessageHistory()
return store[session_id]
chain_with_history = RunnableWithMessageHistory(
chain, get_history,
input_messages_key="input",
history_factory_config=[]
)
# 第一轮
r1 = chain_with_history.invoke(
{"input": "我叫小明,今年 28 岁"},
config={"configurable": {"session_id": "user-1"}}
)
print(r1.content)
# 第二轮,模型能记住上一轮的信息
r2 = chain_with_history.invoke(
{"input": "我刚才告诉你我叫什么?"},
config={"configurable": {"session_id": "user-1"}}
)
print(r2.content) # 会回答"小明"
生产环境中,建议把 InMemoryChatMessageHistory 换成 Redis 或数据库实现,避免服务重启后丢失历史。
七、RAG:让模型读懂你的私有文档
RAG(Retrieval-Augmented Generation,检索增强生成)是 LangChain 最热门的应用场景。它的思路是:先从知识库中检索出与问题相关的文档片段,再把这些片段塞进 prompt,让模型基于文档回答。这样既能让模型“知道”私有知识,又能避免幻觉。
一个最小可用的 RAG 流程如下:
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 1. 准备文档
docs_text = """
EnlyAI 是一个 LLM API 聚合平台,支持 OpenAI、Claude、Gemini 等多种模型。
API base URL 是 https://enlyai.com/v1,完全兼容 OpenAI API 格式。
新用户注册即送免费额度,可以在控制台查看用量和账单。
"""
# 2. 切分文档
splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=20)
chunks = splitter.create_documents([docs_text])
# 3. 生成嵌入并存入向量库
embeddings = OpenAIEmbeddings(
api_key="sk-your-api-key",
base_url="https://enlyai.com/v1"
)
vectorstore = FAISS.from_documents(chunks, embeddings)
# 4. 构建检索器
retriever = vectorstore.as_retriever(search_kwargs={"k": 2})
# 5. 检索 + 生成
llm = ChatOpenAI(
model="gpt-4o-mini",
api_key="sk-your-api-key",
base_url="https://enlyai.com/v1"
)
prompt = ChatPromptTemplate.from_template("""
根据以下资料回答问题。如果资料里没有答案,请说"我不知道"。
资料:
{context}
问题:{question}
""")
from langchain_core.runnables import RunnablePassthrough
rag_chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt | llm | StrOutputParser()
)
answer = rag_chain.invoke("EnlyAI 的 API 地址是什么?")
print(answer) # 会回答 https://enlyai.com/v1
这段代码完成了“切分 → 嵌入 → 存储 → 检索 → 生成”的完整闭环。实际项目中,你只需要把 docs_text 换成从 PDF、网页或数据库加载的真实文档即可。
八、Agent:让模型自主调用工具
前面所有例子都是“固定流程”:输入 → 处理 → 输出。但有些任务需要模型自主决策——比如“查一下北京明天天气,然后写一首诗”,模型需要先调用天气工具,拿到结果后再写诗。这就是 Agent 的用武之地。
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate
# 定义一个工具:计算器
@tool
def calculate(expression: str) -> str:
"""计算一个数学表达式并返回结果。输入应为合法的 Python 表达式,例如 '12 * 8 + 5'。"""
return str(eval(expression))
llm = ChatOpenAI(
model="gpt-4o-mini",
api_key="sk-your-api-key",
base_url="https://enlyai.com/v1"
)
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个能调用工具的助手。"),
("user", "{input}"),
("placeholder", "{agent_scratchpad}")
])
tools = [calculate]
agent = create_tool_calling_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
result = executor.invoke({"input": "帮我算一下 (123 + 456) * 2 等于多少"})
print(result["output"])
运行后你会看到模型先调用 calculate 工具,拿到 1158,再组织成自然语言回复。Agent 的强大之处在于:你只需要定义工具,模型会自己决定什么时候用、怎么用。
九、用 EnlyAI 统一接入多模型
前面所有代码都用了 gpt-4o-mini。但真实业务中,你可能需要在不同模型间切换:用 GPT-4o 做复杂推理,用 Claude 写文案,用 Gemini 处理长文档。如果每个模型都单独对接,密钥管理、计费、SDK 切换会非常麻烦。
EnlyAI 提供了统一 API 接口,完全兼容 OpenAI 格式。你只需要把 base_url 指向 https://enlyai.com/v1,就能用同一套 LangChain 代码调用几十种模型:
from langchain_openai import ChatOpenAI
# 同一套代码,只改 model 名称即可切换
configs = [
{"model": "gpt-4o-mini", "desc": "GPT-4o mini"},
{"model": "claude-3-5-sonnet", "desc": "Claude 3.5 Sonnet"},
{"model": "gemini-2.0-flash", "desc": "Gemini 2.0 Flash"},
]
question = "用一句话解释什么是 RAG"
for cfg in configs:
llm = ChatOpenAI(
model=cfg["model"],
api_key="sk-your-enlyai-key",
base_url="https://enlyai.com/v1"
)
answer = llm.invoke(question)
print(f"[{cfg['desc']}] -> {answer.content}")
对应的 cURL 测试命令,方便你在终端快速验证:
curl https://enlyai.com/v1/chat/completions \
-H "Authorization: Bearer sk-your-enlyai-key" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-3-5-sonnet",
"messages": [{"role": "user", "content": "用一句话解释什么是 RAG"}]
}'
统一 API 的价值在于:
- 一套密钥:不用在每个平台分别注册、充值、管理 key。
- 统一计费:所有模型调用汇总在一个账单,方便成本分析。
- 故障转移:某个模型服务波动时,改一个字符串就能切换备用模型。
- 零迁移成本:原本基于 OpenAI SDK 的 LangChain 代码几乎不用改。
十、生产环境最佳实践
把 LangChain 应用从 Demo 推向生产,有几点经验值得分享:
- 用 LCEL 而不是旧的 LLMChain:LCEL 原生支持流式、异步、批量,性能更好,且是官方主推方向。
- 把记忆持久化:生产环境不要用
InMemoryChatMessageHistory,改用 Redis 或数据库,否则服务重启历史就丢了。 - 限制 Agent 的迭代次数:用
max_iterations防止 Agent 陷入死循环烧 token。 - 监控 token 消耗:每次调用都记录
usage_metadata,否则账单会悄悄失控。 - 密钥走环境变量:永远不要把 API key 写死在代码里,用
os.getenv("OPENAI_API_KEY")读取。 - 给 RAG 加引用来源:让模型在回答中标注引用了哪些文档片段,方便用户核实,也能降低幻觉风险。
总结
LangChain 的学习曲线确实比直接调 OpenAI SDK 陡峭,但它解决的问题也是真实的:当你的应用从“单次问答”进化到“多轮对话 + 文档检索 + 工具调用”时,没有一个框架会非常痛苦。掌握本文讲的六个核心模块——Models、Prompts、Chains、Memory、Retrievers、Agents——你就能应对绝大多数 LLM 应用场景。
而把 LangChain 和 EnlyAI 统一 API 结合起来,你既能享受框架的工程能力,又能用一套密钥、一个地址访问所有主流大模型,把精力集中在业务逻辑而不是基础设施上。
想用 LangChain 调用所有主流大模型?
EnlyAI 提供 OpenAI 兼容的统一接口,支持 GPT、Claude、Gemini 等数十种模型,注册即送免费额度,LangChain 代码只需改一个 base_url 即可接入。
立即注册 EnlyAI →