尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

AI应用开发实战:RAG、Agent与LangGraph技术栈详解

AI应用开发实战:RAG、Agent与LangGraph技术栈详解 在实际 AI 大模型应用开发中RAG、Agent、LangChain、LangGraph 和 DeepSeek 等技术栈正成为构建智能系统的核心组件。无论是想快速搭建一个基于文档的问答系统还是设计一个能自主决策、调用工具的多步骤智能体掌握这些框架和概念都是必经之路。然而面对海量的官方文档、零散的教程和不断迭代的 API很多开发者感到无从下手学习路径模糊更不用说在紧张的面试中清晰、系统地阐述其原理与实践。本文旨在为你梳理一条从概念理解到实战落地的清晰路径。我们将围绕 RAG 检索增强生成、Agent 智能体开发、LangChain 框架核心、LangGraph 工作流编排以及 DeepSeek 模型集成这五大主题构建一个结构化的知识体系。文章不仅会解释每个技术点“是什么”和“为什么”更会通过具体的配置、代码片段和操作步骤展示“怎么做”并附上开发中常见的“坑”及其排查方法。无论你是准备技术面试还是希望在实际项目中应用这些技术都可以跟随本文的节奏建立起扎实的认知和实操能力。1. 理解核心概念RAG、Agent 与框架生态在深入代码之前必须厘清几个核心概念及其相互关系。混淆概念会导致技术选型错误和架构设计混乱。1.1 RAG让大模型“知道”它不知道的事检索增强生成的核心思想是解决大模型的“幻觉”问题和知识截止问题。传统的大模型仅依赖其训练时学习到的参数化知识进行生成对于训练数据中未包含的、实时的或高度专业化的信息它要么胡编乱造要么直接表示不知道。RAG 通过引入一个外部知识库通常是向量数据库来动态地为模型提供上下文。其工作流程可以简化为三步索引将原始文档如 PDF、TXT、网页进行分块通过嵌入模型转换为向量并存储到向量数据库中。检索当用户提出问题时将问题同样转换为向量并在向量数据库中进行相似性搜索找出最相关的文本片段。增强生成将检索到的相关文本片段作为上下文与用户问题一起拼接成提示词提交给大语言模型让模型基于这些“证据”生成答案。这样模型回答的准确性和可信度就得到了极大提升。一个典型的应用场景是公司内部知识库问答你可以将产品手册、技术文档导入系统员工即可用自然语言进行查询。1.2 Agent赋予大模型“行动”的能力如果说 RAG 扩展了模型的“知识”那么 Agent 则扩展了模型的“能力”。一个智能体不仅仅是一个聊天接口它是一个具备感知、规划、决策和执行能力的系统。一个基础的 Agent 通常包含以下几个核心组件工具Agent 可以调用的外部函数或 API例如搜索网络、查询数据库、执行代码、调用第三方服务。记忆用于存储对话历史、中间结果或长期目标使 Agent 具备上下文感知能力。规划将复杂任务分解为一系列可执行的子步骤。执行根据规划按顺序调用工具并处理结果。例如一个“天气查询-行程建议”Agent在用户说“明天北京天气如何如果下雨推荐室内活动”时它会规划出两个步骤先调用天气查询工具获取北京明日天气再根据结果下雨/不下雨调用本地生活服务工具获取相应的活动推荐。1.3 LangChain 与 LangGraph从链式调用到图工作流LangChain是一个用于开发由语言模型驱动的应用程序的框架。它提供了模块化的组件如模型 I/O、提示词模板、记忆、索引和链让开发者可以像搭积木一样快速构建应用。其核心抽象是“链”即将多个组件按顺序组合起来处理任务例如RetrievalQA链就封装了 RAG 的完整流程。然而简单的顺序链无法处理复杂的、有分支和循环的 Agent 任务。这就是LangGraph出现的原因。LangGraph构建在 LangChain 之上它引入了“图”的概念。你可以将应用程序定义为一个有向图其中节点代表执行步骤如调用工具、调用LLM边代表步骤之间的流转条件。这使得构建具备复杂逻辑、循环如让 Agent 反复思考直到满足条件和状态管理的智能体变得非常直观。两者关系LangChain 提供了构建 AI 应用的基础砖块和简单粘合剂链而 LangGraph 提供了设计复杂、有状态工作流的蓝图和引擎。对于简单的 RAG 问答使用 LangChain 的链可能就够了但对于一个需要多轮决策、工具调用的高级 AgentLangGraph 是更合适的选择。1.4 DeepSeek强大且经济的选择DeepSeek 是由深度求索公司开发的大语言模型系列以其出色的推理能力和极具竞争力的性价比受到开发者欢迎。在构建 AI 应用时选择 DeepSeek 作为核心的 LLM 引擎可以显著降低 API 调用成本同时获得接近顶级闭源模型的效果。通过 LangChain 或直接调用其 API可以轻松地将 DeepSeek 集成到你的 RAG 或 Agent 系统中。2. 环境准备与核心依赖配置开始实战前需要搭建一个干净的 Python 开发环境并安装必要的依赖。这里我们以创建一个新的虚拟环境为例。2.1 创建并激活虚拟环境使用venv或conda创建隔离环境是 Python 项目的最佳实践可以避免包版本冲突。# 使用 venv (Python 3.3 内置) python -m venv ai-agent-env # 激活环境 (Linux/macOS) source ai-agent-env/bin/activate # 激活环境 (Windows) ai-agent-env\Scripts\activate2.2 安装核心 Python 包我们将安装 LangChain、LangGraph、向量数据库客户端、嵌入模型以及 DeepSeek 的 SDK。以下requirements.txt文件列出了常用依赖及其典型版本。# requirements.txt langchain0.1.0 langchain-community0.0.10 # 社区贡献的集成工具 langchain-core0.1.0 langgraph0.0.22 # 用于调用 DeepSeek API也可以使用 openai 包如果 DeepSeek 兼容 OpenAI 格式 openai1.12.0 # 嵌入模型这里使用 OpenAI 的 text-embedding-3-small也可替换为本地模型如 BGE langchain-openai0.0.8 # 向量数据库以 Chroma 为例轻量级适合学习和原型开发 chromadb0.4.22 # 文档加载器 langchain-text-splitters0.0.1 pypdf3.17.4 # 用于读取 PDF beautifulsoup44.12.2 # 用于解析 HTML # 其他工具 python-dotenv1.0.0 # 管理环境变量使用 pip 安装pip install -r requirements.txt2.3 配置 API 密钥与环境变量大部分服务如 DeepSeek API、OpenAI API都需要密钥。永远不要将密钥硬编码在代码中。使用.env文件管理。在项目根目录创建.env文件。填入你的 API 密钥。如果你使用 DeepSeek需要去其官网注册并获取。# .env DEEPSEEK_API_KEYyour_deepseek_api_key_here DEEPSEEK_API_BASEhttps://api.deepseek.com # 以官方最新文档为准 # 如果你使用 OpenAI 格式兼容的端点可能还需要 OPENAI_API_KEYyour_deepseek_api_key_here # 有时可直接复用 OPENAI_API_BASEhttps://api.deepseek.com/v1在 Python 代码中使用python-dotenv加载。from dotenv import load_dotenv load_dotenv() # 加载 .env 文件中的环境变量 import os api_key os.getenv(DEEPSEEK_API_KEY)3. 实战一构建一个基础的 RAG 问答系统我们将使用 LangChain 和 Chroma 实现一个最简单的 RAG 流程并用 DeepSeek 作为生成模型。3.1 文档加载与文本分割首先准备你的知识文档例如一个knowledge.pdf文件。LangChain 提供了多种文档加载器。# rag_basic.py from langchain_community.document_loaders import PyPDFLoader from langchain_text_splitters import RecursiveCharacterTextSplitter # 1. 加载文档 loader PyPDFLoader(./knowledge.pdf) # 替换为你的文件路径 documents loader.load() # 2. 分割文本 # 分割的目的是为了适配模型的上下文长度并提高检索精度。 text_splitter RecursiveCharacterTextSplitter( chunk_size500, # 每个块的最大字符数 chunk_overlap50, # 块之间的重叠字符避免语义被切断 separators[\n\n, \n, 。, , , , , ] # 分割符优先级 ) split_docs text_splitter.split_documents(documents) print(f原始文档页数: {len(documents)}) print(f分割后文本块数: {len(split_docs)}) print(f第一个块的内容预览: {split_docs[0].page_content[:200]}...)3.2 向量化存储与检索接下来我们需要一个嵌入模型将文本转换为向量并用向量数据库存储和检索。# rag_basic.py (续) from langchain_openai import OpenAIEmbeddings from langchain_community.vectorstores import Chroma import os # 注意这里使用 OpenAIEmbeddings但指向 DeepSeek 的嵌入端点如果支持。 # 如果 DeepSeek 不提供独立嵌入模型可以使用开源模型如 all-MiniLM-L6-v2 (通过 sentence-transformers)。 # 此处假设使用 OpenAI 兼容的嵌入服务。 embeddings OpenAIEmbeddings( modeltext-embedding-3-small, # 或 DeepSeek 提供的嵌入模型名 openai_api_keyos.getenv(DEEPSEEK_API_KEY), openai_api_baseos.getenv(DEEPSEEK_API_BASE, https://api.deepseek.com) ) # 3. 创建向量数据库并存储 # persist_directory 指定持久化路径否则数据仅在内存中 vectorstore Chroma.from_documents( documentssplit_docs, embeddingembeddings, persist_directory./chroma_db # 数据将保存到此目录 ) vectorstore.persist() # 显式持久化 print(向量数据库已创建并持久化。) # 4. 检索测试 query 什么是机器学习 retrieved_docs vectorstore.similarity_search(query, k2) # 检索最相似的2个块 print(f\n针对问题 {query} 检索到的相关内容) for i, doc in enumerate(retrieved_docs): print(f[片段 {i1}]: {doc.page_content[:300]}...)3.3 集成 LLM 进行增强生成最后将检索到的上下文与用户问题组合发送给 DeepSeek 模型生成最终答案。# rag_basic.py (续) from langchain_openai import ChatOpenAI from langchain.chains import RetrievalQA from langchain.prompts import PromptTemplate # 5. 初始化 DeepSeek LLM (通过 OpenAI 兼容接口) llm ChatOpenAI( modeldeepseek-chat, # 模型名称请查阅 DeepSeek 最新文档 openai_api_keyos.getenv(DEEPSEEK_API_KEY), openai_api_baseos.getenv(DEEPSEEK_API_BASE, https://api.deepseek.com), temperature0.1 # 降低随机性使答案更确定 ) # 6. 定义自定义提示词模板明确告诉模型使用上下文 prompt_template 请根据以下上下文信息回答问题。如果上下文信息不足以回答问题请直接说“根据提供的信息我无法回答这个问题”不要编造信息。 上下文 {context} 问题 {question} 请给出答案 PROMPT PromptTemplate( templateprompt_template, input_variables[context, question] ) # 7. 创建检索问答链 qa_chain RetrievalQA.from_chain_type( llmllm, chain_typestuff, # 最简单的方式将所有检索到的上下文塞入提示词 retrievervectorstore.as_retriever(search_kwargs{k: 3}), # 检索3个片段 chain_type_kwargs{prompt: PROMPT}, return_source_documentsTrue # 返回源文档便于追溯 ) # 8. 提问 result qa_chain.invoke({query: 机器学习的主要类型有哪些}) print(\n RAG 系统回答 ) print(result[result]) print(\n 参考来源 ) for doc in result[source_documents]: print(f- {doc.page_content[:150]}...)运行这个脚本你将看到一个完整的 RAG 系统的工作流程。关键点在于提示词模板的设计它强制模型基于提供的上下文作答这是减少幻觉的关键。4. 实战二使用 LangGraph 构建一个决策型 Agent现在我们构建一个更复杂的 Agent它可以根据用户需求决定是直接回答问题还是需要先查询天气。这需要引入工具和决策逻辑。4.1 定义工具首先我们模拟两个工具一个通用问答工具模拟直接回答简单问题一个天气查询工具。# agent_graph.py from langchain.tools import tool from datetime import datetime tool def general_qa_tool(question: str) - str: 一个通用的问答工具用于回答简单的常识性或介绍性问题。 # 这里为了演示返回一个模拟答案。实际中可以连接一个知识库或另一个LLM。 return f这是一个关于{question}的模拟回答。当前时间是 {datetime.now().strftime(%H:%M)}。 tool def weather_query_tool(city: str) - str: 查询指定城市的天气情况。 # 模拟天气数据 weather_data { 北京: 晴15-25°C微风, 上海: 多云18-28°C东南风3级, 深圳: 阵雨22-30°C南风4级, } return weather_data.get(city, f未找到{city}的天气信息。)4.2 构建 Agent 状态与图节点LangGraph 的核心是定义状态和节点。状态是一个字典在图的执行过程中传递和更新。# agent_graph.py (续) from typing import TypedDict, Annotated, List import operator from langgraph.graph import StateGraph, END # 1. 定义状态结构 class AgentState(TypedDict): question: str # 用户原始问题 needs_weather: bool # 是否需要查询天气 city: str # 需要查询天气的城市 weather_info: str # 查询到的天气信息 final_answer: str # 最终给用户的答案 steps: Annotated[List[str], operator.add] # 记录执行步骤用于调试 # 2. 定义节点函数 def route_question(state: AgentState) - AgentState: 路由节点判断问题是否需要查询天气。 steps state.get(steps, []) question_lower state[question].lower() weather_keywords [天气, 下雨, 下雪, 气温, 温度] needs_weather any(keyword in question_lower for keyword in weather_keywords) city 北京 # 简单起见这里硬编码城市。实际可以用 NER 模型提取。 steps.append(f路由节点问题‘{state[question]}’是否需要天气{needs_weather}城市{city}) return { **state, needs_weather: needs_weather, city: city if needs_weather else , steps: steps } def call_weather_tool(state: AgentState) - AgentState: 调用天气工具节点。 steps state.get(steps, []) city state[city] weather_info weather_query_tool.invoke({city: city}) steps.append(f调用天气工具查询{city}天气结果{weather_info}) return {**state, weather_info: weather_info, steps: steps} def call_qa_tool(state: AgentState) - AgentState: 调用通用问答工具节点。 steps state.get(steps, []) answer general_qa_tool.invoke({question: state[question]}) steps.append(f调用通用问答工具答案{answer}) return {**state, final_answer: answer, steps: steps} def synthesize_answer(state: AgentState) - AgentState: 合成答案节点如果需要天气结合天气信息生成最终答案。 steps state.get(steps, []) if state[needs_weather]: # 这里可以引入 LLM 来生成更自然的结合了天气的回答 final_answer f您询问了{state[city]}的天气。{state[weather_info]}。根据这个天气建议您...此处可扩展 else: final_answer state[final_answer] steps.append(f合成最终答案{final_answer}) return {**state, final_answer: final_answer, steps: steps}4.3 组装图并运行将节点和边连接起来形成一个完整的工作流图。# agent_graph.py (续) # 3. 创建图并添加节点 workflow StateGraph(AgentState) workflow.add_node(router, route_question) workflow.add_node(get_weather, call_weather_tool) workflow.add_node(get_general_answer, call_qa_tool) workflow.add_node(synthesize, synthesize_answer) # 4. 设置边和条件流转 workflow.set_entry_point(router) # 根据路由结果决定下一步 workflow.add_conditional_edges( router, # 下一个节点由这个函数决定 lambda state: get_weather if state[needs_weather] else get_general_answer, { get_weather: get_weather, get_general_answer: get_general_answer } ) workflow.add_edge(get_weather, synthesize) workflow.add_edge(get_general_answer, synthesize) workflow.add_edge(synthesize, END) # 5. 编译图 app workflow.compile() # 6. 运行 Agent if __name__ __main__: # 测试用例1需要天气的问题 test_state_1 {question: 今天北京天气怎么样, steps: []} result_1 app.invoke(test_state_1) print(测试1 - 天气查询:) print(f问题: {result_1[question]}) print(f最终答案: {result_1[final_answer]}) print(执行步骤:, result_1[steps]) print(- * 50) # 测试用例2普通问题 test_state_2 {question: 什么是人工智能, steps: []} result_2 app.invoke(test_state_2) print(测试2 - 普通问答:) print(f问题: {result_2[question]}) print(f最终答案: {result_2[final_answer]}) print(执行步骤:, result_2[steps])运行此脚本你将看到 Agent 根据问题内容自动选择不同的执行路径。LangGraph 的可视化能力需要安装graphviz还能让你直观地看到这个工作流图这对于调试复杂 Agent 至关重要。5. 关键配置、参数与常见问题排查在实际开发中你会遇到各种配置和运行时问题。以下是关键参数和常见问题的速查表。5.1 核心参数配置表组件关键参数说明推荐值/建议文本分割chunk_size文本块大小字符数。取决于模型上下文窗口。对于 4K-8K 窗口500-1000 较合适。chunk_overlap块间重叠字符数。通常为chunk_size的 10%-20%保证语义连贯。向量检索search_kwargs{k: n}检索返回的最相似片段数。根据问题复杂度调整通常 3-5。太多可能引入噪声。distance_metric向量相似度计算方式如余弦相似度。Chroma 默认cosine通常无需更改。LLM 调用temperature生成随机性。0 最确定1 最随机。问答场景建议 0.1-0.3创意生成可调高。max_tokens生成答案的最大长度。根据需求设置避免生成过长或截断。LangGraphcheckpointer状态检查点用于实现长期记忆。对于多轮对话 Agent需配置SqliteSaver等。interrupt_before/after在特定节点前后中断用于人工审核。在关键决策点如执行付费操作前设置。5.2 常见问题与排查路径问题现象可能原因检查与解决步骤RAG 回答与文档无关或胡编乱造1. 检索到的上下文不相关。2. 提示词未强制模型使用上下文。3. 上下文长度超出模型限制。1. 检查嵌入模型是否匹配尝试调整chunk_size或使用不同的分割器。2. 强化提示词例如加入“必须严格依据上下文”。3. 减少检索数量k或使用map_reduce、refine等链类型处理长上下文。向量数据库检索速度慢1. 向量维度高数据量大。2. 未建立索引或索引类型不合适。1. 考虑使用更高效的向量数据库如 Milvus, Qdrant或降维。2. 对于 Chroma确保数据已持久化首次加载后查询会更快。DeepSeek API 调用失败1. API 密钥错误或过期。2. 网络问题或服务端异常。3. 请求格式或参数不兼容。1. 检查.env文件和环境变量是否正确加载。2. 查看错误信息确认 API Base URL 和模型名是否正确。3. 使用curl或 Postman 直接测试 API 端点排除代码问题。LangGraph Agent 陷入循环或状态错误1. 条件边conditional_edges逻辑有误。2. 状态State结构定义与节点返回值不匹配。1. 打印每个节点的输入/输出状态使用app.get_graph().draw_mermaid()可视化图结构。2. 确保所有节点返回的字典都包含状态定义的所有键或使用**state进行合并。工具调用失败或参数错误1. 工具函数参数定义与调用不匹配。2. LLM 生成的工具调用参数格式错误。1. 使用tool装饰器时确保函数有清晰的 docstring 和类型注解。2. 在调用工具前打印出 LLM 生成的参数进行验证。对于复杂参数考虑使用 Pydantic 工具。5.3 生产环境考量学习环境可以快速跑通但生产部署需要考虑更多异步与并发使用langchain的异步接口或asyncio提高吞吐量。错误处理与重试为 LLM API 调用、工具调用添加重试机制和断路器。可观测性集成日志如structlog、指标如 Prometheus和链路追踪如 OpenTelemetry监控耗时、Token 使用量和错误率。缓存对相似的检索查询或 LLM 生成结果进行缓存节省成本和时间。安全与权限对用户输入进行过滤和审查为工具调用设置严格的权限控制。版本管理对提示词模板、嵌入模型、LLM 版本进行管理便于回滚和 A/B 测试。6. 进阶方向与学习建议掌握了以上基础后你可以向更深入的方向探索高级 RAG 技巧研究重排序、HyDE、子查询、多向量检索等技术进一步提升检索质量。复杂 Agent 模式学习 ReAct、Plan-and-Execute、Multi-Agent 等架构让 Agent 能处理更复杂的任务。长期记忆在 LangGraph 中集成SqliteSaver或外部数据库使 Agent 在多次交互中记住用户偏好和历史。流式输出实现答案的逐字生成提升用户体验。前端集成使用 Gradio、Streamlit 或 Web 框架如 FastAPI构建交互式界面。本地化部署尝试使用 Ollama 部署本地 LLM或使用sentence-transformers运行本地嵌入模型完全摆脱对云 API 的依赖。学习这些技术的最佳方式是动手实践。建议从一个明确的小项目开始例如“个人文档摘要助手”或“智能日程规划 Agent”在实现过程中逐一攻克上述知识点。同时养成查阅官方文档的习惯因为 AI 框架的迭代速度非常快。通过结合项目实践、官方文档和社区讨论你就能建立起扎实的 AI 应用开发能力从容应对相关的技术挑战和面试。
返回列表