体验智能体构建过程:从零开始构建Agent

大模型向量数据库云通信

1. 什么是智能体?

智能体(Agents)是一种能够感知环境、做出决策并采取行动来实现特定目标的自主实体。智能体的复杂程度各不相同,从简单的响应式智能体(对刺激直接做出反应)到更高级的智能体(能够学习和适应)都有。常见的智能体类型包括:

  • 响应式智能体:直接对环境变化作出反应,没有内部记忆。
  • 基于模型的智能体:使用内部世界模型来做决策。
  • 基于目标的智能体:基于特定目标规划行动。
  • 基于效用的智能体:通过效用函数评估潜在行动,以优化结果。

智能体的例子包括聊天机器人、推荐系统和自动驾驶汽车,它们各自使用不同类型的智能体来高效智能地执行任务。

我们智能体的核心组件有:

  • 模型:智能体的大脑,负责处理输入并生成响应。

  • 工具:智能体可以根据用户请求执行的预定义函数。

  • 工具箱:智能体可用工具的集合。

  • 系统提示:指导智能体如何处理用户输入并选择合适工具的指令集。

    2. 实现


现在,让我们卷起袖子开始构建吧!

picture.image

构建智能体

2.1 前提条件

在运行代码之前,确保你的系统满足以下前提条件:

1. Python环境设置

你需要安装Python来运行AI智能体。按照以下步骤设置环境:

安装Python(如果尚未安装)

  • 从python.org下载并安装Python(推荐3.8+版本)
  • 验证安装:
  
python --version

创建虚拟环境(推荐)

  • 最好使用虚拟环境来管理依赖项:
  
python -m venv ai\_agents\_env  
source ai\_agents\_env/bin/activate  # Windows上使用:ai\_agents\_env\Scripts\activate  

安装所需依赖

  • 导航到仓库目录并安装依赖:
  
pip install -r requirements.txt

2. 在本地设置Ollama

Ollama用于高效运行和管理本地语言模型。按照以下步骤安装和配置:

下载并安装Ollama

  • 访问Ollama官方网站并下载适合你操作系统的安装程序
  • 按照平台相应指导进行安装

验证Ollama安装

  • 运行以下命令检查Ollama是否正确安装:
  
ollama --version

拉取模型(如需要)

  • 某些智能体实现可能需要特定模型。你可以使用以下命令拉取模型:
  
ollama pull mistral  # 将'mistral'替换为所需模型  

我查了下有些模型是在ollama部署下不支持工具调用的。

2.2 实现步骤

picture.image

步骤1:设置环境

除了Python,我们还需要安装一些基本库。对于本教程,我们将使用requests、json和termcolor。此外,我们将使用dotenv来管理环境变量。

  
pip install requests termcolor python-dotenv

步骤2:定义模型类

首先,我们需要一个处理用户输入的模型。我们将创建一个OllamaModel类,它与本地API交互以生成响应。

基本实现如下:

  
from termcolor import colored  
import os  
from dotenv import load\_dotenv  
load\_dotenv()  
### Models  
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\nOllama模型的响应: {response\_dict}")  
  
            return response\_dict  
        except requests.RequestException as e:  
            response = {"error": f"调用模型时出错!{str(e)}"}  
            return response

这个类以模型名称、系统提示、温度和停止令牌进行初始化。generate_text方法向模型API发送请求并返回响应。

步骤3:为智能体创建工具

