글

10월, 2026의 게시물 표시

Router Chain으로 질문 분기 처리하기

📌 3줄 요약 · Router Chain 은 들어온 질문을 먼저 살펴보고, 성격에 맞는 전용 체인으로 흘려보내는 교통정리 담당입니다. · 수학·과학·역사처럼 분야별로 프롬프트가 다를 때 , 질문마다 가장 알맞은 프롬프트를 자동으로 골라 씁니다. · 핵심은 분류(Router) → 분기(Branch) → 실행 의 흐름으로, 하나의 거대한 프롬프트 대신 작고 전문화된 체인 여러 개 를 상황에 맞게 쓰는 것입니다. 📖 목차 하나의 프롬프트로는 부족할 때 Router Chain의 기본 구조 분기가 일어나는 과정 코드로 살펴보기 기본 경로의 중요성 실무 팁 자주 묻는 질문(FAQ) 💬 질문 입력 → 🧭 분류(Router) → 🔀 알맞은 체인 선택 → ✅ 전용 프롬프트로 답변 지금까지는 하나의 질문을 하나의 체인으로 처리하는 방식을 주로 살펴봤습니다. 그런데 서비스가 커지면 "수학 문제도, 역사 질문도, 코딩 질문도 한 봇이 다 받아야 하는" 상황이 생깁니다. 이때 모든 경우를 담은 거대한 프롬프트 하나 로 버티려 하면 금세 한계가 옵니다. Router Chain 은 이런 고민을 깔끔하게 풀어 줍니다. 질문을 먼저 분류해 가장 알맞은 전용 체인으로 보내 주는 방식이죠. 오늘은 이 분기 처리의 구조를 차근차근 따라가 보겠습니다. 🧩 하나의 프롬프트로는 부족할 때 질문의 종류가 다양해질수록, 모든 분야를 한 프롬프트에 욱여넣는 방식은 점점 불리해집니다. 수학 풀이에 필요한 지시, 역사 설명에 필요한 지시, 코드 작성에 필요한 지시가 서로 뒤엉켜 길어지고, 그만큼 모델이 핵심을 놓치기 쉬워집니다. 지시가 많아질수록 토큰도 늘고 답의 초점도 흐려지는 것입니다. 그래서 나온 발상이 "분야별로 프롬프트를 따로 두고, 질문에 맞는 것만 골라 쓰자" 입니다. 각 분야 전용 프롬프트는 짧고 뾰족하게 유지하고, 그 앞에 교통정리를 맡는 분류기 를 하나 세워 두는 구조입니다. ...

Agent Executor 동작 원리 이해하기

📌 3줄 요약 · Agent Executor 는 LLM이 "어떤 도구 를 어떤 입력으로 쓸지" 스스로 정하고, 그 결과를 다시 받아 다음 행동을 이어 가도록 반복을 돌려 주는 LangChain의 실행 엔진입니다. · 핵심은 생각 → 행동 → 관찰 을 한 바퀴로 묶어, 최종 답이 나올 때까지 이 루프를 자동으로 반복한다는 점입니다. · 도구 호출·결과 수집·종료 판단을 사람이 손으로 짜지 않아도, Executor가 LLM의 결정을 실제 실행으로 연결 해 줍니다. 📖 목차 Agent와 Agent Executor는 다릅니다 생각-행동-관찰 루프 한 바퀴 안에서 벌어지는 일 코드로 살펴보기 루프를 멈추는 기준 실무 팁 자주 묻는 질문(FAQ) 🧠 LLM이 다음 행동 결정 → 🔧 도구 실행 → 👀 결과 관찰 → 🔁 끝날 때까지 반복 앞선 편들에서는 프롬프트를 만들고, 체인을 잇고, 대화를 기억하게 하는 방법을 살펴봤습니다. 그런데 "검색해서 찾아보고, 계산까지 한 다음 답해 줘" 같은 요청은 한 번의 LLM 호출로는 끝나지 않습니다. 모델이 필요한 도구를 직접 골라 쓰고 , 그 결과를 보고 다음 행동을 다시 정해야 하기 때문입니다. 이 반복을 대신 돌려 주는 것이 바로 Agent Executor 입니다. 오늘은 이 실행 엔진이 안에서 무엇을 하는지 차근차근 따라가 보겠습니다. 🧩 Agent와 Agent Executor는 다릅니다 먼저 헷갈리기 쉬운 두 개념을 구분해야 합니다. Agent 는 "지금 상황에서 무엇을 할지 결정하는 두뇌"입니다. 질문과 지금까지의 진행 상황을 받아, 다음에 어떤 도구를 어떤 입력으로 쓸지 , 아니면 이제 최종 답을 낼지 를 한 번 판단해 돌려줄 뿐입니다. 즉 Agent 자체는 결정만 하고, 실제로 도구를 실행하지는 않습니다. 반면 Agent Executor 는 그 결정을 받아 실제로 실행에 옮기고 , 결과...

