에이전트가 조사한 내용을 원문 출처와 대조하기

X Facebook

Written by

in

이 글을 쓰기 위해 research-brief 스킬의 SKILL.md를 처음부터 끝까지 읽었다. 18,024자 분량이다. 기억에 의존했다면 웹 도구의 호출 상한이나 출처 등급을 잘못 적었을 수 있다. 그런 오류는 문장이 자연스럽다는 이유만으로 알아차리기 어렵다.

이 스킬도 조사에서 같은 문제를 막으려 한다. 모델이 기억하는 정보와 현재 문서가 달라도 답변에 그 차이가 드러나지 않을 수 있다. 라이브러리의 함수 이름이 바뀌었는데 예전 이름을 그대로 안내하는 경우가 그렇다. 그래서 “확인했습니다”라는 말에는 대조할 근거가 필요하다.

curvez의 research-brief는 조사 근거를 파일에 남기도록 한다. 그래야 다음 사람이 열어서 대조할 수 있다.

1. 링크 없는 한 줄이 왜 가장 비싼가

조사는 팀에서 제일 앞에 온다. 조사자·아키텍트·구현자·QA는 순서대로 도는 에이전트 넷이다. 조사자가 “이 버전에서 이 API가 된다” 고 적는다. 아키텍트가 그걸 전제로 경계를 나눈다. 구현자가 그 경계 안에서 코드를 쓰고 QA가 그 코드를 테스트한다. 다시 의심하는 절차가 없으니 뒤의 셋은 앞사람이 적어 둔 것을 전부 사실로 믿는다.

조사 결과를 적어 두는 그 파일을 브리프라고 부른다. 채울 칸이 정해져 있고 거기를 메우는 문서 한 장이다.

그래서 SKILL.md는 첫 문단에서 못을 박는다. 링크 없는 한 줄이 팀 전체에서 가장 비싼 실패가 된다고. 앞에서 한 줄을 잘못 적으면 뒤에 쌓인 설계와 코드와 테스트가 같이 무효가 된다. 그 한 줄을 어디서 봤는지도 안 적혀 있으면 어디서부터 어긋났는지 되짚을 수 없다.

특히 검색해서 나온 블로그 글을 그대로 따라 하다 틀리기 쉽다.

블로그에는 두 가지가 잘 빠진다. 하나는 날짜다. 언제 쓴 글인지 안 적혀 있으면 지금도 맞는 얘기인지 판정할 수 없다. 다른 하나가 더 곤란하다. 공식 문서에 있던 단서가 요약하면서 사라진다.

SKILL.md가 든 예가 이렇다. 공식 문서에는 “실험 플래그를 켜면 이게 됩니다”라고 적혀 있다. 그걸 정리한 블로그에는 “이거 됩니다”로만 남는다. 그걸 보고 따라 하면 안 되는 게 당연하다. 그런데 블로그만 보면 플래그 얘기가 있었는지도 드러나지 않는다.

2. 무엇을 1차 출처라고 부르나

“공식 문서를 확인해라”는 말은 지시로는 부족하다. 어디까지가 공식인지가 사람마다 다르다.

1차 출처는 그것을 만든 쪽이 직접 내놓은 것이다. 공식 문서, 소스 코드, 릴리스 노트. 2차 출처는 그걸 읽고 남이 다시 쓴 것이다. 블로그, 튜토리얼, Stack Overflow 답변, AI 요약글.

대개는 2차 출처가 더 읽기 쉬워 먼저 읽게 된다. 다만 옮겨 적는 사람이 조건 하나를 빼먹었는지는 2차만 봐서는 알 수 없다. 위에서 본 플래그 얘기가 그거다.

이 스킬은 둘 사이에 한 칸을 더 두고 세 등급으로 나눈다. 각 등급을 어떻게 취급할지까지 같이 적어 둔다.

등급 출처 취급
A (1차) 공식 문서, 저장소 소스 코드, 릴리스 노트·CHANGELOG, RFC·표준 스펙, 공식 타입 정의, package.json의 engines·peerDependencies 근거로 인용한다
B (준1차) 공식 저장소의 이슈·PR 논의, 메인테이너가 직접 쓴 글 인용하되 A로 뒷받침한다. A가 없으면 확인 불가
C (2차) 블로그, 튜토리얼, Stack Overflow, AI 요약글, 뉴스 A를 찾는 단서로만 쓴다

