ํฐ์คํ ๋ฆฌ ๋ทฐ
๐ฑ Spring AI vs ๐ LangChain4j: Java AI ํ๋ ์์ํฌ ์ ๊ฒฉ ๋น๊ต
owal_returns 2025. 8. 27. 19:41๐ฑ Spring AI vs ๐ LangChain4j: Java AI ํ๋ ์์ํฌ ์ ๊ฒฉ ๋น๊ต
์ต๊ทผ AI ๊ธฐ์ , ํนํ LLM(๋๊ท๋ชจ ์ธ์ด ๋ชจ๋ธ)์ ์์ ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ํตํฉํ๋ ค๋ ๊ฐ๋ฐ์๋ค์ด ๋์ด๋๋ฉด์ Java ์ง์์์๋ ๋๊ฐ์ ๋ํ๋ด๋ ๋ ๊ฐ์ ํ๋ ์์ํฌ๊ฐ ์์ต๋๋ค. ๋ฐ๋ก Spring AI์ LangChain4j์ ๋๋ค.
๋ ํ๋ ์์ํฌ ๋ชจ๋ ๊ฐ๋ ฅํ์ง๋ง, ์งํฅํ๋ ์ฒ ํ๊ณผ ์ฌ์ฉ ๋ฐฉ์์ ์ฐจ์ด๊ฐ ์์ด ํ๋ก์ ํธ์ ์ฑ๊ฒฉ์ ๋ง๋ ๊ธฐ์ ์ ์ ํํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ์ด ๊ธ์์๋ ๋ ํ๋ ์์ํฌ๋ฅผ ์ฌ์ธต์ ์ผ๋ก ๋น๊ตํ๊ณ , ์ด๋ค ์ํฉ์์ ๋ฌด์์ ์ ํํด์ผ ํ ์ง ๋ช ํํ ๊ฐ์ด๋๋ฅผ ์ ์ํฉ๋๋ค.
1. ์ ์: ๋ ๊ฑฐ์ธ์ ๋ฑ์ฅ
๐ฑ Spring AI
Spring AI๋ Spring ๊ฐ๋ฐํ์ด ์ง์ ๋ง๋๋, ์คํ๋ง ์ํ๊ณ์ AI ๊ธฐ๋ฅ์ '๋ค์ดํฐ๋ธ'ํ๊ฒ ํตํฉํ๊ธฐ ์ํ ํ๋ก์ ํธ์ ๋๋ค. ์คํ๋ง ๊ฐ๋ฐ์๋ผ๋ฉด ๋๊ตฌ๋ ์ต์ํ DI, AOP, ์๋ ์ค์ (Auto-configuration)๊ณผ ๊ฐ์ ํจ๋ฌ๋ค์์ ๊ทธ๋๋ก ๋ฐ๋ฅด๋ฉฐ, ์ต์ํ์ ๋ ธ๋ ฅ์ผ๋ก AI ๊ธฐ๋ฅ์ ์ถ๊ฐํ ์ ์๋๋ก ๋๋ ๊ฒ์ ๋ชฉํ๋ก ํฉ๋๋ค.
์๋์ฐจ์ ๋น์ ํ์๋ฉด, ์ ์กฐ์ฌ๊ฐ ๋์๋ณด๋์ ์๋ฒฝํ๊ฒ ๋ด์ฅํด ๋์ ์์ ๋ด๋น๊ฒ์ด์ ๊ณผ ๊ฐ์ต๋๋ค.
๐ LangChain4j
LangChain4j๋ ํ์ด์ฌ์์ ์์๋ ์ ๋ช AI ํ๋ ์์ํฌ 'LangChain'์ Java ๋ฒ์ ์ ๋๋ค. ํน์ ํ๋ ์์ํฌ์ ์ข ์๋์ง ์๋ ๋ ๋ฆฝ์ ์ด๊ณ ๋ฒ์ฉ์ ์ธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก, AI ์์ด์ ํธ, ์ฒด์ธ ๋ฑ ๋ณต์กํ๊ณ ๊ฐ๋ ฅํ AI ์์คํ ์ ๊ตฌ์ถํ๋ ๋ฐ ํ์ํ ํ๋ถํ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
๋ง์ฐฌ๊ฐ์ง๋ก ์๋์ฐจ์ ๋น์ ํ๋ฉด, ๊ธฐ๋ฅ์ด ๋ ๋ค์ํ๊ณ ๊ฐ๋ ฅํ ๊ณ ์ฑ๋ฅ ์ธ์ฅ GPS ๊ธฐ๊ธฐ์ ๊ฐ์ต๋๋ค.
2. ๋น๊ต: ๋ฌด์์ด ์ด๋ป๊ฒ ๋ค๋ฅธ๊ฐ?
ํญ๋ชฉ | ๐ฑ Spring AI | ๐ LangChain4j |
---|---|---|
ํต์ฌ ์ฒ ํ | "AI ๊ธฐ๋ฅ์ ์คํ๋ง๋ต๊ฒ" <br> ์คํ๋ง ์ํ๊ณ์์ ์๋ฒฝํ ํตํฉ | "๊ฐ๋ ฅํ AI ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ์ถ" <br> ๋ค์ํ ๊ธฐ๋ฅ๊ณผ ์ ์ฐ์ฑ ์ ๊ณต |
๊ฐ๋ฐ ์ฃผ์ฒด | ์คํ๋ง ํ (VMware/Pivotal) | ์ปค๋ฎค๋ํฐ ์ฃผ๋ ์คํ์์ค |
ํตํฉ ์์ค | ์ต์ (Native). ์คํ๋ง ๊ฐ๋ฐ์์๊ฒ ๋งค์ฐ ์ต์ํ ํจํด ์ ๊ณต | ์ข์. starter ๋ฅผ ํตํด ์คํ๋ง๊ณผ ์ฝ๊ฒ ํตํฉ๋์ง๋ง, ํต์ฌ์ ๋
๋ฆฝ์ |
RAG ๊ตฌ์ฑ | ๋งค์ฐ ๊ฐ๊ฒฐ. ์๋ ์ค์ ๊ธฐ๋ฐ์ผ๋ก ๋น ๋ฅด๊ฒ ๊ตฌํ ๊ฐ๋ฅ | ๋งค์ฐ ๊ฐ๋ ฅ. ๋ณต์กํ๊ณ ์ธ๋ฐํ ํ์ดํ๋ผ์ธ ์ ์ด์ ์ ๋ฆฌ |
์ ์ฐ์ฑ | ์คํ๋ง ์ํ๊ณ์ ๊ฐํ๊ฒ ์์กด | ๋ ๋ฆฝ์ . ์ด๋ค Java ํ๋ก์ ํธ์์๋ ์ฌ์ฉ ๊ฐ๋ฅ |
๊ธฐ๋ฅ ๋ฒ์ | ํต์ฌ ๊ธฐ๋ฅ(Chat, RAG)์ ์ง์ค | ๊ด๋ฒ์ํจ (๋ณต์กํ ์ฒด์ธ, ์์จ ์์ด์ ํธ ๋ฑ) |
3. ์์ ์ฝ๋: RAG(๊ฒ์ ์ฆ๊ฐ ์์ฑ) ๊ตฌํ ๋น๊ต
๊ฐ์ฅ ๋ํ์ ์ธ AI ๊ธฐ์ ์ธ RAG๋ฅผ ๊ตฌํํ๋ ์ฝ๋๋ฅผ ํตํด ๋ ํ๋ ์์ํฌ์ ์ฐจ์ด๋ฅผ ์ง์ ํ์ธํด ๋ณด๊ฒ ์ต๋๋ค.
๐ฑ Spring AI ์์
application.properties
์ ํ์ํ ์ ๋ณด๋ฅผ ๋ชจ๋ ์ค์ ํ๋ฉด, ์ฝ๋๋ ๋ฏฟ์ ์ ์์ ๋งํผ ๊ฐ๊ฒฐํด์ง๋๋ค.
application.properties
# ๋ชจ๋ธ ์ค์
spring.ai.openai.api-key=${OPENAI_API_KEY}
spring.ai.openai.chat.options.model=gpt-4o
# ๋ฒกํฐ DB ์ค์ (PGVector ์ฌ์ฉ ์์)
spring.ai.vectorstore.postgres.host=localhost
spring.ai.vectorstore.postgres.database=mydb
# ...๊ธฐํ ์ ์ ์ ๋ณด
RagService.java
@Service
public class RagService {
private final ChatClient chatClient;
private final VectorStore vectorStore;
// ๋ชจ๋ Bean์ด ์๋์ผ๋ก ๊ตฌ์ฑ๋์ด ์ฃผ์
๋ฉ๋๋ค.
@Autowired
public RagService(ChatClient chatClient, VectorStore vectorStore) {
this.chatClient = chatClient;
this.vectorStore = vectorStore;
}
public String answer(String question) {
// 1. VectorStore์์ ์ ์ฌ๋ ๊ฒ์
List<Document> similarDocs = vectorStore.similaritySearch(
SearchRequest.query(question).withTopK(5)
);
// 2. ๊ฒ์๋ ๋ด์ฉ์ ๊ธฐ๋ฐ์ผ๋ก ํ๋กฌํํธ ์์ฑ
String documents = similarDocs.stream()
.map(Document::getContent)
.collect(Collectors.joining("\n"));
PromptTemplate promptTemplate = new PromptTemplate("""
์ฃผ์ด์ง ๋ฌธ์ ๋ด์ฉ์ ๋ฐํ์ผ๋ก ์ง๋ฌธ์ ๋ต๋ณํด์ฃผ์ธ์.
๋ฌธ์: {documents}
์ง๋ฌธ: {question}
""");
Prompt prompt = promptTemplate.create(Map.of(
"documents", documents,
"question", question
));
// 3. LLM ํธ์ถ
return chatClient.call(prompt).getResult().getOutput().getContent();
}
}
ํน์ง: ๋ง์น Spring Data JPA๋ฅผ ์ฌ์ฉํ๋ฏ, ์ค์ ์ ์ธ๋ถํํ๊ณ ์ฝ๋์์๋ ์ธํฐํ์ด์ค๋ฅผ ์ฃผ์ ๋ฐ์ ํต์ฌ ๋ก์ง์๋ง ์ง์คํฉ๋๋ค.
๐ LangChain4j ์์ (Spring Boot Starter ์ฌ์ฉ)
LangChain4j๋ starter
๋ฅผ ํตํด ์๋ ์ค์ ์ ์ง์ํ์ง๋ง, AiService
๋ผ๋ ์ ์ธ์ ์ธํฐํ์ด์ค๋ฅผ ํตํด ๋ก์ง์ ๊ตฌ์ฑํ๋ ๋
ํนํ๊ณ ๊ฐ๋ ฅํ ๋ฐฉ์์ ์ ๊ณตํฉ๋๋ค.
application.properties
# langchain4j ์ค์ ์ ๋ค์์คํ์ด์ค๊ฐ ๋ค๋ฆ
๋๋ค.
langchain4j.chat-model.provider=openai
langchain4j.openai.chat-model.model-name=gpt-4o
# ...๊ธฐํ ์ค์
Assistant.java
(AI ์๋น์ค ์ธํฐํ์ด์ค)
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
// ์ธํฐํ์ด์ค๋ง์ผ๋ก RAG ๋ก์ง์ ์ ์ํฉ๋๋ค.
public interface Assistant {
@SystemMessage("""
You are a helpful assistant. Answer the following question
based on the provided context: {{documents}}
""")
String chat(@UserMessage String question, @V("documents") String documents);
}
RagService.java
@Service
public class RagService {
// AiServices๊ฐ ์ธํฐํ์ด์ค์ ๊ตฌํ์ฒด๋ฅผ ์๋์ผ๋ก ๋ง๋ค์ด์ค๋๋ค.
private final Assistant assistant;
private final ContentRetriever contentRetriever; // EmbeddingStoreContentRetriever๊ฐ ์ฃผ์
๋จ
@Autowired
public RagService(Assistant assistant, ContentRetriever contentRetriever) {
this.assistant = assistant;
this.contentRetriever = contentRetriever;
}
public String answer(String question) {
// 1. ContentRetriever๋ก ๊ด๋ จ ๋ฌธ์ ๊ฒ์
List<Content> relevantContent = contentRetriever.retrieve(question);
String documents = relevantContent.stream()
.map(Content::text)
.collect(Collectors.joining("\n\n"));
// 2. AiService ํธ์ถ
return assistant.chat(question, documents);
}
}
ํน์ง:
AiService
๋ฅผ ํตํด AI์ ์ํธ์์ฉํ๋ ๋ก์ง์ ์ ์ธ์ ์ผ๋ก ์ ์ํ์ฌ, ๋น์ฆ๋์ค ์ฝ๋์ AI ํ๋กฌํํธ๋ฅผ ๋ถ๋ฆฌํ๋ ์ฐ์ํ ์ ๊ทผ ๋ฐฉ์์ ๋ณด์ฌ์ค๋๋ค.
4. ๊ฒฐ๋ก : ์ธ์ ๋ฌด์์ ์ ํํด์ผ ํ ๊น?
๐ฑ Spring AI๋ฅผ ์ ํํ์ธ์, ๋ง์ฝ:
- ์ด๋ฏธ ์คํ๋ง ์ํ๊ณ์ ๊น์ด ์์กดํ๊ณ ์๋ ํ๋ก์ ํธ์ผ ๊ฒฝ์ฐ
- ์น API์ ์ฑ๋ด, ์์ฝ, ๋ฌธ์ Q&A ๋ฑ 'AI ๊ธฐ๋ฅ'์ ์ถ๊ฐํ๋ ๊ฒ์ด ๋ชฉํ์ผ ๊ฒฝ์ฐ
- ๊ฐ์ฅ ๋น ๋ฅด๊ณ ๊ฐ๊ฒฐํ๊ฒ AI๋ฅผ ์ฐ๋ํ๊ณ ์ถ๊ณ , '์คํ๋ง๋ค์ด' ์ฝ๋ ์คํ์ผ์ ์ ํธํ ๊ฒฝ์ฐ
๐ LangChain4j๋ฅผ ์ ํํ์ธ์, ๋ง์ฝ:
- AI๊ฐ ์ค์ค๋ก ํ๋จํ๊ณ ์ฌ๋ฌ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ๋ ๋ณต์กํ ์์จ ์์ด์ ํธ๊ฐ ํ์ํ ๊ฒฝ์ฐ
- RAG ํ์ดํ๋ผ์ธ์ ๋งค์ฐ ์ธ๋ฐํ๊ฒ ์ ์ดํ๊ฑฐ๋ ๊ณ ๊ธ ๊ฒ์ ์ ๋ต์ ๊ตฌํํด์ผ ํ ๊ฒฝ์ฐ
- ์คํ๋ง์ด ์๋ Quarkus, Micronaut ๋ฑ ๋ค๋ฅธ Java ํ๋ ์์ํฌ์์ ์ฌ์ฉํ ๊ฐ๋ฅ์ฑ์ด ์๋ ๊ฒฝ์ฐ
์ต์ข ์ถ์ฒ
๋๋ถ๋ถ์ ์คํ๋ง ๋ถํธ ์น ์ ํ๋ฆฌ์ผ์ด์ ์๋ Spring AI๋ก ์์ํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค.
๊ฐ๋ฐ ๊ฒฝํ์ด ๋งค์ฐ ๋ฐ์ด๋๊ณ , ์ผ๋ฐ์ ์ธ AI ์ฐ๋ ์๋๋ฆฌ์ค๋ ๋ชจ๋ ์ปค๋ฒํ ์ ์์ต๋๋ค. ๋ง์ฝ ํ๋ก์ ํธ๊ฐ ๊ณ ๋ํ๋์ด Spring AI๋ง์ผ๋ก ๋ถ์กฑํ ํน์ ๊ธฐ๋ฅ์ด ํ์ํด์ง๋ค๋ฉด, ๊ทธ๋ ๊ฐ์ ๊ทธ ๋ถ๋ถ๋ง LangChain4j ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐ๋ก ๋์ ํ๋ ํ์ด๋ธ๋ฆฌ๋ ์ ๋ต์ ๊ณ ๋ คํด๋ณผ ์ ์์ต๋๋ค.
'spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
- Total
- Today
- Yesterday
- MockMvcTester
- Controller Testing
- pessimistic lock
- org.asciidoctor.jvm.convert
- ํฐ์บฃ ๋ก๊ทธํ์ผ ์๋ ์ญ์
- ContentCachingRequestWrapper caching # ContentCachingRequestWrapper file upload
- LangChain4j
- ๋ฆฌ๋ ์ค์์ mysql ๋ฐฑ์
- sql import
- ๋ฆฌ๋ ์ค ํฐ์บฃ logrotate
- asciidoctorExtensions
- teefilter file upload error
- ๋ฆฌ๋ ์ค sql ๋ฐฑ์ ๋คํ ๋ง๋ค๊ธฐ
- Job Lock
- Spring MockMvc
- ๋ฆฌ๋ ์ค mysql ๋ฐฑ์
- mysql dump sql import
- Spring Boot
- ๋ฆฌ๋ ์ค mysql cron
- ๋ฉํฐ ์ธ์คํด์ค
- Could not find org.ysb33r.gradle:grolifant:0.16.1
- url๊ตฌ์กฐ
- ํฐ์บฃ ๋ก๊ทธํ์ผ ์๋์ญ์
- asciidoctor sourceDir
- ContentCachingRequestWrapper caching error
- ๋ฆฌ๋ ์ค ํ์ผ ์ธ๋ฑ์ค ํ์ธ
- spring test
- RAG
- ๋ฆฌ๋ ์ค ํฐ์บฃ ๋ก๊ทธ๊ด๋ฆฌ
- springai
์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 |