AutoGen v0.2, v0.4でマルチエージェントを構築する

AutoGen v0.2とv0.4でのマルチエージェントの構築を試したので、実装方法を紹介します。

以前、Semantic Kernelで構築したマルチエージェントをもとに、AutoGenで同様のシステムを構築します。

Semantic Kernelでのマルチエージェントの構築は以下の記事をご確認ください。

blog.jbs.co.jp

AutoGenの概要

AutoGenは、Microsoft Researchによって公開された、LLMを活用しマルチエージェントのシステムを手軽に実装できるオープンソースのフレームワークです。

以前利用したSemantic Kernelはエンタープライズ向け、今回利用したAutoGenは概念検証やアイディエーションに最適なフレームワークとなっています。

AutoGenを活用してみた所感としては、手軽に構築が可能なため、様々なマルチエージェントのデザインパターンを試すには最適なフレームワークだと感じました。

v0.4はこの記事を書く際に、急遽v0.2から書き換えましたが、v0.2よりシンプルにマルチエージェントの構築ができるようになったと感じました。

AutoGenに関して詳しくは以下を参照ください。

microsoft.github.io

マルチエージェントの実装

今回はAutoGen v0.2とv0.4の実装方法を紹介します。

v0.4に関しては以下を参考にしました。

microsoft.github.io

qiita.com

v0.2

開発環境の準備
pip install autogen
pip install autogen-agentchat~=0.2
toolの定義

ローカルのRAGを利用するtoolを定義します。

構築方法は「Semantic Kernel Agent Frameworkでマルチエージェントを構築する(2/2):マルチエージェントの構築」でご確認いただけます。

※マルチエージェントの動きのみを確認したい場合は、RAGの代わりにシンプルな文字列を返すメソッドなどを定義することも可能です。

# 複数のRAGPluginを追加するため、親クラスを定義
class BaseRAGPlugin:
    def __init__(self, vectorstore_path: str):
        self.embeddings = AzureOpenAIEmbeddings(
            azure_deployment=os.getenv("AZURE_OPENAI_EMBEDDING_DEPLOYMENT"),
        )
        self.vectorstore_faiss = FAISS.load_local(
            vectorstore_path, self.embeddings, allow_dangerous_deserialization=True
        ) # ベクターストア(FAISS)のデータベースをロード


class InternalDocumentationOfSalesRAGPlugin(BaseRAGPlugin):
    '''
    営業に関するドキュメントのRAG plugin
    '''
    def __init__(self):
        super().__init__("./faiss-db")
        self.prompt = PromptTemplate(
            template=(
                "あなたは営業に関するAIアシスタントです。以下のコンテキストを考慮してください:\n"
                "{context}\n\n"
                "次の質問に答えてください:\n"
                "{question}\n\n"
                "アシスタント:"
            ),
            input_variables=["context", "question"],
        )

    def search(self, query: str) -> str:
        retriever = self.vectorstore_faiss.as_retriever()
        context = retriever.invoke(query)
        # プロンプトを利用してクエリに対する応答を生成
        prompt_text = self.prompt.format(context=context[0].page_content, question=query)
        return prompt_text


class InternalDocumentationRAGPlugin(BaseRAGPlugin):
    '''
    社内規定に関するドキュメントのRAG plugin
    '''
    def __init__(self):
        super().__init__("./faiss-company-rule-db")
        self.prompt = PromptTemplate(
            template=(
                "あなたは社内規定に関するAIアシスタントです。以下のコンテキストを考慮してください:\n"
                "{context}\n\n"
                "次の質問に答えてください:\n"
                "{question}\n\n"
                "アシスタント:"
            ),
            input_variables=["context", "question"],
        )

    def search(self, query: str) -> str:
        retriever = self.vectorstore_faiss.as_retriever()
        context = retriever.invoke(query)
        # プロンプトを利用してクエリに対する応答を生成
        prompt_text = self.prompt.format(context=context[0].page_content, question=query)
        return prompt_text


# 営業用ツールを定義
def search_sales_tool(input: Annotated[str, "Input to the sales search tool."]) -> str:
    """
    Tool for searching internal sales documentation.
    """
    sales_rag_plugin = InternalDocumentationOfSalesRAGPlugin()
    result = sales_rag_plugin.search(input)
    return result


# 社内規定用ツールを定義
def search_rules_tool(input: Annotated[str, "Input to the rules search tool."]) -> str:
    """
    Tool for searching internal company rules documentation.
    """
    rules_rag_plugin = InternalDocumentationRAGPlugin()
    result = rules_rag_plugin.search(input)
    return result
LLMの定義
# LLM への接続設定を環境変数から読み込む。
llm_config = {
    "config_list": [
        {
            "model": os.getenv("AZURE_OPENAI_DEPLOYMENT"),
            "api_type": "azure",
            "api_key": os.getenv("OPENAI_API_KEY"),
            "base_url": os.getenv("AZURE_OPENAI_ENDPOINT"),
            "api_version": os.getenv("OPENAI_API_VERSION"),
        }
    ]
}
エージェントの定義

複数のエージェントを定義します。

company_rule_expertとsales_expertに先ほど定義したtoolを割り当てます。以下のコードではtoolの結果がそのままエージェントの回答として応答されます。

回答するエージェントの選択はdescriptionをもとに行われるため、エージェント定義後に追加します。

# ユーザーの代理となるエージェント (user_proxy) を定義
user_proxy = UserProxyAgent("user_proxy",
                            code_execution_config=False,
                            human_input_mode="NEVER",
                            is_termination_msg=lambda msg: msg.get("content") is not None
                            and "TERMINATE" in msg["content"]
                            )

supervisor = AssistantAgent(
    "supervisor",
    llm_config=llm_config,
    system_message="""あなたは会話を管理するエージェントです。
        他のエージェントからの回答から最終的な結論を導き出してください。
    
        文の最後に TERMINATE を含めてください。""",
)

summarize_agent = AssistantAgent(
    "summarize_agent",
    llm_config=llm_config,
    system_message="""
        これまでのエージェントからの回答を要約し、エージェントの意見の同じ点と食い違う点、そこから導き出される結論を回答する。
        エージェントの意見の同じ点と食い違う点を記載する際には、どのエージェントからの回答か明記する。
        """
)


company_rule_expert = AssistantAgent(
    "company_rule_expert",
    llm_config=llm_config,
    system_message="""あなたは社内規定に関して詳しいエージェントです。トピックに対し社内規定を踏まえた回答をしてください。
    search_rules_toolツールを利用して社内規定の情報を取得し回答を生成します。""",
)

# search_rules_toolをcompany_rule_expertエージェントに登録

register_function(
    search_rules_tool,
    caller=company_rule_expert,
    executor=company_rule_expert,
    name="search_rules",
    description="Search for information in internal documentations of company rules.",
)


sales_expert = AssistantAgent(
    "sales_expert",
    llm_config=llm_config,
    system_message="""あなたは社内の営業に関して詳しいエージェントです。トピックに対し営業の情報を踏まえた回答を提案してください。
    search_sales_toolツールを利用して社内規定の情報を取得し回答を生成します。
    """,
)

# search_sales_toolをcompany_rule_expertエージェントに登録
register_function(
    search_sales_tool,
    caller=sales_expert,
    executor=sales_expert,
    name="search_sales",
    description="Search for information in internal sales documentation.",
)


general_information_expert = AssistantAgent(
    "general_information_expert",
    llm_config=llm_config,
    system_message="あなたは一般的な知識や情報に関して詳しいエージェントです。トピックに対し世間一般な知識や情報を踏まえたアイデアを提案してください。",
)

old_information_expert = AssistantAgent(
    "old_information_expert",
    llm_config=llm_config,
    system_message="あなたは2000年代の一般的な知識や情報に関して詳しいエージェントです。トピックに対し2000年代の世間一般な知識や情報を踏まえたアイデアを提案してください。",
)


# agentのdiscriptionを定義
supervisor.description = "他のエージェントの回答から最終的な結論を導き出す。"
summarize_agent.description = "最初のユーザーの質問を除き、2人以上のエージェントが回答した後に回答を行う。ほかのエージェントの回答を要約し、意見の類似点・相違点をまとめる。"
company_rule_expert.description = "社内規定をもとにトピックに対して回答を行う。社内ルールに関するデータベースにアクセスすることができる。"
general_information_expert.description = "一般的な情報や知識をもとにトピックに対して回答を行う。"
user_proxy.description = "エージェントの会話が最初のトピックからずれた時や回答が得られないときに介入を行う。ほかのエージェントがより詳しい質問を求めていた場合はTerminateを返す"
old_information_expert.description = "2000年代の一般的な情報や知識をもとにトピックに対して回答を行う。"

