
안녕하세요! 벌써 3번째 미니프로젝트 후기입니다!
이번 프로젝트는 지난 번에 진행했던 AI Agent 프로젝트와 상당히 비슷하지만,
훨씬 실무적인 부분에서 문제 정의와 해결을 진행하였습니다!
이번 미니 프로젝트 3차에서는 저 포함 총 9분과 함께 진행하였는데요!
항상 8명에서 진행하다가 딱 1분 늘었다고 뭔가 더 복작복작해지고 되게 사람이 많다고 느껴졌는데요
일단 사람이 더 늘어서 너무너무 좋았습니다!!!
사실 이번 미니 프로젝트 3차의 경우 상태가 매우 안 좋아서 너무너무 걱정을 하고 시작했습니다.
사실 제가 병이 있어요.
쉬지 못하는 병
5월 1일 - 5월 4일까지 평균 이만 삼천보를 찍습니다... 🥲(연휴최고)

이러저러한 이유로 굉장히 골골대다가 맞이한 수업과 미니프로젝트는 상당히 멀쩡하진 않았던 것 같습니다...
시간은 절 기다려주지 않으니 정신 빠짝 차리고 하려고 노력했습니다.
하지만...저도 인간인지라 실수를 하고 마는데요!
팀원 분들께 정말 감사하고 죄송하지만 제가 또 팀장을 하게 되었습니다...!!
흐름 못 잡고 버벅거릴 때마다 도와주신 팀원분들께 또 다시 감사의 말씀 올리고 싶습니다.
그리고 다양한 팀원분들을 만나며 생각한 건데, 저희 5,6반은 전부 능력자인 것 같습니다. 🤔
진짜로...

이제 잡설은 그만하고, 팀원분들과 으쌰으쌰 진행했던 미니프로젝트 3차에 대해 기록해보겠습니다!
멀티 에이전트 ABSA 파이프라인 구축기
LangGraph로 리뷰 분석 자동화하기
1. 프로젝트 개요
상품 리뷰에서 속성(Aspect) 단위로 감정을 분석(ABSA, Aspect-Based Sentiment Analysis)하고 리뷰 자체의 신뢰도까지 가중치로 반영하는 멀티 에이전트 파이프라인을 LangGraph로 설계 및 구현했습니다.
- 속성(Aspect) 단위 감성 분류 — 보습, 가격, 향, 포장, 유지력 5가지 속성으로 리뷰 내용을 분해
- 리뷰 신뢰도 가중치 — -1.0 ~ 1.0 범위로 리뷰의 진정성을 평가
- 가중 감성 점수 — label × quality_score로 무성의한 리뷰의 영향력을 수학적으로 통제
- Streamlit 대시보드 — 시계열 추세, 속성별 분포, 신뢰도 분포를 시각화
단일 LLM호출로 끝내지 않고, 분석 → 검증 → 정책 판단 → 재시도라는 자기 교정 루프를 갖춘 구조가 핵심입니다.
2. 문제 정의
프로젝트 진행 중, 크게 2가지 문제가 발생했습니다.
2-1. Aspect 과다 문제
LLM이 리뷰에서 자유롭게 aspect를 추출하다 보니, 한 데이터 셋 안에서 아래와 같이 수십 가지 표현이 무질서하게 생성되었습니다.
'향', '지속력', '디자인', '커버력', '피부 표현', '촉촉함', '세팅력', '발색', '구성', '재구매 의사', '추천', '손 소독 효과', '흡수력 및 끈적임', '청량감', '유통기한', '발림성', '보습력', '보습' ....

