Community연구 & 데이터 분석github.com

2016judea/vertical-market-agent

특정 업종과 특정 도시에 특화된 채팅 에이전트를 구축합니다. 사전 계산된 실제 공공 기록(또는 수집된 리뷰 코퍼스) 다이제스트를 가지고 있으며, 대화 중에 실시간 기록을 가져올 수 있어 일반 모델보다 뛰어난 정확도를 제공합니다.

vertical-market-agent란 무엇인가요?

이 스킬은 하나의 업종(예: 부동산, 치과, 자동차 정비)과 하나의 도시 지역에 특화된 챗봇 에이전트를 만드는 방법을 상세히 안내합니다. 일반 LLM이 환각(hallucination)을 일으키기 쉬운 구체적인 수치, 규정, 데이터 포인트를 요구하는 질문에 대해, 이 에이전트는 사전에 수집하고 정제한 '서브스트레이트(substrate)'라 불리는 실제 데이터 다이제스트를 시스템 프롬프트에 주입하여 정확한 답변을 제공합니다. 여기에는 공공 기록(카운티 평가 데이터, 세금 기록), 리뷰 데이터, 실시간 매물 정보 등이 포함될 수 있습니다. 핵심은 '확정적 수학(deterministic math)'을 프롬프트가 아닌 도구(tool)로 처리하여 계산 오류를 방지하고, 데이터의 한계와 출처를 명확히 표시하며, '발견된 숫자(plausible wrong number)'를 생성하는 일반적인 함정을 피하는 것입니다. Claude Code, Cursor, Codex 등 다양한 플랫폼에서 구현 가능하며, 특히 광고 목적지로 배송되는 경우 세션 기반 어트리뷰션, 캐시 TTL 설정, 픽셀 이벤트 추적 등 엔지니어링 결정을 안내합니다. 최종적으로는 에이전트가 다루지 않는 분야의 방문자로부터 새로운 업종 아이디어를 얻을 수 있는 '오프 섹터(off-sector)' 종료 지점과 공간적 맥락(이웃 정보) 레이어를 추가하여 완성도를 높입니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/2016judea/brick-mortar-skills/tree/HEAD/skills/vertical-market-agent

Installed? Explore more 연구 & 데이터 분석 skills: affaan-m/uspto-database, affaan-m/scholar-evaluation, affaan-m/literature-review · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

수직 시장 에이전트 구축

일반 모델보다 특정 업종과 특정 도시에서 더 뛰어난 성능을 보이는 채팅 에이전트입니다. 사전 계산된 실제 데이터 다이제스트를 가지고 있으며, 대화 중에 실시간 기록을 가져올 수 있습니다. 완료 = URL에 배포되어, 서브스트레이트로 추적 가능한 수치로 답변하고, 가지고 있지 않은 수치는 절대 만들어내지 않으며, 실제 프로브(로컬 테스트가 아닌)로 프로덕션에서 검증된 상태입니다.

0단계: 소유자가 답할 두 가지 질문

  1. 어떤 도시이며, 왜 그 도시인가? 이미 현장 조사나 말 그대로 사실인 데이터를 보유한 곳을 선택하세요. 하나의 도시를 발굴한 후 그곳에서 광고하세요.
  2. 광고될 예정이며, 연결되어 있는가? 이에 따라 네 가지 엔지니어링 결정(픽셀, 캐시 TTL, 배니티 URL, 어트리뷰션)이 달라집니다. 7단계를 참조하세요.

1단계: 코드를 작성하기 전에 해자(moat)를 찾으세요

두 가지 종류가 있습니다: 직접 발굴하여 소유한 코퍼스(예: 수만 개의 리뷰) 또는 조인(실시간 판매 피드를 카운티 토지, 평가 및 세금 기록과 결합: 아무도 귀찮게 합치지 않는 두 가지 무료 소스)입니다. 유료 대량 수집은 종종 실패합니다(크레딧 소진, 소유자 검색 부재).

