article · 2026-06-19

맥락을 어떻게 전달해야 하는가: LLM은 통 속에 든 아인슈타인이다

지난 글에서 에이전트의 기억(agent-context)을 다뤘다. 이번엔 한 칸 아래로 내려간다. 그 맥락을 실제로 어떻게 적어 넣느냐, 즉 지시의 문제다. 결론부터 말하면 좋은 지시의 역량은 말솜씨가 아니라 정의와 구조화다. 그 이유는 LLM이 통 속에 든 아인슈타인이기 때문이고, 이 글은 그 비유에서 출발해 왜 이것이 prompt가 아니라 context engineering인지, 그리고 컨텍스트 낭비를 줄이는 구조가 어떤 모양인지까지 간다.

요약

지난 글에서 에이전트가 일을 이어서 하기 위해 필요한 기억의 구조, agent-context를 다뤘다. 그 글이 "무엇을 기억할 것인가"였다면, 이번 글은 한 칸 아래다. 그 맥락을 실제로 어떻게 적어 넣느냐, 곧 지시를 어떻게 쓰느냐.

흔히 이걸 "프롬프트를 잘 쓰는 법"이라고 부르고, 그러면 곧장 마법의 문구나 말솜씨 이야기로 샌다. 나는 그게 핵심이 아니라고 본다. 좋은 지시에 필요한 역량은 단 하나, 정의와 구조화를 잘 하는 능력이다. 왜 그런지를 한 비유로 설명할 수 있다. LLM은 통 속에 든 아인슈타인이다. 아인슈타인급 지식을 가졌지만 몸이 없어서, 컨텍스트 윈도우라는 가느다란 관으로 흘려보내 준 것만 본다.

이 글은 그 비유에서 출발해 세 가지를 말한다. 첫째, 사람과 LLM의 커뮤니케이션 차이는 대부분 컨텍스트 윈도우의 한계에서 온다. 둘째, 그래서 좋은 지시는 프롬프트를 잘 쓰되 그것을 컨텍스트 관점에서 설계하는 일이고, 그 차이를 가르는 건 결국 토큰 최적화다. 셋째, 그 설계는 구체적으로 컨텍스트 낭비를 줄이는 일이며, 구조(곱셈을 덧셈으로), 시간(기억의 점진적 승격), 표현(위키 링크 대신 그래프, 사투리 대신 표준어)의 세 방향으로 줄인다.


1. LLM은 통 속에 든 아인슈타인이다

오래된 사고 실험이 하나 있다. 통 속에 뇌가 하나 떠 있고, 거기에 전선이 꽂혀 신호가 들어온다. 뇌는 자기가 세상을 살고 있다고 믿지만, 실제로 아는 것은 전선으로 들어온 신호뿐이다. 바깥에 무엇이 있든, 관을 통해 흘러들어오지 않으면 그 뇌에게는 없는 것과 같다.

LLM이 딱 이렇다. 다만 이 뇌는 아인슈타인급이다. 인류가 써 둔 방대한 텍스트를 학습했으니, 잠재적으로 아는 것은 어마어마하다. 그런데 몸이 없다. 책장을 뒤지지도, 어제 회의를 떠올리지도, 옆자리에 물어보지도 못한다. 그 순간 컨텍스트 윈도우라는 관으로 흘려보내 준 것, 오직 그것만 본다.

여기서 사람과의 결정적 차이가 나온다. 사람도 지식을 다 머리에 이고 다니지 않는다. 하지만 사람은 필요한 순간에 필요한 맥락을 스스로 적재적소에 소환한다. "아, 이건 지난번 그 건과 비슷하지" 하며 관련 기억을 끌어오고, 모르면 찾아본다. LLM은 지식의 총량은 사람보다 많을 수 있어도, 그 방대한 맥락을 그 순간에 끄집어내는 능력이 없다. 학습된 지식은 흐릿한 배경으로 깔려 있을 뿐, 지금 이 작업에 정확히 필요한 한 조각을 스스로 불러오지는 못한다.

그래서 사람과 LLM의 커뮤니케이션 차이는, 흔히 말하듯 "LLM이 멍청해서"가 아니다. 상당 부분은 이 소환 능력의 부재, 곧 컨텍스트 윈도우의 한계에서 온다. 똑똑하지 않은 게 아니라, 통 안에 있는 것이다.


