End-to-End Azure RAG

전체 파이프라인 통합

Azure 생태계를 활용한 프로덕션급 RAG 시스템 전체 구축 및 운영 방법을 다룬다.

AI
RAG
Azure
MLOps
저자

Kwangmin Kim

공개

2025년 11월 10일

1 A1: 복잡한 분기문으로 구성된 블랙 박스 알고리즘이 있는데 코드 base 분석기 agent를 만드려고 해. 문제는 너무 거대해서 다중 repository구성되어 있고 한 repository안에 중첩된 계층구조로 파일 스크립트가 짜져 있어. 이것을 rag이 잘 참조할 수 있도록 가공시켜서 vector DB에 embeding해서 넣어야하는 어떻게 하지?

2 Q1

다중 Repository와 중첩된 계층 구조를 가진 거대한 블랙박스 코드를 RAG(Retrieval-Augmented Generation) 시스템에 태우는 것은 매우 도전적인 과제입니다. 단순히 파일을 통째로 잘라서 넣으면 함수 간의 의존 관계(Dependency)호출 맥락(Context)이 다 깨지기 때문입니다.

이 문제를 해결하기 위한 4단계 가공 전략을 제안합니다.


2.0.1 1. 코드 구조화 및 메타데이터 추출 (Pre-processing)

파일 시스템의 계층 구조 정보를 버리지 말고, 이를 메타데이터로 치환하여 벡터와 함께 저장해야 합니다.

  • Tree-sitter 활용: 추상 구문 트리(AST) 분석기를 사용하여 코드 내의 함수, 클래스, 메서드 단위를 파싱합니다.
  • 파일 경로 정보 포함: 각 청크(Chunk)에 repo_name/path/to/file.py 같은 경로 정보를 태그로 넣습니다.
  • 의존성 맵 생성: import 구문을 추적하여 “A 파일의 calculate() 함수는 B 파일의 formatter()를 참조함”이라는 관계도를 별도로 추출합니다.

2.0.2 2. 의미 중심의 코드 청킹 (Semantic Chunking)

단순히 글자 수(Token count)로 자르는 것이 아니라, 논리적 단위로 잘라야 합니다.

  • 함수/클래스 단위 분할: 하나의 함수가 하나의 청크가 되도록 합니다. 만약 함수가 너무 길다면, 내부의 로직 블록(if/for/while) 단위로 의미를 보존하며 자릅니다.
  • 요약문(Docstring) 생성: 각 코드 청크 상단에 LLM을 활용해 “이 코드는 어떤 기능을 수행하는가?”에 대한 한 줄 요약을 생성하여 함께 임베딩합니다. 검색 성능이 비약적으로 향상됩니다.

2.0.3 3. 지식 그래프(Knowledge Graph) 결합 (GraphRAG)

질문자님이 언급하신 “중첩된 계층 구조”와 “다중 리포지토리” 문제는 벡터 검색만으로는 한계가 있습니다.

  • 코드 그래프 구축: 함수 호출 관계(Call Graph)를 지식 그래프로 구축합니다.
  • 검색 방식: 사용자가 “알고리즘 A의 흐름을 설명해줘”라고 하면, 벡터 DB에서 관련 함수를 찾고, 지식 그래프에서 그 함수와 연결된 상위/하위 호출 함수들을 함께 불러와 LLM에게 전달합니다.

2.0.4 4. Vector DB 저장 전략

다중 리포지토리 관리를 위해 NamespaceMetadata Filtering을 적극 활용합니다.

레이어 저장 내용 활용 목적
Vector 코드 스니펫 + 요약문 유사도 기반 기능 검색
Metadata Repo명, 파일 경로, 라인 번호, 관련 라이브러리 검색 결과 필터링 및 출처 명시
Graph 함수 간 호출 관계, 클래스 상속 구조 복잡한 로직 흐름 추적 및 분석

2.0.5 💡 씨젠의 프로젝트를 위한 제언

