AI 주식 파이프라인 시리즈1편 · 2편 · 3편

[핵심 요약] — 파이프라인을 두 달 운영하며 5번 넘어졌다: AI 비용 초과, API 키 문자열 오류, f-string 버그로 인한 API 낭비, 주가 라이브러리 불안정, 주말에만 재현되는 None 반환 버그. 지금은 월 약 9,200원에 안정 운영 중.


본 포스팅은 자체 개발한 데이터 파이프라인의 생산 배포 이후 발생한 예외 처리 결함 5가지와 비용 최적화 과정을 기록한 엔지니어링 트러블슈팅 문서입니다.

1편에서 설계를 세 번 갈아엎었다고 했는데, 그게 끝이 아니었습니다.

구조를 잡고 실제로 돌리기 시작하면서 이번엔 운영 단계에서 문제가 터졌습니다. 두 달 동안 크게 다섯 번 넘어졌습니다. 비용이 갑자기 두 배가 되거나, 매일 아침 파이프라인이 조용히 실패하거나, 주말에만 이상한 결과가 나오거나.

이 글은 그 다섯 번의 삽질 기록입니다. 코드보다는 “왜 이런 일이 생겼나”에 집중해서 정리했습니다.


지금 시스템 월 운영 비용부터

본론 전에 현재 상태를 먼저 정리합니다. 두 달간 다듬은 끝에 월 비용은 이렇게 됩니다:

항목내용월 비용
보유 종목 분석Claude Sonnet약 2,000원
폴백 처리Claude Haiku약 150원
뉴스 검색Brave Search약 7,000원
대량 스크리닝Gemini Flash-Lite무료
주가 데이터KIS 오픈 API무료
합계약 9,200원

처음 설계 기준이 한 달 4만원 후반이었으니까 절반 이하로 줄었습니다. 그 과정이 아래 다섯 번의 삽질입니다.


삽질 1 — AI 비용이 예상보다 많이 나왔습니다

첫 번째로 부딪힌 문제는 역시 비용이었습니다. 설계 단계에서 역할 분리 원칙을 정했는데, 실제 구현에서 시장 레이더 스크리닝 단계를 비싼 모델로 처리하고 있었습니다. 3,000개 종목 중 신호가 발생한 상위 25개를 한 번 더 걸러내는 단계였는데, 이 부분을 고성능 모델로 돌리니 비용이 의도보다 많이 나왔습니다.

해결책은 단순했습니다. 이 단계를 무료 티어로 쓸 수 있는 Gemini Flash-Lite로 바꿨습니다. 단순 판단 작업에는 충분한 성능이었습니다.

다만 여기서도 작은 함정이 있었습니다. 처음에 쓴 게 프리뷰 버전 모델이었는데 503 오류가 자주 났습니다. 매일 아침 파이프라인이 돌다가 AI가 갑자기 응답을 안 하는 상황이 반복됐습니다. 정식 버전으로 바꾸고 나서야 안정됐습니다. 모델 이름 하나 차이인데 한참 디버깅했습니다.


삽질 2 — API 키가 문자열 그대로 전달되고 있었습니다

5월 어느 날 아침, 판단 엔진이 모든 종목에서 오류를 뱉기 시작했습니다. 확인해보니 인증 실패 오류였습니다. API 키가 분명히 설정 파일에 있는데 왜 인증이 안 되는지 한참 찾았습니다.

원인은 예상 못 한 곳에 있었습니다. 설정 파일에 API 키를 환경변수 방식으로 적어뒀는데, 판단 엔진 코드에는 그 환경변수를 실제로 읽어오는 코드가 없었습니다. 다른 모듈에서 코드를 참고하다가 그 부분을 빼먹은 것이었습니다. 결국 API 키 자리에 변수 이름 문자열이 그대로 서버로 전달되고 있었습니다.

수정 자체는 간단했지만, 이 버그 때문에 한동안 판단 엔진이 조용히 오작동하고 있었다는 게 더 문제였습니다. 이후에는 설정을 읽는 방식을 모든 모듈에서 하나의 공통 함수로 통일했습니다.


삽질 3 — 파이프라인이 멈추면 API 비용이 두 배가 됐습니다

f-string 안에 중괄호를 JSON 예시로 쓴 게 문제였습니다. Python이 그 중괄호를 변수로 해석하면서 오류가 나고 파이프라인이 멈췄습니다.

