콘텐츠로 이동

동형이의어 의미 구분 API (베타)

동형이의어 의미 구분 (베타)

같은 글자인데 뜻이 전혀 다른 단어를 동형이의어라고 합니다. 다리는 건너는 다리(橋)일 수도, 몸의 다리(脚)일 수도 있습니다. 는 타는 배(船)·먹는 배(梨)·아픈 배(腹)가 모두 같은 글자입니다. 품사만 보면 셋 다 NNG(일반 명사)라서 구분되지 않습니다.

바른은 형태소 분석 결과에 그 문맥에서 어떤 뜻으로 쓰였는지를 함께 돌려줄 수 있습니다. 요청에 with_sense 옵션 하나만 켜면 형태소마다 어깨번호(사전 의미 번호)와 뜻풀이가 붙습니다.

베타 기능입니다

동형이의어 의미 구분은 베타(beta) 단계입니다. api.bareun.ai(클라우드)와 자체 설치한 서버 모두에서 사용하실 수 있습니다. 자체 설치본은 의미 구분에 필요한 모델이 첫 기동에 함께 내려오므로, 최신 배포판을 설치하고 서버를 켜면 그대로 동작합니다.

베타 기간에는 다음을 염두에 두세요.

  • 의미 선택이 틀릴 수 있습니다. 특히 동사·형용사, 그리고 한 문장에 같은 표기가 여러 번 나오는 경우에 오류가 관찰됩니다(정확도와 한계 참고).
  • 응답 형식이 정식 릴리스 전까지 바뀔 수 있습니다. 필드가 추가되는 방향의 변화를 우선하지만, 베타 기간의 세부 값·필드는 확정본이 아닙니다.
  • 기존 호출에는 아무 영향이 없습니다. with_sense 를 켜지 않으면 응답도, 처리 시간도 종전과 완전히 동일합니다.

무엇이 달라지나요

같은 다리가 문맥에 따라 다르게 분석됩니다. 품사는 둘 다 NNG 로 동일하지만, 의미는 갈립니다.

문장 형태소 품사 어깨번호 뜻풀이
다리를 건넜다. 다리 NNG 5 물을 건너거나 … 건너다닐 수 있도록 만든 시설물.
다리가 저리다. 다리 NNG 1 사람이나 동물의 몸통 아래 붙어 있는 신체의 부분.
graph LR
  A["다리 / NNG"] --> B["다리를 건넜다<br/>→ 어깨번호 5 (시설물)"];
  A --> C["다리가 저리다<br/>→ 어깨번호 1 (신체)"];

어깨번호란 무엇인가요

국어사전은 표기가 같고 뜻이 다른 단어를 여러 항목으로 나누어 싣고, 각 항목에 번호를 붙입니다. 사전에서 다리¹, 다리² 처럼 표제어 오른쪽 위에 작게 붙는 숫자가 어깨번호입니다.

바른이 돌려주는 어깨번호는 우리말샘(국립국어원 개방형 한국어 지식 대사전)의 의미 번호 체계를 따릅니다. 그래서 어깨번호와 함께 오는 urimal_target_id 로 우리말샘의 해당 표제어 화면을 그대로 열어 볼 수 있습니다.

https://opendict.korean.go.kr/dictionary/view?sense_no=836

표준국어대사전이 아니라 우리말샘 기준입니다

한국어 사전마다 의미를 나누는 기준이 조금씩 달라, 같은 단어의 어깨번호도 사전에 따라 다릅니다. 바른은 표제어 수가 가장 많고 갱신이 이어지는 우리말샘을 기준으로 통일했습니다. 다른 사전의 번호와 그대로 맞지 않을 수 있습니다.

사용 방법

요청에 with_sensetrue 로 넣으면 됩니다. 기본값은 false 입니다.

세 가지 형태소 분석 API 에서 모두 쓸 수 있습니다.

