安装 plugnplai 库,从 https://plugplai.com 目录获取活动插件列表。
# 安装 plugnplai 包!pip install plugnplai -q
[notice] A new release of pip available: 22.3.1 -> 23.1.1 [notice] To update, run: pip install --upgrade pip Note: you may need to restart the kernel to use updated packages.
import re # 导入正则表达式模块from typing import Union # 导入Union类型import plugnplai # 导入plugnplai模块from langchain.agents import ( # 导入langchain.agents模块中的以下类 AgentExecutor, # AgentExecutor类 AgentOutputParser, # AgentOutputParser类 LLMSingleActionAgent, # LLMSingleActionAgent类)from langchain.chains import LLMChain # 导入LLMChain类from langchain.prompts import StringPromptTemplate # 导入StringPromptTemplate类from langchain_community.agent_toolkits import NLAToolkit # 导入NLAToolkit类from langchain_community.tools.plugin import AIPlugin # 导入AIPlugin类from langchain_core.agents import AgentAction, AgentFinish # 导入AgentAction和AgentFinish类from langchain_openai import OpenAI # 导入OpenAI类以上是给定的代码的翻译结果,已经在代码上方添加了注释。
# 导入OpenAI类from openai import OpenAI# 创建OpenAI对象并设置温度为0llm = OpenAI(temperature=0)
# 从plugnplai.com获取所有插件urls = plugnplai.get_plugins()# 获取ChatGPT插件 - 仅获取ChatGPT验证的插件urls = plugnplai.get_plugins(filter="ChatGPT")# 获取可用的插件 - 仅获取经过测试的插件(进行中)urls = plugnplai.get_plugins(filter="working")# 从urls中的每个url获取AI插件的信息并创建AIPlugin对象AI_PLUGINS = [AIPlugin.from_url(url + "/.well-known/ai-plugin.json") for url in urls]
# 导入所需的模块from langchain_community.vectorstores import FAISSfrom langchain_core.documents import Documentfrom langchain_openai import OpenAIEmbeddings
# 导入OpenAIEmbeddings模块embeddings = OpenAIEmbeddings()# 创建一个包含多个Document对象的列表docs = [ Document( page_content=plugin.description_for_model, metadata={"plugin_name": plugin.name_for_model}, ) for plugin in AI_PLUGINS]# 使用docs和embeddings创建一个vector_store对象vector_store = FAISS.from_documents(docs, embeddings)# 创建一个包含多个NLAToolkit对象的字典toolkits_dict = { plugin.name_for_model: NLAToolkit.from_llm_and_ai_plugin(llm, plugin) for plugin in AI_PLUGINS}
Attempting to load an OpenAPI 3.0.1 spec. This may result in degraded performance. Convert your OpenAPI spec to 3.1.* spec for better support. Attempting to load an OpenAPI 3.0.1 spec. This may result in degraded performance. Convert your OpenAPI spec to 3.1.* spec for better support. Attempting to load an OpenAPI 3.0.1 spec. This may result in degraded performance. Convert your OpenAPI spec to 3.1.* spec for better support. Attempting to load an OpenAPI 3.0.2 spec. This may result in degraded performance. Convert your OpenAPI spec to 3.1.* spec for better support. Attempting to load an OpenAPI 3.0.1 spec. This may result in degraded performance. Convert your OpenAPI spec to 3.1.* spec for better support. Attempting to load an OpenAPI 3.0.1 spec. This may result in degraded performance. Convert your OpenAPI spec to 3.1.* spec for better support. Attempting to load an OpenAPI 3.0.1 spec. This may result in degraded performance. Convert your OpenAPI spec to 3.1.* spec for better support. Attempting to load an OpenAPI 3.0.1 spec. This may result in degraded performance. Convert your OpenAPI spec to 3.1.* spec for better support. Attempting to load a Swagger 2.0 spec. This may result in degraded performance. Convert your OpenAPI spec to 3.1.* spec for better support.
retriever = vector_store.as_retriever() # 将vector_store转换为检索器def get_tools(query): # 获取包含要使用的插件的文档 docs = retriever.invoke(query) # 获取每个插件的工具包 tool_kits = [toolkits_dict[d.metadata["plugin_name"]] for d in docs] # 获取每个端点的单独NLAChain工具 tools = [] for tk in tool_kits: tools.extend(tk.nla_tools) return tools # 返回工具列表
我们现在可以测试这个检索器,看看它是否能正常工作。
# 导入get_tools函数from some_module import get_tools# 调用get_tools函数,并传入"What could I do today with my kiddo"作为参数tools = get_tools("What could I do today with my kiddo")# 使用列表推导式,获取tools列表中每个元素的name属性,并将结果存储在新的列表中[name for t in tools]
['Milo.askMilo', 'Zapier_Natural_Language_Actions_(NLA)_API_(Dynamic)_-_Beta.search_all_actions', 'Zapier_Natural_Language_Actions_(NLA)_API_(Dynamic)_-_Beta.preview_a_zap', 'Zapier_Natural_Language_Actions_(NLA)_API_(Dynamic)_-_Beta.get_configuration_link', 'Zapier_Natural_Language_Actions_(NLA)_API_(Dynamic)_-_Beta.list_exposed_actions', 'SchoolDigger_API_V2.0.Autocomplete_GetSchools', 'SchoolDigger_API_V2.0.Districts_GetAllDistricts2', 'SchoolDigger_API_V2.0.Districts_GetDistrict2', 'SchoolDigger_API_V2.0.Rankings_GetSchoolRank2', 'SchoolDigger_API_V2.0.Rankings_GetRank_District', 'SchoolDigger_API_V2.0.Schools_GetAllSchools20', 'SchoolDigger_API_V2.0.Schools_GetSchool20', 'Speak.translate', 'Speak.explainPhrase', 'Speak.explainTask']
# 获取工具函数,参数为用户输入的问题tools = get_tools("我可以买什么样的衬衫?")# 打印工具列表中每个工具的名称[t.name for t in tools]
['Open_AI_Klarna_product_Api.productsUsingGET', 'Milo.askMilo', 'Zapier_Natural_Language_Actions_(NLA)_API_(Dynamic)_-_Beta.search_all_actions', 'Zapier_Natural_Language_Actions_(NLA)_API_(Dynamic)_-_Beta.preview_a_zap', 'Zapier_Natural_Language_Actions_(NLA)_API_(Dynamic)_-_Beta.get_configuration_link', 'Zapier_Natural_Language_Actions_(NLA)_API_(Dynamic)_-_Beta.list_exposed_actions', 'SchoolDigger_API_V2.0.Autocomplete_GetSchools', 'SchoolDigger_API_V2.0.Districts_GetAllDistricts2', 'SchoolDigger_API_V2.0.Districts_GetDistrict2', 'SchoolDigger_API_V2.0.Rankings_GetSchoolRank2', 'SchoolDigger_API_V2.0.Rankings_GetRank_District', 'SchoolDigger_API_V2.0.Schools_GetAllSchools20', 'SchoolDigger_API_V2.0.Schools_GetSchool20']
# 设置基本模板template = """以海盗的口吻回答以下问题,尽力而为。你可以使用以下工具:{tools}使用以下格式:问题:你必须回答的输入问题思考:你应该始终考虑该做什么行动:要采取的行动,应该是[{tool_names}]中的一个行动输入:行动的
自定义提示模板现在具有一个名为tools_getter的概念,我们在输入上调用它来选择要使用的工具。
从typing模块导入Callable# 设置一个提示模板class CustomPromptTemplate(StringPromptTemplate): # 要使用的模板 template: str ############## 新增 ###################### # 可用工具的列表 tools_getter: Callable def format(self, **kwargs) -> str: # 获取中间步骤(AgentAction,Observation元组) # 以特定方式格式化它们 intermediate_steps = kwargs.pop("intermediate_steps") thoughts = "" for action, observation in intermediate_steps: thoughts += action.log thoughts += f"\nObservation: {observation}\nThought: " # 将agent_scratchpad变量设置为该值 kwargs["agent_scratchpad"] = thoughts ############## 新增 ###################### tools = self.tools_getter(kwargs["input"]) # 从提供的工具列表创建一个tools变量 kwargs["tools"] = "\n".join( [f"{tool.name}: {tool.description}" for tool in tools] ) # 为提供的工具创建一个工具名称列表 kwargs["tool_names"] = ", ".join([tool.name for tool in tools]) return self.template.format(**kwargs)
prompt = CustomPromptTemplate( template=template, tools_getter=get_tools, # 这里省略了`agent_scratchpad`、`tools`和`tool_names`变量,因为它们是动态生成的 # 这里包括`intermediate_steps`变量,因为它是必需的 input_variables=["input", "intermediate_steps"],)
class CustomOutputParser(AgentOutputParser): def parse(self, llm_output: str) -> Union[AgentAction, AgentFinish]: # 检查代理是否应该完成 if "Final Answer:" in llm_output: return AgentFinish( # 返回值通常始终是一个带有单个 `output` 键的字典 # 目前不建议尝试其他操作 :) return_values={"output": llm_output.split("Final Answer:")[-1].strip()}, log=llm_output, ) # 解析动作和动作输入 regex = r"Action\s*\d*\s*:(.*?)\nAction\s*\d*\s*Input\s*\d*\s*:[\s]*(.*)" match = re.search(regex, llm_output, re.DOTALL) if not match: raise ValueError(f"无法解析LLM输出:`{llm_output}`") action = match.group(1).strip() action_input = match.group(2) # 返回动作和动作输入 return AgentAction( tool=action, tool_input=action_input.strip(" ").strip('"'), log=llm_output )
# 创建一个名为output_parser的对象,类型为CustomOutputParser()output_parser = CustomOutputParser()
# 创建一个OpenAI对象,设置温度参数为0llm = OpenAI(temperature=0)
# 创建一个LLM链,包括LLM模型和一个提示llm_chain = LLMChain(llm=llm, prompt=prompt)
# 创建一个列表,包含了所有工具的名称tool_names = [tool.name for tool in tools]# 创建一个LLMSingleActionAgent对象# 参数:# llm_chain: LLM链# output_parser: 输出解析器# stop: 停止标志,当遇到"\nObservation:"时停止# allowed_tools: 允许使用的工具名称列表agent = LLMSingleActionAgent( llm_chain=llm_chain, output_parser=output_parser, stop=["\nObservation:"], allowed_tools=tool_names,)
# 导入AgentExecutor类from rasa.core.agent import AgentExecutor# 创建AgentExecutor对象,并传入agent和tools参数,verbose设置为Trueagent_executor = AgentExecutor.from_agent_and_tools( agent=agent, tools=tools, verbose=True)
# 导入所需的库import agent_executor# 调用agent_executor的run函数,并传入参数"what shirts can i buy?"agent_executor.run("what shirts can i buy?")
> Entering new AgentExecutor chain... Thought: I need to find a product API Action: Open_AI_Klarna_product_Api.productsUsingGET Action Input: shirts Observation:I found 10 shirts from the API response. They range in price from $9.99 to $450.00 and come in a variety of materials, colors, and patterns. I now know what shirts I can buy Final Answer: Arg, I found 10 shirts from the API response. They range in price from $9.99 to $450.00 and come in a variety of materials, colors, and patterns. > Finished chain.
'Arg, I found 10 shirts from the API response. They range in price from $9.99 to $450.00 and come in a variety of materials, colors, and patterns.'