Skip to content

创建组件

最小组件

组件可用于实现各种功能,例如向提示提供消息、执行代码或与外部服务交互。

组件*是一个继承自 AgentComponent 或实现一个或多个*协议*的类。每个*协议*都继承自 AgentComponent,因此一旦你的类继承了任何*协议,它就会自动成为一个*组件*。

class MyComponent(AgentComponent):
    pass

这已经是一个有效的组件,但它还没有做任何事情。要为其添加一些功能,你需要实现一个或多个*协议*。

让我们创建一个简单的组件,向代理的提示中添加“Hello World!”消息。为此,我们需要在我们的组件中实现 MessageProvider 协议MessageProvider 是一个带有 get_messages 方法的接口:

# 不再需要继承 AgentComponent,因为 MessageProvider 已经继承了它
class HelloComponent(MessageProvider):
    def get_messages(self) -> Iterator[ChatMessage]:
        yield ChatMessage.user("Hello World!")

现在我们可以将我们的组件添加到现有代理中,或者创建一个新的 Agent 类并在其中添加它:

class MyAgent(Agent):
    self.hello_component = HelloComponent()

每次代理需要构建新提示时,都会调用 get_messages,生成的消息将相应地添加。

传递数据给组件和在组件之间传递数据

由于组件是常规类,你可以通过 __init__ 方法将数据(包括其他组件)传递给它们。例如,我们可以传递一个配置对象,然后在需要时从中检索 API 密钥:

class DataComponent(MessageProvider):
    def __init__(self, config: Config):
        self.config = config

    def get_messages(self) -> Iterator[ChatMessage]:
        if self.config.openai_credentials.api_key:
            yield ChatMessage.system("API key found!")
        else:
            yield ChatMessage.system("API key not found!")

注意

尚未实现组件特定的配置处理。

配置组件

可以使用 pydantic 模型配置组件。 要使组件可配置,它必须继承自 ConfigurableComponent[BM],其中 BM 是继承自 pydantic 的 BaseModel 的配置类。你应该将配置实例传递给 ConfigurableComponent__init__ 或直接设置其 config 属性。使用配置允许你从文件加载配置,并且还可以轻松地序列化和反序列化任何代理的配置。要了解更多关于配置的信息,包括存储敏感信息和序列化,请参阅 组件配置

# 示例组件配置
class UserGreeterConfiguration(BaseModel):
    user_name: str

class UserGreeterComponent(MessageProvider, ConfigurableComponent[UserGreeterConfiguration]):
    def __init__(self):
        # 创建配置实例
        # 你也可以将其传递给组件构造函数
        # 例如 `def __init__(self, config: UserGreeterConfiguration):`
        config = UserGreeterConfiguration(user_name="World")
        # 将配置实例传递给父类
        UserGreeterComponent.__init__(self, config)
        # 这与上面的行效果相同:
        # self.config = UserGreeterConfiguration(user_name="World")

    def get_messages(self) -> Iterator[ChatMessage]:
        # 你可以像使用常规模型一样使用配置
        yield ChatMessage.system(f"Hello, {self.config.user_name}!")

提供命令

要扩展代理的功能,你需要使用 CommandProvider 协议提供命令。例如,要允许代理将两个数字相乘,你可以创建一个这样的组件:

class MultiplicatorComponent(CommandProvider):
    def get_commands(self) -> Iterator[Command]:
        # 生成命令以便代理可以使用它
        yield self.multiply

    @command(
    parameters={
        "a": JSONSchema(
            type=JSONSchema.Type.INTEGER,
            description="The first number",
            required=True,
        ),
        "b": JSONSchema(
            type=JSONSchema.Type.INTEGER,
            description="The second number",
            required=True,
        )})
    def multiply(self, a: int, b: int) -> str:
        """
        将两个数字相乘。

        参数:
            a: 第一个数字
            b: 第二个数字

        返回:
            乘法结果
        """
        return str(a * b)

要了解更多关于命令的信息,请参阅 🛠️ 命令

提示结构

在组件提供所有必要数据后,代理需要构建最终的提示,该提示将被发送到 llm。 目前,PromptStrategy(*不是*协议)负责构建最终提示。 如果你想改变提示的构建方式,你需要创建一个新的 PromptStrategy 类,然后在你的代理类中调用相关方法。 你可以查看 AutoGPT Agent 使用的默认策略:OneShotAgentPromptStrategy,以及它在 Agent 中的使用方式(搜索 self.prompt_strategy)。

