🤖AI/ML

개체명 인식

Named Entity Recognition (NER)

텍스트에서 인명(PER), 기관명(ORG), 지명(LOC) 등 특정 의미를 가진 개체를 자동으로 찾아 분류하는 NLP 기술. 정보 추출, 검색 엔진, 챗봇, 문서 분석의 핵심 요소입니다.

📖 상세 설명

개체명 인식(Named Entity Recognition, NER)은 텍스트에서 인명(PER), 기관명(ORG), 지명(LOC), 날짜/시간(DATE), 금액(MONEY), 수량(QUANTITY) 등 특정 의미를 가진 개체를 자동으로 찾아 분류하는 자연어 처리 기술입니다. 정보 추출(Information Extraction)의 핵심 요소이며, 검색 엔진, 챗봇, 뉴스 분석, 법률/의료 문서 처리에서 광범위하게 활용됩니다.

NER은 1990년대 MUC(Message Understanding Conference) 평가에서 공식적으로 정의되었습니다. 초기에는 규칙 기반과 사전(Dictionary) 매칭이 주류였으나, 2000년대 CRF(Conditional Random Field)가 표준이 되었고, 2015년 이후 BiLSTM-CRF가 등장했습니다. 현재는 BERT, RoBERTa 등 Transformer 기반 모델이 최고 성능을 보여주며, GPT-4 같은 LLM을 활용한 Zero-shot/Few-shot NER도 연구되고 있습니다.

NER은 시퀀스 레이블링 문제로 정의됩니다. 각 토큰에 BIO 태깅(B-시작, I-내부, O-외부) 또는 BIOES(B, I, O, E-끝, S-단일) 방식으로 레이블을 부여합니다. 예를 들어 "삼성전자 이재용 회장이 서울에서"에서 "삼성전자"는 B-ORG, "이재용"은 B-PER, "서울"은 B-LOC로 태깅됩니다.

실무에서 NER은 계약서 분석(당사자/금액/날짜 자동 추출), 의료 기록 분석(약물명/증상/진단명 추출), 금융 뉴스 모니터링(기업/인물/이벤트 추적), 고객 문의 분석(제품명/서비스명 인식) 등에 필수적입니다. 한국어의 경우 조사 처리, 띄어쓰기 오류, 복합 명사 처리가 추가적인 도전 과제입니다.

📊 성능 & 비용

주요 한국어 NER 모델 성능 비교 (2025년 1월 기준)

모델 F1 Score 추론 속도 파라미터 특징
KoELECTRA-base 91.2% ~500 sent/s 110M 범용 한국어 NER
KoBERT-NER 89.5% ~400 sent/s 92M SKT 개발
klue/roberta-large 92.8% ~150 sent/s 337M KLUE 벤치마크 SOTA
spaCy ko_core_news 85.0% ~2000 sent/s 15M 경량/빠른 추론
GPT-4 (Zero-shot) 88.0% ~10 sent/s - 학습 데이터 불필요
Claude 3.5 (Few-shot) 90.5% ~15 sent/s - 복잡한 도메인 강점

선택 가이드: 대량 처리가 필요하면 KoELECTRA, 최고 정확도가 필요하면 klue/roberta-large, 도메인 특화 데이터가 적으면 LLM Zero/Few-shot을 권장합니다. LLM은 API 비용($0.01-0.06/1K tokens)이 발생합니다.

💻 코드 예제

Hugging Face Transformers를 사용한 한국어 NER 예제입니다.

# pip install transformers torch

from transformers import AutoTokenizer, AutoModelForTokenClassification
from transformers import pipeline

# 한국어 NER 모델 로드
model_name = "Leo97/KoELECTRA-small-v3-modu-ner"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForTokenClassification.from_pretrained(model_name)

# NER 파이프라인 생성
ner_pipeline = pipeline("ner", model=model, tokenizer=tokenizer,
                        aggregation_strategy="simple")

# 분석할 텍스트
texts = [
    "삼성전자 이재용 회장이 서울에서 기자회견을 열었다.",
    "2024년 1월 15일 네이버는 신규 AI 서비스를 발표했다.",
    "애플의 팀 쿡 CEO가 도쿄에서 열린 행사에 참석했다."
]

# NER 수행
for text in texts:
    print(f"원문: {text}")
    entities = ner_pipeline(text)

    for entity in entities:
        print(f"  → {entity['word']}: {entity['entity_group']} "
              f"(신뢰도: {entity['score']:.2%})")
    print()

# 출력 예시:
# 원문: 삼성전자 이재용 회장이 서울에서 기자회견을 열었다.
#   → 삼성전자: ORG (신뢰도: 98.45%)
#   → 이재용: PER (신뢰도: 99.12%)
#   → 서울: LOC (신뢰도: 97.89%)

spaCy를 사용한 빠른 NER 예제입니다.

# pip install spacy
# python -m spacy download ko_core_news_lg

import spacy

# 한국어 모델 로드
nlp = spacy.load("ko_core_news_lg")

text = """
카카오뱅크가 2024년 3월에 서울 강남에서 핀테크 컨퍼런스를 개최한다.
행사에는 김범수 카카오 창업자와 이승건 토스 대표가 참석할 예정이다.
"""

# NER 수행
doc = nlp(text)

# 결과 출력
print("개체명 인식 결과:")
for ent in doc.ents:
    print(f"  {ent.text}: {ent.label_} (위치: {ent.start_char}-{ent.end_char})")

