@xdev-asia/xdev-knowledge-mcp 1.0.57 → 1.0.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/content/blog/ai/minimax-danh-gia-chi-tiet-nen-tang-ai-full-stack-trung-quoc.md +450 -0
- package/content/blog/ai/nvidia-dli-generative-ai-chung-chi-va-lo-trinh-hoc.md +894 -0
- package/content/metadata/authors/duy-tran.md +2 -0
- package/content/series/luyen-thi/luyen-thi-nvidia-dli-generative-ai/chapters/01-deep-learning-foundations/lessons/01-bai-1-pytorch-neural-network-fundamentals.md +790 -0
- package/content/series/luyen-thi/luyen-thi-nvidia-dli-generative-ai/chapters/01-deep-learning-foundations/lessons/02-bai-2-transformer-architecture-attention.md +984 -0
- package/content/series/luyen-thi/luyen-thi-nvidia-dli-generative-ai/chapters/02-diffusion-models/lessons/01-bai-3-unet-architecture-denoising.md +1111 -0
- package/content/series/luyen-thi/luyen-thi-nvidia-dli-generative-ai/chapters/02-diffusion-models/lessons/02-bai-4-ddpm-forward-reverse-diffusion.md +1007 -0
- package/content/series/luyen-thi/luyen-thi-nvidia-dli-generative-ai/chapters/02-diffusion-models/lessons/03-bai-5-clip-text-to-image-pipeline.md +1037 -0
- package/content/series/luyen-thi/luyen-thi-nvidia-dli-generative-ai/chapters/03-llm-applications-rag/lessons/01-bai-6-llm-inference-pipeline-design.md +929 -0
- package/content/series/luyen-thi/luyen-thi-nvidia-dli-generative-ai/chapters/03-llm-applications-rag/lessons/02-bai-7-rag-retrieval-augmented-generation.md +1099 -0
- package/content/series/luyen-thi/luyen-thi-nvidia-dli-generative-ai/chapters/03-llm-applications-rag/lessons/03-bai-8-rag-agent-build-evaluate.md +1249 -0
- package/content/series/luyen-thi/luyen-thi-nvidia-dli-generative-ai/chapters/04-agentic-ai-customization/lessons/01-bai-9-agentic-ai-multi-agent-systems.md +1357 -0
- package/content/series/luyen-thi/luyen-thi-nvidia-dli-generative-ai/chapters/04-agentic-ai-customization/lessons/02-bai-10-llm-evaluation-lora-fine-tuning.md +1867 -0
- package/content/series/luyen-thi/luyen-thi-nvidia-dli-generative-ai/index.md +237 -0
- package/data/quizzes/nvidia-dli-generative-ai.json +350 -0
- package/data/quizzes.json +14 -0
- package/package.json +1 -1
|
@@ -0,0 +1,929 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: 019c9619-nv01-p3-l06
|
|
3
|
+
title: 'Bài 6: LLM Inference Pipeline Design'
|
|
4
|
+
slug: bai-6-llm-inference-pipeline-design
|
|
5
|
+
description: >-
|
|
6
|
+
LLM inference parameters: temperature, top-k, top-p.
|
|
7
|
+
NVIDIA NIM microservices cho triển khai model.
|
|
8
|
+
LangChain LCEL pipeline.
|
|
9
|
+
Gradio & LangServe: build UI + API.
|
|
10
|
+
Dialog management & multi-turn conversation.
|
|
11
|
+
duration_minutes: 75
|
|
12
|
+
is_free: true
|
|
13
|
+
video_url: null
|
|
14
|
+
sort_order: 6
|
|
15
|
+
section_title: "Part 3: LLM Applications & RAG"
|
|
16
|
+
course:
|
|
17
|
+
id: 019c9619-nv01-7001-c001-nv0100000001
|
|
18
|
+
title: 'Luyện thi NVIDIA DLI — Generative AI with Diffusion Models & LLMs'
|
|
19
|
+
slug: luyen-thi-nvidia-dli-generative-ai
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
<h2 id="1-gioi-thieu-part-3">1. Từ Diffusion Models sang LLM Applications</h2>
|
|
23
|
+
|
|
24
|
+
<p>Trong Part 2, chúng ta đã làm chủ <strong>Diffusion Models</strong> — từ forward/reverse process đến CLIP-guided generation. Giờ sang Part 3, trọng tâm chuyển sang <strong>Large Language Models (LLMs)</strong> và cách xây dựng ứng dụng thực tế: inference pipeline, RAG, chatbot.</p>
|
|
25
|
+
|
|
26
|
+
<p>Bài này tập trung vào <strong>LLM Inference Pipeline Design</strong> — cách điều khiển output của LLM thông qua sampling parameters, triển khai model với <strong>NVIDIA NIM</strong>, xây pipeline với <strong>LangChain LCEL</strong>, và build UI/API với <strong>Gradio</strong> + <strong>LangServe</strong>.</p>
|
|
27
|
+
|
|
28
|
+
<blockquote><p><strong>Exam tip:</strong> Đề thi NVIDIA DLI rất hay hỏi về inference parameters (temperature, top-k, top-p) và khi nào dùng NIM vs framework khác. Nắm chắc bảng so sánh ở cuối bài.</p></blockquote>
|
|
29
|
+
|
|
30
|
+
<figure><img src="/storage/uploads/2026/04/nvidia-dli-bai6-llm-inference-pipeline.png" alt="LLM Inference Pipeline — Prompt Template, NIM, LCEL Chain, Gradio UI" loading="lazy" /><figcaption>LLM Inference Pipeline — Prompt Template, NIM, LCEL Chain, Gradio UI</figcaption></figure>
|
|
31
|
+
|
|
32
|
+
<h2 id="2-llm-inference-fundamentals">2. LLM Inference Fundamentals</h2>
|
|
33
|
+
|
|
34
|
+
<h3 id="2-1-autoregressive-generation">2.1. Autoregressive Generation</h3>
|
|
35
|
+
|
|
36
|
+
<p>LLM sinh text theo cơ chế <strong>autoregressive</strong>: mỗi bước, model dự đoán token tiếp theo dựa trên tất cả token trước đó. Quá trình lặp lại cho đến khi gặp <strong>stop token</strong> hoặc đạt <strong>max_tokens</strong>.</p>
|
|
37
|
+
|
|
38
|
+
<pre><code class="language-text">
|
|
39
|
+
Autoregressive Generation Flow
|
|
40
|
+
═══════════════════════════════
|
|
41
|
+
|
|
42
|
+
Input: "Hà Nội là"
|
|
43
|
+
│
|
|
44
|
+
▼
|
|
45
|
+
┌─────────────────────┐
|
|
46
|
+
│ LLM Forward Pass │
|
|
47
|
+
│ P(token | context) │
|
|
48
|
+
└──────────┬──────────┘
|
|
49
|
+
│
|
|
50
|
+
▼
|
|
51
|
+
┌─────────────────────┐
|
|
52
|
+
│ Sampling Strategy │──► temperature, top-k, top-p
|
|
53
|
+
│ Select next token │
|
|
54
|
+
└──────────┬──────────┘
|
|
55
|
+
│
|
|
56
|
+
▼
|
|
57
|
+
token = "thủ"
|
|
58
|
+
│
|
|
59
|
+
▼
|
|
60
|
+
Input: "Hà Nội là thủ"
|
|
61
|
+
│
|
|
62
|
+
▼
|
|
63
|
+
┌─────────────────────┐
|
|
64
|
+
│ LLM Forward Pass │
|
|
65
|
+
└──────────┬──────────┘
|
|
66
|
+
│
|
|
67
|
+
▼
|
|
68
|
+
token = "đô"
|
|
69
|
+
│
|
|
70
|
+
▼
|
|
71
|
+
... lặp lại đến <EOS> hoặc max_tokens
|
|
72
|
+
</code></pre>
|
|
73
|
+
|
|
74
|
+
<h3 id="2-2-sampling-parameters">2.2. Sampling Parameters</h3>
|
|
75
|
+
|
|
76
|
+
<p>Ba tham số quan trọng nhất kiểm soát tính sáng tạo của output:</p>
|
|
77
|
+
|
|
78
|
+
<table>
|
|
79
|
+
<thead>
|
|
80
|
+
<tr><th>Parameter</th><th>Range</th><th>Tác dụng</th><th>Giá trị thấp</th><th>Giá trị cao</th></tr>
|
|
81
|
+
</thead>
|
|
82
|
+
<tbody>
|
|
83
|
+
<tr><td><strong>temperature</strong></td><td>0.0 – 2.0</td><td>Điều chỉnh entropy của phân phối xác suất</td><td>Deterministic, lặp lại</td><td>Sáng tạo, random hơn</td></tr>
|
|
84
|
+
<tr><td><strong>top_k</strong></td><td>1 – vocab_size</td><td>Giới hạn chỉ xét top K token có xác suất cao nhất</td><td>Chọn lọc hơn, ít đa dạng</td><td>Nhiều lựa chọn hơn</td></tr>
|
|
85
|
+
<tr><td><strong>top_p</strong></td><td>0.0 – 1.0</td><td>Nucleus sampling: chỉ xét tokens có cumulative prob ≤ p</td><td>Chỉ token chắc chắn nhất</td><td>Xét nhiều token hơn</td></tr>
|
|
86
|
+
</tbody>
|
|
87
|
+
</table>
|
|
88
|
+
|
|
89
|
+
<pre><code class="language-text">
|
|
90
|
+
Token Sampling Process (temperature + top-p)
|
|
91
|
+
═════════════════════════════════════════════
|
|
92
|
+
|
|
93
|
+
Raw logits: [2.1, 1.8, 0.5, 0.3, -1.0, -2.5, ...]
|
|
94
|
+
│
|
|
95
|
+
▼
|
|
96
|
+
┌──────────────┐
|
|
97
|
+
│ ÷ temperature │ (temp=0.7 → sharper)
|
|
98
|
+
└──────┬───────┘
|
|
99
|
+
│
|
|
100
|
+
▼
|
|
101
|
+
Scaled probs: [0.35, 0.28, 0.12, 0.09, 0.08, 0.05, 0.03]
|
|
102
|
+
│
|
|
103
|
+
▼
|
|
104
|
+
┌──────────────┐
|
|
105
|
+
│ top-p=0.8 │ cumsum: 0.35→0.63→0.75→0.84 ✓
|
|
106
|
+
│ Keep top 4 │ → loại bỏ token 5,6,7...
|
|
107
|
+
└──────┬───────┘
|
|
108
|
+
│
|
|
109
|
+
▼
|
|
110
|
+
Filtered: [0.41, 0.33, 0.14, 0.12] (re-normalized)
|
|
111
|
+
│
|
|
112
|
+
▼
|
|
113
|
+
Random sample → token "thủ"
|
|
114
|
+
</code></pre>
|
|
115
|
+
|
|
116
|
+
<h3 id="2-3-other-parameters">2.3. Các tham số khác</h3>
|
|
117
|
+
|
|
118
|
+
<table>
|
|
119
|
+
<thead>
|
|
120
|
+
<tr><th>Parameter</th><th>Mô tả</th><th>Use case</th></tr>
|
|
121
|
+
</thead>
|
|
122
|
+
<tbody>
|
|
123
|
+
<tr><td><strong>max_tokens</strong></td><td>Giới hạn số token output tối đa</td><td>Kiểm soát chi phí, latency</td></tr>
|
|
124
|
+
<tr><td><strong>stop</strong></td><td>Dừng generation khi gặp chuỗi này</td><td>Structured output, function calling</td></tr>
|
|
125
|
+
<tr><td><strong>repetition_penalty</strong></td><td>Phạt token đã xuất hiện (>1.0 = phạt nặng)</td><td>Tránh lặp từ/câu</td></tr>
|
|
126
|
+
<tr><td><strong>frequency_penalty</strong></td><td>Giảm xác suất theo tần suất xuất hiện</td><td>Output đa dạng hơn</td></tr>
|
|
127
|
+
<tr><td><strong>presence_penalty</strong></td><td>Phạt nếu token đã xuất hiện ít nhất 1 lần</td><td>Khuyến khích chủ đề mới</td></tr>
|
|
128
|
+
</tbody>
|
|
129
|
+
</table>
|
|
130
|
+
|
|
131
|
+
<blockquote><p><strong>Exam tip:</strong> Câu hỏi hay gặp: "Muốn output luôn giống nhau (deterministic), set parameter nào?" → <strong>temperature = 0.0</strong>. Nếu hỏi "giảm lặp từ" → dùng <strong>repetition_penalty > 1.0</strong> hoặc <strong>frequency_penalty > 0</strong>.</p></blockquote>
|
|
132
|
+
|
|
133
|
+
<h2 id="3-nvidia-nim">3. NVIDIA NIM (NVIDIA Inference Microservices)</h2>
|
|
134
|
+
|
|
135
|
+
<h3 id="3-1-nim-la-gi">3.1. NIM là gì?</h3>
|
|
136
|
+
|
|
137
|
+
<p><strong>NVIDIA NIM</strong> là bộ <strong>pre-optimized inference containers</strong> cho phép deploy LLM/multimodal models với hiệu năng cao nhất trên GPU NVIDIA. NIM đã tích hợp sẵn <strong>TensorRT-LLM</strong>, quantization, và tối ưu memory.</p>
|
|
138
|
+
|
|
139
|
+
<p>Đặc điểm chính:</p>
|
|
140
|
+
<ul>
|
|
141
|
+
<li><strong>OpenAI-compatible API</strong> — drop-in replacement, dùng openai client gọi thẳng</li>
|
|
142
|
+
<li><strong>TensorRT-LLM backend</strong> — tối ưu kernel cho NVIDIA GPU</li>
|
|
143
|
+
<li><strong>Continuous batching</strong> — xử lý nhiều request cùng lúc hiệu quả</li>
|
|
144
|
+
<li><strong>gRPC + REST API</strong> — flexible integration</li>
|
|
145
|
+
<li><strong>Multi-GPU support</strong> — tensor parallelism tự động</li>
|
|
146
|
+
</ul>
|
|
147
|
+
|
|
148
|
+
<h3 id="3-2-nim-architecture">3.2. NIM Architecture</h3>
|
|
149
|
+
|
|
150
|
+
<pre><code class="language-text">
|
|
151
|
+
NVIDIA NIM Architecture
|
|
152
|
+
════════════════════════
|
|
153
|
+
|
|
154
|
+
┌─────────────────────────────────────────────┐
|
|
155
|
+
│ NIM Container │
|
|
156
|
+
│ │
|
|
157
|
+
│ ┌──────────┐ ┌──────────────────────┐ │
|
|
158
|
+
│ │ REST API │ │ gRPC Endpoint │ │
|
|
159
|
+
│ │ :8000 │ │ :8001 │ │
|
|
160
|
+
│ └─────┬────┘ └──────────┬───────────┘ │
|
|
161
|
+
│ │ │ │
|
|
162
|
+
│ └────────┬───────────┘ │
|
|
163
|
+
│ ▼ │
|
|
164
|
+
│ ┌──────────────────────────────────┐ │
|
|
165
|
+
│ │ Request Router & Batcher │ │
|
|
166
|
+
│ │ (Continuous Batching) │ │
|
|
167
|
+
│ └──────────────┬───────────────────┘ │
|
|
168
|
+
│ ▼ │
|
|
169
|
+
│ ┌──────────────────────────────────┐ │
|
|
170
|
+
│ │ TensorRT-LLM Engine │ │
|
|
171
|
+
│ │ ┌────────┐ ┌────────────────┐ │ │
|
|
172
|
+
│ │ │ KV Cache│ │ Paged Attention│ │ │
|
|
173
|
+
│ │ └────────┘ └────────────────┘ │ │
|
|
174
|
+
│ └──────────────┬───────────────────┘ │
|
|
175
|
+
│ ▼ │
|
|
176
|
+
│ ┌──────────────────────────────────┐ │
|
|
177
|
+
│ │ NVIDIA GPU(s) │ │
|
|
178
|
+
│ │ A100 / H100 / L40S │ │
|
|
179
|
+
│ └──────────────────────────────────┘ │
|
|
180
|
+
└─────────────────────────────────────────────┘
|
|
181
|
+
</code></pre>
|
|
182
|
+
|
|
183
|
+
<h3 id="3-3-pull-run-nim">3.3. Pull & Run NIM Container</h3>
|
|
184
|
+
|
|
185
|
+
<pre><code class="language-python">
|
|
186
|
+
# Pull và chạy NIM container cho Llama-3
|
|
187
|
+
# Yêu cầu: NVIDIA GPU, Docker + NVIDIA Container Toolkit
|
|
188
|
+
|
|
189
|
+
# Terminal command:
|
|
190
|
+
# docker run -it --rm --gpus all \
|
|
191
|
+
# -p 8000:8000 \
|
|
192
|
+
# -e NGC_API_KEY=$NGC_API_KEY \
|
|
193
|
+
# nvcr.io/nim/meta/llama-3.1-8b-instruct:latest
|
|
194
|
+
</code></pre>
|
|
195
|
+
|
|
196
|
+
<h3 id="3-4-call-nim-api">3.4. Gọi NIM API</h3>
|
|
197
|
+
|
|
198
|
+
<pre><code class="language-python">
|
|
199
|
+
from openai import OpenAI
|
|
200
|
+
|
|
201
|
+
# NIM tương thích OpenAI API — chỉ cần đổi base_url
|
|
202
|
+
client = OpenAI(
|
|
203
|
+
base_url="http://localhost:8000/v1",
|
|
204
|
+
api_key="not-used" # NIM local không cần key
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
response = client.chat.completions.create(
|
|
208
|
+
model="meta/llama-3.1-8b-instruct",
|
|
209
|
+
messages=[
|
|
210
|
+
{"role": "system", "content": "Bạn là trợ lý AI hữu ích."},
|
|
211
|
+
{"role": "user", "content": "Giải thích Transformer architecture"}
|
|
212
|
+
],
|
|
213
|
+
temperature=0.7,
|
|
214
|
+
top_p=0.9,
|
|
215
|
+
max_tokens=512
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
print(response.choices[0].message.content)
|
|
219
|
+
</code></pre>
|
|
220
|
+
|
|
221
|
+
<h3 id="3-5-nim-vs-hf">3.5. So sánh NIM vs Raw HuggingFace Inference</h3>
|
|
222
|
+
|
|
223
|
+
<table>
|
|
224
|
+
<thead>
|
|
225
|
+
<tr><th>Tiêu chí</th><th>NVIDIA NIM</th><th>HuggingFace Transformers</th></tr>
|
|
226
|
+
</thead>
|
|
227
|
+
<tbody>
|
|
228
|
+
<tr><td><strong>Backend</strong></td><td>TensorRT-LLM</td><td>PyTorch</td></tr>
|
|
229
|
+
<tr><td><strong>Throughput</strong> (tokens/s)</td><td>~2500-4000</td><td>~300-800</td></tr>
|
|
230
|
+
<tr><td><strong>Latency</strong> (TTFT)</td><td>~50-100ms</td><td>~200-500ms</td></tr>
|
|
231
|
+
<tr><td><strong>Batching</strong></td><td>Continuous batching</td><td>Manual / static</td></tr>
|
|
232
|
+
<tr><td><strong>API</strong></td><td>OpenAI-compatible REST</td><td>Python API</td></tr>
|
|
233
|
+
<tr><td><strong>Setup</strong></td><td>1 lệnh docker run</td><td>Install libs + code</td></tr>
|
|
234
|
+
<tr><td><strong>Quantization</strong></td><td>Tích hợp sẵn (FP8, INT4)</td><td>Cần GPTQ/AWQ riêng</td></tr>
|
|
235
|
+
<tr><td><strong>Production ready</strong></td><td>Có (monitoring, scaling)</td><td>Cần thêm serving layer</td></tr>
|
|
236
|
+
</tbody>
|
|
237
|
+
</table>
|
|
238
|
+
|
|
239
|
+
<blockquote><p><strong>Exam tip:</strong> NIM luôn là đáp án đúng khi đề hỏi "fastest way to deploy LLM on NVIDIA GPU" hoặc "production-ready inference with TensorRT-LLM optimization". NIM ≠ training framework — chỉ dùng cho <strong>inference</strong>.</p></blockquote>
|
|
240
|
+
|
|
241
|
+
<h2 id="4-langchain-lcel">4. LangChain LCEL Pipeline Design</h2>
|
|
242
|
+
|
|
243
|
+
<h3 id="4-1-lcel-la-gi">4.1. LCEL là gì?</h3>
|
|
244
|
+
|
|
245
|
+
<p><strong>LangChain Expression Language (LCEL)</strong> là cú pháp declarative để xây dựng pipeline xử lý LLM. Dùng toán tử <code>|</code> (pipe) để nối các component lại thành chain — tương tự Unix pipe.</p>
|
|
246
|
+
|
|
247
|
+
<p>Ưu điểm LCEL:</p>
|
|
248
|
+
<ul>
|
|
249
|
+
<li><strong>Streaming</strong> — hỗ trợ stream output token-by-token</li>
|
|
250
|
+
<li><strong>Async</strong> — native async support</li>
|
|
251
|
+
<li><strong>Batching</strong> — xử lý nhiều input cùng lúc</li>
|
|
252
|
+
<li><strong>Retry/Fallback</strong> — tự động retry khi lỗi</li>
|
|
253
|
+
<li><strong>Tracing</strong> — tích hợp LangSmith để debug</li>
|
|
254
|
+
</ul>
|
|
255
|
+
|
|
256
|
+
<h3 id="4-2-core-primitives">4.2. Core Primitives</h3>
|
|
257
|
+
|
|
258
|
+
<table>
|
|
259
|
+
<thead>
|
|
260
|
+
<tr><th>Component</th><th>Vai trò</th><th>Input → Output</th></tr>
|
|
261
|
+
</thead>
|
|
262
|
+
<tbody>
|
|
263
|
+
<tr><td><strong>PromptTemplate</strong></td><td>Format prompt với variables</td><td>dict → PromptValue</td></tr>
|
|
264
|
+
<tr><td><strong>ChatPromptTemplate</strong></td><td>Format chat messages</td><td>dict → ChatPromptValue</td></tr>
|
|
265
|
+
<tr><td><strong>ChatModel</strong></td><td>Gọi LLM (ChatOpenAI, ChatNVIDIA...)</td><td>PromptValue → AIMessage</td></tr>
|
|
266
|
+
<tr><td><strong>StrOutputParser</strong></td><td>Extract string từ AIMessage</td><td>AIMessage → str</td></tr>
|
|
267
|
+
<tr><td><strong>JsonOutputParser</strong></td><td>Parse JSON từ output</td><td>AIMessage → dict</td></tr>
|
|
268
|
+
<tr><td><strong>RunnablePassthrough</strong></td><td>Pass input qua không đổi</td><td>any → any</td></tr>
|
|
269
|
+
<tr><td><strong>RunnableLambda</strong></td><td>Wrap function thành Runnable</td><td>any → any</td></tr>
|
|
270
|
+
<tr><td><strong>RunnableParallel</strong></td><td>Chạy nhiều chain song song</td><td>dict → dict</td></tr>
|
|
271
|
+
</tbody>
|
|
272
|
+
</table>
|
|
273
|
+
|
|
274
|
+
<h3 id="4-3-lcel-pipeline-diagram">4.3. LCEL Pipeline Flow</h3>
|
|
275
|
+
|
|
276
|
+
<pre><code class="language-text">
|
|
277
|
+
LCEL Pipeline Architecture
|
|
278
|
+
════════════════════════════
|
|
279
|
+
|
|
280
|
+
Simple Chain:
|
|
281
|
+
─────────────
|
|
282
|
+
{"topic": "AI"}
|
|
283
|
+
│
|
|
284
|
+
▼
|
|
285
|
+
┌───────────────┐ ┌─────────────┐ ┌────────────────┐
|
|
286
|
+
│ PromptTemplate │──►│ ChatModel │──►│ StrOutputParser │──► "AI là..."
|
|
287
|
+
│ "Explain {topic}"│ │ (ChatNVIDIA) │ │ │
|
|
288
|
+
└───────────────┘ └─────────────┘ └────────────────┘
|
|
289
|
+
|
|
290
|
+
prompt | llm | parser
|
|
291
|
+
LCEL: prompt | llm | parser
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
Parallel Chain (RunnableParallel):
|
|
295
|
+
───────────────────────────────────
|
|
296
|
+
{"topic": "AI"}
|
|
297
|
+
│
|
|
298
|
+
┌────────┴────────┐
|
|
299
|
+
▼ ▼
|
|
300
|
+
┌──────────────┐ ┌──────────────┐
|
|
301
|
+
│ chain_summary│ │ chain_quiz │
|
|
302
|
+
│ prompt | llm │ │ prompt | llm│
|
|
303
|
+
└──────┬───────┘ └──────┬───────┘
|
|
304
|
+
│ │
|
|
305
|
+
└────────┬────────┘
|
|
306
|
+
▼
|
|
307
|
+
{"summary": "...", "quiz": "..."}
|
|
308
|
+
</code></pre>
|
|
309
|
+
|
|
310
|
+
<h3 id="4-4-lcel-code">4.4. Code: LCEL Chain</h3>
|
|
311
|
+
|
|
312
|
+
<pre><code class="language-python">
|
|
313
|
+
from langchain_core.prompts import ChatPromptTemplate
|
|
314
|
+
from langchain_core.output_parsers import StrOutputParser
|
|
315
|
+
from langchain_nvidia_ai_endpoints import ChatNVIDIA
|
|
316
|
+
|
|
317
|
+
# 1. Khởi tạo components
|
|
318
|
+
prompt = ChatPromptTemplate.from_messages([
|
|
319
|
+
("system", "Bạn là chuyên gia {domain}. Trả lời ngắn gọn."),
|
|
320
|
+
("human", "{question}")
|
|
321
|
+
])
|
|
322
|
+
|
|
323
|
+
llm = ChatNVIDIA(
|
|
324
|
+
model="meta/llama-3.1-8b-instruct",
|
|
325
|
+
temperature=0.3,
|
|
326
|
+
top_p=0.9,
|
|
327
|
+
max_tokens=512
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
parser = StrOutputParser()
|
|
331
|
+
|
|
332
|
+
# 2. Tạo chain bằng LCEL pipe syntax
|
|
333
|
+
chain = prompt | llm | parser
|
|
334
|
+
|
|
335
|
+
# 3. Invoke (đồng bộ)
|
|
336
|
+
result = chain.invoke({
|
|
337
|
+
"domain": "deep learning",
|
|
338
|
+
"question": "Transformer self-attention hoạt động thế nào?"
|
|
339
|
+
})
|
|
340
|
+
print(result)
|
|
341
|
+
|
|
342
|
+
# 4. Stream (token-by-token)
|
|
343
|
+
for chunk in chain.stream({
|
|
344
|
+
"domain": "deep learning",
|
|
345
|
+
"question": "So sánh RNN và Transformer"
|
|
346
|
+
}):
|
|
347
|
+
print(chunk, end="", flush=True)
|
|
348
|
+
</code></pre>
|
|
349
|
+
|
|
350
|
+
<h3 id="4-5-advanced-lcel">4.5. Advanced: RunnableParallel & RunnableLambda</h3>
|
|
351
|
+
|
|
352
|
+
<pre><code class="language-python">
|
|
353
|
+
from langchain_core.runnables import (
|
|
354
|
+
RunnablePassthrough,
|
|
355
|
+
RunnableParallel,
|
|
356
|
+
RunnableLambda
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
# Custom function wrapped thành Runnable
|
|
360
|
+
def word_count(text: str) -> dict:
|
|
361
|
+
return {"text": text, "word_count": len(text.split())}
|
|
362
|
+
|
|
363
|
+
# Parallel chain: vừa summarize vừa đếm từ
|
|
364
|
+
parallel_chain = RunnableParallel(
|
|
365
|
+
summary=prompt | llm | parser,
|
|
366
|
+
metadata=RunnableLambda(
|
|
367
|
+
lambda x: f"Query: {x['question']}"
|
|
368
|
+
)
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
# Chain với passthrough — giữ input gốc qua pipeline
|
|
372
|
+
chain_with_context = (
|
|
373
|
+
RunnablePassthrough.assign(
|
|
374
|
+
answer=prompt | llm | parser
|
|
375
|
+
)
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
# Invoke parallel
|
|
379
|
+
result = parallel_chain.invoke({
|
|
380
|
+
"domain": "AI",
|
|
381
|
+
"question": "Generative AI là gì?"
|
|
382
|
+
})
|
|
383
|
+
# result = {"summary": "...", "metadata": "Query: Generative AI là gì?"}
|
|
384
|
+
</code></pre>
|
|
385
|
+
|
|
386
|
+
<blockquote><p><strong>Exam tip:</strong> Khi đề cho code LCEL và hỏi "output type là gì", hãy trace từng bước: PromptTemplate → PromptValue, ChatModel → AIMessage, StrOutputParser → str. <strong>Nếu quên parser</strong>, output sẽ là AIMessage object (không phải string).</p></blockquote>
|
|
387
|
+
|
|
388
|
+
<h2 id="5-gradio-langserve">5. Build UI với Gradio & API với LangServe</h2>
|
|
389
|
+
|
|
390
|
+
<h3 id="5-1-gradio-chatbot">5.1. Gradio: Rapid Chatbot UI</h3>
|
|
391
|
+
|
|
392
|
+
<p><strong>Gradio</strong> cho phép tạo web UI cho ML models chỉ với vài dòng code. Component <code>gr.ChatInterface</code> đặc biệt phù hợp cho chatbot.</p>
|
|
393
|
+
|
|
394
|
+
<pre><code class="language-python">
|
|
395
|
+
import gradio as gr
|
|
396
|
+
from langchain_core.prompts import ChatPromptTemplate
|
|
397
|
+
from langchain_core.output_parsers import StrOutputParser
|
|
398
|
+
from langchain_nvidia_ai_endpoints import ChatNVIDIA
|
|
399
|
+
|
|
400
|
+
# Setup chain
|
|
401
|
+
prompt = ChatPromptTemplate.from_messages([
|
|
402
|
+
("system", "Bạn là trợ lý AI thân thiện."),
|
|
403
|
+
("human", "{message}")
|
|
404
|
+
])
|
|
405
|
+
llm = ChatNVIDIA(model="meta/llama-3.1-8b-instruct")
|
|
406
|
+
chain = prompt | llm | StrOutputParser()
|
|
407
|
+
|
|
408
|
+
# Gradio handler
|
|
409
|
+
def respond(message, history):
|
|
410
|
+
"""Handle chat message — history là list of [user, bot] pairs."""
|
|
411
|
+
response = chain.invoke({"message": message})
|
|
412
|
+
return response
|
|
413
|
+
|
|
414
|
+
# Launch UI
|
|
415
|
+
demo = gr.ChatInterface(
|
|
416
|
+
fn=respond,
|
|
417
|
+
title="NVIDIA NIM Chatbot",
|
|
418
|
+
description="Chatbot powered by Llama 3.1 via NIM",
|
|
419
|
+
examples=["Generative AI là gì?", "So sánh GAN và Diffusion"],
|
|
420
|
+
theme="soft"
|
|
421
|
+
)
|
|
422
|
+
demo.launch(server_port=7860)
|
|
423
|
+
</code></pre>
|
|
424
|
+
|
|
425
|
+
<h3 id="5-2-langserve-api">5.2. LangServe: Expose Chain as REST API</h3>
|
|
426
|
+
|
|
427
|
+
<p><strong>LangServe</strong> biến bất kỳ LCEL chain nào thành REST API với docs tự động (Swagger). Phù hợp cho production deployment.</p>
|
|
428
|
+
|
|
429
|
+
<pre><code class="language-python">
|
|
430
|
+
# === Server (server.py) ===
|
|
431
|
+
from fastapi import FastAPI
|
|
432
|
+
from langserve import add_routes
|
|
433
|
+
from langchain_core.prompts import ChatPromptTemplate
|
|
434
|
+
from langchain_core.output_parsers import StrOutputParser
|
|
435
|
+
from langchain_nvidia_ai_endpoints import ChatNVIDIA
|
|
436
|
+
|
|
437
|
+
app = FastAPI(title="LLM API")
|
|
438
|
+
|
|
439
|
+
# Tạo chain
|
|
440
|
+
chain = (
|
|
441
|
+
ChatPromptTemplate.from_messages([
|
|
442
|
+
("system", "Trợ lý AI chuyên về {domain}."),
|
|
443
|
+
("human", "{question}")
|
|
444
|
+
])
|
|
445
|
+
| ChatNVIDIA(model="meta/llama-3.1-8b-instruct")
|
|
446
|
+
| StrOutputParser()
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
# Expose chain tại /chat endpoint
|
|
450
|
+
add_routes(app, chain, path="/chat")
|
|
451
|
+
|
|
452
|
+
# Run: uvicorn server:app --port 8080
|
|
453
|
+
</code></pre>
|
|
454
|
+
|
|
455
|
+
<pre><code class="language-python">
|
|
456
|
+
# === Client (client.py) ===
|
|
457
|
+
from langserve import RemoteRunnable
|
|
458
|
+
|
|
459
|
+
# Kết nối đến LangServe endpoint
|
|
460
|
+
chain = RemoteRunnable("http://localhost:8080/chat")
|
|
461
|
+
|
|
462
|
+
# Invoke giống như local chain
|
|
463
|
+
result = chain.invoke({
|
|
464
|
+
"domain": "machine learning",
|
|
465
|
+
"question": "Overfitting là gì?"
|
|
466
|
+
})
|
|
467
|
+
print(result)
|
|
468
|
+
|
|
469
|
+
# Stream cũng hoạt động
|
|
470
|
+
for chunk in chain.stream({
|
|
471
|
+
"domain": "NLP",
|
|
472
|
+
"question": "Tokenization hoạt động thế nào?"
|
|
473
|
+
}):
|
|
474
|
+
print(chunk, end="")
|
|
475
|
+
</code></pre>
|
|
476
|
+
|
|
477
|
+
<pre><code class="language-text">
|
|
478
|
+
Gradio + LangServe Deployment Pattern
|
|
479
|
+
═══════════════════════════════════════
|
|
480
|
+
|
|
481
|
+
Browser (User) Mobile App / Service
|
|
482
|
+
│ │
|
|
483
|
+
▼ ▼
|
|
484
|
+
┌──────────────┐ ┌──────────────┐
|
|
485
|
+
│ Gradio UI │ │ REST Client │
|
|
486
|
+
│ :7860 │ │ │
|
|
487
|
+
└──────┬───────┘ └──────┬───────┘
|
|
488
|
+
│ │
|
|
489
|
+
└────────┬────────────────┘
|
|
490
|
+
▼
|
|
491
|
+
┌──────────────────┐
|
|
492
|
+
│ LangServe API │
|
|
493
|
+
│ FastAPI :8080 │
|
|
494
|
+
│ /chat/invoke │
|
|
495
|
+
│ /chat/stream │
|
|
496
|
+
└────────┬─────────┘
|
|
497
|
+
▼
|
|
498
|
+
┌──────────────────┐
|
|
499
|
+
│ LCEL Chain │
|
|
500
|
+
│ prompt|llm|parser│
|
|
501
|
+
└────────┬─────────┘
|
|
502
|
+
▼
|
|
503
|
+
┌──────────────────┐
|
|
504
|
+
│ NVIDIA NIM │
|
|
505
|
+
│ :8000 │
|
|
506
|
+
└──────────────────┘
|
|
507
|
+
</code></pre>
|
|
508
|
+
|
|
509
|
+
<blockquote><p><strong>Exam tip:</strong> Gradio = <strong>prototyping/demo UI</strong>, LangServe = <strong>production REST API</strong>. Nếu đề hỏi "fastest way to demo a chatbot" → Gradio. "Expose chain for multiple clients" → LangServe. Hai cái có thể dùng cùng nhau.</p></blockquote>
|
|
510
|
+
|
|
511
|
+
<h2 id="6-dialog-management">6. Dialog Management & Multi-turn Conversation</h2>
|
|
512
|
+
|
|
513
|
+
<h3 id="6-1-memory-types">6.1. Các loại Memory</h3>
|
|
514
|
+
|
|
515
|
+
<p>Chatbot cần <strong>nhớ</strong> context từ các lượt hội thoại trước. LangChain cung cấp nhiều loại memory:</p>
|
|
516
|
+
|
|
517
|
+
<table>
|
|
518
|
+
<thead>
|
|
519
|
+
<tr><th>Memory Type</th><th>Cách hoạt động</th><th>Ưu điểm</th><th>Nhược điểm</th></tr>
|
|
520
|
+
</thead>
|
|
521
|
+
<tbody>
|
|
522
|
+
<tr><td><strong>ConversationBufferMemory</strong></td><td>Lưu toàn bộ lịch sử</td><td>Không mất thông tin</td><td>Token count tăng nhanh</td></tr>
|
|
523
|
+
<tr><td><strong>ConversationBufferWindowMemory</strong></td><td>Giữ N lượt gần nhất</td><td>Kiểm soát token</td><td>Mất context cũ</td></tr>
|
|
524
|
+
<tr><td><strong>ConversationSummaryMemory</strong></td><td>Tóm tắt lịch sử bằng LLM</td><td>Nén thông tin hiệu quả</td><td>Tốn thêm LLM call</td></tr>
|
|
525
|
+
<tr><td><strong>ConversationSummaryBufferMemory</strong></td><td>Tóm tắt cũ + giữ nguyên gần đây</td><td>Cân bằng chi tiết/nén</td><td>Phức tạp hơn</td></tr>
|
|
526
|
+
</tbody>
|
|
527
|
+
</table>
|
|
528
|
+
|
|
529
|
+
<h3 id="6-2-message-types">6.2. Message Types</h3>
|
|
530
|
+
|
|
531
|
+
<p>LangChain dùng typed messages để phân biệt vai trò:</p>
|
|
532
|
+
|
|
533
|
+
<pre><code class="language-python">
|
|
534
|
+
from langchain_core.messages import (
|
|
535
|
+
SystemMessage,
|
|
536
|
+
HumanMessage,
|
|
537
|
+
AIMessage
|
|
538
|
+
)
|
|
539
|
+
|
|
540
|
+
messages = [
|
|
541
|
+
SystemMessage(content="Bạn là trợ lý AI."),
|
|
542
|
+
HumanMessage(content="Xin chào!"),
|
|
543
|
+
AIMessage(content="Chào bạn! Tôi có thể giúp gì?"),
|
|
544
|
+
HumanMessage(content="Giải thích attention mechanism"),
|
|
545
|
+
]
|
|
546
|
+
</code></pre>
|
|
547
|
+
|
|
548
|
+
<h3 id="6-3-multi-turn-code">6.3. Code: Multi-turn Chatbot với Memory</h3>
|
|
549
|
+
|
|
550
|
+
<pre><code class="language-python">
|
|
551
|
+
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
|
552
|
+
from langchain_core.output_parsers import StrOutputParser
|
|
553
|
+
from langchain_core.chat_history import InMemoryChatMessageHistory
|
|
554
|
+
from langchain_core.runnables.history import RunnableWithMessageHistory
|
|
555
|
+
from langchain_nvidia_ai_endpoints import ChatNVIDIA
|
|
556
|
+
|
|
557
|
+
# 1. Prompt có slot cho message history
|
|
558
|
+
prompt = ChatPromptTemplate.from_messages([
|
|
559
|
+
("system", "Bạn là trợ lý AI. Trả lời ngắn gọn."),
|
|
560
|
+
MessagesPlaceholder(variable_name="history"),
|
|
561
|
+
("human", "{input}")
|
|
562
|
+
])
|
|
563
|
+
|
|
564
|
+
llm = ChatNVIDIA(model="meta/llama-3.1-8b-instruct")
|
|
565
|
+
chain = prompt | llm | StrOutputParser()
|
|
566
|
+
|
|
567
|
+
# 2. Session store — mỗi user một history riêng
|
|
568
|
+
session_store = {}
|
|
569
|
+
|
|
570
|
+
def get_session_history(session_id: str):
|
|
571
|
+
if session_id not in session_store:
|
|
572
|
+
session_store[session_id] = InMemoryChatMessageHistory()
|
|
573
|
+
return session_store[session_id]
|
|
574
|
+
|
|
575
|
+
# 3. Wrap chain với message history
|
|
576
|
+
chain_with_history = RunnableWithMessageHistory(
|
|
577
|
+
chain,
|
|
578
|
+
get_session_history,
|
|
579
|
+
input_messages_key="input",
|
|
580
|
+
history_messages_key="history"
|
|
581
|
+
)
|
|
582
|
+
|
|
583
|
+
# 4. Chat — cùng session_id giữ context
|
|
584
|
+
config = {"configurable": {"session_id": "user-123"}}
|
|
585
|
+
|
|
586
|
+
r1 = chain_with_history.invoke(
|
|
587
|
+
{"input": "Tên tôi là Minh"},
|
|
588
|
+
config=config
|
|
589
|
+
)
|
|
590
|
+
print(r1) # "Xin chào Minh!..."
|
|
591
|
+
|
|
592
|
+
r2 = chain_with_history.invoke(
|
|
593
|
+
{"input": "Tên tôi là gì?"},
|
|
594
|
+
config=config
|
|
595
|
+
)
|
|
596
|
+
print(r2) # "Tên bạn là Minh." ← nhớ context!
|
|
597
|
+
</code></pre>
|
|
598
|
+
|
|
599
|
+
<h3 id="6-4-window-memory">6.4. Window Memory Pattern</h3>
|
|
600
|
+
|
|
601
|
+
<pre><code class="language-text">
|
|
602
|
+
Window Memory (k=3): Chỉ giữ 3 lượt gần nhất
|
|
603
|
+
═══════════════════════════════════════════════
|
|
604
|
+
|
|
605
|
+
Turn 1: User: "Xin chào" ─┐
|
|
606
|
+
Turn 2: AI: "Chào bạn!" │ ← bị loại khi turn > 3+k
|
|
607
|
+
Turn 3: User: "Tôi là Minh" │
|
|
608
|
+
Turn 4: AI: "Chào Minh!" ─┘
|
|
609
|
+
|
|
610
|
+
Turn 5: User: "Giải thích CNN" ─┐
|
|
611
|
+
Turn 6: AI: "CNN là..." │ ← giữ lại
|
|
612
|
+
Turn 7: User: "So với RNN?" ─┘
|
|
613
|
+
|
|
614
|
+
Prompt gửi đi chỉ gồm: [System] + [Turn 5,6,7] + [Turn 8 input]
|
|
615
|
+
→ Tiết kiệm token, nhưng mất context "tên là Minh"
|
|
616
|
+
</code></pre>
|
|
617
|
+
|
|
618
|
+
<blockquote><p><strong>Exam tip:</strong> "Chatbot quên context sau vài lượt" → đang dùng <strong>BufferWindowMemory quá nhỏ</strong> hoặc không có memory. "Token limit exceeded" → chuyển sang <strong>ConversationSummaryMemory</strong> để nén lịch sử.</p></blockquote>
|
|
619
|
+
|
|
620
|
+
<h2 id="7-comparison-table">7. So sánh Inference Frameworks</h2>
|
|
621
|
+
|
|
622
|
+
<table>
|
|
623
|
+
<thead>
|
|
624
|
+
<tr><th>Feature</th><th>NVIDIA NIM</th><th>vLLM</th><th>TGI (HuggingFace)</th><th>Ollama</th></tr>
|
|
625
|
+
</thead>
|
|
626
|
+
<tbody>
|
|
627
|
+
<tr><td><strong>Backend</strong></td><td>TensorRT-LLM</td><td>PagedAttention</td><td>PyTorch + Flash</td><td>llama.cpp</td></tr>
|
|
628
|
+
<tr><td><strong>GPU Required</strong></td><td>NVIDIA (A100/H100)</td><td>NVIDIA</td><td>NVIDIA</td><td>Không (CPU OK)</td></tr>
|
|
629
|
+
<tr><td><strong>Throughput</strong></td><td>Cao nhất</td><td>Rất cao</td><td>Cao</td><td>Thấp</td></tr>
|
|
630
|
+
<tr><td><strong>Quantization</strong></td><td>FP8, INT4 tích hợp</td><td>AWQ, GPTQ</td><td>GPTQ, bitsandbytes</td><td>GGUF</td></tr>
|
|
631
|
+
<tr><td><strong>API</strong></td><td>OpenAI-compatible</td><td>OpenAI-compatible</td><td>Custom + Messages</td><td>OpenAI-compatible</td></tr>
|
|
632
|
+
<tr><td><strong>Setup</strong></td><td>Docker (NGC)</td><td>pip install</td><td>Docker</td><td>1 binary</td></tr>
|
|
633
|
+
<tr><td><strong>Best for</strong></td><td>Enterprise, production</td><td>Research, high-throughput</td><td>HF ecosystem</td><td>Local dev, laptop</td></tr>
|
|
634
|
+
<tr><td><strong>NVIDIA optimized</strong></td><td>✅ Sâu nhất</td><td>✅ Tốt</td><td>Một phần</td><td>❌</td></tr>
|
|
635
|
+
</tbody>
|
|
636
|
+
</table>
|
|
637
|
+
|
|
638
|
+
<blockquote><p><strong>Exam tip:</strong> Đề thi NVIDIA DLI sẽ ưu tiên <strong>NIM</strong> cho mọi câu hỏi deployment production. "Best performance on NVIDIA GPU" → NIM. "Quick local testing on laptop" → Ollama. "Open-source high throughput" → vLLM.</p></blockquote>
|
|
639
|
+
|
|
640
|
+
<h2 id="8-cheat-sheet">8. Cheat Sheet</h2>
|
|
641
|
+
|
|
642
|
+
<table>
|
|
643
|
+
<thead>
|
|
644
|
+
<tr><th>Concept</th><th>Key Point</th></tr>
|
|
645
|
+
</thead>
|
|
646
|
+
<tbody>
|
|
647
|
+
<tr><td>temperature = 0.0</td><td>Deterministic output (lặp lại)</td></tr>
|
|
648
|
+
<tr><td>temperature = 1.0+</td><td>Creative, random hơn</td></tr>
|
|
649
|
+
<tr><td>top_p = 0.1</td><td>Chỉ chọn token chắc chắn nhất</td></tr>
|
|
650
|
+
<tr><td>top_k = 50</td><td>Giới hạn 50 token candidates</td></tr>
|
|
651
|
+
<tr><td>NIM</td><td>Pre-optimized container, TensorRT-LLM, OpenAI API</td></tr>
|
|
652
|
+
<tr><td>LCEL pipe</td><td>prompt | llm | parser</td></tr>
|
|
653
|
+
<tr><td>RunnableParallel</td><td>Chạy nhiều chain cùng lúc</td></tr>
|
|
654
|
+
<tr><td>Gradio</td><td>Demo UI, gr.ChatInterface</td></tr>
|
|
655
|
+
<tr><td>LangServe</td><td>REST API từ LCEL chain, FastAPI</td></tr>
|
|
656
|
+
<tr><td>BufferMemory</td><td>Lưu toàn bộ history → token tăng nhanh</td></tr>
|
|
657
|
+
<tr><td>SummaryMemory</td><td>Nén history bằng LLM → tiết kiệm token</td></tr>
|
|
658
|
+
<tr><td>WindowMemory (k=N)</td><td>Giữ N lượt gần nhất</td></tr>
|
|
659
|
+
<tr><td>MessagesPlaceholder</td><td>Slot trong prompt cho chat history</td></tr>
|
|
660
|
+
<tr><td>RunnableWithMessageHistory</td><td>Wrap chain + session-based memory</td></tr>
|
|
661
|
+
</tbody>
|
|
662
|
+
</table>
|
|
663
|
+
|
|
664
|
+
<h2 id="9-practice-questions">9. Practice Questions</h2>
|
|
665
|
+
|
|
666
|
+
<p><strong>Q1: Build LCEL Chain với Streaming</strong></p>
|
|
667
|
+
<p>Viết LCEL chain dùng <code>PromptTemplate</code> → <code>ChatNVIDIA</code> → <code>StrOutputParser</code>. Prompt nhận <code>topic</code>, yêu cầu LLM giải thích topic đó. Thêm streaming output.</p>
|
|
668
|
+
|
|
669
|
+
<details>
|
|
670
|
+
<summary>Xem đáp án Q1</summary>
|
|
671
|
+
|
|
672
|
+
<pre><code class="language-python">
|
|
673
|
+
from langchain_core.prompts import ChatPromptTemplate
|
|
674
|
+
from langchain_core.output_parsers import StrOutputParser
|
|
675
|
+
from langchain_nvidia_ai_endpoints import ChatNVIDIA
|
|
676
|
+
|
|
677
|
+
# Tạo prompt template
|
|
678
|
+
prompt = ChatPromptTemplate.from_messages([
|
|
679
|
+
("system", "Bạn là giáo viên AI. Giải thích dễ hiểu."),
|
|
680
|
+
("human", "Giải thích chi tiết về: {topic}")
|
|
681
|
+
])
|
|
682
|
+
|
|
683
|
+
# Tạo LLM
|
|
684
|
+
llm = ChatNVIDIA(
|
|
685
|
+
model="meta/llama-3.1-8b-instruct",
|
|
686
|
+
temperature=0.5,
|
|
687
|
+
max_tokens=1024
|
|
688
|
+
)
|
|
689
|
+
|
|
690
|
+
# Tạo parser
|
|
691
|
+
parser = StrOutputParser()
|
|
692
|
+
|
|
693
|
+
# LCEL chain
|
|
694
|
+
chain = prompt | llm | parser
|
|
695
|
+
|
|
696
|
+
# Invoke (trả kết quả 1 lần)
|
|
697
|
+
result = chain.invoke({"topic": "Diffusion Models"})
|
|
698
|
+
print(result)
|
|
699
|
+
|
|
700
|
+
# Stream (token-by-token) — dùng .stream() thay vì .invoke()
|
|
701
|
+
for chunk in chain.stream({"topic": "Diffusion Models"}):
|
|
702
|
+
print(chunk, end="", flush=True)
|
|
703
|
+
|
|
704
|
+
# Giải thích:
|
|
705
|
+
# - .invoke() gọi chain và đợi toàn bộ output
|
|
706
|
+
# - .stream() trả về iterator, mỗi chunk là 1 phần output
|
|
707
|
+
# - StrOutputParser cho phép stream vì nó pass-through string chunks
|
|
708
|
+
# - Nếu dùng JsonOutputParser, stream sẽ trả partial JSON
|
|
709
|
+
</code></pre>
|
|
710
|
+
</details>
|
|
711
|
+
|
|
712
|
+
<p><strong>Q2: Configure NIM & So sánh Temperature</strong></p>
|
|
713
|
+
<p>Gọi NIM endpoint dùng OpenAI client. Cùng 1 prompt, so sánh output khi <code>temperature=0.0</code> vs <code>temperature=1.0</code>. Chạy mỗi cấu hình 3 lần và quan sát sự khác biệt.</p>
|
|
714
|
+
|
|
715
|
+
<details>
|
|
716
|
+
<summary>Xem đáp án Q2</summary>
|
|
717
|
+
|
|
718
|
+
<pre><code class="language-python">
|
|
719
|
+
from openai import OpenAI
|
|
720
|
+
|
|
721
|
+
# Kết nối NIM endpoint
|
|
722
|
+
client = OpenAI(
|
|
723
|
+
base_url="http://localhost:8000/v1",
|
|
724
|
+
api_key="not-used"
|
|
725
|
+
)
|
|
726
|
+
|
|
727
|
+
prompt_msg = [
|
|
728
|
+
{"role": "system", "content": "Trả lời ngắn gọn trong 1-2 câu."},
|
|
729
|
+
{"role": "user", "content": "Tại sao bầu trời có màu xanh?"}
|
|
730
|
+
]
|
|
731
|
+
|
|
732
|
+
print("=== Temperature = 0.0 (Deterministic) ===")
|
|
733
|
+
for i in range(3):
|
|
734
|
+
resp = client.chat.completions.create(
|
|
735
|
+
model="meta/llama-3.1-8b-instruct",
|
|
736
|
+
messages=prompt_msg,
|
|
737
|
+
temperature=0.0, # Luôn chọn token có xác suất cao nhất
|
|
738
|
+
max_tokens=100
|
|
739
|
+
)
|
|
740
|
+
print(f"Run {i+1}: {resp.choices[0].message.content}")
|
|
741
|
+
# → 3 lần cho output GIỐNG NHAU
|
|
742
|
+
|
|
743
|
+
print("\n=== Temperature = 1.0 (Creative) ===")
|
|
744
|
+
for i in range(3):
|
|
745
|
+
resp = client.chat.completions.create(
|
|
746
|
+
model="meta/llama-3.1-8b-instruct",
|
|
747
|
+
messages=prompt_msg,
|
|
748
|
+
temperature=1.0, # Phân phối rộng, random hơn
|
|
749
|
+
max_tokens=100
|
|
750
|
+
)
|
|
751
|
+
print(f"Run {i+1}: {resp.choices[0].message.content}")
|
|
752
|
+
# → 3 lần cho output KHÁC NHAU
|
|
753
|
+
|
|
754
|
+
# Key insight:
|
|
755
|
+
# - temp=0.0: greedy decoding, reproducible, dùng cho factual tasks
|
|
756
|
+
# - temp=1.0: sampling rộng hơn, creative, dùng cho brainstorming
|
|
757
|
+
# - NIM dùng OpenAI-compatible API nên client code giống hệt
|
|
758
|
+
</code></pre>
|
|
759
|
+
</details>
|
|
760
|
+
|
|
761
|
+
<p><strong>Q3: Multi-turn Chatbot với Memory</strong></p>
|
|
762
|
+
<p>Tạo chatbot sử dụng <code>ConversationBufferMemory</code> tích hợp vào LCEL chain thông qua <code>RunnableWithMessageHistory</code>. Bot phải nhớ tên user từ lượt trước.</p>
|
|
763
|
+
|
|
764
|
+
<details>
|
|
765
|
+
<summary>Xem đáp án Q3</summary>
|
|
766
|
+
|
|
767
|
+
<pre><code class="language-python">
|
|
768
|
+
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
|
769
|
+
from langchain_core.output_parsers import StrOutputParser
|
|
770
|
+
from langchain_core.chat_history import InMemoryChatMessageHistory
|
|
771
|
+
from langchain_core.runnables.history import RunnableWithMessageHistory
|
|
772
|
+
from langchain_nvidia_ai_endpoints import ChatNVIDIA
|
|
773
|
+
|
|
774
|
+
# 1. Prompt với history placeholder
|
|
775
|
+
prompt = ChatPromptTemplate.from_messages([
|
|
776
|
+
("system", "Bạn là trợ lý thân thiện. Nhớ thông tin user đã chia sẻ."),
|
|
777
|
+
MessagesPlaceholder(variable_name="history"),
|
|
778
|
+
("human", "{input}")
|
|
779
|
+
])
|
|
780
|
+
|
|
781
|
+
# 2. Chain
|
|
782
|
+
llm = ChatNVIDIA(model="meta/llama-3.1-8b-instruct", temperature=0.3)
|
|
783
|
+
chain = prompt | llm | StrOutputParser()
|
|
784
|
+
|
|
785
|
+
# 3. Session store
|
|
786
|
+
store = {}
|
|
787
|
+
def get_history(session_id: str):
|
|
788
|
+
if session_id not in store:
|
|
789
|
+
store[session_id] = InMemoryChatMessageHistory()
|
|
790
|
+
return store[session_id]
|
|
791
|
+
|
|
792
|
+
# 4. Wrap với message history
|
|
793
|
+
chatbot = RunnableWithMessageHistory(
|
|
794
|
+
chain,
|
|
795
|
+
get_history,
|
|
796
|
+
input_messages_key="input",
|
|
797
|
+
history_messages_key="history"
|
|
798
|
+
)
|
|
799
|
+
|
|
800
|
+
# 5. Test multi-turn
|
|
801
|
+
cfg = {"configurable": {"session_id": "demo-001"}}
|
|
802
|
+
|
|
803
|
+
print(chatbot.invoke({"input": "Tên tôi là Lan"}, config=cfg))
|
|
804
|
+
# → "Xin chào Lan! Rất vui được gặp bạn..."
|
|
805
|
+
|
|
806
|
+
print(chatbot.invoke({"input": "Tên tôi là gì?"}, config=cfg))
|
|
807
|
+
# → "Tên bạn là Lan." ← Bot nhớ context!
|
|
808
|
+
|
|
809
|
+
print(chatbot.invoke({"input": "Tôi thích machine learning"}, config=cfg))
|
|
810
|
+
# → "Tuyệt vời Lan! Machine learning là..."
|
|
811
|
+
|
|
812
|
+
# Kiểm tra history đã lưu
|
|
813
|
+
history = store["demo-001"]
|
|
814
|
+
for msg in history.messages:
|
|
815
|
+
print(f"{msg.type}: {msg.content[:50]}...")
|
|
816
|
+
</code></pre>
|
|
817
|
+
</details>
|
|
818
|
+
|
|
819
|
+
<p><strong>Q4: Gradio ChatInterface + LangChain</strong></p>
|
|
820
|
+
<p>Tạo Gradio UI chatbot sử dụng <code>gr.ChatInterface</code>, backend là LCEL chain gọi NIM. Hỗ trợ streaming response.</p>
|
|
821
|
+
|
|
822
|
+
<details>
|
|
823
|
+
<summary>Xem đáp án Q4</summary>
|
|
824
|
+
|
|
825
|
+
<pre><code class="language-python">
|
|
826
|
+
import gradio as gr
|
|
827
|
+
from langchain_core.prompts import ChatPromptTemplate
|
|
828
|
+
from langchain_core.output_parsers import StrOutputParser
|
|
829
|
+
from langchain_nvidia_ai_endpoints import ChatNVIDIA
|
|
830
|
+
|
|
831
|
+
# 1. Setup LCEL chain
|
|
832
|
+
prompt = ChatPromptTemplate.from_messages([
|
|
833
|
+
("system", "Bạn là trợ lý AI chuyên về deep learning."),
|
|
834
|
+
("human", "{message}")
|
|
835
|
+
])
|
|
836
|
+
llm = ChatNVIDIA(
|
|
837
|
+
model="meta/llama-3.1-8b-instruct",
|
|
838
|
+
temperature=0.7
|
|
839
|
+
)
|
|
840
|
+
chain = prompt | llm | StrOutputParser()
|
|
841
|
+
|
|
842
|
+
# 2. Streaming handler cho Gradio
|
|
843
|
+
def respond_stream(message, history):
|
|
844
|
+
"""
|
|
845
|
+
Gradio ChatInterface gọi function này.
|
|
846
|
+
- message: tin nhắn mới của user
|
|
847
|
+
- history: list of [user_msg, bot_msg] pairs
|
|
848
|
+
Yield từng chunk để Gradio hiển thị streaming.
|
|
849
|
+
"""
|
|
850
|
+
partial = ""
|
|
851
|
+
for chunk in chain.stream({"message": message}):
|
|
852
|
+
partial += chunk
|
|
853
|
+
yield partial # Gradio cập nhật UI mỗi lần yield
|
|
854
|
+
|
|
855
|
+
# 3. Launch Gradio app
|
|
856
|
+
demo = gr.ChatInterface(
|
|
857
|
+
fn=respond_stream,
|
|
858
|
+
title="🤖 DL Assistant (NIM-powered)",
|
|
859
|
+
description="Hỏi bất kỳ câu nào về Deep Learning",
|
|
860
|
+
examples=[
|
|
861
|
+
"Transformer hoạt động thế nào?",
|
|
862
|
+
"So sánh CNN và ViT",
|
|
863
|
+
"Batch Normalization dùng để làm gì?"
|
|
864
|
+
],
|
|
865
|
+
theme="soft"
|
|
866
|
+
)
|
|
867
|
+
|
|
868
|
+
demo.launch(server_port=7860, share=False)
|
|
869
|
+
|
|
870
|
+
# Truy cập: http://localhost:7860
|
|
871
|
+
# Gradio sẽ hiển thị streaming response real-time
|
|
872
|
+
</code></pre>
|
|
873
|
+
</details>
|
|
874
|
+
|
|
875
|
+
<p><strong>Q5: Debug — Chain trả về output rỗng</strong></p>
|
|
876
|
+
<p>Code bên dưới chạy nhưng output luôn rỗng hoặc là object không mong muốn. Tìm và sửa lỗi.</p>
|
|
877
|
+
|
|
878
|
+
<pre><code class="language-python">
|
|
879
|
+
# BUG: chain trả về AIMessage object thay vì string
|
|
880
|
+
from langchain_core.prompts import ChatPromptTemplate
|
|
881
|
+
from langchain_core.output_parsers import JsonOutputParser # ← Hmm...
|
|
882
|
+
from langchain_nvidia_ai_endpoints import ChatNVIDIA
|
|
883
|
+
|
|
884
|
+
prompt = ChatPromptTemplate.from_messages([
|
|
885
|
+
("system", "Trả lời ngắn gọn bằng tiếng Việt."),
|
|
886
|
+
("human", "{question}")
|
|
887
|
+
])
|
|
888
|
+
|
|
889
|
+
llm = ChatNVIDIA(model="meta/llama-3.1-8b-instruct")
|
|
890
|
+
chain = prompt | llm | JsonOutputParser() # ← Lỗi ở đây
|
|
891
|
+
|
|
892
|
+
result = chain.invoke({"question": "AI là gì?"})
|
|
893
|
+
print(result) # → Error hoặc output rỗng/lạ
|
|
894
|
+
</code></pre>
|
|
895
|
+
|
|
896
|
+
<details>
|
|
897
|
+
<summary>Xem đáp án Q5</summary>
|
|
898
|
+
|
|
899
|
+
<pre><code class="language-python">
|
|
900
|
+
# PHÂN TÍCH LỖI:
|
|
901
|
+
# - Prompt yêu cầu LLM trả lời bằng text thuần (tiếng Việt)
|
|
902
|
+
# - Nhưng parser là JsonOutputParser → expect JSON format
|
|
903
|
+
# - LLM trả về "AI là trí tuệ nhân tạo..." (not JSON)
|
|
904
|
+
# - JsonOutputParser cố parse → fail hoặc trả output rỗng
|
|
905
|
+
|
|
906
|
+
# SỬA: Thay JsonOutputParser bằng StrOutputParser
|
|
907
|
+
|
|
908
|
+
from langchain_core.prompts import ChatPromptTemplate
|
|
909
|
+
from langchain_core.output_parsers import StrOutputParser # ← FIX!
|
|
910
|
+
from langchain_nvidia_ai_endpoints import ChatNVIDIA
|
|
911
|
+
|
|
912
|
+
prompt = ChatPromptTemplate.from_messages([
|
|
913
|
+
("system", "Trả lời ngắn gọn bằng tiếng Việt."),
|
|
914
|
+
("human", "{question}")
|
|
915
|
+
])
|
|
916
|
+
|
|
917
|
+
llm = ChatNVIDIA(model="meta/llama-3.1-8b-instruct")
|
|
918
|
+
chain = prompt | llm | StrOutputParser() # ← StrOutputParser
|
|
919
|
+
|
|
920
|
+
result = chain.invoke({"question": "AI là gì?"})
|
|
921
|
+
print(result) # → "AI (Artificial Intelligence) là trí tuệ nhân tạo..."
|
|
922
|
+
|
|
923
|
+
# RULE: OutputParser type PHẢI match output format:
|
|
924
|
+
# - Text thuần → StrOutputParser
|
|
925
|
+
# - JSON output (prompt phải yêu cầu JSON) → JsonOutputParser
|
|
926
|
+
# - Structured output → PydanticOutputParser
|
|
927
|
+
# Nếu mismatch → chain fail silently or raise error
|
|
928
|
+
</code></pre>
|
|
929
|
+
</details>
|