Skip to Content
DocsAiLangchainMap

LangChain 的核心思想:链式思维 (Chaining)

想象一下,你要完成一个复杂的任务,比如“总结我上传的这篇PDF,并根据内容回答我的问题”。这个任务可以拆解为:

  1. 加载 PDF 文件。
  2. 读取 文件内容。
  3. 拆分 内容成小块,以便模型处理。
  4. 将文本块转换为向量(一种数学表示)。
  5. 将向量存储起来,方便快速检索。
  6. 当用户提问时,将问题也转换为向量。
  7. 用问题的向量去检索最相关的内容块。
  8. 将问题和检索到的内容组合成一个提示(Prompt)。
  9. 把这个提示喂给大语言模型(LLM)。
  10. 解析并返回模型的答案。

LangChain 的作用就是将这些步骤(组件)标准化,然后像链条一样把它们串联起来,自动化整个流程。你不需要手动去写每一步的胶水代码,只需要选择并配置好合适的“积木”即可。


一、 LangChain 的核心组件 (The “LEGO Bricks”)

这是 LangChain 的基石,理解了它们,你就理解了 LangChain 的一切。

1. Models (模型) - 大脑

这是驱动一切的核心。LangChain 集成了各种模型。

  • LLMs: 普通的语言模型,输入是字符串,输出也是字符串。
    from langchain_openai import OpenAI # 需要在环境变量中设置 OPENAI_API_KEY llm = OpenAI(model_name="gpt-3.5-turbo-instruct") response = llm.invoke("请给我写一首关于宇宙的诗") print(response)
  • Chat Models: 对话模型,为多轮对话优化,输入是消息列表(System, Human, AI),输出是 AI 消息。这是目前更常用的类型。
    from langchain_openai import ChatOpenAI from langchain.schema import HumanMessage, SystemMessage chat = ChatOpenAI(model_name="gpt-4o") messages = [ SystemMessage(content="你是一个专业的菜谱助手。"), HumanMessage(content="你好,请问西红柿炒鸡蛋怎么做?") ] response = chat.invoke(messages) print(response.content)

2. Prompts (提示) - 指示

如何与模型沟通?你需要一个好的提示模板。

  • PromptTemplate: 用于简单的、变量化的提示。
    from langchain.prompts import PromptTemplate prompt_template = PromptTemplate.from_template( "请为我写一个关于 {topic} 的故事大纲。" ) prompt = prompt_template.format(topic="星际旅行") print(prompt) # 输出: "请为我写一个关于星际旅行的故事大纲。"
  • ChatPromptTemplate: 用于对话模型,可以定义系统、用户、AI等不同角色的消息模板。
    from langchain.prompts import ChatPromptTemplate chat_template = ChatPromptTemplate.from_messages([ ("system", "你是一个翻译官,能将{input_language}翻译成{output_language}。"), ("human", "{text}") ]) messages = chat_template.format_messages( input_language="中文", output_language="英文", text="我爱编程" ) # chat.invoke(messages) # 可以直接把这个messages列表传给Chat Model

3. Chains (链) - 胶水和流水线

这是 LangChain 的灵魂,用于将模型和提示等组件粘合在一起。

  • 简单的 LLMChain (传统方式)
    from langchain.chains import LLMChain # 1. 模型 llm = OpenAI(model_name="gpt-3.5-turbo-instruct") # 2. 提示 prompt_template = PromptTemplate.from_template("世界上最高的山是哪座?请用中文回答。") # 3. 链接起来 chain = LLMChain(llm=llm, prompt=prompt_template) # 4. 运行 response = chain.run({}) # 因为模板里没有变量,所以传入空字典 print(response)
  • LCEL (LangChain Expression Language) - 现代化的方式 (强烈推荐!) LCEL 使用管道符 | 来连接组件,更灵活、更强大,支持流式传输、异步、并行等。这是未来的方向。
    from langchain_openai import ChatOpenAI from langchain.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser # 1. 提示 prompt = ChatPromptTemplate.from_template("请告诉我关于 {topic} 的一个冷知识。") # 2. 模型 model = ChatOpenAI() # 3. 输出解析器 (将模型的输出转为字符串) output_parser = StrOutputParser() # 4. 使用管道符 | 链接 chain = prompt | model | output_parser # 5. 调用 response = chain.invoke({"topic": "章鱼"}) print(response)
    LCEL 的 | 符号,你可以理解为:把左边的输出,作为右边的输入。