Aspect가 단순 과다한 문제도 있었지만, 하나의 리뷰에서 '보습', '보습력'과 같이 동일한 속성을 이야기 하지만 표현은 다른 단어가 추출되는 등의 문제가 발생했습니다.
결과적으로,
어떤 aspect가 평균적으로 부정적인가? 에 답변 불가능 → 속성별 통계 집계가 불가능
x 축 카테고리가 매번 달라짐 → 대시보드 시각화의 무력화
입점 업체에게 어떤 점을 개선해야하는지 전달이 불가능함 → 비즈니스 의사결정 불가
2-2. 리뷰 품질의 비균질성(신뢰도 문제 발생)
기존 분석에서는 모든 리뷰를 동등하게 취급하여 "좋아요" 라는 한 줄 짜리 리뷰와 2주간 실사용 경험을 구체적으로 적은 리뷰가 동등한 가중치로 집계되는 등 리뷰의 객관성 및 신뢰도를 전혀 고려하지 않았습니다. 이로인해 리뷰어의 개인 감정 편향으로 인해 부정 의견이 긍정으로 뒤집혀 집계되는 왜곡 현상이 발생했습니다.
3. 해결 아이디어
핵심 설계 원칙은 아래와 같습니다.
| 원칙 | 적용 방식 |
| 속성 제한 | aspect를 5가지(보습, 가격, 향, 포장, 유지력)로 고정 |
| 검증-재시도 루프 | Critic이 부적합 판정 시 Supervisor가 재시도 지시 |
| 에러 타입별 정책 | reason_code로 오류를 분류해 맞춤형 수정 지시 제공 |
| 신뢰도 가중치 | 리뷰 품질을 별도 노드로 평가해 집계 시 가중 적용 |
Supervisor 노드에 대해 설명하자면, 모든 분기 결정을 한 곳에 집중하여 추적 가능성과 수정 용이성을 확보합니다. 각 노드는 실행 과정이 끝난 뒤 Supervisor로 복귀 하면 되고 어디로 가야할지 판단할 필요가 없습니다. 새 노드 추가 시 Supervisor의 분기 로직만 수정하면 돼, 확장성 부분에서 좋습니다.
4. 워크 플로우 명세서
프로젝트가 커지고 많은 사람이 작업을 할 때 중요한 부분은 명세서 작성입니다. 코드를 짜기 전에 명세서로 청사진을 먼저 합의 하여야 합니다.
명세서는 크게 Workflow 명세서, State 정의서, Decision Policy, Prompt 명세서 4가지가 있습니다.
| Workflow 명세서 | 각 단계가 무엇을 받고 무엇을 내보내는지 (Input, Process, Output) |
| State 정의서 | 어떤 데이터가 노드 사이를 흐르는지 |
| Decision Policy | 분기 조건을 표로 정리 |
| Prompt 명세서 | 각 LLM 호출의 시스템 프롬프트 원문 |
이번 프로젝트에서 State 관리자 역할을 맡게 되어 State 정의서 부분을 좀 더 보충하겠습니다.
State 정의서에는 아래와 같은 것들을 작성해야 합니다.
- Key 이름
- 설명
- Data Type
- 구분(Reducer / Overwrite)
- 사용 Agent(어느 노드가 읽고 쓰는지)
멀티 에이전트는 State 공유가 핵심으로 누가 어떤 키를 읽고 쓰는지 명시되지 않으면 충돌과 디버깅에 어려움이 생깁니다. State 정의서는 각 키에 무언가 이상한 값이 들어왔다면 어디 부분의 잘못인지를 알 수 있는 문서입니다.
5. 역할 정의서
역할 정의서는 각 에이전트마다 9개의 항목을 작성 했으나, Analyzer_node의 대표적인 부분만 보여드리겠습니다.
| 항목 | 내용 |
| 주요 기능 | 1) 리뷰 텍스트 분석 2) 평가 관점(Aspect) 추출 3) 감정(Label) 분류 4) 근거 문장(Evidence) 추출 5) JSON 형태 결과 생성 6) 다음 Agent로 상태 전달 |
| 제약 조건 | - 리뷰 내용 기반의 주요 평가 관점만 추출 - 감정 값은 긍정=1 , 부정= 0만 허용 - JSON 형식외에는 출력 금지 - aspect : 평가관점 -> 보습 | 가격 | 향 | 배송 | 유지력 - label : -1(부정) | 1(긍정) - evidence : 근거 문장 |
| 실패 시 리스크 | - JSON 파싱 오류 발생 가능 - 잘못된 감정 분류로 후속 Agent 판단 오류 발생 - Aspect 누락 시 리뷰 분석 품질 저하 - 형식 오류 발생 시 Critic Agent 연계 실패 가능 |
6. 노드 별 구현
6-1. Analyzer Node
핵심 설계 포인트는 Aspect 고정입니다. sys_msg 부분을 주의하여 작성하였습니다. 아래는 그 일부입니다.
반드시 아래 5가지 중에서만 선택하세요. 이 외의 aspect는 절대 사용하지 마세요.
- 보습, 가격, 향, 포장, 유지력
리뷰에 "배송", "디자인", "발림성", "커버력" 등 다른 표현이 있더라도,
위 5가지 중 가장 가까운 aspect로 매핑하세요.
매핑할 수 없으면 해당 내용은 제외하세요.
후 처리를 통해 필터링을 할 경우 LLM의 호출 비용만 쓰고 결과를 버리게 되어 프롬프트 단계에서 제약을 걸었습니다.
이는 위 5가지 속성을 제외하고 새로운 중요 속성이 무시되는 단점이 있으나, 분석 가능한 결과로 인사이트를 제공하기 위해 이와 같은 방법으로 진행했습니다.
6-2. Critic Node
이 노드는 Analyzer node의 결과를 검토합니다.
1. aspect가 허용 목록 안에 있는지
2. label(긍/부정)이 적절한지
3. evidence가 리뷰 원문에 실제로 있는지
4. 중요한 aspect 누락은 없는지
부적합의 경우 reason에 이유를 담아 Supervisor 노드로 넘어가게 됩니다. Critic 노드는 분석과 검증을 나누어 검증 품질을 올리는 중요한 노드로 필수적입니다.
6-3. Supervisor Node
1. quality_score 없으면 → sincerity_weight 실행
2. analyzer_result 없으면 → analyzer 실행
3. critic_result 없으면 → critic 실행
4. verdict == "적합" → 종료
5. verdict == "부적합" → LLM으로 reason_code 분류
6. reason_code 기반 분기
- RETRYABLE + 한도 미달 → repair_directive와 함께 analyzer 재실행
- QUALITY_ERROR 또는 한도 초과 → 종료
위와 같은 의사결정 흐름에 따라 진행 됩니다. reason_code의 체계는 출력 형식 문제, aspect 범위 위반, 근거나 원문에 없거나 변형, 기타 품질 문제, 정상 종료로 이루어져 있습니다.
이와 같이 문류하는 이유는 막연한 재시도를 최소화 하기 위해 에러 타입을 분류하고 맞춤형 수정 지시를 주어 재시도 횟수를 줄이기 위해서 입니다.
6-4. Sincerity Weight Node
리뷰 자체의 진정성을 -1.0 ~ 1.0의 점수로 평가합니다.
| 기준 | 의미 | 안 좋은 예시 / 좋은 예시 |
| 경험의 구체성 | 실사용 상황이 묘사되었는가 | 좋음 / 겨울 실내에서 써봤는데 오후까지 당김 없음 |
| 경험의 고유성 | 본질과 무관한 이야기로 분량만 채우지 않았는가 | 배송굿,포장굿,재구매O / 제품 자체 경험 묘사 |
| 정보 밀도 | 짧아도 핵심 속성을 정확히 평가했는가 | 길지만 TMI / 향 좋고 보습 좋은데 비싸요 |
weighted_score = label * quality_score
진정성 평가를 진행하면 무성의한 리뷰의 영향력이 줄어들고, 신뢰도 높은 부정 리뷰는 더 크게 반영됩니다. 단순 길이로 판단하지 않은 이유는 도배성 글이나, 무의미한 문장만 반복되는 리뷰의 점수가 높아지게 되어 밀도를 중요시 하였습니다.
7. LangSmith로 노드 별 병목 확인
LangSmith Tracing을 켜고 노드 별 실행 시간과 토큰 사용량을 측정하였습니다.
Analyzer 노드가 호출 당 토큰이 가장 많았으며, Supervisor 노드에서는 재시도 마다 누적되는 특징, Sincertiy weight의 경우 호출 당 비용은 낮으나 모든 리뷰에 항상 호출되므로 누적 비용이 크다는 특징을 확인 하였습니다.


