diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2a64d15 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.env +.venv/ +**_pycache__ \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f49a4e1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..9316617 --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# Intro + +**Autonomous agents** possess reasoning and planning capabilities similar to human intelligence, making them advanced AI systems. They are essentially LLMs with brain that has the ability to self-reason and plan the decomposition of the tasks. + + +# Observations + +CrewAI is very powerful for orchestrating agents in sequence but does not yet have the "routing" capability, meaning it cannot redirect the flow to different agents based on user input. + +It is suitable for performing complex specific tasks. + +# Key Takeaways + +1. CrewAI provides wide range of multi-agent functionality and workflows, that helps in efficient task decomposition. + +2. Agents Prompt Engineering stands out as a crucial factor for enhancing task decomposition and planning. + +# Examples + +* [Getting started with CrewAI(https://docs.crewai.com/how-to/Creating-a-Crew-and-kick-it-off/#step-1-assemble-your-agents) +* [CrewAI, Empower your AI Agent](https://nutdnuy.medium.com/crewai-empower-your-ai-agent-bd34fa8b26c9) +* [Building an Agentic Workflow with CrewAI and Groq](https://www.analyticsvidhya.com/blog/2024/06/agentic-workflow-with-crewai-and-groq/) \ No newline at end of file diff --git a/crewai_tools/__init__.py b/crewai_tools/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/crewai_tools/agents.py b/crewai_tools/agents.py new file mode 100644 index 0000000..dcae965 --- /dev/null +++ b/crewai_tools/agents.py @@ -0,0 +1,105 @@ +from crewai import Agent, Task, Crew, Process +from dotenv import load_dotenv +from crewai_tools import SerperDevTool +from tools import github_tools +from langchain_groq import ChatGroq +load_dotenv(override=True) + +search_tool = SerperDevTool() +llm = ChatGroq(temperature=0, model_name="Llama3-8b-8192") + +#define agents + +researcher = Agent( + role='Senior Researcher', + goal='Uncover groundbreaking technologies in {topic}', + verbose=True, + memory=True, + backstory=( + "Driven by curiosity, you're at the forefront of" + "innovation, eager to explore and share knowledge that could change" + "the world." + ), + tools=[search_tool], + allow_delegation=True +) + +planner = Agent( + role="Content Planner", + goal="Plan engaging and factually accurate content on {topic}", + backstory="You're working on planning a blog article " + "about the topic: {topic} in 'https://medium.com/'." + "You collect information that helps the " + "audience learn something " + "and make informed decisions. " + "You have to prepare a detailed " + "outline and the relevant topics and sub-topics that has to be a part of the" + "blogpost." + "Your work is the basis for " + "the Content Writer to write an article on this topic.", + llm=llm, + allow_delegation=False, + verbose=True +) + +writer = Agent( + role="Content Writer", + goal="Write insightful and factually accurate " + "opinion piece about the topic: {topic}", + backstory="You're working on a writing " + "a new opinion piece about the topic: {topic} in 'https://medium.com/'. " + "You base your writing on the work of " + "the Content Planner, who provides an outline " + "and relevant context about the topic. " + "You follow the main objectives and " + "direction of the outline, " + "as provide by the Content Planner. " + "You also provide objective and impartial insights " + "and back them up with information " + "provide by the Content Planner. " + "You acknowledge in your opinion piece " + "when your statements are opinions " + "as opposed to objective statements.", + allow_delegation=False, + llm=llm, + verbose=True +) + +github_developer = Agent( + role="Code Snippet Seeker", + goal="Understand the code inside a GitHub repo and extract useful snippet of code.", + backstory="You are Code Snippet Seeker, an AI agent created to bridge conceptual" + "knowledge and practical implementation. Born from a sophisticated neural" + "network, your mission is to find precise code snippets corresponding to" + "section titles provided by Content Planner." + + "Content Planner structures articles on technical topics, and when a" + "section is ready, you take over. You dive into the given GitHub repository," + "locating the exact lines of code that match the given section titles." + + "With your understanding of context, programming languages, and coding" + "conventions, you ensure articles are both theoretically sound and" + "practically grounded. You are an invaluable asset, maintaining the bridge" + "between high-level concepts and real-world coding practices, and your" + "skills evolve through continuous learning.", + tools=[github_tools], + allow_delegation=False, + verbose=True +) + +editor = Agent( + role="Editor", + goal="Edit a given blog post to align with " + "the writing style of the organization 'https://medium.com/'. ", + backstory="You are an editor who receives a blog post " + "from the Content Writer. " + "Your goal is to review the blog post " + "to ensure that it follows journalistic best practices," + "provides balanced viewpoints " + "when providing opinions or assertions, " + "and also avoids major controversial topics " + "or opinions when possible.", + llm=llm, + allow_delegation=False, + verbose=True +) diff --git a/crewai_tools/crews.py b/crewai_tools/crews.py new file mode 100644 index 0000000..42c4ee1 --- /dev/null +++ b/crewai_tools/crews.py @@ -0,0 +1,14 @@ +from crewai import Crew, Process +from crewai_tools.agents import planner, writer, editor, github_developer +from crewai_tools.tasks import code_tutorial, code_snippets, research_task, plan, write, edit + +# Forming the tech-focused crew with some enhanced configurations +crew = Crew( + agents=[planner, writer, editor, github_developer], + tasks=[code_tutorial, code_snippets, research_task, plan, write, edit], + process=Process.sequential, # Optional: Sequential task execution is default + memory=True, + cache=True, + max_rpm=100, + share_crew=True +) \ No newline at end of file diff --git a/crewai_tools/tasks.py b/crewai_tools/tasks.py new file mode 100644 index 0000000..4f43719 --- /dev/null +++ b/crewai_tools/tasks.py @@ -0,0 +1,91 @@ +from crewai import Task +from crewai_tools.agents import researcher, writer, planner, github_developer, editor +from crewai_tools.tools import TurnOnEC2 +from crewai_tools import SerperDevTool +from dotenv import load_dotenv +load_dotenv(override=True) + +search_tool = SerperDevTool() +turn_on_ec2_tool = TurnOnEC2() + + +#Tasks + +code_tutorial = Task( + description=( + "1. Take a look at the README file on the code \n" + "2. Identify the list of step for the setup of the project \n" + "3. Analyze the code's and find the snippets or cli command of code related to each of the above mentioned code \n" + ), + expected_output="A comprehensive code snippet or cli command for each the points of the tutorial.", + agent=github_developer +) + +code_snippets = Task( + description=( + "1. Take a look at the entire code \n" + "2. Identify the list of main step for the implementation \n" + "3. Analyze the code's and find the snippets that represents each step of implementation of the previous point. \n" + ), + expected_output="A comprehensive code snippets list for each step of implementation.", + agent=github_developer +) + +research_task = Task( + description=( + "Identify all the useful information about the use case {topic}." + "Focus on identifying the current state of art." + "Your final report should clearly articulate the key points," + "the techniques and technologies used for the implementation," + "the tools that are involved (language of programming, cloud vendors, etc.)," + "the market opportunities, and potential risks." + ), + expected_output='A comprehensive long paragraph that report state of art for the given use case.', + tools=[search_tool], + agent=researcher, +) + +plan = Task( + description=( + "1. Examine all the, technologies, techniques, " + "tools, code snippets used for the implementation " + "and noteworthy news on the use case {topic}.\n" + "2. Develop a detailed content outline including " + "an introduction, setup, code explanation, possible applications, conclusion.\n" + "3. Include SEO keywords and relevant data or sources." + ), + expected_output="A comprehensive content plan document " + "with an outline, audience analysis, " + "SEO keywords, and resources.", + agent=planner, +) + +write = Task( + description=( + "1. Use the content plan to craft a compelling " + "blog post on {topic}.\n" + "2. Incorporate code snippets and cli commands in the setup and code explanation paragraphs. \n" + "3. Incorporate SEO keywords naturally.\n" + "4. Sections/Subtitles are properly named " + "in an engaging manner.\n" + "5. Ensure the post is structured with an " + "engaging introduction, insightful body, " + "and a summarizing conclusion.\n" + "6. Proofread for grammatical errors and " + "alignment with the brand's voice.\n" + ), + expected_output="A well-written blog post " + "in markdown format, ready for publication, " + "each section should have as many paragraphs are needed according to the list of extracted snippets and the information retrieved.", + agent=writer, +) + +edit = Task( + description=("Proofread the given blog post for " + "grammatical errors and " + "alignment with the brand's voice."), + expected_output="A well-written blog post in markdown format, " + "ready for publication, " + "each section should have as many paragraphs are needed according to the list of extracted snippets and the information retrieved.", + agent=editor +) diff --git a/crewai_tools/tools.py b/crewai_tools/tools.py new file mode 100644 index 0000000..acb5850 --- /dev/null +++ b/crewai_tools/tools.py @@ -0,0 +1,36 @@ +from crewai_tools import BaseTool +import boto3 +import os +import json +from crewai_tools import GithubSearchTool + +lambda_client = boto3.client('lambda', region_name=os.getenv('AWS_REGION')) +function_name_1 = 'riassume-turnon-ec2-lambda' +function_name_2 = 'riassume-turnoff-ec2-lambda' +payload = {} + +class TurnOnEC2(BaseTool): + name: str = "Turn on EC2" + description: str = "This tool turn on EC2 machine on the AWS Cloud." + + def _run(input : str) -> str: + # Convert the payload to JSON + payload_json = json.dumps(payload) + + # Invoke the Lambda function + response = lambda_client.invoke( + FunctionName=function_name_1, + InvocationType='RequestResponse', # Use 'Event' for asynchronous invocation + Payload=payload_json + ) + # Read the response + response_payload = response['Payload'].read() + response_dict = json.loads(response_payload) + print(response_dict) + return "Started!" + +# Initialize the tool for semantic searches within a specific GitHub repository +github_tool = GithubSearchTool( + github_repo=os.getenv('GITHUB_REPO'), + content_types=['code', 'repo'] # Options: code, repo, pr, issue +) diff --git a/main.py b/main.py new file mode 100644 index 0000000..93dad4e --- /dev/null +++ b/main.py @@ -0,0 +1,11 @@ +import os +os.environ["GITHUB_REPO"] = "https://github.com/riolaf05/langchain-crewai-agent" +os.environ["TOPIC"] = "Agents with CrewAI and Langchain" + +from crewai_tools.crews import crew +from dotenv import load_dotenv +load_dotenv(override=True) + +# Starting the task execution process with enhanced feedback +result = crew.kickoff(inputs={'topic': os.getenv["TOPIC"]}) +print(result) \ No newline at end of file diff --git a/notebooks/main.ipynb b/notebooks/main.ipynb new file mode 100644 index 0000000..5a5a0a8 --- /dev/null +++ b/notebooks/main.ipynb @@ -0,0 +1,223 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "ename": "ModuleNotFoundError", + "evalue": "No module named 'crewai'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[5], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mos\u001b[39;00m\n\u001b[1;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mcrewai\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m Agent, Task, Crew, Process\n\u001b[0;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mlangchain\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mretrievers\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mtavily_search_api\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m TavilySearchAPIRetriever\n\u001b[0;32m 4\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mdotenv\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m load_dotenv\n", + "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'crewai'" + ] + } + ], + "source": [ + "from crewai_tools.crews import crew" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "TAVILY_RESULTS=3\n", + "search_tool = TavilySearchAPIRetriever(k=TAVILY_RESULTS\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "ename": "KeyError", + "evalue": "'tools'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[3], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;66;03m# Senior Researcher Agent\u001b[39;00m\n\u001b[1;32m----> 2\u001b[0m researcher \u001b[38;5;241m=\u001b[39m \u001b[43mAgent\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 3\u001b[0m \u001b[43m \u001b[49m\u001b[43mrole\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mSenior Researcher\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[0;32m 4\u001b[0m \u001b[43m \u001b[49m\u001b[43mgoal\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mUncover groundbreaking technologies in \u001b[39;49m\u001b[38;5;132;43;01m{topic}\u001b[39;49;00m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[0;32m 5\u001b[0m \u001b[43m \u001b[49m\u001b[43mverbose\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[0;32m 6\u001b[0m \u001b[43m \u001b[49m\u001b[43mmemory\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[0;32m 7\u001b[0m \u001b[43m \u001b[49m\u001b[43mbackstory\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m(\u001b[49m\n\u001b[0;32m 8\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mDriven by curiosity, you\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mre at the forefront of\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\n\u001b[0;32m 9\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43minnovation, eager to explore and share knowledge that could change\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\n\u001b[0;32m 10\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mthe world.\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\n\u001b[0;32m 11\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 12\u001b[0m \u001b[43m \u001b[49m\u001b[43mtools\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m[\u001b[49m\u001b[43msearch_tool\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 13\u001b[0m \u001b[43m \u001b[49m\u001b[43mallow_delegation\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\n\u001b[0;32m 14\u001b[0m \u001b[43m)\u001b[49m\n\u001b[0;32m 16\u001b[0m \u001b[38;5;66;03m# Writer Agent\u001b[39;00m\n\u001b[0;32m 17\u001b[0m writer \u001b[38;5;241m=\u001b[39m Agent(\n\u001b[0;32m 18\u001b[0m role\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mWriter\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[0;32m 19\u001b[0m goal\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mNarrate compelling tech stories about \u001b[39m\u001b[38;5;132;01m{topic}\u001b[39;00m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 28\u001b[0m allow_delegation\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m\n\u001b[0;32m 29\u001b[0m )\n", + "File \u001b[1;32mc:\\Users\\ELAFACRB1\\venvs\\crewai\\Lib\\site-packages\\crewai\\agent.py:140\u001b[0m, in \u001b[0;36mAgent.__init__\u001b[1;34m(__pydantic_self__, **data)\u001b[0m\n\u001b[0;32m 138\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__init__\u001b[39m(__pydantic_self__, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mdata):\n\u001b[0;32m 139\u001b[0m config \u001b[38;5;241m=\u001b[39m data\u001b[38;5;241m.\u001b[39mpop(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mconfig\u001b[39m\u001b[38;5;124m\"\u001b[39m, {})\n\u001b[1;32m--> 140\u001b[0m \u001b[38;5;28;43msuper\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;21;43m__init__\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mdata\u001b[49m\u001b[43m)\u001b[49m\n", + " \u001b[1;31m[... skipping hidden 1 frame]\u001b[0m\n", + "File \u001b[1;32mc:\\Users\\ELAFACRB1\\venvs\\crewai\\Lib\\site-packages\\crewai\\agent.py:187\u001b[0m, in \u001b[0;36mAgent.set_agent_executor\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 185\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcache_handler:\n\u001b[0;32m 186\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcache_handler \u001b[38;5;241m=\u001b[39m CacheHandler()\n\u001b[1;32m--> 187\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mset_cache_handler\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcache_handler\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 188\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\n", + "File \u001b[1;32mc:\\Users\\ELAFACRB1\\venvs\\crewai\\Lib\\site-packages\\crewai\\agent.py:259\u001b[0m, in \u001b[0;36mAgent.set_cache_handler\u001b[1;34m(self, cache_handler)\u001b[0m\n\u001b[0;32m 257\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcache_handler \u001b[38;5;241m=\u001b[39m cache_handler\n\u001b[0;32m 258\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtools_handler\u001b[38;5;241m.\u001b[39mcache \u001b[38;5;241m=\u001b[39m cache_handler\n\u001b[1;32m--> 259\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcreate_agent_executor\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[1;32mc:\\Users\\ELAFACRB1\\venvs\\crewai\\Lib\\site-packages\\crewai\\agent.py:332\u001b[0m, in \u001b[0;36mAgent.create_agent_executor\u001b[1;34m(self, tools)\u001b[0m\n\u001b[0;32m 330\u001b[0m bind \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mllm\u001b[38;5;241m.\u001b[39mbind(stop\u001b[38;5;241m=\u001b[39mstop_words)\n\u001b[0;32m 331\u001b[0m inner_agent \u001b[38;5;241m=\u001b[39m agent_args \u001b[38;5;241m|\u001b[39m execution_prompt \u001b[38;5;241m|\u001b[39m bind \u001b[38;5;241m|\u001b[39m CrewAgentParser(agent\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m)\n\u001b[1;32m--> 332\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39magent_executor \u001b[38;5;241m=\u001b[39m \u001b[43mCrewAgentExecutor\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 333\u001b[0m \u001b[43m \u001b[49m\u001b[43magent\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mRunnableAgent\u001b[49m\u001b[43m(\u001b[49m\u001b[43mrunnable\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43minner_agent\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mexecutor_args\u001b[49m\n\u001b[0;32m 334\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[1;32mc:\\Users\\ELAFACRB1\\venvs\\crewai\\Lib\\site-packages\\pydantic\\v1\\main.py:339\u001b[0m, in \u001b[0;36mBaseModel.__init__\u001b[1;34m(__pydantic_self__, **data)\u001b[0m\n\u001b[0;32m 333\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[0;32m 334\u001b[0m \u001b[38;5;124;03mCreate a new model by parsing and validating input data from keyword arguments.\u001b[39;00m\n\u001b[0;32m 335\u001b[0m \n\u001b[0;32m 336\u001b[0m \u001b[38;5;124;03mRaises ValidationError if the input data cannot be parsed to form a valid model.\u001b[39;00m\n\u001b[0;32m 337\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[0;32m 338\u001b[0m \u001b[38;5;66;03m# Uses something other than `self` the first arg to allow \"self\" as a settable attribute\u001b[39;00m\n\u001b[1;32m--> 339\u001b[0m values, fields_set, validation_error \u001b[38;5;241m=\u001b[39m \u001b[43mvalidate_model\u001b[49m\u001b[43m(\u001b[49m\u001b[43m__pydantic_self__\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;18;43m__class__\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdata\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 340\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m validation_error:\n\u001b[0;32m 341\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m validation_error\n", + "File \u001b[1;32mc:\\Users\\ELAFACRB1\\venvs\\crewai\\Lib\\site-packages\\pydantic\\v1\\main.py:1100\u001b[0m, in \u001b[0;36mvalidate_model\u001b[1;34m(model, input_data, cls)\u001b[0m\n\u001b[0;32m 1098\u001b[0m \u001b[38;5;28;01mcontinue\u001b[39;00m\n\u001b[0;32m 1099\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m-> 1100\u001b[0m values \u001b[38;5;241m=\u001b[39m \u001b[43mvalidator\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcls_\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvalues\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 1101\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m (\u001b[38;5;167;01mValueError\u001b[39;00m, \u001b[38;5;167;01mTypeError\u001b[39;00m, \u001b[38;5;167;01mAssertionError\u001b[39;00m) \u001b[38;5;28;01mas\u001b[39;00m exc:\n\u001b[0;32m 1102\u001b[0m errors\u001b[38;5;241m.\u001b[39mappend(ErrorWrapper(exc, loc\u001b[38;5;241m=\u001b[39mROOT_KEY))\n", + "File \u001b[1;32mc:\\Users\\ELAFACRB1\\venvs\\crewai\\Lib\\site-packages\\langchain\\agents\\agent.py:980\u001b[0m, in \u001b[0;36mAgentExecutor.validate_tools\u001b[1;34m(cls, values)\u001b[0m\n\u001b[0;32m 978\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Validate that tools are compatible with agent.\"\"\"\u001b[39;00m\n\u001b[0;32m 979\u001b[0m agent \u001b[38;5;241m=\u001b[39m values[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124magent\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n\u001b[1;32m--> 980\u001b[0m tools \u001b[38;5;241m=\u001b[39m \u001b[43mvalues\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mtools\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\n\u001b[0;32m 981\u001b[0m allowed_tools \u001b[38;5;241m=\u001b[39m agent\u001b[38;5;241m.\u001b[39mget_allowed_tools()\n\u001b[0;32m 982\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m allowed_tools \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n", + "\u001b[1;31mKeyError\u001b[0m: 'tools'" + ] + } + ], + "source": [ + "# Senior Researcher Agent\n", + "researcher = Agent(\n", + " role='Senior Researcher',\n", + " goal='Uncover groundbreaking technologies in {topic}',\n", + " verbose=True,\n", + " memory=True,\n", + " backstory=(\n", + " \"Driven by curiosity, you're at the forefront of\"\n", + " \"innovation, eager to explore and share knowledge that could change\"\n", + " \"the world.\"\n", + " ),\n", + " tools=[search_tool],\n", + " allow_delegation=True\n", + ")\n", + "\n", + "# Writer Agent\n", + "writer = Agent(\n", + " role='Writer',\n", + " goal='Narrate compelling tech stories about {topic}',\n", + " verbose=True,\n", + " memory=True,\n", + " backstory=(\n", + " \"With a flair for simplifying complex topics, you craft\"\n", + " \"engaging narratives that captivate and educate, bringing new\"\n", + " \"discoveries to light in an accessible manner.\"\n", + " ),\n", + " tools=[search_tool],\n", + " allow_delegation=False\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Research Task\n", + "research_task = Task(\n", + " description=(\n", + " \"Identify the next big trend in {topic}.\"\n", + " \"Focus on identifying pros and cons and the overall narrative.\"\n", + " \"Your final report should clearly articulate the key points,\"\n", + " \"its market opportunities, and potential risks.\"\n", + " ),\n", + " expected_output='A comprehensive 3 paragraphs long report on the latest AI trends.',\n", + " tools=[search_tool],\n", + " agent=researcher,\n", + ")\n", + "\n", + "# Writing Task\n", + "write_task = Task(\n", + " description=(\n", + " \"Compose an insightful article on {topic}.\"\n", + " \"Focus on the latest trends and how it's impacting the industry.\"\n", + " \"This article should be easy to understand, engaging, and positive.\"\n", + " ),\n", + " expected_output='A 4 paragraph article on {topic} advancements formatted as markdown.',\n", + " tools=[search_tool],\n", + " agent=writer,\n", + " async_execution=False,\n", + " output_file='new-blog-post.md' # Example of output customization\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Forming the tech-focused crew with enhanced configurations\n", + "crew = Crew(\n", + " agents=[researcher, writer],\n", + " tasks=[research_task, write_task],\n", + " process=Process.sequential # Optional: Sequential task execution is default\n", + ")\n", + "\n", + "# Running the crew with input topic\n", + "result = crew.kickoff(inputs={'topic': 'AI in healthcare'})\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "See https://pub.towardsai.net/building-a-multi-agent-system-to-accomplish-complex-tasks-812aeedda4eb" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from utils.crewai import Agent\n", + "\n", + "#define agents\n", + "data_collector = Agent(\n", + " name=\"researcher\",\n", + " role=\"Climate Data Collector\",\n", + " goal=\"Collect comprehensive climate data from multiple sources.\",\n", + " backstory=\"You gather climate data on temperature, carbon dioxide levels and other variables relevant to climate change, from reliable sources.\",\n", + " tools=['search_tool']\n", + ")\n", + "\n", + "data_analyst = Agent(\n", + " name=\"Data Scientist\",\n", + " role=\"Climate Data Scientist\",\n", + " goal=\"Analyse the collected climate data to identify significant trends.\",\n", + " backstory=\"You analyse climate data to find significant trends and understand the impact of various factors on climate change.\",\n", + " tools=[]\n", + ")\n", + "\n", + "report_writer = Agent(\n", + " name=\"Report Writer\",\n", + " role=\"Senior Scientific Report Writer\",\n", + " goal=\"Generate a comprehensive report on climate change findings.\",\n", + " backstory=\"You write detailed scientific reports based on the analysed climate data, highlighting key findings and implications.\",\n", + " tools=[]\n", + ")\n", + "\n", + "peer_reviewer = Agent(\n", + " name=\"Peer Reviewer\",\n", + " role=\"Scientific Peer Reviewer\",\n", + " goal=\"Review the scientific report for accuracy, clarity, and completeness.\",\n", + " backstory=\"You review scientific reports to ensure they are accurate, clear, and meet the standards for scientific publication.\",\n", + " tools=[]\n", + ")\n", + "\n", + "final_report_writer = Agent(\n", + " name=\"Final Report Writer\",\n", + " role=\"Final Report Writer\",\n", + " goal=\"Incorporate peer review feedback and finalize the scientific report.\",\n", + " backstory=\"You finalize the scientific report by incorporating feedback from peer reviewer and ensure it is publication ready.\",\n", + " tools=[]\n", + ")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "langchain", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..4163019 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +langchain +crewai +'crewai[tools]' +boto3 \ No newline at end of file diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/utils/agents.py b/utils/agents.py new file mode 100644 index 0000000..f9b0a36 --- /dev/null +++ b/utils/agents.py @@ -0,0 +1,37 @@ + + +class TheArchitect: + def __init__(self, agents, tasks): + # dictionary of all agents based on name + self.agents = {agent.name: agent for agent in agents} + self.tasks = tasks + + def process(self, inputs): + results = {} + current_result = None + + for task in self.tasks: + task_agent = self.agents[task.agent.name] + '''to help with debugging and also checking flow of info + we can check/print which tasks are assigned to which agent''' + print(f"assignin task {task.name} to agent {task_agent.name}: {task.info}") + + if current_result: + inputs['previous_result'] = current_result + + if 'search' in inputs: + search_query = inputs['search'] + search_results = search_tool.run(query=search_query) + inputs['search_results'] = search_results + + agent_output = task_agent.do_task(task, inputs) + current_result = agent_output + + # send the agent's output as a message to all other agents + for agent_name, agent in self.agents.items(): + if agent_name != task_agent.name: + task_agent.send_message(agent, agent_output) + + results[task.agent.name] = agent_output + + return results \ No newline at end of file diff --git a/utils/crewai.py b/utils/crewai.py new file mode 100644 index 0000000..21dc36c --- /dev/null +++ b/utils/crewai.py @@ -0,0 +1,64 @@ +import os +import openai +from openai import OpenAI +from crewai_tools import SerperDevTool +from dotenv import load_dotenv +load_dotenv(override=True) + +client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) +search_tool = SerperDevTool() + +class Agent: + def __init__(self, name, role, backstory, goal, tools=None): + self.name = name + self.backstory = backstory + self.goal = goal + self.role = role + self.memory = [] + self.tools = tools if tools else [] + self.message_box = [] + # adding memory for the agent to store recent tasks and outputs + def add_to_memory(self, entry): + self.memory.append(entry) + + # sending messages to other agents + def send_message(self, recipient, message): + recipient.message_box.append((self.name, message)) + + # reading the messages sent from other agents before performing task + # this is done by removing messages from message box and added to memory + def read_messages(self): + while self.message_box: + sender, message = self.message_box.pop(0) + self.add_to_memory(f"message from the {sender}: {message}") + + # we now define the function that will do the task assigned + # reading messages and adding task to the memory first + # the agent will take up the specialised role assigned and querry gpt3.5 + + def do_task(self, task, inputs): + self.read_messages() + task_info = task.info + self.add_to_memory(f"doing task: {task_info}") + + '''for the research agent, the search_tool will be assigned to the agent + which it will be able to use to do a google search online''' + + if 'search_tool' in self.tools: + search_query = task_info + search_results = search_tool.run(query=search_query) + inputs['search_results'] = search_results + task_info += f"\n\nsearch results:\n{search_results}" + + llm_response = client.chat.completions.create( + model="gpt-3.5-turbo", + messages=[ + {"role": "system", "content": f"you are a {self.role}. {self.backstory} Your goal is {self.goal}."}, + {"role": "user", "content": task_info} + ] + ) + output = llm_response.choices[0].message.content + self.add_to_memory(f"task output: {output}") + + return output +