글

Callback와 로깅 — LangChain 내부 들여다보기

📌 3줄 요약 · 콜백(Callback) 은 LangChain이 실행되는 중간중간 특정 시점마다 내가 지정한 함수를 자동으로 불러 주는 장치예요. · 이 콜백을 이용하면 체인이 언제 시작하고, 어떤 프롬프트가 들어가고, 어떤 답이 나왔는지 를 실시간으로 들여다보고 로깅 할 수 있습니다. · 덕분에 "왜 이런 답이 나왔지?"를 추적하는 디버깅과 모니터링 이 훨씬 쉬워집니다. 📖 목차 콜백이 왜 필요할까 콜백은 언제 불릴까 — 이벤트라는 개념 로깅과 콜백은 어떻게 연결되나 코드로 보는 콜백 핸들러 대표적인 콜백 이벤트 한눈에 실무 팁 자주 묻는 질문(FAQ) 🚀 체인 시작 → 🔔 이벤트 발생 → 🪝 콜백 호출 → 📝 기록·로깅 체인을 만들어 실행하면, 겉으로는 질문을 넣으면 답이 나오는 단순한 상자처럼 보입니다. 하지만 그 상자 안에서는 프롬프트가 조립되고, 모델이 호출되고, 출력이 정리되는 여러 단계가 순서대로 벌어지고 있어요. 이 내부 과정을 밖에서 들여다볼 수 있게 해 주는 장치가 바로 콜백(Callback) 입니다. 오늘은 콜백이 무엇이고 왜 유용한지, 그리고 이를 활용한 로깅 이 어떻게 이뤄지는지 차근차근 살펴보겠습니다. 🤔 콜백이 왜 필요할까 체인이 예상과 다른 답을 내놓았을 때, 우리가 볼 수 있는 건 보통 최종 결과 하나뿐 입니다. 그런데 문제의 원인은 대개 중간에 있어요. 실제로 어떤 프롬프트가 모델에 들어갔는지 , 모델이 어떤 원문을 돌려줬는지 를 모르면 원인을 짚기 어렵습니다. 콜백은 이 보이지 않던 중간 과정을 밖으로 꺼내 주는 역할을 합니다. 체인이 시작될 때, 모델이 호출될 때, 답이 완성될 때처럼 중요한 순간마다 내가 등록해 둔 함수가 자동으로 실행되죠. 그래서 실행 흐름을 기록하고 추적하는 일 이 한결 수월해집니다. 콜백의 핵심은 "실행 중간의 특정 순간마다, 내가 원하는 코드를 끼워 넣을 수 있게 하자" 는 것입...

Streaming — 답변을 실시간으로 흘려보내기

📌 3줄 요약 · 스트리밍(Streaming) 은 모델의 답변을 다 만들어진 뒤 한꺼번에 주는 대신, 생성되는 대로 조금씩 흘려보내는 방식이에요. · LangChain에서는 invoke 대신 stream 을 쓰면, 답변이 토큰 단위로 순서대로 도착합니다(타이핑 효과). · 체감 대기 시간이 크게 줄어 챗봇처럼 즉각 반응하는 UX 를 만들 때 특히 유용합니다. 📖 목차 스트리밍이 왜 필요할까 한 번에 vs 조금씩, 무엇이 다른가 토큰 단위로 흘려보낸다는 것 코드로 보는 stream stream vs invoke vs batch 실무 팁 자주 묻는 질문(FAQ) 🙋 질문 → 🤖 모델 생성 → 💧 토큰이 하나씩 → 🖥️ 화면에 실시간 챗봇에 질문을 던졌을 때, 답이 한 글자씩 타이핑되듯 나타나는 화면을 본 적 있을 거예요. 이건 답변이 다 완성될 때까지 기다렸다가 한꺼번에 보여 주는 게 아니라, 모델이 글자를 만들어 내는 즉시 화면으로 흘려보내기 때문에 가능한 일입니다. 이 방식을 스트리밍(Streaming) 이라고 부릅니다. 오늘은 LangChain에서 스트리밍이 무엇이고 왜 유용한지, 그리고 어떻게 쓰는지 차근차근 살펴보겠습니다. 🤔 스트리밍이 왜 필요할까 LLM은 답변을 앞에서부터 순서대로 한 조각씩 생성합니다. 긴 답변일수록 전체가 완성되기까지 시간이 걸리는데, 완성될 때까지 화면에 아무것도 안 보이면 사용자는 "멈춘 건가?" 하고 답답해집니다. 스트리밍은 이 기다리는 시간을 체감상 크게 줄여 줍니다. 첫 글자가 나오기 시작하는 순간부터 화면에 하나씩 채워지니, 실제 전체 생성 시간이 같아도 훨씬 빠르게 느껴지죠. 특히 대화형 챗봇처럼 반응 속도가 중요한 서비스 에서는 거의 필수적인 요소입니다. 스트리밍의 핵심은 "답을 다 만들 때까지 기다리지 말고, 만들어지는 대로 바로 보여 주자" 는 것입니다. ⚖️ 한 번에 vs 조금씩...