대량 수집이 차단된 경우, 진입점은 데이터가 아닌 제약 조건입니다. 아무 주소에나 응답하지만 목록을 제공하지 않는 카운티 앱은 다른 곳에서 주소를 수집한다면(3단계) 괜찮습니다.

비공개 주(non-disclosure states)는 기회입니다: 경쟁자를 포함한 누구도 판매 비교 자료를 가지고 있지 않으므로, 카운티 자체의 산술을 잘 정리한 것이 최고의 기준점이 됩니다.

2단계: 서브스트레이트(substrate) 구축

모든 메시지에 대해 서버 측에서 시스템 프롬프트에 주입되는 고정 JSON 다이제스트입니다.

  • 먼저 패널 크기를 확인하세요(리뷰 코퍼스 에이전트의 경우). "당신과 비슷한 장소들 중 당신의 순위"를 알려면 각각 50개 이상의 리뷰를 가진 ~50개 이상의 업체가 필요합니다. 그 이하에서는 순위를 제공하지 마세요.
  • 모델이 작성한 업종 프로필은 서브스트레이트가 아닙니다. 모델이 작성한 산문을 로드하는 것은 모델이 이미 알고 있는 내용을 알려줄 뿐이며 해자를 만들지 않습니다. 서브스트레이트는 측정된 것입니다.
  • 누락된 데이터는 장애물이 아니라 백로그입니다: 패널을 발굴할 수단이 있다면 발굴하세요.
  • 발굴 전에 라이선스를 확인하세요. 일부 소스의 데이터는 재배포할 수 없으므로, 발굴된 패널이 다운로드 가능한지 여부가 결정됩니다.
  • 모든 블록은 _interpretation을 포함합니다: 그것이 무엇을 의미하며 전문가가 어떻게 사용하는지에 대한 2-4문장입니다. 바이트당 가장 높은 가치를 지니며, 단순 암기와 추론의 차이를 만듭니다.
  • 바이트 안정적인 출력: sort_keys=True, 동점은 고유 필드로 해소되는 전체 정렬, generated_on 외에는 타임스탬프가 없습니다. 하나의 바이트만 변경되어도 모든 메시지에서 캐시된 프리픽스가 다시 청구됩니다.
  • 레이어를 쌓고, 더 나은 레이어가 이전 것을 대체하도록 하세요. 하나의 질문에 대해 서로 다른 숫자를 제시하는 두 블록은 모델이 답변 중간에 중재하도록 만듭니다. 블록이 혼합된 경우 하위 키 수준에서 대체하세요.
  • 전체를 보관하고, 압축하여 배송하세요(.compact.json 쌍). 쌍이 없으면 보관본으로 대체합니다.
  • 병합된 연구에서 개인 이메일은 삭제하세요: 광고 규모에서 모델은 한 공무원의 받은 편지함을 당신의 아웃바운드 채널로 바꿀 수 있습니다. 부서 + 전화번호는 같은 의미를 전달합니다.

3단계: 기록이 할 수 없는 것을 열거하세요

얇은 목록 피드는 거의 아무것도 보지 못합니다. **작은 원 그리드로 "주변 검색"**을 수행하고, 각 히트를 카운티 기록과 조인하세요(한 번 실행: 307개 단지 -> 208개 일치 필지 -> 9,736 유닛).

  • 작은 원(~3.5km, ~3.9km 그리드 간격): API는 호출당 결과 수에 상한이 있으므로, 하나의 메트로폴리탄 전체 쿼리는 조용히 가장 잘 알려진 장소만 반환합니다.
  • 무언가가 무엇인지는 당신이 수집한 출처가 아닌 공공 기록이 결정하도록 하세요(디렉토리에서 "아파트"이지만 카운티 기록은 요양 시설인 경우; 승용차 판매점이 다가구로 태그된 경우).
  • 아무것도 등재되지 않은 시장에서 대화할 가치가 있는 사람은 팔지 않는 사람들입니다.

4단계: 데이터 함정 (두 번 읽으세요)

