大模型揭秘:如何从用户评论中提炼金矿

原创 精选
人工智能
本文探讨了如何利用大型语言模型和LangChain库来分析和抽取用户评论中的关键信息。文章首先描述了运营团队面临的挑战,即如何从大量的用户评论中获取有价值的数据。

作者 | 崔皓

审校 | 重楼

摘要

本文探讨了如何利用大型语言模型和LangChain库来分析和抽取用户评论中的关键信息。文章首先描述了运营团队面临的挑战,即如何从大量的用户评论中获取有价值的数据。然后,介绍了使用LangChain的extraction chain和tagging chain来解决这一问题的具体步骤和代码实现。最后,文章还探讨了如何通过雷达图可视化用户反馈,以更直观地了解用户对产品或服务的感受。

开篇

你有没有遇到过这样的场景?公司的运营团队需要通过用户评论来了解一个新产品在市场上的接受程度,以便更好地制定未来的运营策略。爬用户评论虽然容易但是抽取和分析数据是个难题。

在大型语言模型之前,数据分析依赖于基础统计、手工标签和简单机器学习模型。这些方法不仅耗时耗力,还需要专业工具和复杂的规则维护。因此,分析大规模或非结构化数据往往效果有限。处理用户评论这样非结构化的数据,为大型语言模型的应用提供了广阔的舞台。

需求背景

在当前的商业环境下,用户评论已经成为了衡量产品或服务质量的重要指标。运营团队经常需要依赖这些信息来调整产品特性或优化营销策略。但是,如何从大量的用户评论中提取有用信息,然后将这些信息转化为可行的战略,仍然是一个挑战。

我们一些用户评论的例子分析一下,我们从网络爬取了一些用户的评论信息,从信息上可以看出用户针对手机产品的一些特性进行了评论,包括摄像头,屏幕,性能等。在评论内容中还带有一些用户的个人感情,例如:客服给力,非常满意等等。

风之子: 我刚入手华为的新款手机,电池续航让我大吃一惊,真是不错!摄像头表现一般,但屏幕颜色非常出色。手感很好,流畅度也很高。外观方面,我觉得挺时尚的。总的来说,我非常满意这台手机,性价比非常高,用起来也很可靠。快递也很快,我一定会推荐给朋友。
月光仙子: 这款华为手机手感超好,操作非常流畅,客服也很给力。产品质量优秀,物流速度也快,外观非常吸引我,非常满意。
独孤求败: 摄像头是这款华为手机的一大亮点,但电池续航有点短。外观设计一般,品牌信誉也还行。产品质量不错,但可靠性一般,性价比也就一般。
剑圣: 用了一段时间这款华为,外观很赞,操作也流畅。品牌也是我信赖的。不过屏幕有点让人失望,功能还算齐全。总体来说,性价比还是不错的。
小白龙: 个人不太喜欢这款华为手机的外观,但性价比很高,操作流畅度也不错。摄像头性能强大,但屏幕显示效果一般。个性化需求满足度一般,不确定是否推荐给朋友。
雷霆之怒: 这款华为手机是个好东西,电池续航很长,摄像头表现也相当专业。用户体验上,我觉得是非常好的,流畅度高,一定会推荐给别人。
夜行者: 这款华为手机的屏幕是亮点,但电池上稍微不如意。物流速度一般,外观也挺好看的,总体满意度一般。
魔法少女: 我觉得这款华为手机在功能完整性上做得非常好,而且手感很不错。客服态度也好,就是物流速度一般。品牌信誉很高。
暗夜精灵: 实际使用下来,这款华为手机流畅度很好,而且非常可靠。快递速度也非常快,品牌也是值得信赖的。
星河战士: 这款华为手机性价比高,电池和屏幕都不错。满足了我所有的个性化需求,外观设计也很有特点,我一定会推荐给其他人。

最直接的想法就是从这些评论中把关于商品的部分抽取出来,看看大家对我们的产品认可程度如何。

抽取产品信息

既然目标是了解用户对产品的看法,就先从产品下手。关于信息抽取, LangChain集成了OpenAI的extraction 功能,并且将其封装成了一个Chain如下。

