법률 상담 챗봇 개발기 (1) - 판례 데이터셋 만들고 법적 쟁점 정리하기
법률 상담 챗봇을 만들고 있습니다. 그 첫 단계로, 임베딩과 벡터 스토어를 이용해 가장 많이 인용된 판례와 가장 많이 다뤄진 법리를 정리해보았습니다. 가장 많이 인용된 판례는 대법원 2012다89399 전원합의체 판결이었고, 가장 많이 다뤄진 법리는 "공동정범 성립에 있어서의 공모의 의미"였습니다.
이 다음으로 할 작업은 각각의 법리를 다룬 사례들에서 해당 사례의 사실관계, 결론 등을 추출해내고, 그 결과를 이용해 같은 쟁점의 새로운 사실관계에 대해 법원의 판단을 흉내낸 응답을 생성해보는 것입니다.
(이 글에서 다룬 작업의 코드와 결과물은 구글 CoLab에서 확인하실 수 있습니다)
0. 들어가며
법률 상담 챗봇을 만들어 보고 있습니다. 일반인들이 변호사님과 상담하듯이 법과 관련된 다양한 궁금증들을 편하게 물어볼 수 있는 서비스로서 네이버 지식인 법률 코너의 인터랙티브한 버전으로 생각하시면 되겠습니다.
챗GPT를 위시로 한 인공지능 기술의 발전이 눈부십니다. 저는 3년 안에, 늦어도 5년 안에는 변호사님들이 일하는 방식이 완전히 달라질 것이라고 생각합니다. 대부분의 문서 생성은 기계가 대신하게 될 것이고 사람은 그렇게 생성된 문서를 최종 확인하는 작업 위주로 일하게 될 것이라 생각합니다. 그리고 이 일을 제가 잘 할 수 있을 것 같아서 시도해보고 있습니다. 일반인을 대상으로 하는 챗봇은 아이디어를 검증하는 차원의 작업이고 그 작업을 성공적으로 마치고나면 법률 전문가 분들이 쓰실 수 있는 보다 고도화된 서비스를 만들어 볼 계획입니다.
챗봇을 만드는 일은 다시 3단계로 나눠서 진행하고 있습니다.
첫 번째 단계는 우리 법에 어떤 법적 쟁점들이 있는지, 그리고 그 쟁점들에 대해 확립된 판례는 무엇인지를 정리하는 작업입니다. 챗봇은 언어 모델(LLM)을 사용해서 만들게 되는데, 질의된 법적 쟁점에 대해 정확히 응답하기 위해서는 각 쟁점에 대한 법원의 확립된 판례를 예시와 함께 프롬프트에 넣어줘야 합니다. 즉, 첫 단계 작업은 법적 쟁점별로 프롬프트에 넣어줄 텍스트를 정리하는 작업으로서 판례라는 원 데이터를 가공해 언어 모델에 사용하기 더 적합한, 더 사용 가치가 높은 형태의 중간 결과물을 만들어 놓는 작업입니다.
두 번째 단계는 고정된 질의에 대해 응답을 생성해내는 작업입니다. 네이버 지식인에서의 사용자 질문이나 질의회시집의 예시 질의들처럼, 고정된 질의에 대해 정확한 응답을 생성해 내는 것이 이 단계의 목표입니다.
마지막 세 번째 단계는 대화 형태로 진행되는 질의에 대해 정확한 응답을 생성해내는 것입니다. 여기에는 질의자의 질문에서 정확한 법적 쟁점을 추출하는 일, 그리고 필요한 경우 질의자에게 질문을 해서 필요한 정보를 확인하는 일 등이 포함됩니다.
현재 저는 첫 번째 단계를 진행하고 있습니다. 이 글을 시작으로 앞으로 몇 차례에 걸쳐 제가 이 작업을 하면서 만난 문제들, 그 문제들을 해결한 방법들, 그 과정에서 배운점들, 그리고 중간 결과물들을 공유해보려 합니다. 이 글에서는 1) 챗봇 개발의 사전 작업으로서 법제처 판례 데이터를 허깅페이스 데이터셋으로 만든 일, 2) 이 판례 데이터셋에서 법적 쟁점들을 추출해서 확인해본 일을 정리해 보았습니다.
1. 판례 데이터셋 만들기
법률 상담 챗봇을 만드는데 있어서 가장 중심이 되는 데이터는 역시 판례 데이터입니다. 판례는 법제처 국가법령정보센터 등에서 확인할 수 있지만 컴퓨터 프로그램 안에서 여러 판례들을 보다 쉽게 처리하기 위해서는 이용하기 편리한 형태로 저장해놓는 것이 필요합니다. 관련해서 엘박스라는 회사에서 판례 데이터셋을 공개해 놓은 것이 있지만(엘박스 오픈), 여기에는 판례 본문 정보만 있고 판례를 특정할 수 있는 사건번호 등은 포함돼있지 않아서 사용하기에 적당하지 않았습니다.
그래서 제가 직접 법제처에서 오픈 API 형태로 제공하고 있는 전체 판례 데이터를 다운로드 받아서 약간의 검증을 한 후 허깅페이스 데이터셋으로 공개해 놓았습니다. 이 데이터셋에는 총 85,660개의 판례가 포함돼 있고 사건 번호, 법원명, 선고 일자 등 API 에서 제공되는 모든 정보를 그대로 저장해 놓았습니다.
2. 판례 코퍼스에서 법적 쟁점 추출하기 - 작업 설계
그 다음은 이 판례 코퍼스에서 다뤄진 법적 쟁점들을 정리하였습니다. 여기서 말하는 “법적 쟁점"은 여러 판례들에서 반복해서 인용하고 있는 법원의 정립된 해석을 의미합니다. 보다 구체적으로는, 판례에서 정해진 형식에 따라 앞선 판례를 인용할 때 그 인용 구문이 다루고 있는 사안, 해석하고 있는 대상을 말합니다. 예를 들어 판례에서 어떤 법리를 인용하는 형식은 다음과 같습니다.
"근로기준법상의 근로자에 해당하는지는 계약의 형식보다 근로제공 관계의 실질이 근로제공자가 사업장에서 임금을 목적으로 종속적인 관계에서 사용자에게 근로를 제공하였는지에 따라 판단하여야 한다(대법원 2006. 12. 7. 선고 2004다29736 판결 등 참조)."
- 대법원 2021다210829 판결
이렇게 인용되는 구문 안에는 하나의 법적 쟁점과 그 쟁점에 대한 법원의 해석, 결론이 들어있습니다. 그리고 같은 내용의 구문이 여러 판례에서 반복해서 인용되고 판단의 기준으로 사용되면 그 해석은 해당 쟁점에 대한 법원의 태도가 됩니다.
(나중에는 이렇게 명확한 인용 형식을 갖춘 법리뿐 아니라 판례의 모든 텍스트를 기반으로 보다 풍부하고 정교하게 판례를 이해해야겠습니다만, 현재 단계에서는 명확한 인용으로 한정해서 서비스를 개발해도 충분하다고 생각합니다.)
인용 문구는 항상 일정한 형식을 따르므로(괄호를 열고 법원명, 선고일자, 사건 번호 등을 적고 괄호 닫음), 이 부분을 판례에서 찾아내는 일은 어렵지 않습니다. 그런데 우리 판례에서는 동일한 법리라도 인용할때마다 인용 문구가 조금씩 다릅니다. 예를 들어 위 판례와 동일하게 "대법원 2004다29736 판결"을 인용한 대법원 2020다237117 판결은 같은 법리를 다음과 같이 인용하고 있습니다.
"근로기준법상 근로자에 해당하는지는 계약의 형식보다 근로제공관계의 실질이 근로제공자가 사업 또는 사업장에 임금을 목적으로 종속적인 관계에서 사용자에게 근로를 제공하였는지 여부에 따라 판단해야 한다. 여기에서 종속적인 관계인지는 (중간 생략) 등의 경제적·사회적 여러 조건을 종합해서 판단해야 한다(대법원 2006. 12. 7. 선고 2004다29736 판결, 대법원 2020. 12. 24. 선고 2018다298775, 298782 판결 등 참조)"
- 대법원 2020다237117 판결
앞선 판례에서는 첫 문장이 “근로기준법상의”로 시작하지만, 두 번째 판례는 “근로기준법상”으로 시작하며 띄어 쓰기도 조금씩 다릅니다. 또 이 사례에서처럼 어떤 경우는 핵심만 짧게 인용하는 경우도 있고 다른 경우에는 전체 내용을 보다 상세하게 인용하는 경우도 있습니다. 그래도 이 두 판례는 같은 판례를 인용하고 있는데서 알 수 있듯이 동일한 대상에 대해 동일한 결론을 말하고 있습니다.
그러면 법적 쟁점을 정리하는데 있어서 필요한 다음 작업은, 문구는 조금씩 다르더라도 의미는 같은 문장들을 하나로 묶어주는 작업입니다. 이 작업은 임베딩과 벡터 사이의 유사도 계산을 통해 쉽게 해낼 수 있습니다. 예를 들어 위 두 인용 문구 사이의 벡터간 코사인 유사도는 0.968입니다.
import openai
from openai.embeddings_utils import cosine_similarity
def encode(text):
return openai.Embedding.create(
model="text-embedding-ada-002",
input=[text]
)['data'][0]['embedding']
s1 = "근로기준법상의 근로자에 해당하는지는 계약의 형식보다 ... 판단하여야 한다"
s2 = "근로기준법상 근로자에 해당하는지는 계약의 형식보다 ... 판단해야 한다"
print(cosine_similarity(encode(s1), encode(s2)))이렇게 인용 구문들을 임베딩한 뒤 충분히 유사한 벡터들을 하나로 묶음으로써 판례에서 다뤄진 법리들을 확인할 수 있습니다.
3. 판례 코퍼스에서 법적 쟁점 추출하기 - 작업 실행
이제 작업 설계는 모두 끝났습니다. 여기서 한 가지 제가 추가로 고려한 점은, 전체 법적 쟁점을 모두 정리하는 대신 가장 많이 다뤄진 법적 쟁점을 찾고 그 쟁점들에 대해서만 이후 작업을 진행하기로 한 점입니다. 그 이유는, 인용 문장들을 임베딩하는데도 비용이 들고 또 추후에 쟁점 별로 판례를 정리하는데도 상당한 비용이 들어서(OpenAI Completion API 비용) 작업 범위를 조정하는 것이 필요하기 때문입니다. 지금하고 있는 전체 작업의 목표는 저의 문제 정의와 접근 방법이 유효한 것인지를 확인하는데 있기 때문에 굳이 모든 쟁점을 다 정리할 필요가 없고 대신 선별된 쟁점들에 대해 충분히 좋은 품질의 결과물을 만들어내는 것이 더 중요하다고 판단했습니다.
그리고 가장 많이 다뤄진 법리를 찾는 일에 있어서도 약간의 타협을 하였습니다. 원칙적으로는 판례 코퍼스의 모든 인용 구문을 찾아서 그 인용 구문들을 전부 임베딩한 뒤, 그 임베딩 값들로 클러스터링해야 되겠지만, 돈과 시간을 아끼기 위해서 다음과 같은 방법으로 진행했습니다.
전체 판례 코퍼스에서 피인용 판례들의 인용 횟수를 정리합니다.
피인용 횟수 기준으로 상위 n개의 판례를 추리고, 그 판례들 중 하나를 인용하고 있는 인용 구문에 대해 임베딩 & 클러스터링을 진행합니다.
보다 자세한 작업 과정은 아래와 같습니다(이 전체 과정은 구글 CoLab에서 확인해 보실 수 있습니다).
전체 판례 코퍼스를 순회하면서 각각의 판례에 대해 다음 작업을 수행합니다.
판례 본문 안에서 여는 괄호(‘(‘)와 닫는 괄호(‘)’)로 감싸진 부분을 전부 찾습니다.
이렇게 괄호로 감싸진 부분들 중에서 법리 인용 괄호에 해당하는 것들을 정규표현식으로 확인합니다.
확인된 법리 인용 괄호들에서 법원명과 사건번호를 추출합니다. 법원명과 사건번호는 그 쌍으로 하나의 판결을 특정합니다.
추출된 법원명-사건번호 쌍으로 피인용 횟수를 계산합니다.
이렇게 작업한 결과, 피인용 횟수 상위 3개 판례는 다음과 같았습니다.
대법원 2012다89399 전원합의체 판결, 118회 피인용
대법원 95다28625 전원합의체 판결, 97회 피인용
대법원 2004다29736 판결, 72회 피인용
그 다음 임베딩 & 클러스터링 작업은 다음과 같이 진행하였습니다.
전체 판례 코퍼스를 순회하면서 판례 하나하나에 대해 다음 작업을 수행합니다.
앞에서와 같은 방식으로 괄호로 감싸진 부분을 찾고, 그 괄호 안 내용이 판례를 인용하는 것인지 확인하고, 거기서 인용하고 있는 판례가 피인용 횟수 기준 상위 n개에 포함되는 판례인지 확인합니다.
만약 맞다면 그 인용 구문을 임베딩합니다. 인용 구문은 원칙적으로 인용 괄호가 포함된 문단의 시작부터 해당 인용 괄호 직전까지가 인용 구문인 것으로 가정하였습니다.
이 임베딩 벡터를 가지고 벡터 스토어에서 가장 유사한 벡터를 확인합니다. 가장 유사한 벡터의 유사도가 임계값 이상이면 이 두 벡터는 동일한 것으로 보고 이 법리의 반복 횟수를 1만큼 증가시킵니다. 만약 유사도가 임계값 이하이면 두 벡터는 서로 다른 법리이므로 벡터 스토어에 현재 벡터를 저장하고 법리 반복 횟수를 1로 세팅합니다. 즉, 벡터 스토어를 해시 셋으로 이용하여 반복 횟수를 계산하였습니다.
피인용 횟수 분포도와 예상되는 비용을 종합적으로 고려하여 이하 작업은 피인용 횟수 상위 300개 판례를 대상으로 진행하였습니다. 또 여러 샘플들로 실험해본 결과 두 벡터 사이의 유사도가 0.94 이상이면 대부분 동일한 법리인 것으로 확인하였습니다.
그런데 이 방법은 판례 코퍼스 순회 순서 상 어떤 법리를 다룬 최초 벡터를 기준으로 그 벡터와의 유사도로 클러스터링하는 것이기 때문에 실제로는 같은 법리임에도 불구하고 최초 벡터와 사이에 차이가 좀 있어서 같은 클러스터로 묶이지 않는 경우가 생길 수 있습니다. 이 문제를 해결하기 위해 1차 클러스터링이 끝난 결과물을 가지고 같은 클러스터에 속한 벡터들을 평균 낸 뒤에 이 클러스터 평균값들 사이의 유사도를 다시 한번 계산하여 그 유사도가 임계값 이상인 경우에는 두 클러스터를 하나로 합쳤습니다. 이렇게 작업한 결과, 가장 많이 인용된 법리 3개는 다음과 같습니다.
공동정범 성립에 있어서의 공모의 의미, "공동정범의 성립에 있어서 공범자 사이의 공모와 범죄의 실행에 관하여는 ~", 257회 인용
행정처분이 당연무효가 되기 위한 요건, "행정처분이 당연무효라고 하기 위해서는 그 처분에 위법사유가 있다는 것만으로는 부족하고 ~", 221회 인용
횡령행위 입증의 주체, "불법영득의사를 실현하는 행위로서의 횡령행위가 있다는 점은 어디까지나 검사가 ~", 215회 인용
4. 결론 및 다음편 예고
이 글에서는 법률 상담 챗봇이라는 최종 결과물을 만들기 위해 제가 어떻게 문제에 접근하고 있는지, 그 중간 단계들을 어떻게 설정하고 있는지를 소개하였습니다. 그리고 그 첫 번째 단계로서 판례 데이터셋을 준비한 것, 그리고 그 데이터셋에서 가장 많이 다뤄진 법적 쟁점을 확인한 작업을 공유하였습니다.
다음편부터는 보다 본격적으로 유의미한 결과물들을 공유해보겠습니다. 보다 구체적으로 다음 편에서는,
법적 쟁점별로(예컨대 “근로기준법상 근로자에 해당하는지 판단하는 기준”) 그 쟁점을 다룬 모든 판례를 나열합니다.
그 판례들에서 해당 법적 쟁점에 대한 결론(인정됐는지 여부 등), 해당 쟁점과 관련된 사실 관계, 해당 쟁점에 대한 법원의 판단 부분을 추출해냅니다. 여기에는 알고리즘과 프롬프트 엔지니어링 등을 이용하게 됩니다.
이 결론, 사실 관계, 판단 추출물들을 프롬프트에 삽입해서 동일한 쟁점의 다른 사실 관계에 대해 언어 모델이 얼마나 정확히 응답을 생성해 내는지 확인합니다. 여기서 보다 정확하고 안정적인 결과물을 만들어내기 위해서는 어떤 작업이 추가적으로 필요한지, 컨텍스트 윈도우 크기와 관련하여 생기는 문제들은 어떻게 처리할 수 있는지 등을 다뤄보겠습니다.
댓글
로그인 후 댓글을 남길 수 있습니다.
준호님 메이커로그가 Must Reads #242에 선정되었어요! https://stib.ee/vql8
분야는 다르지만 비슷하게 작업을 진행하고 계신 것 같아 흥미롭게 읽었습니다. 다음편 기대됩니다
법률 상담 챗봇 개발기 2편이 나왔습니다! https://disquiet.io/@pungrue26/makerlog/%EB%B2%95%EB%A5%A0-%EC%83%81%EB%8B%B4-%EC%B1%97%EB%B4%87-%EA%B0%9C%EB%B0%9C%EA%B8%B0-2-%EB%82%98%ED%99%80%EB%A1%9C%EC%86%8C%EC%86%A1-%EC%84%9C%EB%B9%84%EC%8A%A4%EB%A1%9C-%ED%94%BC%EB%B4%87