ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

LangChain快速入门:从零构建LLM应用的核心组件与实战

LangChain快速入门:从零构建LLM应用的核心组件与实战 1. 项目概述为什么你需要关注LangChain如果你最近在捣鼓大语言模型LLM比如想做个智能客服、文档问答机器人或者想把AI能力集成到自己的应用里那你大概率已经听过“LangChain”这个名字了。它现在几乎是LLM应用开发领域的事实标准框架热度居高不下。但你可能也听过一些抱怨比如“学习曲线陡峭”、“概念太多”、“文档看着头大”。这恰恰说明了它的强大和复杂——它试图解决的正是如何将强大的LLM与你的数据、工具和业务流程可靠地连接起来这个核心难题。简单来说LangChain不是一个模型而是一个开发框架。你可以把它想象成乐高积木的底板和一套标准连接件。LLM如GPT-4、Claude、本地部署的模型是功能各异的积木块你的数据、API、数据库是另一堆形状不一的积木。LangChain提供了一套标准化的“接口”和“组装逻辑”让你能把这些原本不兼容的部件快速、稳定地拼装成一个能跑起来的完整应用。它帮你处理了对话记忆管理、工具调用编排、复杂任务分解、文档检索与加工RAG等一系列繁琐但关键的工程问题。所以这篇快速入门的目标很明确帮你绕过初期最让人困惑的概念丛林直接上手搭建出几个能工作的原型在实操中理解LangChain的核心思想。无论你是想验证一个AI点子还是为现有产品添加智能特性掌握LangChain都能让你事半功倍。我们不会面面俱到而是聚焦于最常用、最能体现其价值的几个组件通过代码示例带你快速跑起来。2. 核心概念与架构拆解理解LangChain的“乐高哲学”在动手写代码前花几分钟理解LangChain的几个核心抽象至关重要。这能帮你从“跟着代码敲”升级到“知道为什么这么写”。2.1 核心六大组件LangChain的架构围绕几个核心组件构建它们像乐高积木一样可以灵活组合模型 I/O (Model I/O)这是与LLM交互的入口。它主要包含提示词模板 (Prompt Templates)将用户输入、上下文变量等动态填充到预设的提示词中避免硬编码。比如一个客服模板可能是“请基于以下上下文回答问题{context}\n问题{question}\n回答”。语言模型 (LLMs/Chat Models)LangChain封装了调用各类模型OpenAI, Anthropic, 本地模型等的统一接口。ChatModels专为多轮对话设计接收消息列表而LLMs接收简单字符串。输出解析器 (Output Parsers)将模型返回的非结构化文本如一段JSON字符串解析成你程序里好用的结构如Python字典、Pydantic对象。这是保证程序稳定性的关键。检索 (Retrieval)这是实现RAG检索增强生成的核心。它负责从你的知识库文档、数据库中找到与用户问题最相关的片段作为上下文喂给模型。核心步骤包括文档加载 - 文本分割 - 向量化存储 - 相似度检索。记忆 (Memory)让对话或交互拥有“记忆”。最简单的形式是保存聊天历史。LangChain提供了多种记忆后端从简单的对话缓冲区到基于向量的长期记忆。链 (Chains)这是LangChain的“胶水”。一个链将多个组件或多个其他链按预定顺序组合起来形成一个完整的处理流程。例如一个典型的问答链可能是检索文档 - 构建提示词 - 调用模型 - 解析输出。代理 (Agents)这是LangChain最强大的概念之一。代理大模型工具决策逻辑。模型扮演“大脑”根据用户目标自主决定调用哪个工具如搜索API、计算器、数据库查询并理解工具返回的结果直到完成任务。它让应用从“按固定流程执行”升级为“自主规划与执行”。回调 (Callbacks)用于在链或代理执行的各个阶段插入日志记录、流式输出、监控等逻辑便于调试和观察内部状态。2.2 LangChain vs. LangGraph流程编排的两种范式这是最近的热门话题。简单理解LangChain (Chains/Agents)更像是声明式的编排。你定义好组件和它们之间的连接关系一个接一个的链或代理的决策循环执行时按这个预定结构走。适合逻辑相对固定、可预测的任务流。LangGraph更像是图编程或状态机。你将应用逻辑定义为一个有向图节点是处理函数或工具边是条件跳转逻辑。模型或逻辑可以决定下一步走到哪个节点从而实现更复杂、带循环、分支条件多的动态工作流。它是对LangChain能力的补充和增强特别适合需要多轮规划、回溯、复杂协作如CrewAI中的多智能体的场景。对于快速入门我们首先掌握好LangChain的基础链和代理这已经能解决80%的需求。LangGraph可以在你遇到更复杂的工作流时再深入学习。3. 环境准备与第一个“Hello World”理论说再多不如跑一行代码。我们从最简单的开始让LangChain调用一个模型。3.1 安装与基础配置首先确保你安装了Python建议3.8。然后通过pip安装LangChain。为了调用模型我们通常还需要对应模型的SDK。这里以OpenAI的模型为例因为它最通用。# 安装LangChain核心包 pip install langchain langchain-core # 安装OpenAI的SDK如果你打算使用OpenAI的模型 pip install openai # 安装一些常用的社区工具包如用于网页检索 pip install langchain-community接下来你需要一个OpenAI的API密钥。如果你没有可以去OpenAI官网注册获取。切记不要将密钥直接硬编码在代码中更不要上传到GitHub等公开平台。安全的方式是设置为环境变量# 在终端中设置临时 export OPENAI_API_KEYyour-api-key-here # 或者在代码中通过python-dotenv等库从.env文件加载3.2 调用模型与提示词模板现在我们来写第一个脚本向模型问好。# 导入必要的模块 from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate # 1. 初始化模型 # 默认使用 gpt-3.5-turbo你可以通过 model_name 参数指定其他模型如 gpt-4 llm ChatOpenAI(modelgpt-3.5-turbo, temperature0.7) # temperature 控制创造性0.0最确定1.0最随机。对于事实性任务建议调低如0.1-0.3。 # 2. 创建一个简单的提示词模板 prompt ChatPromptTemplate.from_messages([ (system, 你是一个乐于助人的助手。), (user, {input}) ]) # 这里定义了两个角色消息system设定助手行为和 user用户输入。 # {input} 是一个占位符将在运行时被替换。 # 3. 将提示词模板和模型组合成一个链 chain prompt | llm # 这是LangChain v0.1 推荐的管道操作符语法非常直观prompt - llm。 # 4. 调用链并传入输入 response chain.invoke({input: LangChain是什么}) # 5. 打印结果 print(response.content)运行这段代码你应该能得到一个关于LangChain的解释。response是一个AIMessage对象其content属性包含了模型的文本回复。实操心得一模型初始化参数temperature这是最重要的参数之一。对于需要稳定、事实性输出的场景如摘要、数据提取设为较低值0.1-0.3。对于创意写作、头脑风暴可以调高0.7-0.9。max_tokens限制模型生成的最大长度防止意外产生过长的回复消耗大量token。streaming如果设为True则可以实现流式输出适合需要实时显示生成结果的Web应用。4. 构建一个简单的问答链引入检索与输出解析单纯调用模型回答通用问题意义不大。接下来我们构建一个更实用的链基于自定义文档进行问答。这需要用到检索和输出解析。假设我们想创建一个关于“公司内部政策”的问答机器人。我们有一份简单的政策文档。4.1 准备文档与向量数据库首先我们需要将文档处理成向量并存储起来以便快速检索。from langchain_community.document_loaders import TextLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_openai import OpenAIEmbeddings from langchain_community.vectorstores import Chroma # 1. 加载文档这里我们直接用一个字符串模拟实际可以从文件、网页、PDF加载 policy_text 公司休假政策 1. 所有全职员工每年享有15天带薪年假。 2. 年假需提前至少一周向直属主管申请。 3. 病假需在当天上午10点前通知主管。 4. 公司提供5天带薪病假。 5. 法定节假日按照国家规定执行。 # 实际项目中使用 TextLoader(policy.txt) 或 DirectoryLoader 加载文件。 # 2. 文本分割 # 文档可能很长需要分割成小块以便检索最相关的一段。 text_splitter RecursiveCharacterTextSplitter( chunk_size200, # 每个块的最大字符数 chunk_overlap50, # 块之间的重叠字符避免上下文断裂 separators[\n\n, \n, 。, , , ] # 分割符优先级 ) documents text_splitter.create_documents([policy_text]) print(f将文档分割成了 {len(documents)} 个块) # 3. 创建向量存储 # 使用OpenAI的嵌入模型将文本转换为向量并用Chroma轻量级向量数据库存储。 embeddings OpenAIEmbeddings() vectorstore Chroma.from_documents(documentsdocuments, embeddingembeddings, persist_directory./policy_db) # persist_directory 指定持久化目录下次可以直接加载无需重新生成向量。注意事项文本分割的艺术chunk_size是关键。太小会丢失上下文太大会引入无关噪声。对于事实性问答200-500字符是不错的起点。对于需要长上下文推理的任务可以适当增大。chunk_overlap能有效防止一个完整的句子或概念被割裂在两个块中。不同的文档类型代码、Markdown、论文可能需要定制的分割器。LangChain提供了多种TextSplitter。4.2 构建检索问答链现在我们将检索器、提示词模板和模型组装成一个完整的问答链。from langchain.chains import create_retrieval_chain from langchain.chains.combine_documents import create_stuff_documents_chain from langchain_core.prompts import ChatPromptTemplate # 1. 从向量库创建检索器 retriever vectorstore.as_retriever(search_kwargs{k: 2}) # search_kwargs 中的 k 表示检索返回的最相关文档块数量。不是越多越好一般2-4个足够。 # 2. 定义系统提示词模板 system_prompt 请仅根据以下提供的上下文信息来回答问题。如果上下文信息中没有明确答案请直接说“根据现有政策我无法回答这个问题。”不要编造信息。 上下文 {context} prompt ChatPromptTemplate.from_messages([ (system, system_prompt), (user, {input}) ]) # 3. 初始化模型 llm ChatOpenAI(modelgpt-3.5-turbo, temperature0.1) # 低temperature保证答案忠实于上下文 # 4. 创建“组合文档”链负责将检索到的多个文档块合并到提示词中 combine_docs_chain create_stuff_documents_chain(llm, prompt) # 5. 创建最终的检索链将检索器和组合文档链连接起来 qa_chain create_retrieval_chain(retriever, combine_docs_chain) # 6. 提问 question 我每年有多少天带薪年假 result qa_chain.invoke({input: question}) print(f问题{question}) print(f答案{result[answer]}) print(\n检索到的上下文) for i, doc in enumerate(result[context]): print(f[{i}] {doc.page_content[:100]}...)运行后模型会从我们提供的政策文本中检索出相关片段关于年假天数的句子并基于此生成答案。你会看到答案明确指向“15天”并且模型不会胡编乱造。实操心得二提示词工程在RAG中系统提示词至关重要。上面的例子中我们明确指令模型“仅根据上下文回答”并提供了拒绝回答的模板。这大大减少了模型“幻觉”即编造信息的概率。在实际应用中你可能需要反复调整提示词以获得更精准、更符合业务口吻的回答。4.3 使用输出解析器结构化结果有时我们希望模型的输出不是一段自由文本而是结构化的数据比如JSON方便后续程序处理。这时就需要输出解析器。假设我们想让模型从一段员工反馈中提取结构化信息。from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import PydanticOutputParser from pydantic import BaseModel, Field from typing import List # 1. 使用Pydantic定义我们希望输出的数据结构 class FeedbackInfo(BaseModel): employee_name: str Field(description员工姓名) department: str Field(description所属部门) rating: int Field(description评分1-5分) key_points: List[str] Field(description反馈中的关键点列表) sentiment: str Field(description情感倾向positive/negative/neutral) # 2. 基于Pydantic模型创建输出解析器 parser PydanticOutputParser(pydantic_objectFeedbackInfo) # 3. 在提示词中告诉模型需要输出的格式 # 获取解析器提供的格式指令 format_instructions parser.get_format_instructions() prompt ChatPromptTemplate.from_messages([ (system, 你是一个信息提取助手。请从用户的输入中提取信息。\n{format_instructions}), (user, {input}) ]) # 4. 构建链 chain prompt | llm | parser # 5. 输入一段文本 feedback_text 我是技术部的张三。这次项目支持我觉得可以打4分。团队协作很好但交付时间有点紧张。总体是积极的体验。 result chain.invoke({ input: feedback_text, format_instructions: format_instructions }) print(提取的结构化信息) print(f姓名{result.employee_name}) print(f部门{result.department}) print(f评分{result.rating}) print(f关键点{result.key_points}) print(f情感{result.sentiment}) # 输出将是一个FeedbackInfo对象可以直接通过属性访问。输出解析器会在模型输出不符合预期格式时抛出异常这保证了下游代码的稳定性。PydanticOutputParser是功能最强大的一种你还可以使用CommaSeparatedListOutputParser输出列表或StructuredOutputParser等。5. 探索智能体让模型学会使用工具链是预定义的流程而代理则赋予了模型“自主权”。我们给模型一些工具函数它可以根据用户的问题自己决定是否使用、使用哪个、以及如何使用这些工具。5.1 创建一个简单的数学计算代理我们先定义一个简单的计算器工具然后看看模型如何调用它。from langchain.agents import AgentExecutor, create_tool_calling_agent from langchain_core.tools import tool from langchain_openai import ChatOpenAI # 1. 使用 tool 装饰器定义一个工具 # 工具的描述非常重要模型完全依赖描述来决定是否以及如何调用它。 tool def calculate(expression: str) - str: 计算一个数学表达式的值。支持加减乘除-*/和括号。 # 警告这里使用eval仅作演示在实际生产环境中极其危险必须替换为安全的计算库如ast.literal_eval限制操作或使用math等。 try: # 简单演示实际请勿直接eval不可信输入 result eval(expression) return str(result) except Exception as e: return f计算错误{e} # 2. 准备工具列表和模型 tools [calculate] llm ChatOpenAI(modelgpt-3.5-turbo, temperature0) # 为代理创建专用的提示词LangChain提供了内置模板 from langchain import hub prompt hub.pull(hwchase17/openai-tools-agent) # 3. 创建代理 agent create_tool_calling_agent(llm, tools, prompt) agent_executor AgentExecutor(agentagent, toolstools, verboseTrue) # verboseTrue 会打印思考过程 # 4. 运行代理 result agent_executor.invoke({ input: 请计算一下 (12 34) * 2 等于多少 }) print(f\n最终答案{result[output]})运行代码时你会看到类似以下的verbose输出这揭示了代理的思考过程 Entering new AgentExecutor chain... 我应该使用计算器工具来计算这个数学表达式。 调用calculate参数{expression: (12 34) * 2} 观察92 (12 34) * 2 等于 92。 Finished chain. 最终答案(12 34) * 2 等于 92。模型识别出这是一个数学问题决定调用calculate工具并正确传入了表达式(12 34) * 2最后将工具返回的结果整合成了自然语言回复。5.2 使用预构建工具与搜索引擎LangChain社区提供了大量预构建的工具比如联网搜索。我们结合搜索工具和计算器创建一个更强大的代理。from langchain_community.tools import TavilySearchResults from langchain.agents import AgentExecutor, create_tool_calling_agent # 1. 初始化搜索工具需要TAVILY_API_KEY可在 https://app.tavily.com 免费获取 import os os.environ[TAVILY_API_KEY] your_tavily_api_key search_tool TavilySearchResults(max_results2) # 限制返回2条结果 # 2. 工具列表 tools [calculate, search_tool] # 3. 创建并运行代理 agent create_tool_calling_agent(llm, tools, prompt) agent_executor AgentExecutor(agentagent, toolstools, verboseTrue, handle_parsing_errorsTrue) # handle_parsing_errors 能更好地处理模型输出格式错误的情况。 question 昨天旧金山的天气怎么样另外如果气温是华氏70度那是多少摄氏度 result agent_executor.invoke({input: question}) print(f\n最终答案{result[output]})这个代理会先调用搜索工具查询旧金山昨天的天气然后可能再调用计算器将华氏度转换为摄氏度如果搜索结果没有直接提供的话。你会在verbose日志中看到它依次调用不同工具的过程。实操心得三代理的调试与优化工具描述务必清晰、准确。模型对工具功能的理解完全基于描述。verboseTrue开发阶段务必开启这是理解代理“思考”过程、排查问题的最重要手段。错误处理代理可能陷入循环、调用错误参数或无法解析输出。设置max_iterations最大迭代次数和handle_parsing_errorsTrue是基本的防护措施。ReAct模式这是代理的经典范式Reason Act。你会在日志中看到模型“思考”Reason下一步该做什么然后“行动”Act调用工具。如果代理表现不佳可以尝试使用更强大的模型如GPT-4或优化提示词。6. 常见问题与排查技巧实录在实际使用LangChain时你肯定会遇到各种问题。这里记录了一些典型场景和解决思路。6.1 连接与API错误问题现象可能原因排查步骤AuthenticationError/RateLimitErrorAPI密钥错误、过期或额度不足。1. 检查环境变量OPENAI_API_KEY是否正确设置且生效。2. 登录OpenAI控制台检查密钥状态、用量和余额。3. 对于速率限制考虑增加请求间隔或升级套餐。连接超时网络问题或代理配置。1. 检查本地网络。2. 如果你在特殊网络环境某些SDK可能需要配置http_client或api_base。OpenAI SDK可通过openai.base_url设置。ModuleNotFoundError缺少依赖包。1. LangChain采用模块化设计。langchain是核心但很多功能在子包中。2. 例如使用Chroma需要langchain-chroma使用Tavily需要langchain-community。仔细阅读错误信息安装对应的包。6.2 检索效果不佳问题现象可能原因优化方向答案不准确未引用文档内容。1. 检索到的文档块不相关。2. 提示词未强制模型使用上下文。1.优化检索调整chunk_size和chunk_overlap尝试不同的TextSplitter如按标记分割TokenTextSplitter优化嵌入模型调整检索的相似度阈值或k值。2.强化提示词在系统提示词中明确强调“仅使用以下上下文”并设计当上下文不相关时的拒绝回答话术。答案包含正确信息但冗余或格式差。模型未能很好总结或格式化。在提示词中增加指令如“请用简洁明了的语言总结答案”、“请以要点列表的形式回答”。对于复杂问题单个文档块信息不足。检索的上下文碎片化。1. 增加k值返回更多文档块。2. 使用ContextualCompressionRetriever等高级检索器在检索后对文档块进行压缩或重新排序聚焦最相关信息。6.3 代理行为异常问题现象可能原因解决方案代理陷入循环不停调用同一个工具。1. 工具未能返回有效结果导致模型重复尝试。2. 任务描述模糊模型无法确定完成状态。1. 检查工具函数是否稳定确保返回清晰的结果包括错误信息。2. 在提示词中明确任务完成的标志。3. 设置max_iterations如10强制停止。模型不调用工具直接生成答案。1. 工具描述不够清晰模型不理解其用途。2. 问题太简单模型觉得可以自己回答。3. 使用的模型如gpt-3.5-turbo工具调用能力较弱。1. 细化工具描述说明适用场景、输入输出格式。2. 在用户问题中明确要求“请使用XX工具”。3. 升级到工具调用能力更强的模型如gpt-4-turbo。代理调用工具时参数格式错误。模型对工具输入参数的理解有偏差。1. 使用tool装饰器时确保函数参数有明确的类型注解和文档字符串。2. 可以使用StructuredTool.from_function更精细地定义参数模式schema。6.4 性能与成本优化缓存对于重复的查询使用缓存可以大幅减少API调用和延迟。LangChain内置了InMemoryCache、SQLiteCache也可以集成Redis。from langchain.globals import set_llm_cache from langchain.cache import InMemoryCache set_llm_cache(InMemoryCache())流式输出对于需要长时间生成的文本使用流式输出可以提升用户体验。在初始化ChatOpenAI时设置streamingTrue并使用相应的回调处理器。本地模型与嵌入如果数据敏感或希望控制成本可以考虑使用本地模型通过Ollama,vLLM,LocalAI等集成和本地嵌入模型如BAAI/bge-small-zh-v1.5。这需要更多的本地资源但提供了完全的隐私和可控性。异步调用如果你的应用是异步框架如FastAPI使用LangChain的异步接口ainvoke,astream可以更好地处理并发请求。7. 从原型到生产下一步的方向通过上面的步骤你应该已经能用LangChain搭建起一个具备基本问答和工具调用能力的AI应用原型了。但这距离一个健壮的生产系统还有距离。接下来你可以从以下几个方向深入更复杂的链与工作流学习使用LangGraph来编排带有循环、分支和状态的工作流处理多步骤、需要回溯的复杂任务。评估与监控如何衡量你的RAG系统或代理的好坏需要建立评估体系包括答案相关性、事实准确性、延迟等指标。可以使用RAGAS、TruLens等评估框架。生产部署考虑将你的链或代理封装成API使用FastAPI加入身份验证、速率限制、持久化存储向量数据库如Pinecone,Weaviate,Qdrant和监控告警。高级检索技巧探索混合搜索结合关键词和向量、重排序Cohere Rerank、多索引检索等进一步提升检索精度。智能体优化为代理提供更多、更强大的工具数据库查询、代码执行、内部API并研究更高效的规划与推理策略。我个人在从入门到实战的过程中最大的体会是不要试图一次性理解LangChain的所有概念。最好的学习路径是“以战促学”——先定一个明确的小目标比如“做一个能查询我个人笔记的机器人”然后围绕这个目标去学习必要的组件文档加载、向量化、检索链遇到问题再查阅文档或社区。当你成功实现第一个小应用后那些抽象的概念自然会变得具体而清晰。LangChain的生态在不断进化保持动手实践才是跟上节奏的最好方式。
返回列表