ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

从零构建AI Agent:基于LangChain实现记忆、规划与工具调用的智能体实战

从零构建AI Agent:基于LangChain实现记忆、规划与工具调用的智能体实战 最近在尝试将AI能力集成到自己的项目中时发现市面上的教程要么过于理论化要么就是直接丢给你一个复杂的框架对于想从零开始理解并搭建一个实用AI Agent的开发者来说门槛依然很高。本文旨在解决这个痛点通过一个完整的实战项目手把手带你从核心概念到代码落地构建一个具备记忆、规划和工具调用能力的智能体。无论你是想入门AI应用开发的学生还是希望为业务添加AI能力的工程师都能从这套闭环方案中获得可直接复用的代码与清晰的工程思路。1. AI Agent 核心概念从“聊天机器人”到“自主智能体”在开始写代码之前我们必须厘清一个基本问题AI Agent智能体和普通的AI对话模型如ChatGPT有什么区别简单来说一个普通的AI大模型是一个强大的“反应式系统”。你输入问题它生成回答。这个过程是单次的、无状态的。而一个AI Agent则是一个具备一定自主性的“代理系统”。它被赋予一个目标Goal然后能够自主地规划Plan、执行Act、观察Observe并循环此过程直至完成任务。这个循环就是经典的ReActReasoning Acting框架。我们可以用一个形象的比喻来理解普通AI模型一个学识渊博但被动应答的“百科全书”。AI Agent一个拥有百科全书大脑并且会主动查阅资料工具、记录要点记忆、制定计划规划去完成你交代任务的“私人助理”。一个功能完备的AI Agent通常由以下几个核心组件构成大脑Brain即核心的大语言模型LLM负责理解、推理和决策。例如 GPT-4、Claude、或开源的 Llama、Qwen 等。规划器Planner将复杂目标拆解为可执行的子任务序列。例如“写一份行业报告”可以拆解为“搜索最新资料”、“整理数据”、“撰写大纲”、“润色成文”。记忆系统Memory存储Agent与用户的交互历史、学到的知识、任务上下文等分为短期记忆当前会话和长期记忆向量数据库存储。工具集Tools扩展Agent能力边界的外部函数。例如搜索网络、查询数据库、执行代码、调用API、操作文件等。执行器Executor调用工具并处理返回结果将观察反馈给大脑进行下一轮决策。理解了这些我们就知道搭建一个Agent本质上是为一个大模型装配上“记忆”、“工具”和“规划”能力并设计好它们协同工作的流程。2. 环境准备与项目初始化我们将使用Python作为开发语言因为它拥有最丰富的AI开发生态。本教程基于主流的LangChain框架来构建Agent因为它提供了高度模块化的组件能让我们更专注于逻辑而非底层通信。2.1 基础环境与依赖请确保你的环境满足以下要求操作系统Windows 10/11, macOS 或 Linux (Ubuntu 20.04 推荐)。Python 版本3.8 或更高版本强烈推荐 3.10。包管理工具pip(Python 自带)。首先创建一个干净的虚拟环境来隔离项目依赖这是一个非常重要的工程实践。# 创建项目目录并进入 mkdir ai_agent_tutorial cd ai_agent_tutorial # 创建Python虚拟环境 (以venv为例) python -m venv venv # 激活虚拟环境 # Windows: venv\Scripts\activate # macOS/Linux: source venv/bin/activate激活后命令行提示符前会出现(venv)标识。接下来安装核心依赖。# 升级pip pip install --upgrade pip # 安装LangChain及其相关组件。注意LangChain版本迭代快以下为常用核心包。 pip install langchain langchain-community langchain-core # 安装OpenAI SDK如果你使用GPT系列模型作为大脑 pip install openai # 安装用于向量存储和记忆的库这里以Chroma为例轻量易用 pip install chromadb # 安装用于网页搜索的工具库如DuckDuckGo pip install duckduckgo-search # 安装环境变量管理库用于安全存储API Key pip install python-dotenv2.2 项目结构规划良好的项目结构是可持续开发的基础。创建如下目录和文件ai_agent_tutorial/ ├── .env # 存储敏感信息如API密钥切勿提交至Git ├── .gitignore # Git忽略文件 ├── requirements.txt # 项目依赖清单 ├── config/ # 配置文件目录 │ └── settings.py # 应用配置 ├── core/ # 核心逻辑目录 │ ├── __init__.py │ ├── agent.py # Agent主流程定义 │ ├── memory.py # 记忆系统实现 │ └── tools.py # 自定义工具集 ├── models/ # 数据模型定义可选 │ └── __init__.py ├── utils/ # 工具函数 │ └── __init__.py └── main.py # 应用主入口现在初始化requirements.txt文件记录我们安装的依赖。# 在项目根目录下执行 pip freeze requirements.txt在.gitignore文件中至少添加以下内容确保不提交虚拟环境和敏感信息。# .gitignore venv/ .env __pycache__/ *.pyc chroma_db/ # 向量数据库本地存储目录3. 核心组件拆解与实现我们将采用自底向上的方式先实现各个组件最后将它们组装成完整的Agent。3.1 配置管理与大脑初始化首先我们需要安全地管理API密钥。在项目根目录创建.env文件。# .env OPENAI_API_KEY你的OpenAI_API密钥 # 其他API密钥如SERPER_API_KEY谷歌搜索、TAVILY_API_KEY等可按需添加重要警告.env文件必须加入.gitignore绝对不要提交到代码仓库。这是保护账号安全的第一道防线。接下来创建config/settings.py来读取配置。# config/settings.py import os from dotenv import load_dotenv # 加载 .env 文件中的环境变量 load_dotenv() class Settings: # OpenAI 配置 OPENAI_API_KEY os.getenv(OPENAI_API_KEY) OPENAI_API_BASE os.getenv(OPENAI_API_BASE, https://api.openai.com/v1) # 支持自定义代理 OPENAI_MODEL os.getenv(OPENAI_MODEL, gpt-4o-mini) # 默认使用性价比高的模型 # 记忆存储路径 PERSIST_DIRECTORY os.getenv(PERSIST_DIRECTORY, ./chroma_db) # 工具相关配置例如搜索工具 SEARCH_RESULT_MAX int(os.getenv(SEARCH_RESULT_MAX, 5)) settings Settings()现在我们可以在core/agent.py中初始化我们的“大脑”——LLM。这里以OpenAI的模型为例你也可以替换为其他兼容OpenAI API的模型如Azure OpenAI或本地部署的Ollama。# core/agent.py from langchain_openai import ChatOpenAI from config.settings import settings def create_llm(): 创建并返回大语言模型实例。 llm ChatOpenAI( modelsettings.OPENAI_MODEL, openai_api_keysettings.OPENAI_API_KEY, openai_api_basesettings.OPENAI_API_BASE, temperature0.1, # 降低随机性让Agent更稳定 streamingFalse, # 非流式响应简化处理 ) return llm # 测试LLM连接 if __name__ __main__: llm create_llm() try: response llm.invoke(你好请回复‘大脑初始化成功’以确认连接正常。) print(response.content) except Exception as e: print(fLLM初始化失败: {e})运行python core/agent.py如果看到“大脑初始化成功”说明基础配置正确。3.2 构建工具集为Agent赋予“手脚”工具是Agent与外部世界交互的桥梁。我们实现两个经典工具网页搜索和计算器。首先在core/tools.py中定义工具。# core/tools.py from langchain.tools import Tool, tool from langchain_community.tools import DuckDuckGoSearchRun from langchain_community.utilities import WikipediaAPIWrapper import math import json # 1. 网页搜索工具 (使用 DuckDuckGo无需API Key) def get_search_tool(): 返回一个基于DuckDuckGo的搜索工具。 search DuckDuckGoSearchRun() search_tool Tool( nameWebSearch, funcsearch.run, description当你需要获取最新的、实时的信息或者查询你不知道的事实时使用此工具。 输入应该是一个明确的搜索查询字符串。 ) return search_tool # 2. 维基百科工具 (用于查询结构化知识) def get_wikipedia_tool(): 返回一个维基百科查询工具。 wikipedia WikipediaAPIWrapper() wikipedia_tool Tool( nameWikipedia, funcwikipedia.run, description当你需要查询关于人物、地点、公司、历史事件、科学概念等广泛认可的知识性信息时使用此工具。 输入应该是一个明确的主题名称。 ) return wikipedia_tool # 3. 计算器工具 (使用Python的eval生产环境需严格限制) tool def calculator(expression: str) - str: 执行数学计算。支持加减乘除(-*/)、乘方(**)、括号和常见数学函数如sin, cos, sqrt。 示例: calculator(\3 * (2 5)\) - 21 示例: calculator(\sqrt(16)\) - 4.0 # 安全限制只允许特定的数学字符和函数 allowed_names { k: v for k, v in math.__dict__.items() if not k.startswith(__) } allowed_names.update({abs: abs, round: round}) # 编译表达式并进行安全检查 try: # 使用eval但限制其可访问的全局和局部命名空间这是关键的安全措施 result eval( expression, {__builtins__: {}}, # 禁用内置函数 allowed_names ) return str(result) except Exception as e: return f计算错误: {e}. 请检查表达式格式。示例: 3 5 * 2 # 4. 获取当前时间工具 tool def get_current_time(query: str ) - str: 获取当前的日期和时间。输入可以是空字符串或任何文本工具会忽略输入并返回时间。 from datetime import datetime now datetime.now() # 格式化为易读的字符串 return now.strftime(%Y年%m月%d日 %H时%M分%S秒) def load_all_tools(): 加载并返回所有可用的工具列表。 tools [ get_search_tool(), get_wikipedia_tool(), calculator, # 注意使用tool装饰器定义的函数本身就是Tool实例 get_current_time, ] return tools if __name__ __main__: # 测试工具 tools load_all_tools() for t in tools: print(f工具名: {t.name}, 描述: {t.description[:50]}...) # 测试计算器 print(f测试计算: {calculator.invoke(3 ** 2 4)})安全警告calculator工具中使用了eval()这在生产环境中是高风险操作。我们通过严格限制可用的命名空间allowed_names来缓解风险。在真实业务场景中应使用更安全的数学表达式解析库如ast.literal_eval配合自定义解析器或numexpr。3.3 实现记忆系统让Agent拥有“过去”没有记忆的Agent每次对话都是全新的开始。我们将实现一个结合了“对话历史”和“长期知识”的记忆系统。在core/memory.py中我们使用ConversationBufferWindowMemory来保存最近的对话短期记忆并使用Chroma向量数据库来存储和检索重要的知识片段长期记忆。# core/memory.py from langchain.memory import ConversationBufferWindowMemory, VectorStoreRetrieverMemory from langchain_community.vectorstores import Chroma from langchain_openai import OpenAIEmbeddings from langchain.docstore import InMemoryDocstore from langchain.schema import Document from config.settings import settings import os class AgentMemory: def __init__(self, llm, k5): 初始化Agent的记忆系统。 Args: llm: 语言模型用于某些类型的记忆处理此处主要用于向量化实际由Embeddings完成。 k: 短期记忆对话轮次的窗口大小。 self.llm llm self.k k # 1. 初始化短期记忆对话缓冲区 self.conversation_memory ConversationBufferWindowMemory( memory_keychat_history, return_messagesTrue, # 返回Message对象列表而非字符串 kk # 保留最近k轮对话 ) # 2. 初始化长期记忆向量存储 # 确保存储目录存在 persist_directory settings.PERSIST_DIRECTORY os.makedirs(persist_directory, exist_okTrue) # 使用OpenAI的Embeddings模型将文本转换为向量 # 注意这需要OPENAI_API_KEY embedding_model OpenAIEmbeddings( openai_api_keysettings.OPENAI_API_KEY, modeltext-embedding-3-small ) # 创建或加载向量数据库 self.vectorstore Chroma( collection_nameagent_long_term_memory, embedding_functionembedding_model, persist_directorypersist_directory ) # 包装向量数据库为检索器用于记忆系统 self.retriever self.vectorstore.as_retriever( search_kwargs{k: 3} # 每次检索最相关的3条记忆 ) # 初始化LangChain的VectorStoreRetrieverMemory self.long_term_memory VectorStoreRetrieverMemory( retrieverself.retriever, memory_keylong_term_memory ) def save_to_long_term(self, text: str, metadata: dict None): 将一段文本知识保存到长期记忆向量数据库。 Args: text: 要保存的文本内容。 metadata: 相关的元数据如来源、时间等。 if metadata is None: metadata {} # 创建Document对象 doc Document(page_contenttext, metadatametadata) # 添加到向量库 self.vectorstore.add_documents([doc]) # 持久化到磁盘 self.vectorstore.persist() print(f[记忆系统] 已保存到长期记忆: {text[:50]}...) def query_long_term(self, query: str) - str: 从长期记忆中检索与查询相关的信息。 Args: query: 查询字符串。 Returns: 检索到的相关文本内容。 docs self.vectorstore.similarity_search(query, k2) if docs: content \n.join([doc.page_content for doc in docs]) return f从长期记忆中检索到以下相关信息\n{content} else: return 长期记忆中未找到相关信息。 def get_memory_variables(self): 返回用于传递给Agent的完整记忆上下文。 # 获取短期对话历史 chat_history_dict self.conversation_memory.load_memory_variables({}) chat_history chat_history_dict.get(chat_history, ) # 获取长期记忆这里简化处理实际使用中Agent的prompt会决定何时查询 # 我们可以在主流程中动态调用 query_long_term return { chat_history: chat_history, # long_term_context: long_term_context, // 动态注入 } def clear_conversation(self): 清空短期对话记忆。 self.conversation_memory.clear() print([记忆系统] 短期对话记忆已清空。) def clear_long_term(self): 清空长期向量记忆谨慎操作。 # Chroma 的 delete_collection 会删除数据 # 更安全的方式是重置整个persist目录演示用 import shutil if os.path.exists(settings.PERSIST_DIRECTORY): shutil.rmtree(settings.PERSIST_DIRECTORY) os.makedirs(settings.PERSIST_DIRECTORY) # 需要重新初始化vectorstore self.__init__(self.llm, self.k) print([记忆系统] 长期记忆已清空。) if __name__ __main__: # 测试记忆系统需要先有llm这里简单模拟 from core.agent import create_llm llm create_llm() memory_system AgentMemory(llm) # 测试保存长期记忆 memory_system.save_to_long_term(Python中列表(List)是可变的序列类型用方括号[]定义。) memory_system.save_to_long_term(LangChain是一个用于开发大语言模型应用的框架。) # 测试查询 result memory_system.query_long_term(Python的列表是什么) print(result)3.4 组装智能体定义大脑的工作流程有了大脑LLM、工具Tools和记忆Memory现在我们需要定义Agent如何协调工作。我们将使用LangChain的create_react_agent来构建一个遵循ReAct范式的智能体。在core/agent.py中完善主Agent类。# core/agent.py (续) from langchain.agents import create_react_agent, AgentExecutor from langchain import hub # 用于拉取预设的Prompt from core.tools import load_all_tools from core.memory import AgentMemory from config.settings import settings class MyAIAgent: def __init__(self): 初始化AI Agent整合LLM、工具和记忆。 print(正在初始化AI Agent...) # 1. 创建大脑 self.llm create_llm() # 2. 加载工具 self.tools load_all_tools() print(f已加载工具: {[tool.name for tool in self.tools]}) # 3. 初始化记忆系统 self.memory_system AgentMemory(self.llm) print(记忆系统初始化完成。) # 4. 从LangChain Hub拉取一个优化过的ReAct提示词 # 这是一个社区维护的、针对工具使用优化的Prompt self.prompt hub.pull(hwchase17/react-chat) # 5. 创建ReAct Agent self.agent create_react_agent( llmself.llm, toolsself.tools, promptself.prompt ) # 6. 创建Agent执行器并绑定记忆 # 注意我们将对话记忆注入到执行器中 self.agent_executor AgentExecutor( agentself.agent, toolsself.tools, memoryself.memory_system.conversation_memory, # 注入短期记忆 verboseTrue, # 设置为True可以看到Agent的思考过程调试时非常有用 handle_parsing_errorsTrue, # 处理Agent输出解析错误 max_iterations5, # 限制最大迭代次数防止死循环 early_stopping_methodgenerate # 当Agent认为任务完成时停止 ) print(AI Agent 初始化成功) def run(self, input_text: str, use_long_term_memory: bool False) - str: 运行Agent处理用户输入。 Args: input_text: 用户输入的问题或指令。 use_long_term_memory: 是否在本次查询中启用长期记忆检索。 Returns: Agent的最终回复。 final_input input_text # 可选的长期记忆增强在输入前加入相关记忆上下文 if use_long_term_memory: related_memory self.memory_system.query_long_term(input_text) if 未找到 not in related_memory: final_input f{related_memory}\n\n基于以上背景信息请回答{input_text} print(f[记忆增强] 已注入长期记忆上下文。) try: # 执行Agent response self.agent_executor.invoke({input: final_input, chat_history: []}) # chat_history由memory自动管理 output response.get(output, 抱歉我没有得到有效的回复。) # 可选判断回答是否包含值得保存的知识并存入长期记忆 self._maybe_save_to_memory(input_text, output) return output except Exception as e: error_msg fAgent执行过程中出现错误: {e} print(error_msg) return error_msg def _maybe_save_to_memory(self, question: str, answer: str): 一个简单的启发式规则如果回答包含定义、概念或步骤则保存。 keywords [定义是, 概念是, 步骤是, 方法是, 原理是, 指的是, 包括以下] if any(keyword in answer for keyword in keywords) and len(answer) 500: # 避免保存过长的回答 knowledge fQ: {question}\nA: {answer} self.memory_system.save_to_long_term(knowledge, metadata{type: qa, source: agent_generated}) def clear_chat(self): 清空当前对话历史。 self.memory_system.clear_conversation() print(对话历史已清空。) def create_agent(): 创建并返回一个配置好的Agent实例。 return MyAIAgent() if __name__ __main__: # 快速功能测试 agent create_agent() test_queries [ 今天的日期和时间是什么, 计算一下 15 的平方加上 20 除以 4 等于多少, LangChain是什么, # 这个问题可能触发长期记忆如果之前保存过 搜索一下今天北京天气怎么样, ] for query in test_queries[:2]: # 先测试前两个避免频繁搜索 print(f\n用户: {query}) response agent.run(query) print(fAgent: {response}) print(- * 50)4. 完整实战构建一个命令行交互式智能体现在我们将所有组件集成到一个可以交互的应用程序中。创建main.py作为入口。# main.py import sys from core.agent import create_agent def main(): print( * 60) print(欢迎使用 AI Agent 智能体演示系统) print( * 60) print(功能说明) print( - 支持对话、计算、搜索、查询知识。) print( - 输入 clear 清空对话历史。) print( - 输入 memory on/off 开启/关闭长期记忆增强。) print( - 输入 exit 或 quit 退出程序。) print( * 60) # 初始化Agent try: agent create_agent() except Exception as e: print(fAgent初始化失败请检查配置尤其是API Key: {e}) sys.exit(1) use_long_term False # 默认关闭长期记忆增强避免无关查询干扰 while True: try: user_input input(\n 请输入您的问题: ).strip() if not user_input: continue # 处理系统命令 if user_input.lower() in [exit, quit, q]: print(感谢使用再见) break elif user_input.lower() clear: agent.clear_chat() print(对话历史已清空。) continue elif user_input.lower() memory on: use_long_term True print(长期记忆增强已开启。) continue elif user_input.lower() memory off: use_long_term False print(长期记忆增强已关闭。) continue elif user_input.startswith(save:): # 手动保存知识到长期记忆 knowledge user_input[5:].strip() if knowledge: agent.memory_system.save_to_long_term(knowledge) print(f已手动保存知识到长期记忆。) continue # 运行Agent处理用户输入 print(Agent 正在思考...) response agent.run(user_input, use_long_term_memoryuse_long_term) print(f\nAgent: {response}) except KeyboardInterrupt: print(\n\n检测到中断程序退出。) break except Exception as e: print(f\n系统错误: {e}) if __name__ __main__: main()现在在项目根目录下运行python main.py你将启动一个命令行交互界面。你可以尝试以下指令序列来体验Agent的完整能力计算一下 (12 8) * 3 / 2 等于多少今天的日期和时间是什么搜索一下什么是Transformer模型注意搜索可能需要几秒钟且结果受网络影响memory on开启长期记忆save: Transformer是一种基于自注意力机制的深度学习模型架构广泛应用于自然语言处理。手动保存知识Transformer模型是什么此时Agent会先检索长期记忆可能会直接使用你刚保存的知识回答clear清空对话历史再问同样的问题短期记忆消失但长期记忆仍在exit退出5. 常见问题与排查思路在搭建和运行过程中你可能会遇到以下问题问题现象可能原因解决思路导入LangChain模块失败(ModuleNotFoundError)1. 未安装对应包。2. 虚拟环境未激活。3. 包版本冲突。1. 使用pip list | grep langchain检查安装。2. 确认命令行前有(venv)标识。3. 尝试pip install -r requirements.txt重新安装。OpenAI API 连接错误(AuthenticationError,APIConnectionError)1. API Key 错误或过期。2. 网络问题如代理。3. 余额不足或请求超限。1. 检查.env文件中的OPENAI_API_KEY是否正确。2. 检查网络连接或通过OPENAI_API_BASE配置代理地址。3. 登录OpenAI平台检查用量和余额。Agent陷入循环或报解析错误1. Prompt不适合当前工具集。2. 工具描述不清晰。3. 模型温度 (temperature) 过高导致输出不稳定。1. 将verboseTrue打开观察Agent的思考链看它在哪一步出错。2. 检查并优化tools.py中每个工具的description确保清晰无歧义。3. 在create_llm()中降低temperature(如设为0.1)。4. 在AgentExecutor中适当减少max_iterations。搜索工具返回空或错误1. 网络问题。2. 搜索关键词被屏蔽或服务不稳定。1. 尝试直接运行DuckDuckGoSearchRun().run(“test”)测试。2. 考虑更换搜索工具如使用需要API Key但更稳定的TavilySearchResults。向量数据库Chroma报错1. 存储路径权限问题。2. 嵌入模型初始化失败。1. 检查PERSIST_DIRECTORY路径是否存在且可写。2. 确认OPENAI_API_KEY对Embeddings模型也有效。程序运行缓慢1. 网络请求多搜索、API调用。2. 向量检索计算量大。1. 为工具调用添加超时和重试机制。2. 限制向量检索返回的数量 (search_kwargs{“k”: 2})。3. 考虑使用本地嵌入模型如sentence-transformers替代OpenAI Embeddings。6. 进阶优化与工程实践建议一个可用的Demo只是起点要投入生产环境还需要考虑以下方面6.1 工具设计的鲁棒性错误处理每个工具函数内部都应该有完善的try...except返回结构化的错误信息供Agent理解而不是抛出异常导致流程中断。输入验证对工具输入进行严格的格式和内容检查防止无效或恶意输入。超时与重试对于网络依赖型工具如搜索、API调用必须设置超时和重试逻辑。6.2 记忆系统的优化记忆摘要长时间的对话历史会消耗大量Token。可以实现一个ConversationSummaryMemory定期将冗长的历史总结成精炼的要点。分层记忆区分工作记忆当前任务、短期记忆本次会话、长期记忆知识库。本教程实现了后两者你可以进一步细化。记忆更新与遗忘长期记忆不是只增不减的。需要设计机制对陈旧或错误的信息进行更新、降权或删除。6.3 Agent流程的增强多Agent协作复杂任务可以拆解给多个具有专长的子Agent如研究Agent、写作Agent、审核Agent协作完成。人类反馈循环在关键决策点如执行删除操作、发送邮件前让Agent暂停并请求人类确认。验证与回滚对于工具执行的结果可以设计一个“验证”步骤检查结果是否合理如果不合理则触发回滚或重试。6.4 生产环境部署考量配置外部化将所有配置模型类型、API端点、参数移至环境变量或配置中心如Apollo便于不同环境切换。日志与监控集成详细的日志记录如structlog记录每个Agent的决策链、工具调用和结果便于问题排查和效果分析。限流与熔断对LLM API调用和工具调用实施限流防止意外循环导致巨额账单或系统过载。安全隔离确保Agent运行在沙箱或受限权限环境中特别是当它能够执行代码或访问系统命令时。通过本教程你不仅搭建了一个功能完整的AI Agent原型更掌握了其核心组件的构造原理。接下来你可以尝试为它添加更多工具如发送邮件、读写数据库、分析数据集成更强大的本地模型或者将其封装成Web API服务。AI Agent的开发是一个持续迭代的过程关键在于理解其“感知-思考-行动”的循环本质并在此基础上不断优化各个模块的效能与可靠性。
返回列表