作為一名開發者倡導者,跟上用戶論壇的訊息並了解用戶所說的整體情況是非常具有挑戰性的。有很多有價值的內容,但你怎麼能快速找到關鍵的對話呢?在這篇教程中,我將向你展示一個使用人工智慧(AI)的小技巧,通過提示大型語言模型(LLMs)來進行語義聚類!
簡而言之 🔄 這篇文章是關於如何從(數據科學 + 代碼)轉變為(AI 提示 + LLMs),以獲得相同的結果——只是更快且更省力!🤖⚡。文章的結構如下:
靈感與數據來源
首先,我要感謝2024年12月的論文《Clio(Claude 的見解和觀察)》,這是一個保護隱私的平台,利用 AI 助手分析並顯示數百萬次對話中的聚合使用模式。閱讀這篇論文讓我受到啟發,想要嘗試這個方法。
數據。我只使用了公開的 Discord 訊息,特別是“論壇主題”,用戶在那裡尋求技術幫助。此外,我還對這篇博客的內容進行了聚合和匿名化。每個主題中,我將數據格式化為對話回合格式,並將用戶角色標識為“用戶”(提問者)或“助手”(回答用戶問題的人)。我還添加了一個簡單的二元情感分數(0表示“不開心”,1表示“開心”),根據用戶在主題中是否有說“謝謝”。對於向量數據庫供應商,我使用了 Zilliz/Milvus、Chroma 和 Qdrant。
第一步是將數據轉換為 pandas 數據框。以下是摘錄。你可以看到對於 thread_id=2,一位用戶只問了一個問題。但對於 thread_id=3,一位用戶在同一主題中問了四個不同的問題(另外兩個問題在時間戳較遠的地方,未顯示在下方)。
我添加了一個簡單的情感分數計算函數。
def calc_score(df):
# 定義目標詞
target_words = ["thanks", "thank you", "thx", "🙂", "😉", "👍"]
# 幫助函數檢查是否有目標詞在合併的訊息內容中
def contains_target_words(messages):
concatenated_content = " ".join(messages).lower()
return any(word in concatenated_content for word in target_words)
# 按 'thread_id' 分組並計算每組的分數
thread_scores = (
df[df['role_name'] == 'user']
.groupby('thread_id')['message_content']
.apply(lambda messages: int(contains_target_words(messages)))
)
# 將計算的分數映射回原始數據框
df['score'] = df['thread_id'].map(thread_scores)
return df
…
if __name__ == "__main__":
# 從 YAML 文件加載參數
config_path = "config.yaml"
params = load_params(config_path)
input_data_folder = params['input_data_folder']
processed_data_dir = params['processed_data_dir']
threads_data_file = os.path.join(processed_data_dir, "thread_summary.csv")
# 從 Discord 論壇 JSON 文件讀取數據到 pandas 數據框。
clean_data_df = process_json_files(
input_data_folder,
processed_data_dir)
# 根據訊息內容中的特定詞計算分數
clean_data_df = calc_score(clean_data_df)
# 生成報告和圖表
plot_all_metrics(processed_data_dir)
# 合併主題訊息並保存為 CSV 以進行提示。
thread_summary_df, avg_message_len, avg_message_len_user = \
concat_thread_messages_df(clean_data_df, threads_data_file)
assert thread_summary_df.shape[0] == clean_data_df.thread_id.nunique()
使用儀表板探索數據
從上面的處理數據中,我建立了傳統的儀表板:
- 訊息量:像 Qdrant 和 Milvus 這樣的供應商出現一次性高峰(可能是由於市場活動)。
- 用戶參與度:用戶的條形圖和回應時間與用戶回合數的散點圖顯示,通常更多的用戶回合意味著更高的滿意度。但滿意度似乎與回應時間無關。散點圖中的深色點似乎與 y 軸(回應時間)隨機分佈。也許用戶不在生產環境中,他們的問題不太緊急?存在異常值,例如 Qdrant 和 Chroma,可能是由機器人驅動的異常。
- 滿意度趨勢:約 70% 的用戶似乎對任何互動感到開心。數據說明:確保檢查每個供應商的表情符號,有時用戶使用表情符號而非文字來回應!例如 Qdrant 和 Chroma。

