어떤 기능인가요?
현재 internal/crawler/parser/rule/llmgen/prompt.go 에 system / user 프롬프트가 Go 상수로 하드코딩 되어 있습니다. 프롬프트는 LLM 응답 품질의 가장 큰 lever 인데, 한 줄만 수정해도 다음이 모두 필요합니다:
- 코드 변경 → PR 생성 → 리뷰 → CI → 머지
- 바이너리 재빌드
- 전체 서비스 재배포
운영자 (또는 LLM ops 담당) 이 프롬프트를 자주 튜닝해야 하는 특성상 본 cycle 은 과도합니다. 본 이슈는 프롬프트를 외부 파일에서 런타임에 로드 하여 코드 재배포 없이 수정 가능하게 합니다.
목표 vs 현재 상태
|
현재 |
본 이슈 후 |
| 프롬프트 위치 |
Go 상수 (prompt.go:31-71) |
외부 파일 (예: scripts/prompts/page.txt / list.txt / system.txt) |
| 수정 시 필요 |
코드 변경 + PR + 재빌드 + 재배포 |
파일 수정 + 프로세스 재기동 (또는 reload trigger) |
| Git 추적 |
코드 diff 로 변경 확인 |
scripts/prompts/ 의 파일 diff 로 확인 (동일하게 git 관리) |
| 검증 |
CI 의 build/test |
시작 시 파일 존재 + non-empty 검증, 형식 검증 (placeholder 치환 가능 여부) |
무엇을 하나요?
1. 디렉토리 구조 (scripts/prompts/)
이미 빈 디렉토리 + .gitkeep 만 존재. 본 이슈에서 다음 파일 추가:
scripts/prompts/
├── system.txt # 모든 호출 공통 system prompt
├── page.user.txt # TargetTypePage 용 user prompt 템플릿
└── list.user.txt # TargetTypeList 용 user prompt 템플릿
user prompt 는 placeholder ({{HOST}}, {{TARGET_TYPE}}, {{HTML}}, {{MAX_HTML_BYTES}}) 를 포함하고 런타임에 치환.
2. PromptLoader 추상화
// internal/crawler/parser/rule/llmgen/loader.go (신규)
type PromptLoader interface {
System() string
UserForTarget(targetType storage.TargetType) (string, error)
}
// FilePromptLoader: 시작 시 1회 read + in-memory cache
type FilePromptLoader struct { ... }
func NewFilePromptLoader(dir string) (*FilePromptLoader, error)
// EmbedPromptLoader: 현재 하드코딩 프롬프트의 fallback (file 부재 시)
type EmbedPromptLoader struct{}
3. config 추가
// pkg/config/config.go LLMConfig
PromptDir string // LLM_PROMPT_DIR (default "scripts/prompts")
LLM_PROMPT_DIR=\"\" 또는 디렉토리 부재 → EmbedPromptLoader fallback (graceful)
- 디렉토리 존재 + 일부 파일 누락 → fail-fast (배포 누락 가시화)
4. BuildPrompt 변경
현재 prompt.go:25-29 의 BuildPrompt 함수를 PromptLoader 의존성으로 변경:
func BuildPrompt(loader PromptLoader, host string, t storage.TargetType, html string) (system, user string, err error) {
// loader.System() + loader.UserForTarget(t) 에서 placeholder 치환
}
5. Reload 정책 (선택)
본 이슈 1차 scope: 프로세스 재기동 시에만 reload. 운영자 워크플로:
scripts/prompts/page.user.txt 수정 + commit + push
- 운영 환경에서
git pull + make restart
향후 (별도 이슈로 분리 가능):
- SIGHUP 으로 reload — 단일 인스턴스 무중단 갱신
- 또는
/admin/llm/prompts/reload API endpoint
- 또는 file watcher (fsnotify)
본 이슈에서는 "파일 로드 인프라" 까지만. 동적 reload 는 별도 이슈로 추적 권장.
6. 테스트
의존 / 연관
영향 / 위험
효과
- 프롬프트 튜닝 cycle 단축 — LLM 응답 품질 개선이 운영 액션으로 가능
- 프롬프트가 git 추적되어도 코드 변경과 분리 → 리뷰 부담 ↓
- A/B 테스트 가능 — 환경변수로 디렉토리 swap
위험
- 잘못된 프롬프트 배포: 시작 시 placeholder 검증 + 형식 검증으로 1차 방어. 그래도 LLM 응답 품질 저하는 사후 metric 으로만 발견 가능
- 파일 부재 / 권한 오류: fail-fast 또는 graceful fallback 정책 — 본 이슈에서 명시 결정 필요
- 여러 인스턴스 일관성: 재기동 타이밍 차이로 일시적으로 다른 프롬프트 사용 가능. 무중단 reload 정책 도입 시 더 심각해짐 (별도 이슈)
롤백
LLM_PROMPT_DIR=\"\" 설정 → 즉시 EmbedPromptLoader (현재 하드코딩) 동작
- 또는 본 PR revert
참고
어떤 기능인가요?
현재 internal/crawler/parser/rule/llmgen/prompt.go 에 system / user 프롬프트가 Go 상수로 하드코딩 되어 있습니다. 프롬프트는 LLM 응답 품질의 가장 큰 lever 인데, 한 줄만 수정해도 다음이 모두 필요합니다:
운영자 (또는 LLM ops 담당) 이 프롬프트를 자주 튜닝해야 하는 특성상 본 cycle 은 과도합니다. 본 이슈는 프롬프트를 외부 파일에서 런타임에 로드 하여 코드 재배포 없이 수정 가능하게 합니다.
목표 vs 현재 상태
scripts/prompts/page.txt/list.txt/system.txt)scripts/prompts/의 파일 diff 로 확인 (동일하게 git 관리)무엇을 하나요?
1. 디렉토리 구조 (
scripts/prompts/)이미 빈 디렉토리 +
.gitkeep만 존재. 본 이슈에서 다음 파일 추가:user prompt 는 placeholder (
{{HOST}},{{TARGET_TYPE}},{{HTML}},{{MAX_HTML_BYTES}}) 를 포함하고 런타임에 치환.2. PromptLoader 추상화
3. config 추가
LLM_PROMPT_DIR=\"\"또는 디렉토리 부재 → EmbedPromptLoader fallback (graceful)4. BuildPrompt 변경
현재 prompt.go:25-29 의
BuildPrompt함수를 PromptLoader 의존성으로 변경:5. Reload 정책 (선택)
본 이슈 1차 scope: 프로세스 재기동 시에만 reload. 운영자 워크플로:
scripts/prompts/page.user.txt수정 + commit + pushgit pull+make restart향후 (별도 이슈로 분리 가능):
/admin/llm/prompts/reloadAPI endpoint본 이슈에서는 "파일 로드 인프라" 까지만. 동적 reload 는 별도 이슈로 추적 권장.
6. 테스트
의존 / 연관
영향 / 위험
효과
위험
롤백
LLM_PROMPT_DIR=\"\"설정 → 즉시 EmbedPromptLoader (현재 하드코딩) 동작참고