langchain.chains.openai_functions.extraction.create_extraction_chain(schema: dict, llm: BaseLanguageModel, prompt: Optional[BasePromptTemplate] = None, verbose: bool = False) → Chain
Parameters
schema – The schema of the entities to extract.
llm – The language model to use.
prompt – The prompt to use for extraction.
verbose – Whether to run in verbose mode. In verbose mode, some intermediate logs will be printed to the console. Defaults to langchain.verbose value.
Returns
Chain that can be used to extract information from a passage.

这里对这个类稍微做一下解释。

通过create_extraction_chain创建一个chain,用来信息的抽取,输入的参数如下:

  • Schema这是一个字典,描述了需要从文本中提取哪些实体。
  • Llm语言模型实例。
  • Prompt提示模板,用于生成模型输入。
  • Verbose是否在控制台打印中间日志。

返回值是一个 Chain 对象,该对象可以用于从文本中提取信息。

在参数中schema很重要,我们需要定义抽取信息的属性值。

程序设计

有了基本思路,查找了功能实现以后,我们可以根据这个功能设计一下应用程序。如下图所示,用户请求的时候会将用户评论的信息给到应用程序。应用程序利用LangChain中extraction chain 调用大模型抽取用户评论中关于商品信息的描述,在抽取过程中它会依赖schema文件,这个文件会定义哪些商品属性需要进行抽取。

由于LangChain中extraction chain的功能支持openai的模型,因此我们选择GPT-3.5的版本。接着就是如何定义Schema的问题了。 schema中定义的是商品属性信息,如果运营小妹来提这个需求一定是越多越好,不过通过对用户评论的分析,和运营小妹一顿周旋之后,我们把schema的属性定义如下:

schema = {
"properties": {
"用户名": {"type": "string"},
"电池": {"type": "string"},
"摄像头": {"type": "string"},
"屏幕": {"type": "string"},
"手感": {"type": "string"},
"流畅度": {"type": "string"},
"外观": {"type": "string"},
"品牌": {"type": "string"}
 },
"required": ["用户名"]
}

主要在电池,摄像头,屏幕,手感,流畅度,外观和品牌上。

商品信息抽取:代码实现

有了业务需求加设计思路,就可以撸代码了。为了方便给大家展示,这里的用户评论信息我们放到了inp变量中保存,一般而言应该是从网络爬取之后保存到本地文件或者是数据库中。然后,再读取使用,我们这里简化了过程,将关注点放到如何使用大模型和LangChain上面。

from langchain.chat_models import ChatOpenAI
from langchain.llms.baidu_qianfan_endpoint import QianfanLLMEndpoint
from langchain.chains import create_extraction_chain

# Schema
schema = {
    "properties": {
        "用户名": {"type": "string"},
        "电池": {"type": "string"},
        "摄像头": {"type": "string"},
        "屏幕": {"type": "string"},
        "手感": {"type": "string"},
        "流畅度": {"type": "string"},
        "外观": {"type": "string"},
        "品牌": {"type": "string"}
    },
    "required": ["用户名"]
}

# Input
inp = """
风之子: 我刚入手华为的新款手机,电池续航让我大吃一惊,真是不错!摄像头表现一般,但屏幕颜色非常出色。手感很好,流畅度也很高。外观方面,我觉得挺时尚的。总的来说,我非常满意这台手机,性价比非常高,用起来也很可靠。快递也很快,我一定会推荐给朋友。
月光仙子: 这款华为手机手感超好,操作非常流畅,客服也很给力。产品质量优秀,物流速度也快,外观非常吸引我,非常满意。
独孤求败: 摄像头是这款华为手机的一大亮点,但电池续航有点短。外观设计一般,品牌信誉也还行。产品质量不错,但可靠性一般,性价比也就一般。
剑圣: 用了一段时间这款华为,外观很赞,操作也流畅。品牌也是我信赖的。不过屏幕有点让人失望,功能还算齐全。总体来说,性价比还是不错的。
小白龙: 个人不太喜欢这款华为手机的外观,但性价比很高,操作流畅度也不错。摄像头性能强大,但屏幕显示效果一般。个性化需求满足度一般,不确定是否推荐给朋友。
雷霆之怒: 这款华为手机是个好东西,电池续航很长,摄像头表现也相当专业。用户体验上,我觉得是非常好的,流畅度高,一定会推荐给别人。
夜行者: 这款华为手机的屏幕是亮点,但电池上稍微不如意。物流速度一般,外观也挺好看的,总体满意度一般。
魔法少女: 我觉得这款华为手机在功能完整性上做得非常好,而且手感很不错。客服态度也好,就是物流速度一般。品牌信誉很高。
暗夜精灵: 实际使用下来,这款华为手机流畅度很好,而且非常可靠。快递速度也非常快,品牌也是值得信赖的。
星河战士: 这款华为手机性价比高,电池和屏幕都不错。满足了我所有的个性化需求,外观设计也很有特点,我一定会推荐给其他人。
"""