4. Output Parsers (输出解析器) - 格式化

LLM 的输出是文本,但我们常常需要结构化的数据(如 JSON、列表)。输出解析器就是用来干这个的。

  • PydanticOutputParser: 定义一个 Pydantic 模型,让 LLM 输出符合该模型结构的 JSON。
    from pydantic import BaseModel, Field from langchain.output_parsers import PydanticOutputParser # 1. 定义你的数据结构 class Joke(BaseModel): setup: str = Field(description="笑话的铺垫") punchline: str = Field(description="笑话的点睛之笔") # 2. 创建解析器 parser = PydanticOutputParser(pydantic_object=Joke) # 3. 创建带格式化指令的提示 prompt = ChatPromptTemplate.from_messages([ ("system", "你是一个很棒的笑话机器人。{format_instructions}"), ("human", "请给我讲一个关于程序员的笑话。") ]) chain = prompt | model | parser # 获取格式化指令并注入提示 response = chain.invoke({ "format_instructions": parser.get_format_instructions() }) print(response) print(f"铺垫: {response.setup}") print(f"笑点: {response.punchline}")

5. Indexes and Retrievers (索引与检索器) - 外部知识库 (RAG核心)

这是构建问答机器人、文档分析等应用的关键。它让 LLM 能“看到”你的私有数据。

这个过程通常分为 Indexing (索引)Retrieval (检索) 两步。

  • Indexing 流程:

    1. Document Loaders (文档加载器): 加载各种来源的数据(PDF, TXT, Web, …)。
    2. Text Splitters (文本分割器): 将长文本切分成适合模型处理的小块。
    3. Embeddings (词嵌入): 将文本块转换成向量。这需要一个 Embedding Model。
    4. Vector Stores (向量数据库): 存储这些向量,并提供高效的相似性搜索。
  • Retrieval 流程:

    1. 用户提问。
    2. 将问题也转换成向量。
    3. 去向量数据库中检索与问题向量最相似的文本块向量。
    4. 将这些文本块(即上下文 context)连同问题一起交给 LLM。

一个完整的 RAG 示例 (使用 LCEL):

import os from langchain_openai import OpenAIEmbeddings, ChatOpenAI from langchain.vectorstores import FAISS # 一种简单的本地向量数据库 from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.document_loaders import TextLoader from langchain_core.prompts import ChatPromptTemplate from langchain_core.runnables import RunnablePassthrough from langchain_core.output_parsers import StrOutputParser # --- 1. 索引 (Indexing) --- # 假设我们有一个 'state_of_the_union.txt' 文件 # a. 加载文档 loader = TextLoader("./state_of_the_union.txt") docs = loader.load() # b. 分割文本 text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200) splits = text_splitter.split_documents(docs) # c. 创建向量数据库 # 这会调用 OpenAI Embedding API 将文本转为向量并存储在 FAISS 中 vectorstore = FAISS.from_documents(documents=splits, embedding=OpenAIEmbeddings()) # --- 2. 检索与生成 (Retrieval and Generation) --- # a. 创建检索器 retriever = vectorstore.as_retriever() # b. 创建 RAG 提示模板 template = """ 根据以下上下文来回答问题: {context} 问题: {question} """ prompt = ChatPromptTemplate.from_template(template) # c. 创建 RAG 链 model = ChatOpenAI() rag_chain = ( {"context": retriever, "question": RunnablePassthrough()} | prompt | model | StrOutputParser() ) # d. 调用链 question = "What did the president say about Ketanji Brown Jackson" response = rag_chain.invoke(question) print(response)

