AIAgent技术让你的AI助手学会思考使用工具

98 阅读5分钟

cover_image

AI Agent技术,让你的AI助手学会思考,使用工具

原创 Bob新视界 Bob的AI视界


大家好,我是Bob。

一个想和大家一起慢慢变富的AI程序员。

热爱分享AI前瞻思考、项目经验、面试技巧。

欢迎关注我,一起探索,一起破圈!

AI Agent技术,让大模型学会思考、调用工具。

为什么需要 Agent

在 ChatGPT 横空出世,夺走 Bert 的桂冠之后,大模型愈发 得 火热,国内各种模型层出不穷,史称“百模大战”。 大模型的能力是毋庸置疑的,但大模型在一些 实时的问题 上,或是某些 专有领域 的问题上,可能会显得有些力不从心。 因此,我们需要一些工具来为大模型赋能,给大模型一个抓手,让大模型和现实世界发生的事情对齐颗粒度,这样我们就获得了一个更好的用的大模型。

什么是 Agent

AI Agent(人工智能代理)是image一种能够感知环境、进行决策和执行动作的智能实体,具备通过 独立思考记忆能力调用工具逐步完成给定目标能力 ,也可以称为“智能体”或“智能业务助理”。在大模型技术驱动下,让人们以自然语言为交互方式高自动化地执行和处理专业或繁复的工作任务,从而极大程度释放人员精力。

论文思路图

Agent 代码分享

本次的 Agent 技术分享,主要集中于模型 调用工具 的能力 ,代码比较简单,仅用于学习,切勿部署于生产环境。

项目仓库:Github Project [1]

参考论文:ReAct: Synergizing Reasoning and Acting in Language Models [2]

Tool 工具集类(Tool.py)

import json  
import requests  
import os  
  
class Tools:  
    def __init__(self) -> None:  
        self.tools_config=[  
            {  
                'chinese_name':'谷歌搜索',  
                'english_name':'google_search',  
                'description':'谷歌搜索是一个通用搜索引擎,可用于访问互联网、查询百科知识、了解时事新闻等。',  
                'parameters':[  
                    {  
                        'name''search_query',  
                        'description''搜索关键词或短语',  
                        'required'True,  
                        'schema': {'type''string'},  
                    }  
                ]  
            },  
        ]  
        self.api=os.getenv('google_search_api')  
  
  
    def get_func(self):  
        return self.tools_config  
  
    def google_search(self,search_query:str):  
        url = "https://google.serper.dev/search"  
  
        payload = json.dumps({  
        "q":search_query  
        })  
        headers = {  
        'X-API-KEY': self.api,  
        'Content-Type''application/json'  
        }  
  
        response = requests.request("POST", url, headers=headers, data=payload).json()  
        return  response['organic'][0]['snippet']  

工具类包含两个部分,一个部分是 工具的配置描述 ,另一个部分是 工具对应的方法 .

这里之构建了一个Google搜索工具,需要 Google search API [3] ,其他的工具大家可以按照模板来写。

ps:注意english_name必须和对应的方法名相同

LLM 大模型类(llm.py)

from typing import DictListOptionalTupleUnion  
  
import torch  
from transformers import AutoTokenizer, AutoModelForCausalLM  
from langchain_openai import OpenAI,ChatOpenAI  
from langchain_core.messages.ai import AIMessage  
from langchain_core.messages.human import HumanMessage  
  
class BaseModel:  
    def __init__(self,path:str='') -> None:  
        if path!='':  
            self.tokenizer=AutoTokenizer.from_pretrained(path)  
            self.model=AutoModelForCausalLM.from_pretrained(path)  
        elif path=='':  
            self.model= ChatOpenAI(model="gpt-3.5-turbo", temperature=0.1)  
  
  
    def chat(self,query:str, prompt_template: str='', history:List=[]):  
        pass  
  
    def load_model(self):  
        pass  
  
class OpenAIModel(BaseModel):  
    def __init__(self, path: str = '') -> None:  
        super().__init__(path)  
  
    def chat(self,query:str, prompt_template: str='', history:List=[]):  
        message=[]  
        message.append(HumanMessage(content=prompt_template))  
        message.append(HumanMessage(content=query))  
        # message=prompt_template+f'\nQuestion: {query}'  
        # message=HumanMessage(content=message)  
        res=self.model.invoke(message)  
        return res.content  

大模型类构建,默认使用OpenAI的API( 需要 api-key 喔),可自行修改成本地大模型, 包含一个BaseModel的父类,存在 init 初始化方法和 chat 对话方法,OpenAIModel子类继承BaseModel类

Agent 类(Agent.py)

from typing import Dict, List, Optional, Tuple, Union  
import json5  
  
from components.LLM import OpenAIModel  
from components.Tools import Tools  
  
# from LLM import OpenAIModel  
# from Tools import Tools  
  
  
  
