AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


LLM之Agent再探
发布日期:2024-04-05 13:01:17 浏览次数: 1808



前言

重要: 阅读该文章之前,一定要先阅读:LLM之Agent初探

1、当业务中有大量的tool时,比如有上千个,这些tool的描述加起来,总长度已经大大超过了LLM的最大输入长度,即使能接受这么长的token,从attention机制来看,效果也好不到哪里去。

2、在LLM完成指令时,这几千个tool也不是都会被用上,那些没被用上的tool,且没被使用的tool占了绝大部分,大量的没被使用的tool占着大部分输入的token,造成资源的浪费,且推理性能也会有所下降。

基于以上两点考虑,尽量将与实际指令相关的tool加载进agent,丢弃那些不太可能会用到的tool是十分有必要的。

思考

我们是不是可以将每次输入进来的instruction去和所有 tool 的 description进行语义匹配,将最相关的部分tool加载进agent,以便agent调用,这样,我们既可以将agent执行instruction过程中可能会用到的tool加载进来,又可以过滤掉那些不太可能会用到的tool,既能不损失效果,又达到了减少token消耗的目的。比如:当instruction是please calculator 735456*32时,我们最有可能用得到的tool肯定是和calculator相关的,不太可能用到的是获取实时新闻获取当前时间之类的毫不相干的tool。

解决办法

基于以往的经验,以上思考确实站得住脚,我们可以利用外挂知识库的思想,去完成这件事情。

首先,我们需要构建一个tool知识库,跟我们业务所有的相关的tool应该都在该知识库中维护,格式如下:

tool_name tool_description
calculator Useful for when you need to answer questions about math.
wikipedia A wrapper around Wikipedia. Useful for when you need to answer general questions about people, places, companies, facts, historical events, or other subjects. Input should be a search query.
terminal Run shell commands on this Linux machine.
requests_delete A portal to the internet. Use this when you need to make a DELETE request to a URL. Input should be a specific url, and the output will be the text response of the DELETE request.
duckduckgo_search A wrapper around DuckDuckGo Search. Useful for when you need to answer questions about current events. Input should be a search query.
...

以上这些tool,都是langchain里面内置的,源码路径:langchain/agents/load_tools.py我把这些内置的tool都给存到了本地,用作tool知识库。

对以上tool知识库向量化,这里我的向量化模型是bge-large-zh,将tool_description向量化,使用HNSW方法构建索引,存于本地

注: ToolLLM 团队训练了一个 tool retriever模型,大家可以试下效果如何

    def search(self, query, topk=3):

        query_text_embedding = self.model.encode([query])

        distances, indexs = self.faiss_index.search(query_text_embedding, topk)

        tool_names = []
        for idx in indexs[0]:
            logger.info(self.data["name"][idx], "----" , self.data["description"][idx])

            tool_names.append(self.data["name"][idx])
        
        return tool_names

这里我们召回的是最有可能的 tool names,有了这些tool names后,我们就可以去加载对应的toolagent了。

因为实际的tool name和使用load_tools方法加载tool时名字并非一样的,所以我这里加了个map。去映射对应的load_tools时使用的name

    tool_name_map = {
        "Calculator": "llm-math",
        "Text-Message": "twilio",
        "sleep": "sleep",
        "Open-Meteo-API": "open-meteo-api",
        "requests_get": "requests_get"
    }

这里偷懒了,总共五十个,我只映射了五个,我们使用一个instruction试试

question = "please calculator 735456*32"

召回的top3 tool

Calculator ---- Useful for when you need to answer questions about math.
Text-Message ---- Useful for when you need to send a text message to a provided phone number.
sleep ---- Make agent sleep for a specified number of seconds.

agent回答:

    Thought: I need to use the calculator tool to solve this math problem.
    Action:
    ```
    {
      "action": "Calculator",
      "action_input": "735456*32"
    }
    ```
    Observation: Answer: 23534592
    
    I know what to respond
    Action:
    ```
    {
      "action": "Final Answer",
      "action_input": "23534592"
    }
    ```

可以看出,agent成功调用了Calculator,说明该方法确实有效。

当你使用的是自定义的tool时,原理也是一样的,可以参考langchain/agents/load_tools.py中的源码,将tool组织成dict格式,如:

{
    "tool1_name": "tool1的实现函数",
    "tool2_name": "tool2的实现函数",
    "tool3_name": "tool3的实现函数"
}

总结

1、向量化模型效果决定该agent效果,若是连相关的tool都无法召回出来,那就无法将会被使用到的tool加载到agent中,agent在执行instruction时,无法调用正确的tool

2、当召回的数量较多时(如50以上),我们可以再加一个重排模块,对召回的tool重新排序。

3、当召回效果还是不好时,我们可以通过对tooldescription优化,观察效果

4、当以上方法都尝试之后,可以使用LLM对query进行扩充,让LLM分析该instruction可能会用到哪些tool,最后将LLM扩充后的instruction和原始instruction都作为query来召回,将结果拼接

总之,这一套下来,可以做的事情又变多了



53AI,企业落地应用大模型首选服务商

产品:大模型应用平台+智能体定制开发+落地咨询服务

承诺:先做场景POC验证,看到效果再签署服务协议。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

与创始人交个朋友

回到顶部

 
扫码咨询