Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
133 lines
7.5 KiB
Markdown
133 lines
7.5 KiB
Markdown
# ABAP_INDEXING 을 고객사 사내 LLM(FabriX/Gauss) 으로 돌리기 — 팀원용 가이드
|
|
|
|
2026-09-21. ABAP_INDEXING 레포(팀원 소유)의 Stage 3(로직 조각 추출)을 고객사 -12 컨테이너에서 FabriX 로 돌리는 절차.
|
|
결과(`data/index.db`)는 CodeAssist 의 `abap_index_*` 툴이 씀 → `5_django_backend/README.md` "ABAP 소스 인덱스 붙이기".
|
|
|
|
## 핵심: FabriX 직결 — 헤더 3종만 붙이면 됨
|
|
|
|
ABAP_INDEXING 의 LLM 클라이언트(`summarize/llm_client.py`)는 `Authorization: Bearer <키>` 하나만 보낸다.
|
|
FabriX 는 그걸 안 받고 커스텀 헤더 3종을 요구한다 → 그대로 붙이면 **401**. 아래 패치(10줄)로 직결하면 -12 도 게이트웨이도 필요 없다.
|
|
(값·형식은 CodeAssist 게이트웨이 `apps/gateway/fabrix.py` 와 9/18 실측 그대로 — Bearer 접두 필수, `x-generative-ai-client`, body model 고정.)
|
|
|
|
### `summarize/llm_client.py` 패치
|
|
|
|
`_post_once` 에서 body 의 `model` 과 headers 만 바꾼다:
|
|
|
|
```python
|
|
import os
|
|
|
|
def _post_once(self, system: str, user: str) -> dict:
|
|
body = {
|
|
"model": os.environ.get("FABRIX_BODY_MODEL", "/mnt/models"), # FabriX 규격: body 는 고정 경로, 모델은 헤더가 고름
|
|
"temperature": 0.1,
|
|
"messages": [{"role": "system", "content": system}, {"role": "user", "content": user}],
|
|
"response_format": {"type": "json_object"},
|
|
}
|
|
req = urllib.request.Request(
|
|
f"{self.base}/chat/completions",
|
|
data=json.dumps(body).encode("utf-8"),
|
|
headers={
|
|
"Content-Type": "application/json",
|
|
"x-llm-model-id": self.model, # LLM_MODEL=339
|
|
"x-generative-ai-client": os.environ["FABRIX_CLIENT_KEY"],
|
|
"x-openapi-token": "Bearer " + os.environ["FABRIX_OPENAPI_TOKEN"], # Bearer 접두 필수(날것은 401)
|
|
"x-generative-ai-user-email": os.environ.get("FABRIX_USER_EMAIL", ""),
|
|
},
|
|
method="POST",
|
|
)
|
|
with urllib.request.urlopen(req, timeout=settings.llm_timeout_s) as res:
|
|
return json.loads(res.read().decode("utf-8"))
|
|
```
|
|
|
|
`.env` (고객사 PC 또는 -12, 어디서 돌리든 같음):
|
|
|
|
```ini
|
|
LLM_BASE_URL=https://<FabriX 호스트>/openapi/llm # CodeAssist .env 의 AAF_FABRIX_BASE_URL 과 같은 값. /chat/completions 는 코드가 붙임
|
|
LLM_API_KEY=unused # 클라이언트 생성자가 비어 있으면 에러 내서 아무 값
|
|
LLM_MODEL=339 # x-llm-model-id. GaussO Flash. Gemma(605/580) 금지 — 30~100배 느림
|
|
FABRIX_CLIENT_KEY=... # = AAF_FABRIX_CLIENT_KEY
|
|
FABRIX_OPENAPI_TOKEN=... # = AAF_FABRIX_OPENAPI_TOKEN (Bearer 없이 날것. 코드가 붙임)
|
|
FABRIX_USER_EMAIL= # = AAF_FABRIX_USER_EMAIL (비어도 됨)
|
|
LLM_CONCURRENCY=2 # 429 안 나면 4
|
|
LLM_MAX_RETRIES=5
|
|
LLM_TIMEOUT_S=180
|
|
SUMMARIZE_BACKEND=api
|
|
```
|
|
|
|
## 고객사 PC(윈도우)에서 돌리기
|
|
|
|
```powershell
|
|
cd ABAP_INDEXING
|
|
python -m venv .venv; .venv\Scripts\pip install -e ".[dev]" # pip 안 되면 wheels 로
|
|
# data
|
|
aw\*.txt 배치 후
|
|
$env:PYTHONUTF8="1"
|
|
.venv\Scripts\python -m ingest.normalize; .venv\Scripts\python -m parser.run; .venv\Scripts\python -m index.loader
|
|
.venv\Scripts\python -m summarize.runner --llm api --program <프로그램명> --limit 3 # 작게 먼저 → 아래 "확인할 것" 1번
|
|
.venv\Scripts\python -m summarize.jobs stats
|
|
.venv\Scripts\python -m summarize.runner --llm api # 전량 (며칠 갈 수 있음)
|
|
.venv\Scripts\python -m index.loader --force
|
|
```
|
|
|
|
끝나면 `data\index.db` 를 -12 로 옮겨 거기서 `query.api`(:8100) 를 띄운다("끝나면" 절). PC 에서 8100 을 띄워도 -12 의 OpenCode 는 못 붙는다(컨테이너 → PC 방향 안 열림).
|
|
|
|
### 코드 못 고치는 상황이면 — -12 게이트웨이 경유 (대안)
|
|
|
|
CodeAssist 백엔드 `/api/ito` 가 헤더를 대신 얹어준다. 패치 없이 `.env` 만:
|
|
`LLM_BASE_URL=http://10.196.81.34:8914/api/ito`, `LLM_API_KEY=x`(-12 의 `AAF_GATEWAY_KEY`), `LLM_MODEL=339`.
|
|
-12 백엔드가 떠 있어야 하고 호출이 전부 -12 를 지나니 부하가 거기 걸림. 기본은 위 직결.
|
|
|
|
## -12 에서 준비
|
|
|
|
전제: CodeAssist 백엔드가 -12 에 떠 있고(`curl :8080/api/ito/models` 에 모델 3개), `.env` 의 `AAF_FABRIX_*` 가 채워져 있음.
|
|
|
|
```bash
|
|
# 1) 레포 올리기 (인터넷 없음 — PC 거쳐 scp)
|
|
scp -P 8912 -r ABAP_INDEXING root@10.196.81.34:/www/
|
|
|
|
# 2) 파이썬 — CodeAssist 가 쓰던 offline wheels 에 fastapi·uvicorn·pydantic 은 있음. pydantic-settings 는 없을 수 있음
|
|
cd /www/ABAP_INDEXING && python3 -m venv .venv
|
|
.venv/bin/pip install --no-index --find-links /www/wheels fastapi "uvicorn[standard]" pydantic pydantic-settings
|
|
# pydantic-settings 없다고 하면: PC 에서 `pip download pydantic-settings --platform manylinux2014_x86_64 --python-version 3.12 --only-binary=:all: -d wheels` 받아서 /www/wheels 에 추가
|
|
.venv/bin/pip install --no-index --no-deps -e .
|
|
|
|
# 3) .env
|
|
cp .env.example .env && vi .env
|
|
```
|
|
|
|
`.env` 는 위 "핵심" 절과 같음(직결). -12 안에서 돌리면 `LLM_BASE_URL` 도 FabriX 호스트 그대로.
|
|
|
|
## 돌리기
|
|
|
|
```bash
|
|
cd /www/ABAP_INDEXING && set -a; . ./.env; set +a
|
|
# 소스 수집 파일을 data/raw/*.txt 로 넣은 뒤
|
|
.venv/bin/python -m ingest.normalize # Stage 1 — LLM 없음
|
|
.venv/bin/python -m parser.run # Stage 2 — LLM 없음
|
|
.venv/bin/python -m index.loader # Stage 4
|
|
# Stage 3 — 먼저 작게. 프로그램 하나 unit 3개로 FabriX·JSON 응답이 되는지
|
|
.venv/bin/python -m summarize.runner --llm api --program <프로그램명> --limit 3
|
|
.venv/bin/python -m summarize.jobs stats # failed 없는지
|
|
# 되면 전량 (nohup 으로, 며칠 걸릴 수 있음)
|
|
nohup .venv/bin/python -m summarize.runner --llm api > logs/summarize.log 2>&1 &
|
|
.venv/bin/python -m index.loader --force # 조각 반영
|
|
nohup .venv/bin/python -m query.api > logs/query.log 2>&1 & # :8100 — CodeAssist 툴이 붙음
|
|
curl -s http://127.0.0.1:8100/health
|
|
```
|
|
|
|
## 먼저 확인할 것 3개 (안 되면 여기서 걸림)
|
|
|
|
1. **`response_format: json_object` 를 FabriX 가 받는가.** 클라이언트가 이걸 항상 보낸다. FabriX 가 400 을 주면 `_post_once` 에서 그 줄을 빼고 `_extract_json` 이 본문에서 JSON 을 파싱하게 둬야 함(파서는 이미 관대함).
|
|
확인: 위 `--limit 3` 실행에서 400 나오는지.
|
|
2. **속도·한도.** 55본에 조각 3,212개였음 → 1만 본이면 LLM 호출 수십만 번. 339 가 1.9s/호출이면 순차로 며칠. 이금관 팀에 일일 토큰 한도·동시 호출 제한 미리 물어볼 것.
|
|
3. **한글 출력.** 컨테이너 로케일이 ASCII 라 파이썬이 한글 찍다 죽는다 → 모든 실행 앞에 `PYTHONUTF8=1` (CodeAssist 도 그렇게 띄움).
|
|
|
|
## 하지 말 것
|
|
|
|
- 패치 없이 `LLM_BASE_URL` 에 FabriX 주소만 넣기 — 헤더 없어서 401.
|
|
- `LLM_MODEL` 에 Gemma(605/580) — 텍스트 요약에 이미지 모델 쓸 이유 없고 30~100배 느림.
|
|
- -13 의 게이트웨이(8918) 로 붙기 — 컨테이너 간 통신 금지. -12 안의 8080 만.
|
|
|
|
## 끝나면
|
|
|
|
`data/index.db` 가 커지고(55본에 43MB) `:8100/health` 에 적재 통계가 나오면, CodeAssist 쪽은 `.env` 의 `ABAP_INDEX_URL=http://127.0.0.1:8100` 기본값 그대로라 OpenCode 재시작만 하면 앱이 "출처: 프로그램/unit" 붙은 코드를 답하기 시작함.
|