从零构建AI Agent:基于LangChain的智能数据查询助手实战
30款热门AI模型一站整合DeepSeek/GLM/Qwen 随心用限时 5 折。 点击领海量免费额度最近和几个做开发的朋友聊天发现一个挺有意思的现象大家聊起AI Agent时都头头是道从自主规划到工具调用从多模态到工作流编排仿佛下一秒就能造出个“贾维斯”来。但当我问“那你自己动手搭过一个能跑起来的Agent吗”时场面往往就安静了。这其实不怪大家。AI Agent的概念听起来很酷但真要从零开始面对浩如烟海的框架、API、模型和概念很容易陷入“一看就会一动手就废”的困境。很多人卡在了第一步不知道如何把一个大模型、几个工具和一段逻辑像拼乐高一样组装成一个能自主完成任务的智能体。今天我们不谈空泛的概念就聚焦一个在AI应用开发领域几乎绕不开的框架——LangChain。很多人知道它但可能只停留在“哦那个用来做RAG的框架”。实际上LangChain的核心价值远不止于此它提供了一套标准化的“积木”和“图纸”让你能系统化地构建从简单问答到复杂Agent的各种应用。这篇文章我们就来彻底拆解LangChain的工作机制并亲手从零搭建一个能实际运行的AI Agent把“知道”变成“做到”。1. 为什么是LangChain它解决的远不止“调用API”的问题在深入代码之前我们必须先理解LangChain到底在解决什么核心问题。如果你认为它只是一个封装了OpenAI API调用的Python库那就大大低估了它的价值。它的出现本质上是为了应对大模型应用开发中的几个关键工程化挑战挑战一上下文管理的混乱。大模型有上下文长度限制。一个复杂的任务可能需要多次交互如何有效地组织、修剪、总结和传递历史对话信息自己写状态管理很快就会变得难以维护。挑战二工具调用的标准化。让大模型学会使用外部工具如搜索、计算、查数据库是Agent的核心能力。但如何向模型清晰地描述工具如何解析模型的输出并可靠地执行工具如何将工具执行结果再塞回给模型这个过程充满了胶水代码。挑战三复杂流程的编排。很多任务不是一次LLM调用就能完成的。它可能是一个链式调用Chain比如“总结A - 翻译成B - 提取关键词”也可能是一个基于条件的路由Router比如“如果是技术问题就找文档如果是闲聊就调用对话模型”更可能是拥有记忆、能自主规划步骤的智能体Agent。手动编排这些逻辑代码会迅速变得像意大利面条一样混乱。挑战四组件的可复用与可观测性。当你构建了十几个不同的AI应用后会发现很多组件提示词模板、输出解析器、记忆模块是通用的。如何避免重复造轮子同时当流程出错时如何快速定位是哪个环节LLM、工具、解析出了问题这就需要一套统一的抽象和日志追踪体系。LangChain正是针对这些挑战提供了一套声明式、模块化、可观测的编程范式。它将AI应用的常见模式抽象为几个核心概念Model I/O、Retrieval、Chains、Agents、Memory。开发者像组装流水线一样用这些标准件构建应用从而将精力从繁琐的工程细节中解放出来聚焦于业务逻辑本身。2. 核心积木解析读懂LangChain的“设计图纸”要搭好房子先得认识砖瓦。LangChain的这套“积木”是其灵魂所在。我们逐一拆解并理解它们是如何协作的。2.1 Model I/O与模型对话的标准化接口这是最基础的层负责与大模型交互。它进一步分为三个部分LLMs/ChatModels 这是对文本补全模型如GPT-3和对话模型如GPT-4的抽象。关键价值在于它统一了不同供应商OpenAI, Anthropic, 本地部署的Qwen等的调用方式。切换模型时你通常只需要改一行初始化代码。Prompts 提示词模板。它让你能动态生成提示词比如把用户问题插入到一个固定的指令框架中。这避免了在代码中拼接字符串的混乱。from langchain.prompts import ChatPromptTemplate template ChatPromptTemplate.from_messages([ (system, 你是一个专业的翻译官。), (user, 请将以下英文翻译成中文{text}) ]) prompt template.invoke({text: Hello, world!})Output parsers 输出解析器。LLM的输出是自由文本但程序需要结构化的数据如JSON、列表。输出解析器定义如何将文本解析成所需格式并在提示词中指导模型按格式输出。from langchain.output_parsers import CommaSeparatedListOutputParser parser CommaSeparatedListOutputParser() # 这个format_instructions会自动生成一段指导模型输出列表的提示词 instructions parser.get_format_instructions() # 将instructions加入你的prompt模型就会输出“a, b, c”这样的格式然后parser能将其解析为[a, b, c]2.2 Chains将多个步骤链接成流水线Chain是LangChain的招牌概念。一个Chain由一系列可调用的组件可以是另一个Chain、LLM、工具或自定义函数组成。它定义了执行的顺序和数据流。LCEL (LangChain Expression Language) 这是LangChain最新、最推荐的链式编写方式。它使用管道符|来组合组件代码非常清晰。from langchain_openai import ChatOpenAI from langchain.prompts import ChatPromptTemplate from langchain.schema.output_parser import StrOutputParser model ChatOpenAI(modelgpt-3.5-turbo) prompt ChatPromptTemplate.from_template(讲一个关于{topic}的笑话) # 构建链prompt - model - parser chain prompt | model | StrOutputParser() # 运行链 result chain.invoke({topic: 程序员}) print(result)这个简单的链清晰地展示了数据流topic流入prompt模板生成完整提示词提示词送入model模型的输出再被StrOutputParser解析为字符串。复杂应用就是由许多这样的链嵌套组合而成。2.3 Agents赋予模型使用工具的能力Agent是LangChain实现“智能体”的核心。一个Agent由以下几部分组成LLM 负责思考的大脑。Tools 可供调用的外部工具列表如搜索引擎、计算器、数据库查询API。Agent Executor 运行Agent的引擎。它负责循环将用户输入和记忆交给LLM - LLM思考后决定下一步调用某个工具或直接给出最终答案- 执行工具 - 将工具结果作为新的上下文再次交给LLM - 直到LLM认为可以给出最终答案。Prompt 指导Agent行为的系统提示词通常包含工具描述、行动格式要求等。LangChain内置了多种Agent类型如ReAct,OpenAI Functions它们主要区别在于提示词策略和与LLM的交互方式。Agent Executor帮你处理了所有循环、解析和错误处理的重任。2.4 Memory让对话拥有记忆Memory模块负责在多次交互中持久化状态。它不仅仅是保存历史消息那么简单高级的Memory还能进行总结、压缩以在有限的上下文窗口内保留最关键的信息。ConversationBufferMemory: 简单存储所有对话历史。ConversationSummaryMemory: 定期总结之前的对话以节省token。ConversationBufferWindowMemory: 只保留最近K轮对话。Memory通常与Chain或Agent结合使用在每次调用时自动地将历史记录注入到当前对话的上下文中。2.5 Retrieval与外部知识库连接RAG这是LangChain另一个广为人知的应用场景——检索增强生成。它提供了一套完整的工具链用于加载文档、分割文本、向量化存储、语义检索并将检索到的文档作为上下文提供给LLM。虽然本文重点在Agent但需要知道这是LangChain生态的重要一环。理解了这些核心“积木”我们就可以开始动手搭建了。接下来我们将构建一个实用的、能解决真实问题的AI Agent。3. 实战构建一个“智能数据查询分析师”Agent假设我们是一个数据分析团队的成员经常需要查询数据库来回答业务问题。但并非所有成员都精通SQL。我们的目标是构建一个Agent它能够理解用户用自然语言提出的业务问题如“上个月华东区的销售额前三名产品是什么”。思考并生成正确的SQL查询语句。调用数据库工具执行查询。分析查询结果并用自然语言给出洞察性回答。这个Agent将综合运用LLM、Tool、Memory和Chain。我们使用SQLite作为示例数据库因为它简单易用。3.1 环境准备与数据库搭建首先安装必要库并创建一个示例数据库。pip install langchain langchain-community langchain-openai sqlalchemy然后创建一个Python脚本setup_db.py来初始化数据库和示例数据import sqlite3 # 连接数据库如果不存在则创建 conn sqlite3.connect(sales_data.db) cursor conn.cursor() # 创建销售记录表 cursor.execute( CREATE TABLE IF NOT EXISTS sales ( id INTEGER PRIMARY KEY, region TEXT NOT NULL, product TEXT NOT NULL, sale_date DATE NOT NULL, amount REAL NOT NULL ) ) # 插入示例数据 sample_data [ (华东, 产品A, 2024-03-15, 15000.0), (华东, 产品B, 2024-03-20, 22000.0), (华东, 产品C, 2024-03-10, 18000.0), (华南, 产品A, 2024-03-05, 12000.0), (华南, 产品D, 2024-03-18, 25000.0), (华北, 产品B, 2024-03-22, 19000.0), (华东, 产品A, 2024-04-02, 16000.0), (华东, 产品B, 2024-04-03, 21000.0), ] cursor.executemany(INSERT INTO sales (region, product, sale_date, amount) VALUES (?, ?, ?, ?), sample_data) conn.commit() conn.close() print(数据库sales_data.db及示例数据已创建完成。)运行这个脚本我们就有了一个包含销售数据的SQLite数据库。3.2 构建核心工具数据库查询工具在LangChain中一个Tool本质上是一个带有描述和调用方法的函数。我们需要创建一个能执行SQL查询并返回结果的工具。from langchain.tools import Tool import sqlite3 def query_sqlite_db(query: str) - str: 执行SQL查询并返回结果字符串。 try: conn sqlite3.connect(sales_data.db) cursor conn.cursor() cursor.execute(query) results cursor.fetchall() conn.close() # 将结果格式化为易读的字符串 if results: # 获取列名 column_names [description[0] for description in cursor.description] # 构建结果字符串 result_str | .join(column_names) \n -*50 \n for row in results: result_str | .join(str(item) for item in row) \n return result_str else: return 查询成功但未返回任何数据。 except Exception as e: return f查询执行出错: {e} # 将函数包装成LangChain Tool db_query_tool Tool( nameSales_Database_Query, funcquery_sqlite_db, description用于查询销售数据库。输入必须是一个清晰、有效的SQLite SQL查询语句。 数据库包含一个sales表字段有id(整数), region(文本), product(文本), sale_date(日期), amount(实数)。 请确保生成的SQL语法正确。 )这个工具的关键在于description。Agent的LLM大脑会阅读这个描述来理解工具的用途和使用方法。描述写得越清晰准确LLM调用工具的准确率就越高。3.3 创建Agent并赋予它“大脑”和“记忆”我们将使用OpenAI的Chat模型作为大脑并为其配备我们刚创建的工具。同时为了进行多轮对话我们加入Memory。from langchain_openai import ChatOpenAI from langchain.agents import create_openai_tools_agent, AgentExecutor from langchain.memory import ConversationBufferMemory from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder # 1. 初始化LLM请替换为你的OpenAI API Key llm ChatOpenAI(modelgpt-3.5-turbo, temperature0, openai_api_keyyour-api-key-here) # 2. 定义工具列表 tools [db_query_tool] # 3. 创建Agent提示词模板 # 这个模板定义了Agent的角色、能力、行动格式和记忆插槽。 prompt ChatPromptTemplate.from_messages([ (system, 你是一个智能数据分析助手。你的职责是理解用户关于销售数据的自然语言问题生成正确的SQL查询执行查询并基于结果给出清晰、有洞察的分析回答。 你拥有以下工具 {tools} 请严格按照以下格式思考和回应 问题用户提出的原始问题 思考我需要分析这个问题并决定是否需要查询数据库。如果需要我应该生成什么样的SQL。 行动需要调用的工具名称 行动输入调用工具所需的输入一个SQL查询字符串 观察工具返回的结果 ... (这个思考-行动-观察循环可以重复多次) 最终答案基于所有观察用自然语言总结回答用户的问题。 如果用户的问题无法通过查询数据库回答请直接给出解释。 当前对话历史 {chat_history} ), MessagesPlaceholder(variable_namechat_history), (user, {input}), MessagesPlaceholder(variable_nameagent_scratchpad), # 这是留给Agent记录其思考过程的地方 ]) # 4. 创建Memory memory ConversationBufferMemory(memory_keychat_history, return_messagesTrue) # 5. 使用LangChain的工厂函数创建Agent agent create_openai_tools_agent(llm, tools, prompt) # 6. 创建Agent执行器它将管理整个思考-行动循环 agent_executor AgentExecutor(agentagent, toolstools, memorymemory, verboseTrue, handle_parsing_errorsTrue)代码解析create_openai_tools_agent: 这是一个高级封装它根据我们提供的LLM、工具和提示词创建出一个符合OpenAI工具调用格式的Agent。AgentExecutor: 这是真正的“发动机”。verboseTrue会让它在控制台打印出详细的思考步骤非常适合调试和学习。handle_parsing_errorsTrue: 这是一个重要的安全网。当LLM的输出不符合预期格式时它能防止整个程序崩溃而是进行错误处理。3.4 运行你的第一个AI Agent现在让我们向这个Agent提问。# 第一个问题 question1 上个月华东区的总销售额是多少 print(f用户: {question1}) result1 agent_executor.invoke({input: question1}) print(f助手: {result1[output]}\n) # 第二个问题Agent会记住上下文 question2 那么销售额最高的产品是哪个 print(f用户: {question2}) result2 agent_executor.invoke({input: question2}) print(f助手: {result2[output]})当你运行这段代码时如果设置了verboseTrue你会在控制台看到类似以下的思考过程这是LangChain Agent执行器的核心魅力它让黑盒过程变得透明 进入新的AgentExecutor链... 思考用户想知道上个月华东区的总销售额。我需要查询数据库。首先我需要理解“上个月”指的是哪个月份。假设当前是2024年4月那么上个月就是2024年3月。我需要从sales表中筛选region为‘华东’且sale_date在2024年3月份的数据然后对amount求和。 行动Sales_Database_Query 行动输入SELECT SUM(amount) AS total_sales FROM sales WHERE region 华东 AND strftime(%Y-%m, sale_date) 2024-03 观察total_sales -------------------------------------------------- 55000.0 思考我已经得到了查询结果总销售额是55000.0。现在我可以给出最终答案。 最终答案上个月2024年3月华东区的总销售额为55,000元。对于第二个问题由于Memory的存在Agent知道“那么”指的是继续上一个关于华东区销售额的话题它可能会生成一个查询“华东区销售额排名”的SQL。至此你已经成功构建并运行了一个具备理解、思考、行动、记忆能力的AI Agent。它不再是一个简单的聊天机器人而是一个能主动使用工具解决特定领域问题的智能助手。4. 从“能跑”到“好用”关键优化与避坑指南让一个Agent跑起来只是第一步。要让它在实际项目中可靠、高效地工作还需要考虑很多工程细节。以下是基于经验的关键优化点4.1 工具设计的鲁棒性我们之前创建的query_sqlite_db工具非常简陋存在风险。SQL注入风险 我们直接将LLM生成的SQL字符串执行了。一个恶意的提示词或LLM的失误可能导致破坏性查询。错误处理不足 只返回了错误信息但没有结构化日志不利于调试。性能问题 每次查询都打开和关闭连接。优化建议使用参数化查询或严格的白名单校验 至少可以检查生成的SQL是否只包含SELECT语句并过滤掉DROP、DELETE等危险关键字。增加查询超时和行数限制 防止复杂查询拖垮数据库。使用连接池 在生产环境中使用数据库连接池管理连接。返回结构化数据 除了易读的字符串也可以将结果以JSON格式返回方便后续链式处理。4.2 提示词工程与Agent类型选择我们使用的提示词模板是简化的。一个生产级的Agent提示词需要更精细的设计明确边界 在系统提示词中强调“你只能使用提供的工具”“你不能执行任何数据修改操作”。提供示例 在提示词中加入一两个Few-shot示例能显著提升LLM生成SQL的准确率和格式规范性。选择合适的Agent类型create_openai_tools_agent适用于支持工具调用功能的模型如gpt-3.5-turbo-1106及以上版本。如果你使用其他模型可能需要选择ReAct或其他类型的Agent。选择错误会导致Agent无法正确解析输出。4.3 记忆管理的策略ConversationBufferMemory会无限制地增长最终会耗尽LLM的上下文窗口。对于长对话 考虑使用ConversationSummaryMemory或ConversationBufferWindowMemory。ConversationSummaryMemory会定期将旧对话总结成一段话既能保留关键信息又能节省大量token。记忆的隔离性 默认情况下Memory是全局的。如果构建一个多用户服务你需要为每个会话session创建独立的Memory实例。4.4 可观测性与调试当Agent行为不符合预期时verboseTrue的输出是你的第一手资料。但在生产环境你需要更系统的方案使用LangSmith LangChain官方提供的可观测性平台。它能记录每一次链、每一次工具调用的输入输出、耗时、token使用量并生成跟踪链路图是调试复杂Agent的利器。结构化日志 将Agent的关键步骤接收到问题、生成的SQL、查询结果、最终回答记录到应用日志中。4.5 性能与成本考量减少不必要的LLM调用 Agent的思考-行动循环每次“思考”都是一次LLM API调用成本高昂。在设计工具时尽量让一个工具能完成更复杂的子任务减少循环次数。设置超时和最大迭代次数 通过AgentExecutor的max_iterations和max_execution_time参数防止Agent陷入死循环。缓存 对于相同或相似的查询可以考虑对LLM的响应或数据库查询结果进行缓存。5. 超越单个AgentLangGraph与复杂工作流编排我们构建的Agent是一个单一的、线性的“思考-行动”循环。但现实世界的问题往往更复杂可能需要多个Agent协作或者是一个包含条件分支、并行执行、循环等复杂逻辑的工作流。这就是LangGraph的用武之地。你可以把LangGraph理解为LangChain的“升级版”工作流引擎。它用图Graph的概念来定义计算流程节点Node 一个执行单元可以是一个LLM调用、一个工具、一个条件判断甚至是一个子图。边Edge 定义了节点之间的流转条件。可以是无条件流转也可以根据上一个节点的输出结果决定下一步走哪条路。一个简单的LangGraph思想示例 假设我们想构建一个更强大的数据分析助手其工作流如下问题分类节点 判断用户问题是“需要查询数据库”还是“普通闲聊”。分支 如果是“查询数据库”流向SQL Agent即我们刚构建的那个如果是“普通闲聊”流向一个专门的Chatbot节点。SQL Agent节点 执行查询分析。结果后处理节点 对查询到的原始数据进行可视化建议或深入分析。汇总节点 生成最终回答。在LangGraph中你可以用代码清晰地定义这个有向图并指定每个节点完成后如何决定下一个节点。这比用传统的if-else语句来编排多个Chain和Agent要清晰、可维护得多。何时该用LangChain何时该考虑LangGraph如果你的逻辑是简单的链式调用或一个标准的Agent循环LangChain的Chain和AgentExecutor完全够用且更简单直观。如果你的应用涉及多角色协作、复杂状态机、循环依赖、人工审核节点等复杂流程LangGraph提供了更强大、更灵活的抽象能力。写在最后从构建者到架构师通过亲手构建这个“智能数据查询分析师”你应该已经感受到LangChain并没有魔法它只是将构建AI应用的最佳实践和常见模式进行了标准化、模块化。它的价值在于让你从编写胶水代码的泥潭中跳出来站在更高的层面去思考如何设计AI与外部系统交互的流程。真正的挑战从“让Agent跑起来”之后才开始。你会遇到工具调用的不确定性、提示词的脆弱性、长上下文的管理、多步骤任务的规划与回溯、以及整个系统的可观测性和可维护性。解决这些问题需要的不仅仅是LangChain的API调用更是对问题域的深刻理解、严谨的软件工程思维和持续的迭代优化。所以别再只是谈论AI Agent了。选择一个你熟悉的小场景比如自动整理邮件、监控日志报警、生成周报草稿用LangChain把它实现出来。在动手的过程中你会遇到所有我们提到过的问题而解决这些问题的经验远比读十篇教程更有价值。这就是从“知道”到“做到”从“使用者”到“构建者”甚至最终成为“AI应用架构师”的必经之路。 30款热门AI模型一站整合DeepSeek/GLM/Qwen 随心用限时 5 折。 点击领海量免费额度