当前位置: 首页 > news >正文

LangChain实战:构建具备RAG与Agent能力的智能应用

在实际 AI 应用开发中,将大语言模型(LLM)与外部知识、工具和流程连接起来,是构建真正有价值应用的关键。LangChain 作为一个开源框架,正是为了解决这一核心问题而生,它通过标准化的组件和接口,极大地简化了 LLM 应用的开发流程。然而,面对 LangChain 庞大的概念体系和快速迭代的版本,许多开发者,尤其是初学者,常常感到无从下手,或者仅仅停留在调用 API 的层面,无法构建出具备复杂逻辑和自主决策能力的智能应用。

本文旨在提供一个面向 2026 年技术栈的 LangChain 实战视角,不仅帮助你快速理解其核心概念,更将带你深入 Agent(智能体)和 RAG(检索增强生成)这两个当前最受关注的技术领域。我们将从一个具体的 Agentic RAG 项目实战出发,通过代码和配置,让你掌握如何让 LLM 学会“思考”和“行动”,如何让模型基于私有知识库给出精准回答。无论你是希望将 AI 能力集成到现有业务系统的工程师,还是对构建下一代 AI 应用充满好奇的开发者,这篇文章都将为你提供一条清晰、可复现的实践路径。

1. 理解 LangChain 的核心:组件、链与智能体

在开始写代码之前,必须厘清 LangChain 的几个核心抽象。这能让你在后续配置和调试时,清楚地知道自己在操作什么,以及为什么需要这样操作。

1.1 核心组件:构建应用的积木

LangChain 将 LLM 应用开发拆解为一系列可复用的组件。理解这些组件是理解整个框架的基础。

  • 模型 I/O (Model I/O):这是与 LLM 交互的入口。主要包括:
    • LLMs:封装了文本输入、文本输出的模型,如 OpenAI 的 GPT 系列。
    • Chat Models:封装了基于消息(SystemMessage,HumanMessage,AIMessage)进行对话的模型,这是更推荐的方式,因为它能更好地维护对话上下文和角色。
    • 提示词模板 (Prompt Templates):用于动态生成提示词的模板,可以将用户输入、上下文等信息格式化后喂给模型。
  • 检索 (Retrieval):这是 RAG 的基石。负责从外部知识源(如向量数据库)中,根据用户问题查找相关文档片段。
    • 文档加载器 (Document Loaders):从各种来源(TXT, PDF, 网页,数据库)加载文档。
    • 文本分割器 (Text Splitters):将长文档切割成适合模型处理和检索的小块。
    • 向量存储 (Vectorstores):存储文档嵌入(向量)并支持相似性检索的数据库,如 Chroma, Pinecone, Weaviate。
    • 检索器 (Retrievers):封装了从向量存储中检索文档的接口。
  • 记忆 (Memory):让链或智能体拥有“记忆”能力,记住对话历史或中间状态。常见的如ConversationBufferMemory
  • 工具 (Tools):赋予模型与现实世界交互的能力。一个工具就是一个函数,模型可以调用它来执行特定操作,如搜索网页、查询数据库、执行计算等。

1.2 链 (Chains):将组件串联成流程

链是 LangChain 的核心编排逻辑。它将多个组件(或多个链)按顺序组合起来,形成一个完整的处理流程。最简单的链是LLMChain(提示词 + 模型)。更复杂的链如RetrievalQA链,内部就串联了检索器 -> 提示词模板 -> LLM 的流程。

# 一个简单的 LLMChain 示例结构 from langchain.prompts import ChatPromptTemplate from langchain.chat_models import ChatOpenAI from langchain.chains import LLMChain prompt = ChatPromptTemplate.from_template(“你是一个助手,请用中文回答关于{topic}的问题。”) llm = ChatOpenAI(model=“gpt-4”, temperature=0) chain = LLMChain(llm=llm, prompt=prompt) # 运行链 result = chain.run(topic=“机器学习”) print(result)

1.3 智能体 (Agents) 与 LangGraph:从流程到决策