여기의 모든 버그는 오류가 아닌 그럴듯한 잘못된 숫자를 생성했습니다. 예산 QA 시간을 이미 정확하다고 알려진 픽스처에 맞추어 투자하세요.

  1. 설명을 계획하기 전에 소스를 다시 쿼리하세요. 문서의 레이어 이름은 가설입니다. 필드 이름을 신뢰하기 전에 서비스의 메타데이터(ArcGIS의 경우 ?f=json, editingInfo.dataLastEditDate)와 실제 필드 값을 읽으세요.
  2. 알고 있는 것과 대조하여 검증하세요. 36유닛으로 알려진 건물이 10으로 파싱된 경우: 하나의 픽스처가 최악의 버그를 잡아냈습니다. 더 나은 방법은 출력 샘플을 다른 좌표계에서 게시자의 자체 API로 다시 보내고 비교하는 것입니다.
  3. 특이치뿐만 아니라 역전도 주시하세요: 소규모 부동산이 대규모보다 유닛당 가치가 높게 평가된다면 시장 문제가 아니라 파서가 잘못된 것입니다.
  4. 데이터가 스스로를 검증하도록 만드세요. 교차 확인이 가능한 경우(유닛당 평방피트), 모호한 필드의 두 값을 모두 계산하고 그럴듯한 범위가 선택하도록 하세요; 둘 다 맞지 않으면 플래그를 지정하고 제외하세요.
  5. 집계하기 전에 중복을 제거하세요. 하나의 부동산이 해당되는 모든 자산 유형으로 등재된 피드: 623개 행이 206개 부동산이었습니다.
  6. 파싱된 것이 아닌 RAW를 캐시하세요. 그렇지 않으면 파서 수정 시 작은 카운티의 서버를 다시 크롤링해야 합니다.
  7. 주소 형식이 기록 인덱스와 다릅니다. 방향을 축약하고 접미사를 제거하세요; 변형 사다리를 사용하여 누락의 약 절반을 복구했습니다.
  8. 작은 샘플에는 n을 표시하세요; 때로는 얇음 자체가 발견입니다.
  9. 리뷰 코퍼스에서 공유(shares)가 아닌 일치(MATCHES)를 읽으세요. 모든 분류 정규식을 실제 1-3성 텍스트에 대해 실행하고 일치하는 항목을 읽으세요. 해당 업종의 서비스 동사는 종종 해를 끼치는 동사(harm verb)입니다: cut (me|my)에 대한 "injury" 패턴은 미용실 불만의 10.7%와 일치했으며, 대부분은 "내 머리를 자르기 위해 $40를 지불했습니다"였습니다. drill(치과), pull(견인), strip(세부 관리), break(유리), shave / clip(이발사, 그루밍), stick(채혈)을 확인하세요. 그리고 아무도 언급하지 않는 주제는 계속 밝혀지지 않습니다.
  10. 게시자의 어휘는 구매자의 어휘와 다릅니다. 카운티의 "arterial" 등급은 아무것도 접하지 않는 고속도로 네트워크일 수 있는 반면, 브로커가 의미하는 상업 도로는 "collectors"입니다. 매핑하기 전에 각 버킷의 내용을 나열하고, 필드 이름은 포함된 내용을 나타내도록 지정하세요.
  11. 공유 스키마는 열 이름이 아닌 규칙을 공유합니다. 여러 카운티에 걸쳐 하나의 필드는 네 가지 분류 시스템, -9999 vs 0, 세 번째 주택 가치를 전달할 수 있습니다. 카운티별로 각 필드를 인구 조사하세요; 한 카운티의 0을 입증될 때까지 쿼리 버그로 취급하세요; 파생 테스트를 선호하세요(건물 가치 = 0 및 토지 가치 > 0은 공실을 나타냄).
  12. 하나의 이름은 여러 가지입니다(고속도로와 그 전면 도로가 이름을 공유함). 대안을 반환하고 모델이 어느 것을 사용했는지 말하도록 만드세요.
  13. 한 번 만나야 할 것들이 여러 번 만나는 경우(두 도로가 여섯 곳에서 교차). 점을 평균화하면 들판에 위치합니다; 클러스터링하고, 각 위치를 유지하며, 명시된 규칙에 따라 선택하세요.
  14. 파생된 합계는 계산하지 않은 행을 조용히 누락합니다. 부분 입력이 있는 모든 합계 옆에 적용 범위 개수를 포함시키고, 이를 최소값으로 읽히도록 만드세요.

