페이지 목차
이 페이지에서 검색
로컬 LLM
이 페이지에 묻기
로컬 LLM · 현재 차시와 목차 본문에서만 찾아 답합니다. 답을 지어내지 않고 해당하는 대목을 그대로 보여 주며, 여기에 없으면 없다고 알려 드립니다.
생성형 AI가 아니라 이 페이지 본문을 찾아 그대로 보여 주는 방식입니다. 외부로 나가는 요청이 없습니다.
LOCAL · LLM
로컬 LLM
생성 수정
로컬 모델 실행과 GPU·메모리 이해부터 서빙·RAG·도구 호출·업무형 앱 구현까지 차례로 살펴봅니다.
42개 문서 · 1일차 · 4 / 42
3차시 · 로컬 LLM 개발환경 구축
지도 위치 : 1일차 · ①하드웨어 층과 그 위의 소프트웨어 사슬 | 이전: 2차시 LLM 구조와 추론 원리 | 다음: 4차시 Hugging Face 오픈소스 LLM 활용 키워드 : Python, PyTorch, CUDA 환경 확인, GPU VRAM 확인, LLM 실행을 위한 하드웨어 환경 구성
이 차시를 다 읽으면
- GPU에서 모델이 돌기까지의 다섯 고리 사슬 (GPU → 드라이버 → CUDA → PyTorch → 라이브러리)을 순서대로 말할 수 있다.
nvidia-smi화면에서 Driver Version · CUDA Version · Memory-Usage · GPU-Util · Processes 를 읽고, "CUDA Version"이 무엇을 뜻하는지 바로 말할 수 있다.torch.cuda.is_available()가False일 때 어느 고리부터 볼지 말할 수 있다.- LLM용 하드웨어의 우선순위(VRAM > 메모리 대역폭 > RAM > 디스크 > CPU) 를 이유와 함께 말할 수 있다.
- 왜 엔진마다 가상환경을 따로 만드는지, 왜 Ollama는 PyTorch 없이 GPU를 쓰는지 설명할 수 있다.
0. 이 차시의 판별 축
| # | 축 | 왼쪽 (0) | 오른쪽 (1) | 이 축으로 갈리는 것 | 큰 축 (README 5장) |
|---|---|---|---|---|---|
| 1 | 어디까지 적용되는가 | 전역 (시스템 전체) | 격리 (이 프로젝트만) | 드라이버 ↔ 가상환경 안의 PyTorch | ⑤ 하나 ↔ 여럿의 파생 (환경 분리) |
| 2 | 어디에 있는가 | 디스크 · RAM | VRAM | 모델 파일 ↔ GPU에 올라간 가중치 | ① 디스크 ↔ 메모리 |
| 3 | 일꾼이 몇인가 | 순차 (CPU) | 병렬 (GPU) | 왜 LLM에 GPU가 필요한가 | 순차 ↔ 병렬 (파생 축) |
이 차시의 질문은 "내 컴퓨터의 GPU로 모델을 돌릴 준비가 되었는가, 안 되었다면 어디가 끊겼는가" 입니다. 파이썬 · PyTorch · CUDA · 드라이버는 따로따로 설치하는 부품이 아니라 서로 맞물려야 하는 조합 입니다. 그래서 이 차시는 그 조합을 1절의 사슬 그림 으로 세우고, torch.cuda.is_available()가 False일 때 왜 nvidia-smi부터 보는지 를 그 그림으로 설명합니다. 그리고 2절에서 LLM에서 특히 중요한 VRAM 숫자 읽기 를 익힙니다.
1. GPU에서 모델이 돌기까지 — 다섯 고리 사슬 ⭐
1.1 사슬 그림
⑤ 라이브러리 transformers · accelerate · bitsandbytes · vllm ┐
│ 위에 얹힘 │ 가상환경 안
④ PyTorch 텐서 계산 + GPU 할당. 빌드마다 CUDA 버전이 정해져 있음 ┘ (격리)
│ 호출
③ CUDA 런타임 GPU에 계산을 시키는 NVIDIA의 플랫폼 ← 대개 PyTorch 휠에 같이 들어 있음
│ 호출
② NVIDIA 드라이버 OS가 GPU와 말하는 통로 ┐ 시스템 전체
│ │ (전역)
① GPU VRAM · 연산 코어 ┘
한 고리라도 끊기면 위쪽 전부가 CPU로 떨어지거나 에러가 납니다. 그래서 점검은 아래에서 위로 합니다.
| 고리 | 정의 (유 + 종차) | 확인 명령 | 적용 범위 |
|---|---|---|---|
| ② 드라이버 | [시스템 소프트웨어]인데, [ OS가 GPU 하드웨어를 부릴 수 있게 하는 통로 ]라는 점에서 응용 라이브러리와 구별된다 | nvidia-smi | 전역 |
| ③ CUDA | [병렬 컴퓨팅 플랫폼]인데, [ NVIDIA GPU에 그래픽이 아닌 범용 계산(행렬 곱 등)을 시킨다 ]는 점에서 화면을 그리는 그래픽 API와 구별된다 | torch.version.cuda | PyTorch에 묶여 들어옴 |
| ④ PyTorch | [딥러닝 프레임워크]인데, [ 텐서(숫자를 여러 차원으로 늘어놓은 배열) 연산과 GPU 메모리 할당을 맡는다 ]는 점에서 그 위에 얹히는 모델 라이브러리와 구별된다 | torch.cuda.is_available() | 격리 (가상환경) |
| ⑤ 라이브러리 | [Python 패키지]인데, [ PyTorch 위에서 모델 로딩 · 양자화 · 서빙을 한다 ]는 점에서 프레임워크 자체와 구별된다 | pip list | 격리 |
1.2 ⚠️ "CUDA를 따로 설치해야 하나요?"
대부분의 경우 아닙니다. pip로 받는 GPU용 PyTorch에는 필요한 CUDA 런타임이 같이 들어 있습니다. 시스템에 필요한 것은 충분히 새 드라이버 뿐입니다.
| 필요한 것 | Transformers로 실행 (4차시) | Ollama로 실행 (5차시) |
|---|---|---|
| NVIDIA 드라이버 | ⭕ 필요 | ⭕ 필요 |
| CUDA Toolkit (컴파일러 포함 전체) | 대개 불필요 | 불필요 |
| PyTorch | ⭕ 필요 (CUDA 포함 빌드) | ❌ 불필요 |
⭐ Ollama는 PyTorch 없이 GPU를 씁니다. Ollama는 llama.cpp 계열의 자체 엔진과 GPU 라이브러리를 함께 들고 오기 때문에 ②드라이버만 있으면 됩니다. 그래서 "PyTorch 설치가 꼬였는데 Ollama는 잘 돈다"는 정상입니다. 같은 GPU 위에 서로 다른 사슬 두 개 가 있는 것입니다.
앞으로 다시 만납니다 — 18차시 vLLM은 특정 PyTorch 버전을 고정해서 설치합니다. 그래서 Transformers용 환경과 반드시 다른 가상환경 을 씁니다(3절).
2. ⭐ nvidia-smi 읽는 법 — 이 과정에서 가장 자주 볼 화면
nvidia-smi를 치면 이런 화면이 나옵니다. (숫자는 예시 · 실측 아님 )
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 5xx.xx Driver Version: 5xx.xx CUDA Version: 12.x | ← ⓐ ⓑ
|-------------------------------+----------------------+----------------------+
| GPU Name | Bus-Id | |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
| 0 NVIDIA GeForce RTX 4090 | 00000000:01:00.0 | |
| 30% 45C P2 120W / 450W | 17500MiB / 24564MiB | 85% Default | ← ⓒ ⓓ
+-------------------------------+----------------------+----------------------+
| Processes: |
| GPU PID Type Process name GPU Memory |
| 0 1234 C /usr/local/bin/ollama 17200MiB | ← ⓔ
+-----------------------------------------------------------------------------+
| 표시 | 뜻 | ⚠️ 흔한 오해 |
|---|---|---|
| ⓐ Driver Version | 설치된 드라이버 버전 | — |
| ⓑ CUDA Version | 이 드라이버가 지원하는 CUDA의 최대 버전 | ❌ "설치된 CUDA 버전"이 아닙니다. CUDA를 하나도 안 깔아도 표시됩니다 |
| ⓒ Memory-Usage | VRAM 사용량 / 전체 | 모델 크기만이 아님. KV 캐시 · CUDA 컨텍스트 · 다른 프로세스까지 합친 값 |
| ⓓ GPU-Util | 최근 순간에 GPU가 일하고 있던 시간 비율 | ❌ "GPU를 얼마나 꽉 채워 쓰는가"가 아님. 요청이 없으면 모델이 올라가 있어도 0%에 가까움 |
| ⓔ Processes | 누가 VRAM을 쓰고 있는가 | 환경(WSL · 컨테이너)에 따라 목록이 비어 보일 수 있음 |
⭐ ⓑ와 PyTorch의 관계 : PyTorch가 들고 온 CUDA 버전(torch.version.cuda)이 ⓑ보다 높으면 GPU를 못 잡을 수 있습니다. 대체로 ⓑ ≥ PyTorch의 CUDA 버전 이면 됩니다. 정확한 호환 범위는 버전에 따라 다르니 PyTorch 공식 설치 페이지에서 확인합니다.
💡 숫자를 계속 보려면 이렇게 씁니다. 14 · 22차시 측정 때 그대로 다시 씁니다.
watch -n 1 nvidia-smi
nvidia-smi --query-gpu=utilization.gpu,memory.used,memory.total --format=csv -l 1
🔍 읽는 포인트 : -n 1, -l 1은 1초마다 갱신 . --query-gpu= 뒤에 쉼표로 보고 싶은 열만 고른 것입니다.
앞으로 다시 만납니다 — 5차시에서 모델을 띄우고 내릴 때 ⓒ가 늘었다 줄었다 하는 것을 직접 봅니다. 9차시에서는 ⓒ의 숫자를 가중치 + KV 캐시 + 오버헤드 로 쪼개 계산과 맞춰 봅니다.
3. Python 쪽 — 격리와 확인
3.1 왜 엔진마다 가상환경을 따로 만드는가
먼저 두 용어를 정의합니다.
가상환경 (Virtual Environment) — [격리 장치]인데, [ 프로젝트마다 파이썬과 패키지 묶음을 별도의 폴더에 따로 둔다 ]는 점에서 컴퓨터 전체가 패키지 한 벌을 같이 쓰는 전역 설치와 구별된다. 격리하는 대상이 파이썬 패키지 라는 점에서, OS와 시스템 라이브러리까지 통째로 묶는 Docker 컨테이너(5차시 2.3)와도 구별된다.
의존성 (Dependency) — 내 코드가 돌기 위해 필요한 다른 패키지와 그 버전. 의존성 충돌 은 프로젝트 A는 torch 2.x의 한 버전을, B는 다른 버전을 원할 때 생깁니다. 한 컴퓨터에 전역으로는 한 버전만 깔 수 있으므로 하나를 맞추면 다른 하나가 깨집니다.
| 전역 설치 | 가상환경 | |
|---|---|---|
| 패키지가 놓이는 곳 | 시스템 파이썬 한 곳 | 환경마다 자기 폴더 |
| A와 B가 다른 버전을 원하면 | 둘 중 하나가 깨짐 | 각자 자기 버전을 가짐 |
| 망가지면 | 시스템 파이썬을 고쳐야 함 | 그 환경만 지우고 다시 만들면 끝 |
LLM 쪽에서는 이 충돌이 반드시 일어납니다.
| 환경 | 들어가는 것 | 왜 따로인가 |
|---|---|---|
llm-hf | torch, transformers, accelerate, bitsandbytes | 4 · 11차시 실습용 |
llm-vllm | vllm (자기가 원하는 torch 버전을 고정해서 끌고 옴) | 기존 torch를 덮어써 llm-hf를 깨뜨림 |
llm-app | ollama, openai, streamlit, fastapi | 앱은 GPU 라이브러리가 필요 없음 — API로 부르기만 함 |
0절 축 1로 보면 이렇습니다.
| 전역 (0) — 시스템에 한 번 | 격리 (1) — 환경마다 따로 |
|---|---|
| NVIDIA 드라이버, Ollama | PyTorch, transformers, vllm, 앱 라이브러리 |
| 바꾸면 모든 것 에 영향 → ⚠️ 사람 승인 | 바꾸다 망가지면 환경만 지우고 다시 |
conda create -n llm-hf python=3.12 -y # 또는: uv venv llm-hf --python 3.12
conda activate llm-hf
🔍 읽는 포인트 : -n llm-hf가 환경 이름 , python=3.12가 그 안의 파이썬 버전. 두 번째 줄 activate가 그 환경 안으로 들어가는 명령입니다. 터미널 프롬프트 앞에 (llm-hf)가 붙으면 격리 안으로 들어온 것이고, 이때부터 pip install은 이 환경 폴더에만 깔립니다. ⚠️ 새 터미널을 열면 다시 activate해야 합니다. 파이썬 버전은 설치할 라이브러리가 지원하는 범위에서 고릅니다.
3.2 ⭐ 다섯 줄 확인 스크립트
import sys, torch
print(sys.version) # ① 파이썬 버전
print(torch.__version__) # ② PyTorch 버전 — 끝에 +cpu 가 붙었는가?
print(torch.version.cuda) # ③ PyTorch가 들고 온 CUDA 버전 (CPU 빌드면 None)
print(torch.cuda.is_available()) # ④ GPU를 실제로 잡았는가
print(torch.cuda.get_device_name(0), torch.cuda.get_device_properties(0).total_memory / 1024**3) # ⑤ 이름, VRAM(GB)
🔍 읽는 포인트 : ②의 끝에 +cpu 가 있거나 ③이 None 이면 그 순간 결론이 납니다 — CPU 전용 PyTorch 입니다. ④가 True이고 ⑤에 내 GPU 이름과 약 24가 찍혀야 통과입니다.
3.3 ⚠️ CPU용 PyTorch 함정
pip install torch가 CPU 전용 빌드 를 설치하는 경우가 있습니다(OS · 설치 방법 · 패키지 색인에 따라 다름). 에러가 나지 않습니다. 그냥 느립니다. 8B 모델이 "돌긴 도는데" 한 문장에 몇 분씩 걸리면 가장 먼저 의심할 곳입니다.
is_available()가 False일 때 점검 순서는 1.1의 사슬을 아래에서 위로 올라가는 것입니다. 아래 고리가 끊겼는데 위 고리를 아무리 고쳐도 소용없기 때문입니다.
| 순서 | 확인 | 이상하면 |
|---|---|---|
| 1 | nvidia-smi가 GPU를 보여 주는가 | ②드라이버 문제 → ⚠️ 재설치는 사람이 승인 |
| 2 | torch.__version__에 +cpu가 붙었는가 | ④CPU 빌드 → PyTorch 공식 설치 페이지의 CUDA용 명령 으로 다시 설치 |
| 3 | torch.version.cuda가 nvidia-smi의 CUDA Version 이하인가 | 드라이버가 너무 오래됨 → 드라이버 업데이트(승인) 또는 낮은 CUDA용 PyTorch |
| 4 | 지금 활성화된 환경이 맞는가 | 다른 환경에 깔았음 — 프롬프트 앞의 (환경 이름)을 확인 (3.1) |
⚠️ 에러가 가리키는 곳과 원인이 있는 곳은 다를 수 있습니다. 예를 들어 컨테이너 안에서 GPU가 안 잡히면 "컨테이너라서 GPU를 못 쓴다"고 결론 내리기 쉽지만, 실제 원인은 그 안에 CPU 빌드 PyTorch가 깔려 있던 것 인 경우가 흔합니다. 증상은 GPU 쪽에서 보이지만 원인은 설치된 패키지에 있는 것입니다. 그래서 GPU 문제처럼 보이면 먼저 pip list로 무엇이 깔려 있는지 부터 봅니다.
💡 WSL에서 하는 경우 : 드라이버는 Windows 쪽에 설치 하고 WSL 안에는 Linux용 디스플레이 드라이버를 깔지 않는 것이 NVIDIA 안내입니다. WSL 안에서 nvidia-smi가 보이면 ②는 통과입니다.
4. LLM을 위한 하드웨어 — 무엇이 먼저인가
4.1 ⭐ 우선순위
| 순위 | 자원 | 왜 이 순위인가 | 부족하면 |
|---|---|---|---|
| 1 | VRAM | 가중치 + KV 캐시가 여기에 다 들어가야 GPU 속도가 나옴 (README 7장 문장 1) | 일부가 RAM으로 밀려나 크게 느려짐 (12차시) 또는 로딩 실패 |
| 2 | 메모리 대역폭 | Decode는 토큰 하나마다 가중치 전체를 읽음 (2차시 4절) → 읽는 속도가 곧 생성 속도의 상한 | 같은 VRAM이라도 TPS가 낮음 (15차시) |
| 3 | RAM | 모델 로딩 경로 · VRAM에 못 들어간 층의 피난처 | 로딩 중 멈춤, CPU 혼합 추론 불가 |
| 4 | 디스크 | 모델 하나가 수 GB ~ 수십 GB. 용량 과 읽기 속도 (로딩 시간) | 다운로드 실패, 첫 로딩이 오래 걸림 |
| 5 | CPU | 토크나이저 · 앱 · 전처리. 추론 자체는 GPU가 함 | 대개 병목이 아님 |
⭐ 가중치가 차지하는 메모리는 파라미터 수 × 숫자 하나의 바이트 수 로 어림합니다. 숫자 하나를 FP16/BF16(16비트)으로 저장하면 2바이트, 4bit로 줄이면 0.5바이트입니다. 여기에 KV 캐시와 실행 오버헤드가 더해집니다(9차시에서 완성). 이 식을 RTX 4090 24GB에 대 봅니다.
| 모델 · 정밀도 | 가중치만 (계산값) | 24GB에 |
|---|---|---|
| 8B · FP16/BF16 (2바이트) | 8 × 2 ≈ 16GB | 들어감. KV 캐시 여유는 몇 GB |
| 8B · 4bit (0.5바이트) | 8 × 0.5 ≈ 4GB (+ 메타데이터) | 넉넉함 |
| 32B · FP16 | 32 × 2 ≈ 64GB | ❌ 안 들어감 → 양자화(10~12차시) |
4.2 순차 ↔ 병렬 — 왜 GPU인가
순차 ↔ 병렬 은 "계산을 몇 개의 연산 장치가 나눠 하는가"의 축입니다(README 5.3).
| CPU | GPU | |
|---|---|---|
| 일꾼 | 소수의 강한 일꾼 (코어 수 개~수십 개) | 수천 개의 단순한 일꾼 |
| 잘하는 일 | 복잡하고 갈래가 많은 일을 차례로 | 단순한 곱셈 · 덧셈을 한꺼번에 |
| 비유 | 대학교수 1명 | 초등학생 3,000명 |
병렬화의 조건은 하나입니다. 각 계산이 서로의 결과를 기다리지 않아도 되는가(서로 독립인가). Transformer 한 층의 계산은 거대한 행렬 곱이고, 행렬 곱의 각 칸은 다른 칸의 결과 없이 따로 계산할 수 있습니다. 그래서 수천 명의 일꾼에게 나눠 줄 수 있고, 그것이 LLM에 GPU가 필요한 이유입니다.
⚠️ 그런데 2차시에서 Decode는 순차 라고 했습니다. 모순이 아닙니다.
| 층위 | 순차인가 병렬인가 |
|---|---|
| 토큰과 토큰 사이 | 순차 — 앞 토큰이 나와야 다음 토큰 (Decode) |
| 토큰 하나를 만드는 계산 안 | 병렬 — 수십억 번의 곱셈을 GPU가 동시에 |
그리고 이것은 동기 ↔ 비동기와 다른 축 입니다(README 5.3, 7차시에서 자세히). GPU를 쓴다고 "기다리지 않게" 되는 것이 아니라, 계산 자체가 빨라지는 것입니다.
5. 실습 — 맡기고 검수하기
이 차시는 시스템을 건드리는 실습입니다. AI에게는 진단과 가상환경 작업만 맡기고, 전역 변경은 승인 절차를 둡니다.
지시
목표: 이 서버에서 LLM 실습(Transformers, 이후 vLLM)을 할 수 있는지 진단하고,
Transformers용 가상환경 llm-hf를 만들어 GPU가 잡히는지 확인해줘.
맥락: PyTorch 설치 명령은 pytorch.org의 공식 설치 페이지(Get Started)에서 이 서버의
드라이버가 지원하는 CUDA 버전에 맞는 것을 골라. 기억에 의존하지 마.
제약: - NVIDIA 드라이버, CUDA Toolkit 설치·삭제·업데이트는 하지 마. 필요하면 이유와 명령만 보고하고 멈춰.
- 가상환경 llm-hf 밖에는 pip install 하지 마.
보고 형식: [항목 | 확인 명령 | 출력 원문 | 판정] 표
항목: OS, GPU 이름, Driver Version, nvidia-smi CUDA Version, 전체/사용 중 VRAM,
RAM 전체, 디스크 여유(모델 저장 위치 기준), Python 버전,
torch.__version__, torch.version.cuda, torch.cuda.is_available()
추측하지 말고 실행 출력 원문을 붙여.
받을 증거
nvidia-smi전체 화면 원문 (요약 금지)- 3.2절 다섯 줄 스크립트의 출력 원문
- 설치에 쓴 pip 명령 그대로 (어느 색인에서 받았는지 보이도록)
내가 직접 볼 것
| 볼 것 | 이걸로 아는 것 |
|---|---|
torch.__version__ 끝에 +cpu가 없는가 | CPU 빌드 함정에 빠지지 않았는가 |
torch.version.cuda ≤ nvidia-smi의 CUDA Version | 사슬 ②와 ④가 맞물리는가 |
| Memory-Usage의 사용 중 값 | 실습 전부터 VRAM을 먹는 프로세스가 있는가 — 있으면 Processes 목록(2절 ⓔ)에서 누구인지 확인 |
| 디스크 여유가 200GB 이상 인가 | 2일차에 모델을 여러 개 받을 수 있는가 (README 8장) |
| AI가 드라이버를 건드리지 않았는가 | 전역 변경은 내 승인 사항 |
부록 A. 스스로 확인하기
| # | 질문 | 답이 있는 곳 |
|---|---|---|
| 1 | GPU에서 모델이 돌기까지 다섯 고리를 아래에서부터 말하면? | 1.1 |
| 2 | 다섯 고리 중 전역인 것과 격리인 것은? 가상환경은 무엇을 격리하며, 의존성 충돌은 왜 생기는가? | 1.1, 3.1 |
| 3 | GPU용 PyTorch를 쓰려면 CUDA Toolkit을 따로 깔아야 하는가? | 1.2 |
| 4 | Ollama가 PyTorch 없이 GPU를 쓰는 이유는? | 1.2 |
| 5 | nvidia-smi의 CUDA Version은 무엇의 버전인가? | 2 |
| 6 | GPU-Util이 0%인데 Memory-Usage가 높으면 무슨 상황인가? | 2 |
| 7 | is_available()가 False일 때 점검 순서는? | 3.3 |
| 8 | LLM 하드웨어 우선순위 1, 2위와 그 이유는? | 4.1 |
| 9 | CPU와 GPU는 순차 ↔ 병렬 축에서 어떻게 다르고, Decode는 순차인데 왜 GPU가 필요한가? | 4.2 |
부록 B. 자주 하는 실수
| 실수 | 바로잡기 |
|---|---|
| "nvidia-smi에 CUDA 12.x라고 나오니 CUDA 12.x가 설치돼 있다" | ❌ 드라이버가 지원하는 최대치 입니다 |
| "에러 없이 돌아가니 GPU를 쓰고 있다" | ⚠️ CPU 빌드는 에러 없이 느립니다. +cpu와 is_available()로 확인 |
| "PyTorch가 안 되니 드라이버부터 다시 깔자" | ❌ 사슬을 아래에서 위로 점검. 드라이버 재설치는 시스템 전체 변경 → 승인 |
| "vLLM도 지금 환경에 같이 깔자" | ❌ vLLM은 torch 버전을 고정해 끌고 옴. 환경을 분리 |
| "GPU-Util이 낮으니 GPU가 남는다" | ⚠️ 남는지는 Memory-Usage 로 판단. Util은 "지금 일하는 중인가"일 뿐 |
| "CPU가 좋으면 LLM이 빠르다" | ❌ 순위는 VRAM > 대역폭 이 먼저 |
부록 C. NotebookLM 복습 프롬프트
이 3차시 노트만 근거로 6문제를 내줘. 비전공자 기준으로.
"nvidia-smi의 CUDA Version이 뜻하는 것", "CPU용 PyTorch 함정", "전역(드라이버) ↔ 격리(가상환경)"는 반드시 포함해줘.
답은 내가 답한 다음에 채점하고, 틀린 이유를 노트의 절 번호를 근거로 설명해줘.
LangTailor