LCEL — LangChain 표현식으로 체인 깔끔하게 잇기

📌 3줄 요약 · LCEL(LangChain Expression Language) 은 여러 단계를 파이프 기호(|) 로 이어 하나의 체인으로 만드는 방식이에요. · 프롬프트 → 모델 → 출력 파서처럼 흐름이 그대로 코드에 보여서 읽기 쉽고 수정도 간편합니다. · 스트리밍·배치·비동기 같은 기능을 따로 구현하지 않아도 체인 전체에서 바로 쓸 수 있습니다. 📖 목차 LCEL이 왜 필요할까 파이프(|)로 잇는다는 발상 체인의 기본 3단 구성 코드로 보는 LCEL LCEL이 공짜로 주는 기능들 실무 팁 자주 묻는 질문(FAQ) 📝 프롬프트 → 🤖 모델 → 🔧 출력 파서 → ✅ 결과 LangChain으로 뭔가를 만들다 보면, 프롬프트를 만들고 모델에 넣고 그 결과를 다시 다듬는 여러 단계 가 반복됩니다. 예전에는 이걸 함수로 하나씩 호출하며 이어 붙였는데, 코드가 길어질수록 흐름을 알아보기 어려웠어요. 이 불편을 깔끔하게 정리한 것이 바로 LCEL(LangChain Expression Language) 입니다. 오늘은 LCEL이 무엇이고 왜 편한지 차근차근 살펴보겠습니다. 🤔 LCEL이 왜 필요할까 LLM 앱은 대부분 여러 단계가 순서대로 이어지는 구조 입니다. 사용자 질문을 받아 프롬프트 틀에 채우고, 그걸 모델에 보내고, 모델이 돌려준 답을 원하는 형태로 정리하는 식이죠. 각 단계를 따로 함수로 부르면 이렇게 됩니다. 단계가 두세 개일 땐 괜찮지만, 중간에 검색이나 조건 분기가 끼면 어디서 무엇이 넘어가는지 한눈에 파악하기 어려워집니다. 게다가 스트리밍이나 병렬 처리를 넣으려면 단계마다 코드를 또 손봐야 하죠. LCEL의 목표는 간단합니다. "단계를 이어 붙이는 일"을 눈에 보이게, 그리고 한 번만 만들자는 것입니다. 🔗 파이프(|)로 잇는다는 발상 LCEL의 핵심은 파이프 기호 | 하나입니다. 리눅스 터미널에서 명령어1 | 명령어2 로 앞 결과를 뒤로 ...

텍스트를 숫자로 바꾸는 원리 — Embedding 이해하기