API 경로 비고
형태소 분석 /bareun.LanguageService/AnalyzeSyntax 가장 일반적인 호출
형태소 분석(문장 분할 X) /bareun.LanguageService/AnalyzeSyntaxList 문장 배열 입력
후처리 없는 형태소 분석 /bareun.LanguageService/AnalyzeSyntaxRaw 모델 원출력
curl \
  -H "api-key: koba-ABCDEFG-1234567-LMNOPQR-7654321" \
  -H "Content-Type: application/json" \
  -X POST https://api.bareun.ai/bareun.LanguageService/AnalyzeSyntax \
  -d '{"document": {"content": "다리를 건넜다.", "language": "ko-KR"},
       "encoding_type": "UTF32",
       "with_sense": true}'

파이썬 클라이언트 bareunpy 2.1.0 이상에서 바로 쓸 수 있습니다.

pip install --upgrade "bareunpy>=2.1.0"
import bareunpy as brn

tagger = brn.Tagger(apikey="koba-ABCDEFG-1234567-LMNOPQR-7654321")

# 의미가 부여된 형태소만 바로 받기
for s in tagger.senses('다리를 건넜다.'):
    print(s.content, s.tag, s.sense_no, s.meaning)
# 다리 NNG 5 물을 건너거나 … 건너다닐 수 있도록 만든 시설물.
# 건너 VV 1 무엇을 사이에 두고 한편에서 맞은편으로 가다.

# 분석 결과 전체를 받고 그 안에서 꺼내기
res = tagger.tag('다리가 저리다.', with_sense=True)
print(res.pos(join=True, sense=True))
# ['다리__001/NNG', '가/JKS', '저리__001/VA', '다/EF', './SF']

senses() 가 돌려주는 SenseInfocontent·tag·sense_no·meaning· urimal_target_id·probability 를 담고, urimal_url 로 우리말샘 화면 주소를 만들어 줍니다. tags()·taglist()·tag_raw() 에도 같은 with_sense 옵션이 있습니다. 자세한 내용은 파이썬 클라이언트(bareunpy) 문서를 참고하세요.

import requests

URL = "https://api.bareun.ai/bareun.LanguageService/AnalyzeSyntax"
HEADERS = {"api-key": "koba-ABCDEFG-1234567-LMNOPQR-7654321"}

body = {
    "document": {"content": "다리를 건넜다.", "language": "ko-KR"},
    "encoding_type": "UTF32",
    "with_sense": True,          # 동형이의어 의미 구분(베타)
}
res = requests.post(URL, headers=HEADERS, json=body).json()

for sent in res["sentences"]:
    for token in sent["tokens"]:
        for m in token["morphemes"]:
            sense = m.get("sense")          # 없으면 의미가 부여되지 않은 형태소
            if sense:
                print(m["text"]["content"], m["tag"],
                      sense["senseNo"], sense["meaning"])

바른 MCP 서버analyze_syntax·analyze_syntax_raw 도구도 같은 옵션을 받습니다.

{
  "name": "analyze_syntax",
  "arguments": { "text": "다리를 건넜다.", "with_sense": true }
}

formatcompact 로 주면 한 줄 요약에 어깨번호가 함께 표시됩니다.

다리__005/NNG 를/JKO 건너/VV 었/EP 다/EF ./SF

bareunpy 는 2.1.0 이상이 필요합니다

with_sense·senses()bareunpy 2.1.0 에서 추가되었습니다. 그보다 낮은 버전에서는 인자가 없으니 pip install --upgrade bareunpy 로 올려 주세요. 라이브러리를 올리지 않더라도 위 REST 예시로는 바로 호출할 수 있습니다.

응답 형식

의미가 부여된 형태소에는 sense 객체가 실립니다.

{
  "text": { "content": "다리", "beginOffset": 0, "length": 2 },
  "tag": "NNG",
  "probability": 0.9917928,
  "outOfVocab": "IN_WORD_EMBEDDING",
  "sense": {
    "senseNo": 5,
    "meaning": "물을 건너거나 또는 한편의 높은 곳에서 다른 편의 높은 곳으로 건너다닐 수 있도록 만든 시설물.",
    "urimalTargetId": 836,
    "probability": 0.935963
  }
}
필드 형식 설명
senseNo 정수 어깨번호. 우리말샘 기준 의미 번호입니다. 사전 표기(005)로 되돌리려면 3자리 0채움으로 만드세요.
meaning 문자열 한국어 뜻풀이. 비어 있을 수 있습니다(아래 참고).
urimalTargetId 정수 우리말샘 표제어 고유 번호. …/dictionary/view?sense_no=<값> 으로 사전 화면을 열 수 있습니다. 0이면 미부여입니다.
probability 실수 [0,1] 그 의미를 고른 확률. 아래 확률 읽는 법 참고.