2. 그래서 필요한 역량은 정의와 구조화다

통 속의 아인슈타인에게 일을 시킨다고 해보자. 무엇을 잘해야 할까.

목소리를 키울 필요는 없다. 더 정중하게 부탁할 필요도, 마법의 주문을 찾을 필요도 없다. 통 안의 뇌에게 그런 건 닿지 않는다. 닿는 것은 오직 관으로 흘려보낸 내용물뿐이다. 그러니 잘해야 할 일은 둘로 좁혀진다. 무엇을 흘려보낼지 정확히 정의하는 것, 그리고 그것을 뇌가 바로 쓸 수 있는 형태로 구조화하는 것.

정의가 부실하면 아인슈타인도 엉뚱한 걸 만든다. "좋은 글로 바꿔줘"는 정의가 아니다. 누구에게, 어떤 톤으로, 무엇은 빼고, 무엇은 반드시 넣는지가 정의다. 구조화가 부실하면, 맞는 내용을 줘도 뇌가 그걸 관통해서 핵심을 못 짚는다. 관련 정보가 여기저기 흩어진 채로 한꺼번에 쏟아지면, 사람도 그렇듯 정작 중요한 한 줄이 묻힌다.

이게 내가 "프롬프트를 잘 쓰는 법"이라는 표현을 조심스러워하는 이유다. 그 표현은 자꾸 말솜씨만 떠올리게 한다. 글재주를 버리자는 게 아니다. 그 글재주를 무엇을 어떻게 전달할지의 구조로 설계하는 일에 가깝다. 머릿속에 모호하게 있는 요구를 경계가 분명한 명세로 깎아내고, 흩어진 맥락을 위계 있게 정리하는 일이다.


3. 프롬프트는 컨텍스트의 한 조각이다

여기서 한 단계 더 들어가면, 왜 지난 글의 agent-context, 그리고 그걸 다스리는 일을 prompt engineering이 아니라 context engineering이라 부르는지가 보인다. 단, 둘은 대립하지 않는다. 프롬프트는 컨텍스트의 한 조각이다. context가 prompt를 품는다.

이렇게 잡으면 깔끔하다. prompt는 이번 턴에 무슨 말을 적느냐, 곧 관에 흘려보내는 내용물 중 지금 내가 손으로 쓰는 한 조각이다. context는 그 한 조각을 포함해, 관을 통과하는 맥락 전체를 어떻게 조직하느냐의 문제다. 좋은 프롬프트 한 줄을 고민하는 일은 사라지지 않는다. 그것까지 포함해서, 무엇을 기억하고 무엇을 흘려보내고 어디에 어떤 구조로 쌓아 둘지를 함께 설계하는 것이 context engineering이다. 프롬프트를 잘 쓰는 일은 그 안에 들어 있는 가장 안쪽 조각이다.

이 포함 관계는 한 겹씩 밖으로 이어진다.

prompt engineering ⊂ context engineering ⊂ harness engineering ⊂ loop engineering

안에서 밖으로 읽으면 이렇다. 프롬프트는 이번 턴의 말이고, 컨텍스트는 그 말을 포함해 관을 통과하는 맥락 전체의 조직이며, 하네스는 그 맥락을 모아 관에 넣고 도구를 호출하는 기계 장치(무엇을 어떻게 길어와 어떤 형태로 조립해 실행하느냐)이고, 루프는 올리고 반응 보고 다시 고치는 바깥 순환이다. 안쪽 고리는 바깥 고리에 담긴다.

핵심은 바깥이 안쪽을 대체하지 않는다는 것이다. 컨텍스트를 잘 설계해도 프롬프트 한 줄은 여전히 필요하고, 루프를 잘 돌려도 그 안의 컨텍스트와 하네스가 받쳐 줘야 돈다. 지난 글에서 "노하우는 갈아치우는 게 아니라 겹겹이 쌓인다"고 한 게 바로 이 그림이다. 이 글은 그중 가운데 두 고리, 컨텍스트(4·5절)를 확대하고 하네스(6절)를 건드린다. 가장 바깥의 루프는 지난 글이 다뤘다.

