大模型揭秘:如何從用戶評論中提鍊金礦

2023-11-21     51CTO

原標題:大模型揭秘:如何從用戶評論中提鍊金礦

作者 | 崔皓

本文探討了如何利用大型語言模型和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年分布式架構經驗。

文章來源: https://twgreatdaily.com/zh-cn/01d5a55b5fdc2f0e75799812e43d4c57.html