📌 3줄 요약 · 컴퓨터는 글자 자체를 이해하지 못해서, 텍스트를 숫자 배열 로 바꿔야 다룰 수 있어요. · 임베딩(Embedding) 은 단어·문장의 의미 를 숫자 벡터로 표현하는 기술입니다. · 의미가 비슷한 문장은 벡터도 가까워져서, 검색·추천·RAG의 바탕이 됩니다. 📖 목차 컴퓨터는 글자를 못 읽는다 임베딩의 기본 아이디어 벡터가 '가깝다'는 것의 의미 코드로 감 잡기 어디에 쓰이나 실무 팁 자주 묻는 질문(FAQ) 📝 텍스트 → 🧮 임베딩 모델 → 🔢 숫자 벡터 → 📐 의미 비교 검색창에 "저렴한 노트북"이라고 쳤는데 "가성비 좋은 랩탑" 상품이 딱 나온 적 있으신가요? 글자는 하나도 안 겹치는데 말이죠. 이게 가능한 이유가 바로 임베딩 입니다. 오늘은 텍스트를 숫자로 바꾸는 이 원리를 차근차근 정리해 보겠습니다. 🤖 컴퓨터는 글자를 못 읽는다 사람은 "사과"라는 단어를 보면 빨간 과일을 떠올립니다. 하지만 컴퓨터에게 글자는 그저 기호일 뿐, 의미가 담겨 있지 않아요 . 컴퓨터가 잘 다루는 건 오직 숫자 입니다. 그래서 텍스트를 다루려면 먼저 숫자로 바꿔야 합니다. 가장 단순한 방법은 단어마다 번호를 붙이는 것이지만(사과=1, 배=2…), 이렇게 하면 단어끼리의 의미 관계 가 전혀 담기지 않습니다. 1번과 2번이 가깝다는 게 아무 뜻도 없으니까요. 핵심은 단순히 숫자로 바꾸는 게 아니라, 의미를 담은 숫자 로 바꾸는 것입니다. 💡 임베딩의 기본 아이디어 임베딩 은 단어나 문장을 여러 개의 숫자로 이루어진 벡터 로 바꾸는 기술입니다. 예를 들어 "고양이"라는 단어가 [0.8, -0.2, 0.5, ...] 같은 숫자 배열로 표현되는 식이죠. 이 숫자 하나하나는 사람이 직접 정한 게 아니라, 모델이 방대한 텍스트를 학습하면서 스스로 찾아낸 특징 입니다. 중요한 건 결과입니다. 임베...

벡터 저장소 이해하기 — LangChain Vector Store

📌 3줄 요약 · Vector Store(벡터 저장소) 는 임베딩으로 만든 숫자 벡터를 담아 두고, 의미가 비슷한 조각 을 빠르게 찾아 주는 저장소입니다. · 키워드가 정확히 일치하지 않아도 뜻이 가까운 문서 를 골라내는 유사도 검색 이 핵심 역할입니다. · 잘 저장해 두면 이후 Retriever → RAG 단계에서 질문에 맞는 근거를 손쉽게 가져올 수 있습니다. 📖 목차 벡터 저장소가 필요한 이유 유사도 검색은 어떻게 동작할까 대표적인 벡터 저장소 종류 코드로 저장하고 검색하기 자주 부딪히는 문제 실무 팁 자주 묻는 질문(FAQ) chunk → 임베딩(벡터) → Vector Store 저장 → 유사도 검색 → 관련 조각 반환 지난 글에서 문서를 조각으로 나누고, 그 조각을 임베딩 으로 숫자 벡터로 바꾸는 이야기를 했습니다. 그런데 벡터를 만들기만 해서는 쓸모가 없습니다. 어딘가에 담아 두고 , 나중에 질문이 들어오면 비슷한 벡터를 빠르게 찾아 돌려줄 수 있어야 합니다. 이 역할을 맡는 것이 바로 Vector Store(벡터 저장소) 입니다. 이번 글에서는 벡터 저장소가 왜 필요한지, 유사도 검색이 어떤 원리로 동작하는지, 그리고 실제 코드까지 정리해 보겠습니다. 🗄️ 벡터 저장소가 필요한 이유 일반적인 데이터베이스는 정확히 일치하는 값 을 찾는 데 강합니다. "이름이 홍길동인 행"처럼 조건이 딱 맞아떨어지는 검색이죠. 하지만 문서 검색은 다릅니다. 사용자가 "환불 어떻게 해요?"라고 물어도, 문서에는 "반품 및 대금 반환 절차"라고 적혀 있을 수 있습니다. 단어는 다르지만 뜻은 같은 상황입니다. 핵심은 이렇습니다. 글자가 아니라 '의미'가 가까운 것을 찾는다. 임베딩은 문장의 의미를 숫자 벡터로 표현합니다. 뜻이 비슷한 문장은 벡터 공간에서 서로 가까운 위치 에 놓입니다. 벡터 저장소는 이 벡터들을 모아 두고, 질...

Text Splitter — 문서를 잘 자르는 청킹 전략

