| name | ipzitalk-education-environment |
| description | 주소 또는 단지명을 입력받아 교육 환경(초·중·고 학교, 2~3km 내 대학교, 학원 밀집)을 종합해 종합 등급 + 한줄평 + 인터랙티브 HTML 리포트와 지도를 생성한다. "교육 환경", "학군", "학군 좋아?", "학교 가까워", "중학교/고등학교 근처", "대학교 근처", "학원가", "교육 인프라" 등의 표현이 있으면 이 스킬을 사용한다. (단일 "초품아만"/"학세권만"은 해당 배지 스킬로 분리 — 트리거 겹치지 않게.)
|
| version | 1.0.3 |
| license | proprietary |
교육 환경 분석
주소/단지명 하나로 학교(초·중·고)·대학·학원을 종합해 대표 보고용 교육 리포트를 만든다.
※ 모든 거리는 직선거리 기준. 배정·학군은 미확인(학교 배정은 학구도 별도 확인). 학원 개수는 밀집 근사(과목·규모 미구분).
입력
| 파라미터 | 필수 | 기본 | 설명 |
|---|
address 또는 complex_query | ✅(택1) | - | 주소 또는 단지명 |
radius_m | ✕ | 1500 | 근린 축(초등·중·고) 표시 반경. 최대 5,000m |
단지명이 브랜드(예: 롯데캐슬)라 후보가 여러 개면 자동 확정하지 말고 후보(지역 포함)를 제시해 선택받는다.
⚠️ 5개 축 = 검색 다수 → 크레딧·시간 소요를 감안.
반경 처리 (R1~R3) — radius_m은 판정 파라미터가 아니라 관측 파라미터다
| 층위 | 값 | 사용자 radius_m |
|---|
| 밴드(등급 판정) | 축별 절대 거리, 불변 | 영향 없음 |
| 표시 반경(지도 원·목록) | 초등·중·고 기본 1,000 · 사용자가 주면 그 값 | 그대로 반영 |
| 수집 반경(API 호출) | max(radius_m, 밴드최대 1000 × 1.25) | 하한만 보장 |
- R1. 밴드는 절대 기준. 반경을 3km로 넓혀도 최근접 초등 425m는 여전히 "양호(300–500)"다. 실측으로 확인(아래 검증 섹션).
- R2. 수집 반경은 항상 밴드 최대 이상으로 자동 확장. 사용자가 300m를 줘도 1,250m까지 탐색한다. 안 그러면 800m 학교를 놓치고 ">1000 미흡"으로 오판한다. "반경 내 없음"과 "이격"은 다르다.
- R3. 요청 반경 밖이라도 최근접 1건은 항상 표시. 회색 + "요청 반경 밖 · 2.3km" 꼬리표.
- cap 5,000m. 지방 사업지는 1km 안에 초등학교가 없을 수 있어 2~3km까지 봐야 한다. 수집 반경(최대 5km) 안에도 0건이면 "5km 내 초등학교 없음(미확인)"으로 명시하고 멈춘다. 추정 금지.
- 광역 축 격리: 대학은 3,000m 고정,
radius_m 미적용. 학원은 판정창 700m 고정(개수형 — 반경을 바꾸면 밴드가 무의미해진다).
🚨 45건 캡 + subcategory_filter는 후처리다 (실측)
search_by_nearby_category는 쿼리당 최대 45건만 주고 grid 옵션이 없다(키워드 검색에만 있다). 더 나쁜 것은 subcategory_filter가 서버 필터가 아니라 45건을 받은 뒤 거르는 후처리라는 점이다.
밀집지 실측이 이를 증명한다:
중학교 13 + 고등학교 13 + 대학교 3 + 초등학교 16 = 45 ← 카카오 상한 정확히 도달
categories:['school'] 원본 응답이 45건에서 잘렸고, 그 45건을 subcategory_filter로 나눈 결과다. 즉 3km 내 중·고·대학 중 일부는 응답에 아예 오지 않았다. 네 축 모두 truncated:true.
- 다만 카카오는
sort=distance로 준다 → 잘리는 건 언제나 먼 것들이고 최근접은 정확하다.
- 따라서 등급 판정은 안전, 목록·개수는 근사.
metadata.truncated가 true면 리포트에 "목록 불완전" 경고를 단다.
- 서울 학교 밀집지는 반경 2km부터 이미 캡에 걸린다. cap 5km는 판정용이지 목록용이 아니다.
지도 호출 규칙 (서버 렌더 버그 회피)
/map?d=의 fitBounds는 마커만 감싸고 반경 원을 무시한다. center에서 마커 bounds의 북·남·동·서 여유가 각각 radius_m 이상이어야 원이 온전히 보인다.
- 🚨 반경 눈금 마커를 넣지 않는다. 예전엔
fitBounds가 반경 원을 무시해 원이 잘리는 걸 막으려고
정북·남·동·서에 회색 더미 마커 4개를 심었다. 사용자에게는 정체를 알 수 없는 점으로 보여 혼란만 준다.
원이 잘리더라도 마커는 실제 장소만 찍는다. (근본 해결은 render.ts가 원을 bounds에 포함하도록 고치는 것 — 발견사항 6번)
center + radius_m 항상 함께, 마커 2개 이상(1개면 서버가 zoom:15 고정).
- 카드 CSS에서 iframe에
min-width:720px, .map{overflow-x:auto} — 좁은 화면 최소줌(한반도) 방지.
필수 도구
| 도구 | 용도 |
|---|
get_geocode / get_address | 좌표 확보(주거시설 후보 우선) |
search_by_nearby_category | 초등 categories=['school_elementary'] · 중/고/대학 categories=['school'] + subcategory_filter |
search_by_nearby_keyword | 학원 query="학원" + grid |
get_static_map / get_map_embed_url | 지도(교육시설 마커 + 크게 열기 링크) |
워크플로우 (검증된 검색식)
- 좌표 확보 — address→geocode / 단지명→get_address(주거시설 우선). 후보 다수 → 사용자 선택.
- 초등학교(근린 축) —
search_by_nearby_category(center, radius_m=수집반경, categories=['school_elementary'])
→ 최근접 거리(초품아 밴드). 수집반경 = max(radius_m, 1250). ✅ 검증됨.
- 중학교 / 고등학교(근린 축) —
search_by_nearby_category(center, radius_m=수집반경, categories=['school'], subcategory_filter={category_name_contains:"중학교"})
그리고 동일 방식으로 category_name_contains:"고등학교". ✅ 검증됨(서문여중 613m 등 정확 반환).
⚠️ subcategory_filter는 후처리라 45건 캡 이후에 걸린다 → 목록 불완전 가능(위 캡 섹션).
- 대학교(광역 축, 고정) —
search_by_nearby_category(center, radius_m=3000, categories=['school'], subcategory_filter={category_name_contains:"대학교"})
→ 존재 여부·최근접. radius_m 미적용. ✅ 검증됨.
- 학원(개수형, 판정창 고정) —
search_by_nearby_keyword(center, radius_m=700, query="학원", grid=true, category_filter={include_contains:["학원"]})
→ 700m 내 개수(밀집) + 최근접. grid=true라 45건 캡을 우회한다(truncated:false 확인). ✅ 검증됨(원본 180건 → 중복제거 59개).
- 판정창 700m는 고정. 사용자가
radius_m을 줘도 개수 밴드는 700m 창으로 계산한다. 반경을 바꾸면 "≥20 밀집" 기준이 무의미해진다.
- 사용자가 학원 반경을 명시적으로 지정하면 개수만 제시하고 등급은 유보한다.
- 계열 무관 총계로 판정한다(현행 확정). 교과·예체능·기타(운전면허·카이로프랙틱 등)가 혼재한다. 좁힐 때는
include_contains 를 한 원소씩 따로 호출해 합집합한다(["보습"], ["어학"], ["수학"] …).
🚨 include_contains 는 AND 라 배열로 한꺼번에 넣으면 항상 0건이다(실측 2026-07-10).
exclude_contains 는 OR 이라 배열로 넣어도 된다. 그리고 좁히면 밴드를 재설정해야 한다.
- 판정·등급 → 축별 등급 → 종합 → 지도 → 출력(md 요약 먼저 → HTML).
밴드 (직선거리 / 학원은 개수)
| 축 | 기준 |
|---|
| 초등(초품아) | ≤300 우수 / 300–500 양호 / 500–1000 보통 / >1000 미흡 |
| 중·고 | 최근접 ≤500 우수 / 500–1000 양호 / >1000 미흡 |
| 대학 | 2~3km 내 존재 = 있음 / 없음 / 확인 불가(아래 0건 재확인 절차) |
| 학원(학세권) | 반경 700m 개수 ≥20 밀집 / 8–19 다수 / 1–7 소수 / 0 없음 |
0건이 나오면 재확인한다 (🚨 부재 단정 금지)
카테고리 검색은 45건 캡이 서버가 아니라 후처리 필터라, 밀집지역에서는 실제로 있는 시설이 0건으로 보일 수 있다.
어떤 축이든 0건이 나오면 그대로 "없음"이라 쓰지 말고 아래를 수행한다.
metadata.truncated 를 본다. true 면 캡에 걸린 것이므로 부재로 단정하지 않는다.
- 같은 축을 키워드 검색으로 한 번 더 조회한다(카테고리 필터 대신
search_by_nearby_keyword, 예: 대학 → "대학교"). 반경은 그 축의 판정창 그대로.
- 두 방식 모두 0건이고
truncated:false 면 → "반경 내 없음" 으로 확정한다.
- 한쪽이라도 캡에 걸렸거나 결과가 엇갈리면 → "확인 불가(검색 한계)" 로 적는다.
없음과 확인 불가를 섞어 쓰지 않는다.
- 재확인에도 좌표·center는 재해소하지 않는다(크레딧 낭비).
종합 등급 (★ 3단계)
- 초등 접근성 + 학원 밀집을 주 축, 중·고·대학은 보조. 한줄평에 학군 특성 정직 서술.
- 종합 ★★★ 우수 / ★★☆ 양호 / ★☆☆ 미흡 + 한줄평.
- 강점(학원 밀집·초 보도권)과 약점(중·고 양호·먼 편)을 균형 있게. 초등 최근접이 타 자치구 소재면 반드시 배정주의 명시.
출력 포맷 (교통 환경 분석과 동일 골격)
- 채팅(먼저): 종합 등급 + 한줄평 + 축별(초등/중·고/대학/학원) 최근접·등급 요약(md 표).
- HTML 리포트(선택): 상단 제목+종합 등급 pill → 지도 히어로 iframe → 종합 평가 박스 → 초등/중·고/대학/학원 4섹션 표 → 초등 배정확인 링크 → 출처·hedge 푸터.
- 레이아웃 기준:
templates/result.html
- 초등 배정 확인 링크 필수: 학구도(통학구역) 안내 서비스 https://schoolzone.emac.kr/gis/gis.do
🚨 개교 예정 학교를 최근접으로 쓰지 않는다 (실측 2026-07-09)
카카오 장소명에 개교 예정이 문자열로 들어온다. 좌표·거리는 정상적으로 반환되므로 무심코 최근접이 된다.
"산빛초등학교 (2027년 3월 예정)" distance_m 311 ← 미개교
"서울송례초등학교" distance_m 411 ← 운영 중
- 등급·최근접 라벨은 운영 중인 학교로 판정한다. 예정 학교는 표에 플래그만 단다.
- 판별: 장소명에
예정·개교·(20NN년 이 포함되면 개교 예정, 휴교·폐교 가 포함되면 운영 중단으로 본다.
연도·사유를 지어내지 말 것 — 장소명에 있는 문자열만 쓴다.
- 예정 학교를 최근접으로 쓰면 "지금 걸어갈 수 있는 학교"가 아닌 것을 근거로 등급이 매겨진다.
🚨 경계 생활권은 시·도가 섞인다 (실측 2026-07-09)
위례 반경 1.25km 초등학교 10곳 중 3곳이 경기도였다 — 하남시 위례초(891m), 성남시 위례중앙초(1,084m)·위례고운초(1,148m).
위례는 서울 송파구 · 경기 하남시 · 경기 성남시 3개 시·군에 걸친다.
- 최근접이 타 시·도면 자치구 단위보다 배정 가능성이 더 낮다.
배정주의 를 더 강하게 표기하고 학구도 링크를 반드시 붙인다.
- 표의 주소 열에 시·도를 노출해 사용자가 스스로 알아볼 수 있게 한다.
필수 단서 · 금지 표현
- 필수: 직선거리 기준 · 배정/학군 미확인(초등 최근접이 타 자치구·타 시·도면 배정주의) · 학원 개수는 계열 무관 총계(교과·예체능·운전면허 등 혼재, 과목·규모 미구분) · 중·고·대학 목록은 45건 캡으로 불완전 가능 · 개교 예정 학교는 등급 근거에서 제외 · 출처·조회일 표기.
- 금지: "초품아 확정", "배정 학교 = OO", "특정 학군 우수 확정", "명문 학군" 단정, 개교 예정·휴교·폐교 학교를 최근접으로 제시.
엣지 · 실패 처리
| 상황 | 처리 |
|---|
지오코딩 실패 / NOT_FOUND | 재입력 요청 |
후보 다수 / AMBIGUOUS | 후보(지역) 나열 후 선택 |
| 특정 축 0건 | 해당 섹션 "없음/원거리" 명시, 거리 지어내지 않음 |
| 초등 최근접이 타 자치구 소재 | 표에 "OO구·배정주의" 플래그 + 학구도 링크로 배정 확인 유도 |
| 키워드 45건 cap | 최근접·개수만 사용(밀집 판정엔 영향 적음) |
검증된 사항 (서울 서초구 방배동 사례 · 조회 2026-07-08)
- 초등
school_elementary r1500: 최근접 425m(타 자치구 소재·배정주의) · 이수초 545m · 방배초 556m → 보도권(양호).
- 중학교
school+category_name_contains:"중학교" r1500: 서문여중 613m · 이수중 620m → 양호.
- 고등학교
school+category_name_contains:"고등학교" r1500: 서문여고 702m · 경문고 1.0km → 양호.
- 대학교
school+category_name_contains:"대학교" r3000: 2km 내 3곳 → 있음.
- 학원
query="학원" grid r700: 원본 180건 → 중복제거 59개 밀집 → 우수. truncated:false(grid로 캡 우회).
- 종합 ★★☆ 양호 산정 확인 — 학원 밀집(59) 강점 + 초 보도권 + 중·고 양호 + 대학 존재. 중/고/대학 subcategory 검색식도 검증됨.
추가 검증 (사용자 지정 반경 3km · 2026-07-09)
- R1 실증:
radius_m=3000으로 재조회해도 최근접 초등 425m·중 613m·고 702m는 그대로 → 등급 불변(★★☆ 양호). 반경은 관측 파라미터일 뿐 판정에 새어들지 않는다.
- 45건 캡 실증: r3000에서 중 13 + 고 13 + 대 3 + 초 16 = 정확히 45건.
categories:['school'] 원본이 캡에 걸렸고 subcategory_filter는 그 뒤에 거르는 후처리다. 네 축 모두 truncated:true → 서울 학교 밀집지는 반경 2km부터 목록이 불완전하다. 등급은 sort=distance 덕에 안전.
- 1km 초과 초등 다수 확인(1.3km~2.3km) → R3에 따라 회색·"요청 반경 밖" 표기 대상.
- 학원 계열 분포: 59개 중 교과 약 22 · 예체능 약 30 · 기타 약 7. 계열 무관 총계로 판정하기로 확정. "학원 밀집 = 교과 학원가"로 읽으면 과대평가된다는 점을 hedge에 명시.
섹션마다 출처를 작게 단다
데이터 블록 하단에 .src 한 줄. 도구·API 이름은 쓰지 않는다. 사용자가 아는 기관명만.
| 블록 | 출처 표기 |
|---|
| 단지 개요·세대수·준공·주차·연차 | 공동주택관리정보시스템(K-apt) |
| 매매·전세·평당가·거래량 | 국토교통부 실거래가 |
| 학교·교통·생활·상권 등 장소 | 카카오맵 |
| 분양공고·분양가·주택형·입주월 | 청약홈 |
| 지도 (장소 마커) | 네이버 지도 · 카카오맵 |
| 지도 (분양공고 마커) | 네이버 지도 · 청약홈 |
- 🚨 출처 문자열은
ipzi-data JSON으로 받지 않고 템플릿 마크업에 직접 박는다.
어느 블록이 어디서 왔는지는 실행마다 달라지지 않는다. 데이터로 받으면 채우는 걸 잊거나 틀리게 쓸 여지만 생긴다.
- 🚨 한 블록에 두 출처가 섞이면 병기한다. 예:
세대수·주차 — 공동주택관리정보시스템(K-apt) · 위치 — 카카오맵.
하나로 뭉뚱그리면 어느 숫자가 어디서 왔는지 사용자가 알 수 없다.
- 🚨 쓰지 않은 기관을 출처로 적지 않는다. 우리가 부르는 곳은 위 다섯 곳뿐이다.
- 히어로·유의사항·푸터에는 달지 않는다. 데이터 블록에만.
디자인 정본
스킬 폴더 밖 문서에 의존하지 않도록 규칙을 여기 인라인으로 둔다.
- CDN·외부 폰트·이모지 금지. 아이콘은
<symbol> 인라인 + <use> 참조로 self-contained.
- 라이트/다크 양쪽.
prefers-color-scheme + :root[data-theme] 모두 대응.
- 토큰만 사용:
--g/--y/--o/--r/--x/--brand/--up/--down/--zebra (+ -s 배경 변형).
- 예외 상태:
null은 "정보없음"(0 아님) · 표본 부족은 판정 유보 · 목록 캡 도달은 "목록 불완전" 표기.
★·☆는 활자 기호이며 이모지가 아니다. 등급 표기에 사용 가능.
- 지도 카드 CSS:
.map{overflow-x:auto; overflow-y:hidden} + .map iframe{display:block; min-width:720px}.
overflow:hidden만 주면 iframe이 카드 폭에 짓눌려 지도가 최소 줌(한반도)으로 떨어진다.
- 🚨 지도 링크는 발급 후 7일 만료. 산출물 지도 캡션에 유효기간·재발급 필요를 반드시 적는다.
만료 시 iframe이 빈 화면이 되는데, 원인 표기가 없으면 리포트가 고장난 것처럼 보인다.
🚨 휴교·폐교 학교도 그대로 섞인다 (실측 2026-07-10)
개교 예정과 같은 함정이다. 카카오는 학교의 운영 상태를 장소명 문자열에만 적고,
category_name 은 정상 학교와 글자 하나 다르지 않다. 거리도 정상으로 준다.
서울반포초등학교 (휴교) 728m 교육,학문 > 학교 > 초등학교
반포중학교 (휴교) 626m 교육,학문 > 학교 > 중학교
산빛초등학교 (2027년 3월 예정) 311m 교육,학문 > 학교 > 초등학교
카테고리 검색도 걸러주지 않는다. (지하철은 categories:['subway'] 가 미개통역을 빼주지만, 학교는 아니다.)
등급이 실제로 뒤집힌다 — 서울반포초 바로 앞(반경 700m) 실측:
서울반포초등학교 (휴교) 17m ← 그대로 쓰면 🟢 초품아 인접
계성초등학교 520m ← 운영 중 최근접. 올바른 등급은 🟡
- 🚨 운영 중인 학교로만 판정한다. 휴교/폐교/개교 예정은 목록·지도에 참고로만 두고
개수·등급·최근접에서 뺀다(
aux 처리).
- 재건축 이주 구역에서 특히 잦다(반포·둔촌 등). 휴교는 재개교할 수도, 안 할 수도 있다.
재개교 시점을 추정하지 말 것. 장소명에 있는 문자열만 화면에 쓴다.
- 키워드 검색을 쓰면
학교부속시설(교무실·운동장·정문·별관)까지 딸려 온다. 실측 초등학교 15건 중 8건이 부속시설이었다.
category_name 이 > 학교 > 로 끝나는 것만 학교로 센다.
MCP 도구 네임스페이스와 출처
ipzitalk MCP 도구의 네임스페이스는 실행 환경(Codex, Claude Code, Hermes, claude.ai 커넥터 등)에 따라 다르다.
이 문서에 적힌 도구 이름(search_announcement_info, get_geocode, get_map_embed_url 등)은 접두사 없는 기본 도구명(base tool name) 이다.
- 먼저 연결된 도구 목록에서 같은 기본 도구명을 찾는다.
- 그중
ipzitalk-remote 플러그인의 ipzitalk 서버 provenance가 확인되는 도구만 우선 사용한다. Codex에서는 실제 도구 호출 이벤트의 server: ipzitalk과 기본 도구명을 기준으로 확인한다.
presale-mcp 또는 다른 로컬 MCP provenance의 동명 도구는 Remote Skill의 대체 수단으로 사용하지 않는다.
- provenance를 확인할 수 없거나 같은 기본 도구명이 여러 서버에 있어 모호하면 임의 선택하지 말고 중단하여 필요한 Remote 도구명을 안내한다.
클라이언트가 연결 도구 목록에 plugin/server provenance를 구조적으로 제공하지 않을 때만 다음 명시적 fallback을 사용한다.
mcp__plugin_ipzitalk-remote_ipzitalk__<도구명>
mcp__ipzitalk_mcp__<도구명>
mcp__ipzitalk__<도구명>
mcp__claude_ai_ipzitalk__<도구명>
fallback으로도 Remote 출처를 유일하게 확인할 수 없으면 값을 추정하지 말고, 사용자에게 ipzitalk Remote MCP 연결 상태를 확인하도록 안내한 뒤 중단한다.