# 문제: f-string 안의 JSON 중괄호를 Python이 변수로 해석
prompt = f'결과를 JSON으로 출력하세요: {"signal": 1}'
# → SyntaxError: f-string expression part cannot include a backslash

# 수정: 중괄호를 이중으로 이스케이프
prompt = f'결과를 JSON으로 출력하세요: {{"signal": 1}}'

수정은 간단했는데, 진짜 문제는 재실행할 때 드러났습니다.

파이프라인이 실패하면 처음부터 다시 시작합니다. 이미 뉴스 검색 API를 60건 이상 썼는데, 재실행하면 또 60건이 나갑니다. 오류 수정하고 테스트하고를 반복하다 보면 순식간에 API 사용량이 쌓입니다.

실제로 2주 만에 한 달 할당량의 80%를 써버린 적이 있었습니다. 이후에는 데이터 수집 결과를 임시 저장해두고, 재실행 시 API를 다시 호출하지 않도록 바꿨습니다.


삽질 4 — 주가 데이터가 들쭉날쭉했습니다

처음에는 오픈소스 라이브러리로 주가를 가져왔습니다. 비공식 방식이라 가끔 데이터가 비거나 이상하게 들어오는 문제가 반복됐습니다. 한국 주식 특성상 종목 코드 처리도 번거로웠고, 장 마감 후 데이터가 늦게 반영되는 경우도 잦았습니다.

중간에 다른 라이브러리로 갈아탔는데, 이번엔 Docker 환경에서 의존성 문제가 생겼습니다. 결국 돌고 돌아 KIS(한국투자증권) 공식 API로 전환했습니다. 공식 채널이라 데이터 안정성이 훨씬 좋고, 주가뿐만 아니라 투자의견, 수급 데이터까지 무료로 제공합니다.

생산 환경 파이프라인 결함 분석 매트릭스


삽질 5 — 주말에만 이상한 결과가 나왔습니다

KIS API로 바꾸고 첫 토요일 스크리닝을 돌렸는데 결과가 이상했습니다. 전체 후보 종목 중 90%가까이가 관리종목으로 분류돼서 떨어졌습니다. 코스피, 코스닥 전체에 관리종목이 그렇게 많을 리가 없었습니다.

디버깅해보니 원인이 어이없었습니다. KIS API가 관리종목 여부를 나타내는 필드를 평일에는 정상 값으로 내려주는데, 주말에는 빈 값을 반환하는 특성이 있었습니다. 코드에서 빈 값 처리를 안 해두다 보니 시스템이 이를 전부 관리종목으로 잘못 분류한 겁니다.

# 문제: 주말 None 반환 시 처리 누락
is_managed = data['mrkt_mgmt_yn']  # 주말엔 None 반환
if is_managed != 'N':              # None != 'N' → True → 관리종목 오분류
    continue

# 수정: 빈 값 방어 처리
is_managed = data.get('mrkt_mgmt_yn') or 'N'
if is_managed != 'N':
    continue

평일 데이터로만 개발하고 테스트했기 때문에 이 경우를 전혀 생각하지 못했습니다. 수정은 코드 한 줄이었는데, 직접 주말에 돌려보기 전까지는 절대 발견할 수 없는 종류의 버그였습니다.


지금 시스템이 돌아가는 방식

다섯 번의 삽질을 거치고 지금 구조가 자리를 잡았습니다:

  • 평일 오전 8시: 뉴스 수집 → 중복 제거 → 기술지표 계산 → 시장 레이더 스크리닝 → 카카오톡 발송
  • 토요일 오전 10시: 전 종목 성장주 스크리닝 → 저평가주 스크리닝 → 주간 리포트 발송

아키텍처 리팩토링 전후 비용 최적화 지표


마무리하며

이론대로 만들어놓고 실제로 매일 돌려보지 않으면 보이지 않는 문제들이 있습니다. 위의 다섯 가지 중에서 평일 테스트만으로는 발견할 수 없었던 주말 버그가 특히 그랬습니다.

코드 품질보다 예외 상황 처리가 더 중요한 이유가 여기 있습니다. 3편에서는 데이터 소스를 바꿔온 과정을 정리할 예정입니다.


시리즈 목차

  • 1편 · AI 두 개로 역할 나눠 운영비 줄이기
  • 2편 · 2개월 실전 운영, 삽질의 기록 (현재 글)
  • 3편 · 데이터 소스 변천사 (yfinance → KIS)
  • 4편 · 퀀트 신호 감지
  • 5편 · AI 판단 파이프라인
  • 6편 · 성장주·저평가주 스크리너