下一步是创建我们的智能体可以使用的工具。这些工具是执行特定任务的简单Python函数。以下是一个基本计算器和字符串反转器的例子:

  
def basic\_calculator(input\_str):  
    """  
    根据输入字符串或字典对两个数字执行数学运算。  
  
    参数:  
    input\_str (str或dict): 可以是表示包含'num1'、'num2'和'operation'键的字典的JSON字符串,  
                         或直接是字典。例如:'{"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 = "真" if result else "假"  
        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则反转给定的字符串。

步骤4:构建工具箱

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()

这个类将帮助智能体了解哪些工具可用以及每个工具的功能。

步骤5:创建智能体类

智能体需要思考、决定使用哪个工具并执行它。以下是智能体类:

  
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:用于任何涉及文本反转的请求  
   - 输入格式:仅作为字符串的要反转的文本  
   - 当用户提到"反转"、"倒序"或要求反转文本时,始终使用此工具  
   - 输入和输出示例:  
     输入:"'你好世界'的反转是什么?"  
     输出:{{"tool\_choice": "reverse\_string", "tool\_input": "你好世界"}}  
       
     输入:"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:执行所选工具并返回结果。

步骤6:运行智能体

最后,让我们把所有内容放在一起并运行我们的智能体。在脚本的主要部分,初始化智能体并开始接受用户输入:

  
# 示例用法  
if \_\_name\_\_ == "\_\_main\_\_":  
    """  
    使用此智能体的说明:  
      
    你可以尝试的示例查询:  
    1. 计算器操作:  
       - "计算157"  
       - "100除以5等于多少?"  
       - "23乘以4"  
      
    2. 字符串反转:  
       - "反转'你好世界'这个词"  
       - "你能反转'Python编程'吗?"  
      
    3. 一般问题(将得到直接回应):  
       - "你是谁?"  
       - "你能帮我做什么?"  
      
    Ollama命令(在终端中运行):  
    - 检查可用模型:    'ollama list'  
    - 检查运行中的模型:'ps aux | grep ollama'  
    - 列出模型标签:    'curl http://localhost:11434/api/tags'  
    - 拉取新模型:      'ollama pull mistral'  
    - 运行模型服务器:  'ollama serve'  
    """  
  
    tools = [basic\_calculator, reverse\_string]  
  
    # 取消下面的注释以使用OpenAI  
    # model\_service = OpenAIModel  
    # model\_name = 'gpt-3.5-turbo'  
    # stop = None  
  
    # 使用Ollama的llama2模型  
    model\_service = OllamaModel  
    model\_name = "llama2"  # 可以更改为其他模型,如'mistral'、'codellama'等  
    stop = "<|eot\_id|>"  
  
    agent = Agent(tools=tools, model\_service=model\_service, model\_name=model\_name, stop=stop)  
  
    print("\n欢迎使用AI智能体!输入'exit'退出。")  
    print("你可以让我:")  
    print("1. 执行计算(例如,'计算15加7')")  
    print("2. 反转字符串(例如,'反转你好世界')")  
    print("3. 回答一般问题\n")  
  
    while True:  
        prompt = input("问我任何问题:")  
        if prompt.lower() == "exit":  
            break  
  
        agent.work(prompt)

实测效果如下:

picture.image

3. 总结

在这篇博文中,我们探索了智能体的概念,并一步步实现了它。我们设置了环境,定义了模型,创建了基本工具,并构建了一个结构化的工具箱来支持我们智能体的功能。最后,我们通过运行智能体将所有内容整合在一起。

这种结构化方法为构建能够自动执行任务并做出明智决策的智能交互式智能体提供了坚实的基础。随着AI智能体不断发展,它们的应用将扩展到各个行业,推动效率和创新。敬请关注更多见解和改进,将你的AI智能体提升到新的水平!

picture.image

添加微信,备注” LLM “进入大模型技术交流群

picture.image

picture.image

如果你觉得这篇文章对你有帮助,别忘了点个赞、送个喜欢

/ 作者:致Great

/ 作者:欢迎转载,标注来源即可

0
0
0
0
关于作者
关于作者

文章

0

获赞

0

收藏

0

相关资源
CV 技术在视频创作中的应用
本次演讲将介绍在拍摄、编辑等场景,我们如何利用 AI 技术赋能创作者;以及基于这些场景,字节跳动积累的领先技术能力。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论