
기간
2025.12.02 ~ 12.11 <(주말제외) 8일>
목적
ESG 도메인에 특정한 AI AGENT를 만드는 것이 목적.
배경
상반기에 제조업에서 유럽 규제 관련 ESG 업무 인턴을 했던 나로서는 복잡한 ESG 규제들과 관련 대응 보고서를 작성하는게 만만치 않은 일이었다. 대기업은 회계법인의 컨설팅을 받거나 ESG 담당 팀이 마련되어 있어 관련 대응에 그나마 용이할 수 있겠지만, 계열사나 협력사 등은 정보를 찾는 일 부터 관련 법규에 대응하는 일을 사람이 손수 서치해야하는게 쉽지 않다.
이런 배경과 함께 Agent 개발이라는 2차 프로젝트 목적성에 아주 부합한 ESG Agent 만들기라는 주제가 빠르게 확정되었다.
ESG 목적 달성을 위해 해야할 일들은 크게 4가지로 생각해서 이 기능별로 tool을 만들기로 정했다.
Backend: FastAPI
AI: LangChain + LangGraph + GPT-4-mini
- Embedding: bge-m3
- Parsing: PyPDF, PyMuPDF, Tesseract
Vector DB: ChromaDB
Frontend: React

사실 2차 프로젝트는 10일짜리 단기 프로젝트여서 프로젝트의 목적에 맞게 AI agent 구축에만 신경을 쓸까하다가, 이 프로젝트를 단기 프로젝트로만 끝내고 싶지 않아서 backend와 frontend도 커버해보기로 했다.
멋사를 통해서 frontend로 프로젝트는 몇 번 해봐서 오랜만에 하더라도 프론트는 바이브 코딩으로도 충분했는데 백엔드는 아예 무지해서 로직을 이해하고 수정하는데 시간이 오래 걸렸다.😯

