AI 자동매매 시스템 만들기 #5 - RAG로 AI에게 기억력을 주다(pgvector)

2026. 2. 12. 15:17·일상다반사/개발

AI가 과거를 기억하지 못한다

초기 시스템의 치명적인 약점이 있었습니다. AI가 실시간으로 들어오는 정보만 보고 판단한다는 거예요.

예를 들어 텔레그램 채널에서 이런 메시지들이 왔다고 가정해봅시다:

월요일 오전: "삼성전자 분석 - 반도체 업황 회복 조짐, 목표가 85,000원"
월요일 오후: "삼성전자 실적 발표 예정, 컨센서스 상회 전망"
화요일 오전: "삼성전자 추가 매수 의견, 기술적 지지선 돌파"
수요일: "삼성전자" (단 3글자만)

 

AI는 수요일 메시지를 볼 때 이전 3일간의 맥락을 전혀 모릅니다. 단순히 "삼성전자"라는 키워드만 보고 분석하죠. 당연히 정확도가 떨어질 수밖에 없습니다.

RAG 구축

RAG는 간단히 말하면 "관련 있는 과거 정보를 찾아서 AI에게 함께 제공하는 기술"입니다.

 

이를 위해선 벡터 DB가 필요한데, Qdrant와 Pgvector 중에서 고민 끝에 pgvector로 결정하였습니다.

이유는 SQLite의 확장성 제약에 마이그레이션도 하는 겸 + 벤치마크 또한 pgvector가 우위에 있었는 점 이었습니다.

참고 자료: https://www.tigerdata.com/blog/pgvector-vs-qdrant

 

구현 과정은 이렇습니다:

1단계: PostgreSQL + pgvector 설치

기존에 H2 인메모리 DB를 쓰고 있었는데, 벡터 검색을 위해 PostgreSQL로 마이그레이션했습니다.

pgvector는 PostgreSQL의 확장 기능으로, 벡터 데이터를 저장하고 검색할 수 있게 해줍니다.

2단계: 텔레그램 메시지 임베딩

모든 텔레그램 메시지를 768차원 벡터로 변환해서 DB에 저장합니다. Ollama의 임베딩 모델을 사용했어요.

 

멀티스레드로 분석 속도 향상

RAG를 도입하니 또 다른 문제가 생겼습니다. 한 종목당 임베딩 + 벡터 검색 + AI 분석 시간이 1.5초 정도 걸리는데, 종목이 10개면 15초나 걸립니다.

해결책은 멀티스레드였습니다. 5개 스레드로 병렬 처리하니 10개 종목을 3초 안에 분석할 수 있게 됐습니다.

인덱싱 최적화

HNSW(Hierarchical Navigable Small World) 인덱스를 채택하였습니다. 정확도는 약간 희생되지만 실시간 거래에서는 속도가 더 중요합니다.

컨텍스트 윈도우 전략

처음엔 관련 메시지를 무조건 10개씩 가져왔는데, 너무 많은 정보가 오히려 AI를 헷갈리게 만들었습니다.

실험 결과 최적의 설정은:

  • 최근 7일 이내
  • 유사도 상위 5개
  • 코사인 유사도 0.7 이상만

실제 코드(일부)

@Configuration
class VectorStoreConfig {

    @Bean
    fun embeddingModel(): EmbeddingModel {
        val openAiApi = OpenAiApi.builder()
            .baseUrl("http://localhost:11434")  // Ollama 서버
            .apiKey("ollama")  // 더미 키
            .build()

        return OpenAiEmbeddingModel(
            openAiApi,
            org.springframework.ai.document.MetadataMode.EMBED,
            OpenAiEmbeddingOptions.builder()
                .model("nomic-embed-text")  // 768차원 임베딩 모델
                .build(),
            RetryUtils.DEFAULT_RETRY_TEMPLATE,
        )
    }
}

 

 