# Initialize the ChatOpenAI model
llm = ChatOpenAI(temperature=0, model="gpt-3.5-turbo")

# Create the extraction chain
chain = create_extraction_chain(schema, llm)

# Run the chain
results = chain.run(inp)

# 'results' 变量将包含抽取的信息。

代码不复杂,这里简单解释一下:

1. 定义提取模式(Schema): 使用一个名为 `schema` 的字典来定义我们希望从用户评论中提取哪些信息。这里包括用户名、电池、摄像头等多个维度。

2. 初始化自然语言模型: 创建一个名为 `llm` 的 `ChatOpenAI` 对象,这是 GPT-3.5-turbo 模型的一个封装。这个对象将负责后续的文本生成和理解。

3. 创建信息提取链: 使用 `create_extraction_chain` 函数,结合之前定义的 `schema` 和初始化的模型 `llm`,生成一个信息提取链,存储为 `chain` 变量。

4. 运行信息提取: 最后,使用 `chain.run(inp)` 方法运行这个信息提取链,它将分析输入的用户评论(存储在 `inp` 变量中)并将结果保存在 `results` 变量中。

Results的输出结果如下:

[{'用户名': '风之子', '电池': '续航', '摄像头': '表现', '屏幕': '颜色', '手感': '好', '流畅度': '高', '外观': '时尚', '品牌': '华为'}, 
{'用户名': '月光仙子', '手感': '好', '流畅度': '流畅', '外观': '吸引', '品牌': '华为'}, {'用户名': '独孤求败', '摄像头': '亮点', '电池': '续航', '外观': '设计', '品牌': '华为'}, {'用户名': '剑圣', '外观': '赞', '操作': '流畅', '品牌': '华为'}, 
{'用户名': '小白龙', '外观': '不喜欢', '性价比': '高', '操作': '流畅', '摄像头': '强大', '屏幕': '显示效果', '个性化需求': '满足'}, 
{'用户名': '雷霆之怒', '电池': '续航', '摄像头': '专业', '用户体验': '好', '流畅度': '高'}, 
{'用户名': '夜行者', '屏幕': '亮点', '电池': '不如意', '物流速度': '一般', '外观': '好看'}, 
{'用户名': '魔法少女', '功能完整性': '好', '手感': '不错', '客服态度': '好', '物流速度': '一般', '品牌信誉': '高'}, 
{'用户名': '暗夜精灵', '流畅度': '好', '可靠性': '可靠', '快递速度': '快', '品牌': '值得信赖'}, 
{'用户名': '星河战士', '性价比': '高', '电池': '不错', '屏幕': '不错', '个性化需求': '满足', '外观设计': '特点'}]

看!简单四步搞定数据分析,运营小妹看了直拍手,不过仔细看看,用户的情感似乎没有在输出中体现出来。

需求变更

能够获取商品的信息固然是不错,但是如果能够将用户的情感信息也一并抽取出来就完美了,既然运营小妹有需求,程序员就有办法。

实际上用户的情感,是对产品和服务而言的,综合“借鉴”了其他系统的用户服务满意表,得出如下维度是我们需要关注的:满意度,商品质量,性价比,用户体验,客户服务,推荐意愿,功能完整性,交付速度,可靠性,可行话需求满足度。一般对这些服务都会进行评分,什么 非常满意,“满意”,“一般”等等,分了很多级别。这种功能好像extraction chain 就不能实现了,不要紧程序员有办法,通过对langchainapi的翻找,找到了tagging chain这个类。