대화 기록 붙이기 — ConversationChain

📌 3줄 요약 · ConversationChain 은 LLM 호출에 이전 대화 기록을 자동으로 끼워 넣어 , 앞서 나눈 이야기를 기억한 채 답하게 해 주는 LangChain 체인입니다. · 매번 전체 대화를 손으로 프롬프트에 붙일 필요 없이, Memory 객체 가 주고받은 말을 저장하고 다음 호출에 다시 넣어 줍니다. · 저장 방식을 Memory 종류 로 바꿀 수 있어, 전체를 다 기억할지 최근 몇 턴만 남길지 상황에 맞게 고를 수 있습니다. 📖 목차 LLM이 대화를 못 기억하는 이유 ConversationChain의 아이디어 동작 흐름 따라가기 코드로 살펴보기 기억 방식 바꿔 보기 실무 팁 자주 묻는 질문(FAQ) 💬 새 질문 입력 → 🧠 저장된 대화 기록 불러오기 → 📝 기록+질문 합쳐 LLM 호출 → 💾 이번 대화도 다시 저장 챗봇을 만들다 보면 금방 벽에 부딪히는 지점이 있습니다. 방금 "제 이름은 승일이에요"라고 알려 줬는데, 바로 다음 질문에서 이름을 물으면 모델이 전혀 모른다 고 답하는 상황입니다. 사람 사이의 대화라면 당연한 기억이 LLM에게는 기본으로 주어지지 않기 때문입니다. 오늘은 이 문제를 해결하려고 LangChain이 제공하는 ConversationChain 을 차근차근 살펴보겠습니다. 🧩 LLM이 대화를 못 기억하는 이유 LLM은 기본적으로 이전 호출을 기억하지 못합니다 . 한 번의 호출에서 모델이 볼 수 있는 것은 그때 함께 건네진 프롬프트뿐 이기 때문입니다. 호출이 끝나면 모델 쪽에는 아무것도 남지 않습니다. 그래서 다음 질문을 던질 때 앞선 대화를 알려 주지 않으면, 모델은 매번 처음 보는 사람 처럼 반응합니다. 그렇다면 기억을 흉내 내는 방법은 분명합니다. 지금까지 주고받은 말을 프롬프트에 직접 붙여서 함께 보내면 됩니다. 문제는 대화가 길어질수록 이 작업을 매번 손으로 하기가 번거롭다는 점입니다. 모델이 기억하는 것처럼 보이게 ...

질문을 여러 갈래로 바꿔 검색하기 — Multi-Query Retriever 활용법

