File size: 6,592 Bytes
526927a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# Lily LLM RAG ์‹œ์Šคํ…œ ๊ฐœ๋ฐœ ํžˆ์Šคํ† ๋ฆฌ

## ๐Ÿ“‹ ํ”„๋กœ์ ํŠธ ๊ฐœ์š”
- **๋ชฉํ‘œ**: PDF ๋ฌธ์„œ์˜ ์ˆ˜ํ•™ ๋ฌธ์ œ ํ•ด์„ ๋ฐ ํ•ด๊ฒฐ์„ ์œ„ํ•œ RAG ์‹œ์Šคํ…œ ๊ตฌ์ถ•
- **ํ™˜๊ฒฝ**: CPU ๊ธฐ๋ฐ˜ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ (GPU ์„œ๋ฒ„ ๋ฐฐํฌ ์ „ ํ…Œ์ŠคํŠธ)
- **์ ‘๊ทผ ๋ฐฉ์‹**: ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ RAG โ†’ ์ž‘์€ ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ๋กœ ๋น ๋ฅธ ๊ฒ€์ฆ

## ๐Ÿ”„ ์ฃผ์š” ์ž‘์—… ํ๋ฆ„

### 1๋‹จ๊ณ„: ๊ธฐ์กด ๋ฌธ์ œ ๋ถ„์„
- **๋ฌธ์ œ**: Kanana ๋ชจ๋ธ์˜ ๋ฉ€ํ‹ฐ๋ชจ๋‹ฌ ์ฒ˜๋ฆฌ์—์„œ ํ† ํฐ ID ์‘๋‹ต ๋ฌธ์ œ
- **์›์ธ**: CPU ํ™˜๊ฒฝ์—์„œ Kanana ๋ชจ๋ธ์˜ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ํ•œ๊ณ„
- **๊ฒฐ์ •**: ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ RAG๋กœ ์ „ํ™˜ํ•˜์—ฌ ์•ˆ์ •์„ฑ ํ™•๋ณด

### 2๋‹จ๊ณ„: ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ RAG ์‹œ์Šคํ…œ ๊ตฌ์ถ•

#### 2.1 PDF ํ…์ŠคํŠธ ์ถ”์ถœ ๊ฐœ์„ 
**ํŒŒ์ผ**: `lily_llm_core/document_processor.py`
```python
# ๋ณ€๊ฒฝ ์ „: ์ด๋ฏธ์ง€ ๊ธฐ๋ฐ˜ OCR ์ฒ˜๋ฆฌ
def process_document(self, file_path: str) -> List[Document]:
    if self.get_file_type(file_path) == 'pdf':
        return self._process_pdf_as_images(file_path)  # ์ด๋ฏธ์ง€ ๋ณ€ํ™˜

# ๋ณ€๊ฒฝ ํ›„: ํ…์ŠคํŠธ ์ง์ ‘ ์ถ”์ถœ
def process_document(self, file_path: str) -> List[Document]:
    # ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ ์ฒ˜๋ฆฌ (๋ชจ๋“  ํŒŒ์ผ ํ˜•์‹)
    documents = self.load_document(file_path)
    split_docs = self.split_documents(documents)
    return split_docs
```

#### 2.2 RAG ํ”„๋กœ์„ธ์„œ ๋‹จ์ˆœํ™”
**ํŒŒ์ผ**: `lily_llm_core/rag_processor.py`
```python
# ๋ฉ€ํ‹ฐ๋ชจ๋‹ฌ ์ฒ˜๋ฆฌ ์ œ๊ฑฐ, ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜์œผ๋กœ ๋‹จ์ˆœํ™”
def generate_rag_response(self, user_id: str, document_id: str, query: str, 
                        llm_model=None, image_files: List[str] = None) -> Dict[str, Any]:
    # 1. ์œ ์‚ฌํ•œ ๋ฌธ์„œ ๊ฒ€์ƒ‰
    similar_docs = vector_store_manager.search_similar(
        user_id, document_id, query, k=self.max_search_results
    )
    
    # 2. ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ ์‘๋‹ต ์ƒ์„ฑ
    return self._generate_text_response(query, similar_docs, llm_model, image_files)
```

