创建组件¶
最小组件¶
组件可用于实现各种功能,例如向 prompt 提供消息、执行代码或与外部服务交互。
Component 是一个继承自 AgentComponent
类或实现一个或多个 protocols 的类。每个 protocol 都继承自 AgentComponent
,因此一旦你继承任何 protocol,你的类就会自动成为一个 component。
class MyComponent(AgentComponent):
pass
这已经是一个有效的组件了,但它还没有任何功能。要为其添加一些功能,你需要实现一个或多个 protocols。
让我们创建一个简单的组件,该组件会向 agent 的 prompt 添加“Hello World!”消息。为此,我们需要在组件中实现 MessageProvider
protocol。MessageProvider
是一个带有 get_messages
方法的接口
# No longer need to inherit AgentComponent, because MessageProvider already does it
class HelloComponent(MessageProvider):
def get_messages(self) -> Iterator[ChatMessage]:
yield ChatMessage.user("Hello World!")
现在我们可以将我们的组件添加到现有 agent 中,或者创建一个新的 Agent 类并将其添加进去
class MyAgent(Agent):
self.hello_component = HelloComponent()
agent 在每次需要构建新的 prompt 时都会调用 get_messages
,并且相应的 yield 的消息将被添加。
在组件之间传递数据¶
由于组件是常规类,你可以通过 __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
属性。使用配置可以从文件加载配置,并且方便地序列化和反序列化配置供任何 agent 使用。要了解有关配置的更多信息,包括存储敏感信息和序列化,请参阅组件配置。
# Example component configuration
class UserGreeterConfiguration(BaseModel):
user_name: str
class UserGreeterComponent(MessageProvider, ConfigurableComponent[UserGreeterConfiguration]):
def __init__(self):
# Creating configuration instance
# You could also pass it to the component constructor
# e.g. `def __init__(self, config: UserGreeterConfiguration):`
config = UserGreeterConfiguration(user_name="World")
# Passing the configuration instance to the parent class
UserGreeterComponent.__init__(self, config)
# This has the same effect as the line above:
# self.config = UserGreeterConfiguration(user_name="World")
def get_messages(self) -> Iterator[ChatMessage]:
# You can use the configuration like a regular model
yield ChatMessage.system(f"Hello, {self.config.user_name}!")
提供命令¶
要扩展 agent 的能力,你需要使用 CommandProvider
protocol 提供命令。例如,要允许 agent 乘以两个数字,你可以创建一个如下所示的组件
class MultiplicatorComponent(CommandProvider):
def get_commands(self) -> Iterator[Command]:
# Yield the command so the agent can use it
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:
"""
Multiplies two numbers.
Args:
a: First number
b: Second number
Returns:
Result of multiplication
"""
return str(a * b)
要了解有关命令的更多信息,请参阅 🛠️ 命令。
Prompt 结构¶
组件提供了所有必需的数据后,agent 需要构建将发送到 llm 的最终 prompt。目前,PromptStrategy
(不是 protocol)负责构建最终 prompt。
如果你想改变 prompt 的构建方式,你需要创建一个新的 PromptStrategy
类,然后在你的 agent 类中调用相关方法。你可以查看 AutoGPT Agent 使用的默认策略:OneShotAgentPromptStrategy,以及它在 Agent 中的使用方式(搜索 self.prompt_strategy
)。
UserInteractionComponent
示例¶
让我们创建一个内置 agent 使用的组件的简化版本。它让 agent 能够在终端中向用户请求输入。
-
为该组件创建一个继承自
CommandProvider
的类。class MyUserInteractionComponent(CommandProvider): """Provides commands to interact with the user.""" pass
-
实现一个命令方法,该方法将向用户请求输入并返回它。
def ask_user(self, question: str) -> str: """If you need more details or information regarding the given goals, you can ask the user for input.""" print(f"\nQ: {question}") resp = input("A:") return f"The user's answer: '{resp}'"
-
该命令需要用
@command
装饰器进行装饰。@command( parameters={ "question": JSONSchema( type=JSONSchema.Type.STRING, description="The question or prompt to the user", required=True, ) }, ) def ask_user(self, question: str) -> str: """If you need more details or information regarding the given goals, you can ask the user for input.""" print(f"\nQ: {question}") resp = input("A:") return f"The user's answer: '{resp}'"
-
我们需要实现
CommandProvider
的get_commands
方法来 yield 命令。def get_commands(self) -> Iterator[Command]: yield self.ask_user
-
由于 agent 并非总是在终端或交互模式下运行,因此在无法请求用户输入时,我们需要通过设置
self._enabled=False
来禁用此组件。def __init__(self, interactive_mode: bool): self.config = config self._enabled = interactive_mode
最终的组件应如下所示
# 1.
class MyUserInteractionComponent(CommandProvider):
"""Provides commands to interact with the user."""
# We pass config to check if we're in noninteractive mode
def __init__(self, interactive_mode: bool):
self.config = config
# 5.
self._enabled = interactive_mode
# 4.
def get_commands(self) -> Iterator[Command]:
# Yielding the command so the agent can use it
# This won't be yielded if the component is disabled
yield self.ask_user
# 3.
@command(
# We need to provide a schema for ALL the command parameters
parameters={
"question": JSONSchema(
type=JSONSchema.Type.STRING,
description="The question or prompt to the user",
required=True,
)
},
)
# 2.
# Command name will be its method name and description will be its docstring
def ask_user(self, question: str) -> str:
"""If you need more details or information regarding the given goals,
you can ask the user for input."""
print(f"\nQ: {question}")
resp = input("A:")
return f"The user's answer: '{resp}'"
现在,如果我们想使用我们自己的用户交互方式而不是默认的,我们需要以某种方式移除默认的(如果我们的 agent 继承自 Agent
,则默认的会被继承),然后添加我们自己的。我们可以简单地在 __init__
方法中覆盖 user_interaction
class MyAgent(Agent):
def __init__(
self,
settings: AgentSettings,
llm_provider: MultiProvider,
file_storage: FileStorage,
app_config: Config,
):
# Call the parent constructor to bring in the default components
super().__init__(settings, llm_provider, file_storage, app_config)
# Disable the default user interaction component by overriding it
self.user_interaction = MyUserInteractionComponent()
或者,我们可以通过将其设置为 None
来禁用默认组件
class MyAgent(Agent):
def __init__(
self,
settings: AgentSettings,
llm_provider: MultiProvider,
file_storage: FileStorage,
app_config: Config,
):
# Call the parent constructor to bring in the default components
super().__init__(settings, llm_provider, file_storage, app_config)
# Disable the default user interaction component
self.user_interaction = None
# Add our own component
self.my_user_interaction = MyUserInteractionComponent(app_config)
了解更多¶
查看更多示例的最佳位置是查看 classic/original_autogpt/components 和 classic/original_autogpt/commands 目录中的内置组件。
关于如何扩展内置 agent 并构建自己的 agent 的指南:🤖 Agents
某些组件的顺序很重要,请参阅 🧩 组件 了解有关组件以及如何自定义它们的更多信息。
要查看带有相应示例的内置 protocols,请访问 ⚙️ Protocols。