最近在后台收到不少私信很多同学对AI大模型应用开发很感兴趣但面对RAG、LangChain、Agent这些层出不穷的新概念感觉无从下手网上资料要么太散要么直接上源码对新手极不友好。结合近期多个企业级项目的落地经验我整理了一套从零开始的实战教程。本文将从最基础的环境搭建讲起手把手带你构建一个具备知识库问答RAG和智能体Agent能力的完整应用覆盖原理、编码、调试到部署优化的全流程。无论你是想入门AI应用开发的学生还是寻求技术转型的开发者跟着本文的步骤走七天内掌握核心技能并完成一个可展示的项目是完全可行的。1. 背景与核心概念为什么需要RAG与Agent在开始敲代码之前我们必须先理解要解决的问题。直接使用大语言模型LLM进行对话常常会遇到两个核心痛点知识滞后与幻觉问题。模型训练数据有截止日期无法获取最新信息同时它可能基于内部知识“自信地”编造错误答案即所谓的“AI幻觉”。RAG检索增强生成和Agent智能体正是为了解决这些问题而生的关键技术。RAG的核心思想是“给模型一本参考书”。当用户提问时系统不是让模型凭空回忆而是先从你的专属知识库如公司文档、产品手册中检索出最相关的信息片段然后将这些片段和问题一起交给模型让它基于提供的参考资料生成答案。这大大提高了答案的准确性和时效性。LangChain是一个用于构建LLM驱动应用程序的框架。你可以把它想象成“AI应用开发的乐高积木”。它把大模型调用、文本分割、向量检索、对话记忆等复杂功能封装成一个个标准化的“链”Chain或“智能体”Agent让开发者能像搭积木一样快速组合出功能强大的应用而无需从零处理所有底层细节。Agent则更进一步它让大模型具备了“使用工具”的能力。一个Agent可以理解用户的目标自主地规划步骤、调用工具如搜索网络、查询数据库、执行代码并最终完成任务。例如一个数据分析Agent可以帮你自动查询数据库、进行统计并生成图表。简单来说RAG让模型“有据可依”解决知识更新和幻觉问题。LangChain是构建这类应用的“脚手架”和“工具箱”。Agent让模型从“聊天员”升级为“执行者”能主动调用工具完成任务。接下来我们将通过一个完整的项目串联这三项技术。2. 环境准备与版本说明工欲善其事必先利其器。一个清晰、隔离的开发环境是成功的第一步。为了避免包冲突强烈建议使用虚拟环境。2.1 基础环境与Python版本操作系统Windows 10/11, macOS, 或 Linux (Ubuntu 20.04) 均可。本文演示基于 macOS/Linux 命令行Windows 用户建议使用 WSL2 或 Git Bash 以获得相近体验。Python版本推荐使用 Python 3.9 或 3.10。3.11版本可能存在某些库的兼容性问题。使用以下命令检查python --version # 或 python3 --version2.2 创建并激活虚拟环境# 创建名为 ai_demo 的虚拟环境 python3 -m venv ai_demo # 激活虚拟环境 # macOS/Linux: source ai_demo/bin/activate # Windows: # ai_demo\Scripts\activate激活后命令行提示符前会出现(ai_demo)标识。2.3 安装核心依赖库我们将使用pip安装所有必要的包。请将以下内容保存为requirements.txt文件langchain0.1.0 langchain-community0.0.10 langchain-openai0.0.5 openai1.6.1 chromadb0.4.22 tiktoken0.5.2 pypdf4.0.1 python-dotenv1.0.0 faiss-cpu1.7.4 streamlit1.28.0然后执行安装pip install -r requirements.txt关键版本说明langchain 核心框架版本迭代较快本文基于 0.1.x 稳定API。chromadb 轻量级向量数据库用于存储和检索文档的向量表示。faiss-cpu Facebook开源的向量相似性搜索库CPU版本检索效率高。streamlit 快速构建Web交互界面的神器让我们能专注于逻辑而非前端。2.4 获取并配置API密钥本项目需要调用大模型API。我们将使用 OpenAI 的 GPT 模型也可替换为其他兼容API。你需要一个 OpenAI API Key。访问 OpenAI平台 创建API Key。在项目根目录创建.env文件用于安全存储密钥# .env 文件内容 OPENAI_API_KEY你的实际API密钥sk-...安装的python-dotenv库会在代码中自动加载这个文件。3. 项目一构建你的第一个RAG知识库问答系统让我们从一个具体的需求开始开发一个能读取本地PDF技术文档并回答问题的智能助手。3.1 项目结构与设计创建如下项目目录my_rag_agent_project/ ├── .env # 存储API密钥 ├── requirements.txt # 依赖列表 ├── docs/ # 存放你的知识库文档PDF/TXT │ └── sample.pdf # 示例文档 ├── vector_store/ # 向量数据库存储目录自动创建 ├── app.py # 主应用程序逻辑 └── web_ui.py # Streamlit Web界面3.2 核心代码实现文档加载、切分与向量化创建app.py我们将分步实现核心功能。3.2.1 导入库与加载环境变量# app.py import os from dotenv import load_dotenv # 加载 .env 文件中的环境变量 load_dotenv() from langchain_openai import OpenAIEmbeddings, ChatOpenAI from langchain_community.document_loaders import PyPDFLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_community.vectorstores import Chroma from langchain.chains import RetrievalQA # 打印密钥是否加载成功调试用生产环境应删除 print(API Key 已加载:, os.getenv(OPENAI_API_KEY)[:10] ...)3.2.2 文档加载与文本分割直接让大模型处理整本书籍是不现实的。我们需要将文档拆分成语义连贯的“块”。def load_and_split_documents(pdf_path): 加载PDF文档并将其分割成适合处理的文本块。 参数: pdf_path: PDF文件的路径 返回: 分割后的文档列表 # 1. 加载文档 loader PyPDFLoader(pdf_path) documents loader.load() print(f已加载文档共 {len(documents)} 页。) # 2. 分割文本 text_splitter RecursiveCharacterTextSplitter( chunk_size1000, # 每个块的最大字符数 chunk_overlap200, # 块之间的重叠字符数保持上下文连贯 separators[\n\n, \n, 。, , , , , , ] # 分割符优先级 ) split_docs text_splitter.split_documents(documents) print(f文档已分割为 {len(split_docs)} 个文本块。) return split_docs3.2.3 创建向量存储知识库这是RAG的核心将文本转换为向量一组数字并存入向量数据库以便快速检索。def create_vector_store(documents, persist_directory./vector_store): 将文档转换为向量并存储到Chroma数据库中。 参数: documents: 分割后的文档列表 persist_directory: 向量数据库存储路径 返回: 向量存储检索器 # 初始化嵌入模型用于将文本转换为向量 embeddings OpenAIEmbeddings(modeltext-embedding-3-small) # 创建并持久化向量存储 vector_store Chroma.from_documents( documentsdocuments, embeddingembeddings, persist_directorypersist_directory ) vector_store.persist() # 保存到磁盘 print(f向量数据库已创建并保存至 {persist_directory}) return vector_store3.2.4 构建问答链现在我们将向量数据库和大语言模型连接起来形成一个完整的“检索-生成”链条。def create_qa_chain(vector_store): 创建检索问答链。 参数: vector_store: 向量存储对象 返回: 配置好的问答链 # 初始化LLM llm ChatOpenAI(modelgpt-3.5-turbo, temperature0.1) # temperature控制创造性0.1更倾向于事实性回答 # 从向量库创建检索器 retriever vector_store.as_retriever( search_typesimilarity, # 相似度搜索 search_kwargs{k: 4} # 返回最相关的4个文本块 ) # 创建检索问答链 qa_chain RetrievalQA.from_chain_type( llmllm, chain_typestuff, # 将检索到的所有文本“塞”进提示词 retrieverretriever, return_source_documentsTrue, # 返回参考来源 verboseFalse # 设为True可看到详细过程调试用 ) return qa_chain3.2.5 主函数串联整个流程def main(): # 步骤1: 指定你的PDF文档路径 pdf_path ./docs/sample.pdf # 请确保此路径下有PDF文件 # 步骤2: 加载并分割文档 split_docs load_and_split_documents(pdf_path) # 步骤3: 创建或加载向量存储 persist_dir ./vector_store if os.path.exists(persist_dir) and os.listdir(persist_dir): print(检测到已有向量存储正在加载...) embeddings OpenAIEmbeddings() vector_store Chroma(persist_directorypersist_dir, embedding_functionembeddings) else: print(创建新的向量存储...) vector_store create_vector_store(split_docs, persist_dir) # 步骤4: 创建问答链 qa_chain create_qa_chain(vector_store) # 步骤5: 开始问答循环 print(\n RAG知识库问答系统已就绪 ) print(输入 quit 或 退出 结束程序。) while True: query input(\n请输入你的问题: ) if query.lower() in [quit, 退出, exit]: break try: # 执行查询 result qa_chain.invoke({query: query}) answer result[result] source_docs result[source_documents] print(f\n【AI回答】: {answer}) print(f\n【参考来源】:) for i, doc in enumerate(source_docs[:2]): # 显示前2个来源 print(f 片段{i1}: {doc.page_content[:150]}...) # 预览前150字符 except Exception as e: print(f查询过程中出现错误: {e}) if __name__ __main__: main()3.3 运行与测试在docs/文件夹下放入你的sample.pdf可以是任何技术文档、产品手册。在终端运行python app.py首次运行会进行文档读取、分割和向量化稍等片刻。完成后即可在命令行中输入问题进行测试。系统会返回答案并列出它参考了文档中的哪些片段。至此一个本地化、可运行的RAG系统核心已经完成。它具备了知识库构建和智能问答的能力。4. 项目进阶为RAG系统添加Agent能力现在我们的系统只能回答知识库里的问题。如果用户问“今天北京的天气怎么样”或者“计算一下456乘以123”它就无能为力了。Agent就是为了让模型学会调用外部工具来解决这类问题。我们将创建一个简单的Agent让它除了能检索知识库还能进行数学计算。4.1 定义工具首先我们需要告诉Agent有什么工具可用。我们定义一个数学计算工具。# 在 app.py 中追加以下代码或新建一个 agent.py 文件 from langchain.agents import Tool, AgentExecutor, create_react_agent from langchain import hub # 用于拉取预定义的提示词模板 def calculate(expression: str) - str: 一个安全的数学计算工具仅支持基本算术。 参数: expression: 数学表达式字符串如 456 * 123 返回: 计算结果字符串 # 警告使用 eval 有安全风险此处仅作演示。 # 在生产环境中应使用更安全的表达式解析库如 ast.literal_eval 或自定义解析器。 try: # 限制可用的操作符增加安全性 allowed_chars set(0123456789-*/. ()) if not all(c in allowed_chars for c in expression): return 错误表达式中包含非法字符。 result eval(expression) return str(result) except Exception as e: return f计算错误: {e} # 将函数封装成LangChain可识别的Tool对象 math_tool Tool( nameCalculator, funccalculate, description用于执行数学计算。输入一个数学表达式字符串如 456 * 123。 )4.2 构建智能体我们将把之前创建的RAG问答链也包装成一个工具然后让Agent来决定何时使用知识库何时使用计算器。def create_agent(qa_chain): 创建一个能使用多种工具的智能体。 参数: qa_chain: 之前创建的RAG问答链 返回: 配置好的智能体执行器 # 1. 将RAG链也定义为工具 rag_tool Tool( nameKnowledge_Base, funcqa_chain.run, # 注意这里直接调用.run方法 description用于回答关于公司文档、产品手册等特定知识库的问题。输入一个具体的问题。 ) # 2. 定义工具列表 tools [rag_tool, math_tool] # 3. 初始化LLM使用更聪明的模型如gpt-4效果更好 llm ChatOpenAI(modelgpt-3.5-turbo, temperature0) # 4. 拉取一个优秀的Agent提示词模板 prompt hub.pull(hwchase17/react-chat) # 5. 创建ReAct模式的Agent agent create_react_agent(llm, tools, prompt) # 6. 创建执行器 agent_executor AgentExecutor( agentagent, toolstools, verboseTrue, # 设为True可以看到Agent的思考过程非常有用 handle_parsing_errorsTrue # 优雅地处理解析错误 ) return agent_executor4.3 集成与测试Agent修改主函数用Agent替代简单的QA链。# 修改 main 函数末尾的问答循环部分 def main(): # ... (前面的加载文档、创建向量存储、创建qa_chain的代码不变) # 步骤4: 创建智能体 print(正在创建智能体...) agent_executor create_agent(qa_chain) # 步骤5: 开始智能问答循环 print(\n 智能体RAG工具调用已就绪 ) print(现在我可以回答知识库问题也能进行数学计算了) print(输入 quit 或 退出 结束程序。\n) while True: query input(请输入你的问题: ) if query.lower() in [quit, 退出, exit]: break try: # 通过智能体执行 result agent_executor.invoke({input: query, chat_history: []}) print(f\n【最终答案】: {result[output]}\n) except Exception as e: print(f执行过程中出现错误: {e})运行程序现在你可以尝试问“文档中提到的核心技术是什么” 触发RAG工具“请计算一下 125 的平方根。” 触发计算器工具“先告诉我文档里关于部署的章节说了什么然后计算部署需要多少台服务器如果每台服务100个用户” Agent会规划步骤先后调用两个工具当verboseTrue时你会在终端看到Agent详细的思考过程Thought/Action/Observation这对于调试和理解其工作原理至关重要。5. 打造可视化Web界面使用Streamlit命令行工具不够直观我们使用Streamlit快速构建一个Web应用。创建web_ui.py文件# web_ui.py import streamlit as st import os from dotenv import load_dotenv load_dotenv() from langchain_openai import OpenAIEmbeddings, ChatOpenAI from langchain_community.vectorstores import Chroma from langchain.chains import RetrievalQA from langchain.agents import Tool, AgentExecutor, create_react_agent from langchain import hub import tempfile # --- 工具函数定义 (与app.py中类似需复制过来) --- def calculate(expression: str) - str: try: allowed_chars set(0123456789-*/. ()) if not all(c in allowed_chars for c in expression): return 错误表达式中包含非法字符。 result eval(expression) return str(result) except Exception as e: return f计算错误: {e} # --- Streamlit 应用界面 --- st.set_page_config(page_titleAI知识库助手, page_icon, layoutwide) st.title( 智能知识库问答助手 (RAG Agent)) # 侧边栏配置和文档上传 with st.sidebar: st.header(配置) openai_api_key st.text_input(OpenAI API Key, valueos.getenv(OPENAI_API_KEY, ), typepassword) if not openai_api_key: st.warning(请输入你的 OpenAI API Key) st.stop() os.environ[OPENAI_API_KEY] openai_api_key st.header(知识库管理) uploaded_file st.file_uploader(上传知识文档 (PDF), typepdf) persist_dir ./vector_store_web # 初始化会话状态保存聊天历史和向量库 if vector_store not in st.session_state: st.session_state.vector_store None if agent not in st.session_state: st.session_state.agent None if messages not in st.session_state: st.session_state.messages [] # 处理上传的文档 if uploaded_file is not None: with st.spinner(正在处理文档并构建知识库...): # 保存上传的文件到临时位置 with tempfile.NamedTemporaryFile(deleteFalse, suffix.pdf) as tmp_file: tmp_file.write(uploaded_file.getvalue()) tmp_path tmp_file.name # 加载、分割、创建向量库 (这里需要复用app.py中的函数为简洁起见简化处理) from langchain_community.document_loaders import PyPDFLoader from langchain.text_splitter import RecursiveCharacterTextSplitter loader PyPDFLoader(tmp_path) documents loader.load() text_splitter RecursiveCharacterTextSplitter(chunk_size1000, chunk_overlap200) split_docs text_splitter.split_documents(documents) embeddings OpenAIEmbeddings() st.session_state.vector_store Chroma.from_documents(split_docs, embeddings, persist_directorypersist_dir) st.session_state.vector_store.persist() st.success(f知识库构建完成共处理 {len(split_docs)} 个文本块。) # 创建RAG链和Agent llm ChatOpenAI(modelgpt-3.5-turbo, temperature0.1) retriever st.session_state.vector_store.as_retriever(search_kwargs{k: 4}) qa_chain RetrievalQA.from_chain_type(llmllm, chain_typestuff, retrieverretriever) # 创建工具和Agent rag_tool Tool(nameKnowledge_Base, funcqa_chain.run, description用于回答知识库问题。) math_tool Tool(nameCalculator, funccalculate, description用于数学计算。) tools [rag_tool, math_tool] agent_llm ChatOpenAI(modelgpt-3.5-turbo, temperature0) prompt hub.pull(hwchase17/react-chat) agent create_react_agent(agent_llm, tools, prompt) st.session_state.agent AgentExecutor(agentagent, toolstools, verboseFalse, handle_parsing_errorsTrue) os.unlink(tmp_path) # 删除临时文件 # 显示聊天历史 for message in st.session_state.messages: with st.chat_message(message[role]): st.markdown(message[content]) # 聊天输入框 if prompt : st.chat_input(请问我任何问题关于文档或数学计算...): if st.session_state.agent is None: st.error(请先上传PDF文档构建知识库) st.stop() # 添加用户消息 st.session_state.messages.append({role: user, content: prompt}) with st.chat_message(user): st.markdown(prompt) # 生成AI回复 with st.chat_message(assistant): with st.spinner(思考中...): try: response st.session_state.agent.invoke({input: prompt, chat_history: []}) answer response[output] except Exception as e: answer f抱歉处理你的问题时出现了错误: {str(e)} st.markdown(answer) st.session_state.messages.append({role: assistant, content: answer})运行Web应用streamlit run web_ui.py浏览器会自动打开一个本地页面。你可以上传PDF然后像使用ChatGPT一样进行问答系统会自动判断使用知识库还是计算器。6. 常见问题与排查思路在开发过程中你几乎一定会遇到以下问题。这里提供快速排查指南。问题现象可能原因解决思路ModuleNotFoundError: No module named langchain依赖未安装或虚拟环境未激活。1. 确认已激活虚拟环境(ai_demo)。2. 运行pip install -r requirements.txt。openai.AuthenticationError: Incorrect API key providedAPI密钥错误或未设置。1. 检查.env文件中的OPENAI_API_KEY是否正确。2. 确保代码中通过load_dotenv()加载了环境变量。3. 在OpenAI平台检查密钥是否有效、是否有余额。处理PDF时出错或乱码PDF文件加密、是扫描图片或编码特殊。1. 尝试使用其他PDF文件。2. 对于扫描件需要使用OCR库如pytesseract先提取文字但这会显著增加复杂度。向量数据库创建缓慢或内存不足文档太大或chunk_size设置不当。1. 减小chunk_size(如500)。2. 对于超大文档考虑分批处理。3. 确保有足够可用内存。Agent思考过程太长或陷入循环任务太复杂或提示词引导不足。1. 将verboseTrue打开观察Agent的思考步骤。2. 简化问题或为Agent提供更明确的工具描述。3. 考虑使用更强大的模型如gpt-4。回答与知识库内容无关幻觉检索到的文本块不相关或LLM未遵循指令。1. 检查检索器返回的source_documents是否真的与问题相关。2. 调整search_kwargs{k: 4}中的k值增加检索数量。3. 在提示词中加强指令如“严格根据提供的上下文回答”。Streamlit应用运行后无反应端口冲突或依赖问题。1. 尝试指定端口运行streamlit run web_ui.py --server.port 8502。2. 检查终端是否有错误日志。7. 最佳实践与工程建议当你掌握了基础构建流程后以下建议能帮助你将项目提升到生产可用级别。7.1 RAG 优化策略文本分割策略RecursiveCharacterTextSplitter是通用选择但对技术文档按章节/标题分割效果更好。可以尝试MarkdownHeaderTextSplitter或自定义分割逻辑。嵌入模型选择OpenAI的text-embedding-3-small性价比高。对中文场景可以考虑BGE、M3E等开源模型需本地部署。检索优化混合搜索结合向量相似性搜索语义和关键词搜索字面匹配如使用Chroma的MMR搜索或LangChain的EnsembleRetriever。重排序初步检索出10个结果后用更精细的模型如BGE-reranker重新排序提升Top结果质量。提示工程精心设计给LLM的提示词模板明确指令、上下文格式和输出要求能显著减少幻觉。7.2 Agent 设计原则工具设计精准工具的描述description要清晰准确这是Agent选择工具的主要依据。功能应单一、明确。控制复杂度初期不要给Agent太多工具3-5个为宜避免其困惑。工具之间功能边界要清晰。设置超时与重试在生产中为Agent执行设置超时并设计重试逻辑避免卡死。使用更强大的模型Agent的规划能力严重依赖模型智商。gpt-3.5-turbo能完成简单任务复杂任务务必使用gpt-4或Claude 3系列。7.3 工程化与部署配置管理将所有配置模型名称、温度、API地址、向量库路径抽离到配置文件如config.yaml或环境变量中。日志记录为关键步骤文档加载、分割、检索、LLM调用、工具调用添加详细日志便于监控和调试。异常处理对网络超时、API限流、无效输入等场景做好异常捕获和用户友好提示。缓存机制对频繁相同的查询结果进行缓存如使用langchain.cache或Redis降低API成本并提升响应速度。部署考虑Streamlit适合原型演示和内部工具。对于生产级Web服务考虑使用FastAPI或Django构建后端API用Vue/React构建前端。向量数据库Chroma轻量适合演示。生产环境考虑Weaviate、Qdrant、Milvus或PGVector与PostgreSQL集成。异步处理对于耗时的文档解析和向量化任务应使用异步队列如Celery后台处理避免阻塞Web请求。7.4 安全与成本API密钥安全绝对不要将密钥硬编码在代码或提交到Git。始终使用.env文件或云服务密钥管理。输入验证与清理对用户输入进行严格的验证和清理防止Prompt注入攻击。特别是像我们示例中eval的使用在生产中必须替换为安全的表达式解析器。成本监控OpenAI API调用按Token计费。为应用设置用量监控和预算告警避免意外开销。可以考虑对回答长度进行限制。通过本教程你不仅学会了如何搭建一个RAGAgent系统更掌握了从环境搭建、核心原理、代码实现、问题排查到生产优化的全链路思维。真正的掌握来自于动手实践和迭代优化。接下来你可以尝试用你自己的数据替换示例PDF添加更多工具如网络搜索、数据库查询或者用更强大的开源模型如通过Ollama本地部署的Llama 3替换OpenAI API打造一个完全自主可控的AI应用。