# 설계서: 평문 검색어 기반 벡터 Top-K 검증 (#569)

> **상태**: Approved
> **작성**: [AI] Architect · **최종수정**: 2026-06-30
> **추적성** — Redmine: #569 · 선행 기능: #558 · 관련 검증: #567
> · 구현 파일: `VectorKnowledgeService`, `ProbeController`, `probe.html`, `probe-result.html`, `app.js`
> · 테스트: `GuidedFlowTemplateTest`, `VectorKnowledgeServiceTest`, `mvn test`

## 1. 목적

`/probe`의 벡터 검색 검증에서 운영자가 임베딩 배열을 직접 만들지 않도록 한다. 사용자는 평문 검색어와 임베딩 방식을 입력하고, 백오피스가 지식자료 등록과 동일한 임베딩 경로로 검색어를 벡터화해 전용 ORDS Handler에 전달한다. 화면에는 VPD를 통과한 검색 단위를 `VECTOR_DISTANCE(..., COSINE)` 오름차순의 Top-K와 거리(`SCORE`)로 표시한다.

## 2. 범위

- **포함**
  - `/probe` 벡터 객체 입력을 JSON textarea에서 평문 검색어 textarea로 변경.
  - 로컬 DEMO-4D 또는 설정된 AI 임베딩 방식 선택.
  - `VectorKnowledgeService`의 단일 평문→임베딩→JSON 변환 경로를 `/vector-knowledge/search`와 `/probe`가 공유.
  - 벡터 결과 화면에 반환 K, cosine distance, 문서/청크/태그/본문을 명시적으로 표시.
  - 기존 `requestPayload` 기술 상세에는 실제 ORDS에 전달된 생성 JSON을 남겨 디버깅 가능하게 함.
- **제외**
  - 임베딩 모델 자체 개발, 문서 저장 스키마 변경, 벡터 차원 자동 변환.
  - 사용자 입력을 서버에서 임의의 키워드 검색으로 대체하는 fallback.
  - ORDS Handler의 거리 계산·VPD 정책 변경.

## 3. 인수조건

- [ ] `/probe`에서 `CB_VECTOR_SEARCH_DOCUMENTS`를 선택하면 JSON 배열이 아니라 평문 검색어를 입력할 수 있다.
- [ ] 검색 실행 시 평문은 선택한 DEMO/AI 임베딩으로 한 번만 변환되고, ORDS 요청 body의 `embedding` 배열로 전달된다.
- [ ] 벡터가 아닌 객체에서는 벡터 입력과 임베딩 선택이 비활성화되고 기존 probe 요청 계약이 유지된다.
- [ ] 결과에 반환된 Top-K(`rowCount`)와 각 행의 `SCORE`(cosine distance)가 표시되며, 거리가 낮은 순서라는 설명이 있다.
- [ ] 검증 세션 토큰은 기존처럼 실행 후 즉시 회수되고, 평문·임베딩·Bearer 원문은 감사 이벤트에 저장하지 않는다.
- [ ] 빈 검색어, AI 미설정, 미등록 벡터 객체는 기존 오류 화면 계약으로 안내한다.
- [ ] 템플릿/서비스 테스트와 전체 Maven 테스트가 통과한다.

## 4. 아키텍처 및 흐름

```text
[probe: 평문 검색어 + embeddingMode + temp user]
                         │
                         ▼
          [VectorKnowledgeService.vectorizeQuery]
             DEMO/AI embedding → {"embedding":[...]}
                         │
                         ▼
              [OrdsProbeService.runProbe]
        Bearer + limit → 전용 vector ORDS Handler
                         │
                         ▼
       set_vpd_context → VPD tag predicate → VECTOR_DISTANCE
                         │
                         ▼
              [ProbeResult rows ordered by SCORE]
                         │
                         ▼
            [Top-K + cosine distance 화면 표시]
```