使用 LLM 提示生成 KNN 聚類
在提示中,下一步是按 thread_id 聚合數據。對於 LLMs,你需要將文本合併在一起。我將用戶訊息與整個主題訊息分開,以查看哪一個能產生更好的聚類。最後,我只使用了用戶訊息。

有了 CSV 文件進行提示,你就可以開始使用 LLM 進行數據科學了!
!pip install -q google.generativeai
import os
import google.generativeai as genai
# 從本地系統獲取 API 密鑰
api_key=os.environ.get("GOOGLE_API_KEY")
# 配置 API 密鑰
genai.configure(api_key=api_key)
# 列出所有模型名稱
for m in genai.list_models():
if 'generateContent' in m.supported_generation_methods:
print(m.name)
# 嘗試不同的模型和提示
GEMINI_MODEL_FOR_SUMMARIES = "gemini-2.0-pro-exp-02-05"
model = genai.GenerativeModel(GEMINI_MODEL_FOR_SUMMARIES)
# 結合提示和 CSV 數據。
full_input = prompt + "\n\nCSV Data:\n" + csv_data
# 對 Gemini LLM 進行推理調用
response = model.generate_content(full_input)
# 將 response.text 保存為 .json 文件...
# 檢查令牌計數並與模型限制進行比較:200 萬令牌
print(response.usage_metadata)

不幸的是,Gemini API 總是截斷 response.text。我在直接使用 AI Studio 時運氣更好。

我給 Gemini Flash 和 Pro(溫度設置為 0)的五個提示如下。
提示#1:獲取主題摘要:
給定這個 .csv 文件,對每一行添加 3 列:– thread_summary = 205 個字符或更少的摘要,來自行的 ‘message_content’ 列– user_thread_summary = 126 個字符或更少的摘要,來自行的 ‘message_content_user’ 列– thread_topic = 3–5 個字的超高級類別確保摘要捕捉主要內容而不失去太多細節。確保用戶主題摘要直截了當,捕捉主要內容而不失去太多細節,跳過引言文本。如果較短的摘要已經足夠好,則更喜歡較短的摘要。確保主題足夠一般,以便所有數據的高級主題少於 20 個。更喜歡較少的主題。輸出 JSON 列:thread_id、thread_summary、user_thread_summary、thread_topic。
提示#2:獲取聚類統計:
給定這個消息的 CSV 文件,使用列=’user_thread_summary’ 對所有行進行語義聚類。使用技術 = Silhouette,鏈接方法 = ward,距離度量 = Cosine Similarity。現在只給我 Silhouette 分析方法的統計數據。
提示#3:執行初步聚類:
給定這個消息的 CSV 文件,使用列=’user_thread_summary’ 對所有行進行語義聚類,分成 N=6 個聚類,使用 Silhouette 方法。使用列=”thread_topic” 總結每個聚類主題為 1–3 個字。輸出 JSON,包含列:thread_id、level0_cluster_id、level0_cluster_topic。
Silhouette 分數衡量一個物體與其自身聚類(內聚性)與其他聚類(分離性)的相似程度。分數範圍從 -1 到 1。較高的平均 Silhouette 分數通常表示聚類定義良好且分離良好。欲了解更多詳情,請查看 scikit-learn Silhouette 分數的文檔。
將其應用於 Chroma 數據。以下,我展示了提示#2 的結果,作為 Silhouette 分數的圖表。我選擇 N=6 個聚類作為高分和較少聚類之間的折衷。如今,大多數 LLM 用於數據分析時,輸入為 CSV,輸出為 JSON。

從上面的圖表中,你可以看到我們終於開始深入了解用戶所說的內容!
提示#4:獲取層次聚類統計:
給定這個消息的 CSV 文件,使用列=’thread_summary_user’ 對所有行進行語義聚類,進行層次聚類(Agglomerative)並設置 2 層。使用 Silhouette 分數。下一層的最佳 Level0 和 Level1 聚類數量是多少?每個 Level1 聚類有多少個主題?現在只給我統計數據,我們稍後會進行實際聚類。
提示#5:執行層次聚類:
接受這個 2 層的聚類。添加聚類主題以總結文本列“thread_topic”。聚類主題應該盡可能簡短,而不失去聚類意義的太多細節。– Level0 聚類主題約 1–3 個字。– Level1 聚類主題約 2–5 個字。輸出 JSON,包含列:thread_id、level0_cluster_id、level0_cluster_topic、level1_cluster_id、level1_cluster_topic。
我還提示生成 Streamlit 代碼來可視化聚類(因為我不是 JS 專家 😄)。對於相同的 Chroma 數據,結果如下。

