注意
Go to the end 下载完整示例代码。
智能体¶
在本教程中,我们首先重点介绍agentscope中的ReAct智能体, 然后简要介绍如何从零开始自定义您自己的智能体。
ReAct 智能体¶
在AgentScope中,ReActAgent类将多种功能整合到一个最终的实现中,包括
功能特性 |
参考文献 |
|---|---|
支持实时引导 |
|
支持并行工具调用 |
|
支持结构化输出 |
|
支持细粒度的MCP控制 |
|
支持智能体控制工具管理(元工具) |
|
支持自控长期记忆 |
|
支持自动状态管理 |
由于篇幅有限,在此教程中,我们仅演示ReActAgent类的前三个功能,其余功能请参阅上述相应章节。
import asyncio
import json
import os
from datetime import datetime
import time
from pydantic import BaseModel, Field
from agentscope.agent import ReActAgent
from agentscope.formatter import DashScopeChatFormatter
from agentscope.memory import InMemoryMemory
from agentscope.message import TextBlock, Msg
from agentscope.model import DashScopeChatModel
from agentscope.tool import Toolkit, ToolResponse
实时操控¶
实时控制功能允许用户随时中断智能体的回复,这是通过异步取消机制实现的。
具体来说,当调用智能体的interrupt方法时,它会取消当前回复任务,并执行handle_interrupt方法进行后处理。
提示
通过支持流式工具结果的功能,
在Tool中,如果工具耗时过长或偏离用户预期,
用户可通过在终端按下Ctrl+C或在代码中调用智能体的
interrupt方法来中断工具执行。
中断逻辑已在 AgentBase 类中作为基础功能实现,同时为用户保留了 handle_interrupt 方法,以便自定义中断后的处理流程,具体如下:
# code snippet of AgentBase
class AgentBase:
...
async def __call__(self, *args: Any, **kwargs: Any) -> Msg:
...
reply_msg: Msg | None = None
try:
self._reply_task = asyncio.current_task()
reply_msg = await self.reply(*args, **kwargs)
except asyncio.CancelledError:
# Catch the interruption and handle it by the handle_interrupt method
reply_msg = await self.handle_interrupt(*args, **kwargs)
...
@abstractmethod
async def handle_interrupt(self, *args: Any, **kwargs: Any) -> Msg:
pass
在 ReActAgent 类中, 我们返回了一条固定消息 "I noticed that you have
interrupted me. What can I do for you?" 如下所示:
中断示例¶
你可以用自己的实现来覆盖它,例如调用LLM来生成一个简单的响应来处理中断。
并行工具调用¶
ReActAgent 支持通过在其构造函数中提供 parallel_tool_calls 参数来实现并行工具调用。
当生成多个工具调用且 parallel_tool_calls 设置为 True 时,
它们将由 asyncio.gather 函数并行执行。
# prepare a tool function
def example_tool_function(tag: str) -> ToolResponse:
"""A sample example tool function"""
start_time = datetime.now().strftime("%H:%M:%S.%f")
# Sleep for 3 seconds to simulate a long-running task
time.sleep(3)
end_time = datetime.now().strftime("%H:%M:%S.%f")
return ToolResponse(
content=[
TextBlock(
type="text",
text=f"Tag {tag} started at {start_time} and ended at {end_time}. ",
),
],
)
toolkit = Toolkit()
toolkit.register_tool_function(example_tool_function)
# Create an ReAct agent
agent = ReActAgent(
name="Jarvis",
sys_prompt="You're a helpful assistant named Jarvis.",
model=DashScopeChatModel(
model_name="qwen-max",
api_key=os.environ["DASHSCOPE_API_KEY"],
),
memory=InMemoryMemory(),
formatter=DashScopeChatFormatter(),
toolkit=toolkit,
parallel_tool_calls=True,
)
async def example_parallel_tool_calls() -> None:
"""Example of parallel tool calls"""
# prompt the agent to generate two tool calls at once
await agent(
Msg(
"user",
"Generate two tool calls of the 'example_tool_function' function with tag as 'tag1' and 'tag2' AT ONCE so that they can execute in parallel.",
"user",
),
)
asyncio.run(example_parallel_tool_calls())
Jarvis: {
"type": "tool_use",
"id": "call_30fc47dd0efc4a308bfede",
"name": "example_tool_function",
"input": {
"tag": "tag1"
}
}
system: {
"type": "tool_result",
"id": "call_30fc47dd0efc4a308bfede",
"name": "example_tool_function",
"output": [
{
"type": "text",
"text": "Tag tag1 started at 07:55:25.789639 and ended at 07:55:28.792723. "
}
]
}
Jarvis: {
"type": "tool_use",
"id": "call_0fb8ece015844feb81f99c",
"name": "example_tool_function",
"input": {
"tag": "tag2"
}
}
system: {
"type": "tool_result",
"id": "call_0fb8ece015844feb81f99c",
"name": "example_tool_function",
"output": [
{
"type": "text",
"text": "Tag tag2 started at 07:55:31.203518 and ended at 07:55:34.206590. "
}
]
}
Jarvis: Both example_tool_function calls have been executed in parallel.
- The function call with the tag 'tag1' started at 07:55:25.789639 and ended at 07:55:28.792723.
- The function call with the tag 'tag2' started at 07:55:31.203518 and ended at 07:55:34.206590.
结构化输出¶
要生成结构化输出,ReActAgent实例会在其__call__函数中接收一个pydantic.BaseModel的子类作为structured_model参数。
然后我们可以从返回消息的metadata字段中获取结构化输出。
以介绍爱因斯坦为例:
# Create an ReAct agent
agent = ReActAgent(
name="Jarvis",
sys_prompt="You're a helpful assistant named Jarvis.",
model=DashScopeChatModel(
model_name="qwen-max",
api_key=os.environ["DASHSCOPE_API_KEY"],
# Preset the generation kwargs to enable parallel tool calls
generate_kwargs={
"parallel_tool_calls": True,
},
),
memory=InMemoryMemory(),
formatter=DashScopeChatFormatter(),
toolkit=Toolkit(),
parallel_tool_calls=True,
)
# The structured model
class Model(BaseModel):
name: str = Field(description="The name of the person")
description: str = Field(
description="A one-sentence description of the person",
)
age: int = Field(description="The age")
honor: list[str] = Field(description="A list of honors of the person")
async def example_structured_output() -> None:
"""The example structured output"""
res = await agent(
Msg(
"user",
"Introduce Einstein",
"user",
),
structured_model=Model,
)
print("\nThe structured output:")
print(json.dumps(res.metadata, indent=4))
asyncio.run(example_structured_output())
Jarvis: Albert Einstein was a renowned physicist who developed the theory of relativity, one of the two pillars of modern physics. He was born on March 14, 1879, and passed away on April 18, 1955. His work has had a profound impact on the philosophy of science, and he is best known for developing the theory of relativity, but he also made important contributions to the development of the theory of quantum mechanics.
The structured output:
{
"name": "Albert Einstein",
"description": "A theoretical physicist who developed the theory of relativity",
"age": 76,
"honor": [
"Nobel Prize in Physics (1921)",
"Copley Medal (1925)",
"Max Planck Medal (1929)"
]
}
自定义智能体¶
AgentScope提供了两个基础类,AgentBase和ReActAgentBase,它们
在定义的抽象方法和支持的钩子方面有所不同。
具体来说,ReActAgentBase扩展了AgentBase,增加了额外的_reasoning和_acting
抽象方法,以及它们的前置和后置钩子。
开发者可以根据需要选择继承这些基类中的任一。
我们总结agentscope.agent模块下的智能体如下:
类 |
抽象方法 |
支持钩子 |
描述 |
|---|---|---|---|
|
replyobserveprinthandle_interrupt |
前/后回复
前置/后置观察
前置/后置打印
|
所有智能体的基类,提供基础接口和钩子。 |
|
replyobserveprinthandle_interrupt_reasoning_acting |
前_/后回复
pre_/post_observe
前/后打印
前置/后置推理
前置/后置执行
|
ReAct智能体的抽象类,继承自 |
|
- |
前/后回复
前置/后置观察处理
前/后打印
推理前/推理后
前/后执行
|
|
|
一个代表用户的特殊智能体,用于与智能体进行交互 |
扩展阅读¶
脚本总运行时间: (0 分钟 27.572 秒)