8. DB 연동 및 배치 처리
SQLite를 사용하여 진행하였습니다. 스키마 부분에서 신뢰도 점수와 이유를 확인하기 위해 quality_score와 quality_reason을 추가하여 진행했습니다.
배치 로직에서 agent_aspect IS NULL로 재실행 시 처리된 건은 스팁하여 진행했고, max_retries = 2 로 재시도 한도를 명시하였습니다.

9. 대시보드
9-1. 핵심 지표 배치
- 총 리뷰 수
- 평균 품질 점수
- 가장 긍정적인 속성
- 가장 부정적인 속성
상단에 4가지 지표를 배치하였습니다. 가장 긍정적인 속성과 가장 부정적인 속성은 weighted_score(lable x quality_score)의 속성별 평균으로 산출하여 신뢰도 가중치가 적용된 제품의 긍정적 속성 / 부정적 속성을 확인할 수 있도록 하였습니다.

9-2. 시계열 정보 확인
- 주별/월별/분기별/연도별
- 0을 기준으로 긍정 구간 / 부정 구간 면적 확인
- 각 포인트에 리뷰 수를 확인 할 수 있게하여 표본이 적은 구간 식별 가능함

9-3. 인사이트 추출
인사이트 추출과 리뷰 감성 신뢰도 점수, 품질 점수를 확인하기 위해 기능을 추가하였습니다.