📌 3줄 요약 · Multi-Query Retriever 는 사용자의 질문 하나를 여러 표현의 질문으로 자동 확장 한 뒤, 각각으로 검색해 그 결과를 합쳐 주는 LangChain 검색기입니다. · "같은 뜻이지만 단어가 달라 검색에 걸리지 않던 문서"를 놓치지 않도록, 질문을 여러 각도 에서 다시 던지는 것이 핵심입니다. · 질문 변형은 LLM이 생성 하고, 각 변형으로 얻은 문서를 중복 제거해 하나로 돌려주므로 검색 재현율(recall) 을 끌어올릴 수 있습니다. 📖 목차 한 번의 질문이 놓치는 것들 Multi-Query Retriever의 아이디어 동작 흐름 따라가기 코드로 살펴보기 생성되는 질문을 직접 확인하기 실무 팁 자주 묻는 질문(FAQ) ❓ 원래 질문 → 🧠 LLM이 여러 변형 생성 → 🔍 변형마다 각각 검색 → 📄 중복 제거 후 합치기 RAG(검색 증강 생성)에서 검색 품질은 결국 "질문을 어떻게 던지느냐" 에 크게 좌우됩니다. 그런데 사용자는 보통 한 가지 표현 으로만 질문을 적습니다. 문제는 벡터 검색이 의미의 거리 를 재다 보니, 같은 뜻이라도 단어 선택이 조금만 달라져도 정작 필요한 문서를 놓칠 수 있다는 점입니다. 오늘은 이 약점을 보완하려고 고안된 LangChain의 Multi-Query Retriever 를 차근차근 살펴보겠습니다. 🧩 한 번의 질문이 놓치는 것들 벡터 검색은 질문과 문서를 각각 임베딩 으로 바꾼 뒤, 그 의미적 거리 가 가까운 문서를 찾아 줍니다. 꽤 똑똑해 보이지만 한계가 있습니다. 질문에 쓰인 표현과 관점 이 문서의 그것과 어긋나면, 분명 관련 있는 내용인데도 거리가 멀게 측정되어 검색에서 빠지는 일이 생깁니다. 예를 들어 "앱이 자꾸 느려져요"라고 물었을 때, 정작 해답이 담긴 문서는 "성능 저하 원인"이나 "응답 지연 최적화"라는 다른 어휘 ...

Parent Document Retriever로 RAG 고도화

📌 3줄 요약 · Parent Document Retriever 는 검색은 작게 쪼갠 조각(child) 으로 정확히 하고, 모델에는 그 조각이 속한 더 큰 원문(parent) 을 돌려주는 LangChain 검색기입니다. · "검색 정확도를 높이려면 잘게 쪼개야 하고, 답변 품질을 높이려면 충분한 맥락이 필요하다"는 상충하는 요구 를 한 번에 풀어 줍니다. · 작은 조각은 벡터로 임베딩 해 검색하고, 큰 원문은 별도 저장소 에 보관했다가 이어 붙여 반환하는 이중 구조 가 핵심입니다. 📖 목차 청크 크기의 딜레마 Parent Document Retriever의 아이디어 두 개의 저장소가 하는 일 코드로 살펴보기 전체 조각이 아니라 큰 조각을 부모로 실무 팁 자주 묻는 질문(FAQ) ❓ 질문 → 🔍 작은 조각으로 검색 → 📄 큰 원문으로 교체 → 🤖 풍부한 맥락으로 답변 RAG(검색 증강 생성)를 만들다 보면 누구나 한 번쯤 청크 크기 앞에서 고민하게 됩니다. 문서를 작게 쪼개면 검색은 정확해지는데 모델이 받는 맥락이 부족하고, 크게 쪼개면 맥락은 넉넉한데 검색이 뭉툭해집니다. 오늘은 이 두 마리 토끼 를 동시에 잡으려고 고안된 LangChain의 Parent Document Retriever 를 차근차근 살펴보겠습니다. 🧩 청크 크기의 딜레마 RAG에서는 긴 문서를 그대로 쓰지 않고 청크(chunk) 라는 작은 단위로 잘라 벡터로 바꾼 뒤 저장합니다. 질문이 들어오면 질문과 의미가 가까운 청크 를 찾아 모델에게 함께 넘기는 방식이죠. 그런데 이때 "얼마나 잘게 자를 것인가"가 품질을 크게 좌우합니다. 청크를 작게 만들면, 한 조각이 하나의 좁은 주제만 담게 되어 질문과의 의미 매칭이 또렷 해집니다. 대신 조각 자체가 짧아, 막상 모델에게 넘기면 앞뒤 맥락이 잘려 제대로 된 답을 만들기 어려울 수 있습니다. 반대로 청크를 크게 만들면 맥락은 풍부하지만...

LangSmith로 체인 디버깅·추적하기

📌 3줄 요약 · LangSmith 는 LangChain으로 만든 체인·에이전트가 내부에서 실제로 무엇을 주고받았는지 그대로 기록·추적 해 주는 관측(observability) 도구입니다. · 환경 변수 몇 개만 켜 두면 프롬프트 완성본, 모델 응답, 토큰·지연 시간, 중간 단계 가 자동으로 대시보드에 쌓여, "왜 이런 답이 나왔는지"를 눈으로 따라갈 수 있습니다. · 디버깅 뿐 아니라 입력-출력 쌍을 모아 데이터셋·평가(evaluation) 로 발전시킬 수 있어, 체인을 꾸준히 개선하는 토대가 됩니다. 📖 목차 체인은 왜 디버깅하기 어려울까 LangSmith가 보여 주는 것 환경 변수로 추적 켜기 트레이스(trace) 읽는 법 추적에서 평가로 이어 가기 실무 팁 자주 묻는 질문(FAQ) 🏃 체인 실행 → 📡 단계별 자동 기록 → 🔍 트레이스 확인 → 📈 평가·개선 체인을 몇 줄로 엮어 돌리면 결과는 금방 나옵니다. 그런데 막상 엉뚱한 답 이 나왔을 때가 문제예요. 프롬프트에 변수가 제대로 채워졌는지, 모델이 받은 최종 문장이 무엇이었는지, 중간 단계에서 어디가 틀어졌는지 겉으로는 보이지 않기 때문입니다. 오늘은 이렇게 보이지 않던 체인 내부를 그대로 들여다보게 해 주는 LangSmith 를 차근차근 살펴보겠습니다. 🧩 체인은 왜 디버깅하기 어려울까 LangChain의 체인은 프롬프트 → 모델 → 출력 파서 처럼 여러 조각이 파이프로 연결 된 흐름입니다. 편리한 만큼, 문제가 생겨도 중간 과정이 눈에 보이지 않는다 는 단점이 있어요. 우리가 보는 건 맨 앞의 입력과 맨 뒤의 출력뿐이고, 그 사이에서 벌어진 일은 블랙박스처럼 가려져 있습니다. 그래서 예상과 다른 답이 나오면 print 를 여기저기 끼워 넣어 보지만, 이 방법은 금세 한계에 부딪힙니다. 특히 에이전트 처럼 모델이 스스로 도구를 여러 번 호출하는 구조에서는, 어떤 순서로 무엇을 호출했는지 로그만으로 재구성...

Prompt Template 완전 정복

📌 3줄 요약 · Prompt Template(프롬프트 템플릿) 은 모델에게 보낼 문장을 미리 틀로 만들어 두고, 바뀌는 부분만 변수로 끼워 넣는 도구입니다. · 매번 긴 문자열을 손으로 조립하는 대신, 한 번 만든 틀을 입력만 바꿔 가며 재사용 할 수 있어 코드가 깔끔하고 실수가 줄어듭니다. · 단순 문자열용 PromptTemplate 과 대화형 모델용 ChatPromptTemplate 이 핵심이며, 둘 다 체인(chain)의 맨 앞 에 붙어 입력을 완성합니다. 📖 목차 왜 프롬프트를 템플릿으로 만드나 PromptTemplate 기본 사용법 대화형 모델을 위한 ChatPromptTemplate 부분 적용과 예시 넣기 체인에서 템플릿이 하는 일 실무 팁 자주 묻는 질문(FAQ) 🧩 템플릿(틀) 정의 → ✏️ 변수 값 채우기 → 📝 완성된 프롬프트 → 🤖 LLM 호출 LLM을 다루다 보면 같은 질문을 단어만 바꿔 가며 수없이 보내게 됩니다. "서울의 맛집을 추천해 줘", "부산의 맛집을 추천해 줘"처럼 말이죠. 이때 매번 문장 전체를 손으로 조립하면 번거롭고, 띄어쓰기 하나 틀려도 결과가 흔들립니다. 오늘은 이런 반복을 깔끔하게 정리해 주는 Prompt Template(프롬프트 템플릿) 을 차근차근 살펴보겠습니다. 🧩 왜 프롬프트를 템플릿으로 만드나 프롬프트는 결국 모델에게 건네는 한 덩어리의 문장 입니다. 그런데 실제 애플리케이션에서는 이 문장 중 일부만 바뀌는 경우가 대부분이에요. 도시 이름, 사용자가 입력한 질문, 번역할 문장처럼 달라지는 조각 이 있고, "~을 추천해 줘" 같은 고정된 뼈대 가 있습니다. 매번 "" + city + "의 맛집을..." 식으로 문자열을 이어 붙이면, 코드가 금세 지저분해지고 따옴표나 공백 실수 가 끼어들기 쉽습니다. 그래서 LangChain은 바뀌는 자리를 ...

