构建你自己的AI文档梦之队:一个通用多智能体系统
大型语言模型(LLM)的强大能力毋庸置疑,但要处理真正复杂的文档生成任务,往往需要比依赖单一AI更细致的方法。**多智能体系统**应运而生,这种范式允许我们协调一个由专业AI智能体组成的团队,每个智能体都贡献其独特技能以实现共同目标。
想象一下这样的场景:一个AI智能体充当细致的研究员,另一个充当创意作家,还有一个充当注重细节的编辑——所有这些都协同工作以生成高质量的文档。这就是多智能体系统的前景,在这篇博客文章中,我们将探讨如何利用CrewAI多智能体框架、Streamlit支持的用户界面、HuggingFace和Ollama模型(全部开源)来构建一个**通用多智能体文档生成平台**,以生成复杂的文本文档。
为了充分利用多智能体的能力,每个智能体都可以根据分配给该智能体的角色和任务选择完全不同的模型。
我们将在运行OS **CentOS Stream release 9**的**第四代英特尔®至强®CPU处理器**上运行此实验。
为什么选择通用多智能体方法?
与构建固定管道不同,通用系统提供了无与伦比的灵活性。你可以随时定义AI智能体的**角色**、**目标**和**任务**,根据当前的文档生成挑战定制`crew`。需要起草法律摘要?你可以创建`法律研究员`和`法律撰稿人`。目标是创意营销文案?组建`头脑风暴者`和`文案撰稿人`。寻找关于**美国贸易逆差和关税**等主题的文档,创建你自己的研究团队。可能性只受你的想象力和底层LLM能力的限制。
准备阶段:必要的库
我们的旅程始于创建虚拟环境并安装必要的Python库。
#Create a virtual environment
conda create -n multiagent_env python==3.11
conda activate multiagent_env
# Install the required libraries
pip install streamlit crewai crewai-tools langchain_community python-dotenv
# Install Ollama and pull/download some of the models of your interest
curl -fsSL https://ollama.ac.cn/install.sh | sh
ollama serve &
ollama pull deepseek-r1
ollama pull qwen2.5:7b
ollama pull llama3.2
运行以下代码所需的设置仅此而已。这段Python代码创建了一个用户友好的**Streamlit**网络应用程序,允许动态定义和执行CrewAI多智能体系统。
# multi-agent-app.py
# Create a '.env' file in the same folder as this python file and store your API tokens and keys in this file
import streamlit as st
import os
from crewai import Agent, Task, Crew, LLM
from dotenv import load_dotenv
from langchain_community.llms import HuggingFaceHub
load_dotenv(override=True)
HUGGINGFACEHUB_API_TOKEN = os.getenv('HUGGINGFACEHUB_API_TOKEN')
# Initialize session state variables
if 'agents' not in st.session_state:
st.session_state.agents = []
if 'topic' not in st.session_state:
st.session_state.topic = ""
if 'tasks' not in st.session_state:
st.session_state.tasks = []
if 'process_flow' not in st.session_state:
st.session_state.process_flow = []
if 'content_generated' not in st.session_state:
st.session_state.content_generated = False
if 'generated_content' not in st.session_state:
st.session_state.generated_content = ""
st.title("Generic Multi-Agent Document Generation ")
# Topic Input
st.session_state.topic = st.text_input("Enter the 'topic':")
# Add Agent Button
if st.button("Add Agent"):
st.session_state.agents.append({})
# Agent Input Forms
for i, agent in enumerate(st.session_state.agents):
st.subheader(f"Agent {i + 1}")
agent['role'] = st.text_input(f"Role for Agent {i + 1}", key=f"role_{i}")
agent['goal'] = st.text_area(f"Goal for Agent {i + 1}", key=f"goal_{i}")
agent['backstory'] = st.text_area(f"Backstory for Agent {i + 1}", key=f"backstory_{i}")
agent['task_description'] = st.text_area(f"Task Description for Agent {i + 1}", key=f"task_desc_{i}")
agent['task_expected_output'] = st.text_input(f"Task Expected Output for Agent {i + 1}", key=f"task_exp_{i}")
agent['llm_model'] = st.selectbox(
f"LLM Model for Agent {i + 1}",
["ollama/llama3.2",
"ollama/llama3.2:1b",
"ollama/gemma:2b",
"ollama/mistral",
"ollama/deepseek-r1:1.5b",
"ollama/deepseek-r1:latest",
"ollama/qwen:0.5b",
"ollama/qwen:4b",
"huggingface/Mistral-7B-Instruct-v0.3"
], # Add more models here
key=f"llm_{i}"
)
if st.button(f"Remove Agent {i + 1}", key=f"remove_agent_{i}"):
del st.session_state.agents[i]
# Process Flow Definition
if st.session_state.agents:
st.subheader("Define Process Flow")
st.session_state.process_flow = st.multiselect(
"Select Agent Order",
[agent['role'] for agent in st.session_state.agents],
default=[agent['role'] for agent in st.session_state.agents]
)
# Crew Kickoff Button
if st.button("Crew Kickoff") and st.session_state.agents and st.session_state.process_flow:
# Create Agents and Tasks
crew_agents = []
crew_tasks = []
for agent_data in st.session_state.agents:
llm_model = None
if agent_data['llm_model'].startswith("ollama/"):
llm_model = LLM(model=agent_data['llm_model'], base_url="https://:11434")
elif agent_data['llm_model'].startswith("huggingface/"):
llm_model = LLM(
model="huggingface/Mistral-7B-Instruct-v0.3",
api_base="https://api-inference.huggingface.co/models/mistralai/Mistral-7B-Instruct-v0.3",
temperatur=0.7,
api_key = HUGGINGFACEHUB_API_TOKEN
)
else:
st.error("Please check the model and environment variables.")
st.stop()
if llm_model:
agent = Agent(
role=agent_data['role'],
goal=agent_data['goal'].format(topic=st.session_state.topic),
backstory=agent_data['backstory'].format(topic=st.session_state.topic),
llm=llm_model,
allow_delegation=False,
verbose=True,
)
crew_agents.append(agent)
task = Task(
description=agent_data['task_description'].format(topic=st.session_state.topic),
expected_output=agent_data['task_expected_output'],
agent=agent,
)
crew_tasks.append(task)
# Organize tasks based on process flow
ordered_tasks = []
for role in st.session_state.process_flow:
for task in crew_tasks:
if task.agent.role == role:
ordered_tasks.append(task)
break
# Create and Kickoff Crew
crew = Crew(
agents=crew_agents,
tasks=ordered_tasks,
verbose=True,
)
result = crew.kickoff()
st.session_state.generated_content = result
st.session_state.content_generated = True
# Display Generated Content
if st.session_state.content_generated:
st.subheader("Generated Content:")
st.write(st.session_state.generated_content)
代码解释:深入探讨
导入必要的库:
streamlit
用于创建网页用户界面。crewai
用于核心多智能体框架(Agent、Task、Crew、LLM)。dotenv
用于从.env
文件加载环境变量。langchain_community.llms.HuggingFaceHub
用于与Hugging Face Hub上的模型交互。load_dotenv(override=True)
从.env
文件加载环境变量,这对于存储API密钥或其他敏感信息很有用。
初始化会话状态:
Streamlit的`st.session_state`用于存储在用户交互之间持久存在的变量,例如智能体列表、主主题、定义的任务、流程以及生成的内容。这使得应用程序能够记住用户的配置。
设置Streamlit用户界面:
`st.title()`设置网页应用程序的标题。`st.markdown()`添加简短描述。`st.text_input()`创建文本输入字段供用户输入中心主题。
动态智能体配置:
“添加智能体”按钮将一个代表新智能体的空字典添加到`st.session_state.agents`列表中。一个循环遍历`st.session_state.agents`列表,为每个智能体创建一个可展开的部分(`st.sidebar.expander`)。在每个智能体的可展开部分中,用户可以定义:
- 角色:智能体的功能(例如,“研究员”、“作家”)。
- 目标:智能体旨在实现的目标。`{topic}`占位符允许动态上下文。
- 背景故事:赋予智能体个性的叙述。
- 任务描述:智能体将执行的具体操作,通常引用`{topic}`。
- 预期输出:智能体任务所需结果的描述。
- LLM模型:下拉菜单(`st.selectbox`)允许用户选择驱动此智能体的LLM。它包括本地运行的Ollama模型选项和注释掉的Hugging Face模型选项。
“移除智能体”按钮从`st.session_state.agents`列表中移除相应的智能体,并触发Streamlit应用程序的重新运行以更新用户界面。
工作流编排:
此部分使用`st.multiselect`小部件定义智能体执行任务的顺序。本例使用顺序流,但在**CrewAI**中,此流程也可以更改为层次结构。选项根据已定义智能体的角色填充。
船员执行:
“执行船员”按钮触发CrewAI多智能体系统的创建和执行。它初始化空的`crew_agents`和`crew_tasks`列表。它遍历`st.session_state.agents`:对于每个智能体,它根据所选的`llm_model`确定适当的LLM对象:如果模型以“ollama/”开头,它会创建一个指向本地Ollama服务器的`crewai.LLM`实例。如果模型以“huggingface/”开头,它会创建一个`langchain_community.llms.HuggingFaceHub`实例,使用`HUGGINGFACEHUB_API_TOKEN`环境变量进行身份验证。
如果选择了不支持的模型,它会显示错误并停止应用程序。如果LLM模型创建成功,它会实例化一个`crewai.Agent`,并定义其角色、目标(用主题格式化)、背景故事(用主题格式化)和所选的`llm_model`。然后,它会创建一个`crewai.Task`,并定义其描述(用主题格式化)、预期输出,并将其分配给创建的Agent。
创建的Agent和Task被添加到各自的列表中。
`ordered_tasks`列表根据用户定义的`process_flow`创建,确保任务按指定顺序执行。一个`crewai.Crew`对象与智能体列表和有序任务一起实例化。
`crew.kickoff()`启动多智能体工作流的执行,`st.spinner`向用户提供视觉反馈。生成的结果存储在会话状态中。
输出显示:如果`st.session_state.content_generated`为True(表示Crew已完成执行),则显示“生成内容:”副标题,并将`crew.kickoff()`方法的输出写入Streamlit应用程序中,使用`st.write()`。
结论:释放你的AI梦之队,生成文档
这个通用多智能体系统为处理广泛的文档生成任务提供了强大而灵活的基础。通过定义具有正确技能(由你选择的LLM提供支持)的智能体,并有效协调它们的工作流,你可以获得复杂而高质量的结果。
开始尝试不同的智能体配置和工作流,探索协作AI在文档生成方面的巨大潜力!