Group Chatの定義

2人以上のエージェントが参加するChat Groupを定義し、回答するエージェントの選択を、round_robin(順番)、random、manual、auto(LLM)の4つから選択することができます。

グループチャットはGroupChatManagerが管理し、回答するエージェントを選択します。選択されたエージェントの回答はGroupChatManagerによって全体に共有されます。

group_chat = GroupChat(
    agents=[user_proxy, summarize_agent, company_rule_expert, old_information_expert, general_information_expert, supervisor], 
    speaker_selection_method='auto', #'round_robin',
    messages=[], 
    max_round=10,
    send_introductions=True,
)

group_chat_manager = GroupChatManager(
    groupchat=group_chat,
    llm_config=llm_config,
    is_termination_msg=lambda msg: "TERMINATE" in msg["content"].upper()
)
実行
# Get user input from the console.
user_input = input("Enter a message (type 'exit' to leave): ")
if user_input.strip().lower() == "exit":
    exit()
chat_result = user_proxy.initiate_chat(
    group_chat_manager,
    message=f"{user_input}",
    summary_method="reflection_with_llm",
)

print(f"Chat summary:\n{chat_result.summary}")

pprint.pprint(f"Cost:\n{chat_result.cost}")
コード全体

長いため折りたたみます。


v0.2コード全体(クリックで開く)

import os
from autogen import AssistantAgent, UserProxyAgent, GroupChat, GroupChatManager, register_function
from dotenv import load_dotenv
import pprint
from typing import Annotated

# RAG用
import json
from langchain_core.prompts import PromptTemplate
from langchain_openai import AzureOpenAIEmbeddings
from langchain_community.vectorstores import FAISS


load_dotenv()


# 複数のRAGPluginを追加するため、親クラスを定義
class BaseRAGPlugin:
    def __init__(self, vectorstore_path: str):
        self.embeddings = AzureOpenAIEmbeddings(
            azure_deployment=os.getenv("AZURE_OPENAI_EMBEDDING_DEPLOYMENT"),
        )
        self.vectorstore_faiss = FAISS.load_local(
            vectorstore_path, self.embeddings, allow_dangerous_deserialization=True
        ) # ベクターストア(FAISS)のデータベースをロード


class InternalDocumentationOfSalesRAGPlugin(BaseRAGPlugin):
    '''
    営業に関するドキュメントのRAG plugin
    '''
    def __init__(self):
        super().__init__("./faiss-db")
        self.prompt = PromptTemplate(
            template=(
                "あなたは営業に関するAIアシスタントです。以下のコンテキストを考慮してください:\n"
                "{context}\n\n"
                "次の質問に答えてください:\n"
                "{question}\n\n"
                "アシスタント:"
            ),
            input_variables=["context", "question"],
        )

    def search(self, query: str) -> str:
        retriever = self.vectorstore_faiss.as_retriever()
        context = retriever.invoke(query)
        # プロンプトを利用してクエリに対する応答を生成
        prompt_text = self.prompt.format(context=context[0].page_content, question=query)
        return prompt_text


class InternalDocumentationRAGPlugin(BaseRAGPlugin):
    '''
    社内規定に関するドキュメントのRAG plugin
    '''
    def __init__(self):
        super().__init__("./faiss-company-rule-db")
        self.prompt = PromptTemplate(
            template=(
                "あなたは社内規定に関するAIアシスタントです。以下のコンテキストを考慮してください:\n"
                "{context}\n\n"
                "次の質問に答えてください:\n"
                "{question}\n\n"
                "アシスタント:"
            ),
            input_variables=["context", "question"],
        )

    def search(self, query: str) -> str:
        retriever = self.vectorstore_faiss.as_retriever()
        context = retriever.invoke(query)
        # プロンプトを利用してクエリに対する応答を生成
        prompt_text = self.prompt.format(context=context[0].page_content, question=query)
        return prompt_text


# 営業用ツールを定義
def search_sales_tool(input: Annotated[str, "Input to the sales search tool."]) -> str:
    """
    Tool for searching internal sales documentation.
    """
    sales_rag_plugin = InternalDocumentationOfSalesRAGPlugin()
    result = sales_rag_plugin.search(input)
    return result


# 社内規定用ツールを定義
def search_rules_tool(input: Annotated[str, "Input to the rules search tool."]) -> str:
    """
    Tool for searching internal company rules documentation.
    """
    rules_rag_plugin = InternalDocumentationRAGPlugin()
    result = rules_rag_plugin.search(input)
    return result


# LLM への接続設定を環境変数から読み込む。
llm_config = {
    "config_list": [
        {
            "model": os.getenv("AZURE_OPENAI_DEPLOYMENT"),
            "api_type": "azure",
            "api_key": os.getenv("OPENAI_API_KEY"),
            "base_url": os.getenv("AZURE_OPENAI_ENDPOINT"),
            "api_version": os.getenv("OPENAI_API_VERSION"),
        }
    ]
}


# ユーザーの代理となるエージェント (user_proxy) を定義
user_proxy = UserProxyAgent("user_proxy",
                            code_execution_config=False,
                            human_input_mode="NEVER",
                            is_termination_msg=lambda msg: msg.get("content") is not None
                            and "TERMINATE" in msg["content"]
                            )

supervisor = AssistantAgent(
    "supervisor",
    llm_config=llm_config,
    system_message="""あなたは会話を管理するエージェントです。
        他のエージェントからの回答から最終的な結論を導き出してください。
    
        文の最後に TERMINATE を含めてください。""",
)

summarize_agent = AssistantAgent(
    "summarize_agent",
    llm_config=llm_config,
    system_message="""
        これまでのエージェントからの回答を要約し、エージェントの意見の同じ点と食い違う点、そこから導き出される結論を回答する。
        エージェントの意見の同じ点と食い違う点を記載する際には、どのエージェントからの回答か明記する。
        """
)


company_rule_expert = AssistantAgent(
    "company_rule_expert",
    llm_config=llm_config,
    system_message="""あなたは社内規定に関して詳しいエージェントです。トピックに対し社内規定を踏まえた回答をしてください。
    search_rules_toolツールを利用して社内規定の情報を取得し回答を生成します。""",
)

# search_rules_toolをcompany_rule_expertエージェントに登録

register_function(
    search_rules_tool,
    caller=company_rule_expert,
    executor=company_rule_expert,
    name="search_rules",
    description="Search for information in internal documentations of company rules.",
)


sales_expert = AssistantAgent(
    "sales_expert",
    llm_config=llm_config,
    system_message="""あなたは社内の営業に関して詳しいエージェントです。トピックに対し営業の情報を踏まえた回答を提案してください。
    search_sales_toolツールを利用して社内規定の情報を取得し回答を生成します。
    """,
)

# search_sales_toolをcompany_rule_expertエージェントに登録
register_function(
    search_sales_tool,
    caller=sales_expert,
    executor=sales_expert,
    name="search_sales",
    description="Search for information in internal sales documentation.",
)


general_information_expert = AssistantAgent(
    "general_information_expert",
    llm_config=llm_config,
    system_message="あなたは一般的な知識や情報に関して詳しいエージェントです。トピックに対し世間一般な知識や情報を踏まえたアイデアを提案してください。",
)

old_information_expert = AssistantAgent(
    "old_information_expert",
    llm_config=llm_config,
    system_message="あなたは2000年代の一般的な知識や情報に関して詳しいエージェントです。トピックに対し2000年代の世間一般な知識や情報を踏まえたアイデアを提案してください。",
)


# agentのdiscriptionを定義
supervisor.description = "他のエージェントの回答から最終的な結論を導き出す。"
summarize_agent.description = "最初のユーザーの質問を除き、2人以上のエージェントが回答した後に回答を行う。ほかのエージェントの回答を要約し、意見の類似点・相違点をまとめる。"
company_rule_expert.description = "社内規定をもとにトピックに対して回答を行う。社内ルールに関するデータベースにアクセスすることができる。"
general_information_expert.description = "一般的な情報や知識をもとにトピックに対して回答を行う。"
user_proxy.description = "エージェントの会話が最初のトピックからずれた時や回答が得られないときに介入を行う。ほかのエージェントがより詳しい質問を求めていた場合はTerminateを返す"
old_information_expert.description = "2000年代の一般的な情報や知識をもとにトピックに対して回答を行う。"