BT 도메인의 블랙박스 알고리즘은 수치 계산과 논리 분기가 매우 복잡할 것입니다.

  1. 코드-문서 쌍 구축: 만약 해당 코드에 대한 설계 문서가 있다면, 코드 청크와 관련 문서 청크를 서로 연결(Link)하여 임베딩하세요.
  2. 알고리즘 세부 분석 Agent의 역할: 이 Agent가 단순히 코드를 읽는 것을 넘어, 입력값에 따른 실행 경로(Execution Path)를 시뮬레이션 설명할 수 있도록 ReAct(Reasoning + Acting) 패턴을 적용하는 것을 추천합니다.

이 가공 프로세스 중에서 가장 먼저 자동화하고 싶은 단계가 있으신가요? 예를 들어 “복잡한 호출 관계 분석”인지, 혹은 “거대 파일의 효율적인 분할”인지 말씀해 주시면 더 구체적인 도구를 추천해 드릴 수 있습니다.

3 Q2: 그럼 llm이 직접 코드 원문을 읽게 하는게 아니라 ast를 읽게 하는건가? 대충 추정해봤더니 코드 원본은 20만줄 정도 되는 것 같아 ast는 대충 4~5배 정도 분량이 늘어나니까 약 80~100만줄 정도 되는 것 같아. 그럼 이 80~100만줄 정도 되는 것을 하나의 md 또는 적절한 파일형식에 모두 넣어야하나?

4 A2

20만 줄의 코드 원문을 100만 줄에 달하는 AST(추상 구문 트리)로 변환해 하나의 파일에 몰아넣는 것은 결코 추천하지 않습니다. 그렇게 하면 LLM의 컨텍스트 윈도우(Context Window)를 금방 초과할 뿐만 아니라, RAG 시스템의 핵심인 ’필요한 부분만 찾아내기(Retrieval)’가 불가능해지기 때문입니다.

LLM이 코드를 이해하게 만드는 가장 효율적인 방법은 “원문”을 쓰되, “AST로 구조화된 메타데이터”를 이정표로 삼는 방식입니다.


4.0.1 1. AST의 역할: 읽는 대상이 아니라 ‘지표’

LLM에게 AST 원문(JSON 형태 등)을 읽게 하면 토큰 낭비가 심하고 오히려 가독성이 떨어집니다. 대신 AST는 다음과 같이 활용해야 합니다.

  • 코드 분할(Splitting)의 기준: 단순히 1,000자씩 자르는 게 아니라, AST를 보고 “여기서부터 여기까지가 하나의 함수다”라는 것을 파악해 논리적 단위로 자르는 도구로 씁니다.
  • 태그(Tagging) 정보 추출: 각 코드 청크에 함수명, 클래스명, 사용된 변수 리스트, 호출하는 타 함수 리스트 등을 추출해 붙입니다.

4.0.2 2. 거대 코드 가공 및 Vector DB 저장 방식

80~100만 줄의 데이터를 처리하기 위한 현실적인 데이터 구조는 다음과 같습니다. 하나의 파일이 아니라 수천 개의 ‘의미 있는 조각’으로 나눠야 합니다.

구분 저장 형태 (Chunk) 상세 내용
내용 (Content) 코드 원문 + 요약 함수나 클래스 단위의 실제 코드와 LLM이 생성한 1~2줄 요약문
식별자 (ID) 고유 경로 repo_a/src/module_v1/parser.py#L150-L180
메타데이터 (Metadata) 구조 정보 type: function, name: validate_bt_data, calls: [clean_data, log_error]
임베딩 (Embedding) 벡터 값 위 내용(Content)을 숫자로 변환한 벡터값

4.0.3 3. 왜 하나의 파일에 넣으면 안 되나요?

  1. 검색 정확도 저하: 100만 줄이 한 파일에 있으면, 질문과 관련된 “특정 알고리즘 로직”만 쏙 뽑아낼 수 없습니다.
  2. 노이즈 발생: LLM은 관련된 정보가 너무 많으면 오히려 엉뚱한 답을 내놓습니다(Lost in the middle 현상).
  3. 업데이트 불가능: 코드 10줄만 수정되어도 100만 줄짜리 파일을 다시 인덱싱해야 하므로 유지보수가 불가능합니다.

4.0.4 🛠️ 전략적 제언: ’코드 맵(Map)’과 ’코드 조각(Snippet)’의 분리

