AI 세무 상담 (tax-chat)
얼마집 AI 세무 상담은 재개발·재건축 소유자를 위한 세무 Q&A 서비스입니다. Claude Haiku 4.5 + 세금 계산 도구 + 법령 PDF 주입으로 구성됩니다.
도메인 지식
세무 코드를 수정할 때 반드시 알아야 하는 한국 세법 맥락입니다.
양도소득세
- 1세대 1주택 비과세 경계: 실거래가 12억원이 기준선. 이하이면 전액 비과세, 초과 시 초과분에 대해서만 과세. 이 12억 기준은 법 개정으로 변경될 수 있음 (2021년 이전에는 9억이었음).
- 장기보유특별공제 이중 구조: 1세대 1주택은 보유기간 공제(최대 40%) + 거주기간 공제(최대 40%) = 최대 80%. 일반 부동산은 보유기간 공제만(최대 30%). 이 두 로직이 코드에서 분기됨.
- 단기매매 중과: 1년 미만 70%, 1~2년 60%. 이건 누진세율이 아니라 단일세율이므로
applyBracket()을 쓰지 않음. - 다주택자 중과: 기본세율 + 중과세율(2주택 +20%, 3주택+ +30%). 장기보유특별공제 미적용. 조정대상지역 한정.
취득세
- 조정대상지역 2주택 중과(8%) 한시 유예: 2022.12.21 이후 유예 중으로 일반세율 적용. 유예 종료 시
route.ts의calculate_acquisition_tax로직 수정 필요 — 현재 2주택 조정대상지역에서 일반세율을 적용하는 분기가 이 유예를 반영한 것임. - 6억~9억 구간 비례세율:
(취득가액 × 2/3억 - 3) / 100— 단순 구간이 아니라 연속 함수이므로TaxBracket으로 표현하지 않고 inline 계산 유지.
종합부동산세
- 공정시장가액비율: 현재 60%. 이 비율은 매년 변경 가능 (과거 100% → 95% → 60% 변동 이력).
route.ts의calculate_property_tax에서fairMarketRatio = 0.60으로 하드코딩되어 있으므로, 변경 시 이 값과prompt.ts의 종부세 텍스트 모두 수정 필요. - 기본공제: 1세대 1주택자 12억원, 그 외 9억원. 이것도 법 개정 대상.
재산세 (지방세)
종부세와 이름만 비슷할 뿐 다른 세목이다. 도구도 calculate_local_property_tax로 따로 있다
(calculate_property_tax는 종부세 전용). 세율·과세표준·부가세가 전부 다르므로 섞지 말 것.
- 누진세율이다: 표준세율 “3억 초과 0.4%“는 단일세율이 아니라
과세표준 × 0.4% - 630,000원이다. 누진공제를 빼먹으면 과다 계산된다 — 2026-08-27에 모델이 정확히 이 실수를 해서 사용자에게 지적받았다(HMH-8947). - 1세대 1주택은 기준선이 두 개고 서로 다르다:
- 특례세율(지방세법 제111조의2) → 시가표준액 9억원 이하만
- 공정시장가액비율 43/44/45% (시행령 제109조①2 단서) → 9억 초과도 포함
- 즉 공시 12억 1주택은 “표준세율 + 45% 비율”이라는 조합이 된다.
- 공정시장가액비율에 연도가 박혀 있다: 시행령 조문이 “2026년도에 납세의무가 성립하는” 이라고 명시한다.
매년 개정되므로
LOCAL_PROPERTY_TAX_1HOUSE_FAIR_MARKET_RATIOS는 해마다 시행령을 다시 확인해야 한다. - 고지액 = 본세 + 도시지역분 + 지방교육세: 도시지역분은 과세표준의 0.14%(제112조①2), 지방교육세는 본세의 20%(제151조①6, 도시지역분 제외). 본세만 답하면 실제 고지서와 어긋난다.
- 주택에는 세부담상한(150%)을 걸지 않는다: 제122조 단서가 “다만, 주택의 경우에는 적용하지 아니한다”라고
명시한다(각 호는 2023.3.14 삭제). 주택은 세액이 아니라 과세표준에 상한을 건다 —
과세표준상한액 = 직전 연도 과세표준 상당액 + (당해 과세표준 × 5%)(제110조③ + 시행령 제109조의2). 직전 연도 과세표준 상당액은 직전 연도 시가표준액 × 당해 연도 공정시장가액비율이므로, 필요한 입력은 작년 ‘납부세액’이 아니라 작년 ‘공시가격’이다. ⚠️ 종부세(calculate_property_tax)는 여전히 세부담상한 150%가 있다 — 다른 세목이니 섞지 말 것. - 공유 지분은 누진세율 적용 “후”에 안분한다: 지분을 과세표준에 먼저 곱하면 낮은 누진구간이 걸려 과소 산출된다. 제107조①2가 건물·토지 소유자가 다른 경우에 대해 “그 주택에 대한 산출세액을 …비율로 안분계산”이라고 정한 것과 같은 순서다.
증여세
- 10년 합산과세: “동일인” 기준. 아버지와 어머니는 별도 동일인으로, 각각 5천만원 공제 적용(직계존비속 성년 기준). 단, 배우자의 직계존속은 동일인 취급에 주의가 필요함.
- 혼인·출산 증여재산 공제 (2024.1.1~ 시행): 직계존속→직계비속 증여 시, 혼인신고일 전후 2년 이내 또는 자녀 출산·입양일로부터 2년 이내인 경우 기본 인적공제 외 1억원 추가 공제.
calculate_gift_tax의marriage_or_childbirth파라미터로 적용. 추가공제 상수:taxRates.ts의GIFT_MARRIAGE_CHILDBIRTH_EXTRA_EXEMPTION. - 부담부증여: 수증자가 인수하는 채무 부분은 증여세가 아닌 양도소득세 과세 대상. 현재
calculate_gift_tax는 안내 메시지만 제공하고 양도세 연계 계산은 하지 않음. - 증여 시가 기준: 증여일 전후 6개월(비상장주식은 전후 3개월) 내 매매사례가액, 감정가액, 수용·공매가액 순으로 적용.
주택 수 판단
- 관리처분인가 이후의 입주권은 주택 수에 포함
- 분양권은 2021.1.1. 이후 취득분부터 주택 수 포함
- 법인 명의 주택은 1세대 1주택 비과세 제외, 다주택자 판정에 미포함
- 상속주택 소수 지분(15~20% 이하)은 주택으로 미판정되는 특례 존재
외부 API 제약
국토교통부 RTMS (실거래가)
- 월 단위 조회만 가능:
DEAL_YMD파라미터가YYYYMM형식. 일 단위 필터링 불가. - 아파트 전용:
RTMSDataSvcAptTrade엔드포인트는 아파트만. 빌라(RTMSDataSvcRHTrade), 오피스텔(RTMSDataSvcOffiTrade)은 별도 엔드포인트. - XML 응답: JSON이 아님.
<item>태그를 정규식으로 파싱하는 구조. - 법정동코드 5자리 필요: Kakao 지오코딩으로
b_code를 얻은 뒤 앞 5자리(lawdCd)로 조회. - 데이터 지연: 실거래 신고 후 30일 이내 등록이므로 최근 1개월 데이터는 불완전할 수 있음.
Kakao Maps (지오코딩)
- “반포자이 아파트” 같은 키워드 검색 시 동명 아파트가 여러 곳 나올 수 있음. 현재는 첫 번째 결과만 사용.
- 키워드 검색(
/v2/local/search/keyword) → 주소 검색(/v2/local/search/address) 2단계로b_code를 추출.
공시가격 API (향후 연동 예정)
- 매년 4월경 공시. 그 전에는 전년도 데이터만 존재하므로 fallback 필요.
MOLIT_API_KEY로 접근 가능.
세율 변경 시 수정 가이드
세율은 features/tax-chat/lib/taxRates.ts 한 곳에서 관리됩니다.
taxRates.ts 수정 → prompt.ts가 자동으로 프롬프트 텍스트 재생성
→ route.ts의 tool들이 applyBracket()으로 동일 데이터 참조taxRates.ts에 없는 하드코딩 값들 (별도 수정 필요):
| 위치 | 값 | 설명 |
|---|---|---|
route.ts calculate_capital_gain_tax | 1200000000 | 1세대 1주택 비과세 한도 12억 |
route.ts calculate_capital_gain_tax | 0.70, 0.60 | 단기매매 중과세율 |
route.ts calculate_capital_gain_tax | 0.30, 0.20 | 다주택자 중과 가산세율 |
route.ts calculate_capital_gain_tax | 2500000 | 양도소득 기본공제 250만원 |
route.ts calculate_property_tax | 0.60 | 종부세 공정시장가액비율 |
route.ts calculate_property_tax | 1200000000, 900000000 | 종부세 기본공제 |
route.ts calculate_acquisition_tax | 0.08, 0.12 | 다주택 취득세 중과세율 |
taxRates.ts GIFT_MARRIAGE_CHILDBIRTH_EXTRA_EXEMPTION | 100_000_000 | 혼인·출산 증여재산 추가공제 1억원 |
prompt.ts LONG_TERM_HOLDING_TEXT | 공제율 테이블 | 장기보유특별공제율 (구간이 복잡하여 별도 관리) |
검증 시나리오
세금 계산 로직 수정 후 반드시 확인해야 하는 케이스입니다.
양도소득세
| 시나리오 | 입력 | 기대 결과 |
|---|---|---|
| 1주택 비과세 | 매도 12억, 취득 6억, 보유 3년, is_acquired_in_adjusted_area=false | 세금 0원 |
| 1주택 고가주택 | 매도 15억, 취득 6억, 보유 5년, 거주 3년, is_acquired_in_adjusted_area=false | 초과분만 과세, 장특공 적용 |
| 조정대상지역 거주요건 | 매도 12억, 취득 6억, 보유 3년, is_acquired_in_adjusted_area=true, 거주 0년 | 비과세 아님 — 전액 과세 |
| 조정대상지역 미지정 | 위와 동일하되 is_acquired_in_adjusted_area 생략 | needs_input 반환 (비과세 단정 금지) |
| 날짜 역전 | 취득 2025-01-01, 양도 2024-01-01 | needs_input='sale_date' |
| 존재하지 않는 날짜 | 취득 2024-02-30 | needs_input='acquisition_date' |
| 단기매매 1년 미만 | 매도 5억, 취득 4억, 보유 6개월 | 70% 단일세율 |
| 다주택 중과 | 매도 10억, 취득 5억, 3주택, 조정대상 | 기본세율 + 30% |
증여세
| 시나리오 | 입력 | 기대 결과 |
|---|---|---|
| 배우자 10억 | gift_value=10억, spouse | 과세표준 4억, 세액 7천만원 |
| 성년자녀 3억 | gift_value=3억, lineal_adult | 과세표준 2.5억, 세액 4천만원 |
| 공제 이하 | gift_value=5천만, lineal_adult | 세금 0원 |
| 혼인·출산 공제 | gift_value=1.5억, lineal_adult, marriage_or_childbirth=true, gift_direction='from_ascendant' | 과세표준 0원 (5천만+1억=1.5억 공제), 세금 0원 |
| 혼인·출산 방향 역전 | 위와 동일하되 gift_direction='from_descendant' | 추가공제 미적용 — 기본공제 5천만만 |
| 혼인·출산 방향 미지정 | 위와 동일하되 gift_direction 생략 | needs_input='gift_direction' |
| 혼인·출산 비해당 관계 | gift_value=1.5억, other_relative, marriage_or_childbirth=true | 추가공제 미적용, 과세표준 1.4억 |
| 10년 합산 | gift_value=3억, previous_gifts=2억, lineal_adult | 합산 5억-5천만=4.5억 기준 |
조정대상지역 판정 (isAdjustedArea)
시 단위 입력은 조정대상지역으로 보지 않습니다. 같은 시 안에서도 구마다 지정 여부가 다르기 때문입니다.
| 입력 | 기대 결과 |
|---|---|
수원 · 용인 · 성남 · 안양 | false — 시 단위로는 판정하지 않음 |
분당구 · 수지구 · 장안구 | true — 구 이름이 유일하면 시를 생략해도 매칭 |
강남 · 과천 | true — 말미 행정단위 생략 허용 |
중랑구 | 중랑구 — 중구로 오매칭되지 않음 |
종합부동산세
| 시나리오 | 입력 | 기대 결과 |
|---|---|---|
| 1주택 공제 이하 | 공시가격 11억, 1주택자 | 세금 0원 (12억 공제) |
| 1주택 과세 | 공시가격 15억, 1주택자 | 과세표준 3억, 공정비율 60% 적용 |
재산세 (computeLocalPropertyTax)
| 시나리오 | 입력 | 기대 결과 |
|---|---|---|
| 8/27 사고 케이스 | 공시 7.4억, 1주택 | 비율 45%, 특례세율, 본세 535,500원, 총 1,108,800원 |
| 특례세율 상한 초과 | 공시 12억, 1주택 | 표준세율 + 비율 45% (두 기준선이 다름) |
| 다주택 | 공시 7.4억, 1주택 아님 | 비율 60%, 표준세율, 본세 1,146,000원 |
| 과세표준상한 | 위 + 직전연도 공시 5억 | 과세표준 241,650,000원으로 제한, 본세 303,300원 |
| 공유 지분 50% | 위 + share_ratio=0.5 | 과세표준은 전체 유지, 본세만 절반 안분 |
| 도시지역분 비대상 | 위 + is_urban_area=false | 도시지역분 0원 |
| 공시가격 미입력 | assessed_value=0 | needs_input='assessed_value' (0원 아님) |
법령 코퍼스 (public/laws)
법령은 도구가 아니라 시스템 프롬프트에 사전 주입됩니다. RAG·벡터 검색이 아니라
pdfTextExtractor.ts의 키워드 매칭으로 파일을 고르고, LAW_INJECTION_BYTE_BUDGET(80,000B) 안에서 담습니다.
코퍼스는 apps/api/public/laws/와 apps/app/public/laws/ 양쪽에 동일하게 둡니다
(apps/api/next.config.ts의 outputFileTracingIncludes가 이 경로를 서버리스 번들에 넣습니다).
| 디렉토리 | 성격 | 주입 우선순위 |
|---|---|---|
0_종합부동산세법 · 4_양도소득세 · 5_소득세법 · 6_상속증여세법 · 7_지방세법 · 8_조세특례제한법 | 세법 | 0 (먼저) |
1_재건축_재개발 · 2_토지거래_허가 · 3_투기과열지구 | 절차법 | 1 |
예산이 빠듯할 때 절차법 전문이 세법 발췌를 밀어내지 않도록 (우선순위, 크기) 순으로 채웁니다.
세액 답변의 근거는 세법이기 때문입니다(HMH-8943).
어떤 메시지로 고르는가 — 대화 전체 폴백
키워드 매칭은 마지막 사용자 메시지를 먼저 봅니다. 여기서 아무 문서도 못 고르면
(law_path='none') 그때만 대화 전체 사용자 메시지 합본으로 한 번 더 고릅니다
(getTaxLawContextWithSession). 복구된 턴은 tools_used.law_sticky=true 로 남습니다.
사용자는 법률 용어가 아니라 구어체로 말하기 때문입니다. “처제가 나한데 현금 4억원을
계좌이체로 주면 세금이 나오나” 에는 증여 가 없습니다. 그래서 계산에 필요한 값을 건네는
후속 턴일수록 매칭이 깨져 법령 0바이트로 답하고, 모델은 조문 번호를 기억으로 지어냅니다.
실측으로 응답턴의 19%가 law_path='none' 이었고 그중 80%는 대화 전체를 보면 매칭됐습니다
(HMH-9303). 모델 선택(selectTaxChatModel)은 이미 대화 전체를 보는데 법령 선택만
마지막 메시지를 보던 비대칭이 원인이었습니다.
1차에서 고른 턴은 재조회하지 않습니다 — 이미 매칭된 턴의 주입량·지연·프롬프트 캐시 특성을
그대로 두기 위해서입니다. 대화 전체를 봐도 매칭이 없으면 'none' 을 유지하고 법령을 억지로
끌어오지 않습니다(잡담·기록 삭제 요청 등).
세법 발췌 갱신 (매년)
5_~8_ 디렉토리는 국가법령정보센터 OPEN API에서 조문 단위로 뽑아 생성합니다. 손으로 편집하지 마세요 —
다음 갱신 때 덮어써집니다. 세법은 통상 연말 공포·1월 시행이므로 개정 후 아래를 실행합니다.
yarn tax-law:fetch --dry-run # 파일 크기만 확인
yarn tax-law:fetch # apps/api·apps/app 양쪽에 생성- 뽑을 조문 목록은
scripts/fetch-tax-law-excerpts.ts의EXCERPTS에 있습니다. 개정으로 조문 번호가 바뀌면 여기를 고칩니다(없는 조문이면 스크립트가 실패합니다). - 법령 전문은 넣지 않습니다. 소득세법 1.3MB·조특법 2.8MB로 예산을 통째로 넘깁니다.
- 발췌본에 요약·의역·해석을 넣지 않습니다. 이 파일이 곧 모델의 인용 근거이므로, 사람이 쓴 해석이 섞이면 “근거 있는 답변”이라는 전제가 깨집니다.
- 파일을 추가·개명하면
pdfTextExtractor.ts의LAW_FILE_RULES(filenameContains)도 함께 고칩니다.apps/app/src/features/tax-chat/lib/lawContext.test.ts가 실제 코퍼스를 읽어 이 계약을 검증합니다.
공시가격 데이터 적재 (assessed_prices)
get_assessed_value 도구가 사용하는 정식 공시가격 데이터의 Supabase 적재·운영 가이드는 별도 페이지에서 다룹니다:
- 공동주택 공시가격 데이터 (assessed_prices) — 매년 1회 CSV 적재 SOP, 트러블슈팅, 운영 명령어, 적재 이력