5단계: 확정적 수학은 프롬프트가 아닌 도구로 처리하세요

DSCR, IRR, 현금-현금 수익률, 복용량, 세금: 도구로, 계산되어 가정과 경고를 반환합니다. 모델의 산술은 그럴듯하게 잘못될 수 있습니다(실제 1.09인 DSCR이 1.19로 표시되면 대출 기관에 전달됨). 이는 실제 에이전트 루프(스트림 -> 도구 실행 -> 피드백 -> 스트림)를 강제하며, pause_turn 및 max_tokens 처리가 필요합니다.

6단계: 프롬프트 비용, 측정

  • API로 토큰을 계산하세요. 밀집된 JSON은 토큰당 약 2.4바이트이며, ~4바이트가 아닙니다.
  • 테스트에서 바이트/토큰 상한을 적용하세요: 압축 쌍 대신 아카이브를 배송하면 청구서 외에는 증상이 없습니다.
  • 캐시 TTL은 트래픽을 따릅니다. 드물고, 수동으로 공유되는 경우: 5분 기본값(1시간 쓰기는 아무도 재사용하지 않는 추가 요금). 지속적인 유료 트래픽: 1시간, 방문자가 프리픽스를 공유하기 때문입니다.

7단계: 배송

  • 페이지를 하나의 생성기에서 파생시키세요; 모든 대체는 앵커가 존재함을 주장하며, 가드는 양방향을 확인합니다(제거된 콘텐츠는 사라졌고 *기능은 유지됨).
  • 광고 목적지인 경우: 배니티 URL은 임시 리디렉션으로(영구 리디렉션은 광고 플랫폼에 의해 캐시됨), 쿼리 문자열이 유지되는지 확인; 캠페인별 픽셀 이벤트 이름; 캐시 TTL 1시간; 그리고 어트리뷰션은 랜딩 히트 시 sessionStorage에 고정되어 모든 턴에 전달됩니다(localStorage가 아님. 그렇지 않으면 다음 주의 유기적 방문이 오늘의 광고에 크레딧을 받게 됩니다).
  • 빌드 로그가 아닌 배포 상태를 확인하세요; 서버리스 함수 제한 또는 추적되지 않은 파일이 녹색 로그 뒤에서 실패할 수 있습니다. 데이터 파일을 정적으로 가져와 번들러가 포함하도록 하세요.

프롬프트에 대한 엄격한 규칙

  1. 절대 숫자를 만들어내지 마세요. 서브스트레이트, 실제로 실행된 도구 호출, 또는 플래그가 지정된 추정치만 사용하세요.
  2. 공공 기록 값을 시장 가치로 제시하지 마세요. 어떤 값을 제공하는지 명확히 말하세요.
  3. 도구 설명과 프롬프트 모두에 적용 범위 경계를 명시하세요(어떤 카운티인지). 한 곳의 규칙은 우회됩니다.
  4. 공공 기록은 목록이 아닌 한 번에 하나씩 조회하세요. 요청된 부동산에 대한 소유자 조회는 괜찮지만, 대량 이름 및 주소 명단은 상업적 사용에 대해 주 공개 기록법을 위반할 수 있습니다.
  5. 프롬프트가 불가능하다고 말하는 것을 다시 확인하세요. 알 수 없는 것에 대한 자신 있는 허위 진술은 데이터 격차보다 더 나쁩니다.

컨텍스트 레이어를 위한 리서치 에이전트

