[AI] 06_멀티스텝_파이프라인 - 100-hours-a-week/9-team-Devths-WIKI GitHub Wiki

단계 4: 멀티스텝 AI/파이프라인 구현 검토

📋 과제 요약

프로젝트명: Devths AI 취업 도우미
서비스 유형: LLM + Vision 복합 서비스
제출일: 2026-01-13


✅ 제출 항목 체크리스트

1. 멀티스텝 체인/파이프라인 다이어그램 ✅

1-1. V1 (MVP) - 기본 기능

📸 [사진 1-1: V1 랭체인 구조]

alt text

  • ✅ LangChain 기본 구조
  • ✅ LLM 호출 래퍼
  • ✅ Prompt Template 관리
📸 [사진 1-2: V1 챗봇 LLM 파이프라인]

alt text

  • ✅ 일반 대화 처리
  • ✅ 이력서 분석
  • ✅ 면접 질문 생성
  • ✅ 면접 리포트 생성
📸 [사진 1-3: V1 마스킹 파이프라인]

alt text

  • ✅ VLM 단독 처리
  • ✅ 개인정보 좌표 추출
  • ✅ 마스킹 이미지 생성

1-2. V2 - 에이전트 + 캘린더 추가

📸 [사진 2-1: V2 랭체인 구조 (에이전트 추가)]

alt text

  • ✅ LangChain + LangGraph
  • ✅ Agent 모듈 추가
  • ✅ Tool Calling 지원
📸 [사진 2-2: V2 챗봇 LLM + 에이전트 파이프라인]

alt text

  • ✅ 일반 대화 + RAG
  • ✅ 이력서 분석
  • ✅ 면접 질문/리포트
  • 구글 캘린더 에이전트 (AI chatbot에서 사용) alt text
📸 [사진 2-3: V2 마스킹 파이프라인 (동일)]

alt text

  • ✅ V1과 동일 (VLM 단독 처리)
📸 [사진 2-4: V2 캘린더 일정 파싱]

alt text

  • ✅ 캘린더 모달에서 파일/텍스트 입력
  • ✅ 회사명, 전형 일정 자동 추출
  • ✅ 모달 폼 자동 채우기

1-3. V3 - 고도화 (RAG + 마스킹 개선)

📸 [사진 3-1: V3 랭체인 구조 (RAG 추가)]

alt text

  • ✅ LangChain + LangGraph
  • ✅ RAG Module 추가
  • ✅ Hybrid Search + Reranker
📸 [사진 3-2: V3 챗봇 LLM + RAG 파이프라인]

alt text

  • ✅ RAG 기반 대화
  • ✅ 이력서 분석 (이전 피드백 참조)
  • ✅ 면접 질문 (약점 기반)
  • ✅ 면접 리포트 (유사 면접 결과 참조)
  • ✅ 구글 캘린더 에이전트
📸 [사진 3-3: V3 마스킹 파이프라인 (개선)]

alt text

  • ✅ CLOVA OCR + YOLO 병렬 처리
  • ✅ 정확도 95%+ 달성
  • ✅ 처리 속도 50% 단축
📸 [사진 3-4: V3 캘린더 일정 파싱 (동일)]

alt text alt text

  • ✅ V2와 동일
📸 [사진 3-5: V3 RAG 검색 워크플로우]
  • ✅ 데이터 저장 (Indexing): OCR → 청킹 → 임베딩 → VectorDB
  • ✅ RAG 검색 (Retrieval): Hybrid Search (BM25 30% + Vector 70%) → Reranker
  • ✅ 프롬프트 증강 (Augmentation): 페르소나 + 컨텍스트 + 질문
  • ✅ LLM 응답: 개인화된 분석 결과

1-4. LangGraph 워크플로우 (V2+)

📸 [사진 4-1: LangGraph 면접 워크플로우]
  • ✅ 상태 기반 워크플로우 (StateGraph)
  • ✅ 조건 분기 (질문 수 < 5, 사용자 종료 요청)
  • ✅ 노드 간 연결 (generate_question → save_qa → check_condition)
📸 [사진 4-2: LangGraph 에이전트 워크플로우]
  • ✅ Tool Calling 흐름
  • ✅ 조건 분기 (Tool 필요 여부)
  • ✅ Tool 실행 → 결과 반영 → 최종 응답

2. 사용 모델·도구·프레임워크 목록 ✅

구분 기술 선택 이유 기대 효과
LLM 프레임워크 LangChain 체인 구성, 프롬프트 관리 표준화 코드 재사용성 향상
워크플로우 LangGraph 상태 기반 복잡한 흐름, 조건 분기 면접 모드 상태 관리
LLM Gemini 2.0 Flash 빠른 응답, 저비용, Vision 지원 비용 절감 + 성능
VectorDB ChromaDB 로컬 실행, LangChain 연동 RAG 성능 향상
캐시 Redis 대화 컨텍스트, TTL 지원 응답 속도 향상
스트리밍 SSE 실시간 응답 전송 UX 개선
OCR CLOVA OCR 한글 인식 정확도 95%+ 마스킹 정확도 향상
객체 탐지 YOLO 얼굴 탐지 98% 마스킹 정확도 향상
Embedding Gemini text-embedding-004 단일 모델 통일 벡터 공간 일관성
Reranker Cohere Rerank RAG 정확도 10-15% 향상 검색 품질 개선

3. 구현 코드 (의사코드 포함) ✅

3-1. LangGraph 면접 워크플로우

from langgraph.graph import StateGraph, END
from typing import TypedDict, List

# State 정의
class InterviewState(TypedDict):
    session_id: str
    user_id: str
    questions: List[dict]
    answers: List[dict]
    current_index: int
    status: str  # "in_progress" | "completed"

