baiyuting LV
发表于 2025-4-9 19:04:47
在之前的文章里,我们详细介绍了 AI 智能体,聊了聊它们的特点、组成部分、发展历程、遇到的挑战以及未来的可能性。
在这篇文章里,我们要一起用 Python 从零开始做一个智能体。这个智能体能根据你输入的信息做决定,选择合适的工具,然后执行任务。让我们开始吧!
1. 什么是智能体?
智能体就像一个独立的小家伙,它能感知周围的环境,自己做决定,然后采取行动来实现特定的目标。智能体可以很简单,也可以很复杂。简单的就像那种只会对刺激做出反应的“反应型智能体”,复杂的就像那种能不断学习和适应的“智能智能体”。常见的智能体类型包括:
- 反应型智能体(Reactive Agents): 直接对环境变化做出反应,没有记忆。
- 基于模型的智能体(Model-Based Agents): 使用内部的世界模型来做决策。
- 基于目标的智能体(Goal-Based Agents): 根据要实现的目标来规划行动。
- 基于效用的智能体(Utility-Based Agents): 通过评估不同行动的“价值”来选择最佳方案。
像聊天机器人、推荐系统、自动驾驶汽车,它们都用了不同类型的智能体来高效、智能地完成任务。
我们这个智能体的核心组成部分是:
- 模型: 智能体的大脑,负责处理输入的信息并生成回应。
- 工具: 预先定义好的一些功能,智能体可以根据你的请求来执行这些功能。
- 工具箱: 智能体拥有的所有工具的集合。
- 系统提示: 一组指令,告诉智能体如何处理你的输入,并选择合适的工具。
2. 动手实现
好啦,让我们挽起袖子开始干活吧!
构建智能体
2.1 准备工作
在运行代码之前,请确保你的电脑满足以下条件:
- Python 环境设置
你需要安装 Python 才能运行 AI 智能体。按照以下步骤设置你的环境:
- 安装 Python(如果还没安装的话)
- 从 python.org 下载并安装 Python(推荐 3.8 或更高版本)。
- 验证安装:
- python -m venv ai_agents_env
- source ai_agents_env/bin/activate # Windows 上:ai_agents_env\Scripts\activate
复制代码
- 本地设置 Ollama
Ollama 用于高效地运行和管理本地语言模型。按照以下步骤安装和配置:
- 下载并安装 Ollama
- 访问 Ollama 官网 并下载适用于你的操作系统的安装程序。(请替换为实际链接)
- 按照你的操作系统平台的说明进行安装。
- 验证 Ollama 安装
- 拉取模型(如果需要)
- 某些智能体实现可能需要特定的模型。你可以使用以下命令拉取模型:
- ollama pull mistral # 将 'mistral' 替换为你需要的模型
复制代码 2.2 实现步骤
第一步:设置环境
除了 Python,我们还需要安装一些必要的库。在这个教程中,我们将使用 requests、json 和 termcolor。此外,我们将使用 dotenv 来管理环境变量。- pip install requests termcolor python-dotenv
复制代码 第二步:定义模型类
我们首先需要一个模型来处理用户的输入。我们将创建一个 OllamaModel 类,它与本地 API 交互以生成响应。
这是一个基本的实现:- from termcolor import colored
- import os
- from dotenv import load_dotenv
- load_dotenv()
- import requests
- import json
- import operator
- class OllamaModel:
- def __init__(self, model, system_prompt, temperature=0, stop=None):
- """
- 用给定的参数初始化 OllamaModel。
- 参数:
- model (str): 要使用的模型的名称。
- system_prompt (str): 要使用的系统提示。
- temperature (float): 模型的温度设置。
- stop (str): 模型的停止标记。
- """
- self.model_endpoint = "http://localhost:11434/api/generate"
- self.temperature = temperature
- self.model = model
- self.system_prompt = system_prompt
- self.headers = {"Content-Type": "application/json"}
- self.stop = stop
- def generate_text(self, prompt):
- """
- 根据提供的提示从 Ollama 模型生成响应。
- 参数:
- prompt (str): 用于生成响应的用户查询。
- 返回:
- dict: 模型的响应,以字典形式返回。
- """
- payload = {
- "model": self.model,
- "format": "json",
- "prompt": prompt,
- "system": self.system_prompt,
- "stream": False,
- "temperature": self.temperature,
- "stop": self.stop
- }
- try:
- request_response = requests.post(
- self.model_endpoint,
- headers=self.headers,
- data=json.dumps(payload)
- )
- print("请求响应", request_response)
- request_response_json = request_response.json()
- response = request_response_json['response']
- response_dict = json.loads(response)
- print(f"\n\n来自 Ollama 模型的响应: {response_dict}")
- return response_dict
- except requests.RequestException as e:
- response = {"error": f"调用模型时出错!{str(e)}"}
- return response
复制代码 这个类用模型的名称、系统提示、温度和停止标记进行初始化。generate_text 方法向模型 API 发送请求并返回响应。
第三步:为智能体创建工具
下一步是创建我们的智能体可以使用的工具。这些工具是执行特定任务的简单 Python 函数。这是一个基本计算器和字符串反转器的示例:- def basic_calculator(input_str):
- """
- 根据输入的字符串或字典对两个数字执行数值运算。
- 参数:
- input_str (str 或 dict): 表示字典的 JSON 字符串,包含键 'num1'、'num2' 和 'operation',
- 或者直接是一个字典。例如:'{"num1": 5, "num2": 3, "operation": "add"}'
- 或 {"num1": 67869, "num2": 9030393, "operation": "divide"}
- 返回:
- str: 运算结果的格式化字符串。
- 抛出:
- Exception: 如果在运算过程中发生错误(例如,除以零)。
- ValueError: 如果请求了不支持的运算或输入无效。
- """
- try:
- # 同时处理字典和字符串输入
- if isinstance(input_str, dict):
- input_dict = input_str
- else:
- # 清理并解析输入字符串
- input_str_clean = input_str.replace("'", "\"")
- input_str_clean = input_str_clean.strip().strip("\"")
- input_dict = json.loads(input_str_clean)
- # 验证必需的字段
- if not all(key in input_dict for key in ['num1', 'num2', 'operation']):
- return "错误:输入必须包含 'num1'、'num2' 和 'operation'"
- num1 = float(input_dict['num1']) # 转换为浮点数以处理小数
- num2 = float(input_dict['num2'])
- operation = input_dict['operation'].lower() # 不区分大小写
- except (json.JSONDecodeError, KeyError) as e:
- return "无效的输入格式。请提供有效的数字和运算。"
- except ValueError as e:
- return "错误:请提供有效的数值。"
- # 定义支持的运算并进行错误处理
- operations = {
- 'add': operator.add,
- 'plus': operator.add, # add 的替代词
- 'subtract': operator.sub,
- 'minus': operator.sub, # subtract 的替代词
- 'multiply': operator.mul,
- 'times': operator.mul, # multiply 的替代词
- 'divide': operator.truediv,
- 'floor_divide': operator.floordiv,
- 'modulus': operator.mod,
- 'power': operator.pow,
- 'lt': operator.lt,
- 'le': operator.le,
- 'eq': operator.eq,
- 'ne': operator.ne,
- 'ge': operator.ge,
- 'gt': operator.gt
- }
- # 检查运算是否受支持
- if operation not in operations:
- return f"不支持的运算:'{operation}'。支持的运算有:{', '.join(operations.keys())}"
- try:
- # 特殊处理除以零的情况
- if (operation in ['divide', 'floor_divide', 'modulus']) and num2 == 0:
- return "错误:不允许除以零"
- # 执行运算
- result = operations[operation](num1, num2)
- # 根据类型格式化结果
- if isinstance(result, bool):
- result_str = "True" if result else "False"
- elif isinstance(result, float):
- # 处理浮点数精度
- result_str = f"{result:.6f}".rstrip('0').rstrip('.')
- else:
- result_str = str(result)
- return f"答案是:{result_str}"
- except Exception as e:
- return f"计算过程中出错:{str(e)}"
- def reverse_string(input_string):
- """
- 反转给定的字符串。
- 参数:
- input_string (str): 要反转的字符串。
- 返回:
- str: 反转后的字符串。
- """
- # 检查输入是否为字符串
- if not isinstance(input_string, str):
- return "错误:输入必须是字符串"
- # 使用切片反转字符串
- reversed_string = input_string[::-1]
- # 格式化输出
- result = f"反转后的字符串是:{reversed_string}"
- return result
复制代码 这些函数被设计为根据提供的输入执行特定任务。basic_calculator 处理算术运算,而 reverse_string 反转给定的字符串。
第四步:构建工具箱
ToolBox 类存储智能体可以使用的所有工具,并提供每个工具的描述:- class ToolBox:
- def __init__(self):
- self.tools_dict = {}
- def store(self, functions_list):
- """
- 存储列表中每个函数的字面名称和文档字符串。
- 参数:
- functions_list (list): 要存储的函数对象列表。
- 返回:
- dict: 以函数名称为键,其文档字符串为值的字典。
- """
- for func in functions_list:
- self.tools_dict[func.__name__] = func.__doc__
- return self.tools_dict
- def tools(self):
- """
- 将 store 中创建的字典作为文本字符串返回。
- 返回:
- str: 存储的函数及其文档字符串的字典,以文本字符串形式返回。
- """
- tools_str = ""
- for name, doc in self.tools_dict.items():
- tools_str += f"{name}: \"{doc}\"\n"
- return tools_str.strip()
复制代码 这个类将帮助智能体了解哪些工具可用以及每个工具的作用。
第五步:创建智能体类
智能体需要思考,决定使用哪个工具,并执行它。这是 Agent 类:- agent_system_prompt_template = """
- 你是一个可以访问特定工具的智能 AI 助手。你的响应必须始终采用以下 JSON 格式:
- {{
- "tool_choice": "工具名称",
- "tool_input": "工具的输入"
- }}
- 工具及其使用时机:
- 1. basic_calculator: 用于任何数学计算
- - 输入格式:{{"num1": 数字, "num2": 数字, "operation": "add/subtract/multiply/divide"}}
- - 支持的运算:add/plus, subtract/minus, multiply/times, divide
- - 示例输入和输出:
- 输入:"计算 15 加 7"
- 输出:{{"tool_choice": "basic_calculator", "tool_input": {{"num1": 15, "num2": 7, "operation": "add"}}}}
- 输入:"100 除以 5 是多少?"
- 输出:{{"tool_choice": "basic_calculator", "tool_input": {{"num1": 100, "num2": 5, "operation": "divide"}}}}
- 2. reverse_string: 用于任何涉及反转文本的请求
- - 输入格式:只需将要反转的文本作为字符串
- - 当用户提到“反转”、“倒过来”或要求反转文本时,始终使用此工具
- - 示例输入和输出:
- 输入:"Howwwww 的反转?"
- 输出:{{"tool_choice": "reverse_string", "tool_input": "Howwwww"}}
- 输入:"Python 的反转是什么?"
- 输出:{{"tool_choice": "reverse_string", "tool_input": "Python"}}
- 3. no tool: 用于一般对话和问题
- - 示例输入和输出:
- 输入:"你是谁?"
- 输出:{{"tool_choice": "no tool", "tool_input": "我是一个 AI 助手,可以帮助你进行计算、反转文本和回答问题。我可以执行数学运算和反转字符串。今天我能帮你做什么?"}}
- 输入:"你好吗?"
- 输出:{{"tool_choice": "no tool", "tool_input": "我运行良好,谢谢你的关心!我可以帮你进行计算、文本反转或回答你可能有的任何问题。"}}
- 规则:
- 1. 对于关于身份、能力或感受的问题:
- - 始终使用 "no tool"
- - 提供完整、友好的回应
- - 提及你的能力
- 2. 对于任何文本反转请求:
- - 始终使用 "reverse_string"
- - 仅提取要反转的文本
- - 删除引号、“的反转”和其他多余的文本
- 3. 对于任何数学运算:
- - 始终使用 "basic_calculator"
- - 提取数字和运算
- - 将文本数字转换为数字
- 这是你的工具及其描述的列表:
- {tool_descriptions}
- 记住:你的响应必须始终是包含 "tool_choice" 和 "tool_input" 字段的有效 JSON。
- """
- class Agent:
- def __init__(self, tools, model_service, model_name, stop=None):
- """
- 用工具列表和模型初始化智能体。
- 参数:
- tools (list): 工具函数列表。
- model_service (class): 具有 generate_text 方法的模型服务类。
- model_name (str): 要使用的模型的名称。
- """
- self.tools = tools
- self.model_service = model_service
- self.model_name = model_name
- self.stop = stop
- def prepare_tools(self):
- """
- 将工具存储在工具箱中并返回它们的描述。
- 返回:
- str: 存储在工具箱中的工具的描述。
- """
- toolbox = ToolBox()
- toolbox.store(self.tools)
- tool_descriptions = toolbox.tools()
- return tool_descriptions
- def think(self, prompt):
- """
- 使用系统提示模板和工具描述对模型运行 generate_text 方法。
- 参数:
- prompt (str): 用于生成响应的用户查询。
- 返回:
- dict: 模型的响应,以字典形式返回。
- """
- tool_descriptions = self.prepare_tools()
- agent_system_prompt = agent_system_prompt_template.format(tool_descriptions=tool_descriptions)
- # 使用系统提示创建模型服务实例
- if self.model_service == OllamaModel:
- model_instance = self.model_service(
- model=self.model_name,
- system_prompt=agent_system_prompt,
- temperature=0,
- stop=self.stop
- )
- else:
- model_instance = self.model_service(
- model=self.model_name,
- system_prompt=agent_system_prompt,
- temperature=0
- )
- # 生成并返回响应字典
- agent_response_dict = model_instance.generate_text(prompt)
- return agent_response_dict
- def work(self, prompt):
- """
- 解析 think 返回的字典并执行适当的工具。
- 参数:
- prompt (str): 用于生成响应的用户查询。
- 返回:
- 执行适当工具的响应,如果找不到匹配的工具,则返回 tool_input。
- """
- agent_response_dict = self.think(prompt)
- tool_choice = agent_response_dict.get("tool_choice")
- tool_input = agent_response_dict.get("tool_input")
- for tool in self.tools:
- if tool.__name__ == tool_choice:
- response = tool(tool_input)
- print(colored(response, 'cyan'))
- return
- print(colored(tool_input, 'cyan'))
- return
复制代码 这个类有三个主要方法:
- prepare_tools: 存储并返回工具的描述。
- think: 根据用户提示决定使用哪个工具。
- work: 执行所选工具并返回结果。
第六步:运行智能体
最后,让我们把所有东西放在一起并运行我们的智能体。在脚本的主要部分,初始化智能体并开始接受用户输入:- # 示例用法
- if __name__ == "__main__":
- """
- 使用此智能体的说明:
- 你可以尝试的示例查询:
- 1. 计算器运算:
- - "计算 15 加 7"
- - "100 除以 5 是多少?"
- - "23 乘以 4"
- 2. 字符串反转:
- - "反转单词 'hello world'"
- - "你能反转 'Python Programming' 吗?"
- 3. 一般问题(将获得直接响应):
- - "你是谁?"
- - "你能帮我做什么?"
- Ollama 命令(在终端中运行):
- - 检查可用模型: 'ollama list'
- - 检查正在运行的模型: 'ps aux | grep ollama'
- - 列出模型标签: 'curl http://localhost:11434/api/tags'
- - 拉取新模型: 'ollama pull mistral'
- - 运行模型服务器: 'ollama serve'
- """
- tools = [basic_calculator, reverse_string]
- # 使用 Ollama 和 llama2 模型
- model_service = OllamaModel
- model_name = "llama2" # 可以更改为其他模型,如 'mistral'、'codellama' 等。
- stop = &#34;<|eot_id|>&#34;
- agent = Agent(tools=tools, model_service=model_service, model_name=model_name, stop=stop)
- print(&#34;\n欢迎使用 AI 智能体!输入 &#39;exit&#39; 退出。&#34;)
- print(&#34;你可以让我:&#34;)
- print(&#34;1. 执行计算(例如,&#39;计算 15 加 7&#39;)&#34;)
- print(&#34;2. 反转字符串(例如,&#39;反转 hello world&#39;)&#34;)
- print(&#34;3. 回答一般问题\n&#34;)
- while True:
- prompt = input(&#34;问我任何问题:&#34;)
- if prompt.lower() == &#34;exit&#34;:
- break
- agent.work(prompt)
复制代码 3. 总结
在这篇文章里,我们从理解什么是智能体到一步步实现一个智能体。我们设置了环境,定义了模型,创建了必要的工具,并构建了一个结构化的工具箱来支持我们智能体的功能。最后,我们通过运行智能体将所有内容整合在一起。
这种结构化的方法为构建能够自动执行任务和做出明智决策的智能、交互式智能体奠定了坚实的基础。随着 AI 智能体的不断发展,它们的应用将在各个行业中扩展,推动效率和创新。
<hr/>我会定期更新干货和学习笔记。喜欢的话,记得点个关注 ,不错过后续精彩内容!
|
|