병렬 리서치 에이전트에게 토큰 예산(2.4 바이트/토큰 비율)을 주고, 주의 사항보다 수치를 줄이도록 지시하며, 당신의 이전 작업을 수정할 것으로 기대하세요.

8단계: 업종 외 종료 (off-sector ending)

일부 방문자는 이 에이전트의 사용자가 아닙니다(레스토랑 에이전트에 중고품 가게). 기본 "그건 없습니다"는 당신이 얻을 수 있는 최고의 신호를 잃게 만듭니다: 다음에 구축할 업종을 지명하는 실제 소유자입니다.

  • flag_out_of_scope(sector) 도구: 클라이언트는 세 가지 탭 가능한 옵션을 렌더링합니다; submit_feature_request 도구가 탭을 제출합니다.
  • 첫 번째 응답에 모든 것을 포함하세요: 중간 세션 깊이는 한 턴입니다.
  • 에이전트가 대신 가지고 있는 것을 나열하지 마세요(한 번의 수정으로 응답이 1,275자에서 124자로 줄었습니다).
  • 옵션은 클라이언트에서 렌더링되며, 산문의 번호 목록이 아닙니다(단순한 "2"가 스킬 2를 트리거할 수 있음).
  • 옵션이 렌더링되는 위치를 모델에 알리세요; 모델은 클라이언트를 볼 수 없습니다.
  • 옵션을 보편적 기능에 매핑하여 제출된 요청이 업종에 대한 기능을 지칭하도록 하세요.

9단계: 공간 레이어 ("이것 옆에 무엇이 있나요")

  • 카운티의 ArcGIS Online 조직을 찾으세요. WAF 차단된 GIS 호스트가 아닙니다. 호스팅된 서비스는 종종 익명으로 제공됩니다. 레이어의 네이티브 공간 참조로 지오메트리를 요청하세요.
  • 두 소스가 만날 때, 첫 번째 소스의 프레임으로 두 번째를 요청하고(outSR), 행을 내보내기 전에 범위가 겹치는지 확인하세요: 프레임 불일치는 아무것도 교차하지 않으며 "모든 필지가 구역 미지정"으로 보고됩니다. DuckDB에서 ST_Transform은 always_xy := true가 필요하며, 그렇지 않으면 조용히 POINT(inf inf)를 반환합니다.
  • 중심점 기반 구역 지정; 분할 구역 지정은 공유 임계값이 필요합니다(대지의 >5%), 폴리곤이 아닌 지구를 비교합니다. 단순 교차 호출은 필지의 37%를 분할로 간주했습니다; 임계값은 ~4%를 제공했습니다.
  • 도시의 구역 코드는 그 도시의 것입니다. 동일한 코드가 이웃에서 다른 지구를 의미합니다; 모든 코드와 함께 도시 이름과 게시된 이름을 함께 제공하세요.
  • 오프라인에서 사전 계산하고, 지오메트리가 없는 인덱스를 배송하며, API 경로를 추가하지 마세요: 카운티 GIS -> DuckDB 공간 미러 -> 하나의 커밋된 JSON 인덱스; 런타임은 조회와 하버사인만 수행합니다. 실패하는 공간 종속성은 빈 이웃 목록으로 저하되며, 이는 확신에 찬 잘못된 답변입니다. 로드 시 인덱스의 유효성을 검사하고 오류를 던지세요.
  • 공간 조인의 어디에서든 부등식은 공간 조건자를 사후 필터로 강등시킵니다(ON a.id < b.id AND ST_Intersects(...)는 약 290억 쌍을 테스트함). 조건자를 단독으로 두고, EXPLAIN으로 SPATIAL_JOIN을 확인하고, 키를 내보낸 후 중복을 제거하세요: 7분 미완료가 19초가 되었습니다.
  • 배송되는 인덱스의 범위를 구매자가 거래하는 지역과 인접 지역으로 제한하고, "컨텍스트" 필지에는 더 적은 데이터가 포함됨을 표시하세요.

Individual skills in this repo

This repo contains 7 individual skills — each has its own dedicated page.

2016judea/ascii-charts