sense 가 없는 형태소가 정상입니다

sense의미가 부여된 형태소에만 실립니다. 없으면 키 자체가 응답에 나타나지 않습니다.

  • 조사·어미·기호 등은 애초에 사전 의미 번호를 갖지 않습니다(를/JKO, 다/EF, ./SF).
  • 동형이의어가 아닌 단어도 의미가 하나뿐이면 부여되지 않을 수 있습니다.
  • with_sense 를 켜지 않은 호출에는 모든 형태소에 sense 가 없습니다.

따라서 클라이언트는 sense 키의 존재 여부로 판정하세요. 파이썬이면 m.get("sense"), 자바스크립트면 m.sense?.senseNo 처럼 없을 수 있음을 전제로 다루면 됩니다.

뜻풀이가 비어 있는 경우

어깨번호는 정상인데 meaning 이 빈 문자열일 수 있습니다. 우리말샘에 그 표제어 자체가 없는 경우(숫자가 앞에 붙은 말 등)로, 전체의 1% 미만입니다. 뜻풀이가 항상 있다고 가정하지 말고 없을 때의 표시를 준비해 두세요.

확률 읽는 법

sense.probability그 단어의 후보 의미들 사이에서 정규화한 값입니다. 사전 전체의 수만 개 의미와 겨룬 값이 아니라, "이 표제어·품사에 가능한 의미들 중 이것을 고를 확률"입니다. 그래서 한 형태소의 후보 확률을 모두 더하면 1이 됩니다.

형태소의 probability 와 같은 값이 아닙니다

형태소에는 이미 probability 필드가 있는데(품사 판정에 대한 모델 점수), 성질이 다릅니다.

morpheme.probability sense.probability
이 품사일 가능성에 대한 모델 점수 후보 의미 중 이 의미를 고른 확률
한 위치의 값을 더해도 1이 아님 후보를 더하면 1

두 값을 같은 임계값으로 비교하거나 한 축에 나란히 그리지 마세요.

후보가 하나면 항상 1.0 입니다

후보 의미가 하나뿐인 단어는 확률이 늘 1(또는 1에 가까운 값)로 나옵니다. 이는 "확신이 강하다"가 아니라 "고를 것이 하나뿐"이라는 뜻입니다. 신뢰도 기준으로 쓰려면 확률만 보지 말고 그 단어가 실제로 동형이의어인지도 함께 보세요.

어떻게 쓸 수 있나요

동형이의어 구분은 "표기가 같다"는 이유로 섞여 버리던 데이터를 갈라 줍니다.

  • 검색·색인: 다리(橋) 문서와 다리(脚) 문서를 나눠 색인해, 교통 관련 검색에 신체 관련 문서가 섞이지 않게 합니다.
  • 키워드·트렌드 분석: 뉴스에서 배(船) 언급량과 배(梨) 언급량을 분리해 셉니다.
  • RAG 문서 분할·태깅: 청크에 의미 번호를 메타데이터로 붙여, 같은 표기라도 다른 주제로 묶이도록 합니다(RAG 한국어 chunking).
  • 용어 사전 연결: urimal_target_id 로 우리말샘 항목에 바로 연결해, 사용자에게 뜻풀이를 보여 줍니다.
  • LLM 프롬프트 보강: 모호한 단어의 뜻풀이를 함께 넣어 주어 모델이 문맥을 오해하지 않게 합니다.

성능과 비용

