|
6 | 6 | "id": "ksUdu7H7qBig" |
7 | 7 | }, |
8 | 8 | "source": [ |
9 | | - "# 🤖 벡터 검색 에이전트: 허깅페이스 허브를 백엔드로 하는 똑똑한 검색 엔진\n", |
| 9 | + "# 🤖 벡터 검색 에이전트: 허깅페이스 허브를 백엔드로 하는 지능형 검색 엔진\n", |
10 | 10 | "\n", |
11 | 11 | "_참조: [Martin Elstner](https://github.com/MartinEls)\n", |
12 | 12 | "_작성자: [안정](https://github.com/ahnjj)\n", |
13 | 13 | "\n", |
14 | | - "검색엔진은 크게 키워드 검색과 벡터 검색으로 분류 됩니다. 키워드 검색과는 달리, 벡터 검색으로 진행할 경우 두가지를 고려해야합니다.\n", |
| 14 | + "검색 엔진은 크게 키워드 검색과 벡터 검색으로 나눌 수 있습니다.\n", |
| 15 | + "키워드 검색과 달리, 벡터 검색을 사용할 때는 두 가지를 고려해야 합니다.\n", |
15 | 16 | "1. 적합한 임베딩 모델로 데이터셋과 쿼리를 임베딩하는 작업\n", |
16 | 17 | "2. 임베딩 데이터를 처리할 수 있는 DB\n", |
17 | 18 | "\n", |
18 | | - "그러나, 임베딩값을 기반으로하는 벡터 검색만으로는 '사용자가 원하는 답변'를 보장하기 어렵습니다.\n", |
| 19 | + "하지만 임베딩 값을 기반으로 한 벡터 검색만으로는 ‘사용자가 원하는 답변’을 보장하기 어렵습니다.\n", |
19 | 20 | "\n", |
20 | | - "따라서 검색의 각 단계에서 에이전트가 각 단계를 자율적으로 판단하고 최적화한다면 사용자가 원하는 답변에 가까운 검색 결과를 얻을 수 있을 것 같습니다!\n", |
| 21 | + "그래서 검색 과정에서 에이전트가 자율적으로 판단하고 최적화한다면, 사용자 의도에 더 가까운 검색 결과를 얻을 수 있습니다.\n", |
21 | 22 | "\n", |
22 | 23 | "### Agentic 접근 방식의 차별점\n", |
23 | | - "기존 벡터검색 워크플로우\n", |
| 24 | + "기존 벡터 검색 워크플로우\n", |
24 | 25 | "```\n", |
25 | 26 | "데이터 ➡ 데이터 임베딩(고정 모델) ➡ 인덱스 생성 ➡ 사용자 질의 ➡ 유사도 검색 ➡ 답변\n", |
26 | 27 | "```\n", |
|
30 | 31 | "```\n", |
31 | 32 | "\n", |
32 | 33 | "### DuckDB?\n", |
33 | | - "허깅페이스의 데이터셋은 파켓(parquet) 파일에 의존하는데 빠른 인메모리 데이터베이스 시스템인 [DuckDB를 사용하면 이 파일들과 상호작용](https://huggingface.co/docs/hub/en/datasets-duckdb)할 수 있습니다. 또한 DuckDB의 기능 중 하나는 [벡터 유사도 검색](https://duckdb.org/docs/extensions/vss.html)으로, 인덱스 유무에 관계없이 사용할 수 있습니다.\n", |
| 34 | + "허깅페이스의 데이터셋은 파켓(parquet) 파일을 기반으로 동작하는데, 이때 빠른 인메모리 데이터베이스 시스템인 [DuckDB를 사용하면 이 파일들과 상호작용](https://huggingface.co/docs/hub/en/datasets-duckdb)할 수 있습니다. 또한 DuckDB의 기능 중 하나는 [벡터 유사도 검색](https://duckdb.org/docs/extensions/vss.html)으로, 인덱스 유무에 관계없이 사용할 수 있습니다.\n", |
34 | 35 | "\n", |
35 | 36 | "\n", |
36 | 37 | "이번 노트북에서는 단일 Agent에 여러가지 도구를 주어 수행하는 간단한 Agentic 벡터 검색 엔진을 만들어 보겠습니다." |
37 | 38 | ] |
38 | 39 | }, |
39 | 40 | { |
40 | 41 | "cell_type": "markdown", |
41 | | - "metadata": { |
42 | | - "id": "Old2t6dnpi3M" |
43 | | - }, |
| 42 | + "metadata": {}, |
44 | 43 | "source": [ |
45 | | - "# 도구정의\n", |
46 | | - "정의할 도구는 아래와 같습니다.\n", |
47 | | - "- 임베딩 생성 도구\n", |
48 | | - "- 인덱스 생성 도구\n", |
49 | | - "- 유사도 검색 도구\n", |
50 | | - "- 답변 생성 도구" |
| 44 | + "필요한 의존성을 설치합니다 :" |
| 45 | + ] |
| 46 | + }, |
| 47 | + { |
| 48 | + "cell_type": "code", |
| 49 | + "execution_count": null, |
| 50 | + "metadata": {}, |
| 51 | + "outputs": [], |
| 52 | + "source": [ |
| 53 | + "# 본 예제 파일은 Python 3.10 이상 버전에서만 실행할 수 있습니다.\n", |
| 54 | + "!pip install -U smolagents datasets sentence-transformers duckdb openai" |
| 55 | + ] |
| 56 | + }, |
| 57 | + { |
| 58 | + "cell_type": "markdown", |
| 59 | + "metadata": {}, |
| 60 | + "source": [ |
| 61 | + "HuggingFace의 추론 API를 사용하기 위해 로그인합니다 : " |
| 62 | + ] |
| 63 | + }, |
| 64 | + { |
| 65 | + "cell_type": "code", |
| 66 | + "execution_count": null, |
| 67 | + "metadata": {}, |
| 68 | + "outputs": [], |
| 69 | + "source": [ |
| 70 | + "from huggingface_hub import notebook_login\n", |
| 71 | + "\n", |
| 72 | + "notebook_login()" |
51 | 73 | ] |
52 | 74 | }, |
53 | 75 | { |
|
60 | 82 | "source": [ |
61 | 83 | "from smolagents import tool\n", |
62 | 84 | "from datasets import Dataset\n", |
63 | | - "from sentence_transformers import SentenceTransformer\n", |
64 | | - "import duckdb\n", |
65 | | - "import openai" |
| 85 | + "import os\n", |
| 86 | + "\n", |
| 87 | + "# 도구 사용을 위해 OPENAI 키를 발급 받아야합니다.\n", |
| 88 | + "os.environ[\"OPENAI_API_KEY\"] = \"YOUR KEY\"" |
| 89 | + ] |
| 90 | + }, |
| 91 | + { |
| 92 | + "cell_type": "markdown", |
| 93 | + "metadata": { |
| 94 | + "id": "Old2t6dnpi3M" |
| 95 | + }, |
| 96 | + "source": [ |
| 97 | + "# 도구 정의\n", |
| 98 | + "정의할 도구는 아래와 같습니다.\n", |
| 99 | + "- 임베딩 생성 도구\n", |
| 100 | + "- 인덱스 생성 도구\n", |
| 101 | + "- 유사도 검색 도구\n", |
| 102 | + "- 답변 생성 도구" |
66 | 103 | ] |
67 | 104 | }, |
68 | 105 | { |
|
72 | 109 | }, |
73 | 110 | "source": [ |
74 | 111 | "### 도구1 : 임베딩 생성\n", |
75 | | - "일반적으로, 임베딩 작업에서는 더 작은 배치사이즈로 줄여 청킹하나 여기서는 데이터셋을 임베딩으로 바꾸기만 하겠습니다." |
| 112 | + "일반적으로, 임베딩 작업에서는 작은 배치 사이즈로 데이터를 청킹하지만 여기서는 단순히 데이터셋을 임베딩으로 변환하는 과정만 수행하겠습니다." |
76 | 113 | ] |
77 | 114 | }, |
78 | 115 | { |
|
95 | 132 | " Args:\n", |
96 | 133 | " dataset: 임베딩을 생성할 대상 데이터셋\n", |
97 | 134 | " model_id: 임베딩에 사용할 모델\n", |
98 | | - " column_name: 임베딩할 컬럼 이름\n", |
| 135 | + " column_name: 임베딩할 열 이름\n", |
99 | 136 | "\n", |
100 | 137 | " Returns:\n", |
101 | 138 | " 임베딩이 추가된 데이터셋\n", |
102 | 139 | " \"\"\"\n", |
| 140 | + " from sentence_transformers import SentenceTransformer\n", |
103 | 141 | "\n", |
104 | 142 | " model = SentenceTransformer(model_id)\n", |
105 | 143 | "\n", |
|
144 | 182 | "id": "kS61lIgSAYmS" |
145 | 183 | }, |
146 | 184 | "source": [ |
147 | | - "### 도구2 : DuckDB인덱스 만들기" |
| 185 | + "### 도구2 : DuckDB 인덱스 만들기" |
148 | 186 | ] |
149 | 187 | }, |
150 | 188 | { |
|
167 | 205 | " Args:\n", |
168 | 206 | " dataset_with_embeddings: 이미 임베딩이 포함된 데이터셋\n", |
169 | 207 | " table_name: 생성할 테이블 이름\n", |
170 | | - " embedding_column: 임베딩 컬럼 이름\n", |
| 208 | + " embedding_column: 임베딩 열 이름\n", |
171 | 209 | "\n", |
172 | 210 | " Returns:\n", |
173 | 211 | " None\n", |
174 | 212 | " \"\"\"\n", |
| 213 | + " import duckdb\n", |
| 214 | + " \n", |
175 | 215 | " # VSS 확장 설치 및 로드\n", |
176 | 216 | " duckdb.sql(\"INSTALL vss; LOAD vss;\")\n", |
177 | 217 | " duckdb.sql(f\"DROP TABLE IF EXISTS {table_name};\")\n", |
|
218 | 258 | "id": "ygW649Ln0OvV" |
219 | 259 | }, |
220 | 260 | "source": [ |
221 | | - "### 도구3: 벡터 검색 수행하기" |
| 261 | + "### 도구3 : 벡터 검색 수행하기" |
222 | 262 | ] |
223 | 263 | }, |
224 | 264 | { |
|
251 | 291 | " dict: 검색 결과\n", |
252 | 292 | " \"\"\"\n", |
253 | 293 | " from sentence_transformers import SentenceTransformer\n", |
| 294 | + " import duckdb\n", |
| 295 | + " \n", |
254 | 296 | " model = SentenceTransformer(model_id)\n", |
255 | 297 | " embedding = model.encode(query).tolist()\n", |
256 | 298 | " return duckdb.sql(\n", |
|
269 | 311 | "id": "XVT4VYknqBij" |
270 | 312 | }, |
271 | 313 | "source": [ |
272 | | - "무거운 벡터 검색 엔진을 배포할 필요가 없고 저장소는 허브에서 처리됩니다." |
| 314 | + "무거운 벡터 검색 엔진을 따로 배포할 필요 없고, 저장소는 허브에서 처리됩니다." |
273 | 315 | ] |
274 | 316 | }, |
275 | 317 | { |
|
278 | 320 | "id": "AQf6IxFGqBij" |
279 | 321 | }, |
280 | 322 | "source": [ |
281 | | - "### 도구4 :답변 생성 도구\n", |
| 323 | + "### 도구4 : 답변 생성 도구\n", |
282 | 324 | "유사도 검색 결과 청크를 기반으로, LLM이 사용자가 원할 만한 답변을 생성합니다." |
283 | 325 | ] |
284 | 326 | }, |
|
302 | 344 | " Returns:\n", |
303 | 345 | " str: 생성된 답변\n", |
304 | 346 | " \"\"\"\n", |
| 347 | + " import openai # OPENAI 키 발급이 필요합니다.\n", |
| 348 | + " \n", |
305 | 349 | " context = \"\\n\\n\".join(chunks)\n", |
306 | 350 | " prompt = f\"Context:\\n{context}\\n\\nQuestion: {query}\\nAnswer:\"\n", |
307 | 351 | " response = openai.ChatCompletion.create(\n", |
|
523 | 567 | "\n", |
524 | 568 | "단순히 검색 결과만을 가져오는 것이 아니라, 검색결과를 바탕으로 쿼리에 따른 답변을 정제해서 보여주었습니다.✌🏻\n", |
525 | 569 | "\n", |
526 | | - "위는 간단한 에이전트 시스템이지만, 품질 평가, 분석 등을 추가한다면 진정한 Agentic 검색 엔진을 구현할 수 있을 것 입니다!" |
| 570 | + "지금까지 간단한 에이전트 시스템을 만들어보았습니다. 여기에 품질 평가, 분석 등을 추가한다면 진정한 Agentic 검색 엔진을 구현할 수 있습니다." |
527 | 571 | ] |
528 | 572 | } |
529 | 573 | ], |
|
0 commit comments