# 노드 함수들
def generate_question(state: InterviewState) -> InterviewState:
    """RAG 기반 질문 생성"""
    context = vectordb.search(state['user_id'])
    question = llm.invoke(f"컨텍스트: {context}\n질문 생성")
    state['questions'].append({"q": question, "type": "main"})
    return state

def save_qa(state: InterviewState) -> InterviewState:
    """Q&A 저장"""
    db.save_qa(state['session_id'], state['questions'][-1], state['answers'][-1])
    state['current_index'] += 1
    return state

def check_condition(state: InterviewState) -> str:
    """종료 조건 확인"""
    if state['current_index'] >= 5:
        return "generate_report"
    if state['status'] == "user_ended":
        return "generate_report"
    return "generate_question"

# 그래프 구성
workflow = StateGraph(InterviewState)

workflow.add_node("generate_question", generate_question)
workflow.add_node("save_qa", save_qa)
workflow.add_node("generate_report", generate_report)

workflow.set_entry_point("generate_question")
workflow.add_edge("generate_question", "save_qa")
workflow.add_conditional_edges(
    "save_qa",
    check_condition,
    {
        "generate_question": "generate_question",
        "generate_report": "generate_report"
    }
)
workflow.add_edge("generate_report", END)

app = workflow.compile()

3-2. RAG Hybrid Search + Reranker

from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever

async def rag_search_pipeline(
    query: str,
    user_id: str,
    collection: str = "resumes",
    k: int = 3
):
    """Hybrid Search + Reranker RAG 파이프라인"""

    # 1. 쿼리 임베딩
    query_embedding = await gemini_embedding.embed_query(query)

    # 2. Hybrid Search (BM25 + Vector)
    bm25_retriever = BM25Retriever.from_documents(
        documents=vectordb.get_documents(collection),
        k=20
    )

    vector_retriever = vectordb.as_retriever(
        search_type="similarity",
        search_kwargs={
            "k": 20,
            "filter": {"user_id": user_id}
        }
    )

    # Ensemble Retriever (BM25 30% + Vector 70%)
    ensemble_retriever = EnsembleRetriever(
        retrievers=[bm25_retriever, vector_retriever],
        weights=[0.3, 0.7]
    )

    # 3. Top 20 검색
    docs = await ensemble_retriever.aget_relevant_documents(query)

    # 4. Reranker (Top 20 → Top 3)
    reranked = await cohere_rerank(
        query=query,
        documents=docs,
        top_n=k
    )

    # 5. 컨텍스트 구성
    context = "\n\n".join([doc.page_content for doc in reranked])

    # 6. 프롬프트 증강
    augmented_prompt = f"""
[페르소나]
{CAREER_COACH_PERSONA}

[컨텍스트]
{context}

[사용자 질문]
{query}

위 컨텍스트를 참고하여 개인화된 답변을 제공하세요.
"""

    # 7. LLM 호출
    response = await llm.ainvoke(augmented_prompt)

    return response

3-3. 마스킹 파이프라인 (V3)

async def masking_pipeline_v3(image_url: str):
    """CLOVA OCR + YOLO 병렬 처리"""
    
    # 1. 병렬 처리
    ocr_task = asyncio.create_task(clova_ocr(image_url))
    yolo_task = asyncio.create_task(yolo_detect(image_url))
    
    ocr_result, yolo_result = await asyncio.gather(ocr_task, yolo_task)
    
    # 2. 좌표 통합
    all_coordinates = []
    
    # OCR 좌표 (이름, 전화번호, 이메일)
    for item in ocr_result['fields']:
        if item['type'] in ['name', 'phone', 'email']:
            all_coordinates.append({
                "type": item['type'],
                "coordinates": item['boundingPoly'],
                "confidence": item['confidence']
            })
    
    # YOLO 좌표 (얼굴)
    for face in yolo_result['detections']:
        all_coordinates.append({
            "type": "face",
            "coordinates": face['bbox'],
            "confidence": face['confidence']
        })
    
    # 3. 마스킹 처리
    masked_image = apply_masking(image_url, all_coordinates)
    
    return {
        "masked_url": masked_image,
        "detected_pii": all_coordinates
    }

4. 멀티스텝 도입 효과 및 서비스 요구와의 관련성 ✅

4-1. 도입 효과

구분 도입 전 도입 후 개선율
복잡한 작업 단일 프롬프트 한계 체인으로 분할 처리 -
상태 관리 매번 전체 컨텍스트 전달 LangGraph State로 효율 관리 메모리 50% 절감
외부 시스템 별도 로직 필요 Tool Calling 자연스러운 통합 코드 30% 감소
RAG 수동 프롬프트 삽입 RAG Chain 자동화 정확도 10-15% 향상
마스킹 정확도 VLM 85% CLOVA+YOLO 95% +10%
마스킹 속도 3초 1.5초 (병렬 처리) 50% 단축

4-2. 서비스 요구와의 관련성

서비스 요구사항 멀티스텝 적용 효과
개인화된 면접 RAG + LangGraph 약점 기반 꼬리질문 생성
맥락 유지 대화 Redis Memory + RAG 이전 대화 참조 가능
정확한 마스킹 OCR + YOLO 병렬 개인정보 검출률 98%
빠른 응답 스트리밍 + 캐싱 TTFT 500ms 이하
캘린더 연동 Agent Tool Calling 자연어로 일정 관리

🎊 최종 체크리스트

  • 멀티스텝 체인/파이프라인 다이어그램 (V1/V2/V3별)
  • 사용 모델·도구·프레임워크 목록
  • 구현 코드 (의사코드 포함)
  • 멀티스텝 도입 효과 및 서비스 요구와의 관련성
  • 버전별 기능 진화 과정 (V1 → V2 → V3)

제출 완료! 🎉