개발자로 성장하는 데 필요한 건 어떤 태도일까? | 우아한 형제들 출신 멘토님
F-Lab : 상위 1% 개발자들의 멘토링
#항해99 #항해플러스 #AI #AI개발자 #항해플러스AI후기 #LLM #HuggingFace #Langchain
블로그에서 읽기 : https://velog.io/@soonmac/hh-plus-ai-week5
드디어 내가 가장 배우고 싶은 랭체인과 RAG 주차가 찾아왔다.
5주차부터 프로젝트 제작을 위한 실무 지식들을 배운다.
나는 랭체인과 RAG를 사용해서 도메인에 특화된 프로젝트를 진행하고 싶었다.
그래서 논문 pdf를 주면 해당 논문에 대해 질의응답을 해주는 챗봇을 만들어보려고 한다.
## 🍀심화 과제 회고: Langchain과 RAG로 논문 요약 서비스 만들어보기
[깃헙 코드 보기](https://github.com/sosososoyoen/hh_plus_ai_3/tree/main/work/week5/%E1%84%89%E1%85%B5%E1%86%B7%E1%84%92%E1%85%AA)
플로우는 대략적으로
논문 pdf 파일을 받으면 pdf 내의 텍스트를 추출하여, 임베딩한 후 RAG의 벡터 DB에 담아두고 해당 논문의 요약본을 생성하는 서비스다.
from langchain.document_loaders import UnstructuredPDFLoader
loader = UnstructuredPDFLoader("./example.pdf")
docs = loader.load()
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1500,
chunk_overlap=200
)
splits = text_splitter.split_documents(docs)
vectorstore = Chroma.from_documents(
documents=splits,
embedding=OpenAIEmbeddings(api_key=api_key)
)
나는 UnstructuredPDFLoader
를 사용하여 pdf에서 텍스트를 추출하여 청크 사이즈를 1500, 오버랩을 200으로 맞추어 텍스트를 청킹했다. 그 다음엔 Chroma에 이를 임베딩하여 집어넣어줬는데.. 사실 여기까진 별 거 없었다.
테스트로 사용한 논문은 https://arxiv.org/pdf/2005.11401 RAG에 관한 논문이고
내 파이프라인이 만들어낸 요약본은 아래와 같았다. (gpt-4o-mini)
-------------------
### 1. 논문의 목적
이 논문의 목적은 RAG( retrieval-augmented generation) 모델을 통해 사실 추출 및 검증을 수행하는 새로운 접근 방식을 제시하는 것이다. 이를 통해 기존의 복잡한 파이프라인 시스템과 비교하여 단순성과 효율성을 강조한다. 특히, RAG는 도메인 특정 아키텍처나 중간 검색 감독 없이도 성능을 발휘할 수 있음을 보여준다.
### 2. 주요 기여
- 성능: RAG 모델은 3-way 분류에서 최첨단 모델과 비교했을 때 4.3% 내외의 성과를 보였다(§4.4, p.14).
- 단순성: RAG는 복잡한 시스템 없이도 유효한 결과를 도출할 수 있는 능력을 지닌다.
- 응용 가능성: 다양한 언어 모델의 기능을 접목하여 사실 기반의 대화형 응용 프로그램 개발에 기여할 수 있다.
### 3. 사용된 방법론
- 데이터셋: FEVER 데이터셋을 사용하여 모델 성능을 검증한다.
- 모델 검증: RAG 모델의 성능을 3-way 분류로 평가하며, 복잡한 파이프라인 대비 단순한 구조를 강조한다(§4.4, p.14).
- 정량적 결과: RAG 모델이 생성한 응답의 사실 정확성은 높은 비율로 유지되며, 특정 입력에 대해 더 정교한 응답을 낸다.
### 4. 주요 결과
- RAG 모델은 3-way 분류에서 정확도가 4.3% 떨어지는 성과를 보였으며, 이는 기존 방법론에 비해 우수한 수치를 나타낸다(§4.4, p.14).
- 생성된 응답의 구체성과 사실 기반 정확성을 높여, 더 나은 대화형 AI의 기반을 마련한다.
### 5. 한계 및 미래 연구 방향
- 한계: RAG 모델의 데이터 기반이 외부 지식원(예: 위키피디아)의 완전한 사실성을 담보하지 않음으로 인해 생성된 콘텐츠의 신뢰성에 문제가 있을 수 있다(§4.4, p.14).
- 미래 연구 방향: 다루기 어려운 또는 편향된 내용을 자동으로 생성하지 않도록 개선할 수 있는 AI 시스템의 개발 필요성; 다양한 언어의 지원 범위를 확대하여 모델의 효용성을 높이는 연구가 제안된다.
--------------------------
나는 내 서비스가 생성한 요약본을 ROUGE와 BertScore를 기준으로 평가했다.
사용 모델 : gpt-4o-mini
정답용 모델 : gpt-4o
### 🔷 ROUGE
| 지표 | 점수 | 설명 |
|-------------|--------|------|
| ROUGE-1 | 0.2543 | 단어 수준 유사도 |
| ROUGE-2 | 0.0702 | 2-gram 연속성 유사도 (문장 구성 구조) |
| ROUGE-L | 0.2197 | 문장 뼈대의 유사성 |
| ROUGE-Lsum | 0.2428 | 전체 요약 구조 유사성 |
### 🔷 BERTScore
| 지표 | 점수 | 설명 |
|-------------|--------|------|
| Precision | 0.7095 | 정답 요약 의미 중 포함된 비율 |
| Recall | 0.6887 | 내가 쓴 요약이 정답을 얼마나 커버했는지 |
| F1 | 0.6990 | 의미 유사성 종합 점수 (사람 기준으로 매우 양호함) |
의미적으로는 핵심 내용을 잘 전달한 것 같으나,
문장 구성 방식이나 표현 스타일은 논문 요약 스타일과 차이가 있어보인다.
그리고, 출처를 적어달라했는데 얘가 출처를 제대로 못적는거 보면.. 아직 개선의 여지가 더 필요해 보인다.
다음 과제를 위한 액션 아이템 3가지를 잡아보았다.
1. 프롬프트 수정
→ "논문 스타일로 학술적인 요약을 해줘" 같은 지시 문구 사용
2. 예시 문장 추가
→ 학습 시 논문 스타일 예시 문장을 함께 제시
3. 문단 단위 요약 후 통합
→ Recall + Precision 균형 잡기
심화 과제를 진행하면서, 궁금했던 점들을 과제 QnA 섹션과 멘토링 시간 때 코치님들께 여쭤보았다.
아래는 내가 한 질문들과 다른 분들이 질문해준 것 중에 나도 궁금했던 것들, 그리고 그 답변을 정리한 내용이다!
나처럼 실무에 LLM을 적용해야하는 사람들에게 도움이 됐으면 좋겠다.
## 🌼과제 QnA 섹션 정리
Q1. 요약 텍스트 생성 평가 지표 : ROUGE vs BertScore 어느 쪽이 더 좋을까요?
A.
ROUGE
* 전통적인 요약 태스크 평가 지표
* 정답과 모델이 예측한 요약을 갖고, 레퍼런스 요약 간의 겹치는 토큰 비율을 측정한다.
* 여러 LLM 간의 상대 비교에 유용하다. (=어느 모델이 더 좋은지 체크 가능)
BertScore
* 의미적 유사도 평가
* ROUGE와 달리 어휘가 달라도 유사한 문맥을 포착하기 때문에 점수가 높게 나올 수 있다.
=> 보통은 ROUGE, BertScore, GPT4 평가(LLM-as-a-Judge) 결과를 결합하여 최종 점수를 산출하는 방식으로 진행한다.
Q2. 한국어 텍스트를 평가할 때 중간에 영어로 번역 후 평가를 하는 것이 좋을까요?
A.
번역 품질이 낮으면 평가가 왜곡될 위험성이 많다.
Q3. OpenAI API 서버 불안정 시 대응 전략
A.
인하우스 LLM 대체 (오픈소스 LLM 파인튜닝)
* 규모가 큰 서비스의 경우, 오픈소스 LLM을 튜닝하는 방식으로 내재화를 많이 고려한다.
* 기존에 OpenAI API를 쓰고 있던 서비스라면 그 동안 쌓인 데이터를 통해 오픈소스 LLM을 튜닝하고,
* 모듈, 기능을 하나씩 대체하는 방식으로 진행한다.
Multi-LLM
* OpenAI 뿐만 아니라 Gemini, Claude 등 여러 api를 구성하여 한 쪽 모델에서 응답 실패 시 다음 모델로 전환하는 방식을 채택하기도 한다.
LLM 라우터
* 모든 기능에서 OpenAI를 쓰는 것은 가성비가 좋지 않기 때문에 LLM 라우터를 통해 쿼리 유형별로 최적의 모델을 라우팅한다.
질문 외 추가 팁
* RouteLLM - 프로젝트에 이런 오케스트레이션도 넣으면 좋지 않을까 싶다.
https://github.com/lm-sys/RouteLLM
* RAG 설계
* 모든 문서를 벡터 스토어에 넣기 어렵다면, 핵심 페이지만 선택적으로 저장하라
* 프롬프트 엔지니어링이나 function calling 등 LLM 관련 지식들이 모여있는 블로그
https://devocean.sk.com/blog/techBoardDetail.do?ID=165806&boardType=techBlog
* Outlines 라이브러리
* https://github.com/dottxt-ai/outlines
* LLM의 응답을 파싱해준다. 숫자만 추출하거나 json 포맷을 맞추기에 편해보임.
* 논문을 기반으로 질의응답을 해주는 챗봇 튜토리얼
* https://github.com/liner-engineering/liner-pdf-chat-tutorial
## 🌻멘토링 노트 정리
Q1. RecursiveCharacterTextSplitter에서 텍스트를 청크로 분할할 때 overlap하는 이유에 대해 궁금합니다.
A1.
* 만약 문서를 청크 단위로 완전히 잘라버리면, 문단의 앞뒤 맥락이 끊겨 의미 파악이 어려워진다.
* 어떤 설명이 문단 A 끝 + 문단 B 시작에 걸쳐 있을 경우, 완전히 분리되면 의미를 놓치게 됨.
* 오버랩 안한 chunk의 경우
```
일론 머스크 테슬라 최고경영자(CEO)가 자사 휴머노이드 로봇 '옵
티머스'의 생산이 중국의 희토류 수출 규제로 타격을 입었다고 밝혔다. 테슬라는 중 국 정부와 협의를 진행 중이며, 관련 자원 접근을 위한 승인 절차를 밟고 있다고 덧붙였다.
```
* '옵티머스'가 '옵'과 '티머스'로 분리되어서 옵티머스에 대해 물어보면 제대로 된 답변이 생성안될 가능성이 높다.
Q2. open ai의 서버 상태가 불안정해져서 gpt를 사용할 수 없을 때엔 어떻게 하는 것이 좋을까요?(QnA 섹션 때와 같은 질문을 했다.)
A2.
* 대부분의 회사들은 openLLM을 도입하려고 한다. LLM 서비스 전부를 openLLM으로 사용하거나, 일부 기능만 chatGPT를 사용하는 형태로 운영함.
* 1. 완전 자립
* Open LLM만 사용하여 API 의존성을 완전히 제거
* 2. 하이브리드
* 핵심 기능에는 GPT API를 쓰되, 부가 기능 또는 fallback 용도로는 Open LLM을 사용
* 장점
* api 비용 없음, 보안 이슈 없음(자체 서버에서 가능), api 서버 의존성 이슈 없음
* 단점
* 초기비용 큼(gpu 인프라) 또는 클라우드비용 증가, 상대적으로 낮은 성능
->인력을 통해 개선을 시켜야함 (프롬프트 엔지니어링, RAG, 튜닝)
chatGPT 크기: 1000B이상
openLLM 중에 큰 것들 700B -> GPU인프라 비용 최소 20억 이상
* Ollama를 통해 openLLM 활용할 때 적합한 것: 7B짜리
* 회사 내부 문서가지고 답변하는 것
* RAG -프롬프팅, 튜닝이 많이 필요
Q3. RAG의 동작방식에 대해: 유저의 입력 → 모든 벡터 DB의 문서들의 임베딩 유사도를 체크 → 가장 유사도가 높은 문서를 가져와서 프롬프트에 얹는다. 이 방식이 맞을까요? 맞다면 문서의 양이 많아질 수록 검색속도가 느려지지 않을까요?
A3.
ㅇㅇ 더 자세하게 말씀드리자면 아래와 같다.
1. 유저 질문을 입력
2. 입력을 임베딩하여 쿼리 벡터 생성
3. 벡터 DB (예: FAISS, Chroma, Weaviate 등)에서 유사도가 높은 문서 top-k를 검색 -> 검색된 문서들을 프롬프트에 넣어 LLM에게 전달
4. LLM이 응답 생성
* Retrieval: 저장된 벡터DB에서 프롬프트 벡터와 유사도가 높은 top k개 텍스트 추출
* 시간복잡도: O(log n) (헉..빠르다)
* Augmented: 추출된 텍스트를 context로 프롬프트 앞에 끼워넣기
* Generation : 문맥 + 질문을 포함하는 프롬프트에 대한 답변 생성
문서의 수가 많아지면 느려지는 게 맞다.
* 그래서 벡터DB 선택, indexing 방식, hardware infra가 중요하다.
* FAISS: CPU 기반, 빠르고 단순. 중소규모에 적합.
* Chroma, Weaviate: 실시간 대응 및 확장성에 유리.
* OpenSearch <- Elastic Search
* Pre-filtering (metadata filter) → 벡터 검색 → 프롬프트 구성: 속도 최적화 전략.
* 실무에서는 단순히 문서 다 넣고 “검색!”이 아니라, 도메인, 날짜, 문서 유형 등을 먼저 필터링하고, 벡터 검색은 그 후에 수행한다.
Q4. 사내에 있는 문서들을 미리 임베딩 후 벡터 DB에 넣어서 검색 속도를 높이고 싶습니다. 이럴 경우에는 벡터 DB를 띄워야할 것 같은데 실무에서는 어떻게 하고 있나요?
* 문서 전처리 및 임베딩 단계 (오프라인 작업)
* PDF, Word, Excel → 텍스트 추출
* RecursiveCharacterTextSplitter
로 문서 분할
* Excel은 row, sheet별로 chunk를 하는 것이 효과적일 수 있음.
* github codebase의 경우에도, 파일, 클래스, 함수 단위로 chunking하는 것이 좋을 수 있음
* OpenAI 또는 local 모델로 임베딩
* 임베딩된 결과를 벡터 DB에 저장 (Chroma, FAISS 등)
* 이건 서비스 시작 전에 한 번 미리 돌려놓고 저장합니다. 실시간 아님.
* 서비스 운영 중
* Vector DB를 서버에 띄운 상태로 유지:
* 실무에선 보통 Docker로 띄우거나, AWS EC2 / GCP VM 등에 올려놓습니다.
* Chroma: 매우 가볍고 단일 서버에서 운영 가능
* Weaviate, Pinecone: Managed 서비스 or K8s 클러스터로 운영 가능
## 앞으로 작업할 프로젝트의 목표
나는 이번 AI 코스를 통해 이런 것들을 가져가고 싶다.
1. 프롬프트 엔지니어링 + RAG + openLLM 모델 파인튜닝 + LoRA + 양자화 등을 통해 하드웨어의 제약을 극복하고 비용을 절감하여 LLM 파이프라인을 구축하는 것.
2. 정량적인 성능 지표를 설정하여, 객관적인 성능 비교를 통해 LLM 모델의 퀄리티가 지속적으로 상향되는 것을 포트폴리오에 담기!
태스크별 평가 지표
* 텍스트 분류 – Accuracy, F-1
* 번역, 요약
* 정량평가 - ROUGE-L, BLEU
* 정성평가 - (open-ended) – GPT 평가 / 인간 평가
* test data가 1000개 있으면, chatGPT api로 1000번 (입력, 출력) 보내서 채점하게 하기
* 텍스트 생성 (채팅, 스토리) – Win rate / GPT preference
* 문서 검색 / RAG – MRR 또는 Recallk
주제의 참신함과 여러가지 기능 추가보다는 여러가지 프롬프팅 기법과 RAG로 다양한 경우의 수를 만들어내고, 성능을 비교하는 것에 초점을 맞출 것이다!
남은 3주 동안 화이팅!
다음 내용이 궁금하다면?
이미 회원이신가요?
2025년 4월 27일 오전 9:42
이
... 더 보기제가 리드하고 있는 조직(당근마켓 커뮤니티실)에서 백엔드 엔지니어를 채용 중이에요.
커뮤니티실에는 동네 이웃들의 이야기와 정보를 공유하는 동네생활팀, 이웃 간의 취미와 관심사를 연결하는 모임팀, 그리고 아파트 단지 생활을 더 편리하고 즐겁게 만들어 줄 단지팀이 있어요. 지금 내 동네에서 일어나고 있는 일들을 더 쉽게 즐기고 공유할 방법들을 찾는 일이라면 무엇이든 도전하여 실행에 옮겨요. 만드는 사람이 불편할수록 쓰는 사람은 편하다는 믿음으로 도전적인 문제를 풀어나갈 분과 함께하고자 해요.
... 더 보기2
... 더 보기