그런데 둘을 가르는 진짜 기준은 따로 있다. 토큰이다. 관이 무한히 굵다면 정의도 구조화도 크게 고민할 필요가 없다. 가진 걸 전부 쏟아부으면 그만이다. 통 속의 아인슈타인이 답답한 건 바로 관이 가늘기 때문이다. 컨텍스트 윈도우는 유한하고, 그건 곧 토큰 예산이 유한하다는 뜻이다.

그래서 맥락을 다루는 일에는 필연적으로 토큰 최적화가 따라붙는다. 같은 작업을 시켜도, 필요한 맥락만 정확히 추려 넣은 경우와 관련 자료를 통째로 밀어넣은 경우는 결과도 비용도 다르다. 후자는 핵심이 묻히고, 예산을 태우고, 정작 중요한 맥락이 들어갈 자리를 잡동사니가 차지한다. agent-context를 "그냥 다 적어 두는 문서"가 아니라 "구조로 다스려야 하는 레이어"라고 부른 이유가 여기 있다. 무엇을 남기고 무엇을 흘려보낼지를 토큰 예산 안에서 설계하는 것, 그게 프롬프트 한 줄까지 품는 context engineering의 본령이다.


4. 컨텍스트 낭비를 줄이는 구조: 곱셈을 덧셈으로

그럼 그 설계는 구체적으로 어떤 모양인가. 내가 만드는 MSO에서 저장소의 agent-context는 크게 세 덩어리다.

  • index. 무엇이 어디에 있는지 적어 둔 지도. 저장소당 1개다.
  • workflow. 일을 어떤 순서로 하는지를 그래프(DAG)로 적은 절차. 작업 노드, 위임 노드, 단계 관계 같은 class들로 이뤄진다. 저장소엔 workflow가 여러 개, N개 있고, 그 안의 class는 M종류라고 하자.
  • work-memory. 지난 작업에서 쌓인 기억. 그 개수를 K개라고 하자.

핵심 질문은 이거다. N개의 workflow와 M종류의 class가 있을 때, 작업 기억 K를 어떻게 두어야 에이전트가 매번 스캔해야 하는 컨텍스트가 적어질까. 통이 가늘다는 걸 떠올리면, 이건 한가한 미학의 문제가 아니라 토큰 예산의 문제다.

두 가지 설계가 있다.

(가) workflow가 class를 품는 경우 (1 : M). 각 workflow가 자기 class들을 안에 끌어안고, class를 공유하지 않는다. 그러면 같은 종류의 class와 거기 딸린 기억이 workflow마다 복제된다. 기억은 (workflow × class) 칸마다 따로 쌓이므로,

K = N × M (곱셈)

(나) workflow와 class를 분리하고 매핑하는 경우 (N : M). class를 한 번만 정의해 두고, 각 workflow는 그 class를 바라보도록(매핑) 연결한다. 그러면 기억은 workflow 쪽에 N개, class 쪽에 M개로 각각 한 번씩만 쌓이고, 연결은 매핑이 담당한다.

K = N + M (덧셈)

N과 M이 조금만 커져도 곱셈과 덧셈의 차이는 벌어진다. workflow 5개, class 8종류면 40 대 13이다. 에이전트가 한 작업을 위해 훑어야 하는 기억의 단위 수가 그만큼 차이 난다. 이게 곧 관에 욱여넣어야 하는 토큰의 차이다.

솔직하게 단서를 하나 단다. 덧셈은 class가 정말로 workflow들 사이에서 재사용될 때만 성립한다. workflow마다 진짜로 고유한 기억이 필요하다면 곱셈을 피할 도리가 없다. 그러니 정확한 주장은 "K를 무조건 N+M으로 만들 수 있다"가 아니라, **"공유 가능한 것을 분리하고 매핑으로 잇는 순간, 유지하고 스캔할 컨텍스트 단위가 O(N×M)에서 O(N+M)으로 떨어진다"**이다. 이게 workflow와 class를 굳이 나누고, workflow → class로 바라보게 매핑하는 이유다. 사실 이 정리는 글을 쓰다 떠오른 것이고, 아직 코드에 다 반영하지는 못했다. 다만 방향은 분명하다. 곱셈으로 새는 컨텍스트를 덧셈으로 막는 것이다.

