| name | stage2-extraction |
| description | This SOP guides the real sample-based LLM extraction of patterns, FAQs, and response strategies from clustered customer support data. This is Stage 2 of the Userchat-to-SOP pipeline, combining Python sample extraction with AI agent natural language analysis. **Language:** Auto-detects Korean (ํ๊ตญ์ด) or Japanese (ๆฅๆฌ่ช) from user input. |
Stage 2: Pattern & FAQ Extraction
Overview
This SOP guides the real sample-based LLM extraction of patterns, FAQs, and response strategies from clustered customer support data. This is Stage 2 of the Userchat-to-SOP pipeline, combining Python sample extraction with AI agent natural language analysis.
Language: Detect the language from the user's first message and respond in that language throughout. Support Korean (ํ๊ตญ์ด) and Japanese (ๆฅๆฌ่ช). Default to Korean if language is unclear.
Stage Flow:
- Input: Stage 1 clustering results (Excel files + analysis report)
- Process:
- Load Stage 1 results and run enrichment (extract full conversation transcripts)
- LLM reads full conversation transcripts (NOT summaries) per cluster
- LLM extracts patterns, classifies HT vs TS
- LLM defines SOP topics and re-classifies clusters โ topics
- LLM generates FAQs, response strategies, keywords
- Output: Structured JSON files with patterns, FAQ pairs, SOP topic map, enriched conversations
Critical Philosophy:
- โ DO NOT analyze
enhanced_text (summaries) โ they lose customer expressions and agent responses
- โ
DO read full conversation transcripts (
turns from enriched data) for all analysis
- โ
DO extract verbatim customer expressions from actual conversations
- โ
DO preserve company tone from actual agent responses
- โ
DO re-classify clusters into SOP topics based on what you actually read
Parameters
Required
Optional
- min_total_samples (default: 300): Minimum total conversation samples across all clusters
- Dynamically adjusts
n_samples_per_cluster based on cluster count (K)
- Formula:
n_samples_per_cluster = max(20, ceil(min_total_samples / K))
- Examples: K=8 โ 38/cluster (304 total), K=10 โ 30/cluster (300 total), K=15 โ 20/cluster (300 total), K=25 โ 20/cluster (500 total)
- n_samples_per_cluster (default: dynamically calculated): Number of conversation samples to extract per cluster
- If explicitly set by user, overrides dynamic calculation
- If not set, calculated from
min_total_samples and K
- focus_clusters (default: "all"): Which clusters to analyze
"all": All clusters
"top_10": Top 10 by size
- List:
"0,2,5,7"
Steps
1. Load Stage 1 Results and Run Enrichment
Read clustering results, then immediately run enrichment to extract full conversation transcripts. All subsequent steps use these transcripts, not summaries.
Constraints:
- You MUST read Stage 1 files first:
{prefix}_tags.xlsx: Cluster summary (ID, label, category, keywords, count)
analysis_report.md: Analysis insights and recommendations
- (DO NOT read
{prefix}_clustered.xlsx for samples โ enrichment will provide better data)
- You MUST calculate
n_samples_per_cluster dynamically (unless user explicitly set it):
import math
K = len(tags)
min_total = 300
n_samples = max(20, math.ceil(min_total / K))
- You MUST create a bootstrap patterns.json from tags.xlsx, then run enrichment:
mkdir -p results/{company}/02_extraction
python3 -c "
import pandas as pd, json
tags = pd.read_excel('results/{company}/01_clustering/{prefix}_tags.xlsx')
data = {'metadata': {'company': '{company}', 'bootstrap': True}, 'clusters': []}
for _, r in tags.iterrows():
data['clusters'].append({'cluster_id': int(r['cluster_id']), 'label': r['label'], 'category': r['category'], 'cluster_size': int(r['cluster_size'])})
with open('results/{company}/02_extraction/patterns.json', 'w') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
"
python3 scripts/enrich_patterns.py \
--patterns results/{company}/02_extraction/patterns.json \
--messages results/{company}/01_clustering/{prefix}_messages.csv \
--output results/{company}/02_extraction/conversations_by_cluster.json \
--n-samples {n_samples}
- You MUST verify enrichment succeeded: each cluster has
{n_samples} conversation transcripts with full turns
- You MUST display the calculated n_samples_per_cluster and total sample count
Why enrichment first?
- All subsequent analysis (patterns, HT/TS, topic mapping, FAQ, strategies) benefits from reading actual agent-customer dialog, not summaries
- Summaries (
enhanced_text) lose: customer tone, agent response style, conversation flow, escalation moments, resolution steps
Fallback if enrichment fails:
- If
enrich_patterns.py fails or messages.csv is missing, fall back to extracting samples from clustered.xlsx using enhanced_text
- Mark analysis as
"data_source": "summary_fallback" in metadata
Expected Output:
โ
Enrichment ์๋ฃ
- ํด๋ฌ์คํฐ: 12๊ฐ (K=12)
- ํด๋ฌ์คํฐ๋น ๋ํ: 25๊ฑด (= max(20, ceil(300/12)))
- ์ด ๋ถ์ ๋ํ: 300๊ฑด
- ํ์ผ: conversations_by_cluster.json
2. Analyze Full Conversations per Cluster
For each cluster, read the full conversation transcripts and extract patterns, classify HT vs TS.
Constraints:
- You MUST read actual conversation
turns from enrichment output (NOT enhanced_text)
- You MUST process clusters sequentially in main agent (no subagents)
- You MUST identify 3-8 distinct patterns per cluster
- You MUST extract actual customer phrases verbatim from conversations
- You MUST categorize patterns by:
์ ๋ณด_์์ฒญ, ๋ฌธ์ _์ ๊ณ , ํ๋ก์ธ์ค_๋ฌธ์, ๋ถ๋ง_์ ๊ธฐ
- You MUST classify each cluster as HT or TS based on conversation content
- You MUST note if a cluster contains mixed topics (e.g., both hardware AS and Windows issues)
- You SHOULD measure frequency by counting pattern occurrences across
{n_samples} conversations
Per-Cluster Analysis Process:
For each cluster, read {n_samples} conversations and extract:
-
Patterns (3-8 per cluster):
- Pattern name, type, common phrases (verbatim from conversations), intent, frequency
-
HT vs TS Classification:
- HT (How-To): ์ฃผ์ ๋ชฉ์ ์ด ์ ๋ณด ์ ๊ณต/์๋ด
- TS (Troubleshooting): ์ฃผ์ ๋ชฉ์ ์ด ๋ฌธ์ ํด๊ฒฐ
- If mixed: note which conversations belong to which type
-
Mislabel Detection:
- Compare cluster label with actual conversation content
- Flag if >30% of conversations don't match the label
- Record
actual_content description
-
Company Tone (from agent messages in conversations):
- Greeting style, emoji usage, brand messaging
- Response structure (numbered steps, bullet points)
- Closing style
Reading Conversations (important):
For Cluster X, read each conversation's turns:
Turn 1 (customer): "๋ธ๋ฃจ์คํฌ๋ฆฐ์ด ๊ณ์ ๋ ์. ์ด์ ๋ถํฐ ๊ฐ์๊ธฐ..."
Turn 2 (agent): "์๋
ํ์ธ์, ๊ณ ๊ฐ๋! ... ๋จผ์ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฅ์ฐฉ์ ์๋ํด์ฃผ์ธ์"
Turn 3 (customer): "์ฌ์ฅ์ฐฉ ํ๋๋ฐ ์์ง๋ ๊ฐ์์"
Turn 4 (agent): "๊ทธ๋ ๋ค๋ฉด ํ๋ฐฐ AS ์ ์๋ฅผ ๋์๋๋ฆฌ๊ฒ ์ต๋๋ค..."
โ Pattern: ๋ธ๋ฃจ์คํฌ๋ฆฐ โ ์๊ฐ์กฐ์น โ AS ์ ์ (TS, ๋ฌธ์ ํด๊ฒฐ ํ๋ก์ธ์ค)
โ Agent tone: emoji ์ฌ์ฉ, ๊ณต๊ฐ ํํ ๋จผ์ , ๋จ๊ณ๋ณ ์๋ด
โ Real phrase: "๋ธ๋ฃจ์คํฌ๋ฆฐ์ด ๊ณ์ ๋ ์" (not "๋ธ๋ฃจ์คํฌ๋ฆฐ ๋ฌธ์ ๋ฐ์")
Output per cluster:
{
"cluster_id": 0,
"original_label": "์ค๋ฅ ํด๊ฒฐ ๋ฌธ์",
"actual_content": "A/S ์ ์ + ํ๋์จ์ด ๋ถ๋ + ์๋์ฐ ์ค์น (ํผํฉ)",
"is_mixed": true,
"mixed_topics": ["ํ๋์จ์ด_AS", "์๋์ฐ_์ํํธ์จ์ด", "์ผ์ด๋ธ_์ฐ๊ฒฐ"],
"sop_type": "TS",
"patterns": [...],
"tone_observations": {...}
}
3. Define SOP Topics and Map Clusters (Re-classification)
After analyzing ALL clusters, define the actual SOP topic list independent of cluster boundaries. This is the authoritative plan that Stage 3 must follow.
Constraints:
- You MUST execute this step AFTER completing Step 2 for ALL clusters
- You MUST define SOP topics based on what you actually read in conversations, not cluster labels
- You MUST handle these cases:
- Mixed cluster (1 cluster โ 2+ topics): Split. Record which conversations belong to which topic
- Duplicate clusters (2+ clusters โ 1 topic): Merge
- Mislabeled cluster: Use actual content, ignore label
- Noise cluster (mostly greetings/empty): Absorb into "์ด๊ธฐ ์๋" or exclude
- You MUST produce a
sop_topic_map โ Stage 3 MUST follow this map
- You SHOULD aim for 8-15 SOP topics
- You SHOULD organize by customer journey (๊ตฌ๋งค ์ โ ๊ตฌ๋งค/๊ฒฐ์ โ ์๋ น/์ค์น โ ์ฌ์ฉ ์ค โ AS โ ๊ธฐํ)
Process:
- Review all cluster analyses from Step 2
- List all actual topics observed across all conversations (ignore cluster boundaries)
- For mixed clusters: assign each of the 20 conversations to a topic
- Map clusters (or portions) โ topics
- Assign HT or TS to each topic
- Validate: every cluster mapped, total records โ input total
Output Structure (sop_topic_map in patterns.json):
{
"sop_topic_map": {
"description": "Authoritative SOP topic list. Stage 3 MUST follow this map.",
"topics": [
{
"topic_id": "TS_HARDWARE_AS",
"title": "A/S ์ ์ ๋ฐ ํ๋์จ์ด ๋ถ๋ ์ฒ๋ฆฌ",
"type": "TS",
"journey_stage": "์ฌ์ฉ ์ค",
"source_clusters": [
{"cluster_id": 0, "portion": "partial", "conversation_ids": [1,3,5,6,8,10,12,14,15,17,19], "reason": "ํ๋์จ์ด ๋ถ๋/AS ์ ์ ๊ด๋ จ ๋ํ๋ง"},
{"cluster_id": 6, "portion": "full", "reason": "์ ์ฒด๊ฐ AS ๋ฌธ์"}
],
"estimated_records": 500,
"key_patterns": ["๋ธ๋ฃจ์คํฌ๋ฆฐ", "์ฟจ๋ฌ_์์", "ํ๋ฐฐ_AS_์ ์"]
},
{
"topic_id": "TS_WINDOWS_SW",
"title": "์๋์ฐ/์ํํธ์จ์ด ๋ฌธ์ ํด๊ฒฐ",
"type": "TS",
"journey_stage": "์ค์น",
"source_clusters": [
{"cluster_id": 0, "portion": "partial", "conversation_ids": [2,4,7,9,11,13,16,18,20], "reason": "์๋์ฐ ์ค์น/๋๋ผ์ด๋ฒ ๊ด๋ จ ๋ํ๋ง"}
],
"estimated_records": 300,
"key_patterns": ["์๋์ฐ_์ค์น", "์ ํ_์ธ์ฆ", "๋๋ผ์ด๋ฒ_๋ฌธ์ "]
}
],
"merge_log": [
"Clusters 2+5+6 merged โ HT_INITIAL_INTAKE (๋ชจ๋ ์ด๊ธฐ ์ธ์ฌ ๋ฉ์์ง)"
],
"label_corrections": [
{"cluster_id": 7, "original_label": "ํ๊ธ์์์ฆ ๋ฌธ์", "actual_content": "80% ์ทจ์/ํ๋ถ + 20% ์๋ฅ ๋ฐํ", "action": "split into TS_CANCEL + HT_DOCUMENTS"}
]
}
}
Validation Checklist:
4. Generate FAQ Pairs
Create question-answer pairs based on actual conversations read in Step 2.
Constraints:
- You MUST generate 3-5 FAQ pairs per SOP topic (from Step 3 topic map)
- You MUST write questions using actual customer language from conversations (verbatim!)
- You MUST write answers following the company's actual agent tone from conversations
- You MUST ensure answers include specific steps, timeframes, contact info observed in conversations
- You MUST NOT create generic FAQ pairs
Critical Requirement:
- โ "AS ์ ์๋ ์ด๋ป๊ฒ ํ๋์?" (generic)
- โ
"๋ธ๋ฃจ์คํฌ๋ฆฐ์ด ๊ณ์ ๋ ์. ์ด์ ๋ถํฐ ๊ฐ์๊ธฐ..." (from actual conversation)
- โ
Answer includes actual agent response pattern observed: "๋จผ์ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฅ์ฐฉ์ ์๋ํด์ฃผ์ธ์ โ ์ ๋๋ฉด ํ๋ฐฐ AS ์ ์"
5. Identify Response Strategies
Define response strategies and escalation rules per SOP topic.
Constraints:
- You MUST define strategy per SOP topic (not per cluster)
- You MUST extract escalation triggers from actual conversations (when did agents escalate?)
- You MUST identify automation opportunities
- You SHOULD document standard response patterns observed in conversations
6. Build Keyword Taxonomy
Create keyword taxonomy from all analyzed conversations.
Constraints:
- You MUST extract keywords from actual conversations (not summaries)
- You MUST group hierarchically (category โ subcategory โ keywords)
- You SHOULD include synonyms and common typos observed
7. Save All Results
Save extraction results and run final enrichment.
Constraints:
Note: If enrichment was already run in Step 1 for analysis, this second run updates the file with the final patterns structure. The conversations are re-selected based on the finalized cluster assignments.
Examples
Example 1: Standard Extraction (Assacom)
Parameters:
- clustering_output_dir:
results/assacom
- company: "Assacom"
- min_total_samples: 300 (default)
- K=12 โ n_samples_per_cluster = max(20, ceil(300/12)) = 25
Execution:
- Load tags + analysis report, calculate n_samples = 25
- Run enrichment โ get 25 full conversations per cluster (total: 300)
- Read conversations sequentially per cluster:
- Cluster 0 (799๊ฑด): Read 25 conversations โ discover it's mixed (AS + ์๋์ฐ + ์ผ์ด๋ธ)
- Cluster 1 (592๊ฑด): Read 25 conversations โ clean ๊ฒฌ์ /์ฌ์ topic
- ...
- Define topic map: 12 clusters โ 8 SOP topics (split Cluster 0, merge Clusters 2+5+6)
- Generate FAQs per SOP topic using actual customer expressions
- Save all files + run final enrichment
Time: ~8-12 minutes
Output: 8 SOP topics, 47 patterns, 42 FAQ pairs, enriched conversations
Example 2: Mixed Cluster Handling
Scenario: Cluster 0 has 799 records with hardware AS, Windows issues, and cable questions mixed together.
What happens in Step 2:
- Read 20 conversations
- Conv 1: customer reports blue screen โ agent suggests memory reinstall โ AS pickup โ ํ๋์จ์ด_AS
- Conv 2: customer asks about Windows install USB โ agent provides guide link โ ์๋์ฐ_์ํํธ์จ์ด
- Conv 3: customer can't connect dual monitor โ agent explains D-SUB vs HDMI โ ๊ทธ๋ํฝ์นด๋_๋ชจ๋ํฐ
- ...
What happens in Step 3:
- Cluster 0 split into 3 topics with conversation_ids assigned
- Each topic gets its own SOP in Stage 3
Troubleshooting
Issue 1: Enrichment fails (messages.csv missing)
Solution:
- Fall back to reading
enhanced_text from clustered.xlsx
- Mark
"data_source": "summary_fallback" in metadata
- Quality will be lower but pipeline continues
Issue 2: Patterns are too generic
Root Cause: LLM summarized instead of quoting verbatim
Solution: Re-read specific conversations and copy-paste exact customer phrases
Issue 3: Too many SOP topics (>15)
Solution: Merge related topics. If "SSD ์ธ์ ๋ฌธ์ " and "HDD ์ฐ๊ฒฐ ๋ฌธ์ " are separate, combine into "์ ์ฅ์ฅ์น ๋ฌธ์ "
Notes
Why Full Conversations Instead of Summaries?
| Aspect | Summary (enhanced_text) | Full Conversation (turns) |
|---|
| Customer tone | Lost | "๋ธ๋ฃจ์คํฌ๋ฆฐ์ด ๊ณ์ ๋ ์ ใ
ใ
" |
| Agent response pattern | Lost | "๋จผ์ ~ํด์ฃผ์ธ์ โ ์ ๋๋ฉด ~" |
| Escalation moment | Lost | "3๋ฒ ์๋ ํ AS ์ ์ ์ ํ" |
| Resolution steps | Lost | Step-by-step troubleshooting flow |
| Conversation length | Lost | Short (3 turns) vs Complex (15+ turns) |
| Mixed topic detection | Hard (summary blends topics) | Clear (each turn has context) |
Execution Strategy
- โ ๏ธ ์๋ธ์์ด์ ํธ ์ฌ์ฉ ๊ธ์ง โ hanging ๋ฐ์
- โ
๋ฉ์ธ ์์ด์ ํธ ์์ฐจ ์ฒ๋ฆฌ โ ํด๋ฌ์คํฐ ํ๋์ฉ ๋ํ ์ฝ๊ณ ๋ถ์
- โ
์ปจํ
์คํธ ๊ด๋ฆฌ โ ํด๋ฌ์คํฐ ํ๋ ๋ถ์ ์๋ฃ ํ ๊ฒฐ๊ณผ ์ ์ฅ, ๋ค์ ํด๋ฌ์คํฐ ์งํ
- {n_samples}๊ฑด ๋ํ ร ํ๊ท 10ํด = ~{n_samples*10} ๋ฉ์์ง/ํด๋ฌ์คํฐ โ ์ปจํ
์คํธ์ ์ถฉ๋ถํ ๋ค์ด๊ฐ (K=8์ผ ๋ 38๊ฑด๋ ~380 ๋ฉ์์ง๋ก 1M ์ปจํ
์คํธ ๋ด ์ถฉ๋ถ)
Time Estimates
With min_total_samples=300, n_samples_per_cluster = max(20, ceil(300/K)):
| K (Clusters) | Samples/Cluster | Total Samples | Estimated Time |
|---|
| 8 | 38 | 304 | ~12-18 min |
| 10 | 30 | 300 | ~12-16 min |
| 12 | 25 | 300 | ~12-16 min |
| 15 | 20 | 300 | ~12-16 min |
| 20 | 20 | 400 | ~15-20 min |
| 25 | 20 | 500 | ~18-25 min |
Relationship with Stage 3
- Stage 3์ Customer Journey Mapping์ ์ด ๋จ๊ณ์
sop_topic_map์ ๋ฐ๋ผ์ผ ํจ
- Stage 3์ ํ ํฝ ๋งต์ ์ฌ์ ์ํ์ง ์๊ณ , ์ฃผ์ด์ง ํ ํฝ๋ณ๋ก SOP๋ฅผ ์์ฑ๋ง ํจ
patterns_enriched.json์ ๋ํ ์ํ์ด Stage 3์ ์ฃผ์ ์
๋ ฅ