我發現這非常有見地。對於 Chroma,聚類顯示用戶對查詢、距離和性能等主題感到滿意,但對數據、客戶和部署等領域感到不滿。
實驗自定義嵌入
我重複了上述聚類提示,使用 CSV 中的數值嵌入(“user_embedding”),而不是原始文本摘要(“user_text”)。我在之前的博客中詳細解釋了嵌入,以及在排行榜上過擬合模型的風險。OpenAI 提供的嵌入非常可靠,API 調用的價格也非常實惠。以下是創建嵌入的示例代碼片段。
from openai import OpenAI
EMBEDDING_MODEL = "text-embedding-3-small"
EMBEDDING_DIM = 512 # 512 或 1536 的可能值
# 使用 API 密鑰初始化客戶端
openai_client = OpenAI(
api_key=os.environ.get("OPENAI_API_KEY"),
)
# 創建嵌入的函數
def get_embedding(text, embedding_model=EMBEDDING_MODEL,
embedding_dim=EMBEDDING_DIM):
response = openai_client.embeddings.create(
input=text,
model=embedding_model,
dimensions=embedding_dim
)
return response.data[0].embedding
# 在 pandas 數據框的每一行中調用的函數
def generate_row_embeddings(row):
return
'user_embedding': get_embedding(row['user_thread_summary']),
# 使用 pandas apply 生成嵌入
embeddings_data = df.apply(generate_row_embeddings, axis=1)
# 將嵌入添加回數據框作為單獨的列
df['user_embedding'] = embeddings_data.apply(lambda x: x['user_embedding'])
display(df.head())
# 保存為 CSV ...

有趣的是,Perplexity Pro 和 Gemini 2.0 Pro 有時會產生錯誤的聚類主題(例如,將有關慢查詢的問題錯誤分類為“個人事務”)。
結論:在使用提示進行自然語言處理(NLP)時,讓 LLM 自行生成嵌入——外部生成的嵌入似乎會使模型困惑。

跨多個 Discord 伺服器進行聚類
最後,我擴大了分析範圍,納入來自三個不同向量數據庫供應商的 Discord 訊息。結果的可視化突出了共同問題——例如 Milvus 和 Chroma 都面臨身份驗證問題。

總結
以下是我用於執行語義聚類的步驟摘要:
- 提取 Discord 主題。
- 將數據格式化為對話回合,並標識角色(“用戶”、“助手”)。
- 計算情感分數並保存為 CSV。
- 提示 Google Gemini 2.0 Flash 獲取主題摘要。
- 提示 Perplexity Pro 或 Gemini 2.0 Pro 基於主題摘要進行聚類,使用相同的 CSV。
- 提示 Perplexity Pro 或 Gemini 2.0 Pro 編寫 Streamlit 代碼以可視化聚類(因為我不是 JS 專家 😆)。
通過遵循這些步驟,你可以快速將原始論壇數據轉換為可行的見解——以前需要幾天的編碼,現在只需一個下午就能完成!
參考資料
- Clio: Privacy-Preserving Insights into Real-World AI Use, https://arxiv.org/abs/2412.13678
- Anthropic blog about Clio, https://www.anthropic.com/research/clio
- Milvus Discord Server, last accessed Feb 7, 2025
- Chroma Discord Server, last accessed Feb 7, 2025
- Qdrant Discord Server, last accessed Feb 7, 2025
- Gemini models, https://ai.google.dev/gemini-api/docs/models/gemini
- Blog about Gemini 2.0 models, https://blog.google/technology/google-deepmind/gemini-model-updates-february-2025/
- Scikit-learn Silhouette Score
- OpenAI Matryoshka embeddings
- Streamlit
本文由 AI 台灣 運用 AI 技術編撰,內容僅供參考,請自行核實相關資訊。
歡迎加入我們的 AI TAIWAN 台灣人工智慧中心 FB 社團,
隨時掌握最新 AI 動態與實用資訊!