LLM 은 판단과 말하기밖에 안 한다 — 나머지는 전부 하네스다
“클로드가 내 파일을 지웠다.” “GPT 가 서버를 재시작했다.” 흔히 하는 말이고, 나도 한다. 그런데 이 문장은 틀렸다. 문법이 아니라 범주가 틀렸다. 언어 모델은 파일을 지울 수 없다. 지울 손이 없다. 모델이 한 일은 rm -rf 라는 문자열이 담긴 JSON 을 내보낸 것이고, 그걸 읽어 실제 시스템 콜을 부른 건 모델 바깥의 프로그램이다.
이 글의 주장은 한 줄이다. LLM 이 하는 일은 판단과 말하기, 둘뿐이다. 실행·기억·인지·권한·시간·반복은 전부 모델을 감싼 프로그램 — 하네스 — 의 일이다. 당연한 소리 같지만, 이 구분을 정확히 잡으면 보안·책임·평가·로그에 대한 판단이 꽤 달라진다.
사실관계: 도구 호출의 실제 프로토콜
“모델이 도구를 쓴다” 는 말부터 뜯어보자. 각 벤더의 공식 문서가 프로토콜을 정확히 적어 놨다.
Anthropic 의 tool use 문서는 흐름을 이렇게 나눈다. 클라이언트가 도구 정의와 함께 요청을 보낸다. 모델은 도구를 쓰기로 결정하면 tool_use 블록 — 도구 이름과 입력 JSON — 을 응답에 담아 내보내고 멈춘다. 그 다음 문장이 핵심이다. 클라이언트가 그 입력으로 도구를 실행하고, 결과를 tool_result 블록으로 다음 요청에 넣어 보낸다. 모델은 그 결과를 읽고 다시 판단한다.
OpenAI 의 function calling 문서도 같은 구조를 그린다. 모델은 함수 이름과 인자를 돌려줄 뿐이고, 함수를 실제로 실행하는 것은 개발자의 코드다. 문서가 이 점을 명시적으로 강조한다.
MCP(Model Context Protocol) 사양은 이 분리를 아예 역할 이름으로 못박았다. 도구를 실행하는 것은 서버, 그 서버에 요청을 보내는 것은 클라이언트, 클라이언트를 소유하고 모델과 대화하는 것은 호스트다. 모델은 이 셋 중 어디에도 없다. 모델은 호스트가 보여준 도구 목록을 보고 “이걸 이 인자로 불러 달라” 고 말할 뿐이다.
셋 다 같은 그림이다. 모델의 출력은 두 종류뿐이다 — 사람에게 보여줄 텍스트, 또는 “이 도구를 이 인자로 실행해 달라” 는 구조화된 요청. 두 번째도 결국 말이다. 요청이지 실행이 아니다.
그래서 둘뿐이다
판단. 지금 컨텍스트에서 다음에 무엇을 내보낼지 고르는 것. 답을 쓸지, 도구를 부를지, 어떤 도구를 어떤 인자로 부를지, 멈출지. 기술적으로는 다음 토큰의 확률 분포에서 고르는 일이지만, 에이전트 관점에서는 이게 “결정” 이다.
말하기. 그 판단을 밖으로 내보내는 것. 자연어든, JSON 이든, 코드 블록이든, 확장 사고(extended thinking)의 내부 토큰이든 형식만 다를 뿐 전부 생성된 텍스트다.
이게 새로운 관찰은 아니다. 에이전트 프레임워크의 출발점으로 흔히 인용되는 ReAct 논문 (Yao et al., 2022) 은 제목이 “Reasoning and Acting” 인데, 본문을 보면 추론 흔적(reasoning trace)과 행동(action) 을 둘 다 모델이 텍스트로 생성하고, 행동을 실제로 수행해 관찰(observation)을 돌려주는 것은 환경이다. “Acting” 은 모델이 행동 문자열을 말하는 것이고, 행동 자체는 바깥에서 일어난다. Toolformer (Schick et al., 2023) 도 모델이 배우는 것은 API 호출 텍스트를 언제 어디에 삽입할지 이고, 호출을 실행해 결과를 채워 넣는 것은 별도 절차다.
나머지는 전부 하네스다
그러면 에이전트가 하는 것처럼 보이는 나머지 일들은 누가 하나. 전부 하네스다.
실행. 위에서 본 대로다. 셸 명령, 파일 쓰기, HTTP 요청, DB 쿼리 — 모델이 요청 문자열을 말하면 하네스가 실행한다.
기억. 모델에게 컨텍스트 윈도 밖은 존재하지 않는다. “지난주에 이렇게 하기로 했잖아” 를 모델이 아는 건 하네스가 그 기록을 파일에서 읽어 이번 요청에 넣어줬기 때문이다. 메모리 파일, 요약, 벡터 검색 — 전부 하네스가 무엇을 보여줄지 고르는 일이다. 모델은 보여준 것만 본다.
인지. 모델은 스스로 보지 못한다. 디스크에 파일이 있어도 하네스가 읽어 넣어주기 전엔 모델에게 없는 것이다. 나는 이걸 여러 번 틀렸다. 노드 봇을 운영하면서 “파일이 디스크에 있으니 봇이 안다” 고 보고했다가, 봇의 컨텍스트에 그 파일이 한 번도 들어간 적이 없다는 걸 나중에 확인한 일이 하루에 여러 번 있었다. 디스크에 있다는 것과 모델이 안다는 것은 층위가 다르다.
권한. 어떤 도구를 보여줄지, 승인을 받을지, 샌드박스 안에서 돌릴지는 전부 하네스 설정이다. 모델은 자기가 못 보는 도구를 부를 수 없고, 하네스가 거부하면 실행되지 않는다.
시간과 반복. 모델은 기다리지 못한다. “5분 뒤에 다시 확인해” 를 모델이 실행하는 것처럼 보이면, 실제로는 하네스가 타이머를 걸고 5분 뒤에 모델을 다시 호출한 것이다. 에이전트 루프 — 판단 → 실행 → 관찰 → 판단 — 에서 화살표는 전부 하네스 코드다. 모델은 각 화살표 사이의 한 칸을 채울 뿐이다.
내가 직접 겪은 사고 하나가 이 구분을 정확히 보여준다. 텔레그램으로 명령을 받는 봇을 노드마다 하나씩 띄워 두고 있다. 어느 날 한 봇이 사용자 질문에 답을 터미널에만 쓰고, 텔레그램으로 보내는 도구를 부르지 않았다. 프로세스·서비스·플러그인 전부 정상이었다. 모델은 판단했고(답을 정했고) 말했다(텍스트를 생성했다). 그런데 그 말이 사용자에게 닿는 경로 — 도구 호출 — 를 타지 않았으니 사용자 입장에선 무응답이었다. 모델은 자기가 답했다고 “생각” 했을 것이다. 말하기는 했는데 하네스 채널을 안 탔으니 세상에는 아무 일도 안 일어난 것이다.
이 프레임이 바꾸는 것
보안의 통제 지점은 모델이 아니다
프롬프트 인젝션 대응을 “모델을 더 잘 설득하자” 로 접근하면 끝이 없다. 모델은 판단하는 존재고, 판단은 입력에 따라 흔들린다. 통제 지점은 하네스다 — 무엇을 보여줄지, 무엇을 실행할지, 어디로 내보낼지.
Simon Willison 이 Lethal Trifecta 라고 이름 붙인 조합이 정확히 이 얘기다. 사적 데이터 접근, 신뢰 못 할 콘텐츠 노출, 외부로 내보내는 통신 — 셋이 한 에이전트에 모이면 데이터가 샌다. 셋 중 어느 것도 모델의 속성이 아니다. 전부 하네스가 모델에게 준 능력이다. 셋 중 하나를 빼는 것도 하네스에서 한다.
DeepSeek Harness 의 SAFETY.md 가 이 점을 벤더 스스로 인정한다. 샌드박스·승인 프롬프트·권한 통제는 위험을 줄일 뿐 격리를 보장하지 않고, 이 하네스를 유일한 보안 통제로 삼지 말라고 쓴다. 통제가 하네스에 있다는 걸 알기 때문에 하네스의 한계를 경고하는 것이다. 모델을 경고하지 않는다.
책임의 문장이 바뀐다
“모델이 파일을 지웠다” 대신 “하네스가 모델의 요청을 승인 없이 실행했다” 로 쓰면 고칠 자리가 보인다. 승인 프롬프트, 허용 목록, 읽기 전용 모드는 전부 이 문장의 뒷부분을 고치는 장치다. 앞부분 — 모델이 그런 요청을 말한 것 — 은 프롬프트로 줄일 수는 있어도 없앨 수는 없다.
벤치마크는 모델+하네스의 합산이다
에이전트 벤치마크 점수는 모델만의 점수가 아니다. 같은 모델을 다른 하네스에 넣으면 점수가 달라진다 — 어떤 도구를 줬는지, 컨텍스트를 어떻게 관리했는지, 실패했을 때 재시도를 누가 하는지가 전부 하네스 몫이기 때문이다. Anthropic 의 Building effective agents 는 그래서 프레임워크보다 단순하고 조립 가능한 패턴을 권하고, 에이전트를 “모델이 자기 프로세스와 도구 사용을 동적으로 지시하는 시스템” 으로 정의한다. 지시(direct)한다고 썼지 실행한다고 쓰지 않았다.
로그는 두 가지만 남기면 완전하다
모델이 판단과 말하기밖에 안 한다면, 모델이 본 것과 모델이 말한 것만 빠짐없이 기록하면 모델의 모든 행동을 재구성할 수 있다. 지난 글에서 본 DeepSeek Harness 의 규칙 — “Model-visible means logged”, 모델 요청에 닿는 모든 것은 로그에서 재구성 가능해야 한다 — 이 성립하는 이유가 이거다. 하네스가 실행한 것은 하네스 로그에 있고, 모델은 그 사이의 판단만 했으니 입력과 출력이 전부다.
반론 몇 개
“코드를 실행해서 계산하잖아.” 코드 실행은 하네스다. 모델은 코드를 말했고, 인터프리터가 돌렸다. 모델 내부에서 일어나는 “계산” 은 판단의 일부다 — 다음 토큰을 고르는 과정에서 일어나는 것이고, 그 결과는 말로 나온다.
“확장 사고(reasoning)는 다르지 않나.” 형식은 다르지만 범주는 같다. 사용자에게 안 보이는 토큰을 먼저 생성하고 그 뒤에 답을 생성하는 것이니, 말하기를 두 단계로 나눈 것이다. 판단의 질이 올라가는 건 맞다. 범주가 바뀌는 건 아니다.
“그럼 모델은 별거 아니라는 건가.” 반대다. 하네스는 누구나 만들 수 있고 실제로 지금 수십 개가 있다. 판단은 대체가 안 된다. 이 글은 모델을 깎는 게 아니라 모델이 안 하는 일을 모델 탓으로 돌리지 말자 는 것이다. 그래야 모델이 하는 일 — 판단 — 을 제대로 평가할 수 있다.
가져갈 것
- 에이전트 사고가 나면 문장을 둘로 쪼개라. 모델이 무엇을 말했나, 하네스가 그걸 어떻게 처리했나. 고칠 자리는 대개 뒤쪽에 있다.
- 보안 통제를 프롬프트에 두지 마라. 도구 목록, 승인, 샌드박스, 송신 경로 — 하네스에 둔다.
- “봇이 안다” 고 말하기 전에 그 정보가 컨텍스트에 들어갔는지 확인하라. 디스크에 있는 것과 모델이 본 것은 다른 층위다.
- 에이전트 벤치마크 숫자를 볼 때 하네스가 뭔지 같이 봐라. 모델 이름만 적힌 점수는 절반의 정보다.
- 로그를 설계할 때 모델의 입력과 출력을 빠짐없이 남겨라. 그 둘이 모델 행동의 전부다.
검증 범위. 도구 호출 프로토콜에 대한 서술은 각 벤더의 공식 문서와 MCP 사양의 현재 내용을 요약한 것이며, 문서가 바뀌면 세부가 달라질 수 있다. 노드 봇 사고는 필자의 운영 기록이고 이 글에 필요한 범위만 적었다. 모델 내부 동작(판단이 어떻게 이뤄지는가)에 대한 주장은 하지 않았다 — 이 글은 모델의 입출력 경계에 대한 글이다.
References
- Anthropic, Tool use overview — https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview
- OpenAI, Function calling — https://platform.openai.com/docs/guides/function-calling
- Model Context Protocol, Specification 2025-06-18 — https://modelcontextprotocol.io/specification/2025-06-18
- S. Yao et al., ReAct: Synergizing Reasoning and Acting in Language Models, arXiv:2210.03629 (2022) — https://arxiv.org/abs/2210.03629
- T. Schick et al., Toolformer: Language Models Can Teach Themselves to Use Tools, arXiv:2302.04761 (2023) — https://arxiv.org/abs/2302.04761
- Anthropic, Building effective agents (2024) — https://www.anthropic.com/research/building-effective-agents
- S. Willison, The lethal trifecta for AI agents (2025, 에세이) — https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/
- DeepSeek Harness,
SAFETY.md— https://github.com/deepseek-ai/deepseek-harness/blob/master/SAFETY.md
관련 글: DeepSeek Harness 를 직접 돌려봤다 (9/17) · 다음 모델이 와도 남는 것 (8/13)