从零构建AI Agent:基于RAG与ReAct的智能文档问答与执行系统实战
在实际项目中AI Agent 已经从实验室概念演变为解决复杂任务的关键技术组件。无论是自动化客服、智能数据分析还是代码生成与辅助决策一个设计良好的 AI Agent 能够理解用户意图、规划任务步骤、调用工具并持续学习。然而从零开始构建一个功能完整、鲁棒性强的 AI Agent 系统开发者常常会陷入概念混淆、工具链断裂、调试困难等困境。本文将以一个可运行的“智能文档问答与执行” Agent 为例系统性地拆解其核心组件、实现路径和工程化细节帮助开发者理解从 Prompt 工程到工具调用再到记忆与反思的完整闭环。我们将使用 Python 作为主要语言结合主流的大模型接口如 OpenAI GPT 或开源模型和必要的工具库构建一个能够读取本地文档、理解问题、执行代码或搜索并给出答案的 Agent。通过这个项目你将掌握 Agent 的核心架构、LangChain 等框架的实战用法以及如何规避生产环境中的常见陷阱。1. 理解 AI Agent 的核心架构与工作流在开始编码之前必须厘清 AI Agent 与普通大模型调用的本质区别。一个简单的模型调用是单次、被动的问答而 Agent 是主动的、具备持续交互和决策能力的智能体。1.1 Agent 的基本组成模块一个典型的 AI Agent 系统通常包含以下核心模块它们协同工作形成一个自主循环大脑Brain/Core LLM这是 Agent 的决策中心通常是一个大语言模型LLM。它的核心职责是理解输入用户问题、工具返回结果、历史记忆进行推理并决定下一步行动是直接回答还是调用某个工具。我们通常通过精心设计的 Prompt 来引导 LLM 扮演“规划者”和“调度者”的角色。工具Tools这是 Agent 的手和脚。LLM 本身无法直接操作外部世界工具赋予了它这种能力。工具可以是搜索工具如 SerpAPI、DuckDuckGo Search。计算工具如 Python REPL执行代码、计算器。知识库工具如基于 RAG检索增强生成的文档问答系统。API 调用工具执行特定的 Web API如发送邮件、查询数据库、控制智能设备。记忆Memory这是 Agent 的经验。记忆分为短期记忆会话历史和长期记忆向量数据库存储的关键信息。记忆使得 Agent 能在多轮对话中保持上下文连贯并基于历史经验优化当前决策。规划与执行循环Planning Execution Loop这是 Agent 的工作流程。它通常遵循“思考-行动-观察”的循环思考LLM 根据当前目标、记忆和可用工具规划下一步行动例如“我需要先搜索最新的股价然后计算平均成本”。行动根据规划选择并调用一个具体的工具传入所需参数。观察接收工具的返回结果可能是成功的数据也可能是错误信息。反思/下一步LLM 结合观察结果判断目标是否完成。若未完成则进入下一个“思考”步骤若完成则生成最终答案返回给用户。1.2 关键技术选型为什么是 RAG 和 ReAct 模式从热搜词可以看出RAG和Transformer是当前构建 AI 应用的热点。RAG检索增强生成它解决了大模型的两个核心痛点——知识更新滞后和“幻觉”生成不准确信息。RAG 通过将外部知识库如你的文档、手册向量化存储在回答问题时先进行相关检索再将检索到的片段作为上下文提供给 LLM从而生成更准确、有据可依的答案。这对于构建企业级知识库问答 Agent 至关重要。ReActReasoning Acting这是一种 Prompting 范式它显式地要求 LLM 将“推理”和“行动”步骤以结构化格式如Thought:Action:Observation:输出。这极大地提升了 Agent 决策的可解释性和可靠性是构建复杂任务 Agent 的推荐模式。Transformer作为几乎所有现代 LLM 的底层架构理解其自注意力机制有助于你更好地设计 Prompt 和理解模型的上下文窗口限制。但在应用层我们更多是调用其 API 或使用预训练模型。基于以上理解我们的实战项目将构建一个具备RAG 知识库和代码执行工具的 Agent并采用ReAct模式来驱动其决策循环。2. 环境准备与依赖配置我们将创建一个独立的 Python 项目环境以确保依赖隔离和可复现性。2.1 创建项目与虚拟环境首先在命令行中创建项目目录并设置虚拟环境。推荐使用conda或venv。# 创建项目目录 mkdir ai_agent_project cd ai_agent_project # 创建并激活 Python 虚拟环境 (以 venv 为例) python -m venv venv # 在 Windows 上激活 venv\Scripts\activate # 在 macOS/Linux 上激活 source venv/bin/activate激活后命令行提示符前应显示(venv)表示你已进入该虚拟环境。2.2 安装核心依赖我们将使用LangChain作为 Agent 框架它封装了工具、记忆、链等高级抽象能极大简化开发。同时需要安装向量数据库Chroma轻量级适合本地开发和嵌入模型sentence-transformers。创建一个requirements.txt文件内容如下# 核心框架 langchain0.1.0 langchain-community0.0.10 # 社区工具和集成 langchain-openai0.0.5 # OpenAI 集成 # 向量数据库与嵌入模型 chromadb0.4.22 sentence-transformers2.2.2 # 大模型接口 (这里以 OpenAI 为例也可替换为其他) openai1.12.0 # 其他工具 python-dotenv1.0.0 # 管理环境变量 jupyter1.0.0 # 可选用于交互式实验然后安装所有依赖pip install -r requirements.txt注意langchain版本迭代较快上述版本号为撰写本文时的稳定版本。在实际项目中建议先查看官方文档确认最新兼容版本以避免 API 变更带来的问题。2.3 配置大模型 API 密钥为了调用 LLM如 GPT-4你需要一个 API 密钥。我们将使用环境变量来安全地管理它。在项目根目录创建.env文件。在.env文件中添加你的 OpenAI API 密钥OPENAI_API_KEYsk-your-actual-api-key-here重要确保.env文件已被添加到.gitignore中切勿提交到版本控制系统。在 Python 代码中使用python-dotenv加载密钥from dotenv import load_dotenv import os load_dotenv() # 加载 .env 文件中的环境变量 openai_api_key os.getenv(OPENAI_API_KEY) if not openai_api_key: raise ValueError(请在 .env 文件中设置 OPENAI_API_KEY)如果你希望使用开源模型如 Qwen、Llama则需要相应的模型文件和推理库如transformers,vllm并调整LangChain的 LLM 初始化部分。本文为简化流程以 OpenAI 接口为例。3. 构建核心组件RAG 知识库与工具我们的 Agent 将拥有两个核心工具一个用于回答基于内部文档的问题RAG另一个用于执行 Python 代码进行计算或数据处理。3.1 实现 RAG 知识库工具RAG 工具的工作流程是加载文档 - 分割文本 - 向量化 - 存储 - 检索。我们将使用Chroma作为向量数据库sentence-transformers本地模型进行嵌入。首先在项目目录下创建一个docs文件夹并放入一些示例文档如product_manual.txt,api_spec.md。然后创建build_rag_tool.py# build_rag_tool.py from langchain_community.document_loaders import TextLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_community.vectorstores import Chroma from langchain.tools.retriever import create_retriever_tool def create_rag_tool(persist_directory./chroma_db): 创建并返回一个基于本地文档的 RAG 检索工具。 # 1. 加载文档 documents [] doc_files [./docs/product_manual.txt, ./docs/api_spec.md] # 你的文档路径 for file_path in doc_files: try: loader TextLoader(file_path, encodingutf-8) documents.extend(loader.load()) except FileNotFoundError: print(f警告未找到文件 {file_path}请确保文档已放置。) # 创建示例文档 with open(file_path, w, encodingutf-8) as f: f.write(f这是 {file_path} 的示例内容。AI Agent 可以通过 RAG 工具检索到这里的信息。) loader TextLoader(file_path, encodingutf-8) documents.extend(loader.load()) # 2. 分割文本 text_splitter RecursiveCharacterTextSplitter( chunk_size500, # 每个文本块的大小 chunk_overlap50 # 块之间的重叠部分保持上下文 ) splits text_splitter.split_documents(documents) # 3. 创建嵌入模型和向量数据库 # 使用本地嵌入模型无需额外 API 调用 embeddings HuggingFaceEmbeddings(model_nameall-MiniLM-L6-v2) # 持久化向量数据库到本地目录 vectorstore Chroma.from_documents( documentssplits, embeddingembeddings, persist_directorypersist_directory ) vectorstore.persist() # 4. 创建检索器 retriever vectorstore.as_retriever(search_kwargs{k: 3}) # 返回最相关的3个片段 # 5. 将检索器包装成 LangChain Tool rag_tool create_retriever_tool( retriever, search_company_docs, 当用户的问题涉及公司产品、API规范或内部文档时使用此工具查找相关信息。输入应该是具体的问题或关键词。 ) return rag_tool if __name__ __main__: # 测试构建过程 tool create_rag_tool() print(fRAG 工具创建成功: {tool.name})运行此脚本将生成向量数据库并返回一个工具对象。工具描述“当用户的问题涉及...时使用”至关重要LLM 会根据描述决定是否调用该工具。3.2 实现 Python 代码执行工具LangChain 社区提供了现成的PythonREPLTool它可以在一个安全的沙箱环境中执行 Python 代码。# 在 main_agent.py 或类似文件中引入 from langchain_community.tools import PythonREPLTool python_tool PythonREPLTool( namepython_repl, description当你需要进行计算、数据分析、字符串操作或运行任何Python代码时使用此工具。 输入应该是一段有效的Python代码字符串。工具会返回代码的执行结果或错误信息。 注意不要用它执行危险操作如删除文件、访问网络。 )警告在生产环境中直接执行任意 Python 代码极其危险。必须进行严格的沙箱隔离、资源限制和代码审查。开发环境用于演示工作流但上线前必须替换为更安全的方案如限制可调用的特定函数或使用 Docker 容器。4. 组装 AI Agent 并实现 ReAct 循环现在我们将大脑LLM、工具和记忆组装起来创建一个具备 ReAct 推理能力的 Agent。4.1 初始化 LLM 和工具列表# main_agent.py from dotenv import load_dotenv from langchain_openai import ChatOpenAI from langchain.agents import AgentExecutor, create_react_agent from langchain.prompts import PromptTemplate from build_rag_tool import create_rag_tool from langchain_community.tools import PythonREPLTool load_dotenv() # 1. 初始化 LLM # 使用 gpt-3.5-turbo 以控制成本对于复杂任务可升级至 gpt-4 llm ChatOpenAI(modelgpt-3.5-turbo, temperature0, openai_api_keyos.getenv(OPENAI_API_KEY)) # temperature0 使输出更确定适合任务执行 # 2. 准备工具列表 rag_tool create_rag_tool() # 从上一节创建 python_tool PythonREPLTool() tools [rag_tool, python_tool] # 3. 定义 ReAct 提示模板 # LangChain 提供了默认的 ReAct 模板但我们也可以自定义以更好地适应任务 react_prompt PromptTemplate.from_template( 你是一个智能助手可以访问以下工具 {tools} 请严格按照以下格式回答 Thought: 你需要思考当前情况决定是否需要使用工具以及使用哪个工具。 Action: 需要使用的工具名称必须是[{tool_names}]中的一个。 Action Input: 提供给工具的输入内容。 Observation: 工具返回的结果。 ... (这个 Thought/Action/Action Input/Observation 循环可以重复多次) 当你认为已经获得足够信息来回答用户问题时或者无需使用工具时请使用以下格式 Thought: 我现在可以给出最终答案了。 Final Answer: [你的最终回答] 开始 用户问题: {input} {agent_scratchpad} # LangChain 会自动将历史步骤填充到这里 )4.2 创建 Agent 执行器并运行# 接 main_agent.py # 4. 创建 Agent agent create_react_agent(llm, tools, react_prompt) # 5. 创建执行器并开启详细日志和错误处理 agent_executor AgentExecutor( agentagent, toolstools, verboseTrue, # 打印详细的 Thought/Action/Observation 日志便于调试 handle_parsing_errorsTrue, # 处理 LLM 输出格式解析错误 max_iterations5, # 限制最大循环次数防止无限循环 early_stopping_methodgenerate, # 当 LLM 输出 Final Answer 时停止 ) # 6. 运行 Agent 测试 if __name__ __main__: test_questions [ “我们产品的退货政策是什么” # 预期触发 RAG 工具 “计算 15 的阶乘是多少” # 预期触发 Python 工具 “先查一下我们 API 的速率限制然后告诉我每天调用 10000 次需要多少小时。” # 预期触发 RAG然后 Python 计算 ] for question in test_questions: print(f\n{*50}) print(f用户问题: {question}) print(f{*50}) try: result agent_executor.invoke({input: question}) print(f\n最终结果: {result[output]}) except Exception as e: print(f执行出错: {e})运行python main_agent.py你将在控制台看到类似以下的详细输出清晰地展示了 Agent 的思考过程 用户问题: 计算 15 的阶乘是多少 Thought: 用户需要计算一个数学问题。我有 Python 代码执行工具可以完成这个任务。 Action: python_repl Action Input: import math\nmath.factorial(15) Observation: 1307674368000 Thought: 我已经得到了计算结果可以给出最终答案。 Final Answer: 15 的阶乘是 1307674368000。 最终结果: 15 的阶乘是 1307674368000。5. 关键配置、参数详解与生产环境考量5.1 核心参数调优表组件参数默认/示例值作用与影响生产环境建议文本分割器chunk_size500每个文本块的长度。太小丢失上下文太大检索不准。根据文档类型调整。技术文档可设 800-1000对话记录可设 200-300。chunk_overlap50块间重叠字符数。有助于保持语义连贯。通常设为chunk_size的 10%-20%。向量检索search_kwargs[“k”]3每次检索返回的文本块数量。根据答案精度要求调整。增加k能提供更多上下文但可能引入噪声。通常 3-5。LLMtemperature0生成随机性。0 最确定越高越有创意。任务执行型 Agent 设为 0 或接近 0如 0.1。创意生成型可适当提高。modelgpt-3.5-turbo模型版本。影响能力与成本。复杂推理、长上下文任务用gpt-4-turbo。简单任务用gpt-3.5-turbo控制成本。Agent执行器max_iterations5Agent 最大思考-行动循环次数。防止死循环。根据任务复杂度设置通常 5-10。可结合超时时间控制。verboseTrue是否打印详细步骤日志。开发调试设为True生产环境设为False并通过结构化日志记录。5.2 生产环境必须处理的工程问题错误处理与稳定性工具调用失败网络超时、API 限流、工具内部错误。Agent 执行器应能捕获异常并将错误信息作为Observation反馈给 LLM让其尝试其他方案或优雅失败。LLM 输出格式错误LLM 可能不按 ReAct 格式输出。handle_parsing_errorsTrue是基础更健壮的做法是加入输出格式校验和重试机制。# 示例简单的重试装饰器 from tenacity import retry, stop_after_attempt, wait_exponential retry(stopstop_after_attempt(3), waitwait_exponential(multiplier1, min4, max10)) def robust_agent_invoke(question): return agent_executor.invoke({input: question})安全与权限代码执行沙箱PythonREPLTool绝不可直接用于生产。必须使用如Docker容器隔离、资源限制CPU、内存、运行时间、禁用危险模块如os,subprocess,sys的部分功能的沙箱环境。敏感信息API 密钥、数据库密码等必须通过环境变量或密钥管理服务如 AWS Secrets Manager获取严禁硬编码。用户输入净化防止 Prompt 注入攻击。对用户输入进行基本的过滤和转义避免其篡改系统 Prompt。性能与成本缓存对频繁相同的查询如常见问题的 LLM 响应和工具调用结果进行缓存可使用LangChain的LLMCache或外部缓存如 Redis。异步调用如果工具调用是 IO 密集型如网络请求使用异步 Agent 执行器提升吞吐量。Token 消耗监控记录每次调用的输入/输出 Token 数设置预算告警。对于 RAG优化检索到的文本块长度和数量是控制 Token 的关键。可观测性结构化日志记录完整的 Agent 执行轨迹Thought, Action, Observation便于事后分析和调试复杂问题。链路追踪为每个用户会话分配唯一 ID贯穿所有工具调用和 LLM 请求方便定位问题。关键指标监控成功率、平均响应时间、工具调用分布、Token 消耗速率。6. 常见问题排查与调试指南在开发过程中你可能会遇到以下典型问题。这里提供排查思路。6.1 Agent 不调用工具直接回答问题现象对于明显需要工具的问题如“计算...”、“查询文档...”Agent 直接猜测回答不输出Action。可能原因与解决工具描述不清检查工具Tool的description字段。描述必须清晰说明工具的用途和适用场景。LLM 仅根据描述决定是否调用。修改描述使其更精确匹配问题类型。Prompt 引导不足ReAct 提示模板可能不够强调工具使用。在 Prompt 的开头部分明确指令如“你必须使用工具来获取准确信息严禁猜测”。LLM 能力不足gpt-3.5-turbo在复杂规划上可能不如gpt-4。尝试切换模型或简化任务。6.2 RAG 检索结果不相关现象Agent 调用了 RAG 工具但返回的文档片段与问题无关导致最终答案错误。可能原因与解决文本分割不当chunk_size可能太大导致一个文本块包含多个不相关主题。尝试减小chunk_size或使用基于语义的分割器如SemanticChunker。嵌入模型不匹配用于构建索引的嵌入模型与查询时使用的模型不一致虽然代码中是一个。确保生产环境部署时构建和查询阶段加载的是同一个模型文件。检索策略单一尝试混合检索策略如结合关键词搜索BM25和向量搜索相似度LangChain的EnsembleRetriever可以做到。查询改写用户问题可能太口语化。在检索前先用一个 LLM 将用户问题改写成更利于检索的关键词或陈述句。6.3 Agent 陷入无限循环或达到最大迭代次数现象控制台不断打印Thought/Action/Observation直到max_iterations用尽。可能原因与解决工具输出未满足 LLM 预期LLM 根据Observation决定下一步。如果工具返回的结果格式混乱、包含错误信息或未提供关键数据LLM 可能无法理解从而反复尝试。确保工具返回清晰、结构化的结果。任务过于复杂或定义模糊LLM 无法规划出清晰的解决路径。尝试将用户问题拆分成更小、更具体的子任务或者引导用户提供更明确的输入。缺少“最终答案”的强引导在 Prompt 中强化“当你获得答案后必须使用Final Answer:格式”的指令。6.4 性能慢响应延迟高现象Agent 响应一个简单问题也需要数秒甚至更久。可能原因与解决顺序执行工具调用如果是网络请求如搜索顺序执行会累积延迟。考虑使用异步 Agent (create_react_agent支持异步) 来并行执行可独立运行的工具调用。LLM 响应慢检查是否是 GPT API 响应慢或者本地开源模型加载/推理慢。考虑使用流式响应Streaming先返回部分结果或对模型进行量化、加速。向量检索慢如果文档库很大Chroma 的检索可能变慢。考虑使用更高效的向量数据库如Pinecone,Weaviate云服务或本地的FAISS优化索引或引入缓存层。7. 扩展方向与最佳实践7.1 扩展 Agent 能力更多工具集成网络搜索、数据库查询、内部系统 API、文件操作等。确保每个工具都有清晰、安全的边界。记忆机制会话记忆使用ConversationBufferMemory或ConversationSummaryMemory让 Agent 记住当前对话历史。长期记忆将重要的交互结果向量化后存入另一个专门的向量库供未来检索参考实现持续学习。多 Agent 协作创建具有不同专长如分析、写作、审核的多个 Agent让它们通过消息队列或协调器协同完成复杂工作流。7.2 从开发到生产的 checklist在将 Agent 系统部署上线前请逐一核对以下清单[ ]安全代码执行是否已被严格沙箱化用户输入是否经过过滤敏感配置是否已移出代码[ ]稳定性是否对 LLM API 调用、工具调用设置了超时和重试是否有熔断机制[ ]可观测性是否集成了日志、指标Metrics和分布式追踪Tracing能否看到一次请求的完整 Agent 决策链[ ]成本控制是否对 Token 消耗进行了监控和告警是否对高成本操作如调用 GPT-4设置了频率限制[ ]数据隐私用户数据、公司文档在向量化、存储、传输过程中是否符合合规要求[ ]性能测试是否在模拟负载下测试过系统的响应时间和资源消耗CPU、内存[ ]回滚方案新版本 Agent 出现严重问题时是否能快速回退到旧版本构建 AI Agent 是一个迭代过程从最小可行产品MVP开始聚焦解决一个具体问题然后逐步增加工具、优化 Prompt、完善记忆和错误处理。始终以实际任务完成度和用户体验为核心指标而非盲目追求技术的复杂性。通过本文的实战框架你可以快速搭建起自己的第一个 Agent并在此基础上探索更广阔的应用场景。