표 1. 출처 세 등급과 등급별 취급 방법

소스 코드도 공식 문서와 같은 A 등급이다. package.json 안의 engines와 peerDependencies도 A 다. 남이 쓴 설명이 아니라 패키지가 스스로 선언한 값이라 그렇다.

C 등급은 근거로 쓸 수 없어도 조사 경로에는 남겨야 한다. C 등급 글에서 답을 봤으면 그 글이 인용한 A 출처를 직접 확인한다. 같은 내용이 있는지 대조한 뒤 그 A 출처의 URL을 적는다. 단서로 본 C 글이 무엇이었고 거기서 어떤 A에 도달했는지 ## 조사 경로 섹션에 남긴다. 숨겨 버리면 다음 사람이 같은 검색을 처음부터 다시 한다.

3. 그 사실은 어느 버전의 사실인가

1단계에서는 조사 질문을 다루기 전에 기준 버전부터 고정한다. 우선 셸에서 두 줄을 돌린다.

TODAY=$(date +%F)                       # 확인 날짜. 추측하지 말고 여기서 얻는다
test -f .curvez/profile.json || echo "BLOCKED: profile.json 없음"

그다음 읽을 파일이 넷이다. .curvez/profile.json의 stack, package.json, lockfile, .nvmrc. 여기서 관련 패키지 버전을 읽어 브리프 머리말의 기준 버전 칸에 적는다. 패키지명@버전과 그 값을 읽은 파일 경로를 함께 적는다.

버전을 못 읽었으면 조사를 멈추지는 않고 대신 버전에 기대는 모든 주장을 확인 불가(프로젝트 버전 미상)로 남긴다. 버전을 모르는 채로 시작한 조사는 최신 문서만 보게 되고 그러면 결과 전체가 이 프로젝트에 안 맞을 수 있어서다. 프레임워크 API는 메이저 버전이 올라갈 때 이름을 그대로 두고 동작만 바꾸기도 한다. 그러면 코드는 그대로 도는데 결과만 달라진다.

TODAY를 굳이 셸에서 얻는 이유도 같다. 확인 날짜는 이 브리프가 아직 유효한지를 판정하는 유일한 근거다. 날짜를 기억으로 적으면 세션마다 값이 어긋나서 판정 자체를 못 한다.

기준 버전을 어디서 읽는지는 이 시리즈 1편에서 다뤘다. 프로젝트별 경로와 실행 명령을 에이전트 설정으로 분리하기 에서 확정한 stack이 여기서 그대로 조사의 전제가 된다. 그래서 profile.json이 없으면 이 스킬은 bootstrap이 먼저라고 돌려보낸다.

4. 답을 찾지 못한 자리에 무엇을 남기나

조사가 답을 아예 못 찾았을 때 적는 것도 확인 불가 다. 찾지 못한 것을 그럴듯하게 채우지 말라는 규칙은 흔하다. 그런데 “채우지 마라”만으로는 무엇을 하라는 건지 알 수 없다. 그래서 빈자리에 무엇을 어떻게 적을지를 하나씩 시켜 둔다.

  1. ## 확인 불가 표에 행을 추가한다
  2. 왜 확인 불가인지 적는다 — 문서에 없음 / 유료 문서 / 접근 실패(403·타임아웃·robots) / 버전 불일치 / 조사 상한 도달
  3. 어디까지 확인됐는지 적는다 (예: v14.2까지는 Y로 동작 (URL))
  4. 핸드오프의 blocked_on에 질문으로 1:1로 올린다

blocked_on은 “답을 받아야 다음이 진행된다”를 적는 칸이다.

다음 사람이 어디서 시작할지는 특히 3번에 달려 있다. “모른다”와 “v14.2까지는 이렇게 동작하고 v15부터를 모른다”는 전혀 다른 출발점이다.

확인 불가라고 적어 두는 것은 그냥 빈칸으로 두는 것과 다르다. 빈칸을 본 사람은 조사에서 아예 빠진 건지, 조사는 했는데 못 찾은 건지, 문제가 없다는 뜻인지를 구별할 수 없다. 그럴듯한 문장으로 채워 넣은 자리는 틀렸다는 표시가 안 붙어 더 나쁘다. 확인 불가라고 적힌 행만 여기는 아직 모른다고 말해 주고 그래야 다음 사람이 그 자리부터 시작한다.

