{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "6f4981db",
   "metadata": {},
   "source": [
    "# Part 13: 생성형 AI 및 AI 에이전트 심화\n",
    "\n",
    "**⬅️ 이전 시간: [Part 12: 대규모 AI 모델 최적화 및 서빙](../12_model_optimization/part_12_model_optimization.md)**\n",
    "**➡️ 다음 시간: [고급 RAG 기법](./part_13.1_advanced_rag_techniques.md)**\n",
    "\n",
    "---\n",
    "\n",
    "## 1. 학습 목표 (Learning Objectives)\n",
    "\n",
    "> 이 섹션에서는 최신 생성형 AI 기술의 핵심을 이해하고, 스스로 생각하고 행동하는 자율 AI 에이전트를 설계 및 구축하는 방법을 학습합니다.\n",
    "\n",
    "- PEFT, 특히 LoRA의 원리를 이해하고, 적은 리소스로 거대 언어 모델(LLM)을 효율적으로 파인튜닝할 수 있습니다.\n",
    "- 쿼리 변환, 재순위화 등 고급 RAG 기술을 적용하여 검색 증강 생성의 정확도를 향상시킬 수 있습니다.\n",
    "- ReAct 프레임워크를 이해하고, LangGraph를 사용하여 복잡한 작업을 수행하는 자율 AI 에이전트를 설계 및 구현할 수 있습니다.\n",
    "- LangSmith를 활용하여 LLM 및 에이전트 기반 애플리케이션을 추적, 모니터링, 평가하는 LLMOps/AgentOps의 개념을 이해합니다.\n",
    "\n",
    "## 2. 핵심 키워드 (Keywords)\n",
    "\n",
    "`PEFT`, `LoRA`, `RAG`, `쿼리 변환`, `Re-ranking`, `AI 에이전트`, `ReAct`, `LangGraph`, `LLMOps`, `LangSmith`\n",
    "\n",
    "## 3. 도입\n",
    "\n",
    "거대 언어 모델(LLM)의 등장은 AI의 패러다임을 바꾸어 놓았습니다. 이제 AI는 단순히 주어진 데이터를 처리하는 것을 넘어, 스스로 지식을 생성하고, 도구를 사용하며, 목표를 향해 자율적으로 행동하는 단계로 진화하고 있습니다. Part 13에서는 생성형 AI의 최전선에 있는 기술들을 탐험합니다. LLM을 내 목적에 맞게 길들이는 효율적인 파인튜닝 방법부터, 더 똑똑하게 정보를 찾아 활용하는 RAG 심화 기술, 그리고 궁극적으로 스스로 문제를 해결하는 AI 에이전트를 만드는 설계도까지, 차세대 AI 애플리케이션을 구축하는 핵심 역량을 배우게 될 것입니다.\n",
    "\n",
    "---\n",
    "\n",
    "## 4. LLM 효율적 Fine-tuning 및 RAG 심화\n",
    "\n",
    "사전 학습된 거대 언어 모델(LLM)은 그 자체로도 강력하지만, 특정 도메인이나 스타일에 맞게 성능을 최적화하기 위해서는 파인튜닝(Fine-tuning) 과정이 필요합니다. 하지만 수백억, 수천억 개의 파라미터를 가진 LLM 전체를 파인튜닝하는 것은 엄청난 컴퓨팅 자원을 요구하며, 때로는 원본 모델이 가진 일반적인 지식을 잃어버리는 '치명적 망각(Catastrophic Forgetting)' 현상을 겪기도 합니다.\n",
    "\n",
    "이러한 문제를 해결하기 위해, 모델의 극히 일부 파라미터만 업데이트하여 효율적으로 파인튜닝하는 **PEFT(Parameter-Efficient Fine-Tuning)** 기법들이 등장했습니다.\n",
    "\n",
    "### PEFT (Parameter-Efficient Fine-Tuning) 란?\n",
    "\n",
    "PEFT는 LLM의 사전 학습된 가중치(weights) 대부분을 그대로 두고, 일부 추가되거나 선택된 파라미터만을 학습시키는 방법론의 총칭입니다. 이를 통해 다음과 같은 장점을 얻습니다.\n",
    "\n",
    "- **메모리 효율성**: 전체 모델이 아닌, 수백만 개 수준의 적은 파라미터만 학습하므로 훨씬 적은 GPU 메모리로 파인튜닝이 가능합니다. (예: 단일 GPU에서도 가능)\n",
    "- **빠른 학습 속도**: 학습 대상 파라미터가 적어 학습 시간이 단축됩니다.\n",
    "- **치명적 망각 방지**: 원본 모델의 가중치를 변경하지 않으므로, 기존에 학습된 지식을 보존하는 데 유리합니다.\n",
    "- **다중 작업 용이성**: 원본 LLM 하나에 여러 개의 작은 PEFT 모듈(어댑터)을 추가하여, 작업에 따라 어댑터만 교체하며 사용할 수 있습니다.\n",
    "\n",
    "### LoRA (Low-Rank Adaptation of Large Language Models)\n",
    "\n",
    "LoRA는 가장 대표적이고 널리 사용되는 PEFT 기법 중 하나입니다.\n",
    "\n",
    "**핵심 아이디어**:\n",
    "LoRA는 \"사전 학습된 언어 모델은 낮은 내재적 차원(low intrinsic rank)을 가진다\"는 가정에서 출발합니다. 즉, 특정 작업에 맞게 모델을 업데이트할 때, 가중치 행렬의 변화량(Weight Update Matrix, ΔW) 또한 낮은 랭크(low rank)를 가질 것이라고 가정합니다.\n",
    "\n",
    "**작동 방식**:\n",
    "기존의 가중치 행렬 `W` (d x d)를 직접 업데이트하는 대신, `W` 옆에 작은 크기의 학습 가능한 행렬 `A` (d x r)와 `B` (r x d)를 추가합니다. 여기서 `r`은 랭크(rank)로, `d`보다 훨씬 작은 값(예: 8, 16, 64)입니다. 학습 중에는 원본 `W`는 고정된 채 `A`와 `B` 행렬만 업데이트됩니다. 최종적으로 모델의 가중치는 `W + BA`로 계산됩니다.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "211f97ea",
   "metadata": {},
   "outputs": [],
   "source": [
    "Input (x)\n",
    "         |\n",
    "      +-----+\n",
    "      |  W  |  (Frozen)  <-- 기존 가중치 (d x d)\n",
    "      +-----+\n",
    "         |\n",
    "         +----------------> Output (h = Wx + BAx)\n",
    "         |\n",
    "      +-----+\n",
    "      |  A  |  (Trainable) <-- Low-rank matrix (r x d)\n",
    "      +-----+\n",
    "         |\n",
    "      +-----+\n",
    "      |  B  |  (Trainable) <-- Low-rank matrix (d x r)\n",
    "      +-----+\n",
    "         |"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ae0f65c9",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "Hugging Face의 `peft` 라이브러리를 사용하면 LoRA를 매우 쉽게 적용할 수 있습니다.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6a028550",
   "metadata": {},
   "outputs": [],
   "source": [
    "from peft import LoraConfig, get_peft_model\n",
    "from transformers import AutoModelForCausalLM\n",
    "\n",
    "model = AutoModelForCausalLM.from_pretrained(\"meta-llama/Llama-2-7b-chat-hf\")\n",
    "\n",
    "# LoRA 설정\n",
    "config = LoraConfig(\n",
    "    r=16, # rank\n",
    "    lora_alpha=32, # alpha scaling\n",
    "    target_modules=[\"q_proj\", \"v_proj\"], # 적용할 레이어\n",
    "    lora_dropout=0.05,\n",
    "    bias=\"none\",\n",
    "    task_type=\"CAUSAL_LM\"\n",
    ")\n",
    "\n",
    "# 모델에 PEFT 적용\n",
    "lora_model = get_peft_model(model, config)\n",
    "lora_model.print_trainable_parameters()\n",
    "# 출력: trainable params: 8,388,608 || all params: 6,746,832,896 || trainable%: 0.12433"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "298eb289",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "### RAG (Retrieval-Augmented Generation) 심화\n",
    "\n",
    "기본적인 RAG는 외부 문서에서 관련 정보를 검색하여 LLM의 답변에 활용하는 강력한 기술이지만, 복잡한 질문에 대해서는 한계를 보이기도 합니다. 사용자의 질문이 모호하거나, 검색된 문서의 순위가 최적이 아닐 수 있기 때문입니다. 고급 RAG는 이러한 문제를 해결하기 위해 '쿼리 변환'과 '재순위화' 같은 기법들을 도입합니다.\n",
    "\n",
    "#### 1. 쿼리 변환 (Query Transformation)\n",
    "\n",
    "사용자의 원본 질문을 그대로 벡터 검색에 사용하기보다, 더 나은 검색 결과를 얻기 위해 질문을 여러 개로 변형하거나 더 명확하게 만드는 과정입니다.\n",
    "\n",
    "- **Multi-Query**: LLM을 사용하여 사용자의 단일 질문을 다양한 관점의 여러 질문으로 확장합니다. 예를 들어, \"RAG의 장단점은?\" 이라는 질문을 \"RAG의 장점은 무엇인가?\", \"RAG의 단점은 무엇인가?\", \"RAG는 어떤 경우에 유용한가?\" 와 같이 여러 개로 만들어 각각 검색을 수행하고 결과를 종합합니다.\n",
    "- **RAG-Fusion**: Multi-Query와 유사하지만, 검색된 결과들의 순위를 Reciprocal Rank Fusion (RRF) 알고리즘을 사용하여 지능적으로 결합하여 가장 관련성 높은 문서를 찾아냅니다.\n",
    "- **Step-back Prompting**: 사용자의 구체적인 질문에서 한 단계 물러나, 더 일반적이고 근원적인 질문을 생성하여 검색에 활용합니다. 예를 들어, \"우리 회사 복지제도 중 출산휴가는 며칠이야?\" 라는 질문에 대해 \"회사의 휴가 관련 복지제도\" 라는 상위 개념의 질문을 생성하여 먼저 검색하고, 그 결과를 바탕으로 구체적인 답변을 찾게 하여 더 정확한 컨텍스트를 확보합니다.\n",
    "\n",
    "#### 2. 재순위화 (Re-ranking)\n",
    "\n",
    "벡터 검색(Retriever)은 수많은 문서 중에서 관련성이 있을 법한 후보 문서들을 빠르게 찾아내는 데 효과적입니다. 하지만 이 초기 검색 결과가 항상 최적의 순서를 보장하지는 않습니다. **재순위화**는 Retriever가 찾아온 상위 K개의 문서를 더 정교하지만 느린 모델(Cross-Encoder)을 사용하여 다시 평가하고, 사용자 질문과의 관련성이 가장 높은 순서로 재정렬하는 과정입니다.\n",
    "\n",
    "- **작동 방식**:\n",
    "    1.  **1단계 (Retrieval)**: Bi-Encoder 기반의 빠른 벡터 검색으로 후보 문서 50~100개를 검색합니다.\n",
    "    2.  **2단계 (Re-ranking)**: Cross-Encoder 모델이 '(질문, 문서1)', '(질문, 문서2)' ... 와 같이 질문과 각 후보 문서를 쌍으로 입력받아, 두 텍스트 간의 실제 관련도를 0과 1 사이의 점수로 계산합니다.\n",
    "    3.  이 점수를 기준으로 문서들의 순위를 다시 매겨, 가장 관련도 높은 상위 3~5개의 문서를 최종적으로 LLM에 전달합니다.\n",
    "\n",
    "- **장점**: 검색의 정확도(Precision)를 크게 향상시켜, LLM이 더 정확하고 관련성 높은 답변을 생성하도록 돕습니다.\n",
    "\n",
    "**고급 RAG 파이프라인 아키텍처:**\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cb3abb88",
   "metadata": {},
   "outputs": [],
   "source": [
    "User Query --> [Query Transformation] --> Multi-Queries --> [Retrieval (Vector Search)] --> Candidate Docs --> [Re-ranking (Cross-Encoder)] --> Top-K Docs --> LLM --> Final Answer"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c9aba6c3",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "---\n",
    "\n",
    "## 5. 자율 AI 에이전트 설계 및 구축\n",
    "\n",
    "AI 에이전트(Agent)는 단순히 주어진 질문에 답변하는 것을 넘어, 목표 달성을 위해 스스로 생각하고, 도구를 사용하며, 계획을 수정하는 능동적인 시스템을 의미합니다. 에이전트는 LLM을 '뇌'로 사용하여 주변 환경(API, 데이터베이스, 웹 검색 등)과 상호작용하며 복잡한 문제를 해결합니다.\n",
    "\n",
    "### ReAct (Reason + Act) 프레임워크\n",
    "\n",
    "ReAct는 에이전트가 어떻게 행동해야 할지 결정하는 가장 대표적인 프레임워크 중 하나입니다. 이름 그대로 **추론(Reasoning)**과 **행동(Action)**을 결합합니다.\n",
    "\n",
    "**작동 방식**:\n",
    "LLM은 단순히 최종 답변을 내놓는 것이 아니라, 다음과 같은 생각의 연쇄 과정을 통해 목표를 달성합니다.\n",
    "\n",
    "1.  **Thought (생각)**: 현재 상황을 분석하고 목표를 달성하기 위한 다음 행동 계획을 세웁니다.\n",
    "2.  **Action (행동)**: 계획에 따라 사용할 도구(Tool)와 그 도구에 전달할 입력(Input)을 결정합니다. 예를 들어, '웹 검색' 도구에 'AI 에이전트 최신 동향'이라는 입력을 전달할 수 있습니다.\n",
    "3.  **Observation (관찰)**: 행동의 결과(도구의 출력)를 관찰합니다. 웹 검색 결과, API 호출 결과 등이 해당됩니다.\n",
    "4.  **Thought (생각)**: 관찰된 결과를 바탕으로 목표가 달성되었는지, 또는 다음 행동은 무엇이어야 할지 다시 생각합니다.\n",
    "5.  위 과정을 목표가 달성될 때까지 반복합니다.\n",
    "\n",
    "이러한 \"생각-행동-관찰\"의 순환 구조를 통해 에이전트는 복잡한 작업을 체계적으로 해결하고, 중간에 문제가 발생했을 때 대처할 수 있는 능력을 갖게 됩니다.\n",
    "\n",
    "### LangGraph: 복잡한 에이전트 워크플로우 구축\n",
    "\n",
    "하나의 에이전트만으로는 해결하기 어려운 복잡한 작업(예: 여러 리서치 결과를 종합하여 보고서 작성)을 위해서는 여러 전문 에이전트가 서로 협력하는 '멀티-에이전트(Multi-agent)' 시스템이 필요합니다.\n",
    "\n",
    "**LangGraph**는 LangChain에서派生된 라이브러리로, 이러한 멀티-에이전트 시스템이나 순환(cyclic)적인 계산 흐름을 그래프(Graph) 형태로 쉽게 구현할 수 있도록 돕습니다.\n",
    "\n",
    "**주요 개념:**\n",
    "\n",
    "- **State (상태)**: 그래프 전체에서 공유되는 데이터 객체입니다. 각 단계(노드)를 거치면서 상태가 업데이트됩니다. 예를 들어, '수집된 정보', '남은 작업 목록' 등이 상태에 포함될 수 있습니다.\n",
    "- **Nodes (노드)**: 그래프의 각 단계를 나타내며, 특정 작업을 수행하는 함수나 LangChain Runnable 객체입니다. 각 노드는 현재 상태를 입력받아 작업을 수행하고, 변경된 상태를 반환합니다.\n",
    "- **Edges (엣지)**: 노드 간의 연결을 정의하며, 다음으로 어떤 노드로 이동할지 결정하는 역할을 합니다.\n",
    "    - **Conditional Edges (조건부 엣지)**: 특정 노드의 실행 결과(상태)에 따라 다음에 실행될 노드를 동적으로 결정할 수 있습니다. 예를 들어, '리서치 결과가 충분하면 보고서 작성 노드로, 부족하면 추가 검색 노드로 이동'과 같은 분기 처리를 구현할 수 있습니다.\n",
    "\n",
    "**LangGraph의 장점:**\n",
    "\n",
    "- **순환성 및 제어**: 기존의 LangChain Expression Language (LCEL)이 비순환 그래프(DAG)에 최적화된 것과 달리, LangGraph는 \"생각-행동-관찰\" 루프와 같은 순환적인 흐름을 자연스럽게 구현할 수 있습니다.\n",
    "- **상태 관리**: 중앙 집중화된 상태 객체를 통해 여러 에이전트나 노드 간의 정보 공유 및 흐름 제어가 명확하고 용이합니다.\n",
    "- **시각화 및 디버깅**: 복잡한 에이전트의 작동 흐름을 그래프로 시각화할 수 있어, 전체 구조를 이해하고 디버깅하기 편리합니다.\n",
    "\n",
    "**LangGraph 코드 예시 (의사 코드):**\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dfb5f5aa",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langgraph.graph import StateGraph, END\n",
    "\n",
    "# 1. 상태 정의\n",
    "class AgentState(TypedDict):\n",
    "    task: str\n",
    "    result: str\n",
    "\n",
    "# 2. 노드(함수) 정의\n",
    "def research_node(state):\n",
    "    # ... 리서치 수행 ...\n",
    "    return {\"result\": \"리서치 결과\"}\n",
    "\n",
    "def report_node(state):\n",
    "    # ... 보고서 작성 ...\n",
    "    return {\"result\": \"최종 보고서\"}\n",
    "\n",
    "# 3. 조건부 엣지를 위한 함수 정의\n",
    "def should_continue(state):\n",
    "    if \"보고서\" in state['result']:\n",
    "        return \"end\"\n",
    "    else:\n",
    "        return \"continue\"\n",
    "\n",
    "# 4. 그래프 구축\n",
    "workflow = StateGraph(AgentState)\n",
    "workflow.add_node(\"researcher\", research_node)\n",
    "workflow.add_node(\"reporter\", report_node)\n",
    "\n",
    "workflow.set_entry_point(\"researcher\")\n",
    "\n",
    "# 엣지 연결\n",
    "workflow.add_conditional_edges(\n",
    "    \"researcher\",\n",
    "    should_continue,\n",
    "    {\"continue\": \"reporter\", \"end\": END}\n",
    ")\n",
    "workflow.add_edge('reporter', END)\n",
    "\n",
    "# 5. 그래프 컴파일 및 실행\n",
    "app = workflow.compile()\n",
    "final_state = app.invoke({\"task\": \"AI 에이전트 동향 보고서 작성\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "50868ab3",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "LangGraph를 사용하면, 각자 다른 전문성을 가진 여러 에이전트(리서처, 작가, 비평가 등)가 서로의 작업 결과를 바탕으로 협력하고, 필요에 따라 작업을 반복하거나 수정하는 정교한 자율 에이전트 시스템을 효과적으로 구축할 수 있습니다.\n",
    "\n",
    "---\n",
    "\n",
    "## 6. LLMOps & AgentOps\n",
    "\n",
    "LLM과 에이전트 기반의 애플리케이션이 프로덕션 환경에서 안정적으로 운영되기 위해서는 기존의 MLOps를 넘어서는 새로운 운영 패러다임이 필요합니다. 이것이 바로 **LLMOps**와 **AgentOps**입니다.\n",
    "\n",
    "### LLMOps: LLM 기반 애플리케이션을 위한 MLOps\n",
    "\n",
    "LLMOps는 LLM 기반 애플리케이션의 전체 수명 주기(프로토타이핑, 테스트, 배포, 모니터링, 유지보수)를 관리하고 자동화하기 위한 DevOps 원칙과 MLOps 프랙티스를 확장한 개념입니다.\n",
    "\n",
    "**기존 MLOps와의 차이점 및 LLMOps의 고유한 과제:**\n",
    "\n",
    "- **프롬프트 관리 (Prompt Management)**: LLM 앱의 성능은 프롬프트에 매우 민감합니다. 프롬프트의 버전을 관리하고, 여러 프롬프트를 A/B 테스트하며, 성능을 지속적으로 최적화하는 '프롬프트 엔지니어링'이 핵심적인 관리 대상이 됩니다.\n",
    "- **성능 평가의 모호성**: 모델의 정확도, F1 점수 등으로 비교적 명확하게 평가할 수 있었던 기존 ML 모델과 달리, LLM의 출력은 정성적인 평가(예: 답변의 유용성, 창의성, 적절성)가 중요합니다. 이를 위해 LLM 자체를 평가자(LLM-as-a-judge)로 활용하거나, 사람이 직접 피드백하는 등 새로운 평가 파이프라인이 필요합니다.\n",
    "- **실시간 추적 및 디버깅의 어려움**: 복잡한 체인(Chain)이나 에이전트의 작동 과정에서 어떤 프롬프트와 컨텍스트가 사용되었고, 중간 결과는 어떠했는지 추적하기 어렵습니다. 문제 발생 시 원인을 파악하기 위한 상세한 실행 로그와 추적 기능이 필수적입니다.\n",
    "- **컨텍스트 및 외부 데이터 관리**: RAG 시스템의 경우, 벡터 데이터베이스, 검색 알고리즘, 외부 API 등 관리해야 할 요소가 추가됩니다. 데이터가 변경되었을 때 전체 시스템에 미치는 영향을 관리하고 최신 상태를 유지해야 합니다.\n",
    "\n",
    "### AgentOps: 자율 에이전트 시스템을 위한 운영\n",
    "\n",
    "AgentOps는 LLMOps에서 한 단계 더 나아가, 여러 도구와 상호작용하며 자율적으로 작업을 수행하는 AI 에이전트 시스템에 특화된 운영 방법론입니다. 에이전트의 복잡한 \"생각-행동-관찰\" 루프와 멀티-에이전트 간의 상호작용을 안정적으로 운영하는 데 중점을 둡니다.\n",
    "\n",
    "**AgentOps의 주요 관심사:**\n",
    "\n",
    "- **도구 사용 모니터링**: 에이전트가 사용하는 외부 도구(API, 데이터베이스 등)의 성공/실패 여부, 지연 시간, 비용 등을 모니터링합니다.\n",
    "- **에이전트 궤적(Trajectory) 분석**: 에이전트가 목표를 달성하기 위해 거친 전체 의사결정 과정(생각의 연쇄)을 추적하고 분석하여, 비효율적인 행동이나 잘못된 판단을 개선합니다.\n",
    "- **동적 계획 및 회복력(Resilience)**: 예기치 않은 오류(예: API 실패, 잘못된 도구 사용)가 발생했을 때, 에이전트가 스스로 문제를 인식하고 계획을 수정하여 작업을 계속할 수 있도록 하는 메커니즘을 구축합니다.\n",
    "\n",
    "### LangSmith: LLMOps & AgentOps를 위한 통합 플랫폼\n",
    "\n",
    "LangSmith는 LangChain 개발팀이 만든 LLM 애플리케이션 개발 및 운영을 위한 통합 플랫폼입니다. 복잡한 LLM 및 에이전트 애플리케이션의 내부 작동을 투명하게 들여다보고, 문제를 진단하며, 성능을 평가하는 데 강력한 기능을 제공합니다.\n",
    "\n",
    "**주요 기능:**\n",
    "\n",
    "- **추적 (Tracing)**:\n",
    "    - LLM 호출, 체인 실행, 에이전트의 모든 단계를 시각적으로 추적합니다.\n",
    "    - 각 단계별 입력, 출력, 사용된 프롬프트, 토큰 사용량, 지연 시간 등의 상세 정보를 확인할 수 있어 디버깅에 매우 유용합니다.\n",
    "- **모니터링 (Monitoring)**:\n",
    "    - 프로덕션 환경에서 운영되는 LLM 앱의 전반적인 상태를 모니터링하는 대시보드를 제공합니다.\n",
    "    - API 에러율, 평균 지연 시간, 토큰 사용량, 사용자 피드백 등을 통해 서비스의 이상 징후를 신속하게 파악할 수 있습니다.\n",
    "- **평가 (Evaluation)**:\n",
    "    - 특정 데이터셋에 대한 LLM 앱의 성능을 정량적/정성적으로 평가하는 프레임워크를 제공합니다.\n",
    "    - 사용자 정의 평가 기준(예: 답변의 간결성, 유해성)을 만들거나, LLM을 평가자로 사용하여 \"답변이 컨텍스트에 기반하는가?\"와 같은 항목을 자동으로 채점할 수 있습니다.\n",
    "    - 여러 버전의 프롬프트나 모델을 비교 평가하여 최적의 조합을 찾는 데 활용됩니다.\n",
    "- **프롬프트 허브 (Prompt Hub)**:\n",
    "    - 자주 사용되거나 성능이 검증된 프롬프트를 중앙에서 관리하고 버전 제어를 할 수 있습니다. (LangChain 커뮤니티와 프롬프트를 공유할 수도 있습니다)\n",
    "\n",
    "LangSmith는 개발 초기 단계의 디버깅부터 프로덕션 환경의 모니터링 및 성능 최적화에 이르기까지, LLMOps와 AgentOps의 거의 모든 과정을 지원하는 핵심적인 도구라고 할 수 있습니다.\n",
    "\n",
    "---\n",
    "\n",
    "## 7. 캡스톤 프로젝트 연계 미니 프로젝트: 고급 RAG 기술을 적용한 'AI 논문 Q&A 봇' 만들기\n",
    "\n",
    "단순한 챗봇을 넘어, 특정 전문 분야의 지식을 깊이 있게 이해하고 답변하는 AI를 만드는 것은 생성형 AI의 핵심적인 활용 사례입니다. 이번 미니 프로젝트에서는 여러 편의 AI 논문을 학습하여, 사용자의 복잡한 질문에 대해 근거를 찾아 답변하는 'AI 논문 Q&A 봇'을 만듭니다. 이 과정에서 고급 RAG 기술을 직접 구현하고 LangSmith로 내부 동작을 추적하며, 캡스톤 프로젝트의 기술적 완성도를 한 단계 끌어올립니다.\n",
    "\n",
    "### 프로젝트 목표\n",
    "- 특정 PDF 문서들을 기반으로 질문에 답변하는 RAG 기반의 Q&A 챗봇을 구축할 수 있습니다.\n",
    "- 쿼리 변환, 재순위화 등 최소 1개 이상의 고급 RAG 기술을 적용하여 답변의 정확성과 관련성을 향상시킬 수 있습니다.\n",
    "- LangSmith를 사용하여 챗봇의 전체 실행 과정을 추적하고 디버깅하며, 각 컴포넌트의 상호작용을 분석할 수 있습니다.\n",
    "\n",
    "### 개발 과정\n",
    "1.  **데이터 준비**:\n",
    "    - `ArXiv` 등에서 관심 있는 최신 AI 논문 3~5편의 PDF 파일을 다운로드합니다.\n",
    "    - LangChain의 `PyMuPDFLoader`와 같은 문서 로더를 사용하여 PDF를 텍스트로 변환하고, 적절한 크기의 청크(Chunk)로 분할합니다.\n",
    "    - 분할된 텍스트 청크를 임베딩하여 로컬 벡터 저장소(예: `FAISS`, `ChromaDB`)에 저장합니다.\n",
    "\n",
    "2.  **고급 RAG 파이프라인 구현**:\n",
    "    - **(기본)** 먼저 저장된 벡터 저장소를 기반으로 기본적인 Retriever를 구현합니다.\n",
    "    - **(택 1)** 아래의 고급 RAG 기법 중 하나를 선택하여 파이프라인을 개선합니다.\n",
    "        - **옵션 A (쿼리 확장)**: `MultiQueryRetriever`를 사용하여, 사용자의 질문을 LLM이 여러 개의 다른 질문으로 확장하고, 각 질문에 대한 검색 결과를 종합하여 더 풍부한 컨텍스트를 확보합니다.\n",
    "        - **옵션 B (재순위화)**: 기본적인 Retriever가 1차로 검색해 온 문서 목록을, `CrossEncoder` 기반의 재순위화 모델(`CohereRerank` 또는 `bge-reranker-base` 등)을 사용하여 질문과 가장 관련성이 높은 순서로 재정렬합니다.\n",
    "\n",
    "3.  **LCEL을 이용한 체인 구성**:\n",
    "    - LangChain Expression Language (LCEL)를 사용하여 전체 파이프라인을 구성합니다.\n",
    "    - `(사용자 질문) -> (고급 RAG Retriever) -> (검색된 문서 컨텍스트 + 질문을 프롬프트에 삽입) -> (LLM) -> (최종 답변)`의 흐름으로 체인을 설계합니다.\n",
    "\n",
    "4.  **LangSmith 연동 및 분석**:\n",
    "    - LangSmith 사용을 위한 환경 변수를 설정하고, 챗봇을 실행하여 여러 질문을 테스트합니다.\n",
    "    - LangSmith 대시보드에서 생성된 트레이스(Trace)를 확인합니다.\n",
    "        - `MultiQueryRetriever`를 사용했다면, 원본 질문이 어떻게 여러 질문으로 확장되었는지 확인합니다.\n",
    "        - `Re-ranker`를 사용했다면, 초기 검색 결과와 재순위화된 후의 문서 순서가 어떻게 바뀌었는지 비교 분석합니다.\n",
    "        - 최종적으로 LLM에 전달된 전체 프롬프트(컨텍스트 포함) 내용을 확인하며 챗봇의 답변 생성 과정을 디버깅합니다.\n",
    "\n",
    "### 캡스톤 프로젝트 연계 방안\n",
    "- 이 Q&A 봇은 '사내 규정 안내 봇', '법률 문서 검색 어시스턴트', '개인화된 학습 자료 추천 봇' 등 여러분의 캡스톤 프로젝트에서 핵심 기능으로 활용될 수 있습니다.\n",
    "- 고급 RAG 기법의 구현 및 디버깅 경험은 현재 가장 수요가 높은 LLM 애플리케이션 개발 역량을 증명하는 좋은 사례가 될 것입니다.\n",
    "- LangSmith를 활용한 추적 및 평가는 단순한 기능 구현을 넘어, 서비스의 신뢰성과 운영 효율성까지 고려하는 프로페셔널한 개발 접근법을 보여줍니다.\n",
    "\n",
    "---\n",
    "\n",
    "## 8. 트러블슈팅 (Troubleshooting)\n",
    "\n",
    "- **LoRA 파인튜닝 후 모델 성능이 오히려 떨어지거나, 이상한 답변을 생성하나요?**\n",
    "  - **학습률(Learning Rate)이 너무 높을 수 있습니다.** 파인튜닝은 매우 낮은 학습률(e.g., `1e-5` ~ `5e-4`)로 시작하는 것이 일반적입니다. 학습률이 너무 높으면 사전 학습된 지식이 손상될 수 있습니다.\n",
    "  - **LoRA 설정값을 조정해보세요.** `r` (rank)과 `lora_alpha`는 중요한 하이퍼파라미터입니다. `alpha`를 `r`의 2배 정도로 설정하는 것이 일반적인 출발점입니다. (`lora_alpha=32`, `r=16`)\n",
    "  - **학습 데이터의 품질을 확인하세요.** 적은 양이라도 품질이 낮은 데이터(e.g., 잘못된 형식, 관련 없는 내용)가 포함되면 모델 성능에 악영향을 줍니다.\n",
    "- **RAG의 재순위화(Re-ranking) 단계에서 관련 없는 문서가 더 높은 점수를 받나요?**\n",
    "  - **Cross-Encoder 모델이 현재 도메인에 적합하지 않을 수 있습니다.** 일반적인 목적으로 학습된 Cross-Encoder는 특정 전문 분야의 미묘한 의미 차이를 잘 잡아내지 못할 수 있습니다. 해당 도메인의 데이터로 파인튜닝된 Cross-Encoder를 사용하거나, 직접 파인튜닝하는 것을 고려해볼 수 있습니다.\n",
    "- **AI 에이전트가 의도와 다른 도구(Tool)를 사용하거나, 무한 루프에 빠지나요?**\n",
    "  - **프롬프트가 명확하지 않기 때문일 가능성이 높습니다.** ReAct 프롬프트에서 각 도구의 역할과 사용법(인풋 형식 등)을 매우 명확하고 상세하게 설명해야 합니다. \"이 도구는 이런 상황에서, 이런 형식의 입력을 받아, 이런 결과를 반환한다\" 와 같이 구체적으로 명시해주세요.\n",
    "  - **생각(Thought) 단계를 강제하세요.** LLM이 충분히 생각하지 않고 성급하게 행동을 결정하는 것을 방지하기 위해, 프롬프트에 \"먼저 다음 행동 계획을 신중하게 생각하고, 그 다음에 행동을 결정하라\"는 지시를 명시적으로 추가하는 것이 효과적입니다.\n",
    "- **LangGraph 실행 시 `RecursionError`가 발생하나요?**\n",
    "  - 이는 그래프의 조건부 엣지(conditional edge) 로직이 잘못되어 두 개 이상의 노드를 계속해서 오가는 무한 루프가 발생했음을 의미합니다. 각 노드의 실행 후 상태(State)를 면밀히 추적하고, 조건부 엣지의 분기 조건이 명확하게 종료(END) 상태로 이어질 수 있도록 로직을 수정해야 합니다.\n",
    "\n",
    "더 자세한 문제 해결 가이드나 다른 동료들이 겪은 문제에 대한 해결책이 궁금하다면, 아래 문서를 참고해주세요.\n",
    "\n",
    "- **➡️ [Geumdo-Docs: TROUBLESHOOTING.md](../../../TROUBLESHOOTING.md)**\n",
    "\n",
    "---\n",
    "\n",
    "## 9. 개념 확인 퀴즈 (Concept Check Quiz)\n",
    "\n",
    "1. PEFT, 특히 LoRA 방식이 전체 파인튜닝(Full Fine-tuning)에 비해 가지는 3가지 주요 이점은 무엇인가요?\n",
    "2. 고급 RAG 파이프라인에서 '재순위화(Re-ranking)' 단계가 필요한 이유는 무엇이며, 이는 기존의 벡터 검색(Retrieval)과 어떻게 다른가요?\n",
    "3. LangGraph가 기존의 LangChain Expression Language (LCEL)과 비교하여 AI 에이전트 구축에 더 적합한 이유는 무엇인가요?\n",
    "\n",
    "---\n",
    "\n",
    "## 10. 과제 (Assignment)\n",
    "\n",
    "1. **LoRA 파인튜닝 설계**: 여러분이 Llama 3 8B 모델을 '법률 자문' 챗봇으로 파인튜닝하려고 합니다. Hugging Face의 `peft` 라이브러리를 사용한다고 가정할 때, 어떤 `LoraConfig`를 사용할지 예시를 작성하고, 왜 `target_modules`를 특정 레이어(예: `q_proj`, `k_proj`, `v_proj`)에 주로 적용하는지 이유를 설명해 보세요.\n",
    "2. **AI 에이전트 프롬프트 작성**: '오늘 서울의 날씨를 확인하고, 날씨가 비가 오면 우산을 챙기라는 메시지를, 맑으면 좋은 하루 보내라는 메시지를 반환하는' AI 에이전트를 만든다고 가정해 보세요. 이 에이전트를 위한 ReAct 프롬프트의 '생각(Thought)' 부분을 어떻게 작성할지 예시를 보여주세요. (사용 가능한 도구: `search_weather(city: str)`)\n",
    "\n",
    "---\n",
    "\n",
    "## 11. 되짚어보기 (Summary)\n",
    "\n",
    "이번 파트에서는 생성형 AI와 자율 에이전트의 최신 기술들을 깊이 있게 탐구했습니다.\n",
    "\n",
    "- **효율적 LLM 파인튜닝**: PEFT와 LoRA의 원리를 이해하고, 적은 리소스로 LLM을 특정 작업에 맞게 효율적으로 튜닝하는 방법을 배웠습니다.\n",
    "- **고급 RAG 기술**: 쿼리 변환과 재순위화 기법을 통해 RAG 시스템의 검색 정확도를 한 단계 높여, 더 신뢰도 높은 답변을 생성하는 방법을 확인했습니다.\n",
    "- **자율 AI 에이전트**: ReAct 프레임워크를 통해 에이전트의 행동 원리를 이해하고, LangGraph를 사용하여 여러 에이전트가 협력하는 복잡하고 순환적인 워크플로우를 구축하는 방법을 탐구했습니다.\n",
    "- **LLMOps/AgentOps**: LLM과 에이전트 기반 애플리케이션의 운영 및 평가를 위한 LLMOps의 개념과 LangSmith와 같은 전문 도구의 필요성을 이해했습니다.\n",
    "\n",
    "---\n",
    "\n",
    "## 12. 더 깊이 알아보기 (Further Reading)\n",
    "- [Hugging Face PEFT 라이브러리 공식 문서](https://huggingface.co/docs/peft)\n",
    "- [Pinecone: RAG-Fusion 설명 블로그](https://www.pinecone.io/learn/rag-fusion/)\n",
    "- [LangChain: ReAct 프레임워크 설명](https://python.langchain.com/docs/modules/agents/concepts/react)\n",
    "- [LangGraph 공식 문서](https://langchain-ai.github.io/langgraph/): 다양한 에이전트 아키텍처 예제 포함\n",
    "\n",
    "---\n",
    "\n",
    "**➡️ 다음 시간: [고급 RAG 기법](./part_13.1_advanced_rag_techniques.md)**\n",
    "\n",
    "### 참고 자료\n",
    "\n",
    "*   [LangChain 공식 문서](https://python.langchain.com/docs/get_started/introduction): LangChain 라이브러리의 공식 문서\n",
    "*   [Awesome Agents](https://github.com/kyrolabs/awesome-agents): AI 에이전트 관련 최신 논문, 리소스 모음\n",
    "\n",
    "---\n",
    "\n",
    "### ⚠️ What Could Go Wrong? (토론 주제)\n",
    "\n",
    "생성형 AI와 에이전트 기술은 엄청난 가능성을 보여주지만, 동시에 통제 불가능성, 비용, 저작권 등 수많은 잠재적 위험을 안고 있습니다.\n",
    "\n",
    "1.  **환각 현상의 통제 불가능성 (Uncontrollability of Hallucinations)**\n",
    "    *   RAG(Retrieval-Augmented Generation)나 정교한 프롬프트 엔지니어링을 통해 LLM이 사실이 아닌 내용을 그럴듯하게 지어내는 '환각'을 줄일 수는 있지만, 완전히 없애는 것은 현재 기술로는 거의 불가능합니다.\n",
    "    *   환각 현상이 치명적인 오류로 이어질 수 있는 서비스(예: 법률 자문 챗봇, 의료 정보 제공)에 생성형 AI를 어떻게 '안전하게' 적용할 수 있을까요? '사실 기반' 응답과 '창의적' 응답의 경계를 어떻게 제어해야 할까요?\n",
    "\n",
    "2.  **데이터 오염과 저작권 문제 (Data Contamination and Copyright Issues)**\n",
    "    *   LLM이 인터넷의 저작권 있는 자료(코드, 기사, 이미지)를 학습하여 매우 유사한 결과물을 생성했을 때, 이는 저작권 침해에 해당할까요? 서비스 제공자는 어떤 법적 책임을 져야 할까요?\n",
    "    *   AI가 대량으로 생성한 저품질 콘텐츠가 다시 인터넷에 확산되고, 다음 세대 AI가 그 오염된 데이터를 학습하게 되는 '모델 자가 중독(Model Autophagy)' 현상은 AI 생태계에 어떤 장기적인 위험을 초래할까요?\n",
    "\n",
    "3.  **예측 불가능한 비용 문제 (Unpredictable Cost Issues)**\n",
    "    *   복잡한 에이전트 시스템에서, 사용자의 간단한 질문 하나가 내부적으로 수십, 수백 번의 LLM API 호출로 이어져 막대한 비용을 발생시킬 수 있습니다. (예: \"A와 B를 비교 분석하고, 그 결과를 바탕으로 C에 대한 리포트를 써줘.\")\n",
    "    *   프로덕션 환경에서 생성형 AI 서비스의 운영 비용을 어떻게 안정적으로 예측하고 통제할 수 있을까요? 사용자별로 토큰 사용량을 제한하거나, 비용 효율적인 모델(오픈소스 소형 모델)을 혼합하는 전략의 장단점은 무엇일까요?\n",
    "\n",
    "4.  **사용자의 악의적인 이용 (Malicious Use by Users)**\n",
    "    *   사용자가 생성형 AI를 악용하여 가짜 뉴스, 스팸 메일, 피싱 공격 스크립트, 딥페이크 등 유해하거나 불법적인 콘텐츠를 대량으로 생산하는 문제를 어떻게 막을 수 있을까요?\n",
    "    *   서비스 제공자 입장에서, 이러한 악용을 방지하기 위해 어떤 기술적, 정책적 안전장치(예: 입력/출력 필터링, 워터마킹, 사용자 행위 모니터링)를 마련해야 할까요? 자유로운 활용과 통제 사이의 균형점은 어디일까요?\n",
    "\n",
    "5.  **고정된 지식과 최신성 부족 (Fixed Knowledge and Lack of Timeliness)**\n",
    "    *   대부분의 LLM은 특정 시점(Knowledge Cutoff)까지의 데이터로 학습되어, 그 이후의 최신 정보를 알지 못합니다. RAG로 이를 보완할 수 있지만, 실시간으로 빠르게 변하는 정보(예: 주식 시세, 뉴스 속보)를 다뤄야 하는 서비스에 LLM을 적용할 때의 근본적인 한계는 무엇일까요? "
   ]
  }
 ],
 "metadata": {},
 "nbformat": 4,
 "nbformat_minor": 5
}