이름을 붙이자면 새로운 발명은 아니다. 데이터베이스를 정규화하고, 코드에서 중복을 걷어내는 것과 같은 원리다(같은 것을 두 번 적지 않기). 다만 여기서 그 원리가 아끼는 자원이 디스크나 유지보수가 아니라 에이전트가 매 순간 통으로 빨아들이는 컨텍스트 토큰이라는 점이 다르다.


5. 점진적 승격도 같은 이유다

지난 글에서 기억이 한 계단씩 추려진다고 했다. 올렸다는 사실에서, 반응이 별로였다는 관찰로, 바꾸니 나아졌다는 해결로, 반복되면 패턴으로, 굳으면 원칙으로. 나는 이걸 추상화 그래디언트라고 불렀다.

이 승격을 왜 하는가. 지난 글에서는 "교훈을 재사용 가능하게 만들려고"라고 했다. 이번 글의 관점에서 한 겹을 더 보탤 수 있다. 바라봐야 할 컨텍스트를 줄이려고.

생각해 보자. "낚는 제목이 반응이 약했다"는 개별 사건이 스무 번 쌓여 있다고 하자. 에이전트가 다음 제목을 정할 때 그 스무 줄을 다 훑어야 한다면, 그것만으로 관의 상당 부분이 찬다. 그런데 그 스무 사건이 "이 주제에선 낚는 제목보다 단정하는 제목이 낫다"는 원칙 한 줄로 추려져 있으면, 에이전트는 한 줄만 보면 된다. 스무 개의 사건이 하나의 원칙으로 압축되는 순간, 스캔해야 할 컨텍스트 단위가 스물에서 하나로 준다.

곧 4절의 "곱셈을 덧셈으로"가 구조의 가로축에서 컨텍스트를 아끼는 일이라면, 점진적 승격은 시간축에서 같은 일을 한다. 쌓인 사건을 위로 추려 올려, 아래의 잡다한 디테일을 관에 매번 흘려보내지 않아도 되게 만드는 것이다. 둘 다 결국 한 가지를 향한다. 가느다란 관에 무엇을 통과시킬지를 줄이는 것.


6. 표현 방식도 컨텍스트다: 위키 링크 대신 그래프, 사투리 대신 표준어

여기까지 오면 한 가지가 더 보인다. 기억을 아무리 잘 추리고 구조를 아무리 잘 정규화해도, 그것들을 잇는 방식이 헐거우면 아꼈던 컨텍스트가 다시 샌다. 대표적인 게 지식베이스를 위키 링크로 엮는 방식, 흔히 쓰는 Obsidian 같은 도구다.

문제는 traversal에서 터진다. 에이전트가 한 노드에서 출발해 연결된 맥락을 1에서 x 깊이까지 길어오려 한다고 하자. 그래프라면 "이 노드에서 깊이 2까지, 이 관계만" 같은 식으로 결정적으로 훑어 필요한 노드만 추려낼 수 있다. 그런데 위키 링크는 그렇게 동작하지 않는다. 에이전트가 링크를 발견하면 그 문서를 통째로 한 번 읽고, 그 안의 또 다른 링크를 따라 또 한 문서를 읽는다. 깊이도, 어디서 멈출지도, 무엇을 가져오고 무엇을 버릴지도 통제되지 않는다. 매 링크가 파일 하나를 통째로 가느다란 관에 들이민다. 4절에서 막아 둔 누수가, 정작 맥락을 길어오는 단계에서 그대로 다시 새는 것이다.

위키 링크는 본래 사람이 클릭으로 헤매며 읽으라고 만든 장치다. 사람에게는 훌륭하지만, 에이전트에게는 "통제되지 않는 읽기"가 된다. 그래서 나는 Obsidian을 그대로 쓰기보다, md 파일의 front-matter 같은 곳에 관계와 타입을 적는 규범을 정해 두고, 그걸 script로 호출하는 쪽을 택한다. script가 그래프를 결정적으로 1에서 x까지 훑어, 필요한 노드만 추려 관에 넣는다. 사람용 위키와 에이전트용 그래프는 같은 것이 아니다. 3절의 고리로 말하면, 이 단계가 바로 컨텍스트를 한 겹 감싸는 하네스다. 무엇을 어떻게 길어와 어떤 형태로 조립해 관에 넣을지를 정하는 기계 장치이기 때문이다.

