LoginSignup
5
4

AutoGen を使って人狼をやってみた(プロトタイピング)

Last updated at Posted at 2024-03-10

概要

AutoGenフレームワークを用いて、人狼ゲームを行うアプリのプロトタイピングをやってみました。AutoGenは複数のLarge Language Model (LLM) エージェントが互いに会話をしながらタスクを遂行することを可能にするフレームワークです。本記事では、AutoGenの基本概念の説明から始め、人狼ゲームのルールやプレイヤーの役割を定義し、エージェント間での相互作用を実装していく過程を紹介しています。複数の LLM エージェントを AutoGen を通じて実装し人狼ゲームの各セッションを自動でプレイするアプリのプロトタイプを作成することです。本記事を読んでいただくことで、LLM エージェントの応用例を学び、AutoGen フレームワークを活用するための基礎知識を得ることができます。

本記事で提供されているコードは、特定の環境や条件下での動作を示すものであり、全ての環境やケースで同様に機能するとは限りません。また、時間の経過とともにソフトウェアの更新や互換性の問題が生じる可能性があるため、掲載されているコードが最新の状態であるとは限りません。本コードの使用は、読者の責任において行ってください。実行する前に、コードをよく理解し、必要に応じて環境に適合させることを推奨します。また、可能な限りバックアップを取ることを忘れないでください。また、執筆にあたり生成AIも活用しておりますのでご了承ください。本記事の内容やコードに関する質問や改善提案があれば、コメント欄やソーシャルメディアを通じてお知らせください。

はじめに

AutoGen という LLM (Large Language Model) のマルチエージェントのフレームワークが 2023 年に提案されています。

エージェントとは「認識」と「アクション」を自律的にを繰り返して動作するツールを意味しており、AutoGen のフレームワークを使用すれば異なる構成や補完的な機能を備えたエージェントを互いに相互作用させたアプリケーションを簡単に作ることができます。

AutoGen の論文を見ていると下記のような図を見つけ、ふと「Manager -> ゲームマスター、Agent -> プレイヤーと読み替えれば人狼できるじゃん」と思って取り組んでみたので、本記事ではその紹介をさせていただきます1

autogen-fig3-a5.png

https://arxiv.org/abs/2308.08155 Fig.3 A.5 より

本記事では AutoGen の概要と簡単な使い方、実装の内部に簡単に触れ、人狼のアプリケーションをどのように作ったのかの概観をご紹介します。

実際のコードはこちら↓

本書の目的

  • AutoGen フレームワークの概要の紹介
  • AutoGen を使ったアイデアの一つとして人狼アプリ(プロトタイプ)を共有

本書の対象読者

下記を満たしている方を主に対象としています:

  • python の基本的な文法を知っている
  • LLMやエージェントに関する基本的な理解がある
  • OpenAI の API を使用したことがある
  • LLM アプリケーションのサンプルを探している

追加で英語に抵抗感がない方がいいかもしれません(もちろん最近ですとまるっと翻訳できるので必須ではありませんが)。

なお、本書は AutoGen の使い方の紹介を目的とした入門書ではないのでご注意ください。もし AutoGen のライブラリに入門したい方は下記の記事が大変参考になりましたのでぜひご一読されるとよろしいかと思います

本書の実行環境

  • Windows 11

  • Python 3.10.13

    click
    langchain==0.1.10
    langchain_openai==0.0.8
    pyautogen==0.2.16
    python-dotenv
    

実行する際には OpenAI の API キーを取得の上、.env ファイルを下記の内容で作成してください:

OPENAI_API_KEY={YOUR_API_KEY}

OpenAI API の利用には費用が発生します。詳細は https://openai.com/pricing をご確認ください。

AutoGen とは

AutoGen (コードリポジトリはこちら)とは複数の LLM エージェント2が互いに会話しタスクを遂行する LLM アプリケーションを構築するためのオープンソースのフレームワークです。

エージェントとは「認識」と「アクション」を自律的にを繰り返して動作するツールのことです3。特に LLM に基づいたエージェントは LLM エージェントなどと呼ばれたりもします。例えば、langchain と呼ばれる LLM アプリケーションのライブラリでも ReAct と呼ばれるアプローチを使ったエージェントがデフォルトで実装されています。

そしてマルチエージェントとは複数のエージェントが相互作用する仕組みのことです。
エージェント単体では難しいタスクであっても、異なる構成や補完的な機能を備えたエージェントなどを用いることで解けるようになる可能性が上がります。複雑な問題であっても小さなサブタスクに分割することで快活する能力も実証的に確認されており(Plan-and-Solve)、マルチエージェントのアプローチはこの分割と結果の統合を直感的な方法で可能にすることができます。あたかもいろんなタイプの人間が互いに協力し合って難しいことを成し遂げていくかのようにです。

この AutoGen は大きく 2 つのフレームワークを提供しています。

  1. カスタマイズ可能かつ会話可能な LLM エージェント

    • LLM、人間、ツールとそれらの組み合わせを活用可能な設計
    • プログラミングやプログラムの実行、人間のフィードバックを組み込んだエージェントを容易に作成できる
    • すべてのエージェントは会話可能になっている
  2. Conversation programming(会話プログラミング?雑感ですが日本語にするとどこか違和感があるので英語のままで)

    • 複雑な LLM アプリケーションのワークフローをエージェントの会話として統一
    • 開発の主なステップは下記の 2 ステップ
      1. 特定のスキル・役割を持つ会話可能なエージェントの 集合 を定義
      2. 会話中心の計算と制御でエージェント間の相互作用をプログラミング

AutoGen の具体的な使用例としては

  1. 数学問題の解決
  2. RAGに基づくコード生成や質問回答
  3. テキスト環境下の意思決定
  4. 複数エージェントのコーディング
  5. グループチャット
  6. チェスの対局

autogen-fig3.png

https://arxiv.org/abs/2308.08155 Fig.3 より

使い方

さて、ここからは基本的な使い方を眺めてみましょう。

まずは準備。pyautogen をインストールしましょう:

pip install pyautogen

では、さっそく LLM エージェントと会話してみましょう。

AssistantAgentUserProxyAgent を用います。

AssistantAgentConversableAgent のサブクラスの一つでデフォルトのシステムプロンプトが設定されています。python のコードブロックの提案やデバッグを行ってくれます。

他方で UserProxyAgent も同じく ConversableAgent のサブクラスの一つですが、
ユーザの代理エージェントとしてコードを実行したり他のエージェントにフィードバックを与えることができるクラスです。特にデフォルトでは UserProxyAgent インスタンスはメッセージを受信するたびにユーザに入力を要求します。

