微信扫码
与创始人交个朋友
我要投稿
重要: 阅读该文章之前,一定要先阅读: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
后,我们就可以去加载对应的tool
进agent
了。
因为实际的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、当召回效果还是不好时,我们可以通过对tool
的description
优化,观察效果
4、当以上方法都尝试之后,可以使用LLM对query
进行扩充,让LLM分析该instruction
可能会用到哪些tool
,最后将LLM扩充后的instruction
和原始instruction
都作为query
来召回,将结果拼接
总之,这一套下来,可以做的事情又变多了
53AI,企业落地应用大模型首选服务商
产品:大模型应用平台+智能体定制开发+落地咨询服务
承诺:先做场景POC验证,看到效果再签署服务协议。零风险落地应用大模型,已交付160+中大型企业
2024-03-30
2024-04-26
2024-04-12
2024-05-10
2024-05-14
2024-05-28
2024-07-18
2024-04-25
2024-05-22
2024-04-26
2024-12-04
2024-12-03
2024-12-02
2024-12-01
2024-12-01
2024-12-01
2024-11-30
2024-11-29