Build an Efficient Automated Weekly Report System Using CrewAI Framework

In daily work, writing personal and team weekly reports is a tedious and monotonous task. Fortunately, this scenario is very suitable for leveraging artificial intelligence (AI) technology to simplify the process. Although there are various GPT-based agents available in the market, such as Wenxin Yiyan, iFlytek Spark, and Zhipu Qingyan, which can summarize content provided by users, they cannot create content from scratch without user input. Moreover, there is currently no effective solution in the market for summarizing the workflows of department members for team weekly reports.

To address this issue, I adopted a multi-agent collaboration approach and chose the CrewAI framework to build an automated secretary team. CrewAI is a framework focused on multi-agent collaboration, showcasing significant advantages in team collaboration capabilities, communication interfaces, built-in algorithms, parallel computing, scalability, and application scenarios.

If you want to learn more about CrewAI, you can check out this article on WeChat. “Follow my steps to easily create AI agents”.

Next, I will share how to use the CrewAI framework to create multi-agent applications to automatically organize, summarize, and send weekly reports for department members.

Preparation:

First, to achieve this workflow, we need to clarify the roles, tasks, and required tools for the agents. Since our goal is to compile individual weekly reports into a team report, I developed custom tools to operate on Yuque documents and Alibaba Cloud email, all built according to CrewAI specifications.

Build an Efficient Automated Weekly Report System Using CrewAI Framework
Agent Composition

Core Files and Agent Definitions:

In the core files of CrewAI, agents.yaml and tasks.yaml define the agents and tasks, while crew.py and main.py define the logic and input information for the agents.

  • agents.yaml: In this file, we define two agents, one for obtaining individual weekly reports and summarizing them into a team weekly report, and the other for sending emails and publishing Yuque documents. For example:
writer:
 role: >
  Weekly Report Writer
 goal: >
  Summarize the weekly reports of department members into a team report.
 backstory: >
  You are a secretary to the manager, responsible for compiling the weekly reports of department members into a team report. You need to review each member's weekly report to ensure they are accurate, then summarize them into a team report.


sender:
 role: >
  Email and Yuque Sender
 goal: >
  Send emails and Yuque documents to the leaders
 backstory: >
  You are an email and Yuque sender, responsible for sending emails and Yuque documents to the leaders. You need to send the team weekly report to the leaders, ensuring the email content is correct and not creating attachments separately.
  • tasks.yaml: In this file, we define two tasks, one for summarizing weekly report content and organizing the document in Markdown format; the other task is to send the organized report to the leaders.
writing_task:
 description: >
  Summarize the weekly reports of department members into a team report.
  Ensure the final document is in Chinese.
  Avoid content compression as much as possible, ensuring all work content is included.
  Do not list names; just write down the work done.
  Call the member report retrieval tool only once; do not call it repeatedly, as each call retrieves the same information.
  After completing the overall creation of the department report, confirm with the human whether to send the email and publish the Yuque document.

  The final team report should be filled out according to the following sample, output in markdown format:

  ## Key Work This Week

  ### Product A Related

  * xxxx 5.5.6: Fixed backend bugs this week.

  * XXXX 6 & 6.2 Development: Planned to fix issues raised during XXX 6.0 testing and develop XXX 6.2.

  ### XXX Project

  * Multiple optimizations were made, including alarm rules, log download interfaces, node management interfaces, etc.

  * Planned for project maintenance and version adaptation.

  ### Frontend Logic

  ...

  ## Plans for Next Week

  * Continue development and issue handling related to XXX 6.

  * Subsequent development of XXX 3.0 page components.

  ...

 expected_output: >
  A markdown formatted team report.


send_task:
 description: >
  Send emails and Yuque documents to relevant leaders.
  Do not send emails or publish Yuque documents until the compilation is complete.
  Ensure the content parameter for sending emails and publishing Yuque is the markdown formatted team report content.
    
  Email content example:

  This week, the main work completed is... Below are the details:

  [Compiled Department Weekly Report]
  ***********************************************************************
  Zhang San /Zhangsan
  
  Mobile: 86-13122223333;
  
  Email: [email protected]
  
  XXXXXXX Company / XXXXXXXX Technology Ltd.
  ***********************************************************************
  
  Yuque document content example:
  
  [Compiled markdown formatted department weekly report]
 
 expected_output: >
 
  Was the task completed?

Agent Logic Orchestration:

