1. 项目概述从概念到实践的AI Agent构建之旅最近和几个做产品和开发的朋友聊天发现“AI Agent”这个词的热度已经高到离谱了。无论是技术社区、投资报告还是产品发布会好像不提一嘴Agent就显得不够前沿。但当我问他们“你自己动手搭过一个能跑起来的Agent吗”时大部分人又陷入了沉默。这其实反映了一个普遍现象概念很火但真正从零到一实现一个AI Agent的实践经验却非常稀缺。很多人被“自主智能体”、“任务分解”、“工具调用”这些高大上的术语唬住了觉得门槛极高。今天我就想打破这个迷思用一个最直接、最“接地气”的方式带你亲手构建你的第一个AI Agent。我们不谈空洞的理论不搞复杂的架构设计就从一行代码开始让你在半小时内看到一个能理解你意图、并调用工具为你完成任务的“智能体”跑起来。这个过程就像你第一次成功运行“Hello World”程序一样那种亲手创造并见证其运作的成就感是理解所有复杂概念的最佳起点。这个项目适合谁呢首先当然是所有对AI应用开发感兴趣的开发者无论你是前端、后端还是全栈具备基础的Python编程能力即可。其次是产品经理和技术管理者通过亲手实践你能更深刻地理解Agent的能力边界和落地成本避免提出“让AI自己写个操作系统”这类不切实际的需求。最后也适合任何有强烈好奇心的技术爱好者。你不需要是机器学习专家我们使用的核心是大型语言模型LLM的API就像你调用任何一个云服务一样简单。我们将聚焦于最核心的“智能体”逻辑如何让LLM理解任务、规划步骤、并安全地使用工具执行。我会基于当前最主流、生态最成熟的框架之一——LangChain来展开因为它抽象得很好让我们能专注于智能逻辑本身而非底层通信细节。记住我们的目标不是造一个“贾维斯”而是打造一个能帮你查天气、做摘要、处理数据的“小助手”并在此过程中彻底搞懂AI Agent究竟是如何“思考”和“行动”的。2. 核心思路拆解AI Agent究竟在做什么在动手写代码之前我们必须先统一思想弄清楚我们要构建的到底是个什么东西。很多人把AI Agent想象成一个无所不能的超级AI这其实是个误区。在我看来一个最基础的AI Agent本质上是一个**“基于LLM的自动任务执行器”**。它核心的工作流程可以概括为“感知-思考-行动”循环在技术实现上则具体化为以下三个关键环节理解它们就理解了Agent的骨架。2.1 任务规划与分解让LLM学会“分步骤”这是Agent的“大脑”或“思考”环节。当你给Agent一个指令比如“帮我查一下北京明天下午的天气然后根据天气决定是否推荐我去颐和园并给出理由”LLM并不会像魔法一样直接给出最终答案。它需要被引导去“思考”如何解决这个任务。这就是任务规划与分解。在这个环节我们依赖LLM强大的推理和上下文理解能力。我们会设计一个特定的“提示词”Prompt引导LLM将复杂的用户请求拆解成一系列有序的、可执行的子任务。例如针对上面的请求一个规划良好的Agent应该输出类似这样的步骤子任务一调用“天气查询工具”参数为{城市“北京” 时间“明天下午”}。子任务二分析子任务一返回的天气数据如温度、降水概率、空气质量。子任务三基于分析结果和预设规则如“下雨或PM2.5150则不推荐户外活动”做出“推荐”或“不推荐”的决策。子任务四生成最终的回答汇总天气信息和推荐理由。注意这里的“规划”能力完全依赖于你提供的Prompt设计和LLM本身的能力。Prompt需要清晰定义输出格式比如要求以JSON或特定列表格式输出步骤并给出少量示例Few-shot Learning这样才能让LLM稳定输出结构化的规划。初期规划步骤不宜过多过复杂最好控制在3-5步内以降低LLM出错的概率。2.2 工具调用与执行赋予Agent“手和脚”规划好了步骤接下来就需要执行。但LLM本身只是一个语言模型它不知道如何连接互联网查天气也不会操作你电脑上的Excel表格。它需要“工具”Tools。工具就是一个个封装好的函数每个函数都有明确的功能描述、输入参数格式和返回结果格式。Agent的核心能力之一就是学会在合适的时机根据规划调用正确的工具并传入正确的参数。继续上面的例子我们需要提前定义一个get_weather工具函数。当LLM在规划中决定执行“子任务一”时它会生成一个工具调用请求内容可能是{“action”: “get_weather”, “action_input”: {“city”: “北京” “time”: “明天下午”}}。Agent的执行器会捕获这个请求找到名为get_weather的工具函数用action_input作为参数执行它得到真实的天气数据如{“temp”: 22, “condition”: “晴”, “pm25”: 80}。实操心得工具的定义至关重要。工具的函数名和描述必须清晰、无歧义因为LLM主要依靠这些描述来决定使用哪个工具。描述应像API文档一样例如“get_weather(city: str, time: str) - dict根据城市名和时间查询天气返回包含温度、天气状况、PM2.5等信息的字典。” 输入输出格式尽量标准化如使用JSON这能极大提高LLM调用工具的准确率。2.3 记忆与状态管理维持对话的连贯性一个有用的Agent不应该像金鱼一样只有7秒记忆。当用户说“用刚才查到的北京天气再对比一下上海的天气”时Agent需要记得“刚才查到的北京天气”是什么。这就是记忆Memory功能。记忆模块让Agent能够保留对话历史、工具执行结果等上下文信息从而处理多轮交互和依赖先前结果的复杂任务。在简单的Agent中记忆可能就是一个不断追加的列表保存着之前所有的对话和工具调用记录。在更复杂的场景中记忆可能分为短期记忆当前会话和长期记忆向量数据库存储的过往关键信息。对于我们的第一个Agent我们会实现一个基础的对话缓冲记忆它能确保LLM在规划下一步时知道之前都说过什么、做过什么。将这三个环节串联起来就构成了Agent的核心工作流接收用户输入结合记忆上下文让LLM规划步骤执行规划中的第一个工具调用将工具执行结果和当前状态更新到记忆循环这个过程直到规划中的所有步骤完成最后LLM整合所有中间结果生成最终回复给用户。这个循环就是著名的“ReAct”Reasoning and Acting框架的简化体现。3. 环境准备与工具选型打造你的开发工作台工欲善其事必先利其器。构建AI Agent虽然核心逻辑清晰但选择一个合适的开发框架能让我们事半功倍避免重复造轮子。目前社区主流的框架有LangChain、LlamaIndex、Semantic Kernel等。这里我强烈推荐使用LangChain来构建你的第一个Agent原因有三第一它的社区最活跃遇到问题几乎都能找到解决方案或讨论第二它的抽象层次非常合适既提供了构建Agent所需的所有高级组件Agent、Tools、Memory、Chains又保持了足够的灵活性第三文档和教程极其丰富。当然这并不意味着其他框架不好只是对于快速上手和降低初期学习成本而言LangChain是最佳选择。3.1 基础开发环境搭建首先确保你有一个Python环境建议3.8以上。我强烈建议使用虚拟环境来管理项目依赖避免包冲突。# 创建项目目录并进入 mkdir my_first_ai_agent cd my_first_ai_agent # 创建并激活虚拟环境以venv为例 python -m venv venv # Windows系统激活 venv\Scripts\activate # macOS/Linux系统激活 source venv/bin/activate激活虚拟环境后你的命令行提示符前通常会显示(venv)表示你已处于隔离的Python环境中。接下来安装核心依赖。我们将安装langchain核心库以及langchain-openai这是LangChain官方维护的OpenAI模型集成包。同时为了让我们定义的“工具”能真正执行一些有趣的任务比如网页搜索我们还需要安装langchain-community它包含了大量社区贡献的工具和组件。python-dotenv用于管理API密钥等环境变量。pip install langchain langchain-openai langchain-community python-dotenv安装完成后创建一个.env文件来存储你的敏感信息比如OpenAI的API密钥。千万不要将密钥硬编码在代码中# 在项目根目录创建.env文件并写入以下内容将your_openai_api_key_here替换为你的真实密钥 OPENAI_API_KEYyour_openai_api_key_here3.2 LLM模型选择与配置Agent的“大脑”是LLM。对于初学者我建议直接使用OpenAI的GPT模型如gpt-3.5-turbo因为它非常稳定对话和推理能力足够强大且通过API调用简单。当然你也可以选择 Anthropic 的 Claude、Google 的 Gemini 或者开源的 Llama 系列模型但初期可能会在部署和调试上花费更多时间。我们需要在代码中加载环境变量并初始化LLM。创建一个名为agent_basic.py的Python文件。# agent_basic.py import os from dotenv import load_dotenv from langchain_openai import ChatOpenAI # 加载.env文件中的环境变量 load_dotenv() # 初始化LLM # 我们使用ChatOpenAI这是为对话优化的接口 # model参数指定模型名称temperature控制创造性0.0更确定1.0更多变 llm ChatOpenAI( modelgpt-3.5-turbo, temperature0, # 对于任务执行类Agent低temperature输出更稳定 api_keyos.getenv(OPENAI_API_KEY) # 从环境变量读取密钥 ) # 简单测试一下LLM连接 print(llm.invoke(你好请用一句话介绍你自己。).content)运行这个脚本(python agent_basic.py)如果看到LLM的回复说明你的环境配置和API连接都成功了。这里将temperature设为0是为了让Agent在执行确定性任务时如工具调用减少随机性输出更可靠。在需要创造性的场景如写诗、头脑风暴可以适当调高。注意事项使用OpenAI API会产生费用。GPT-3.5-turbo成本很低但对于学习阶段的频繁调用建议在OpenAI平台设置用量限制并密切关注账单。同时所有代码示例都应视为学习用途避免在生产环境中暴露API密钥。4. 定义你的第一个工具让Agent“动”起来LLM已经就位但它现在还只是一个“思想家”无法与外界交互。接下来我们要为它打造“手和脚”也就是工具。在LangChain中定义一个工具非常简单核心是创建一个函数并用tool装饰器来包装它。这个装饰器会自动为函数生成LLM能理解的描述。让我们从两个最实用、最能体现Agent价值的工具开始一个用于计算一个用于获取实时信息。4.1 创建数学计算工具虽然LLM本身能做简单计算但对于复杂、精确的数学运算专门的工具更可靠。我们将使用Python内置的math库和eval需谨慎使用来创建一个计算器工具。# 在agent_basic.py中继续添加 from langchain.tools import tool import math tool def calculator(expression: str) - str: 执行一个数学表达式计算并返回结果。 支持加减乘除(,-,*,/)、乘方(**)、括号和常见数学函数如sqrt, sin, cos等。 例如‘sqrt(16) 3 * (2 - 1)’ Args: expression (str): 一个合法的数学表达式字符串。 Returns: str: 计算结果字符串或错误信息。 try: # 安全提示在生产环境中直接使用eval是危险的可能执行恶意代码。 # 这里仅用于演示。实际应用应使用更安全的表达式解析库如ast.literal_eval配合自定义解析。 # 我们限制可用的命名空间增加一点安全性。 allowed_names {k: v for k, v in math.__dict__.items() if not k.startswith(_)} result eval(expression, {__builtins__: {}}, allowed_names) return str(result) except Exception as e: return f计算错误{e} # 测试工具 print(calculator.invoke(3 5 * 2)) # 输出13 print(calculator.invoke(sqrt(9))) # 输出3.0这个calculator工具接受一个表达式字符串尝试安全地计算它并返回结果。装饰器tool会自动根据函数名、参数和文档字符串来生成工具描述这个描述对于LLM决定何时调用此工具至关重要。4.2 创建网络搜索工具模拟一个能获取实时信息的Agent才是有用的Agent。由于直接集成真正的搜索引擎API如Serper、Tavily需要额外注册和配置我们这里先模拟一个“网络搜索”工具来演示流程。在实际项目中你可以轻松替换成真实的搜索工具。# 继续在agent_basic.py中添加 tool def search_web(query: str) - str: 根据查询词模拟网络搜索返回简化的摘要信息。 注意这是一个模拟工具返回的是预设的静态数据。 在实际应用中应替换为真正的搜索引擎API如SerperDev、Tavily。 Args: query (str): 搜索关键词。 Returns: str: 模拟的搜索结果摘要。 # 这是一个模拟的数据库 mock_knowledge_base { 今天的北京天气: 北京今天晴转多云气温15-25摄氏度南风2-3级空气质量良。, LangChain是什么: LangChain是一个用于开发由语言模型驱动的应用程序的框架。它提供了组件化和链式调用的能力简化了构建复杂AI应用的过程。, Python的最新版本: 截至2023年10月Python的最新稳定版本是3.11。, 如何学习机器学习: 学习机器学习通常需要掌握线性代数、概率论、Python编程并实践经典算法和项目。推荐课程有吴恩达的机器学习课程。 } # 简单模拟如果查询完全匹配键则返回值否则返回一个通用提示。 return mock_knowledge_base.get(query, f“已收到您的搜索请求{query}。这是一个模拟工具真实环境下将返回实时网络结果。”) # 测试工具 print(search_web.invoke(“今天的北京天气”))这个模拟工具虽然简单但它完整地展示了工具的定义模式功能描述、输入参数、返回结果。当你后续接入真正的搜索API时只需要修改这个函数内部的实现逻辑即可对Agent的其他部分完全透明。4.3 工具集的封装与管理定义好多个工具后我们需要将它们打包成一个列表供Agent使用。LangChain的Agent需要接收一个工具列表作为参数。# 将所有工具放入一个列表 tools [calculator, search_web] # 我们可以打印一下工具的描述看看LLM会看到什么 for tool in tools: print(f“工具名{tool.name}”) print(f“描述{tool.description}”) print(“-” * 20)运行这部分代码你会看到每个工具的名称和自动生成的详细描述。这些描述是LLM选择工具的唯一依据因此务必确保它们准确、清晰。例如calculator的描述会包含我们写在文档字符串里的所有说明LLM读到后就会知道“哦有一个工具可以计算数学表达式我需要把表达式字符串传给它。”5. 组装智能体构建大脑与工具的连接桥梁现在我们有了思考的“大脑”LLM和可用的“手脚”Tools。下一步就是创建一位“指挥官”它能够根据大脑的指令协调手脚去完成任务。在LangChain中这个“指挥官”就是Agent Executor。它封装了ReAct循环的核心逻辑调用LLM进行规划解析LLM的输出决定是使用工具还是直接回答执行工具将结果返回给LLM进行下一轮思考直到任务完成。5.1 选择Agent类型与初始化LangChain提供了多种预设的Agent类型适用于不同的场景。对于初学者我推荐使用ZERO_SHOT_REACT_DESCRIPTION。这是一种零样本Zero-Shot的ReAct Agent它不依赖于大量的示例训练仅凭我们提供的工具描述和通用的ReAct指令就能很好地工作。它的名字也揭示了其原理“零样本Zero-Shot”意味着不需要示例“ReAct”代表其推理与行动框架“Description”表示它依赖工具的描述来做决策。# 在agent_basic.py中继续添加 from langchain.agents import initialize_agent, AgentType from langchain.memory import ConversationBufferMemory # 初始化记忆模块。这将保存对话历史。 memory ConversationBufferMemory(memory_key“chat_history”, return_messagesTrue) # 创建Agent Executor # 参数解释 # - tools: 我们定义的工具列表 # - llm: 我们初始化的大语言模型 # - agent: 使用的Agent类型 # - memory: 记忆模块 # - verbose: 设为True会打印出Agent思考的详细过程便于调试和学习 # - handle_parsing_errors: 当LLM输出格式不符合Agent预期时尝试优雅处理 agent_executor initialize_agent( toolstools, llmllm, agentAgentType.ZERO_SHOT_REACT_DESCRIPTION, memorymemory, verboseTrue, # 强烈建议初期开启观察内部运作 handle_parsing_errorsTrue ) print(“AI Agent 初始化成功”)ConversationBufferMemory创建了一个简单的对话缓冲区它会自动保存用户和AI的对话历史。memory_key“chat_history”指定了在传递给LLM的Prompt中这段历史所用的变量名。verboseTrue是学习阶段最重要的开关打开它你就能像看电影一样看到Agent内部“思考”的每一步。5.2 运行你的第一个智能体任务激动人心的时刻到了让我们用一个简单的多步骤任务来测试我们刚刚组装好的Agent。# 运行一个需要结合计算和搜索模拟的任务 question “首先请搜索‘Python的最新版本’是什么然后计算这个版本号加上5.5等于多少” print(f“用户问题{question}”) print(“” * 50) try: response agent_executor.invoke({“input”: question}) print(“\n” “” * 50) print(f“Agent最终回答\n{response[output]}”) except Exception as e: print(f“运行过程中出现错误{e}”)运行整个脚本。由于我们设置了verboseTrue你会在控制台看到大量详细的日志输出。让我们解读一下其中关键的部分以下为模拟日志实际输出可能略有不同 Entering new AgentExecutor chain... Thought: 用户需要我先搜索Python的最新版本然后进行计算。我需要使用搜索工具。 Action: search_web Action Input: Python的最新版本 Observation: 截至2023年10月Python的最新稳定版本是3.11。 Thought: 我得到了版本号是3.11。现在需要计算3.11加上5.5。这需要用到计算器工具。 Action: calculator Action Input: 3.11 5.5 Observation: 8.61 Thought: 我现在有了所有信息。搜索结果是3.11计算结果是8.61。我可以回答用户了。 Final Answer: 根据搜索Python的最新稳定版本是3.11。3.11加上5.5等于8.61。 Finished chain. Agent最终回答 根据搜索Python的最新稳定版本是3.11。3.11加上5.5等于8.61。看明白了吗这就是一个完整的ReAct循环Thought思考LLM分析用户问题决定第一步要使用search_web工具。Action行动LLM输出要执行的动作search_web和输入参数“Python的最新版本”。Observation观察Agent Executor执行工具并将结果“截至2023年10月...”作为观察返回给LLM。Thought思考LLM基于观察进行下一步思考决定使用calculator工具。Action Observation再次执行工具调用和获取结果。Final Answer最终答案当LLM认为所有必要步骤已完成它不再调用工具而是直接输出最终答案给用户。这个清晰的链条展示了Agent如何将复杂任务分解、执行并整合。verbose日志是你调试Agent最强大的武器任何逻辑错误、工具选择失误都能在这里一目了然。5.3 测试记忆功能现在让我们测试一下记忆模块是否工作。我们进行一个多轮对话后一个问题依赖于前一个问题的答案。print(“\n” “” * 50) print(“测试多轮对话记忆功能”) print(“” * 50) # 第一轮对话 response1 agent_executor.invoke({“input”: “我的名字叫小明。”}) print(f“第一轮回答{response1[output]}”) # Agent可能只会简单确认 # 第二轮对话依赖第一轮的记忆 response2 agent_executor.invoke({“input”: “我刚才告诉你我的名字是什么”}) print(f“第二轮回答{response2[output]}”) # 正确的Agent应该回答“小明” # 第三轮结合记忆和工具 response3 agent_executor.invoke({“input”: “好的小明想计算一下圆周率π的平方根。”}) print(f“第三轮回答{response3[output]}”) # 应该能正确调用计算器并称呼用户为小明观察输出你会发现Agent在第二轮对话中成功回忆起了你的名字“小明”并在第三轮对话中不仅完成了计算任务还在回答中使用了“小明”这个称呼。这说明ConversationBufferMemory正在正常工作它将之前的对话历史都传递给了LLM使得Agent具备了上下文感知能力。6. 深入原理与高级调试让Agent更可靠看到Agent跑起来固然兴奋但构建一个真正健壮、可用的Agent我们还需要深入一些细节并知道如何排查问题。这一步是区分“玩具”和“工具”的关键。6.1 理解Prompt与Agent的决策逻辑Agent的核心决策逻辑是由一个系统级的Prompt驱动的。当我们使用ZERO_SHOT_REACT_DESCRIPTION时LangChain使用了一个预设的Prompt模板。我们可以查看并理解它这有助于我们未来定制自己的Agent。# 我们可以查看一下Agent使用的Prompt模板部分核心内容 from langchain.agents import ZeroShotAgent from langchain.agents.mrkl import prompt # 打印出Prompt的模板观察其结构 print(prompt.PREFIX) print(“\n” “-”*50 “\n”) print(prompt.FORMAT_INSTRUCTIONS) print(“\n” “-”*50 “\n”) print(prompt.SUFFIX)这个Prompt通常包含以下几个部分PREFIX前缀定义Agent的角色和目标例如“你是一个有帮助的AI助手可以使用工具来回答问题...”。FORMAT_INSTRUCTIONS格式指令这是最关键的部分它严格规定了LLM输出的格式。例如它要求LLM必须以“Thought:”、“Action:”、“Action Input:”这样的固定格式来输出以便Agent Executor能够准确解析。任何偏离这个格式的输出都会导致解析错误。SUFFIX后缀定义了最终输入给LLM的模板它会将工具描述、用户问题、对话历史等变量填充进去。当Agent出现“胡言乱语”不按格式输出或者总是选择错误工具时问题往往出在两个方面一是工具描述不够清晰二是这个系统Prompt可能不适合你的具体任务。对于后者你可以创建自定义的Prompt模板。6.2 处理常见的解析与执行错误在开发过程中你一定会遇到各种错误。以下是两种最常见的情况及其解决方法。情况一LLM输出格式错误Parsing Error有时LLM可能不会严格按照“Thought: ... Action: ... Action Input: ...”的格式输出它可能说一堆废话或者格式有细微差别。这会导致Agent Executor抛出OutputParserException。解决方案设置handle_parsing_errorsTrue就像我们在初始化Agent时做的那样这会让Executor尝试从错误中恢复或者给用户一个友好的错误提示而不是直接崩溃。优化Prompt和工具描述不清晰的指令是格式错误的元凶。确保你的工具描述精准并考虑在系统Prompt中提供更明确的格式示例Few-shot。降低temperature就像我们之前做的将LLM的temperature设为0或一个较低的值如0.1可以减少输出的随机性使格式更稳定。情况二工具选择错误或参数错误这是更常见的问题。比如用户问“今天天气怎么样”Agent却调用了calculator工具。解决方案审查工具描述这是首要步骤。工具的函数名和文档字符串 ... 里的内容必须清晰、无歧义地说明工具的功能和输入格式。例如search_web的描述应该强调它是用于“搜索实时信息或知识”而calculator强调是“数学计算”。提供更详细的上下文在用户问题不明确时Agent容易选错。可以在系统Prompt中要求Agent“如果不确定用户意图应先进行澄清”。或者利用记忆功能在对话历史中提供更多背景。使用更强大的模型如果gpt-3.5-turbo频繁出错可以尝试切换到gpt-4或gpt-4-turbo它们在复杂推理和遵循指令方面通常表现更好当然成本也更高。实现工具验证层在工具被调用前可以添加一个简单的验证逻辑。例如在calculator工具内部先检查输入的字符串是否看起来像一个数学表达式包含数字和运算符如果不是则直接返回“此问题不适合用计算器解决”并提示Agent重新思考。6.3 为Agent增加“安全护栏”让Agent能任意调用工具是强大的但也存在风险。例如一个未加限制的search_web工具如果接入了真实网络可能会执行不恰当的搜索。我们需要为Agent添加一些基本的安全约束。工具权限控制不是所有工具都需要对所有问题开放。你可以根据会话上下文或用户身份动态地加载或卸载工具列表。输入验证与过滤在每个工具函数内部对输入参数进行严格的验证和清洗。例如对于计算器可以禁用eval改用更安全的表达式解析库如ast.literal_eval结合自定义的数学表达式解析器或者白名单只允许特定的数学函数。输出审查对工具返回的结果进行审查特别是来自外部API如搜索、数据库查询的结果过滤掉敏感或不适当的内容再交给LLM和用户。设置执行超时与步骤限制在初始化AgentExecutor时可以设置max_iterations最大迭代次数和max_execution_time最大执行时间防止Agent陷入死循环或执行过长时间。# 一个更安全的Agent Executor配置示例 from langchain.agents import AgentExecutor agent_executor_safe AgentExecutor.from_agent_and_tools( agentagent, # 之前用initialize_agent创建的agent对象 toolstools, memorymemory, verboseTrue, handle_parsing_errorsTrue, max_iterations5, # 最多执行5个“思考-行动”循环 early_stopping_method“generate” # 达到限制时让LLM生成一个最终回答 )7. 项目扩展与实战化改造你的第一个能跑通的Agent已经完成了但这只是一个起点。要让这个“玩具”变成一个真正有用的“工具”我们需要从以下几个方面对它进行扩展和加固。7.1 接入真实世界工具替换掉模拟的search_web工具是第一步。这里以接入一个免费的新闻搜索API例如使用newsapi.org的API为例。你需要先注册获取API密钥。import requests from langchain.tools import tool tool def search_news(query: str, api_key: str os.getenv(“NEWS_API_KEY”)) - str: 使用NewsAPI搜索最新的新闻标题和摘要。 需要配置NEWS_API_KEY环境变量。 Args: query (str): 搜索关键词。 Returns: str: 返回最多5条相关新闻的标题和描述每条用‘-’分隔。 if not api_key: return “错误未配置NEWS_API_KEY环境变量。” url f“https://newsapi.org/v2/everything?q{query}apiKey{api_key}pageSize5sortBypublishedAt” try: response requests.get(url) data response.json() if data[“status”] “ok”: articles data[“articles”][:5] # 取前5条 results [] for article in articles: title article.get(“title”, “无标题”) description article.get(“description”, “无描述”) results.append(f“标题{title}\n摘要{description}”) return “\n\n”.join(results) if results else “未找到相关新闻。” else: return f“API请求失败{data.get(message, 未知错误)}” except Exception as e: return f“搜索过程中发生网络或解析错误{e}” # 更新工具列表 tools [calculator, search_news] # 用真实的搜索工具替换模拟工具 # 记得在.env文件中添加 NEWS_API_KEYyour_news_api_key_here现在你的Agent就能获取真实的新闻信息了。同样的模式你可以接入天气API、股票API、数据库查询、发送邮件等等将Agent的能力无限扩展。7.2 构建专属技能库自定义复杂工具工具不仅可以调用外部API也可以封装你内部的业务逻辑。例如你可以创建一个“数据清洗工具”它接收一段脏数据调用你写好的数据清洗函数返回干净数据。import pandas as pd import numpy as np tool def clean_data(data_input: str) - str: 对提供的CSV格式字符串数据进行基础清洗。 清洗包括去除首尾空格、填充数字列的空值为0填充文本列的空值为‘未知’。 Args: data_input (str): 以CSV格式字符串表示的数据第一行为表头。 Returns: str: 清洗后的CSV格式字符串。 try: from io import StringIO # 将字符串转换为DataFrame df pd.read_csv(StringIO(data_input)) # 1. 去除字符串列的首尾空格 df df.applymap(lambda x: x.strip() if isinstance(x, str) else x) # 2. 填充空值 for col in df.columns: if pd.api.types.is_numeric_dtype(df[col]): df[col].fillna(0, inplaceTrue) else: df[col].fillna(“未知”, inplaceTrue) # 将清洗后的DataFrame转回CSV字符串 output df.to_csv(indexFalse) return output except Exception as e: return f“数据清洗失败请检查输入格式是否为有效的CSV{e}” # 测试 dirty_data “““name,age,city Alice, 25 ,New York Bob, ,London Charlie,30,”“” print(clean_data.invoke(dirty_data))将这个工具加入你的Agent你就可以用自然语言指挥Agent帮你清洗数据了“帮我清洗一下这份用户数据把空值处理一下。”7.3 设计多Agent协作系统当任务变得极其复杂时单个Agent可能力不从心。这时可以引入“多Agent系统”的概念。例如你可以设计一个“主管Agent”它负责接收用户原始请求然后将其分发给不同的“专家Agent”去执行。研究Agent专门负责搜索和收集信息。分析Agent专门负责处理数据、进行计算。写作Agent专门负责整合信息生成报告。这些Agent可以共享记忆也可以通过消息队列进行通信。LangChain提供了AgentExecutor作为基础运行时你可以通过更高级的LangGraph等库来编排多个Agent的工作流。这属于进阶话题但思路是清晰的将大问题分解由不同的、功能专注的Agent协同解决。构建你的第一个AI Agent的旅程到此就告一段落了。我们从理解核心概念开始一步步搭建了环境、定义了工具、组装了智能体并让它成功运行了一个多步骤任务。更重要的是我们探讨了如何调试、加固和扩展它。回顾整个过程最关键的不是代码本身而是理解了Agent那种“思考-行动-观察”的循环范式。这个简单的范式是当今所有复杂AI智能体应用的基石。我个人的体会是AI Agent开发目前更像是一门“提示词工程”和“系统集成”的艺术。模型的强大能力需要通过精巧的Prompt和可靠的工具来引导和释放。最大的挑战往往不在于让LLM生成一段漂亮的文本而在于让它稳定、准确地选择并调用正确的工具。这需要开发者对业务逻辑、工具接口以及LLM的“脾气”都有深入的理解。所以多动手实践多观察verbose日志不断迭代你的工具描述和系统Prompt是提升Agent能力的不二法门。最后别忘了从简单的场景开始先让你的Agent可靠地解决一个小问题再逐步增加它的能力和职责范围。