문서는 확인 불가도 정상 산출물로 다룬다고 덧붙인다. 조사 결과가 “이 방식은 불가능하다”로 나온 것도 정상 산출물이다. 근거 URL만 붙으면 그건 status: done이다.

5. 출처끼리 다르면 어느 쪽을 믿나

공식 문서에 적힌 것과 실제 소스 코드가 다를 때 어느 쪽이 사실인지를 미리 정해 둬야 한다. 이런 상황은 실제로 생기고 그때마다 판단하면 세션마다 답이 달라진다. 그래서 순서가 정해져 있다. 위에서부터 적용하고 먼저 걸리는 규칙이 이긴다.

# 상황 tie-break
1 등급이 다르다 등급이 높은 쪽(A > B > C)
2 공식 문서와 실제 소스 코드가 다르다 소스 코드. 문서 URL과 소스 URL을 둘 다 남기고 문서 미갱신이라고 적는다
3 대상 버전이 다르다 프로젝트 기준 버전에 가까운 쪽. 기준 버전 문서가 없으면 확인 불가
4 등급·버전이 같고 날짜가 다르다 날짜가 최신인 쪽
5 위 넷으로 판정이 안 된다 더 보수적인 쪽(제약이 강한 쪽, “안 된다” 쪽)

표 2. 출처가 서로 다를 때 적용하는 판정 순서

5번은 판정을 못 하는 자리에도 답을 정해 준다. 멈추는 게 아니라 “안 된다” 쪽을 택하고 decisions에 reversible_at을 남긴다. 조사 단계에서 낙관적으로 판정해 놓으면 구현 단계에서 막힌다. 구현 중에 되돌리는 비용이 조사 중에 한 번 더 확인하는 비용보다 훨씬 크다.

어느 쪽을 택하든 버린 쪽 URL을 같이 적는다. 한쪽을 조용히 지우면 나중에 반대쪽 출처를 본 사람이 조사 전체를 못 믿고 처음부터 다시 하게 된다.

6. 어디까지 찾고 멈추나

조사는 상한이 없으면 끝나지 않는다. 그래서 숫자로 끊어 놓았다.

항목 상한
질문 1개당 인용하는 A 등급 출처 5개
브리프 1개당 웹 도구 호출 (WebSearch + WebFetch 합) 30회
미해결 질문 1개당 검색어를 바꾼 재시도 3회
같은 URL의 WebFetch 재시도 2회

표 3. 조사에 걸어 둔 네 가지 상한

호출할 때마다 세고 최종 횟수를 ## 조사 경로에 24/30 형식으로 적는다. 상한에 걸리면 그 자리에서 멈춘다. 확인 불가(조사 상한 도달)로 남긴 뒤 status: partial로 보고한다. 상한을 조용히 늘리는 건 금지다. 늘려도 되는 경우는 오케스트레이터가 명시적으로 다시 부를 때뿐이다. 그때도 같은 파일이 아니라 새 브리프(-v2)로 쓴다.

7. 실제로 어떻게 쓰는가

“조사해줘”, “찾아봐”, “공식 문서 확인”, “버전 호환 확인”, “라이브러리 비교” 같은 말이 트리거다. 영어로는 “research this”, “check the docs”, “verify the API” 다. 아키텍처나 구현 결정 전에 사실 확인이 필요할 때도 걸린다.

산출물은 .curvez/research/<주제>.md이고 <주제>는 next-app-router-caching처럼 소문자 kebab-case로 쓴다. 같은 주제를 다시 조사할 때는 기존 파일을 고치지 않고 <주제>-v2.md로 새로 쓴다. 덮어쓰면 retrospective가 조사 이력을 시간순으로 재구성할 때 언제 무엇이 바뀌었는지 복원할 수 없다.

브리프 안쪽은 머리말 4항목(조사 질문·조사 일자·기준 버전·결론 한 줄)과 ## 섹션 5개(확인된 사실·확인 불가·모순과 선택·선택지 비교·조사 경로)로 고정돼 있다. 채울 행이 없어도 헤더만 남기고 섹션 자체는 지우지 않는다. 표의 열 순서도 바꾸면 안 된다. 검증 명령이 첫 열의 번호와 열 안의 문자열로 행을 센다. 열을 밀어 놓으면 검증은 통과한 것처럼 보이는데 실제로는 아무것도 검사하지 않는다.