示例 UserInteractionComponent

让我们创建一个稍微简化版本的组件,该组件由内置代理使用。 它赋予代理在终端中向用户请求输入的能力。

  1. 创建一个继承自 CommandProvider 的组件类。

    class MyUserInteractionComponent(CommandProvider):
        """提供与用户交互的命令。"""
        pass
    
  2. 实现命令方法,该方法将向用户请求输入并返回结果。

    def ask_user(self, question: str) -> str:
        """如果你需要更多关于给定目标的详细信息或信息,
        你可以向用户请求输入。"""
        print(f"\nQ: {question}")
        resp = input("A:")
        return f"用户的回答: '{resp}'"
    
  3. 需要使用 @command 装饰命令。

    @command(
        parameters={
            "question": JSONSchema(
                type=JSONSchema.Type.STRING,
                description="向用户提出的问题或提示",
                required=True,
            )
        },
    )
    def ask_user(self, question: str) -> str:
        """如果你需要更多关于给定目标的详细信息或信息,
        你可以向用户请求输入。"""
        print(f"\nQ: {question}")
        resp = input("A:")
        return f"用户的回答: '{resp}'"
    
  4. 我们需要实现 CommandProviderget_commands 方法来生成命令。

    def get_commands(self) -> Iterator[Command]:
        yield self.ask_user
    
  5. 由于代理并不总是在终端或交互模式下运行,我们需要在无法请求用户输入时通过设置 self._enabled=False 来禁用此组件。

    def __init__(self, interactive_mode: bool):
        self.config = config
        self._enabled = interactive_mode
    

最终的组件应如下所示:

# 1.
class MyUserInteractionComponent(CommandProvider):
    """提供与用户交互的命令。"""

    # 我们传递配置以检查是否处于非交互模式
    def __init__(self, interactive_mode: bool):
        self.config = config
        # 5.
        self._enabled = interactive_mode

    # 4.
    def get_commands(self) -> Iterator[Command]:
        # 生成命令以便代理可以使用
        # 如果组件被禁用,则不会生成
        yield self.ask_user

    # 3.
    @command(
        # 我们需要为所有命令参数提供一个模式
        parameters={
            "question": JSONSchema(
                type=JSONSchema.Type.STRING,
                description="向用户提出的问题或提示",
                required=True,
            )
        },
    )
    # 2.
    # 命令名称将是其方法名称,描述将是其文档字符串
    def ask_user(self, question: str) -> str:
        """如果你需要更多关于给定目标的详细信息或信息,
        你可以向用户请求输入。"""
        print(f"\nQ: {question}")
        resp = input("A:")
        return f"用户的回答: '{resp}'"

现在,如果我们想使用我们的用户交互组件 代替 默认的组件,我们需要以某种方式移除默认的组件(如果我们的代理继承自 Agent,则默认组件被继承)并添加我们自己的。我们可以简单地在 __init__ 方法中覆盖 user_interaction

class MyAgent(Agent):
    def __init__(
        self,
        settings: AgentSettings,
        llm_provider: MultiProvider,
        file_storage: FileStorage,
        app_config: Config,
    ):
        # 调用父构造函数以引入默认组件
        super().__init__(settings, llm_provider, file_storage, app_config)
        # 通过覆盖来禁用默认的用户交互组件
        self.user_interaction = MyUserInteractionComponent()

或者我们可以通过将其设置为 None 来禁用默认组件:

class MyAgent(Agent):
    def __init__(
        self,
        settings: AgentSettings,
        llm_provider: MultiProvider,
        file_storage: FileStorage,
        app_config: Config,
    ):
        # 调用父类构造函数以引入默认组件
        super().__init__(settings, llm_provider, file_storage, app_config)
        # 禁用默认的用户交互组件
        self.user_interaction = None
        # 添加我们自己的组件
        self.my_user_interaction = MyUserInteractionComponent(app_config)

了解更多

查看更多示例的最佳地点是浏览 classic/original_autogpt/componentsclassic/original_autogpt/commands 目录中的内置组件。

关于如何扩展内置代理并构建自己的指南:🤖 代理
某些组件的顺序很重要,请参阅 🧩 Components 以了解更多关于组件及其自定义方式的信息。
要查看内置协议及其示例,请访问 ⚙️ Protocols