构建LangChain应用程序的示例代码:17、使用Plug-and-Plai自定义代理与插件检索教程

自定义代理与插件检索使用Plug-and-Plai

设置环境

进行必要的导入等。

import re
from typing import Union

import plugnplai
from langchain.agents import (
    AgentExecutor,
    AgentOutputParser,
    LLMSingleActionAgent,
)
from langchain.chains import LLMChain
from langchain.prompts import StringPromptTemplate
from langchain_community.agent_toolkits import NLAToolkit
from langchain_community.tools.plugin import AIPlugin
from langchain_core.agents import AgentAction, AgentFinish
from langchain_openai import OpenAI

设置LLM

llm = OpenAI(temperature=0)

设置插件

加载并索引插件。

# 从plugnplai.com获取所有插件
urls = plugnplai.get_plugins()

# 仅获取ChatGPT验证的插件
urls = plugnplai.get_plugins(filter="ChatGPT")

# 仅获取经过测试的插件(进行中)
urls = plugnplai.get_plugins(filter="working")

AI_PLUGINS = [AIPlugin.from_url(url + "/.well-known/ai-plugin.json") for url in urls]

工具检索器

我们将使用向量存储为每个工具描述创建嵌入。然后,对于传入的查询,我们可以创建查询的嵌入并执行相似性搜索以找到相关工具。

from langchain_community.vectorstores import FAISS
from langchain_core.documents import Document
from langchain_openai import OpenAIEmbeddings

embeddings = OpenAIEmbeddings()
docs = [
    Document(
        page_content=plugin.description_for_model,
        metadata={"plugin_name": plugin.name_for_model},
    )
    for plugin in AI_PLUGINS
]
vector_store = FAISS.from_documents(docs, embeddings)
toolkits_dict = {
    plugin.name_for_model: NLAToolkit.from_llm_and_ai_plugin(llm, plugin)
    for plugin in AI_PLUGINS
}

retriever = vector_store.as_retriever()

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

我们现在可以测试这个检索器,看看它是否有效。

tools = get_tools("今天我可以和我的小孩做什么")
[t.name for t in tools]

tools = get_tools("我可以买什么衬衫")
[t.name for t in tools]

提示模板

提示模板相当标准,因为我们实际上并没有改变提示模板中的逻辑,而是改变了检索的执行方式。

设置基础模板

template = """
尽你所能回答问题,但要像海盗那样说话。你可以使用以下工具:
{tools}

使用以下格式:

问题:你必须回答的输入问题
思考:你应该总是思考要做什么
动作:要采取的动作,应该是[{tool_names}]之一
动作输入:动作的输入
观察:动作的结果
...(这个思考/动作/动作输入/观察可以重复N次)
思考:我现在知道最终答案了
最终答案:原始输入问题的最终答案

开始!记住在给出最终答案时要像海盗一样说话。多用“Arg”
问题:{input}
{agent_scratchpad}
"""

自定义提示模板现在有了一个tools_getter的概念,我们在输入时调用它来选择要使用的工具
from typing import Callable

设置提示模板

class CustomPromptTemplate(StringPromptTemplate):
    # 使用的模板
    template: str
    ### 新增 ###
    # 可用工具的列表
    tools_getter: Callable
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()

设置LLM、停止序列和代理

与前一个笔记本相同。

llm = OpenAI(temperature=0)

LLM链由LLM和提示组成

llm_chain = LLMChain(llm=llm, prompt=prompt)
tool_names = [tool.name for tool in tools]
agent = LLMSingleActionAgent(
    llm_chain=llm_chain,
    output_parser=output_parser,
    stop=["\nObservation:"],
    allowed_tools=tool_names,
)

使用代理

现在我们可以使用它了!

agent_executor = AgentExecutor.from_agent_and_tools(
    agent=agent, tools=tools, verbose=True
)

agent_executor.run("我可以买什么衬衫")

总结

本文介绍了如何使用plugnplai库构建一个自定义代理,该代理能够检索并利用AI插件来执行任务。通过设置环境、配置语言模型、加载插件、创建工具检索器、定义提示模板和输出解析器、设置代理以及测试检索器,我们能够构建一个强大的系统,它可以动态地选择并使用最合适的工具来响应查询。这种结合了自定义代理和插件检索的方法,为开发智能自动化工具提供了一个灵活而强大的框架。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hugo_Hoo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值