그런데 여기서 한 번 더 꺾인다. 규범을 직접 만들면, 이번엔 그 규범 자체를 LLM에게 가르치는 데 또 토큰이 든다. "우리 front-matter에서 이 필드는 이런 뜻이고 이 관계는 이렇게 읽어라"를 매번 컨텍스트로 깔아 줘야 한다. 자체 규범은 결국 우리만 쓰는 사투리라, 늘 통역을 데리고 다녀야 하는 셈이다.

그래서 생각보다 semantic web 쪽이 좋다. RDF나 표준 어휘 같은 것들은 통 속의 아인슈타인이 이미 학습해 둔 언어다. 표준어로 적어 두면, 그 언어의 규칙을 알려주려고 컨텍스트를 따로 집어넣지 않아도 된다. 모델이 이미 안다. 사투리에는 통역(컨텍스트)이 붙지만 표준어에는 붙지 않는다. 곧 표현을 표준에 맞추는 것만으로, "규칙을 가르치는 컨텍스트" 자체를 거의 0으로 만들 수 있다. 1절의 비유가 여기서 한 번 더 일한다. 통 안의 아인슈타인에게는 그가 이미 아는 말로 적어 주는 게, 새 약속을 매번 설명하는 것보다 늘 싸다.


7. 한 문장 요약

LLM은 통 속에 든 아인슈타인이다. 지식은 방대하지만, 컨텍스트 윈도우라는 가느다란 관으로 흘려보낸 것만 본다. 그래서 좋은 지시의 역량은 말솜씨가 아니라 정의와 구조화이고, 그 일은 프롬프트를 잘 쓰되 그것을 토큰 예산 안에서 컨텍스트로 설계하는 일이다. 그 설계는 세 방향으로 컨텍스트 낭비를 줄인다. 구조에서는 workflow와 class를 분리해 곱셈을 덧셈으로 바꾸고, 시간에서는 기억을 점진적으로 승격해 매번 훑을 단위를 줄이며, 표현에서는 통제되지 않는 위키 링크 대신 결정적 그래프를, 자체 사투리 대신 모델이 이미 아는 표준어를 쓴다. 이 모든 일은 prompt ⊂ context ⊂ harness ⊂ loop라는 겹겹의 고리 중 가운데 두 겹(컨텍스트와 하네스)에서 일어나며, 바깥이 안쪽을 대체하는 게 아니라 감싼다. 더 굵은 관을 기다리는 대신, 가느다란 관에 무엇을 통과시킬지를 설계하는 것이다.


메모 (발행 전 정리용)

  • 지난 글 agent-context란 무엇인가의 후속편. 도입에서 그 글을 한 줄로 받되, 단독으로도 읽히게 구성함.
  • 4절 수식은 "K를 N+M으로 만든다"가 아니라 "O(N×M) → O(N+M)"으로 표현(class 재사용 전제 명시). 과장 금지.
  • workflow ↔ class 분리·매핑은 아직 구현 전인 설계 방향임을 본문에 정직하게 표기함(4절). 실제 적용 시 work-memory 결정으로 별도 기록 필요.
  • "통 속의 뇌(brain in a vat)"는 퍼트넘의 사고 실험 변주. 학술 인용까지 달지, 비유로만 쓸지는 채널별로 판단. 지난 글 수준의 근거 섹션이 필요하면 컨텍스트 엔지니어링/토큰 예산 관련 1차 출처 보강 가능.
  • 6절(위키 링크 vs 그래프 traversal, 자체 규범 vs semantic web 표준 어휘)도 4절 매핑과 마찬가지로 현재 운영 방향이자 설계 판단임. semantic web 채택을 확정하면 work-memory(AD)로 별도 기록 필요. front-matter 규범 + script 호출은 이미 일부 운영 중(wm_node.py / sf_node.py).
  • 엠대시 미사용 확인 (UD-0021).