智能体是 LangChain 的进阶概念。如果说链是预定义的、线性的工作流,那么智能体则赋予了 LLM 自主决策的能力。智能体的核心是一个“大脑”(通常是 LLM)和一套可供其使用的“工具”。

  1. 智能体工作流程

    • 用户提出一个问题或请求。
    • 智能体(LLM)根据当前上下文(问题、历史、可用工具描述)进行“思考”,决定下一步该做什么。
    • 可能的决策包括:调用某个工具、直接给出最终答案、或者需要更多信息。
    • 如果调用工具,则执行工具函数,并将工具返回的结果作为新的上下文,再次让 LLM 进行“思考”。
    • 循环此过程,直到 LLM 认为可以给出最终答案为止。
  2. LangChain 与 LangGraph 的区别: 这是当前社区的一个热点。简单来说:

    • LangChain Agents:提供了高级别的、开箱即用的智能体实现(如create_react_agent),易于上手,适合标准场景。
    • LangGraph:是一个基于图(Graph)的、更低级别的框架,用于构建有状态、多参与者的复杂工作流。它让你能精细控制智能体的每一步决策循环、状态转移和分支逻辑。如果你需要构建高度定制化、涉及复杂循环或多人协作的智能体,LangGraph 是更强大的选择。对于大多数入门和中级 RAG 场景,LangChain 的标准智能体已足够。

2. 环境准备与项目初始化

我们将构建一个 Agentic RAG 项目:一个能根据本地知识库回答问题,并且在需要时能使用搜索工具查询最新信息的智能助手。

2.1 环境与依赖配置

首先确保你的 Python 环境(建议 3.9+)并安装核心依赖。我们将使用 OpenAI 的模型、Chroma 作为本地向量数据库。

# 创建项目目录并进入 mkdir agentic-rag-project && cd agentic-rag-project # 创建虚拟环境(可选但推荐) python -m venv venv # Windows: venv\Scripts\activate # Mac/Linux: source venv/bin/activate # 安装核心 LangChain 包和 OpenAI pip install langchain langchain-openai langchain-community # 安装向量数据库 Chroma 和嵌入模型相关 pip install chromadb langchain-chroma # 安装用于网页检索的工具(如 Tavily,或其他) pip install langchain-tavily # 安装环境变量管理库 pip install python-dotenv

注意:langchain-openai,langchain-chroma,langchain-tavily是 LangChain 官方维护的集成包,其命名和导入方式可能与早期版本(直接来自langchain.llmslangchain.embeddings)不同。使用新版集成包是 2026 年教程的推荐做法,能获得更好的兼容性和支持。

2.2 项目结构与关键文件

一个清晰的项目结构有助于管理代码和配置。

agentic-rag-project/ ├── .env # 存储 API Keys 等敏感信息 ├── requirements.txt # 项目依赖 ├── data/ # 存放原始知识文档 │ └── your_document.pdf ├── docs/ # 处理后的文档片段(可选) ├── vectorstore/ # Chroma 持久化数据存放目录 ├── config.py # 配置文件 ├── ingest.py # 文档加载与向量化脚本 └── main.py # 主应用/智能体脚本

2.3 配置 API 密钥

在项目根目录创建.env文件,并填入你的 API 密钥。切勿将此文件提交到版本控制系统

# .env OPENAI_API_KEY=sk-your-openai-api-key-here TAVILY_API_KEY=tvly-your-tavily-api-key-here # 用于网络搜索工具

config.py中读取配置:

# config.py import os from dotenv import load_dotenv load_dotenv() # 加载 .env 文件中的环境变量 OPENAI_API_KEY = os.getenv(“OPENAI_API_KEY”) TAVILY_API_KEY = os.getenv(“TAVILY_API_KEY”) # 向量数据库持久化路径 PERSIST_DIRECTORY = “./vectorstore” # 原始数据路径 DATA_PATH = “./data”

3. 构建知识库:文档加载、处理与向量化

RAG 的第一步是创建私有知识库。这个过程通常称为“嵌入”或“向量化”。

