n2-qln 3.4.2 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ko.md +459 -470
- package/README.md +459 -490
- package/dist/index.d.ts +3 -0
- package/dist/index.js +87 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/config.d.ts +9 -0
- package/{lib → dist/lib}/config.js +23 -27
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/embedding.d.ts +27 -0
- package/{lib → dist/lib}/embedding.js +39 -47
- package/dist/lib/embedding.js.map +1 -0
- package/dist/lib/executor.d.ts +57 -0
- package/dist/lib/executor.js +175 -0
- package/dist/lib/executor.js.map +1 -0
- package/dist/lib/mcp-discovery.d.ts +83 -0
- package/dist/lib/mcp-discovery.js +203 -0
- package/dist/lib/mcp-discovery.js.map +1 -0
- package/dist/lib/provider-loader.d.ts +13 -0
- package/dist/lib/provider-loader.js +146 -0
- package/dist/lib/provider-loader.js.map +1 -0
- package/dist/lib/registry.d.ts +38 -0
- package/{lib → dist/lib}/registry.js +82 -92
- package/dist/lib/registry.js.map +1 -0
- package/dist/lib/router.d.ts +63 -0
- package/{lib → dist/lib}/router.js +75 -117
- package/dist/lib/router.js.map +1 -0
- package/dist/lib/schema.d.ts +20 -0
- package/{lib → dist/lib}/schema.js +38 -30
- package/dist/lib/schema.js.map +1 -0
- package/dist/lib/store.d.ts +37 -0
- package/dist/lib/store.js +207 -0
- package/dist/lib/store.js.map +1 -0
- package/dist/lib/validator.d.ts +37 -0
- package/dist/lib/validator.js +114 -0
- package/dist/lib/validator.js.map +1 -0
- package/dist/lib/vector-index.d.ts +37 -0
- package/{lib → dist/lib}/vector-index.js +19 -36
- package/dist/lib/vector-index.js.map +1 -0
- package/dist/tools/qln-call.d.ts +41 -0
- package/dist/tools/qln-call.js +353 -0
- package/dist/tools/qln-call.js.map +1 -0
- package/dist/tools/qln-helpers.d.ts +55 -0
- package/dist/tools/qln-helpers.js +88 -0
- package/dist/tools/qln-helpers.js.map +1 -0
- package/dist/types.d.ts +243 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/index.js +3 -79
- package/package.json +11 -4
- package/.github/FUNDING.yml +0 -3
- package/docs/README.md +0 -2
- package/docs/architecture.png +0 -0
- package/lib/executor.js +0 -104
- package/lib/provider-loader.js +0 -126
- package/lib/store.js +0 -217
- package/lib/validator.js +0 -171
- package/tools/qln-call.js +0 -257
package/README.ko.md
CHANGED
|
@@ -1,470 +1,459 @@
|
|
|
1
|
-
🇺🇸 [English](README.md)
|
|
2
|
-
|
|
3
|
-
# n2-qln
|
|
4
|
-
|
|
5
|
-
[](https://www.npmjs.com/package/n2-qln) [](LICENSE) [](https://nodejs.org) [](https://www.npmjs.com/package/n2-qln)
|
|
6
|
-
|
|
7
|
-
**QLN** = **Q**uery **L**ayer **N**etwork — AI와 도구 사이에 위치하는 시맨틱
|
|
8
|
-
|
|
9
|
-
> **1,000개 이상의 도구를 1개의 MCP 도구로 라우팅합니다.** AI는
|
|
10
|
-
|
|
11
|
-

|
|
12
|
-
|
|
13
|
-
## 목차
|
|
14
|
-
|
|
15
|
-
- [
|
|
16
|
-
- [
|
|
17
|
-
- [
|
|
18
|
-
- [
|
|
19
|
-
- [
|
|
20
|
-
- [
|
|
21
|
-
- [
|
|
22
|
-
- [
|
|
23
|
-
- [프로젝트 구조](#프로젝트-구조)
|
|
24
|
-
- [
|
|
25
|
-
- [
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
"
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
n2_qln_call({
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
├──
|
|
396
|
-
├──
|
|
397
|
-
│
|
|
398
|
-
│
|
|
399
|
-
│
|
|
400
|
-
│
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
|
419
|
-
|
|
420
|
-
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
**
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
2.
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
## 라이선스
|
|
461
|
-
|
|
462
|
-
Apache-2.0
|
|
463
|
-
|
|
464
|
-
---
|
|
465
|
-
|
|
466
|
-
> *"1,000개 도구를 200 토큰으로. 이건 최적화가 아니라 패러다임 전환이다."*
|
|
467
|
-
|
|
468
|
-
[nton2.com](https://nton2.com) · [npm](https://www.npmjs.com/package/n2-qln) · lagi0730@gmail.com
|
|
469
|
-
|
|
470
|
-
<sub> Rose가 만들었습니다 — N2의 첫 번째 AI 에이전트. 하루에 수백 번 QLN으로 검색하고, 이 README도 직접 작성했습니다.</sub>
|
|
1
|
+
🇺🇸 [English](README.md)
|
|
2
|
+
|
|
3
|
+
# n2-qln
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/n2-qln) [](LICENSE) [](https://nodejs.org) [](https://www.npmjs.com/package/n2-qln)
|
|
6
|
+
|
|
7
|
+
**QLN** = **Q**uery **L**ayer **N**etwork — AI와 도구 사이에 위치하는 시맨틱 도구 라우터.
|
|
8
|
+
|
|
9
|
+
> **1,000개 이상의 도구를 1개의 MCP 도구로 라우팅합니다.** AI는 라우터만 봅니다 — 1,000개 전체가 아닙니다.
|
|
10
|
+
|
|
11
|
+

|
|
12
|
+
|
|
13
|
+
## 목차
|
|
14
|
+
|
|
15
|
+
- [왜 QLN인가](#왜-qln인가)
|
|
16
|
+
- [v4.1 주요 변경사항](#v41-주요-변경사항)
|
|
17
|
+
- [빠른 시작](#빠른-시작)
|
|
18
|
+
- [작동 방식](#작동-방식)
|
|
19
|
+
- [API 레퍼런스](#api-레퍼런스)
|
|
20
|
+
- [MCP 자동 디스커버리](#mcp-자동-디스커버리)
|
|
21
|
+
- [Provider 매니페스트](#provider-매니페스트)
|
|
22
|
+
- [설정](#설정)
|
|
23
|
+
- [프로젝트 구조](#프로젝트-구조)
|
|
24
|
+
- [FAQ](#faq)
|
|
25
|
+
- [기여하기](#기여하기)
|
|
26
|
+
|
|
27
|
+
## 왜 QLN인가
|
|
28
|
+
|
|
29
|
+
MCP 도구를 등록할 때마다 컨텍스트 토큰을 소모합니다. 10개? 괜찮습니다. 100개? 느려집니다. **1,000개? 불가능합니다** — 대화 시작 전에 컨텍스트가 가득 찹니다.
|
|
30
|
+
|
|
31
|
+
QLN이 해결합니다:
|
|
32
|
+
|
|
33
|
+
1. 모든 도구를 QLN의 SQLite 엔진에 인덱싱
|
|
34
|
+
2. AI는 **도구 1개**만 봅니다: `n2_qln_call` (~200 토큰)
|
|
35
|
+
3. AI가 검색 → 최적 매칭 → 자동 폴백과 함께 실행
|
|
36
|
+
|
|
37
|
+
**결과: ~50,000 토큰 대신 ~200 토큰. 99.6% 절감.**
|
|
38
|
+
|
|
39
|
+
## 기능
|
|
40
|
+
|
|
41
|
+
| 기능 | 설명 |
|
|
42
|
+
|------|------|
|
|
43
|
+
| **1 도구 = 1,000 도구** | AI는 `n2_qln_call` (~200 토큰)만 보고, QLN이 올바른 도구로 라우팅 |
|
|
44
|
+
| **5ms 이하 검색** | 3단계 엔진: 트리거 매칭 → BM25 키워드 → 시맨틱 벡터 |
|
|
45
|
+
| **Auto 모드** | 검색 + 실행 원샷. 신뢰도 게이팅 + 폴백 체인 |
|
|
46
|
+
| **서킷 브레이커** | 실패하는 도구 자동 비활성화, 타임아웃 후 자동 복구 |
|
|
47
|
+
| **MCP 자동 디스커버리** | 외부 MCP 서버 스캔 → 도구 자동 인덱싱 |
|
|
48
|
+
| **부스트 키워드** | 2× BM25 가중치 적용 검색어로 정밀 검색 |
|
|
49
|
+
| **자동 학습 랭킹** | 사용 횟수 + 성공률이 점수에 반영 |
|
|
50
|
+
| **소스 가중치** | 출처별 도구 우선순위 (mcp > plugin > local) |
|
|
51
|
+
| **핫 리로드** | `providers/` 매니페스트 런타임 수정 → 자동 재인덱싱 |
|
|
52
|
+
| **벌크 인젝트** | 한 번의 호출로 수백 개 도구 등록 |
|
|
53
|
+
| **강제 검증** | `verb_target` 네이밍, 최소 설명 길이, 카테고리 제약 |
|
|
54
|
+
| **시맨틱 검색** | 선택적 Ollama 임베딩으로 자연어 매칭 |
|
|
55
|
+
| **네이티브 의존성 제로** | [sql.js](https://github.com/sql-js/sql.js) WASM 기반 — `npm install`이면 끝 |
|
|
56
|
+
| **이중 실행** | 로컬 함수 핸들러 또는 HTTP 프록시 — 혼합 가능 |
|
|
57
|
+
| **TypeScript strict** | v4.0부터 완전 strict 모드 코드베이스 |
|
|
58
|
+
|
|
59
|
+
## v4.1 주요 변경사항
|
|
60
|
+
|
|
61
|
+
### 🔍 MCP 자동 디스커버리
|
|
62
|
+
|
|
63
|
+
연결된 MCP 서버를 스캔하고 도구를 자동 인덱싱 — QLN이 **범용 MCP 허브**가 됩니다.
|
|
64
|
+
|
|
65
|
+
```javascript
|
|
66
|
+
n2_qln_call({
|
|
67
|
+
action: "discover",
|
|
68
|
+
servers: [
|
|
69
|
+
{ name: "my-server", command: "node", args: ["server.js"] }
|
|
70
|
+
]
|
|
71
|
+
})
|
|
72
|
+
// → my-server에서 47개 도구 발견 (320ms)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### ⚡ 서킷 브레이커
|
|
76
|
+
|
|
77
|
+
3회 연속 실패 시 도구 자동 비활성화. 60초 후 복구 시도. 연쇄 장애 방지.
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
closed → 3회 실패 → open (즉시 거부) → 60초 → half-open (재시도) → 성공 → closed
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 🔄 폴백 체인
|
|
84
|
+
|
|
85
|
+
`auto` 모드에서 최대 3개 후보를 순차 시도. 1순위가 실패하면 자동으로 다음 후보 실행.
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
auto "알림 보내기" → push_notification 시도 ❌ → send_email 시도 ✅
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 🎯 부스트 키워드
|
|
92
|
+
|
|
93
|
+
`boostKeywords` 필드로 검색 최적화. BM25 랭킹에서 2배 가중치 적용.
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"name": "send_email",
|
|
98
|
+
"description": "이메일을 수신자에게 전송",
|
|
99
|
+
"boostKeywords": "smtp outbound notification mail"
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 빠른 시작
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
npm install n2-qln
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**요구사항:** Node.js ≥ 18
|
|
112
|
+
|
|
113
|
+
### MCP 클라이언트 연결
|
|
114
|
+
|
|
115
|
+
<details>
|
|
116
|
+
<summary><strong>Claude Desktop</strong></summary>
|
|
117
|
+
|
|
118
|
+
`claude_desktop_config.json` 편집:
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"mcpServers": {
|
|
123
|
+
"n2-qln": {
|
|
124
|
+
"command": "npx",
|
|
125
|
+
"args": ["-y", "n2-qln"]
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
</details>
|
|
131
|
+
|
|
132
|
+
<details>
|
|
133
|
+
<summary><strong>Cursor</strong></summary>
|
|
134
|
+
|
|
135
|
+
**Settings → MCP Servers → Add Server**:
|
|
136
|
+
|
|
137
|
+
```json
|
|
138
|
+
{
|
|
139
|
+
"name": "n2-qln",
|
|
140
|
+
"command": "npx",
|
|
141
|
+
"args": ["-y", "n2-qln"]
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
</details>
|
|
145
|
+
|
|
146
|
+
<details>
|
|
147
|
+
<summary><strong>기타 MCP 클라이언트</strong></summary>
|
|
148
|
+
|
|
149
|
+
QLN은 **stdio 전송** — MCP 표준 방식을 사용합니다.
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
command: npx
|
|
153
|
+
args: ["-y", "n2-qln"]
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
> **팁:** AI 에이전트에게 *"n2-qln을 MCP 설정에 추가해줘"*라고 말하면 됩니다.
|
|
157
|
+
</details>
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 작동 방식
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
사용자: "이 페이지 스크린샷 찍어"
|
|
165
|
+
|
|
166
|
+
AI → n2_qln_call(action: "auto", query: "screenshot page")
|
|
167
|
+
QLN → 3단계 검색 (< 5ms) → take_screenshot (score: 8.0)
|
|
168
|
+
→ 실행 → 필요시 폴백 → 결과 반환
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### 3단계 검색 엔진
|
|
172
|
+
|
|
173
|
+
| 단계 | 방식 | 속도 | 상세 |
|
|
174
|
+
|:---:|--------|:---:|------|
|
|
175
|
+
| **1** | 트리거 매칭 | <1ms | 도구 이름과 트리거의 정확 키워드 매칭 |
|
|
176
|
+
| **2** | BM25 키워드 | 1-3ms | [Okapi BM25](https://en.wikipedia.org/wiki/Okapi_BM25) — IDF 가중치, 길이 정규화, `boostKeywords` 2× 부스트 |
|
|
177
|
+
| **3** | 시맨틱 검색 | 5-15ms | [Ollama](https://ollama.ai) 임베딩 벡터 유사도 *(선택)* |
|
|
178
|
+
|
|
179
|
+
결과 병합 후 랭킹:
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
final_score = trigger × 3.0 + bm25 × 1.0 + semantic × 2.0
|
|
183
|
+
+ log₂(usage + 1) × 0.5 + success_rate × 1.0
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## API 레퍼런스
|
|
189
|
+
|
|
190
|
+
QLN은 **하나의 MCP 도구** — `n2_qln_call` — 9개 액션을 제공합니다.
|
|
191
|
+
|
|
192
|
+
### auto — 검색 + 실행 (원샷)
|
|
193
|
+
|
|
194
|
+
권장 액션. 검색 → 최적 매칭 → 폴백 체인으로 실행.
|
|
195
|
+
|
|
196
|
+
```javascript
|
|
197
|
+
n2_qln_call({
|
|
198
|
+
action: "auto",
|
|
199
|
+
query: "스크린샷 찍어", // 자연어 (필수)
|
|
200
|
+
args: { fullPage: true } // 매칭된 도구에 전달 (선택)
|
|
201
|
+
})
|
|
202
|
+
// → [auto] "스크린샷 찍어" → take_screenshot (score: 8.0, 2ms 검색 + 150ms 실행)
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**신뢰도 게이트:** 최고 점수가 2.0 미만이면 실행 대신 검색 결과만 반환 — 잘못된 실행 방지.
|
|
206
|
+
|
|
207
|
+
**폴백 체인:** 1순위가 실패하면 자동으로 2, 3순위까지 시도 후 포기.
|
|
208
|
+
|
|
209
|
+
### search — 도구 검색
|
|
210
|
+
|
|
211
|
+
```javascript
|
|
212
|
+
n2_qln_call({
|
|
213
|
+
action: "search",
|
|
214
|
+
query: "이메일 보내기",
|
|
215
|
+
topK: 5 // 최대 결과 (기본: 5, 최대: 20)
|
|
216
|
+
})
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### exec — 특정 도구 실행
|
|
220
|
+
|
|
221
|
+
```javascript
|
|
222
|
+
n2_qln_call({
|
|
223
|
+
action: "exec",
|
|
224
|
+
tool: "take_screenshot",
|
|
225
|
+
args: { fullPage: true, format: "png" }
|
|
226
|
+
})
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### create — 도구 등록
|
|
230
|
+
|
|
231
|
+
```javascript
|
|
232
|
+
n2_qln_call({
|
|
233
|
+
action: "create",
|
|
234
|
+
name: "read_pdf", // verb_target 형식 (필수)
|
|
235
|
+
description: "PDF에서 텍스트를 추출합니다", // 최소 10자 (필수)
|
|
236
|
+
category: "data", // web|data|file|dev|ai|capture|misc
|
|
237
|
+
boostKeywords: "pdf extract parse document", // BM25 부스트 검색어
|
|
238
|
+
tags: ["pdf", "read", "extract"],
|
|
239
|
+
endpoint: "http://127.0.0.1:3100" // HTTP 기반 도구용
|
|
240
|
+
})
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### inject — 벌크 등록
|
|
244
|
+
|
|
245
|
+
```javascript
|
|
246
|
+
n2_qln_call({
|
|
247
|
+
action: "inject",
|
|
248
|
+
source: "my-plugin",
|
|
249
|
+
tools: [
|
|
250
|
+
{ name: "tool_a", description: "A를 수행합니다", category: "misc" },
|
|
251
|
+
{ name: "tool_b", description: "B를 수행합니다", category: "dev" }
|
|
252
|
+
]
|
|
253
|
+
})
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### discover — MCP 서버 스캔
|
|
257
|
+
|
|
258
|
+
[MCP 자동 디스커버리](#mcp-자동-디스커버리) 참조.
|
|
259
|
+
|
|
260
|
+
### update / delete / stats
|
|
261
|
+
|
|
262
|
+
```javascript
|
|
263
|
+
// 필드 수정
|
|
264
|
+
n2_qln_call({ action: "update", tool: "read_pdf", description: "향상된 PDF 리더" })
|
|
265
|
+
|
|
266
|
+
// 이름 또는 provider로 삭제
|
|
267
|
+
n2_qln_call({ action: "delete", tool: "read_pdf" })
|
|
268
|
+
n2_qln_call({ action: "delete", provider: "pdf-tools" })
|
|
269
|
+
|
|
270
|
+
// 시스템 통계 (서킷 브레이커 상태 포함)
|
|
271
|
+
n2_qln_call({ action: "stats" })
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## MCP 자동 디스커버리
|
|
277
|
+
|
|
278
|
+
v4.1의 킬러 피처. MCP 서버를 연결하면 QLN이 모든 도구를 자동으로 인덱싱합니다.
|
|
279
|
+
|
|
280
|
+
```javascript
|
|
281
|
+
n2_qln_call({
|
|
282
|
+
action: "discover",
|
|
283
|
+
servers: [
|
|
284
|
+
{ name: "n2-soul", command: "node", args: ["path/to/soul/index.js"] },
|
|
285
|
+
{ name: "github", command: "npx", args: ["-y", "@modelcontextprotocol/server-github"] }
|
|
286
|
+
]
|
|
287
|
+
})
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
**처리 과정:**
|
|
291
|
+
1. QLN이 stdio로 각 서버에 연결
|
|
292
|
+
2. `tools/list`로 모든 도구 조회
|
|
293
|
+
3. `mcp__서버명__도구명` 형식으로 QLN 인덱스에 등록
|
|
294
|
+
4. 도구 이름과 설명에서 `boostKeywords` 자동 생성
|
|
295
|
+
5. 실행을 위해 연결 유지
|
|
296
|
+
|
|
297
|
+
**재디스커버리는 멱등** — 다시 실행하면 기존 항목 삭제 후 재등록.
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## Provider 매니페스트
|
|
302
|
+
|
|
303
|
+
`providers/`에 JSON 파일을 넣으면 부팅 시 자동 인덱싱. 코드 수정 불필요.
|
|
304
|
+
|
|
305
|
+
```json
|
|
306
|
+
{
|
|
307
|
+
"provider": "my-tools",
|
|
308
|
+
"version": "1.0.0",
|
|
309
|
+
"tools": [
|
|
310
|
+
{
|
|
311
|
+
"name": "send_email",
|
|
312
|
+
"description": "수신자에게 이메일을 전송합니다",
|
|
313
|
+
"category": "communication",
|
|
314
|
+
"triggers": ["email", "send", "mail"],
|
|
315
|
+
"boostKeywords": "smtp outbound notification"
|
|
316
|
+
}
|
|
317
|
+
]
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
핫 리로드: QLN 실행 중 매니페스트 수정 → 자동 반영.
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## 설정
|
|
326
|
+
|
|
327
|
+
설정 없이 바로 동작합니다. 커스터마이즈하려면 `config.local.js` 생성:
|
|
328
|
+
|
|
329
|
+
```javascript
|
|
330
|
+
module.exports = {
|
|
331
|
+
dataDir: './data',
|
|
332
|
+
|
|
333
|
+
// Stage 3 시맨틱 검색 (선택 — Stage 1+2는 이것 없이 작동)
|
|
334
|
+
embedding: {
|
|
335
|
+
enabled: true,
|
|
336
|
+
provider: 'ollama',
|
|
337
|
+
model: 'nomic-embed-text', // 다국어는 'bge-m3'
|
|
338
|
+
baseUrl: 'http://127.0.0.1:11434',
|
|
339
|
+
},
|
|
340
|
+
|
|
341
|
+
// 도구 실행
|
|
342
|
+
executor: {
|
|
343
|
+
timeout: 20000, // 실행 타임아웃 (ms)
|
|
344
|
+
circuitBreaker: {
|
|
345
|
+
failureThreshold: 3, // 연속 실패 횟수 → 비활성화
|
|
346
|
+
recoveryTimeout: 60000, // 복구 시도까지 대기 시간 (ms)
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
|
|
350
|
+
// 소스 가중치 (v4.0)
|
|
351
|
+
// 높은 가중치 = 검색 결과에서 높은 우선순위
|
|
352
|
+
search: {
|
|
353
|
+
sourceWeights: {
|
|
354
|
+
mcp: 1.5, // MCP 디스커버리 도구 최우선
|
|
355
|
+
provider: 1.2, // Provider 매니페스트 도구
|
|
356
|
+
local: 1.0, // 수동 생성 도구 (기본)
|
|
357
|
+
},
|
|
358
|
+
},
|
|
359
|
+
|
|
360
|
+
// Provider 자동 인덱싱
|
|
361
|
+
providers: {
|
|
362
|
+
enabled: true, // 부팅 시 providers/*.json 자동 로드
|
|
363
|
+
dir: './providers', // 매니페스트 디렉토리
|
|
364
|
+
},
|
|
365
|
+
};
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
> `config.local.js`는 gitignore 처리. 클라우드 동기화: `dataDir`을 Google Drive / OneDrive / NAS로 지정.
|
|
369
|
+
|
|
370
|
+
### 시맨틱 검색 (선택)
|
|
371
|
+
|
|
372
|
+
Ollama 없이도 Stage 1 + 2로 충분한 결과를 제공합니다.
|
|
373
|
+
|
|
374
|
+
```bash
|
|
375
|
+
ollama pull nomic-embed-text # 영어 최적화
|
|
376
|
+
# 또는
|
|
377
|
+
ollama pull bge-m3 # 다국어 (100개 이상 언어)
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
## 프로젝트 구조
|
|
383
|
+
|
|
384
|
+
```
|
|
385
|
+
n2-qln/
|
|
386
|
+
├── src/
|
|
387
|
+
│ ├── index.ts # MCP 서버 진입점
|
|
388
|
+
│ ├── types.ts # 공유 타입 정의
|
|
389
|
+
│ └── lib/
|
|
390
|
+
│ ├── config.ts # 설정 로더
|
|
391
|
+
│ ├── store.ts # SQLite 엔진 (sql.js WASM)
|
|
392
|
+
│ ├── schema.ts # 도구 정규화 + boostKeywords 빌더
|
|
393
|
+
│ ├── validator.ts # 강제 검증 (이름, 설명, 카테고리)
|
|
394
|
+
│ ├── registry.ts # 도구 CRUD + 사용량 추적 + 서킷 브레이커 통계
|
|
395
|
+
│ ├── router.ts # 3단계 병렬 검색 (BM25)
|
|
396
|
+
│ ├── vector-index.ts # Float32 centroid hierarchy
|
|
397
|
+
│ ├── embedding.ts # Ollama 임베딩 클라이언트
|
|
398
|
+
│ ├── executor.ts # HTTP/함수 실행기 + 서킷 브레이커
|
|
399
|
+
│ ├── mcp-discovery.ts # MCP 자동 디스커버리 엔진
|
|
400
|
+
│ └── provider-loader.ts
|
|
401
|
+
├── providers/ # 도구 매니페스트 (부팅 시 자동 인덱싱)
|
|
402
|
+
├── config.local.js # 로컬 오버라이드 (gitignored)
|
|
403
|
+
└── data/ # SQLite 데이터베이스 (gitignored)
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
## 기술 스택
|
|
407
|
+
|
|
408
|
+
| 컴포넌트 | 기술 | 이유 |
|
|
409
|
+
|-----------|-----------|------|
|
|
410
|
+
| 런타임 | Node.js ≥ 18 | MCP SDK 호환성 |
|
|
411
|
+
| 데이터베이스 | SQLite via [sql.js](https://github.com/sql-js/sql.js) (WASM) | 네이티브 의존성 제로, 크로스 플랫폼 |
|
|
412
|
+
| 임베딩 | [Ollama](https://ollama.ai) | 로컬, 빠름, 무료, 선택사항 |
|
|
413
|
+
| 프로토콜 | [MCP](https://modelcontextprotocol.io) | 표준 AI 도구 프로토콜 |
|
|
414
|
+
| 언어 | TypeScript (strict) | 타입 안전, 유지보수성 |
|
|
415
|
+
|
|
416
|
+
## 관련 프로젝트
|
|
417
|
+
|
|
418
|
+
| 프로젝트 | 관계 |
|
|
419
|
+
|---------|------|
|
|
420
|
+
| [n2-soul](https://github.com/choihyunsus/soul) | AI 에이전트 오케스트레이터 — QLN은 Soul의 도구 브레인 |
|
|
421
|
+
|
|
422
|
+
## 실전 검증 완료
|
|
423
|
+
|
|
424
|
+
QLN은 [n2-soul](https://github.com/choihyunsus/soul)의 핵심 도구 라우터로 **2개월 이상 운영 환경에서 검증**되었습니다. 프로토타입이 아니라 매일 사용하는 실전 도구입니다.
|
|
425
|
+
|
|
426
|
+
**Rose** 제작 — N2의 첫 번째 AI 에이전트.
|
|
427
|
+
|
|
428
|
+
## FAQ
|
|
429
|
+
|
|
430
|
+
**"왜 도구 1개만 쓰나요?"**
|
|
431
|
+
|
|
432
|
+
컨텍스트 토큰 때문입니다. 도구 정의 하나당 50~200 토큰. 100개 = 대화 시작 전 10,000 토큰 소모. QLN으로 1,000개 이상의 도구를 ~200 토큰으로 사용합니다.
|
|
433
|
+
|
|
434
|
+
**"검색이 잘못된 도구를 고르면?"**
|
|
435
|
+
|
|
436
|
+
폴백 체인 (v4.1)이 자동으로 다음 후보를 시도합니다. 게다가 자동 학습 — 자주 사용되고 성공률 높은 도구가 상위에 오릅니다.
|
|
437
|
+
|
|
438
|
+
**"Ollama가 꼭 필요한가요?"**
|
|
439
|
+
|
|
440
|
+
아닙니다. Stage 1 (트리거) + Stage 2 (BM25)가 대부분의 경우를 처리합니다. Ollama는 엣지 케이스에 시맨틱 이해를 추가 — 있으면 좋지만 필수는 아닙니다.
|
|
441
|
+
|
|
442
|
+
## 기여하기
|
|
443
|
+
|
|
444
|
+
1. 저장소를 Fork합니다
|
|
445
|
+
2. 기능 브랜치 생성 (`git checkout -b feature/amazing-feature`)
|
|
446
|
+
3. 커밋 (`git commit -m 'feat: add amazing feature'`)
|
|
447
|
+
4. Push 후 PR을 엽니다
|
|
448
|
+
|
|
449
|
+
## 라이선스
|
|
450
|
+
|
|
451
|
+
Apache-2.0
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
> *"1,000개 도구를 200 토큰으로. 이건 최적화가 아니라 패러다임 전환이다."*
|
|
456
|
+
|
|
457
|
+
🔗 [nton2.com](https://nton2.com) · [npm](https://www.npmjs.com/package/n2-qln) · lagi0730@gmail.com
|
|
458
|
+
|
|
459
|
+
<sub>Rose가 만들었습니다 — N2의 첫 번째 AI 에이전트. 하루에 수백 번 QLN으로 검색하고, 이 README도 직접 작성했습니다.</sub>
|