1. 项目概述从工具链到智能体上一部分我们搭建了基础的LangChain环境并实现了简单的RAG问答。但LangChain真正的魅力远不止于此它最核心的价值在于其“链”Chain和“代理”Agent的抽象能力。如果说RAG是给大模型装上了“记忆库”那么Agent就是为它赋予了“行动力”和“决策力”。这部分的实战我们将深入LangChain的智能体世界构建一个能自主调用工具、规划步骤、解决复杂任务的AI助手。想象一下你不再需要手动拼接多个API调用而是告诉AI“帮我查一下今天上海的天气然后根据天气推荐一个适合的户外活动最后用中文写一份简单的出行建议。” 一个设计良好的Agent就能理解这个多步骤任务自动调用天气查询工具、活动推荐逻辑并最终生成文本。这就是智能体开发要达成的目标。本教程将带你从零开始理解Agent的核心组件并动手构建一个具备联网搜索、代码执行、文件处理等能力的多功能智能体最终将其封装成一个可交互的Web应用。2. 智能体Agent核心架构深度解析在深入代码之前我们必须先厘清几个核心概念这决定了你构建的Agent是“玩具”还是“生产力工具”。2.1 智能体、工具与执行器的关系很多人容易混淆这些概念。你可以把智能体看作一个“大脑”它负责接收用户指令、进行思考规划和做出决策。工具Tools则是这个大脑可以调用的“手和脚”每一个工具都封装了一个特定的功能比如搜索网络、执行Python代码、查询数据库等。执行器Agent Executor则是协调大脑和手脚的“神经系统”或“流程控制器”它负责迭代运行将用户输入和当前状态交给大脑思考大脑决定下一步调用哪个工具或直接给出最终答案执行器则调用该工具将工具返回的结果连同历史记录再次交给大脑思考如此循环直到大脑认为任务完成。一个常见的误区是试图让一个Agent完成所有事情。更优雅的设计是遵循“单一职责原则”创建多个专注的Agent并通过更上层的元Agent或LangGraph来编排它们。例如一个数据分析Agent专门处理数据查询和图表生成一个文档处理Agent专门总结和提取PDF内容一个通用助手Agent负责回答日常问题并视情况调用前两者。2.2 关键组件选型与实战考量1. 语言模型LLM的选择Agent的核心是LLM它的推理能力直接决定了Agent的智能水平。对于开发我强烈建议从OpenAI的GPT-4系列开始特别是gpt-4-turbo或gpt-4o。它们在遵循指令、工具调用格式Function Calling和复杂推理上表现最为稳定。虽然成本较高但稳定的开发体验能让你更专注于逻辑而非调试模型本身的古怪行为。待核心流程跑通后可以尝试切换到Claude 3Haiku/Sonnet或开源的DeepSeek-V2、Qwen2.5等模型它们在某些场景下性价比更高。切勿在初期使用过于轻量的模型那会极大增加调试难度。注意使用OpenAI API时务必妥善保管你的API Key不要将其硬编码在客户端代码中。最佳实践是通过环境变量加载并在服务端进行调用。2. 工具Tools的设计哲学工具不是越多越好而是越“精准”越好。一个好的工具应该功能单一一个工具只做一件事并把它做好。例如search_web工具就只负责返回搜索摘要而不负责总结。描述清晰工具的description属性至关重要。Agent完全依靠这段描述来决定是否以及何时调用该工具。描述应明确说明工具的用途、输入格式和输出内容。例如“使用DuckDuckGo搜索互联网获取最新信息。输入应为搜索查询词。”就比“搜索工具”要好得多。返回结构化工具应尽可能返回结构化的数据如字典、列表而非冗长的自然语言。这有利于后续Agent或其他工具处理。例如天气查询工具应返回{“city”: “Shanghai”, “temp”: 22, “condition”: “Sunny”}而不是一段“上海今天晴气温22度...”的文本。3. 提示词Prompt的工程化LangChain提供了默认的Agent提示模板但对于复杂任务自定义提示词是必须的。你需要在提示词中明确Agent的角色例如“你是一个专业的数据分析助手擅长使用Python处理数据和绘制图表。”可用工具列表及其详细说明。输出格式的严格要求必须强调Agent需要输出一个包含action和action_input的JSON对象来调用工具或者输出Final Answer:来结束任务。任务分解的范例对于复杂任务在提示词中提供一两个多步思考的示例Few-shot Learning能显著提升Agent的规划能力。3. 构建多功能智能体从理论到代码接下来我们动手构建一个具备联网搜索、代码执行和文件读取能力的智能体。我们将使用gpt-4-turbo作为大脑并整合多个实用工具。3.1 环境准备与工具集成首先确保安装必要的库。除了langchain我们还需要一些工具库。pip install langchain-openai duckduckgo-search langchain-community python-dotenv然后在项目根目录创建.env文件存储你的OpenAI API Key。OPENAI_API_KEY你的密钥现在开始编写核心代码。我们创建一个新的Python文件advanced_agent.py。import os from dotenv import load_dotenv from langchain_openai import ChatOpenAI from langchain.agents import AgentExecutor, create_openai_tools_agent from langchain.tools import Tool from langchain_community.tools import DuckDuckGoSearchRun from langchain_community.utilities import WikipediaAPIWrapper from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain.tools.render import render_text_description # 加载环境变量 load_dotenv() # 1. 初始化LLM # 使用gpt-4-turbo以获得更好的工具调用和推理能力 llm ChatOpenAI(modelgpt-4-turbo, temperature0, api_keyos.getenv(OPENAI_API_KEY)) # 2. 创建工具集 # 工具一联网搜索使用DuckDuckGo search DuckDuckGoSearchRun() search_tool Tool( nameWeb_Search, funcsearch.run, description使用DuckDuckGo搜索引擎在互联网上搜索最新信息。当问题涉及实时事件、新闻或未知领域知识时使用此工具。输入应为明确的搜索查询字符串。 ) # 工具二维基百科查询 wiki WikipediaAPIWrapper(top_k_results2, doc_content_chars_max1000) wiki_tool Tool( nameWikipedia, funcwiki.run, description查询维基百科获取关于人物、地点、历史事件、科学概念等的事实性摘要。输入应为具体的查询主题。 ) # 工具三Python代码执行谨慎使用 # 注意这是一个高风险工具仅用于演示。在生产环境中必须在严格的沙箱环境中执行。 from langchain_experimental.tools import PythonREPLTool python_repl_tool PythonREPLTool() python_repl_tool.description 执行Python代码并返回结果。用于数学计算、数据转换、字符串处理等。**警告**不要执行来自不可信来源的代码。输入应为一段有效的Python代码。 # 将工具放入列表 tools [search_tool, wiki_tool, python_repl_tool] # 3. 构建自定义提示词模板 # 这是提升Agent性能的关键步骤 prompt ChatPromptTemplate.from_messages([ (system, 你是一个功能强大的AI助手名为“智囊”。你可以通过调用工具来获取信息或执行任务。 你的核心能力包括网页搜索、查询维基百科、执行Python代码。 请严格按照以下规则行动 1. 首先理解用户的请求。 2. 如果需要实时信息或未知知识使用Web_Search工具。 3. 如果需要权威的事实性背景知识使用Wikipedia工具。 4. 如果需要计算、数据处理或文本分析使用Python_REPL工具。 5. 在最终回答前尽量综合所有工具获取的信息。 6. 你的最终输出必须是完整的、对人类友好的答案。 可用工具 {tools} 请严格按此格式响应 思考分析我需要做什么是否需要使用工具 行动json {{ action: 工具名称, action_input: 工具的输入参数 }}或者当你有最终答案时 最终答案你的答案文本历史对话记录 {chat_history}用户输入{input} ), MessagesPlaceholder(variable_namechat_history, optionalTrue), (human, {input}), MessagesPlaceholder(variable_nameagent_scratchpad), ])4. 创建Agent和Executor使用LangChain的新版create_openai_tools_agent它原生支持OpenAI的function callingagent create_openai_tools_agent(llm, tools, prompt) agent_executor AgentExecutor(agentagent, toolstools, verboseTrue, handle_parsing_errorsTrue)print(多功能智能体初始化完成)### 3.2 运行与测试智能体 编写一个简单的测试函数来运行我们的Agent。 python def run_agent_query(query): 执行一次查询 print(f\n用户提问: {query}) print(- * 50) try: result agent_executor.invoke({input: query, chat_history: []}) print(f\n智能体回答: {result[output]}) except Exception as e: print(f执行出错: {e}) if __name__ __main__: # 测试1需要联网搜索的问题 run_agent_query(特斯拉最新的车型是什么有什么亮点) # 测试2需要事实性知识的问题 run_agent_query(爱因斯坦的相对论主要讲了什么) # 测试3需要计算的问题 run_agent_query(请计算3425乘以178等于多少) # 测试4复杂多步问题真正的挑战 run_agent_query(请搜索‘LangChain’的最新版本号然后用Python计算这个版本号假设是2.1.8的各个数字之和。)运行这个脚本你会看到verboseTrue模式下Agent详细的思考过程Chain of Thought它如何选择工具如何解析工具返回的结果并最终给出答案。例如对于最后一个复杂问题一个表现良好的Agent应该会思考需要最新版本号这需要实时信息调用Web_Search。行动搜索“LangChain latest version”。观察从搜索结果中提取出版本号比如“2.1.8”。思考现在需要计算数字之和这是一个计算任务调用Python_REPL。行动执行代码sum([int(d) for d in 2.1.8.split(.)])或类似逻辑。观察得到结果11。最终答案给出综合回答。这个过程完美诠释了智能体的“规划-执行-观察”循环。3.3 为智能体增加记忆能力上面的Agent是“无状态”的每次对话都是独立的。为了让Agent能进行多轮对话我们需要为其添加记忆。LangChain提供了多种记忆后端这里使用最简单的ConversationBufferMemory。from langchain.memory import ConversationBufferMemory # 创建带记忆的提示词模板 prompt_with_memory ChatPromptTemplate.from_messages([ (system, 你是智能助手智囊。你有工具和记忆。以下是对话历史。), MessagesPlaceholder(variable_namechat_history), (human, {input}), MessagesPlaceholder(variable_nameagent_scratchpad), ]) # 初始化记忆 memory ConversationBufferMemory(memory_keychat_history, return_messagesTrue) # 创建带记忆的Agent agent_with_memory create_openai_tools_agent(llm, tools, prompt_with_memory) agent_executor_with_memory AgentExecutor( agentagent_with_memory, toolstools, memorymemory, verboseTrue, handle_parsing_errorsTrue ) # 测试多轮对话 print(第一轮) result1 agent_executor_with_memory.invoke({input: 我的名字叫小明。}) print(fAgent: {result1[output]}) print(\n第二轮) result2 agent_executor_with_memory.invoke({input: 我刚才说我叫什么名字}) # Agent应该能记住 print(fAgent: {result2[output]})4. 高级主题RAG与Agent的融合Agentic RAG单纯的RAG是被动的问答而Agent是主动的规划者。将它们结合就能创造出更强大的“Agentic RAG”系统。其核心思想是让Agent来主导RAG的过程决定何时检索、检索什么、如何整合检索结果。一个典型的场景是复杂问答。用户问“对比一下LangChain和LlamaIndex在构建RAG系统方面的优缺点。” 传统RAG可能直接检索出两段分别介绍LangChain和LlamaIndex的文字然后拼接。而Agentic RAG可以这样做规划Agent分析问题认为需要分别获取LangChain和LlamaIndex在RAG方面的特点然后进行对比。执行-检索Agent可能发起两次检索查询“LangChain RAG 优点 缺点”、“LlamaIndex RAG 优点 缺点”或者更精细地拆解。观察与整合Agent收到多份检索结果后不是简单拼接而是主动提取关键点组织成对比表格或结构化摘要。最终回答生成一个清晰的对比报告。下面我们实现一个简单的Agentic RAG其中Agent负责生成优化的搜索查询。from langchain.agents import initialize_agent, AgentType from langchain.vectorstores import Chroma from langchain.embeddings import OpenAIEmbeddings from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.document_loaders import TextLoader # 假设我们已有一个关于AI框架的文档库 loader TextLoader(ai_frameworks.txt) # 你需要准备这个文件 documents loader.load() text_splitter RecursiveCharacterTextSplitter(chunk_size500, chunk_overlap50) docs text_splitter.split_documents(documents) # 创建向量库 embeddings OpenAIEmbeddings() vectorstore Chroma.from_documents(docs, embeddings) retriever vectorstore.as_retriever() # 创建一个自定义的RAG工具 from langchain.tools import BaseTool from typing import Type from pydantic import BaseModel, Field class RagQueryInput(BaseModel): query: str Field(description用于检索相关文档的查询语句) class CustomRagTool(BaseTool): name Knowledge_Base_Search description 从内部知识库中搜索与查询最相关的技术文档片段。用于回答关于AI框架、编程概念等特定领域知识。 args_schema: Type[BaseModel] RagQueryInput def _run(self, query: str) - str: 执行检索并返回相关文档内容 docs retriever.get_relevant_documents(query) content \n\n.join([doc.page_content for doc in docs[:3]]) # 返回前3个最相关片段 return f根据你的查询‘{query}’从知识库中找到以下相关信息\n{content} async def _arun(self, query: str) - str: raise NotImplementedError(此工具不支持异步) rag_tool CustomRagTool() # 创建一个专门用于技术问答的Agent它可以选择使用RAG工具或搜索工具 tech_tools [rag_tool, search_tool] # 结合内部知识库和外部搜索 tech_agent_prompt ChatPromptTemplate.from_messages([ (system, 你是一个技术专家助手。你拥有一个内部AI知识库和一个互联网搜索工具。 请遵循以下策略 1. 当问题涉及具体的AI框架如LangChain, LlamaIndex、库的API用法或已知技术概念时优先使用Knowledge_Base_Search工具从内部知识库查找精准信息。 2. 当问题涉及最新动态、版本发布、新闻或内部知识库没有的信息时使用Web_Search工具。 3. 综合分析所有获取的信息给出准确、全面的答案。 ), MessagesPlaceholder(variable_namechat_history), (human, {input}), MessagesPlaceholder(variable_nameagent_scratchpad), ]) tech_agent create_openai_tools_agent(llm, tech_tools, tech_agent_prompt) tech_agent_executor AgentExecutor(agenttech_agent, toolstech_tools, verboseTrue) # 测试 query LangChain的Chain和Agent有什么区别请结合知识库和最新信息回答。 result tech_agent_executor.invoke({input: query, chat_history: []}) print(result[output])这个Agent会先判断问题性质优先从本地向量库检索高质量文档如果不够再补充联网搜索从而提供更精准、信息量更丰富的答案。5. 使用FastAPI构建智能体Web服务一个命令行工具实用性有限。我们将使用FastAPI将智能体封装成RESTful API服务并提供一个简单的HTML前端进行交互。首先安装FastAPI和Uvicorn。pip install fastapi uvicorn创建app.py文件。from fastapi import FastAPI, HTTPException from fastapi.responses import HTMLResponse from pydantic import BaseModel from typing import List, Optional import json from advanced_agent import agent_executor_with_memory # 导入我们之前构建的带记忆Agent app FastAPI(title智囊AI助手API, description一个基于LangChain的多功能智能体服务) # 定义请求/响应模型 class ChatRequest(BaseModel): message: str session_id: Optional[str] None # 用于区分不同对话会话 class ChatResponse(BaseModel): reply: str session_id: str tool_calls: Optional[List[dict]] [] # 可选返回Agent调用的工具信息用于前端展示 # 简单的内存会话存储生产环境应使用Redis或数据库 sessions {} app.get(/, response_classHTMLResponse) async def read_root(): 提供一个简单的测试前端页面 html_content !DOCTYPE html html head title智囊AI助手/title style body { font-family: Arial; max-width: 800px; margin: 40px auto; } #chatbox { border: 1px solid #ccc; height: 400px; overflow-y: scroll; padding: 10px; margin-bottom: 10px; } .user { text-align: right; color: blue; } .bot { text-align: left; color: green; } input { width: 70%; padding: 10px; } button { padding: 10px 20px; } /style /head body h2 智囊AI助手 (LangChain Agent)/h2 div idchatbox/div input typetext idmessage placeholder输入你的问题... button onclicksendMessage()发送/button script const sessionId session_ Math.random().toString(36).substr(2, 9); function addMessage(sender, text) { const chatbox document.getElementById(chatbox); const msgDiv document.createElement(div); msgDiv.className sender; msgDiv.innerHTML strong${sender}:/strong ${text}; chatbox.appendChild(msgDiv); chatbox.scrollTop chatbox.scrollHeight; } async function sendMessage() { const input document.getElementById(message); const message input.value.trim(); if (!message) return; addMessage(你, message); input.value ; try { const response await fetch(/chat, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ message: message, session_id: sessionId }) }); const data await response.json(); addMessage(智囊, data.reply); if(data.tool_calls data.tool_calls.length 0) { addMessage(系统, 本次思考使用了工具: ${JSON.stringify(data.tool_calls)}); } } catch (error) { addMessage(系统, 请求出错: error); } } // 按Enter发送 document.getElementById(message).addEventListener(keypress, function(e) { if (e.key Enter) sendMessage(); }); /script /body /html return HTMLResponse(contenthtml_content) app.post(/chat, response_modelChatResponse) async def chat_with_agent(request: ChatRequest): 与智能体对话的主接口 try: # 这里为了简化我们直接使用全局的agent_executor_with_memory # 在实际生产中需要根据session_id管理不同的memory实例 result agent_executor_with_memory.invoke({input: request.message}) # 可以从result中提取工具调用历史用于前端展示verbose输出中的内容 tool_calls_history [] # 注意实际工具调用信息在result的中间步骤中这里做简化处理 if intermediate_steps in result: for step in result[intermediate_steps]: if len(step) 0: action, _ step tool_calls_history.append({tool: action.tool, input: action.tool_input}) return ChatResponse( replyresult[output], session_idrequest.session_id or default_session, tool_callstool_calls_history ) except Exception as e: raise HTTPException(status_code500, detailf智能体处理失败: {str(e)}) if __name__ __main__: import uvicorn uvicorn.run(app, host0.0.0.0, port8000)运行这个应用python app.py然后在浏览器中打开http://localhost:8000你就可以看到一个简单的聊天界面可以与你的智能体进行多轮对话了。前端会展示对话内容如果Agent调用了工具也会在消息中显示出来。6. 生产环境部署与优化建议将原型投入生产需要考虑更多工程化问题。1. 性能与成本优化缓存对频繁且结果不变的查询如“爱因斯坦是谁”实施缓存。可以使用LangChain的LLMCache或外部缓存如Redis。限流与降级对API调用进行限流防止意外高频请求产生巨额费用。当主要LLM如GPT-4不可用时应有降级方案如切换到更便宜的gpt-3.5-turbo或本地模型。异步处理对于耗时的任务如处理长文档使用异步队列Celery Redis/RabbitMQ处理通过WebSocket或轮询向客户端返回结果。2. 可靠性提升错误处理与重试为LLM调用和工具调用添加完善的错误处理网络超时、API限额、无效响应和指数退避重试机制。验证与过滤对用户输入进行清理和验证防止Prompt注入攻击。对工具尤其是Python_REPL的输出进行过滤避免返回敏感信息或错误代码。日志与监控记录所有交互日志包括用户输入、Agent思考过程、工具调用、最终输出和延迟。这有助于调试和优化。3. 高级架构模式使用LangGraph对于需要复杂工作流、循环、分支的AgentLangChain的LangGraph库是更好的选择。它允许你以图Graph的形式定义Agent的工作流状态流转更清晰可控。多Agent系统如前所述设计多个专用Agent客服Agent、数据分析Agent、文档处理Agent并通过一个路由Agent或基于LangGraph的编排器来分发任务。RAG流水线优化对于Agentic RAG可以优化检索步骤例如引入重排序Re-ranking模型如Cohere的Rerank API或BGE Reranker对初步检索到的文档进行精排将最相关的文档排在前面提升后续生成质量。4. 安全与合规沙箱环境任何代码执行工具必须在完全隔离的沙箱如Docker容器、Firecracker微VM中运行并严格限制资源CPU、内存、网络、文件系统访问。内容审核对用户输入和Agent输出实施内容安全过滤防止生成有害、偏见或不合规的内容。数据隐私如果处理用户私有数据确保向量化、存储和传输过程加密并遵守相关数据保护法规。构建一个成熟可用的AI智能体系统是一个持续迭代的过程。从本文的入门实战出发理解其核心原理然后根据你的具体业务需求在可靠性、性能和成本之间找到最佳平衡点。记住最好的智能体不是功能最多的而是最理解用户需求、最稳定可靠的那一个。