langchain.chains.openai_functions.tagging.create_tagging_chain(schema: dict, llm: BaseLanguageModel, prompt: Optional[ChatPromptTemplate] = None, **kwargs: Any) → Chain[source]
Creates a chain that extracts information from a passage
based on a schema.
Parameters
schema – The schema of the entities to extract.
llm – The language model to use.
Returns
Chain (LLMChain) that can be used to extract information from a passage.

代码还是老套路,我们依旧需要定义shcema,告诉大模型我们要抽取的数据类型。

程序再设计

有了需求思路,也能够通过技术实现,接着我们把设计稍微调整一下。如下图所示,和extraction chain组件一样,我们加入了tagging chain组件,他们之间是平行关系,都需要接受用户传入的用户评论信息,同时利用schema定义的属性,调用大模型完成信息的抽取。

情感信息抽取:代码实现

程序设计比较简,程序员小哥离胜利更进一步了。快点开始撸代码吧,今天下班还有约会!

from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.chains import create_tagging_chain, create_tagging_chain_pydantic

# 定义schema,用于描述我们想要标记的属性
schema = {
    "properties": {
        "满意度": {
            "type": "string",
            "enum": ["非常满意", "满意", "一般", "不满意", "非常不满意"],
            "description": "描述对产品或服务的整体满意度"
        },
        "产品质量": {
            "type": "string",
            "enum": ["优秀", "良好", "一般", "差劲"],
            "description": "描述产品的质量"
        },
        "性价比": {
            "type": "string",
            "enum": ["非常高", "高", "一般", "低"],
            "description": "描述产品的性价比"
        },
        "用户体验": {
            "type": "string",
            "enum": ["非常好", "好", "一般", "差"],
            "description": "描述用户体验"
        },
        "客户服务": {
            "type": "string",
            "enum": ["非常满意", "满意", "一般", "不满意"],
            "description": "描述客户服务"
        },
        "推荐意愿": {
            "type": "string",
            "enum": ["一定会", "可能会", "不确定", "不会"],
            "description": "描述推荐意愿"
        },
        "功能完整性": {
            "type": "string",
            "enum": ["非常好", "好", "一般", "差"],
            "description": "描述功能完整性"
        },
        "交付速度": {
            "type": "string",
            "enum": ["非常快", "快", "一般", "慢"],
            "description": "描述交付速度"
        },
        "可靠性": {
            "type": "string",
            "enum": ["非常可靠", "可靠", "一般", "不可靠"],
            "description": "描述可靠性"
        },
        "个性化需求满足度": {
            "type": "string",
            "enum": ["非常满意", "满意", "一般", "不满意"],
            "description": "描述个性化需求满足度"
        }
    },
    "required": ["满意度", "产品质量", "性价比"]  # 示例中一些必须要有的属性
}

# 初始化LLM模型
llm = ChatOpenAI(temperature=0, model="gpt-3.5-turbo")

# 创建标记链
chain = create_tagging_chain(schema, llm)

# 分割输入文本以获取单个用户的评论
user_comments = inp.strip().split("\n")

# 创建一个空字典用于保存每个用户的标记结果
tagged_results = {}

# 遍历每个用户的评论
for comment in user_comments:
    user, user_comment = comment.split(": ", 1)
    # 执行标记操作
    result = chain.run(user_comment)
    # 将标记结果保存到字典中
    tagged_results[user] = result

# 遍历tagged_results字典
for user, feedback in tagged_results.items():
    # 格式化反馈内容为一个字符串
    feedback_str = ", ".join(f"{key}: {value}" for key, value in feedback.items())
    # 打印用户名和反馈
    print(f"用户名:{user},反馈:{feedback_str}")

代码依旧是熟悉的配方,显然小哥已经轻车熟路了。

1.导入依赖库导入了 `ChatOpenAI`、`ChatPromptTemplate`、`create_tagging_chain` 和 `create_tagging_chain_pydantic` 等所需库和函数。

2.定义标记模式(Schema)使用 `schema` 变量定义了需要从用户评论中标记的信息,这里包括了满意度、产品质量、性价比等多个维度。

3.初始化自然语言模型创建了一个名为 `llm` 的 `ChatOpenAI` 对象,用于后续的文本生成和理解任务。

4.创建标记链使用 `create_tagging_chain` 函数和之前定义的 `schema` 及初始化的 `llm` 对象,生成了一个信息标记链,存储为 `chain` 变量。