#### 2.3 LLM ์—†์ด๋„ ์ž‘๋™ํ•˜๋Š” ๊ตฌ์กฐํ™”๋œ ์‘๋‹ต
```python
def _generate_text_response(self, query: str, text_docs: List[Document], 
                          llm_model, image_files: List[str] = None) -> Dict[str, Any]:
    # ์ปจํ…์ŠคํŠธ ๊ตฌ์„ฑ (์ž‘์€ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด ๊ธธ์ด ์ œํ•œ)
    context = self._build_context(text_docs)
    if len(context) > 2000:
        context = context[:2000] + "..."
    
    # LLM ๋ชจ๋ธ์ด ์žˆ์œผ๋ฉด ์‘๋‹ต ์ƒ์„ฑ, ์—†์œผ๋ฉด ์ปจํ…์ŠคํŠธ๋งŒ ๋ฐ˜ํ™˜
    if llm_model:
        response = self._generate_with_llm_simple(prompt, llm_model)
    else:
        # ๊ตฌ์กฐํ™”๋œ ํ…์ŠคํŠธ ์‘๋‹ต ์ƒ์„ฑ
        response = f"""๋ฌธ์„œ์—์„œ ๊ฒ€์ƒ‰๋œ ๊ด€๋ จ ๋‚ด์šฉ์„ ๋ฐ”ํƒ•์œผ๋กœ ๋‹ต๋ณ€๋“œ๋ฆฝ๋‹ˆ๋‹ค:

๐Ÿ“‹ ๊ฒ€์ƒ‰๋œ ๋‚ด์šฉ:
{context}

โ“ ์งˆ๋ฌธ: {query}

๐Ÿ’ก ๋‹ต๋ณ€: ์œ„ ๊ฒ€์ƒ‰๋œ ๋‚ด์šฉ์„ ์ฐธ๊ณ ํ•˜์—ฌ ์งˆ๋ฌธ์— ๋Œ€ํ•œ ๋‹ต๋ณ€์„ ์ฐพ์•„๋ณด์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค."""
```

### 3๋‹จ๊ณ„: ํ…Œ์ŠคํŠธ ์‹œ์Šคํ…œ ๊ตฌ์ถ•

#### 3.1 ์„œ๋ฒ„ ์—ฐ๊ฒฐ ๋ฐ ๋ฌธ์„œ ์—…๋กœ๋“œ ํ…Œ์ŠคํŠธ
**ํŒŒ์ผ**: `test_simple_rag.py`
```python
def test_server_connection():
    response = requests.get("http://localhost:8001/health", timeout=10)
    return response.status_code == 200

def test_document_upload():
    response = requests.post(
        "http://localhost:8001/document/upload",
        files=files,
        data=data,
        timeout=120
    )
```

#### 3.2 ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ RAG ํ…Œ์ŠคํŠธ
**ํŒŒ์ผ**: `test_text_only_rag.py`
```python
def test_text_only_rag():
    test_queries = [
        "1๋ฒˆ ๋ฌธ์ œ",
        "2๋ฒˆ ๋ฌธ์ œ", 
        "3๋ฒˆ ๋ฌธ์ œ",
        "์ˆ˜ํ•™ ๋ฌธ์ œ"
    ]
    
    for query in test_queries:
        rag_data = {
            'user_id': 'test_user',
            'document_id': document_id,
            'query': query
        }
        response = requests.post(
            f"{base_url}/rag/generate",
            data=rag_data,
            timeout=60
        )
```

#### 3.3 ๊ตฌ์ฒด์ ์ธ ์ˆ˜ํ•™ ๋ฌธ์ œ ์งˆ๋ฌธ ํ…Œ์ŠคํŠธ
**ํŒŒ์ผ**: `test_specific_questions.py`
```python
test_queries = [
    "23๋ฒˆ ๋ฌธ์ œ์˜ ๋‹ต์€ ๋ฌด์—‡์ธ๊ฐ€์š”?",
    "24๋ฒˆ ๋ฌธ์ œ๋ฅผ ํ’€์–ด์ฃผ์„ธ์š”",
    "15๋ฒˆ ๋ฌธ์ œ์˜ ๋‹ต์„ ๊ตฌํ•ด์ฃผ์„ธ์š”",
    "23๋ฒˆ ๋ฌธ์ œ์—์„œ 5๊ฐœ์˜ ๋ฌธ์ž๋ฅผ ์ผ๋ ฌ๋กœ ๋‚˜์—ดํ•˜๋Š” ๊ฒฝ์šฐ์˜ ์ˆ˜๋Š”?",
    "24๋ฒˆ ๋ฌธ์ œ์—์„œ P(B)์˜ ๊ฐ’์€?"
]
```

### 4๋‹จ๊ณ„: ์„ฑ๊ณผ ํ™•์ธ

#### 4.1 ์„ฑ๊ณตํ•œ ๊ธฐ๋Šฅ๋“ค
- โœ… **PDF ํ…์ŠคํŠธ ์ถ”์ถœ ์™„๋ฒฝ**: ์‹ค์ œ ์ˆ˜ํ•™ ๋ฌธ์ œ ๋‚ด์šฉ ์ •ํ™•ํžˆ ์ถ”์ถœ
- โœ… **๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ ์™„๋ฒฝ**: ๊ด€๋ จ ๋ฌธ์ œ๋“ค์„ ์ •ํ™•ํžˆ ์ฐพ์•„๋ƒ„
- โœ… **๋น ๋ฅธ ์ฒ˜๋ฆฌ**: ์ฆ‰์‹œ ์‘๋‹ต (LLM ์—†์ด๋„ ์ž‘๋™)
- โœ… **๊ตฌ์กฐํ™”๋œ ์‘๋‹ต**: ๋ฌธ์ œ ๋ถ„์„๊ณผ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• ์ œ์‹œ
- โœ… **์ •ํ™•ํ•œ ๋ฌธ์ œ ๋งค์นญ**: 23๋ฒˆ, 24๋ฒˆ, 15๋ฒˆ ๋ฌธ์ œ ์ •ํ™•ํžˆ ์ฐพ์Œ

#### 4.2 ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ
- **๋ฌธ์„œ ์—…๋กœ๋“œ**: 12๊ฐœ ์ฒญํฌ ์„ฑ๊ณต
- **๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ**: 5๊ฐœ์”ฉ ์ •ํ™•ํžˆ ๋ฐ˜ํ™˜
- **์‘๋‹ต ์‹œ๊ฐ„**: ์ฆ‰์‹œ (ํ† ํฐ ID ๋ฌธ์ œ ํ•ด๊ฒฐ๋จ)
- **๋ฌธ์ œ ์ธ์‹**: ์‹ค์ œ ์ˆ˜ํ•™ ๋ฌธ์ œ ๋‚ด์šฉ ์ •ํ™•ํžˆ ์ถ”์ถœ

## ๐ŸŽฏ ์ตœ์ข… ์„ฑ๊ณผ

### ํ•ด๊ฒฐ๋œ ๋ฌธ์ œ๋“ค
1. โœ… **ํ† ํฐ ID ๋ฌธ์ œ**: ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•ด๊ฒฐ
2. โœ… **PDF ํ…์ŠคํŠธ ์ถ”์ถœ**: ์‹ค์ œ ๋ฌธ์ œ ๋‚ด์šฉ ์ถ”์ถœ ์„ฑ๊ณต
3. โœ… **๋น ๋ฅธ ๊ฒ€์ฆ**: ์ž‘์€ ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ๋กœ ์„ฑ๊ณต
4. โœ… **๊ตฌ์กฐํ™”๋œ ์‘๋‹ต**: ๋ฌธ์ œ ๋ถ„์„๊ณผ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• ํฌํ•จ

### ํ˜„์žฌ ์ƒํƒœ
**"์ž‘์€ ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ๋กœ ๋น ๋ฅธ ๊ฒ€์ฆ"** ๋ชฉํ‘œ ๋‹ฌ์„ฑ!

- CPU ํ™˜๊ฒฝ์—์„œ๋„ ๋น ๋ฅด๊ฒŒ ์ž‘๋™
- ์‹ค์ œ ์ˆ˜ํ•™ ๋ฌธ์ œ ๋‚ด์šฉ ์ •ํ™•ํžˆ ์ถ”์ถœ
- ๊ฒ€์ƒ‰๊ณผ ์ปจํ…์ŠคํŠธ ๋ฐ˜ํ™˜ ์™„๋ฒฝ ์ž‘๋™
- ๊ตฌ์กฐํ™”๋œ ์‘๋‹ต ์ƒ์„ฑ

**๋‹ค์Œ ๋‹จ๊ณ„**: ์„œ๋ฒ„์— ์˜ฌ๋ ค์„œ GPU๋กœ ์‹ค์‚ฌ์šฉ ์ค€๋น„ ์™„๋ฃŒ

## ๐Ÿ“ ์ฃผ์š” ์ˆ˜์ • ํŒŒ์ผ๋“ค

### Core ํŒŒ์ผ๋“ค
- `lily_llm_core/document_processor.py`: PDF ํ…์ŠคํŠธ ์ถ”์ถœ ๊ฐœ์„ 
- `lily_llm_core/rag_processor.py`: RAG ํ”„๋กœ์„ธ์„œ ๋‹จ์ˆœํ™”
- `lily_llm_api/app_v2.py`: ์—”๋“œํฌ์ธํŠธ ์ˆ˜์ •

### ํ…Œ์ŠคํŠธ ํŒŒ์ผ๋“ค
- `test_simple_rag.py`: ๊ธฐ๋ณธ ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ
- `test_text_only_rag.py`: ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ RAG ํ…Œ์ŠคํŠธ
- `test_specific_questions.py`: ๊ตฌ์ฒด์  ์งˆ๋ฌธ ํ…Œ์ŠคํŠธ
- `test_llm_rag.py`: LLM ํฌํ•จ ํ…Œ์ŠคํŠธ

## ๐Ÿ”ง ๊ธฐ์ˆ ์  ๊ฐœ์„ ์‚ฌํ•ญ

### 1. PDF ์ฒ˜๋ฆฌ ๋ฐฉ์‹ ๋ณ€๊ฒฝ
- **์ด์ „**: ์ด๋ฏธ์ง€ ๊ธฐ๋ฐ˜ OCR โ†’ ํ† ํฐ ID ๋ฌธ์ œ
- **ํ˜„์žฌ**: ํ…์ŠคํŠธ ์ง์ ‘ ์ถ”์ถœ โ†’ ์•ˆ์ •์  ์ฒ˜๋ฆฌ

### 2. RAG ํ”„๋กœ์„ธ์„œ ๋‹จ์ˆœํ™”
- **์ด์ „**: ๋ฉ€ํ‹ฐ๋ชจ๋‹ฌ ๋ณต์žกํ•œ ์ฒ˜๋ฆฌ
- **ํ˜„์žฌ**: ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ ๋‹จ์ˆœ ์ฒ˜๋ฆฌ

### 3. ์‘๋‹ต ๊ตฌ์กฐ ๊ฐœ์„ 
- **์ด์ „**: ํ† ํฐ ID ์‘๋‹ต
- **ํ˜„์žฌ**: ๊ตฌ์กฐํ™”๋œ ํ…์ŠคํŠธ ์‘๋‹ต

## ๐Ÿš€ ๋‹ค์Œ ๋‹จ๊ณ„ ์ œ์•ˆ

1. **GPU ์„œ๋ฒ„ ๋ฐฐํฌ**: ํ˜„์žฌ CPU ํ…Œ์ŠคํŠธ ์™„๋ฃŒ
2. **LLM ํ†ตํ•ฉ ๊ฐœ์„ **: ํ† ํฐ ๋””์ฝ”๋”ฉ ๋ฌธ์ œ ํ•ด๊ฒฐ
3. **์‹ค์ œ ๋ฌธ์ œ ํ•ด๊ฒฐ**: ์ˆ˜ํ•™ ๋ฌธ์ œ ํ’€์ด ๋Šฅ๋ ฅ ํ–ฅ์ƒ
4. **์„ฑ๋Šฅ ์ตœ์ ํ™”**: ๋” ํฐ ๋ฐ์ดํ„ฐ์…‹ ์ฒ˜๋ฆฌ