# Group Chatの定義
group_chat = GroupChat(
    agents=[user_proxy, summarize_agent, company_rule_expert, old_information_expert, general_information_expert, supervisor], 
    speaker_selection_method='auto', #'round_robin',
    messages=[], 
    max_round=10,
    send_introductions=True,
)

group_chat_manager = GroupChatManager(
    groupchat=group_chat,
    llm_config=llm_config,
    is_termination_msg=lambda msg: "TERMINATE" in msg["content"].upper()
)


# Get user input from the console.
user_input = input("Enter a message (type 'exit' to leave): ")
if user_input.strip().lower() == "exit":
    exit()
chat_result = user_proxy.initiate_chat(
    group_chat_manager,
    message=f"{user_input}",
    summary_method="reflection_with_llm",
)

print(f"Chat summary:\n{chat_result.summary}")

pprint.pprint(f"Cost:\n{chat_result.cost}")

実行結果

いくつかの回答例を記載します。

以下を確認すると、ユーザーのプロンプトに基づいてエージェントが選択され回答を生成していることが確認できます。

※RAGの結果はすべてサンプルのデータになります。

Enter a message (type 'exit' to leave):  リモートワークの決まりを教えてください。
user_proxy (to chat_manager):

リモートワークの決まりを教えてください。

--------------------------------------------------------------------------------

Next speaker: company_rule_expert

company_rule_expert (to chat_manager):

***** Suggested tool call (call_VPcZSSQ0Ec5mmsYZijoTuRr4): search_rules *****
Arguments: 
{"input":"リモートワーク"}
*****************************************************************************

--------------------------------------------------------------------------------

Next speaker: company_rule_expert


>>>>>>>> EXECUTING FUNCTION search_rules...
Call ID: call_VPcZSSQ0Ec5mmsYZijoTuRr4
Input arguments: {'input': 'リモートワーク'}
company_rule_expert (to chat_manager):

***** Response from calling tool (call_VPcZSSQ0Ec5mmsYZijoTuRr4) *****
あなたは社内規定に関するAIアシスタントです。以下のコンテキストを考慮してください:
リモートワーク規定
第1条(目的)
本規定は、従業員がリモートワークを行う際の基本的な方針及び手続きについて定めることを目的とする。

第2条(適用範囲)
この規定は、全ての従業員に適用される。ただし、業務の性質上、出社が必要とされる職種については適用を除外する場合がある。

次の質問に答えてください:
リモートワーク

アシスタント:
**********************************************************************

--------------------------------------------------------------------------------

Next speaker: summarize_agent

summarize_agent (to chat_manager):

リモートワークに関する社内規定の要点は以下の通りです。

1. **目的**: 従業員がリモートワークを行う際の基本的な方針及び手続きについて定めています。
2. **適用範囲**: 全ての従業員に適用されますが、業務の性質上出社が必要な職種には適用されないことがあります。

他に具体的なルールや条件がある場合、それに関しても質問していただければ、さらに詳しい情報を提供できます。

--------------------------------------------------------------------------------

Next speaker: supervisor

supervisor (to chat_manager):

リモートワークの決まりは以下の通りです:

1. **目的**: 従業員がリモートワークを行う際の基本的な方針及び手続きについて定めています。
2. **適用範囲**: 全ての従業員に適用されますが、業務の性質上出社が必要な職種には適用されないことがあります。

他に具体的なルールや条件について質問があればお知らせください。TERMINATE

--------------------------------------------------------------------------------
Chat summary:
リモートワークの決まりには、従業員がリモートワークを行う際の基本的な方針と手続きを定める目的があり、全ての従業員に適用されるが、出社が必要な職種には適用されない場合がある。
('Cost:\n'
 "{'usage_including_cached_inference': {'total_cost': 0.00011925, "
 "'gpt-4o-mini-2024-07-18': {'cost': 0.00011925, 'prompt_tokens': 511, "
 "'completion_tokens': 71, 'total_tokens': 582}}, "
 "'usage_excluding_cached_inference': {'total_cost': 0.00011925, "
 "'gpt-4o-mini-2024-07-18': {'cost': 0.00011925, 'prompt_tokens': 511, "
 "'completion_tokens': 71, 'total_tokens': 582}}}")
Enter a message (type 'exit' to leave):  経費に含まれるものを教えてください
user_proxy (to chat_manager):

経費に含まれるものを教えてください

--------------------------------------------------------------------------------

Next speaker: company_rule_expert

company_rule_expert (to chat_manager):

***** Suggested tool call (call_j7TWFRKKhKHbC9FVYVtK6z8z): search_rules *****
Arguments: 
{"input":"経費に含まれるもの"}
*****************************************************************************

--------------------------------------------------------------------------------

Next speaker: company_rule_expert


>>>>>>>> EXECUTING FUNCTION search_rules...
Call ID: call_j7TWFRKKhKHbC9FVYVtK6z8z
Input arguments: {'input': '経費に含まれるもの'}
company_rule_expert (to chat_manager):

***** Response from calling tool (call_j7TWFRKKhKHbC9FVYVtK6z8z) *****
あなたは社内規定に関するAIアシスタントです。以下のコンテキストを考慮してください:
出張費(交通費、宿泊費、食事代など)
事務用品費
講演会・セミナー参加費
業務に必要なソフトウェア購入費

次の質問に答えてください:
経費に含まれるもの

アシスタント:
**********************************************************************

--------------------------------------------------------------------------------

Next speaker: summarize_agent

summarize_agent (to chat_manager):

経費に含まれるものは、以下のように分類されます:

1. 出張費(交通費、宿泊費、食事代など)
2. 事務用品費
3. 講演会・セミナー参加費
4. 業務に必要なソフトウェア購入費

これらは社内規定に基づいて経費として認められています。他に何か知りたいことがあればお知らせください。

--------------------------------------------------------------------------------

Next speaker: supervisor

supervisor (to chat_manager):

経費に含まれるものは主に次の4つです:

1. 出張費(交通費、宿泊費、食事代など)
2. 事務用品費
3. 講演会・セミナー参加費
4. 業務に必要なソフトウェア購入費

これらは社内規定に基づいて認められています。TERMINATE

--------------------------------------------------------------------------------
Chat summary:
経費に含まれるものは、出張費(交通費、宿泊費、食事代など)、事務用品費、講演会・セミナー参加費、業務に必要なソフトウェア購入費の4つです。
('Cost:\n'
 "{'usage_including_cached_inference': {'total_cost': 9.164999999999999e-05, "
 "'gpt-4o-mini-2024-07-18': {'cost': 9.164999999999999e-05, 'prompt_tokens': "
 "387, 'completion_tokens': 56, 'total_tokens': 443}}, "
 "'usage_excluding_cached_inference': {'total_cost': 9.164999999999999e-05, "
 "'gpt-4o-mini-2024-07-18': {'cost': 9.164999999999999e-05, 'prompt_tokens': "
 "387, 'completion_tokens': 56, 'total_tokens': 443}}}")
Enter a message (type 'exit' to leave):  日本の人口を教えてください。
user_proxy (to chat_manager):

日本の人口を教えてください。

--------------------------------------------------------------------------------

Next speaker: general_information_expert

general_information_expert (to chat_manager):

2023年の時点で、日本の人口は約1億2500万人前後と推定されています。日本は高齢化が進んでおり、少子化の影響で人口が減少傾向にあることが大きな課題とされています。今後の予測でも、人口減少が続く可能性が高いとされています。

--------------------------------------------------------------------------------

Next speaker: summarize_agent

summarize_agent (to chat_manager):

現在の時点では、他のエージェントからの追加の回答がないため、現時点での情報を基に回答をまとめます。

- **一般情報エキスパート**の意見によると、日本の人口は2023年時点で約1億2500万人であり、高齢化と少子化が進行中とされています。

この情報から導き出される結論は、日本は人口減少に直面しており、その対策が重要であるという点です。将来の人口動態について懸念が表されていることも注目すべき点です。

--------------------------------------------------------------------------------

Next speaker: supervisor

supervisor (to chat_manager):

日本の2023年の人口は約1億2500万人と推定されており、高齢化と少子化が進行中であるため、人口減少が続く可能性が高いという大きな課題があります。このような状況から、今後の人口動態について懸念が高まっていることが伺えます。TERMINATE

--------------------------------------------------------------------------------
Chat summary:
日本の2023年の人口は約1億2500万人で、高齢化と少子化が進行しているため、人口減少が続く可能性が高い。今後の人口動態について懸念が高まっている。
('Cost:\n'
 "{'usage_including_cached_inference': {'total_cost': 8.984999999999999e-05, "
 "'gpt-4o-mini-2024-07-18': {'cost': 8.984999999999999e-05, 'prompt_tokens': "
 "371, 'completion_tokens': 57, 'total_tokens': 428}}, "
 "'usage_excluding_cached_inference': {'total_cost': 8.984999999999999e-05, "
 "'gpt-4o-mini-2024-07-18': {'cost': 8.984999999999999e-05, 'prompt_tokens': "
 "371, 'completion_tokens': 57, 'total_tokens': 428}}}")

