"""업소 조사 프롬프트 — 소개문을 쓸 **근거**를 공개 웹에서 찾아온다. ★ 무엇을 요구하나 "소개문을 써 달라"가 아니다. **사실 조각을 출처와 함께** 달라고 한다. 소개문을 모델에게 바로 시키면 그 문장이 어디서 왔는지 알 수 없고, 우리 규칙은 근거 없는 문장을 발행하지 않는다(`copy_service.ground_check`). 그래서 이 단계는 재료만 모으고, 문장은 기존 생성기(Gemini)가 그 재료로 쓴다. ★ 왜 이게 필요한가 (실측 2026-09-10, 스테이,머뭄) 네이버 플레이스가 주는 fact 는 3건(주차·와이파이·휠체어)뿐이고 TourAPI 는 미등록, 예약 페이지와 인스타그램은 robots 가 자동 수집을 금지한다. 그 상태로 소개문을 생성하면 "군산시에 있는 스테이,머뭄입니다. 주차 가능." 한 줄이 나온다 — 쓸 재료가 그것뿐이라 생성기 잘못이 아니다. 그런데 이 업소에 대한 사실(1920년대 고택 · 히로쓰 가옥 옆 · 2024년 리모델링 · A동/B동)은 블로그·기사에 공개돼 있다. 그걸 **출처와 함께** 가져오는 자리가 없었을 뿐이다. ★ 지어내게 두지 않는다 - 항목마다 출처 URL 을 요구한다. 없으면 버린다(`grounding/place_research.py`). - 확인할 수 없는 것은 비우라고 명시한다. 모델은 빈칸을 싫어해서, 안 그러면 채운다. - **가격·객실 수·운영 규정은 묻지 않는다.** 그건 fact 이고, 틀리면 예약 클레임이 난다 — 출처가 블로그면 옛 요금이 그대로 올라온다. 이 단계가 모으는 것은 **소개문의 재료**다. """ SYSTEM_PROMPT = ( "당신은 지역 업소를 조사하는 사람이다. 웹에서 확인되는 사실만 적는다. " "확인되지 않으면 그 항목을 아예 빼라 — 추측하거나 일반론으로 채우지 마라. " "출력은 JSON 하나뿐이고 코드펜스를 두르지 않는다." ) # ★ 최대 개수를 둔다. 많이 받아 봐야 소개문 한 문단이고, 길수록 옛 정보가 섞인다. MAX_ITEMS = 8 def build_prompt(name: str, address: str, category_label: str) -> str: """조사 프롬프트. 상호와 주소를 **둘 다** 준다 — 동명 업소를 가르는 유일한 단서다.""" return f"""다음 업소에 대해 웹에서 확인되는 사실을 모아라. 상호: {name} 주소: {address} 업종: {category_label} [무엇을 찾나] - 이 업소만의 특징: 건물의 내력·연식, 공간 구성, 주변 랜드마크와의 관계, 운영 방식 - 손님이 실제로 겪는 것: 어떤 사람이 어떤 목적으로 오는가, 무엇이 인상적이라고 말하는가 - 시기: 문을 연 때, 고쳐 지은 때 [적지 않을 것] - 요금·객실 수·체크인 시각·취소 규정 — 이건 다른 경로로 확인한다. 옛 값이 섞이면 위험하다 - "아름다운", "최고의" 같은 형용사만 있는 문장 - 다른 업소 이야기. 상호와 주소가 위와 일치하는 곳만이다 [문장 쓰는 법] - **각 문장에 업소 이름을 넣어라.** "이 숙소는…" 처럼 쓰지 마라 — 문장만 떼어 놔도 어느 업소 이야기인지 알 수 있어야 한다. 뒤에서 이 문장들만 모아 근거로 쓰기 때문이다. - 한 문장에 사실 하나. 두 가지를 이어 붙이면 한쪽이 틀렸을 때 통째로 버리게 된다. [형식] 아래 JSON 만 출력한다. 각 항목에 **그 사실이 적힌 페이지 주소**를 단다. {{"items": [{{"text": "한 문장으로 적은 사실", "source": {{"name": "출처 이름", "url": "https://..."}}}}]}} 항목은 최대 {MAX_ITEMS}개. 출처를 댈 수 없는 항목은 넣지 마라 — 적게 주는 편이 낫다."""