5.获取用户评论从 `inp` 变量中提取单个用户的评论,并存储在 `user_comments` 列表中。

6.初始化结果存储创建了一个名为 `tagged_results` 的空字典,用于保存每个用户的标记结果。

7.循环标记用户评论遍历每个用户的评论,使用 `chain.run()` 方法运行标记链,然后将标记结果保存到 `tagged_results` 字典中。

8.输出标记结果最后,遍历 `tagged_results` 字典,将每个用户的标记结果格式化为字符串并输出。

输出内容如下

用户名:风之子,反馈:满意度: 非常满意, 性价比: 非常高, 可靠性: 很可靠, 交付速度: 很快, 推荐意愿: 一定会
用户名:月光仙子,反馈:满意度: 非常满意, 产品质量: 优秀, 客户服务: 满意, 交付速度: 快
用户名:独孤求败,反馈:产品质量: 一般, 可靠性: 一般, 性价比: 一般
用户名:剑圣,反馈:满意度: 一般, 产品质量: 一般, 性价比: 不错, 功能完整性: 好
用户名:小白龙,反馈:性价比: 高, 个性化需求满足度: 一般, 推荐意愿: 不确定
用户名:雷霆之怒,反馈:用户体验: 非常好, 推荐意愿: 一定会
用户名:夜行者,反馈:满意度: 一般, 产品质量: 一般, 性价比: 一般
用户名:魔法少女,反馈:功能完整性: 非常好, 客户服务: 好, 交付速度: 一般, 可靠性: 一般
用户名:暗夜精灵,反馈:可靠性: 非常可靠, 交付速度: 非常快
用户名:星河战士,反馈:性价比: 高, 个性化需求满足度: 非常满意, 推荐意愿: 一定会

从内容上虽然可以看到每个用户对产品和服务的态度,但是运营小妹提出了要求,需要进行一些统计帮助运营进行用户的区分。例如:非常满意的用户占比是多少,感觉产品质量优秀的用户占比等等。

这难不倒小哥,继续加代码:

# 初始化计数器
count_very_satisfied = 0
count_excellent_quality = 0

# 计算总用户数
total_users = len(tagged_results)

# 遍历tagged_results字典
for user, feedback in tagged_results.items():
    # 检查满意度是否为“非常满意”
    if feedback.get("满意度") == "非常满意":
        count_very_satisfied += 1
    # 检查产品质量是否为“优秀”
    if feedback.get("产品质量") == "优秀":
        count_excellent_quality += 1

# 计算百分比
percent_very_satisfied = (count_very_satisfied / total_users) * 100
percent_excellent_quality = (count_excellent_quality / total_users) * 100

# 打印百分比
print(f"非常满意的用户百分比: {percent_very_satisfied}%")
print(f"产品质量优秀的用户百分比: {percent_excellent_quality}%")

输出如下:

非常满意的用户百分比: 20.0%
产品质量优秀的用户百分比: 10.0%

看看需求轻松搞定,看来可以按时下班了。

生成评论数据的雷达图

运营小妹见程序员小哥这么快完成了功能,觉得没有难度于是提出,是否能够将用户的反馈数据通过雷达图的方式展示。程序员小哥,突然“由喜转悲”心中一万个草泥马在奔腾,不过精心一想,雷达图不同的顶点代表不同的情感维度,每个用户的反馈按照等级给一个分数,然后将分数平均以后得到的值就可以代表某个维度的最终显示值了。这么一想瞬间通透了,代码呼之欲出:

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.font_manager import FontProperties

# 转换为 DataFrame
df = pd.DataFrame.from_dict(tagged_results, orient='index')

# 定义枚举到数值的映射
mapping = {
    "非常满意": 5, "满意": 4, "一般": 3, "不满意": 2, "非常不满意": 1,
    "优秀": 4, "良好": 3, "一般": 2, "差劲": 1,
    "非常高": 4, "高": 3, "一般": 2, "低": 1,
    "非常好": 4, "好": 3, "一般": 2, "差": 1,
    "非常满意": 4, "满意": 3, "一般": 2, "不满意": 1,
    "一定会": 4, "可能会": 3, "不确定": 2, "不会": 1,
    "非常快": 4, "快": 3, "一般": 2, "慢": 1,
    "非常可靠": 4, "可靠": 3, "一般": 2, "不可靠": 1
}