10. 추후 개선 방향
LangSmith 부분에서 확인 할 수 있듯이, 부적합 판정을 받아 재시도가 발생하면 Analyzer node가 2-3번 호출됩니다. 100개의 리뷰를 처리할 때, 재시도율이 30%면 실제 호출이 매우 많아집니다.
1. Anaylzer 시스템 프롬프트 압축 - 핵심 규칙만 남기기
2. Sincerity weight 모델 다운 그레이드 - 더 작은 모델로 분리
3. 재시도 시 diff만 전달 - 전체 리뷰 + 전체 프롬프트가 아니라 직전 출력 + 수정 포인트만 전달
4. Critic 패스율이 높은 케이스 식별 - 짧고 명확한 리뷰는 Critic 스킵 옵션 추가
노드 별 병목을 확인할 수 있는 코드를 통해 병목을 확인 했으나, 단순 병목을 확인하는 것보다 왜 느린지를 파악해야함을 깨달았습니다. 각 노드에서 최소화 시킬 수 있는 부분은 최소화 하고, 프롬프트 부분에서 더욱 신경을 써서 개선하면 비용 문제나 속도 방향에서 좋을 것 같습니다.
11. 발전 방향
프로젝트를 진행하면서 초기에 나온 아이디어들이 매우 많았습니다. 시간적 한계, 데이터 부족으로 인해 구현하지 못했던 기능을 추가하여 발전 방향을 정해보았습니다.
1.리뷰에서 FAQ 자동 생성 - 부정 리뷰 바탕으로 불만 추출하여 FAQ 생성
2. 별점 기능을 통한 가중치 부여 (1-5) - 명시적인 평점과 텍스트 감정 간의 차이 분석
3. Insight Agent 추가를 통해 속성 점수가 떨어졌을 때 그 이유 리포팅
읽어주셔서 감사합니다!!!
사실 2차 미니프로젝트 후기를 너무 조금 적었나..? 내가 나중에 보고 다시 기억해낼 수 있을까..?
내가 정말 열심히 적은게 맞나..? 검색해도 안 뜨는 이 글에 소중한 분들이 직접 링크 타서 봐주시는는데 내가 대충 쓰는게 맞나?
하는 불안형이 되었는데요

그래서 이번 3차는 내용도 많고 중요하니 최선을 다해 써보자!!! 하는 마음으로 열심히 작성을 해보았는데
최장 길이, 최다 글자 수, 최다 이미지를 달성하게 되어 뿌듰합니다!!!
읽어주셔서 정말 감사드립니다
이제 미프 4차를 앞두고 FrontEnd 수업을 듣는데 정말 머리만 긁고 있습니다.
칠판에 1+1 적길래 잠깐 눈 돌렸더니 기하 수업을 하고 계신 기분

4차 시작 전에 정말 공부를 열심히 해가야할 것 같습니다...
남은 교육도 파이팅!

'KT AIVLE school' 카테고리의 다른 글
| KT AIVLE school 미니프로젝트 2차 후기 (0) | 2026.05.11 |
|---|---|
| KT AIVLE school 미니 프로젝트 1차 후기 (0) | 2026.04.28 |
| KT AIVLE school 9기 2주차 후기 (0) | 2026.04.13 |
| KT AIVLE school 9기 노트북 수령 + 1주차 후기 (0) | 2026.04.05 |
| KT AIVLE school 9기 합격 후기 (0) | 2026.04.05 |