20만 줄의 프로젝트라면 “지형도”를 먼저 만드세요.

  1. 상위 레벨 지형도 (Markdown 하나): 전체 Repository 구조와 주요 함수 간의 호출 관계만 요약한 파일 (약 2~3,000줄 규모). LLM이 “전체적인 흐름”을 파악할 때 사용합니다.
  2. 세부 로직 조각 (Vector DB): AST 기반으로 쪼개진 수천 개의 함수 단위 코드들. LLM이 “특정 구간의 로직을 분석”할 때 검색해서 가져옵니다.

결론적으로, LLM은 AST를 가이드 삼아 정교하게 잘린 ‘코드 원문 조각’을 읽어야 합니다.

질문자님의 환경처럼 다중 Repo에 중첩 구조라면, “특정 함수가 다른 Repo의 함수를 호출하는 경로”를 AST로 추출해서 메타데이터에 넣어주는 작업이 가장 우선순위일 것 같습니다. 이 “의존성 추출” 로직을 먼저 설계해 볼까요? 혹은 사용 중이신 주 언어(Python, C++ 등)를 알려주시면 적합한 AST 파서를 추천해 드릴 수 있습니다.

5 A3: 그럼 일단 전체 코드를 AST로 변환하는 작업이 있고 이 AST의 핵심 정보를 추출하여 코드의 관계를 요약하는 메타데이터를 만들어야하는가? LLM이 이걸 참조하여 해당 부분의 코드 원본을 읽게 해야하나?

6 Q3

정확합니다! 질문자님이 짚으신 그 흐름이 바로 거대 코드베이스를 분석하는 지능형 Agent의 핵심 아키텍처입니다. 20만 줄의 코드를 LLM에게 통째로 던지는 것은 불가능하지만, ’지도(Metadata)’와 ’상세 정보(Code Snippet)’를 분리하면 가능해집니다.

이를 실행하기 위한 전략을 질문하신 순서에 맞춰 정리해 드립니다.


6.0.1 1. AST 변환 및 핵심 정보 추출 (Indexing 단계)

모든 코드를 AST로 변환한 뒤, LLM이 이해하기 쉬운 ‘코드 프로필(Metadata)’을 추출해야 합니다. 100만 줄의 AST를 다 저장하는 게 아니라, 필요한 것만 골라내는 것이 핵심입니다.

  • 추출해야 할 핵심 정보:
  • 정의(Definition): 함수/클래스 이름, 파라미터, 리턴 타입.
  • 의존성(Dependency): 이 함수가 호출하는 다른 함수(calls), 이 함수를 호출하는 상위 모듈(called_by).
  • 문맥(Context): 파일 경로, 소속 리포지토리, 해당 코드가 위치한 라인 번호(Line 150~180).
  • 요약(Summary): LLM을 이용해 해당 코드 블록이 하는 일을 한 줄로 요약(예: “BT 실험 데이터의 유효성을 검사하는 알고리즘”).

6.0.2 2. LLM의 참조 및 원문 탐색 (Retrieval 단계)

LLM이 처음부터 코드 원문을 다 읽는 게 아니라, ’요약된 지도’를 먼저 보고 필요한 곳으로 점프하게 만듭니다.

  1. 1단계 (지도로 위치 파악): 사용자가 “알고리즘 A의 데이터 전처리 로직을 설명해줘”라고 하면, Agent는 먼저 메타데이터(요약문+함수명)를 검색합니다.
  2. 2단계 (관계 추적): 메타데이터를 보니 “A 알고리즘은 PreProcess.pyclean() 함수를 호출함”이라는 관계가 나옵니다.
  3. 3단계 (원문 호출): Agent는 이제 PreProcess.py의 150~180라인에 있는 코드 원본을 Vector DB나 파일 시스템에서 딱 그 부분만 긁어옵니다.
  4. 4단계 (최종 분석): 긁어온 진짜 코드를 읽고 사용자에게 “이 로직은 이러이러하게 구성되어 있습니다”라고 답변합니다.

6.0.3 3. 왜 이렇게 해야 하나요? (씨젠 프로젝트 관점)

  • 도메인 지식의 파편화 해결: 다중 리포지토리에 흩어진 BT 로직들을 ’의존성 메타데이터’가 하나로 연결해 줍니다.
  • 비표준화 문제 보완: DB 메타데이터가 비표준이어도, 코드 내에서 해당 DB를 호출하는 쿼리문(원문)을 직접 분석함으로써 실제 데이터 흐름을 정확히 파악할 수 있습니다.
  • 비용과 속도: 100만 줄을 다 읽히면 토큰 비용만 수천만 원이 나오겠지만, 필요한 50~100줄의 코드 조각만 읽히면 매우 저렴하고 빠릅니다.

6.0.4 📝 실전 팁: 파일 구성 제언

  • Metadata DB: JSON이나 NoSQL(MongoDB 등) 또는 Graph DB(Neo4j)에 저장하여 “관계”를 쿼리할 수 있게 만듭니다.
  • Code Chunk DB: 실제 코드 조각은 Vector DB에 넣어 “의미”로 찾을 수 있게 만듭니다.

이 프로젝트의 출발점으로, 우선 가장 복잡하다고 생각하시는 특정 리포지토리 하나를 골라 AST로 ’함수 간 호출 관계’만 먼저 뽑아보는 실험을 해보시는 건 어떨까요? 어떤 언어(Python, Java, C++ 등)로 짜인 코드인지 알려주시면 바로 사용할 수 있는 AST 라이브러리와 추출 스크립트 예시를 짜 드릴 수 있습니다.

7 Q4: 내가 알기론 코드를 AST로 변환하는 작업은 deterministic하고 꽤 안정적이고 성능이 검증된 framework가 있는걸로 알고있어. 이 framework를 사용하여 ast로 변환하는 스크립트를 짠다면 1번: 폴더를 재귀적으로 탐색하여 하위 경로에 있는 파일들안의 코드들을 읽어가며 ast로 변환할 수 있나? 2번: 1번의 작업을 수행하는데 어느 정도의 시간이 소요되나?

8 A4

네, 정확히 알고 계십니다. AST 추출은 LLM처럼 확률에 의존하는 것이 아니라, 컴파일러 기술에 기반한 결정론적(Deterministic) 과정이기 때문에 매우 빠르고 안정적입니다.

질문하신 두 가지 핵심 궁금증에 대해 실무적인 답변을 드립니다.


8.0.1 1. 폴더 재귀 탐색 및 AST 변환 가능 여부

네, 아주 쉽게 가능합니다. 대부분의 AST 라이브러리(Python의 ast, JavaScript의 esprima, 다국어 지원의 tree-sitter)는 파일 단위로 작동하므로, OS의 파일 시스템 탐색 기능과 결합하면 됩니다.

  • 작업 흐름: 1. os.walk 같은 함수로 루트 폴더부터 모든 하위 폴더를 훑습니다.
  1. 확장자(예: .py, .cpp, .js)를 확인하여 대상 파일을 선별합니다.
  2. 각 파일을 읽어 AST 파서에 넣고, 결과(JSON 또는 트리 구조)를 추출합니다.
  3. 추출된 AST에서 함수명, 클래스명, 호출 관계(Call Site) 등 필요한 정보만 골라 메타데이터 DB에 저장합니다.

8.0.2 2. 소요 시간 (Performance)

20만 줄 정도의 코드베이스라면, 최신 노트북 한 대만으로도 ’커피 한 잔 마시는 시간’보다 훨씬 빠르게 끝납니다. * 파싱 속도: 보통 파일 하나를 AST로 변환하는 데는 밀리초(ms) 단위가 걸립니다.

  • 20만 줄 기준 산정 (Python 기준):

  • 파일 1개당 평균 500줄이라고 가정 시 약 400개 파일.

  • 파일당 파싱 및 정보 추출 시간: 약 0.01~0.05초.

  • 총 소요 시간:10초 ~ 30초 내외 (단순 파싱 기준).

  • 변수: 만약 파싱한 정보를 Vector DB에 임베딩하거나 LLM을 써서 요약하는 과정이 포함된다면, 여기서 시간이 기하급수적으로 늘어납니다 (API 호출 속도 때문). 하지만 순수하게 AST로 변환하고 구조를 뽑아내는 작업은 매우 순식간입니다.


