构建LangChain应用程序的示例代码:63、如何使用Petting Zoo库定义和运行多智能体模拟环境

多智能体模拟环境: Petting Zoo

在这个例子中,我们展示如何使用模拟环境定义多智能体模拟。与我们的单智能体Gymnasium示例类似,我们创建了一个具有外部定义环境的智能体-环境循环。主要区别在于我们现在使用多个智能体实现这种交互循环。我们将使用Petting Zoo库,它是Gymnasium的多智能体对应版本。

安装pettingzoo和其他依赖

!pip install pettingzoo pygame rlcard

导入模块

import collections
import inspect

import tenacity
from langchain.output_parsers import RegexParser
from langchain.schema import (
    HumanMessage,
    SystemMessage,
)
from langchain_openai import ChatOpenAI

GymnasiumAgent

这里我们复现了Gymnasium示例中定义的相同GymnasiumAgent。如果多次重试后仍未采取有效行动,它会简单地采取随机行动。

class GymnasiumAgent:
    @classmethod
    def get_docs(cls, env):
        return env.unwrapped.__doc__

    def __init__(self, model, env):
        self.model = model
        self.env = env
        self.docs = self.get_docs(env)

        self.instructions = """
你的目标是最大化你的回报,即你收到的奖励总和。
我会给你一个观察、奖励、终止标志、截断标志和到目前为止的回报,格式如下:

Observation: <observation>
Reward: <reward>
Termination: <termination>
Truncation: <truncation>
Return: <sum_of_rewards>

你将以以下格式回应一个动作:

Action: <action>

其中你用实际的动作替换<action>。
除此之外不要做任何其他事情。
"""
        self.action_parser = RegexParser(
            regex=r"Action: (.*)", output_keys=["action"], default_output_key="action"
        )

        self.message_history = []
        self.ret = 0

    def random_action(self):
        action = self.env.action_space.sample()
        return action

    def reset(self):
        self.message_history = [
            SystemMessage(content=self.docs),
            SystemMessage(content=self.instructions),
        ]

    def observe(self, obs, rew=0, term=False, trunc=False, info=None):
        self.ret += rew

        obs_message = f"""
Observation: {obs}
Reward: {rew}
Termination: {term}
Truncation: {trunc}
Return: {self.ret}
        """
        self.message_history.append(HumanMessage(content=obs_message))
        return obs_message

    def _act(self):
        act_message = self.model.invoke(self.message_history)
        self.message_history.append(act_message)
        action = int(self.action_parser.parse(act_message.content)["action"])
        return action

    def act(self):
        try:
            for attempt in tenacity.Retrying(
                stop=tenacity.stop_after_attempt(2),
                wait=tenacity.wait_none(),  # 重试之间无等待时间
                retry=tenacity.retry_if_exception_type(ValueError),
                before_sleep=lambda retry_state: print(
                    f"发生ValueError: {retry_state.outcome.exception()}, 正在重试..."
                ),
            ):
                with attempt:
                    action = self._act()
        except tenacity.RetryError:
            action = self.random_action()
        return action

主循环

def main(agents, env):
    env.reset()

    for name, agent in agents.items():
        agent.reset()

    for agent_name in env.agent_iter():
        observation, reward, termination, truncation, info = env.last()
        obs_message = agents[agent_name].observe(
            observation, reward, termination, truncation, info
        )
        print(obs_message)
        if termination or truncation:
            action = None
        else:
            action = agents[agent_name].act()
        print(f"Action: {action}")
        env.step(action)
    env.close()

PettingZooAgent

PettingZooAgent扩展了GymnasiumAgent以适应多智能体设置。主要区别是:

  • PettingZooAgent接受一个name参数来在多个智能体中识别它
  • get_docs函数的实现不同,因为PettingZoo仓库结构与Gymnasium仓库不同
class PettingZooAgent(GymnasiumAgent):
    @classmethod
    def get_docs(cls, env):
        return inspect.getmodule(env.unwrapped).__doc__

    def __init__(self, name, model, env):
        super().__init__(model, env)
        self.name = name

    def random_action(self):
        action = self.env.action_space(self.name).sample()
        return action

