"""尝试按照arxiv.org/pdf/2205.00445.pdf中描述的方式实现MRKL系统。"""
from __future__ import annotations
from typing import Any, Callable, List, NamedTuple, Optional, Sequence
from langchain_core._api import deprecated
from langchain_core.callbacks import BaseCallbackManager
from langchain_core.language_models import BaseLanguageModel
from langchain_core.prompts import PromptTemplate
from langchain_core.pydantic_v1 import Field
from langchain_core.tools import BaseTool, Tool
from langchain.agents.agent import Agent, AgentExecutor, AgentOutputParser
from langchain.agents.agent_types import AgentType
from langchain.agents.mrkl.output_parser import MRKLOutputParser
from langchain.agents.mrkl.prompt import FORMAT_INSTRUCTIONS, PREFIX, SUFFIX
from langchain.agents.utils import validate_tools_single_input
from langchain.chains import LLMChain
from langchain.tools.render import render_text_description
[docs]class ChainConfig(NamedTuple):
"""MRKL系统中用于链配置。
参数:
action_name:操作的名称。
action:要调用的操作函数。
action_description:操作的描述。"""
action_name: str
action: Callable
action_description: str
[docs]@deprecated("0.1.0", alternative="create_react_agent", removal="0.3.0")
class ZeroShotAgent(Agent):
"""MRKL链的代理。"""
output_parser: AgentOutputParser = Field(default_factory=MRKLOutputParser)
@classmethod
def _get_default_output_parser(cls, **kwargs: Any) -> AgentOutputParser:
return MRKLOutputParser()
@property
def _agent_type(self) -> str:
"""返回代理类型的标识符。"""
return AgentType.ZERO_SHOT_REACT_DESCRIPTION
@property
def observation_prefix(self) -> str:
"""要附加到观测值前面的前缀。"""
return "Observation: "
@property
def llm_prefix(self) -> str:
"""在llm调用前附加的前缀。"""
return "Thought:"
[docs] @classmethod
def create_prompt(
cls,
tools: Sequence[BaseTool],
prefix: str = PREFIX,
suffix: str = SUFFIX,
format_instructions: str = FORMAT_INSTRUCTIONS,
input_variables: Optional[List[str]] = None,
) -> PromptTemplate:
"""创建与零shot代理风格相似的提示。
参数:
tools:代理将可以访问的工具列表,用于格式化提示。
prefix:工具列表之前要放置的字符串。
suffix:工具列表之后要放置的字符串。
input_variables:最终提示将期望的输入变量列表。
返回:
从这里的各个部分组装而成的PromptTemplate。
"""
tool_strings = render_text_description(list(tools))
tool_names = ", ".join([tool.name for tool in tools])
format_instructions = format_instructions.format(tool_names=tool_names)
template = "\n\n".join([prefix, tool_strings, format_instructions, suffix])
if input_variables:
return PromptTemplate(template=template, input_variables=input_variables)
return PromptTemplate.from_template(template)
@classmethod
def _validate_tools(cls, tools: Sequence[BaseTool]) -> None:
validate_tools_single_input(cls.__name__, tools)
if len(tools) == 0:
raise ValueError(
f"Got no tools for {cls.__name__}. At least one tool must be provided."
)
for tool in tools:
if tool.description is None:
raise ValueError(
f"Got a tool {tool.name} without a description. For this agent, "
f"a description must always be provided."
)
super()._validate_tools(tools)
[docs]@deprecated("0.1.0", removal="0.3.0")
class MRKLChain(AgentExecutor):
"""[已弃用] 实现MRKL系统的链。"""
[docs] @classmethod
def from_chains(
cls, llm: BaseLanguageModel, chains: List[ChainConfig], **kwargs: Any
) -> AgentExecutor:
"""用户友好的初始化MRKL链的方式。
这旨在是一个简单的方法来启动和运行MRKL链。
参数:
llm: 用作代理LLM的LLM。
chains: MRKL系统可以访问的链。
**kwargs: 传递给初始化的参数。
返回:
初始化的MRKL链。
"""
tools = [
Tool(
name=c.action_name,
func=c.action,
description=c.action_description,
)
for c in chains
]
agent = ZeroShotAgent.from_llm_and_tools(llm, tools)
return cls(agent=agent, tools=tools, **kwargs)