Output Parser — 구조화된 응답 받기

📌 3줄 요약 · LLM의 답은 기본적으로 자유로운 문장(텍스트) 이라, 프로그램이 그대로 받아 쓰기엔 다루기 어렵습니다. 이때 필요한 것이 Output Parser(출력 파서) 입니다. · Output Parser는 모델의 텍스트 답변을 리스트·JSON·객체처럼 코드가 다루기 쉬운 형태로 바꿔 주는 변환기 입니다. · 핵심은 "형식을 어떻게 맞춰 달라"는 안내를 프롬프트에 넣고 , 돌아온 답을 파서가 정해진 구조로 해석 하게 하는 두 단계입니다. 📖 목차 왜 구조화된 응답이 필요한가 Output Parser란 무엇인가 가장 단순한 파서: 문자열과 리스트 구조를 지정하는 파서: Pydantic·JSON 파서가 실패할 때 생기는 일 실무 팁 자주 묻는 질문(FAQ) 📝 형식 안내 프롬프트 → 🤖 LLM 텍스트 응답 → 🔧 Output Parser 변환 → 📦 구조화된 데이터 LLM에게 "서울의 장점 세 가지를 알려 줘"라고 물으면, 보기 좋은 문장으로 답해 줍니다. 그런데 그 답을 프로그램에서 하나씩 꺼내 쓰려면 이야기가 달라집니다. 사람이 읽기엔 자연스러운 문장이, 코드 입장에서는 어디서부터 어디까지가 한 항목인지 알 수 없는 긴 글 덩어리 일 뿐이기 때문이에요. 오늘은 모델의 답을 코드가 바로 다룰 수 있는 형태로 받아 내는 방법 , 즉 Output Parser 를 차근차근 살펴보겠습니다. 🧩 왜 구조화된 응답이 필요한가 LLM의 기본 출력은 자유로운 자연어 문장 입니다. 사람이 읽기에는 더없이 좋지만, 프로그램이 그 결과를 다음 단계로 넘겨 처리 하려고 하면 문제가 생깁니다. 예를 들어 "추천 영화 세 편"을 받아서 화면에 목록으로 하나씩 그려야 한다고 해 봅시다. 모델이 "첫째는 A, 둘째는 B, 그리고 C도 좋아요" 처럼 답하면, 코드는 이 문장을 어떻게 세 조각으로 나눠야 할지 알기 어렵습니다. 그래서...

커스텀 Tool 만들기 — 나만의 LangChain 도구

