Skip to content

feat(ai): 내부 어시스턴트 수집 파이프라인과 Elasticsearch 검색 기반 - #352

Merged
ohhalim merged 8 commits into
developfrom
feat/350/ai-operations-assistant
Sep 10, 2026
Merged

feat(ai): 내부 어시스턴트 수집 파이프라인과 Elasticsearch 검색 기반#352
ohhalim merged 8 commits into
developfrom
feat/350/ai-operations-assistant

Conversation

@ohhalim

@ohhalim ohhalim commented Sep 10, 2026

Copy link
Copy Markdown
Owner

배경

내부 개발·운영 어시스턴트(#350)의 첫 실행 가능 단위다. 문서·코드 corpus 수집부터
Elasticsearch 한국어 검색까지를 실제로 동작하는 상태로 만든다.

검색 저장소는 AI-ELASTICSEARCH-DECISION.md 결정에 따라
BM25S·pgvector 대신 Elasticsearch 단일 노드를 사용한다.

변경 범위

수집 파이프라인 (ai-assistant/)

  • scanner·parsers(Markdown/Java tree-sitter)·chunker·embeddings·pipeline
  • PostgreSQL 버전 관리 저장소 + alembic 마이그레이션
  • CLI ingest

Elasticsearch 검색

  • ES 9.5.3 + analysis-nori 이미지, 127.0.0.1:9208 루프백 전용
  • 문서 계약 매핑(dynamic: strict), 결정적 build_id, bulk·개수 검증·alias 발행
  • keyword(multi_match) / vector(script_score) 질의, RRF(k=60) 결합
  • CLI search --retriever hybrid|keyword|vector --source-type

제거

  • retrieval/bm25.py, retrieval/vector.py, bm25s 의존성, .data/bm25
  • persistence/*ai-postgres 는 유지. ingest 가 아직 원본을 저장하며
    Postgres 제거는 snapshot 색인(계획 2단계) 범위다

실측 결과

ingest (exit 0)

  • 문서 16(Markdown 11 + Java 5) -> 청크 317 -> 임베딩 317, 누락 0

Elasticsearch 색인 (exit 0)

  • 317청크 색인, bulk 실패 0, 개수 검증 통과, alias 전환 완료

한국어 분석 비교 — 이번 저장소 교체의 근거

문서 결제를 검증하였습니다 질의 결제 검증 매칭
BM25S ['결제를','검증하였습니다'] ['결제','검증'] 공통 토큰 0
Nori ['결제','검증'] ['결제','검증'] 일치

검색 (exit 0)

  • 결제 검증 keyword -> docs/operations/payment-load-test.md:79-93 (12.2224)
  • 결제를 검증하였습니다 keyword -> 동일 문서 상위 (9.0762)
  • hybrid -> rrf(es_keyword) / rrf(es_vector_exact) 결합 동작

품질 게이트

  • ruff·mypy: 21개 소스 통과. 기존 parsers.py SIM102 1건은 이번 범위 밖이라 미접촉

수정한 결함

tree-sitter 0.26.0 + tree-sitter-java 0.23.5 조합에서 Node.start_point 접근 시
프로세스가 SIGSEGV/SIGBUS 로 종료된다. 상한이 없어 0.26.0 이 설치되고 있었다.

  • 0.26.0 -> 크래시 (exit 138/139)
  • 0.25.2 / 0.25.0 -> 정상 (노드 3856개 순회)

tree-sitter>=0.25.0,<0.26 으로 고정했다.

미검증 / 범위 밖

  • 임베딩이 fake 결정적 해시(1024차원)라 vector·hybrid 순위는 품질 근거가 없다
  • 검색 품질·지연 비교값 없음. 평가셋(tuning/held-out)은 후속 이슈
  • LLM 답변 생성·질문 라우팅·Spring 조회·Slack 은 이 PR 범위 밖
  • 실제 임베딩 모델(bge-m3)·리랭커 미적용

확인 요청

  • ES 컨테이너는 로컬 전용(127.0.0.1:9208)이며 profiles: ["ai"] 로 기본 기동에서 제외된다
  • 운영 배포·원격 리소스 변경 없음

https://claude.ai/code/session_01GDm6wJvLcheakBeELYsLMk

corpus 스캔부터 청크 저장까지의 수집 경로와 검색 원시 계층을 추가한다.

- ingestion: scanner(allowlist·원문 hash), parsers, chunker, embeddings, pipeline
- retrieval: bm25 artifact store, pgvector 조회
- persistence: SQLAlchemy 모델·repository, alembic initial_corpus
- cli: ingest 명령
- .gitignore: AI 로컬 산출물(.data, mypy/ruff 캐시) 제외

미검증: 아직 실행한 적 없음. ingest 실행·검색 경로·평가 러너는 후속 작업.

Claude-Session: https://claude.ai/code/session_01GDm6wJvLcheakBeELYsLMk
ai 프로필로 분리해 기존 로컬 스택과 포트·수명주기를 겹치지 않게 한다.

- ai-postgres: pgvector 0.8.1-pg17, 127.0.0.1:5433 루프백 바인딩
- ai-api: ai-assistant 이미지 빌드
- profiles ai 로 기본 기동에서 제외

Claude-Session: https://claude.ai/code/session_01GDm6wJvLcheakBeELYsLMk
검색 저장소를 BM25S·pgvector에서 Elasticsearch 단일 노드로 교체하기로 한
결정과 그 세부 구현 계획을 남긴다. 적용 우선순위는 DECISION > V1 > MVP 설계.

- AI-ELASTICSEARCH-DECISION.md: 결정 근거, 검색 계약, 인덱스 발행 절차
- AI-ELASTICSEARCH-IMPLEMENTATION-PLAN.md: 모듈 책임, 문서 계약, 이슈 분리
- AI-INTERNAL-ASSISTANT-V1.md: 내부 어시스턴트 v1 범위
- AI-OPERATIONS-ASSISTANT-MVP-DESIGN.md: 상위 문서와의 우선순위 반영

미측정: 현재 검색 품질·지연 비교값 없음. 교체 전 baseline 확보가 선행 과제.

Claude-Session: https://claude.ai/code/session_01GDm6wJvLcheakBeELYsLMk
tree-sitter-java 0.23.5(ABI 14)와 tree-sitter 0.26.0 조합에서 Node.start_point
필드 접근 시 프로세스가 SIGSEGV/SIGBUS로 종료된다. 상한이 없어 0.26.0이 설치되고
있었다.

실측 (PaddleWebhookService.java, 노드 3856개 순회):
- tree-sitter 0.26.0 + java 0.23.5 → 크래시 (exit 138/139)
- tree-sitter 0.25.2 + java 0.23.5 → 정상 (rows read 3856)
- tree-sitter 0.25.0 + java 0.23.5 → 정상

수정 후 ingest 실행 결과 (exit 0):
- 문서 16 / 청크 317 / 임베딩 317, 누락 0
- 크래시 대상이던 PaddleWebhookService.java 도 청크 17개로 정상 처리

임베딩은 AI_EMBEDDING_PROVIDER=fake(결정적 해시) 기준. 실제 모델 검증은 미수행.
검색 품질은 측정하지 않았다.

Claude-Session: https://claude.ai/code/session_01GDm6wJvLcheakBeELYsLMk
구현 계획 1단계(Nori 이미지·client·mapping·실제 서버 smoke)를 구성한다.

- docker/elasticsearch/Dockerfile: ES 9.5.3 + analysis-nori 이미지 빌드 시 설치
- docker-compose.ai.yml: ai-elasticsearch 서비스, 127.0.0.1:9208 루프백 전용,
  보안 활성, ES_JAVA_OPTS 512m, mem_limit 2g
- config/settings.py: endpoint·자격증명·CA·alias·timeout
- persistence/elasticsearch_store.py: 문서 계약 매핑(dynamic strict),
  결정적 build_id, 물리 인덱스 생성·bulk·개수 검증·alias 발행
- retrieval/fusion.py: chunk_id 중복 제거 RRF(k=60), 동점은 chunk_id 정렬

실측 (Nori 대 BM25S 토크나이징):
- 문서 "결제를 검증하였습니다" / 질의 "결제 검증"
- BM25S: ['결제를','검증하였습니다'] 대 ['결제','검증'] -> 공통 토큰 0
- Nori:  ['결제','검증'] 대 ['결제','검증'] -> 일치

실측 (색인·검색, exit 0):
- 청크 317 / 차원 1024 색인, bulk 실패 0, 개수 검증 통과, alias 전환 완료
- match 질의 "결제 검증" -> toss-billing-review-readiness.md:64-70 (score 7.01)
- match 질의 "구독 갱신" -> API.md:688-692 (score 7.00)

미검증: 임베딩은 fake 해시(1024차원)라 벡터 검색 품질은 의미 없음.
벡터 검색·하이브리드 CLI 경로·평가셋은 후속. 검색 품질 비교값 없음.

Claude-Session: https://claude.ai/code/session_01GDm6wJvLcheakBeELYsLMk
계획서 "이전 pgvector/BM25S 구현은 활성 경로 교체 검증 후 정리"를 따른다.

추가:
- retrieval/elasticsearch.py: keyword(multi_match) / vector(script_score) 질의,
  요청당 물리 인덱스 고정, source_type 필터, timeout·shard 실패 시 명시적 실패
- cli/main.py: search 명령을 ES 경로로 재배선(--retriever hybrid|keyword|vector,
  --source-type 반복 지정), 출력에 physical_index 포함

제거:
- retrieval/bm25.py, retrieval/vector.py
- bm25s 의존성, bm25_index_dir 설정, .data/bm25 산출물
- IngestionSummary.bm25_fingerprint 및 파이프라인의 BM25 빌드 단계

유지: persistence/* 와 ai-postgres. ingest 가 아직 문서·청크 원본을 저장하며
Postgres 제거는 snapshot 색인(계획 2단계) 범위다.

실측 (교체 후, exit 0):
- ingest: scanned 16 / unchanged 16 / chunk 0 변경 없음
- ruff·mypy: 신규·수정 파일 통과 (기존 parsers.py SIM102 1건은 미접촉)
- search "결제 검증" keyword -> payment-load-test.md:79-93 (12.2224)
- search "결제를 검증하였습니다" keyword -> 동일 문서 상위 (9.0762)
  BM25S 에서는 공통 토큰 0으로 불가능했던 매칭이다
- search hybrid -> rrf(es_keyword)/rrf(es_vector_exact) 결합 동작

미검증: 임베딩이 fake 해시라 vector·hybrid 순위는 품질 근거가 없다.
평가셋·리랭커·LLM 답변 생성은 후속.

Claude-Session: https://claude.ai/code/session_01GDm6wJvLcheakBeELYsLMk
@coderabbitai

coderabbitai Bot commented Sep 10, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: de9c556a-bd02-496e-8122-3cca7b09b065


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ohhalim
ohhalim merged commit 7c2c37f into develop Sep 10, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant