从零构建会思考的AI智能体:基于ReAct框架的自主决策系统开发实践

📅 发布时间:2026/8/11 3:40:26
从零构建会思考的AI智能体:基于ReAct框架的自主决策系统开发实践
1. 项目概述从“执行”到“思考”的跨越最近和几个做产品的朋友聊天大家都有一个共同的感受现在市面上的AI应用无论是聊天机器人还是自动化工具大多还停留在“你问我答”或“你指令我执行”的层面。它们很强大能写代码、画图、分析数据但总觉得缺了点“灵性”——就像一个反应迅速但缺乏主观能动性的助手。这让我萌生了一个想法能不能自己动手打造一个真正会“思考”的AI智能体不是那种简单地调用API返回结果而是能自主规划、分解任务、调用工具、并从结果中学习调整的智能体。这个“手撸一个会‘思考’的AI智能体”的项目核心目标就是构建一个具备初步自主决策能力的AI Agent。它不再是一个被动的响应者而是一个主动的问题解决者。想象一下你给它一个模糊的目标比如“帮我分析一下上个月的销售数据找出问题并给出下个月的优化建议”。一个传统的脚本或简单的API调用可能就卡壳了因为它不知道具体要分析什么、用什么工具、步骤是什么。但一个会“思考”的智能体应该能自己拆解这个目标第一步需要获取销售数据可能调用数据库API或读取本地文件第二步进行数据清洗和预处理调用Pandas库第三步进行趋势分析和异常检测可能结合统计分析或简单的机器学习第四步基于分析结果生成可视化图表调用Matplotlib第五步综合所有信息用自然语言撰写一份分析报告。这个过程就是“思考”的体现。这个项目非常适合有一定Python基础并对大模型应用开发感兴趣的开发者。你不需要是机器学习专家但需要对如何将大模型的能力与编程逻辑结合有浓厚的兴趣。通过这个项目你将深入理解智能体的核心架构——ReActReasoning and Acting、工具调用Tool Calling、记忆Memory和规划Planning等概念并亲手用代码将它们实现出来。我们将使用目前公认最易上手且功能强大的开发框架之一结合一个主流的大模型API如DeepSeek、OpenAI等从零开始搭建。你会发现让AI“思考”起来其内核是一套精巧的流程设计和提示词工程而代码则是实现这套设计的骨架。2. 智能体的核心架构与设计思路要构建一个会“思考”的智能体首先得弄明白“思考”在代码层面意味着什么。它不是一个玄学概念而是一系列可设计、可实现的模块协同工作的结果。经过业界多年的探索一个功能完备的智能体通常包含以下几个核心组件我们的项目也将围绕它们展开。2.1 大脑大语言模型与提示词工程智能体的“大脑”无疑是大语言模型。它负责理解用户指令、进行逻辑推理、生成决策和自然语言回应。但直接给模型一个复杂问题它往往无法给出可执行的方案。这时就需要“提示词工程”来引导它的思考过程。这里的关键是设计一套系统提示词它定义了智能体的角色、能力范围、思考格式和行动规范。例如我们的提示词会明确告诉模型“你是一个AI智能体可以调用各种工具解决问题。请遵循以下格式思考Thought: 分析当前情况和下一步该做什么Action: 需要调用的工具名称Action Input: 调用该工具所需的输入参数。当你得到工具的执行结果后再继续思考。” 这种结构化的提示强制模型进行一步步的推理并将思考过程与执行动作分离这是我们实现“思考”可视化和可控化的基础。选择大模型API时我们需要考虑其推理能力、对工具调用格式的支持、上下文长度以及成本。例如DeepSeek-V4-Pro或DeepSeek-V4-Flash在推理和代码能力上表现突出且提供了清晰的API。在代码中我们会通过API密钥来初始化模型客户端并确保请求格式符合其规范避免出现类似‘type‘ must be in [“enabled“, “disabled“, “auto“]或maximum context length超限这类常见错误。2.2 记忆模块短期记忆与长期记忆一个只会处理当前对话的智能体是健忘的算不上真正的思考者。记忆模块让智能体拥有“上下文”和“经验”。短期记忆Conversation Memory通常指对话历史。我们将使用“对话缓冲区记忆”它保存了最近几轮的用户输入、智能体的思考Thought、行动Action和观察结果Observation。这保证了智能体在连续对话中能理解指代关系比如用户说“把刚才分析的那个图表再解释一下”智能体能知道“刚才”指的是什么。长期记忆Vector Store对于更复杂的需求比如让智能体记住自己的操作手册、特定领域知识或历史任务总结我们需要向量数据库。将文本信息通过嵌入模型转化为向量并存储当遇到相关问题时智能体可以快速检索这些知识来辅助决策。例如我们可以把“如何生成销售报表”的步骤文档存入向量库当用户提出类似需求时智能体能自动检索并参考。在实现上短期记忆可以通过一个简单的列表或队列在内存中维护。而长期记忆则需要引入像ChromaDB、FAISS这样的轻量级向量数据库并结合一个嵌入模型API如OpenAI的text-embedding-3-small。2.3 工具集智能体的“手脚”思考之后需要行动工具就是智能体的手脚。一个智能体的能力边界很大程度上取决于它拥有什么工具。在我们的项目中工具可以是搜索工具调用搜索引擎API获取实时信息。计算器/代码执行工具在一个安全的沙箱环境中执行Python代码进行数学计算或数据处理。文件读写工具读取本地文本文件、CSV数据或将结果保存到文件。专用API工具调用天气查询、股票数据、翻译等第三方服务。每个工具都需要被明确定义工具名称、描述、输入参数JSON Schema格式。智能体的大脑LLM根据当前思考决定调用哪个工具并生成符合该工具要求的输入参数。在代码中我们会将每个工具封装成一个Python函数并提供一个统一的“工具注册表”供智能体查询和调用。2.4 控制流ReAct循环与规划器这是将以上所有模块串联起来的“神经系统”也是“思考”流程的核心体现。最经典的范式是ReActReason Act循环。观察智能体接收用户的初始输入或上一个工具的执行结果。思考智能体结合当前观察、记忆中的历史信息和可用工具列表分析现状决定下一步是直接回答用户还是调用某个工具。这一步的输出就是结构化的Thought。行动如果决定调用工具则输出Action和Action Input。我们的程序会解析这个输出找到对应的工具函数并执行。观察获取工具执行的结果或错误信息作为新的“观察”输入给智能体进入下一轮循环。这个循环会一直持续直到智能体在“思考”步骤中认为任务已经完成并输出最终的Final Answer。对于更复杂的任务我们还需要一个规划器。比如面对“分析销售数据”这种宏大目标智能体可能需要先将其分解为“获取数据”、“清洗数据”、“分析趋势”、“生成报告”等子任务然后为每个子任务启动一个ReAct循环。规划器可以是一个更高级的LLM调用专门用于任务分解和排序。3. 环境搭建与核心依赖配置工欲善其事必先利其器。在开始编码之前我们需要一个干净、可复现的Python开发环境。这里我强烈推荐使用conda或venv创建虚拟环境避免包版本冲突。3.1 Python环境与IDE准备首先确保你的系统安装了Python 3.9或更高版本。你可以从Python官网下载安装。对于IDEVSCode是一个绝佳的选择配合Python插件和Pylance语言服务器能获得很好的代码提示和调试体验。在项目根目录下创建并激活虚拟环境# 使用 venv python -m venv venv # 在Windows上激活 venv\Scripts\activate # 在Mac/Linux上激活 source venv/bin/activate激活后你的命令行提示符前会出现(venv)字样表示你已进入该虚拟环境。3.2 依赖包安装与关键版本锁定接下来创建requirements.txt文件并填入我们项目所需的核心依赖。这里的选择基于当前2024年最稳定和流行的智能体开发库。# 核心LLM交互与智能体框架 langchain0.1.0 langchain-community0.0.10 # 我们使用OpenAI格式的API兼容DeepSeek等众多模型 langchain-openai0.0.5 # 向量数据库用于长期记忆 chromadb0.4.22 # 文本嵌入模型用于将知识转化为向量 langchain-openai # 同样包含embeddings # 用于生成结构化输出如Thought/Action这对工具调用至关重要 langchain-core0.1.0 # 可选但推荐用于更优雅地管理环境变量 python-dotenv1.0.0 # 基础工具包 requests2.31.0 # 用于构建自定义API工具 pandas2.1.0 # 数据处理工具示例使用pip安装pip install -r requirements.txt注意langchain及其生态版本迭代很快上述版本号是撰写本文时的稳定组合。直接安装最新版可能会遇到接口不兼容的问题。如果你遇到ImportError或AttributeError首先检查版本是否匹配。锁定版本是保证项目可复现的关键一步。3.3 API密钥配置与安全管理我们的智能体需要调用大模型API因此需要配置API密钥。绝对不要将密钥硬编码在代码中标准做法是使用环境变量。在项目根目录创建.env文件。在.env文件中填入你的API密钥例如使用DeepSeekDEEPSEEK_API_KEYyour_deepseek_api_key_here DEEPSEEK_API_BASEhttps://api.deepseek.com # DeepSeek的API基础地址如果你使用OpenAI则对应是OPENAI_API_KEY。在Python代码中使用python-dotenv加载配置from dotenv import load_dotenv import os load_dotenv() # 加载 .env 文件中的环境变量 deepseek_api_key os.getenv(DEEPSEEK_API_KEY) api_base os.getenv(DEEPSEEK_API_BASE)这样你的密钥就与代码分离了。记得将.env文件添加到.gitignore中避免意外提交到公开仓库。4. 核心模块实现打造智能体的“器官”环境就绪后我们开始动手实现智能体的各个核心模块。我会从最简单的工具开始逐步组装成完整系统。4.1 工具库的构建与封装工具是智能体能力的延伸。我们先实现两个基础但强大的工具网络搜索和Python代码执行。工具一DuckDuckGo搜索工具我们利用duckduckgo-search这个包来实现无需API密钥的搜索。 首先安装它pip install duckduckgo-search。 然后封装成LangChain可识别的工具格式from langchain.tools import Tool from duckduckgo_search import DDGS def search_duckduckgo(query: str) - str: 使用DuckDuckGo搜索网络信息。 try: with DDGS() as ddgs: # 获取最相关的5条结果 results [r for r in ddgs.text(query, max_results5)] if not results: return 未找到相关信息。 # 将结果格式化为字符串 formatted_results \n\n.join([ f标题{r[title]}\n摘要{r[body]}\n链接{r[href]} for r in results ]) return f搜索到以下信息\n{formatted_results} except Exception as e: return f搜索过程中出现错误{str(e)} # 创建Tool对象定义名称、描述和函数 search_tool Tool( nameWeb_Search, funcsearch_duckduckgo, description当需要获取最新的、实时的或未知领域的信息时使用此工具。输入一个搜索查询词。 )工具二Python代码执行工具安全沙箱让智能体直接执行Python代码非常强大但也极其危险。切勿在生产环境中直接使用exec()。这里我们使用langchain社区提供的PythonREPLTool它在某种程度上提供了隔离。from langchain_community.tools import PythonREPLTool python_repl_tool PythonREPLTool( namePython_REPL, description执行Python代码并返回结果。适用于数学计算、数据转换、字符串处理等。输入一段有效的Python代码。 )重要警告即使在开发中也要谨慎使用此工具避免执行删除文件、访问网络等危险代码。最好限制其可访问的模块如禁用os,sys等。工具三自定义计算器对于简单的算术我们可以做一个更安全的专用工具import ast import operator as op # 支持的操作符 allowed_operators {ast.Add: op.add, ast.Sub: op.sub, ast.Mult: op.mul, ast.Div: op.truediv} def safe_eval(expr: str) - str: 安全地评估一个仅包含数字和基础运算符的数学表达式。 try: node ast.parse(expr, modeeval).body def _eval(node): if isinstance(node, ast.Num): # Python 3.7及以下用 ast.Num return node.n elif isinstance(node, ast.Constant): # Python 3.8 return node.value elif isinstance(node, ast.BinOp): left _eval(node.left) right _eval(node.right) return allowed_operators[type(node.op)](left, right) else: raise TypeError(f不支持的表达式类型{type(node)}) result _eval(node) return str(result) except Exception as e: return f计算错误{str(e)}。请确保输入是纯数学表达式如‘(35)*2‘。 calc_tool Tool( nameCalculator, funcsafe_eval, description计算一个数学表达式的结果。输入如 ‘(35)*2‘ 的表达式。 )将这三个工具放入一个列表就构成了我们智能体的初始工具箱tools [search_tool, python_repl_tool, calc_tool]4.2 记忆系统的实现接下来我们实现短期记忆。LangChain提供了多种记忆后端这里我们使用简单的ConversationBufferMemory。from langchain.memory import ConversationBufferMemory # 创建记忆对象。memory_key定义了存储对话历史的变量名return_messagesTrue确保返回的是消息列表格式。 memory ConversationBufferMemory(memory_keychat_history, return_messagesTrue) # 我们还需要一个单独的变量来存储“中间步骤”即Thought/Action/Observation的记录这对于ReAct循环至关重要。 agent_memory ConversationBufferMemory(memory_keyagent_scratchpad, return_messagesTrue)这个memory对象会自动保存用户和AI的对话。而agent_memory则专门用于记录智能体在思考过程中的中间步骤这些步骤会作为上下文的一部分输入给模型帮助它了解自己已经做了什么。4.3 大模型连接与智能体创建现在我们连接“大脑”。这里以DeepSeek API为例因为它兼容OpenAI的接口格式性价比高且能力强劲。from langchain_openai import ChatOpenAI # 注意虽然导入的是ChatOpenAI但通过指定base_url我们可以连接任何兼容OpenAI API格式的服务如DeepSeek。 llm ChatOpenAI( modeldeepseek-chat, # 根据DeepSeek文档这是正确的模型名。也可能是“deepseek-v4-pro” openai_api_keydeepseek_api_key, # 从环境变量读取 base_urlapi_base, # 从环境变量读取例如 https://api.deepseek.com/v1 temperature0.1, # 温度设低让输出更确定、更遵循指令 streamingFalse, # 非流式响应简化处理 )有了LLM、工具和记忆我们就可以创建智能体了。LangChain提供了高级的create_react_agent函数它封装了ReAct逻辑和提示词模板。from langchain.agents import create_react_agent, AgentExecutor from langchain.agents.react.agent import get_prompt # 1. 获取ReAct智能体的专用提示词模板 # 这个模板包含了指导模型进行思考-行动循环的详细指令。 prompt_template get_prompt(tools) # 2. 创建ReAct智能体 # 它将llm、提示词模板和工具绑定在一起。 agent create_react_agent(llm, tools, prompt_template) # 3. 创建智能体执行器 # 这是真正运行智能体的引擎它负责处理循环、调用工具、管理记忆。 agent_executor AgentExecutor( agentagent, toolstools, memoryagent_memory, # 使用专门记录中间步骤的记忆 verboseTrue, # 设为True会在控制台打印详细的思考过程便于调试 handle_parsing_errorsTrue, # 当模型输出格式不符合预期时尝试自动修复 max_iterations10, # 限制最大循环次数防止陷入死循环 early_stopping_methodgenerate, # 停止条件 )至此一个具备基础思考能力、拥有三个工具、并带有记忆的AI智能体骨架就搭建完成了。agent_executor就是我们的主入口。5. 运行、测试与迭代优化让我们用一个复杂的任务来测试这个智能体观察它如何“思考”。5.1 首次测试与思考过程观察# 测试查询 query “请先搜索‘2024年奥运会举办地’然后用计算器计算一下如果一张门票平均100美元卖出500万张门票总收入是多少美元最后用Python验证一下这个计算结果。” try: response agent_executor.invoke({input: query}) print(\n 智能体最终回答 ) print(response[output]) except Exception as e: print(f执行过程中出现错误{e})当verboseTrue时你会在控制台看到类似以下的详细输出这就是智能体的“思考链” Entering new AgentExecutor chain... Thought: 用户给了我一个多步骤的任务。首先需要搜索2024年奥运会举办地然后进行一个乘法计算最后用Python验证。我应该按顺序执行。 Action: Web_Search Action Input: 2024年奥运会举办地 Observation: 搜索到以下信息 标题2024年夏季奥运会 - 维基百科 摘要2024年夏季奥运会正式名称为第三十三届夏季奥林匹克运动会将于2024年7月26日至8月11日在法国巴黎举行。 链接https://zh.wikipedia.org/... 更多结果... Thought: 好的举办地是法国巴黎。现在进行第二步计算。总收入 平均票价 * 售票数量 100美元 * 5,000,000。 Action: Calculator Action Input: 100 * 5000000 Observation: 500000000 Thought: 计算结果是500,000,000美元。现在需要用Python验证这个结果。我可以写一个简单的乘法脚本。 Action: Python_REPL Action Input: result 100 * 5000000 print(f“验证结果{result}美元”) Observation: 验证结果500000000美元 Thought: 所有步骤都已完成。我可以整理最终答案了。 Final Answer: 根据搜索2024年奥运会将在法国巴黎举行。通过计算平均100美元的门票卖出500万张总收入为500,000,000美元五亿美元。Python代码验证结果一致。 Finished chain. 智能体最终回答 根据搜索2024年奥运会将在法国巴黎举行。通过计算平均100美元的门票卖出500万张总收入为500,000,000美元五亿美元。Python代码验证结果一致。看到吗智能体自主规划了步骤搜索-计算-验证在每一步都进行了“思考”选择了正确的工具并传递了正确的参数。这就是“思考”的直观体现。5.2 常见问题排查与调试技巧在实际开发中你肯定会遇到各种问题。下面是一个常见错误速查表问题现象可能原因解决方案API Error: 400 ‘type‘ must be in [“enabled“, “disabled“, “auto“]请求体中的参数不符合API规范。检查初始化ChatOpenAI时传递的参数移除或更正未知参数。确保model名称正确。API Error: 400 This model‘s maximum context length is ...输入给模型的上下文对话历史当前问题太长超出了模型的令牌限制。1. 使用ConversationSummaryMemory或ConversationBufferWindowMemory替代ConversationBufferMemory只保留最近几轮或总结历史。2. 在AgentExecutor中设置max_token_limit参数。Unable to connect to API (ECONNRESET)网络连接问题或API服务端不稳定。1. 检查网络。2. 增加请求超时时间llm ChatOpenAI(..., request_timeout60)。3. 实现简单的重试逻辑。智能体陷入死循环不断重复相同动作模型无法从工具返回的结果中提取有效信息来推进任务或者任务本身无法完成。1. 检查工具返回的结果是否清晰、格式是否易于模型理解。2. 设置AgentExecutor的max_iterations如10和early_stopping_method。3. 优化提示词明确告诉模型在何种条件下应停止并给出最终答案。模型不按格式输出Thought/Action提示词模板对模型的约束力不够或者模型本身对结构化输出支持不佳。1. 确保使用的get_prompt是专为ReAct设计的。2. 尝试降低temperature到0.1以下。3. 考虑使用支持“函数调用”或“JSON模式”的新版模型和对应Agent类型如create_openai_tools_agent格式更稳定。工具调用时参数错误模型生成的Action Input不符合工具函数定义的参数格式。1. 在工具description中更清晰地描述输入格式例如“输入一个搜索关键词字符串”。2. 在工具函数内部做好错误处理和类型转换返回友好的错误信息给模型作为“Observation”。调试心得从简到繁先用一个工具如计算器测试确保基础流程跑通再逐步增加复杂工具。善用verboseTrue这是理解智能体内部决策过程最重要的窗口。通过观察“Thought”你能知道模型是否真正理解了任务和工具。优化工具描述工具的name和description是模型选择工具的唯一依据。描述要精准、无歧义并说明输入格式。例如“输入一个搜索查询词”比“输入查询”要好得多。处理解析错误handle_parsing_errorsTrue是个救星但有时模型输出完全混乱时它也无能为力。这时可以捕获异常在代码中给模型一个友好的错误提示作为新的“Observation”让它重试。5.3 功能增强与进阶探索基础版本运行稳定后我们可以考虑增强它增加长期记忆集成ChromaDB让智能体能够学习并记住你的个人文档、项目代码库。当用户问“我之前写的那个数据处理函数逻辑是什么”时智能体可以自动检索相关代码片段。from langchain_community.vectorstores import Chroma from langchain_openai import OpenAIEmbeddings from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_community.document_loaders import TextLoader # 加载文档、分割、生成向量并存储 loader TextLoader(“your_document.txt”) documents loader.load() text_splitter RecursiveCharacterTextSplitter(chunk_size500, chunk_overlap50) splits text_splitter.split_documents(documents) vectorstore Chroma.from_documents(documentssplits, embeddingOpenAIEmbeddings()) # 创建一个检索工具 retriever_tool Tool( name“Document_Search”, funclambda q: vectorstore.similarity_search(q, k2), description“从知识库中搜索与问题相关的文档片段。” ) # 将此工具加入到tools列表中实现子任务规划对于“写一份行业分析报告”这种复杂指令可以设计一个“规划器”智能体先将任务分解为“搜集资料”、“整理数据”、“撰写大纲”、“润色成文”等子任务然后由“执行器”智能体即我们刚建的逐个完成。接入图形界面使用Gradio或Streamlit快速构建一个Web界面让非技术用户也能与你的智能体对话。pip install gradioimport gradio as gr def chat_with_agent(message, history): response agent_executor.invoke({“input”: message}) return response[“output”] gr.ChatInterface(chat_with_agent).launch()构建一个会“思考”的AI智能体就像在组装一个数字生命。从简单的工具调用到复杂的规划循环每一步都让你更贴近AI应用开发的前沿。这个项目最大的收获不是最终的代码而是在调试过程中对模型思维模式、提示词魔力以及系统工程设计的深刻理解。当你看到它第一次自主地、正确地完成一个多步骤任务时那种成就感是无可比拟的。接下来试着给它接入更多工具比如发送邮件、操作日历、管理文件你会发现一个属于你的“贾维斯”正在慢慢成型。