📌 3줄 요약 · LLM은 스스로 계산하거나 검색하거나 외부 시스템을 다루지 못합니다. 이런 일은 Tool(도구) 이라는 외부 함수에 맡겨야 합니다. · LangChain에서 커스텀 Tool 은 사실 평범한 파이썬 함수에 이름과 설명을 붙인 것 입니다. 설명을 보고 LLM이 언제 그 도구를 쓸지 판단합니다. · @tool 데코레이터만 붙이면 함수가 바로 도구가 되고, 에이전트가 필요할 때 알아서 호출합니다. 핵심은 설명(docstring)을 잘 쓰는 것 입니다. 📖 목차 LLM이 못 하는 일, 그래서 Tool이 필요하다 커스텀 Tool이란 무엇인가 @tool 데코레이터로 도구 만들기 에이전트에 도구를 연결하기 좋은 도구를 만드는 네 가지 원칙 실무 팁 자주 묻는 질문(FAQ) 🙋 사용자 질문 → 🤖 LLM 판단 → 🔧 Tool 호출 → 💬 결과로 답변 LLM에게 "오늘 환율로 100달러가 몇 원이야?"라고 물으면, 그럴듯한 숫자를 말하지만 실제 환율은 아닙니다 . 모델은 실시간 정보를 모르고, 정확한 계산도 보장하지 못하기 때문이에요. 이럴 때 필요한 것이 바로 Tool(도구) 입니다. 오늘은 LangChain에서 나만의 커스텀 Tool 을 어떻게 만들고, 에이전트가 그것을 어떻게 알아서 쓰게 되는지 차근차근 살펴보겠습니다. 🧩 LLM이 못 하는 일, 그래서 Tool이 필요하다 LLM은 텍스트를 생성하는 데는 탁월하지만 , 몇 가지 일은 근본적으로 하지 못합니다. 지금 이 순간의 실시간 정보 를 알 수 없고, 복잡한 수식 계산 을 정확히 보장하지 못하며, 데이터베이스를 조회하거나 메일을 보내는 외부 시스템 조작 도 스스로는 할 수 없어요. 모델은 어디까지나 말을 만들어 내는 존재 이기 때문입니다. 그래서 이런 일들은 바깥의 실제 함수 에 맡기고, LLM은 "언제 어떤 함수를 부를지"만 판단하도록 역할을 나눕니다. 이때 LLM이 부를 수 있는 외부 ...

LangChain Memory — 대화 맥락 유지하기

📌 3줄 요약 · LLM 은 기본적으로 이전 대화를 기억하지 못합니다. 매 호출이 백지에서 시작하기 때문에, 맥락을 이어가려면 지난 대화를 다시 넣어 줘야 합니다. · LangChain의 Memory 는 주고받은 대화를 저장해 두었다가 다음 요청에 자동으로 끼워 넣어 , 챗봇이 맥락을 기억하는 것처럼 동작하게 해 줍니다. · 전체를 저장할지, 최근 몇 개만 남길지, 요약해서 압축할지에 따라 여러 종류의 Memory 가 있고, 상황에 맞게 고르면 됩니다. 📖 목차 LLM은 왜 대화를 기억하지 못할까 Memory가 하는 일 — 저장하고 되돌려 넣기 Memory의 종류 — 전체·창·요약 코드로 보는 대화 기억 챗봇 토큰과 비용, 그리고 트레이드오프 실무 팁 자주 묻는 질문(FAQ) 💬 사용자 입력 → 📚 지난 대화 불러오기 → 🤖 LLM 호출 → 💾 대화 저장 챗봇을 직접 만들어 보면 가장 먼저 부딪히는 벽이 있습니다. 바로 "방금 말한 걸 왜 기억 못 하지?" 하는 순간이죠. 이름을 알려 줬는데도 다음 질문에서 모른다고 답하는 식입니다. 이는 버그가 아니라 LLM의 본래 성질 에서 비롯된 현상이에요. 오늘은 LangChain의 Memory 가 이 문제를 어떻게 풀어 주는지, 그리고 어떤 방식들이 있는지 차근차근 살펴보겠습니다. 🧠 LLM은 왜 대화를 기억하지 못할까 LLM은 요청을 받을 때마다 그 순간 전달된 입력만 보고 답을 만듭니다. 이전에 어떤 대화를 나눴는지는 모델 안에 남아 있지 않아요. 즉 매번 백지 상태에서 시작 하는 셈입니다. 우리가 흔히 쓰는 챗봇이 대화를 이어가는 것처럼 보이는 이유는, 모델이 기억하고 있어서가 아니라 지난 대화를 매 요청마다 함께 넣어 주기 때문 입니다. 그렇다면 방법은 분명해집니다. 주고받은 대화를 어딘가에 쌓아 두었다가 , 새 질문을 보낼 때 그 기록을 앞에 붙여서 함께 전달하면 됩니다. 이 과정을 매번 손으로 하면 번거로우...