微信扫码
添加专属顾问
新的 AI 代理工具使得自动化数据分析变得异常简单。当与像 Streamlit 这样的可视化平台结合时,创建一个视觉上引人注目的商业报告应用程序变得轻而易举。
在本教程中,我们将重点分析客户反馈。这种分析和对客户情绪的良好理解对于确保产品满足期望并解决质量问题至关重要。被认为质量差的产品根本就无法销售。
然而,分析客户反馈可能涉及处理大量非结构化数据——这是一项令人畏惧的任务。这正是大型语言模型的优势所在,使得从这些数据中提取有意义的见解成为可能。
我们的第一步是明确目标。
假设我们有一份关于在线零售商产品的客户反馈消息列表。我们的目标是生成一份高管报告,突出表现优异的产品,识别表现不佳的产品存在的问题,并包含客户情绪的引人注目的可视化。
我们将使用 CrewAI 来协调一组 AI 代理,结构化数据,分析数据,创建一份洞察报告,最后构建一个 Streamlit 应用程序来展示结果。
它将看起来像下面的截图。
首先,我们需要准确地定义我们想要做的事情。
我有一份关于在线零售商产品的虚构客户反馈消息列表。这些消息采用 Markdown 格式。我想生成一份高管报告,突出表现良好的产品,识别表现不佳的产品存在的问题,并包括一些关于客户情绪的互动图表。而且我希望所有这些都能在一个互动网页应用程序中展示。
所以,让我们定义一下我们需要采取的步骤。
以下是步骤列表:
与我之前的文章 *AI for BI: Building a Business Information Report with CrewAI and OpenAI* 一样,我使用 CrewAI 和 OpenAI 来构建此软件。原因相同,并不是因为它们必然是这个问题的最佳技术解决方案,而是它们方便、易于使用,并且能够完成任务。
我使用 Jupyter Notebook 编写分析代码,因此您在下面看到的大部分代码可以直接按顺序写入笔记本单元格中。(要创建独立应用,只需将单元格连接起来。)
Streamlit 中的报告程序是独立的,由 AI 创建。您将在我的 GitHub 仓库中找到所有代码和数据。
由于我们将使用 OpenAI API,您需要一个 API 密钥,该密钥应作为环境变量可访问。如果尚未将其存储为环境变量,您可以先运行以下代码块以确保其可用。
## Omit this if your API key is already set as an environment variable
import os
os.environ["OPENAI_API_KEY"] = "your api key"OpenAI 将对使用其 LLM 收取费用。不过,运行以下代码不应超过几美分的费用(但请在 OpenAI 仪表板上关注您的使用情况)。我们使用的 CrewAI 软件是开源的,且不收费。
让我们开始编码吧。
我已经概述了我们将要经历的步骤。这些步骤可以分为三个阶段:将原始数据转换为CSV,编写报告并创建Streamlit应用。我们将为每个阶段定义代理和任务,并保存结果。因此,我们将最终得到三个文件:结构化数据的CSV文件、Markdown格式的报告和Streamlit应用。
保存中间文件有两个优点。第一个是,如果我们愿意,可以独立运行这三个阶段中的每一个。例如,如果我们想调整报告的结构,就不需要重新创建CSV文件,我们可以使用之前准备好的文件。如果Streamlit应用需要修改,也可以独立于其余代码进行处理。第二个优点是,生成的应用可以使用这些文件。
这就是我们将要进行的步骤,但在进入主要代码之前,需要进行一些设置。
我们需要从CrewAI导入一些内容并设置LLM模型。正如我之前所说,CrewAI默认使用OpenAI API,因此,只要我们拥有API密钥,所需做的就是在变量llm中设置我们想要使用的模型。我还将temperature设置为零。这减少了随机性,使响应更加一致。
我还设置了一个标志DEBUG。这个标志用于控制代理响应的详细程度。出于调试目的,获取完整的响应是一个好主意,以查看代理如何处理请求。将DEBUG设置为True即可。
from crewai import Agent, Task, Crew, LLM
llm = LLM(
model="gpt-4o-mini",
temperature=0.0
)
DEBUG = False代码的下一部分定义了一些文件名。第一个是原始客户数据文件。接下来的两个文件将存储Streamlit应用的中间数据,最后一个是应用本身。
## files
fb_raw = "./data/shoes.md"
fb_csv = "./data/fb.csv"
report_md = "./data/report.md"
st_app = "./data/report.py"现在我们导入CrewAI工具,以便读取和写入文件,并将其分配给变量。
from crewai_tools import FileReadTool, FileWriterTool
file_read_tool = FileReadTool()
file_writer_tool = FileWriterTool()所有的前导代码都完成了,我们可以开始主要程序。
CrewAI应用有三个基本组件:代理、任务和团队。代理是与LLM的接口;它有特定的目的,并可以提供功能(工具)来帮助它。任务详细说明了代理需要完成的事情。最后,团队执行一系列任务和代理,并返回结果。
我们将定义三个代理,分别对应上述阶段。一个用于创建和修改CSV文件,另一个用于以Markdown格式编写报告,第三个用于构建Streamlit应用。
每个代理都提供一个或多个任务,这些代理/任务组合将由一个团队进行管理。
第一个代理的任务是从客户反馈的原始Markdown文件构建数据结构,然后计算客户情感并将其添加到数据结构中。
代理的属性与任务之间没有严格的区分。任务有一个description,而代理有三个描述性属性role、goal和backstory。每个属性都为CrewAI生成有意义的提示做出贡献,但最终我们如何使用它们是由我们决定的。
我的方法是在代理定义中简明扼要,并为代理的任务留下详细的描述。
通过这种方法,我可以将同一个代理用于多个任务,正如我们将看到的那样。
这是我对CSV代理的定义。
csv_agent = Agent(
role="Extract, process data and record data",
goal="""Extract data and organise as instructed.
The result MUST be valid CSV.""",
backstory="""You are a data processing agent""",
tools=[file_read_tool],
llm=llm,
)这是第一个任务。
create_CSV = Task(
description="""
Analyse '{input_file}' the data provided - it is in
Markdown format.
Your output should be in CSV format. Respond without
using Markdown code fences.
The data is about the range of items in an online shop.
Following this is a set of messages from customers giving
feedback about the products that they have purchased.
Your task is to:
Create a structured file in CSV format that records a
list of all customer feedback messages.
Each item in the list should have its columns
populated as follows.
"Product": insert the name of the item,
"Overall_Rating": insert the rating as given by customer,
"Issue": insert any issues identified
- if no issue can be identified write 'None',
"Review": insert the customer message
""",
expected_output="A correctly formatted CSV data structure",
agent=csv_agent,
tools=[file_read_tool]
)
任务更加明确,并告诉代理确切的操作。结果应该是一个具有四列的CSV结构。
我们还希望有一列第五列,记录每条消息的情感。为了不使提示过于复杂,我将其分配给第二个任务。
add_sentiment = Task(
description="""
Analyse CSV data and calculate the sentiment of each
message in the 'Review' column. Add a new column to the
CSV that records that sentiment.
Your output should be in CSV format. Respond without
using Markdown code fences.
""",
expected_output="A correctly formatted CSV data file",
agent=csv_agent,
output_file=fb_csv,
tools=[file_read_tool]
)注意,在这个任务中有一个额外的属性output_file,它设置为CSV文件的文件名。这告诉任务自动将结果放入该文件中。
定义任务后,我们执行它们。
crew = Crew(
agents=[csv_agent, csv_agent],
tasks=[create_CSV, add_sentiment],
verbose=DEBUG,
)
result1 = crew.kickoff(inputs={'input_file': fb_raw})在这个Crew中,有一个代理和任务的列表,这些任务将按顺序执行,当Crew运行时,输入文件名作为参数设置。注意我们有两个任务使用同一个代理。
完成后,我们将得到一个结构类似于以下内容的CSV文件:
我们的下一个任务是写一份报告。
我们现在有一些格式良好的数据,这些数据经过客户情感评估的增强,并已保存到文件中以备后用。
我们的下一个任务是尝试使用一个新的代理对数据进行更深入的分析。
再次强调,代理的定义很简短,工作的细节在任务中。
## Define agent
report_generator = Agent(
role="Compile and present results",
goal="""Deliver a polished, structured report on customer
satisfaction.
""",
backstory="""You are an agent, that generates clear,
well-designed and professional reports""",
tools=[file_read_tool],
llm=llm,
)任务明确规定了报告的外观和内容。
create_report = Task(
description="""
Read the CSV data in '{csv_file}', create a summary report.
The report must consolidate and summarize the customer
feedback, it should be in Markdown file format
(without ``` fences).
The report should be structured as follows:
# Product review report
### Summary
Insert a Markdown table with a row for every product.
The table header should look like this:
| Product | Average Rating | Number of reviews | Positive | Neutral | Negative |
The should be a row for every product like this:
| insert the product name here
| insert the average of all the rating for this product
| insert total number of reviews
| insert number of positive reviews
| insert number of neutral reviews
| insert number of negative reviews |
### Insights
#### Best performers
insert a short report on the products with the best reviews
#### Underperformers
insert a short report on the products that are underperforming
#### Issues
insert a short report on what steps need to be taken to improve products and sales
""",
expected_output="""A Markdown report file""",
agent=report_generator,
output_file = report_md,
tools=[file_read_tool]
)
CrewAI 在生成报告方面表现良好,结果通过执行以下 crew 保存在 report_md 中。
crew = Crew(
agents=[report_generator],
tasks=[create_report],
verbose=DEBUG,
)
result2 = crew.kickoff(inputs={'input_file':fb_raw, 'csv_file': fb_csv})您可以在我的 GitHub 仓库中查看完整报告,但下面是应用程序报告部分的截图,以便您可以看到生成的内容。
接下来,我们想要生成应用程序。
我尽量使应用程序尽可能通用,以便能够处理关于不同产品的不同反馈消息集。
因此,您只需运行这部分代码一次。然后,您将拥有一个 Streamlit 应用程序,它将读取我们之前生成的 CSV 文件和 Markdown 报告,或者实际上是我们稍后创建的文件。
我将应用程序生成分为两个部分,使用两个任务,但使用相同的 Streamlit 生成代理。
这是代理的定义。
## 定义代理
app_generator = Agent(
role="创建或修改一个 Streamlit 程序",
goal="""交付一个有效的 Streamlit 程序,使用 Python 编写,
变量和函数名称要有意义。
确保输出严格符合 Python 语法。
不要包含 ``` 包围。
""",
backstory="""您是一个生成清晰、设计良好的
Streamlit 程序的代理""",
tools=[file_writer_tool, file_read_tool],
llm=llm,
)现在进行第一个任务。它设置了基本应用并将 CSV 数据加载为 Pandas 数据框。我不得不告诉它关于 Streamlit API 的一个(现在相当旧的)更新。早期版本使用了装饰器 st.cache,这个已经被弃用,我们应该使用 st.cache_data 来缓存 CSV 数据。我对此感到相当惊讶,因为新的装饰器已经存在一段时间了。然而,问题很容易解决,如您所见。
create_app = Task(
description="""
创建一个 Streamlit 应用,如下所示:
- 将显示设置为宽格式
- 包含 pandas 和 plotly express 库
- 从 csv 文件 {csv_file} 创建一个名为 "df" 的 pandas 数据框
包含所有字段
请注意,st.cache 已被弃用,请改用 st.cache_data。
不要将程序保存到文件中。
""",
expected_output="""一个有效且语法正确的 Python 程序""",
agent=app_generator,
tools=[file_read_tool]
)
现在我们有了一个基本程序。在下一个任务中,我给出了明确的指示,说明如何在此程序中添加以显示数据和构建图表。
add_content = Task(
description="""
修改 Streamlit 代码,如下所示:
- 创建两个标签,第一个命名为 "report_tab",第二个
命名为 "messages_tab"
- 在 "messages_tab" 中加载数据框 "df",在 st.table 中显示
- 在 report_tab 中创建两个相等宽度的列,分别称为
"report_column" 和 "chart_column"
- 在 "report_column" 列中从 {report_file} 读取报告,并在
st.markdown 中显示
- 在 "chart_column" 列中绘制 'Product' 与
'Overall_Rating' 的条形图
- 在 "chart_column" 列中绘制 'Sentiment' 的直方图,
条形按 'Product' 着色""",
expected_output="一个有效且语法正确的 Python 程序",
output_file = st_app,
agent=app_generator,
tools=[file_read_tool]
)
和之前一样,我们用一个代理运行两个任务。
crew = Crew(
agents=[app_generator, app_generator],
tasks=[create_app, add_content],
verbose=DEBUG,
)
result3 = crew.kickoff(inputs={'csv_file': fb_csv ,
'report_file': report_md})这是最后一个阶段。运行 Streamlit 应用,结果将是我们之前看到的截图。请注意,由于我组织文件夹的方式,您需要从父文件夹运行 Streamlit,如下所示:
streamlit run data/report.py
总体来说,我对结果相当满意。CrewAI是一个容易上手的框架,尽管它有一些小毛病。有很多描述性字符串在竞争产品中并不存在,虽然我相信这些对CrewAI的优秀团队来说是有意义的,但我并不完全相信它们都是必要的。
尽管如此,我确实喜欢我们可以将任务与代理分开的方式,给代理提供其能力的广泛描述,并提供任务中需要完成的详细信息。我最近查看的另一个框架(Swarm)不允许这样做。
我在CrewAI中遇到了一个问题,我可能通过这个功能解决了它。
当我运行其中一个小组时,我收到了以下错误:
Tool Output:
Error: the Action Input is not a valid key, value dictionary.
Error parsing LLM output, agent will retry: I did it wrong.
Invalid Format: I missed the 'Action:' after 'Thought:'.
I will do right next, and don't use a tool I have already used.这有点难以理解。
这似乎与任务的复杂性有关,因为当我将任务拆分时,问题消失了。
然而,我不确定我的复杂性诊断是否正确,因为我与其他开发者保持联系,他们找到了解决看似相同问题的不同方案(例如,降低温度——这对我没用)。在撰写本文时,这是CrewAI GitHub仓库上的一个实时问题。
我在定义 Streamlit 应用时非常明确。你可以说我明确得甚至可以自己编写这个应用。这是一个简单的程序,所以这确实有其价值。
但我想要制作一个从原始数据到最终产品的端到端程序。也许,我可以对程序的定义模糊一点。也许那样会导致一个更好的程序!但除了缓存装饰器的问题,AI 没有产生任何错误(而且它的输入速度比我快得多!)所以我并不抱怨。
最后一个问题是,为什么选择 Streamlit?虽然它是这种应用的一个非常好的框架,但真正的原因是,因为 ChatGPT-4o mini 具备使用它的编程知识!
让 ChatGPT 使用一个更新的或不太知名的框架,比如 Mesop 或 Taipy,可能会产生更差的结果。大型语言模型对这些产品的了解更少,更有可能犯错误和产生幻觉。
本文的代码和数据可以在这个 GitHub 仓库 的 AI4BI-fb 文件夹中找到。生成的图表和报告也在同一文件夹中。
https://github.com/alanjones2/CrewAIapps
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业
2026-07-05
AI 知识库的下一步,不是更会回答,而是能帮你把事办了
2026-07-05
企业AI知识库落地全复盘:从搭建到高效运营的实战方法论
2026-07-04
全员都在用AI,为什么组织效率纹丝不动?
2026-07-02
LLM Wiki 构建手册:一份可直接落地的标准流程
2026-07-02
认识LLM Wiki,一个新的知识库构建技术
2026-07-01
一次差点闯祸的分享,让我们把企业知识库重新想了一遍
2026-07-01
8000星!Karpathy力推的LLM Wiki理念,被这个项目完美落地了
2026-07-01
Karpathy又封神!掀翻RAG,把你的笔记变成第二大脑
2026-04-07
2026-04-28
2026-04-12
2026-04-07
2026-06-04
2026-04-07
2026-06-11
2026-04-20
2026-04-26
2026-04-08
2026-07-04
2026-06-30
2026-06-29
2026-06-29
2026-06-19
2026-06-04
2026-06-01
2026-05-27
欢迎您使用【53AI 官方网站】(以下简称“本网站”或“我们”)。本《会员服务协议》(以下简称“本协议”)是您(以下简称“会员”或“用户”)与【深圳市博思协创网络科技有限公司】之间关于注册、登录及使用本网站会员服务所订立的法律协议。
在您注册或登录前,请务必审慎阅读、充分理解各条款内容,特别是免除或限制责任的条款、知识产权条款、争议解决条款等。此类条款将以加粗形式提示您注意。 当您通过微信公众号授权、手机验证码验证或其他方式成功登录本网站时,即视为您已完全理解并同意接受本协议的全部内容。
一、 定义
本网站:指由【深圳市博思协创网络科技有限公司】运营的,域名为【53ai.com】的网站及相关移动端页面。
会员服务:指本网站向注册会员提供的知识库文章查阅、内容检索及其他相关增值服务。
知识库内容:指本网站发布的包括但不限于文字、图表、数据、研究报告、行业分析等数字化内容资源。
二、 账号注册与登录
登录方式:本网站支持以下登录方式,您可根据实际情况选择:
微信公众号授权登录:您同意将您的微信OpenID信息授权给本网站,用于创建或关联会员账号。
手机验证码登录:您需提供真实有效的手机号码,并通过短信验证码完成身份验证与登录/注册。
账号安全:您的账号仅限您本人使用,禁止赠与、借用、租用、转让或售卖。因您保管不善导致的账号被盗、密码泄露等损失,由您自行承担。
实名认证:根据相关法律法规要求,我们可能要求您在特定功能下完成实名认证。如您拒绝提供,可能无法使用部分或全部服务。
未成年人保护:若您未满18周岁,请在法定监护人的陪同下阅读本协议,并在征得监护人同意后使用本服务。
三、 服务内容与规范
知识库查阅权限:会员登录后,有权按照其会员等级对应的权限范围,在线浏览、检索本网站知识库中的相关文章及内容。
服务变更:我们有权根据业务发展需要,调整、变更或终止部分服务内容,并将以网站公告、公众号消息等方式提前通知。
禁止行为:您在使用服务时不得实施以下行为:
利用技术手段批量爬取、下载、转存知识库内容;
将知识库内容用于商业目的或未经授权地向第三方传播;
干扰本网站正常运行或侵犯其他用户合法权益;
发布违法违规信息或从事违反公序良俗的活动。
四、 知识产权声明
权利归属:本网站知识库中的排版设计、软件代码等内容的知识产权均归【公司全称】或原权利人所有,受《中华人民共和国著作权法》等法律保护。
有限许可:本网站授予会员一项非独占、不可转让、不可转授权的普通许可,仅限于个人学习、研究之目的在线查阅知识库内容。
侵权追责:未经书面许可,任何单位或个人不得以任何形式复制、转载、摘编、镜像、汇编或以其他方式使用上述内容。一经发现,我们保留追究其法律责任的权利。
五、 个人信息保护
我们重视对您个人信息的保护。关于我们如何收集、使用、存储和保护您的个人信息,请单独阅读 《隐私政策》。
您通过微信公众号授权或手机号验证所提供的信息,我们将严格按照《个人信息保护法》的规定处理,仅用于身份识别、服务提供及安全验证等必要用途。
您可以随时通过网站设置或联系客服行使查阅、更正、删除个人信息及撤回授权同意的权利。
六、 免责声明
内容准确性:知识库内容仅供参考,不构成专业建议。我们不对其完整性、准确性、时效性作任何明示或暗示的保证,您应自行判断并承担使用风险。
不可抗力:因自然灾害、政策法规变化、网络故障、第三方平台接口异常(如微信接口维护、运营商短信通道故障)等不可抗力导致的服务中断或延迟,我们不承担违约责任。
第三方链接:本网站可能包含指向第三方网站的链接,该等网站的内容和服务不受我们控制,请您自行甄别风险。
七、 违约责任
如您违反本协议约定,我们有权视情节采取警告、限制功能、暂停服务、注销账号等措施,并保留要求赔偿损失的权利。
如因您的违约行为导致我们遭受行政处罚、第三方索赔或商誉损失,您应承担全部赔偿责任(包括但不限于罚款、赔偿金、律师费、公证费等)。
八、 法律适用与争议解决
本协议的订立、执行和解释均适用中华人民共和国大陆地区法律。
因本协议产生的或与本协议有关的任何争议,双方应友好协商解决;协商不成的,任何一方均可向【公司所在地】有管辖权的人民法院提起诉讼。
九、 其他
本协议构成双方就本服务达成的完整协议,取代此前任何口头或书面约定。
本协议任一条款被认定为无效或不可执行的,不影响其他条款的效力。
我们对本协议享有最终解释权,并在法律允许的范围内保留随时修改的权利。修改后的协议一经公布即生效,继续使用服务即视为同意修订内容。