「클로드 코드가 파일을 고쳤다」고 할 때 실제로 파일을 고친 것이 무엇인지. 모델이 낸 글자가 터미널 명령이 되어 돌아오기까지 열두 번을 오간다.
하네스는 AI 모델과 실제 컴퓨터 사이에 서서 모델이 뱉은 글자를 실행으로 바꾸는 프로그램이다. 모델은 다음에 올 토큰(한 번에 내놓는 글자 조각)을 이어 붙일 뿐 파일을 열지도 명령을 돌리지도 못한다. 그 글자를 셸에 던지고, 돌아온 로그를 모델이 읽을 크기로 줄여 다시 넣어 준다. 이 일을 맡은 프로그램이 하네스다.
핵심 포인트
pytest라고 써 놓아도 그 자체로는 아무 일도 안 벌어진다. 답이 옳은지 그른지와 무관하게, 모델의 출력은 문서 한 조각이다.EXEC: 같은 접두어나 도구 호출 JSON)를 찾아내 셸과 파일 시스템에 실제로 던진다. 클로드 코드·커서·오픈 인터프리터가 전부 하네스다.하네스가 도는 한 판
Loop (Typescript)
type Msg = { role: "user" | "assistant" | "tool"; text: string };
async function harness(ask: string) {
// 상태는 하네스가 들고 있다. 모델은 요청과 요청 사이에 아무것도 기억하지 않는다
① const state: Msg[] = [{ role: "user", text: RULES + "\n" + ask }];
while (true) {
② const reply = await model.complete(state, TOOLS); // 상태를 통째로 보낸다
state.push({ role: "assistant", text: reply.text });
// 모델이 낸 것은 글자뿐이다. 도구 호출도 실행이 아니라 JSON 한 조각이다
⑪⑫ if (reply.toolCalls.length === 0) return reply.text;
③ for (const call of reply.toolCalls) { // 모델이 적어 보낸 명령
if (risky(call)) await askUser(call); // 지우는 명령 앞에서 멈춘다
④⑤ const log = await runInShell(call); // 셸에 실제로 던진다
⑥ state.push({ role: "tool", text: shrink(log) }); // 실패한 줄만 남긴다
}
if (stuckOnSameError(state)) return "같은 실패가 되풀이돼 멈춥니다";
}
}EXEC:는 설명을 위해 쓴 표시다. 실제 제품은 도구 호출(tool use) 규격에 맞춘 JSON을 주고받는 쪽이 많다. 순서와 역할 분담은 같다. 코드도 뼈대만 남긴 것이다 — 실제 하네스에는 답을 한 글자씩 받아 보여 주는 처리, 끊긴 요청을 다시 부르는 처리, 오래된 대화를 요약해 넣는 처리가 더 붙는다.