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의 품질을 높이려면 검색 성능만 개선하기보다, 의미 단위·원문 근거·출처 간 관계·최신성·충돌 상태를 함께 관리해야 한다. 특히 자동화는 명확한 변경 감지와 관계 추출에 사용하고, 사내 용어 통합이나 중요한 정책 판단처럼 맥락 의존적인 문제는 근거를 제시한 뒤 사람의 승인을 받는 방식이 안전하다.