장기 작업을 수행하는 AI 에이전트의 상태, 메모리, 실행 흐름을 안정적으로 제어하려면 하네스 엔지니어링이 필수적입니다. 에이전트가 단번에 완벽한 답을 내놓지 못하더라도, 결과물을 단계별로 검증하며 완성도를 올려가는 흐름을 만드는 것이 핵심인데요. 오늘은 Planner - Generator - Evaluator 구조를 활용해 명령어 한 줄로 주식 분석 리포트를 자동 생성하는 하네스의 파이프라인을 하나씩 뜯어서 살펴봅니다. 먼저 이 하네스 시스템이 실제로 어떻게 작동하고 어떤 결과물이 나오는지 간단한 실행부터 확인해 보겠습니다.
다음 깃허브를 클론한 뒤 해당 폴더로 이동해서 클로드 코드를 실행합니다.
[Terminal]
git clone https://github.com/wnghdcjfe/stock-report-harness
cd stock-report-harness
claude
클로드 코드에서 다음처럼 입력하여 실행합니다.
[Claude Code]
/stock-goal 네이버 주가 1년 분석

30분 정도 기다리면 다음 그림처럼 네이버를 분석한 주식 리포트가 나옵니다.

생각보다 네이버의 주가를 분석하는 리포트가 잘 나온 것을 볼 수 있습니다. 어떻게 만들었을까요? 지금부터 살펴보겠습니다.
이 에이전트는 사용자의 주식 리포트 요청을 바로 HTML로 만들지 않습니다. 그 대신 plan, research, draft, image, review, build 순서의 하네스 엔지니어링으로 구현합니다.
각 단계는 다음 단계가 검증할 수 있는 산출물을 남깁니다. 특히 종목 관련 리서치는 최신 뉴스 100건과 최신 뉴스 5건 요약, 가격 차트, 출처, 리뷰 결과를 모두 추적 가능하게 보존합니다.