PyMuPDF+조건부 OCR로 텍스트 확보 → 표지·목차·헤더 제거 → source_file, source_type, year, page, ocr 등 메타데이터 포함한 chunk 생성.
- 조건부 OCR? : 기업에서 발행한 ESG 보고서 등은 그림 및 표 자료가 많아서 PyPDF 등으로는 파싱이 잘 안 됨 → 이럴 경우 OCR 이용
┌────────────────────────────────────────┐
│ 🔵 1단계: PDF 로드 & 파싱
├────────────────────────────────────────┤
│ - PDF 파일 읽기 │
│ - 텍스트 추출 │
│ - 테이블/이미지 처리 (선택) │
└────────────┬───────────────────────────┘
↓
┌────────────────────────────────────────┐
│ 🔵 2단계: 청킹 (Chunking)
├────────────────────────────────────────┤
│ - 문서를 작은 조각으로 분할
│ - 메타데이터 추가 │
│ (회사명, 연도, 페이지, 섹션 등)
│ - 청크 크기: 500-1000 토큰 │
└────────────┬───────────────────────────┘
BAAI/bge-m3 임베딩으로 chunk 벡터화 → Chroma에 collection_name 지정해 저장.
vector_db 디렉터리(
vector_db/esg_all)에는 ESG 보고서·규제 문서·협력사 자료를 임베딩해 놓은 Chroma 컬렉션이 저장된다.
[Retriever Logic]
- retriever/retriever_pipeline.py는 이미 VectorDB에 저장돼 있는 메타데이터를 검색 시 필터로 쓰도록 구성.
- vector_db/esg_all.py에서 chunk마다
Document(..., metadata=...)를 만들어 Chroma에 넣었기 때문에, 저장 단계에서 포함된 필드(source_file, source_type, page, ocr, 앞으로 추가할 company, year, country 등)가 VectorDB에 그대로 남는다.
리트리버는 metadata_filter에{"source_type": "companies", "company": "DL건설"}같은 조건을 전달해서 “이미 저장돼 있는 메타데이터”를 기준으로 검색 범위를 좁히는 것!
만약, 필드를 더 쓰고 싶으면 ingestion 단계에서 metadata.update(...)에 추가하고 VectorDB를 다시 생성하면 됨
[ 각 TOOL 별 RAG 체인]
각 툴(policy_tool.py, regulation_tool.py, risk/…, supplier_eval.py 등)이 동일한 벡터 DB를 직접 로드하지만, retriever 설정·프롬프트·LLM 파라미터는 서로 다름.
| 모듈 | 벡터 DB | Retriever / LLM 특성 |
|---|---|---|
| policy_tool.py | Chroma(persist_directory="vector_db/esg_all") | ① vector_db/esg_all.py 등으로 PDF를 chunk → BGE 임베딩 후 저장② 사용자 질의를 동일 모델로 벡터화해 retriever.get_relevant_documents(k=5)로 상위 문단을 가져옴③ “정책 요약/비교/평가” 프롬프트에 [관련 근거] 블록 형태로 삽입해 LLM(GPT-4o mini) 을 호출하는 정석 RAG 체인 |
| regulation_tool.py | Chroma(collection_name="esg_regulations", persist_directory="vector_db/all_esg") | Selenium + Tavily 로 최신 문서를 수집·저장 후, 필요할 때만 RAG로 규제 요약 수행 동일한 BGE 임베딩을 사용하지만 크롤러 히스토리, 검색 범위, 스케줄링 로직이 다름 |
| risk / supplier_eval | 템플릿 기반 점수 / 보고서 | RAG 의존도는 낮음, 그러나 필요 시 다문서 증거를 vector DB에서 가져와 항목별 근거를 생성 |
위 Retriever를 그래프/체인 노드로 넣어 LLM이 항상 필터링된 chunk를 받도록 구성.
run_custom_agent가 LangGraph를 호출해 종합 결과를 만드는 구조.우선 Notion을 사용하여 매일 진행상황을 꼼꼼히 문서화한 것이 프로젝트 진행을 원활히 하는데 큰 도움이 되었다. 매일 아침 저녁으로 팀원마다 계획과 진행상황 점검을 하며 회의록을 작성하다보니, 나무만 보는 게 아니라 숲을 보며 프로젝트를 진행할 수 있어서 흐름이 끊기지 않아 좋았다. 3차 프로젝트를 시작하기 전까지 텀이 있을텐데, 노션을 보며 바로 상황을 파악하고 바로 진행할 수 있을 것 같다.
또한 깃허브의 중요성을 강조하여 팀원들 모두가 깃허브로 코드를 공유하며 협업할 수 있도록 이끈 점이 매우 뿌듯하다. 팀원 모두가 깃허브에 익숙한 것은 아니라서 사용하는데 어려움이 있었고 오류를 해결하는데 시간이 많이 걸렸지만, 그 과정에서 나 역시 깃허브에 더 익숙해졌고 각자 코드의 진행상황을 바로 공유할 수 있어서 좋았다.
도메인 특화적인 Agent였기 때문에 짧은 시간 내에 도메인 지식을 습득하고 정보와 문서를 찾아오는게 쉽지 않았다. 하루 안에 도메인 정보를 찾아오고 개발을 시작하려다 보니 그에 따라 성능이 낮아진 게 아쉬웠다. 3차 프로젝트에서는 도메인 지식을 확실히 하고 전처리나 모델의 성능들도 하나씩 테스트해가며 우리 프로젝트에 잘 맞는 모델과 기능들을 찾았으면 좋겠다.
LangGraph, LangChain을 이용하면 RAG Agent를 만드는 게 그렇게 어렵지 않다고 오만했는데, 이론과 실전은 다르다는 것을 깨달았다. 문서를 파싱하여 청킹하는 것부터 깔끔하게 하는 게 쉽지 않았고, 문서를 찾아올 때도 정해진 로직을 따라서 하기만 하면 잘 찾아올 줄 알았는데 아니었다.. 넣고 싶었던 기능이 많다보니 tool 별로 retriever 설정도 다르게 해야했고, 단일 retirever를 쓰다보니 정확도도 낮았다.
그러나 여러 시행착오를 겪으며 디벨롭해나가야 할 부분이나 해결방안들이 현재로서는 명확하게 보여서 발전 가능성이 보인다. 그래도 RAG를 직접 사용해봤다는 경험에서 더 나은 성능을 내는 방법을 깨달은 것 같다. (전처리나 도메인 지식이나 이 프로젝트에 맞는 모델들은 써보면서 알 수 있다는 점 등등..)
짧은 기간이라서 부족했던 부분이 많지만 3차 프로젝트를 진행하면서 더 높은 완성도를 가진, 내가 원했던 그런 ESG Agent를 만들어 낼 수 있으면 좋겠다!!!