# 출력 예시:
# 개체명 인식 결과:
#   카카오뱅크: ORG (위치: 1-6)
#   2024년 3월: DATE (위치: 8-16)
#   서울 강남: LOC (위치: 18-24)
#   김범수: PER (위치: 50-53)
#   카카오: ORG (위치: 54-57)
#   이승건: PER (위치: 65-68)
#   토스: ORG (위치: 69-71)

LLM을 활용한 Few-shot NER 예제입니다.

# pip install anthropic

import anthropic
import json

client = anthropic.Anthropic()

def extract_entities_with_llm(text: str) -> dict:
    prompt = f"""다음 텍스트에서 개체명을 추출하세요.

개체 유형:
- PER: 인명
- ORG: 기관/회사명
- LOC: 지명
- DATE: 날짜/시간
- MONEY: 금액

예시:
텍스트: "삼성전자 이재용 회장이 2024년 1월 서울에서 10억원 투자를 발표했다."
결과: {{"PER": ["이재용"], "ORG": ["삼성전자"], "LOC": ["서울"], "DATE": ["2024년 1월"], "MONEY": ["10억원"]}}

텍스트: "{text}"
결과:"""

    response = client.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=500,
        messages=[{"role": "user", "content": prompt}]
    )

    return json.loads(response.content[0].text)

# 사용 예시
text = "LG전자가 2024년 4월 부산 벡스코에서 500억원 규모의 AI 로봇 사업을 공개한다."
entities = extract_entities_with_llm(text)
print(entities)

# 출력: {"PER": [], "ORG": ["LG전자"], "LOC": ["부산 벡스코"], "DATE": ["2024년 4월"], "MONEY": ["500억원"]}

🗣️ 실무 대화 예시

💬 회의에서

"계약서에서 당사자명과 계약금액을 자동 추출하려면 NER이 필요합니다. 법률 도메인에 특화된 데이터로 KoELECTRA를 파인튜닝하면 F1 95% 이상 나올 거예요. 특히 '을', '갑' 같은 법률 용어 처리가 중요합니다."

💬 면접에서

"의료 NER 시스템을 구축했습니다. 처방전에서 약물명, 용량, 복용 방법을 추출하는데, BioBERT 기반으로 파인튜닝하여 약물명 인식에서 F1 0.94를 달성했어요. 의약품 데이터베이스와 연동해서 후처리로 정규화도 진행합니다."

💬 기술 토론에서

"한국어 NER에서 '삼성전자 반도체 사업부'처럼 중첩 개체가 문제예요. 기본 BIO 태깅으로는 안 되고, Span-based 모델이나 Multi-label classification으로 접근해야 해요. 아니면 계층적으로 먼저 전체를 인식하고 다시 분해하는 방법도 있어요."

⚠️ 주의사항

도메인 불일치

일반 뉴스로 학습된 모델을 의료/법률/금융 문서에 적용하면 성능이 크게 떨어집니다. 도메인 특화 용어와 표현 방식이 다르기 때문입니다.

중첩 개체 무시

"삼성전자 반도체 사업부"처럼 개체가 중첩되는 경우를 처리하지 못하는 모델이 많습니다. 실무에서는 자주 발생하는 패턴입니다.

띄어쓰기/오타 민감

한국어 NER은 띄어쓰기 오류("서울시" vs "서울 시")와 오타에 민감합니다. 전처리 없이 모델에 넣으면 성능이 저하됩니다.

올바른 방법

도메인 특화 데이터로 파인튜닝하고, 맞춤법 검사기로 전처리하세요. 중첩 NER이 필요하면 Span-based 모델을 사용하고, 후처리로 사전 기반 검증과 정규화를 추가하면 정확도가 올라갑니다.

🔥 실제 장애 사례

금융권 A사 2022

NER 오인식으로 고객 계좌 잘못 연결

원인: 고객 문의에서 "김민수"를 인명으로 인식했으나, 실제로는 지점명("김민수 지점")이었음. 동명이인 고객 계좌에 잘못 연결

영향: 개인정보 유출, 고객 클레임, 금융감독원 경고

해결: 컨텍스트 기반 검증 강화, "~지점", "~점" 패턴 후처리 규칙 추가

교훈: NER 결과를 그대로 신뢰하지 말고, 특히 금융/의료 등 민감한 도메인에서는 반드시 후처리 검증과 휴먼 리뷰를 병행해야 합니다.

뉴스 미디어 B사 2023

동명이인 오인식으로 잘못된 기사 자동 생성

원인: NER이 "이영희"를 단순히 PER로 태깅, 동명이인 구분 없이 유명인 프로필을 자동 연결하여 잘못된 정보 노출

영향: 명예훼손 소송, 기사 삭제, 신뢰도 하락

해결: Entity Linking(개체 연결) 파이프라인 추가, 확신도 낮은 경우 휴먼 리뷰 필수화

교훈: NER은 "무엇이 개체인가"만 알려줄 뿐, "누구인가"는 Entity Linking이 필요합니다. 특히 인명은 동명이인 처리가 필수입니다.

📝 이해도 퀴즈

Q1. NER에서 "삼성전자"를 태깅할 때 올바른 BIO 레이블은?

Q2. 다음 중 NER의 성능 평가에 가장 널리 사용되는 지표는?

Q3. "삼성전자 반도체 사업부"처럼 개체가 중첩되는 경우를 처리하기 위한 방법이 아닌 것은?

🔗 관련 용어

📚 더 배우기