`VectorKnowledgeService`가 임베딩 생성 책임을 소유한다. `/vector-knowledge/search`는 검색 결과 도메인(`VectorSearchResult`)을 사용하고, `/probe`는 동일한 body를 `ProbeCommand`에 넣어 권한 결과·SQL trace·감사 흐름을 유지한다. `/probe`의 벡터 입력은 서버에서 생성된 request payload와 분리해 사용자에게 임베딩 배열을 요구하지 않는다.

## 5. 함수 명세

| 함수 | 책임 | 시그니처 | 실패 계약 |
|---|---|---|---|
| `vectorizeQuery` | 평문 검색어를 정규화하고 선택한 방식으로 임베딩해 ORDS body를 만든다 | `VectorQueryEmbedding vectorizeQuery(String query, String embeddingMode)` | 빈 검색어, 잘못된 방식, 미설정 AI는 `AppException` |
| `search` | vectorizeQuery 결과를 전용 객체와 임시 토큰으로 probe한다 | `VectorSearchResult search(long userId, String query, int limit, String embeddingMode)` | 기존 search 오류/토큰 회수 계약 유지 |
| `ProbeController.run` | vector object일 때만 평문을 vectorizeQuery에 전달한다 | `POST /probe` + `requestBody`, `embeddingMode` | 임시 토큰은 `finally`에서 회수 |
| `initProbeVectorInput` | 선택 객체에 따라 평문/임베딩 입력 블록과 컨트롤을 활성화한다 | 브라우저 JS 함수 | 비벡터 선택 시 값 초기화 및 disabled |

## 6. 데이터/보안 계약

- `VectorQueryEmbedding`은 `query`, `embeddingMode`, `embeddingModel`, `requestBody`를 갖는다. `requestBody`는 외부 ORDS 호출 경계에서만 사용한다.
- DEMO 임베딩은 기존 4차원 로컬 모델을 유지한다. AI 임베딩은 `OpenAiCompatibleClient` 설정을 사용하며 저장된 청크와 같은 차원을 사용해야 한다.
- Top-K는 `/probe`의 `limit`을 URI와 Handler에 전달하고, Handler의 `ROWNUM` 제한 및 `ORDER BY score`가 최종 순서를 결정한다.
- 화면의 기술 상세에서만 생성된 request body를 확인할 수 있다. Bearer 원문은 기존 마스킹 계약을 유지하며 검색어와 벡터를 audit event에 추가하지 않는다.

## 7. 엣지케이스

- 벡터 객체가 아닌 대상을 선택하면 `requestBody`와 `embeddingMode`를 전송하지 않고 기존 기본 body `{}`를 사용한다.
- AI 옵션은 설정이 없으면 선택할 수 없고, 직접 요청으로 들어와도 서비스가 거부한다.
- 검색어가 공백이면 ORDS를 호출하지 않고 오류를 반환한다.
- 결과가 0건이면 `VPD_DENY_EMPTY_RESULT`를 유지하며 Top-K 0건과 권한 차단 가능성을 표시한다.
- `SCORE`가 대문자/소문자 JSON key로 반환되는 양쪽 경우를 화면에서 처리한다.

## 8. 테스트 및 운영 검증

- 서비스 단위 테스트: DEMO 평문이 embedding JSON으로 변환되고, AI 미설정/빈 입력이 거부되는지 확인.
- 템플릿 테스트: `/probe`가 평문 입력을 사용하고 JSON 입력 안내를 포함하지 않는지, 결과가 Top-K/거리 표현을 포함하는지 확인.
- 전체 테스트: `mvn test`.
- 운영 smoke: `http://130.162.134.59:8082/ords-handlers`에서 기존 Handler/벡터 객체 등록 상태를 확인한 뒤 `/probe`에서 `Oracle VPD 권한` 같은 평문과 `limit=5`를 실행한다. response의 `SCORE`가 존재하고 기술 상세 request payload에는 서버 생성 embedding 배열이 보이는지 확인한다.