石头剪刀布

现在我们可以使用PettingZooAgent运行一个多智能体石头剪刀布游戏模拟。

from pettingzoo.classic import rps_v2

env = rps_v2.env(max_cycles=3, render_mode="human")
agents = {
    name: PettingZooAgent(name=name, model=ChatOpenAI(temperature=1), env=env)
    for name in env.possible_agents
}
main(agents, env)

ActionMaskAgent

一些PettingZoo环境提供action_mask来告诉智能体哪些动作是有效的。ActionMaskAgent继承自PettingZooAgent,使用action_mask中的信息来选择动作。

class ActionMaskAgent(PettingZooAgent):
    def __init__(self, name, model, env):
        super().__init__(name, model, env)
        self.obs_buffer = collections.deque(maxlen=1)

    def random_action(self):
        obs = self.obs_buffer[-1]
        action = self.env.action_space(self.name).sample(obs["action_mask"])
        return action

    def reset(self):
        self.message_history = [
            SystemMessage(content=self.docs),
            SystemMessage(content=self.instructions),
        ]

    def observe(self, obs, rew=0, term=False, trunc=False, info=None):
        self.obs_buffer.append(obs)
        return super().observe(obs, rew, term, trunc, info)

    def _act(self):
        valid_action_instruction = "根据动作格式规则,生成由`action_mask`中非0索引给出的有效动作。"
        self.message_history.append(HumanMessage(content=valid_action_instruction))
        return super()._act()

井字棋

这里是一个使用ActionMaskAgent的井字棋游戏示例。

from pettingzoo.classic import tictactoe_v3

env = tictactoe_v3.env(render_mode="human")
agents = {
    name: ActionMaskAgent(name=name, model=ChatOpenAI(temperature=0.2), env=env)
    for name in env.possible_agents
}
main(agents, env)

德州扑克无限注

这里是一个使用ActionMaskAgent的德州扑克无限注游戏示例。

from pettingzoo.classic import texas_holdem_no_limit_v6

env = texas_holdem_no_limit_v6.env(num_players=4, render_mode="human")
agents = {
    name: ActionMaskAgent(name=name, model=ChatOpenAI(temperature=0.2), env=env)
    for name in env.possible_agents
}
main(agents, env)

总结

这个文件展示了如何使用Petting Zoo库定义和运行多智能体模拟环境。主要内容包括:

  1. 定义了一个基础的GymnasiumAgent类
  2. 扩展出PettingZooAgent类以适应多智能体环境
  3. 进一步定义了ActionMaskAgent类来处理带动作掩码的环境
  4. 展示了在石头剪刀布、井字棋和德州扑克无限注环境中使用这些智能体的例子

扩展知识

  1. 多智能体强化学习:与单智能体强化学习相比,多智能体强化学习涉及多个智能体在同一环境中学习和交互,这增加了问题的复杂性,因为每个智能体的行为都会影响其他智能体和环境。

  2. Petting Zoo:这是一个用于多智能体强化学习的Python库,提供了多种标准化的多智能体环境,类似于单智能体强化学习中广泛使用的Gymnasium(前身是OpenAI Gym)。

  3. 动作掩码(Action Mask):在某些强化学习环境中,并非所有动作在任何时候都是有效的。动作掩码是一种技术,用于指示在当前状态下哪些动作是合法或可行的。这可以显著提高学习效率,因为它可以防止智能体尝试无效或非法的动作。

  4. 温度(Temperature):在使用语言模型(如ChatOpenAI)时,温度是一个控制输出随机性的参数。较低的温度(如0.2)会使输出更加确定和一致,而较高的温度(如1.0)会增加输出的多样性和创造性。

  5. 重试机制:在代码中使用了tenacity库来实现重试机制。这在处理可能失败的操作时非常有用,特别是在涉及网络请求或其他不稳定操作时。

  • 16
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hugo_Hoo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值