前端转agent-【python】-12 LangChain 集成:用框架快速搭建 RAG 与链
之前我们用纯 Python 手写了记忆管理、语义检索、状态图和工具调用。轮子造得爽,但生产环境总该有更快的办法。
LangChain 就是这些轮子的"标准化工厂",把常见模式封装成可组合的模块。
今天用 LangChain 重写我们的 RAG 流程,再用 LCEL(LangChain Expression Language)串一条问答链,感受"搭积木"的快感。
为什么学 LangChain?
| 手写版本(07/09) | LangChain 对应 | 类比 Vue 3 |
|---|---|---|
| 手动管理消息列表 | ChatPromptTemplate + MessagesPlaceholder |
自己写 reactive 对象 vs 用 useChatMessages |
调 ollama.chat() |
ChatOllama |
直接 fetch vs 用 useFetch |
| 手写 ChromaDB 检索逻辑 | Chroma vectorstore + Retriever |
手写 IndexedDB 查询 vs 用 useVectorStore |
| 手动拼接上下文 | create_stuff_documents_chain |
手动拼接 props vs 用 v-bind 自动展开 |
LangChain 不改变底层原理,只是把"手动拼字符串、手动调 API"变成声明式链式调用。理解原理后用它,事半功倍。
环境准备
bash
pip install langchain langchain-ollama langchain-chroma sentence-transformers
模型:
bash
ollama pull qwen3:4b
用 LangChain 重写 RAG 流程
RAG(检索增强生成)的核心是:把相关文档片段注入提示词,让 LLM 基于这些内容回答 。
之前我们用 ChromaDB 手动检索,然后手动拼接 messages。现在用 LangChain 自动化。
第一步:准备文档并建立向量存储
python
# rag_with_langchain.py
from langchain_ollama import ChatOllama, OllamaEmbeddings
from langchain_chroma import Chroma
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_core.documents import Document
# 模拟产品文档
docs = [
Document(page_content="智能手表续航7天,支持IP68防水。", metadata={"source": "specs"}),
Document(page_content="退货政策:7天内无理由退货,30天内质量问题换货。", metadata={"source": "policy"}),
Document(page_content="客服电话:400-123-4567,工作时间9:00-18:00。", metadata={"source": "contact"}),
]
# 分割文本(正式项目可调整参数)
splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=20)
chunks = splitter.split_documents(docs)
# 嵌入模型(使用 Ollama 本地嵌入,需要先 pull 嵌入模型)
# ollama pull nomic-embed-text (小型嵌入模型)
embedding_model = OllamaEmbeddings(model="nomic-embed-text")
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embedding_model,
persist_directory="./langchain_chroma_db" # 持久化目录
)
注意 :Ollama 需要一个嵌入模型,这里用
nomic-embed-text,请先拉取:
bashollama pull nomic-embed-text
第二步:构建检索链
python
# rag_with_langchain.py(接上段)
from langchain_core.prompts import ChatPromptTemplate
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain.chains import create_retrieval_chain
# 定义 LLM
llm = ChatOllama(model="qwen3:4b", temperature=0)
# 提示词模板
prompt = ChatPromptTemplate.from_template("""
你是一个电商客服助手。根据以下已知信息回答问题。
如果找不到答案,请说"暂时没有相关信息"。
已知信息:
{context}
用户问题:{input}
回答:
""")
# 创建"填充文档"链:将检索到的文档填入 prompt 的 {context}
combine_docs_chain = create_stuff_documents_chain(llm, prompt)
# 创建完整的 RAG 链:检索 + 生成
rag_chain = create_retrieval_chain(
retriever=vectorstore.as_retriever(search_kwargs={"k": 2}),
combine_docs_chain=combine_docs_chain
)
对比手写版:
- 手写时要
query -> embedding -> search -> 取文档 -> 拼字符串 -> 调 llm。 - LangChain 只需定义
retriever和prompt,一行create_retrieval_chain完成。
第三步:测试 RAG
python
# 接 rag_with_langchain.py
result = rag_chain.invoke({"input": "手表防水吗?"})
print(result["answer"])
# 输出:是的,智能手表支持IP68防水。
result2 = rag_chain.invoke({"input": "怎么退货?"})
print(result2["answer"])
# 输出:7天内无理由退货,30天内质量问题换货。
用 LCEL 构建更灵活的链
LCEL(LangChain Expression Language)是 LangChain 的"管道操作符" |,让链的定义像 Unix 管道一样直观。
python
# lcel_demo.py
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
# 自定义 prompt
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个幽默的助手,用一句话回答。"),
("user", "{input}")
])
# LCEL 链:prompt -> llm -> 解析器
chain = prompt | llm | StrOutputParser()
# 调用
print(chain.invoke({"input": "什么是人工智能?"}))
# 可能输出:人工智能就是让电脑学会偷懒还能领工资(开玩笑啦)。
加上检索的 LCEL 写法
python
# lcel_rag.py
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)
rag_chain_lcel = (
{
"context": vectorstore.as_retriever() | format_docs,
"input": RunnablePassthrough()
}
| prompt
| llm
| StrOutputParser()
)
print(rag_chain_lcel.invoke("客服电话多少?"))
# 输出:客服电话是400-123-4567,工作时间9:00-18:00。
Vue 3 类比 :LCEL 就像 Vue 的模板编译,| 操作符如同管道 |,RunnablePassthrough() 相当于 props 透传。整个过程是响应式的:输入一变,链自动重跑。
将之前的工具调用改造成 LangChain Agent
LangChain 内置了 create_tool_calling_agent + AgentExecutor,它能自动解析 LLM 输出的工具调用并循环执行。对比如下:
python
# tool_agent_langchain.py
from langchain_ollama import ChatOllama
from langchain_core.tools import tool
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_core.prompts import ChatPromptTemplate
@tool
def get_weather(city: str) -> str:
"""查询指定城市的天气"""
return {"北京":"晴","上海":"雨"}.get(city, "未知")
@tool
def calculator(expression: str) -> str:
"""计算数学表达式"""
try:
return str(eval(expression, {"__builtins__": {}}))
except:
return "计算错误"
llm = ChatOllama(model="qwen3:4b")
tools = [get_weather, calculator]
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个助手,可以使用工具。"),
("human", "{input}"),
("placeholder", "{agent_scratchpad}") # 工具调用的中间步骤
])
agent = create_tool_calling_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=False)
result = agent_executor.invoke({"input": "北京天气和 3*9 是多少?"})
print(result["output"])
自动循环 :AgentExecutor 内部就是一个 while 循环,直到 LLM 不再调用工具,完全替代了之前我们手写的 LangGraph 循环。
Vue 3 横向总结
| LangChain 概念 | Vue 3 类比 |
|--------------------------------|------------------------------------|-----------------------------------------------|
| ChatPromptTemplate | 组件模板,{{ variable }} 占位 |
| create_stuff_documents_chain | 一个组合式函数,内部处理文档拼接 |
| create_retrieval_chain | 封装了异步检索和生成的 useQuery |
| LCEL ` | ` 管道 | Vue 的 computed(() => ...) 或 transform 函数链 |
| @tool 装饰器 | 定义一个 action 方法,框架自动暴露给 LLM |
| AgentExecutor | 内置 while 循环的状态机,类似我们之前写的 LangGraph |
什么时候用 LangChain,什么时候用 LangGraph?
- LangChain:适合标准流程(RAG、普通链、简单工具调用),开箱即用。
- LangGraph:适合复杂状态机、多分支、需要检查点和中断的自定义流程。
两者来自同一团队,可以无缝混用。
总结
- LangChain 把之前我们手写的逻辑封装成了模块,代码量减少 50% 以上。
- 核心还是消息列表、检索、提示词、工具调用------理解原理后用它,如虎添翼。
- 对于 Vue 3 开发者来说,LangChain 就是 AI 领域的"VueUse + 状态管理",让你快速搭建可靠的应用。
- 建议先学原理再学框架,现在你可以自信地说:我不只会用 LangChain,我知道它下面怎么跑。
开始你的"搭积木"之旅吧:
bash
python rag_with_langchain.py