# 将标签转换为数值
for column in df.columns:
    df[column] = df[column].map(mapping)

# 计算每个属性(列)的平均得分
averages = df.mean()

# 准备绘制雷达图
attributes = list(df.columns)
num_vars = len(attributes)

# 计算角度
angles = np.linspace(0, 2 * np.pi, num_vars, endpoint=False).tolist()
angles += angles[:1]  # 使雷达图封闭

# 平均得分
averages = averages.tolist() + averages.tolist()[:1]

# 设置字体
font = FontProperties(fname='SimHei.ttf')

# 绘制雷达图
plt.figure(figsize=(8, 8))
ax = plt.subplot(polar=True)

# 画线
ax.fill(angles, averages, color='blue', alpha=0.25)
ax.set_xticks(angles[:-1])
ax.set_xticklabels(attributes, fontproperties=font)

# 添加标题
plt.title('标记结果的雷达图', size=20, color='blue', y=1.1, fontproperties=font)

plt.show()

虽然代码简单,但是小哥担心大家不懂,还是“画蛇添足”地给出了解释。

1.导入依赖库导入了 Pandas、Matplotlib 和 NumPy 等库,以及一些字体设置的工具。

2.从字典到 DataFrame使用 `pd.DataFrame.from_dict()` 将 `tagged_results` 字典转化为 Pandas DataFrame,这样更便于后续的数据处理。

3.定义标签到数值的映射创建了一个名为 `mapping` 的字典,用于将用户反馈的标签(如 "非常满意"、"满意" 等)映射到数值。

4.标签转换为数值遍历 DataFrame 的每一列,使用 `map()` 函数将所有的标签转换为对应的数值。

5.计算平均得分对 DataFrame 的每一列(即每一个属性)计算平均得分,并保存在 `averages` 变量中。

6.雷达图准备设置雷达图的各个顶点标签(即 `attributes`),并计算每个顶点对应的角度。

7.角度和平均得分计算每个属性对应的角度,并确保雷达图是一个封闭的形状。同时,对 `averages` 列表进行操作以确保雷达图的封闭。

8.设置字体使用 `FontProperties` 来设置字体,确保中文能够正确显示。

9.绘制雷达图使用 Matplotlib 的 `subplot` 和其他函数来绘制雷达图。设置了图的大小、颜色、透明度等。

10.设置标题和标签最后,添加了标题并设置了各个轴的标签。

雷达图展示结果:

总结

运用大型语言模型和LangChain库,我们不仅可以高效地从用户评论中抽取产品相关信息,还可以获取到用户的情感反馈。这一整套方案大大简化了传统的数据分析过程,减少了人工标签和复杂规则维护的需要。通过进一步的数据可视化,运营团队可以更容易地理解用户需求和感受,从而更精准地调整产品特性和营销策略。这不仅提高了数据分析的准确性,也极大地提升了工作效率。

作者介绍

崔皓,51CTO社区编辑,资深架构师,拥有18年的软件开发和架构经验,10年分布式架构经验。



责任编辑:华轩 来源: 51CTO
相关推荐

2023-11-17 23:02:38

模型学习

2021-10-09 07:55:49

设计师业务用户需求

2021-05-13 23:54:12

DockerDockerfile镜像

2024-05-22 07:57:34

2024-02-01 08:34:30

大模型推理框架NVIDIA

2023-11-29 11:30:17

PDF语言模型

2016-01-26 11:08:54

2023-03-16 08:00:00

机器学习深度学习人工智能

2024-12-02 09:37:09

大模型AI产品

2024-04-15 13:51:03

模型LLMLLMs

2014-07-16 17:35:03

Android表单模型

2017-07-05 16:43:52

VSAN加密虚拟化

2016-02-29 16:54:10

OpenStack混合云应用软件定义基础设施

2023-11-15 13:04:30

Python提取表格

2011-03-22 10:16:01

苹果

2017-07-06 08:21:27

VSAN加密虚拟机

2009-05-28 10:12:04

2017-08-24 09:19:20

分解技术揭秘
点赞
收藏

51CTO技术栈公众号