前端转agent-【python】-12 LangChain 入门实战:RAG + LCEL 链式调用

前端转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,请先拉取:

bash 复制代码
ollama 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 只需定义 retrieverprompt,一行 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
相关推荐
字节跳动数据库1 小时前
文章分享——相似函数处理方法
人工智能·后端·程序员
程序员cxuan2 小时前
读懂 Claude Code 架构分析系列,第一篇,开始!
人工智能·后端·架构
饼干哥哥2 小时前
扣子3.0测评:我让 Codex 和 Claude Code 住同一个桌面,结果它们打架了!
人工智能·开源·代码规范
Token炼金师3 小时前
IP-Adapter:解耦交叉注意力如何让扩散模型看见图像
人工智能
Bigfish_coding3 小时前
前端转agent-【python】-11 LangGraph 高级特性:时间旅行与人工介入
人工智能
Token炼金师3 小时前
从safetensors到像素:ComfyUI Checkpoint加载机制的底层拆解
人工智能
AI闲人3 小时前
AI 写代码越来越快,为什么 Code Review 反而更慢了?
人工智能·code review·ai 编程
武子康3 小时前
调查研究-202 SGLang 深度解析:为什么大模型推理框架不只是“把模型跑起来“
人工智能·openai·agent
我是大卫3 小时前
Trae 读取 agents.md 并驱动 AI 完整底层原理
人工智能