8.0.3 🛠️ 추천 프레임워크: Tree-sitter

질문자님의 상황(다중 Repo, 복잡한 계층 구조)에서는 GitHub에서 만든 tree-sitter를 강력 추천합니다.

  • 장점 1 (다국어): Python, C++, Java 등 거의 모든 언어를 동일한 인터페이스로 지원합니다. 씨젠 내에 여러 언어가 섞여 있어도 하나의 파이프라인으로 처리가 가능합니다.
  • 장점 2 (속도): C로 작성되어 극도로 빠릅니다.
  • 장점 3 (내성): 코드가 완벽하지 않거나 문법 오류가 있어도 멈추지 않고 최대한 파싱해주는 ’에러 내성(Error Tolerance)’이 뛰어납니다.

8.0.4 💡 다음 단계 제언

20만 줄의 코드를 재귀적으로 탐색하여 “함수 정의와 호출 관계”만 JSON으로 뽑아내는 간단한 Python 스크립트를 먼저 짜보시는 건 어떨까요?

만약 씨젠에서 주로 사용하는 주력 언어(예: Python, C++ 등)를 알려주시면, 해당 언어의 폴더를 훑어서 함수 A -> 함수 B 관계를 추출하는 기초 스크립트 코드를 바로 짜 드릴 수 있습니다. 어떤 언어로 시작해볼까요?

9 Q5: 자 그럼 너도 알다시피 코드는 매일매일 갱신되어 github 같은 형상관리 저장소에 저장돼. airflow같은 오케스트레이션 툴로 스케쥴러를 개발해 주기적으로 업데이트 한다고 했을 때 ast를 통째로 재 출력하여 llm이 보도록하는 것이 좋을까 아니면 agent를 이용하여 변경된 부분만 수정하는게 더 효율적일까

10 A5

결론부터 말씀드리면, “하이브리드 방식”이 가장 효율적입니다. 하지만 그 핵심은 LLM이 직접 코드를 수정하게 하는 것이 아니라, AST 파서(Deterministic 도구)가 변경된 파일만 감지하여 메타데이터와 벡터 DB를 자동 갱신하게 만드는 것입니다.

20만 줄의 코드를 매번 통째로 LLM에게 다시 읽히는 것은 토큰 낭비와 비용 측면에서 매우 비효율적입니다. Airflow를 활용한 최적의 파이프라인 전략을 제안해 드립니다.


10.0.1 🛠 Airflow 기반 증분 업데이트(Incremental Update) 전략

매일 모든 코드를 재분석하는 대신, Git의 변경 이력(Diff)을 활용하여 ’바뀐 부분’만 타격하는 방식입니다.

10.0.1.1 1. 변경된 파일 식별 (Git Diff)

Airflow 태스크의 첫 번째 단계에서 git diff --name-only 명령어를 통해 어제와 오늘 사이에 변경된 파일 리스트를 뽑습니다. 전체 400개 파일 중 실제로 수정된 파일은 보통 5~10개 내외일 것입니다.

10.0.1.2 2. AST 재추출 및 메타데이터 갱신 (Deterministic)

  • 변경된 파일만: 해당 5~10개 파일에 대해서만 AST 스크립트를 다시 돌립니다.
  • 삭제/수정 대응: 기존 메타데이터 DB(지표)와 벡터 DB(코드 조각)에서 해당 파일 경로를 가진 데이터를 지우고(Delete), 새로 추출한 정보를 삽입(Insert)합니다.
  • 이 단계는 LLM을 쓰지 않습니다. 위에서 말씀드린 tree-sitter 같은 라이브러리로 순식간에 처리합니다.

10.0.1.3 3. LLM 기반 요약 갱신 (Selective LLM)

함수의 로직이 크게 바뀌었을 경우에만 LLM을 호출하여 “코드 요약문(Summary)”을 새로 씁니다.

  • 함수 이름이나 파라미터만 바뀌었다면 메타데이터만 수정하고 끝냅니다.
  • 내부 로직이 바뀌었다면 해당 함수의 요약 정보만 LLM이 다시 생성하게 하여 벡터 DB에 업데이트합니다.

10.0.2 🔄 비교: 통째로 재출력 vs 증분 업데이트