TOOL_DESC = """{english_name}: Call this tool to interact with the {chinese_name} API. What is the {chinese_name} API useful for? {description} Parameters: {parameters} Format the arguments as a JSON object."""  
  
REACT_PROMPT = """Answer the following questions as best you can. You have access to the following tools:  
  
{tools_description}  
  
Use the following format:  
  
Question: the input question you must answer  
Thought: you should always think about what to do  
Action: the action to take, should be one of [{tools_name}]  
Action Input: the input to the action  
Observation: the result of the action  
... (this Thought/Action/Action Input/Observation can be repeated zero or more times)  
Thought: I now know the final answer  
Final Answer: the final answer to the original input question  
  
Begin!  
  
  
"""  
  
class Agent:  
    def __init__(self,path:str='') -> None:  
        self.path=path  
        self.tools=Tools()  
        self.tools_config=self.tools.get_func()  
        self.llm=OpenAIModel()  
        self.template_prompt=self.build_template_prompt()  
  
    def build_template_prompt(self):  
        tools_description,tools_name=[],[]  
        for tool in self.tools_config:  
            tools_description.append(TOOL_DESC.format(**tool))  
            tools_name.append(tool['english_name'])  
        tools_description = '\n\n'.join(tools_description)  
        tools_name = ','.join(tools_name)  
  
        template_prompt=REACT_PROMPT.format(tools_description=tools_description,tools_name=tools_name)  
  
        return template_prompt  
  
    def select_func_call(self,text:str):  
        func_name=''  
        func_args=''  
        i = text.rfind('\nAction:')  
        j = text.rfind('\nAction Input:')  
        k = text.rfind('\nObservation:')  
        if j>i>=0:  
            if k<0:  
                text.strip()+'\nObservation:'  
            k = text.rfind('\nObservation:')  
            func_name=text[i+len('\nAction:'):j].strip()  
            func_args=text[j+len('\nAction Input:'):k].strip()  
            text=text[:k].strip()  
        return func_name,func_args,text  
  
    def call_plugin(self, func_name, func_args):  
        func_args = json5.loads(func_args)  
        if func_name=="google_search":  
            return '\nObservation:' + self.tools.google_search(**func_args)  
  
    def chat_by_func(self,query,history=[]):  
        res_model_1=self.llm.chat(query,self.template_prompt)  
        func_name,func_args,text=self.select_func_call(res_model_1)  
        if func_name:  
            res_func=self.call_plugin(func_name, func_args)  
            res_model_2=text+res_func  
        result=self.llm.chat(res_model_2,self.template_prompt)  
        show='第一次模型交互:\n'+text+'\n\n'+f'执行{func_name}的结果:\n'+res_func+'\n\n'+'第二次交互:\n'+res_model_2+'\n\n'+'最终结果:\n'+result  
  
        return  show

Agent类包含 init 方法, build_prompt 构建提示词, select_func_call 选择需要调用的方法, call_plugin 调用方法, chat_by_func 整合所有步骤的函数。

解释一下流程:

  1. 第一次与AI交互:提出问题,利用提示词,引导模型做出思考,需要什么 流程 ,什么 方法 来完成目标。

2.与方法交互:解析回答的字符串,得到需要调用的 方法名参数 ,调用方法,得到信息。

3.第二次与AI交互:结合 问题 与调用方法的 信息 ,再次给到AI模型,让AI参考信息,做出最终回答

提示词如下:

Answer the following questions as best you can. You have access to the following tools:  
  
{tools_description}  
  
Use the following format:  
  
Question: the input question you must answer  
Thought: you should always think about what to do  
Action: the action to take, should be one of [{tools_name}]  
Action Input: the input to the action  
Observation: the result of the action  
... (this Thought/Action/Action Input/Observation can be repeated zero or more times)  
Thought: I now know the final answer  
Final Answer: the final answer to the original input question  
  
Begin!

Web_demo演示 (demo.py)

import gradio as gr  
import time  
from components.Agent import Agent  
  
  
agent=Agent()  
  
  
  
def echo(message, history):  
    # result=agent.llm.chat(message,agent.template_prompt)  
    result=agent.chat_by_func(message)  
      
    for i in range(len(result)):  
        time.sleep(0.02)  
        yield result[: i+1]  
  
        #自定义的流式输出  
  
  
  
demo = gr.ChatInterface(fn=echo,   
                        examples=["特朗普什么时候出生?","github是什么?"],   
                        title="Echo Bot",  
                        theme="soft")  
demo.launch()

demo基于Gradio构建,可自行调试

结果如下

引用链接

[1] 项目仓库:Github Project: github.com/phbst/TinyA…
[2] 参考论文:ReAct: Synergizing Reasoning and Acting in Language Models: arxiv.org/abs/2210.03…
[3] Google search API: serper.dev/api-key