리서치
검색 질의 하나를 SEO 콘텐츠 브리프로 바꾸기
현재 그 질의에 답하는 페이지를 확인하고, Markdown으로 읽고, 답하는 질문과 놓친 질문을 정리한 뒤 작가가 바로 개요를 잡을 수 있는 브리프를 씁니다.
프롬프트 복사
대괄호 항목을 바꾼 뒤 Claude Code, Codex 또는 터미널에 접근할 수 있는 AI에 붙여넣으세요. Felo 스킬을 설치하고 크레딧을 쓰기 전에 확인한 뒤 워크플로를 실행합니다.
[제품 또는 사이트]를 위한 [대상 쿼리] SEO 콘텐츠 브리프를 작성해 주세요. 독자: [독자]. 시장과 언어: [지역], [언어]. 관점: [가이드 / 비교 / 제품 페이지]. 이 분석이 지원하는 결정: [새 글 / 새로고침 / 갭 보완]. 개요를 잡기 전에 지금 이 쿼리에 답하는 페이지를 먼저 읽어 주세요. Markdown 브리프에 다음을 포함해 주세요. 1. 대상 쿼리와 당신이 추론한 검색 의도, 그 판단의 근거. 2. 현재 페이지가 다루는 내용: 제목, URL, 도입 섹션. 3. 현재 페이지가 답하는 질문과 놓치는 질문. 4. 제안 개요. 각 섹션이 무엇을 증명해야 하는지 한 줄로. 5. 출처의 근거와 사례, 링크 포함. 6. 전체 출처 목록. 규칙: - 검색량, 키워드 난이도, 순위, 트래픽을 주장하지 마세요. 이 워크플로는 그것을 측정하지 않습니다. 숫자 대신 "여기서는 측정하지 않음"이라고 쓰세요. - 통계, 인용, 경쟁사 콘텐츠에 대한 주장을 지어내지 마세요. - 의도는 페이지를 읽은 해석으로 설명하고, 측정된 사실처럼 쓰지 마세요. - 인용은 짧게 하고 출처와 링크를 붙여 주세요. - 지역과 언어를 명시적인 값으로 확정해 주세요. - 크레딧을 쓰기 전에 실행할 API 호출을 보여 주고 제 승인을 기다려 주세요. - 게시, 예약, 전송을 하지 마세요. - 결과를 ./seo-brief.md에 쓰고 채팅에서 요약해 주세요.
복사 내용에는 설치 단계와 안전 규칙도 포함됩니다.
완성되는 것
실행 시 예제 출력입니다. 실시간 생성이 아닙니다.
SEO 브리프 — “지원 트리아지를 자동화하는 방법”
대상 쿼리와 의도
쿼리: “지원 트리아지를 자동화하는 방법”. 반환된 페이지는 제품 페이지가 아니라 구현 단계로 시작하므로 의도는 how-to로 읽힌다. 이것은 페이지를 읽은 것이지 측정된 의도 라벨이 아니다.
현재 페이지가 다루는 것
| 페이지 | URL | 시작 내용 |
|---|---|---|
| 지원 트리아지 자동화: 실용 가이드 | https://example.com/guide | 라우팅 규칙, 그다음 태그 |
| 트리아지 자동화 체크리스트 | https://example.com/checklist | 체크리스트 자체 |
페이지가 답하는 질문
- 트리아지 자동화가 바꾸는 것
- 어떤 라우팅 규칙부터 시작할지
페이지가 놓치는 질문
- 트리아지가 실제로 개선됐는지 측정하는 방법
- 분류기가 틀렸을 때 할 일
제안 개요
- 트리아지 자동화가 바꾸는 것 — 인원이 아니라 큐의 문제임을 증명.
- 자동화할 가치가 있는 첫 세 가지 라우팅 규칙 — 각각 사례로 증명.
- 첫 달에 측정하는 방법 — 운영 리드가 뽑을 수 있는 지표로 증명.
- 자동화가 틀렸을 때 — 사람이 받는 폴백 경로를 증명.
증거
- 라우팅 규칙 예시, https://example.com/guide에서 인용(2026-10-30 확인)
여기서 측정하지 않음
검색량, 키워드 난이도, 순위. 이 워크플로는 공개 페이지를 읽으며 검색 인덱스나 순위 추적기를 조회하지 않는다.
출처
- https://example.com/guide
- https://example.com/checklist
실제 호출
개발자용: 같은 워크플로를 실행 순서대로 담은 복사 가능한 코드.
실제 API 호출 보기
현재 누가 답하는지 보기
Chat에 질의를 묻고 답변과 인용 페이지를 가져옵니다. 그 페이지가 현재 경쟁 콘텐츠입니다.
seo-brief.ts const BASE = "https://openapi.felo.ai"; const headers = { Authorization: `Bearer ${process.env.FELO_API_KEY}`, "Content-Type": "application/json", }; async function felo<T>(path: string, body?: unknown): Promise<T> { const res = await fetch(`${BASE}${path}`, { method: body ? "POST" : "GET", headers, body: body ? JSON.stringify(body) : undefined, }); if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`); return res.json() as Promise<T>; } type ChatData = { data: { answer: string; resources: { link: string; title: string; snippet: string }[]; }; }; const query = "how to automate support triage"; const ourSite = "example.com"; const coverage = await felo<ChatData>("/v2/chat", { query: `What pages currently answer the search query "${query}"? List the pages and what each one covers.`, }); const candidates = coverage.data.resources .filter((resource) => !resource.link.includes(ourSite)) .slice(0, 5) .map((resource) => ({ url: resource.link, title: resource.title }));예제 출력
{ "answer": "Readers searching this usually want a step-by-step …", "sources": [ { "link": "https://example.com/guide", "title": "…", "snippet": "…" } ] }페이지를 Markdown으로 읽기
상위 3~5페이지를 Web Fetch로 Markdown으로 만들고 제목과 질문을 남깁니다.
seo-brief.ts type ExtractData = { data: { content: string } }; const pages = await Promise.all( candidates.map(async (page) => { const res = await felo<ExtractData>("/v2/web/extract", { url: page.url, output_format: "markdown", with_readability: true, with_cache: true, }); const checkedAt = new Date().toISOString().slice(0, 10); return { ...page, checkedAt, content: res.data.content }; }), );예제 출력
{ "url": "https://example.com/guide", "checkedAt": "2026-10-30", "content": "# Automating support triage\n\n## Routing rules\n…" }커버리지와 빈틈 정리하기
각 페이지의 H2/H3와 FAQ 질문을 추출해 답한 질문과 놓친 질문 표를 만듭니다.
seo-brief.ts type Heading = { page: string; heading: string }; const headings: Heading[] = pages.flatMap((page) => page.content .split("\n") .filter((line) => line.startsWith("## ")) .map((line) => ({ page: page.title, heading: line.replace(/^##\s+/, ""), })), ); const questions = headings.filter((item) => item.heading.includes("?")); const byTopic = new Map<string, string[]>(); for (const item of headings) { byTopic.set(item.heading, [...(byTopic.get(item.heading) ?? []), item.page]); }예제 출력
// questions [ { "page": "…", "heading": "What routes should you automate first?" } ]브리프 작성하기
대상 질의, 의도, 커버리지 비교, 놓친 질문, 제안 개요, 출처 목록을 씁니다.
seo-brief.ts const today = new Date().toISOString().slice(0, 10); const brief = [ `# SEO brief — "${query}"`, `Checked ${today}. Site: ${ourSite}.`, "", "## Intent read", "The pages returned for this query lead with: " + headings.slice(0, 6).map((item) => item.heading).join("; ") + ". This is a reading of their structure, not a measured intent label.", "", "## What the pages cover", "| Page | URL | Checked |", "| --- | --- | --- |", ...pages.map((page) => `| ${page.title} | ${page.url} | ${page.checkedAt} |`), "", "## Questions the pages answer", ...questions.map((item) => `- ${item.heading} (${item.page})`), "", "## Topics more than one page covers", ...[byTopic.entries()] .filter(([, pageTitles]) => pageTitles.length > 1) .map(([heading, pageTitles]) => `- ${heading} (${pageTitles.length} pages)`), "", "## Proposed outline", ...questions.slice(0, 5).map((item, index) => `${index + 1}. ${item.heading}`), "", "## Questions they miss", "<!-- Only questions none of the fetched pages answer. Delete this comment when filled. -->", "", "## Not measured here", "Search volume, keyword difficulty, and ranking position. This workflow reads public pages; it does not query a search index or a rank tracker.", "", "## Sources", ...pages.map((page) => `- ${page.title}: ${page.url}`), ].join("\n"); console.log(brief);예제 출력
# SEO brief — "how to automate support triage"
LiveDoc에 저장하기
브리프와 페이지 링크를 LiveDoc에 저장하고 다음에는 바뀐 부분만 가져옵니다.
seo-brief.ts type LiveDocData = { data: { short_id: string } }; const briefDoc = await felo<LiveDocData>("/v2/livedocs", { name: `SEO briefs: ${ourSite}`, description: "One document resource per target query", }); await felo(`/v2/livedocs/${briefDoc.data.short_id}/resources/urls`, { urls: pages.map((page) => ({ url: page.url, title: page.title })), }); await felo(`/v2/livedocs/${briefDoc.data.short_id}/resources/doc`, { title: `SEO brief — ${query}`, content: brief, }); console.log(briefDoc.data.short_id); // the next query adds to this archive예제 출력
{ "short_id": "PvyKouzJirXjFdst4uKRK3" }
포함되는 것
- Chat의 출처 있는 페이지 목록과 답변 근거 링크
- 현재 상위 페이지를 Markdown으로
- 그 페이지가 다루는 제목과 질문
- 바로 개요를 잡을 수 있는 브리프
- 다음 갱신에 재사용할 LiveDoc
하지 않는 것
- 검색 순위, 검색량, 키워드 난이도, 트래픽을 측정하지 않음
- 공개 페이지만. 로그인과 유료 장벽은 실패할 수 있음
- 글을 게시하거나 전면 재작성하지 않음
- 질의 하나당 1회 실행. 여러 질의는 직접 반복
- 순위를 보장하지 않음
자주 묻는 질문
검색량이나 순위를 측정하나요?
아니요. 공개 페이지를 읽고 현재 어떤 콘텐츠가 그 질의에 답하는지만 판단합니다. 순위와 검색량은 기존 SEO 도구를 쓰세요.
데이터는 어디서 오나요?
Chat이 출처 있는 페이지를 반환하고 Web Fetch가 Markdown으로 바꿉니다. 브리프의 각 판단은 구체적 페이지와 날짜를 가리킵니다.
여러 질의를 다룰 수 있나요?
가능하지만 한 번에 하나입니다. 여러 개는 각 질의에 같은 단계를 반복하고 브리프를 따로 저장하세요.
어떤 질의에 적합한가요?
정보형, 비교형, “방법” 질의에 적합합니다. 공개 페이지가 충분한 신호를 줍니다. 거래형은 자체 제품과 전환 데이터도 필요합니다.
글도 써 주나요?
아니요. 브리프와 개요를 출력하고 실제 작성은 편집자나 작성 agent가 합니다.
한 번 비용은?
Chat과 페이지 추출은 사용량 기반 크레딧을 씁니다. 현재 요금은 가격 페이지에 있고 프롬프트는 쓰기 전에 승인을 요청합니다.
관련 워크플로
질문 하나를 출처 있는 리서치 브리프로 바꾸기
웹에 질문을 던지고, 답변의 근거 페이지를 Markdown으로 가져오고, X의 실무자 의견을 더한 뒤 증거를 나중에도 검색할 수 있는 LiveDoc에 남깁니다.
워크플로 열기콘텐츠청중이 실제로 묻는 질문으로 한 달 콘텐츠 채우기
Chat으로 주제를 정리하고, 청중이 X에서 묻는 질문을 찾고, 참고 영상 자막에서 실제 각도를 뽑아 모든 행에 증거를 적은 4주 콘텐츠 캘린더를 만듭니다.
워크플로 열기콘텐츠팀이 실제로 읽는 일일 AI 뉴스 다이제스트 만들기
출처 있는 뉴스 요약을 가져오고 X의 실무자 논의를 더하고 영상 자막 하나를 가져온 뒤 Markdown으로 호를 구성해 LiveDoc에 보관합니다.
워크플로 열기내 방식으로 바꾸기
같은 레시피를 실제 배포 방식에 맞게 조정합니다.
비교 질의만 다루기
“X vs Y”, “최고의 X”로 범위를 좁히면 차별화 각도가 보입니다.
자체 제품 페이지 추가하기
제품 페이지를 추가 출처로 넣어 개요가 자사 기능과 가격에 착지하게 합니다.
분기마다 갱신하기
같은 LiveDoc으로 다시 실행해 경쟁 페이지와 개요 제안의 변화를 봅니다.
더 알아보기
이 레시피의 배경이 되는 참고 페이지와 다음에 볼 곳.