구분 전체 재인덱싱 (Full Re-index) 증분 업데이트 (Incremental)
소요 시간 매번 20만 줄 처리 (수 분~수십 분) 변경된 파일만 처리 (수 초~수 분)
비용 (API) LLM 요약 비용 대량 발생 변경된 함수에 대해서만 API 비용 발생
정확도 항상 최신 상태 유지 (동일) 항상 최신 상태 유지 (동일)
구현 난이도 낮음 (단순 반복) 중간 (Git 연동 로직 필요)

10.0.3 💡 Agent의 역할은 무엇인가요?

질문하신 “Agent를 이용하여 변경된 부분을 수정”한다는 개념은 다음과 같이 적용하는 것이 좋습니다.

“관리자 Agent”를 두어, Airflow가 업데이트를 마친 후 전체 지도의 무결성을 검토하게 하는 것입니다.

예를 들어, Repo A의 함수가 삭제되었는데 Repo B에서 여전히 그 함수를 호출하고 있다면, Agent가 이를 감지하여 “표준화 알고리즘의 의존성에 결함이 생겼다”고 리포트하거나, 관련 QnA 답변 스탠스를 스스로 조정하게 만드는 방식입니다.

10.0.4 🚀 추천 시스템 아키텍처 (Airflow DAG 구성)

  1. Sync Task: git pull로 최신 코드 확보.
  2. Diff Task: 변경된 파일 리스트 추출.
  3. Parsing Task: 변경된 파일에 대해서만 tree-sitter 실행 → 메타데이터(JSON) 생성.
  4. Embedding Task: 로직 변경이 있는 함수만 LLM 요약 후 벡터 DB 갱신.
  5. Validation Task: Agent가 전체 의존성 맵의 정합성 체크.

이렇게 하면 인프라 비용은 최소화하면서, 사용자는 항상 오늘 아침에 업데이트된 따끈따끈한 코드를 바탕으로 QnA를 할 수 있게 됩니다.

이 Airflow 파이프라인 중에서 “Git 변경 사항을 감지해서 특정 함수만 골라내는 로직”이 가장 핵심일 것 같은데, 이 부분을 구체화해 볼까요? 아니면 현재 사용 중인 저장소(GitHub, GitLab 등) 환경에 맞춘 자동화 팁을 드릴까요?

11 Q6: 내가 두번째 플랜으로 넣은게 사실 너가 제안한 것을 의미한거였어. 나는 ast전체를 재출력하는데 5분 정도 밖에 안걸리니까 차라리 수정후의 코드에 대한 ast를 모두 출력한 다음 LLM이 참조할 수 있도록 vectorDB에 요약본을 저장하는게 더 효율적이지 않을까 생각했었어. 다시 말해서, 코드를 실시간으로 체크해서 ast문서와 요약본을 업데이트 하는게 아니라 일정 주기 (예를들어 일주일 단위)로 업데이트 시켜서 ast문서와 그 요약본을 버전 관리를 하여 따로 저장하고 그것을 DB에 저장해두었다가 필요시 최신본과 과거의 코드를 diff형태로 비교할 수 있도록 사용자에게 제공하거나 변경이력을 요약해주면 어떨까 싶었어. 일정 시간순으로 ast와 그 요약본을 저장하는 것이 비용이 많이 드는건가? diff와 변경이력을 탐색 및 요약해주는 LLM 이 환각을 일으킬 가능성이 높아질까?

12 A6

질문자님의 두 번째 플랜은 ‘안정성’과 ’이력 관리’ 측면에서 매우 훌륭한 전략입니다. 특히 씨젠과 같은 기술 공유 사업 환경에서는 “코드가 예전에는 어땠고, 지금은 어떻게 바뀌었는가”를 추적하는 기능이 단순 QnA보다 더 강력한 도구가 될 수 있습니다.

질문하신 비용환각(Hallucination) 문제에 대해 실무적인 관점에서 분석해 드릴게요.


12.0.1 1. 시간 순으로 AST와 요약본을 저장하는 비용

