# Part 7.5: LLM 애플리케이션 개발과 LangChain **⬅️ 이전 시간: [Part 7: 딥러닝 기초와 PyTorch](./part_7_deep_learning.md)** | **➡️ 다음 시간: [Part 8: FastAPI를 이용한 모델 서빙](./part_8_model_serving_with_fastapi.md)** --- ## 📜 실습 코드 바로가기 - **`part_7_5_llm_application_development.py`**: [바로가기](./source_code/part_7_5_llm_application_development.py) - 본 파트에서 다루는 LangChain RAG 파이프라인 예제 코드를 직접 실행하고 수정해볼 수 있습니다. --- ## 1. 거대 언어 모델(LLM)의 발전과 새로운 패러다임 최근 몇 년간 딥러닝 분야, 특히 자연어 처리(NLP) 분야는 [거대 언어 모델(LLM)](./glossary.md#llm-large-language-model)의 등장으로 인해 혁명적인 변화를 겪고 있습니다. GPT-3, LLaMA, PaLM과 같은 모델들은 수십억 개에서 수천억 개의 파라미터를 가지며, 방대한 양의 텍스트 데이터로 사전 훈련(pre-training)되었습니다. 이러한 LLM들은 단순히 텍스트를 생성하는 것을 넘어, 번역, 요약, 질의응답, 코드 생성 등 다양한 작업에서 인간에 가까운 성능을 보여주며, 이는 '파운데이션 모델(Foundation Model)'이라는 새로운 패러다임의 등장을 이끌었습니다. 파운데이션 모델은 특정 작업에 국한되지 않고, 다양한 다운스트림 작업(downstream task)에 약간의 [미세조정(fine-tuning)](./glossary.md#미세조정fine-tuning)이나 [프롬프트 엔지니어링(prompt engineering)](./glossary.md#프롬프트-엔지니어링prompt-engineering)만으로도 적용될 수 있는 범용적인 모델을 의미합니다. LLM의 등장은 개발자들이 AI 애플리케이션을 구축하는 방식에도 큰 변화를 가져왔습니다. 과거에는 특정 작업을 위해 모델을 처음부터 훈련하거나 복잡한 파이프라인을 구축해야 했다면, 이제는 강력한 LLM을 '두뇌'로 활용하고, 다양한 외부 도구 및 데이터와 연결하여 훨씬 더 복잡하고 지능적인 애플리케이션을 손쉽게 개발할 수 있게 되었습니다. ## 2. LLM 애플리케이션의 핵심, LangChain LLM을 기반으로 애플리케이션을 개발할 때, 단순히 모델에 질문하고 답변을 받는 것을 넘어, 외부 데이터베이스를 참조하거나, 특정 API를 호출하거나, 여러 단계를 거쳐 복잡한 추론을 수행해야 하는 경우가 많습니다. 이러한 과정은 생각보다 복잡하며, 많은 반복적인 코드를 요구합니다. **[LangChain](./glossary.md#langchain)**은 바로 이러한 문제점을 해결하기 위해 등장한 프레임워크입니다. LangChain은 LLM을 활용한 애플리케이션 개발을 위한 강력하고 유연한 도구 모음을 제공하며, 개발자가 LLM을 외부 데이터 소스나 계산 로직과 쉽게 '연결(chain)'할 수 있도록 돕습니다. ### LangChain의 핵심 컴포넌트 LangChain은 여러 핵심 컴포넌트들의 조합으로 이루어져 있으며, 이를 통해 모듈식으로 애플리케이션을 구성할 수 있습니다. - **Models**: 다양한 종류의 언어 모델(LLM, Chat Models, Text Embedding Models 등)을 표준화된 인터페이스로 제공합니다. - **Prompts**: 사용자 입력과 추가적인 정보를 결합하여 모델에 전달할 프롬프트를 동적으로 생성하고 관리합니다. - **Chains**: 가장 핵심적인 개념으로, LLM 호출과 다른 컴포넌트(예: 다른 Chain, 외부 API, 데이터 처리 로직 등)들을 순차적으로 연결하여 복잡한 작업을 수행하는 파이프라인을 구성합니다. - **Indexes & Retrievers**: 외부 데이터 소스를 LLM이 활용할 수 있도록 구조화하고(Indexing), 사용자의 질문과 관련된 정보를 효율적으로 찾아오는(Retrieval) 기능을 담당합니다. - **Agents**: LLM을 '추론 엔진'으로 사용하여, 어떤 도구(Tool)를 어떤 순서로 사용해야 할지 스스로 결정하고 작업을 수행하도록 만듭니다. LangChain을 사용하면 개발자는 LLM 자체의 한계를 넘어, 외부 세계의 정보와 상호작용하는 훨씬 더 강력하고 실용적인 애플리케이션을 만들 수 있습니다. ## 2.5. RAG의 핵심 부품: 벡터 데이터베이스 (Vector Database) RAG 파이프라인을 구축하려면 대량의 텍스트 조각(Chunk)들을 벡터로 변환하고, 사용자 질문 벡터와 가장 유사한 벡터들을 빠르게 찾아내야 합니다. 이 과정을 효율적으로 처리해주는 것이 바로 **[벡터 데이터베이스(Vector Database)](./glossary.md#벡터-데이터베이스vector-database)**입니다. > **💡 비유: '의미로 책을 찾는 도서관 사서'** > > 일반적인 데이터베이스가 '정확한 제목'이나 '저자'로 책을 찾는다면, 벡터 데이터베이스는 "사랑과 희생에 관한 슬픈 이야기"처럼 **추상적인 의미**로 책을 찾아주는 똑똑한 사서와 같습니다. > - **인덱싱(책 정리)**: 사서는 도서관의 모든 책(Chunk)을 읽고, 각 책의 핵심 내용을 요약한 '의미 태그(Vector)'를 붙여 특수한 서가(DB)에 정리합니다. > - **검색(책 찾기)**: 사용자가 질문하면, 사서는 질문의 '의미'를 파악하고, 서가에서 가장 비슷한 '의미 태그'를 가진 책들을 순식간에 찾아 건네줍니다. 수백만, 수억 개의 벡터 속에서 가장 가까운 벡터를 찾는 것은 엄청난 계산량을 요구하는 어려운 문제입니다('차원의 저주'). 벡터 데이터베이스는 **ANN(Approximate Nearest Neighbor, 근사 최근접 이웃)** 같은 알고리즘을 사용하여, 100% 정확하지는 않지만 매우 빠른 속도로 충분히 정확한 결과를 찾아줍니다. RAG에서 주로 사용되는 벡터 데이터베이스는 다음과 같습니다. - **FAISS (Facebook AI Similarity Search)** - **특징**: Facebook(Meta)에서 개발한, 매우 빠른 유사도 검색에 특화된 **라이브러리**입니다. - **장점**: 인메모리(in-memory) 기반으로 작동하여 속도가 매우 빠르고, 별도의 서버 설치 없이 쉽게 사용할 수 있어 프로토타이핑이나 연구에 적합합니다. - **단점**: 기본적으로 데이터를 메모리에 저장하므로, 프로세스가 종료되면 데이터가 사라집니다. (파일로 저장하고 불러올 수는 있습니다.) - **Chroma (또는 ChromaDB)** - **특징**: AI 네이티브(AI-native)를 표방하는 오픈소스 **벡터 데이터베이스**입니다. - **장점**: 데이터를 디스크에 영속적으로(persistently) 저장하며, 클라이언트-서버 모드로 실행할 수 있어 여러 애플리케이션이 동시에 접근하는 실제 서비스 환경에 더 적합합니다. SDK가 사용하기 쉽게 설계되었습니다. - **단점**: FAISS보다는 설정이 조금 더 필요할 수 있습니다. 이 외에도 Pinecone, Weaviate, Milvus 등 다양한 상용/오픈소스 벡터 데이터베이스가 있으며, 각기 다른 특징과 장단점을 가지고 있습니다. ## 3. 외부 지식의 통합: 검색 증강 생성 (Retrieval-Augmented Generation, RAG) LLM은 방대한 지식을 학습했지만, 몇 가지 본질적인 한계를 가집니다. 1. **지식의 최신성 문제(Knowledge Cut-off)**: 모델이 훈련된 특정 시점 이후의 정보는 알지 못합니다. 2. **[환각(Hallucination)](./glossary.md#환각hallucination)**: 사실이 아닌 내용을 그럴듯하게 지어내는 경향이 있습니다. 3. **정보 출처의 부재**: 답변이 어떤 근거로 생성되었는지 알기 어렵습니다. 4. **사적인 데이터 접근 불가**: 기업 내부 문서나 개인적인 파일과 같은 비공개 데이터에 대해서는 알지 못합니다. **[검색 증강 생성(RAG)](./glossary.md#rag-retrieval-augmented-generation)**는 이러한 한계를 극복하기 위한 매우 효과적인 방법론입니다. RAG의 핵심 아이디어는 LLM이 답변을 생성하기 전에, 먼저 외부 지식 소스(Knowledge Base)에서 사용자의 질문과 관련된 정보를 검색하고, 검색된 정보를 LLM에게 '참고 자료'로 함께 제공하는 것입니다. ### RAG의 작동 방식 RAG 파이프라인은 크게 **Indexing**과 **Retrieval & Generation** 두 단계로 나뉩니다. 1. **Indexing (인덱싱)** - **Load**: PDF, TXT, HTML 등 다양한 형식의 외부 문서를 불러옵니다. - **Split (Chunking)**: 불러온 문서를 LLM이 처리하기 좋은 크기의 작은 조각(Chunk)으로 나눕니다. 이 과정이 바로 **'Chunking'**입니다. - **Embed**: 각 Chunk를 텍스트 임베딩 모델을 사용하여 고차원의 벡터(Vector)로 변환합니다. 이 벡터는 해당 Chunk의 의미적인 내용을 담고 있습니다. - **Store**: 변환된 벡터와 원본 Chunk 텍스트를 특수한 데이터베이스인 '벡터 저장소(Vector Store)'에 저장합니다. 2. **Retrieval & Generation (검색 및 생성)** - **Retrieve**: 사용자의 질문(Query) 또한 [임베딩 모델](./glossary.md#임베딩-모델embedding-model)을 통해 벡터로 변환한 뒤, 벡터 저장소에서 이와 유사한(가까운) 벡터를 가진 Chunk들을 찾아냅니다. - **Generate**: 검색된 Chunk들을 사용자의 원본 질문과 함께 프롬프트에 담아 LLM에 전달합니다. LLM은 이 정보를 바탕으로 신뢰성 높고 정확한 답변을 생성합니다. ## 4. RAG의 핵심, 문서 분할 (Document Splitting / Chunking) RAG 파이프라인의 성능은 '얼마나 관련성 높은 정보를 잘 찾아오는가'에 크게 좌우되며, 이는 Chunking 전략에 직접적인 영향을 받습니다. 문서를 어떻게 의미 있는 단위로 잘 나누는가(Chunking)가 RAG 시스템 전체의 성공을 결정하는 핵심 요소 중 하나입니다. ### Chunking이 왜 중요한가? - **컨텍스트 유지**: 너무 작게 자르면 문맥 정보가 손실되고, 너무 크게 자르면 관련 없는 정보가 많이 포함되어 LLM의 집중력을 방해할 수 있습니다. - **검색 정확도**: Chunk가 의미적으로 완결된 단위일 때, 사용자의 질문과 관련된 Chunk를 더 정확하게 찾아올 수 있습니다. - **비용 및 성능 효율성**: 대부분의 LLM API는 입력 토큰 길이에 따라 비용이 책정됩니다. 적절한 크기의 Chunk는 불필요한 비용을 줄이고, 모델의 응답 속도를 향상시킵니다. ### 주요 Chunking 전략 다양한 Chunking 전략이 있으며, 문서의 종류와 구조에 따라 적절한 방법을 선택해야 합니다. 1. **고정 크기 분할 (Fixed-size Chunking)** - 가장 간단한 방식으로, 문서를 정해진 글자 수나 토큰 수로 자릅니다. - **장점**: 구현이 매우 쉽습니다. - **단점**: 문장의 중간이나 단어의 중간에서 잘릴 수 있어 의미 단위가 깨질 위험이 큽니다. - **개선**: Chunk 간에 일부 내용을 겹치게(Overlap) 설정하여, 문맥이 끊어지는 문제를 어느 정도 완화할 수 있습니다. `CharacterTextSplitter`가 대표적입니다. 2. **재귀적 문자 분할 (Recursive Character Text Splitting)** - 가장 널리 사용되는 방법 중 하나입니다. `["\n\n", "\n", " ", ""]` 와 같이 여러 종류의 구분자(separator)를 순서대로 시도하며 문서를 분할합니다. - 큰 의미 단위(단락)부터 시작하여, Chunk가 원하는 크기보다 크면 더 작은 의미 단위(문장)으로 나누는 방식으로 재귀적으로 작동합니다. - **장점**: 고정 크기 분할보다 의미 단위를 더 잘 보존하면서, 원하는 Chunk 크기를 비교적 일정하게 유지할 수 있습니다. `RecursiveCharacterTextSplitter`가 대표적입니다. 3. **구문 기반 분할 (Syntax-aware Chunking)** - 문서의 구조나 특정 프로그래밍 언어의 구문을 이해하고, 이를 바탕으로 Chunk를 나눕니다. - 예를 들어, Markdown 문서의 경우 제목(#), 목록(-), 코드 블록(```) 등을 기준으로 분할하거나, Python 코드의 경우 클래스나 함수 단위로 분할할 수 있습니다. - **장점**: 매우 높은 수준의 의미적 일관성을 유지할 수 있습니다. - **단점**: 특정 문서 유형이나 언어에 대한 파서(parser)가 필요하며, 구현이 복잡합니다. `MarkdownTextSplitter`, `PythonCodeTextSplitter` 등이 있습니다. 4. **에이전틱 분할 (Agentic Chunking)** - 최근 제안된 가장 진보된 방식으로, LLM 자체를 사용하여 최적의 Chunk를 결정하는 방법입니다. - 문서의 각 문장이나 섹션에 대해 "이 내용을 독립적으로 이해할 수 있는가?" 또는 "이웃한 내용과 합쳐져야 더 나은 컨텍스트를 형성하는가?"와 같은 질문을 LLM에게 던져 분할 여부를 결정합니다. - **장점**: 문서의 내용에 따라 동적으로 최적의 Chunk를 생성하여 매우 높은 품질을 보장합니다. - **단점**: Chunking 과정에서 LLM API 호출 비용이 발생하며, 처리 속도가 느립니다. 어떤 Chunking 전략이 가장 좋은지는 정답이 없습니다. 문서의 특성(텍스트, 코드, 테이블 등), RAG 시스템의 목적, 그리고 가용한 리소스(비용, 시간)를 종합적으로 고려하여 최적의 전략을 선택하는 것이 중요합니다. ## 5. 실습: LangChain으로 간단한 RAG 파이프라인 만들기 이제 LangChain을 사용하여 간단한 RAG 시스템을 구축하는 예제를 살펴보겠습니다. 우리는 텍스트 파일을 불러와 Chunking하고, 이를 벡터 저장소에 저장한 뒤, 사용자 질문에 가장 관련성 높은 정보를 찾아 답변을 생성하는 과정을 구현할 것입니다. 이번 예제에서는 OpenAI의 모델 대신, **Hugging Face의 오픈소스 모델**을 사용하여 임베딩을 생성하고, **FAISS**와 **Chroma** 벡터 저장소를 모두 활용하는 방법을 보여줍니다. ```python # 필요한 라이브러리 설치 # !pip install langchain langchain-openai langchain-community faiss-cpu chromadb tiktoken sentence-transformers import os from langchain_community.document_loaders import TextLoader from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_openai import ChatOpenAI from langchain.text_splitter import CharacterTextSplitter from langchain_community.vectorstores import FAISS, Chroma from langchain.chains import RetrievalQA # (주의: 이 코드는 OpenAI LLM을 사용하므로, OPENAI_API_KEY 환경변수 설정이 필요합니다.) # os.environ["OPENAI_API_KEY"] = "YOUR_API_KEY" # --- 1. 문서 로드 및 분할 --- # RAG를 시연하기 위해 방금 생성한 샘플 문서를 로드합니다. loader = TextLoader("./docker/ai lecture/sample_document.txt", encoding='utf-8') documents = loader.load() text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=100) docs = text_splitter.split_documents(documents) print(f"문서 조각(Chunk) 수: {len(docs)}") # --- 2. 임베딩 모델 준비 --- # Hugging Face의 오픈소스 한국어 임베딩 모델을 사용합니다. # https://huggingface.co/jhgan/ko-sroberta-multitask model_name = "jhgan/ko-sroberta-multitask" model_kwargs = {'device': 'cpu'} encode_kwargs = {'normalize_embeddings': True} hf_embeddings = HuggingFaceEmbeddings( model_name=model_name, model_kwargs=model_kwargs, encode_kwargs=encode_kwargs ) # --- 3. 벡터 저장소(Vector Store)에 저장 --- # 방법 A: FAISS (인메모리, 임시 저장) # 가장 빠르고 간단하게 시작할 수 있습니다. db_faiss = FAISS.from_documents(docs, hf_embeddings) retriever_faiss = db_faiss.as_retriever() # 방법 B: Chroma (영속적 저장) # 데이터를 디스크에 저장하여 나중에 다시 불러와 사용할 수 있습니다. persist_directory = "./chroma_db" db_chroma = Chroma.from_documents(docs, hf_embeddings, persist_directory=persist_directory) retriever_chroma = db_chroma.as_retriever() # --- 4. RAG 체인 생성 및 실행 --- # LLM은 OpenAI의 gpt-3.5-turbo를 사용합니다. llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0) # FAISS를 사용한 RAG qa_chain_faiss = RetrievalQA.from_chain_type( llm=llm, chain_type="stuff", retriever=retriever_faiss, ) # Chroma를 사용한 RAG qa_chain_chroma = RetrievalQA.from_chain_type( llm=llm, chain_type="stuff", retriever=retriever_chroma, ) # --- 5. 질문 및 답변 --- query = "AI 비전공자를 위한 최고의 입문서는 무엇인가?" # FAISS 기반 RAG 실행 print("\n--- [FAISS 기반 RAG] ---") response_faiss = qa_chain_faiss.invoke(query) print(response_faiss["result"]) # Chroma 기반 RAG 실행 print("\n--- [Chroma 기반 RAG] ---") response_chroma = qa_chain_chroma.invoke(query) print(response_chroma["result"]) # Chroma DB 영속성 확인 # 위에서 생성한 Chroma 객체를 메모리에서 삭제했다고 가정 del db_chroma # 디스크에서 다시 불러오기 db_chroma_loaded = Chroma(persist_directory=persist_directory, embedding_function=hf_embeddings) retriever_chroma_loaded = db_chroma_loaded.as_retriever() qa_chain_chroma_loaded = RetrievalQA.from_chain_type( llm=llm, chain_type="stuff", retriever=retriever_chroma_loaded ) print("\n--- [Chroma DB 로드 후 RAG] ---") response_chroma_loaded = qa_chain_chroma_loaded.invoke(query) print(response_chroma_loaded["result"]) ``` 이 예제는 RAG의 가장 기본적인 흐름을 보여줍니다. 실제 애플리케이션에서는 문서의 종류에 맞는 `Loader`와 `TextSplitter`를 선택하고, `retriever`의 검색 옵션을 조정하며, `chain_type`을 변경하는 등 다양한 방식으로 파이프라인을 고도화할 수 있습니다. --- ## 6. 또 다른 선택지: LlamaIndex LangChain이 LLM 애플리케이션을 위한 '범용 스위스 칼'이라면, **LlamaIndex**는 'RAG 전문 수술 도구'에 비유할 수 있습니다. LlamaIndex는 LLM이 외부 데이터를 더 쉽게 활용할 수 있도록, 데이터의 수집(ingestion), 인덱싱(indexing), 검색(retrieval) 과정에 특화된 기능들을 매우 상세하고 강력하게 제공하는 데이터 프레임워크입니다. ### LangChain vs. LlamaIndex | 구분 | LangChain | LlamaIndex | |:--- |:--- |:--- | | **핵심 철학** | LLM을 중심으로 다양한 컴포넌트(Tool, Chain)를 연결하는 범용 프레임워크 | 데이터를 중심으로 LLM과 연결하는 데이터 프레임워크 | | **주요 강점** | 에이전트(Agent)와 다양한 종류의 체인(Chain)을 이용한 복잡한 워크플로우 생성 | 고성능 RAG를 위한 고급 인덱싱, 데이터 수집, 검색 전략 제공 | | **주요 사용 사례** | 챗봇, 자율 에이전트, API 연동 등 | 고도화된 RAG, 지식 관리 시스템, 문서 기반 질의응답 | 두 프레임워크는 경쟁 관계라기보다는 상호 보완적이며, 실제로 LlamaIndex의 데이터 인덱싱/검색 기능을 LangChain의 에이전트와 함께 사용하는 경우도 많습니다. ### 실습: LlamaIndex와 오픈소스 모델로 RAG 파이프라인 만들기 이번에는 LlamaIndex를 사용하여 RAG 파이프라인을 구축해 보겠습니다. 임베딩 모델뿐만 아니라 LLM까지 Hugging Face의 무료 추론 API를 사용하여, 완전한 오픈소스 스택으로 RAG를 구현하는 방법을 알아봅니다. ```python # 필요한 라이브러리 설치 # !pip install llama-index llama-index-embeddings-huggingface llama-index-vector-stores-chroma llama-index-llms-huggingface import os import chromadb from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, StorageContext from llama_index.vector_stores.chroma import ChromaVectorStore from llama_index.embeddings.huggingface import HuggingFaceEmbedding from llama_index.llms.huggingface import HuggingFaceInferenceAPI from llama_index.core import Settings # --- 0. Hugging Face API 토큰 설정 --- # Hugging Face Hub(hf.co)에서 무료 API 토큰을 발급받아 아래에 입력하거나 환경변수로 설정하세요. # HF_TOKEN = "YOUR_HUGGINGFACE_API_TOKEN" # os.environ["HF_TOKEN"] = HF_TOKEN # --- 1. LLM 및 임베딩 모델 설정 --- # Settings를 사용하여 전역적으로 모델을 설정할 수 있습니다. # LLM: Hugging Face의 공개 모델을 Inference API를 통해 사용합니다. # https://huggingface.co/google/gemma-2-9b-it Settings.llm = HuggingFaceInferenceAPI( model_name="google/gemma-2-9b-it", tokenizer_name="google/gemma-2-9b-it" ) # Embedding Model: LangChain 예제와 동일한 한국어 모델 사용 Settings.embed_model = HuggingFaceEmbedding( model_name="jhgan/ko-sroberta-multitask" ) # --- 2. 데이터 로드 --- # SimpleDirectoryReader는 디렉토리 내의 모든 문서를 편리하게 불러옵니다. documents = SimpleDirectoryReader( input_files=["./docker/ai lecture/sample_document.txt"] ).load_data() print(f"로드된 문서 수: {len(documents)}") # --- 3. 인덱싱 및 저장 (ChromaDB 사용) --- # ChromaDB 클라이언트 초기화 및 컬렉션 생성 db = chromadb.PersistentClient(path="./chroma_db_llamaindex") chroma_collection = db.get_or_create_collection("rag_tutorial") # 벡터 저장소 설정 vector_store = ChromaVectorStore(chroma_collection=chroma_collection) # 데이터 인덱싱 storage_context = StorageContext.from_defaults(vector_store=vector_store) index = VectorStoreIndex.from_documents( documents, storage_context=storage_context ) # --- 4. 쿼리 엔진 생성 및 질문 --- # 인덱스로부터 쿼리 엔진을 생성합니다. query_engine = index.as_query_engine(streaming=True) query = "AI 비전공자를 위한 최고의 입문서는 무엇인가?" print(f"\n--- [LlamaIndex + Gemma-2 기반 RAG] ---") print(f"질문: {query}") print(f"답변: ", end="") # 스트리밍 형태로 답변 받기 streaming_response = query_engine.query(query) streaming_response.print_response_stream() print() ``` 이 코드는 LlamaIndex가 어떻게 데이터 소스, 임베딩 모델, 벡터 저장소, LLM을 유연하게 조합하여 RAG 파이프라인을 구성하는지 보여줍니다. `Settings`를 통해 기본 컴포넌트를 설정하고, `SimpleDirectoryReader`로 데이터를 쉽게 로드하며, `VectorStoreIndex`로 인덱싱과 검색 과정을 아름답게 추상화하는 LlamaIndex의 디자인 철학을 엿볼 수 있습니다. LangChain, LlamaIndex와 같은 프레임워크와 RAG, Chunking, 벡터 데이터베이스에 대한 이해는 최신 AI 트렌드를 따라가고, LLM의 잠재력을 최대한 활용하는 지능형 애플리케이션을 개발하는 데 있어 필수적인 역량이 될 것입니다.