简介
在本案例中,我们将展示如何创建一个可用于文本摘要的自定义智能体。
安装
通过下述命令安装需要的依赖包
pip install "dbgpt[agent]>=0.5.9rc1" -U
pip install openai
创建自定义智能体
初始化智能体
绝大多数情况下,你只需要继承基础Agent并重写相应的方法即可。
from dbgpt.agent import ConversableAgent
class MySummarizerAgent(ConversableAgent):
def __init__(self, **kwargs):
super().__init__(**kwargs)
定义Profile
在设计每个智能体之前,需要定义它的角色、身份和功能角色。具体定义如下
from dbgpt.agent import ConversableAgent, ProfileConfig
class MySummarizerAgent(ConversableAgent):
profile: ProfileConfig = ProfileConfig(
# The name of the agent
name="Aristotle",
# The role of the agent
role="Summarizer",
# The core functional goals of the agent tell LLM what it can do with it.
goal=(
"Summarize answer summaries based on user questions from provided "
"resource information or from historical conversation memories."
),
# Introduction and description of the agent, used for task assignment and display.
# If it is empty, the goal content will be used.
desc=(
"You can summarize provided text content according to user's questions"
" and output the summarization."
),
)
def __init__(self, **kwargs):
super().__init__(**kwargs)
提供Prompt约束
智能体的Prompt默认使用固定的模版组装(如有特殊需求,可绑定外部模版)。其中主要包括
- 角色认定(自动生成)
- 资源信息(自动生成)
- 约束逻辑
- 参考案例
- 输出格式模版和限制
所以我们定义的智能体提示词如下:
from dbgpt.agent import ConversableAgent, ProfileConfig
class MySummarizerAgent(ConversableAgent):
profile: ProfileConfig = ProfileConfig(
# The name of the agent
name="Aristotle",
# The role of the agent
role="Summarizer",
# The core functional goals of the agent tell LLM what it can do with it.
goal=(
"Summarize answer summaries based on user questions from provided "
"resource information or from historical conversation memories."
),
# Introduction and description of the agent, used for task assignment and display.
# If it is empty, the goal content will be used.
desc=(
"You can summarize provided text content according to user's questions"
" and output the summarization."
),
# Refer to the following. It can contain multiple constraints and reasoning
# restriction logic, and supports the use of parameter template {{ param_name }}.
constraints=[
"Prioritize the summary of answers to user questions from the improved resource"
" text. If no relevant information is found, summarize it from the historical "
"dialogue memory given. It is forbidden to make up your own.",
"You need to first detect user's question that you need to answer with your"
" summarization.",
"Extract the provided text content used for summarization.",
"Then you need to summarize the extracted text content.",
"Output the content of summarization ONLY related to user's question. The "
"output language must be the same to user's question language.",
"If you think the provided text content is not related to user questions at "
"all, ONLY output '{{ not_related_message }}'!!.",
]
)
def __init__(self, **kwargs):
super().__init__(**kwargs)
Prompt模版格式
如果提示中使用了动态参数,则需要实际的对话过程来组装这些值,需要重载并实现以下接口(_init_reply_message
)
from dbgpt.agent import AgentMessage, ConversableAgent, ProfileConfig
NOT_RELATED_MESSAGE = "Did not find the information you want."
class MySummarizerAgent(ConversableAgent):
profile: ProfileConfig = ProfileConfig(
# The name of the agent
name="Aristotle",
# The role of the agent
role="Summarizer",
# The core functional goals of the agent tell LLM what it can do with it.
goal=(
"Summarize answer summaries based on user questions from provided "
"resource information or from historical conversation memories."
),
# Introduction and description of the agent, used for task assignment and display.
# If it is empty, the goal content will be used.
desc=(
"You can summarize provided text content according to user's questions"
" and output the summarization."
),
# Refer to the following. It can contain multiple constraints and reasoning
# restriction logic, and supports the use of parameter template {{ param_name }}.
constraints=[
"Prioritize the summary of answers to user questions from the improved resource"
" text. If no relevant information is found, summarize it from the historical "
"dialogue memory given. It is forbidden to make up your own.",
"You need to first detect user's question that you need to answer with your"
" summarization.",
"Extract the provided text content used for summarization.",
"Then you need to summarize the extracted text content.",
"Output the content of summarization ONLY related to user's question. The "
"output language must be the same to user's question language.",
"If you think the provided text content is not related to user questions at "
"all, ONLY output '{{ not_related_message }}'!!.",
],
)
def __init__(self, **kwargs):
super().__init__(**kwargs)
def _init_reply_message(self, received_message: AgentMessage) -> AgentMessage:
reply_message = super()._init_reply_message(received_message)
# Fill in the dynamic parameters in the prompt template
reply_message.context = {"not_related_message": NOT_RELATED_MESSAGE}
return reply_message
资源预加载(可选)
如果有一些特定的资源,则必须在智能体初始化时提前加载绑定的资源。可以参考下面的实现。根据资源的实际情况确定。在大多数情况下,是没有必要的。
from dbgpt.agent import ConversableAgent, AgentMessage
class MySummarizerAgent(ConversableAgent):
# ... other code
async def preload_resource(self) -> None:
# Load the required resources
for resource in self.resources:
# Load your resource, please write your own code here
pass
结果检查
如果动作执行结果需要严格验证与校验,有两种模式: 代码逻辑验证和LLM验证。当然,验证不是必须的,也没有默认实现。如下使用LLM的例子
from typing import Tuple, Optional
from dbgpt.agent import ConversableAgent, AgentMessage
from dbgpt.core import ModelMessageRoleType
CHECK_RESULT_SYSTEM_MESSAGE = (
"You are an expert in analyzing the results of a summary task."
"Your responsibility is to check whether the summary results can summarize the "
"input provided by the user, and then make a judgment. You need to answer "
"according to the following rules:\n"
" Rule 1: If you think the summary results can summarize the input provided"
" by the user, only return True.\n"
" Rule 2: If you think the summary results can NOT summarize the input "
"provided by the user, return False and the reason, split by | and ended "
"by TERMINATE. For instance: False|Some important concepts in the input are "
"not summarized. TERMINATE"
)
class MySummarizerAgent(ConversableAgent):
# ... other code
async def correctness_check(
self, message: AgentMessage
) -> Tuple[bool, Optional[str]]:
current_goal = message.current_goal
action_report = message.action_report
task_result = ""
if action_report:
task_result = action_report.get("content", "")
check_result, model = await self.thinking(
messages=[
AgentMessage(
role=ModelMessageRoleType.HUMAN,
content=(
"Please understand the following user input and summary results"
" and give your judgment:\n"
f"User Input: {current_goal}\n"
f"Summary Results: {task_result}"
),
)
],
prompt=CHECK_RESULT_SYSTEM_MESSAGE,
)
fail_reason = ""
if check_result and (
"true" in check_result.lower() or "yes" in check_result.lower()
):
success = True
else:
success = False
try:
_, fail_reason = check_result.split("|")
fail_reason = (
"The summary results cannot summarize the user input due"
f" to: {fail_reason}. Please re-understand and complete the summary"
" task."
)
except Exception:
fail_reason = (
"The summary results cannot summarize the user input. "
"Please re-understand and complete the summary task."
)
return success, fail_reason
创建自定义Action
初始化Action
所有的智能体操作外部环境或者跟真实世界交互都是通过行动(Action
)。Action定义了Agent的输出内容结构,并实际执行相应的操作。具体Action实现继承Action基类,如下
from typing import Optional
from pydantic import BaseModel, Field
from dbgpt.vis import Vis
from dbgpt.agent import Action, ActionOutput, AgentResource, ResourceType
from dbgpt.agent.util import cmp_string_equal
NOT_RELATED_MESSAGE = "Did not find the information you want."
# The parameter object that the Action that the current Agent needs to execute needs to output.
class SummaryActionInput(BaseModel):
summary: str = Field(
...,
description="The summary content",
)
class SummaryAction(Action[SummaryActionInput]):
def __init__(self):
super().__init__()
@property
def resource_need(self) -> Optional[ResourceType]:
# The resource type that the current Agent needs to use
# here we do not need to use resources, just return None
return None
@property
def render_protocol(self) -> Optional[Vis]:
# The visualization rendering protocol that the current Agent needs to use
# here we do not need to use visualization rendering, just return None
return None
@property
def out_model_type(self):
return SummaryActionInput
async def run(
self,
ai_message: str,
resource: Optional[AgentResource] = None,
rely_action_out: Optional[ActionOutput] = None,
need_vis_render: bool = True,
**kwargs,
) -> ActionOutput:
"""Perform the action.
The entry point for actual execution of Action. Action execution will be
automatically initiated after model inference.
"""
try:
# Parse the input message
param: SummaryActionInput = self._input_convert(ai_message, SummaryActionInput)
except Exception:
return ActionOutput(
is_exe_success=False,
content="The requested correctly structured answer could not be found, "
f"ai message: {ai_message}",
)
# Check if the summary content is not related to user questions
if param.summary and cmp_string_equal(
param.summary,
NOT_RELATED_MESSAGE,
ignore_case=True,
ignore_punctuation=True,
ignore_whitespace=True,
):
return ActionOutput(
is_exe_success=False,
content="the provided text content is not related to user questions at all."
f"ai message: {ai_message}",
)
else:
return ActionOutput(
is_exe_success=True,
content=param.summary,
)
绑定Action到智能体
在开发并且定义好Agent和Action之后,将Action绑定到对应的智能体
from pydantic import BaseModel
from dbgpt.agent import Action,ConversableAgent
class SummaryActionInput(BaseModel):
...
class SummaryAction(Action[SummaryActionInput]):
...
class MySummarizerAgent(ConversableAgent):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._init_actions([SummaryAction])
Action扩展参数处理
from typing import Optional, Dict, Any
from pydantic import BaseModel
from dbgpt.agent import Action, ActionOutput, AgentResource, ConversableAgent
class SummaryActionInput(BaseModel):
...
class SummaryAction(Action[SummaryActionInput]):
...
async def run(
self,
ai_message: str,
resource: Optional[AgentResource] = None,
rely_action_out: Optional[ActionOutput] = None,
need_vis_render: bool = True,
**kwargs,
) -> ActionOutput:
# Read the extended parameters passed in by the agent
extra_param = kwargs.get("action_extra_param_key", None)
pass
class MySummarizerAgent(ConversableAgent):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._init_actions([SummaryAction])
def prepare_act_param(self) -> Dict[str, Any]:
return {"action_extra_param_key": "this is extra param"}
使用自定义智能体
自定义智能体创建好之后,可以通过下面的方式使用对应的智能体。
import asyncio
from dbgpt.agent import AgentContext, ConversableAgent, AgentMemory, LLMConfig, UserProxyAgent
from dbgpt.model.proxy import OpenAILLMClient
class MySummarizerAgent(ConversableAgent):
...
async def main():
llm_client = OpenAILLMClient(model_alias="gpt-3.5-turbo")
context: AgentContext = AgentContext(conv_id="summarize")
agent_memory: AgentMemory = AgentMemory()
summarizer = (
await MySummarizerAgent()
.bind(context)
.bind(LLMConfig(llm_client=llm_client))
.bind(agent_memory)
.build()
)
user_proxy = await UserProxyAgent().bind(agent_memory).bind(context).build()
await user_proxy.initiate_chat(
recipient=summarizer,
reviewer=user_proxy,
message="""I want to summarize advantages of Nuclear Power according to the following content.
Nuclear power in space is the use of nuclear power in outer space, typically either small fission systems or radioactive decay for electricity or heat. Another use is for scientific observation, as in a Mössbauer spectrometer. The most common type is a radioisotope thermoelectric generator, which has been used on many space probes and on crewed lunar missions. Small fission reactors for Earth observation satellites, such as the TOPAZ nuclear reactor, have also been flown.[1] A radioisotope heater unit is powered by radioactive decay and can keep components from becoming too cold to function, potentially over a span of decades.[2]
The United States tested the SNAP-10A nuclear reactor in space for 43 days in 1965,[3] with the next test of a nuclear reactor power system intended for space use occurring on 13 September 2012 with the Demonstration Using Flattop Fission (DUFF) test of the Kilopower reactor.[4]
After a ground-based test of the experimental 1965 Romashka reactor, which used uranium and direct thermoelectric conversion to electricity,[5] the USSR sent about 40 nuclear-electric satellites into space, mostly powered by the BES-5 reactor. The more powerful TOPAZ-II reactor produced 10 kilowatts of electricity.[3]
Examples of concepts that use nuclear power for space propulsion systems include the nuclear electric rocket (nuclear powered ion thruster(s)), the radioisotope rocket, and radioisotope electric propulsion (REP).[6] One of the more explored concepts is the nuclear thermal rocket, which was ground tested in the NERVA program. Nuclear pulse propulsion was the subject of Project Orion.[7]
Regulation and hazard prevention[edit]
After the ban of nuclear weapons in space by the Outer Space Treaty in 1967, nuclear power has been discussed at least since 1972 as a sensitive issue by states.[8] Particularly its potential hazards to Earth's environment and thus also humans has prompted states to adopt in the U.N. General Assembly the Principles Relevant to the Use of Nuclear Power Sources in Outer Space (1992), particularly introducing safety principles for launches and to manage their traffic.[8]
Benefits
Both the Viking 1 and Viking 2 landers used RTGs for power on the surface of Mars. (Viking launch vehicle pictured)
While solar power is much more commonly used, nuclear power can offer advantages in some areas. Solar cells, although efficient, can only supply energy to spacecraft in orbits where the solar flux is sufficiently high, such as low Earth orbit and interplanetary destinations close enough to the Sun. Unlike solar cells, nuclear power systems function independently of sunlight, which is necessary for deep space exploration. Nuclear-based systems can have less mass than solar cells of equivalent power, allowing more compact spacecraft that are easier to orient and direct in space. In the case of crewed spaceflight, nuclear power concepts that can power both life support and propulsion systems may reduce both cost and flight time.[9]
Selected applications and/or technologies for space include:
Radioisotope thermoelectric generator
Radioisotope heater unit
Radioisotope piezoelectric generator
Radioisotope rocket
Nuclear thermal rocket
Nuclear pulse propulsion
Nuclear electric rocket
""",
)
print(await agent_memory.gpts_memory.one_chat_completions("summarize"))
if __name__ == "__main__":
asyncio.run(main())
全部代码如下
import asyncio
from typing import Any, Dict, Optional, Tuple
from dbgpt.agent import (
Action,
ActionOutput,
AgentContext,
AgentMemory,
AgentMessage,
AgentResource,
ConversableAgent,
LLMConfig,
ProfileConfig,
ResourceType,
UserProxyAgent,
)
from dbgpt.agent.util import cmp_string_equal
from dbgpt.core import ModelMessageRoleType
from dbgpt.model.proxy import OpenAILLMClient
from dbgpt.vis import Vis
from pydantic import BaseModel, Field
NOT_RELATED_MESSAGE = "Did not find the information you want."
CHECK_RESULT_SYSTEM_MESSAGE = (
"You are an expert in analyzing the results of a summary task."
"Your responsibility is to check whether the summary results can summarize the "
"input provided by the user, and then make a judgment. You need to answer "
"according to the following rules:\n"
" Rule 1: If you think the summary results can summarize the input provided"
" by the user, only return True.\n"
" Rule 2: If you think the summary results can NOT summarize the input "
"provided by the user, return False and the reason, split by | and ended "
"by TERMINATE. For instance: False|Some important concepts in the input are "
"not summarized. TERMINATE"
)
class MySummarizerAgent(ConversableAgent):
profile: ProfileConfig = ProfileConfig(
# The name of the agent
name="Aristotle",
# The role of the agent
role="Summarizer",
# The core functional goals of the agent tell LLM what it can do with it.
goal=(
"Summarize answer summaries based on user questions from provided "
"resource information or from historical conversation memories."
),
# Introduction and description of the agent, used for task assignment and display.
# If it is empty, the goal content will be used.
desc=(
"You can summarize provided text content according to user's questions"
" and output the summarization."
),
# Refer to the following. It can contain multiple constraints and reasoning
# restriction logic, and supports the use of parameter template {{ param_name }}.
constraints=[
"Prioritize the summary of answers to user questions from the improved resource"
" text. If no relevant information is found, summarize it from the historical "
"dialogue memory given. It is forbidden to make up your own.",
"You need to first detect user's question that you need to answer with your"
" summarization.",
"Extract the provided text content used for summarization.",
"Then you need to summarize the extracted text content.",
"Output the content of summarization ONLY related to user's question. The "
"output language must be the same to user's question language.",
"If you think the provided text content is not related to user questions at "
"all, ONLY output '{{ not_related_message }}'!!.",
],
)
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._init_actions([SummaryAction])
def _init_reply_message(self, received_message: AgentMessage) -> AgentMessage:
reply_message = super()._init_reply_message(received_message)
# Fill in the dynamic parameters in the prompt template
reply_message.context = {"not_related_message": NOT_RELATED_MESSAGE}
return reply_message
def prepare_act_param(self) -> Dict[str, Any]:
return {"action_extra_param_key": "this is extra param"}
async def correctness_check(
self, message: AgentMessage
) -> Tuple[bool, Optional[str]]:
current_goal = message.current_goal
action_report = message.action_report
task_result = ""
if action_report:
task_result = action_report.get("content", "")
check_result, model = await self.thinking(
messages=[
AgentMessage(
role=ModelMessageRoleType.HUMAN,
content=(
"Please understand the following user input and summary results"
" and give your judgment:\n"
f"User Input: {current_goal}\n"
f"Summary Results: {task_result}"
),
)
],
prompt=CHECK_RESULT_SYSTEM_MESSAGE,
)
fail_reason = ""
if check_result and (
"true" in check_result.lower() or "yes" in check_result.lower()
):
success = True
else:
success = False
try:
_, fail_reason = check_result.split("|")
fail_reason = (
"The summary results cannot summarize the user input due"
f" to: {fail_reason}. Please re-understand and complete the summary"
" task."
)
except Exception:
fail_reason = (
"The summary results cannot summarize the user input. "
"Please re-understand and complete the summary task."
)
return success, fail_reason
# The parameter object that the Action that the current Agent needs to execute needs to output.
class SummaryActionInput(BaseModel):
summary: str = Field(
...,
description="The summary content",
)
class SummaryAction(Action[SummaryActionInput]):
def __init__(self):
super().__init__()
@property
def resource_need(self) -> Optional[ResourceType]:
# The resource type that the current Agent needs to use
# here we do not need to use resources, just return None
return None
@property
def render_protocol(self) -> Optional[Vis]:
# The visualization rendering protocol that the current Agent needs to use
# here we do not need to use visualization rendering, just return None
return None
@property
def out_model_type(self):
return SummaryActionInput
async def run(
self,
ai_message: str,
resource: Optional[AgentResource] = None,
rely_action_out: Optional[ActionOutput] = None,
need_vis_render: bool = True,
**kwargs,
) -> ActionOutput:
"""Perform the action.
The entry point for actual execution of Action. Action execution will be
automatically initiated after model inference.
"""
extra_param = kwargs.get("action_extra_param_key", None)
try:
# Parse the input message
param: SummaryActionInput = self._input_convert(
ai_message, SummaryActionInput
)
except Exception:
return ActionOutput(
is_exe_success=False,
content="The requested correctly structured answer could not be found, "
f"ai message: {ai_message}",
)
# Check if the summary content is not related to user questions
if param.summary and cmp_string_equal(
param.summary,
NOT_RELATED_MESSAGE,
ignore_case=True,
ignore_punctuation=True,
ignore_whitespace=True,
):
return ActionOutput(
is_exe_success=False,
content="the provided text content is not related to user questions at all."
f"ai message: {ai_message}",
)
else:
return ActionOutput(
is_exe_success=True,
content=param.summary,
)
async def main():
llm_client = OpenAILLMClient(model_alias="gpt-3.5-turbo")
context: AgentContext = AgentContext(conv_id="summarize")
agent_memory: AgentMemory = AgentMemory()
summarizer = (
await MySummarizerAgent()
.bind(context)
.bind(LLMConfig(llm_client=llm_client))
.bind(agent_memory)
.build()
)
user_proxy = await UserProxyAgent().bind(agent_memory).bind(context).build()
await user_proxy.initiate_chat(
recipient=summarizer,
reviewer=user_proxy,
message="""I want to summarize advantages of Nuclear Power according to the following content.
Nuclear power in space is the use of nuclear power in outer space, typically either small fission systems or radioactive decay for electricity or heat. Another use is for scientific observation, as in a Mössbauer spectrometer. The most common type is a radioisotope thermoelectric generator, which has been used on many space probes and on crewed lunar missions. Small fission reactors for Earth observation satellites, such as the TOPAZ nuclear reactor, have also been flown.[1] A radioisotope heater unit is powered by radioactive decay and can keep components from becoming too cold to function, potentially over a span of decades.[2]
The United States tested the SNAP-10A nuclear reactor in space for 43 days in 1965,[3] with the next test of a nuclear reactor power system intended for space use occurring on 13 September 2012 with the Demonstration Using Flattop Fission (DUFF) test of the Kilopower reactor.[4]
After a ground-based test of the experimental 1965 Romashka reactor, which used uranium and direct thermoelectric conversion to electricity,[5] the USSR sent about 40 nuclear-electric satellites into space, mostly powered by the BES-5 reactor. The more powerful TOPAZ-II reactor produced 10 kilowatts of electricity.[3]
Examples of concepts that use nuclear power for space propulsion systems include the nuclear electric rocket (nuclear powered ion thruster(s)), the radioisotope rocket, and radioisotope electric propulsion (REP).[6] One of the more explored concepts is the nuclear thermal rocket, which was ground tested in the NERVA program. Nuclear pulse propulsion was the subject of Project Orion.[7]
Regulation and hazard prevention[edit]
After the ban of nuclear weapons in space by the Outer Space Treaty in 1967, nuclear power has been discussed at least since 1972 as a sensitive issue by states.[8] Particularly its potential hazards to Earth's environment and thus also humans has prompted states to adopt in the U.N. General Assembly the Principles Relevant to the Use of Nuclear Power Sources in Outer Space (1992), particularly introducing safety principles for launches and to manage their traffic.[8]
Benefits
Both the Viking 1 and Viking 2 landers used RTGs for power on the surface of Mars. (Viking launch vehicle pictured)
While solar power is much more commonly used, nuclear power can offer advantages in some areas. Solar cells, although efficient, can only supply energy to spacecraft in orbits where the solar flux is sufficiently high, such as low Earth orbit and interplanetary destinations close enough to the Sun. Unlike solar cells, nuclear power systems function independently of sunlight, which is necessary for deep space exploration. Nuclear-based systems can have less mass than solar cells of equivalent power, allowing more compact spacecraft that are easier to orient and direct in space. In the case of crewed spaceflight, nuclear power concepts that can power both life support and propulsion systems may reduce both cost and flight time.[9]
Selected applications and/or technologies for space include:
Radioisotope thermoelectric generator
Radioisotope heater unit
Radioisotope piezoelectric generator
Radioisotope rocket
Nuclear thermal rocket
Nuclear pulse propulsion
Nuclear electric rocket
""",
)
print(await agent_memory.gpts_memory.one_chat_completions("summarize"))
if __name__ == "__main__":
asyncio.run(main())