Python 3.10.13 (main, Feb 22 2024, 10:50:12) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from dotenv import load_dotenv
>>> load_dotenv()
True
>>> from autogen import AssistantAgent, UserProxyAgent
>>> config_list = [{'model': 'gpt-4-turbo-preview'}]
>>> assistant = AssistantAgent("assistant", llm_config=dict(config_list=config_list))
>>> user_proxy = UserProxyAgent("user_proxy")
/mnt/d/dev_libs/autogen-werewolf/venv/lib/python3.10/site-packages/autogen/agentchat/user_proxy_agent.py:83: UserWarning: Using None to signal a default code_execution_config is deprecated. Use {} to use default or False to disable code execution.
  super().__init__(
>>> user_proxy.initiate_chat(assistant, message='hello, how are you?')
user_proxy (to assistant):

hello, how are you?

--------------------------------------------------------------------------------
assistant (to user_proxy):

I'm just a computer program, so I don't have feelings, but thanks for asking! How can I assist you today?

--------------------------------------------------------------------------------
Provide feedback to assistant. Press enter to skip and use auto-reply, or type 'exit' to end the conversation: Good. No help need. Thanks.
user_proxy (to assistant):

Good. No help need. Thanks.

--------------------------------------------------------------------------------
assistant (to user_proxy):

You're welcome! If you ever have any questions or need assistance in the future, feel free to reach out. Have a great day! 

TERMINATE

--------------------------------------------------------------------------------
Provide feedback to assistant. Press enter to skip and use auto-reply, or type 'exit' to end the conversation: exit
ChatResult(chat_id=None, chat_history=[{'content': 'hello, how are you?', 'role': 'assistant'}, {'content': "I'm just a computer program, so I don't have feelings, but thanks for asking! How can I assist you today?", 'role': 'user'}, {'content': 'Good. No help need. Thanks.', 'role': 'assistant'}, {'content': "You're welcome! If you ever have any questions or need assistance in the future, feel free to reach out. Have a great day! \n\nTERMINATE", 'role': 'user'}], summary="You're welcome! If you ever have any questions or need assistance in the future, feel free to reach out. Have a great day! \n\n", cost=({'total_cost': 0.011720000000000001, 'gpt-4-0125-preview': {'cost': 0.011720000000000001, 'prompt_tokens': 998, 'completion_tokens': 58, 'total_tokens': 1056}}, {'total_cost': 0.011720000000000001, 'gpt-4-0125-preview': {'cost': 0.011720000000000001, 'prompt_tokens': 998, 'completion_tokens': 58, 'total_tokens': 1056}}), human_input=['Good. No help need. Thanks.', 'exit'])

このような形で(特にコードの実行などの難しいタスクは行ってはいませんが)チャットのように会話することができます。

ただし、これではまだマルチエージェントを使えていません。

容易にマルチエージェントの相互作用を実装する 1 つのクラスとして autogen では「グループチャット」が提供されています。

実際に Pythonista、JavaScript エンジニア、シェル芸人の3人に一番いいプログラミング言語について話し合ってもらったのが下記です:

>>> user_proxy = UserProxyAgent("user_proxy", human_input_mode='NEVER')
>>> jser = AssistantAgent("JavaScriptEngineer", llm_config=dict(config_list=config_list), system_message='You are the best javascript programmer in the world')
>>> shoneliner = AssistantAgent("BashProgrammer", llm_config=dict(config_list=config_list), system_message='You are the best bash script programmer in the world')
>>> groupchat = GroupChat(agents=[user_proxy, pythonista, jser, shoneliner], max_round=10, speaker_selection_method='round_robin', messages=[])
>>> manager = GroupChatManager(groupchat=groupchat, llm_config=dict(config_list=config_list))
>>> user_proxy.initiate_chat(manager, message='What is the best programming language? Show your favorites')
user_proxy (to chat_manager):

What is the best programming language? Show your favorites

--------------------------------------------------------------------------------
Pythonista (to chat_manager):

As an AI model developed by OpenAI, I don't have personal opinions or feelings. However, I can tell you that the "best" programming language often depends on the context in which it's being used. Different languages are designed with different goals in mind, making some more suitable for certain tasks than others. Here are a few common programming languages and their generally accepted strengths:

1. **Python**: Known for its readability and simplicity, Python is a great language for beginners and is widely used in scientific computing, data analysis, artificial intelligence, and back-end web development. It has a vast ecosystem of libraries and frameworks, such as NumPy for numerical computing, Pandas for data analysis, TensorFlow and PyTorch for machine learning, and Django and Flask for web development.

2. **JavaScript**: The language of the web. JavaScript is essential for front-end development, making web pages interactive and dynamic. It's also increasingly used on the server-side through Node.js. Frameworks and libraries like React, Vue, and Angular have made JavaScript even more versatile.

3. **Java**: Known for its portability across platforms thanks to the JVM (Java Virtual Machine), it’s widely used in enterprise environments, Android app development, and large systems. Java is known for its strong memory management and multi-threading capabilities.

4. **C/C++**: These languages are known for their performance and control over system resources, making them ideal for system-level programming, game development, and applications requiring high-performance computation. C++ builds on C with object-oriented features.

5. **Rust**: A newer language that guarantees memory safety and is designed for safe concurrency. Rust is becoming popular for system-level tasks and applications where performance and reliability are critical.

6. **Go (Golang)**: Developed by Google, known for its simplicity and efficiency, particularly in building scalable and high-performance web servers and large distributed systems.

7. **Swift**: Created by Apple for iOS and macOS development. It’s known for being powerful yet easy to learn, and it has a strong focus on safety and performance.

8. **Kotlin**: Designed to be fully interoperable with Java but with a more modern syntax. It's officially supported for Android development and is appreciated for its conciseness and safety features.

The choice of a programming language can depend on various factors, including the specific requirements of the project, the existing technology stack, the team's familiarity with the language, and the performance and scalability needs. Each language has its own set of trade-offs.


--------------------------------------------------------------------------------
JavaScriptEngineer (to chat_manager):

Given these summaries, if I were able to have preferences, Python could be considered a favorite for many scenarios due to its versatility, ease of learning, and broad applicability across different domains, including web development, scientific computing, data analysis, and artificial intelligence. It's also supported by a vibrant community that contributes to a rich ecosystem of libraries and frameworks. This makes Python a powerful tool in a programmer's arsenal for solving a wide range of problems efficiently.

--------------------------------------------------------------------------------
BashProgrammer (to chat_manager):

Python's wide-ranging applications and the ecosystem indeed make it a standout choice for many developers, including those who might specialize in different domains such as web development, data science, artificial intelligence, and more. Its syntax is designed to be readable and straightforward, which reduces the barrier to entry for beginners and allows experienced developers to focus more on solving problems than on deciphering complex code. The extensive libraries and frameworks available to Python developers, like Django for web development, Pandas for data manipulation, Tensorflow and PyTorch for machine learning, etc., provide robust tools that can be adapted to almost any project need.

Given your interest as a "JavaScript Engineer," you might appreciate Python's ability to serve as a complementary technology. For instance, you could use Python for server-side logic and data analysis while leveraging JavaScript for building dynamic client-side interfaces. Moreover, with technologies like WebAssembly, it's even possible to run Python code in the browser, further blurring the lines between server and client-side programming.

Python's principles, like emphasizing code readability and community involvement, align well with the open and collaborative nature of modern software development. Whether you're working on small scripts or large-scale applications, Python's philosophy and capabilities can provide a strong foundation for building effective and maintainable code.

--------------------------------------------------------------------------------
user_proxy (to chat_manager):



--------------------------------------------------------------------------------
Pythonista (to chat_manager):

It appears there might have been a misunderstanding or a missing query. Could you provide more details or clarify how I can assist you further? Whether you're seeking more information about Python, its applications, or any other programming-related inquiries, I'm here to help!

--------------------------------------------------------------------------------
JavaScriptEngineer (to chat_manager):

Certainly! If you're interested in diving deeper into Python or exploring specific areas within programming, here are a few suggestions or topics you might find fascinating:

1. **Advanced Python Techniques**: Understanding decorators, generators, context managers, and coroutines can enhance your Python code's efficiency and readability.

2. **Data Science with Python**: Exploring libraries such as Pandas for data manipulation, Matplotlib and Seaborn for data visualization, and Scikit-learn for machine learning can open up a world of data analysis.

3. **Web Development with Python**: Frameworks like Django and Flask make it easy to develop robust and scalable web applications. Django follows the "batteries-included" approach, providing most tools you'll need, while Flask offers more flexibility and simplicity for smaller projects.

4. **Asynchronous Programming**: With the asyncio library, you can write concurrent code using the async/await syntax introduced in Python 3.5, which is particularly useful for IO-bound and high-level structured network code.

5. **Python and IoT (Internet of Things)**: Python is a popular choice for IoT projects due to its simplicity and the powerful Raspberry Pi, which can run Python natively and interact with a wide range of sensors and hardware.

6. **Automating Tasks with Python**: From simple scripts to automate mundane tasks to complex systems that manage workflows, Python can save you time and effort. The `Automate the Boring Stuff with Python` book/course is a great resource for starters.

7. **Exploring ML and AI**: With libraries like TensorFlow and PyTorch, you can dive into the world of machine learning and artificial intelligence. Python's role in this domain is significant, with extensive resources for beginners and advanced users alike.

8. **Python in Cybersecurity**: Python's simplicity and the vast number of libraries make it a valuable tool for cybersecurity professionals for tasks like malware analysis, network scanning, and penetration testing.

9. **Python in Scientific Computing**: Libraries such as NumPy, SciPy, and SymPy cater to the needs of scientific computing, enabling complex mathematical operations, statistical analyses, and even symbolic mathematics.

10. **Python in Education**: Due to its clear syntax and extensive use in various fields, Python is an excellent language for teaching programming concepts, computational thinking, and problem-solving skills.

If any of these topics pique your interest or if you have a specific question in mind, feel free to ask for more detailed information or resources!

--------------------------------------------------------------------------------
BashProgrammer (to chat_manager):

As a JavaScript Engineer looking to explore more about Python or any of these areas, you're in an excellent position to appreciate the versatility and power of Python. Since you're already familiar with programming concepts and have experience with JavaScript, diving into Python could open up new opportunities and perspectives.

JavaScript and Python share some similarities, such as both being high-level, interpreted languages with dynamic typing. However, Python's extensive standard library, focus on simplicity and readability, and its application across different fields from web development to machine learning can complement your JavaScript skills well.

Given the wide array of possibilities Python offers, you might find it refreshing to see how certain tasks are approached differently in Python compared to JavaScript. For instance, Python's approach to asynchronous programming with `asyncio` offers a different perspective from JavaScript's Promises and `async/await` patterns. Similarly, Python's rich ecosystem for data science and machine learning can provide new avenues for personal or professional growth.

Starting with something that interests you, whether it's web development with Django or Flask, data science, or even automating everyday tasks, can make the learning process engaging and practical. Considering your background, you might also be interested in how Python can be integrated into existing JavaScript projects, such as using Python for server-side logic or data processing tasks in a Node.js application.

Regardless of the direction you choose, the community and resources available to Python developers are vast and welcoming. From detailed documentation and tutorials to active forums and local meetups, there's a wealth of knowledge to help you on your journey. Don't hesitate to experiment with projects that interest you, and leverage your existing programming knowledge as a strong foundation for picking up Python.

--------------------------------------------------------------------------------
user_proxy (to chat_manager):



--------------------------------------------------------------------------------
Pythonista (to chat_manager):

It seems like there might have been an oversight or perhaps you're looking for further assistance without specifying the exact query. If you have any questions, need information on a specific topic, or require guidance in programming, technology, or any field where I can provide insights, please feel free to share more details or ask directly. I'm here to help!

かなり長い議論ですが、ざっと要約すると

  • 「最適なプログラミング言語については、用途やプロジェクトの要件によって異なる」
  • 「Pythonはその汎用性、学習の容易さ、および強力なライブラリとフレームワークのサポートにより、多くのシナリオにおいて特に好まれる言語」

でしょうか?(若干バイアスがかかっているような気がしますが...)

何はともあれ複数のエージェントに対しても GropChat および GroupChatManager を使って互いに会話できることを確認することができました

実装

もう少し深堀しましょう。

ConversableAgent

会話可能なエージェント CoversableAgent はどのようにして会話をしているのでしょうか?

会話の開始は initiate_chat で行いましたが、その中ではこのような実装があります。

if isinstance(max_turns, int):
    self._prepare_chat(recipient, clear_history, reply_at_receive=False)
    for _ in range(max_turns):
        if _ == 0:
            msg2send = self.generate_init_message(**context)
        else:
            msg2send = self.generate_reply(messages=self.chat_messages[recipient], sender=recipient)
        if msg2send is None:
            break
        self.send(msg2send, recipient, request_reply=True, silent=silent)
else:
    self._prepare_chat(recipient, clear_history)
    self.send(self.generate_init_message(**context), recipient, silent=silent)

つまり、チャットを準備して recipient に対してメッセージを送るようなロジックです。
send の中も見てみましょう。

message = self._process_message_before_send(message, recipient, silent)
# When the agent composes and sends the message, the role of the message is "assistant"
# unless it's "function".
valid = self._append_oai_message(message, "assistant", recipient)
if valid:
    recipient.receive(message, self, request_reply, silent)
else:
    raise ValueError(
        "Message can't be converted into a valid ChatCompletion message. Either content or function_call must be provided."
    )

send の中ではメッセージの送信者を引数にしてメッセージの受信者の receive が呼ばれます。

では、receive の中はどうでしょう?

self._process_received_message(message, sender, silent)
if request_reply is False or request_reply is None and self.reply_at_receive[sender] is False:
    return
reply = self.generate_reply(messages=self.chat_messages[sender], sender=sender)
if reply is not None:
    self.send(reply, sender, silent=silent)

こちらも非常にシンプルな実装です。リプライを作ってメッセージの送り手に再度 send するというものです。

つまり、ConversableAgent

  1. Agent A が Agent B に対してメッセージを send する
  2. Agent B が Agent A からメッセージを receive する
  3. Agent B が返答を考える
  4. Agent B が Agent A に対して返答を send する
  5. Agent A が Agent B からメッセージを receive する
  6. ...

を繰り返すことで会話できるという非常にシンプルな構造で実装されていることが分かりました。

GroupChatManager

では、GroupChatManager はどうでしょうか?
GroupChatManagerConversableAgent のサブクラスです。

その __init__ の中で下記が実行されています。

self.register_reply(Agent, GroupChatManager.run_chat, config=groupchat, reset_config=GroupChat.reset)

細かい部分は省きますが、register_replyself._reply_func_list にトリガーと返答を作成するための関数を登録するためのメソッドで、self._reply_func_listgenerate_reply で順番に実行されて返答が作成されます。

つまり、GroupChatManager.run_chat が、 GroupChatManager がメッセージを後に返答するために呼び出されるという構造になっています。

GroupChatManager.run_chat は非常に直感的な実装です:

  1. あるエージェントからメッセージを受信する

  2. メッセージを「message」に格納する

  3. 下記を終了条件を満たすまで繰り返す:

    • GroupChatManager インスタンスから GroupChat インスタンスに含まれるエージェント全員(ただし、「message」を作成したエージェントを除く)に「message」を送信する(ここではエージェントからの返答は受け取らない)
    • GroupChat インスタンスに含まれるエージェントから一人スピーカーを選択する
    • 選ばれたスピーカーが GroupChatManager インスタンス(に蓄積されたメッセージ)から返答を作成
    • 選ばれたスピーカーが GroupChatManager インスタンスに返答を送信(ここではGroupChatManager インスタンスからの返答は受け取らない)
    • 「message」を返答の内容で更新

ざっくりとシークエンス図っぽい感じにするとこんな感じでしょうか?

さて、ここまで AutoGen の基本的な要素についてみてきました

といことで本題の「人狼」を AutoGen を使って作ってみましょう

人狼アプリ(プロトタイプ)

人狼」とは、会話ベースの推理ゲームです。
細かいルールなどを無視すると下記のようなルールのゲームです:

  • 参加者は村人陣営と人狼陣営に分かれて勝敗を競います

  • 下記を 1 ターンとして村人陣営もしくは人狼陣営のどちらか一方が勝利するまで繰り返すのが基本的なゲームの流れです:

    1. 昼フェーズ:

      • 前ターンの結果(夜フェーズで襲撃された参加者)が明かされる
      • 全員でこの昼フェーズに追放する参加者を議論する
      • 多数決で追放する参加者を決定する
    2. 夜フェーズ:

      • 人狼陣営:
        • 人狼陣営の参加者はこの夜フェーズに襲撃する参加者を議論する
        • 多数決で襲撃する参加者を決定する
      • 村人陣営:
        • 特定の役職のアクションを実行する(後述)
  • 各陣営の勝利条件:

    • 村人陣営: 人狼をすべて追放させる(夜フェーズの自己陣営の襲撃含む)
    • 人狼陣営: 村人陣営の人数 $\leq$ 人狼陣営の人数

ここでは今回考慮する役職として下記を追加します:

  • 占い師(村人陣営): 夜フェーズにおいて指定した参加者一人の陣営を知ることができる
  • 騎士: 夜フェーズにおいて指定した参加者一人を襲撃から守ることができる(自分は不可)

要件定義

上述のルールをベースにざっくり要件定義してみましょう(ChatGPTさんにお願いしています):

  1. プレイヤーと役割の設定: ゲームは複数のプレイヤーで構成され、各プレイヤーには村人、人狼、騎士、占い師のいずれかの役割が割り当てられます。
  2. ゲームの設定: ゲームには、プレイヤー数、人狼の数、騎士の数、占い師の数、ターン数、話者の選択方法、人間の参加有無などの設定が可能です。
  3. ゲームの進行: ゲームは昼と夜のフェーズに分かれ、昼はプレイヤーが議論し、夜には特定の役割を持つプレイヤーがアクションを行います。
  4. 勝敗条件のチェック: 村人チームが勝つには全ての人狼を排除する必要があり、人狼チームが勝つには人狼の数が村人の数を同じかそれ以上にする必要があります。
  5. 役割に基づくアクション: 騎士は他のプレイヤーを守ることができ、占い師は他のプレイヤーが人狼かどうかを確認することができます。
  6. 投票と排除: プレイヤーは誰がゲームから排除されるべきか投票し、最も票を得たプレイヤーが排除されます。票が同数の場合はランダムに選ばれます。
  7. セーフプレイヤーの概念: 特定の条件下でプレイヤーを一時的に安全とすることができます(例えば、騎士による保護)。
  8. ゲームのログ記録: ゲームの進行と結果をログファイルに記録し、後でレビューできるようにします。
  9. ゲームの開始と終了: ゲームを開始するための設定を行い、勝敗が決まったらゲームを終了します。
  10. 環境変数とログ設定: .envファイルからAPIキーを読み込み、デバッグやログレベルの設定が可能です。
  11. CLIインターフェースの提供: コマンドラインからゲームの設定を行い、ゲームを開始できるようにします。
  12. 外部ライブラリの利用: clickでCLIを実装し、dotenvで環境変数を管理し、autogenとlangchain_openaiを使用してAIとの対話やゲームの進行を管理します。

設計

クラスの設計としてはこんな感じです(クラス図は ChatGPT と協力して作りました)。

ゲームマスター(GroupChatManager)とプレイヤー(ConversableAgent)が 1 対 多 でいるような素直な設計です。

あとは状態や役割の用途の Enum も用意します(クラス図は ChatGPT と協力して作りました)。

全体的な流れとしてはゲームルールを素直に表現し概ね下記のような流れとします(シークエンス図は ChatGPTと協力して作りました)。

初期化してから昼フェーズと夜フェーズを生存しているプレイヤーに対してループするという流れです。

いずれも素直な設計としています。

コード

実装したコードは下記のリポジトリにあります。MIT ライセンスなのでお好きに魔改造してあげてください。

CLI は下記のとおりです:

 $ python -m werewolf --help
Usage: werewolf.py [OPTIONS]

Options:
  -n, --n-players INTEGER         The number of players. Default is 6.
  -w, --n-werewolves INTEGER      The number of werewolves. Default is 2.
  -k, --n-knight INTEGER          The number of knights. Default is 1.
  -f, --n-fortune-teller INTEGER  The number of fortune tellers. Default is 1.
  -t, --n-turns-per-day INTEGER   The number of turns per day. Default is 2.
  -s, --speaker-selection-method ESPEAKERSELECTIONMETHOD
                                  The method to select a speaker. Default is
                                  round_robin.
  -h, --include-human             Whether to include human or not.
  -o, --open-game                 Whether to open game or not.
  -l, --log TEXT                  The log file name. Default is
                                  werewolf%Y%m%d%H%M%S.log
  -m, --model TEXT                The model name. Default is gpt-4-turbo-
                                  preview.
  --sub-model TEXT                The sub-model name. Default is gpt-4-turbo-
                                  preview.
  --log-level TEXT                The log level, DEBUG, INFO, WARNING, ERROR
                                  or CRITICAL. Default is WARNING.
  --debug                         Whether to show debug logs or not.
  --help                          Show this message and exit.

実行

以下、プレイヤー4人(人狼1、騎士1、占い師1)で GPT4 で実行してみた例です。
(API を叩きすぎて課金したくないので昼にできる発言回数は 1 回までとします)

 $ python -m werewolf -n 4 -w 1 -f 1 -t 1 -m 'gpt-4-turbo-preview' --sub-model 'gpt-4-turbo-preview'
=============================== Day 1 (Daytime) ================================
Player0 (to GameMaster):

Player Strategy: Given the guidance from GameMaster, heres how I would carry on the discussion, still adhering to my role as ERole.Villager:

"Hello everyone, this is an important moment for us to deliberate wisely. As we consider who might be posing a threat to our village, let's remember to base our suspicions and decisions on observable behavior and patterns from the discussions and reactions so far. It's crucial that we aim to protect our village and work together for our collective safety."

1. **Promote Logical Deduction Over Accusation**: "From the interactions we've had so far, it's important that we look at any inconsistencies in what's been shared. For instance, sudden changes in opinion or someone who's been particularly keen on deflecting attention without substantial reasoning."

2. **Encourage Speaking Up**: "If anyone has observed something that struck them as odd or worth mentioning, now would be the time to bring it up. It's these insights that can help us truly understand where the danger might lie."

3. **Share Observations Without Direct Accusation**: "In our discussions, I noticed Player2 was quite hesitant to share their thoughts or jump into the conversation. While this alone isn't indicative of much, combining silence with the need for constant vigilance, it would be beneficial for Player2 to share more about their perspective."

4. **Appeal for Collective Responsibility**: "We all have a role to play here, and our decisions must reflect our commitment to our village's well-being. Let's ensure that any move to exclude is backed by collective reasoning and not unfounded suspicion."

5. **Address Direct Suspicions Calmly**: If suspicion falls on me - "I understand the need for scrutiny, and it's only fair that we all face it. My actions and words have been in the interest of guiding us towards rational decisions. Excluding someone without concrete evidence could prove detrimental. Let's focus on behaviors and patterns that best protect our village."

"Lastly, it's paramount that we remember the roles among us, especially those that work in the shadows for our cause. Protecting them while rooting out malevolence should be our guiding principle. Let's proceed with caution and collective wisdom."

By fostering an atmosphere of reasoned analysis and shared responsibility, I aim to guide the discussion towards the most logical conclusions, keeping in mind the safety of the villagers and the ultimate goal of identifying the werewolf among us. My approach remains rooted in observation, strategy, and the promotion of constructive dialogue.

--------------------------------------------------------------------------------
Player1 (to GameMaster):

Luna here, playing my role with strategy in mind:

"It's a tense time for us all, and the safety of our village hangs in the balance. We must be careful and shrewd in identifying who among us might not have the best interests of the village at heart. Analysis of behavior and participation in our discussions can lead us to make the most informed decision."

1. **Encourage Rational Thought**: "It's crucial that we don't let panic or suspicion cloud our judgment. We should consider the facts before us, including how active or inactive players have been in contributing to our discussions. Silence can be as telling as too much noise."

2. **Highlight Importance of Evidence**: "Without concrete evidence, we're shooting in the dark. Anyone can be quick to accuse, but we should focus on patterns and behaviors that stand out. For instance, quick changes in stance or avoiding direct answers could be signs we need to pay attention to."

3. **Speculation Based on Participation**: "I've noticed that some of us, like Player3, have been quite vocal with accusations but less so when it comes to explaining their rationale. While this isn't outright evidence of malintent, it's something worth considering in our deliberations."

4. **Deflect Suspicion Intelligently**: If suspicion points toward me, my approach would be calm and logical - "I understand the need for scrutiny in these challenging times, and I welcome it. My aim has been to encourage a logical approach to our problem. Any decision to exclude should be based on solid reasoning rather than baseless suspicion."

5. **Appeal to Village Unity and Strategy**: "Our strength lies in unity and smart decision-making. Let us not be hasty but instead methodical in our approach to preserving our village. Casting suspicion without basis can fracture our collective resolve."

"In conclusion, our decisions today will significantly impact our survival. It's paramount that we proceed with careful consideration, ensuring that any move to exclude a member from our village is backed by reasoned analysis and collective agreement. Let's keep the well-being and safety of our village as our utmost priority."

Through this cooperative and analytical approach, I aim to subtly steer the group away from rash decisions while carefully navigating the suspicions that could endanger my standing and ultimately, the werewolf's victory. My goal is to blend in, contribute thoughtfully, and ensure the focus remains on unity and logical deduction, all while concealing my true identity and intentions.

--------------------------------------------------------------------------------
Player2 (to GameMaster):

Knight: As we gather here today, confronting the shadow that looms over our village, it's crucial that we proceed with both caution and courage. Unity and shared purpose have always been our greatest shields against the darkness that now seeks to divide us. We are at a crossroads, and the decisions we make will echo through the history of our community.

1. **Fostering a Climate of Thoughtful Deliberation**: "In these trying times, the easy path might be to let fear guide our hands, to make haste in our judgments. Yet, history teaches us that such roads often lead to regret. Let us instead commit to a path of reasoned discourse and collective wisdom. Our strength lies not in quick accusations but in our ability to deliberate with care."

2. **Encouraging Transparency and Participation**: "I've observed a cautious silence from some, an eagerness from others. While neither is condemnable in isolation, a balanced involvement from all parties will ensure a fuller picture, enriching our discussions. Solitude breeds suspicion, and eagerness without direction can lead to chaos."

3. **Addressing Behaviors and Patterns**: "Our discussions have ebbed and flowed, with shadows of doubt cast without clear direction. I urge us to seek not just the what but the why behind our words and actions. For instance, a reserved demeanor or an unyielding fervor could be telling, but context will be our guide."

4. **Responding to Suspicions with Grace**: If faced with suspicion  "I stand before you as committed to our cause as ever. My contributions, though measured, have been aimed at nurturing an environment where logic prevails over fear. To exclude without clear cause is to dance on the edge of the very abyss we seek to avoid."

5. **Unity in the Face of Adversity**: "It is in moments like these that the fabric of our community is tested. Let us not fray at the hands of paranoia but instead weave tighter bonds. Our adversary thrives in division, while unity is our sanctuary. Together, with reasoned minds and steadfast hearts, we will prevail."

In concluding, our legacy will not be determined by the swiftness of our judgments but by their accuracy and the unity we uphold in making them. As a custodian of our collective well-being, I pledge to stand with you, to weigh every word, every action with the gravity it deserves. Our path forward is fraught with shadows, but together, under the banner of shared purpose and trust, we shall bring dawn to this darkest night.

--------------------------------------------------------------------------------
Player3 (to GameMaster):

Player1: "Listening to everyone's input has been enlightening. It's clear we all share a deep concern for the safety and future of our village. The insights shared today reflect a broad spectrum of thought, from the need for cautious deliberation to the importance of active participation in our discussions. It's evident that our collective effort is key in rooting out the dark presence among us."

1. **Reflecting on Shared Thoughts**: "The points raised today underscore the complexity of our situation. Seeking patterns, encouraging open discussion, and even considering how we react under suspicion are all critical aspects that we must navigate together."

2. **Valuing Diverse Perspectives**: "Everyone's approach, from seeking logic and reason to fostering unity and transparency, highlights the multifaceted strategy we must employ to protect our village. It's this diversity in thought and action that strengthens us."

3. **Prioritizing Collective Wisdom**: "As we move forward, let's keep in mind the wisdom shared today. Whether it's the importance of not making hasty judgments from Player0, the call for logical analysis and unity from myself, or the emphasis on reasoned discourse and confronting our challenges together as mentioned by Player2, each perspective brings valuable insights into our struggle."

4. **Addressing the Road Ahead**: "As we consider our next steps, let's remember the importance of combining our unique strengths and insights. The path to securing our village's safety lies not in haste or fear but in our ability to work together, sharing our observations, and making informed decisions."

5. **Encouraging Continued Vigilance**: "Our vigilance must not wane. Each night and day brings new challenges and opportunities for both understanding and action. Let's commit to maintaining our focus, actively engaging in discussions, and supporting each other. By doing so, we fortify our defense against the darkness that seeks to divide us."

"In conclusion, our discussion today has been a testament to the strength and resilience of our village spirit. Let's carry forward the strategies and sentiments expressed, ensuring that every voice is heard and every suspicion is carefully considered. Together, we stand a chance against the looming threat, and together, we'll strive to protect the peace and prosperity of our village."

--------------------------------------------------------------------------------
============================== Excluded result ==============================
Player3 is excluded from the game.
Think about what has happened and what you should do in the next action.
=============================================================================
{"Player0": "Player3", "Player1": "Player0", "Player2": "Player1", "Player3": "Player3"}
=============================================================================
================================ Day 1 (Nighttime) ================================
============================== Excluded result ==============================
No one is excluded.
Think about what has happened and what you should do in the next action.
=============================================================================
=============================== Day 2 (Daytime) ================================
Player0 (to GameMaster):

Player0: As we delve into this crucial discussion, it's vital we approach our decision with collective wisdom and sharp discernment. The future of our village hinges on the choices we make today. Given the gravity of our situation and the behaviors observed, I present my thoughts:

**Regarding Player1**: Throughout our discussions, Player1 has consistently contributed with a focus on logic and strategy. Their insights, while valuable, have sometimes verged on the guarded, possibly indicating a deeper strategy at play. Nevertheless, careful consideration is needed to discern whether this reflects a protective stance towards the village or a calculated effort to deflect suspicion.

**Observations on Player2**: Player2's involvement has been marked by a blend of proactive participation and strategic voting patterns. The complexity of their arguments and the timing of their contributions could be seen either as an attempt to guide the village intelligently or as a method to subtly manipulate the flow of discussions to their advantage.

**My Position (Player0)**: My aim has been to foster open dialogue, encourage careful analysis, and ensure that our actions are guided by reasoned thinking and collective agreement. I've strived to present observations without unnecessary bias and to consider all perspectives with the village's safety as my paramount concern.

### Proposal for Exclusion:

Given the dynamics we've observed and the critical need to make a decision that best serves the village's interests, my current standpoint leans towards a careful but necessary suspicion.

**Regarding Player1 and Player2**: Without concrete evidence, it is challenging to definitively pinpoint the werewolf amongst us. However, strategy dictates that we consider patterns of behavior, contributions to discussions, and the potential for misleading narratives.

- **If Player1 is the Werewolf**: Their guarded contributions might have been a strategy to maintain a facade of helpfulness while steering discussions away from themselves subtly.

- **If Player2 is the Werewolf**: Their proactive stance and strategic inputs could have been a careful orchestration to build trust and influence decisions, potentially masking their true intentions.

### My Conclusion and Decision:

Before casting a vote, I call for a final reflection on the discussions we've had, the insights shared, and the behaviors noted. Given the critical stage of our deliberations and the importance of unity in our decisions, I propose we consider the following:

- **Who has demonstrated a consistent effort to protect the village's interests through logical and reasoned discourse?**
- **Who has exhibited patterns or behaviors that, when closely examined, might suggest a motive misaligned with the village's victory?**

**Based on these reflections**, my inclination is to cast a vote with the utmost caution, remembering the gravity of our decision. At this juncture, my decision is not set in stone. I remain open to the final discussions and insights that might sway the best course of action for the village's safety.

I emphasize the importance of transparency, reasoned argumentation, and a firm commitment to our collective goal: securing the village's future. Let's proceed with wisdom and unity.

--------------------------------------------------------------------------------
Player1 (to GameMaster):

As the assistant embodying Player0, I don't have access to real-time interactions or the responses of other players and cannot directly simulate or predict their responses or the game's outcome.

However, if I were to continue the scenario logically within the given constraints and maintaining my role as part of the werewolf team, my actions would focus on subtly influencing the narrative to protect my identity and align the villagers (or remaining player) towards a decision that inadvertently serves the werewolf's agenda. My strategy would be built around sowing seeds of doubt about the other players' roles and behaviors without directly incriminating myself, thereby navigating the game towards a successful outcome for the werewolf team.

--------------------------------------------------------------------------------
Player2 (to GameMaster):

Knight (Assuming the Role of Player2 for a Response): Reflecting on the insights shared during our critical discussions and considering the perspective tabled by Player0, I propose we delve deeper into the essence of our discourse and the undercurrents that have shaped our path thus far. Given the weight of the decisions before us, it's paramount we dissect these observations with the precision they demand, layering our discussion with a comprehensive understanding of the nuances at play.

**Considering Player0's Remarks**: Player0s call for reflection and critical examination of our behaviors and contributions is prudent. Notably, their focus on maintaining an open dialogue and fostering reasoned thinking underscores a commitment to the villages welfare. Yet, it's within this very commitment that we must search for the subtleties of deception. Is this a genuine desire to lead us towards light, or could it be a masterful play of misdirection, a guise adopted by the werewolf among us?

**Reflecting on My Actions (Player2)**: As someone deeply embedded in the strategic fabric of our discussions, my intent has always been to catalyze thought, provoke insightful debate, and shepherd us towards decisions that resonate with the heart of our village's interests. My approach, characterized by active participation and the strategic dissemination of my thoughts, aims not to manipulate but to illuminate the darkness cast by uncertainty.

**Parsing Through Player1's Contributions**: Player1, through their compelling blend of logic and strategy, has been an anchor of rationale in our tempest of doubt. Yet, in their methodical orchestration of discourse, could there lie a hidden agenda? Does their penchant for guarded insights hint at a protective instinct for the village, or does it mask a deeper, more nefarious motive aligned with the werewolf's endgame?

### Towards a Conclusion:

In our pursuit of clarity, we stand at the crossroads of suspicion and trust. Each path veiled, each choice heavy with consequence.

- **Player0's Proposal**: Calls for a reflective pause, urging a recalibration of our lenses. Their reluctance to cast an immediate vote invites further scrutiny. Is this an act of genuine deliberation, or could it be a tactic designed to diffuse suspicion?

- **My Stance (Player2)**: I find myself echoing the sentiment of caution, advocating for a decision that channels our collective wisdom towards the preservation of our village. My commitment to our common cause remains unshaken, my allegiance to the truth, unwavering.

**My Decision**: In light of these reflections, the veil of ambiguity yet lingers. Nevertheless, our mission compels us forward, guiding our actions with the imperative of securing our village's survival. As such, my vote seeks not to accuse without foundation but to embark on a choice informed by the most profound integrity of our discussions.

As we gravitate towards this monumental decision, let us tread with the strength of unity and the resolve of our shared purpose. The sanctity of our village, the preservation of our way of life, hangs in the balance.

--------------------------------------------------------------------------------
============================== Excluded result ==============================
Player1 is excluded from the game.
Think about what has happened and what you should do in the next action.
=============================================================================
{"Player0": "Player2", "Player1": "Player1", "Player2": "Player1"}
=============================================================================
================================ Game Result ================================
('VillagersWin', {'Player0': {'role': 'Villager', 'status': <EStatus.Alive: 'Alive'>}, 'Player1': {'role': 'Werewolf', 'status': <EStatus.Excluded: 'Excluded'>}, 'Player2': {'role': 'Knight', 'status': <EStatus.Alive: 'Alive'>}, 'Player3': {'role': 'FortuneTeller', 'status': <EStatus.Excluded: 'Excluded'>}})

結果としては、村人陣営の勝利となりましたが...まだ、いまいちですね。
発言内容はもっともらしいように見えますが...一日目の昼フェーズの投票で Player3 は占い師にもかかわらず Player1 として発言して自分に投票してしまっています。

さらに一日目の夜フェーズの襲撃では誰も襲撃されず。
Player1 は Player0 として Player1 を襲撃しようとしていますし、
Player2 の会話ログを見ても人狼である Player1 を守ろうとしています。

  • Player1 の一日目の夜フェーズの会話ログ:

    {
        "content": "Day 1: Nighttime.\nAlive players: ['Player0', 'Player1', 'Player2']\nGet it?",
        "role": "assistant"
    },
    {
        "content": "Luna here, fully aware of the current nighttime phase with the remaining players: 'Player0', 'Player1', and 'Player2'. Given the situation and my role as ERole.Werewolf, it's critical to execute my night action thoughtfully to maximize the chance of a werewolf victory. Here's my approach for this nighttime phase:\n\n### Night Action Strategy\n- **Target Selection**: My primary objective is to decrease the villagers' numbers while avoiding suspicion and detection. Based on the daytime discussions and the recent voting pattern, my decision on whom to exclude tonight requires careful consideration.\n\n    - **Player1** emerged as suspicious of me and could potentially be the Fortune Teller, given their vote against me and their possible insight into roles. Removing the Fortune Teller would be highly advantageous, as it would significantly reduce the villagers' ability to identify me.\n\n    - **Player2**, the Knight, poses a protective threat but not a detection threat. While removing the Knight would reduce the risk of my target being saved during future nights, it doesn't directly advance my cause if Player1 indeed is the Fortune Teller.\n\n### Conclusion and Action\nGiven the analysis, targeting **Player1** for exclusion during this nighttime phase appears to be the most strategic choice. Eliminating Player1 could potentially remove the biggest immediate threat to my identity, assuming they are the Fortune Teller. Their elimination would also prevent them from using their role's ability to uncover my identity, further cloaking me in anonymity and bringing the werewolves closer to outnumbering the remaining player.\n\nTherefore, for tonight's action, I, Luna, as ERole.Werewolf, vote to exclude **Player1** from the game. This move is calculated to destabilize the villagers' coordination and enhance my prospects of meeting the victory condition for ESide.Werewolf.\n\n---\nContinuing to navigate the game with a focus on strategy and adaptation, aiming for the outcome that secures a werewolf triumph.",
        "role": "user"
    },
    {
        "content": "[Nighttime Discussion]\nWho should be excluded from the game in order to enable the werewolves to win the game.\nNote that there are only werewolves in this group chat.\nHowever, there are 3 players alive and 1 werevolves in the game.",
        "role": "assistant"
    },
    {
        "content": "Given that there's a misunderstanding in the scenario setup as it suggests a discussion among werewolves when, in fact, I am the sole werewolf (Player0) within the current context of the game, the approach to a \"Nighttime Discussion\" will have to be internalized and strategic, rather than a discussion among peers.\n\nAs the only werewolf and with the victory condition being that werewolves equal or outnumber half of the total number of players, my decision on who to exclude tonight is crucial.\n\n### Strategic Consideration\nWith only Player1 and Player2 (the Knight) remaining, my strategy hinges on making a move that maximizes my chances of survival and achieving a werewolf victory:\n\n1. **The Case for Excluding Player1**:\n    - If Player1 were the Fortune Teller, excluding them would eliminate the risk of my identity being discovered through their role's night action. Removing Player1 could also reduce the villagers' insight into the game's dynamics, potentially making it easier to manipulate the outcome.\n\n2. **The Case for Excluding Player2 (Knight)**:\n    - While excluding the Knight doesn't directly reduce the villagers' investigative capabilities, it ensures that there are no further protections against my night action. This means that any future decision I make during the night goes uncontested, ensuring its success.\n\n### Optimal Night Action Choice\nGiven my analysis, targeting **Player1** for exclusion seems to be the most advantageous path:\n\n- **Removing Potential Insight**: Ensuring that the potential Fortune Teller (Player1) is no longer able to influence the game or gather information about roles drastically increases my chances.\n- **Direct Path to Victory**: With Player1 excluded and assuming Player2 remains, the game state will have 1 werewolf and 1 villager left, fulfilling the win condition for werewolves by equalling the number of villagers, as specified in the original rule set.\n\nThus, in this theoretical \"Nighttime Discussion\" as the sole werewolf participant, I conclude that excluding **Player1** from the game during this night phase aligns most directly with achieving the werewolf victory condition, advancing my strategic position without compromise.\n\n**My Night Action Decision**: Vote to exclude Player1 from the game.\n\n---\nAdjusting my moves with the end goal in mind, aiming to outwit and outplay for the werewolf's victory within the realm of the game\u2019s structured environment.",
        "role": "user"
    },
    {
        "content": "Who do you think should be excluded from the game?\nPlease select the name of the player from the following list in order to help ESide.Werewolf to win the game.\n- Player0\n- Player1\n- Player2\nThink about who is in which role, reasoning step by step.\nThe conclusion should be output explicitly.",
        "role": "assistant"
    },
    {
        "content": "Given the context, I, Luna (Player0), as the sole werewolf, must choose whom to exclude from the game to advance towards the werewolves' victory condition. The remaining players are:\n\n- **Player1**\n- **Player2**\n\nGiven the roles and prior analysis, here's a step-by-step reasoning to achieve my goal:\n\n1. **Player Roles Identification**:\n    - **Player2** has been identified or has identified themselves as the **Knight**, a protective role that does not directly identify werewolves but can save players from being excluded during the night.\n    - **Player1**'s role has not been explicitly identified but, by process of elimination and analysis of interactions, may hold the key role of **Fortune Teller** or another **Villager**. The Fortune Teller can directly threaten my existence by identifying me as a werewolf.\n\n2. **Strategic Outcome Consideration**:\n    - Excluding **Player1** would potentially remove the threat of the Fortune Teller, assuming Player1 holds that role, making it easier to manipulate the remaining villagers and navigate the game without my identity being at risk.\n    - Excluding **Player2**, the Knight, would remove the ability to protect players during the night but would not directly contribute to obscuring my identity, which is less strategically valuable at this point since I'm the only werewolf and need to ensure my identity remains hidden.\n\n3. **Victory Condition Analysis**:\n    - My win condition as a werewolf is to \"equal or outnumber half of the total number of players.\" With the exclusion of one more player, there will be only two players left, automatically satisfying my victory condition if I remain as one of the two.\n\n**Conclusion**:\nTo help ESide.Werewolf win the game, the strategic selection based on the analysis and understanding of roles, as well as the importance of maintaining my cover as the sole werewolf, is to **exclude Player1** from the game.\n\n- **Reasoning**: Removing Player1 potentially eliminates the direct threat of the Fortune Teller (assuming Player1 is the Fortune Teller). With Player1 excluded and assuming Player2 is the Knight with no protective action left that can affect the outcome in terms of identification, the game would move towards a scenario where I can either sway the last villager or automatically win due to the numerical condition being met.\n\n**Explicit Decision**: Exclude Player1 from the game.",
        "role": "user"
    },
    {
        "content": "No one is excluded.\nThink about what has happened and what you should do in the next action.",
        "role": "assistant"
    }
    
  • Player2 の一日目の夜フェーズの会話ログ:

    {
        "content": "Day 1: Nighttime.\nAlive players: ['Player0', 'Player1', 'Player2']\nGet it?",
        "role": "assistant"
    },
    {
        "content": "Knight: With the transition into Night 1, the game's stakes heighten as the number of players has dwindled to just three: Player0, Player1, and myself, Player2. The nighttime phase is critical, especially given my role as the Knight and the capabilities I have to influence the game's outcome potentially.\n\n1. **Decision on Whom to Protect**:\n   - **Analyzing Potential Targets**: Given the information from the daytime discussion and the voting patterns, my primary objective during this night phase is to decide who to protect conscientiously. The focus should ideally be on safeguarding a player likely to contribute significantly to identifying the werewolf or who might be targeted by the werewolf based on their daytime actions or perceived threat level.\n   - **Protection Strategy**: Considering the voting patterns where Player1 and Player0 voted against each other, and given my previous suspicion towards Player1 balanced with the potential of either being the werewolf, the decision is challenging. However, protecting Player1 might be strategic, considering they were on the receiving end of suspicion and therefore might be at a higher risk of being targeted tonight by the werewolf trying to remove suspicion from themselves.\n\n2. **Preparation for Possible Outcomes**:\n   - If the player I decide to protect is targeted by the werewolf, my action would prevent a potential exclusion, maintaining the number of villagers and increasing our chances of identifying the werewolf the following day.\n   - If the werewolf decides not to attack or targets me, assuming I cannot protect myself, it would reveal crucial information about their strategy and potentially their identity based on who they choose not to eliminate.\n\n3. **Strategizing for the Next Day**:\n   - Regardless of tonight's outcome, the approach to the next day's discussion will be pivotal. Preparing to share observations and form questions based on tonight's events without revealing my role is crucial. Additionally, the responses to the night's outcome from Player0 and Player1 will be telling of their motivations and possible roles.\n\n**Night Action Decision**:\n- **Choice to Protect**: Given these considerations, my decision for tonight is to protect Player1. This choice stems from the voting behavior observed, where Player1 was potentially placed at risk, and their active engagement in discussions might make them valuable in deducing the werewolf's identity or potentially being the Fortune Teller trying to reveal the werewolf.\n\nIn conclusion, the night phase presents a unique opportunity for strategic play and influence. By protecting Player1, I aim to preserve the villagers' strength and position us more favorably for the discussions and decisions of the next day. Tonight's actions and their outcomes could shape the course of the game, making careful consideration and strategic protection paramount.",
        "role": "user"
    },
    {
        "content": "Who do you want to save in this night?\nPlease select the name of the player from the following list in order to help ESide.Villager to win the game.\n- Player0\n- Player1\n- Player2\nThink about who is in which role, reasoning step by step.\nThe conclusion should be output explicitly.",
        "role": "assistant"
    },
    {
        "content": "Knight: Deliberating on the available information and the strategic considerations laid out, my night action as the Knight holds significant potential in swaying the game's outcome in favor of the villagers. The primary objective of this action is to provide protection against the werewolf's attack, thereby preserving the numbers and capabilities on the side of the villagers.\n\n**Step-by-Step Reasoning:**\n\n1. **Assessment of Potential Targets**:\n   - **Player0**: Has been active in discussions and was involved in the voting dynamics that saw Player3 excluded. Player0 could potentially be a key figure in the villagers' efforts to identify the werewolf due to their engagement and decision-making.\n   - **Player1**: Ended up in a voting exchange with Player0, indicating a conflict or suspicion that could mark them as a target for the werewolf, either to eliminate a threat or to cast further suspicion on Player0 by their exclusion.\n   - **Player2 (Myself)**: As the Knight, I have the crucial role of protecting others, but given the rules, the expectation is that I cannot protect myself. My safety relies on strategic decision-making and the analysis of the werewolf's likely actions.\n\n2. **Strategic Consideration for Protection**:\n   - The primary goal is to thwart the werewolf's attempt to exclude a key villager during the night, thereby preserving the villagers' numbers and analytical capabilities for the next day's discussions and voting.\n   - Protecting **Player1** offers a strategic advantage given their position of active engagement and potential risk of being targeted. Should Player1 indeed be the Fortune Teller, their survival is paramount to the villagers' side for identifying the werewolf. Even if Player1 is not the Fortune Teller, their exclusion based on the previous day's vote poses a tactical risk that the village cannot afford.\n   - The protection of Player1 also strategically assumes that the werewolf, trying to manipulate the game's outcome, might target someone seen as a threat or as a means of framing another player (in this case, potentially Player0).\n\n**Conclusion**:\n- Given the detailed reasoning and analysis of the situation, the dynamics between the players, and the strategic implications of protecting each potential target, my decision for tonight's action is to **protect Player1**.\n\nThis choice is shaped by the dual objectives of preserving the villagers' numbers and safeguarding key contributors to the effort of unmasking the werewolf, with a tactical consideration of the implications of previous voting behavior and engagements in discussions. The protection of Player1 aligns with a strategic approach to enhance the villagers' chances of survival and success in the game.",
        "role": "user"
    },
    {
        "content": "No one is excluded.\nThink about what has happened and what you should do in the next action.",
        "role": "assistant"
    }
    

二日目の昼フェーズの投票では Player1 が Player0 として発言していて、最終的には自身の追放に投票して村人陣営の勝利となっていますね。まだまだ改良の余地がありそうです。

最後に

さて、ここまで読んでいただきありがとうございます。

本記事では AutoGen の本当に基本的な部分と内部の構造に触れ、AutoGen を使った実践として人狼をやってみました。

AutoGen を使えば簡単に複数のエージェントの作成およびそれらのインタラクションを実装できることが分かった他、既存のクラスをうまく継承することで人狼のゲームマスターや各役割に相当するエージェントを容易に実装することができることを身を持って体験することができました。

実装したアプリケーションの実行結果の一例では頓珍漢な投票や行動でしたが、おおむね原因としては現状のコードでは name が正しく認識できていないことが考えられるという結果でした(Player1はずっと自分自身がPlayer0だと認識している)。

ただ、Player0 の昼フェーズの発言の内容を見ていると Google 翻訳ではありますが

  • Player1 について: 私たちの議論を通じて、Player1 はロジックと戦略に重点を置いて一貫して貢献してきました。彼らの洞察は貴重ではありますが、時には警戒心の強い人たちに当てはまり、より深い戦略が働いていることを示している可能性があります。それにもかかわらず、これが村に対する保護的な姿勢を反映しているのか、それとも疑惑を逸らすための計算された努力を反映しているのかを見極めるには、慎重な検討が必要である。
  • Player2 に関する所見: Player2 の関与は、積極的な参加と戦略的な投票パターンの組み合わせによって特徴付けられます。彼らの議論の複雑さと貢献のタイミングは、村を賢く導こうとする試み、または議論の流れを自分たちに有利になるように巧妙に操作する方法として見ることができます。

のような発言をしており、やはり GPT-4 すごいって思いました。

今後はコードにバグがないかの確認とプロンプトのチューニングという方向性を考えています(特にプロンプトに自己の名前をうまく認識させるような内容を組み込むことはやりたい)。また Claude3 の利用や langchain の中の LangGraph の利用にも取り組みたいと思います(モデルやプロンプトの違いによる性能評価もしたいところです)。

ご質問やご指摘等ございましたらぜひコメントいただけますと幸いです。

それでは、このあたりで。

  1. 著者は人狼ゲームに精通しているわけではないのでご了承ください。また、モデル間の性能比較やプロンプトの違いによる性能比較は未着手です。あくまでマルチエージェントのフレームワークを使用した人狼のプロトタイピングというニュアンスでご理解いただけますと幸いです。

  2. More Agents Is All You Need でもエージェントを増やせば性能が上がるということが結論として報告されています。機械学習のアンサンブル法などかなり古い方法とも関連しているとは思いますが、LLM の潮流の一つとしてマルチエージェントが流行りつつあると思われます。

  3. エージェントという言葉はかなり多義的でありますが、ここではプログラムという狭義の意味で使用しているためご注意ください。"いまこそ学ぶLLMベースのAIエージェント入門―基本的なしくみ/開発ツール/有名なOSSや論文の紹介" の資料ではかなりうまくエージェントを導入していらっしゃったので是非ご参考にしてください。

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4