crewAI实践--AiRusumeGenerator
- 什么是crewAI
- AiRusumeGenerator
- 功能效果展示
- 开发背景
- 开发步骤
- 1. 首先得学习下这款框架
- 原理
- 大概用法
- 能够用来做什么?
- 2. 安装crewAI以及使用概述
- 3. 写代码
- Agents.py
- Tasks.py
- mian.py
- 关于task中引入的自定义工具这里不再赘述
什么是crewAI
Cutting-edge framework for orchestrating role-playing, autonomous AI agents. By fostering collaborative intelligence, CrewAI empowers agents to work together seamlessly, tackling complex tasks.
CrewAI 是一个前沿的框架,用于组织和协调角色扮演的自主AI代理。通过促进协作智能,它使代理能够无缝地协同工作,应对复杂任务。
官网:https://www.crewai.com/
AiRusumeGenerator
ai智能简历在线生成器,一个有点用,但用处不多的多智能体应用。代码在最后。
项目相关文章:
memory的启用,避开openai
功能效果展示
简历结构设计方案
求职着目标岗位概况
开发背景
最近在准备找工作,准备简历是个烦心的事情,恰好在微信公众号看到了crewAI的介绍,又恰好看到官方案例中有简历优化这样一个应用,于是花了一个星期来学习以及使用这款框架,不得不说目前的大模型诞生在国外这一事实造成了很多麻烦,很多AI框架都是围绕着openai开发的。但是,费点力气还是能克服的。
开发步骤
1. 首先得学习下这款框架
这里是学习视频网址。
原理
简单说说我的理解,其原理就是将一个可能比较复杂的任务,比如生成一个简历。。。如果你直接让大模型给你,其实也是可以的,给出的结果有时候可能也还不错,但是就是感觉不是想要的结果,想要改就得不断的修改提示词去调整,才有可能得到想要的结果。
但是懒惰是人的本性,我想要的是我把我的个人信息材料和我目标岗位的信息提供给你,然后你直接给我一份针对性的定制性的简历,最好还能提供一些岗位匹配报告、面试指南等等,这一切都要是针对性的。那么这就是一个复杂的业务流程了。
而复杂的业务流程实现高质量结果的核心就是分工合作,每个人专注自己的事情。据官方提供的信息大模型同样据有此种特性。
由于之前在erp行业干过一年半,所以我对SOP标准作业程序这一概念有所了解,我发现这个概念和crewAI可以说是相当契合了。
于是我们的第一个问题就是,一个简历的标准制作流程是什么?想当然的我认为现在的猎头公司应当有这项任务。什么?没干过猎头,不知道是他有什么业务?很简单,问AI嘛
好的,流程有了,那么所谓的专人专事,什么人做什么呢?依旧不知道,当然还是问AI:
好的,应用的基本运行逻辑也就有了,但是一个好的SOP应该每一个关键步骤都有其标准的结果文档才行,那么好,继续问ai:
ok,到目前为止,一个简历生成器的基本运行逻辑有了,下面就是如何利用crewAI框架去实现了。
大概用法
简单浏览下其官方文档,大概步骤是这样
(1) 解决大模型的使用问题
直接给答案:
from langchain_community.chat_models import ChatZhipuAI,ChatTongyi
import os
#两种大模型,一个是阿里的大模型Qwen,一个是智谱AI的glm4
os.environ["DASHSCOPE_API_KEY"] = ""
os.environ["ZHIPUAI_API_KEY"] = ""#为memeory的启用而设置,国内用不了openai,也不想用,url是本地部署的xinference服务,兼容openai的api
os.environ['OPENAI_API_BASE'] ="http://localhost:9997/v1"
os.environ['OPENAI_API_KEY'] = 'not empty'zhipullm = ChatZhipuAI(model="glm-4",temperature=0.6,max_tokens = 4096,
)TongyiQW = ChatTongyi(model="qwen-turbo",max_tokens = 4096,temperature=0.7
)# 设个变量好赋值
llm = TongyiQW
(2) 关键概念,设置agent
这里仅仅展示其中一个,构造可以说是相当简单
其实也展现了一种格式化的提示词写作方法,确定角色、目标、背景,这些就是人类的人设。作为模拟人工智能的大模型也是如此。
# 初始化Agent对象,设置其角色、目标、背景故事以及其他配置ICNS = Agent(role="信息收集与分析专员",goal="深入了解求职者,精准把握职位需求,为简历制作提供详实基础。",backstory="1. 作为一家猎头公司求职项目组的信息收集与分析专员,你所在的项目组正在协助求职者准备他的简历。""2. 你将负责通过求职者提供的材料,深入了解其背景、经历、技能及职业目标。""3. 你需要收集并整理求职者提供的所有相关材料,包括现有简历、项目案例、证书等。""4. 你需要深入分析目标职位的详细要求,明确招聘方的偏好和需求。",#是否允许智能体生成任务分配给其他智能体allow_delegation=False,#不使用openai必须单独指定大模型,否则其会默认使用openaillm=llm,verbose=True,)
(3) 关键概念,设置task
任务也就是程序步骤,关键在description和expected_output,即任务描述和生成什么样的结果。以及什么人去执行,需要用到什么工具。工具是另一个核心概念。
applicant_analysis = Task(name="求职者信息收集与分析",description="1. 通过求职者提供的材料,深入了解和分析其背景、经历、技能及职业目标等。""2. 如果在材料中发现有可以打开的url,可以尝试使用网页抓取工具获取更多信息进行分析。""2. 撰写求职者概况报告,要求汇总求职者关键信息。",expected_output = "一份详细且准确的Markdown格式的求职者概况报告,汇总求职者关键信息。",agent = agent,tools = [FileReadTool,scrapeWebsiteTool],#将大模型得出的结果存到文件里output_file = "result/AiResumeGenerator/求职者概况报告.md",#没有文件目录时自动创建create_directory=True,#异步执行,就是没执行完也可以执行下一个async_execution=True,)
(4) 关键概念,crew
crew是船员的意思,意思是将上面设置的agent与task结合到一起,形成一个完整的团体,也是一个完整的工作流程。
crew = Crew(agents=[info_collection_analysis_specialist, resume_architect,content_editor,quality_control_expert,customer_manager],tasks=[info_collection_analysis, resume_structure_design,content_creation_filling,content_review_optimization,joint_resume_review],verbose=2, # You can set it to 1 or 2 to different logging levelsmemory=True,output_log_file = True,#据说这里也可以指定代理用什么模型会覆盖agent里面的llm设置#function_calling_llm = zhipullm,#memeory启用时,embeddr也必须启用,不然会默认使用openaiembedder={"provider": "openai","config":{#这是通过xinference框架提供的服务,因为在之前设置了openai的baseurl环境变量"model": 'custom-embedding-bge-large-zh-v1.5'}})
能够用来做什么?
了解了大体框架原理以及用法,用来能做什么你们心理应该也有数了。
用官方的话来说,这其实是一种新型的编程方式,整个软件运行过程中的每一步,只有软件的流程是确定的(当然开启了层级流程控制,流程也不确定了),输入是模糊的,输出也是模糊的,这里的模糊对比于以前编程函数中的输入和输出,以前我们程序中的每一步骤的数据类型、数据值都是确定的,而crewAI程序不同,只有输入输出的类型是确定的都是字符串,但是值每一次可能都是不同的,这也是ai的魅力所在。
且个人感觉crewAI已经有了半面向自然语言编程的味道了。
最后,出于我狭窄的视野,crewAI能够用来做所有的文字类工作,好像是句废话,但是现在的咨询公司、自媒体等等,都是可以被取代的。
2. 安装crewAI以及使用概述
这里不再赘述,直接引用前辈的贡献。多Agent协作工具CrewAI使用指南
3. 写代码
由于代码长度的问题,agent、task、crew启动单独封装在不同的文件
Agents.py
from crewai import Agentclass Agents():"""Agents class : This class is used to create agentsfunction: manager,icns,resume_architect,content_editor,qce,interviewCoach"""def manger(self,llm):"""创建一个表示项目经理的Agent对象,该对象具有特定的角色、目标、背景故事,并允许委托和详细输出。参数:self: 对象实例,通常在类方法中使用,表示当前类的实例。llm: (类型未指定) - 这个参数的用途需要具体上下文来确定,可能是某种管理资源或配置。返回:manager: Agent对象 - 包含项目经理角色信息的实例,具备管理功能和配置的Agent。注意:- Agent对象的角色是"项目经理",其目标是高效管理团队并保证任务质量。- 背景故事描述了项目经理的角色职责,包括协调团队和确保任务按期高质量完成。- 允许代理(allow_delegation=True)意味着该角色可以将部分任务委派给其他对象。- 设置为verbose=True,意味着Agent在执行操作时会提供详细的输出信息。"""manager = Agent(role="项目经理",goal="高效管理团队,确保高质量完成任务",backstory="您是一位经验丰富的项目经理,擅长监督复杂项目并引领团队走向成功。您的职责是协调团队成员的努力,确保每项任务按时完成并达到最高标准。",allow_delegation=True,verbose=True,llm = llm,)return managerdef icns(self, llm):"""创建一个信息收集与分析专员的Agent实例。该函数用于初始化一个名为ICNS的Agent对象,该对象将扮演信息收集与分析专员的角色,其主要职责是深入了解求职者背景和职位需求,为简历制作提供支持。参数:- llm: 低层模型的缩写,具体用途未说明,可能是一个用于辅助分析的模型或算法。返回:- 返回创建的ICNS Agent实例。"""# 初始化Agent对象,设置其角色、目标、背景故事以及其他配置ICNS = Agent(role="信息收集与分析专员",goal="深入了解求职者,精准把握职位需求,为简历制作提供详实基础。",backstory="1. 作为一家猎头公司求职项目组的信息收集与分析专员,你所在的项目组正在协助求职者准备他的简历。""2. 你将负责通过求职者提供的材料,深入了解其背景、经历、技能及职业目标。""3. 你需要收集并整理求职者提供的所有相关材料,包括现有简历、项目案例、证书等。""4. 你需要深入分析目标职位的详细要求,明确招聘方的偏好和需求。",allow_delegation=False,llm=llm,verbose=True,)return ICNSdef resume_architect(self,llm):"""创建一个代理角色,负责高级简历架构师的工作。该函数初始化一个Agent对象,配置了该角色的相关属性,如角色名称、目标、背景故事等,以及是否允许委托和使用的LLM模型等设置。参数:llm: Large Language Model的缩写,推测是指用于辅助简历设计的语言模型。返回:返回初始化后的Agent对象,该对象代表了高级简历架构师的角色。"""resume_architect = Agent(role="高级简历架构师",goal="设计简历布局,确保内容结构清晰、吸引眼球,符合求职者身份及目标职位特点。",backstory="1. 作为一家猎头公司求职项目组的简历架构师,你所在的项目组正在协助求职者准备他的简历。""2. 你将负责根据信息收集与分析专员的报告,选择最适合求职者的简历模板和结构。""3. 你需要设计简历的整体布局,确保视觉上的吸引力和内容的逻辑性。""4. 你需要制定简历各部分内容的呈现框架,指导内容编辑人员如何组织信息。",allow_delegation=False,llm=llm,verbose=True,)return resume_architectdef content_editor(self,llm):"""创建一个Agent对象,扮演资深内容编辑师的角色,负责编写高质量的简历内容。参数:llm - 大语言模型的实例,用于协助编辑师生成和优化简历内容。返回:content_editor - 资深内容编辑师的Agent对象,具备特定的角色、目标、背景和行为设置。"""content_editor = Agent(role = "资深内容编辑师",goal = "编写高质量、针对性强的简历内容,凸显求职者优势,提升简历吸引力。",backstory = "1. 作为一家猎头公司求职项目组的内容编辑师,你所在的项目组正在协助求职者准备他的简历。""2. 你需要在简历架构师的指导下,负责不同部分的内容撰写和优化,如个人信息、职业目标、工作经验、项目经历、教育背景、技能清单等。""3. 你需要确保每部分内容精准、突出亮点,符合目标职位的要求。""4. 你需要对接信息收集与分析专员,确保信息的准确性和最新性。",allow_delegation=False,llm=llm,verbose=True,)return content_editordef qce(self,llm):"""创建一个质量控制专家代理该函数用于初始化并返回一个质量控制专家的角色代理。质量控制专家负责审核简历,确保其质量达到高标准,无错误,内容准确且具有专业性和吸引力。参数:llm (object): 语言模型接口,用于代理与语言模型之间的交互。返回:Agent: 质量控制专家的角色代理实例。"""quality_control_expert = Agent(role = "质量控制专家",goal = "严格把关简历质量,保证无错误,内容准确、专业,提升整体表现力。",backstory = "1. 作为一家猎头公司求职项目组的质量控制专家,你所在的项目组正在协助求职者准备他的简历。""2. 你需要进行简历的全面审核,包括语法、拼写、逻辑性、语言风格等方面的检查。""3. 你需要确保简历符合行业标准,且具有高度的专业性和吸引力。""4. 你需要协调内容编辑师进行必要的修订,直至达到高标准。",allow_delegation=True,llm=llm,verbose=True,)return quality_control_expertdef interviewCoach(self,llm):"""创建一个面试辅导顾问的Agent对象,旨在帮助求职者准备面试。该顾问将根据求职者的目标职位,提供个性化的面试准备策略,包括公司文化了解、职位要求解析和行业动态把握等方面。参数:llm: 一个语言模型的实例,用于生成有关面试准备的建议和解答求职者的问题。返回:一个配置了特定角色、目标、背景故事和行为模式的Agent对象,专注于面试辅导功能。"""interviewCoach = Agent(role = "面试辅导顾问",goal = "根据目标职位,帮助求职者深入了解公司文化、职位要求及行业动态,准备与职位相关的案例和问题解答。",backstory = "1. 作为一家猎头公司求职项目组的面试辅导顾问,你所在的项目组已经完成简历的制作,现在你需要协助求职者准备面试。""2. 你需要根据面试者的简历和目标职位,分析针对该职位的面试准备的要点。""3. 你需要尽可能全面的考虑求职者面试其目标职位时可能遇到的情况。""4. 你需要确保你做的工作能够帮助求职者有更大的机会通过面试。",allow_delegation=False,llm=llm,verbose=True,)return interviewCoach
Tasks.py
from crewai import Task
from crewai_tools import ScrapeWebsiteTool
from customtools.BaiduSearch import BaiduSearchTool
from customtools.ChineseFileRead import ChineseFileReadToolclass Tasks():def applicant_analysis(self,agent,file_path):FileReadTool=ChineseFileReadTool(file_path=file_path)scrapeWebsiteTool=ScrapeWebsiteTool()applicant_analysis = Task(name="求职者信息收集与分析",description="1. 通过求职者提供的材料,深入了解和分析其背景、经历、技能及职业目标等。""2. 如果在材料中发现有可以打开的url,可以尝试使用网页抓取工具获取更多信息进行分析。""2. 撰写求职者概况报告,要求汇总求职者关键信息。",expected_output = "一份详细且准确的Markdown格式的求职者概况报告,汇总求职者关键信息。",agent = agent,tools = [FileReadTool,scrapeWebsiteTool],output_file = "result/AiResumeGenerator/求职者概况报告.md",create_directory=True,async_execution=True,)return applicant_analysisdef targetjob_analysis(self,agent,file_path):FileReadTool=ChineseFileReadTool(file_path=file_path)scrapeWebsiteTool=ScrapeWebsiteTool()baiduSearchTool = BaiduSearchTool()targetjob_analysis = Task(name="求职者目标岗位信息收集与分析",description="1. 通过求职者提供的材料,深入了解其目标岗位相关信息,包括但不限于岗位职责、岗位要求、岗位所在行业、目标岗位所在公司概况等。""2. 若目标岗位所在公司信息不足,可以尝试使用网页搜索工具获取更多信息进行分析。""3. 如果在获得的所有信息中发现有可以打开的url,可以尝试使用网页抓取工具获取更多信息进行分析。""4. 根据获得的所有信息,撰写求职者目标岗位概况报告,要求汇总求职者目标岗位关键信息。",expected_output = "一份详细且准确的Markdown格式的求职者目标岗位概况报告,汇总求职者目标岗位关键信息。",agent = agent,tools = [FileReadTool,scrapeWebsiteTool,baiduSearchTool],output_file = "result/AiResumeGenerator/求职者目标岗位概况报告.md",create_directory=True,async_execution=True,)return targetjob_analysisdef application_analysis(self,agent,context):application_analysis = Task(name="求职者与目标职位综合分析",description="1. 通过求职者概况报告和求职者目标岗位概况报告联合分析,内容包括但不限于:求职者与目标职位的匹配度、求职者与目标职位的差异性、求职者与目标职位的共性以及求职者简历内容建议。",expected_output = "一份详细且准确的Markdown格式的求职者与目标职位综合报告。",agent = agent,output_file = "result/AiResumeGenerator/求职者与目标职位综合报告.md",create_directory=True,context = context,)return application_analysisdef resume_structure_design(self,agent,context):resume_structure_design = Task(name = "简历结构设计",description="1. 根据求职者的职业阶段和目标行业,选择合适的简历模板(如逆向时间顺序、功能性或混合式简历)。""2. 设计清晰、专业的排版,确保简历易于阅读,重点突出。考虑使用清晰的字体、合适的字号、恰当的标题和子标题。""3. 最后根据你完美的设计,撰写简历结构设计方案,包括但不限于简历模板、各部分内容概要及设计说明等。",expected_output = "一份Markdown格式的简历结构设计方案,包括但不限于简历模板、各部分内容概要及设计说明等。",agent = agent,output_file = "result/AiResumeGenerator/简历结构设计方案.md",create_directory=True,context = context)return resume_structure_designdef writing_resume(self,agent,context):content_creation_filling = Task(name = "求职者简历制作",description="1. 根据简历结构设计方案以及求职者概况报告,编写并填充简历的每个部分,确保内容精确、突出亮点。""2. 撰写简历,确保内容准确、完整、专业且整体符合简历结构设计方案要求。""3. 如果质量控制专家或者高级简历架构师对完成的简历不满意,根据他们的建议进行简历内容的修正和优化。",expected_output = "一份精心设计的Markdown格式的个人求职简历。",agent = agent,output_file = "result/AiResumeGenerator/简历.md",create_directory=True,context = context,)return content_creation_fillingdef content_review_optimization(self,agent,context):content_review_optimization = Task(name = "内容审查与优化",description="1. 对简历内容进行全面审查,包括语法、拼写、逻辑、表述清晰度及专业术语的正确使用。""2. 与资深内容编辑师和高级简历架构师沟通简历的优化与修正。""3. 撰写内容审查报告,记录所有修改建议、已更正的错误及优化点。",expected_output = "一份Markdown格式的简历内容审查报告,记录着所有修改建议及优化点。",agent = agent,output_file = "result/AiResumeGenerator/简历审查报告.md",create_directory=True,context = context)return content_review_optimizationdef resume_finalization(self,agent,context):resume_finalization = Task(name = "简历修订",description="1. 根据简历审查报告提供的建议修订简历,完成简历的优化。",expected_output = "一份Markdown格式的简历。",agent = agent,output_file = "result/AiResumeGenerator/简历终稿.md",create_directory=True,context = context)return resume_finalizationdef interview_prep(self, agent, context):interview_prep = Task(name = "面试准备指南制作",description="1. 根据求职者与目标职位综合报告和最终修订好的简历,制作面试准备指南。",expected_output = "一份精心制作且量身订制的Markdown格式的面试准备指南。",agent = agent,output_file = "result/AiResumeGenerator/用户面试准备指南.md",create_directory=True,context = context,async_execution=True,)return interview_prep
mian.py
from Agents import Agents
from Tasks import Tasks
from crewai import Crew,Process
from langchain_community.chat_models import ChatZhipuAI,ChatTongyi
import os
os.environ["DASHSCOPE_API_KEY"] = "******************"
os.environ["ZHIPUAI_API_KEY"] = "**********************"
os.environ['OPENAI_API_BASE'] = 'http://localhost:9997/v1'
os.environ['OPENAI_API_KEY'] = 'not empty'zhipullm = ChatZhipuAI(model="glm-4",temperature=0.6,max_tokens = 4096,
)TongyiQW = ChatTongyi(model="qwen-turbo",max_tokens = 4096,temperature=0.7
)llm = TongyiQWAgents = Agents()agent1 = Agents.manger(llm)
agent2 = Agents.icns(llm)
agent3 = Agents.resume_architect(llm)
agent4 = Agents.content_editor(llm)
agent5 = Agents.interviewCoach(llm)
agent6 = Agents.qce(llm)Tasks = Tasks()
#path_file 指向文件为用户的个人信息文件
task1 = Tasks.applicant_analysis(agent=agent2,file_path=r"D:\crewAI\myagentproject\resource\AiResumeGenerator\custominformation.md")
#这里path_file 指向文件为用户目标岗位的相关信息
task2 = Tasks.targetjob_analysis(agent=agent2,file_path=r"D:\crewAI\myagentproject\resource\AiResumeGenerator\targetjob.txt")
task3 = Tasks.application_analysis(agent=agent2,context=[task1,task2])
task4 = Tasks.resume_structure_design(agent=agent3,context=[task3])
task5 = Tasks.writing_resume(agent=agent4,context=[task4,task1])
task6 = Tasks.content_review_optimization(agent=agent6,context=[task5])
task7 = Tasks.resume_finalization(agent=agent4,context=[task6,task5])
task8 = Tasks.interview_prep(agent=agent5,context=[task3,task7])crew = Crew(agents=[agent2, agent3, agent4, agent5, agent6],tasks=[task1, task2, task3, task4, task5, task6, task7, task8],verbose=2, # You can set it to 1 or 2 to different logging levelsmemory=True,output_log_file = True,#function_calling_llm = zhipullm,embedder={"provider": "openai","config":{"model": 'custom-embedding-bge-large-zh-v1.5'}},share_crew = False,)crew.kickoff()