자, 그러면 각 에이전트는 어떻게 구성해야 할까요?
각 에이전트는 앞 단계가 남긴 파일을 입력으로 읽고, 자신의 결과를 다음 단계가 읽을 파일로 남깁니다. Planner가 plan/<slug>.md를 쓰면 Research Generator가 그것을 읽어 research/<slug>.md를 만들고, Lecture Generator가 다시 그 둘을 읽어 drafts/<slug>.md를 작성하는 식입니다.
Planner는 사용자의 자연어 요청을 plan/<slug>.md로 바꾸는 기준 문서 작성자입니다. 이 에이전트는 주제를 정리하는 수준을 넘어 후속 단계가 따라야 할 데이터 조건과 검증 기준까지 지정합니다. Planner의 역할은 ‘무엇을 만들지’뿐만 아니라 ‘어떤 근거로 검증할지’까지 먼저 고정하는 것입니다. Planner가 확정하는 주요 항목은 다음과 같습니다.
slug / topic, request / output_type / audience / ticker / period_start, period_end / chart_required / price_data_source: yfinance / price_data_interval: 1d / assumptions / 리서치 질문 / 데이터 요구 사항 / 리포트 개요 / 차트 계획 / Hero 이미지 방향 / 리뷰 기준 / 리스크와 제약
Research Generator는 plan/<slug>.md를 읽고 research/<slug>.md를 작성합니다. 이 파이프라인에서 가장 강화된 단계입니다. 종목이 포함된 경우 Research Generator는 다음을 수행합니다.
Lecture Generator는 plan과 research를 읽어 drafts/<slug>.md를 만듭니다. 이 단계의 목표는 리서치 메모를 독자가 이해할 수 있는 리포트 원고로 바꾸는 것입니다. draft 규칙은 다음을 요구합니다.
예시 차트 블록은 다음과 같습니다.
title: 삼성전자 최근 30일 종가 추이
aria_label: 삼성전자 2026-04-27부터 2026-05-26까지 일별 종가 추이
field: Close
interval: 1d
currency: KRW
이 구조 덕분에 초안 작성자는 가격 데이터를 꾸며 쓰지 않고, build 단계가 실제 yfinance 데이터를 사용하여 차트를 생성합니다. 작성과 데이터 처리를 분리하는 단순한 장치이지만, 잘못된 가격표가 본문에 섞이는 사고를 원천적으로 막습니다.
Image Generator는 plan, research, draft를 모두 읽고 GPT의 image gen 스킬을 이용하여 3개의 이미지 후보를 만듭니다. 이미지 규칙은 이미지가 단순 장식이 아니라 리포트 메시지의 시각 요약이어야 한다고 봅니다. 필수 산출물은 다음과 같습니다.
├─ output/assets/<slug>-hero-v1.prompt.txt
├─ output/assets/<slug>-hero-v2.prompt.txt
├─ output/assets/<slug>-hero-v3.prompt.txt
├─ output/assets/<slug>-hero-v1.png
├─ output/assets/<slug>-hero-v2.png
├─ output/assets/<slug>-hero-v3.png
├─ output/assets/<slug>-hero-v1.score.json
├─ output/assets/<slug>-hero-v2.score.json
├─ output/assets/<slug>-hero-v3.score.json
├─ output/assets/<slug>-image-manifest.json
└─ output/assets/<slug>-selected-image.json
최종 HTML은 선택된 hero 이미지 한 장만 사용합니다. 선택 정보가 없으면 build 단계는 완료로 취급하지 않습니다.
리뷰 단계는 이 시스템에서 가장 중요한 안전장치입니다. 메인 세션이 직접 “괜찮다”고 판단하지 않고, 별도 관점의 리뷰 에이전트를 거쳐 검토합니다. 이때 리뷰 에이전트들은 모두 메인 세션과 분리된 다른 세션에서 독립적으로 실행됩니다. 같은 모델을 쓰더라도 세션이 다르면 사고의 관성이 끊어지고, 처음 보는 사람의 시선이 되살아나기 때문입니다.
여기에 더해 클로드 코드 기반의 리뷰뿐만 아니라 코덱스의 리뷰까지 함께 활용합니다. 같은 결과물을 서로 다른 모델로 한 번 더 보게 해서 교차 검증을 거치는 셈입니다. 한 모델이 놓친 부분을 다른 모델이 잡아낼 가능성을 높이는 장치입니다.
fact-checker는 사실성 담당 에이전트입니다. 즉, fact-checker는 ‘문장이 그럴 듯한가’가 아니라 ‘근거 체인이 끊기지 않았는가’를 봅니다. 주요 역할은 다음과 같습니다.
lecture-designer는 교육 설계 담당 에이전트입니다. 주요 역할은 다음과 같습니다.
content-editor는 문장과 톤 담당 에이전트입니다. 주요 역할은 다음과 같습니다.
코덱스의 리뷰는 같은 내용을 코덱스라는 다른 LLM 세션에서 다시 보는 교차 리뷰어입니다. 이 리뷰는 메인 세션의 추론으로 대체할 수 없습니다. 다음과 같은 검토 범위를 기반으로 최종 상태 pass, needs_fix, blocked 중 하나로 판단합니다.
리뷰 에이전트는 몇 개가 적정할까요?
리뷰어를 늘릴수록 결과물의 품질이 단조롭게 좋아질 것 같지만, 실제 연구 결과는 그렇지 않습니다. 학계는 일관되게 ‘3~5명이 sweet spot, 6~8명이 상한’이라는 결론으로 수렴하고 있습니다.
리뷰가 끝나면reviews/<slug>.md의 status에 따라 다음 행동이 자동으로 분기됩니다.
needs_fix는 자동 처리, blocked는 항상 인간 호출입니다. 이 둘을 구분하지 않으면 에이전트가 해결할 수 없는 문제까지 무한 재시도하게 됩니다.
리뷰에서 지적이 나오면 그 종류에 따라 돌아가야 할 단계가 달라집니다. 출처가 잘못된 글을 문장만 다듬어 내보내면 안 됩니다. 어떤 리뷰어가 어떤 종류의 지적을 했는지에 따라 어디부터 다시 손볼지를 미리 정해둡니다.
(예)
회귀를 받은 Generator는 모든 리뷰 의견을 무조건 반영하지 않습니다. 세 가지 응답 중 하나를 선택하고 그 근거를 reviews/<slug>.md에 기록합니다.
핑퐁은 반드시 끝이 있어야 합니다. 다음 세 조건 중 하나가 충족되면 루프를 중단합니다.
핑퐁이 끝난 뒤에는 그 라운드에서 반복적으로 등장한 지적을 기록으로 남깁니다. 다만 이 기록을 단순히 텍스트 파일에 쌓아 두기만 하면 다음 라운드에서 또 같은 실수가 나오기 쉽습니다. 그래서 이 시스템에서는 회고 결과를 memory 파일에 정리해 두고, 다음 작업이 시작될 때 inject-memory-context.sh 훅이 해당 도메인과 관련된 메모리를 자동으로 컨텍스트에 주입합니다. 회고가 “한 번 쓰고 끝나는 글”이 아니라, 다음 작업에서 곧바로 활용되는 살아 있는 기억이 되는 구조입니다.
같은 종류의 지적이 여러 작업물에서 반복된다면 그것은 한 작업의 문제가 아니라, 하네스 자체가 그 실패를 막지 못하고 있다는 신호입니다. 이때는 memory에만 적어 두는 것으로는 부족합니다. 더 강한 가드레일, 즉 lint 규칙, 자동 테스트, 리뷰어 프롬프트, 새 스킬 같은 형태로 끌어올려야 합니다.
Builder는 plan, research, draft, review, selected-image를 모두 읽고 최종 HTML을 만듭니다. Builder의 책임은 다음과 같습니다.
훅을 통해 가드레일 패턴을 구현합니다. 클로드 코드가 명령을 실행하거나 파일을 수정하는 등 주요 작업을 수행하는 순간마다 훅이 먼저 개입하여 작업이 정해진 규칙과 절차를 벗어나지 않도록 통제합니다. 구체적으로는 위험한 명령을 차단하고, 정해진 작업 순서를 강제하고, 출력물이 규칙을 지켰는지 검증하며, 필요한 컨텍스트를 자동으로 주입하는 역할을 합니다. 여기에서의 하네스 예시는 다음 여덟 가지 훅을 사용합니다.
rm -rf /, sudo, 원격 스크립트 파이프 실행, 강제 푸시 같은 위험 명령을 차단합니다.
.env, .git, 깃허브 워크플로, 핵심 금융 스타일 가이드, 출력 스펙 같은 보호 경로의 수정을 막습니다.
draft와 HTML에 투자 권유, 수익 보장, 사기성 표현이 들어가면 차단합니다.
research, drafts, output 변경 시 선행 산출물이 있는지 확인합니다. 다음 순서를 강제합니다.
/plan → /research → /draft → /image → /review → /build
draft의 [3]과 같은 출처와 연동되어 있는지 등을 확인합니다.
draft가 변경되었는데 별도 세션 기반 4-way 리뷰가 없다고 나타나면 이후의 종료를 막고 다시 리뷰를 실행합니다.
사용자 요청 도메인에 맞는 memory topic을 자동 주입합니다.
memory 파일이 변경되었을 때 scripts/validate_memory.py로 형식을 검증합니다. 이 구조는 같은 실패를 반복하지 않도록 경험을 문서와 검증 도구로 남기는 장치입니다.
하나의 리포트 산출물이 “완료되었다”고 말하려면 다음 조건을 모두 만족해야 합니다.
plan/<slug>.md가 있습니다.research/<slug>.md가 있고 plan을 참조합니다.drafts/<slug>.md가 있고 plan과 research를 참조합니다.reviews/<slug>.md가 있고 status가 pass입니다.output/<slug>.html이 생성되어 있습니다.
그러면 실제로 stock-report-harness 폴더의 구조와 주요한 실제 코드를 살펴보겠습니다. stock-report-harness 폴더를 열어 보면 .claude 아래의 그림처럼 훅과 에이전트, 스킬 등이 정리되어 있습니다.

