abap-indexing

ABAP 소스코드 인덱싱 서버. 약 1만 본의 ABAP 프로그램 소스와 프로그램 메타정보를 정규화 → 구조 파싱 → (LLM 로직 조각 추출) → 인덱싱하고, 질의 API 를 제공한다. 계획서: ABAP_INDEXING_PLAN.md (Downloads), 진행 가정: ASSUMPTIONS.md.

조각의 코드 원문은 로직만이고, 붙여넣는 데 필요한 선언(정의부)은 따로 수집한다 — ABAP 은 내부테이블·스트럭처를 TOP 에 선언하므로 로직만 복사하면 컴파일되지 않는다. 쓸지 말지는 붙여넣는 쪽 LLM 이 정한다. → docs/definition-block-design.md

인덱스의 1차 단위는 로직 조각(logic chunk) 이다. 파서가 자른 FORM/METHOD 는 LLM 에게 코드를 나눠 보여주는 창이고, LLM 이 그 안에서 업무적으로 의미 있는 조각(특정 SQL, DB 갱신, BAPI 호출, 집계 LOOP …)을 골라내 설명을 붙인다. 의미 없는 코드는 인덱스에서 버린다. → docs/logic-chunk-design.md

소비자: opencode-be 레포의 OpenCode 커스텀 툴(.opencode/tool/_index_client.ts)이 이 서버의 HTTP API 를 호출한다 (기본 http://127.0.0.1:8100).

파이프라인

data/raw/*.txt (수집 JSON)
  → python -m ingest.normalize      # Stage 1: 줄바꿈 아티팩트 제거, 프로그램/인클루드 파일화
  → python -m parser.run            # Stage 2: unit·참조·데이터플로우·호출그래프·정의부 (LLM 없이)
  → python -m index.loader          # Stage 4: SQLite(FTS5) 적재
  → python -m summarize.runner      # Stage 3: 프로그램 요약 → unit 별 로직 조각 추출
  → python -m wiki_out.run --all    # OKF v0.2 위키 (프로그램 문서 + tables/functions 엔티티)
  → python -m query.api             # Stage 5: 질의 API :8100
  → python -m eval.run_eval         # Stage 6: recall / 조각 적중 / 추적 평가

설치 / 실행

python -m venv .venv && .venv/Scripts/python -m pip install -e ".[dev]"   # Linux/mac: .venv/bin/python
cp .env.example .env
# data/raw/ 에 수집 파일(ZFI01.txt, ZFIR10070.txt 형식) 배치
python -m ingest.normalize && python -m parser.run && python -m index.loader
python -m query.api            # 127.0.0.1:8100

테스트: python -m pytest (샘플 데이터가 있으면 §4.6 실측 검증 포함)

파서나 색인 로직을 바꿨으면 소스가 그대로라도 재적재가 필요하다: python -m index.loader --force (정의부를 처음 붙이는 기존 DB 도 python -m parser.run && python -m index.loader --force 한 번이 필요하다 — declaration 테이블은 빈 채로 만들어지고 재적재 때 채워진다.)

서버가 코드 변경을 반영하지 않을 때

/dashboard/wiki-viewer템플릿(html)을 요청마다 다시 읽지만, 파이썬 모듈은 프로세스에 캐시된다(sys.modules). 그래서 CSS·JS 를 고치면 새로고침만으로 보이지만 wiki_out/viewer.py 같은 파이썬 코드를 고치면 서버를 다시 띄워야 한다. (실제로 조각 내비게이션을 추가했는데 사이드바가 계속 0 으로 보인 적이 있다.)

  • 개발 중에는 자동 재시작: python -m query.api --reload
  • 낡았는지 확인: GET /healthstarted_at 이 코드 수정 시각보다 이전인지 본다

Stage 3 을 LLM 키 없이 돌리기

--llm file 은 프롬프트를 data/llm_jobs/ 에 파일로 내놓고 응답 파일을 기다린다. 사람이 채워도 되고, 코딩 에이전트가 프롬프트를 읽고 채워도 된다.

python -m summarize.runner --llm file --program ZFIR10070 --limit 3   # 1) 프롬프트 내놓기
python -m summarize.jobs list --pending                               # 2) 대기 목록
python -m summarize.jobs show <job_id>                                #    프롬프트 읽기
python -m summarize.jobs answer <job_id> --file answer.json           # 3) 응답 저장(스키마 검증)
python -m summarize.runner --llm file --program ZFIR10070 --limit 3   # 4) 같은 명령 → 적재

프로그램 요약은 unit 프롬프트의 문맥이므로 먼저 답해야 한다 — 요약이 대기 중이면 그 프로그램의 unit 프롬프트는 나오지 않는다(요약이 채워진 뒤 프롬프트 내용이 달라져 두 번 답하게 되는 것을 막는다).

백엔드 3종: --llm api(환경변수 키) / --llm file(키 불필요) / --llm fake(배선 검증용 더미). /ingest 가 뒤이어 돌리는 요약의 백엔드는 SUMMARIZE_BACKEND=api|file|off 로 고른다. 큐 현황은 GET /summaries/jobs 또는 python -m summarize.jobs stats.

결과를 다른 PC 로 가져가기

방법 A — 단일 HTML 스냅샷 (파이썬·서버 불필요)

python -m wiki_out.viewer          # → data/wiki-viewer.html  (약 1.2 MB)
python -m query.dashboard          # → data/dashboard.html    (약 1.4 MB)

데이터가 파일 안에 박히므로 그 파일 하나만 복사해 브라우저로 열면 된다. 로직 조각의 소스 원문과 자연어 설명, 테이블·펑션 문서, 관측소 수치가 모두 들어 있다. 외부 스크립트·이미지를 받지 않으며, 웹폰트는 못 받아도 시스템 한글 글꼴로 폴백한다(폐쇄망 가능).

안 되는 것: 조각 검색(/search/logic)과 trace_variable·get_call_graph·get_table_usage 같은 구조 도구. 이건 DB 질의라 서버가 필요하다 (뷰어 사이드바의 문서 검색은 동작).

방법 B — 인덱스째로 옮기기 (전체 기능)

가져갈 것은 소스 + data/index.db + wiki/ 뿐이다 (합쳐 약 14 MB).

config/ ingest/ parser/ index/ summarize/ query/ wiki_out/ eval/ docs/
pyproject.toml
data/index.db      ← 조각·요약·심볼·호출그래프 + 인클루드 소스 원문까지 전부 들어있다
wiki/              ← 사람 교정본이 있으면 함께 (없으면 재생성 가능)

data/normalized/·data/parsed/·data/llm_jobs/가져갈 필요 없다 — 재생성 가능하고, 조각의 소스 원문은 include.code 로 DB 안에 있다. 새 PC 에서:

python -m venv .venv && .venv/Scripts/python -m pip install -e ".[dev]"
python -m query.api                # 관측소·뷰어·검색 API 전부 동작
python -m wiki_out.run --all       # (선택) 위키 재생성 — DB 만으로 된다

실측 검증: 위 최소 세트만 복사한 디렉토리에서 위키 재생성(283건 검증 통과)·스냅샷 생성· search_logic·get_table_usage·trace_variable·서버 기동이 모두 정상 동작했다.

API

Method Path 설명
GET /health 상태 + 적재 통계
GET /search/logic?q=&top_k=&program=&kind= 로직 조각 검색 — 자연어 로직 질의의 1차 진입점. 프로그램 단위로 묶어 반환
GET /summaries/jobs LLM 키 없이 돌릴 때의 프롬프트 대기 큐
GET /chunks/{chunk_id} 조각 메타 + 코드 원문 + 정의부(붙여넣기용 선언, ?decls=false 로 끔). chunk_id 의 #%23 으로 인코딩
GET /programs/{name}/declarations?scope= 프로그램의 선언 카탈로그 (정의부)
GET /programs/{name}/chunks?unit_id= 프로그램(또는 unit)의 조각 목록
GET /search/programs?q=&top_k= 프로그램 검색 — 이름·타이틀 기반 얇은 색인 (FTS + 한글 2-gram)
GET /search/units?q=&program= unit 검색 — 이름·주석·한 줄 요약 기반 얇은 색인
GET /programs/{name}/summary 프로그램 요약(LLM) + 구조 요약(파서, 조각 목록 포함)
GET /programs/{name}/source 정규화된 전체 소스 (opencode-be 의 fetch_abap 용)
GET /programs/{name}/units/{unit}/code unit 코드 원문(400줄 상한) + 요약 + 정의부
GET /programs/{name}/trace/{symbol} 변수 선언 + 쓰기 지점 (via_perform 재귀 전개, 깊이 5)
GET /programs/{name}/call-graph?unit= 호출 그래프
GET /programs/{name}/who-calls/{unit} 역참조
GET /tables/{name}/usage 테이블 읽기/쓰기 프로그램·unit

오류: 404(존재하지 않는 프로그램/심볼 — 유사 후보를 detail 에 포함), 503(DB 오류).

원칙 (계획서)

  • 사실은 파서가, 해석은 LLM이 — tables/calls/writes 는 파서 결과가 항상 우선. 조각의 줄 번호도 first_line 앵커로 검증하고, 조각의 테이블·호출은 파서로 다시 뽑는다.
  • 코드 원문은 로직, 선언은 정의부로 분리. 조각에는 로직만 담아 검색 품질을 지키고, 붙여넣을 때 필요한 선언은 declaration 테이블에서 의존까지 묶어 따로 조립한다 (index/decls.py). 인덱스는 재료와 분류만 넘기고, 쓸지 말지는 붙여넣는 쪽이 정한다.
  • 인덱스 단위는 LLM 이 골라낸 로직 조각. 파서의 문법 단위(FORM/METHOD/FUNCTION/MODULE/이벤트 블록)는 LLM 에게 보여주는 창이자 조각의 컨테이너다. 프로그램 요약을 먼저 만들어 문맥으로 붙인다.
  • 모든 산출물은 코드 해시에 묶여 증분 처리 (unit code_hash 가 같으면 조각 보존).
  • 요약·태그·키워드는 한국어 우선 + SAP 영어 용어·객체명 병기.

현재 상태 / 남은 일

  • Stage 1·2·4·5·6 동작. 샘플 14본(문장 24,578) 실측: 미인식 문장 30건(0.12%), 프로그램별 최대 0.46% (프로그램 하나만 보면 안 된다 — tests/test_parser_fieldsymbol.py 가 전체를 잰다)
  • Stage 3(로직 조각 추출): 구조 완료. LLM 키 없이 --llm file 로 실행 가능 (위 참고)
  • 임베딩/벡터 검색: 모델 미정으로 보류 — FTS(+2-gram, 동의어 확장)만 사용 중
  • DB: SQLite 기본. PostgreSQL 전환 스키마는 index/schema_postgres.sql
  • 보강 과제 10건 중 9건 반영 완료 — 판정·적용 내역은 docs/수정사항-적용.md (1 색인 반영 / 3 텍스트 심볼 FTS / 4 용어 사전 질의 확장 / 6 중복 조각 복제 / 8 엔티티 위키·계층 index / 10 병렬 실행 + 429 백오프. 2·5·9 는 이미 완료·무효)
  • 남은 일: 7번 정답셋 확대. 개발자 질의 50~100개를 받아 recall@10/MRR 을 재고 베이스라인과 비교해야 한다. 이게 없으면 위 검색 변경들의 정밀도 효과를 검증할 수 없다 (튜닝 대상 값: query/expand.pyEXPANDED_WEIGHT, MAX_SYNONYMS, 2단 검색 보충 조건)
  • 프로세스 위키 페이지("입고 처리는 세 경로")는 reduce 단계가 필요해 조각 데이터가 쌓인 뒤로 보류
S
Description
ABAP Source Indexing
Readme
2.2 MiB
Languages
Python 94.5%
HTML 5.5%