v0.4

まずはv0.2と同じ、複数のエージェントをオーケストレーションするシステムを構築します。

開発環境の準備
pip install -U "autogen-agentchat"
pip install "autogen-ext[openai,azure]"
toolの定義

Toolの定義はv0.2と同じコードを利用します。

# 複数のRAGPluginを追加するため、親クラスを定義
class BaseRAGPlugin:
    def __init__(self, vectorstore_path: str):
        self.embeddings = AzureOpenAIEmbeddings(
            azure_deployment=os.getenv("AZURE_OPENAI_EMBEDDING_DEPLOYMENT"),
        )
        self.vectorstore_faiss = FAISS.load_local(
            vectorstore_path, self.embeddings, allow_dangerous_deserialization=True
        ) # ベクターストア(FAISS)のデータベースをロード


class InternalDocumentationOfSalesRAGPlugin(BaseRAGPlugin):
    '''
    営業に関するドキュメントのRAG plugin
    '''
    def __init__(self):
        super().__init__("./faiss-db")
        self.prompt = PromptTemplate(
            template=(
                "あなたは営業に関するAIアシスタントです。以下のコンテキストを考慮してください:\n"
                "{context}\n\n"
                "次の質問に答えてください:\n"
                "{question}\n\n"
                "アシスタント:"
            ),
            input_variables=["context", "question"],
        )

    def search(self, query: str) -> str:
        retriever = self.vectorstore_faiss.as_retriever()
        context = retriever.invoke(query)
        # プロンプトを利用してクエリに対する応答を生成
        prompt_text = self.prompt.format(context=context[0].page_content, question=query)
        print(f'return: "{prompt_text}"')
        return prompt_text


class InternalDocumentationRAGPlugin(BaseRAGPlugin):
    '''
    社内規定に関するドキュメントのRAG plugin
    '''
    def __init__(self):
        super().__init__("./faiss-company-rule-db")
        self.prompt = PromptTemplate(
            template=(
                "あなたは社内規定に関するAIアシスタントです。以下のコンテキストを考慮してください:\n"
                "{context}\n\n"
                "次の質問に答えてください:\n"
                "{question}\n\n"
                "アシスタント:"
            ),
            input_variables=["context", "question"],
        )

    def search(self, query: str) -> str:
        retriever = self.vectorstore_faiss.as_retriever()
        context = retriever.invoke(query)
        # プロンプトを利用してクエリに対する応答を生成
        prompt_text = self.prompt.format(context=context[0].page_content, question=query)
        print(f'return: "{prompt_text}"')
        return prompt_text


# 営業用ツールを定義
def search_sales_tool(input: Annotated[str, "Input to the sales search tool."]) -> str:
    """
    Tool for searching internal sales documentation.
    """
    sales_rag_plugin = InternalDocumentationOfSalesRAGPlugin()
    result = sales_rag_plugin.search(input)
    return result


# 社内規定用ツールを定義
def search_rules_tool(input: Annotated[str, "Input to the rules search tool."]) -> str:
    """
    Tool for searching internal company rules documentation.
    """
    rules_rag_plugin = InternalDocumentationRAGPlugin()
    result = rules_rag_plugin.search(input)
    return result
LLMの定義
client = AzureOpenAIChatCompletionClient(
    azure_deployment=os.getenv("AZURE_OPENAI_DEPLOYMENT"),
    model="gpt-4o-mini",
    api_key=os.getenv("AZURE_OPENAI_API_KEY"),
    api_version=os.getenv("OPENAI_API_VERSION"),
    azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
)
エージェントの定義

v0.4ではエージェントの定義に、toolとdescriptionを含めて定義を行います。

supervisor_agent = AssistantAgent(
    "SupervisorAgent",
    description="他のエージェントの回答から最終的な結論を導き出す。",
    model_client=client,
    system_message=f"""
        あなたは会話を管理するエージェントです。
        他のエージェントからの回答から最終的な結論を導き出してください。
    
        文の最後に TERMINATE を含めてください。
        """,
)

summarize_agent = AssistantAgent(
    "summarize_agent",
    description="A summarize agent. ほかのエージェントの回答を要約し、意見の類似点・相違点をまとめる。",
    model_client=client,
    system_message="""これまでのエージェントからのユーザーの質問に対する回答を要約し、エージェントの意見の同じ点と食い違う点、そこから導き出される結論を回答する。
        エージェントの意見の同じ点と食い違う点を記載する際には、どのエージェントからの回答か明記する。
    """,
)


company_rule_expert = AssistantAgent(
    "company_rule_expert",
    description="A company rule expert. 社内規定をもとにトピックに対して回答を行うエージェント。社内ルールに関するデータベースにアクセスすることができる。",
    model_client=client,
    tools=[search_rules_tool],
    reflect_on_tool_use=True,
    system_message="""あなたは社内規定に関して詳しいエージェントです。トピックに対し社内規定を踏まえた回答をしてください。
    search_rules_toolツールを利用して社内規定の情報を取得し回答を生成します。
    """,
)

sales_expert = AssistantAgent(
    "sales_expert",
    description="A sales expert. 営業の社内情報をもとにトピックに対して回答を行うエージェント。営業に関するデータベースにアクセスすることができる。",
    model_client=client,
    tools=[search_sales_tool],
    reflect_on_tool_use=True,
    system_message="""あなたは社内の営業に関して詳しいエージェントです。トピックに対し営業の情報を踏まえた回答を提案してください。
    search_sales_toolツールを利用して社内規定の情報を取得し回答を生成します。
    """,
)

general_information_expert= AssistantAgent(
    "general_information_expert",
    description="A general information expert. 一般的な情報や知識をもとにトピックに対して回答を行うエージェント",
    model_client=client,
    system_message="""
    あなたは一般的な知識や情報に関して詳しいエージェントです。トピックに対し世間一般な知識や情報を踏まえたアイデアを提案してください。
    """,
)

old_information_expert= AssistantAgent(
    "old_information_expert",
    description="An old information expert. 2000年代の一般的な情報や知識をもとにトピックに対して回答を行うエージェント",
    model_client=client,
    system_message="""
        あなたは2000年代の一般的な知識や情報に関して詳しいエージェントです。トピックに対し2000年代の世間一般な知識や情報を踏まえたアイデアを提案してください。
    """,
)
Group Chatの定義

今回はSelectorGroupChatを利用します。

SelectorGroupChatでは、参加者が交代でメッセージを全体に共有する仕組みを提供します。生成モデルが状況に基づいて話者を決定するため、効率的で柔軟なコラボレーションが可能です。

主な機能として以下のものが挙げられます。

  • 生成モデル(LLM)に基づく話者の選択機能
  • 役割や説明を設定できる柔軟な参加者構成
  • 同一話者が連続して発言することを防ぐ(オプション設定)
  • 選択プロンプトを自由にカスタマイズ可能
  • デフォルトの話者選択ロジックを上書きするための選択機能のカスタマイズ

チームは会話履歴や参加者の名前やdescriptionを含む現在の会話のコンテキストを分析し、生成モデルを用いて次の話者を決定します。

SelectorGroupChatに関して詳しくは以下で確認いただけます。

microsoft.github.io

# Define termination condition
max_msg_termination = MaxMessageTermination(max_messages=10)
text_termination = TextMentionTermination("TERMINATE")
time_terminarion = TimeoutTermination(120)
combined_termination = max_msg_termination | text_termination | time_terminarion

group_chat = SelectorGroupChat(
    [supervisor_agent, summarize_agent, company_rule_expert, sales_expert, general_information_expert, old_information_expert],
    model_client=client,
    termination_condition=combined_termination,
)
実行
# Get user input from the console.
    user_input = input("Enter a message (type 'exit' to leave): ").strip().lower()
    
    if user_input == "exit":  # "exit"の場合には終了
        exit()
    else:
        # 非同期関数を呼び出します
        async for message in group_chat.run_stream(task=user_input):  # 非同期ループで処理
            print(message)  # コンソールにメッセージを出力
コード全体

長いため折りたたみます。


v0.4コード全体(クリックで開く)

import os
import asyncio
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.teams import SelectorGroupChat
from autogen_ext.models.openai import AzureOpenAIChatCompletionClient
from autogen_agentchat.conditions import MaxMessageTermination, TextMentionTermination, TimeoutTermination
from autogen_agentchat.ui import Console

from dotenv import load_dotenv
from typing import Annotated

# RAG用
from langchain_core.prompts import PromptTemplate
from langchain_openai import AzureOpenAIEmbeddings
from langchain_community.vectorstores import FAISS


load_dotenv()


# 複数のRAGPluginを追加するため、親クラスを定義
class BaseRAGPlugin:
    def __init__(self, vectorstore_path: str):
        self.embeddings = AzureOpenAIEmbeddings(
            azure_deployment=os.getenv("AZURE_OPENAI_EMBEDDING_DEPLOYMENT"),
        )
        self.vectorstore_faiss = FAISS.load_local(
            vectorstore_path, self.embeddings, allow_dangerous_deserialization=True
        ) # ベクターストア(FAISS)のデータベースをロード


class InternalDocumentationOfSalesRAGPlugin(BaseRAGPlugin):
    '''
    営業に関するドキュメントのRAG plugin
    '''
    def __init__(self):
        super().__init__("./faiss-db")
        self.prompt = PromptTemplate(
            template=(
                "あなたは営業に関するAIアシスタントです。以下のコンテキストを考慮してください:\n"
                "{context}\n\n"
                "次の質問に答えてください:\n"
                "{question}\n\n"
                "アシスタント:"
            ),
            input_variables=["context", "question"],
        )

    def search(self, query: str) -> str:
        retriever = self.vectorstore_faiss.as_retriever()
        context = retriever.invoke(query)
        # プロンプトを利用してクエリに対する応答を生成
        prompt_text = self.prompt.format(context=context[0].page_content, question=query)
        return prompt_text


class InternalDocumentationRAGPlugin(BaseRAGPlugin):
    '''
    社内規定に関するドキュメントのRAG plugin
    '''
    def __init__(self):
        super().__init__("./faiss-company-rule-db")
        self.prompt = PromptTemplate(
            template=(
                "あなたは社内規定に関するAIアシスタントです。以下のコンテキストを考慮してください:\n"
                "{context}\n\n"
                "次の質問に答えてください:\n"
                "{question}\n\n"
                "アシスタント:"
            ),
            input_variables=["context", "question"],
        )

    def search(self, query: str) -> str:
        retriever = self.vectorstore_faiss.as_retriever()
        context = retriever.invoke(query)
        # プロンプトを利用してクエリに対する応答を生成
        prompt_text = self.prompt.format(context=context[0].page_content, question=query)
        return prompt_text


# 営業用ツールを定義
def search_sales_tool(input: Annotated[str, "Input to the sales search tool."]) -> str:
    """
    Tool for searching internal sales documentation.
    """
    sales_rag_plugin = InternalDocumentationOfSalesRAGPlugin()
    result = sales_rag_plugin.search(input)
    return result


# 社内規定用ツールを定義
def search_rules_tool(input: Annotated[str, "Input to the rules search tool."]) -> str:
    """
    Tool for searching internal company rules documentation.
    """
    rules_rag_plugin = InternalDocumentationRAGPlugin()
    result = rules_rag_plugin.search(input)
    return result


# LLM への接続設定を環境変数から読み込む。
client = AzureOpenAIChatCompletionClient(
    azure_deployment=os.getenv("AZURE_OPENAI_DEPLOYMENT"),
    model="gpt-4o-mini",
    api_key=os.getenv("AZURE_OPENAI_API_KEY"),
    api_version=os.getenv("OPENAI_API_VERSION"),
    azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
)


supervisor_agent = AssistantAgent(
    "SupervisorAgent",
    description="他のエージェントの回答から最終的な結論を導き出す。",
    model_client=client,
    system_message=f"""
        あなたは会話を管理するエージェントです。
        他のエージェントからの回答から最終的な結論を導き出してください。
    
        文の最後に TERMINATE を含めてください。
        """,
)

summarize_agent = AssistantAgent(
    "summarize_agent",
    description="A summarize agent. ほかのエージェントの回答を要約し、意見の類似点・相違点をまとめる。",
    model_client=client,
    system_message="""これまでのエージェントからのユーザーの質問に対する回答を要約し、エージェントの意見の同じ点と食い違う点、そこから導き出される結論を回答する。
        エージェントの意見の同じ点と食い違う点を記載する際には、どのエージェントからの回答か明記する。
    """,
)


company_rule_expert = AssistantAgent(
    "company_rule_expert",
    description="A company rule expert. 社内規定をもとにトピックに対して回答を行うエージェント。社内ルールに関するデータベースにアクセスすることができる。",
    model_client=client,
    tools=[search_rules_tool],
    reflect_on_tool_use=True,
    system_message="""あなたは社内規定に関して詳しいエージェントです。トピックに対し社内規定を踏まえた回答をしてください。
    search_rules_toolツールを利用して社内規定の情報を取得し回答を生成します。
    """,
)

sales_expert = AssistantAgent(
    "sales_expert",
    description="A sales expert. 営業の社内情報をもとにトピックに対して回答を行うエージェント。営業に関するデータベースにアクセスすることができる。",
    model_client=client,
    tools=[search_sales_tool],
    reflect_on_tool_use=True,
    system_message="""あなたは社内の営業に関して詳しいエージェントです。トピックに対し営業の情報を踏まえた回答を提案してください。
    search_sales_toolツールを利用して社内規定の情報を取得し回答を生成します。
    """,
)

general_information_expert= AssistantAgent(
    "general_information_expert",
    description="A general information expert. 一般的な情報や知識をもとにトピックに対して回答を行うエージェント",
    model_client=client,
    system_message="""
    あなたは一般的な知識や情報に関して詳しいエージェントです。トピックに対し世間一般な知識や情報を踏まえたアイデアを提案してください。
    """,
)

old_information_expert= AssistantAgent(
    "old_information_expert",
    description="An old information expert. 2000年代の一般的な情報や知識をもとにトピックに対して回答を行うエージェント",
    model_client=client,
    system_message="""
        あなたは2000年代の一般的な知識や情報に関して詳しいエージェントです。トピックに対し2000年代の世間一般な知識や情報を踏まえたアイデアを提案してください。
    """,
)


# Define termination condition
max_msg_termination = MaxMessageTermination(max_messages=10)
text_termination = TextMentionTermination("TERMINATE")
time_terminarion = TimeoutTermination(120)
combined_termination = max_msg_termination | text_termination | time_terminarion

group_chat = SelectorGroupChat(
    [supervisor_agent, summarize_agent, company_rule_expert, sales_expert, general_information_expert, old_information_expert],
    model_client=client,
    termination_condition=combined_termination,
)



async def main():
    # Get user input from the console.
    user_input = input("Enter a message (type 'exit' to leave): ").strip().lower()
    
    if user_input == "exit":  # "exit"の場合には終了
        exit()
    else:
        # 非同期関数を呼び出します
        async for message in group_chat.run_stream(task=user_input):  # 非同期ループで処理
            print(message)  # コンソールにメッセージを出力


# イベントループで非同期関数を実行する
if __name__ == "__main__":
    asyncio.run(main())


実行結果

※RAGで取得されるものはすべてサンプルのデータを利用します。

Enter a message (type 'exit' to leave):  リモートワークの決まりを教えてください。
---------- user ----------
リモートワークの決まりを教えてください。
---------- company_rule_expert ----------
[FunctionCall(id='call_r7qCYmy6mwlekE8XzKw6RPNK', arguments='{"input":"リモートワーク"}', name='search_rules_tool')]
return: "あなたは社内規定に関するAIアシスタントです。以下のコンテキストを考慮してください:
リモートワーク規定
第1条(目的)
本規定は、従業員がリモートワークを行う際の基本的な方針及び手続きについて定めることを目的とする。

第2条(適用範囲)
この規定は、全ての従業員に適用される。ただし、業務の性質上、出社が必要とされる職種については適用を除外する場合がある。

次の質問に答えてください:
リモートワーク

アシスタント:"
---------- company_rule_expert ----------
[FunctionExecutionResult(content='あなたは社内規定に関するAIアシスタントです。以下のコンテキストを考慮してください:\nリモートワーク規定\n第1条(目的)\n本規定は、従業員がリモートワークを行う際の基本的な方針及び手続きについて定めることを目的とする。\n\n第2条(適用範囲)\nこの規定は、全ての従業員に適用される。ただし、業務の性質上、出社が必要とされる職種については適用を除外する場合がある。\n\n次の質問に答えてください:\nリモートワーク\n\nアシスタント:', call_id='call_r7qCYmy6mwlekE8XzKw6RPNK')]
---------- company_rule_expert ----------
リモートワークに関する社内規定は以下のようになっています。

### 第1条(目的)
本規定は、従業員がリモートワークを行う際の基本的な方針および手続きについて定めることを目的としています。

### 第2条(適用範囲)
この規定は、全ての従業員に適用されます。ただし、業務の性質上、出社が必要とされる職種については、この規定の適用を除外する場合があります。

具体的な手続きやルールについては、詳細なガイドラインが別途存在する場合があるため、確認が必要です。リモートワークを実施する場合は、上司への初めの承認を得ることや、業務遂行に必要な環境を整えることが求められます。
---------- summarize_agent ----------
### 要約
リモートワークに関する社内規定は、従業員がリモートワークを行う際の基本方針と手続きを定めている。全従業員に適用されるが、業務によっては出社が必要な職種には適用されない。リモートワークを行うには上司の承認が必要で、業務環境を整えることが求められる。

### エージェントの意見の同じ点と食い違う点
この情報は、一貫してリモートワークには上司の承認と適切な業務環境の整備が必要であると強調している。この点に関しては全てのエージェントの意見が一致している。食い違う点は、業務の性質上出社が必要な職種に関する取り扱いや、具体的なガイドラインの有無に関して具体的な説明がなされていない点で、他のエージェントがその点について言及する可能性がある。

### 導き出された結論
リモートワークを導入する際は、上司の承認と業務環境の整備が不可欠であり、適用されない職種も存在することから、自身の業務内容の確認が重要である。また、詳細なガイドラインの存在を把握し、遵守することが求められる。
---------- SupervisorAgent ----------
リモートワークに関する社内規定は、全従業員に適用される基本方針と手続きを定めており、業務によっては出社が求められる職種もあることを考慮する必要があります。リモートワークを行う際は、上司の承認を得て、適切な業務環境を整えることが重要です。また、詳細なガイドラインの有無を確認し、遵守することが求められます。TERMINATE
Enter a message (type 'exit' to leave):  経費に含まれるものを教えてください
---------- user ----------
経費に含まれるものを教えてください
---------- company_rule_expert ----------
[FunctionCall(id='call_tj9qBje5XD2FcLp71dLfN5pG', arguments='{"input":"経費 含まれるもの"}', name='search_rules_tool')]
---------- company_rule_expert ----------
[FunctionExecutionResult(content='あなたは社内規定に関するAIアシスタントです。以下のコンテキストを考慮してください:\n出張費(交通費、宿泊費、食事代など)\n事務用品費\n講演会・セミナー参加費\n業務に必要なソフトウェア購入費\n\n次の質問に答えてください:\n経費 含まれるもの\n\nアシスタント:', call_id='call_tj9qBje5XD2FcLp71dLfN5pG')]
---------- company_rule_expert ----------
経費に含まれるものについては、以下の項目が一般的に該当します:

1. **出張費**:
   - 交通費(公共交通機関利用、タクシーなど)
   - 宿泊費
   - 食事代

2. **事務用品費**:
   - 文房具やオフィス用品の購入費用

3. **講演会・セミナー参加費**:
   - 業務に関連するイベントの参加費用

4. **業務に必要なソフトウェア購入費**:
   - 業務遂行に必要なソフトウェアのライセンス費用

これらの項目は、社内規定に基づき経費と認められ、適切な手続きに従い申請することで、経費精算が行われます。詳細については社内の経費規定を確認することをお勧めします。
---------- summarize_agent ----------
ユーザーの質問に対するエージェントの回答を要約すると、経費に含まれる一般的な項目として次の4つが挙げられています。

1. 出張費(交通費、宿泊費、食事代)
2. 事務用品費(文房具やオフィス用品)
3. 講演会・セミナー参加費
4. 業務に必要なソフトウェア購入費

### 同じ点:
- **company_rule_expert**の回答は経費の範囲を具体的に定義しており、出張費や事務用品費、セミナー参加費など、一般的に経費として認められる項目について言及しています。

### 食い違う点:
- 現時点では他のエージェントからの関連する質問はなく、唯一の見解として**company_rule_expert**の意見が示されています。

### 結論:
経費に含まれるものは、一般的に出張費、事務用品費、講演会・セミナー参加費、ソフトウェア購入費があり、社内の経費規定によって具体的な内容は異なる可能性があるため、社内規定の確認が重要です。
---------- SupervisorAgent ----------
経費に含まれるものは一般的に以下の4つです。

1. 出張費(交通費、宿泊費、食事代)
2. 事務用品費(文房具やオフィス用品)
3. 講演会・セミナー参加費
4. 業務に必要なソフトウェア購入費

これらは社内の経費規定に基づき申請され、具体的な内容は企業によって異なる可能性があるため、社内規定の確認が重要です。TERMINATE
Enter a message (type 'exit' to leave):  日本の人口を教えてください。
---------- user ----------
日本の人口を教えてください。
---------- general_information_expert ----------
日本の人口は、2023年時点で約1億2500万人程度とされています。ただし、日本の人口は少子高齢化の影響で減少傾向にあるため、具体的な数字は年々変わる可能性があります。最新の人口統計については、日本の総務省や国立社会保障・人口問題研究所などの公式サイトを参照することをお勧めします。
---------- summarize_agent ----------
エージェントの意見の要約は以下の通りです:

- **同じ点**: 日本の人口は2023年時点で約1億2500万人とされていること。少子高齢化により減少傾向にある点。
- **食い違う点**: 特にエージェント間での意見の食い違いはありませんが、最新の統計についての参照するべき場所が異なるかもしれません(他のエージェントの情報がないため、現状では確認できません)。

**結論**: 日本の人口は約1億2500万人であり、少子高齢化の影響で減少傾向にあるため、最新の人口統計を確認することが重要です。
---------- SupervisorAgent ----------
日本の人口は2023年時点で約1億2500万人であり、少子高齢化の影響で減少傾向にあるため、最新の人口統計を確認することが重要です。 TERMINATE

v0.4 エージェントの定義を変更

v0.4のSelector Group Chat — AutoGenの説明では、Planning Agentを定義し、タスクを分割し他のエージェントに割り当てる役割を設定しています。
SuperisorAgentをPlanningAgentに置き換え、同様なものが再現可能か試します。

エージェントの定義
planning_agent = AssistantAgent(
    "PlanningAgent",
    description="タスクを管理するエージェントを計画するエージェント。新しいタスクが与えられたときに最初に起動するエージェントです。",
    model_client=client,
    system_message=f"""
        あなたはplanningエージェントです。
        あなた複雑なタスクを、小さく、管理可能なサブタスクに分解します。
        あなたのチームメンバーは次のエージェントたちです。
         - company rule expert: 社内規定のエキスパート
         - sales expert: 会社の営業に関するエキスパート
         - general information expert: 一般的な知識と情報のエキスパート
         - old information expert: 一般的な知識と情報のエキスパート
        あなたはタスクを計画し、割り当てることだけを行い、自分自身ではタスクを実行しません。
        タスクを割り当てる際には、このフォーマットを使用してください:
        1. <agent> : <task>
    
        上記のタスクの最終回答が完成したら調査結果を要約し、
        エージェントの意見の同じ点と食い違う点、そこから導き出される結論を回答し、文の最後に TERMINATE を含めてください。
        """,
)


company_rule_expert = AssistantAgent(
    "company_rule_expert",
    description="A company rule expert.",# 社内規定をもとにトピックに対して回答を行うエージェント。社内ルールに関するデータベースにアクセスすることができる。",
    model_client=client,
    tools=[search_rules_tool],
    reflect_on_tool_use=True,
    system_message="""あなたは社内規定に関して詳しいエージェントです。トピックに対し社内規定を踏まえた回答をしてください。
    search_rules_toolツールを利用して社内規定の情報を取得し回答を生成します。
    """,
)

sales_expert = AssistantAgent(
    "sales_expert",
    description="A sales expert.",# 営業の社内情報をもとにトピックに対して回答を行うエージェント。営業に関するデータベースにアクセスすることができる。",
    model_client=client,
    tools=[search_sales_tool],
    reflect_on_tool_use=True,
    system_message="""あなたは社内の営業に関して詳しいエージェントです。トピックに対し営業の情報を踏まえた回答を提案してください。
    search_sales_toolツールを利用して社内規定の情報を取得し回答を生成します。
    """,
)

general_information_expert= AssistantAgent(
    "general_information_expert",
    description="A general information expert.",# 一般的な情報や知識をもとにトピックに対して回答を行うエージェント",
    model_client=client,
    system_message="""
    あなたは一般的な知識や情報に関して詳しいエージェントです。トピックに対し世間一般な知識や情報を踏まえたアイデアを提案してください。
    """,
)

old_information_expert= AssistantAgent(
    "old_information_expert",
    description="An old information expert.",# 2000年代の一般的な情報や知識をもとにトピックに対して回答を行うエージェント",
    model_client=client,
    system_message="""
        あなたは2000年代の一般的な知識や情報に関して詳しいエージェントです。トピックに対し2000年代の世間一般な知識や情報を踏まえたアイデアを提案してください。
    """,
)
実行結果

何回か試したうちの一例を記載します。

PlanningAgentが最初に実行されなかったり、計画されたすべてのタスクが実行されなかったりしたこともあったので、エージェントの定義や実装方法にもう少し工夫が必要かもしれません。

Enter a message (type 'exit' to leave):  リモートワークに関して議論し、導入するべきか教えてください。
---------- user ----------
リモートワークに関して議論し、導入するべきか教えてください。
---------- general_information_expert ----------
リモートワークの導入には多くの利点と課題が存在します。以下に両方の側面をまとめ、導入を検討する際のアイデアをいくつか提案します。

### リモートワークの利点

1. **柔軟な働き方**: リモートワークは従業員に柔軟性を提供し、生活とのバランスを取りやすくします。これにより、仕事のパフォーマンスや満足度が向上する可能性があります。

2. **コスト削減**: 企業はオフィススペースや光熱費といった固定費の削減が可能です。また、勤務地に縛られないため、人件費の安い地域から優秀な人材を採用できるメリットがあります。

3. **通勤時間の削減**: 通勤にかかる時間をなくすことで、従業員は仕事により多くの時間を費やしたり、プライベートの充実に使ったりできます。

4. **広範な人材プール**: 地理的な制約がないため、企業は多様なバックグラウンドを持つ人材を採用しやすくなります。

### リモートワークの課題

1. **コミュニケーションの難しさ**: リモートワークでは顔を合わせる機会が減り、チーム内のコミュニケーションが減少することがあります。これが協力や情報共有に影響を与える可能性があります。

2. **仕事とプライベートの境界**: 自宅での仕事は、仕事とプライベートの境界を越えやすく、長時間働きがちになることがあります。

3. **マネジメントの難易度**: 従業員のエンゲージメントや進捗管理が難しくなる可能性があり、特に新しいチームメンバーの育成が課題となることがあります。

4. **テクノロジーの依存**: リモートワークではインターネットやテクノロジーに依存することになり、システムの不具合やセキュリティリスクも考慮する必要があります。

### 導入を検討する際のアイデア

1. **ハイブリッドモデルの導入**: 完全なリモートワークだけでなく、オフィスでの対面勤務と組み合わせるハイブリッドモデルを検討することで、コミュニケーションやチームの絆を維持しつつ、柔軟性を確保できます。

2. **明確なポリシーの策定**: リモートワークに関する期待やルールを明確にし、従業員と共有することで、よりスムーズな業務運営が可能になります。

3. **テクノロジーの活用**: コミュニケーションツールやプロジェクト管理ツールを適切に活用し、チームのつながりや情報の透明性を高める工夫が必要です。

4. **フィードバックの文化を促進**: 定期的なフィードバックセッションを設け、従業員が感じている課題や改善案を話し合う場を設けることで、リモートワーク環境を継続的に向上させることができます。

最終的には、組織の文化やビジョンに応じてリモートワークを導入するかどうかを判断することが重要です。それぞれの状況に合わせたアプローチを模索することをお勧めします。
---------- PlanningAgent ----------
1. general information expert : リモートワークの利点と課題を詳しくまとめ、導入を検討する際のアイデアを提案してください。
2. company rule expert : リモートワークに関する社内規定について、必要なルールやポリシーの提案をしてください。
3. sales expert : リモートワーク導入が営業活動に及ぼす影響を分析し、販売戦略の観点から意見を提供してください。
4. old information expert : 過去のリモートワーク実施の事例や成功/失敗の教訓を調査し、参考になる点を指摘してください。 

各エージェントにタスクが完了するまで待ちます。
---------- company_rule_expert ----------
[FunctionCall(id='call_tatUWsQfZVWSxQXbKIcQJITT', arguments='{"input": "リモートワークに関する社内規定の提案"}', name='search_rules_tool'), FunctionCall(id='call_q3OgPe0xVTN6v9UuVnCbWwje', arguments='{"input": "リモートワークに関するルールやポリシー"}', name='search_rules_tool')]
---------- company_rule_expert ----------
[FunctionExecutionResult(content='あなたは社内規定に関するAIアシスタントです。以下のコンテキストを考慮してください:\nリモートワーク規定\n第1条(目的)\n本規定は、従業員がリモートワークを行う際の基本的な方針及び手続きについて定めることを目的とする。\n\n第2条(適用範囲)\nこの規定は、全ての従業員に適用される。ただし、業務の性質上、出社が必要とされる職種については適用を除外する場合がある。\n\n次の質問に答えてください:\nリモートワークに関する社内規定の提案\n\nアシスタント:', call_id='call_tatUWsQfZVWSxQXbKIcQJITT'), FunctionExecutionResult(content='あなたは社内規定に関するAIアシスタントです。以下のコンテキストを考慮してください:\nリモートワーク規定\n第1条(目的)\n本規定は、従業員がリモートワークを行う際の基本的な方針及び手続きについて定めることを目的とする。\n\n第2条(適用範囲)\nこの規定は、全ての従業員に適用される。ただし、業務の性質上、出社が必要とされる職種については適用を除外する場合がある。\n\n次の質問に答えてください:\nリモートワークに関するルールやポリシー\n\nアシスタント:', call_id='call_q3OgPe0xVTN6v9UuVnCbWwje')]
---------- company_rule_expert ----------
リモートワークに関する社内規定について、以下のようなルールやポリシーの提案があります。

### リモートワークに関する社内規定の提案

#### 1. 目的(目指すべきこと)
本規定は、従業員がリモートワークを行う際の基本的な方針及び手続きについて定めることを目的とします。

#### 2. 適用範囲
この規定は、全ての従業員に適用されます。ただし、業務の特性上、出社が必要とされる職種については適用外とします。

### 具体的なルール

1. **リモートワークの申請**
   - リモートワークを希望する場合、事前に上司の承認を得なければなりません。
   - 申請は所定のフォーマット(例:リモートワーク申請書)に記入し提出します。

2. **勤務時間の遵守**
   - リモートワークを行う際は、通常の勤務時間(例:9:00~18:00など)を遵守することとします。
   - 勤務中は、業務に専念し、業務時間外の私用を避けるよう努めます。

3. **コミュニケーションの確保**
   - 定期的なチームミーティングをオンラインで実施し、業務の進捗を共有します。
   - チャットツールやビデオ会議ツールを活用し、必要な連絡を日常的に行うこととします。

4. **セキュリティ対策**
   - リモート環境で業務を行う際は、会社のセキュリティポリシーに従い、データの取り扱いに注意します。
   - VPN接続やパスワード管理を徹底し、不正アクセスを防止します。

5. **評価とフィードバック**
   - リモートワーク中の業務成績については、定期的な評価を行い、フィードバックを共有します。
   - 課題を早期に発見し、改善策を講じるための機会を設けます。