In crew.py, we orchestrate the workflow of the agents by defining the WeeklyReportCrew class. Each agent has its own role and goal; for instance, the writer agent aims to summarize the weekly reports of department members, while the sender agent is responsible for sending the report to the leaders.

from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task
from weekly_report.tools.ali_mail import SendEmailTool
from weekly_report.tools.send_yuque_doc import SendYuqueDocTool
from weekly_report.utils.llms import LLMs
from langchain.agents import load_tools

# Uncomment the following line to use an example of a custom tool
from weekly_report.tools.weekly_reports import GetWeeklyReportsTool

# Check our tools documentations for more information on how to use them
# from crewai_tools import SerperDevTool

llm = LLMs(model_name="glm-3-turbo").get_llm()
function_calling_llm = LLMs(model_name="gpt-3.5-turbo-0125").get_llm()

get_weekly_reports_tool = GetWeeklyReportsTool()
send_email_tool = SendEmailTool()
send_yuque_doc_tool = SendYuqueDocTool()
human_tools = load_tools(["human"])

@CrewBase
class WeeklyReportCrew():
 """WeeklyReport crew"""
 agents_config = 'config/agents.yaml'
 tasks_config = 'config/tasks.yaml'
 
 @agent
 def writer(self) -> Agent:
  return Agent(
   config=self.agents_config['writer'],
   tools=[get_weekly_reports_tool], 
   verbose=True,
   llm=llm, 
   function_calling_llm=function_calling_llm,
   allow_delegation=True
  )
 
 @agent
 def sender(self) -> Agent:
  return Agent(
   config=self.agents_config['sender'],
   tools=[send_email_tool, send_yuque_doc_tool],
   verbose=True,
   llm=llm, 
   function_calling_llm=function_calling_llm,
   allow_delegation=True
  )

 @task
 def writing_task(self) -> Task:
  return Task(
   config=self.tasks_config['writing_task'],
   agent=self.writer(),
   # context=[self.manage_task()]
  )
 
 @task
 def send_task(self) -> Task:
  return Task(
   config=self.tasks_config['send_task'],
   agent=self.sender(),
   context=[self.writing_task()]
  )

 @crew
 def crew(self) -> Crew:
  """Creates the WeeklyReport crew"""
  return Crew(
   agents=self.agents, # Automatically created by the @agent decorator
   tasks=self.tasks, # Automatically created by the @task decorator
   # process=Process.sequential,
   verbose=2,
   process=Process.hierarchical, # In case you wanna use that instead https://docs.crewai.com/how-to/Hierarchical/
   manager_llm=function_calling_llm,
  )

Custom Tool Development:

In the CrewAI framework, custom tools are implemented through Python classes that inherit from BaseTool and complete specific tasks as needed. For example, SendEmailTool and SendYuqueDocTool are two tools used for sending emails and publishing Yuque documents.

  • SendEmailTool: This tool is responsible for sending emails containing the weekly report content. It uses Python’s smtplib library to send emails through Alibaba Cloud’s corporate email. The input for the tool is a string containing the email content, and the output is the success or failure message of the sending process.
import os

from dotenv import load_dotenv
from crewai_tools import BaseTool
from pydantic.v1 import BaseModel, Field
from typing import Type, List

class SendEmailInput(BaseModel):
    content: str = Field(..., title="Email Body", description="Specific content of the weekly report")

class SendEmailTool(BaseTool):
    name: str = "Email Sending Tool"
    description: str = "Tool for sending department weekly report emails, title and recipient do not need to be filled, fixed to AI&UI group weekly report"
    args_schema: Type[BaseModel] = SendEmailInput

    def send_email(self, content: str):
        load_dotenv()
        # Configure Alibaba corporate email
        mail_host = "smtp.qiye.aliyun.com"
        sender = os.getenv("ALI_SENDER")
        passwd = os.getenv("ALI_PASSWD")
        import smtplib
        from email.mime.text import MIMEText
        from email.header import Header
        from email.utils import formataddr
        receivers = os.getenv("ALI_RECEIVERS")
        # Send email in markdown format
        content = f"""{content}"""
        import markdown2
        content = markdown2.markdown(content)
        print(content)
        print(sender)
        print(receivers)
        msg = MIMEText(content, 'html', 'utf-8')
        msg['From'] = formataddr(["xdfs", sender])
        msg['To'] = receivers
        msg['Subject'] = Header("AI&UI Group Weekly Report", 'utf-8').encode()
        print(msg)
        to_list = receivers.split(',')
        try:
            server = smtplib.SMTP_SSL(mail_host, 465)
            server.login(sender, passwd)
            server.sendmail(sender, to_list, msg.as_string())
            server.close()
            return 'Email sent successfully'
        except Exception as e:
            return 'Email sending failed %s' % e
    
    def _run(self, content: str) -> str:
        load_dotenv()
        result = self.send_email(content)
        return result
  • SendYuqueDocTool: This tool is used to publish the weekly report in Markdown format to the Yuque knowledge base. It uses the Yuque API to create new documents and uses the report content as the document body. The input for the tool is the Markdown formatted report content, and the output is the success or failure message of the publishing process.