fun embedMessage(message: ChannelMessage) {
    // 메시지 내용 + 이미지 분석 결과 결합
    val content = message.content + 
        if (message.imageAnalysis != null) "\n[이미지 분석] ${message.imageAnalysis}" else ""
    
    // 메타데이터 구성
    val metadata = mutableMapOf<String, Any>(
        "channelName" to message.channelName,
        "createdAt" to message.createdAt.toString(),
        "stockCode" to message.matchedStockCode,
        "stockName" to message.matchedStockName,
        "type" to "channel_message"
    )
    
    // Spring AI Document로 변환 후 저장
    val document = Document(content, metadata)
    vectorStore.add(listOf(document))
}

 

 

fun searchRelatedMessages(
    stockName: String,
    stockCode: String,
    sectorName: String? = null,
    topK: Int = 8,
    similarityThreshold: Double = 0.5,
    daysBack: Long = 7L
): List<RelevantMessage> {
    
    // 검색 쿼리: 종목명 + 섹터명 + "관련 뉴스 소식"
    val query = "$stockName ${sectorName ?: ""} 관련 뉴스 소식"
    
    // 시간 필터: 최근 7일 이내
    val sinceDate = LocalDateTime.now().minusDays(daysBack).toString()
    val filterExpression = "createdAt >= '$sinceDate'"
    
    // 벡터 검색 실행
    val request = SearchRequest.builder()
        .query(query)
        .topK(topK)
        .similarityThreshold(similarityThreshold)  // 0.5 이상만
        .filterExpression(filterExpression)
        .build()
    
    return vectorStore.similaritySearch(request)
}

 

@Scheduled(cron = "0 0 4 * * *")  // 매일 오전 4시
fun cleanupOldEntries() {
    val cutoffDate = LocalDateTime.now().minusDays(30).toString()
    
    jdbcTemplate.update(
        "DELETE FROM vector_store WHERE metadata->>'createdAt' < ? AND metadata->>'type' = 'channel_message'",
        cutoffDate
    )
}

배운 점

1. RAG는 LLM의 게임 체인저: 같은 모델이라도 컨텍스트 유무에 따라 성능이 12% 이상 차이 납니다.

2. 벡터 DB 선택이 중요: 처음엔 Chroma, Qdrant 같은 전용 벡터 DB를 고려했지만, pgvector로도 충분했습니다.

3. 임베딩 모델 선택: 로컬 모델 nomic-embed-text(768차원)을 사용하였습니다. 한국어 성능은 약간 떨어지지만 실시간 처리엔 문제없었어요.

 

 

반응형
저작자표시 비영리 (새창열림)
'일상다반사/개발' 카테고리의 다른 글
  • AI 자동매매 시스템 만들기 #6 - 예외처리시간! (LLM 환각, WebSocket 재연결, API 비용 최적화)
  • AI 자동매매 시스템 만들기 #4 - AI가 실제로 판단하는 방법
  • AI 자동매매 시스템 만들기 #3 - 키움증권 API 연동과 실전 거래
  • AI 자동매매 시스템 만들기 #2 - 채널 모니터링과 5단계 매칭 시스템
Kua
Kua
정보 공유, 개인 정리 공간 입니다.
  • Kua
    Kua's Miscellaneous
    Kua
  • 전체
    오늘
    어제
    • 분류 전체보기 (192) N
      • 대문 (2)
      • Tips (1)
        • Chrome (2)
        • Windows (4)
        • IDE (3)
        • 기타 (16)
      • CodingTest (44)
      • Language (20)
        • PHP (5)
        • C# (7)
        • Java (1)
        • Kotlin (7)
      • Framework & Runtime (16)
        • SpringBoot (12)
        • Node.js (2)
        • Vue.js (1)
        • Gradle (1)
      • DevOps (13)
        • Linux (1)
        • Docker (4)
        • Kubernetes (2)
        • Apache Kafka (1)
        • AWS (1)
      • 일상다반사 (59) N
        • 도서 (1)
        • 개발 (14) N
        • 후기 - IT (7)
        • 후기 - 일상 (13)
        • 차가리 (4)
        • 방송통신대학교 (4)
        • 음식 (2)
      • Games (12)
        • Minecraft (7)
        • VR (2)
        • 그외 (3)
  • 인기 글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
Kua
AI 자동매매 시스템 만들기 #5 - RAG로 AI에게 기억력을 주다(pgvector)
상단으로

티스토리툴바