Create ReAct Agent

AgentScope provides out-of-the-box ReAct agent ReActAgent under agentscope.agent that can be used directly.

It supports the following features at the same time:

  • ✨ Basic features
    • Support hooks around reply, observe, print, _reasoning and _acting functions

    • Support structured output

  • ✋ Realtime Steering
    • Support user interrupt

    • Support customized interruption handling

  • 🛠️ Tools
    • Support both sync/async tool functions

    • Support streaming tool response

    • Support stateful tools management

    • Support parallel tool calls

    • Support MCP server

  • 💾 Memory
    • Support agent-controlled long-term memory management

    • Support static long-term memory management

Tip

Refer to the Agent section for more details about these features. In quickstart, we focus on how to create a ReAct agent and run it.

from agentscope.agent import ReActAgent, AgentBase
from agentscope.formatter import DashScopeChatFormatter
from agentscope.memory import InMemoryMemory
from agentscope.message import Msg
from agentscope.model import DashScopeChatModel
import asyncio
import os

from agentscope.tool import Toolkit, execute_python_code

Creating ReAct Agent

To improve the flexibility, the ReActAgent class exposes the following parameters in its constructor:

Initialization parameters of ReActAgent class

Parameter

Further Reading

Description

name (required)

The name of the agent

sys_prompt (required)

The system prompt of the agent

model (required)

Model

The model used by the agent to generate responses

formatter (required)

Prompt Formatter

The prompt construction strategy, should be consisted with the model

toolkit

Tool

The toolkit to register/call tool functions.

memory

Memory

The short-term memory used to store the conversation history

long_term_memory

Long-Term Memory

The long-term memory

long_term_memory_mode

Long-Term Memory

The mode of the long-term memory:

  • agent_control: allow agent to control the long-term memory by itself

  • static_control: retrieving and recording from/to long-term memory will happen in the beginning/end of each reply.

  • both: active the above two modes at the same time

enable_meta_tool

Tool

Whether to enable the meta tool, which allows the agent to manage tools by itself

parallel_tool_calls

Agent

Whether to allow parallel tool calls

max_iters

The maximum number of iterations for the agent to generate a response

Taking DashScope API as example, we create an agent object as follows:

async def creating_react_agent() -> None:
    """Create a ReAct agent and run a simple task."""
    # Prepare tools
    toolkit = Toolkit()
    toolkit.register_tool_function(execute_python_code)

    jarvis = 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"],
            stream=True,
            enable_thinking=False,
        ),
        formatter=DashScopeChatFormatter(),
        toolkit=toolkit,
        memory=InMemoryMemory(),
    )

    msg = Msg(
        name="user",
        content="Hi! Jarvis, run Hello World in Python.",
        role="user",
    )

    await jarvis(msg)


asyncio.run(creating_react_agent())
Jarvis: {
    "type": "tool_use",
    "id": "call_e8b3780fc9c94822a9da2e",
    "name": "execute_python_code",
    "input": {
        "code": "print('Hello World')",
        "timeout": 10
    }
}
system: {
    "type": "tool_result",
    "id": "call_e8b3780fc9c94822a9da2e",
    "name": "execute_python_code",
    "output": [
        {
            "type": "text",
            "text": "<returncode>0</returncode><stdout>Hello World\n</stdout><stderr></stderr>"
        }
    ]
}
Jarvis: The Python code has been executed successfully and it printed:

```
Hello World
```

Creating From Scratch

You may want to create an agent from scratch, AgentScope provides two base classes for you to inherit from:

Class

Abstract Methods

Description

AgentBase

reply
observe
handle_interrupt
  • The base class for all agents, supporting pre- and post- hooks around reply, observe and print functions.

  • Implement the realtime steering within the __call__ method.

ReActAgentBase

reply
observe
handle_interrupt
_reasoning
_acting

Add two abstract functions _reasoning and _acting on the basis of AgentBase, as well as their hooks.

Please refer to the Agent section for more details about the agent class.

Taking the AgentBase class as an example, we can create a custom agent class by inheriting from it and implementing the reply method.

class MyAgent(AgentBase):
    """A custom agent class"""

    def __init__(self) -> None:
        """Initialize the agent"""
        super().__init__()

        self.name = "Friday"
        self.sys_prompt = "You're a helpful assistant named Friday."
        self.model = DashScopeChatModel(
            model_name="qwen-max",
            api_key=os.environ["DASHSCOPE_API_KEY"],
            stream=False,
        )
        self.formatter = DashScopeChatFormatter()
        self.memory = InMemoryMemory()

    async def reply(self, msg: Msg | list[Msg] | None) -> Msg:
        """Reply to the message."""
        await self.memory.add(msg)

        # Prepare the prompt
        prompt = await self.formatter.format(
            [
                Msg("system", self.sys_prompt, "system"),
                *await self.memory.get_memory(),
            ],
        )

        # Call the model
        response = await self.model(prompt)

        msg = Msg(
            name=self.name,
            content=response.content,
            role="assistant",
        )

        # Record the response in memory
        await self.memory.add(msg)

        # Print the message
        await self.print(msg)
        return msg

    async def observe(self, msg: Msg | list[Msg] | None) -> None:
        """Observe the message."""
        # Store the message in memory
        await self.memory.add(msg)

    async def handle_interrupt(self) -> Msg:
        """Postprocess the interrupt."""
        # Taking a fixed response as example
        return Msg(
            name=self.name,
            content="I noticed you interrupted me, how can I help you?",
            role="assistant",
        )


async def run_custom_agent() -> None:
    """Run the custom agent."""
    agent = MyAgent()
    msg = Msg(
        name="user",
        content="Who are you?",
        role="user",
    )
    await agent(msg)


asyncio.run(run_custom_agent())
Friday: Hello! I'm Friday, an AI assistant designed to help with a wide range of tasks, from answering questions and providing information to assisting with planning and more. How can I assist you today?

Further Reading

Total running time of the script: (0 minutes 8.584 seconds)

Gallery generated by Sphinx-Gallery