これらのルールを守ることにより、リモートワークの導入が円滑に進み、業務効率の向上を図ることが可能になります。社内での合意形成を図りつつ、持続可能なリモートワーク環境を構築することが期待されます。
---------- sales_expert ----------
[FunctionCall(id='call_i0nSCVCa3QlmRCbrmhPSqyNG', arguments='{"input": "リモートワーク導入が営業活動に及ぼす影響と販売戦略の観点からの意見"}', name='search_sales_tool'), FunctionCall(id='call_PjLesD6oBwJYEHjJHeDXQDjI', arguments='{"input": "過去のリモートワーク実施の事例と成功/失敗の教訓"}', name='search_sales_tool')]
---------- sales_expert ----------
[FunctionExecutionResult(content='あなたは営業に関するAIアシスタントです。以下のコンテキストを考慮してください:\n特性: 論理的で、計画的に物事を進める。細部にこだわる傾向。\n利用しやすいスキル:\nデータ分析スキル: 市場データや顧客データを元に、戦略を立てるのが得意。競合分析も効果的に行えます。\nプレゼンテーションにおける論理的構成: 論理的に構成された情報を提供することで、顧客の納得感を高める。\n5. リーダーシップ性\n特性: 他者を引きつけ、導く力がある。\n利用しやすいスキル:\nモチベーションスキル: 顧客やチームメンバーを鼓舞し、積極的に行動してもらうためのスキル。\n交渉スキル: リーダーシップを活かして、相手を説得する能力が高く、ウィンウィンの結果を導きやすいです。\n\n次の質問に答えてください:\nリモートワーク導入が営業活動に及ぼす影響と販売戦略の観点からの意見\n\nアシスタント:', call_id='call_i0nSCVCa3QlmRCbrmhPSqyNG'), FunctionExecutionResult(content='あなたは営業に関するAIアシスタントです。以下のコンテキストを考慮してください:\n### 3. クロージング(契約の締結)\n- **スキル内容**: \n  - **交渉スキル**: 顧客と条件について話し合い、ウィンウィンの関係を築くための技術です。相手の反応を見ながら柔軟に対応します。\n  - **心理的トリガーの活用**: 限定オファーや時間制限を利用して、顧客に「今決断する」理由を与える技術です。\n\n次の質問に答えてください:\n過去のリモートワーク実施の事例と成功/失敗の教訓\n\nアシスタント:', call_id='call_PjLesD6oBwJYEHjJHeDXQDjI')]
---------- sales_expert ----------
### リモートワークの導入が営業活動に及ぼす影響

リモートワークの導入は、営業活動にさまざまな影響を及ぼします。以下に主な影響を示します。

1. **顧客とのコミュニケーション**:
   - リモートワークにより営業活動がオンライン中心になることで、対面でのコミュニケーションが減少します。しかし、ビデオ会議やチャットツールを活用すれば、顧客との接点は維持できるため、オンラインコミュニケーションのスキルが重要です。

2. **販売戦略の見直し**:
   - 従来の営業活動が通用しづらくなる中で、デジタルマーケティングやデータ分析を活用した新しい販売戦略を立てる必要があります。特にリモート環境では、オンラインでのリードジェネレーションが重要になります。

3. **チームのエンゲージメント**:
   - リモートワークに伴い、チーム内のモチベーションやエンゲージメントを保つためには、明確な目標設定やフィードバックの仕組みが必要です。定期的なオンラインミーティングやチームビルディング活動を取り入れることで、関係性を強化できます。

4. **テクノロジーの活用**:
   - 営業チームが情報を共有し、効率的に仕事を進めるためにはCRM(顧客関係管理)システムやプロジェクト管理ツールを活用することが求められます。これにより、営業の進捗や結果をデジタルでトラッキングできます。

5. **リモート営業のスキル**:
   - リモートワークでは、対面営業とは異なるアプローチが必要です。オンライン営業のスキルやテクニックを習得するためのトレーニングを導入することで、営業パフォーマンスを向上させることができます。

### 参考となる過去のリモートワーク実施の事例と成功/失敗の教訓

1. **成功事例**:
   - あるテクノロジー企業は、リモートワークを積極的に導入し、オフィスの経費を大幅に削減しました。その結果、全ての従業員が高いレベルの生産性を維持し続け、業績も向上しました。彼らは、透明性のあるコミュニケーションと定期的なフィードバックを重視しました。

2. **失敗事例**:
   - 一方、別の企業ではリモートワークを導入したものの、適切な対応策を講じられず、コミュニケーションの希薄化や従業員の孤立感が問題視されました。特に新規営業の際に、対面での関係構築ができず、顧客との信頼関係が築けなかった点が大きな課題でした。

### 教訓
- **計画的な導入**: リモートワークを導入する際は、しっかりとした計画やルールを策定し、従業員との合意を得ることが重要です。
- **コミュニケーションの強化**: リモート環境特有のコミュニケーション課題に強い意識を持ち、チーム内での接触を意識的に増やす工夫が必要です。

これらを踏まえ、営業のプロセスや戦略を見直し、リモートワーク環境でも成功を収めるための行動をとることが求められます。
---------- old_information_expert ----------
### 過去のリモートワーク実施の事例と成功/失敗の教訓

#### 成功事例
1. **テクノロジー企業の事例**: 
   - ある大手テクノロジー企業では、リモートワークを導入した結果、オフィスの維持費を削減しつつ、従業員の生産性を高めることに成功しました。この企業は、透明性のあるコミュニケーションを確立し、定期的なフィードバックセッションを設けることで全従業員が一体感を持てるようにしました。その結果、業績も上昇し、従業員の定着率も高まりました。

2. **営業チームの特化したトレーニング**: 
   - リモート営業を行なった別の企業では、全営業担当者に対してオンラインでの販売スキルを強化するトレーニングプログラムを実施しました。特に、オンラインプレゼンテーションや顧客との関係構築に関するスキルを意識的に磨くことで、リモートであっても高い販売達成率を記録しました。

#### 失敗事例
1. **コミュニケーションの希薄化**:
   - 一方で、ある中小企業ではリモートワークを導入したものの、特に新規顧客との対面関係を築くことができず、顧客との信頼関係が薄れてしまう結果に。社員同士のコミュニケーションも減少し、孤立感が強まり、効率が低下した陰で従業員のモチベーションも下がったとされています。これにより、業績は悪化しました。

2. **プロセスの適応不足**:
   - 別の企業では、リモートワークに必要なプロセスやツールが導入されなかったため、従業員が独自のやり方で業務を進めることが多くなり、情報が分散。全員が同じ情報を共有できなくなり、戦略的な一貫性が失われてしまったことで、営業成績が落ち込む結果になりました。

### 教訓
- **計画的な導入と明確な方針**: リモートワークを導入する際には、計画的に進めることが重要です。しっかりとしたルールや方針を策定し、それを従業員と共有することで、業務の進行を円滑に保ちることができます。

- **定期的なコミュニケーション**: リモート環境においては、従業員同士や顧客とのコミュニケーションを意識的に増やすための施策がカギとなります。定期的にチームミーティングやフィードバックセッションを設けることで、エンゲージメントや進捗報告を強化できます。

- **適切なツールの導入**: CRMシステムやプロジェクト管理ツールを活用し、情報共有や業務のトラッキングを行うことが成功の基礎となります。効率的な業務運営のためには、テクノロジーの利用を推進することが不可欠です。

これらの成功事例と失敗事例から得られる教訓を踏まえ、リモートワーク環境でも高い成果を上げるための戦略を検討することが求められます。
---------- PlanningAgent ----------
リモートワークに関する議論から得られた情報を以下にまとめます。

### エージェントの意見

#### 一致点
1. **リモートワークのメリット**:
   - 柔軟な働き方やコスト削減、通勤時間の削減、広範な人材プールの獲得など、多くの利点が挙げられました。

2. **コミュニケーションの重要性**:
   - 定期的なコミュニケーションやフィードバックの場を設けることが、業務の効率を高めるために必要不可欠であるとの意見が一致しました。

3. **テクノロジーの利用**:
   - リモートワークを成功させるためには、適切なツール(CRMやプロジェクト管理ツール等)の活用が重要だという点で合意が得られました。

#### 食い違い点
1. **営業活動への影響**:
   - 営業エキスパートからは、リモートワークによって顧客との関係構築が課題になる旨の指摘がありましたが、一般情報エキスパートはリモート環境での新たなコミュニケーションスキルの習得が必要であることを強調しました。観点は異なるものの、顧客とのつながりを維持するための工夫の必要性は共通しています。

2. **社内規定の具体例**:
   - 社内規定エキスパートは具体的なルールを提案したのに対し、一般情報エキスパートはより広範なアイデアを提示しました。このことから、リモートワーク導入には定義されたルールの策定が重要であることが導き出されます。

### 結論
リモートワーク導入においては、利点と課題を理解し、明確な社内規定とコミュニケーション戦略を構築することが重要です。また、テクノロジーを適切に活用し、チームエンゲージメントを高める施策を取り入れることで、成功確率を高めることができるでしょう。リモート環境での適応を計画的に進めることで、業績向上が期待されます。 

TERMINATE

終わりに

今回は、AutoGen v0.2とv0.4でのマルチエージェントの構築を行いました。

冒頭でも記載しましたが、AutoGenでは手軽にマルチエージェントの構築と実行が可能だと感じました。

AutoGen v0.4はまだしっかりと内容の確認ができていないので、今後も調査を続けたいと思います。

執筆担当者プロフィール
寺澤 駿

寺澤 駿(日本ビジネスシステムズ株式会社)

IoTやAzure Cognitive ServicesのAIを活用したデモ環境・ソリューション作成を担当。

担当記事一覧