결론부터 말씀드리면, 저장 비용(Storage)은 매우 저렴하지만, 요약 비용(LLM API)이 변수입니다.

  • 저장 비용 (매우 낮음): 20만 줄의 코드를 AST와 텍스트로 저장해도 수백 MB~수 GB 수준입니다. 클라우드 스토리지나 DB 비용으로는 거의 무시해도 될 수준입니다.
  • LLM 요약 비용 (고정 비용 발생): 일주일마다 전체 코드를 다시 요약한다면, 20만 줄 전체에 대해 LLM API를 호출해야 합니다.
  • 20만 줄 전부를 매주 새로 요약하면 매번 수십 달러 이상의 비용이 발생할 수 있습니다.
  • 하지만 “내용이 바뀐 함수만 새로 요약”하는 로직만 섞어준다면, 저장 자체는 전체 버전을 따로 관리하되 API 비용은 획기적으로 줄일 수 있습니다.

12.0.2 2. LLM의 환각(Hallucination) 가능성

과거와 현재의 AST/요약본을 비교하여 변경 이력을 설명할 때, 환각이 발생할 위험은 분명히 존재합니다. 하지만 이를 제어할 방법이 있습니다.

  • 환각이 발생하는 이유: LLM에게 “A 버전과 B 버전의 차이를 말해줘”라고만 하면, context가 너무 길어질 때 일부 로직을 생략하거나 꾸며낼 수 있습니다.
  • 해결책 (Deterministic Diff + LLM):
  1. 먼저 기계적으로 Diff를 뜹니다. (AST 레벨에서 어떤 함수가 추가/삭제/수정되었는지 텍스트로 명확히 추출)
  2. LLM에게는 ‘추출된 Diff’ 정보만 전달합니다. “이 함수의 로직이 if x > 0에서 if x > 10으로 바뀌었어. 이 변화의 의미를 요약해줘.”
  3. 결과: LLM이 스스로 코드를 비교해서 찾아내게 시키지 말고, 비교는 프로그램(AST 파서)이 하고 설명만 LLM이 하게 하면 환각은 거의 사라집니다.

12.0.3 3. 질문자님의 플랜을 시각화한 구조

이 방식은 단순히 코드를 읽어주는 것을 넘어, ’코드의 진화 과정’을 설명하는 지능형 대시보드가 될 수 있습니다.

12.0.4 4. 이 방식의 강력한 장점: “데이터 표준화의 역사”

씨젠에서 겪고 계신 ‘문서화되지 않은 암묵지’ 문제를 해결하는 데 이보다 좋은 방법은 없습니다.

  • “작년 알고리즘에서는 이 메타데이터를 A라고 정의했는데, 왜 올해 B로 바뀌었지?”라는 질문에 시스템이 “2025년 6월 업데이트 때 표준화 사업의 일환으로 로직이 통합되었습니다”라고 답해줄 수 있게 됩니다.

12.0.5 💡 제언: ’버전 관리형 RAG’를 위한 데이터 스키마

일주일 단위로 저장하실 때 DB 구성을 다음과 같이 제안합니다.

  • **Table: Code_Snapshots**
  • version_id (예: 2026-W05)
  • file_path, function_name
  • ast_structure (JSON)
  • summary_text (LLM이 쓴 요약)
  • raw_code_snippet (원본 코드)

이렇게 하면 사용자가 다음과 같이 요청할 수 있습니다:

“이번 주 업데이트에서 데이터 표준화 알고리즘 중 ‘결측치 처리’ 부분이 어떻게 바뀌었는지 알려주고, 작년 버전이랑 비교해줘.”

이 정도의 ’버전 관리형 지식 플랫폼’이라면 프로젝트 발의 시 기술적 완성도와 업무 활용도 면에서 매우 높은 점수를 받으실 것 같습니다.

혹시 사용자에게 보여줄 ‘변경 이력 요약 리포트’의 구체적인 예시(LLM 프롬프트 등)를 구상해 볼까요? 아니면 AST를 이용해 두 코드의 차이점을 추출하는 로직에 대해 더 깊이 들어가 볼까요?

13 Q7: 지금 나의 이 전략이 너가 제안해준 것보다 더 효율적인가? 충분히 기술적으로 쉽게 실현가능한가?

14 A7

