code-analysis

2 개의 포스트

toss5분 읽기큐레이션 요약

LLM은 똑똑한데, 왜 우리 회사 일은 모를까

LLM이 사내 질문에 정확히 답하려면 단순히 관련 문서를 검색하는 것만으로는 부족하다. 문서·코드·메신저의 최신성, 상충 여부, 실제 구현과의 일치 여부까지 관리하는 신뢰 가능한 컨텍스트 계층이 필요하며, Topic은 이를 구축하기 위한 시스템이다. Topic은 원본을 의미 단위로 정규화하고, 개념과 관계를 연결한 뒤, 변경된 부분만 선택적으로 검증한다. ## 검색만으로는 신뢰를 보장할 수 없는 이유 - 검색은 질문과 관련된 텍스트를 찾아줄 뿐, 해당 정보가 최종 결정인지 판단하지 못한다. - 문서, 미팅, 코드가 서로 다른 정책을 설명할 수 있다. - 메신저 논의가 실제 결론인지, 문서가 오래된 것인지, 코드 변경이 의도된 것인지 추가 판단이 필요하다. - 에이전트가 각자 원문을 검색하면 자료 선택과 충돌 해석이 달라져 답변 일관성이 떨어진다. - Topic은 출처, 관계, 최신성, 충돌 상태를 공통 계층에서 관리해 사람과 LLM이 같은 근거를 사용하도록 한다. ## 신뢰를 구성하는 여섯 가지 축 - **Granularity**: 독립적으로 관리할 수 있는 적절한 크기와 의미의 컨텍스트인지 판단한다. - **Faithfulness**: 컨텍스트의 주장이나 설명이 원문 근거로 뒷받침되는지 확인한다. - **Staleness**: 정보가 현재도 유효한지 검사한다. - **Canonicality**: 서로 다른 이름이나 표현이 같은 대상을 가리키는지 판단한다. - **Consistency**: 여러 출처의 내용이 서로 양립하는지 확인한다. - **Coverage**: 중요한 근거와 관점이 누락되지 않았는지 살핀다. - 모든 문제를 하나의 신뢰도 점수로 합치지 않고, 규칙·LLM·사람 검토를 각각 적합한 판단에 사용한다. ## Ingest: 출처별 의미 단위를 보존한 정규화 Topic은 문서·코드·메신저의 원본을 공통 `ContentUnit`으로 변환한다. - 주요 필드: - `source_type`: document, code, messenger - `unit_type`: 문서 섹션, 메신저 스레드 등 - `source_uri`: 원문으로 돌아가는 주소 - `content_hash`: 변경 감지용 해시 - `created_at_src`, `updated_at_src` - 출처별 식별자와 구조를 담은 `metadata` - 공통 형식은 후속 추출·검증을 일관되게 만든다. - 출처별 구조는 의미 경계와 증거의 원천을 보존하기 위해 유지한다. ### 문서는 제목 계층 단위로 분할 - Markdown 문서를 고정 길이가 아니라 제목 구조에 따라 나눈다. - 상위 제목 경로를 함께 저장해 문장이 어떤 정책이나 기능에 속하는지 보존한다. - 섹션이 지나치게 긴 경우에만 추가 분할한다. - 문서 경로, 원문 URL, 작성·수정 시각도 검증 정보로 남긴다. ### 메신저는 개별 메시지보다 스레드 단위로 처리 - 메시지 하나만 보면 질문인지 결론인지 알기 어렵기 때문에 스레드 전체를 하나의 의미 단위로 삼는다. - 요약 시: - 함수명, 에러 클래스, 파일 경로 등 기술 식별자를 원문 그대로 보존한다. - 질문, 검토한 선택지, 최종 결과를 구분한다. - 확정된 내용과 미결정 내용을 나눈다. - 대화에 없는 합의를 만들어내지 않는다. - 잡담만 있는 스레드는 컨텍스트로 만들지 않는다. ### 코드는 심볼과 비즈니스 동작을 함께 표현 - 파서로 함수·클래스 등 코드 심볼을 추출한다. - 파일 경로, 심볼 종류, 시작·종료 줄, import 관계는 규칙 기반으로 수집한다. - 여러 심볼을 가로지르는 업무 동작은 `CodeSemanticCard`로 묶는다. - semantic card에는 다음 정보가 포함된다. - 업무 대상과 실제 동작 - 도메인 용어와 코드 식별자 - 저장소·파일·줄·심볼 단위의 근거 span - 기준이 된 `commit_sha` - LLM이 만든 카드는 파일·줄이 실제 존재하는지, 설명을 뒷받침하는 span이 있는지 규칙 기반으로 재검사한다. - 최종 검증에서는 카드의 설명만 믿지 않고 현재 코드의 실제 span을 다시 읽는다. ## Extract: 개념과 관계를 원문 근거와 연결 - 각 `ContentUnit`에서 개념 후보와 이를 뒷받침하는 문장을 추출한다. - 함께 등장한 후보를 중심으로 관계를 제안하고, 표현·의미가 유사한 후보의 중복 가능성을 계산한다. - 충분한 근거가 있을 때만 대표 개념으로 통합한다. - 문서·메신저·코드처럼 출처가 다른 unit 사이에도 연결 후보를 만든다. - 개념과 관계에는 원문 위치, 인용, 판단 상태를 함께 저장한다. ### 사내 용어는 사람 검토를 포함 - 띄어쓰기·대소문자 차이는 정규화와 임베딩으로 자동 탐지할 수 있다. - 사내 약어와 별칭은 잘못 합치면 검색·검증 전체를 오염시킬 수 있다. - 애매한 동의어는 즉시 병합하지 않고 `Synonym Proposal`로 등록한다. - 사람이 승인한 별칭만 관리되는 관계로 반영하며, 거절된 후보는 반복 제안하지 않는다. ### 문서와 코드 관계를 유형별로 구분 - `supported_by`: 코드가 문서의 설명을 뒷받침한다. - `contradicted_by`: 코드와 문서의 동작이 충돌한다. - `mentions`: 같은 기능을 언급하지만 일치·충돌 여부를 판단할 근거가 부족하다. - 임베딩으로 후보를 제한한 뒤, 의미 판단이 필요한 후보만 배치 검증한다. - 관계에는 유형뿐 아니라 신뢰도, 판단 이유, 원문 인용, 검증 상태를 기록한다. - 검증 실패나 낮은 신뢰도는 관계를 저장하지 않는다. 관계가 없다는 것은 무관하다는 뜻이 아니라 아직 확인되지 않았다는 의미다. ## Verify: 변경된 부분만 선택적으로 재검증 - 각 unit의 안정적인 식별자와 `content_hash`를 이용해 변경 범위를 추적한다. - 변경되지 않은 unit의 추출·관계 결과는 재사용한다. - 새로 생성되거나 변경된 unit만 다시 처리한다. - 원본이 삭제되면 해당 원본을 참조하던 관계도 정리한다. - 코드 anchor에는 검증 당시의 commit과 span hash를 저장한다. - 현재 코드에서 anchor가 사라졌으면 orphaned 상태로 표시한다. - anchor의 span hash가 같으면 의미 검증을 생략한다. - span hash가 달라졌으면 변경된 코드에 대해 faithfulness를 다시 검증한다. - 해시와 참조 무결성은 규칙 기반으로 검사하고, 실제 의미가 달라진 경우에만 LLM을 호출한다. - 이 방식은 비용을 줄이면서도 변경 원인과 컨텍스트 상태 변화를 추적하게 해준다. ## 실용적인 결론 사내 LLM의 품질을 높이려면 검색 성능만 개선하기보다, 의미 단위·원문 근거·출처 간 관계·최신성·충돌 상태를 함께 관리해야 한다. 특히 자동화는 명확한 변경 감지와 관계 추출에 사용하고, 사내 용어 통합이나 중요한 정책 판단처럼 맥락 의존적인 문제는 근거를 제시한 뒤 사람의 승인을 받는 방식이 안전하다.