📌 3줄 요약 · Text Splitter 는 불러온 긴 문서를 검색·모델 입력에 알맞은 작은 조각(chunk) 으로 나눠 주는 단계입니다. · 무작정 글자 수로 자르면 문맥이 끊기므로, 문단·문장 경계 를 존중하며 나누고 겹침(overlap) 을 조금 두는 것이 핵심입니다. · 조각 크기와 겹침을 잘 잡아 두면 이후 임베딩 → 검색(RAG) 품질이 눈에 띄게 좋아집니다. 📖 목차 왜 문서를 '잘라야' 할까 chunk_size와 chunk_overlap 대표적인 분할 방식 코드로 잘라 보기 자주 부딪히는 문제 실무 팁 자주 묻는 질문(FAQ) 긴 Document → Text Splitter → 작은 chunk 여러 개 → 임베딩 → 검색·답변 지난 글에서 Document Loader 로 자료를 불러왔다면, 이번엔 그 문서를 알맞은 크기로 나누는 이야기입니다. 보고서 한 편, 웹페이지 한 장은 그대로 쓰기엔 너무 깁니다. 모델이 한 번에 읽을 수 있는 양에는 한계가 있고, 검색도 문서 전체보다 필요한 부분 만 골라낼 때 정확합니다. 이 나누는 작업을 맡는 것이 바로 Text Splitter(텍스트 분할기) 입니다. 이번 글에서는 왜 잘라야 하는지, 어떤 기준으로 나누는지, 그리고 실제 코드까지 정리해 보겠습니다. ✂️ 왜 문서를 '잘라야' 할까 이유는 크게 두 가지입니다. 첫째, 모델과 임베딩에는 한 번에 처리할 수 있는 길이의 한계 가 있습니다. 수십 페이지짜리 문서를 통째로 밀어 넣을 수는 없습니다. 둘째, RAG에서 검색은 질문과 가장 관련 있는 조각 만 찾아 오는 방식으로 동작합니다. 문서가 하나의 큰 덩어리라면 "이 문서 안 어딘가에 답이 있다" 수준에서 멈추지만, 잘게 나눠 두면 답이 있는 바로 그 대목 을 집어낼 수 있습니다. 핵심은 이렇습니다. 검색이 잘 되도록, 그리고 문맥이 끊기지 않도록 나눈다. 다만 무작정 잘게 쪼갠다고 ...

다양한 문서를 불러오는 법 — LangChain Document Loader

📌 3줄 요약 · Document Loader 는 PDF·웹페이지·CSV 같은 다양한 원본 을 LangChain이 다룰 수 있는 Document 객체 로 바꿔 주는 입구입니다. · 어떤 형식이든 불러오고 나면 본문(page_content) 과 출처·페이지 같은 메타데이터(metadata) 가 담긴 같은 모양으로 정리됩니다. · 로더로 불러오기 만 하면, 이후 분할 → 임베딩 → 검색(RAG) 으로 매끄럽게 이어집니다. 📖 목차 왜 문서를 '불러오는' 단계가 따로 필요할까 Document 객체의 생김새 자주 쓰는 로더 종류 코드로 불러오기 자주 부딪히는 문제 실무 팁 자주 묻는 질문(FAQ) 원본 파일·URL → Document Loader → Document(본문+메타) → 분할·임베딩 → 검색·답변 앞선 글들에서 모델과 체인, 에이전트를 다뤘다면, 이번엔 그들이 읽을 재료 를 준비하는 이야기입니다. 우리가 쓰는 지식은 PDF 보고서, 회사 홈페이지, 엑셀 표, 노션 문서처럼 제각각의 형식 으로 흩어져 있습니다. 이 서로 다른 원본을 하나의 통일된 모양으로 정리해 주는 것이 바로 Document Loader(문서 로더) 입니다. 이번 글에서는 로더가 무엇을 해 주는지, 어떤 종류가 있고 어떻게 불러오는지 정리해 보겠습니다. 📥 왜 문서를 '불러오는' 단계가 따로 필요할까 PDF는 페이지와 폰트 정보가 뒤섞여 있고, 웹페이지는 HTML 태그로 가득하며, CSV는 행과 열로 나뉘어 있습니다. 형식이 다르면 읽어 들이는 방법도 전부 다릅니다 . 만약 형식마다 직접 파싱 코드를 짜야 한다면, 새로운 자료를 붙일 때마다 처음부터 다시 작업해야 하겠죠. 로더의 발상은 이렇습니다. 불러오는 방식은 형식마다 감추고, 나오는 결과는 항상 같은 모양으로 통일하자. 덕분에 우리는 "이건 PDF, 저건 웹페이지"를 신경 쓰지 않고, 불러온 다음의 일(분할·검색·요...