代码解释:

  • {"context": retriever, "question": RunnablePassthrough()} 是 LCEL 的一个技巧。它会创建一个字典,question 的值直接来自 invoke 的输入,context 的值则是通过 retriever 处理 invoke 的输入(即问题)得到的。
  • 这个字典随后被传递给 prompt 进行格式化,然后是模型,最后是解析器。

6. Agents (代理) - 思考与行动

如果说 Chain 是固定的流水线,那 Agent 就是一个拥有工具箱的智能工人。它能根据你的问题,自己决定调用哪个工具(如谷歌搜索、计算器、数据库查询等),然后根据工具返回的结果,思考下一步该怎么做,直到问题解决。

from langchain.agents import tool, AgentExecutor, create_react_agent from langchain_community.tools.tavily_search import TavilySearchResults from langchain_openai import ChatOpenAI from langchain import hub # 1. 准备工具 (需要安装 langchain-community 和 tavily-python) # 需要设置 TAVILY_API_KEY 环境变量 search = TavilySearchResults() tools = [search] # 2. 获取 Agent 的核心提示 (ReAct 范式) prompt = hub.pull("hwchase17/react") # 从 LangChain Hub 拉取一个成熟的提示模板 # 3. 创建 Agent llm = ChatOpenAI(model_name="gpt-4o", temperature=0) agent = create_react_agent(llm, tools, prompt) # 4. 创建 Agent 执行器 agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True) # verbose=True 可以看到思考过程 # 5. 运行 agent_executor.invoke({"input": "今天北京的天气怎么样?2024年诺贝尔物理学奖得主是谁?"})

当你运行这个 Agent,verbose=True 会打印出它的思考过程,你会看到它先决定使用搜索工具查天气,得到答案;然后再次决定使用搜索工具查诺贝尔奖得主,最后汇总答案。


二、如何开始你的第一个 LangChain 项目

  1. 明确目标: 你想做什么?一个简单的问答机器人?一个能帮你写代码的助手?还是一个能查询公司内部文档的系统?
  2. 选择模式:
    • 如果任务流程是固定的(比如,总结文本、翻译),用 Chain
    • 如果需要与外部世界互动,且步骤不固定(比如,查询实时信息、执行代码),用 Agent
    • 如果需要基于你的私有数据进行问答,核心就是 RAG (Retrieval-Augmented Generation),它本身就是一个特殊的 Chain。
  3. 搭建你的链 (使用 LCEL):
    • 输入: 你的 Chain 需要什么输入?(一个字符串?一个字典?)
    • 提示: 设计你的 ChatPromptTemplate
    • 模型: 选择合适的 ChatOpenAI 或其他模型。
    • 检索 (如果需要): 准备你的文档,配置 DocumentLoader, TextSplitter, Embedding, VectorStore,并创建 retriever
    • 输出: 你希望得到什么格式的输出?字符串(StrOutputParser)还是 JSON(PydanticOutputParser)?
    • | 把它们串起来!

三、调试与观察:LangSmith

在开发过程中,你会想知道你的链或 Agent 内部到底发生了什么。LangSmith 是 LangChain 官方提供的调试、监控和评估平台。强烈建议你使用它!

你只需要设置几个环境变量,LangChain 就会自动将每次运行的详细步骤、输入输出、耗时等信息记录到 LangSmith 平台,可视化地展示给你,这对于调试复杂的链和 Agent 来说是无价的。

export LANGCHAIN_TRACING_V2="true" export LANGCHAIN_API_KEY="..." # 在 LangSmith 网站上获取 # export LANGCHAIN_PROJECT="My First Project" # (可选) 指定项目名称
Last updated on