원문 읽기(새 탭에서 열림)
toss원문

LLM을 이용한 서비스 취약점 분석 자동화 #1 (새 탭에서 열림)

토스 보안 연구팀은 구글의 'Project Naptime'에서 영감을 얻어 LLM 기반의 취약점 분석 자동화 시스템을 구축했습니다. 대용량 코드 처리, 결과의 불확실성, 운영 비용 등 실무 적용 과정에서 마주한 네 가지 핵심 기술적 난제를 단계별로 해결하며 최종적으로 95% 이상의 분석 정확도를 달성했습니다. 기술적 가능성을 넘어 실제 수백 개의 서비스에 지속적으로 적용 가능한 수준의 보안 자동화 환경을 마련했다는 점에 의의가 있습니다. **대용량 소스코드 분석을 위한 MCP 도입** * 단순히 소스코드 전체를 LLM에 입력하는 방식은 토큰 한계와 환각(Hallucination) 문제로 인해 대규모 프로젝트 분석에는 부적합했습니다. * 대안으로 RAG(검색 증강 생성)를 시도했으나 코드 간의 복잡한 연관 관계를 파악하는 데 한계가 있었습니다. * 최종적으로 MCP(Model Context Protocol)를 구축하여 LLM 에이전트가 필요할 때마다 함수 정의나 변수 사용처를 도구 호출(Tool Calling) 방식으로 자유롭게 탐색하도록 설계했습니다. **SAST 결합을 통한 분석 일관성 확보** * 동일한 코드에 대해서도 분석 결과가 매번 달라지는 LLM의 비결정성 문제를 해결하기 위해 정적 분석 도구(SAST)를 결합했습니다. * 빌드 과정이 복잡하고 무거운 CodeQL 대신, 가볍고 빠른 오픈소스 도구인 Semgrep을 활용하여 모든 입력 경로(Source)에서 위험 지점(Sink)까지의 경로를 먼저 수집했습니다. * SAST가 추출한 잠재적 취약 경로를 LLM이 집중 분석하게 함으로써 탐지 누락을 방지하고 분석의 신뢰도를 높였습니다. **멀티 에이전트 체계를 통한 비용 최적화** * 모든 코드 경로를 심층 분석할 경우 발생하는 막대한 토큰 비용을 줄이기 위해 역할을 분담한 세 가지 에이전트를 도입했습니다. * **Discovery 에이전트:** 수집된 경로 중 실제 취약점 가능성이 높은 경로를 1차로 선별하는 거름망 역할을 수행합니다. * **Analysis 에이전트:** 선별된 경로를 심층 분석하여 실제 취약 여부를 판별합니다. * **Review 에이전트:** 최종 결과를 검토하여 오탐(False Positive)을 제거함으로써 분석의 정교함을 더했습니다. **지속 가능한 운영을 위한 오픈 모델 전환** * 상용 클라우드 모델(Claude 등)의 높은 비용 문제를 해결하기 위해 직접 호스팅 가능한 오픈 모델(Open Model)로 전환했습니다. * Qwen3:30B, gpt-oss:20B, llama3.1:8B 등 다양한 모델의 ROI를 비교 분석한 결과, 취약점 분석 정확도와 도구 호출 성능이 가장 우수한 'Qwen3:30B'를 최종 선택했습니다. * 오픈 모델의 성능을 보완하기 위해 프롬프트 엔지니어링과 퓨샷 러닝(Few-shot Learning)을 적용하여 클라우드 모델 못지않은 성능을 구현했습니다. 단순히 최신 기술을 도입하는 것에 그치지 않고, 기업 환경에서 실제 운영 가능한 수준의 '비용 대비 성능'을 확보하는 것이 중요합니다. LLM 취약점 분석 시스템을 구축할 때는 모든 판단을 모델에 맡기기보다 Semgrep과 같은 전통적인 보안 도구로 분석 범위를 좁혀주고, 멀티 에이전트 구조로 단계별 필터링을 거치는 설계가 실무적으로 가장 효과적입니다.