3.1 文档加载与分割

创建ingest.py脚本,负责将原始文档处理成向量数据库可用的格式。

# ingest.py from langchain_community.document_loaders import PyPDFLoader, TextLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_openai import OpenAIEmbeddings from langchain_chroma import Chroma import os from config import DATA_PATH, PERSIST_DIRECTORY, OPENAI_API_KEY def ingest_documents(): “”” 加载指定目录下的文档,分割文本,生成嵌入并存入向量数据库。 “”” documents = [] # 遍历数据目录,根据后缀名选择加载器 for filename in os.listdir(DATA_PATH): file_path = os.path.join(DATA_PATH, filename) if filename.endswith(“.pdf”): loader = PyPDFLoader(file_path) elif filename.endswith(“.txt”): loader = TextLoader(file_path, encoding=“utf-8”) else: continue # 可扩展支持更多格式 loaded_docs = loader.load() documents.extend(loaded_docs) print(f“已加载文档: {filename}”) if not documents: print(“未找到可处理的文档。”) return # 分割文本 text_splitter = RecursiveCharacterTextSplitter( chunk_size=1000, # 每个文本块的最大字符数 chunk_overlap=200, # 块之间的重叠字符数,保持上下文连贯 separators=[“\n\n”, “\n”, “。”, “.”, “ ”, “”, “”] # 中文友好的分隔符 ) splits = text_splitter.split_documents(documents) print(f“原始文档分割为 {len(splits)} 个文本块。”) # 初始化嵌入模型 embeddings = OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY) # 创建并持久化向量存储 vectordb = Chroma.from_documents( documents=splits, embedding=embeddings, persist_directory=PERSIST_DIRECTORY ) vectordb.persist() # 确保数据写入磁盘 print(f“向量数据库已创建并保存至 {PERSIST_DIRECTORY}”) if __name__ == “__main__”: ingest_documents()

关键参数解释

  • chunk_size:决定检索精度和模型处理效率。太小会丢失上下文,太大会引入噪声。1000-1500 是常见起点。
  • chunk_overlap:防止一个句子或概念被生硬地切断,重叠部分能帮助模型理解边界信息。
  • separators:分割符列表,按优先级尝试分割。我们加入了中文句号“。”,这对中文文档处理很重要。

运行此脚本以构建知识库:

python ingest.py

3.2 验证向量数据库

可以编写一个简单的脚本来测试检索功能。

# test_retrieval.py from langchain_openai import OpenAIEmbeddings from langchain_chroma import Chroma from config import PERSIST_DIRECTORY, OPENAI_API_KEY embeddings = OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY) vectordb = Chroma(persist_directory=PERSIST_DIRECTORY, embedding_function=embeddings) # 进行相似性检索 query = “你的知识文档中的某个核心概念” retrieved_docs = vectordb.similarity_search(query, k=3) # 返回最相关的3个文档块 print(f“查询: ‘{query}’\n”) for i, doc in enumerate(retrieved_docs): print(f“--- 检索结果 {i+1} ---“) print(doc.page_content[:500]) # 打印前500个字符 print(“\n”)

4. 创建智能体:整合工具与决策逻辑

现在,我们将创建一个智能体,它拥有两个核心工具:1) 从本地向量数据库检索知识(RAG),2) 搜索互联网获取最新信息。

4.1 定义工具

首先,在main.py中定义工具函数,并使用 LangChain 的@tool装饰器将其包装成智能体可识别的工具。

# main.py from langchain_openai import ChatOpenAI from langchain.agents import AgentExecutor, create_react_agent from langchain import hub from langchain.tools import tool from langchain_chroma import Chroma from langchain_openai import OpenAIEmbeddings from langchain_community.tools.tavily_search import TavilySearchResults from config import * # 工具1: RAG 检索工具 @tool def retrieve_from_knowledge_base(query: str) -> str: “”” 当问题涉及公司内部知识、私有文档或特定领域信息时,使用此工具。 输入应为清晰的自然语言问题。 “”” embeddings = OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY) vectordb = Chroma(persist_directory=PERSIST_DIRECTORY, embedding_function=embeddings) docs = vectordb.similarity_search(query, k=4) # 将检索到的文档内容合并成一个上下文字符串 context = “\n\n”.join([doc.page_content for doc in docs]) return f“以下是从知识库中检索到的相关信息:\n{context}” # 工具2: 网络搜索工具 # 注意:这里直接使用 TavilySearchResults,它本身就是一个 LangChain Tool 实例 search_tool = TavilySearchResults(api_key=TAVILY_API_KEY, max_results=3) # 将工具组合成列表 tools = [retrieve_from_knowledge_base, search_tool]

4.2 初始化智能体

使用 ReAct 框架来创建智能体。ReAct 提示词鼓励模型进行“推理(Reasoning)”和“行动(Acting)”。

# main.py (续) def create_agent(): # 1. 加载一个预定义的 ReAct 提示词模板 # 可以从 LangChain Hub 拉取,也可以使用本地定义 prompt = hub.pull(“hwchase17/react”) # 一个广泛使用的 ReAct 提示词 # 2. 初始化 LLM llm = ChatOpenAI( model=“gpt-4”, # 或 “gpt-3.5-turbo”,智能体任务建议使用能力更强的模型 temperature=0, # 降低随机性,使决策更稳定 openai_api_key=OPENAI_API_KEY ) # 3. 创建智能体 agent = create_react_agent(llm, tools, prompt) # 4. 创建执行器,它负责运行智能体的决策循环 agent_executor = AgentExecutor( agent=agent, tools=tools, verbose=True, # 打印详细的思考过程,调试时非常有用 handle_parsing_errors=True, # 处理模型输出解析错误 max_iterations=5, # 防止智能体陷入无限循环 early_stopping_method=“generate” # 当模型决定最终答案时停止 ) return agent_executor

4.3 运行与测试智能体

最后,编写主函数来运行智能体并与用户交互。

# main.py (续) def main(): print(“初始化智能体...”) agent_executor = create_agent() print(“智能体就绪。输入您的问题(输入 ‘quit’ 退出):”) while True: user_input = input(“\n>>> “) if user_input.lower() == ‘quit’: break if not user_input.strip(): continue try: # 运行智能体 result = agent_executor.invoke({“input”: user_input}) print(f“\n最终答案: {result[‘output’]}”) except Exception as e: print(f“执行过程中出现错误: {e}”) if __name__ == “__main__”: main()

现在,运行你的智能体:

python main.py

你会看到类似以下的输出(verbose=True时):

初始化智能体... 智能体就绪。输入您的问题(输入 ‘quit’ 退出): >>> 我们公司今年的产品战略是什么? Action: retrieve_from_knowledge_base Action Input: {“query”: “公司今年产品战略”} Observation: 以下是从知识库中检索到的相关信息: [文档内容...] Thought: 我已经从内部知识库找到了相关信息,可以基于此给出答案。 Final Answer: 根据公司内部文档,今年的产品战略聚焦于...

5. 关键配置与高级调优

一个基础的智能体已经运行起来,但要使其在生产环境中可靠、高效,还需要关注以下方面。

5.1 提示词工程与系统消息

智能体的表现很大程度上受提示词影响。我们可以自定义提示词来更好地引导模型。

from langchain.prompts import PromptTemplate custom_prompt = PromptTemplate.from_template(“”” 你是一个专业的助理,拥有访问内部知识库和互联网搜索的能力。 请遵循以下步骤回答问题: 1. 首先,判断问题是否涉及公司内部、私有或特定领域知识。 2. 如果是,使用 `retrieve_from_knowledge_base` 工具获取信息。 3. 如果问题需要最新的、公开的或通用信息,使用 `search_tool`。 4. 如果你已经掌握了足够的信息,请用清晰、有条理的中文给出最终答案。 5. 如果你无法找到相关信息,请如实告知。 工具: {tools} 历史对话: {history} 问题:{input} 请开始你的思考:”””) # 然后使用 custom_prompt 替换 hub.pull(“hwchase17/react”)

5.2 检索优化:重排序与元数据过滤

基础的相似性搜索可能返回不精确的结果。RAG 的重排序(Re-ranking)技术可以提升精度。

# 示例:使用 Cohere 或 BGE 的重新排序器(需要额外安装包) # from langchain.retrievers import ContextualCompressionRetriever # from langchain.retrievers.document_compressors import CohereRerank # compressor = CohereRerank(cohere_api_key=COHERE_API_KEY, top_n=3) # compression_retriever = ContextualCompressionRetriever(base_compressor=compressor, base_retriever=vectordb.as_retriever()) # 然后在工具中使用 compression_retriever

此外,可以在文档加载时添加元数据(如来源、章节),并在检索时进行过滤。

# 在 ingest.py 的加载和分割步骤,为文档添加元数据 for doc in splits: doc.metadata[“source”] = filename doc.metadata[“chunk_id”] = i # 在检索工具中,可以基于元数据过滤 # vectordb.similarity_search_with_score(…, filter={“source”: “specific_doc.pdf”})

5.3 记忆管理

为了让智能体在单次对话中记住上下文,需要为其添加记忆功能。

from langchain.memory import ConversationBufferMemory memory = ConversationBufferMemory(memory_key=“history”, return_messages=True) # 在创建 AgentExecutor 时传入 memory agent_executor = AgentExecutor( agent=agent, tools=tools, memory=memory, verbose=True, # … 其他参数 ) # 同时需要修改提示词模板,包含 {history} 占位符。

6. 常见问题排查与性能优化

在实际开发中,你可能会遇到以下典型问题。

6.1 智能体决策循环问题

问题现象可能原因检查与解决
智能体不调用工具,直接猜测答案。1. 提示词未明确要求使用工具。
2. 工具描述不够清晰。
3. 模型温度 (temperature) 过高,导致输出随机。
1. 强化提示词中对工具使用的指令。
2. 完善工具的descriptionargs_schema,让模型明白何时该用。
3. 将temperature设为 0 或接近 0 的值。
智能体陷入无限循环,反复调用同一工具。1.max_iterations设置过高或未设置。
2. 工具返回的结果无法让模型推导出答案。
3. 模型对当前状态判断失误。
1. 合理设置max_iterations(如 5-10)。
2. 检查工具返回的信息是否相关、完整。
3. 在提示词中增加对循环的警告,或使用 LangGraph 实现更精细的状态控制。
模型输出格式错误,执行器解析失败。模型未严格按照 ReAct 格式(Thought/Action/Action Input/Observation)输出。1. 设置handle_parsing_errors=True让执行器尝试修复。
2. 使用更强大的模型(如 GPT-4)。
3. 在提示词中提供更清晰、更严格的输出格式示例。

6.2 RAG 检索效果不佳

问题现象可能原因检查与解决
检索到的文档与问题不相关。1. 文本分割策略不当(chunk_size太大/太小)。
2. 嵌入模型不适合该领域语言。
3. 查询本身表述模糊。
1. 调整chunk_sizechunk_overlap,尝试不同的分割器。
2. 考虑使用针对特定语言(如中文)优化的嵌入模型。
3. 实现查询重写或扩展,使用 LLM 将用户问题优化为更适合检索的查询。
答案未包含在检索到的上下文中。1. 知识库未覆盖该问题。
2. 检索数量k值太小。
3. 文档处理时信息丢失(如表格、图片)。
1. 扩充知识库文档。
2. 适当增加k值,但需权衡上下文长度和成本。
3. 对复杂文档使用专用加载器(如处理表格的pandas)。
答案包含过时信息。知识库文档未更新。建立知识库定期更新机制,或结合网络搜索工具获取最新信息。

