75 lines
2.5 KiB
Kotlin
75 lines
2.5 KiB
Kotlin
|
|
// 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)
|
||
|
|
}
|
||
|
|
}
|