with_sense 를 켜면 의미를 고르기 위한 추론이 한 번 더 수행됩니다.

  • 켜지 않으면(기본값) 처리 시간·응답은 종전과 완전히 동일합니다.
  • 켰을 때의 추가 시간은 문장 길이에 비례하며, 형태소 분석 자체와 같은 규모의 계산이 한 번 더 붙는 정도로 보시면 됩니다. 대량 배치 처리에서는 필요한 문서에만 켜는 편이 좋습니다.
  • 응답 크기는 의미가 붙은 형태소 수만큼 늘어납니다(뜻풀이 문자열이 가장 큰 부분입니다).

정확도와 한계

베타 단계의 실제 동작을 숨기지 않고 적어 둡니다. 아래는 모두 실측 사례입니다.

잘 되는 쪽 — 명사, 문맥 단서가 분명한 문장

문장 결과
다리를 건넜다. 다리 → 5 (시설물) ✅
다리가 저리다. 다리 → 1 (신체) ✅
은행에서 돈을 찾았다. 은행 → 2 (금융 기관) ✅
은행 열매를 주웠다. 은행 → 4 (은행나무의 열매) ✅
새 배가 항구에 들어왔다. 배 → 7 (선박) ✅
과일 가게에서 배를 한 개 샀다. 배 → 8 (배나무의 열매) ✅

아직 약한 쪽

상황 실측
한 문장에 같은 표기가 여러 번 밤에 밤을 구웠다. → 두 모두 '야간'으로 판정 ❌ 같은 표기의 두 번째 출현을 첫 출현과 다르게 보는 힘이 아직 부족합니다.
동사·형용사의 의미 배를 타고 를 '피부가 햇볕에 타다'로 판정 ❌ 용언은 의미 구분 기준이 촘촘하고 학습 예문이 상대적으로 적습니다.
문맥 단서가 짧은 문장 배를 먹었다. → 배를 '복부'로 판정 ❌ 짧은 문장에는 뜻을 가릴 단서가 부족합니다.
드물게 쓰이는 의미 사전에 있으나 실제 용례가 매우 적은 의미는 자주 쓰이는 의미로 쏠립니다. 학습 예문 수가 의미별로 크게 다릅니다.

베타 기간의 권장 사용법

  • 명사 위주로 활용하세요. 검색·색인·키워드 분석 등 명사가 중요한 작업에 효과가 큽니다.
  • 자동으로 확정하지 말고, sense.probability 가 낮은 결과는 사람 확인이나 후처리 대상으로 돌리는 파이프라인을 권합니다.
  • 잘못된 판정을 발견하시면 문장과 함께 알려 주세요. 정식 릴리스 품질에 직접 반영합니다.

원리와 학습 데이터가 궁금하시면 동형이의어 구분 원리를, 다른 도구·자원과의 비교는 한국어 동형이의어 분석 자원 비교를 참고하세요.

자주 묻는 질문

Q. with_sense 를 켜지 않으면 기존 결과가 달라지나요?

A. 달라지지 않습니다. 옵션을 켜지 않은 호출은 응답 내용도, 처리 시간도 종전과 동일합니다. sense 필드도 아예 실리지 않습니다.

Q. 어깨번호는 어느 사전 기준인가요?

A. 우리말샘(국립국어원 개방형 한국어 지식 대사전) 기준입니다. 함께 오는 urimal_target_id 로 우리말샘 화면을 열 수 있습니다. 표준국어대사전의 번호와는 서로 다를 수 있습니다.

Q. 모든 형태소에 의미가 붙나요?

A. 아닙니다. 조사·어미·기호처럼 사전 의미 번호가 없는 형태소에는 붙지 않습니다. sense 키의 존재 여부로 판정하세요.

Q. 자체 설치한 바른에서도 쓸 수 있나요?

A. 네. 클라우드(api.bareun.ai)와 자체 설치 서버에서 모두 쓰실 수 있습니다. 의미 구분에 필요한 모델은 서버가 처음 실행될 때 함께 내려받으므로, 최신 배포판을 설치했다면 별도 준비 없이 with_sense 옵션만 켜면 됩니다.

Q. 맞춤법 검사기에서도 의미 구분이 쓰이나요?

A. 이번 베타는 형태소 분석 API 의 응답에 의미를 실어 주는 기능입니다. 맞춤법 교정 결과에 직접 반영되는 단계는 아닙니다.

도움이 되었나요?