Reorganize repo structure and upgrade to CrewAI 0.152.0 (#277)

* Reorganize repo structure and upgrade to CrewAI 0.152.0

* chore(gitignore): ignore Python bytecode and __pycache__ across templates

* chore(gitignore): ignore Python bytecode and __pycache__ across templates; clean tracked artifacts

* Update crews/instagram_post/pyproject.toml

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Tony Kipkemboi
2025-08-12 12:05:06 -04:00
committed by GitHub
parent 18e1ce703c
commit 7045b059bf
341 changed files with 77344 additions and 13685 deletions

View File

@@ -0,0 +1,3 @@
.env
__pycache__/
lib/

View File

@@ -0,0 +1,80 @@
# Self Evaluation Loop Flow
Welcome to the Self Evaluation Loop Flow project, powered by [crewAI](https://crewai.com). This project showcases a powerful pattern in AI workflows: automatic self-evaluation. By leveraging crewAI's multi-agent system, this flow demonstrates how to set up a Crew that evaluates the responses of other Crews, iterating with feedback to improve results.
## Overview
This flow guides you through setting up an automated self-evaluation system using two main Crews: the `ShakespeareanXPostCrew` and the `XPostReviewCrew`. The process involves the following steps:
1. **Generate Initial Output**: The `ShakespeareanXPostCrew` generates an initial Shakespearean-style post (X post) on a given topic, such as "Flying cars". This post is crafted to be humorous and playful, adhering to specific character limits and style guidelines.
2. **Evaluate Output**: The `XPostReviewCrew` evaluates the generated post to ensure it meets the required criteria, such as character count and absence of emojis. The crew provides feedback on the post's validity and quality.
3. **Iterate with Feedback**: If the post does not meet the criteria, the flow iterates by regenerating the post with the feedback provided. This iterative process continues until the post is valid or a maximum retry limit is reached.
4. **Finalize and Save**: Once the post is validated, it is finalized and saved for further use. If the maximum retry count is exceeded without achieving a valid post, the flow exits with the last generated post and feedback.
This pattern of automatic self-evaluation is crucial for developing robust AI systems that can adapt and improve over time, ensuring high-quality outputs through iterative refinement.
## Installation
Ensure you have Python >=3.10 <=3.13 installed on your system.
To install CrewAI, run the following command:
```bash
pip install crewai==0.130.0
```
This command will install CrewAI and its necessary dependencies, allowing you to start building and managing AI agents efficiently.
### Customizing
**Add your `OPENAI_API_KEY` into the `.env` file**
- Modify `src/flow_self_evalulation_loop/config/agents.yaml` to define your agents.
- Modify `src/flow_self_evalulation_loop/config/tasks.yaml` to define your tasks.
- Modify `src/flow_self_evalulation_loop/crew.py` to add your own logic, tools, and specific arguments.
- Modify `src/flow_self_evalulation_loop/main.py` to add custom inputs for your agents and tasks.
## Running the Project
To kickstart your crew of AI agents and begin task execution, run this from the root folder of your project:
```bash
crewai flow kickoff
```
This command initializes the self-evaluation loop flow, assembling the agents and assigning them tasks as defined in your configuration.
The unmodified example will generate a `report.md` file with the output of a research on LLMs in the root folder.
## Understanding Your Flow
The self-evaluation loop flow is composed of 2 Crews. These agents collaborate on a series of tasks, defined in `config/tasks.yaml`, leveraging their collective skills to achieve complex objectives. The `config/agents.yaml` file outlines the capabilities and configurations of each agent in your flow.
This flow is centered around two major Crews: the `ShakespeareanXPostCrew` and the `XPostReviewCrew`. The `ShakespeareanXPostCrew` is responsible for generating a Shakespearean-style post (X post) on a given topic, while the `XPostReviewCrew` evaluates the generated post to ensure it meets specific criteria. The process is iterative, using feedback from the review to refine the post until it is valid or a maximum retry limit is reached.
### Flow Structure
1. **Generate Initial Output**: A Crew generates the initial output based on predefined criteria.
2. **Evaluate Output**: Another Crew evaluates the output, providing feedback on its validity and quality.
3. **Iterate with Feedback**: If necessary, the initial Crew is re-run with feedback to improve the output.
4. **Finalize and Save**: Once validated, the output is saved for further use.
By understanding the flow structure, you can see how multiple Crews are orchestrated to work together, each handling a specific part of the self-evaluation process. This modular approach allows for efficient and scalable automation.
## Support
For support, questions, or feedback regarding the Self Evaluation Loop Flow or crewAI:
- Visit our [documentation](https://docs.crewai.com)
- Reach out to us through our [GitHub repository](https://github.com/joaomdmoura/crewai)
- [Join our Discord](https://discord.com/invite/X4JWnZnxPb)
- [Chat with our docs](https://chatg.pt/DWjSBZn)
Let's create wonders together with the power and simplicity of crewAI.

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,17 @@
[project]
name = "self_evaluation_loop_flow"
version = "0.1.0"
description = "self-evalulation-loop-flow using crewAI"
authors = [{ name = "Your Name", email = "you@example.com" }]
requires-python = ">=3.10,<=3.13"
dependencies = [
"crewai[tools]>=0.152.0",
]
[project.scripts]
kickoff = "self_evaluation_loop_flow.main:kickoff"
plot = "self_evaluation_loop_flow.main:plot"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

View File

@@ -0,0 +1,10 @@
shakespearean_bard:
role: >
Shakespearean Bard
goal: >
Craft sarcastic and playful hot takes in the style of Shakespeare.
Ensure that all responses fit within 280 characters and contain no emojis.
backstory: >
Thou art a witty bard, renowned for turning the mundane into the
magnificent with thy playful jests and biting sarcasm. Armed with wit and
wisdom, thou dost revel in the creation of humorous quips most pleasing to the ear.

View File

@@ -0,0 +1,12 @@
write_x_post:
description: >
Given the topic '{topic}', compose a humorous hot take in the style of Shakespeare.
The tone should be sarcastic and playful. The final short form social media post
must be over 200 characters and not exceed 280 characters, and emojis are strictly forbidden.
Please incorporate the following feedback if present:
{feedback}
expected_output: >
A witty, Shakespearean hot take between 200 and 280 characters [Inclusive].
agent: shakespearean_bard

View File

@@ -0,0 +1,34 @@
from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task
from self_evaluation_loop_flow.tools.CharacterCounterTool import CharacterCounterTool
@CrewBase
class ShakespeareanXPostCrew:
"""Shakespearean X Post Crew"""
agents_config = "config/agents.yaml"
tasks_config = "config/tasks.yaml"
@agent
def shakespearean_bard(self) -> Agent:
return Agent(
config=self.agents_config["shakespearean_bard"],
tools=[CharacterCounterTool()],
)
@task
def write_x_post(self) -> Task:
return Task(
config=self.tasks_config["write_x_post"],
)
@crew
def crew(self) -> Crew:
"""Creates the Shakespearean X Post 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=True,
)

View File

@@ -0,0 +1,10 @@
x_post_verifier:
role: >
X Post Verifier
goal: >
Ensure that any X post meets the strict guidelines:
it must be under 280 characters, contain no emojis, and be free of additional commentary.
backstory: >
You are a careful reviewer, skilled at understanding the core message of a post.
Your job is to maintain the clarity and brevity of the post by ensuring it contains no emojis,
unnecessary commentary, or excessive verbosity.

View File

@@ -0,0 +1,30 @@
verify_x_post:
description: >
Verify that the given X post meets the following criteria:
- It is between 200 and 280 characters inclusive.
- It contains no emojis.
- It contains only the post itself, without additional commentary.
The post should follow the 1-3-1 rule:
- 1 bold statement to hook the reader
- 3 lines of supporting information
- 1 sentence to summarize the post
Additionally, if you believe there are any issues with the post
or ways it could be improved, such as the structure of the post,
rhythm, word choice, please provide feedback.
If any of the criteria are not met, the post is considered invalid.
Provide actionable changes about what is wrong and what actions
need to be taken to fix the post.
Your final response must include:
- Valid: True/False
- Feedback: Provide commentary if the post fails any of the criteria.
X Post to Verify:
{x_post}
expected_output: >
Pass: True/False
Feedback: Commentary here if failed.
agent: x_post_verifier

View File

@@ -0,0 +1,43 @@
from typing import Optional
from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task
from pydantic import BaseModel
from self_evaluation_loop_flow.tools.CharacterCounterTool import CharacterCounterTool
class XPostVerification(BaseModel):
valid: bool
feedback: Optional[str]
@CrewBase
class XPostReviewCrew:
"""X Post Review Crew"""
agents_config = "config/agents.yaml"
tasks_config = "config/tasks.yaml"
@agent
def x_post_verifier(self) -> Agent:
return Agent(
config=self.agents_config["x_post_verifier"],
tools=[CharacterCounterTool()],
)
@task
def verify_x_post(self) -> Task:
return Task(
config=self.tasks_config["verify_x_post"],
output_pydantic=XPostVerification,
)
@crew
def crew(self) -> Crew:
"""Creates the X Post Review Crew"""
return Crew(
agents=self.agents,
tasks=self.tasks,
process=Process.sequential,
verbose=True,
)

View File

@@ -0,0 +1,81 @@
from typing import Optional
from crewai.flow.flow import Flow, listen, router, start
from pydantic import BaseModel
from self_evaluation_loop_flow.crews.shakespeare_crew.shakespeare_crew import (
ShakespeareanXPostCrew,
)
from self_evaluation_loop_flow.crews.x_post_review_crew.x_post_review_crew import (
XPostReviewCrew,
)
class ShakespeareXPostFlowState(BaseModel):
x_post: str = ""
feedback: Optional[str] = None
valid: bool = False
retry_count: int = 0
class ShakespeareXPostFlow(Flow[ShakespeareXPostFlowState]):
@start("retry")
def generate_shakespeare_x_post(self):
print("Generating Shakespearean X post")
topic = "Flying cars"
result = (
ShakespeareanXPostCrew()
.crew()
.kickoff(inputs={"topic": topic, "feedback": self.state.feedback})
)
print("X post generated", result.raw)
self.state.x_post = result.raw
@router(generate_shakespeare_x_post)
def evaluate_x_post(self):
if self.state.retry_count > 3:
return "max_retry_exceeded"
result = XPostReviewCrew().crew().kickoff(inputs={"x_post": self.state.x_post})
self.state.valid = result["valid"]
self.state.feedback = result["feedback"]
print("valid", self.state.valid)
print("feedback", self.state.feedback)
self.state.retry_count += 1
if self.state.valid:
return "complete"
return "retry"
@listen("complete")
def save_result(self):
print("X post is valid")
print("X post:", self.state.x_post)
# Save the valid X post to a file
with open("x_post.txt", "w") as file:
file.write(self.state.x_post)
@listen("max_retry_exceeded")
def max_retry_exceeded_exit(self):
print("Max retry count exceeded")
print("X post:", self.state.x_post)
print("Feedback:", self.state.feedback)
def kickoff():
shakespeare_flow = ShakespeareXPostFlow()
shakespeare_flow.kickoff()
def plot():
shakespeare_flow = ShakespeareXPostFlow()
shakespeare_flow.plot()
if __name__ == "__main__":
kickoff()

View File

@@ -0,0 +1,20 @@
from typing import Type
from crewai_tools import BaseTool
from pydantic import BaseModel, Field
class CharacterCounterInput(BaseModel):
"""Input schema for CharacterCounterTool."""
text: str = Field(..., description="The string to count characters in.")
class CharacterCounterTool(BaseTool):
name: str = "Character Counter Tool"
description: str = "Counts the number of characters in a given string."
args_schema: Type[BaseModel] = CharacterCounterInput
def _run(self, text: str) -> str:
character_count = len(text)
return f"The input string has {character_count} characters."

4583
flows/self_evaluation_loop_flow/uv.lock generated Normal file

File diff suppressed because it is too large Load Diff