결론부터 말씀드리면, 질문자님의 전략은 ‘지식 관리’와 ’기술적 안정성’ 측면에서 제가 제안한 방식보다 한 단계 더 진화한 모델입니다. 특히 씨젠과 같이 암묵지를 명시화하고 데이터 표준화의 역사를 관리해야 하는 환경에서는 훨씬 더 효율적이고 강력한 도구가 될 것입니다.

질문하신 두 가지 핵심 포인트에 대해 분석해 드립니다.


14.0.1 1. 질문자님의 전략이 더 효율적인가? (Yes, 전략적 효율성 압승)

제 제안은 ’최신성’에 집중한 반면, 질문자님의 전략은 ‘맥락(Context)과 히스토리’에 집중하고 있습니다.

  • 지식 플랫폼으로서의 가치: 단순히 “지금 코드가 뭐야?”라고 묻는 것보다 “왜 이렇게 바뀌었어?” 혹은 “예전 로직이랑 뭐가 달라?”라는 질문에 답할 수 있는 능력이 씨젠의 ’기술 공유 사업’에는 훨씬 중요합니다.
  • 리소스 관리의 예측 가능성: 실시간 업데이트는 인프라 부하가 불규칙하지만, 주 단위 업데이트는 리소스 사용을 예약(Batch)할 수 있어 운영 면에서 훨씬 안정적입니다.
  • 검증된 데이터 제공: 실시간 업데이트는 자칫 검증되지 않은 코드가 지식 베이스에 들어올 수 있지만, 버전별로 관리하면 ’검증된 배포 버전’만 지식화할 수 있어 답변의 신뢰도가 높아집니다.

14.0.2 2. 기술적으로 쉽게 실현 가능한가? (Yes, 매우 실용적인 난이도)

이 전략은 현재 가용한 기술들로 충분히, 그리고 꽤 ‘쉽게’ 구현 가능합니다.

  • AST 기반의 결정론적 비교: 텍스트(Diff)가 아니라 AST 구조를 비교하는 도구(예: Python의 ast.dump 비교나 tree-sitter의 노드 비교)를 쓰면, 단순 줄바꿈이나 주석 변경은 무시하고 ’로직의 변화’만 정확히 감지할 수 있습니다. 이는 기술적으로 이미 완성된 영역입니다.
  • 버전 관리 데이터베이스: Git처럼 모든 조각을 다 저장할 필요 없이, Snapshot 단위로 DB 테이블만 잘 설계하면 됩니다. (예: version_tag 컬럼 추가)
  • 환각 제어: LLM에게 “두 코드를 비교해봐”라고 시키지 않고, “프로그램이 찾아낸 차이점(Diff 데이터)을 바탕으로 해설해줘”라고 역할을 한정하면 환각 현상은 거의 완벽하게 제어됩니다.

14.0.3 💡 기술적 실현을 위한 구체적 팁

이 프로젝트를 성공시키기 위해 다음 두 가지만 기억하세요.

  1. ’의미 있는 차이’만 요약: 모든 사소한 수정을 다 요약하면 비용이 낭비됩니다. AST 비교를 통해 함수의 시그니처(이름, 파라미터)가 바뀌었거나, 로직의 깊이(Complexity)가 크게 변한 경우에만 LLM 요약을 트리거하게 설계하세요.
  2. 하이브리드 검색: 사용자가 질문할 때 ‘최신 버전’ 테이블을 기본으로 검색하되, “과거와 비교해줘”라는 키워드가 있을 때만 ‘과거 버전’ 테이블을 조인(Join)하도록 프롬프트를 설계하면 비용과 성능을 모두 잡을 수 있습니다.

14.0.4 🏆 결론

질문자님의 전략은 “AI Agent가 스스로 코드의 역사를 공부하고 기록하는 사관(Historian)” 역할을 부여하는 것과 같습니다. 이는 씨젠 프로젝트 발의안에서 “단순 챗봇을 넘어 지능형 플랫폼으로 가는 핵심 차별화 포인트”로 강조하기에 충분합니다.

기술적으로 막히는 부분(예: 특정 언어의 AST 비교 로직 등)이 생기면 언제든 물어봐 주세요. 바로 코드로 구현해 드릴 수 있습니다.

Subscribe

Enjoy this blog? Get notified of new posts by email: