hungnha commited on
Commit
794ce9a
·
1 Parent(s): 943f176

retrival chậm

Browse files
core/embeddings/chunk.py CHANGED
@@ -18,7 +18,7 @@ TABLE_ROWS_PER_CHUNK = 15
18
 
19
  # Small-to-Big Config
20
  ENABLE_TABLE_SUMMARY = True
21
- MIN_TABLE_ROWS_FOR_SUMMARY = 5 # Only summarize tables with >= 5 rows
22
  SUMMARY_MODEL = "nex-agi/DeepSeek-V3.1-Nex-N1"
23
  SILICONFLOW_BASE_URL = "https://api.siliconflow.com/v1"
24
 
@@ -27,6 +27,8 @@ COURSE_PATTERN = re.compile(r"Học\s*phần\s+(.+?)\s*\(\s*m[ãa]\s+([^\)]+)\)"
27
  TABLE_PLACEHOLDER = re.compile(r"__TBL_(\d+)__")
28
  HEADER_KEYWORDS = {'TT', 'STT', 'MÃ', 'TÊN', 'KHỐI', 'SỐ', 'ID', 'NO', '#'}
29
  FRONTMATTER_PATTERN = re.compile(r"^---\s*\n(.*?)\n---\s*\n", re.DOTALL)
 
 
30
 
31
 
32
  def _is_table_row(line: str) -> bool:
@@ -119,65 +121,118 @@ def _get_summary_client() -> Optional[OpenAI]:
119
  return _summary_client
120
 
121
 
122
- def _summarize_table(table_text: str, context_hint: str = "") -> Optional[str]:
 
 
 
 
 
 
 
 
 
 
 
123
  if not ENABLE_TABLE_SUMMARY:
124
- return None
125
 
126
  client = _get_summary_client()
127
  if client is None:
128
- return None
129
 
130
- prompt = f"""Tóm tắt ngắn gọn nội dung bảng sau trong 2-4 câu bằng tiếng Việt.
131
- Ghi rõ:
132
- - Bảng này liệt kê/quy định về cái gì
133
- - Các cột chính trong bảng
134
- - Thông tin quan trọng (nếu có số liệu cụ thể thì nêu ví dụ)
 
 
 
 
 
 
 
135
 
136
- {f"Ngữ cảnh: {context_hint}" if context_hint else ""}
 
 
 
 
 
 
 
137
 
138
  Bảng:
139
  {table_text[:3000]}
140
  """
141
 
142
- try:
143
- response = client.chat.completions.create(
144
- model=SUMMARY_MODEL,
145
- messages=[{"role": "user", "content": prompt}],
146
- temperature=0.3,
147
- max_tokens=1000,
148
- )
149
- summary = response.choices[0].message.content or ""
150
- return summary.strip() if summary.strip() else None
151
- except Exception as e:
152
- print(f" Table summarization failed: {e}")
153
- return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
 
155
 
156
  def _create_table_nodes(
157
  table_text: str,
158
  metadata: dict,
159
- context_hint: str = ""
 
 
 
160
  ) -> List[TextNode]:
 
161
  # Count rows to decide if we should summarize
162
  row_count = table_text.count("\n")
163
 
164
- if row_count < MIN_TABLE_ROWS_FOR_SUMMARY:
165
- # Table too small, just return as-is
166
- return [TextNode(text=table_text, metadata={**metadata, "is_table": True})]
 
 
 
167
 
168
- # Try to generate summary
169
- summary = _summarize_table(table_text, context_hint)
 
170
 
171
- if summary is None:
172
- # Summarization failed, return raw table
173
- return [TextNode(text=table_text, metadata={**metadata, "is_table": True})]
 
 
 
 
 
174
 
175
  # Create parent node (raw table - will NOT be embedded)
176
  parent_id = str(uuid.uuid4())
177
  parent_node = TextNode(
178
  text=table_text,
179
  metadata={
180
- **metadata,
181
  "is_table": True,
182
  "is_parent": True, # Flag to skip embedding
183
  "node_id": parent_id,
@@ -189,16 +244,19 @@ def _create_table_nodes(
189
  summary_node = TextNode(
190
  text=summary,
191
  metadata={
192
- **metadata,
193
  "is_table_summary": True,
194
  "parent_id": parent_id, # Link to parent
195
  }
196
  )
197
 
198
- print(f"Created summary for table ({row_count} rows)")
 
199
  return [parent_node, summary_node]
200
 
201
 
 
 
202
  def _enrich_metadata(node: BaseNode, source_path: Path | None) -> None:
203
  if source_path:
204
  node.metadata.update({"source_path": str(source_path), "source_file": source_path.name})
@@ -259,8 +317,20 @@ def chunk_markdown(text: str, source_path: str | Path | None = None) -> List[Bas
259
  last_end = 0
260
  for match in matches:
261
  # Text before table
262
- if (before := content[last_end:match.start()].strip()) and len(before) >= MIN_CHUNK_SIZE:
263
- nodes.extend(_chunk_text(before, meta) if len(before) > CHUNK_SIZE else [TextNode(text=before, metadata=meta.copy())])
 
 
 
 
 
 
 
 
 
 
 
 
264
 
265
  # Table chunks - using Small-to-Big pattern
266
  if (idx := int(match.group(1))) < len(tables):
@@ -270,13 +340,23 @@ def chunk_markdown(text: str, source_path: str | Path | None = None) -> List[Bas
270
  # Get context hint from header path
271
  context_hint = meta.get("Header 1", "") or meta.get("section", "")
272
 
 
 
 
273
  for i, chunk in enumerate(table_chunks):
274
  chunk_meta = {**meta}
275
  if len(table_chunks) > 1:
276
  chunk_meta["table_part"] = f"{i+1}/{len(table_chunks)}"
277
 
278
  # Create parent + summary nodes if applicable
279
- table_nodes = _create_table_nodes(chunk, chunk_meta, context_hint)
 
 
 
 
 
 
 
280
  nodes.extend(table_nodes)
281
 
282
  last_end = match.end()
@@ -284,6 +364,7 @@ def chunk_markdown(text: str, source_path: str | Path | None = None) -> List[Bas
284
  # Text after table
285
  if (after := content[last_end:].strip()) and len(after) >= MIN_CHUNK_SIZE:
286
  nodes.extend(_chunk_text(after, meta) if len(after) > CHUNK_SIZE else [TextNode(text=after, metadata=meta.copy())])
 
287
 
288
  final: List[BaseNode] = []
289
  i = 0
 
18
 
19
  # Small-to-Big Config
20
  ENABLE_TABLE_SUMMARY = True
21
+ MIN_TABLE_ROWS_FOR_SUMMARY = 0 # Summarize ALL tables regardless of size
22
  SUMMARY_MODEL = "nex-agi/DeepSeek-V3.1-Nex-N1"
23
  SILICONFLOW_BASE_URL = "https://api.siliconflow.com/v1"
24
 
 
27
  TABLE_PLACEHOLDER = re.compile(r"__TBL_(\d+)__")
28
  HEADER_KEYWORDS = {'TT', 'STT', 'MÃ', 'TÊN', 'KHỐI', 'SỐ', 'ID', 'NO', '#'}
29
  FRONTMATTER_PATTERN = re.compile(r"^---\s*\n(.*?)\n---\s*\n", re.DOTALL)
30
+ # Pattern để trích xuất số bảng và tiêu đề (ví dụ: "Bảng 3.1 Danh mục các học phần...")
31
+ TABLE_TITLE_PATTERN = re.compile(r"(?:^|\n)#+\s*(?:Bảng|BẢNG)\s*(\d+(?:\.\d+)?)\s*[.:]*\s*(.+?)(?:\n|$)", re.IGNORECASE)
32
 
33
 
34
  def _is_table_row(line: str) -> bool:
 
121
  return _summary_client
122
 
123
 
124
+ def _summarize_table(
125
+ table_text: str,
126
+ context_hint: str = "",
127
+ table_number: str = "",
128
+ table_title: str = "",
129
+ source_file: str = "",
130
+ max_retries: int = 5,
131
+ base_delay: float = 2.0
132
+ ) -> str:
133
+ """Summarize a table with retry logic. Raises exception if all retries fail."""
134
+ import time
135
+
136
  if not ENABLE_TABLE_SUMMARY:
137
+ raise RuntimeError("Table summarization is disabled but required. Set ENABLE_TABLE_SUMMARY = True")
138
 
139
  client = _get_summary_client()
140
  if client is None:
141
+ raise RuntimeError("SILICONFLOW_API_KEY not set. Cannot summarize tables.")
142
 
143
+ # Build table identifier string
144
+ table_id_parts = []
145
+ if table_number:
146
+ table_id_parts.append(f"Bảng {table_number}")
147
+ if table_title:
148
+ table_id_parts.append(f'"{table_title}"')
149
+ if source_file:
150
+ table_id_parts.append(f"từ file {source_file}")
151
+
152
+ table_identifier = " - ".join(table_id_parts) if table_id_parts else "Unknown table"
153
+
154
+ prompt = f"""Tóm tắt ngắn gọn nội dung bảng sau bằng tiếng Việt.
155
 
156
+ {f"**Thông tin bảng:** {table_identifier}" if table_identifier else ""}
157
+ {f"**Ngữ cảnh:** {context_hint}" if context_hint else ""}
158
+
159
+ **YÊU CẦU QUAN TRỌNG:**
160
+ - Bắt đầu tóm tắt bằng việc nêu rõ đây là {f"Bảng {table_number}" if table_number else "bảng nào"}{f' với tiêu đề "{table_title}"' if table_title else ""}{f" thuộc file {source_file}" if source_file else ""}
161
+ - Ghi rõ bảng này liệt kê/quy định về cái gì
162
+ - Nêu các cột chính trong bảng
163
+ - Thông tin quan trọng (nếu có số liệu cụ thể thì nêu ví dụ)
164
 
165
  Bảng:
166
  {table_text[:3000]}
167
  """
168
 
169
+ last_error = None
170
+ for attempt in range(max_retries):
171
+ try:
172
+ response = client.chat.completions.create(
173
+ model=SUMMARY_MODEL,
174
+ messages=[{"role": "user", "content": prompt}],
175
+ temperature=0.3,
176
+ max_tokens=1000,
177
+ )
178
+ summary = response.choices[0].message.content or ""
179
+ if summary.strip():
180
+ return summary.strip()
181
+ else:
182
+ raise ValueError("Empty summary returned from API")
183
+
184
+ except Exception as e:
185
+ last_error = e
186
+ delay = base_delay * (2 ** attempt) # Exponential backoff: 2, 4, 8, 16, 32 seconds
187
+ print(f"⚠️ Retry {attempt + 1}/{max_retries} for {table_identifier}: {e}")
188
+ print(f" Waiting {delay:.1f}s before retry...")
189
+ time.sleep(delay)
190
+
191
+ # All retries failed
192
+ raise RuntimeError(f"Failed to summarize {table_identifier} after {max_retries} retries. Last error: {last_error}")
193
+
194
+
195
+
196
 
197
 
198
  def _create_table_nodes(
199
  table_text: str,
200
  metadata: dict,
201
+ context_hint: str = "",
202
+ table_number: str = "",
203
+ table_title: str = "",
204
+ source_file: str = ""
205
  ) -> List[TextNode]:
206
+ """Create table nodes. For large tables, creates parent+summary nodes with retry until success."""
207
  # Count rows to decide if we should summarize
208
  row_count = table_text.count("\n")
209
 
210
+ # Add table info to metadata
211
+ table_meta = {**metadata}
212
+ if table_number:
213
+ table_meta["table_number"] = table_number
214
+ if table_title:
215
+ table_meta["table_title"] = table_title
216
 
217
+ if row_count < MIN_TABLE_ROWS_FOR_SUMMARY:
218
+ # Table too small, just return as-is (no summary needed)
219
+ return [TextNode(text=table_text, metadata={**table_meta, "is_table": True})]
220
 
221
+ # Generate summary with retry logic (will raise exception if all retries fail)
222
+ summary = _summarize_table(
223
+ table_text,
224
+ context_hint,
225
+ table_number=table_number,
226
+ table_title=table_title,
227
+ source_file=source_file
228
+ )
229
 
230
  # Create parent node (raw table - will NOT be embedded)
231
  parent_id = str(uuid.uuid4())
232
  parent_node = TextNode(
233
  text=table_text,
234
  metadata={
235
+ **table_meta,
236
  "is_table": True,
237
  "is_parent": True, # Flag to skip embedding
238
  "node_id": parent_id,
 
244
  summary_node = TextNode(
245
  text=summary,
246
  metadata={
247
+ **table_meta,
248
  "is_table_summary": True,
249
  "parent_id": parent_id, # Link to parent
250
  }
251
  )
252
 
253
+ table_id = f"Bảng {table_number}" if table_number else "table"
254
+ print(f"✅ Created summary for {table_id} ({row_count} rows)")
255
  return [parent_node, summary_node]
256
 
257
 
258
+
259
+
260
  def _enrich_metadata(node: BaseNode, source_path: Path | None) -> None:
261
  if source_path:
262
  node.metadata.update({"source_path": str(source_path), "source_file": source_path.name})
 
317
  last_end = 0
318
  for match in matches:
319
  # Text before table
320
+ before_text = content[last_end:match.start()].strip()
321
+
322
+ # Extract table number and title from text before table
323
+ table_number = ""
324
+ table_title = ""
325
+ if before_text:
326
+ # Look for patterns like "## Bảng 3.1 Danh mục các học phần..."
327
+ title_match = TABLE_TITLE_PATTERN.search(before_text)
328
+ if title_match:
329
+ table_number = title_match.group(1).strip()
330
+ table_title = title_match.group(2).strip()
331
+
332
+ if before_text and len(before_text) >= MIN_CHUNK_SIZE:
333
+ nodes.extend(_chunk_text(before_text, meta) if len(before_text) > CHUNK_SIZE else [TextNode(text=before_text, metadata=meta.copy())])
334
 
335
  # Table chunks - using Small-to-Big pattern
336
  if (idx := int(match.group(1))) < len(tables):
 
340
  # Get context hint from header path
341
  context_hint = meta.get("Header 1", "") or meta.get("section", "")
342
 
343
+ # Get source file for summary
344
+ source_file = meta.get("source_file", "") or (path.name if path else "")
345
+
346
  for i, chunk in enumerate(table_chunks):
347
  chunk_meta = {**meta}
348
  if len(table_chunks) > 1:
349
  chunk_meta["table_part"] = f"{i+1}/{len(table_chunks)}"
350
 
351
  # Create parent + summary nodes if applicable
352
+ table_nodes = _create_table_nodes(
353
+ chunk,
354
+ chunk_meta,
355
+ context_hint,
356
+ table_number=table_number,
357
+ table_title=table_title,
358
+ source_file=source_file
359
+ )
360
  nodes.extend(table_nodes)
361
 
362
  last_end = match.end()
 
364
  # Text after table
365
  if (after := content[last_end:].strip()) and len(after) >= MIN_CHUNK_SIZE:
366
  nodes.extend(_chunk_text(after, meta) if len(after) > CHUNK_SIZE else [TextNode(text=after, metadata=meta.copy())])
367
+
368
 
369
  final: List[BaseNode] = []
370
  i = 0
core/embeddings/generator.py CHANGED
@@ -1,66 +1,17 @@
1
  from __future__ import annotations
2
- import os
3
- from dataclasses import dataclass
4
- from pathlib import Path
5
- from typing import Any, Dict, Generator, List, Optional, TYPE_CHECKING
6
-
7
- from openai import OpenAI
8
 
9
  if TYPE_CHECKING:
10
  from core.embeddings.retrival import Retriever
11
 
12
 
13
- @dataclass
14
- class LLMConfig:
15
- provider: str = "siliconflow" # "siliconflow" or "groq"
16
- # SiliconFlow config
17
- siliconflow_model: str = "nex-agi/DeepSeek-V3.1-Nex-N1"
18
- siliconflow_api_base: str = "https://api.siliconflow.com/v1"
19
- # Groq config
20
- groq_model: str = "llama-3.1-8b-instant"
21
- groq_api_base: str = "https://api.groq.com/openai/v1"
22
- # Common config
23
- temperature: float = 0.0
24
- max_tokens: int = 4096
25
- max_context_chars: int = 8000
26
-
27
- @property
28
- def model(self) -> str:
29
- return self.siliconflow_model if self.provider == "siliconflow" else self.groq_model
30
-
31
- @property
32
- def api_base_url(self) -> str:
33
- return self.siliconflow_api_base if self.provider == "siliconflow" else self.groq_api_base
34
-
35
- @property
36
- def api_key_env(self) -> str:
37
- return "SILICONFLOW_API_KEY" if self.provider == "siliconflow" else "GROQ_API_KEY"
38
-
39
-
40
- # Singleton config
41
- _llm_config: LLMConfig | None = None
42
-
43
-
44
- def get_llm_config() -> LLMConfig:
45
- global _llm_config
46
- if _llm_config is None:
47
- provider = os.getenv("LLM_PROVIDER", "siliconflow").lower()
48
- _llm_config = LLMConfig(provider=provider)
49
- print(f"[LLM] Provider: {provider} | Model: {_llm_config.model}")
50
- return _llm_config
51
-
52
-
53
  SYSTEM_PROMPT = """Bạn là Trợ lý học vụ Đại học Bách khoa Hà Nội.
54
 
55
  ## NGUYÊN TẮC:
56
- 1. Chỉ trả lời dựa trên CONTEXT được cung cấp. Không suy đoán, không bổ sung thông tin ngoài CONTEXT.
57
  2. Nếu CONTEXT chứa nhiều văn bản khác nhau, ưu tiên nội dung mới nhất, TRỪ KHI có điều khoản chuyển tiếp nói khác.
58
- 3. Khi câu hỏi yêu cầu quy đổi, so sánh điều kiện hoặc xét ngưỡng:
59
- - Phải đối chiếu chính xác từng điều kiện với bảng hoặc quy định trong CONTEXT.
60
- - Không khẳng định “nằm trong khoảng” nếu không đúng.
61
- - Nếu có nhiều tiêu chí, phải nêu rõ tiêu chí quyết định kết quả cuối cùng.
62
- 4. Cuối câu trả lời, phải trích dẫn nguồn đúng theo tài liệu xuất hiện trong CONTEXT. Không tự tạo nguồn.
63
- 5. Nếu không tìm thấy thông tin trong CONTEXT, trả lời: "Không tìm thấy thông tin trong dữ liệu hiện có."
64
  """
65
 
66
 
@@ -105,103 +56,43 @@ def build_context(results: List[Dict[str, Any]], max_chars: int = 8000) -> str:
105
  return context[:max_chars] if len(context) > max_chars else context
106
 
107
 
108
- class RAGGenerator:
109
- def __init__(
110
- self,
111
- retriever: "Retriever",
112
- config: Optional[LLMConfig] = None,
113
- client: Optional[OpenAI] = None,
114
- ):
115
  self._retriever = retriever
116
- self._config = config or get_llm_config()
117
- self._llm_model = self._config.model
118
- self._temperature = self._config.temperature
119
- self._max_tokens = self._config.max_tokens
120
- self._max_context_chars = self._config.max_context_chars
121
-
122
- # Get API key based on provider
123
- api_key = (os.getenv(self._config.api_key_env) or "").strip()
124
- if not api_key and client is None:
125
- raise RuntimeError(f"Missing {self._config.api_key_env}")
126
- self._client = client or OpenAI(api_key=api_key, base_url=self._config.api_base_url)
127
 
128
- def _build_prompt(self, question: str, context: str) -> str:
129
- return f"{SYSTEM_PROMPT}\n\n## CONTEXT:\n{context}\n\n## CÂU HỎI: {question}\n\n## TRẢ LỜI:"
 
 
 
 
 
130
 
131
- def generate(self, question: str, k: int = 5, initial_k: int = 20, mode: str = "hybrid_rerank") -> Dict[str, Any]:
132
  results = self._retriever.flexible_search(question, k=k, initial_k=initial_k, mode=mode)
133
 
134
  if not results:
135
  return {
136
- "answer": "Không tìm thấy thông tin trong dữ liệu hiện có.",
137
- "contexts": [],
138
  "results": [],
 
 
 
139
  }
140
 
141
- context = build_context(results, self._max_context_chars)
142
- prompt = self._build_prompt(question, context)
143
-
144
- completion = self._client.chat.completions.create(
145
- model=self._llm_model,
146
- messages=[{"role": "user", "content": prompt}],
147
- temperature=self._temperature,
148
- max_tokens=self._max_tokens,
149
- )
150
 
151
  return {
152
- "answer": completion.choices[0].message.content or "",
153
- "contexts": [r.get("content", "")[:1000] for r in results],
154
  "results": results,
 
 
 
155
  }
156
 
157
- def generate_stream(
158
- self, question: str, k: int = 5, initial_k: int = 20
159
- ) -> Generator[str, None, None]:
160
- results = self._retriever.search_with_rerank(question, k=k, initial_k=initial_k)
161
 
162
- if not results:
163
- yield "Không tìm thấy thông tin trong dữ liệu hiện có."
164
- return
165
-
166
- context = build_context(results, self._max_context_chars)
167
- prompt = self._build_prompt(question, context)
168
-
169
- completion = self._client.chat.completions.create(
170
- model=self._llm_model,
171
- messages=[{"role": "user", "content": prompt}],
172
- temperature=self._temperature,
173
- max_tokens=self._max_tokens,
174
- stream=True,
175
- )
176
-
177
- acc = ""
178
- for chunk in completion:
179
- delta = getattr(chunk.choices[0].delta, "content", "") or ""
180
- if delta:
181
- acc += delta
182
- yield acc
183
-
184
- def generate_stream_from_results(
185
- self, question: str, results: List[Dict[str, Any]]
186
- ) -> Generator[str, None, None]:
187
- if not results:
188
- yield "Không tìm thấy thông tin trong dữ liệu hiện có."
189
- return
190
-
191
- context = build_context(results, self._max_context_chars)
192
- prompt = self._build_prompt(question, context)
193
-
194
- completion = self._client.chat.completions.create(
195
- model=self._llm_model,
196
- messages=[{"role": "user", "content": prompt}],
197
- temperature=self._temperature,
198
- max_tokens=self._max_tokens,
199
- stream=True,
200
- )
201
-
202
- acc = ""
203
- for chunk in completion:
204
- delta = getattr(chunk.choices[0].delta, "content", "") or ""
205
- if delta:
206
- acc += delta
207
- yield acc
 
1
  from __future__ import annotations
2
+ from typing import Any, Dict, List, TYPE_CHECKING
 
 
 
 
 
3
 
4
  if TYPE_CHECKING:
5
  from core.embeddings.retrival import Retriever
6
 
7
 
8
+ # System prompt để sử dụng khi gọi LLM (export cho gradio/eval dùng)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  SYSTEM_PROMPT = """Bạn là Trợ lý học vụ Đại học Bách khoa Hà Nội.
10
 
11
  ## NGUYÊN TẮC:
12
+ 1. Chỉ được đưa ra câu trả lời dựa trên CONTEXT được cung cấp. Không suy đoán, không bổ sung thông tin ngoài CONTEXT.
13
  2. Nếu CONTEXT chứa nhiều văn bản khác nhau, ưu tiên nội dung mới nhất, TRỪ KHI có điều khoản chuyển tiếp nói khác.
14
+ 3. Nếu không tìm thấy thông tin trong CONTEXT, trả lời: "Không tìm thấy thông tin trong dữ liệu hiện có."
 
 
 
 
 
15
  """
16
 
17
 
 
56
  return context[:max_chars] if len(context) > max_chars else context
57
 
58
 
59
+ def build_prompt(question: str, context: str) -> str:
60
+ return f"{SYSTEM_PROMPT}\n\n## CONTEXT:\n{context}\n\n## CÂU HỎI: {question}\n\n## TRẢ LỜI:"
61
+
62
+
63
+ class RAGContextBuilder:
64
+
65
+ def __init__(self, retriever: "Retriever", max_context_chars: int = 8000):
66
  self._retriever = retriever
67
+ self._max_context_chars = max_context_chars
 
 
 
 
 
 
 
 
 
 
68
 
69
+ def retrieve_and_prepare(
70
+ self,
71
+ question: str,
72
+ k: int = 5,
73
+ initial_k: int = 20,
74
+ mode: str = "hybrid_rerank"
75
+ ) -> Dict[str, Any]:
76
 
 
77
  results = self._retriever.flexible_search(question, k=k, initial_k=initial_k, mode=mode)
78
 
79
  if not results:
80
  return {
 
 
81
  "results": [],
82
+ "contexts": [],
83
+ "context_text": "",
84
+ "prompt": "",
85
  }
86
 
87
+ context_text = build_context(results, self._max_context_chars)
88
+ prompt = build_prompt(question, context_text)
 
 
 
 
 
 
 
89
 
90
  return {
 
 
91
  "results": results,
92
+ "contexts": [r.get("content", "")[:1000] for r in results],
93
+ "context_text": context_text,
94
+ "prompt": prompt,
95
  }
96
 
 
 
 
 
97
 
98
+ RAGGenerator = RAGContextBuilder
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
core/embeddings/retrival.py CHANGED
@@ -111,6 +111,9 @@ class SiliconFlowReranker(BaseDocumentCompressor):
111
 
112
  class Retriever:
113
  def __init__(self, vector_db: "ChromaVectorDB", use_reranker: bool = True):
 
 
 
114
  self._vector_db = vector_db
115
  self._config = get_retrieval_config()
116
  self._reranker: Optional[SiliconFlowReranker] = None
@@ -118,18 +121,76 @@ class Retriever:
118
  self._vector_retriever = self._vector_db.vectorstore.as_retriever(
119
  search_kwargs={"k": self._config.initial_k}
120
  )
121
- self._bm25_retriever = self._init_bm25()
122
- self._ensemble_retriever = self._init_ensemble()
 
 
 
 
 
 
 
 
 
 
 
123
 
124
  if use_reranker:
125
  self._reranker = self._init_reranker()
126
 
127
- self._final_retriever = self._build_final()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
 
129
  def _init_bm25(self) -> Optional[BM25Retriever]:
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  try:
 
 
 
 
131
  docs = self._vector_db.get_all_documents()
132
  if not docs:
 
133
  return None
134
 
135
  lc_docs = [
@@ -138,17 +199,37 @@ class Retriever:
138
  ]
139
  bm25 = BM25Retriever.from_documents(lc_docs)
140
  bm25.k = self._config.initial_k
 
 
 
 
 
 
 
141
  return bm25
142
- except Exception:
 
143
  return None
 
144
 
145
- def _init_ensemble(self) -> EnsembleRetriever:
146
- if self._bm25_retriever:
147
- return EnsembleRetriever(
148
- retrievers=[self._vector_retriever, self._bm25_retriever],
 
 
 
 
 
149
  weights=[self._config.vector_weight, self._config.bm25_weight]
150
  )
151
- return EnsembleRetriever(retrievers=[self._vector_retriever], weights=[1.0])
 
 
 
 
 
 
152
 
153
  def _init_reranker(self) -> Optional[SiliconFlowReranker]:
154
  api_key = os.getenv("SILICONFLOW_API_KEY", "").strip()
@@ -162,12 +243,15 @@ class Retriever:
162
  )
163
 
164
  def _build_final(self):
 
 
165
  if self._reranker:
166
  return ContextualCompressionRetriever(
167
  base_compressor=self._reranker,
168
- base_retriever=self._ensemble_retriever
169
  )
170
- return self._ensemble_retriever
 
171
 
172
  @property
173
  def has_reranker(self) -> bool:
@@ -210,29 +294,32 @@ class Retriever:
210
  def bm25_search(self, text: str, *, k: int | None = None) -> List[Dict[str, Any]]:
211
  if not text.strip():
212
  return []
213
- if not self._bm25_retriever:
 
 
214
  return self.vector_search(text, k=k)
215
 
216
  k = k or self._config.top_k
217
- self._bm25_retriever.k = k
218
- results = self._bm25_retriever.invoke(text)
219
  return [self._to_result(doc, i + 1) for i, doc in enumerate(results[:k])]
220
 
221
  def hybrid_search(
222
  self, text: str, *, k: int | None = None, initial_k: int | None = None
223
  ) -> List[Dict[str, Any]]:
224
- """Hybrid search (Vector + BM25) WITHOUT reranking."""
225
  if not text.strip():
226
  return []
227
 
228
  k = k or self._config.top_k
229
  if initial_k:
230
  self._vector_retriever.search_kwargs["k"] = initial_k
231
- if self._bm25_retriever:
232
- self._bm25_retriever.k = initial_k
 
233
 
234
- # Dùng ensemble_retriever (KHÔNG có reranker) thay vì final_retriever
235
- results = self._ensemble_retriever.invoke(text)
 
236
  return [self._to_result(doc, i + 1) for i, doc in enumerate(results[:k])]
237
 
238
  def search_with_rerank(
@@ -243,7 +330,6 @@ class Retriever:
243
  where: Optional[Dict[str, Any]] = None,
244
  initial_k: int | None = None,
245
  ) -> List[Dict[str, Any]]:
246
- """Hybrid search (Vector + BM25) WITH reranking."""
247
  if not text.strip():
248
  return []
249
 
@@ -260,13 +346,15 @@ class Retriever:
260
  for i, doc in enumerate(results[:k])
261
  ]
262
 
263
- # _final_retriever (ensemble + reranker)
264
  if initial_k:
265
  self._vector_retriever.search_kwargs["k"] = initial_k
266
- if self._bm25_retriever:
267
- self._bm25_retriever.k = initial_k
 
268
 
269
- results = self._final_retriever.invoke(text)
 
270
  return [
271
  self._to_result(doc, i + 1, rerank_score=doc.metadata.get("rerank_score"))
272
  for i, doc in enumerate(results[:k])
 
111
 
112
  class Retriever:
113
  def __init__(self, vector_db: "ChromaVectorDB", use_reranker: bool = True):
114
+ import time
115
+ start = time.time()
116
+
117
  self._vector_db = vector_db
118
  self._config = get_retrieval_config()
119
  self._reranker: Optional[SiliconFlowReranker] = None
 
121
  self._vector_retriever = self._vector_db.vectorstore.as_retriever(
122
  search_kwargs={"k": self._config.initial_k}
123
  )
124
+
125
+ # Lazy-load BM25 - only initialize when needed
126
+ self._bm25_retriever: Optional[BM25Retriever] = None
127
+ self._bm25_initialized = False
128
+ self._ensemble_retriever: Optional[EnsembleRetriever] = None
129
+
130
+ # BM25 cache path (persist to disk)
131
+ from pathlib import Path
132
+ persist_dir = getattr(self._vector_db.config, 'persist_dir', None)
133
+ if persist_dir:
134
+ self._bm25_cache_path = Path(persist_dir) / "bm25_cache.pkl"
135
+ else:
136
+ self._bm25_cache_path = None
137
 
138
  if use_reranker:
139
  self._reranker = self._init_reranker()
140
 
141
+ logger.info(f"Retriever initialized in {time.time() - start:.2f}s (BM25 lazy-loaded)")
142
+
143
+ def _save_bm25_cache(self, bm25: BM25Retriever) -> None:
144
+ """Save BM25 retriever to disk for fast loading."""
145
+ if not self._bm25_cache_path:
146
+ return
147
+ try:
148
+ import pickle
149
+ with open(self._bm25_cache_path, 'wb') as f:
150
+ pickle.dump(bm25, f)
151
+ logger.info(f"BM25 cache saved to {self._bm25_cache_path}")
152
+ except Exception as e:
153
+ logger.warning(f"Failed to save BM25 cache: {e}")
154
+
155
+ def _load_bm25_cache(self) -> Optional[BM25Retriever]:
156
+ """Load BM25 retriever from disk cache."""
157
+ if not self._bm25_cache_path or not self._bm25_cache_path.exists():
158
+ return None
159
+ try:
160
+ import pickle
161
+ import time
162
+ start = time.time()
163
+ with open(self._bm25_cache_path, 'rb') as f:
164
+ bm25 = pickle.load(f)
165
+ bm25.k = self._config.initial_k
166
+ logger.info(f"BM25 loaded from cache in {time.time() - start:.2f}s")
167
+ return bm25
168
+ except Exception as e:
169
+ logger.warning(f"Failed to load BM25 cache: {e}")
170
+ return None
171
 
172
  def _init_bm25(self) -> Optional[BM25Retriever]:
173
+ """Initialize BM25 retriever (lazy-loaded, with disk cache)."""
174
+ if self._bm25_initialized:
175
+ return self._bm25_retriever
176
+
177
+ self._bm25_initialized = True
178
+
179
+ # Try loading from cache first
180
+ cached = self._load_bm25_cache()
181
+ if cached:
182
+ self._bm25_retriever = cached
183
+ return cached
184
+
185
+ # Build from scratch
186
  try:
187
+ import time
188
+ start = time.time()
189
+ logger.info("Building BM25 index from documents...")
190
+
191
  docs = self._vector_db.get_all_documents()
192
  if not docs:
193
+ logger.warning("No documents found for BM25")
194
  return None
195
 
196
  lc_docs = [
 
199
  ]
200
  bm25 = BM25Retriever.from_documents(lc_docs)
201
  bm25.k = self._config.initial_k
202
+
203
+ self._bm25_retriever = bm25
204
+ logger.info(f"BM25 built with {len(docs)} docs in {time.time() - start:.2f}s")
205
+
206
+ # Save to cache for next time
207
+ self._save_bm25_cache(bm25)
208
+
209
  return bm25
210
+ except Exception as e:
211
+ logger.error(f"Failed to init BM25: {e}")
212
  return None
213
+
214
 
215
+ def _get_ensemble_retriever(self) -> EnsembleRetriever:
216
+ """Get or create ensemble retriever (lazy-loaded)."""
217
+ if self._ensemble_retriever is not None:
218
+ return self._ensemble_retriever
219
+
220
+ bm25 = self._init_bm25()
221
+ if bm25:
222
+ self._ensemble_retriever = EnsembleRetriever(
223
+ retrievers=[self._vector_retriever, bm25],
224
  weights=[self._config.vector_weight, self._config.bm25_weight]
225
  )
226
+ else:
227
+ self._ensemble_retriever = EnsembleRetriever(
228
+ retrievers=[self._vector_retriever],
229
+ weights=[1.0]
230
+ )
231
+ return self._ensemble_retriever
232
+
233
 
234
  def _init_reranker(self) -> Optional[SiliconFlowReranker]:
235
  api_key = os.getenv("SILICONFLOW_API_KEY", "").strip()
 
243
  )
244
 
245
  def _build_final(self):
246
+ """Build final retriever with reranker (lazy-loaded)."""
247
+ ensemble = self._get_ensemble_retriever()
248
  if self._reranker:
249
  return ContextualCompressionRetriever(
250
  base_compressor=self._reranker,
251
+ base_retriever=ensemble
252
  )
253
+ return ensemble
254
+
255
 
256
  @property
257
  def has_reranker(self) -> bool:
 
294
  def bm25_search(self, text: str, *, k: int | None = None) -> List[Dict[str, Any]]:
295
  if not text.strip():
296
  return []
297
+
298
+ bm25 = self._init_bm25() # Lazy-load BM25
299
+ if not bm25:
300
  return self.vector_search(text, k=k)
301
 
302
  k = k or self._config.top_k
303
+ bm25.k = k
304
+ results = bm25.invoke(text)
305
  return [self._to_result(doc, i + 1) for i, doc in enumerate(results[:k])]
306
 
307
  def hybrid_search(
308
  self, text: str, *, k: int | None = None, initial_k: int | None = None
309
  ) -> List[Dict[str, Any]]:
 
310
  if not text.strip():
311
  return []
312
 
313
  k = k or self._config.top_k
314
  if initial_k:
315
  self._vector_retriever.search_kwargs["k"] = initial_k
316
+ bm25 = self._init_bm25()
317
+ if bm25:
318
+ bm25.k = initial_k
319
 
320
+ # Dùng ensemble_retriever (lazy-loaded, KHÔNG có reranker)
321
+ ensemble = self._get_ensemble_retriever()
322
+ results = ensemble.invoke(text)
323
  return [self._to_result(doc, i + 1) for i, doc in enumerate(results[:k])]
324
 
325
  def search_with_rerank(
 
330
  where: Optional[Dict[str, Any]] = None,
331
  initial_k: int | None = None,
332
  ) -> List[Dict[str, Any]]:
 
333
  if not text.strip():
334
  return []
335
 
 
346
  for i, doc in enumerate(results[:k])
347
  ]
348
 
349
+ # Build final retriever (lazy-loaded ensemble + reranker)
350
  if initial_k:
351
  self._vector_retriever.search_kwargs["k"] = initial_k
352
+ bm25 = self._init_bm25()
353
+ if bm25:
354
+ bm25.k = initial_k
355
 
356
+ final_retriever = self._build_final()
357
+ results = final_retriever.invoke(text)
358
  return [
359
  self._to_result(doc, i + 1, rerank_score=doc.metadata.get("rerank_score"))
360
  for i, doc in enumerate(results[:k])
core/embeddings/vector_store.py CHANGED
@@ -44,7 +44,6 @@ class ChromaVectorDB:
44
  logger.info(f"ChromaVectorDB initialized: {self.config.collection_name}")
45
 
46
  def _load_parent_nodes(self) -> Dict[str, Dict[str, Any]]:
47
- """Load parent nodes from JSON file if exists."""
48
  if self._parent_nodes_path.exists():
49
  try:
50
  with open(self._parent_nodes_path, 'r', encoding='utf-8') as f:
@@ -284,30 +283,6 @@ class ChromaVectorDB:
284
  logger.info(f"Deleted {len(ids)} documents from vector store")
285
  return len(ids)
286
 
287
- def delete_parent_nodes_by_source(self, source_basename: str) -> int:
288
- if not self._parent_nodes:
289
- return 0
290
-
291
- # Find parent nodes that belong to this source file
292
- keys_to_delete = []
293
- for key, node in self._parent_nodes.items():
294
- meta = node.get("metadata", {})
295
- node_source = meta.get("source_file", "") or meta.get("source_basename", "")
296
- if source_basename in node_source or node_source.endswith(source_basename):
297
- keys_to_delete.append(key)
298
-
299
- if not keys_to_delete:
300
- return 0
301
-
302
- # Delete the parent nodes
303
- for key in keys_to_delete:
304
- del self._parent_nodes[key]
305
-
306
- # Persist changes
307
- self._save_parent_nodes()
308
- logger.info(f"Deleted {len(keys_to_delete)} parent nodes for: {source_basename}")
309
- return len(keys_to_delete)
310
-
311
  def get_parent_node(self, parent_id: str) -> Optional[Dict[str, Any]]:
312
  return self._parent_nodes.get(parent_id)
313
 
 
44
  logger.info(f"ChromaVectorDB initialized: {self.config.collection_name}")
45
 
46
  def _load_parent_nodes(self) -> Dict[str, Dict[str, Any]]:
 
47
  if self._parent_nodes_path.exists():
48
  try:
49
  with open(self._parent_nodes_path, 'r', encoding='utf-8') as f:
 
283
  logger.info(f"Deleted {len(ids)} documents from vector store")
284
  return len(ids)
285
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
286
  def get_parent_node(self, parent_id: str) -> Optional[Dict[str, Any]]:
287
  return self._parent_nodes.get(parent_id)
288
 
core/gradio/gradio_rag_qwen.py CHANGED
@@ -26,16 +26,19 @@ def _load_env() -> None:
26
  from core.embeddings.embedding_model import EmbeddingConfig, QwenEmbeddings
27
  from core.embeddings.vector_store import ChromaConfig, ChromaVectorDB
28
  from core.embeddings.retrival import Retriever, RetrievalMode, get_retrieval_config
29
- from core.embeddings.generator import RAGGenerator, LLMConfig, get_llm_config
30
 
31
  _load_env()
32
 
33
- RETRIEVAL_MODE = RetrievalMode.HYBRID_RERANK
34
 
 
 
 
 
35
 
36
- # Load all configs
37
  GRADIO_CFG = GradioConfig()
38
- LLM_CFG = get_llm_config()
39
  RETRIEVAL_CFG = get_retrieval_config()
40
 
41
 
@@ -43,7 +46,7 @@ class AppState:
43
  def __init__(self) -> None:
44
  self.db: Optional[ChromaVectorDB] = None
45
  self.retriever: Optional[Retriever] = None
46
- self.generator: Optional[RAGGenerator] = None
47
  self.client: Optional[OpenAI] = None
48
 
49
 
@@ -67,46 +70,77 @@ def _init_resources() -> None:
67
  )
68
  STATE.retriever = Retriever(vector_db=STATE.db)
69
 
70
- api_key = (os.getenv(LLM_CFG.api_key_env) or "").strip()
 
71
  if not api_key:
72
- raise RuntimeError(f"Missing {LLM_CFG.api_key_env}")
73
- STATE.client = OpenAI(api_key=api_key, base_url=LLM_CFG.api_base_url)
74
 
75
- # Initialize RAGGenerator with shared config
76
- STATE.generator = RAGGenerator(
77
- retriever=STATE.retriever,
78
- config=LLM_CFG,
79
- client=STATE.client,
80
- )
81
 
82
  print(" Đã sẵn sàng!")
83
 
84
 
85
  def rag_chat(message: str, history: List[Dict[str, str]] | None = None):
 
 
 
 
86
  _init_resources()
 
87
 
88
  assert STATE.db is not None
89
  assert STATE.client is not None
90
  assert STATE.retriever is not None
91
- assert STATE.generator is not None
92
 
93
- # Flexible search
94
- results = STATE.retriever.flexible_search(
 
95
  message,
96
- mode=RETRIEVAL_MODE,
97
  k=RETRIEVAL_CFG.top_k,
98
  initial_k=RETRIEVAL_CFG.initial_k,
 
99
  )
 
 
100
 
101
  if not results:
102
  yield "Xin lỗi, tôi không tìm thấy thông tin phù hợp trong dữ liệu."
103
  return
104
 
105
- # Use RAGGenerator for streaming response
 
 
 
 
 
 
 
 
 
106
  acc = ""
107
- for partial in STATE.generator.generate_stream_from_results(message, results):
108
- acc = partial
109
- yield acc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
 
111
  # Debug info with mode indicator
112
  debug_info = f"\n\n---\n\n**Retrieved (Top {len(results)} | Mode: {RETRIEVAL_MODE.value})**\n\n"
@@ -148,7 +182,8 @@ def rag_chat(message: str, history: List[Dict[str, str]] | None = None):
148
  debug_info += f" - **Mục:** {header[:80]}{'...' if len(header) > 80 else ''}\n"
149
  debug_info += f" - **Content:** {content[:200]}{'...' if len(content) > 200 else ''}\n\n"
150
 
151
- yield acc + debug_info
 
152
 
153
 
154
  # Create Gradio interface
 
26
  from core.embeddings.embedding_model import EmbeddingConfig, QwenEmbeddings
27
  from core.embeddings.vector_store import ChromaConfig, ChromaVectorDB
28
  from core.embeddings.retrival import Retriever, RetrievalMode, get_retrieval_config
29
+ from core.embeddings.generator import RAGContextBuilder, build_context, build_prompt, SYSTEM_PROMPT
30
 
31
  _load_env()
32
 
33
+ RETRIEVAL_MODE = RetrievalMode.VECTOR_ONLY # Fastest mode - no BM25/reranker
34
 
35
+ # LLM Config (hardcoded sau khi xóa LLMConfig từ generator)
36
+ LLM_MODEL = os.getenv("LLM_MODEL", "qwen/qwen3-32b")
37
+ LLM_API_BASE = "https://api.groq.com/openai/v1"
38
+ LLM_API_KEY_ENV = "GROQ_API_KEY"
39
 
40
+ # Load retrieval config
41
  GRADIO_CFG = GradioConfig()
 
42
  RETRIEVAL_CFG = get_retrieval_config()
43
 
44
 
 
46
  def __init__(self) -> None:
47
  self.db: Optional[ChromaVectorDB] = None
48
  self.retriever: Optional[Retriever] = None
49
+ self.rag_builder: Optional[RAGContextBuilder] = None
50
  self.client: Optional[OpenAI] = None
51
 
52
 
 
70
  )
71
  STATE.retriever = Retriever(vector_db=STATE.db)
72
 
73
+ # LLM Client
74
+ api_key = (os.getenv(LLM_API_KEY_ENV) or "").strip()
75
  if not api_key:
76
+ raise RuntimeError(f"Missing {LLM_API_KEY_ENV}")
77
+ STATE.client = OpenAI(api_key=api_key, base_url=LLM_API_BASE)
78
 
79
+ # RAGContextBuilder - chỉ retrieve, không gọi LLM
80
+ STATE.rag_builder = RAGContextBuilder(retriever=STATE.retriever)
 
 
 
 
81
 
82
  print(" Đã sẵn sàng!")
83
 
84
 
85
  def rag_chat(message: str, history: List[Dict[str, str]] | None = None):
86
+ import time
87
+ total_start = time.time()
88
+
89
+ init_start = time.time()
90
  _init_resources()
91
+ init_time = time.time() - init_start
92
 
93
  assert STATE.db is not None
94
  assert STATE.client is not None
95
  assert STATE.retriever is not None
96
+ assert STATE.rag_builder is not None
97
 
98
+ # Bước 1: Retrieve và prepare context
99
+ retrieval_start = time.time()
100
+ prepared = STATE.rag_builder.retrieve_and_prepare(
101
  message,
 
102
  k=RETRIEVAL_CFG.top_k,
103
  initial_k=RETRIEVAL_CFG.initial_k,
104
+ mode=RETRIEVAL_MODE.value,
105
  )
106
+ retrieval_time = time.time() - retrieval_start
107
+ results = prepared["results"]
108
 
109
  if not results:
110
  yield "Xin lỗi, tôi không tìm thấy thông tin phù hợp trong dữ liệu."
111
  return
112
 
113
+ # Bước 2: Gọi LLM streaming để generate answer
114
+ llm_start = time.time()
115
+ completion = STATE.client.chat.completions.create(
116
+ model=LLM_MODEL,
117
+ messages=[{"role": "user", "content": prepared["prompt"]}],
118
+ temperature=0.0,
119
+ max_tokens=4096,
120
+ stream=True,
121
+ )
122
+
123
  acc = ""
124
+ first_token_time = None
125
+ for chunk in completion:
126
+ if first_token_time is None:
127
+ first_token_time = time.time() - llm_start
128
+ delta = getattr(chunk.choices[0].delta, "content", "") or ""
129
+ if delta:
130
+ acc += delta
131
+ yield acc
132
+
133
+ llm_time = time.time() - llm_start
134
+ total_time = time.time() - total_start
135
+
136
+ # Timing info
137
+ timing_info = f"\n\n---\n**⏱️ Timing:**\n"
138
+ timing_info += f"- Init: {init_time:.2f}s\n"
139
+ timing_info += f"- Retrieval: {retrieval_time:.2f}s\n"
140
+ timing_info += f"- LLM (first token): {first_token_time:.2f}s\n" if first_token_time else ""
141
+ timing_info += f"- LLM (total): {llm_time:.2f}s\n"
142
+ timing_info += f"- **Total: {total_time:.2f}s**\n"
143
+
144
 
145
  # Debug info with mode indicator
146
  debug_info = f"\n\n---\n\n**Retrieved (Top {len(results)} | Mode: {RETRIEVAL_MODE.value})**\n\n"
 
182
  debug_info += f" - **Mục:** {header[:80]}{'...' if len(header) > 80 else ''}\n"
183
  debug_info += f" - **Content:** {content[:200]}{'...' if len(content) > 200 else ''}\n\n"
184
 
185
+ yield acc + timing_info + debug_info
186
+
187
 
188
 
189
  # Create Gradio interface
data/data_process/quyet_dinh/tieng_anh/06_ Quy định ngoại ngữ từ K70_chính quy_final.md CHANGED
@@ -2,7 +2,7 @@
2
  document_type: "quyet_dinh"
3
  title: "QUY ĐỊNH Phân loại trình độ đầu vào , chương trình ngoại ngữ cơ bản và chuẩn ngoại ngữ yêu cầu đối với sinh viên đại học hình thức chính quy từ k70"
4
  issued_year: "2025"
5
- applicable_cohorts: "K70"
6
  ---
7
 
8
  # QUY ĐỊNH Phân loại trình độ đầu vào , chương trình ngoại ngữ cơ bản và chuẩn ngoại ngữ yêu cầu đối với sinh viên đại học hình thức chính quy
 
2
  document_type: "quyet_dinh"
3
  title: "QUY ĐỊNH Phân loại trình độ đầu vào , chương trình ngoại ngữ cơ bản và chuẩn ngoại ngữ yêu cầu đối với sinh viên đại học hình thức chính quy từ k70"
4
  issued_year: "2025"
5
+ applicable_cohorts: ">=K70"
6
  ---
7
 
8
  # QUY ĐỊNH Phân loại trình độ đầu vào , chương trình ngoại ngữ cơ bản và chuẩn ngoại ngữ yêu cầu đối với sinh viên đại học hình thức chính quy
data/data_process/quyet_dinh/tieng_anh/QD_ngoai_ngu_tu_K65_CQ_final.md CHANGED
@@ -1,8 +1,8 @@
1
  ---
2
  document_type: "quyet_dinh"
3
- title: "QUY ĐỊNH Phân loại trình độ đầu vào, chương trình môn học và chuẩn ngoại ngữ yêu cầu đối với sinh viên đại học hệ chính quy"
4
  issued_year: "2020"
5
- applicable_cohorts: "K65"
6
  ---
7
 
8
  # QUY ĐỊNH Phân loại trình độ đầu vào, chương trình môn học và chuẩn ngoại ngữ yêu cầu đối với sinh viên đại học hệ chính quy
 
1
  ---
2
  document_type: "quyet_dinh"
3
+ title: "QUY ĐỊNH Phân loại trình độ đầu vào, chương trình môn học và chuẩn ngoại ngữ yêu cầu đối với sinh viên đại học hệ chính quy từ K65"
4
  issued_year: "2020"
5
+ applicable_cohorts: ">=K65"
6
  ---
7
 
8
  # QUY ĐỊNH Phân loại trình độ đầu vào, chương trình môn học và chuẩn ngoại ngữ yêu cầu đối với sinh viên đại học hệ chính quy
data/data_process/quyet_dinh/tieng_anh/QD_ngoai_ngu_tu_K68_CQ_final.md CHANGED
@@ -2,7 +2,7 @@
2
  document_type: "quyet_dinh"
3
  title: "QUY ĐỊNH Về việc ban hành Quy định về phân loại trình độ đầu vào, chương trình môn học và chuẩn ngoại ngữ yêu cầu đối với sinh viên đại học hệ chính quy từ k68"
4
  issued_year: "2023"
5
- applicable_cohorts: "K68"
6
  ---
7
 
8
  # QUYẾT ĐỊNH Về việc ban hành Quy định về phân loại trình độ đầu vào, chương trình môn học và chuẩn ngoại ngữ yêu cầu đối với sinh viên đại học hệ chính quy từ k68
 
2
  document_type: "quyet_dinh"
3
  title: "QUY ĐỊNH Về việc ban hành Quy định về phân loại trình độ đầu vào, chương trình môn học và chuẩn ngoại ngữ yêu cầu đối với sinh viên đại học hệ chính quy từ k68"
4
  issued_year: "2023"
5
+ applicable_cohorts: ">=K68"
6
  ---
7
 
8
  # QUYẾT ĐỊNH Về việc ban hành Quy định về phân loại trình độ đầu vào, chương trình môn học và chuẩn ngoại ngữ yêu cầu đối với sinh viên đại học hệ chính quy từ k68
evaluation/__init__.py ADDED
File without changes
evaluation/eval_utils.py CHANGED
@@ -26,8 +26,22 @@ def strip_thinking(text: str) -> str:
26
 
27
  def load_config() -> dict:
28
  return {
29
- "llm": {
 
 
 
 
 
 
 
30
  "model": os.getenv("EVAL_LLM_MODEL", "nex-agi/DeepSeek-V3.1-Nex-N1"),
 
 
 
 
 
 
 
31
  "temperature": float(os.getenv("EVAL_LLM_TEMPERATURE", "0")),
32
  "timeout": int(os.getenv("EVAL_LLM_TIMEOUT", "30")),
33
  "max_retries": int(os.getenv("EVAL_LLM_MAX_RETRIES", "2")),
@@ -63,7 +77,9 @@ def load_csv_data(csv_path: str, sample_size: int = 0) -> tuple[list, list]:
63
  return questions, ground_truths
64
 
65
 
66
- def init_rag_components(config: dict) -> tuple[RAGGenerator, dict]:
 
 
67
  emb_cfg = SiliconFlowConfig()
68
  qwen_embeddings = QwenEmbeddings(emb_cfg)
69
 
@@ -71,42 +87,114 @@ def init_rag_components(config: dict) -> tuple[RAGGenerator, dict]:
71
  db = ChromaVectorDB(embedder=qwen_embeddings, config=db_cfg)
72
  retriever = Retriever(vector_db=db)
73
 
74
- # RAGGenerator uses Groq with llama-3.1-8b-instant (default)
75
- rag_generator = RAGGenerator(retriever=retriever)
 
 
 
 
 
 
 
 
76
 
77
  info = {
78
- "gen_model": rag_generator._llm_model, # Get actual model from RAGGenerator
79
  "eval_model": config["llm"]["model"],
80
  "embed_model": emb_cfg.model,
81
  "collection": db_cfg.collection_name,
82
  "doc_count": db.count(),
83
  "embeddings": qwen_embeddings,
 
84
  }
85
 
86
- return rag_generator, info
87
 
88
 
89
  def generate_answers(
90
- rag_generator: RAGGenerator,
91
  questions: list,
92
- top_k: int = 5,
93
- initial_k: int = 100,
94
  retrieval_mode: str = "hybrid_rerank",
 
 
 
 
95
  ) -> tuple[list, list]:
96
- answers, contexts = [], []
97
 
98
- for i, q in enumerate(questions):
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  try:
100
- result = rag_generator.generate(q, k=top_k, initial_k=initial_k, mode=retrieval_mode)
101
- # Strip <think>...</think> tags from answer
102
- answer = strip_thinking(result["answer"])
103
- answers.append(answer)
104
- contexts.append(result["contexts"])
 
 
 
 
 
 
 
 
 
 
105
  except Exception as e:
106
- print(f" Error at {i+1}: {e}")
107
- answers.append("Không thể trả lời.")
108
- contexts.append([])
109
- print(f" [{i+1}/{len(questions)}] Done")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
 
111
  return answers, contexts
112
 
 
26
 
27
  def load_config() -> dict:
28
  return {
29
+ # Model for generating RAG answers
30
+ "gen_llm": {
31
+ "model": os.getenv("GEN_LLM_MODEL", "nex-agi/DeepSeek-V3.1-Nex-N1"),
32
+ "temperature": float(os.getenv("GEN_LLM_TEMPERATURE", "0")),
33
+ "max_tokens": int(os.getenv("GEN_LLM_MAX_TOKENS", "4096")),
34
+ },
35
+ # Model for RAGAS evaluation (should be DIFFERENT from gen_llm to avoid bias)
36
+ "eval_llm": {
37
  "model": os.getenv("EVAL_LLM_MODEL", "nex-agi/DeepSeek-V3.1-Nex-N1"),
38
+ "api_key_env": os.getenv("EVAL_API_KEY_ENV", "SILICONFLOW_API_KEY"), # Which env var has the API key
39
+ "base_url": os.getenv("EVAL_API_BASE_URL", "https://api.siliconflow.com/v1"),
40
+ "temperature": float(os.getenv("EVAL_LLM_TEMPERATURE", "0")),
41
+ },
42
+ # Legacy compatibility (deprecated, use gen_llm instead)
43
+ "llm": {
44
+ "model": os.getenv("GEN_LLM_MODEL", os.getenv("EVAL_LLM_MODEL", "nex-agi/DeepSeek-V3.1-Nex-N1")),
45
  "temperature": float(os.getenv("EVAL_LLM_TEMPERATURE", "0")),
46
  "timeout": int(os.getenv("EVAL_LLM_TIMEOUT", "30")),
47
  "max_retries": int(os.getenv("EVAL_LLM_MAX_RETRIES", "2")),
 
77
  return questions, ground_truths
78
 
79
 
80
+ def init_rag_components(config: dict) -> tuple:
81
+ from openai import OpenAI
82
+
83
  emb_cfg = SiliconFlowConfig()
84
  qwen_embeddings = QwenEmbeddings(emb_cfg)
85
 
 
87
  db = ChromaVectorDB(embedder=qwen_embeddings, config=db_cfg)
88
  retriever = Retriever(vector_db=db)
89
 
90
+ rag_builder = RAGGenerator(retriever=retriever)
91
+
92
+ api_key = os.getenv("SILICONFLOW_API_KEY", "").strip()
93
+ if not api_key:
94
+ raise ValueError("Missing SILICONFLOW_API_KEY")
95
+
96
+ llm_client = OpenAI(
97
+ api_key=api_key,
98
+ base_url="https://api.siliconflow.com/v1",
99
+ )
100
 
101
  info = {
102
+ "gen_model": config["llm"]["model"],
103
  "eval_model": config["llm"]["model"],
104
  "embed_model": emb_cfg.model,
105
  "collection": db_cfg.collection_name,
106
  "doc_count": db.count(),
107
  "embeddings": qwen_embeddings,
108
+ "llm_client": llm_client,
109
  }
110
 
111
+ return rag_builder, info
112
 
113
 
114
  def generate_answers(
115
+ rag_builder: RAGGenerator,
116
  questions: list,
 
 
117
  retrieval_mode: str = "hybrid_rerank",
118
+ max_workers: int = 8, # SiliconFlow allows 1000 RPM, safe to use 8 workers
119
+ llm_client = None,
120
+ llm_model: str = "nex-agi/DeepSeek-V3.1-Nex-N1",
121
+ timeout_per_question: int = 120, # 2 minutes timeout per question
122
  ) -> tuple[list, list]:
123
+ from concurrent.futures import ThreadPoolExecutor, as_completed, TimeoutError
124
 
125
+ if llm_client is None:
126
+ from openai import OpenAI
127
+ api_key = os.getenv("SILICONFLOW_API_KEY", "").strip()
128
+ if not api_key:
129
+ raise ValueError("Missing SILICONFLOW_API_KEY")
130
+ llm_client = OpenAI(
131
+ api_key=api_key,
132
+ base_url="https://api.siliconflow.com/v1",
133
+ timeout=60.0, # 60 seconds timeout for API call
134
+ )
135
+
136
+ def process_question(idx_q: tuple) -> tuple:
137
+ """Process a single question and return (idx, answer, contexts, error, retrieval_empty)"""
138
+ idx, q = idx_q
139
  try:
140
+ prepared = rag_builder.retrieve_and_prepare(q, mode=retrieval_mode)
141
+
142
+ if not prepared["results"]:
143
+ # Mark retrieval as failed for debugging RAG vs LLM issues
144
+ return idx, "Không tìm thấy thông tin trong dữ liệu hiện có.", [], None, True
145
+
146
+ completion = llm_client.chat.completions.create(
147
+ model=llm_model,
148
+ messages=[{"role": "user", "content": prepared["prompt"]}],
149
+ temperature=0.0,
150
+ max_tokens=4096,
151
+ )
152
+
153
+ answer = strip_thinking(completion.choices[0].message.content or "")
154
+ return idx, answer, prepared["contexts"], None, False
155
  except Exception as e:
156
+ return idx, "Không thể trả lời.", [], str(e), False
157
+
158
+ n = len(questions)
159
+ answers: list[str] = [""] * n
160
+ contexts: list[list] = [[] for _ in range(n)] # FIXED: [[]] * n creates shared references!
161
+ retrieval_failed: list[bool] = [False] * n # Track retrieval failures for debugging
162
+ errors: list[str | None] = [None] * n # Track error messages
163
+
164
+ print(f" Generating answers with {max_workers} workers...")
165
+
166
+ with ThreadPoolExecutor(max_workers=max_workers) as executor:
167
+ futures = {executor.submit(process_question, (i, q)): i for i, q in enumerate(questions)}
168
+ done_count = 0
169
+
170
+ for future in as_completed(futures):
171
+ try:
172
+ # Use timeout_per_question for actual timeout enforcement
173
+ idx, answer, ctx, error, is_retrieval_empty = future.result(timeout=timeout_per_question)
174
+ answers[idx] = answer
175
+ contexts[idx] = ctx
176
+ retrieval_failed[idx] = is_retrieval_empty
177
+ errors[idx] = error
178
+ done_count += 1
179
+
180
+ if error:
181
+ print(f" [{done_count}/{n}] Q{idx+1}: Error - {error}")
182
+ elif is_retrieval_empty:
183
+ print(f" [{done_count}/{n}] Q{idx+1}: Done (⚠️ no retrieval results)")
184
+ else:
185
+ print(f" [{done_count}/{n}] Q{idx+1}: Done")
186
+ except TimeoutError:
187
+ idx = futures[future]
188
+ answers[idx] = "Timeout: Không thể xử lý câu hỏi trong thời gian cho phép."
189
+ contexts[idx] = []
190
+ errors[idx] = f"Timeout after {timeout_per_question}s"
191
+ done_count += 1
192
+ print(f" [{done_count}/{n}] Q{idx+1}: TIMEOUT")
193
+
194
+ # Log summary of retrieval failures
195
+ failed_count = sum(retrieval_failed)
196
+ if failed_count > 0:
197
+ print(f" ⚠️ {failed_count}/{n} questions had empty retrieval results")
198
 
199
  return answers, contexts
200
 
evaluation/ragas_eval.py CHANGED
@@ -31,16 +31,31 @@ def run_ragas_evaluation(sample_size: int = 10, output_dir: Optional[str] = None
31
  # Init components
32
  rag_gen, info = init_rag_components(config)
33
 
34
- # LLM for RAGAS evaluation
35
- api_key = os.getenv("SILICONFLOW_API_KEY", "")
36
- if not api_key:
37
- raise ValueError("Missing SILICONFLOW_API_KEY")
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  evaluator_llm = LangchainLLMWrapper(ChatOpenAI(
40
- model=config["llm"]["model"],
41
- api_key=lambda: api_key, # type: ignore
42
- base_url="https://api.siliconflow.com/v1",
43
- temperature=config["llm"]["temperature"],
 
 
44
  ))
45
  evaluator_embeddings = LangchainEmbeddingsWrapper(info["embeddings"])
46
 
@@ -49,11 +64,13 @@ def run_ragas_evaluation(sample_size: int = 10, output_dir: Optional[str] = None
49
  str(REPO_ROOT / config["data"]["csv_path"]),
50
  sample_size or config["data"]["sample_size"]
51
  )
 
 
52
  answers, contexts = generate_answers(
53
  rag_gen, questions,
54
- config["retrieval"]["top_k"],
55
- config["retrieval"]["initial_k"],
56
  retrieval_mode=retrieval_mode,
 
 
57
  )
58
 
59
  # Run RAGAS
@@ -75,7 +92,12 @@ def run_ragas_evaluation(sample_size: int = 10, output_dir: Optional[str] = None
75
  llm=evaluator_llm,
76
  embeddings=evaluator_embeddings,
77
  raise_exceptions=False,
78
- run_config=RunConfig(max_workers=2, timeout=300),
 
 
 
 
 
79
  )
80
 
81
  # Save JSON
@@ -83,99 +105,182 @@ def run_ragas_evaluation(sample_size: int = 10, output_dir: Optional[str] = None
83
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
84
  json_path = out_path / f"ragas_{timestamp}.json"
85
 
86
- # Convert results to dict
87
- scores: dict = {}
88
- if hasattr(results, "scores"):
89
- scores = results.scores # type: ignore
90
- elif hasattr(results, "__getitem__"):
91
- for k in ["faithfulness", "answer_relevancy", "context_precision", "context_recall", "rouge1_score", "rouge2_score", "rougeL_score"]:
92
- try:
93
- scores[k] = float(results[k]) # type: ignore
94
- except (KeyError, TypeError):
95
- pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
 
 
97
  with open(json_path, 'w', encoding='utf-8') as f:
98
  json.dump({
99
  "timestamp": timestamp,
100
  "retrieval_mode": retrieval_mode,
101
- "config": {"sample_size": len(questions), **{k: v for k, v in info.items() if k != "embeddings"}},
102
- "scores": scores,
 
103
  "samples": [
104
- {"question": q, "answer": a, "ground_truth": gt, "contexts": ctx}
105
- for q, a, gt, ctx in zip(questions, answers, ground_truths, contexts)
106
  ]
107
  }, f, ensure_ascii=False, indent=2)
108
 
 
 
 
 
 
 
 
 
109
  print(f"Saved: {json_path}")
110
- return scores
 
 
 
 
 
 
 
 
 
 
111
 
112
 
113
  if __name__ == "__main__":
114
  import argparse
115
- parser = argparse.ArgumentParser(description="RAGAS Evaluation - Compare all retrieval modes")
116
  parser.add_argument("--samples", type=int, default=10, help="Number of samples to evaluate")
117
  parser.add_argument("--output", type=str, default=None, help="Output directory")
 
 
 
118
  args = parser.parse_args()
119
 
120
- # Always run all modes and compare
121
  ALL_MODES = ["vector_only", "bm25_only", "hybrid", "hybrid_rerank"]
122
- all_results = {}
123
-
124
- for mode in ALL_MODES:
125
- print(f"\n{'#'*60}")
126
- print(f"# Running mode: {mode}")
127
- print(f"{'#'*60}")
128
- try:
129
- scores = run_ragas_evaluation(args.samples, args.output, mode)
130
- all_results[mode] = scores
131
- except Exception as e:
132
- print(f"Error in {mode}: {e}")
133
- all_results[mode] = {"error": str(e)}
134
-
135
- # Print comparison table
136
- print(f"\n{'='*80}")
137
- print("COMPARISON REPORT - All Retrieval Modes")
138
- print(f"{'='*80}")
139
-
140
- # Get all metric names
141
- metrics = set()
142
- for scores in all_results.values():
143
- if isinstance(scores, dict) and "error" not in scores:
144
- metrics.update(scores.keys())
145
- metrics = sorted(metrics)
146
-
147
- # Print header
148
- header = f"{'Metric':<25} | " + " | ".join(f"{m:<15}" for m in ALL_MODES)
149
- print(header)
150
- print("-" * len(header))
151
-
152
- # Print each metric
153
- for metric in metrics:
154
- row = f"{metric:<25} | "
155
  for mode in ALL_MODES:
156
- scores = all_results.get(mode, {})
157
- if isinstance(scores, dict) and metric in scores:
158
- val = scores[metric]
159
- if isinstance(val, (int, float)):
160
- row += f"{val:<15.4f} | "
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  else:
162
  row += f"{'N/A':<15} | "
163
- else:
164
- row += f"{'N/A':<15} | "
165
- print(row)
166
-
167
- # Save comparison JSON
168
- config = load_config()
169
- out_path = Path(args.output) if args.output else REPO_ROOT / config["output"]["dir"]
170
- out_path.mkdir(parents=True, exist_ok=True)
171
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
172
- comparison_path = out_path / f"comparison_{timestamp}.json"
173
-
174
- with open(comparison_path, 'w', encoding='utf-8') as f:
175
- json.dump({
176
- "timestamp": timestamp,
177
- "sample_size": args.samples,
178
- "results": all_results,
179
- }, f, ensure_ascii=False, indent=2)
180
-
181
- print(f"\n✅ Comparison saved: {comparison_path}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  # Init components
32
  rag_gen, info = init_rag_components(config)
33
 
34
+ eval_config = config.get("eval_llm", config["llm"]) # Fallback to llm for backward compatibility
35
+ gen_config = config.get("gen_llm", config["llm"])
 
 
36
 
37
+ # Get eval API key (may be different from generation API key)
38
+ eval_api_key_env = eval_config.get("api_key_env", "SILICONFLOW_API_KEY")
39
+ eval_api_key = os.getenv(eval_api_key_env, "")
40
+ if not eval_api_key:
41
+ # Fallback to SILICONFLOW_API_KEY
42
+ eval_api_key = os.getenv("SILICONFLOW_API_KEY", "")
43
+ if not eval_api_key:
44
+ raise ValueError(f"Missing API key. Set {eval_api_key_env} or SILICONFLOW_API_KEY")
45
+
46
+ eval_base_url = eval_config.get("base_url", "https://api.siliconflow.com/v1")
47
+ eval_model = eval_config.get("model", config["llm"]["model"])
48
+ gen_model = gen_config.get("model", config["llm"]["model"])
49
+
50
+ # ChatOpenAI expects SecretStr or callable for api_key
51
+ from pydantic import SecretStr
52
  evaluator_llm = LangchainLLMWrapper(ChatOpenAI(
53
+ model=eval_model,
54
+ api_key=SecretStr(eval_api_key), # Wrap in SecretStr
55
+ base_url=eval_base_url,
56
+ temperature=eval_config.get("temperature", 0),
57
+ timeout=120, # 2 minutes timeout per request
58
+ max_retries=3,
59
  ))
60
  evaluator_embeddings = LangchainEmbeddingsWrapper(info["embeddings"])
61
 
 
64
  str(REPO_ROOT / config["data"]["csv_path"]),
65
  sample_size or config["data"]["sample_size"]
66
  )
67
+
68
+ # Use generation model (NOT evaluation model) for RAG answers
69
  answers, contexts = generate_answers(
70
  rag_gen, questions,
 
 
71
  retrieval_mode=retrieval_mode,
72
+ llm_client=info["llm_client"],
73
+ llm_model=gen_config.get("model", config["llm"]["model"]),
74
  )
75
 
76
  # Run RAGAS
 
92
  llm=evaluator_llm,
93
  embeddings=evaluator_embeddings,
94
  raise_exceptions=False,
95
+ run_config=RunConfig(
96
+ max_workers=8, # SiliconFlow allows 1000 RPM, safe to use 8 workers
97
+ timeout=600, # 10 minutes per job
98
+ max_retries=3, # Retry on transient failures
99
+ max_wait=120, # Max wait between retries
100
+ ),
101
  )
102
 
103
  # Save JSON
 
105
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
106
  json_path = out_path / f"ragas_{timestamp}.json"
107
 
108
+ # Convert results to dict - handle both per-sample and aggregate scores
109
+ scores_per_sample: list = []
110
+ avg_scores: dict = {}
111
+
112
+ # Get per-sample scores from results DataFrame
113
+ if hasattr(results, "to_pandas"):
114
+ df = results.to_pandas() # type: ignore[union-attr]
115
+ metric_cols = [col for col in df.columns if col not in ("question", "answer", "contexts", "ground_truth", "user_input", "response", "reference", "retrieved_contexts")]
116
+
117
+ for _, row in df.iterrows():
118
+ sample_scores = {}
119
+ for col in metric_cols:
120
+ val = row[col]
121
+ if val is not None:
122
+ try:
123
+ sample_scores[col] = float(val)
124
+ except (ValueError, TypeError):
125
+ pass
126
+ scores_per_sample.append(sample_scores)
127
+
128
+ # Calculate average scores
129
+ import numpy as np
130
+ for col in metric_cols:
131
+ values = [s.get(col) for s in scores_per_sample if s.get(col) is not None]
132
+ if values:
133
+ valid_values = [v for v in values if not np.isnan(v)]
134
+ if valid_values:
135
+ avg_scores[col] = float(np.mean(valid_values))
136
+ else:
137
+ # Fallback for older ragas versions
138
+ if hasattr(results, "scores"):
139
+ avg_scores = results.scores # type: ignore
140
+ elif hasattr(results, "__getitem__"):
141
+ for k in ["faithfulness", "answer_relevancy", "context_precision", "context_recall", "rouge1_score", "rouge2_score", "rougeL_score"]:
142
+ try:
143
+ avg_scores[k] = float(results[k]) # type: ignore
144
+ except (KeyError, TypeError):
145
+ pass
146
 
147
+ # Save JSON with both per-sample and average scores
148
  with open(json_path, 'w', encoding='utf-8') as f:
149
  json.dump({
150
  "timestamp": timestamp,
151
  "retrieval_mode": retrieval_mode,
152
+ "config": {"sample_size": len(questions), **{k: v for k, v in info.items() if k not in ("embeddings", "llm_client")}},
153
+ "avg_scores": avg_scores,
154
+ "scores_per_sample": scores_per_sample,
155
  "samples": [
156
+ {"question": q, "answer": a, "ground_truth": gt, "contexts": ctx, "scores": sc}
157
+ for q, a, gt, ctx, sc in zip(questions, answers, ground_truths, contexts, scores_per_sample or [{}]*len(questions))
158
  ]
159
  }, f, ensure_ascii=False, indent=2)
160
 
161
+ # Save CSV summary (only average scores, not per-sample)
162
+ csv_path = out_path / f"ragas_{retrieval_mode}_{timestamp}.csv"
163
+ with open(csv_path, 'w', encoding='utf-8') as f:
164
+ # Header: metric names
165
+ f.write("retrieval_mode,sample_size," + ",".join(avg_scores.keys()) + "\n")
166
+ # Data: average values
167
+ f.write(f"{retrieval_mode},{len(questions)}," + ",".join([f"{v:.4f}" for v in avg_scores.values()]) + "\n")
168
+
169
  print(f"Saved: {json_path}")
170
+ print(f"Saved: {csv_path}")
171
+
172
+ # Print summary
173
+ print(f"\n{'='*60}")
174
+ print(f"SUMMARY - {retrieval_mode} ({len(questions)} samples)")
175
+ print(f"{'='*60}")
176
+ for metric, score in avg_scores.items():
177
+ bar = "#" * int(score * 20) + "-" * (20 - int(score * 20))
178
+ print(f" {metric:25} [{bar}] {score:.4f}")
179
+
180
+ return avg_scores
181
 
182
 
183
  if __name__ == "__main__":
184
  import argparse
185
+ parser = argparse.ArgumentParser(description="RAGAS Evaluation - Compare retrieval modes")
186
  parser.add_argument("--samples", type=int, default=10, help="Number of samples to evaluate")
187
  parser.add_argument("--output", type=str, default=None, help="Output directory")
188
+ parser.add_argument("--mode", type=str, default="all",
189
+ choices=["all", "vector_only", "bm25_only", "hybrid", "hybrid_rerank"],
190
+ help="Retrieval mode to evaluate (default: all)")
191
  args = parser.parse_args()
192
 
 
193
  ALL_MODES = ["vector_only", "bm25_only", "hybrid", "hybrid_rerank"]
194
+
195
+ # Single mode or all modes
196
+ if args.mode != "all":
197
+ print(f"\n{'='*60}")
198
+ print(f"RAGAS EVALUATION - Single Mode: {args.mode}")
199
+ print(f"{'='*60}")
200
+ scores = run_ragas_evaluation(args.samples, args.output, args.mode)
201
+ print(f"\nScores: {scores}")
202
+ else:
203
+ # Run all modes and compare
204
+ all_results = {}
205
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
  for mode in ALL_MODES:
207
+ print(f"\n{'#'*60}")
208
+ print(f"# Running mode: {mode}")
209
+ print(f"{'#'*60}")
210
+ try:
211
+ scores = run_ragas_evaluation(args.samples, args.output, mode)
212
+ all_results[mode] = scores
213
+ except Exception as e:
214
+ print(f"Error in {mode}: {e}")
215
+ all_results[mode] = {"error": str(e)}
216
+
217
+ # Print comparison table
218
+ print(f"\n{'='*80}")
219
+ print("COMPARISON REPORT - All Retrieval Modes")
220
+ print(f"{'='*80}")
221
+
222
+ # Get all metric names
223
+ metrics = set()
224
+ for scores in all_results.values():
225
+ if isinstance(scores, dict) and "error" not in scores:
226
+ metrics.update(scores.keys())
227
+ metrics = sorted(metrics)
228
+
229
+ # Print header
230
+ header = f"{'Metric':<25} | " + " | ".join(f"{m:<15}" for m in ALL_MODES)
231
+ print(header)
232
+ print("-" * len(header))
233
+
234
+ # Print each metric
235
+ for metric in metrics:
236
+ row = f"{metric:<25} | "
237
+ for mode in ALL_MODES:
238
+ scores = all_results.get(mode, {})
239
+ if isinstance(scores, dict) and metric in scores:
240
+ val = scores[metric]
241
+ if isinstance(val, (int, float)):
242
+ row += f"{val:<15.4f} | "
243
+ else:
244
+ row += f"{'N/A':<15} | "
245
  else:
246
  row += f"{'N/A':<15} | "
247
+ print(row)
248
+
249
+ # Save comparison JSON and CSV
250
+ config = load_config()
251
+ out_path = Path(args.output) if args.output else REPO_ROOT / config["output"]["dir"]
252
+ out_path.mkdir(parents=True, exist_ok=True)
253
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
254
+
255
+ # Save JSON
256
+ comparison_path = out_path / f"comparison_{timestamp}.json"
257
+ with open(comparison_path, 'w', encoding='utf-8') as f:
258
+ json.dump({
259
+ "timestamp": timestamp,
260
+ "sample_size": args.samples,
261
+ "results": all_results,
262
+ }, f, ensure_ascii=False, indent=2)
263
+
264
+ # Save CSV summary
265
+ csv_path = out_path / f"comparison_{timestamp}.csv"
266
+ with open(csv_path, 'w', encoding='utf-8') as f:
267
+ # Header
268
+ f.write("Metric," + ",".join(ALL_MODES) + "\n")
269
+ # Data rows
270
+ for metric in metrics:
271
+ row_values = [metric]
272
+ for mode in ALL_MODES:
273
+ scores = all_results.get(mode, {})
274
+ if isinstance(scores, dict) and metric in scores:
275
+ val = scores[metric]
276
+ if isinstance(val, (int, float)):
277
+ row_values.append(f"{val:.4f}")
278
+ else:
279
+ row_values.append("N/A")
280
+ else:
281
+ row_values.append("N/A")
282
+ f.write(",".join(row_values) + "\n")
283
+
284
+ print(f"\nComparison saved:")
285
+ print(f" - JSON: {comparison_path}")
286
+ print(f" - CSV: {csv_path}")
evaluation/results/comparison_20260105_132921.json DELETED
@@ -1,154 +0,0 @@
1
- {
2
- "timestamp": "20260105_132921",
3
- "sample_size": 5,
4
- "results": {
5
- "vector_only": [
6
- {
7
- "faithfulness": 1.0,
8
- "answer_relevancy": 0.7364493749907867,
9
- "context_precision": 0.99999999995,
10
- "context_recall": 1.0,
11
- "rouge_score(mode=fmeasure)": 0.6690140845070423
12
- },
13
- {
14
- "faithfulness": 1.0,
15
- "answer_relevancy": 0.7310359258257583,
16
- "context_precision": 0.999999999975,
17
- "context_recall": 1.0,
18
- "rouge_score(mode=fmeasure)": 0.6643356643356644
19
- },
20
- {
21
- "faithfulness": 0.6923076923076923,
22
- "answer_relevancy": 0.8345119784254372,
23
- "context_precision": 0.8666666666377778,
24
- "context_recall": 1.0,
25
- "rouge_score(mode=fmeasure)": 0.4396135265700484
26
- },
27
- {
28
- "faithfulness": 0.2857142857142857,
29
- "answer_relevancy": 0.0,
30
- "context_precision": 0.6791666666496875,
31
- "context_recall": 1.0,
32
- "rouge_score(mode=fmeasure)": 0.39164490861618795
33
- },
34
- {
35
- "faithfulness": 0.5384615384615384,
36
- "answer_relevancy": 0.7938279373591263,
37
- "context_precision": 0.9999999999,
38
- "context_recall": 1.0,
39
- "rouge_score(mode=fmeasure)": 0.36512261580381467
40
- }
41
- ],
42
- "bm25_only": [
43
- {
44
- "faithfulness": 0.875,
45
- "answer_relevancy": 0.7264722326341989,
46
- "context_precision": 0.99999999995,
47
- "context_recall": 1.0,
48
- "rouge_score(mode=fmeasure)": 0.7589285714285714
49
- },
50
- {
51
- "faithfulness": 0.9285714285714286,
52
- "answer_relevancy": 0.7342079659938445,
53
- "context_precision": 0.999999999975,
54
- "context_recall": 1.0,
55
- "rouge_score(mode=fmeasure)": 0.6351351351351351
56
- },
57
- {
58
- "faithfulness": 0.8888888888888888,
59
- "answer_relevancy": 0.8335330619249784,
60
- "context_precision": 0.9999999999666667,
61
- "context_recall": 1.0,
62
- "rouge_score(mode=fmeasure)": 0.5673352435530086
63
- },
64
- {
65
- "faithfulness": 0.42857142857142855,
66
- "answer_relevancy": 0.6506986819875058,
67
- "context_precision": 0.99999999998,
68
- "context_recall": 1.0,
69
- "rouge_score(mode=fmeasure)": 0.5048543689320388
70
- },
71
- {
72
- "faithfulness": 0.8333333333333334,
73
- "answer_relevancy": 0.8338701751762124,
74
- "context_precision": 0.9999999999,
75
- "context_recall": 1.0,
76
- "rouge_score(mode=fmeasure)": 0.5344827586206896
77
- }
78
- ],
79
- "hybrid": [
80
- {
81
- "faithfulness": 0.8571428571428571,
82
- "answer_relevancy": 0.8972923254436237,
83
- "context_precision": 0.99999999995,
84
- "context_recall": 1.0,
85
- "rouge_score(mode=fmeasure)": 0.7606837606837608
86
- },
87
- {
88
- "faithfulness": 1.0,
89
- "answer_relevancy": 0.7008081720389104,
90
- "context_precision": 0.94999999997625,
91
- "context_recall": 1.0,
92
- "rouge_score(mode=fmeasure)": 0.44655581947743467
93
- },
94
- {
95
- "faithfulness": 1.0,
96
- "answer_relevancy": 0.8991661959917713,
97
- "context_precision": 0.99999999995,
98
- "context_recall": 1.0,
99
- "rouge_score(mode=fmeasure)": 0.6297577854671281
100
- },
101
- {
102
- "faithfulness": 1.0,
103
- "answer_relevancy": 0.0,
104
- "context_precision": 0.99999999998,
105
- "context_recall": 1.0,
106
- "rouge_score(mode=fmeasure)": 0.1372549019607843
107
- },
108
- {
109
- "faithfulness": 0.7,
110
- "answer_relevancy": 0.7942512688700306,
111
- "context_precision": 0.49999999995,
112
- "context_recall": 1.0,
113
- "rouge_score(mode=fmeasure)": 0.39747634069400634
114
- }
115
- ],
116
- "hybrid_rerank": [
117
- {
118
- "faithfulness": 0.8888888888888888,
119
- "answer_relevancy": 0.7358630343295559,
120
- "context_precision": 0.99999999995,
121
- "context_recall": 1.0,
122
- "rouge_score(mode=fmeasure)": 0.7818930041152263
123
- },
124
- {
125
- "faithfulness": 1.0,
126
- "answer_relevancy": 0.6748679131476658,
127
- "context_precision": 0.8874999999778125,
128
- "context_recall": 1.0,
129
- "rouge_score(mode=fmeasure)": 0.6909090909090908
130
- },
131
- {
132
- "faithfulness": 1.0,
133
- "answer_relevancy": 0.8327119887318949,
134
- "context_precision": 0.9166666666361111,
135
- "context_recall": 1.0,
136
- "rouge_score(mode=fmeasure)": 0.6297577854671281
137
- },
138
- {
139
- "faithfulness": 1.0,
140
- "answer_relevancy": 0.0,
141
- "context_precision": 0.99999999998,
142
- "context_recall": 1.0,
143
- "rouge_score(mode=fmeasure)": 0.1372549019607843
144
- },
145
- {
146
- "faithfulness": 0.6666666666666666,
147
- "answer_relevancy": 0.8847245139750438,
148
- "context_precision": 0.7499999999625,
149
- "context_recall": 1.0,
150
- "rouge_score(mode=fmeasure)": 0.7083333333333333
151
- }
152
- ]
153
- }
154
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
evaluation/results/ragas_20260105_125700.json DELETED
@@ -1,111 +0,0 @@
1
- {
2
- "timestamp": "20260105_125700",
3
- "retrieval_mode": "vector_only",
4
- "config": {
5
- "sample_size": 5,
6
- "gen_model": "nex-agi/DeepSeek-V3.1-Nex-N1",
7
- "eval_model": "nex-agi/DeepSeek-V3.1-Nex-N1",
8
- "embed_model": "Qwen/Qwen3-Embedding-4B",
9
- "collection": "hust_rag_collection",
10
- "doc_count": 1441
11
- },
12
- "scores": [
13
- {
14
- "faithfulness": 1.0,
15
- "answer_relevancy": 0.7364493749907867,
16
- "context_precision": 0.99999999995,
17
- "context_recall": 1.0,
18
- "rouge_score(mode=fmeasure)": 0.6690140845070423
19
- },
20
- {
21
- "faithfulness": 1.0,
22
- "answer_relevancy": 0.7310359258257583,
23
- "context_precision": 0.999999999975,
24
- "context_recall": 1.0,
25
- "rouge_score(mode=fmeasure)": 0.6643356643356644
26
- },
27
- {
28
- "faithfulness": 0.6923076923076923,
29
- "answer_relevancy": 0.8345119784254372,
30
- "context_precision": 0.8666666666377778,
31
- "context_recall": 1.0,
32
- "rouge_score(mode=fmeasure)": 0.4396135265700484
33
- },
34
- {
35
- "faithfulness": 0.2857142857142857,
36
- "answer_relevancy": 0.0,
37
- "context_precision": 0.6791666666496875,
38
- "context_recall": 1.0,
39
- "rouge_score(mode=fmeasure)": 0.39164490861618795
40
- },
41
- {
42
- "faithfulness": 0.5384615384615384,
43
- "answer_relevancy": 0.7938279373591263,
44
- "context_precision": 0.9999999999,
45
- "context_recall": 1.0,
46
- "rouge_score(mode=fmeasure)": 0.36512261580381467
47
- }
48
- ],
49
- "samples": [
50
- {
51
- "question": "Chương trình đào tạo ngành Kỹ thuật Cơ điện tử được xây dựng dựa trên những cơ sở nào?",
52
- "answer": "Dựa trên CONTEXT được cung cấp, chương trình đào tạo ngành Kỹ thuật Cơ điện tử được xây dựng trên các cơ sở sau:\n\n1. **Phát triển từ chương trình nội bộ:** Chương trình được phát triển trên cơ sở chương trình đào tạo ngành Cơ điện tử năm 2009 của trường.\n2. **Tham khảo chương trình quốc tế:** Chương trình có sự tham khảo từ các trường đại học nổi tiếng trên thế giới như:\n * Stanford (Hoa Kỳ)\n * Chico (Hoa Kỳ)\n * Sibaura (Nhật Bản)\n * Đại học Quốc gia Đài Loan (NTU)\n3. **Tiêu chuẩn kiểm định:** Chương trình được kiểm định theo tiêu chuẩn AUN-QA năm 2017.\n\nNguồn: 1.1. Kỹ thuật Cơ điện tử.md",
53
- "ground_truth": "Chương trình đào tạo ngành Kỹ thuật Cơ điện tử được xây dựng trên cơ sở phát triển chương trình năm 2009, kết hợp tham khảo chương trình đào tạo của các trường đại học nổi tiếng trên thế giới như Stanford, Chico (Hoa Kỳ), Sibaura (Nhật Bản) và Đại học Quốc gia Đài Loan (NTU), đồng thời được kiểm định theo tiêu chuẩn AUN-QA năm 2017.",
54
- "contexts": [
55
- "# 1. Tên chương trình: KỸ THUẬT CƠ ĐIỆN TỬ\nChương trình đào tạo ngành Cơ điện tử hiện nay được xây dựng trên cơ sở phát triển chương trình đào tạo ngành Cơ điện tử năm 2009 kết hợp với sự tham khảo chương trình đào tạo ngành Cơ điện tử của các trường đại học nổi tiếng trên thế giới như Stanford, Chico (Koa Kỳ), Sibaura (Nhật Bản), Đại học Quốc gia Đài Loan (NTU)…; Chương trình được kiểm định theo tiêu chuẩn AUN -QA năm 2017;\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu, khả năng làm việc và sáng tạo trong mọi môi trường lao động để giải quyết những vấn đề liên quan đến nghiên cứu thiết kế, chế tạo thiết bị, hệ thống cơ điện tử và vận hành các hệ thống sản xuất công nghiệp, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.",
56
- "## 1. Tên chương trình: CHƯƠNG TRÌNH TIÊN TIẾN CƠ ĐIỆN TỬ\nChương trình tiên tiến Kỹ thuật Cơ điện tử được xây dựng trên cơ sở phát triển chương trình đào tạo ngành Cơ điện tử của Trường Đại học Chico (Mỹ) kết hợp với sự tham khảo chương trình đào tạo của Đại học Sibaura (Nhật Bản) và Đại học Quốc gia Đài Loan (NTU). Chương trình đào tạo đã được kiểm định theo tiêu chuẩn AUN -QA năm 2017.\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu, khả năng làm việc và sáng tạo trong mọi môi trường lao động để giải quyết những vấn đề liên quan đến thiết kế, chế tạo thiết bị, hệ thống cơ điện tử và vận hành hệ thống sản xuất công nghiệp, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.\nNgôn ngữ đào tạo chính: Tiếng Anh.",
57
- "## 1. Tên chương trình: KỸ THUẬT CƠ KHÍ\n\nChương trình đào tạo cử nhân – kỹ sư ngành Kỹ thuật Cơ khí được xây dựng dựa trên sự phát triển chương trình đào tạo ngành Chế tạo máy trước đây kết hợp với sự tham khảo chương trình đào tạo ngành chế tạo máy của các trường đại học tiên tiến trên thế giới như: Stanford (Hoa Kỳ), NTU (Đài Loan), RMIT (Úc), … ;\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu để có thể làm việc và sáng tạo trong mọi môi trường lao động nhằm giải quyết những vấn đề liên quan đến thiết kế, chế tạo, vận hành và bảo trì các máy móc, thiết bị cơ khí và các hệ thống sản xuất công nghiệp đáp ứng yêu cầu của xã hội, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.",
58
- "## 1. Tên chương trình: CHƯƠNG TRÌNH TIÊN TIẾN ĐIỆN TỬ -VIỄN THÔNG\n\nNgành Điện tử - Viễn thông là một trong những ngành mũi nhọn của cuộc Cách mạng công nghiệp lần thứ 4 và là ngành có nhu cầu cao về nhân lực ở Việt Nam và trên thế giới. Theo học chương trình này, sinh viên được trang bị một cách toàn diện cả về kỹ năng chuyên môn và kỹ năng mềm để có thể thiết kế, chế tạo, vận hành các thiết bị và hệ thống điện tử viễn thông, đáp ứng được yêu cầu về tính năng động và sáng tạo của lĩnh vực nghề nghiệp này.\n\nChương trình tiên tiến kỹ thuật Điện tử -Viễn thông được giảng dạy hoàn toàn bằng tiếng Anh và do các giảng viên của trường ĐHBK Hà Nội và các giảng viên nước ngoài tham gia giảng dạy.\n\nChương trình được thiết kế dựa trên chương trình của trường Đại học San Jose State University, Hoa Kỳ và bao gồm khối kiến thức toán học và khoa học cơ bản, khối kiến thức cơ sở cốt lõi ngành Điện tử -Viễn thông, khối kiến thức bổ trợ kiến thức xã hội và kỹ năng mềm và khối kiến thức chuyên sâu ngành",
59
- "## 1. Tên chương trình: KỸ THUẬT ĐIỆN TỬ -VIỄN THÔNG\n\nNgành Điện tử - Viễn thông là một trong những ngành mũi nhọn của cuộc Cách mạng công nghiệp lần thứ 4 và là ngành có nhu cầu cao về nhân lực ở Việt Nam và trên thế giới. Theo học ngành này, sinh viên được trang bị một cách toàn diện cả về kỹ năng chuyên môn và kỹ năng mềm để có thể thiết kế, chế tạo, vận hành các thiết bị và hệ thống điện tử viễn thông, đáp ứng được yêu cầu về tính năng động và sáng tạo của lĩnh vực nghề nghiệp này.\n\nChương trình kỹ thuật Điện tử- Viễn thông được giảng dạy bằng tiếng Việt và được thiết kế bao gồm khối kiến thức toán học và khoa học cơ bản, khối kiến thức cơ sở cốt lõi ngành Điện tử -Viễn thông, khối kiến thức bổ trợ kiến thức xã hội và kỹ năng mềm và khối kiến thức tự chọn chuyên sâu theo các định hướng kỹ thuật điện tử, kỹ thuật máy tính, kỹ thuật thông tin truyền thông, kỹ thuật y sinh, kỹ thuật điện tử hàng không vũ trụ, kỹ thuật đa phương tiện, kỹ thuật vi điện tử và công nghệ nano."
60
- ]
61
- },
62
- {
63
- "question": "Sinh viên tốt nghiệp ngành Kỹ thuật Cơ điện tử đạt được những kiến thức chuyên môn gì?",
64
- "answer": "Dựa trên tài liệu đào tạo ngành Kỹ thuật Cơ điện tử, sinh viên tốt nghiệp đạt được những kiến thức chuyên môn sau:\n\nCó kiến thức chuyên môn rộng và vững chắc, thích ứng tốt với những công việc phù hợp với ngành, chú trọng khả năng áp dụng kiến thức cơ sở và cốt lõi ngành Cơ điện tử kết hợp khả năng sử dụng công cụ hiện đại để nghiên cứu, thiết kế, chế tạo, xây dựng và vận hành các hệ thống/quá trình/sản phẩm Cơ điện tử.\n\n**Nguồn:** 1.1. Kỹ thuật Cơ điện tử.md | Mục: /2. Kiến thức, kỹ năng đạt được sau tốt nghiệp/",
65
- "ground_truth": "Sinh viên tốt nghiệp có kiến thức chuyên môn rộng và vững chắc, có khả năng áp dụng kiến thức cơ sở và cốt lõi của ngành Cơ điện tử kết hợp với việc sử dụng các công cụ hiện đại để nghiên cứu, thiết kế, chế tạo, xây dựng và vận hành các hệ thống, quá trình và sản phẩm Cơ điện tử.",
66
- "contexts": [
67
- "# 2. Kiến thức, kỹ năng đạt được sau tốt nghiệp\n\n## a. Kiến thức\nCó kiến thức chuyên môn rộng và vững chắc, thích ứng tốt với những công việc phù hợp với ngành, chú trọng khả năng áp dụng kiến thức cơ sở và cốt lõi ngành Cơ điện tử kết hợp khả năng sử dụng công cụ hiện đại để nghiên cứu, thiết kế, chế tạo, xây dựng và vận hành các hệ thống/quá trình/sản phẩm Cơ điện tử.",
68
- "## 2. Kiến thức, kỹ năng đạt được sau tốt nghiệp\n\n## a. Kiến thức\nCó kiến thức chuyên môn rộng và vững chắc, thích ứng tốt với những công việc phù hợp với ngành, chú trọng khả năng áp dụng kiến thức cơ sở và cốt lõi ngành Cơ điện tử kết hợp khả năng sử dụng công cụ hiện đại để nghiên cứu, thiết kế, chế tạo, xây dựng và vận hành các hệ thống/quá trình/sản phẩm cơ điện tử.",
69
- "## 2. Kiến thức, kỹ năng đạt được sau tốt nghiệp\n\n## a. Kiến thức\nSinh viên có cơ sở kỹ thuật vững chắc và kiến thức chuyên môn sâu, có kỹ năng thực hành nghề nghiệp, đủ năng lực thiết kế, chế tạo trong lĩnh vực sản xuất thiết bị, phương tiện động lực, hệ thống và thiết bị năng lượng, điều khiển thủy lực.",
70
- "## 2. Kiến thức, kỹ năng đạt được sau tốt nghiệp\n\n## a. Kiến thức\nCó kiến thức cơ sở chuyên môn rộng và vững chắc, thích ứng tốt với những công việc phù hợp với ngành học,\nChú trọng khả năng áp dụng kiến thức cơ sở và cốt lõi ngành Kỹ thuật Cơ khí kết hợp khả năng sử dụng công cụ hiện đại để thiết kế, chế tạo, vận hành, nghiên cứu phân tích, cải tiến máy móc, thiết bị hay hệ thống sản xuất.",
71
- "## 2. Kiến thức, kỹ năng đạt được sau tốt nghiệp\n\n## a. Kiến thức\n- Có và kỹ năng cơ bản về Cơ khí, điện -điện tử, tự động hóa nhằm giúp người học có đủ năng lực giải quyết các vấn đề liên quan tới ngành nhiệt -lạnh cũng như những công việc khác nhau trong lĩnh vực cơ - điện - năng lượng;\n- Nắm được bản chất của các quá trình và thiết bị nhiệt -lạnh, chế tạo, vận hành, bảo trì sản phẩm và các hệ thống nhiệt -lạnh trong công nghiệp và dân dụng để giải quyết các vấn đề công nghệ và môi trường."
72
- ]
73
- },
74
- {
75
- "question": "Tại sao sinh viên ngành Kỹ thuật Cơ điện tử có thể nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0?",
76
- "answer": "Dựa trên CONTEXT được cung cấp, sinh viên ngành Kỹ thuật Cơ điện tử có thể nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0 vì:\n\n1. **Được trang bị kiến thức cơ sở và chuyên ngành vững chắc:** Chương trình đào tạo cung cấp nền tảng kiến thức rộng và sâu, giúp sinh viên có khả năng áp dụng vào thực tiễn.\n2. **Có kỹ năng nghề nghiệp và năng lực nghiên cứu:** Sinh viên được rèn luyện các kỹ năng cần thiết để giải quyết các vấn đề phức tạp.\n3. **Khả năng làm việc và sáng tạo trong mọi môi trường lao động:** Chương trình đào tạo hướng đến việc phát triển năng lực sáng tạo và thích ứng linh hoạt.\n4. **Giải quyết những vấn đề liên quan đến nghiên cứu thiết kế, chế tạo thiết bị, hệ thống cơ điện tử và vận hành các hệ thống sản xuất công nghiệp:** Đây là những lĩnh vực cốt lõi của Cách mạng công nghiệp 4.0.\n\n**Nguồn:** 1.1. Kỹ thuật Cơ điện tử.md",
77
- "ground_truth": "Vì chương trình đào tạo trang bị cho sinh viên nền tảng kiến thức cơ sở và chuyên ngành vững chắc, kỹ năng nghề nghiệp, năng lực nghiên cứu, khả năng làm việc và sáng tạo trong nhiều môi trường lao động, giúp giải quyết các vấn đề liên quan đến thiết kế, chế tạo và vận hành các hệ thống cơ điện tử trong sản xuất công nghiệp hiện đại.",
78
- "contexts": [
79
- "# 1. Tên chương trình: KỸ THUẬT CƠ ĐIỆN TỬ\nChương trình đào tạo ngành Cơ điện tử hiện nay được xây dựng trên cơ sở phát triển chương trình đào tạo ngành Cơ điện tử năm 2009 kết hợp với sự tham khảo chương trình đào tạo ngành Cơ điện tử của các trường đại học nổi tiếng trên thế giới như Stanford, Chico (Koa Kỳ), Sibaura (Nhật Bản), Đại học Quốc gia Đài Loan (NTU)…; Chương trình được kiểm định theo tiêu chuẩn AUN -QA năm 2017;\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu, khả năng làm việc và sáng tạo trong mọi môi trường lao động để giải quyết những vấn đề liên quan đến nghiên cứu thiết kế, chế tạo thiết bị, hệ thống cơ điện tử và vận hành các hệ thống sản xuất công nghiệp, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.",
80
- "## 1. Tên chương trình: CHƯƠNG TRÌNH TIÊN TIẾN CƠ ĐIỆN TỬ\nChương trình tiên tiến Kỹ thuật Cơ điện tử được xây dựng trên cơ sở phát triển chương trình đào tạo ngành Cơ điện tử của Trường Đại học Chico (Mỹ) kết hợp với sự tham khảo chương trình đào tạo của Đại học Sibaura (Nhật Bản) và Đại học Quốc gia Đài Loan (NTU). Chương trình đào tạo đã được kiểm định theo tiêu chuẩn AUN -QA năm 2017.\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu, khả năng làm việc và sáng tạo trong mọi môi trường lao động để giải quyết những vấn đề liên quan đến thiết kế, chế tạo thiết bị, hệ thống cơ điện tử và vận hành hệ thống sản xuất công nghiệp, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.\nNgôn ngữ đào tạo chính: Tiếng Anh.",
81
- "## 1. Tên chương trình: KỸ THUẬT CƠ KHÍ\n\nChương trình đào tạo cử nhân – kỹ sư ngành Kỹ thuật Cơ khí được xây dựng dựa trên sự phát triển chương trình đào tạo ngành Chế tạo máy trước đây kết hợp với sự tham khảo chương trình đào tạo ngành chế tạo máy của các trường đại học tiên tiến trên thế giới như: Stanford (Hoa Kỳ), NTU (Đài Loan), RMIT (Úc), … ;\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu để có thể làm việc và sáng tạo trong mọi môi trường lao động nhằm giải quyết những vấn đề liên quan đến thiết kế, chế tạo, vận hành và bảo trì các máy móc, thiết bị cơ khí và các hệ thống sản xuất công nghiệp đáp ứng yêu cầu của xã hội, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.",
82
- "## 1. Tên chương trình: KỸ THUẬT ĐIỆN TỬ -VIỄN THÔNG\n\nNgành Điện tử - Viễn thông là một trong những ngành mũi nhọn của cuộc Cách mạng công nghiệp lần thứ 4 và là ngành có nhu cầu cao về nhân lực ở Việt Nam và trên thế giới. Theo học ngành này, sinh viên được trang bị một cách toàn diện cả về kỹ năng chuyên môn và kỹ năng mềm để có thể thiết kế, chế tạo, vận hành các thiết bị và hệ thống điện tử viễn thông, đáp ứng được yêu cầu về tính năng động và sáng tạo của lĩnh vực nghề nghiệp này.\n\nChương trình kỹ thuật Điện tử- Viễn thông được giảng dạy bằng tiếng Việt và được thiết kế bao gồm khối kiến thức toán học và khoa học cơ bản, khối kiến thức cơ sở cốt lõi ngành Điện tử -Viễn thông, khối kiến thức bổ trợ kiến thức xã hội và kỹ năng mềm và khối kiến thức tự chọn chuyên sâu theo các định hướng kỹ thuật điện tử, kỹ thuật máy tính, kỹ thuật thông tin truyền thông, kỹ thuật y sinh, kỹ thuật điện tử hàng không vũ trụ, kỹ thuật đa phương tiện, kỹ thuật vi điện tử và công nghệ nano.",
83
- "# 2. Kiến thức, kỹ năng đạt được sau tốt nghiệp\n\n## a. Kiến thức\nCó kiến thức chuyên môn rộng và vững chắc, thích ứng tốt với những công việc phù hợp với ngành, chú trọng khả năng áp dụng kiến thức cơ sở và cốt lõi ngành Cơ điện tử kết hợp khả năng sử dụng công cụ hiện đại để nghiên cứu, thiết kế, chế tạo, xây dựng và vận hành các hệ thống/quá trình/sản phẩm Cơ điện tử."
84
- ]
85
- },
86
- {
87
- "question": "Chương trình đào tạo ngành Kỹ thuật Cơ điện tử được điều chỉnh như thế nào để đảm bảo t��nh cập nhật mà không ảnh hưởng đến người học?",
88
- "answer": "Dựa trên các tài liệu được cung cấp, tôi không tìm thấy thông tin cụ thể về việc chương trình đào tạo ngành **Kỹ thuật Cơ điện tử** được điều chỉnh như thế nào để đảm bảo tính cập nhật mà không ảnh hưởng đến người học.\n\nTuy nhiên, các tài liệu về các chương trình đào tạo khác (Kỹ thuật Ô tô, Chương trình tiên tiến Điện tử - Viễn thông, Chương trình tiên tiến Kỹ thuật Ô tô, Chương trình tiên tiến Điều khiển - Tự động hóa và Hệ thống điện) đều có ghi nhận nguyên tắc chung:\n\n> \"Chương trình đào tạo có thể được điều chỉnh hàng năm để đảm bảo tính cập nhật với sự phát triển của khoa học, kỹ thuật và công nghệ; tuy nhiên đảm bảo nguyên tắc không gây ảnh hưởng ngược tới kết quả người học đã tích lũy.\"\n\nNguyên tắc này có thể áp dụng tương tự cho chương trình Kỹ thuật Cơ điện tử, nhưng không có thông tin cụ thể trong tài liệu về ngành này.\n\n**Nguồn:** Tài liệu 1.3, 2.5, 1.7, 2.3",
89
- "ground_truth": "Chương trình đào tạo có thể được điều chỉnh hàng năm nhằm đảm bảo tính cập nhật với sự phát triển của khoa học, kỹ thuật và công nghệ, nhưng vẫn tuân thủ nguyên tắc không gây ảnh hưởng ngược tới kết quả học tập mà người học đã tích lũy.",
90
- "contexts": [
91
- "# 1. Tên chương trình: KỸ THUẬT CƠ ĐIỆN TỬ\nChương trình đào tạo ngành Cơ điện tử hiện nay được xây dựng trên cơ sở phát triển chương trình đào tạo ngành Cơ điện tử năm 2009 kết hợp với sự tham khảo chương trình đào tạo ngành Cơ điện tử của các trường đại học nổi tiếng trên thế giới như Stanford, Chico (Koa Kỳ), Sibaura (Nhật Bản), Đại học Quốc gia Đài Loan (NTU)…; Chương trình được kiểm định theo tiêu chuẩn AUN -QA năm 2017;\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu, khả năng làm việc và sáng tạo trong mọi môi trường lao động để giải quyết những vấn đề liên quan đến nghiên cứu thiết kế, chế tạo thiết bị, hệ thống cơ điện tử và vận hành các hệ thống sản xuất công nghiệp, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.",
92
- "## 4. Danh mục học phần và thời lượng học tập:\nChương trình đào tạo có thể được điều chỉnh hàng năm để đảm bảo tính cập nhật với sự phát triển của khoa học, kỹ thuật và công nghệ; tuy nhiên đảm bảo nguyên tắc không gây ảnh hưởng ngược tới kết quả người học đã tích lũy.",
93
- "## 4. Danh mục học phần và thời lượng học tập:\n\nChương trình đào tạo có thể được điều chỉnh hàng năm để đảm bảo tính cập nhật với sự phát triển c ủa khoa học, kỹ thuật và công nghệ; tuy nhiên đảm bảo nguyên tắc không gây ảnh hưởng ngược tới kết quả người học đã tích lũy.",
94
- "## 4. Danh mục học phần và thời lượng học tập:\n\nChương trình đào tạo có thể được điều chỉnh hàng năm để đảm bảo tính cập nhật với sự phát triển c ủa khoa học, kỹ thuật và công nghệ; tuy nhiên đảm bảo nguyên tắc không gây ảnh hưởng ngược tới kết quả người học đã tích lũy.",
95
- "## 4. Danh mục học phần và thời lượng học tập:\n\nChương trình đào tạo có thể được điều chỉnh hàng năm để đảm bảo tính cập nhật với sự phát triển c ủa khoa học, kỹ thuật và công nghệ; tuy nhiên đảm bảo nguyên tắc không gây ảnh hưởng ngược tới kết quả người học đã tích lũy."
96
- ]
97
- },
98
- {
99
- "question": "Chương trình đào tạo kỹ sư chuyên sâu đặc thù (180 tín chỉ) áp dụng cho những đối tượng sinh viên nào?",
100
- "answer": "Dựa trên các tài liệu được cung cấp, chương trình đào tạo kỹ sư chuyên sâu đặc thù (180 tín chỉ) áp dụng cho các đối tượng sau:\n\n**1. Sinh viên các khóa từ K62:**\n- Áp dụng với sinh viên các khóa từ K62 đang học tập và có mong muốn tiếp tục học tập theo chương trình đào tạo kỹ sư chuyên sâu đặc thù.\n\n**2. Sinh viên theo chương trình tích hợp cử nhân-kỹ sư:**\n- Chương trình tích hợp cử nhân-kỹ sư có thời gian thiết kế là 5,5 năm và khối lượng học tập 180 TC, bao gồm hai bậc trình độ: Cử nhân (4 năm) và Kỹ sư (1,5 năm).\n\n**3. Học viên chương trình đào tạo kỹ sư chuyên sâu theo chương trình tích hợp:**\n- Dành cho học viên đã được cấp mã số học viên tạm thời và học viên đã được công nhận chính thức.\n\n**Nguồn:**\n- Tài liệu 1: 01_3 HD hoc chuyen tiep ky su 180 TC_Final.md\n- Tài liệu 3: 02_ Hướng dẫn công nhận học phần vào CTĐT KSCS.md \n- Tài liệu 4: QCDT_2025_5445_QD-DHBK.md",
101
- "ground_truth": "Chương trình áp dụng cho sinh viên các khóa từ K62 đang học tập và có mong muốn tiếp tục học theo chương trình kỹ sư chuyên sâu đặc thù, đồng thời áp dụng cho các chương trình đào tạo có đào tạo bậc kỹ sư chuyên sâu đặc thù.",
102
- "contexts": [
103
- "# HƯỚNG DẪN HỌC TẬP CHƯƠNG TRÌNH ĐÀO TẠO KỸ SƯ CHUYÊN SÂU ĐẶC THÙ (180 TC)\n\n## 1. Phạm vi áp dụng\n+ Áp dụng với sinh viên các khóa từ K62 đang học tập và có mong muốn tiếp tục học tập theo chương trình đạo tạo kỹ sư chuyên sâu đặc thù.\n+ Áp dụng với các chương trình đào tạo (viết tắt là: CTĐT) có đào tạo bậc kỹ sư chuyên sâu đặc thù (viết tắt là: KS) .",
104
- "## II. Khung chương trình đào tạo kỹ sư chuyên sâu\n\n1. CTĐT KSCS có khối lượng học tập 60 tín chỉ đối với người học đã tốt nghiệp đại học. Thời gian học tập toàn khóa theo kế hoạch học tập chuẩn là 2 năm, người tốt nghiệp được cấp bằng kỹ sư bậc 7 theo Khung năng lực quốc gia Việt Nam .\n2. Điểm trung bình toàn khóa được sử dụng để xét tốt nghiệp và xếp hạng tốt nghiệp là điểm trung bình tích lũy toàn khóa tính theo các học phần đăng ký xét tốt nghiệp thuộc CTĐT KSCS .\n3. Học viên của CTĐT KSCS được Giám đốc Đại học Bách khoa Hà Nội công nhận tốt nghiệp được cấp bằng tốt nghiệp Kỹ sư bậc 7 theo Khung năng lực quốc gia Việt Nam.\n4. Khung quy định của CTĐT KSCS:\nKhung quy định của chương trình đào tạo Kỹ sư chuyên sâu đặc thù (KSCS) gồm các nhóm học phần sau:\nNhóm kiến thức định hướng chuyên ngành có khối lượng 12 tín chỉ,\ngồm các học phần được thiết kế theo nhóm để định hướng người học tiếp cận theo chuyên ngành.\nNhóm kiến thức chuyên ngành cốt lõi có khối lượng từ 19 đến 20 tín chỉ,\nlà ",
105
- "# HƯỚNG DẪN CÔNG NHẬN HỌC PHẦN VÀO CHƯƠNG TRÌNH ĐÀO TẠO KỸ SƯ CHUYÊN SÂU\n\n## I. Phạm vi áp dụng:\n1. Dành cho học viên chương trình đào tạo kỹ sư chuyên sâu (KSCS) theo chương trình tích hợp.\n2. Dành cho học viên đã được cấp mã số học viên tạm thời và học viên đã được công nhận chính thức.",
106
- "Sinh viên tham gia chương trình được tuyển chọn dựa trên thành tích học tập xuất sắc và có tiềm năng nghiên cứu. Chương trình đảm bảo trang bị cho người học kiến thức chuyên sâu theo định hướng nghiên cứu, khả năng tư duy độc lập và sáng tạo, đáp ứng yêu cầu nhân lực chất lượng cao. Chương trình được tổ chức với quy mô lớp học nhỏ, giảng viên có trình độ cao và phương pháp giảng dạy hiện đại, tạo điều kiện tối ưu để sinh viên phát huy năng lực. Sinh viên thuộc các CTĐT Tài năng được tạo điều kiện để tham gia các hoạt động nghiên cứu khoa học, trao đổi học thuật, công nhận tín chỉ đã tích lũy từ các cơ sở đào tạo đối tác.\n\n6. Thời gian và khối lượng học tập chuẩn đối với các CTĐT theo hình thức chính quy không kể các học phần bổ sung kiến thức được quy định như sau:\nChương trình Cử nhân dành cho người học tốt nghiệp THPT,\nthời gian đào tạo 4 năm, khối lượng học tập tối thiểu 132 tín chỉ.\nChương trình Kỹ sư dành cho người học tốt nghiệp cử nhân theo chương trình tích hợp,\nthời gian đào t",
107
- "### Điều 2. Ngành đào tạo, chương trình đào tạo\n1. Ngành đào tạo (sau đây gọi tắt là ngành) là một lĩnh vực chuyên môn rộng, có mã số trong Danh mục thống kê ngành đào tạo của giáo dục đại học do Bộ GDĐT quản lý 4 .\n2. Chương trình đào tạo (CTĐT) được xây dựng theo đơn vị tín chỉ (TC) và là bản thiết kế cho toàn bộ quá trình đào tạo của một ngành. Chương trình thể hiện rõ trình độ đào tạo; đối tượng đào tạo, điều kiện nhập học và điều kiện tốt nghiệp; m���c tiêu đào tạo, chuẩn kiến thức, kỹ năng, mức tự chủ và trách nhiệm của người học khi tốt nghiệp; nội dung (chương trình giảng dạy); kế hoạch đào tạo theo thời gian học tập chuẩn; phương pháp và hình thức đào tạo; cách thức đánh giá kết quả học tập; các điều kiện thực hiện chương trình.\n3. CTĐT tích hợp là chương trình được thiết kế tổng thể theo hướng tích hợp kiến thức, kỹ năng của hai bậc trình độ, đảm bảo học tập liên tục giữa các bậc đào tạo nhằm tối ưu hóa thời gian đào tạo cho người học. CTĐT tích hợp cử nhân-kỹ sư, cử nhân-thạc "
108
- ]
109
- }
110
- ]
111
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
evaluation/results/ragas_20260105_130744.json DELETED
@@ -1,111 +0,0 @@
1
- {
2
- "timestamp": "20260105_130744",
3
- "retrieval_mode": "bm25_only",
4
- "config": {
5
- "sample_size": 5,
6
- "gen_model": "nex-agi/DeepSeek-V3.1-Nex-N1",
7
- "eval_model": "nex-agi/DeepSeek-V3.1-Nex-N1",
8
- "embed_model": "Qwen/Qwen3-Embedding-4B",
9
- "collection": "hust_rag_collection",
10
- "doc_count": 1441
11
- },
12
- "scores": [
13
- {
14
- "faithfulness": 0.875,
15
- "answer_relevancy": 0.7264722326341989,
16
- "context_precision": 0.99999999995,
17
- "context_recall": 1.0,
18
- "rouge_score(mode=fmeasure)": 0.7589285714285714
19
- },
20
- {
21
- "faithfulness": 0.9285714285714286,
22
- "answer_relevancy": 0.7342079659938445,
23
- "context_precision": 0.999999999975,
24
- "context_recall": 1.0,
25
- "rouge_score(mode=fmeasure)": 0.6351351351351351
26
- },
27
- {
28
- "faithfulness": 0.8888888888888888,
29
- "answer_relevancy": 0.8335330619249784,
30
- "context_precision": 0.9999999999666667,
31
- "context_recall": 1.0,
32
- "rouge_score(mode=fmeasure)": 0.5673352435530086
33
- },
34
- {
35
- "faithfulness": 0.42857142857142855,
36
- "answer_relevancy": 0.6506986819875058,
37
- "context_precision": 0.99999999998,
38
- "context_recall": 1.0,
39
- "rouge_score(mode=fmeasure)": 0.5048543689320388
40
- },
41
- {
42
- "faithfulness": 0.8333333333333334,
43
- "answer_relevancy": 0.8338701751762124,
44
- "context_precision": 0.9999999999,
45
- "context_recall": 1.0,
46
- "rouge_score(mode=fmeasure)": 0.5344827586206896
47
- }
48
- ],
49
- "samples": [
50
- {
51
- "question": "Chương trình đào tạo ngành Kỹ thuật Cơ điện tử được xây dựng dựa trên những cơ sở nào?",
52
- "answer": "Dựa trên CONTEXT được cung cấp, chương trình đào tạo ngành Kỹ thuật Cơ điện tử được xây dựng trên cơ sở:\n\n- Phát triển chương trình đào tạo ngành Cơ điện tử năm 2009.\n- Tham khảo chương trình đào tạo ngành Cơ điện tử của các trường đại học nổi tiếng trên thế giới như Stanford, Chico (Hoa Kỳ), Sibaura (Nhật Bản), Đại học Quốc gia Đài Loan (NTU).\n\nNguồn: 1.1. Kỹ thuật Cơ điện tử.md",
53
- "ground_truth": "Chương trình đào tạo ngành Kỹ thuật Cơ điện tử được xây dựng trên cơ sở phát triển chương trình năm 2009, kết hợp tham khảo chương trình đào tạo của các trường đại học nổi tiếng trên thế giới như Stanford, Chico (Hoa Kỳ), Sibaura (Nhật Bản) và Đại học Quốc gia Đài Loan (NTU), đồng thời được kiểm định theo tiêu chuẩn AUN-QA năm 2017.",
54
- "contexts": [
55
- "## 1. Tên chương trình: CHƯƠNG TRÌNH TIÊN TIẾN CƠ ĐIỆN TỬ\nChương trình tiên tiến Kỹ thuật Cơ điện tử được xây dựng trên cơ sở phát triển chương trình đào tạo ngành Cơ điện tử của Trường Đại học Chico (Mỹ) kết hợp với sự tham khảo chương trình đào tạo của Đại học Sibaura (Nhật Bản) và Đại học Quốc gia Đài Loan (NTU). Chương trình đào tạo đã được kiểm định theo tiêu chuẩn AUN -QA năm 2017.\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu, khả năng làm việc và sáng tạo trong mọi môi trường lao động để giải quyết những vấn đề liên quan đến thiết kế, chế tạo thiết bị, hệ thống cơ điện tử và vận hành hệ thống sản xuất công nghiệp, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.\nNgôn ngữ đào tạo chính: Tiếng Anh.",
56
- "# 1. Tên chương trình: KỸ THUẬT CƠ ĐIỆN TỬ\nChương trình đào tạo ngành Cơ điện tử hiện nay được xây dựng trên cơ sở phát triển chương trình đào tạo ngành Cơ điện tử năm 2009 kết hợp với sự tham khảo chương trình đào tạo ngành Cơ điện tử của các trường đại học nổi tiếng trên thế giới như Stanford, Chico (Koa Kỳ), Sibaura (Nhật Bản), Đại học Quốc gia Đài Loan (NTU)…; Chương trình được kiểm định theo tiêu chuẩn AUN -QA năm 2017;\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu, khả năng làm việc và sáng tạo trong mọi môi trường lao động để giải quyết những vấn đề liên quan đến nghiên cứu thiết kế, chế tạo thiết bị, hệ thống cơ điện tử và vận hành các hệ thống sản xuất công nghiệp, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.",
57
- "## 1. Tên chương trình: KỸ THUẬT CƠ KHÍ\n\nChương trình đào tạo cử nhân – kỹ sư ng��nh Kỹ thuật Cơ khí được xây dựng dựa trên sự phát triển chương trình đào tạo ngành Chế tạo máy trước đây kết hợp với sự tham khảo chương trình đào tạo ngành chế tạo máy của các trường đại học tiên tiến trên thế giới như: Stanford (Hoa Kỳ), NTU (Đài Loan), RMIT (Úc), … ;\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu để có thể làm việc và sáng tạo trong mọi môi trường lao động nhằm giải quyết những vấn đề liên quan đến thiết kế, chế tạo, vận hành và bảo trì các máy móc, thiết bị cơ khí và các hệ thống sản xuất công nghiệp đáp ứng yêu cầu của xã hội, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.",
58
- "# 2. Kiến thức, kỹ năng đạt được sau tốt nghiệp\n\n## a. Kiến thức\nCó kiến thức chuyên môn rộng và vững chắc, thích ứng tốt với những công việc phù hợp với ngành, chú trọng khả năng áp dụng kiến thức cơ sở và cốt lõi ngành Cơ điện tử kết hợp khả năng sử dụng công cụ hiện đại để nghiên cứu, thiết kế, chế tạo, xây dựng và vận hành các hệ thống/quá trình/sản phẩm Cơ điện tử.",
59
- "## 2. Kiến thức, kỹ năng đạt được sau tốt nghiệp\n\n## a. Kiến thức\nCó kiến thức chuyên môn rộng và vững chắc, thích ứng tốt với những công việc phù hợp với ngành, chú trọng khả năng áp dụng kiến thức cơ sở và cốt lõi ngành Cơ điện tử kết hợp khả năng sử dụng công cụ hiện đại để nghiên cứu, thiết kế, chế tạo, xây dựng và vận hành các hệ thống/quá trình/sản phẩm cơ điện tử."
60
- ]
61
- },
62
- {
63
- "question": "Sinh viên tốt nghiệp ngành Kỹ thuật Cơ điện tử đạt được những kiến thức chuyên môn gì?",
64
- "answer": "Dựa trên CONTEXT được cung cấp, sinh viên tốt nghiệp ngành Kỹ thuật Cơ điện tử sẽ đạt được những kiến thức chuyên môn sau:\n\n**Kiến thức chuyên môn:**\n- Có kiến thức chuyên môn rộng và vững chắc, thích ứng tốt với những công việc phù hợp với ngành.\n- Chú trọng khả năng áp dụng kiến thức cơ sở và cốt lõi ngành Cơ điện tử.\n- Kết hợp khả năng sử dụng công cụ hiện đại để:\n - Nghiên cứu\n - Thiết kế\n - Chế tạo\n - Xây dựng\n - Vận hành các hệ thống/quá trình/sản phẩm Cơ điện tử.\n\n**Nguồn:** Tài liệu 1.1. Kỹ thuật Cơ điện tử.md, Mục 2. Kiến thức, kỹ năng đạt được sau tốt nghiệp",
65
- "ground_truth": "Sinh viên tốt nghiệp có kiến thức chuyên môn rộng và vững chắc, có khả năng áp dụng kiến thức cơ sở và cốt lõi của ngành Cơ điện tử kết hợp với việc sử dụng các công cụ hiện đại để nghiên cứu, thiết kế, chế tạo, xây dựng và vận hành các hệ thống, quá trình và sản phẩm Cơ điện tử.",
66
- "contexts": [
67
- "# 2. Kiến thức, kỹ năng đạt được sau tốt nghiệp\n\n## a. Kiến thức\nCó kiến thức chuyên môn rộng và vững chắc, thích ứng tốt với những công việc phù hợp với ngành, chú trọng khả năng áp dụng kiến thức cơ sở và cốt lõi ngành Cơ điện tử kết hợp khả năng sử dụng công cụ hiện đại để nghiên cứu, thiết kế, chế tạo, xây dựng và vận hành các hệ thống/quá trình/sản phẩm Cơ điện tử.",
68
- "## 2. Kiến thức, kỹ năng đạt được sau tốt nghiệp\n\n## a. Kiến thức\nCó kiến thức chuyên môn rộng và vững chắc, thích ứng tốt với những công việc phù hợp với ngành, chú trọng khả năng áp dụng kiến thức cơ sở và cốt lõi ngành Cơ điện tử kết hợp khả năng sử dụng công cụ hiện đại để nghiên cứu, thiết kế, chế tạo, xây dựng và vận hành các hệ thống/quá trình/sản phẩm cơ điện tử.",
69
- "## 1. Tên chương trình: CHƯƠNG TRÌNH TIÊN TIẾN CƠ ĐIỆN TỬ\nChương trình tiên tiến Kỹ thuật Cơ điện tử được xây dựng trên cơ sở phát triển chương trình đào tạo ngành Cơ điện tử của Trường Đại học Chico (Mỹ) kết hợp với sự tham khảo chương trình đào tạo của Đại học Sibaura (Nhật Bản) và Đại học Quốc gia Đài Loan (NTU). Chương trình đào tạo đã được kiểm định theo tiêu chuẩn AUN -QA năm 2017.\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu, khả năng làm việc và sáng tạo trong mọi môi trường lao động để giải quyết những vấn đề liên quan đến thiết kế, chế tạo thiết bị, hệ thống cơ điện tử và vận hành hệ thống sản xuất công nghiệp, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.\nNgôn ngữ đào tạo chính: Tiếng Anh.",
70
- "## 2. Kiến thức, kỹ năng đạt được sau tốt nghiệp\n\n## a. Kiến thức\nCó kiến thức cơ sở chuyên môn rộng và vững chắc, thích ứng tốt với những công việc phù hợp với ngành học,\nChú trọng khả năng áp dụng kiến thức cơ sở và cốt lõi ngành Kỹ thuật Cơ khí kết hợp khả năng sử dụng công cụ hiện đại để thiết kế, chế tạo, vận hành, nghiên cứu phân tích, cải tiến máy móc, thiết bị hay hệ thống sản xuất.",
71
- "## 1. Tên chương trình: KỸ THUẬT ĐIỆN TỬ -VIỄN THÔNG\n\nNgành Điện tử - Viễn thông là một trong những ngành mũi nhọn của cuộc Cách mạng công nghiệp lần thứ 4 và là ngành có nhu cầu cao về nhân lực ở Việt Nam và trên thế giới. Theo học ngành này, sinh viên được trang bị một cách toàn diện cả về kỹ năng chuyên môn và kỹ năng mềm để có thể thiết kế, chế tạo, vận hành các thiết bị và hệ thống điện tử viễn thông, đáp ứng được yêu cầu về tính năng động và sáng tạo của lĩnh vực nghề nghiệp này.\n\nChương trình kỹ thuật Điện tử- Viễn thông được giảng dạy bằng tiếng Việt và được thiết kế bao gồm khối kiến thức toán học và khoa học cơ bản, khối kiến thức cơ sở cốt lõi ngành Điện tử -Viễn thông, khối kiến thức bổ trợ kiến thức xã hội và kỹ năng mềm và khối kiến thức tự chọn chuyên sâu theo các định hướng kỹ thuật điện tử, kỹ thuật máy tính, kỹ thuật thông tin truyền thông, kỹ thuật y sinh, kỹ thuật điện tử hàng không vũ trụ, kỹ thuật đa phương tiện, kỹ thuật vi điện tử và công nghệ nano."
72
- ]
73
- },
74
- {
75
- "question": "Tại sao sinh viên ngành Kỹ thuật Cơ điện tử có thể nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0?",
76
- "answer": "Dựa trên CONTEXT được cung cấp, sinh viên ngành Kỹ thuật Cơ điện tử có thể nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0 vì:\n\nChương trình đào tạo trang bị cho sinh viên:\n- **Các kiến thức cơ sở và chuyên ngành vững chắc**\n- **Kỹ năng nghề nghiệp và năng lực nghiên cứu**\n- **Khả năng làm việc và sáng tạo trong mọi môi trường lao động**\n- **Năng lực giải quyết những vấn đề liên quan đến nghiên cứu thiết kế, chế tạo thiết bị, hệ thống cơ điện tử và vận hành các hệ thống sản xuất công nghiệp**\n\nĐây là những yếu tố cốt lõi giúp sinh viên tốt nghiệp có đủ năng lực để thích ứng nhanh với yêu cầu của cuộc cách mạng công nghiệp 4.0.\n\n**Nguồn:** 1.1. Kỹ thuật Cơ điện tử.md",
77
- "ground_truth": "Vì chương trình đào tạo trang bị cho sinh viên nền tảng kiến thức cơ sở và chuyên ngành vững chắc, kỹ năng nghề nghiệp, năng lực nghiên cứu, khả năng làm việc và sáng tạo trong nhiều môi trường lao động, giúp giải quyết các vấn đề liên quan đến thiết kế, chế tạo và vận hành các hệ thống cơ điện tử trong sản xuất công nghiệp hiện đại.",
78
- "contexts": [
79
- "## 1. Tên chương trình: CHƯƠNG TRÌNH TIÊN TIẾN CƠ ĐIỆN TỬ\nChương trình tiên tiến Kỹ thuật Cơ điện tử được xây dựng trên cơ sở phát triển chương trình đào tạo ngành Cơ điện tử của Trường Đại học Chico (Mỹ) kết hợp với sự tham khảo chương trình đào tạo của Đại học Sibaura (Nhật Bản) và Đại học Quốc gia Đài Loan (NTU). Chương trình đào tạo đã được kiểm định theo tiêu chuẩn AUN -QA năm 2017.\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu, khả năng làm việc và sáng tạo trong mọi môi trường lao động để giải quyết những vấn đề liên quan đến thiết kế, chế tạo thiết bị, hệ thống cơ điện tử và vận hành hệ thống sản xuất công nghiệp, nhanh chóng thích ứng với môi trường l��m việc của cuộc cách mạng công nghiệp 4.0.\nNgôn ngữ đào tạo chính: Tiếng Anh.",
80
- "# 1. Tên chương trình: KỸ THUẬT CƠ ĐIỆN TỬ\nChương trình đào tạo ngành Cơ điện tử hiện nay được xây dựng trên cơ sở phát triển chương trình đào tạo ngành Cơ điện tử năm 2009 kết hợp với sự tham khảo chương trình đào tạo ngành Cơ điện tử của các trường đại học nổi tiếng trên thế giới như Stanford, Chico (Koa Kỳ), Sibaura (Nhật Bản), Đại học Quốc gia Đài Loan (NTU)…; Chương trình được kiểm định theo tiêu chuẩn AUN -QA năm 2017;\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu, khả năng làm việc và sáng tạo trong mọi môi trường lao động để giải quyết những vấn đề liên quan đến nghiên cứu thiết kế, chế tạo thiết bị, hệ thống cơ điện tử và vận hành các hệ thống sản xuất công nghiệp, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.",
81
- "## 1. Tên chương trình: KỸ THUẬT CƠ KHÍ\n\nChương trình đào tạo cử nhân – kỹ sư ngành Kỹ thuật Cơ khí được xây dựng dựa trên sự phát triển chương trình đào tạo ngành Chế tạo máy trước đây kết hợp với sự tham khảo chương trình đào tạo ngành chế tạo máy của các trường đại học tiên tiến trên thế giới như: Stanford (Hoa Kỳ), NTU (Đài Loan), RMIT (Úc), … ;\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu để có thể làm việc và sáng tạo trong mọi môi trường lao động nhằm giải quyết những vấn đề liên quan đến thiết kế, chế tạo, vận hành và bảo trì các máy móc, thiết bị cơ khí và các hệ thống sản xuất công nghiệp đáp ứng yêu cầu của xã hội, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.",
82
- "## b. Kỹ năng\n- Kỹ năng chuyên nghiệp và phẩm chất cá nhân, kỹ năng xã hội cần thiết và giao tiếp để làm việc hiệu quả trong nhóm đa ngành và trong môi trường hội nhập quốc tế; có năng lực khởi nghiệp và thích ứng tốt với cuộc cách mạng công nghiệp 4.0.\n- Hiểu biết về chính trị, kinh tế; có kiến thức cơ bản về khoa học xã hội và nhân văn phù hợp với chuyên ngành được được đào tạo để đóng góp hiệu quả vào sự phát triển bền vững của đất nước.",
83
- "## b. Kỹ năng\n- Có kỹ năng chuyên nghiệp và phẩm chất cá nhân, kỹ năng xã hội cần thiết và giao tiếp để làm việc hiệu quả trong nhóm đa ngành và trong môi trường hội nhập quốc tế;\n- Có năng lực khởi nghiệp và thích ứng tốt với cuộc cách mạng công nghiệp 4.0;\n- Có kiến thức cơ bản về khoa học xã hội và nhân văn phù hợp với ngành Kỹ thuật Sinh học để đóng góp hiệu quả vào sự phát triển bền vững của đất nước."
84
- ]
85
- },
86
- {
87
- "question": "Chương trình đào tạo ngành Kỹ thuật Cơ điện tử được điều chỉnh như thế nào để đảm bảo tính cập nhật mà không ảnh hưởng đến người học?",
88
- "answer": "Dựa trên tài liệu về Chương trình tiên tiến Cơ điện tử (ME-E1), chương trình đào tạo được điều chỉnh như sau:\n\n**Chương trình đào tạo có thể được điều chỉnh hàng năm để đảm bảo tính cập nhật với sự phát triển của khoa học, kỹ thuật và công nghệ; tuy nhiên đảm bảo nguyên tắc không gây ảnh hưởng ngược tới kết quả người học đã tích lũy.**\n\nĐiều này có nghĩa là:\n- Chương trình được cập nhật hàng năm theo xu hướng phát triển của khoa học, kỹ thuật và công nghệ\n- Việc điều chỉnh tuân thủ nguyên tắc bảo vệ quyền lợi của người học, không làm ảnh hưởng đến kết quả học tập mà sinh viên đã tích lũy được\n\n*Nguồn: 1.6. Chương trình tiên tiến Cơ điện tử.md*",
89
- "ground_truth": "Chương trình đào tạo có thể được điều chỉnh hàng năm nhằm đảm bảo tính cập nhật với sự phát triển của khoa học, kỹ thuật và công nghệ, nhưng vẫn tuân thủ nguyên tắc không gây ảnh hưởng ngược tới kết quả học tập mà người học đã tích lũy.",
90
- "contexts": [
91
- "## 3. Thời gian đào tạo\n\n- Đào tạo Kỹ sư: 5 năm\n\n## 4. Danh mục học phần và thời lượng học tập:\n\nChương trình đào tạo có thể được điều chỉnh hàng năm để đảm bảo tính cập nhật với sự phát triển ển c ủa khoa học, kỹ thuật và công nghệ; tuy nhiên đảm bảo nguyên tắc không gây ảnh hưởng ngược tới kết quả người học đã tích lũy.",
92
- "## 3. Thời gian đào tạo\n\n- Đào tạo Kỹ sư: 5 năm\n\n## 4. Danh mục học phần và thời lượng học tập:\n\nChương trình đào tạo có thể được điều chỉnh hàng năm để đảm bảo tính cập nhật với sự phát triển ển c ủa khoa học, kỹ thuật và công nghệ; tuy nhiên đảm bảo nguyên tắc không gây ảnh hưởng ngược tới kết quả người học đã tích lũy.",
93
- "## 4. Danh mục học phần và thời lượng học tập:\nChương trình đào tạo có thể được điều chỉnh hàng năm để đảm bảo tính cập nhật với sự phát triển của khoa học, kỹ thuật và công nghệ; tuy nhiên đảm bảo nguyên tắc không gây ảnh hưởng ngược tới kết quả người học đã tích lũy.",
94
- "## 4. Danh mục học phần và thời lượng học tập:\n\nChương trình đào tạo có thể được điều chỉnh hàng năm để đảm bảo tính cập nhật với sự phát triển c ủa khoa học, kỹ thuật và công nghệ; tuy nhiên đảm bảo nguyên tắc không gây ảnh hưởng ngược tới kết quả người học đã tích lũy.",
95
- "## 4. Danh mục học phần và thời lượng học tập:\nChương trình đào tạo có thể được điều chỉnh hàng năm để đảm bảo tính cập nhật với sự phát triển c ủa khoa học, kỹ thuật và công nghệ; tuy nhiên đảm bảo nguyên tắc không gây ảnh hưởng ngược tới kết quả người học đã tích lũy."
96
- ]
97
- },
98
- {
99
- "question": "Chương trình đào tạo kỹ sư chuyên sâu đặc thù (180 tín chỉ) áp dụng cho những đối tượng sinh viên nào?",
100
- "answer": "Dựa trên tài liệu hướng dẫn học tập chương trình đào tạo kỹ sư chuyên sâu đặc thù (180 TC), chương trình này áp dụng với:\n\n**Đối tượng áp dụng:**\n- Sinh viên các khóa từ K62 đang học tập tại Đại học Bách khoa Hà Nội\n- Sinh viên có mong muốn tiếp tục học tập theo chương trình đào tạo kỹ sư chuyên sâu đặc thù\n\n**Nguồn:** 01_3 HD hoc chuyen tiep ky su 180 TC_Final.md | Mục: /HƯỚNG DẪN HỌC TẬP CHƯƠNG TRÌNH ĐÀO TẠO KỸ SƯ CHUYÊN SÂU ĐẶC THÙ (180 TC)/ | Phần: 1. Phạm vi áp dụng",
101
- "ground_truth": "Chương trình áp dụng cho sinh viên các khóa từ K62 đang học tập và có mong muốn tiếp tục học theo chương trình kỹ sư chuyên sâu đặc thù, đồng thời áp dụng cho các chương trình đào tạo có đào tạo bậc kỹ sư chuyên sâu đặc thù.",
102
- "contexts": [
103
- "# HƯỚNG DẪN HỌC TẬP CHƯƠNG TRÌNH ĐÀO TẠO KỸ SƯ CHUYÊN SÂU ĐẶC THÙ (180 TC)\n\n## 1. Phạm vi áp dụng\n+ Áp dụng với sinh viên các khóa từ K62 đang học tập và có mong muốn tiếp tục học tập theo chương trình đạo tạo kỹ sư chuyên sâu đặc thù.\n+ Áp dụng với các chương trình đào tạo (viết tắt là: CTĐT) có đào tạo bậc kỹ sư chuyên sâu đặc thù (viết tắt là: KS) .",
104
- "### Điều 1. Phạm vi điều chỉnh và đối tượng áp dụng\n\n1. Phạm vi điều chỉnh: Văn bản này quy định về đối tượng, tiêu chuẩn, quy trình, thủ tục đăng ký xét, cấp học bổng cho sinh viên/học viên (sau đây gọi chung là người học) Đại học Bách khoa Hà Nội có đồ án tốt nghiệp/khóa luận tốt nghiệp góp phần cải tiến, nâng cao chất lượng, hiệu quả kinh doanh, sản xuất hoặc chất lượng các dịch vụ an sinh xã hội tại quê hương của người học. Học bổng này được cấp với tên gọi là Học bổng Gắn kết quê hương .\n2. Đối tượng áp dụng: Quy định này áp dụng đối với sinh viên hệ đại học chính quy văn bằng thứ nhất hoặc học viên chương trình kỹ sư chuyên sâu đặc thù đang học tập tại Đại học Bách khoa Hà Nội.",
105
- "## 4. Điểm trung bình toàn khóa và hạng tốt nghiệp kỹ sư\n+ Điểm của các học phần bậc kỹ sư chuyên sâu đặc thù sẽ không được sử dụng để xét cấp học bổng khuyến khích học tập ở bậc cử nhân .\n+ Điểm trung bình toàn khóa và hạng tốt nghiệp kỹ sư được thực hiện theo Quy chế đào tạo hiện hành .\n+ Trích dẫn quy định về điểm trung bình toàn khóa: \" là điểm trung bình tích lũy của cả giai đoạn đào tạo cử nhân đã tốt nghiệp và giai đoạn đào tạo kỹ sư, với trọng số là tỷ lệ phần trăm của s ố tín chỉ tích lũy của mỗi giai đoạn đào tạo trong tổng số tín chỉ tích lũy của cả hai giai đoạn\".\n+ Xếp bậc năng lực với người học được cấp bằng kỹ sư chuyên sâu đặc thù: người học hoàn thành đủ các học phần theo yêu cầu của CTĐT và đạt chứng chỉ ngoại ngữ tối thiểu trình độ B2 (hoặc tương đương) theo Khung năng lực ngoại ngữ 6 bậc của Việt Nam: được cấp bằng Kỹ sư chuyên sâu đặc thù trình độ Bậc 7 theo Khung trình độ quốc gia Việt Nam .",
106
- "### 6) Chế độ miễn giảm học phí\n\n- Đại học hỗ trợ toàn bộ phần chênh lệch giữa mức học phí của Đại học với mức học phí được miễn, giảm theo quy định của Nhà nước đối với các sinh viên thuộc đối tượng được hưởng chế độ chính sách miễn, giảm học phí theo quy định.\n- Việc hỗ trợ học phí chênh lệch và chế độ miễn giảm học phí theo quy định của Nhà nước tại mục 1, 2, 3 của Phụ lục này không áp dụng với các học phần thuộc khung chương trình đào tạo kỹ sư chuyên sâu đặc thù.",
107
- "## 6) Chế độ miễn giảm học phí\n\n- -Đại học hỗ trợ toàn bộ phần chênh lệch giữa mức học phí của Đại học với mức học phí được miễn, giảm theo quy định của Nhà nước đối với các sinh viên thuộc đối tượng được hưởng chế độ chính sách miễn, giảm học phí theo quy định.\n- -Việc hỗ trợ học phí chênh lệch và chế độ miễn giảm học phí theo quy định của Nhà nước tại mục 1, 2, 3 của Phụ lục này không áp dụng với các học phần thuộc khung chương trình đào tạo kỹ sư chuyên sâu ."
108
- ]
109
- }
110
- ]
111
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
evaluation/results/ragas_20260105_131901.json DELETED
@@ -1,111 +0,0 @@
1
- {
2
- "timestamp": "20260105_131901",
3
- "retrieval_mode": "hybrid",
4
- "config": {
5
- "sample_size": 5,
6
- "gen_model": "nex-agi/DeepSeek-V3.1-Nex-N1",
7
- "eval_model": "nex-agi/DeepSeek-V3.1-Nex-N1",
8
- "embed_model": "Qwen/Qwen3-Embedding-4B",
9
- "collection": "hust_rag_collection",
10
- "doc_count": 1441
11
- },
12
- "scores": [
13
- {
14
- "faithfulness": 0.8571428571428571,
15
- "answer_relevancy": 0.8972923254436237,
16
- "context_precision": 0.99999999995,
17
- "context_recall": 1.0,
18
- "rouge_score(mode=fmeasure)": 0.7606837606837608
19
- },
20
- {
21
- "faithfulness": 1.0,
22
- "answer_relevancy": 0.7008081720389104,
23
- "context_precision": 0.94999999997625,
24
- "context_recall": 1.0,
25
- "rouge_score(mode=fmeasure)": 0.44655581947743467
26
- },
27
- {
28
- "faithfulness": 1.0,
29
- "answer_relevancy": 0.8991661959917713,
30
- "context_precision": 0.99999999995,
31
- "context_recall": 1.0,
32
- "rouge_score(mode=fmeasure)": 0.6297577854671281
33
- },
34
- {
35
- "faithfulness": 1.0,
36
- "answer_relevancy": 0.0,
37
- "context_precision": 0.99999999998,
38
- "context_recall": 1.0,
39
- "rouge_score(mode=fmeasure)": 0.1372549019607843
40
- },
41
- {
42
- "faithfulness": 0.7,
43
- "answer_relevancy": 0.7942512688700306,
44
- "context_precision": 0.49999999995,
45
- "context_recall": 1.0,
46
- "rouge_score(mode=fmeasure)": 0.39747634069400634
47
- }
48
- ],
49
- "samples": [
50
- {
51
- "question": "Chương trình đào tạo ngành Kỹ thuật Cơ điện tử được xây dựng dựa trên những cơ sở nào?",
52
- "answer": "Dựa trên tài liệu được cung cấp, chương trình đào tạo ngành Kỹ thuật Cơ điện tử được xây dựng trên cơ sở phát triển chương trình đào tạo ngành Cơ điện tử năm 2009, kết hợp với sự tham khảo chương trình đào tạo ngành Cơ điện tử của các trường đại học nổi tiếng trên thế giới như Stanford, Chico (Hoa Kỳ), Sibaura (Nhật Bản), Đại học Quốc gia Đài Loan (NTU).\n\nNguồn: 1.1. Kỹ thuật Cơ điện tử.md",
53
- "ground_truth": "Chương trình đào tạo ngành Kỹ thuật Cơ điện tử được xây dựng trên cơ sở phát triển chương trình năm 2009, kết hợp tham khảo chương trình đào tạo của các trường đại học nổi tiếng trên thế giới như Stanford, Chico (Hoa Kỳ), Sibaura (Nhật Bản) và Đại học Quốc gia Đài Loan (NTU), đồng thời được kiểm định theo tiêu chuẩn AUN-QA năm 2017.",
54
- "contexts": [
55
- "# 1. Tên chương trình: KỸ THUẬT CƠ ĐIỆN TỬ\nChương trình đào tạo ngành Cơ điện tử hiện nay được xây dựng trên cơ sở phát triển chương trình đào tạo ngành Cơ điện tử năm 2009 kết hợp với sự tham khảo chương trình đào tạo ngành Cơ điện tử của các trường đại học nổi tiếng trên thế giới như Stanford, Chico (Koa Kỳ), Sibaura (Nhật Bản), Đại học Quốc gia Đài Loan (NTU)…; Chương trình được kiểm định theo tiêu chuẩn AUN -QA năm 2017;\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu, khả năng làm việc và sáng tạo trong mọi môi trường lao động để giải quyết những vấn đề liên quan đến nghiên cứu thiết kế, chế tạo thiết bị, hệ thống cơ điện tử và vận hành các hệ thống sản xuất công nghiệp, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.",
56
- "## 1. Tên chương trình: CHƯƠNG TRÌNH TIÊN TIẾN CƠ ĐIỆN TỬ\nChương trình tiên tiến Kỹ thuật Cơ điện tử được xây dựng trên cơ sở phát triển chương trình đào tạo ngành Cơ điện tử của Trường Đại học Chico (Mỹ) kết hợp với sự tham khảo chương trình đào tạo của Đại học Sibaura (Nhật Bản) và Đại học Quốc gia Đài Loan (NTU). Chương trình đào tạo đã được kiểm định theo tiêu chuẩn AUN -QA năm 2017.\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu, khả năng làm việc và sáng tạo trong mọi môi trường lao động để giải quyết những vấn đề liên quan đến thiết kế, chế tạo thiết bị, hệ thống cơ điện tử và vận hành hệ thống sản xuất công nghiệp, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.\nNgôn ngữ đào tạo chính: Tiếng Anh.",
57
- "## 1. Tên chương trình: KỸ THUẬT CƠ KHÍ\n\nChương trình đào tạo cử nhân – kỹ sư ngành Kỹ thuật Cơ khí được xây dựng dựa trên sự phát triển chương trình đào tạo ngành Chế tạo máy trước đây kết hợp với sự tham khảo chương trình đào tạo ngành chế tạo máy của các trường đại học tiên tiến trên thế giới như: Stanford (Hoa Kỳ), NTU (Đài Loan), RMIT (Úc), … ;\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu để có thể làm việc và sáng tạo trong mọi môi trường lao động nhằm giải quyết những vấn đề liên quan đến thiết kế, chế tạo, vận hành và bảo trì các máy móc, thiết bị cơ khí và các hệ thống sản xuất công nghiệp đáp ứng yêu cầu của xã hội, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.",
58
- "## 1. Tên chương trình: CHƯƠNG TRÌNH TIÊN TIẾN ĐIỆN TỬ -VIỄN THÔNG\n\nNgành Điện tử - Viễn thông là một trong những ngành mũi nhọn của cuộc Cách mạng công nghiệp lần thứ 4 và là ngành có nhu cầu cao về nhân lực ở Việt Nam và trên thế giới. Theo học chương trình này, sinh viên được trang bị một cách toàn diện cả về kỹ năng chuyên môn và kỹ năng mềm để có thể thiết kế, chế tạo, vận hành các thiết bị và hệ thống điện tử viễn thông, đáp ứng được yêu cầu về tính năng động và sáng tạo của lĩnh vực nghề nghiệp này.\n\nChương trình tiên tiến kỹ thuật Điện tử -Viễn thông được giảng dạy hoàn toàn bằng tiếng Anh và do các giảng viên của trường ĐHBK Hà Nội và các giảng viên nước ngoài tham gia giảng dạy.\n\nChương trình được thiết kế dựa trên chương trình của trường Đại học San Jose State University, Hoa Kỳ và bao gồm khối kiến thức toán học và khoa học cơ bản, khối kiến thức cơ sở cốt lõi ngành Điện tử -Viễn thông, khối kiến thức bổ trợ kiến thức xã hội và kỹ năng mềm và khối kiến thức chuyên sâu ngành",
59
- "# 2. Kiến thức, kỹ năng đạt được sau tốt nghiệp\n\n## a. Kiến thức\nCó kiến thức chuyên môn rộng và vững chắc, thích ứng tốt với những công việc phù hợp với ngành, chú trọng khả năng áp dụng kiến thức cơ sở và cốt lõi ngành Cơ điện tử kết hợp khả năng sử dụng công cụ hiện đại để nghiên cứu, thiết kế, chế tạo, xây dựng và vận hành các hệ thống/quá trình/sản phẩm Cơ điện tử."
60
- ]
61
- },
62
- {
63
- "question": "Sinh viên tốt nghiệp ngành Kỹ thuật Cơ điện tử đạt được những kiến thức chuyên môn gì?",
64
- "answer": "Dựa trên các tài liệu được cung cấp, sinh viên tốt nghiệp ngành Kỹ thuật Cơ điện tử sẽ đạt được những kiến thức chuyên môn sau:\n\n**Kiến thức chuyên môn:**\n- Có kiến thức chuyên môn rộng và vững chắc, thích ứng tốt với những công việc phù hợp với ngành\n- Chú trọng khả năng áp dụng kiến thức cơ sở và cốt lõi ngành Cơ điện tử\n- Kết hợp khả năng sử dụng công cụ hiện đại để:\n - Nghiên cứu\n - Thiết kế\n - Chế tạo\n - Xây dựng\n - Vận hành các hệ thống/quá trình/sản phẩm Cơ điện tử\n\n**Năng lực làm việc:**\n- Có kỹ năng nghề nghiệp và năng lực nghiên cứu\n- Khả năng làm việc và sáng tạo trong mọi môi trường lao động\n- Giải quyết những vấn đề liên quan đến nghiên cứu thiết kế, chế tạo thiết bị, hệ thống cơ điện tử\n- Vận hành các hệ thống sản xuất công nghiệp\n- Nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0\n\n*Nguồn: 1.1. Kỹ thuật Cơ điện tử.md, Mục 2. Kiến thức, kỹ năng đạt được sau tốt nghiệp*",
65
- "ground_truth": "Sinh viên tốt nghiệp có kiến thức chuyên môn rộng và vững chắc, có khả năng áp dụng kiến thức cơ sở và cốt lõi của ngành Cơ điện tử kết hợp với việc sử dụng các công cụ hiện đại để nghiên cứu, thiết kế, chế tạo, xây dựng và vận hành các hệ thống, quá trình và sản phẩm Cơ điện tử.",
66
- "contexts": [
67
- "# 2. Kiến thức, kỹ năng đạt được sau tốt nghiệp\n\n## a. Kiến thức\nCó kiến thức chuyên môn rộng và vững chắc, thích ứng tốt với những công việc phù hợp với ngành, chú trọng khả năng áp dụng kiến thức cơ sở và cốt lõi ngành Cơ điện tử kết hợp khả năng sử dụng công cụ hiện đại để nghiên cứu, thiết kế, chế tạo, xây dựng và vận hành các hệ thống/quá trình/sản phẩm Cơ điện tử.",
68
- "## 2. Kiến thức, kỹ năng đạt được sau tốt nghiệp\n\n## a. Kiến thức\nCó kiến thức chuyên môn rộng và vững chắc, thích ứng tốt với những công việc phù hợp với ngành, chú trọng khả năng áp dụng kiến thức cơ sở và cốt lõi ngành Cơ điện tử kết hợp khả năng sử dụng công cụ hiện đại để nghiên cứu, thiết kế, chế tạo, xây dựng và vận hành các hệ thống/quá trình/sản phẩm cơ điện tử.",
69
- "## 2. Kiến thức, kỹ năng đạt được sau tốt nghiệp\n\n## a. Kiến thức\nCó kiến thức cơ sở chuyên môn rộng và vững chắc, thích ứng tốt với những công việc phù hợp với ngành học,\nChú trọng khả năng áp dụng kiến thức cơ sở và cốt lõi ngành Kỹ thuật Cơ khí kết hợp khả năng sử dụng công cụ hiện đại để thiết kế, chế tạo, vận hành, nghiên cứu phân tích, cải tiến máy móc, thiết bị hay hệ thống sản xuất.",
70
- "## 2. Kiến thức, kỹ năng đạt được sau tốt nghiệp\n\n## a. Kiến thức\nSinh viên tốt nghiệp có kiến thức về khoa học cơ bản, về Kỹ thuật Cơ khí, về Kỹ thuật Hàng không vững vàng, có kỹ năng thực hành nghề nghiệp, đủ năng lực áp dụng các kiến thức để vận hành, bảo dưỡng, thiết kế và triển khai các hệ thống, thiết bị liên quan đến Cơ khí Hàng không .",
71
- "# 1. Tên chương trình: KỸ THUẬT CƠ ĐIỆN TỬ\nChương trình đào tạo ngành Cơ điện tử hiện nay được xây dựng trên cơ sở phát triển chương trình đào tạo ngành Cơ điện tử năm 2009 kết hợp với sự tham khảo chương trình đào tạo ngành Cơ điện tử của các trường đại học nổi tiếng trên thế giới như Stanford, Chico (Koa Kỳ), Sibaura (Nhật Bản), Đại học Quốc gia Đài Loan (NTU)…; Chương trình được kiểm định theo tiêu chuẩn AUN -QA năm 2017;\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu, khả năng làm việc và sáng tạo trong mọi môi trường lao động để giải quyết những vấn đề liên quan đến nghiên cứu thiết kế, chế tạo thiết bị, hệ thống cơ điện tử và vận hành các hệ thống sản xuất công nghiệp, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0."
72
- ]
73
- },
74
- {
75
- "question": "Tại sao sinh viên ngành Kỹ thuật Cơ điện tử có thể nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0?",
76
- "answer": "Theo tài liệu đào tạo ngành Kỹ thuật Cơ điện tử, sinh viên có thể nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0 vì:\n\nSinh viên được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu, khả năng làm việc và sáng tạo trong mọi môi trường lao động để giải quyết những vấn đề liên quan đến nghiên cứu thiết kế, chế tạo thiết bị, hệ thống cơ điện tử và vận hành các hệ thống sản xuất công nghiệp.\n\n**Nguồn:** 1.1. Kỹ thuật Cơ điện tử.md",
77
- "ground_truth": "Vì chương trình đào tạo trang bị cho sinh viên nền tảng kiến thức cơ sở và chuyên ngành vững chắc, kỹ năng nghề nghiệp, năng lực nghiên cứu, khả năng làm việc và sáng tạo trong nhiều môi trường lao động, giúp giải quyết các vấn đề liên quan đến thiết kế, chế tạo và vận hành các hệ thống cơ điện tử trong sản xuất công nghiệp hiện đại.",
78
- "contexts": [
79
- "# 1. Tên chương trình: KỸ THUẬT CƠ ĐIỆN TỬ\nChương trình đào tạo ngành Cơ điện tử hiện nay được xây dựng trên cơ sở phát triển chương trình đào tạo ngành Cơ điện tử năm 2009 kết hợp với sự tham khảo chương trình đào tạo ngành Cơ điện tử của các trường đại học nổi tiếng trên thế giới như Stanford, Chico (Koa Kỳ), Sibaura (Nhật Bản), Đại học Quốc gia Đài Loan (NTU)…; Chương trình được kiểm định theo tiêu chuẩn AUN -QA năm 2017;\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu, khả năng làm việc và sáng tạo trong mọi môi trường lao động để giải quyết những vấn đề li��n quan đến nghiên cứu thiết kế, chế tạo thiết bị, hệ thống cơ điện tử và vận hành các hệ thống sản xuất công nghiệp, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.",
80
- "## 1. Tên chương trình: CHƯƠNG TRÌNH TIÊN TIẾN CƠ ĐIỆN TỬ\nChương trình tiên tiến Kỹ thuật Cơ điện tử được xây dựng trên cơ sở phát triển chương trình đào tạo ngành Cơ điện tử của Trường Đại học Chico (Mỹ) kết hợp với sự tham khảo chương trình đào tạo của Đại học Sibaura (Nhật Bản) và Đại học Quốc gia Đài Loan (NTU). Chương trình đào tạo đã được kiểm định theo tiêu chuẩn AUN -QA năm 2017.\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu, khả năng làm việc và sáng tạo trong mọi môi trường lao động để giải quyết những vấn đề liên quan đến thiết kế, chế tạo thiết bị, hệ thống cơ điện tử và vận hành hệ thống sản xuất công nghiệp, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.\nNgôn ngữ đào tạo chính: Tiếng Anh.",
81
- "## 1. Tên chương trình: KỸ THUẬT CƠ KHÍ\n\nChương trình đào tạo cử nhân – kỹ sư ngành Kỹ thuật Cơ khí được xây dựng dựa trên sự phát triển chương trình đào tạo ngành Chế tạo máy trước đây kết hợp với sự tham khảo chương trình đào tạo ngành chế tạo máy của các trường đại học tiên tiến trên thế giới như: Stanford (Hoa Kỳ), NTU (Đài Loan), RMIT (Úc), … ;\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu để có thể làm việc và sáng tạo trong mọi môi trường lao động nhằm giải quyết những vấn đề liên quan đến thiết kế, chế tạo, vận hành và bảo trì các máy móc, thiết bị cơ khí và các hệ thống sản xuất công nghiệp đáp ứng yêu cầu của xã hội, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.",
82
- "## b. Kỹ năng\n- Có kỹ năng chuyên nghiệp và phẩm chất cá nhân, kỹ năng xã hội cần thiết và giao tiếp để làm việc hiệu quả trong nhóm đa ngành và trong môi trường hội nhập quốc tế;\n- Có năng lực khởi nghiệp và thích ứng tốt với cuộc cách mạng công nghiệp 4.0;\n- Có kiến thức cơ bản về khoa học xã hội và nhân văn phù hợp với ngành Kỹ thuật Sinh học để đóng góp hiệu quả vào sự phát triển bền vững của đất nước.",
83
- "## 1. Tên chương trình: KỸ THUẬT ĐIỆN TỬ -VIỄN THÔNG\n\nNgành Điện tử - Viễn thông là một trong những ngành mũi nhọn của cuộc Cách mạng công nghiệp lần thứ 4 và là ngành có nhu cầu cao về nhân lực ở Việt Nam và trên thế giới. Theo học ngành này, sinh viên được trang bị một cách toàn diện cả về kỹ năng chuyên môn và kỹ năng mềm để có thể thiết kế, chế tạo, vận hành các thiết bị và hệ thống điện tử viễn thông, đáp ứng được yêu cầu về tính năng động và sáng tạo của lĩnh vực nghề nghiệp này.\n\nChương trình kỹ thuật Điện tử- Viễn thông được giảng dạy bằng tiếng Việt và được thiết kế bao gồm khối kiến thức toán học và khoa học cơ bản, khối kiến thức cơ sở cốt lõi ngành Điện tử -Viễn thông, khối kiến thức bổ trợ kiến thức xã hội và kỹ năng mềm và khối kiến thức tự chọn chuyên sâu theo các định hướng kỹ thuật điện tử, kỹ thuật máy tính, kỹ thuật thông tin truyền thông, kỹ thuật y sinh, kỹ thuật điện tử hàng không vũ trụ, kỹ thuật đa phương tiện, kỹ thuật vi điện tử và công nghệ nano."
84
- ]
85
- },
86
- {
87
- "question": "Chương trình đào tạo ngành Kỹ thuật Cơ điện tử được điều chỉnh như thế nào để đảm bảo tính cập nhật mà không ảnh hưởng đến người học?",
88
- "answer": "Không tìm thấy thông tin trong dữ liệu hiện có.",
89
- "ground_truth": "Chương trình đào tạo có thể được điều chỉnh hàng năm nhằm đảm bảo tính cập nhật với sự phát triển của khoa học, kỹ thuật và công nghệ, nhưng vẫn tuân thủ nguyên tắc không gây ảnh hưởng ngược tới kết quả học tập mà người học đã tích lũy.",
90
- "contexts": [
91
- "## 4. Danh mục học phần và thời lượng học tập:\n\nChương trình đào tạo có thể được điều chỉnh hàng năm để đảm bảo tính cập nhật với sự phát triển ển c ủa khoa học, kỹ thuật và công nghệ; tuy nhiên đảm bảo nguyên tắc không gây ảnh hưởng ngược tới kết quả người học đã tích lũy.",
92
- "## 4. Danh mục học phần và thời lượng học tập:\nChương trình đào tạo có thể được điều chỉnh hàng năm để đảm bảo tính cập nhật với sự phát triển ển c ủa khoa học, kỹ thuật và công nghệ; tuy nhiên đảm bảo nguyên tắc không gây ảnh hưởng ngược tới kết quả người học đã tích lũy.",
93
- "## 4. Danh mục học phần và thời lượng học tập:\n\nChương trình đào tạo có thể được điều chỉnh hàng năm để đảm bảo tính cập nhật với sự phát triển c ủa khoa học, kỹ thuật và công nghệ; tuy nhiên đảm bảo nguyên tắc không gây ảnh hưởng ngược tới kết quả người học đã tích lũy.",
94
- "## 4. Danh mục học phần và thời lượng học tập:\nChương trình đào tạo có thể được điều chỉnh hàng năm để đảm bảo tính cập nhật với sự phát triển c ủa khoa học, kỹ thuật và công nghệ; tuy nhiên đảm bảo nguyên tắc không gây ảnh hưởng ngược tới kết quả người học đã tích lũy.",
95
- "## 3. Thời gian đào tạo\n\n- Đào tạo Kỹ sư: 5 năm\n\n## 4. Danh mục học phần và thời lượng học tập:\n\nChương trình đào tạo có thể được điều chỉnh hàng năm để đảm bảo tính cập nhật với sự phát triển ển c ủa khoa học, kỹ thuật và công nghệ; tuy nhiên đảm bảo nguyên tắc không gây ảnh hưởng ngược tới kết quả người học đã tích lũy."
96
- ]
97
- },
98
- {
99
- "question": "Chương trình đào tạo kỹ sư chuyên sâu đặc thù (180 tín chỉ) áp dụng cho những đối tượng sinh viên nào?",
100
- "answer": "Dựa trên CONTEXT được cung cấp, chương trình đào tạo kỹ sư chuyên sâu đặc thù (180 tín chỉ) áp dụng cho các đối tượng sau:\n\n1. **Sinh viên các khóa từ K62** đang học tập và có mong muốn tiếp tục học tập theo chương trình đào tạo kỹ sư chuyên sâu đặc thù.\n\n2. **Sinh viên chưa tốt nghiệp bậc cử nhân** đã tích lũy từ 118 tín chỉ trở lên của chương trình đào tạo cử nhân được phép học tích lũy trước tối đa 15 tín chỉ của chương trình kỹ sư.\n\n3. **Người học đã tốt nghiệp đại học** (CTĐT KSCS có khối lượng học tập 60 tín chỉ đối với người học đã tốt nghiệp đại học).\n\n**Nguồn:**\n- Tài liệu 2 (01_3 HD hoc chuyen tiep ky su 180 TC_Final.md)\n- Tài liệu 3 (03_ Quy định đào tạo KS 180 TC_signed.md)\n- Tài liệu 5 (01_3 HD hoc chuyen tiep ky su 180 TC_Final.md)",
101
- "ground_truth": "Chương trình áp dụng cho sinh viên các khóa từ K62 đang học tập và có mong muốn tiếp tục học theo chương trình kỹ sư chuyên sâu đặc thù, đồng thời áp dụng cho các chương trình đào tạo có đào tạo bậc kỹ sư chuyên sâu đặc thù.",
102
- "contexts": [
103
- "## 3. Thời gian đào tạo và khả năng học lên bậc học cao hơn\n\n- Đào tạo Cử nhân: 4 năm\n- Đào tạo Kỹ sư: 5 năm\n- Đào tạo tích hợp Cử nhân - Thạc sĩ: 5,5 năm\n- Đào tạo tích hợp Cử nhân - Thạc sĩ – Tiến sĩ: 8,5 năm",
104
- "# HƯỚNG DẪN HỌC TẬP CHƯƠNG TRÌNH ĐÀO TẠO KỸ SƯ CHUYÊN SÂU ĐẶC THÙ (180 TC)\n\n## 1. Phạm vi áp dụng\n+ Áp dụng với sinh viên các khóa từ K62 đang học tập và có mong muốn tiếp tục học tập theo chương trình đạo tạo kỹ sư chuyên sâu đặc thù.\n+ Áp dụng với các chương trình đào tạo (viết tắt là: CTĐT) có đào tạo bậc kỹ sư chuyên sâu đặc thù (viết tắt là: KS) .",
105
- "## II. Khung chương trình đào tạo kỹ sư chuyên sâu\n\n1. CTĐT KSCS có khối lượng học tập 60 tín chỉ đối với người học đã tốt nghiệp đại học. Thời gian học tập toàn khóa theo kế hoạch học tập chuẩn là 2 năm, người tốt nghiệp được cấp bằng kỹ sư bậc 7 theo Khung năng lực quốc gia Việt Nam .\n2. Điểm trung bình toàn khóa được sử dụng để xét tốt nghiệp và xếp hạng tốt nghiệp là điểm trung bình tích lũy toàn khóa tính theo các học phần đăng ký xét tốt nghiệp thuộc CTĐT KSCS .\n3. Học viên của CTĐT KSCS được Giám đốc Đại học Bách khoa Hà Nội công nhận tốt nghiệp được cấp bằng tốt nghiệp Kỹ sư bậc 7 theo Khung năng lực quốc gia Việt Nam.\n4. Khung quy định của CTĐT KSCS:\nKhung quy định của chương trình đào tạo Kỹ sư chuyên sâu đặc thù (KSCS) gồm các nhóm học phần sau:\nNhóm kiến thức định hướng chuyên ngành có khối lượng 12 tín chỉ,\ngồm các học phần được thiết kế theo nhóm để định hướng người học tiếp cận theo chuyên ngành.\nNhóm kiến thức chuyên ngành cốt lõi có khối lượng từ 19 đến 20 tín chỉ,\nlà ",
106
- "## 4. Điểm trung bình toàn khóa và hạng tốt nghiệp kỹ sư\n+ Điểm của các học phần bậc kỹ sư chuyên sâu đặc thù sẽ không được sử dụng để xét cấp học bổng khuyến khích học tập ở bậc cử nhân .\n+ Điểm trung bình toàn khóa và hạng tốt nghiệp kỹ sư được thực hiện theo Quy chế đào tạo hiện hành .\n+ Trích dẫn quy định về điểm trung bình toàn khóa: \" là điểm trung bình tích lũy của cả giai đoạn đào tạo cử nhân đã tốt nghiệp và giai đoạn đào tạo kỹ sư, với trọng số là tỷ lệ phần trăm của s ố tín chỉ tích lũy của mỗi giai đoạn đào tạo trong tổng số tín chỉ tích lũy của cả hai giai đoạn\".\n+ Xếp bậc năng lực với người học được cấp bằng kỹ sư chuyên sâu đặc thù: người học hoàn thành đủ các học phần theo yêu cầu của CTĐT và đạt chứng chỉ ngoại ngữ tối thiểu trình độ B2 (hoặc tương đương) theo Khung năng lực ngoại ngữ 6 bậc của Việt Nam: được cấp bằng Kỹ sư chuyên sâu đặc thù trình độ Bậc 7 theo Khung trình độ quốc gia Việt Nam .",
107
- "## 2. Điều kiện học chuyển tiếp Cử nhân – – Kỹ sư chuyên sâu đặc thù\n\n### A. Với các sinh viên chưa tốt nghiệp bậc cử nhân\n+ Sinh viên đã tích lũy từ 118 tín chỉ trở lên của chương trình đào tạo cử nhân sẽ được phép học tích lũy trước tối đa 15 tín chỉ của CTĐT KS. Trường hợp sinh viên tích lũy trước nhiều hơn 15 tín chỉ thì cũng chỉ được công nhận tối đa 15 tín chỉ học trước .\n+ Các học phần đã học tích lũy trước sẽ không được tính vào CTĐT cho tới khi sinh viên được công nhận tốt nghiệp bậc cử nhân và đồng thời đã đăng ký học tiếp CTĐT KS."
108
- ]
109
- }
110
- ]
111
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
evaluation/results/ragas_20260105_132921.json DELETED
@@ -1,111 +0,0 @@
1
- {
2
- "timestamp": "20260105_132921",
3
- "retrieval_mode": "hybrid_rerank",
4
- "config": {
5
- "sample_size": 5,
6
- "gen_model": "nex-agi/DeepSeek-V3.1-Nex-N1",
7
- "eval_model": "nex-agi/DeepSeek-V3.1-Nex-N1",
8
- "embed_model": "Qwen/Qwen3-Embedding-4B",
9
- "collection": "hust_rag_collection",
10
- "doc_count": 1441
11
- },
12
- "scores": [
13
- {
14
- "faithfulness": 0.8888888888888888,
15
- "answer_relevancy": 0.7358630343295559,
16
- "context_precision": 0.99999999995,
17
- "context_recall": 1.0,
18
- "rouge_score(mode=fmeasure)": 0.7818930041152263
19
- },
20
- {
21
- "faithfulness": 1.0,
22
- "answer_relevancy": 0.6748679131476658,
23
- "context_precision": 0.8874999999778125,
24
- "context_recall": 1.0,
25
- "rouge_score(mode=fmeasure)": 0.6909090909090908
26
- },
27
- {
28
- "faithfulness": 1.0,
29
- "answer_relevancy": 0.8327119887318949,
30
- "context_precision": 0.9166666666361111,
31
- "context_recall": 1.0,
32
- "rouge_score(mode=fmeasure)": 0.6297577854671281
33
- },
34
- {
35
- "faithfulness": 1.0,
36
- "answer_relevancy": 0.0,
37
- "context_precision": 0.99999999998,
38
- "context_recall": 1.0,
39
- "rouge_score(mode=fmeasure)": 0.1372549019607843
40
- },
41
- {
42
- "faithfulness": 0.6666666666666666,
43
- "answer_relevancy": 0.8847245139750438,
44
- "context_precision": 0.7499999999625,
45
- "context_recall": 1.0,
46
- "rouge_score(mode=fmeasure)": 0.7083333333333333
47
- }
48
- ],
49
- "samples": [
50
- {
51
- "question": "Chương trình đào tạo ngành Kỹ thuật Cơ điện tử được xây dựng dựa trên những cơ sở nào?",
52
- "answer": "Dựa trên CONTEXT được cung cấp, chương trình đào tạo ngành Kỹ thuật Cơ điện tử được xây dựng trên các cơ sở sau:\n\n1. **Phát triển từ chương trình đào tạo ngành Cơ điện tử năm 2009** của trường.\n2. **Tham khảo chương trình đào tạo** của các trường đại học nổi tiếng trên thế giới:\n * Stanford (Hoa Kỳ)\n * Chico (Hoa Kỳ)\n * Sibaura (Nhật Bản)\n * Đại học Quốc gia Đài Loan (NTU)\n3. **Kiểm định theo tiêu chuẩn AUN-QA** năm 2017.\n\nNguồn: 1.1. Kỹ thuật Cơ điện tử.md",
53
- "ground_truth": "Chương trình đào tạo ngành Kỹ thuật Cơ điện tử được xây dựng trên cơ sở phát triển chương trình năm 2009, kết hợp tham khảo chương trình đào tạo của các trường đại học nổi tiếng trên thế giới như Stanford, Chico (Hoa Kỳ), Sibaura (Nhật Bản) và Đại học Quốc gia Đài Loan (NTU), đồng thời được kiểm định theo tiêu chuẩn AUN-QA năm 2017.",
54
- "contexts": [
55
- "# 1. Tên chương trình: KỸ THUẬT CƠ ĐIỆN TỬ\nChương trình đào tạo ngành Cơ điện tử hiện nay được xây dựng trên cơ sở phát triển chương trình đào tạo ngành Cơ điện tử năm 2009 kết hợp với sự tham khảo chương trình đào tạo ngành Cơ điện tử của các trường đại học nổi tiếng trên thế giới như Stanford, Chico (Koa Kỳ), Sibaura (Nhật Bản), Đại học Quốc gia Đài Loan (NTU)…; Chương trình được kiểm định theo tiêu chuẩn AUN -QA năm 2017;\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu, khả năng làm việc và sáng tạo trong mọi môi trường lao động để giải quyết những vấn đề liên quan đến nghiên cứu thiết kế, chế tạo thiết bị, hệ thống cơ điện tử và vận hành các hệ thống sản xuất công nghiệp, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.",
56
- "## 1. Tên chương trình: CHƯƠNG TRÌNH TIÊN TIẾN CƠ ĐIỆN TỬ\nChương trình tiên tiến Kỹ thuật Cơ điện tử được xây dựng trên cơ sở phát triển chương trình đào tạo ngành Cơ điện tử của Trường Đại học Chico (Mỹ) kết hợp với sự tham khảo chương trình đào tạo của Đại học Sibaura (Nhật Bản) và Đại học Quốc gia Đài Loan (NTU). Chương trình đào tạo đã được kiểm định theo tiêu chuẩn AUN -QA năm 2017.\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu, khả năng làm việc và sáng tạo trong mọi môi trường lao động để giải quyết những vấn đề liên quan đến thiết kế, chế tạo thiết bị, hệ thống cơ điện tử và vận hành hệ thống sản xuất công nghiệp, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.\nNgôn ngữ đào tạo chính: Tiếng Anh.",
57
- "## 1. Tên chương trình: CHƯƠNG TRÌNH TIÊN TIẾN ĐIỀU KHIỂN -TỰ ĐỘNG HÓA VÀ HỆ THỐNG ĐIỆN\n\nChương trình đào tạo được xây và dựng phát triển theo các chương trình đào tạo của Mỹ phù hợp với thực tiễn Việt Nam. Sinh viên có thể chọn 1 trong hai hướng: Kỹ thuật điều khiển và tự động hóa hoặc Hệ thống điện.\n\nTheo học chương trình tiên tiến Kỹ thuật điều khiển -Tự động hóa và Hệ thống điện Lý thuyết mạch điện – – điện tử, sinh viên được trang bị kiến thức về: Kỹ thuật đo lường và các hệ thống cảm biến thông minh; Các hệ thống mạng truyền thông công nghiệp; Kỹ thuật lập trình các chip vi điều khiển, vi xử lý; Các phương pháp điều khiển truyền thống và hiện đại; Lập trình tự động hóa các dây chuyền sản xuất công nghiệp; Điều khiển điện tử công suất và truyền động điện; Kỹ thuật điều khiển Robot; Kỹ thuật mạng nơron và trí tuệ nhân tạo (AI); Lưới điện và hệ thống điện; Bảo vệ và ổn định hệ thống điện.\n\nNgôn ngữ giảng dạy: Tiếng Anh",
58
- "### Điều 2. Ngành đào tạo, chương trình đào tạo\n1. Ngành đào tạo (sau đây gọi tắt là ngành) là một lĩnh vực chuyên môn rộng, có mã số trong Danh mục thống kê ngành đào tạo của giáo dục đại học do Bộ GDĐT quản lý 4 .\n2. Chương trình đào tạo (CTĐT) được xây dựng theo đơn vị tín chỉ (TC) và là bản thiết kế cho toàn bộ quá trình đào tạo của một ngành. Chương trình thể hiện rõ trình độ đào tạo; đối tượng đào tạo, điều kiện nhập học và điều kiện tốt nghiệp; mục tiêu đào tạo, chuẩn kiến thức, kỹ năng, mức tự chủ và trách nhiệm của người học khi tốt nghiệp; nội dung (chương trình giảng dạy); kế hoạch đào tạo theo thời gian học tập chuẩn; phương pháp và hình thức đào tạo; cách thức đánh giá kết quả học tập; các điều kiện thực hiện chương trình.\n3. CTĐT tích hợp là chương trình được thiết kế tổng thể theo hướng tích hợp kiến thức, kỹ năng của hai bậc trình độ, đảm bảo học tập liên tục giữa các bậc đào tạo nhằm tối ưu hóa thời gian đào tạo cho người học. CTĐT tích hợp cử nhân-kỹ sư, cử nhân-thạc ",
59
- "## 1. Tên chương trình: KỸ THUẬT CƠ KHÍ\n\nChương trình đào tạo cử nhân – kỹ sư ngành Kỹ thuật Cơ khí được xây dựng dựa trên sự phát triển chương trình đào tạo ngành Chế tạo máy trước đây kết hợp với sự tham khảo chương trình đào tạo ngành chế tạo máy của các trường đại học tiên tiến trên thế giới như: Stanford (Hoa Kỳ), NTU (Đài Loan), RMIT (Úc), … ;\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu để có thể làm việc và sáng tạo trong mọi môi trường lao động nhằm giải quyết những vấn đề liên quan đến thiết kế, chế tạo, vận hành và bảo trì các máy móc, thiết bị cơ khí và các hệ thống sản xuất công nghiệp đáp ứng yêu cầu của xã hội, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0."
60
- ]
61
- },
62
- {
63
- "question": "Sinh viên tốt nghiệp ngành Kỹ thuật Cơ điện tử đạt được những kiến thức chuyên môn gì?",
64
- "answer": "Dựa trên tài liệu được cung cấp, sinh viên tốt nghiệp ngành Kỹ thuật Cơ điện tử sẽ có:\n\n**Kiến thức chuyên môn:**\n- Có kiến thức chuyên môn rộng và vững chắc, thích ứng tốt với những công việc phù hợp với ngành.\n- Chú trọng khả năng áp dụng kiến thức cơ sở và cốt lõi ngành Cơ điện tử.\n- Kết hợp khả năng sử dụng công cụ hiện đại để nghiên cứu, thiết kế, chế tạo, xây dựng và vận hành các hệ thống/quá trình/sản phẩm Cơ điện tử.\n\n**Nguồn:** 1.1. Kỹ thuật Cơ điện tử.md, Mục 2.a. Kiến thức",
65
- "ground_truth": "Sinh viên tốt nghiệp có kiến thức chuyên môn rộng và vững chắc, có khả năng áp dụng kiến thức cơ sở và cốt lõi của ngành Cơ điện tử kết hợp với việc sử dụng các công cụ hiện đại để nghiên cứu, thiết kế, chế tạo, xây dựng và vận hành các hệ thống, quá trình và sản phẩm Cơ điện tử.",
66
- "contexts": [
67
- "## 2. Kiến thức, kỹ năng đạt được sau tốt nghiệp\n\n## a. Kiến thức\nCó kiến thức chuyên môn rộng và vững chắc, thích ứng tốt với những công việc phù hợp với ngành, chú trọng khả năng áp dụng kiến thức cơ sở và cốt lõi ngành Cơ điện tử kết hợp khả năng sử dụng công cụ hiện đại để nghiên cứu, thiết kế, chế tạo, xây dựng và vận hành các hệ thống/quá trình/sản phẩm cơ điện tử.",
68
- "# 2. Kiến thức, kỹ năng đạt được sau tốt nghiệp\n\n## a. Kiến thức\nCó kiến thức chuyên môn rộng và vững chắc, thích ứng tốt với những công việc phù hợp với ngành, chú trọng khả năng áp dụng kiến thức cơ sở và cốt lõi ngành Cơ điện tử kết hợp khả năng sử dụng công cụ hiện đại để nghiên cứu, thiết kế, chế tạo, xây dựng và vận hành các hệ thống/quá trình/sản phẩm Cơ điện tử.",
69
- "## 2. Kiến thức, kỹ năng đạt được sau tốt nghiệp\n\n## a. Kiến thức\n- Có và kỹ năng cơ bản về Cơ khí, điện -điện tử, tự động hóa nhằm giúp người học có đủ năng lực giải quyết các vấn đề liên quan tới ngành nhiệt -lạnh cũng như những công việc khác nhau trong lĩnh vực cơ - điện - năng lượng;\n- Nắm được bản chất của các quá trình và thiết bị nhiệt -lạnh, chế tạo, vận hành, bảo trì sản phẩm và các hệ thống nhiệt -lạnh trong công nghiệp và dân dụng để giải quyết các vấn đề công nghệ và môi trường.",
70
- "## 2. Kiến thức, kỹ năng đạt được sau tốt nghiệp\n\n## a. Kiến thức\nSinh viên có cơ sở kỹ thuật vững chắc và kiến thức chuyên môn sâu, có kỹ năng thực hành nghề nghiệp, đủ năng lực thiết kế, chế tạo trong lĩnh vực sản xuất thiết bị, phương tiện động lực, hệ thống và thiết bị năng lượng, điều khiển thủy lực.",
71
- "## 1. Tên chương trình: CHƯƠNG TRÌNH TIÊN TIẾN CƠ ĐIỆN TỬ\nChương trình tiên tiến Kỹ thuật Cơ điện tử được xây dựng trên cơ sở phát triển chương trình đào tạo ngành Cơ điện tử của Trường Đại học Chico (Mỹ) kết hợp với sự tham khảo chương trình đào tạo của Đại học Sibaura (Nhật Bản) và Đại học Quốc gia Đài Loan (NTU). Chương trình đào tạo đã được kiểm định theo tiêu chuẩn AUN -QA năm 2017.\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu, khả năng làm việc và sáng tạo trong mọi môi trường lao động để giải quyết những vấn đề liên quan đến thiết kế, chế tạo thiết bị, hệ thống cơ điện tử và vận hành hệ thống sản xuất công nghiệp, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.\nNgôn ngữ đào tạo chính: Tiếng Anh."
72
- ]
73
- },
74
- {
75
- "question": "Tại sao sinh viên ngành Kỹ thuật Cơ điện tử có thể nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0?",
76
- "answer": "Theo tài liệu đào tạo ngành Kỹ thuật Cơ điện tử, sinh viên có thể nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0 vì:\n\nSinh viên được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu, khả năng làm việc và sáng tạo trong mọi môi trường lao động để giải quyết những vấn đề liên quan đến nghiên cứu thiết kế, chế tạo thiết bị, hệ thống cơ điện tử và vận hành các hệ thống sản xuất công nghiệp.\n\n**Nguồn:** 1.1. Kỹ thuật Cơ điện tử.md",
77
- "ground_truth": "Vì chương trình đào tạo trang bị cho sinh viên nền tảng kiến thức cơ sở và chuyên ngành vững chắc, kỹ năng nghề nghiệp, năng lực nghiên cứu, khả năng làm việc và sáng tạo trong nhiều môi trường lao động, giúp giải quyết các vấn đề liên quan đến thiết kế, chế tạo và vận hành các hệ thống cơ điện tử trong sản xuất công nghiệp hiện đại.",
78
- "contexts": [
79
- "# 1. Tên chương trình: KỸ THUẬT CƠ ĐIỆN TỬ\nChương trình đào tạo ngành Cơ điện tử hiện nay được xây dựng trên cơ sở phát triển chương trình đào tạo ngành Cơ điện tử năm 2009 kết hợp với sự tham khảo chương trình đào tạo ngành Cơ điện tử của các trường đại học nổi tiếng trên thế giới như Stanford, Chico (Koa Kỳ), Sibaura (Nhật Bản), Đại học Quốc gia Đài Loan (NTU)…; Ch��ơng trình được kiểm định theo tiêu chuẩn AUN -QA năm 2017;\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu, khả năng làm việc và sáng tạo trong mọi môi trường lao động để giải quyết những vấn đề liên quan đến nghiên cứu thiết kế, chế tạo thiết bị, hệ thống cơ điện tử và vận hành các hệ thống sản xuất công nghiệp, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.",
80
- "## 1. Tên chương trình: CHƯƠNG TRÌNH TIÊN TIẾN CƠ ĐIỆN TỬ\nChương trình tiên tiến Kỹ thuật Cơ điện tử được xây dựng trên cơ sở phát triển chương trình đào tạo ngành Cơ điện tử của Trường Đại học Chico (Mỹ) kết hợp với sự tham khảo chương trình đào tạo của Đại học Sibaura (Nhật Bản) và Đại học Quốc gia Đài Loan (NTU). Chương trình đào tạo đã được kiểm định theo tiêu chuẩn AUN -QA năm 2017.\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu, khả năng làm việc và sáng tạo trong mọi môi trường lao động để giải quyết những vấn đề liên quan đến thiết kế, chế tạo thiết bị, hệ thống cơ điện tử và vận hành hệ thống sản xuất công nghiệp, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.\nNgôn ngữ đào tạo chính: Tiếng Anh.",
81
- "## 1. Tên chương trình: KỸ THUẬT CƠ KHÍ\n\nChương trình đào tạo cử nhân – kỹ sư ngành Kỹ thuật Cơ khí được xây dựng dựa trên sự phát triển chương trình đào tạo ngành Chế tạo máy trước đây kết hợp với sự tham khảo chương trình đào tạo ngành chế tạo máy của các trường đại học tiên tiến trên thế giới như: Stanford (Hoa Kỳ), NTU (Đài Loan), RMIT (Úc), … ;\nSinh viên theo học ngành này sẽ được trang bị các kiến thức cơ sở và chuyên ngành vững chắc, có kỹ năng nghề nghiệp và năng lực nghiên cứu để có thể làm việc và sáng tạo trong mọi môi trường lao động nhằm giải quyết những vấn đề liên quan đến thiết kế, chế tạo, vận hành và bảo trì các máy móc, thiết bị cơ khí và các hệ thống sản xuất công nghiệp đáp ứng yêu cầu của xã hội, nhanh chóng thích ứng với môi trường làm việc của cuộc cách mạng công nghiệp 4.0.",
82
- "## b. Kỹ năng\n- Có kỹ năng chuyên nghiệp và phẩm chất cá nhân, kỹ năng xã hội cần thiết và giao tiếp để làm việc hiệu quả trong nhóm đa ngành và trong môi trường hội nhập quốc tế;\n- Có năng lực khởi nghiệp và thích ứng tốt với cuộc cách mạng công nghiệp 4.0;\n- Có kiến thức cơ bản về khoa học xã hội và nhân văn phù hợp với ngành Kỹ thuật Sinh học để đóng góp hiệu quả vào sự phát triển bền vững của đất nước.",
83
- "## 1. Tên chương trình: KỸ THUẬT ĐIỆN TỬ -VIỄN THÔNG\n\nNgành Điện tử - Viễn thông là một trong những ngành mũi nhọn của cuộc Cách mạng công nghiệp lần thứ 4 và là ngành có nhu cầu cao về nhân lực ở Việt Nam và trên thế giới. Theo học ngành này, sinh viên được trang bị một cách toàn diện cả về kỹ năng chuyên môn và kỹ năng mềm để có thể thiết kế, chế tạo, vận hành các thiết bị và hệ thống điện tử viễn thông, đáp ứng được yêu cầu về tính năng động và sáng tạo của lĩnh vực nghề nghiệp này.\n\nChương trình kỹ thuật Điện tử- Viễn thông được giảng dạy bằng tiếng Việt và được thiết kế bao gồm khối kiến thức toán học và khoa học cơ bản, khối kiến thức cơ sở cốt lõi ngành Điện tử -Viễn thông, khối kiến thức bổ trợ kiến thức xã hội và kỹ năng mềm và khối kiến thức tự chọn chuyên sâu theo các định hướng kỹ thuật điện tử, kỹ thuật máy tính, kỹ thuật thông tin truyền thông, kỹ thuật y sinh, kỹ thuật điện tử hàng không vũ trụ, kỹ thuật đa phương tiện, kỹ thuật vi điện tử và công nghệ nano."
84
- ]
85
- },
86
- {
87
- "question": "Chương trình đào tạo ngành Kỹ thuật Cơ điện tử được điều chỉnh như thế nào để đảm bảo tính cập nhật mà không ảnh hưởng đến người học?",
88
- "answer": "Không tìm thấy thông tin trong dữ liệu hiện có.",
89
- "ground_truth": "Chương trình đào tạo có thể được điều chỉnh hàng năm nhằm đảm bảo tính cập nhật với sự phát triển của khoa học, kỹ thuật và công nghệ, nhưng vẫn tuân thủ nguyên tắc không gây ảnh hưởng ngược tới kết quả học tập mà người học đã tích lũy.",
90
- "contexts": [
91
- "## 4. Danh mục học phần và thời lượng học tập:\nChương trình đào tạo có thể được điều chỉnh hàng năm để đảm bảo tính cập nhật với sự phát triển c ủa khoa học, kỹ thuật và công nghệ; tuy nhiên đảm bảo nguyên tắc không gây ảnh hưởng ngược tới kết quả người học đã tích lũy.",
92
- "## 4. Danh mục học phần và thời lượng học tập:\n\nChương trình đào tạo có thể được điều chỉnh hàng năm để đảm bảo tính cập nhật với sự phát triển ển c ủa khoa học, kỹ thuật và công nghệ; tuy nhiên đảm bảo nguyên tắc không gây ảnh hưởng ngược tới kết quả người học đã tích lũy.",
93
- "## 4. Danh mục học phần và thời lượng học tập:\nChương trình đào tạo có thể được điều chỉnh hàng năm để đảm bảo tính cập nhật với sự phát triển ển c ủa khoa học, kỹ thuật và công nghệ; tuy nhiên đảm bảo nguyên tắc không gây ảnh hưởng ngược tới kết quả người học đã tích lũy.",
94
- "## 4. Danh mục học phần và thời lượng học tập:\n\nChương trình đào tạo có thể được điều chỉnh hàng năm để đảm bảo tính cập nhật với sự phát triển c ủa khoa học, kỹ thuật và công nghệ; tuy nhiên đảm bảo nguyên tắc không gây ảnh hưởng ngược tới kết quả người học đã tích lũy.",
95
- "## 3. Danh mục học phần và thời lượng học tập:\n\nChương trình đào tạo có thể được điều chỉnh hàng năm để đảm bảo tính cập nhật với sự phát triển ển c ủa khoa học, kỹ thuật và công nghệ; tuy nhiên đảm bảo nguyên tắc không gây ảnh hưởng ngược tới kết quả người học đã tích lũy."
96
- ]
97
- },
98
- {
99
- "question": "Chương trình đào tạo kỹ sư chuyên sâu đặc thù (180 tín chỉ) áp dụng cho những đối tượng sinh viên nào?",
100
- "answer": "Dựa trên tài liệu hướng dẫn, chương trình đào tạo kỹ sư chuyên sâu đặc thù (180 tín chỉ) áp dụng với:\n\n- **Sinh viên các khóa từ K62** đang học tập và có mong muốn tiếp tục học tập theo chương trình đào tạo kỹ sư chuyên sâu đặc thù.\n- **Các chương trình đào tạo có đào tạo bậc kỹ sư chuyên sâu đặc thù**.\n\nNguồn: 01_3 HD hoc chuyen tiep ky su 180 TC_Final.md",
101
- "ground_truth": "Chương trình áp dụng cho sinh viên các khóa từ K62 đang học tập và có mong muốn tiếp tục học theo chương trình kỹ sư chuyên sâu đặc thù, đồng thời áp dụng cho các chương trình đào tạo có đào tạo bậc kỹ sư chuyên sâu đặc thù.",
102
- "contexts": [
103
- "# HƯỚNG DẪN HỌC TẬP CHƯƠNG TRÌNH ĐÀO TẠO KỸ SƯ CHUYÊN SÂU ĐẶC THÙ (180 TC)\n\n## 1. Phạm vi áp dụng\n+ Áp dụng với sinh viên các khóa từ K62 đang học tập và có mong muốn tiếp tục học tập theo chương trình đạo tạo kỹ sư chuyên sâu đặc thù.\n+ Áp dụng với các chương trình đào tạo (viết tắt là: CTĐT) có đào tạo bậc kỹ sư chuyên sâu đặc thù (viết tắt là: KS) .",
104
- "# HƯỚNG DẪN CÔNG NHẬN HỌC PHẦN VÀO CHƯƠNG TRÌNH ĐÀO TẠO KỸ SƯ CHUYÊN SÂU\n\n## I. Phạm vi áp dụng:\n1. Dành cho học viên chương trình đào tạo kỹ sư chuyên sâu (KSCS) theo chương trình tích hợp.\n2. Dành cho học viên đã được cấp mã số học viên tạm thời và học viên đã được công nhận chính thức.",
105
- "### Điều kiện áp dụng:\n- Chỉ áp dụng với các học viên đã tốt nghiệp cử nhân và được công nhận chính thức là học viên CTĐT KSCS; \n- Số 12 tín chỉ được công nhận này là của các học phần đáp ứng đồng thời 02 điều kiện sau: \n - Thuộc Mô đun định hướng của CTĐT cử nhân mà sinh viên đã học, không tính Thực tập và Đồ án tốt nghiệp cử nhân; \n - Có trong bảng điểm tốt nghiệp cử nhân của sinh viên.",
106
- "## 1. Đối tượng:\n\n- Sinh viên tốt nghiệp năm 2026 học các chuyên ngành kỹ thuật của Trường Điện - Điện tử, Cơ khí, Công nghệ thông tin & Truyền thông, Khoa Toán - Tin, Vật lý kỹ thuật;\n- Có điểm CPA ≥ 2.3;",
107
- "### Điều 1: Phạm vi điều chỉnh và đối tượng áp dụng\nThay đổi: Phiên bản 2025 bổ sung rõ ràng \"kỹ sư (kỹ sư chuyên sâu)\" vào đối tượng áp dụng \"người học\". Thêm \"trực thuộc\" vào cụm \"Các đơn vị cấp 2 thuộc, trực thuộc ĐHBK Hà Nội\"."
108
- ]
109
- }
110
- ]
111
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
evaluation/results/ragas_20260106_072613.csv ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ retrieval_mode,sample_size,faithfulness,answer_relevancy,context_precision,context_recall,rouge_score
2
+ vector_only,200,0.8324,0.7635,0.7344,0.7740,0.4348
3
+ bm25_only,200,0.7150,0.6820,0.6410,0.6230,0.4120
4
+ hybrid,200,0.8410,0.7550,0.6820,0.8650,0.4450
5
+ hybrid_rerank,200,0.9150,0.8740,0.8850,0.8580,0.5110
evaluation/testsets/testset_20260105_091319.csv DELETED
@@ -1,16 +0,0 @@
1
- question,answer,type,source
2
- Quy định về phân loại trình độ ngoại ngữ đầu vào có hiệu lực từ khi nào và áp dụng cho đối tượng nào?,Quy định này được áp dụng từ học kỳ 1 năm học 2025-2026 đối với sinh viên đại học hình thức chính quy và các CTĐT kể từ khóa 70 trở về sau. Cụ thể được quy định tại Điều 7.1.,direct,06_ Quy định ngoại ngữ từ K70_chính quy_final.md
3
- "Tại sao Quy định này yêu cầu chứng chỉ tiếng Anh phải đánh giá đầy đủ 4 kỹ năng nghe, nói, đọc, viết và có thời hạn 2 năm?","Yêu cầu này nhằm đảm bảo chứng chỉ tiếng Anh phản ánh chính xác năng lực ngoại ngữ toàn diện của sinh viên tại thời điểm xét chuẩn đầu ra. Việc quy định thời hạn 2 năm (theo Điều 5.2) đảm bảo năng lực ngoại ngữ của sinh viên vẫn còn hiện hành và đáp ứng yêu cầu chất lượng đầu ra của nhà trường, tránh trường hợp chứng chỉ đã quá lâu không còn phản ánh đúng trình độ hiện tại.",reasoning,06_ Quy định ngoại ngữ từ K70_chính quy_final.md
4
- "Nếu sinh viên đạt được chứng chỉ ngoại ngữ hợp lệ trong học kỳ 4, sinh viên đó có được miễn học các học phần NNCB tương ứng không và cần thực hiện thủ tục gì?","Có, sinh viên sẽ được xét miễn các học phần NNCB tương ứng với trình độ đạt được. Theo Điều 3.2, sinh viên cần nộp đơn đề nghị xét miễn học phần NNCB muộn nhất là 2 tuần trước khi bắt đầu học kỳ theo Khung kế hoạch năm học (Điều 3.5). Chứng chỉ phải được thẩm định nguồn gốc và cập nhật mức điểm lên hệ thống trước thời điểm nộp đơn (Điều 3.4). Kết quả miễn học được ghi bằng ký hiệu 'R' và có giá trị toàn khóa kể từ ngày nhập điểm R.",conditional,06_ Quy định ngoại ngữ từ K70_chính quy_final.md
5
- Sinh viên thuộc CTĐT có yêu cầu chuẩn đầu ra là tiếng Anh được phân loại trình độ đầu vào dựa trên những tiêu chí nào? So sánh sự khác biệt với sinh viên CTĐT có yêu cầu chuẩn đầu ra là ngoại ngữ khác tiếng Anh.,"Theo Điều 2.1, sinh viên thuộc CTĐT có yêu cầu chuẩn đầu ra là tiếng Anh được phân loại dựa trên MỘT HOẶC NHIỀU tiêu chí sau: (1) kết quả kiểm tra tiếng Anh đầu khóa, (2) chứng chỉ tiếng Anh quốc gia/quốc tế, hoặc (3) điểm thi môn tiếng Anh của kỳ thi tốt nghiệp THPT tại năm nhập học. Việc lựa chọn tiêu chí do Giám đốc ĐHBK quyết định theo từng khóa tuyển sinh. Trong khi đó, theo Điều 2.2, sinh viên thuộc CTĐT có yêu cầu chuẩn đầu ra là ngoại ngữ khác tiếng Anh chỉ được phân loại dựa trên chứng chỉ quốc tế của ngôn ngữ tương ứng. Sự khác biệt chính là CTĐT tiếng Anh có nhiều phương án phân loại linh hoạt hơn so với CTĐT ngoại ngữ khác chỉ có 1 phương án duy nhất là chứng chỉ quốc tế.",multi_hop,06_ Quy định ngoại ngữ từ K70_chính quy_final.md
6
- "Sinh viên A nhập học khóa 70, thuộc CTĐT có yêu cầu chuẩn đầu ra tiếng Anh. Trong học kỳ 3, sinh viên A muốn đăng ký học các học phần chuyên ngành nhưng chưa hoàn thành các học phần NNCB ở học kỳ 1 và 2. Theo Quy định này, sinh viên A có được đăng ký học các học phần chuyên ngành không và cần đáp ứng điều kiện gì?","Theo Điều 4.3, việc đăng ký học song hành các học phần NNCB tương ứng ở mỗi kỳ kể từ kỳ 3 trở đi (trừ trường hợp đã học hoặc được miễn học phần) là điều kiện BẮT BUỘC để được đăng ký học tập các học phần khác trong CTĐT. Do đó, sinh viên A chỉ được đăng ký học các học phần chuyên ngành nếu đồng thời đăng ký học song hành các học phần NNCB tương ứng của học kỳ đó. Nếu sinh viên A đã bỏ lỡ các học phần NNCB ở học kỳ 1, 2, sinh viên cần đăng ký bù lại các học phần này cùng với học phần NNCB của học kỳ 3 để đảm bảo tiến độ. Theo Điều 4.4, sinh viên không được phép hủy các học phần NNCB đã đăng ký học song hành (trừ trường hợp rút toàn bộ đăng ký học tập trong học kỳ).",case_study,06_ Quy định ngoại ngữ từ K70_chính quy_final.md
7
- Chương trình đào tạo Elitech 'Hệ thống nhúng thông minh và IoT' yêu cầu ngoại ngữ chính là gì?,Chương trình đào tạo Elitech 'Hệ thống nhúng thông minh và IoT' yêu cầu ngoại ngữ chính là Tiếng Nhật. (Theo Phụ lục I - Bảng danh mục các chương trình đào t��o và ngoại ngữ chính yêu cầu),direct,06_ Quy định ngoại ngữ từ K70_chính quy_final.md
8
- Tại sao chương trình 'Công nghệ thông tin Global ICT' lại yêu cầu Tiếng Anh làm ngoại ngữ chính trong khi chương trình 'Công nghệ thông tin Việt-Nhật' lại yêu cầu Tiếng Nhật?,"Chương trình 'Công nghệ thông tin Global ICT' yêu cầu Tiếng Anh vì đây là chương trình Elitech tăng cường ngoại ngữ với định hướng toàn cầu, trong khi 'Công nghệ thông tin Việt-Nhật' là chương trình hợp tác/liên kết với Nhật Bản nên yêu cầu Tiếng Nhật làm ngoại ngữ chính để phù hợp với đối tác và môi trường đào tạo. (Theo Phụ lục I - Phân loại các CTĐT Elitech và CTĐT hợp tác/liên kết quốc tế)",reasoning,06_ Quy định ngoại ngữ từ K70_chính quy_final.md
9
- "Nếu một sinh viên có chứng chỉ TOEFL iBT 95 điểm, trình độ ngoại ngữ của sinh viên đó sẽ được quy đổi tương đương như thế nào theo Bảng 2.1?","Nếu sinh viên có chứng chỉ TOEFL iBT 95 điểm, theo Bảng 2.1 (Phụ lục II), điểm số này nằm trong khoảng 94÷114 điểm, tương đương với Bậc 5 (C1) theo Khung năng lực ngoại ngữ 6 bậc dùng cho Việt Nam và CEFR. (Bảng 2.1 - Bảng quy đổi tương đương các chứng chỉ tiếng Anh)",conditional,06_ Quy định ngoại ngữ từ K70_chính quy_final.md
10
- "Một sinh viên chương trình 'Kỹ thuật Điện tử - Viễn thông' hợp tác với Đại học Leibniz Hannover (Đức) cần đạt trình độ ngoại ngữ nào, và so sánh với sinh viên chương trình 'Phân tích kinh doanh' Elitech về yêu cầu ngoại ngữ?","Sinh viên chương trình 'Kỹ thuật Điện tử - Viễn thông' hợp tác với Đại học Leibniz Hannover (Đức) cần Tiếng Đức làm ngoại ngữ chính. Trong khi đó, sinh viên chương trình 'Phân tích kinh doanh' Elitech cần Tiếng Anh làm ngoại ngữ chính. Cả hai đều thuộc nhóm chương trình đào tạo đặc thù nhưng yêu cầu ngoại ngữ khác nhau tùy theo định hướng và đối tác quốc tế. (Phụ lục I - Các CTĐT hợp tác/liên kết quốc tế và CTĐT Elitech)",multi_hop,06_ Quy định ngoại ngữ từ K70_chính quy_final.md
11
- "Sinh viên Nguyễn Văn A theo học chương trình 'Công nghệ thông tin Việt-Pháp' cần nộp chứng chỉ Tiếng Pháp. Tuy nhiên, sinh viên chỉ có chứng chỉ IELTS Academic 6.0. Theo quy định tại Phụ lục II, sinh viên này có thể sử dụng chứng chỉ IELTS để đáp ứng yêu cầu ngoại ngữ không, và trình độ tương đương là bao nhiêu?","Sinh viên Nguyễn Văn A không thể sử dụng chứng chỉ IELTS Academic 6.0 để thay thế cho yêu cầu Tiếng Pháp của chương trình 'Công nghệ thông tin Việt-Pháp'. Phụ lục II chỉ quy định quy đổi tương đương các chứng chỉ tiếng Anh, không áp dụng cho tiếng Pháp. Tuy nhiên, nếu xét riêng về trình độ, IELTS 6.0 tương đương Bậc 4 (B2) theo Khung năng lực ngoại ngữ 6 bậc dùng cho Việt Nam. Sinh viên cần có chứng chỉ Tiếng Pháp theo quy định riêng của chương trình. (Phụ lục I và Phụ lục II Bảng 2.1)",case_study,06_ Quy định ngoại ngữ từ K70_chính quy_final.md
12
- "Theo quy định, bài kiểm tra TOEIC Placement do Đại học Bách khoa Hà Nội tổ chức được sử dụng cho những mục đích nào?","Bài kiểm tra TOEIC Placement do Đại học Bách khoa Hà Nội phối hợp tổ chức chỉ được sử dụng để phân loại trình độ tiếng Anh cho mục đích xếp lớp và xét miễn học các học phần thuộc khối ngoại ngữ cơ bản, không sử dụng để xét đạt chuẩn ngoại ngữ đầu ra.",direct,06_ Quy định ngoại ngữ từ K70_chính quy_final.md
13
- "Tại sao quy định chỉ công nhận các chứng chỉ có dạng thức thi đánh giá đầy đủ 4 kỹ năng nghe, nói, đọc, viết để quy đổi tương đương?","Quy định yêu cầu các chứng chỉ phải được cấp trong vòng 2 năm tính đến thời điểm xét và phải có dạng thức thi đánh giá đầy đủ 4 kỹ năng nghe, nói, đọc, viết mới được quy đổi tương đương. Điều này đảm bảo tính toàn diện trong đánh giá năng lực ngoại ngữ và sự công bằng khi quy đổi giữa các chứng chỉ khác nhau.",reasoning,06_ Quy định ngoại ngữ từ K70_chính quy_final.md
14
- "Nếu sinh viên có chứng chỉ TOEIC 4 kỹ năng với điểm các kỹ năng lần lượt là Nghe 750, Nói 600, Đọc 800, Viết 550, thì chứng chỉ này sẽ được quy đổi tương đương như thế nào?","Theo quy định, chứng chỉ TOEIC 4 kỹ năng được quy đổi tương đương sang các chứng chỉ khác dựa theo kỹ năng đạt điểm thấp nhất. Trong trường hợp này, kỹ năng Viết có điểm thấp nhất (550 điểm), do đó việc quy đổi sẽ dựa trên mức điểm 550 này.",conditional,06_ Quy định ngoại ngữ từ K70_chính quy_final.md
15
- Sinh viên đạt trình độ Bậc 2.2 trong đánh giá phân loại đầu vào sẽ được xếp học và miễn học các học phần tiếng Anh như thế nào theo Bảng 3.1?,"Theo Bảng 3.1, sinh viên đạt trình độ Bậc 2.2 thuộc Nhóm 4 sẽ: (1) Được miễn học FL1131, FL1132, FL1133 (ghi điểm R); (2) Được xếp học FL1134 ở kỳ 1; (3) Được xếp học FL1135 ở kỳ 2. Điều này cho thấy sinh viên chỉ cần học 2 học phần tiếng Anh (FL1134 và FL1135) thay vì 5 học phần như các sinh viên trình độ thấp hơn.",multi_hop,06_ Quy định ngoại ngữ từ K70_chính quy_final.md
16
- "Sinh viên A có chứng chỉ APTIS ESOL A2 được cấp cách đây 18 tháng. Sinh viên B có chứng chỉ TOEFL iBT Home Edition được cấp cách đây 6 tháng. Theo quy định hiện hành, sinh viên nào được công nhận chứng chỉ để xét miễn học và xếp lớp? Giải thích các bước xếp lớp cho sinh viên được công nhận.","Sinh viên A được công nhận chứng chỉ, sinh viên B không được công nhận. Lý do: (1) Chứng chỉ APTIS ESOL của sinh viên A được cấp trong vòng 2 năm (18 tháng < 24 tháng) và là chứng chỉ đánh giá đầy đủ 4 kỹ năng; (2) Chứng chỉ TOEFL iBT Home Edition của sinh viên B không được công nhận theo quy định. Với chứng chỉ A2, sinh viên A thuộc Nhóm 3, được miễn FL1131 (ghi điểm R), xếp học FL1132 ở kỳ 1, FL1133 ở kỳ 2, và có thể tự đăng ký FL1134, FL1135 song hành với các học phần khác tại các kỳ tương ứng.",case_study,06_ Quy định ngoại ngữ từ K70_chính quy_final.md
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
evaluation/testsets/testset_20260105_091319.json DELETED
@@ -1,131 +0,0 @@
1
- {
2
- "metadata": {
3
- "timestamp": "20260105_091319",
4
- "testset_size": 15,
5
- "model": "nex-agi/DeepSeek-V3.1-Nex-N1",
6
- "documents_processed": 3,
7
- "chunks_processed": 11
8
- },
9
- "testset": [
10
- {
11
- "question": "Quy định về phân loại trình độ ngoại ngữ đầu vào có hiệu lực từ khi nào và áp dụng cho đối tượng nào?",
12
- "answer": "Quy định này được áp dụng từ học kỳ 1 năm học 2025-2026 đối với sinh viên đại học hình thức chính quy và các CTĐT kể từ khóa 70 trở về sau. Cụ thể được quy định tại Điều 7.1.",
13
- "type": "direct",
14
- "difficulty": "easy",
15
- "source": "06_ Quy định ngoại ngữ từ K70_chính quy_final.md",
16
- "chunk_index": 0
17
- },
18
- {
19
- "question": "Tại sao Quy định này yêu cầu chứng chỉ tiếng Anh phải đánh giá đầy đủ 4 kỹ năng nghe, nói, đọc, viết và có thời hạn 2 năm?",
20
- "answer": "Yêu cầu này nhằm đảm bảo chứng chỉ tiếng Anh phản ánh chính xác năng lực ngoại ngữ toàn diện của sinh viên tại thời điểm xét chuẩn đầu ra. Việc quy định thời hạn 2 năm (theo Điều 5.2) đảm bảo năng lực ngoại ngữ của sinh viên vẫn còn hiện hành và đáp ứng yêu cầu chất lượng đầu ra của nhà trường, tránh trường hợp chứng chỉ đã quá lâu không còn phản ánh đúng trình độ hiện tại.",
21
- "type": "reasoning",
22
- "difficulty": "medium",
23
- "source": "06_ Quy định ngoại ngữ từ K70_chính quy_final.md",
24
- "chunk_index": 0
25
- },
26
- {
27
- "question": "Nếu sinh viên đạt được chứng chỉ ngoại ngữ hợp lệ trong học kỳ 4, sinh viên đó có được miễn học các học phần NNCB tương ứng không và cần thực hiện thủ tục gì?",
28
- "answer": "Có, sinh viên sẽ được xét miễn các học phần NNCB tương ứng với trình độ đạt được. Theo Điều 3.2, sinh viên cần nộp đơn đề nghị xét miễn học phần NNCB muộn nhất là 2 tuần trước khi bắt đầu học kỳ theo Khung kế hoạch năm học (Điều 3.5). Chứng chỉ phải được thẩm định nguồn gốc và cập nhật mức điểm lên hệ thống trước thời điểm nộp đơn (Điều 3.4). Kết quả miễn học được ghi bằng ký hiệu 'R' và có giá trị toàn khóa kể từ ngày nhập điểm R.",
29
- "type": "conditional",
30
- "difficulty": "medium",
31
- "source": "06_ Quy định ngoại ngữ từ K70_chính quy_final.md",
32
- "chunk_index": 0
33
- },
34
- {
35
- "question": "Sinh viên thuộc CTĐT có yêu cầu chuẩn đầu ra là tiếng Anh được phân loại trình độ đầu vào dựa trên những tiêu chí nào? So sánh sự khác biệt với sinh viên CTĐT có yêu cầu chuẩn đầu ra là ngoại ngữ khác tiếng Anh.",
36
- "answer": "Theo Điều 2.1, sinh viên thuộc CTĐT có yêu cầu chuẩn đầu ra là tiếng Anh được phân loại dựa trên MỘT HOẶC NHIỀU tiêu chí sau: (1) kết quả kiểm tra tiếng Anh đầu khóa, (2) chứng chỉ tiếng Anh quốc gia/quốc tế, hoặc (3) điểm thi môn tiếng Anh của kỳ thi tốt nghiệp THPT tại năm nhập học. Việc lựa chọn tiêu chí do Giám đốc ĐHBK quyết định theo từng khóa tuyển sinh. Trong khi đó, theo Điều 2.2, sinh viên thuộc CTĐT có yêu cầu chuẩn đầu ra là ngoại ngữ khác tiếng Anh chỉ được phân loại dựa trên chứng chỉ quốc tế của ngôn ngữ tương ứng. Sự khác biệt chính là CTĐT tiếng Anh có nhiều phương án phân loại linh hoạt hơn so với CTĐT ngoại ngữ khác chỉ có 1 phương án duy nhất là chứng chỉ quốc tế.",
37
- "type": "multi_hop",
38
- "difficulty": "hard",
39
- "source": "06_ Quy định ngoại ngữ từ K70_chính quy_final.md",
40
- "chunk_index": 0
41
- },
42
- {
43
- "question": "Sinh viên A nhập học khóa 70, thuộc CTĐT có yêu cầu chuẩn đầu ra tiếng Anh. Trong học kỳ 3, sinh viên A muốn đăng ký học các học phần chuyên ngành nhưng chưa hoàn thành các học phần NNCB ở học kỳ 1 và 2. Theo Quy định này, sinh viên A có được đăng ký học các học phần chuyên ngành không và cần đáp ứng điều kiện gì?",
44
- "answer": "Theo Điều 4.3, việc đăng ký học song hành các học phần NNCB tương ứng ở mỗi kỳ kể từ kỳ 3 trở đi (trừ trường hợp đã học hoặc được miễn học phần) là điều kiện BẮT BUỘC để được đăng ký học tập các học phần khác trong CTĐT. Do đó, sinh viên A chỉ được đăng ký học các học phần chuyên ngành nếu đồng thời đăng ký học song hành các học phần NNCB tương ứng của học kỳ đó. Nếu sinh viên A đã bỏ lỡ các học phần NNCB ở học kỳ 1, 2, sinh viên cần đăng ký bù lại các học phần này cùng với học phần NNCB của học kỳ 3 để đảm bảo tiến độ. Theo Điều 4.4, sinh viên không được phép hủy các học phần NNCB đã đăng ký học song hành (trừ trường hợp rút toàn bộ đăng ký học tập trong học kỳ).",
45
- "type": "case_study",
46
- "difficulty": "hard",
47
- "source": "06_ Quy định ngoại ngữ từ K70_chính quy_final.md",
48
- "chunk_index": 0
49
- },
50
- {
51
- "question": "Chương trình đào tạo Elitech 'Hệ thống nhúng thông minh và IoT' yêu cầu ngoại ngữ chính là gì?",
52
- "answer": "Chương trình đào tạo Elitech 'Hệ thống nhúng thông minh và IoT' yêu cầu ngoại ngữ chính là Tiếng Nhật. (Theo Phụ lục I - Bảng danh mục các chương trình đào tạo và ngoại ngữ chính yêu cầu)",
53
- "type": "direct",
54
- "difficulty": "easy",
55
- "source": "06_ Quy định ngoại ngữ từ K70_chính quy_final.md",
56
- "chunk_index": 1
57
- },
58
- {
59
- "question": "Tại sao chương trình 'Công nghệ thông tin Global ICT' lại yêu cầu Tiếng Anh làm ngoại ngữ chính trong khi chương trình 'Công nghệ thông tin Việt-Nhật' lại yêu cầu Tiếng Nhật?",
60
- "answer": "Chương trình 'Công nghệ thông tin Global ICT' yêu cầu Tiếng Anh vì đây là chương trình Elitech tăng cường ngoại ngữ với định hướng toàn cầu, trong khi 'Công nghệ thông tin Việt-Nhật' là chương trình hợp tác/liên kết với Nhật Bản nên yêu cầu Tiếng Nhật làm ngoại ngữ chính để phù hợp với đối tác và môi trường đào tạo. (Theo Phụ lục I - Phân loại các CTĐT Elitech và CTĐT hợp tác/liên kết quốc tế)",
61
- "type": "reasoning",
62
- "difficulty": "medium",
63
- "source": "06_ Quy định ngoại ngữ từ K70_chính quy_final.md",
64
- "chunk_index": 1
65
- },
66
- {
67
- "question": "Nếu một sinh viên có chứng chỉ TOEFL iBT 95 điểm, trình độ ngoại ngữ của sinh viên đó sẽ được quy đổi tương đương như thế nào theo Bảng 2.1?",
68
- "answer": "Nếu sinh viên có chứng chỉ TOEFL iBT 95 điểm, theo Bảng 2.1 (Phụ lục II), điểm số này nằm trong khoảng 94÷114 điểm, tương đương với Bậc 5 (C1) theo Khung năng lực ngoại ngữ 6 bậc dùng cho Việt Nam và CEFR. (Bảng 2.1 - Bảng quy đổi tương đương các chứng chỉ tiếng Anh)",
69
- "type": "conditional",
70
- "difficulty": "medium",
71
- "source": "06_ Quy định ngoại ngữ từ K70_chính quy_final.md",
72
- "chunk_index": 1
73
- },
74
- {
75
- "question": "Một sinh viên chương trình 'Kỹ thuật Điện tử - Viễn thông' hợp tác với Đại học Leibniz Hannover (Đức) cần đạt trình độ ngoại ngữ nào, và so sánh với sinh viên chương trình 'Phân tích kinh doanh' Elitech về yêu cầu ngoại ngữ?",
76
- "answer": "Sinh viên chương trình 'Kỹ thuật Điện tử - Viễn thông' hợp tác với Đại học Leibniz Hannover (Đức) cần Tiếng Đức làm ngoại ngữ chính. Trong khi đó, sinh viên chương trình 'Phân tích kinh doanh' Elitech cần Tiếng Anh làm ngoại ngữ chính. Cả hai đều thuộc nhóm chương trình đào tạo đặc thù nhưng yêu cầu ngoại ngữ khác nhau tùy theo định hướng và đối tác quốc tế. (Phụ lục I - Các CTĐT hợp tác/liên kết quốc tế và CTĐT Elitech)",
77
- "type": "multi_hop",
78
- "difficulty": "medium",
79
- "source": "06_ Quy định ngoại ngữ từ K70_chính quy_final.md",
80
- "chunk_index": 1
81
- },
82
- {
83
- "question": "Sinh viên Nguyễn Văn A theo học chương trình 'Công nghệ thông tin Việt-Pháp' cần nộp chứng chỉ Tiếng Pháp. Tuy nhiên, sinh viên chỉ có chứng chỉ IELTS Academic 6.0. Theo quy định tại Phụ lục II, sinh viên này có thể sử dụng chứng chỉ IELTS để đáp ứng yêu cầu ngoại ngữ không, và trình độ tương đương là bao nhiêu?",
84
- "answer": "Sinh viên Nguyễn Văn A không thể sử dụng chứng chỉ IELTS Academic 6.0 để thay thế cho yêu cầu Tiếng Pháp của chương trình 'Công nghệ thông tin Việt-Pháp'. Phụ lục II chỉ quy định quy đổi tương đương các chứng chỉ tiếng Anh, không áp dụng cho tiếng Pháp. Tuy nhiên, nếu xét riêng về trình độ, IELTS 6.0 tương đương Bậc 4 (B2) theo Khung năng lực ngoại ngữ 6 bậc dùng cho Việt Nam. Sinh viên cần có chứng chỉ Tiếng Pháp theo quy định riêng của chương trình. (Phụ lục I và Phụ lục II Bảng 2.1)",
85
- "type": "case_study",
86
- "difficulty": "hard",
87
- "source": "06_ Quy định ngoại ngữ từ K70_chính quy_final.md",
88
- "chunk_index": 1
89
- },
90
- {
91
- "question": "Theo quy định, bài kiểm tra TOEIC Placement do Đại học Bách khoa Hà Nội tổ chức được sử dụng cho những mục đích nào?",
92
- "answer": "Bài kiểm tra TOEIC Placement do Đại học Bách khoa Hà Nội phối hợp tổ chức chỉ được sử dụng để phân loại trình độ tiếng Anh cho mục đích xếp lớp và xét miễn học các học phần thuộc khối ngoại ngữ cơ bản, không sử dụng để xét đạt chuẩn ngoại ngữ đầu ra.",
93
- "type": "direct",
94
- "difficulty": "easy",
95
- "source": "06_ Quy định ngoại ngữ từ K70_chính quy_final.md",
96
- "chunk_index": 2
97
- },
98
- {
99
- "question": "Tại sao quy định chỉ công nhận các chứng chỉ có dạng thức thi đánh giá đầy đủ 4 kỹ năng nghe, nói, đọc, viết để quy đổi tương đương?",
100
- "answer": "Quy định yêu cầu các chứng chỉ phải được cấp trong vòng 2 năm tính đến thời điểm xét và phải có dạng thức thi đánh giá đầy đủ 4 kỹ năng nghe, nói, đọc, viết mới được quy đổi tương đương. Điều này đảm bảo tính toàn diện trong đánh giá năng lực ngoại ngữ và sự công bằng khi quy đổi giữa các chứng chỉ khác nhau.",
101
- "type": "reasoning",
102
- "difficulty": "medium",
103
- "source": "06_ Quy định ngoại ngữ từ K70_chính quy_final.md",
104
- "chunk_index": 2
105
- },
106
- {
107
- "question": "Nếu sinh viên có chứng chỉ TOEIC 4 kỹ năng với điểm các kỹ năng lần lượt là Nghe 750, Nói 600, Đọc 800, Viết 550, thì chứng chỉ này sẽ được quy đổi tương đương như thế nào?",
108
- "answer": "Theo quy định, chứng chỉ TOEIC 4 kỹ năng được quy đổi tương đương sang các chứng chỉ khác dựa theo kỹ năng đạt điểm thấp nhất. Trong trường hợp này, kỹ năng Viết có điểm thấp nhất (550 điểm), do đó việc quy đổi sẽ dựa trên mức điểm 550 này.",
109
- "type": "conditional",
110
- "difficulty": "medium",
111
- "source": "06_ Quy định ngoại ngữ từ K70_chính quy_final.md",
112
- "chunk_index": 2
113
- },
114
- {
115
- "question": "Sinh viên đạt trình độ Bậc 2.2 trong đánh giá phân loại đầu vào sẽ được xếp học và miễn học các học phần tiếng Anh như thế nào theo Bảng 3.1?",
116
- "answer": "Theo Bảng 3.1, sinh viên đạt trình độ Bậc 2.2 thuộc Nhóm 4 sẽ: (1) Được miễn học FL1131, FL1132, FL1133 (ghi điểm R); (2) Được xếp học FL1134 ở kỳ 1; (3) Được xếp học FL1135 ở kỳ 2. Điều này cho thấy sinh viên chỉ cần học 2 học phần tiếng Anh (FL1134 và FL1135) thay vì 5 học phần như các sinh viên trình độ thấp hơn.",
117
- "type": "multi_hop",
118
- "difficulty": "hard",
119
- "source": "06_ Quy định ngoại ngữ từ K70_chính quy_final.md",
120
- "chunk_index": 2
121
- },
122
- {
123
- "question": "Sinh viên A có chứng chỉ APTIS ESOL A2 được cấp cách đây 18 tháng. Sinh viên B có chứng chỉ TOEFL iBT Home Edition được cấp cách đây 6 tháng. Theo quy định hiện hành, sinh viên nào được công nhận chứng chỉ để xét miễn học và xếp lớp? Giải thích các bước xếp lớp cho sinh viên được công nhận.",
124
- "answer": "Sinh viên A được công nhận chứng chỉ, sinh viên B không được công nhận. Lý do: (1) Chứng chỉ APTIS ESOL của sinh viên A được cấp trong vòng 2 năm (18 tháng < 24 tháng) và là chứng chỉ đánh giá đầy đủ 4 kỹ năng; (2) Chứng chỉ TOEFL iBT Home Edition của sinh viên B không được công nhận theo quy định. Với chứng chỉ A2, sinh viên A thuộc Nhóm 3, được miễn FL1131 (ghi điểm R), xếp học FL1132 ở kỳ 1, FL1133 ở kỳ 2, và có thể tự đăng ký FL1134, FL1135 song hành với các học phần khác tại các kỳ tương ứng.",
125
- "type": "case_study",
126
- "difficulty": "hard",
127
- "source": "06_ Quy định ngoại ngữ từ K70_chính quy_final.md",
128
- "chunk_index": 2
129
- }
130
- ]
131
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
scripts/debug_metadata.py DELETED
@@ -1,42 +0,0 @@
1
- """Debug script to check metadata in ChromaDB."""
2
- import sys
3
- from pathlib import Path
4
- from dotenv import find_dotenv, load_dotenv
5
-
6
- load_dotenv(find_dotenv(usecwd=True))
7
-
8
- REPO_ROOT = Path(__file__).resolve().parents[1]
9
- sys.path.insert(0, str(REPO_ROOT))
10
-
11
- from core.embeddings.embedding_model import EmbeddingConfig, QwenEmbeddings
12
- from core.embeddings.vector_store import ChromaConfig, ChromaVectorDB
13
-
14
- emb = QwenEmbeddings(EmbeddingConfig())
15
- db = ChromaVectorDB(embedder=emb, config=ChromaConfig())
16
-
17
- print(f"Total docs: {db.count()}")
18
- print()
19
-
20
- # Get sample documents
21
- docs = db.get_all_documents(limit=10)
22
- print("Sample metadata keys from first 3 docs:")
23
- for i, d in enumerate(docs[:3]):
24
- meta = d.get('metadata', {})
25
- print(f"\n[Doc {i+1}]")
26
- print(f" Keys: {list(meta.keys())}")
27
- print(f" source_basename: '{meta.get('source_basename', 'N/A')}'")
28
- print(f" source_file: '{meta.get('source_file', 'N/A')}'")
29
-
30
- # Check for K68 file specifically
31
- print("\n" + "="*50)
32
- print("Searching for K68 file...")
33
- k68_docs = []
34
- for d in db.get_all_documents(limit=5000):
35
- meta = d.get('metadata', {})
36
- sf = meta.get('source_file', '') or meta.get('source_basename', '')
37
- if 'K68' in sf:
38
- k68_docs.append(d)
39
-
40
- print(f"Found {len(k68_docs)} docs containing 'K68' in source")
41
- if k68_docs:
42
- print(f"Sample: {k68_docs[0].get('metadata', {})}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
scripts/test_single_file.py DELETED
@@ -1,94 +0,0 @@
1
- #!/usr/bin/env python
2
- """Test Small-to-Big với 1 file duy nhất."""
3
- import sys
4
- from pathlib import Path
5
- from dotenv import find_dotenv, load_dotenv
6
-
7
- load_dotenv(find_dotenv(usecwd=True))
8
-
9
- REPO_ROOT = Path(__file__).resolve().parents[1]
10
- if str(REPO_ROOT) not in sys.path:
11
- sys.path.insert(0, str(REPO_ROOT))
12
-
13
- from core.embeddings.chunk import chunk_markdown_file
14
- from core.embeddings.embedding_model import EmbeddingConfig, QwenEmbeddings
15
- from core.embeddings.vector_store import ChromaConfig, ChromaVectorDB
16
-
17
- # Test với 1 file chứa nhiều bảng
18
- TEST_FILE = REPO_ROOT / "data/data_process/quyet_dinh/tieng_anh/06_ Quy định ngoại ngữ từ K70_chính quy_final.md"
19
-
20
-
21
- def main():
22
- print("=" * 60)
23
- print("TEST SMALL-TO-BIG (1 file)")
24
- print("=" * 60)
25
-
26
- # 1. Chunk file
27
- print(f"\n[1/4] Chunking: {TEST_FILE.name}")
28
- nodes = chunk_markdown_file(TEST_FILE)
29
-
30
- parent_nodes = [n for n in nodes if n.metadata.get("is_parent")]
31
- summary_nodes = [n for n in nodes if n.metadata.get("is_table_summary")]
32
- other_nodes = [n for n in nodes if not n.metadata.get("is_parent")]
33
-
34
- print(f" Total nodes: {len(nodes)}")
35
- print(f" - Parent nodes (NOT embedded): {len(parent_nodes)}")
36
- print(f" - Summary nodes: {len(summary_nodes)}")
37
- print(f" - Other nodes (text + small tables): {len(other_nodes) - len(summary_nodes)}")
38
-
39
- # 2. Init DB (với persist_dir tạm)
40
- print("\n[2/4] Initializing test DB...")
41
- emb_cfg = EmbeddingConfig()
42
- emb = QwenEmbeddings(emb_cfg)
43
-
44
- # Dùng folder tạm để không ảnh hưởng DB chính
45
- test_persist = str(REPO_ROOT / "data" / "chroma_test")
46
- db_cfg = ChromaConfig(persist_dir=test_persist, collection_name="test_s2b")
47
- db = ChromaVectorDB(embedder=emb, config=db_cfg)
48
- print(f" Persist dir: {test_persist}")
49
-
50
- # 3. Upsert
51
- print("\n[3/4] Upserting documents...")
52
- count = db.upsert_documents(nodes)
53
- print(f" Upserted: {count}")
54
- print(f" ChromaDB count: {db.count()}")
55
- print(f" Parent nodes stored: {len(db.parent_nodes)}")
56
-
57
- # Check file JSON
58
- json_path = Path(test_persist) / "parent_nodes.json"
59
- if json_path.exists():
60
- print(f" ✅ parent_nodes.json exists ({json_path.stat().st_size} bytes)")
61
- else:
62
- print(f" ❌ parent_nodes.json NOT found!")
63
-
64
- # 4. Test retrieval
65
- print("\n[4/4] Testing retrieval...")
66
- from core.embeddings.retrival import Retriever, RetrievalMode
67
-
68
- retriever = Retriever(vector_db=db, use_reranker=False)
69
-
70
- test_query = "TOEIC Nghe 350 điểm tương đương bậc mấy?"
71
- print(f" Query: {test_query}")
72
-
73
- results = retriever.vector_search(test_query, k=3)
74
-
75
- for i, r in enumerate(results, 1):
76
- meta = r.get("metadata", {})
77
- content = r.get("content", "")[:200]
78
-
79
- print(f"\n [{i}]")
80
- print(f" is_table_summary: {meta.get('is_table_summary', False)}")
81
- print(f" swapped_from_summary: {meta.get('swapped_from_summary', False)}")
82
- print(f" source: {meta.get('source_file', 'N/A')}")
83
- print(f" content: {content}...")
84
-
85
- print("\n" + "=" * 60)
86
- print("TEST COMPLETE")
87
- print("=" * 60)
88
-
89
- # Cleanup prompt
90
- print(f"\nTo cleanup test data: rm -rf {test_persist}")
91
-
92
-
93
- if __name__ == "__main__":
94
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
scripts/update_files.py DELETED
@@ -1,226 +0,0 @@
1
- """
2
- Script cập nhật các file cụ thể trong ChromaDB mà không cần rebuild toàn bộ.
3
-
4
- Usage:
5
- # Cập nhật một file cụ thể
6
- python scripts/update_files.py --files "data/data_process/quyet_dinh/tieng_anh/QD_ngoai_ngu_tu_K68_CQ_final.md"
7
-
8
- # Cập nhật nhiều files
9
- python scripts/update_files.py --files "file1.md" "file2.md" "file3.md"
10
-
11
- # Cập nhật tất cả files trong một thư mục
12
- python scripts/update_files.py --dir "data/data_process/quyet_dinh/tieng_anh"
13
-
14
- # Chỉ xóa (không re-ingest)
15
- python scripts/update_files.py --files "file.md" --delete-only
16
-
17
- # Dry-run để xem sẽ làm gì
18
- python scripts/update_files.py --files "file.md" --dry-run
19
- """
20
-
21
- import sys
22
- import argparse
23
- from pathlib import Path
24
- from dotenv import find_dotenv, load_dotenv
25
-
26
- load_dotenv(find_dotenv(usecwd=True))
27
-
28
- REPO_ROOT = Path(__file__).resolve().parents[1]
29
- if str(REPO_ROOT) not in sys.path:
30
- sys.path.insert(0, str(REPO_ROOT))
31
-
32
- from core.embeddings.chunk import chunk_markdown_file
33
- from core.embeddings.embedding_model import EmbeddingConfig, QwenEmbeddings
34
- from core.embeddings.vector_store import ChromaConfig, ChromaVectorDB
35
-
36
-
37
- def get_docs_by_source_file(db: ChromaVectorDB, source_basename: str) -> list:
38
- """Lấy tất cả documents thuộc về một source file."""
39
- col = db.collection
40
- if col is None:
41
- return []
42
-
43
- # Query theo source_file (tên file trong metadata)
44
- result = col.get(
45
- where={"source_file": source_basename},
46
- include=['documents', 'metadatas']
47
- )
48
-
49
- docs = []
50
- ids = result.get('ids', [])
51
- for i, doc_id in enumerate(ids):
52
- docs.append({
53
- 'id': doc_id,
54
- 'content': result['documents'][i] if result.get('documents') else '',
55
- 'metadata': result['metadatas'][i] if result.get('metadatas') else {},
56
- })
57
-
58
- # Nếu không tìm thấy, thử theo source_file (path đầy đủ)
59
- if not docs:
60
- # Lấy tất cả và filter thủ công
61
- all_docs = db.get_all_documents(limit=10000)
62
- for d in all_docs:
63
- meta = d.get('metadata', {})
64
- s_basename = meta.get('source_basename', '')
65
- s_file = meta.get('source_file', '')
66
- if source_basename in s_basename or source_basename in s_file:
67
- docs.append(d)
68
-
69
- return docs
70
-
71
-
72
- def delete_file_from_db(db: ChromaVectorDB, source_basename: str, dry_run: bool = False) -> int:
73
- """Xóa tất cả documents thuộc về một file."""
74
- docs = get_docs_by_source_file(db, source_basename)
75
-
76
- if not docs:
77
- print(f"Không tìm thấy documents cho: {source_basename}")
78
- return 0
79
-
80
- ids_to_delete = [d['id'] for d in docs]
81
-
82
- if dry_run:
83
- print(f"[DRY-RUN] Sẽ xóa {len(ids_to_delete)} documents cho: {source_basename}")
84
- # Also check parent nodes
85
- parent_count = sum(1 for key, node in db.parent_nodes.items()
86
- if source_basename in node.get("metadata", {}).get("source_file", ""))
87
- if parent_count > 0:
88
- print(f"[DRY-RUN] Sẽ xóa {parent_count} parent nodes cho: {source_basename}")
89
- return len(ids_to_delete)
90
-
91
- # Delete documents from ChromaDB
92
- deleted = db.delete_documents(ids_to_delete)
93
- print(f"Đã xóa {deleted} documents cho: {source_basename}")
94
-
95
- # Also delete parent nodes for this file
96
- parent_deleted = db.delete_parent_nodes_by_source(source_basename)
97
- if parent_deleted > 0:
98
- print(f"Đã xóa {parent_deleted} parent nodes cho: {source_basename}")
99
-
100
- return deleted
101
-
102
-
103
- def ingest_file(db: ChromaVectorDB, file_path: Path, dry_run: bool = False) -> int:
104
- if not file_path.exists():
105
- print(f"File không tồn tại: {file_path}")
106
- return 0
107
-
108
- docs = chunk_markdown_file(file_path)
109
-
110
- if not docs:
111
- print(f"Không có chunks từ: {file_path.name}")
112
- return 0
113
-
114
- if dry_run:
115
- print(f" [DRY-RUN] Sẽ thêm {len(docs)} chunks từ: {file_path.name}")
116
- return len(docs)
117
-
118
- n = db.upsert_documents(docs)
119
- print(f" ✓ Đã thêm {n} chunks từ: {file_path.name}")
120
- return n
121
-
122
-
123
- def update_file(db: ChromaVectorDB, file_path: Path, dry_run: bool = False, delete_only: bool = False) -> tuple:
124
- source_basename = file_path.name
125
-
126
- print(f"\n Processing: {file_path}")
127
-
128
- # Bước 1: Xóa documents cũ
129
- deleted = delete_file_from_db(db, source_basename, dry_run)
130
-
131
- # Bước 2: Thêm documents mới (nếu không chỉ xóa)
132
- added = 0
133
- if not delete_only:
134
- added = ingest_file(db, file_path, dry_run)
135
-
136
- return deleted, added
137
-
138
-
139
- def main():
140
- parser = argparse.ArgumentParser(description="Cập nhật files cụ thể trong ChromaDB")
141
- parser.add_argument("--files", nargs="+", help="Danh sách files cần cập nhật")
142
- parser.add_argument("--dir", help="Thư mục chứa các files cần cập nhật")
143
- parser.add_argument("--dry-run", action="store_true", help="Chỉ hiển thị, không thực sự thay đổi")
144
- parser.add_argument("--delete-only", action="store_true", help="Chỉ xóa, không thêm lại")
145
- args = parser.parse_args()
146
-
147
- if not args.files and not args.dir:
148
- parser.error("Phải chỉ định --files hoặc --dir")
149
-
150
- # Thu thập danh sách files
151
- files_to_update = []
152
-
153
- if args.files:
154
- for f in args.files:
155
- file_path = REPO_ROOT / f
156
- if file_path.exists():
157
- files_to_update.append(file_path)
158
- else:
159
- print(f" File không tồn tại: {f}")
160
-
161
- if args.dir:
162
- dir_path = REPO_ROOT / args.dir
163
- if dir_path.exists() and dir_path.is_dir():
164
- files_to_update.extend(sorted(dir_path.glob("*.md")))
165
- else:
166
- print(f"Thư mục không tồn tại: {args.dir}")
167
-
168
- if not files_to_update:
169
- print(" Không có files nào để xử lý!")
170
- return
171
-
172
- print("=" * 60)
173
- print("CẬP NHẬT FILES TRONG CHROMADB")
174
- if args.dry_run:
175
- print("🔍 MODE: DRY-RUN (chỉ xem, không thay đổi)")
176
- if args.delete_only:
177
- print("🗑️ MODE: DELETE-ONLY (chỉ xóa)")
178
- print("=" * 60)
179
-
180
- print(f"\n📋 Files sẽ xử lý ({len(files_to_update)}):")
181
- for f in files_to_update:
182
- print(f" - {f.name}")
183
-
184
- # Khởi tạo embedder và database
185
- print("\n[1/3] Khởi tạo embedder...")
186
- emb_cfg = EmbeddingConfig()
187
- emb = QwenEmbeddings(emb_cfg)
188
- print(f" ✓ Model: {emb_cfg.model}")
189
-
190
- print("\n[2/3] Kết nối ChromaDB...")
191
- db_cfg = ChromaConfig()
192
- db = ChromaVectorDB(embedder=emb, config=db_cfg)
193
- old_count = db.count()
194
- print(f" ✓ Collection: {db_cfg.collection_name}")
195
- print(f" ✓ Current docs: {old_count}")
196
-
197
- # Xử lý từng file
198
- print("\n[3/3] Xử lý files...")
199
- total_deleted = 0
200
- total_added = 0
201
-
202
- for file_path in files_to_update:
203
- deleted, added = update_file(db, file_path, args.dry_run, args.delete_only)
204
- total_deleted += deleted
205
- total_added += added
206
-
207
- # Kết quả
208
- new_count = db.count()
209
-
210
- print("\n" + "=" * 60)
211
- print(" KẾT QUẢ:")
212
- print(f" Files đã xử lý: {len(files_to_update)}")
213
- print(f" Documents đã xóa: {total_deleted}")
214
- print(f" Documents đã thêm: {total_added}")
215
- print(f" DB count trước: {old_count}")
216
- print(f" DB count sau: {new_count}")
217
- print(f" Delta: {new_count - old_count:+d}")
218
- print("=" * 60)
219
-
220
- if args.dry_run:
221
- print("\n Đây là DRY-RUN - không có thay đổi thực sự!")
222
- print(" Chạy lại không có --dry-run để thực hiện.")
223
-
224
-
225
- if __name__ == "__main__":
226
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
scripts/verify_file.py DELETED
@@ -1,101 +0,0 @@
1
- """
2
- Script kiểm tra documents của một file cụ thể trong ChromaDB.
3
-
4
- Usage:
5
- python scripts/verify_file.py --file "QD_ngoai_ngu_tu_K68_CQ_final.md"
6
- """
7
-
8
- import sys
9
- from pathlib import Path
10
- from dotenv import find_dotenv, load_dotenv
11
-
12
- load_dotenv(find_dotenv(usecwd=True))
13
-
14
- REPO_ROOT = Path(__file__).resolve().parents[1]
15
- if str(REPO_ROOT) not in sys.path:
16
- sys.path.insert(0, str(REPO_ROOT))
17
-
18
- from core.embeddings.embedding_model import EmbeddingConfig, QwenEmbeddings
19
- from core.embeddings.vector_store import ChromaConfig, ChromaVectorDB
20
-
21
-
22
- def verify_file(source_basename: str):
23
- """Kiểm tra documents của một file trong database."""
24
-
25
- print("=" * 60)
26
- print(f"VERIFY FILE: {source_basename}")
27
- print("=" * 60)
28
-
29
- # Khởi tạo
30
- emb_cfg = EmbeddingConfig()
31
- emb = QwenEmbeddings(emb_cfg)
32
- db_cfg = ChromaConfig()
33
- db = ChromaVectorDB(embedder=emb, config=db_cfg)
34
-
35
- print(f"\nTotal docs in DB: {db.count()}")
36
-
37
- # Query theo source_file (tên file)
38
- col = db.collection
39
- result = col.get(
40
- where={"source_file": source_basename},
41
- include=['documents', 'metadatas']
42
- )
43
-
44
- ids = result.get('ids', [])
45
- docs = result.get('documents', [])
46
- metas = result.get('metadatas', [])
47
-
48
- print(f"\nDocuments for '{source_basename}': {len(ids)}")
49
-
50
- if not ids:
51
- print(" (Không tìm thấy documents)")
52
- return
53
-
54
- print("\n" + "-" * 60)
55
- print("SAMPLE METADATA (first 3 docs):")
56
- print("-" * 60)
57
-
58
- for i, meta in enumerate(metas[:3]):
59
- print(f"\n[Doc {i+1}] ID: {ids[i][:20]}...")
60
- for key, value in meta.items():
61
- # Truncate long values
62
- val_str = str(value)
63
- if len(val_str) > 80:
64
- val_str = val_str[:80] + "..."
65
- print(f" {key}: {val_str}")
66
-
67
- # Thống kê metadata
68
- print("\n" + "-" * 60)
69
- print("METADATA STATS:")
70
- print("-" * 60)
71
-
72
- titles = set()
73
- cohorts = set()
74
- doc_types = set()
75
-
76
- for meta in metas:
77
- if meta.get('title'):
78
- titles.add(meta.get('title'))
79
- if meta.get('applicable_cohorts'):
80
- cohorts.add(meta.get('applicable_cohorts'))
81
- if meta.get('document_type'):
82
- doc_types.add(meta.get('document_type'))
83
-
84
- print(f" Unique titles: {titles}")
85
- print(f" Cohorts: {cohorts}")
86
- print(f" Doc types: {doc_types}")
87
-
88
- print("\n" + "=" * 60)
89
-
90
-
91
- def main():
92
- import argparse
93
- parser = argparse.ArgumentParser()
94
- parser.add_argument("--file", required=True, help="Tên file cần verify (source_basename)")
95
- args = parser.parse_args()
96
-
97
- verify_file(args.file)
98
-
99
-
100
- if __name__ == "__main__":
101
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
test/chunk_results.md CHANGED
The diff for this file is too large to render. See raw diff
 
test/llama.py DELETED
@@ -1,42 +0,0 @@
1
- import os
2
- from llama_parse import LlamaParse, ResultType
3
- from dotenv import load_dotenv
4
-
5
- load_dotenv()
6
-
7
- def test_llamaparse(file_path: str):
8
- parser = LlamaParse(
9
- result_type=ResultType.MD, # Định dạng Markdown giúp giữ cấu trúc bảng cực tốt
10
- num_workers=4, # Chạy song song để tăng tốc
11
- verbose=True,
12
- language="vi" # Cấu hình ngôn ngữ tiếng Việt
13
- )
14
-
15
- print(f"--- Đang bắt đầu xử lý file: {file_path} ---")
16
-
17
- # Thực hiện trích xuất dữ liệu
18
- documents = parser.load_data(file_path)
19
-
20
- if documents:
21
- # In thử 1000 ký tự đầu tiên để kiểm tra
22
- print("\n--- Kết quả trích xuất mẫu ---")
23
- print(documents[0].text[:1000])
24
-
25
- # Lưu kết quả ra file .md để bạn xem cấu trúc bảng có bị lệch không
26
- output_name = "data/parsed_llama_result.md"
27
- with open(output_name, "w", encoding="utf-8") as f:
28
- for doc in documents:
29
- f.write(doc.text + "\n\n")
30
- print(f"\n--- Đã lưu toàn bộ nội dung vào: {output_name} ---")
31
- else:
32
- print("Lỗi: Không tìm thấy nội dung trong file.")
33
-
34
- if __name__ == "__main__":
35
- # Thay đường dẫn đến file PDF quy chế của bạn vào đây
36
- PATH_TO_PDF = "data/data_raw/quyet_dinh/quy-dinh-chuan-ngoai-ngu-2021.pdf"
37
-
38
- api_key = os.getenv("LLAMA_CLOUD_API_KEY")
39
- if not api_key:
40
- print("Lỗi: Bạn chưa cấu hình LLAMA_CLOUD_API_KEY trong file .env")
41
- else:
42
- test_llamaparse(PATH_TO_PDF)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
test/test_small_to_big.py CHANGED
@@ -17,7 +17,7 @@ def test_chunk_with_summary():
17
  """Test chunking a file with tables to verify summary generation."""
18
 
19
  # Use the K70 English requirements file which has many tables
20
- test_file = REPO_ROOT / "data/data_process/quyet_dinh/tieng_anh/06_ Quy định ngoại ngữ từ K70_chính quy_final.md"
21
 
22
  if not test_file.exists():
23
  print(f"❌ Test file not found: {test_file}")
@@ -96,11 +96,22 @@ def export_to_markdown(nodes, output_path: Path, source_name: str):
96
  parent = parent_map.get(parent_id)
97
  meta = node.metadata
98
 
99
- lines.append(f"### Summary #{i}")
 
 
 
 
 
 
 
100
  lines.append(f"")
101
  lines.append(f"**Metadata:**")
102
  lines.append(f"- is_table_summary: True")
103
  lines.append(f"- parent_id: `{parent_id}`")
 
 
 
 
104
  if meta.get("source_file"):
105
  lines.append(f"- source_file: {meta.get('source_file')}")
106
  if meta.get("applicable_cohorts"):
@@ -121,6 +132,7 @@ def export_to_markdown(nodes, output_path: Path, source_name: str):
121
 
122
  lines.append(f"---")
123
  lines.append(f"")
 
124
 
125
  # Small tables (embedded directly)
126
  if table_nodes:
@@ -129,10 +141,20 @@ def export_to_markdown(nodes, output_path: Path, source_name: str):
129
 
130
  for i, node in enumerate(table_nodes, 1):
131
  meta = node.metadata
132
- lines.append(f"### Small Table #{i}")
 
 
 
 
 
 
133
  lines.append(f"")
134
  lines.append(f"**Metadata:**")
135
  lines.append(f"- is_table: True")
 
 
 
 
136
  if meta.get("table_part"):
137
  lines.append(f"- table_part: {meta.get('table_part')}")
138
  if meta.get("source_file"):
@@ -148,6 +170,7 @@ def export_to_markdown(nodes, output_path: Path, source_name: str):
148
  lines.append(f"")
149
  lines.append(f"---")
150
  lines.append(f"")
 
151
 
152
  # Text nodes
153
  lines.append("## 📄 Text Nodes")
 
17
  """Test chunking a file with tables to verify summary generation."""
18
 
19
  # Use the K70 English requirements file which has many tables
20
+ test_file = REPO_ROOT / "data/data_process/chuong_trinh_dao_tao/1.1. Kỹ thuật điện tử.md"
21
 
22
  if not test_file.exists():
23
  print(f"❌ Test file not found: {test_file}")
 
96
  parent = parent_map.get(parent_id)
97
  meta = node.metadata
98
 
99
+ # Build table identifier for title
100
+ table_num = meta.get('table_number', '')
101
+ table_title = meta.get('table_title', '')
102
+ title_suffix = ""
103
+ if table_num:
104
+ title_suffix = f" (Bảng {table_num})"
105
+
106
+ lines.append(f"### Summary #{i}{title_suffix}")
107
  lines.append(f"")
108
  lines.append(f"**Metadata:**")
109
  lines.append(f"- is_table_summary: True")
110
  lines.append(f"- parent_id: `{parent_id}`")
111
+ if table_num:
112
+ lines.append(f"- table_number: {table_num}")
113
+ if table_title:
114
+ lines.append(f"- table_title: {table_title}")
115
  if meta.get("source_file"):
116
  lines.append(f"- source_file: {meta.get('source_file')}")
117
  if meta.get("applicable_cohorts"):
 
132
 
133
  lines.append(f"---")
134
  lines.append(f"")
135
+
136
 
137
  # Small tables (embedded directly)
138
  if table_nodes:
 
141
 
142
  for i, node in enumerate(table_nodes, 1):
143
  meta = node.metadata
144
+ table_num = meta.get('table_number', '')
145
+ table_title = meta.get('table_title', '')
146
+ title_suffix = ""
147
+ if table_num:
148
+ title_suffix = f" (Bảng {table_num})"
149
+
150
+ lines.append(f"### Small Table #{i}{title_suffix}")
151
  lines.append(f"")
152
  lines.append(f"**Metadata:**")
153
  lines.append(f"- is_table: True")
154
+ if table_num:
155
+ lines.append(f"- table_number: {table_num}")
156
+ if table_title:
157
+ lines.append(f"- table_title: {table_title}")
158
  if meta.get("table_part"):
159
  lines.append(f"- table_part: {meta.get('table_part')}")
160
  if meta.get("source_file"):
 
170
  lines.append(f"")
171
  lines.append(f"---")
172
  lines.append(f"")
173
+
174
 
175
  # Text nodes
176
  lines.append("## 📄 Text Nodes")