Build charts as plain Unicode-block text — bar, range, bullet, gap-bracket, star-histogram, heatmap, line, Venn, pie, donut and scatter — with a dependency-free Python script, for anywhere only monospace text survives (newsletter code blocks, Markdown, terminals, plain-text email, chat). Use when a chart has to embed as literal text instead of an image or a third-party chart service, or when you want a hand-made terminal look with no branding footer.

2016judea/buffett-checklist

Apply Warren Buffett's investment framework as a discipline lens when weighing a buy, hold, or sell decision — circle of competence, economic moat, owner earnings & intrinsic value, margin of safety, management/capital-allocation quality, and market psychology (Mr. Market, fear vs greed, temperament). Use when asked to "run this through Buffett", "what would Buffett say", "does this pass the moat test", "is this cheap enough", or for a second, more skeptical read on a name being evaluated or already held. This is a discipline overlay, not a replacement for a strategy — it applies the Buffett lens to how someone actually invests, rather than issuing generic advice.

2016judea/image-riff

Turn one or more reference images into original art in that reference's own visual language, then cut it to whatever surface it's for. Use when you paste or point at art and say "use this as the base image", "generate art from this", "riff on this", "some creative ideation with these images", "make me a channel banner / avatar / cover / plate", "wilder version of this", or want a spread of options off one piece of reference. This is the TASK skill; the engine is the `make-art` tool skill.

2016judea/leonardo

Draw the way Leonardo da Vinci drew — a study sheet, a notebook folio, a red-chalk or silverpoint study, a machine cutaway, a storm of vortices — in his real materials and page-logic, generated with the make-art engine and anchored on fifteen of his actual (public-domain) sheets. Use when you say "Leonardo", "da Vinci", "like his notebooks", "a codex page of X", "draw this as one of his study sheets", "sanguine", "silverpoint", or wants a design, diagram, or illustration in that hand. Also a reading guide to his notebooks (Richter's 1883 public-domain translation) for "what did Leonardo say about shadow / trees / water". This is a TASK skill; the engine is `make-art`.

2016judea/mcp-stack

Which free MCP server or framework to reach for, and its traps — finance/gov data (SEC EDGAR, Yahoo, SAM.gov, USAspending), web research (Exa, Firecrawl, Crawl4AI, Jina reader), design/art/brand (Canva, Inkscape, Penpot, Figma, Orshot, Hugging Face image gen, vectorizing, charts), data/spatial (DuckDB spatial, live ArcGIS layers, OpenStreetMap/Overpass, Census, MapLibre), and ops (PostHog, iMessage, context7 docs). Use when making a social post, OG card, poster, logo/vector, chart, map, or brand asset; when querying parquet/geojson/duckdb or a city's open-data layer; when an MCP "needs authentication" or fails; or when asked "what tools do we have", "is there an MCP for X", "should we add X".

2016judea/records-request

Get a specific record out of a US government office by public-records request — "request the assessor's model", "file a data practices request", "FOIA this", "open records request", "can we just ask the county for it", "who do I write to at <county>", "chase that request", "did they ever answer". Covers checking the website first, finding the right office and statute, the carve-out paragraph that makes a request answerable instead of refused, web-form traps (hidden character caps, WAFs that reject apostrophes), chasing (there is usually no deadline), whether what comes back may be republished, and parsing multi-year tables without silent errors.

2016judea/sms-native-product

Build a product whose interface is text messages rather than an app or a website — "no app, no website", "they just text a number", "chat with our agent natively in Text Messages", "can we do this over text", "an SMS bot", "a Telegram bot", "make it a group chat", "minimum viable friction". Fires equally when it has already gone wrong — "my campaign got rejected", "our number is blocked", "the texts aren't arriving", "why do I need to register". Covers the gate that decides whether such a product can send at all (US A2P 10DLC registration, SHAFT content rules, permanent rejection codes), group MMS from code, what each channel can't do, an architecture that survives losing the channel, and guarding model-rewritten user content.

관련 스킬