from crewai_tools import BaseTool
from dotenv import load_dotenv
import os
import requests

class SendYuqueDocTool(BaseTool):
    name: str = "Send Yuque Document Tool"
    description: str = "Tool for sending or publishing Yuque documents to the Yuque knowledge base"

    def get_this_friday(self):
        import datetime
        today = datetime.date.today()
        today_weekday = today.weekday()
        print(today_weekday)
        if today_weekday == 4:
            return today
        elif today_weekday > 4:
            return today - datetime.timedelta(days=(today_weekday-4) % 7)
        else:
            return today + datetime.timedelta(days=(4 - today_weekday) % 7)
    
    def _run(self, content: str) -> str:
        load_dotenv()
        auth_token = os.getenv("YUQUE_AUTH_TOKEN")
        login = os.getenv("YUQUE_LOGIN")
        slug = os.getenv("YUQUE_SLUG")
        # Get the UUID of the directory where the report is located
        get_toc_url = f"https://www.yuque.com/api/v2/repos/{login}/{slug}/toc"
        header = {"X-Auth-Token": auth_token}
        res_toc = requests.get(get_toc_url, headers=header)
        toc = res_toc.json()
        this_friday = self.get_this_friday().strftime("%Y%m%d")
        print(this_friday)
        target_uuid = ""
        for item in toc["data"]:
            if item["type"] == "TITLE" and item["title"] == this_friday:
                target_uuid = item["uuid"]
                break
        print(target_uuid)
        # Need to separately call the update directory interface to update the document to the directory
        if target_uuid == "":
            return "Weekly report directory not found"
        create_doc_url = f"https://www.yuque.com/api/v2/repos/{login}/{slug}/docs"
        header = {"X-Auth-Token": auth_token}
        data = {
            "title": "Department Weekly Report",
            "format": "markdown",
            "body": content
        }
        created_article = requests.post(create_doc_url, headers=header, data=data)
        update_toc_url = f"https://www.yuque.com/api/v2/repos/{login}/{slug}/toc"
        data = {
            "action": "appendNode",
            "action_mode": "child",
            "type": "DOC",
            "doc_ids": [created_article.json()["data"]["id"]],
            "target_uuid": target_uuid
        }
        response = requests.put(update_toc_url, headers=header, json=data)
        return "Yuque document created successfully!"

Execution Process:

  1. Retrieve Weekly Reports: The writer agent first uses the GetWeeklyReportsTool to retrieve the personal weekly reports from Yuque.
  2. Summarize Weekly Reports: Then, the writer agent summarizes this information into a complete team weekly report, formatting it according to the predefined Markdown template.
  3. Send Weekly Reports: After confirming the report content is correct, the sender agent uses the SendEmailTool to send the report via email to the leaders and uses the SendYuqueDocTool to publish the report to the Yuque knowledge base.

Pitfall Guide:

  • If you are not using OpenAI’s LLM, you need to specify the LLM you are using.
  • If using domestic LLMs, be sure to specify a foreign LLM as function_calling_llm to avoid potential errors.
  • Although the current tasks are sequential, using hierarchical process mode is more effective than sequential.
  • For generated content, it is best to provide a clear template to ensure accuracy and consistency.

Through the steps outlined above, we successfully built an automated secretary team capable of efficiently organizing, summarizing, and sending weekly reports. This not only saves a significant amount of human resources but also improves work efficiency and accuracy. I hope this article can help you apply AI technology in your actual work to automate workflows.

Due to space limitations, I cannot provide a detailed explanation of the code. If you are interested in this topic or need further assistance, feel free to add me on WeChat for communication. If you are interested in the complete source code, please follow my WeChat account and contact me.

Leave a Comment