atrade/src/main/kotlin/network/RagService.kt

75 lines
2.5 KiB
Kotlin
Raw Normal View History

2026-01-21 18:30:03 +09:00
// src/main/kotlin/network/RagService.kt
import dev.langchain4j.data.segment.TextSegment
import dev.langchain4j.model.openai.OpenAiChatModel
import dev.langchain4j.model.openai.OpenAiEmbeddingModel
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.plus
import org.jetbrains.exposed.sql.transactions.transaction
import java.time.Duration
object RagService {
// 임베딩 모델 (8081) 및 채팅 모델 (8080) 설정
private val embeddingModel = OpenAiEmbeddingModel.builder()
.baseUrl("http://127.0.0.1:8081/v1")
.apiKey("unused")
.build()
private val chatModel = OpenAiChatModel.builder()
.baseUrl("http://127.0.0.1:8080/v1")
.apiKey("unused")
.timeout(Duration.ofSeconds(60))
.build()
/**
* 텍스트를 임베딩하여 H2 DB에 저장합니다.
*/
fun ingest(text: String, meta: String = "") {
val embedding = embeddingModel.embed(text).content().vector()
transaction {
VectorStoreTable.insert {
it[content] = text
it[metadata] = meta
// 벡터 데이터를 문자열 형태로 저장 (H2 포맷)
it[VectorStoreTable.embedding] = embedding.joinToString(",", "[", "]")
}
}
println("💾 H2 벡터 저장 완료: ${text.take(15)}...")
}
/**
* 질문과 가장 유사한 정보를 H2에서 검색하여 AI 답변을 생성합니다.
*/
fun ask(question: String): String {
val queryVector = embeddingModel.embed(question).content().vector()
val vectorStr = queryVector.joinToString(",", "[", "]")
// H2의 VECTOR_COSINE_SIMILARITY 함수를 사용하여 검색
val context = transaction {
val query = "SELECT content FROM VECTOR_STORE " +
"ORDER BY VECTOR_COSINE_SIMILARITY(embedding, '$vectorStr') DESC " +
"LIMIT 3"
val results = mutableListOf<String>()
exec(query) { rs ->
while (rs.next()) {
results.add(rs.getString("content"))
}
}
results.joinToString("\n\n")
}
val prompt = """
[참고 정보]
$context
[질문]
$question
정보를 참고하여 분석 결과를 말해주세요.
""".trimIndent()
return chatModel.generate(prompt)
}
}