중요한 파일들 위주로 살펴봅시다.
└─ agents/fact-checker.md
---
name: fact-checker
description: 주식 리포트 plan/research/draft의 사실 일관성, 출처 품질, 티커/날짜 정합성, yfinance 가격 데이터, 뉴스 URL, 금융 안전 요건을 검증한다.
---
주식 리포트 하네스의 fact-checker 리뷰어다.
검토 항목:
- `ticker`, `period_start`, `period_end`가 plan/research/draft/review 전체에서 일치하는지 확인한 다.
- 가격 관련 주장이 yfinance/원본 차트 JSON과 요청 기간에 부합하는지 확인한다.
- 수치 주장에 출처 표식이 있고, 리서치 출처에 실제로 등장하는지 확인한다.
- 뉴스 항목에 실제 URL 또는 명시적 폴백 마커가 있는지 확인한다. 조작된 기사 URL은 실패 처리한다.
- 한국 주식 리포트에 토스 증권 뉴스와 투자자 매매 동향이 가능한 경우 포함되는지 확인한다.
- 초안에 투자 조언, 매매 지시, 수익 보장, FOMO 표현이 없는지 확인한다. 모든 핵심 사실이 추적 가능할 때만 `pass`를 반환한다. 그렇지 않으면 정확한 파일/섹션별 수정 사항과 함 께 `needs_fix`를 반환한다.
└─ skills/stock-research/SKILL.md
command
---
name: stock-research
description: 주식 리포트 slug에 대한 출처 기반 리서치를 수행한다. /stock-plan 이후 /stock-research <slug>로 사용하며, yfinance 일봉 가격, 최신 뉴스 100건, 한국 주식의 토스 증권 뉴스/매매 동향 확인, research/<slug>.md 출력을 포함한다.
---
# 주식 리서치 스킬
`plan/<slug>.md`를 기반으로 `research/<slug>.md`와 `output/assets/` 원자료 파일을 생성한다.
## 선행 조건
- `plan/<slug>.md`가 존재해야 한다. 없으면 중단하고 `/stock-plan <요청>`을 먼저 실행하라고 안내한다.
- plan 프론트매터에서 `ticker`, `period_start`, `period_end`, `price_data_source`, `price_data_ interval`을 읽고 유지한다.
## 절차
1. 티커와 기간을 plan 대비 검증한다.
2. `yfinance`로 요청 기간 전체의 실제 일봉 가격 데이터를 수집한다.
- 원본/정규화 데이터를 `output/assets/<slug>-price-chart-v1.json` 또는 명확히 명명된 파일로 저장한다.
- `YYYY-MM-DD` 레이블을 오름차순으로 사용한다.
3. 출처 기반 맥락을 수집한다:
- 1차 출처 우선: 기업 IR, 공식 뉴스룸, 공시, 거래소/중앙은행 데이터.
- 이벤트와 리스크는 공신력 있는 매체를 사용한다.
- 한국 상장 주식은 토스 증권 주식 뉴스와 투자자 매매 동향을 가능한 경우 확인한다.
4. 주식/ETF/섹터 요청 시 가능하면 최신 관련 뉴스 100건 이상을 수집·분류한다.
- 최신 뉴스 원본 JSON을 `output/assets/<slug>-*-latest100.json`으로 저장한다.
- 분류/분석 JSON을 `output/assets/<slug>-*-analysis100.json`으로 저장한다.
- 기사 URL을 조작하지 않는다. API에 개별 URL이 없으면 제공자/검색 폴백을 유지하고 `url_is_ fallback: true`로 표시한다.
5. `research/<slug>.md`에 최소 다음 프론트매터를 포함해서 작성한다:
`slug`, `title`, `created_at`, `period_start`, `period_end`, `ticker`, `price_data_source`, `price_data_interval`, `plan_source`, `sources`.
6. 본문 필수 항목:
- 결론 요약
- 주가 데이터 메모
- 핵심 이벤트/메커니즘
- 뉴스 100건 표 또는 수집 한계와 근거
- 수급/투자자별 매매 동향 (가능한 경우)
- 리스크/불확실성
- References/출처 표식 (`[S1]` 등)
## 제약 조건 - 임의·샘플링 가격 데이터를 사용하지 않는다.
- 존재하지 않는 기사 URL을 조작하지 않는다.
- 사실과 추론을 분리한다.
- 외부 접근이 차단되면 증거를 지어내지 말고 정확한 누락 데이터를 명시한 `blocked`/한계 섹션을 작성한다.
## 완료 보고
`research/<slug>.md`, 주요 원자료 JSON 파일, 가격 데이터 행 수, 뉴스 건수, 다음 명령어를 보고한다: `/stock-draft <slug>`.
`stock-goal`에서 호출된 경우 이 보고는 내부 체크포인트일 뿐이다. 멈추거나 사용자를 기다리지 않고 즉시 `/stock-draft <slug>`로 진행한다.
이것만으로도 주식 분석 리포트를 만드는 자동 시스템을 구축했다고 할 수 있습니다. 그러나 여기에서 시스템적으로 더 개선해 나갈 부분들이 있습니다. 바로 이 부분이 개발자가 해야 할 일입니다.
yfinance로 시세를 매번 끌어오는 방식은 빠르게 시작하기에는 편리하지만, 보고서를 한 번 만들 때마다 같은 API를 반복해서 두드리는 구조라 비용과 지연이 누적됩니다. 또한 다음 그림처럼 클로드 코드의 rate limit에 걸려서 데이터를 아예 가져오지 못하는 경우도 발생합니다.

뉴스도 같은 문제를 안고 있습니다. 보고서를 만들 때마다 즉석에서 뉴스를 긁어 오면 양은 많아도 광고성 · 중복성 기사로 채워지기 쉽습니다.
현재 이 시스템에서 리뷰 에이전트의 독립 컨텍스트는 부분적으로만 보장됩니다. 실제 독립적으로 실행될 수도 있고 아닐 수도 있습니다. 그저 아래처럼 “권장” 수준으로만 강제하고 있을 뿐입니다. 또한 이 리뷰 에이전트 부분은 병렬 실행이 아닙니다.
리포트의 경우 본문 구조도 고정되어 있습니다. 지금은 LLM Evaluator를 통해 토큰을 쓰면서 검증하는 방식으로 동작합니다.
이렇게 하네스 시스템을 활용하면 AI 에이전트의 불확실성을 통제하여 장기 작업을 안정적으로 수행할 수 있습니다. 물론 실무 환경에 맞추어 데이터 수집 방식이나 토큰 최적화 등 개선해 나갈 과제들도 여전히 남아 있지만 이제 우리가 고민해야 할 것은 함수 한 줄이 아니라 에이전트가 일하는 시스템 설계가 될 것이라는 점은 분명해 보입니다.


ⓒ요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.