브리프를 쓴 직후 돌리는 검증 명령은 awk로 ## 확인된 사실 섹션만 잘라내고 숫자 일곱 개(행수, URL없음, 날짜없음, C등급인용, 섹션, 머리말, 확인불가)를 찍는다. 완료 기준이 그 수치다. URL없음 0, 날짜없음 0, C등급인용 0, 섹션 5, 머리말 4, 그리고 확인불가 수치가 핸드오프 blocked_on 개수와 같을 것. 하나라도 못 넘기면 status를 done으로 올리지 않고 partial로 낮춘다.

핸드오프에서 하나 더 정해 둔 게 있다. summary에는 결론 대신 답한 질문과 확인 불가 개수를 적는다. summary만 읽고 진행하는 수신자를 막을 방법이 없으니, summary 자체가 “브리프를 읽어야 한다”는 신호가 되게 만든 것이다. 결론을 한 줄로 요약하면 브리프 본문의 “단, v15부터는” 같은 단서가 빠진다. 요약만 읽은 사람은 그런 단서가 없는 줄 알고 그대로 다음 사람에게 넘긴다. 1절의 블로그 글과 같은 일이 팀 안에서 벌어지는 것이다.

후보를 고르는 조사일 때는 references/option-comparison.md를 추가로 읽는다. 여기 규칙이 둘이다. 후보 셋 중 하나는 반드시 아무것도 추가하지 않는 것이어야 한다. 직접 구현하거나 그냥 안 하는 선택지다. 그리고 조사자는 표를 채우기만 할 뿐 권장·1순위를 쓰지 않는다. 순위를 붙여 놓으면 결정자가 표는 안 읽고 순위만 읽는다.

8. 도입 비용과 한계

느려진다. 답을 이미 아는 질문에도 A 출처를 직접 확인해 대조해야 한다. 브리프 하나에 웹 도구 호출이 스무 번 넘게 나가는 일이 흔하다. 그동안 뒤 순서 에이전트는 기다린다. 5분이면 끝날 결정에 30분이 든다.

출처가 약한 주제에서는 표가 비는 채로 끝난다. 문서가 부실한 라이브러리, 유료 문서 뒤에 있는 API, robots로 막힌 사이트. 이런 걸 만나면 ## 확인된 사실은 몇 줄뿐이고 ## 확인 불가만 길어진다. SKILL.md는 이걸 정상 산출물이라고 부른다. 조사자 기준에서는 맞는 말이다. 결정을 내려야 하는 쪽에서 보면 진행이 그 자리에서 멈춘 것이기도 하다. 그래서 blocked_on이 오케스트레이터에게 올라간다.

결정이 한 단계 늦어진다. 조사자는 선택지와 근거까지만 낸다. 최종 선택은 architecture-setup에서 아키텍트가 한다. 조사와 결정을 붙여 두면 조사자가 자기 조사 범위 안에서만 답을 찾는다. 조사에서 빠진 선택지는 검토 대상에조차 못 오른다. 대신 결정자가 표를 직접 읽어야 하고 그 표에 순위가 없다.

브리프가 낡는다. 확인 날짜를 적는 것까지가 이 스킬의 몫이다. 며칠 지나면 다시 확인해야 하는지는 SKILL.md에 없다. 낡은 브리프를 누가 찾아내는지도 없다. “이미 있는 브리프가 낡았는지 다시 확인할 때”가 사용 조건에 들어 있긴 하다. 그런데 낡음의 기준 일수는 안 적혀 있다. 지금은 읽는 사람이 확인 날짜를 보고 스스로 판단하는 구조다. 이 두 파일에서는 그 기준을 찾지 못했다. 다른 문서에 적혀 있을 가능성은 남겨 둔다.

파일이 쌓인다. 덮어쓰지 않고 -v2, -v3로 늘린다. 같은 주제 브리프가 여러 개 남는다. 이력을 복원하려다 보니 파일이 계속 늘어난다.


에이전트가 “확인했습니다”라고 말하면 표에서 그 주장이 실린 행을 본다. URL과 확인 날짜, 대상 버전이 같이 적혀 있어야 믿을 근거가 된다.

Comments

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다