
1. 从“聊天”到“做事”为什么我们需要智能体如果你最近关注AI领域可能会发现一个明显的趋势大家不再仅仅满足于让大模型“回答问题”或“生成文本”了。我们开始期待它能“动手干活”——比如你告诉它“帮我查一下明天上海的天气如果下雨就提醒我带伞并把提醒事项加到我的日历里”它就能自动调用天气API、判断条件、再调用日历API一气呵成地完成这个任务。这个能“自主规划、调用工具、完成任务”的AI就是我们今天要聊的“智能体”。这背后是一个根本性的需求升级。过去大模型就像一个知识渊博但“四肢不勤”的顾问你问它答。它的价值在于信息处理和内容生成。但现在我们希望它能成为一个真正的“数字员工”或“个人助理”能主动去操作软件、查询数据、执行流程把我们从重复、琐碎的数字劳动中解放出来。这就是智能体Agent的核心使命让大模型不仅会“想”还要会“做”。为什么现在这个节点变得如此火热一方面大模型本身的能力特别是逻辑推理和指令遵循能力在持续进化让它具备了理解复杂任务和拆解步骤的基础。另一方面像LangChain、Dify这样的框架和平台降低了开发门槛让“组装”一个智能体变得像搭积木一样直观。更重要的是各行各业的实际场景在呼唤自动化无论是自动处理客服工单、分析销售数据并生成报告还是辅助编程、自动化测试智能体都展现出了巨大的潜力。它不再是实验室里的概念而是正在落地、能产生实际价值的工具。所以无论你是开发者想为自己的产品增加AI自动化能力还是业务人员希望用AI提升效率甚至是爱好者想体验最前沿的AI应用学习如何“从零打造一个智能体”都是一项极具价值的技能。这个系列我们就抛开复杂的理论直接上手用最实用的方式带你构建出你的第一个能真正“干活”的智能体。2. 智能体的核心组件它到底是怎么“思考”和“行动”的在开始写代码之前我们必须先搞清楚智能体是如何工作的。你可以把它想象成一个高级的项目经理。这个经理智能体接到一个任务用户输入他不会自己亲手去做所有事而是会思考、规划、然后指挥手下的专家各种工具去完成。这个过程通常包含几个核心组件理解了它们你就掌握了智能体的“设计图纸”。2.1 大脑大语言模型智能体的“大脑”就是大语言模型。它的核心职责是理解、规划和决策。理解准确解析用户的指令理解其深层意图。比如用户说“我有点冷”模型需要理解这可能意味着“用户想调高空调温度”或“询问天气”。规划将复杂的最终目标拆解成一系列可执行的子步骤。例如完成“订一张明天北京飞上海的最便宜机票”这个任务模型需要规划出1. 查询航班信息API2. 从结果中筛选出明天且价格最低的航班3. 调用预订API。决策在每一步决定接下来该做什么以及调用哪个工具。这是智能体“自主性”的体现。这里有一个关键点我们通常不需要为了智能体去从头训练一个模型。我们利用现成的、强大的基座模型如GPT-4、Claude、国内的各种大模型API通过提示工程来引导它按照我们设定的“思维框架”去工作。这个思维框架就是通过精心设计的系统提示词来灌输的。2.2 记忆短期与长期人没有记忆就无法连续对话智能体也一样。记忆模块让智能体拥有“上下文”。短期记忆/对话记忆保存当前一轮对话的历史。这确保了智能体能理解指代比如“它”、“上面的方法”并保持对话的连贯性。技术上这通常就是我们把过去的对话内容作为上下文连同新问题一起喂给模型。长期记忆这是更高级的能力指智能体能够将重要的信息持久化存储并在未来的对话中检索使用。比如智能体可以记住用户的偏好“不喜欢乘坐早班机”并在每次规划行程时自动过滤。实现上这通常需要引入向量数据库来存储和检索历史信息。在入门阶段我们先聚焦于实现短期记忆这是智能体运转的基础。2.3 工具智能体的“双手”工具是智能体与外部世界交互的接口。大模型本身无法直接获取实时数据、操作软件或影响物理世界工具赋予了它这些能力。一个工具本质上就是一个函数它有名称和描述用自然语言清晰地告诉模型这个工具是干什么的。例如get_current_weather工具的描述是“获取指定城市的当前天气情况”。模型的决策很大程度上依赖于这些描述。输入参数定义工具需要什么信息。比如city: string。执行函数一段实际的代码用于执行具体操作。比如函数内部会调用一个天气API传入城市名返回天气数据。常见的工具有搜索引擎API、计算器、数据库查询、代码执行器、文件读写、发送邮件等等。智能体的强大程度直接取决于你为它配备了多么丰富和好用的工具库。2.4 执行引擎控制工作流的“调度中心”这是将大脑、记忆和工具串联起来的中枢系统。它负责管理智能体的“思考-行动”循环将用户输入和记忆上下文组合传递给大模型。大模型“思考”后输出一个决策是直接回答用户还是调用某个工具如果调用工具参数是什么执行引擎解析这个决策如果是要调用工具就找到对应的工具函数传入参数并执行。获取工具的执行结果比如天气数据是“上海晴25摄氏度”。将这个结果作为新的信息连同最初的用户问题和历史记忆再次传递给大模型让它进行“反思”并给出最终回答或下一步行动。重复这个过程直到模型认为任务完成输出最终答案给用户。这个循环是智能体工作的核心机制。目前主流的框架如LangChain、LangGraph其核心价值就是为我们提供了强大、灵活且可靠的方式来构建和管理这个执行引擎。3. 环境搭建与工具选择你的第一个智能体工坊理论清楚了我们开始动手。首先需要搭建开发环境。这里我会给出一个基于Python的、最小依赖的方案确保你能快速跑起来。之后我们会对比主流框架让你理解为什么这么选。3.1 基础环境准备确保你的电脑上安装了Python建议3.8以上版本。我们使用venv创建独立的虚拟环境避免包冲突。# 创建项目目录并进入 mkdir my-first-agent cd my-first-agent # 创建虚拟环境 python -m venv venv # 激活虚拟环境 # Windows: venv\Scripts\activate # macOS/Linux: source venv/bin/activate激活后命令行提示符前会出现(venv)字样。3.2 核心依赖安装我们将使用LangChain这个目前最流行的智能体开发框架。它封装了上述的几乎所有组件让我们可以像搭积木一样构建智能体。同时我们需要一个大模型。为了最简化和免费我们首先使用Ollama在本地运行一个开源模型。最后安装langchain-community来获取社区维护的各种工具集成。pip install langchain langchain-community接下来安装Ollama。请根据你的操作系统从Ollama官网下载并安装。安装完成后在终端拉取一个轻量级模型比如llama3.2约4B参数对普通电脑友好。# 拉取模型 ollama pull llama3.2 # 运行模型服务通常安装后会自动运行Ollama会在本地11434端口提供一个类OpenAI API兼容的服务。这样我们就有了一个免费的、本地的“大脑”。3.3 为什么是LangChain 本地模型这里解释一下我们的技术选型逻辑为什么用框架LangChain而不是从头写智能体的执行引擎尤其是工具调用的解析、循环控制涉及很多细节和边界情况处理自己从头实现费时费力且容易出错。LangChain经过了大量实践检验提供了稳定、模块化的实现让我们能专注于任务逻辑本身。它就像一个提供了标准接口的“机器人底盘”。为什么用本地模型Ollama而不是直接调用GPT-4对于学习和原型开发成本、速度和隐私是关键。本地模型零成本、响应快无需网络往返、数据完全不出本地。虽然能力上可能不如顶级商用模型但对于学习智能体的核心工作机制和构建简单应用完全足够。等概念跑通后你可以轻松地将大脑切换到GPT-4或Claude等云端API。备选方案浅析你可能也听过LangGraph和Dify。LangGraph是LangChain官方推出的用于构建复杂、有状态工作流的库它用图Graph的概念来定义智能体的执行流非常适合需要循环、分支、并行等复杂逻辑的智能体。我们第一讲先从简单的链式智能体开始后续再引入LangGraph。Dify则是一个开源的AI应用开发平台提供了可视化的编排界面更适合不想写太多代码的快速应用搭建。从学习底层原理的角度从代码框架LangChain入手更扎实。环境就绪大脑和工具架也已备好接下来我们开始为智能体打造第一件“工具”。4. 打造第一件工具让智能体学会“查天气”智能体没有工具就像巧妇难为无米之炊。我们首先来创建一个最经典的示例工具天气查询。这个过程会让你彻底理解“工具”是如何被定义、封装和调用的。4.1 模拟一个天气查询函数在真实场景中你需要去注册一个天气API服务如和风天气、OpenWeatherMap等来获取实时数据。为了简化演示我们创建一个模拟函数它接收城市名返回固定的天气数据。重点在于理解接口形式。在你的项目目录下创建一个tools.py文件# tools.py import json def get_weather(city: str) - str: 根据城市名称获取当前的天气信息。 参数: city (str): 城市名称例如 北京、Shanghai。 返回: str: 格式化的天气信息字符串。 # 模拟一个天气数据字典 weather_data { 北京: {condition: 晴, temperature: 22, humidity: 40%}, 上海: {condition: 多云, temperature: 25, humidity: 65%}, 广州: {condition: 雷阵雨, temperature: 28, humidity: 85%}, New York: {condition: Partly Cloudy, temperature: 18, humidity: 55%}, } # 查找城市若未找到则返回默认信息 city_data weather_data.get(city, None) if city_data: result f{city}的天气是{city_data[condition]}气温{city_data[temperature]}摄氏度湿度{city_data[humidity]}。 else: # 如果城市不在列表中模拟一个通用回答 result f未找到{city}的实时天气信息。当前模拟数据仅支持{, .join(weather_data.keys())}。 # 打印日志方便我们观察工具是否被调用 print(f[工具调用日志] 执行 get_weather 参数: city{city} 返回: {result}) return result这个函数非常简单但它完整定义了一个工具的要素明确的函数名、清晰的文档字符串描述和参数、具体的执行逻辑、以及格式化的返回结果。print语句是我们调试的利器可以让我们清晰地看到智能体在何时调用了这个工具。4.2 将函数包装成LangChain工具LangChain不能直接使用普通的Python函数需要将其包装成Tool对象。Tool对象包含了模型所需的自然语言描述。我们修改tools.py# tools.py from langchain.tools import Tool import json def get_weather(city: str) - str: # ... 函数体保持不变 ... # 创建Tool对象 weather_tool Tool( nameget_weather, # 工具名称模型通过这个名称来指定调用哪个工具 funcget_weather, # 关联的实际执行函数 description当你需要查询某个城市的当前天气情况时使用此工具。 输入应该是一个字符串仅包含城市名称例如“北京”或“San Francisco”。 不要输入其他无关文本。, # 这是给模型看的“说明书”至关重要 )注意description字段它是模型决定是否调用以及如何调用该工具的关键。描述要准确、无歧义并说明输入格式。一个常见的错误是描述过于简略导致模型无法正确使用。4.3 创建工具包并测试通常一个智能体会配备多个工具。我们创建一个工具列表方便后续使用。同时我们可以先独立测试一下工具是否正常工作。在tools.py末尾添加# 工具列表 tools [weather_tool] # 简单的独立测试 if __name__ __main__: # 测试工具调用 print(测试天气查询工具) print(weather_tool.run(上海)) print(\n测试工具列表) for tool in tools: print(f- {tool.name}: {tool.description[:50]}...)在终端运行python tools.py你应该能看到测试输出和工具调用日志。这验证了我们的工具基础功能是完好的。至此智能体的“双手”之一已经准备就绪。接下来我们要为它注入“大脑”和“灵魂”——连接大模型并设计它的思维逻辑。5. 连接大脑与组装智能体让模型学会使用工具现在我们有工具天气查询也有大脑通过Ollama运行的本地LLM。下一步是将它们连接起来并教导大脑在什么情况下应该使用工具。这需要通过提示工程和智能体架构来实现。5.1 初始化大语言模型我们使用LangChain的ChatOllama类来连接我们本地运行的Ollama服务。创建一个新的agent.py文件。# agent.py from langchain_community.chat_models import ChatOllama from langchain.tools import Tool from tools import weather_tool, tools # 导入我们刚才创建的工具 # 1. 初始化LLM大脑 # 连接到本地Ollama服务指定我们拉取的模型 llm ChatOllama( modelllama3.2, # 与 ollama pull llama3.2 对应 base_urlhttp://localhost:11434, # Ollama默认地址 temperature0.1, # 温度参数越低输出越确定适合工具调用任务 ) print(LLM初始化成功。)temperature参数设置为较低值如0.1是为了让模型在决定调用哪个工具、传递什么参数时更加确定和一致减少随机性这对于任务执行型智能体非常重要。5.2 设计系统提示词给智能体“植入工作准则”系统提示词是引导模型行为的关键。它定义了智能体的角色、能力、工作流程和输出格式。一个好的提示词能极大提升智能体的可靠性和准确性。我们设计一个针对工具调用场景的提示词。在agent.py中继续添加# 2. 定义系统提示词 system_prompt 你是一个有帮助的AI助手并且可以使用工具来完成任务。 你的核心工作流程如下 1. **理解用户请求**仔细分析用户想要什么。 2. **判断是否需要工具** - 如果问题涉及实时信息如天气、新闻、股票、计算、数据查询或任何需要外部能力的操作你必须使用工具。 - 如果问题是一般性知识问答或聊天你可以直接回答。 3. **使用工具** - 如果你决定使用工具你的思考过程Reasoning和最终输出必须严格遵循以下格式 思考[你的推理过程解释为什么需要调用工具以及调用哪个工具] 行动 行动工具名称 行动输入工具的输入参数通常是一个字符串 - 等待工具返回结果。 4. **处理工具结果并回复** - 收到工具返回的结果后结合结果和用户原始问题生成最终回复给用户。 - 你的回复应该友好、准确、完整。 你可以使用的工具如下 {tools} 记住你的“行动”输出必须完全是上述格式不要添加任何其他内容以便系统能正确解析。 现在开始与用户对话吧。这个提示词做了几件重要的事明确角色和能力告诉模型它是一个能使用工具的助手。定义决策逻辑给出了何时该用工具的简单规则实时信息、计算等。强制格式化输出这是最关键的一步。我们要求模型在决定调用工具时必须输出一个特定格式的文本块。这个格式以“思考”和“行动”为标记是我们后续代码用来解析模型意图的约定。LangChain的智能体执行器就是靠识别这种格式来知道“哦模型现在想调用工具了”。预留工具列表{tools}是一个占位符我们会在运行时将可用工具的详细描述名称和描述填充进去。5.3 创建智能体执行器在LangChain中AgentExecutor是负责运行智能体循环思考-行动-观察的组件。我们需要将LLM、工具和提示词组合起来创建一个智能体。这里我们使用一种简单但有效的ReAct推理行动智能体类型。在agent.py中继续添加from langchain.agents import AgentExecutor, create_react_agent from langchain.prompts import PromptTemplate # 3. 准备提示词模板并将工具描述填充进去 # 首先将工具列表转换为模型可读的描述字符串 tools_description \n.join([f- {tool.name}: {tool.description} for tool in tools]) # 创建提示词模板 prompt_template PromptTemplate.from_template(system_prompt) # 生成最终的提示词其中{tools}被替换为具体的工具描述 final_prompt prompt_template.format(toolstools_description) # 4. 创建ReAct智能体 agent create_react_agent(llm, tools, final_prompt) # 5. 创建智能体执行器 agent_executor AgentExecutor( agentagent, toolstools, verboseTrue, # 设为True可以看到智能体内部的详细思考过程对调试极其重要 handle_parsing_errorsTrue, # 优雅地处理模型输出格式解析错误 max_iterations5, # 限制最大循环次数防止死循环 early_stopping_methodgenerate, # 当模型连续两次输出最终答案时停止 ) print(智能体执行器创建成功。)代码解析create_react_agent: 这是LangChain提供的一个高阶函数它根据我们提供的LLM、工具和提示词构建一个遵循ReAct范式的智能体。ReAct要求模型显式地输出“思考”和“行动”正好契合我们提示词中定义的格式。AgentExecutor: 这是“发动机”。它负责将用户输入和对话历史传给智能体agent。智能体返回一个包含“行动”的响应。AgentExecutor解析这个响应找到要调用的工具和参数然后执行工具。将工具执行结果作为“观察”反馈给智能体。智能体进行下一轮思考直到输出最终答案。verboseTrue: 这是最重要的调试选项。当它开启时我们能在控制台看到智能体完整的思考链、工具调用和观察结果就像打开了它的“思维黑箱”对于理解其工作原理和排查问题不可或缺。max_iterations: 设置安全阀防止智能体陷入无限循环。至此一个具备基础能力的智能体已经组装完毕。它拥有一个本地大脑Llama 3.2、一件工具天气查询和一套行为准则系统提示词。接下来让我们点燃引擎看它如何工作。6. 运行与调试见证你的智能体首次“自主工作”现在到了最激动人心的环节与我们的智能体对话看它是否能理解指令、正确调用工具并给出回答。我们在agent.py中添加一个简单的对话循环。6.1 实现对话循环在agent.py文件末尾添加以下代码# 6. 运行智能体 def chat_with_agent(): print(\n *50) print(你的第一个智能体已启动) print(输入 quit 或 exit 结束对话。) print(*50) # 初始化一个简单的对话历史短期记忆 # 在实际复杂应用中我们会使用更高级的记忆管理这里先用一个列表模拟 chat_history [] while True: try: user_input input(\n你: ).strip() if user_input.lower() in [quit, exit, q]: print(对话结束。) break if not user_input: continue # 调用智能体执行器 print(\n[智能体思考中...]) response agent_executor.invoke({ input: user_input, chat_history: chat_history, # 传入历史记录 }) # 获取智能体的最终输出 agent_output response[output] print(f\n助手: {agent_output}) # 更新对话历史简易版 chat_history.append((user_input, agent_output)) except Exception as e: print(f\n[出错] 处理请求时发生错误: {e}) # 一个简单的容错建议用户重试或换种问法 print(抱歉我遇到了点问题。请尝试重新表述你的问题。) if __name__ __main__: chat_with_agent()6.2 启动并测试保存所有文件在终端运行python agent.py。你应该会看到初始化成功的消息然后进入对话界面。现在让我们进行一系列测试观察智能体的行为测试1直接知识问答不使用工具你: 你好请介绍一下你自己。观察输出。由于我们的提示词规定一般性聊天可以直接回答模型应该不会调用工具而是直接生成回复。控制台的verbose日志会显示它的思考过程其中“行动”部分 likely 会是“Final Answer”。测试2触发工具调用你: 上海今天天气怎么样这是关键时刻仔细观察控制台打印的verbose日志。你应该会看到类似这样的输出 进入新的AgentExecutor链... 思考用户想了解上海的当前天气。这是一个需要实时信息的问题我无法凭固有知识回答必须使用天气查询工具。 行动 行动get_weather 行动输入上海 [工具调用日志] 执行 get_weather 参数: city上海 返回: 上海的天气是多云气温25摄氏度湿度65%。 观察上海的天气是多云气温25摄氏度湿度65%。 思考我已经通过工具获取了上海的天气信息现在可以将这个结果直接告诉用户。 行动 行动Final Answer 行动输入上海今天的天气是多云气温大约25摄氏度湿度为65%。 链结束。太棒了你刚刚亲眼目睹了智能体的完整工作循环思考模型推理出需要查询天气并决定调用get_weather工具。行动它输出了格式化的“行动”指令。执行AgentExecutor捕获到这个指令调用我们的get_weather函数并传入了参数“上海”。观察工具返回结果并被作为“观察”反馈给模型。再思考与最终回答模型接收到天气数据思考后决定输出最终答案。测试3处理未知城市你: 拉萨的天气呢由于我们的模拟函数中没有“拉萨”的数据工具会返回一个友好的错误信息。观察智能体是否会把这个信息如实转达给用户。这测试了它对工具失败情况的处理能力。测试4无需工具的后续对话你: 谢谢。那北京和上海哪个更热这是一个有趣的测试。对话历史中已经有了上海的天气信息25°C但北京的天气信息需要重新查询。观察智能体是会直接根据记忆中的上海数据来比较还是意识到缺少北京数据而再次调用工具由于我们使用了简单的chat_history模型很可能看到历史里有“上海25°C”但为了准确比较它应该再次调用工具查询北京天气。通过verbose日志验证你的猜想。6.3 调试与问题排查在开发过程中你肯定会遇到智能体“不听话”的情况。以下是一些常见问题及排查思路问题模型不调用工具总是直接回答。可能原因1提示词不够清晰。检查description字段是否准确描述了工具的功能和适用场景。模型可能没理解这个工具能解决当前问题。可能原因2模型能力不足。较小的开源模型在工具调用遵循指令上可能不如大模型稳定。尝试优化提示词或者换用更大的模型如ollama pull llama3.1:8b。排查方法开启verboseTrue看模型的“思考”部分。如果它根本没提到工具那就是提示词或模型理解的问题。问题模型调用了工具但参数格式错误。可能原因工具的描述description中没有明确指定输入格式。例如我们的描述要求“输入应该是一个字符串仅包含城市名称”。如果描述是“输入城市名”模型可能会输出“请告诉我上海的天气”导致解析失败。排查方法查看verbose日志中“行动输入”的内容。确保它是工具函数能直接处理的格式。问题陷入无限循环或多次调用同一工具。可能原因模型对工具返回的结果不满意或无法理解试图再次尝试。或者任务本身就需要多步查询比如比较多个城市。解决方法我们已经在AgentExecutor中设置了max_iterations5作为安全措施。你可以观察循环中的“思考”内容看模型卡在了哪里进而优化提示词或工具返回的信息格式。通过以上测试和调试你已经掌握了智能体运行的基本状态监控和问题诊断方法。你的第一个智能体已经能够根据你的指令自主决策并调用工具来完成一个具体任务了。这只是一个起点但已经涵盖了最核心的闭环。在接下来的部分我们将为它添加更多能力并深入更高级的控制流程。