6.3 性能与成本优化

  • 缓存嵌入:使用Chroma持久化功能,避免每次启动都重新计算文档嵌入。
  • 异步调用:如果工具调用涉及网络 I/O(如搜索),考虑使用智能体的异步接口 (ainvoke) 来提高并发性能。
  • 限制令牌数:在AgentExecutor中设置max_tokens_limit,防止上下文过长导致 API 调用失败或成本激增。
  • 分级检索:先使用简单的关键词匹配(如 BM25)进行粗筛,再使用向量检索进行精排,兼顾速度和精度。

7. 从原型到生产:最佳实践与扩展方向

当你完成一个可工作的原型后,下一步是考虑如何将其变得健壮、可维护。

  1. 配置外置化:将所有配置(模型名称、API 密钥、路径、参数)移出代码,放入配置文件(如config.yaml)或环境变量。
  2. 日志与监控:为智能体的关键步骤(工具调用、最终答案、错误)添加结构化日志。监控 API 调用次数、令牌消耗和响应时间。
  3. 异常处理与降级:对工具调用失败、模型超时等情况设计降级策略(例如,检索失败时,尝试用更泛化的查询再试一次,或直接告知用户暂时无法获取某类信息)。
  4. 评估与测试:建立评估流水线,使用一组标准问题测试智能体回答的准确性、相关性和安全性。这对于持续改进至关重要。
  5. 探索 LangGraph:当你的智能体逻辑变得非常复杂,需要多轮次、多分支、或有状态的工作流时,是时候学习 LangGraph。它允许你将工作流定义为一个有向图,精确控制每个节点的状态转移,非常适合构建复杂的多智能体协作系统。

构建 AI 智能体是一个迭代过程。从最简单的 RAG 链开始,逐步引入工具和决策逻辑,再针对具体问题调整提示词、优化检索、完善错误处理。理解每个组件背后的原理,远比记住某个固定的代码片段更重要。

http://www.jsqmd.com/news/1233345/

相关文章:

  • 系统行为设计:从状态跃迁到可观测契约的工程实践
  • 非标定制球墨铸铁管件供应商 - 中媒介
  • Python条件判断详解:从基础语法到实战技巧
  • 万德高科网关管理软件PLC数据采集使用教程——2.0西门子S7-200-SMART的数采全流程
  • ArrayList:你手机里那个“无限容量且秒翻页”的智能订单列表
  • 真实传播的力量:从语言风格到受众心理分析
  • 2020年2月疫情热词解析与社会记忆
  • 弧形设计哪家专业? - 中媒介
  • 零基础入门PLC编程:从理论到实践的全方位指南
  • 粮油供应商的售后服务响应速度快吗? - 中媒介
  • C语言30天零基础速成:从语法到实战接单全路径解析
  • C++任意进制转换:从数学原理到工程实现与竞赛实战
  • Unity编辑器功能解锁技术原理与实现深度解析
  • Unity主程成长路线:从脚本到架构的5个关键跃迁点
  • 搜狗C++ Workflow安装配置与项目集成实战指南
  • 56.嵌入式中断与主循环解耦设计:生产消费模式完整实现
  • C++容器全面解析:从底层原理到实战选型与性能优化
  • 由近及远的智慧:深入理解不透明物体(Opaque)的绘制顺序
  • HarmonyOS7 双指缩放手势:PinchGesture 实现组件放大缩小
  • 卫生巾哪家用户体验好? - 中媒介
  • 电机技术咨询哪家推荐? - 中媒介
  • 专利无效代理哪家专业? - 中媒介
  • 足球资讯自动化采集与本地化处理实践
  • 鸿蒙Flutter DecoratedBox装饰容器:前景与背景装饰
  • 市政工程保温胶水哪家效果好? - 中媒介
  • SpringBoot集成Activiti/Flowable工作流引擎与bpmnjs流程设计器实战
  • LangChain 之 【RAG简介、文档加载器、文本分割器】
  • 贵阳贵安数字应用场景案例解析与关键技术
  • 四川能做照片定制的蛋糕店 - 中媒介
  • 深入解析C2000 XINTF接口:DMA握手机制与精细化时序配置实战