인간의 뇌는 어떻게 공간과 이미지,
언어와 행동을 만들어내는가

인간의 뇌를 이해할 때 가장 중요한 것은 뇌 영역의 이름을 많이 외우는 것이 아니다. 감각이 어떤 내부 표상으로 바뀌고, 그 표상이 기억과 목표를 만나 어떻게 사고와 행동으로 이어지는가를 이해하는 것이다.

이 글의 중심 명제
뇌는 외부 세계를 그대로 받아들이지 않는다.
감각신호를 행동에 사용할 수 있는 내부 모델로 바꾸고, 그 모델을 기억과 현재 목표에 맞게 재구성한 뒤, 행동하고, 그 결과를 이용해 다시 자신의 회로를 수정한다.
이 글에서 따라갈 흐름

감각 입력 → 시각·청각·신체 표상 → 공간과 객체의 구성 → 기억과 맥락의 결합 → 언어와 관계구조 → 작업기억과 목표 → 행동 선택과 운동계획 → 감각 피드백 → 학습과 회로 변화

뇌 구조 도식

뇌는 ‘기능 상자’가 아니라 정보가 계속 변환되는 시스템이다

뇌를 처음 공부하면 기능별로 영역을 나누게 된다. 후두엽은 시각, 측두엽은 청각과 언어, 전두엽은 사고, 중심앞이랑은 운동이라는 식이다.

해부학을 배우는 단계에서는 필요한 구분이다. 하지만 실제 뇌가 이런 독립된 상자들의 집합이라고 생각하면 곧 설명이 막힌다.

컵을 집는 행동 하나만 봐도 그렇다. 컵이 보여야 하고, 무엇인지 알아봐야 하며, 공간의 어디에 있는지 계산해야 한다. 동시에 손이 어디에 있는지 알아야 하고, 손가락을 얼마나 벌릴지 정해야 한다. 팔을 뻗은 뒤에는 컵이 예상보다 무거운지, 미끄러지고 있는지도 계속 확인해야 한다.

이 과정에는 시각피질, 두정피질, 전전두피질, 전운동피질, 일차운동피질(primary motor cortex, M1), 기저핵, 소뇌, 척수, 체성감각계가 함께 관여한다.

말 한 문장을 이해하는 것도 마찬가지다. 귀에 들어오는 것은 의미가 아니라 시간에 따라 변하는 음향파형이다. 뇌는 이 파형에서 음성 특징을 추출하고, 음소와 단어를 식별하고, 의미를 불러오고, 문장 안의 관계를 계산한 뒤, 그 내용을 현재 상황과 기억에 연결한다.

따라서 뇌를 이해할 때 질문은 “어디에서 무슨 일이 일어나는가?”에서 한 단계 더 나아가야 한다.

더 중요한 질문은 “이 정보가 다음 회로로 넘어갈 때 무엇으로 바뀌는가?”다.

이 관점에서 보면 시각, 공간, 기억, 언어, 사고, 운동은 서로 떨어진 주제가 아니다. 앞 단계에서 만들어진 표상이 다음 단계의 계산 재료가 되는 하나의 연속된 과정이다.

우리가 경험하는 세계는 감각의 복사본이 아니다

눈앞에 사과가 있을 때 우리는 사과를 직접 본다고 느낀다. 하지만 망막에 도달하는 것은 사과라는 개념이 아니라 빛이다.

귀로 문장을 들을 때도 ‘의미’가 귀로 들어오는 것은 아니다. 들어오는 것은 공기압의 변화다.

근육과 관절에서 올라오는 정보 역시 “내 오른팔이 몸에서 이 방향에 있다”라는 완성된 문장이 아니다. 각각의 감각수용기가 만들어낸 전기화학적 신호다.

뇌의 중요한 역할은 이런 서로 다른 신호를 외부 세계와 자신의 몸에 관한 사용 가능한 표현으로 바꾸는 것이다.

신경표상은 뇌 안의 ‘작은 사진’이 아니다

여기서 중요한 개념이 신경표상(neural representation)이다.

표상이라고 하면 외부 세계의 작은 그림이 뇌 안에 저장돼 있는 것처럼 느껴질 수 있다. 실제로는 그렇지 않다.

물체의 위치, 방향, 형태, 정체성, 가치 같은 정보는 많은 뉴런이 만드는 집단 활동패턴(population activity pattern)에 분산되어 표현된다.

즉 ‘컵’이라는 정보는 컵 모양의 뉴런 하나에 들어 있는 것이 아니라, 여러 뉴런의 활동관계가 컵에 관한 정보를 표현하는 것이다.

뇌가 감각을 처리한다는 말의 본질

감각을 그대로 보존한다는 뜻이 아니다.
현재 판단과 행동에 필요한 형태로 다시 부호화한다는 뜻이다.

시각계는 빛을 ‘물체’와 ‘행동 가능한 공간’으로 바꾼다

망막의 광수용체는 빛을 전기화학적 신호로 변환한다. 이 신호는 망막 내부 회로에서 가공된 뒤 시신경을 통해 뇌로 전달되고, 주요 경로는 시상의 외측슬상핵(lateral geniculate nucleus, LGN)을 거쳐 후두엽의 일차시각피질(primary visual cortex, V1)에 도달한다.

하지만 일차시각피질에서 곧바로 ‘사과’, ‘자동차’, ‘얼굴’이 만들어지는 것은 아니다.

이 단계에서는 특정 공간 위치의 대비, 경계의 방향, 공간주파수 같은 비교적 기초적인 시각특징이 처리된다.

빛의 공간적 패턴

경계·방향·대비

형태와 부분의 관계

객체와 정체성

물론 실제 시각계가 이렇게 완전히 직렬적으로만 작동하는 것은 아니다. 많은 피드포워드(feedforward)와 피드백(feedback) 연결이 병렬적으로 작동한다.

그래도 이 흐름은 중요한 원리를 보여준다. 시각계는 빛을 받는 것이 아니라 점차 더 추상적인 표상을 구성한다.

복측 시각경로는 ‘무엇인가’를 구성한다

후두엽에서 측두엽 방향으로 이어지는 복측 시각경로(ventral visual stream)는 물체와 얼굴, 형태, 정체성의 인식에 중요한 역할을 한다.

쉽게 말하면 “지금 보고 있는 것이 무엇인가?”라는 문제를 푸는 계통에 가깝다.

초기의 단순한 형태정보가 측두엽 방향으로 갈수록 보다 복잡한 객체와 범주의 표상으로 발전한다.

배측 시각경로는 ‘어떻게 행동할 것인가’를 계산한다

후두엽에서 두정엽으로 이어지는 배측 시각경로(dorsal visual stream)는 과거에는 단순히 ‘어디 경로’라고 많이 불렸다.

그러나 기능을 더 정확히 표현하면 행동을 위한 시각(vision for action)에 가깝다.

컵이 컵이라는 사실을 아는 것과 실제로 컵에 손을 정확히 가져가는 것은 전혀 다른 계산이기 때문이다.

손을 뻗으려면 컵의 위치뿐 아니라 손의 현재 위치, 눈의 방향, 머리 방향, 몸통 자세, 컵까지의 거리와 방향을 함께 계산해야 한다.

이때 상두정소엽(superior parietal lobule), 후두정피질(posterior parietal cortex)을 포함한 두정계가 핵심적으로 관여한다.

두정엽의 핵심은 ‘감각 통합’보다 좌표변환이다

두정엽을 단순히 여러 감각을 합치는 곳이라고 설명하는 경우가 많다. 하지만 실제 계산을 이해하려면 좌표변환(coordinate transformation)이라는 개념이 더 중요하다.

망막에 표시되는 물체의 위치는 눈을 기준으로 한다. 눈이 움직이면 같은 물체도 망막에서는 다른 위치에 투사된다.

그런데 실제 행동은 눈 좌표만으로 할 수 없다. 머리, 몸통, 어깨, 팔, 손의 위치와 모두 연결해야 한다.

“망막의 오른쪽에 있다”

“내 몸의 오른쪽 앞에 있다”

“오른손을 이 방향으로 뻗으면 닿는다”

이 변환에 시각정보뿐 아니라 눈의 위치, 머리 방향, 고유수용감각(proprioception), 몸의 자세와 같은 정보가 사용된다.

그래서 우리가 경험하는 공간은 단순한 시각적 배경이 아니다.

“내가 이 세계 안에서 무엇을 할 수 있는가”가 포함된 행동공간이다.

공간기억은 지도 한 장이 아니라 여러 좌표계의 관계다

익숙한 집이나 학교를 떠올리면 눈을 감아도 문, 계단, 창문, 복도와 같은 공간관계를 어느 정도 재구성할 수 있다.

이를 넓게 지형기억(topographical memory)이라고 부를 수 있다.

하지만 뇌 안에 실제 지도가 한 장 저장돼 있다고 생각하면 곤란하다.

길을 찾으려면 장면을 알아보고, 현재 방향을 파악하고, 이전 위치를 기억하고, 현재 위치를 장기적인 공간구조에 맞춰야 한다.

해마는 ‘장소’를 저장하기보다 장소·시간·사건의 관계를 묶는다

해마(hippocampus)는 공간기억과 일화기억(episodic memory)에 핵심적으로 관여한다.

해마에서는 특정 위치와 관련해 활성화되는 장소세포(place cell)가 발견된다.

그러나 해마의 기능을 위치 저장으로만 축소해서는 안 된다. 해마는 어디에서, 언제, 무엇이 일어났는가를 하나의 관계적 사건으로 묶는 데 중요하다.

“어제 도서관에서 친구를 만났다”는 기억에서 도서관, 시간, 친구, 대화는 서로 떨어진 파일이 아니다. 하나의 사건구조를 형성한다.

내후각피질은 공간 속 위치와 이동을 표현한다

해마와 밀접하게 연결된 내후각피질(entorhinal cortex)에서는 격자세포(grid cell)를 포함한 다양한 공간표상 뉴런이 발견된다.

격자세포는 특정 장소 하나만 표시하는 것이 아니라 공간을 이동할 때 규칙적인 공간주기를 가진 활성패턴을 만든다.

따라서 해마-내후각피질 계통은 공간 속 위치와 이동관계를 표현하는 핵심 회로로 이해되고 있다.

후방비장피질은 현재 시야와 기억 속 공간을 연결한다

지금 보이는 공간은 대개 나를 기준으로 표현된다.

“문이 내 오른쪽에 있다.”

이를 자기중심적 표상(egocentric representation)이라고 한다.

반면 익숙한 장소에 대한 장기적인 공간지식은 환경 자체를 기준으로 표현할 수 있다.

“문은 건물 북쪽에 있다.”

이것은 환경중심적 표상(allocentric representation)이다.

후방비장피질(retrosplenial cortex)은 현재 방향, 랜드마크, 기억된 공간관계를 연결하는 데 중요한 역할을 한다.

공간기억의 핵심

해마에 ‘지도’가 저장되어 있는 것이 아니다. 시각계가 장면을 분석하고, 두정계가 현재 몸과 공간의 관계를 계산하며, 후방비장피질이 좌표계를 연결하고, 해마-내후각계가 장소와 경험의 관계를 조직한다.

그리고 이런 공간표상 능력은 인간만의 능력도 아니다. 여러 동물에서도 장소세포와 격자세포가 발견된다. 인간의 특별함은 이런 공간표상을 언어, 장기계획, 상징적 추론과 결합해 매우 복잡한 수준으로 확장한다는 데 있다.

머릿속 이미지는 저장된 사진보다 ‘재구성된 상태’에 가깝다

눈을 감고 사과를 떠올려보면 붉은색, 둥근 형태, 꼭지 같은 특징을 어느 정도 떠올릴 수 있다.

이런 현상을 시각심상(visual imagery)이라고 한다.

시각심상은 실제로 사물을 볼 때와 완전히 동일한 신경상태는 아니다. 하지만 고차 시각피질과 전두-두정 네트워크를 포함해 실제 시지각과 일부 공통된 회로를 사용한다.

중요한 것은 이미지가 기억 속 사진을 꺼내는 방식으로 생성된다고 생각하지 않는 것이다.

더 적절한 표현은 기억 속 특징과 관계를 다시 불러와 시각적 상태를 재구성한다는 것이다.

그리고 인간의 모든 생각이 이미지로 이루어지는 것도 아니다. 사람마다 시각심상의 선명도는 크게 다르고, 시각심상이 매우 약한 사람도 충분히 정상적인 추론과 계산을 할 수 있다.

따라서 인간 사고의 중요한 특징은 ‘시각적 사고’ 하나가 아니라 시각·공간·언어·수량·행동 표상을 문제에 따라 바꿔 쓰는 능력이다.

계산도 단순한 ‘숫자 이미지’가 아니다

암산을 할 때 숫자를 머릿속에 시각적으로 배치하거나, 필산 형태를 떠올리는 사람이 많다. 따라서 시각적 전략이 계산을 도울 수 있는 것은 맞다.

그러나 수학적 계산 자체를 시각피질의 기능이라고 볼 수는 없다.

수량과 크기의 관계를 처리할 때는 두정엽, 특히 두정내고랑(intraparietal sulcus, IPS)을 포함한 회로가 중요하다.

복잡한 연산에서는 배외측 전전두피질과 작업기억계가 강하게 관여하고, 익숙한 산술 사실을 빠르게 불러오는 상황에서는 언어와 장기기억 회로의 기여가 커질 수 있다.

따라서 계산은 수량표상, 기호인식, 작업기억, 규칙 적용, 기억검색이 결합된 작업이다.

시각화는 이 계산을 수행하는 하나의 전략일 수 있지만, 계산의 본질 그 자체는 아니다.

‘통합된 경험’은 하나의 통합센터에서 만들어지지 않는다

우리는 친구의 얼굴을 보면서 목소리를 듣고, 그 사람이 누구인지 기억하고, 상대방의 표정에서 감정을 읽으며, 자신의 몸이 공간의 어디에 있는지도 동시에 느낀다.

의식에서는 이것이 하나의 경험처럼 느껴진다.

하지만 뇌 안에 모든 정보가 마지막에 모이는 하나의 ‘통합적 표상 공간’이 존재한다고 보기는 어렵다.

시각은 시각 네트워크, 청각은 청각 네트워크, 신체감각은 체성감각계, 기억은 해마와 연합피질, 목표와 규칙은 전두-두정 네트워크 등에서 서로 다른 방식으로 표현된다.

통합은 이 정보가 한 장소에 쌓이는 방식보다 여러 네트워크가 필요한 순간에 서로의 정보를 교환하면서 하나의 일관된 상태를 형성하는 과정으로 이해하는 편이 적절하다.

경험은 하나처럼 느껴지지만, 그 경험을 만드는 계산은 분산되어 있다.

언어는 소리를 ‘관계와 계층을 가진 구조’로 바꾼다

언어는 시각과 다른 중요한 특성을 가진다.

시각장면은 공간적으로 펼쳐져 있지만, 말소리는 시간에 따라 차례로 들어온다.

“사과를 먹었다”라는 문장이 귀에 한 번에 들어오는 것이 아니다. 시간에 따라 변하는 음압의 패턴이 연속적으로 들어온다.

청각정보는 달팽이관에서 시작해 뇌간의 여러 청각핵, 중뇌의 하구(inferior colliculus), 시상의 내측슬상체(medial geniculate body)를 거쳐 측두엽의 일차청각피질(primary auditory cortex)에 도달한다.

이 과정에서 주파수, 강도, 시간차, 위치와 같은 음향정보가 여러 단계에서 분석된다.

그리고 언어 네트워크로 들어가면서 물리적 소리는 점차 언어적 구조로 변환된다.

음향패턴

음성특징

음소·음절

단어

구문관계

의미와 맥락

베르니케와 브로카 영역은 두 개의 독립된 언어센터가 아니다

고전 신경학에서는 베르니케 영역(Wernicke's area)을 언어 이해, 브로카 영역(Broca's area)을 언어산출의 중심으로 설명했다.

병변 신경학의 역사에서는 매우 중요한 모델이지만, 현대 언어신경과학에서 언어는 훨씬 넓은 네트워크 기능으로 이해된다.

왼쪽 하전두회의 덮개부분(pars opercularis)은 음운처리, 조음과 관련된 운동계획, 구문처리 등에 비교적 강하게 관여하고, 삼각부분(pars triangularis)은 어휘와 의미선택, 경쟁하는 의미의 조절 등에 더 관여하는 경향이 있다.

측두엽에서는 말소리, 어휘, 개념적 의미와 관련된 다양한 계산이 분산되어 이루어진다.

따라서 언어는 소리·음운·어휘·의미·구문·운동이 연결된 측두-전두 네트워크의 기능으로 보는 편이 정확하다.

언어의 본질은 단순한 순서가 아니라 구조화된 순서다

“개가 사람을 물었다”와 “사람이 개를 물었다”는 같은 단어를 써도 배열이 달라지면 의미가 바뀐다.

그래서 언어에는 분명 시퀀스(sequence)가 중요하다.

그러나 인간 언어는 단순한 단어 순서 이상의 계산을 한다.

어떤 단어가 어떤 단어에 종속되는지, 어떤 구가 더 큰 구 안에 포함되는지, 주어와 술어가 어떤 관계를 이루는지를 표현하는 계층구조(hierarchical structure)가 필요하다.

언어의 중요한 계산

시퀀스 + 관계 + 계층구조

이 원리는 언어를 넘어 인간의 고등사고 전체로 확장된다.

인간은 단순히 A 다음 B를 기억하는 것이 아니다. A가 B의 원인이고, B가 C가 일어나기 위한 조건이며, 상황이 달라지면 B 대신 다른 행동을 해야 한다는 관계를 구성한다.

즉 인간 사고는 순서 안에 인과, 조건, 규칙, 계층을 삽입한다.

생각은 언어와 같지 않지만, 언어는 생각의 구조를 크게 확장한다

인간은 많은 생각을 말이나 문장으로 표현하기 때문에 생각 자체가 문장으로 이루어졌다고 느끼기 쉽다.

하지만 모든 사고가 언어는 아니다.

공간탐색, 얼굴인식, 운동계획, 음악적 예측, 시각심상, 수량판단은 완성된 문장을 만들지 않아도 가능하다.

그럼에도 언어는 인간 사고의 범위를 크게 넓힌다.

언어를 사용하면 지금 눈앞에 없는 대상, 과거 사건, 아직 일어나지 않은 미래, 가상의 상황, 추상적인 규칙을 명시적으로 다룰 수 있다.

이런 능력을 탈맥락화(decontextualization)라는 관점에서 볼 수 있다. 현재의 감각환경에 묶이지 않고 정보를 다룰 수 있다는 뜻이다.

인간 언어의 진화를 특정 하나의 발화형태에서 시작했다고 단정하기는 어렵다. 발성, 사회적 의사소통, 상징사용, 공동주의(joint attention), 계층적 조합능력 등이 오랜 진화과정에서 함께 변화했다고 보는 편이 적절하다.

전전두피질의 핵심은 ‘생각 저장’이 아니라 현재 문제를 조직하는 것이다

전두엽을 흔히 ‘생각하는 곳’이라고 부르지만, 생각이 전두엽 안에 저장되어 있다는 뜻은 아니다.

특히 배외측 전전두피질(dorsolateral prefrontal cortex, DLPFC)과 두정피질이 참여하는 전두-두정 네트워크(frontoparietal network)는 현재 과제를 해결하는 데 필요한 정보를 유지하고 조절하는 데 중요하다.

작업기억은 ‘잠깐 저장’보다 ‘유지하며 조작’하는 능력이다

작업기억(working memory)을 단순한 단기기억으로 이해하면 핵심이 빠진다.

중요한 것은 필요한 정보를 잠시 유지하면서 현재 목적에 맞게 그 정보를 조작한다는 점이다.

예를 들어 어떤 숫자 배열을 들은 뒤 역순으로 말해야 한다면, 정보를 기억하면서 동시에 배열을 바꿔야 한다.

이때 전전두피질과 두정피질이 강하게 협력한다.

구성적 사고(constructive thinking)를 신경과학적으로 풀면

기억과 현재 입력에서 필요한 요소를 꺼내고, 그 요소를 작업기억 안에 유지하면서 관계를 새롭게 배치해 현재 문제에 맞는 내부 모델을 구성하는 과정이라고 할 수 있다.

이런 재구성 능력 자체가 오직 인간에게만 존재하는 것은 아니다. 하지만 인간에서는 언어, 장기계획, 추상규칙과 결합해 압도적으로 복잡한 수준까지 확장되어 있다.

전두극피질은 더 긴 시간척도의 목표를 관리한다

전전두피질의 가장 앞쪽에 있는 전두극피질(frontopolar cortex)은 현재 행동을 넘어선 미래 목표, 여러 과제 사이의 관계, 아직 실행하지 않은 의도를 유지하는 데 관여한다.

책을 읽으면서도 “조금 뒤에 해야 할 일이 있다”는 사실을 유지하는 것이 대표적이다.

이런 기능을 전향기억(prospective memory)과 연결해 이해할 수 있다.

즉 인간은 지금 수행하는 행동뿐 아니라 서로 다른 시간척도의 목표를 동시에 관리한다.

동기는 하나의 ‘의지 중추’가 아니라 가치·노력·확률의 계산이다

행동을 시작하려면 단순히 ‘하고 싶은 느낌’만 필요한 것이 아니다.

뇌는 얻을 수 있는 보상, 필요한 노력, 성공 가능성, 시간비용, 다른 선택지를 함께 평가해야 한다.

여기에는 복내측 전전두피질(ventromedial prefrontal cortex, vmPFC), 안와전두피질(orbitofrontal cortex, OFC), 전방 대상피질(anterior cingulate cortex, ACC), 복측선조체(ventral striatum), 중뇌 도파민계가 중요하게 관여한다.

동기를 계산의 관점에서 보면

“얼마나 하고 싶은가?”만의 문제가 아니라
“이 행동을 지금 실행하는 것이 가치가 있는가?”를 평가하는 과정이다.

발달하면서 행동이 점차 장기적이고 목표지향적으로 변하는 것도 전전두피질과 기저핵, 보상계가 성숙하고, 경험을 통해 행동의 결과를 더 잘 예측하게 되기 때문이다.

운동은 생각의 마지막 출력이 아니라 예측과 피드백의 반복이다

운동을 ‘생각한 뒤 근육에 명령을 보내는 것’으로만 이해하면 운동제어의 가장 중요한 부분을 놓친다.

컵을 잡는 동안에도 뇌는 계속 정보를 받는다. 컵이 예상보다 무겁다면 힘을 높이고, 미끄러지기 시작하면 손가락의 압력을 조절한다.

행동목표

운동계획

운동 실행

감각 피드백

예측오차

운동 수정

이런 형태를 폐쇄루프 제어(closed-loop control)라고 한다.

일차운동피질은 정교한 수의운동 출력에 중요하다

일차운동피질(primary motor cortex, M1)은 피질척수로(corticospinal tract)를 통해 척수 운동계에 강한 영향을 주며, 특히 손과 손가락처럼 정밀한 수의운동에 중요하다.

하지만 운동피질을 근육 하나씩 켜고 끄는 버튼판이라고 생각하면 부정확하다.

운동피질의 활동은 여러 근육이 함께 만드는 움직임의 방향, 힘, 협응과 연관되어 있다.

전운동피질과 보조운동영역은 움직임의 구조를 준비한다

전운동피질(premotor cortex)보조운동영역(supplementary motor area, SMA)은 실제 움직임이 일어나기 전에 운동을 준비하고 조직하는 데 중요하다.

외부 단서에 맞춰 어떤 동작을 선택할지, 여러 동작을 어떤 순서로 연결할지, 양손을 어떻게 협응할지 등이 이 계통과 연결된다.

기저핵은 어떤 행동을 실행할지를 조절한다

기저핵(basal ganglia)은 선조체(striatum), 담창구(globus pallidus), 시상하핵(subthalamic nucleus), 흑질(substantia nigra) 등을 포함한다.

기저핵은 단순한 운동기관이 아니다.

여러 가능한 행동 가운데 어떤 행동을 촉진하고 어떤 행동을 억제할 것인지를 조절하는 데 중요하다.

반복되는 행동이 습관화되고 잘 학습된 행동 시퀀스가 효율적으로 실행되는 과정에도 깊게 관여한다.

소뇌는 예측과 실제 결과의 차이를 이용한다

소뇌(cerebellum)는 균형만 담당하는 구조가 아니다.

운동명령이 나갈 때 신경계는 이 명령을 실행했을 때 어떤 감각결과가 생길지 예측한다.

이를 전향모델(forward model)과 연결해 설명한다.

실제 움직임에서 돌아온 감각정보와 예측 사이에 차이가 있으면, 그 오차를 이용해 다음 움직임을 수정한다.

숙련의 본질

숙련은 근육이 단순히 강해지는 것이 아니다.
행동 결과를 더 정확하게 예측하고, 오차를 더 작고 빠르게 수정할 수 있도록 내부 모델이 조정되는 과정이다.

힘을 느끼는 감각과 균형회복도 하나의 영역에서 만들어지지 않는다

자신이 얼마나 힘을 주고 있는지 느끼는 경험을 하나의 독립된 ‘힘 감각 영역’으로 보는 것은 현대 신경과학의 표준적인 설명이 아니다.

근육과 관절에서 올라오는 고유수용감각(proprioception), 운동명령에 관한 원심성 사본(efference copy), 심박·호흡·피로와 관련된 내수용감각(interoception), 실제 운동 결과가 함께 결합된다.

따라서 노력감이나 힘의 감각은 운동명령과 신체 피드백을 비교해 만들어지는 복합적인 경험에 가깝다.

넘어질 때 몸을 회복시키는 반응도 특정 ‘반사 영역’ 하나의 기능이 아니다.

내이의 전정기관(vestibular apparatus)이 머리의 회전과 선형가속도를 감지하고, 뇌간의 전정핵과 전정척수로(vestibulospinal tract), 망상척수로(reticulospinal tract)가 빠른 자세조절에 관여한다.

소뇌는 움직임을 정밀하게 조절하고, 더 느린 시간대에는 기저핵과 대뇌피질이 발을 내딛거나 손을 뻗는 행동을 선택한다.

같은 행동에서도 서로 다른 시간척도의 회로가 겹쳐 작동한다는 점이 중요하다.

숙련되면 긴 행동은 ‘청크’로 압축된다

피아노를 처음 배울 때는 손가락 하나하나를 의식적으로 선택한다.

하지만 반복연습이 충분히 이루어지면 여러 동작이 하나의 행동단위처럼 실행된다.

이를 운동 청크(motor chunk)라고 한다.

숙련자가 빠른 이유는 모든 세부동작을 더 빨리 생각하기 때문이 아니다.

여러 동작이 하나의 묶음으로 압축되어 불러와질 수 있기 때문이다.

이런 자동화와 시퀀스 학습에는 전운동피질, 보조운동영역, 기저핵, 운동피질, 소뇌가 함께 관여한다.

인간 지능의 중요한 특징은 ‘구조화된 시퀀스’를 다룬다는 데 있다

시퀀스는 뇌의 여러 기능을 관통한다.

말은 시간에 따라 전개되고, 운동은 순서대로 실행되며, 사건기억 역시 시간구조를 가진다.

그러나 인간의 고등사고를 ‘순서를 길게 기억하는 능력’으로 설명하면 부족하다.

인간은 A 다음 B를 기억하는 데서 그치지 않는다.

A가 B의 원인이고, B는 C가 일어나기 위한 조건이며, 상황이 바뀌면 다른 규칙을 적용해야 한다는 구조를 만든다.

그래서 더 중요한 개념이 구조화된 시퀀스(structured sequence)다.

즉 순서 안에 관계, 인과, 조건, 계층이 들어간다.

행동도 계층구조를 가진다

커피를 만드는 행동은 ‘물을 끓인다 → 커피를 넣는다 → 물을 붓는다’라는 단순한 긴 문자열이 아니다.

‘커피 만들기’라는 상위 목표 아래 ‘물 끓이기’, ‘컵 준비하기’, ‘추출하기’ 같은 하위 목표가 있고, 각 하위 목표 안에 다시 작은 행동들이 들어 있다.

상위 목표

하위 목표

세부 행동

실제 운동

인간이 집을 짓고, 프로그램을 만들고, 과학실험을 수행할 수 있는 이유도 이와 관련된다.

수백 개의 행동을 일렬로 외우는 것이 아니라 복잡한 목표를 여러 수준의 하위 목표로 나누고, 필요할 때 구조를 수정할 수 있기 때문이다.

기억 역시 과거의 사진보다 사건의 구조다

해마는 장면을 사진처럼 저장하는 장치가 아니다.

아침에 일어나고, 학교에 가고, 친구를 만나고, 수업을 듣고, 집에 돌아온 사건이 ‘하루’라는 시간적 구조 안에서 관계를 가진다.

흥미로운 점은 과거를 재구성하는 회로가 미래를 상상할 때도 상당 부분 동원된다는 것이다.

미래를 계획하려면 과거 경험의 요소를 꺼내 새로운 조합을 만들어야 하기 때문이다.

따라서 기억은 단순히 과거를 보존하는 기능이 아니라 미래를 시뮬레이션하는 재료를 제공하는 시스템이기도 하다.

글쓰기는 생각을 외부로 꺼내 구조를 다시 조작하게 만든다

글쓰기는 단순히 말을 문자로 옮기는 작업이 아니다.

기억에서 필요한 내용을 꺼내고, 중요한 정보만 선택하고, 앞 문장의 의미를 유지하고, 다음 문장과의 논리적 관계를 만들고, 전체 구조를 다시 점검해야 한다.

즉 언어계, 기억계, 전두-두정 인지통제계가 동시에 참여한다.

그런데 글쓰기가 사고에 미치는 더 중요한 효과가 있다.

생각을 뇌 밖으로 꺼낼 수 있다는 것이다.

작업기억의 용량은 제한적이다. 머릿속에 모든 요소를 동시에 유지하려 하면 구조가 복잡해질수록 한계에 부딪힌다.

하지만 종이나 화면에 적으면 이미 적힌 내용을 다시 보고, 다른 문장과 비교하고, 순서를 바꾸고, 전체 관계를 다시 구성할 수 있다.

종이나 화면은 일종의 외부 작업기억(external working memory)으로 기능한다.

그래서 글쓰기는 생각을 기록하는 수단인 동시에 생각의 구조 자체를 조작하는 인지 도구다.

이 모든 고등기능은 결국 뉴런의 전기·화학 과정으로 구현된다

공간기억, 언어, 계획, 행동은 매우 추상적으로 보인다. 하지만 그 아래에는 실제 세포막과 이온, 단백질, 시냅스가 있다.

뉴런 안과 밖에는 나트륨 이온 Na⁺, 칼륨 이온 K⁺ 등 여러 이온의 농도차가 존재한다.

세포막의 선택적 투과성과 이온통로, 나트륨-칼륨 펌프 등의 작용으로 휴지막전위(resting membrane potential)가 형성된다.

다른 뉴런의 입력은 작은 막전위 변화부터 만든다

앞 뉴런에서 방출된 신경전달물질이 다음 뉴런의 수용체에 결합하면 특정 이온통로가 열리거나 닫힌다.

그 결과 막전위가 조금 변한다. 이를 시냅스후전위(postsynaptic potential)라고 한다.

뉴런은 이 입력을 단순히 ‘있다/없다’로만 처리하지 않는다.

입력이 언제 들어왔는지, 수상돌기의 어느 위치에 들어왔는지, 흥분성인지 억제성인지, 여러 입력이 얼마나 가까운 시간에 들어왔는지를 통합한다.

따라서 뉴런 하나도 이미 시간적·공간적 신호 통합장치다.

임계값을 넘으면 활동전위가 발생한다

축삭 초기분절(axon initial segment)의 막전위가 임계값을 넘으면 전압개폐성 나트륨 통로가 빠르게 열리면서 Na⁺가 유입된다.

막전위가 급격히 상승하는 과정을 탈분극(depolarization)이라고 한다.

곧이어 나트륨 통로가 불활성화되고 칼륨 통로가 열리면서 K⁺가 세포 밖으로 이동한다. 막전위가 다시 내려오는 과정이 재분극(repolarization)이다.

이렇게 만들어지는 빠른 전기적 사건이 활동전위(action potential)다.

활동전위가 축삭말단에 도착하면 전압개폐성 칼슘 통로가 열리고, Ca²⁺의 유입이 시냅스 소포의 융합과 신경전달물질 방출을 유도한다.

즉 많은 화학적 시냅스에서 전기적 신호가 화학적 신호로 바뀌고, 다음 뉴런에서 다시 전기적 상태변화로 바뀐다.

수초는 전달속도뿐 아니라 네트워크의 시간정밀도에도 중요하다

축삭을 둘러싼 수초(myelin)는 전기적 절연체 역할을 한다.

활동전위는 랑비에 결절(Node of Ranvier)을 중심으로 재생되며, 이를 도약전도(saltatory conduction)라고 한다.

이 구조 덕분에 긴 축삭에서도 빠르고 에너지 효율적인 신호전달이 가능하다.

하지만 고등 뇌기능에서 중요한 것은 ‘빠름’만이 아니다.

서로 다른 회로의 신호가 적절한 시간차를 두고 도착해야 한다. 몇 밀리초의 차이도 네트워크의 동기화와 상호작용에 의미를 가질 수 있다.

뇌는 단순히 빠른 회로가 아니라 시간관계가 정밀하게 조율된 회로다.

생각과 기억은 활동전위 하나나 뉴런 하나에 들어 있지 않다

모든 뉴런이 기본적으로 활동전위를 사용한다고 해서 뇌의 정보가 단순한 펄스의 순서만으로 표현되는 것은 아니다.

어떤 뉴런이 활성화되는지, 얼마나 자주 발화하는지, 정확히 언제 발화하는지, 여러 뉴런이 어떤 집단 패턴을 만드는지가 함께 중요하다.

여기에 발화율(firing rate), 발화시점(spike timing), 집단 부호(population coding), 신경진동의 위상, 시냅스 강도, 도파민과 아세틸콜린 같은 신경조절계가 함께 작용한다.

따라서 생각 하나가 뉴런 하나에 들어 있는 것도 아니고, 기억 하나가 특정 피질영역에 파일처럼 저장되어 있는 것도 아니다.

인지적 내용은 분산된 뉴런 집단의 활동상태와 연결구조에서 나타난다.

학습은 정보를 ‘넣는 것’보다 회로의 다음 상태를 바꾸는 것이다

학습을 컴퓨터 파일 저장에 비유하면 직관적으로는 편하지만, 실제 뇌의 작동과는 차이가 있다.

반복 경험이 일어나면 뉴런 사이의 시냅스 효율이 변한다. 일부 연결은 강해지고, 일부는 약해지며, 구조적 연결 자체가 재편되기도 한다.

대표적인 기전이 장기강화(long-term potentiation, LTP)장기억제(long-term depression, LTD)다.

학습을 가장 본질적으로 표현하면

정보를 어떤 곳에 집어넣는 것이 아니라, 어떤 신경상태가 다음 신경상태를 얼마나 쉽게 만들어내는지를 바꾸는 과정이라고 할 수 있다.

그래서 구조화된 지식이 기억에 강하다

서로 관련 없는 사실을 여러 개 암기하는 것보다 인과관계로 묶어 이해하면 기억이 훨씬 안정된다.

예를 들어 수초, 전류누설, 랑비에 결절, 도약전도를 독립된 사실로 외우는 것보다

수초 형성

막을 통한 전류누설 감소

결절 중심의 활동전위 재생

도약전도

빠르고 효율적인 축삭전도

라는 구조로 이해하면 한 개념이 다음 개념을 불러오는 검색단서가 된다.

그래서 지식이 구조화되었다는 말은 단순히 정리가 잘됐다는 뜻이 아니다.

한 개념에서 다른 개념으로 도달할 수 있는 연결경로가 많아졌다는 뜻이다.

단백질과 DNA는 이 모든 계산의 물질적 조건을 만든다

아무리 추상적인 사고라도 결국은 생물학적 조직인 뇌에서 일어난다.

이온통로, 수용체, 효소, 세포골격, 신경전달물질의 합성과 분해에 관여하는 단백질, 시냅스 구조를 유지하고 변화시키는 단백질은 모두 신경기능에 필수적이다.

DNA는 이러한 단백질과 세포의 발달·조절에 필요한 유전정보를 담고 있다.

하지만 DNA가 진화의 역사를 연대기처럼 그대로 저장하고 있다거나, 사람마다 약물반응이 다른 이유가 단백질 서열 차이 하나 때문이라고 말하면 지나치게 단순해진다.

현재 인간의 신경계는 돌연변이, 자연선택, 유전자 중복, 유전자 발현조절 변화 등 긴 진화과정의 결과다.

약물반응 역시 유전변이뿐 아니라 약물대사 효소, 수용체 발현, 간과 신장 기능, 나이, 환경, 다른 약물과의 상호작용이 함께 결정한다.

다만 한 가지는 분명하다.

언어와 기억과 생각은 생물학적 물질과 분리된 별도의 현상이 아니다.

이온통로와 수용체, 유전자 발현, 시냅스 단백질, 세포대사의 물질적 과정 위에서 신경회로가 작동하고, 그 집단활동에서 우리가 인지라고 부르는 현상이 나타난다.

주요 뇌 영역을 ‘기능 흐름’ 안에서 보면

영역 핵심 계산 전체 흐름에서의 의미
일차시각피질 초기 시각특징 처리 빛의 공간패턴을 피질이 사용할 특징으로 변환
복측 시각경로 객체·정체성 표상 ‘무엇인가’를 구성
후두정피질 공간 좌표변환 시각을 행동 가능한 공간으로 변환
해마 관계적·일화적 기억 현재 경험을 장소·시간·사건의 구조로 묶음
내후각피질 공간 위치·이동 표상 공간탐색을 위한 좌표계 제공
후방비장피질 방향과 좌표계 연결 현재 시야와 기억된 공간을 연결
일차청각피질 기본 음향특징 분석 물리적 소리를 피질표상으로 변환
측두-전두 언어 네트워크 음운·어휘·구문·의미 소리를 구조화된 언어로 변환
배외측 전전두피질 작업기억·인지통제 필요한 정보를 유지하고 재구성
전두극피질 미래 목표·관계 통합 여러 시간척도의 목표를 관리
전운동피질·보조운동영역 운동 준비·시퀀스 구성 선택된 목표를 실제 동작구조로 변환
일차운동피질 정교한 수의운동 출력 운동계획을 하행성 운동신호로 연결
기저핵 행동 선택·억제·습관 여러 행동후보 중 실행할 행동을 조절
소뇌 예측·오차수정 행동 결과를 이용해 다음 행동을 정밀화

전체를 하나의 기능 구조로 연결하면

이제 공간, 이미지, 언어, 계산, 사고, 동기, 운동, 학습을 하나의 흐름 안에서 볼 수 있다.

감각 입력

특징 추출과 신경표상

객체·공간·언어구조의 구성

기억과 현재 맥락의 결합

목표와 행동가치 평가

행동 선택과 계층적 계획

운동 실행

감각 피드백과 예측오차

학습과 회로 변화

이 흐름에서 시각은 단순한 입력장치가 아니다.

기억도 저장창고가 아니고, 전두엽도 생각이 들어 있는 장소가 아니다.

기저핵은 단순한 운동기관이 아니며, 소뇌 역시 단순한 균형기관이 아니다.

각 시스템은 앞 단계에서 만들어진 정보를 다음 계산이 사용할 수 있는 형태로 다시 변환한다.

인간 지능의 핵심을 한 문장으로 정리하면
시간적으로 전개되는 감각과 사건을 공간·관계·인과·계층을 가진 내부 모델로 만들고, 그 모델을 현재 목표에 맞게 유지하고 재구성하며, 아직 일어나지 않은 미래를 예측해 행동을 조직하는 능력이라고 할 수 있다.

인간은 단순히 긴 시퀀스를 기억하는 존재가 아니다.

시퀀스 자체를 사고의 대상으로 삼고, 여러 시퀀스를 하나의 상위 목표 아래 묶고, 상황이 달라지면 일부 구조를 다른 구조로 교체하며, 아직 일어나지 않은 행동을 머릿속에서 미리 시뮬레이션할 수 있다.

공간탐색, 언어, 글쓰기, 수학, 도구제작, 과학적 추론이 겉으로는 전혀 다른 능력처럼 보이면서도 깊은 수준에서 공통된 신경계 원리를 공유하는 이유가 여기에 있다.

결국 뇌를 이해한다는 것은 각 영역의 이름을 많이 외우는 것이 아니다.

감각이 어떻게 내부 표상이 되고,
그 표상이 어떻게 기억과 의미를 만나며,
기억과 의미가 어떻게 목표와 행동으로 이어지고,
행동의 결과가 어떻게 다시 뇌의 회로를 바꾸는지를 이해하는 것이다.

뇌의 진짜 기능적 구조는 ‘영역들의 목록’이 아니라 정보가 계속 다른 형태로 변환되며 순환하는 과정 그 자체에 있다.

모델보다 중요한 것은 모델을 둘러싼 실행 구조다

RAG에서 MCP·Harness·Loop·Orchestration까지, 실제 업무를 맡길 수 있는 Agent Runtime을 설계하는 법

 

Agent를 오래 만들수록 이상한 장면을 자주 보게 된다. 모델은 분명 좋아졌는데, 서비스의 신뢰성은 그만큼 좋아지지 않는다. 짧은 답변은 놀라울 정도로 좋아졌지만 작업이 길어지면 이미 읽은 파일을 다시 찾고, 실패한 테스트를 놓치고, 같은 도구를 반복 호출하고, 때로는 “명령이 실행됐다”는 사실을 “업무가 끝났다”는 뜻으로 착각한다.

이 문제를 프롬프트 부족으로만 보면 해결이 어렵다. 실제 업무는 한 번의 생성이 아니라 상태가 변하는 과정이기 때문이다. 무엇을 알고 있는지, 무엇을 실행했는지, 환경이 무엇을 돌려줬는지, 그 결과가 성공 조건을 만족하는지, 실패했다면 무엇을 다음 시도에 남길지까지 하나의 실행 구조로 연결되어야 한다.

Agent Engineering의 중심은 “모델에게 어떻게 잘 말할 것인가”에서 “확률적인 모델을 어떻게 관찰 가능하고, 검증 가능하고, 중단·복구 가능한 업무 시스템으로 만들 것인가”로 이동했다.

이 글의 목적은 Agent 관련 용어를 많이 소개하는 것이 아니다. Prompt, RAG, Context Engineering, LangGraph, MCP, Skills, Hooks, Memory, Multi-Agent, Human-in-the-loop, Background Agent, Loop Engineering이 왜 필요해졌고 서로 어디에 놓이는지를 하나의 Runtime 관점으로 정리하는 것이다. 이 관점을 잡으면 특정 프레임워크가 바뀌어도 설계 원리는 남는다.

이 글의 핵심을 한 문장으로 줄이면 다음과 같다.

모델은 다음 행동을 제안하는 추론 엔진이고, 실제 업무의 신뢰성은 Context·State·Tool·Permission·Verifier·Retry·Handoff·Trace를 묶는 Runtime이 만든다.

1. 기술의 역사는 모델이 아니라 제어 표면이 넓어진 역사다

초기 LLM 애플리케이션에서는 한 번의 호출이 거의 전부였다. 결과가 나쁘면 Role을 바꾸고, Few-shot 예시를 넣고, 출력 형식을 더 자세히 적었다. 이 시기의 핵심 질문은 단순했다.

Prompt Engineering(프롬프트 엔지니어링) — “이번 호출에서 모델에게 어떻게 말할 것인가?”

RAG(Retrieval-Augmented Generation, 검색 증강 생성)가 본격화되면서 질문이 달라졌다. 모델이 사내 문서나 최신 정보를 원래 학습하지 않았더라도, 호출 직전에 필요한 자료를 검색해 넣을 수 있게 됐다. 이제 품질은 프롬프트뿐 아니라 어떤 자료를 골라 Context에 넣었는지에 좌우됐다.

Context Engineering(컨텍스트 엔지니어링) — “이번 판단에 무엇을 보여줄 것인가?”

Tool Calling이 붙으면서 모델은 답변을 만드는 존재에서 환경을 바꾸는 존재가 됐다. 파일을 읽고, 웹을 검색하고, 코드를 실행하고, API를 호출하고, 데이터베이스를 조회할 수 있게 됐다. 이때부터 모델 주위에 행동 규칙과 권한, 재사용 절차, 실행 격리가 필요해졌다.

Harness Engineering(하네스 엔지니어링) — “모델이 어떤 규칙과 도구와 권한을 갖고 일하게 할 것인가?”

그리고 긴 작업에서는 한 번의 Tool Call로 끝나지 않는다. Tool 결과를 다시 읽고, 실패를 다음 상태에 넣고, 재시도하거나 사람에게 넘기고, 성공 증거가 있을 때만 멈춰야 한다.

Loop Engineering(루프 엔지니어링) — “행동 결과를 어떻게 관찰·검증·갱신하고, 언제 계속하거나 멈출 것인가?”

마지막으로 사람이 매번 호출하지 않아도 Event, Queue, Cron, Schedule에 따라 일이 시작되면 시간축을 관리하는 계층이 필요하다.

Orchestration(오케스트레이션) — “어떤 일을 언제, 어떤 Worker에게, 어떤 우선순위와 동시성으로 맡길 것인가?”

Prompt어떻게 말할까
Context무엇을 보여줄까
Harness어떻게 일하게 할까
Loop어떻게 검증·복구할까
Orchestration언제 누구에게 맡길까

여기서 중요한 것은 새 단어가 이전 기술을 없애지 않았다는 점이다. 실제 자료의 흐름도 문서 파싱과 VectorStore에서 Agentic RAG, Tool Calling, Memory, Human-in-the-loop, MCP, Multi-Agent, Harness로 넓어졌다. 하지만 문서 파싱, 평가, 추적, 배포 같은 기반 문제는 계속 남았다. Agent는 RAG를 대체하지 않고, MCP는 API 설계를 대체하지 않으며, Harness는 좋은 모델을 대체하지 않는다. 모두 더 큰 Runtime 안에서 서로 다른 실패를 해결한다.

2. 하나의 Agent Runtime으로 보면 용어가 단순해진다

제품마다 이름이 다르다. LangGraph에는 State·Node·Edge가 있고, Claude Code에는 CLAUDE.md·Skills·Hooks·Subagents가 있고, Deep Agents에는 Filesystem·Planning·Subagents가 있고, MCP에는 Tools·Resources가 있다. 기능 목록으로 외우면 금방 복잡해진다.

대신 “누가 무엇을 소유하는가”로 보면 대부분 여섯 층으로 정리된다.

Model모호한 입력을 해석하고 다음 행동 후보를 만든다. 지능의 중심이지만 시스템 전체는 아니다.
Context / State이번 판단에 필요한 Working Set과 현재 작업 상태를 구성한다.
HarnessRules, Skills, Tools, Sandbox, Hooks로 행동 방식과 권한을 규정한다.
LoopObservation을 Verifier에 연결하고 Retry·Handoff·Stop을 결정한다.
Orchestrator여러 Task와 Worker의 Queue, Schedule, 동시성, 우선순위를 관리한다.
GovernanceApproval, Audit, Version, Eval, Rollback으로 자동화의 경계를 통제한다.

이 구조에서 모델은 “무엇을 할지 생각하는 부분”에 가깝다. 하지만 실제 서비스가 안정적으로 일하려면 무엇을 기억할지, 무엇을 실행할 수 있는지, 무엇을 성공으로 인정할지, 어디서 멈출지를 다른 계층이 책임져야 한다.

그래서 Agent Architecture를 결정할 때 “최고 모델이 무엇인가?”만 묻는 것은 부족하다. 더 중요한 질문은 우리 팀이 State, Permission, Trace, Eval, Termination 중 어디까지 직접 소유할 것인가다.

3. Workflow와 Agent를 먼저 구분해야 한다

Agent의 자율성은 기능이 아니라 비용이다. 자율성이 늘면 예외 대응 능력이 좋아질 수 있지만 Tool Call 수, Latency(지연시간), Token 비용, Side Effect(외부 상태 변경), Debugging 난이도도 함께 늘어난다.

따라서 가장 먼저 해야 할 일은 “이 문제에 정말 Agent가 필요한가?”를 묻는 것이다.

WorkflowAgent
경로 코드가 미리 정의한다. 실행 중 모델이 다음 행동을 고른다.
잘 맞는 문제 정형·반복·규칙 기반 탐색형·개방형·예외가 많은 문제
장점 예측 가능, 테스트 쉬움, 저비용 환경 피드백을 보고 유연하게 복구
주요 위험 새로운 예외에 약함 비용·지연·오류 전파가 커질 수 있음
운영 핵심 분기, 에러 처리, 회귀 테스트 Verifier, Budget, Sandbox, Trace, HITL

실전에서는 둘을 섞는 경우가 많다. “장애 원인을 찾아라”는 개방형 문제이므로 모델이 조사 순서를 선택할 가치가 있다. 그러나 “Production DB 변경 전에는 승인받아라”, “테스트가 실패하면 Merge하지 마라” 같은 규칙을 모델이 매번 판단하게 할 이유는 없다.

모호함은 모델에게, 불변 규칙은 코드에게.

좋은 Agent Runtime은 모든 것을 LLM에게 넘기는 구조가 아니라, LLM이 잘하는 열린 판단과 코드가 잘하는 결정론적 제어를 의도적으로 분리한 구조다.

복잡도는 보통 다음 순서로 올리는 편이 낫다.

Single Call한 번 생성
Tool외부 기능 추가
Workflow고정된 제어 흐름
Eval + Retry검증 후 재시도
Bounded Agent제한된 자율 Loop

4. Context는 저장소가 아니라 지금 추론하는 Working Set이다

긴 Agent 작업에서 가장 먼저 무너지는 것은 추론 능력보다 Context인 경우가 많다. 처음에는 사용자 목표와 관련 파일 몇 개뿐이지만, 시간이 지나면 검색 결과, Shell 출력, 과거 실패, 테스트 로그, Tool 정의, Memory, Subagent 결과가 계속 붙는다.

“Context Window가 크면 전부 넣으면 되지 않을까?”라는 생각이 자연스럽지만, 실제로는 그렇지 않다. Context는 장기 저장소가 아니라 다음 결정을 위해 지금 읽는 작업 메모리다. 오래된 정보와 중복 로그가 늘어날수록 중요한 신호의 밀도가 떨어진다.

Always-on과 On-demand를 분리한다

Always-on보안 규칙, 금지된 경로, 코드 Convention, 필수 테스트, Source of Truth 위치처럼 항상 필요한 계약
On-demandDB Migration Runbook, 특정 Framework 사용법, PDF 처리 절차, 특정 고객 정책처럼 상황이 맞을 때만 필요한 지식

이 패턴을 Progressive Disclosure(점진적 공개)라고 이해하면 쉽다. “이런 Skill이 존재한다”는 짧은 설명은 알려주되, 전체 절차와 Reference는 실제로 필요할 때만 Context에 넣는다.

Context Engineering은 네 동작으로 생각하면 된다

Write — 나중에도 필요한 Plan·Decision·Evidence를 외부 State나 파일로 내린다.

Select — 이번 Step에 필요한 정보만 다시 선택한다.

Compress — 긴 History와 Tool Output을 Summary·Checkpoint로 압축한다.

Isolate — 독립 작업을 별도 Context의 Subagent/Worker로 분리한다.

이 네 가지는 “Context를 많이 확보하는 기술”이 아니라 다음 판단에 필요한 정보 밀도를 높이는 기술이다.

5. RAG의 품질은 Retriever보다 앞단에서 이미 결정되기 시작한다

업로드된 2024년 Parser 자료와 실제 코드가 보여주는 중요한 교훈이 있다. PDF를 “긴 문자열 하나”로 보는 순간 RAG는 이미 정보를 잃을 수 있다.

실제 문서는 Paragraph(문단), Heading(제목), Table(표), Figure(도형/이미지), Chart(차트), Caption(설명), Header/Footer(머리말/꼬리말)가 섞여 있다. 샘플로 포함된 21페이지 시장 보고서도 한 페이지에 시장 코멘터리, 가격표, 시계열 그래프, 지역별 구분이 함께 들어간다. 이런 문서를 텍스트만 일렬로 이어 붙이면 표의 행·열 관계, 차트의 의미, 페이지 출처, 요소의 역할이 사라질 수 있다.

따라서 실전 문서 파이프라인은 다음에 가깝다.

Parse요소 단위 추출
NormalizeText·Table·Image 정규화
Provenancepage·source·element id
IndexChunk·Metadata
Retrieve검색·재정렬
Context Pack이번 질문용 Working Set

업로드된 export.py도 이 구조를 잘 보여준다. Figure·Chart·Table은 이미지 Artifact로 저장하고, HTML에는 Base64 이미지를 삽입하며, Markdown에서는 이미지 경로와 Table Markdown을 남기고, Table은 별도 CSV로도 변환한다. 핵심은 “한 가지 출력 포맷”이 아니라 원본 구조를 여러 검증 가능한 Artifact로 보존한다는 점이다.

현업에서는 Element Schema부터 명확하게 잡는다

문서 파싱 결과를 RAG와 Trace가 함께 쓸 수 있게 정규화하는 예시

from __future__ import annotations

from dataclasses import dataclass
from enum import StrEnum
from pathlib import Path


class ElementKind(StrEnum):
    TEXT = "text"
    TABLE = "table"
    IMAGE = "image"
    CHART = "chart"


@dataclass(frozen=True)
class DocumentElement:
    # 어떤 문서의 어떤 요소인지 추적할 수 있어야 한다.
    source_id: str
    page: int
    element_id: str
    kind: ElementKind

    # 검색에 사용할 의미 표현.
    # 표라면 표의 제목/요약, 이미지라면 이미지 설명이 들어갈 수 있다.
    text_for_retrieval: str

    # 실제 답변에 사용할 상세 Artifact.
    markdown: str | None = None
    artifact_path: Path | None = None


@dataclass(frozen=True)
class ContextItem:
    text: str
    citation: str


def to_context_item(element: DocumentElement) -> ContextItem:
    """
    Retriever가 찾은 결과를 LLM Context에 넣기 직전 변환한다.

    중요한 점:
    - 내용만 보내지 않고 provenance(출처 정보)를 함께 보낸다.
    - source/page/element_id가 있어야 이후 Citation과 Eval이 가능하다.
    """
    if element.kind == ElementKind.TABLE and element.markdown:
        body = element.markdown
    else:
        body = element.text_for_retrieval

    citation = (
        f"{element.source_id}"
        f"#page={element.page}"
        f"&element={element.element_id}"
    )

    return ContextItem(
        text=body,
        citation=citation,
    )


sample = DocumentElement(
    source_id="market-report-2024-03-22",
    page=1,
    element_id="price-table-01",
    kind=ElementKind.TABLE,
    text_for_retrieval="지역별 제품 가격 범위를 정리한 표",
    markdown="| region | low | high |\n|---|---:|---:|\n| A | 100 | 110 |",
)

item = to_context_item(sample)

print(item.text)
print(item.citation)

# 예상 결과
# | region | low | high |
# |---|---:|---:|
# | A | 100 | 110 |
#
# market-report-2024-03-22#page=1&element=price-table-01

이 코드는 Embedding 모델을 보여주려는 예제가 아니다. 더 본질적인 포인트는 검색 결과와 출처를 분리하지 않는 것이다. Citation을 답변 마지막에 억지로 붙이는 것이 아니라, Retrieval 단계부터 Source·Page·Element ID를 데이터 구조에 포함한다.

Dense, Sparse, Hybrid, Reranker는 서로 경쟁하는 기술이 아니다

방식왜 쓰는가주요 설계값
Dense Retrieval
의미 기반 검색
표현이 달라도 의미가 비슷한 문서를 찾는다. Embedding model, top-k, threshold
Sparse / Keyword
키워드 검색
제품명, 코드, 법령 조항처럼 정확한 문자열이 중요할 때 강하다. Tokenizer, BM25 계열 점수
Hybrid
혼합 검색
의미와 정확 키워드를 함께 놓치지 않기 위해 결합한다. 가중치, fusion 방식
Reranker
재정렬기
1차 검색 후보를 더 비싼 모델로 정밀 재평가한다. candidate 수, final top-k
Parent-child
부모-자식 청크
작은 청크로 정확히 찾고, 큰 부모 Context로 의미를 복구한다. child size, parent boundary

좋은 RAG는 “Vector DB를 썼다”가 아니라 어떤 종류의 정보 손실을 어떤 단계에서 막았는지 설명할 수 있는 시스템이다.

6. Memory, State, Skill을 같은 저장소로 생각하면 구조가 꼬인다

세 개는 모두 “기억하는 것”처럼 보이지만 저장하는 대상이 다르다.

개념질문예시
State
상태
지금 이 실행은 어디까지 왔는가? attempt=2, last_failed_check="reconciliation"
Memory
기억
과거 실행이나 사용자에게서 무엇을 배웠는가? 이 Repository는 Python 3.13을 사용한다.
Skill
절차적 능력
이 종류의 일을 어떻게 반복 수행하는가? Migration 사전 점검 → dry-run → 검증 → 승인

State를 장기 Memory처럼 쌓으면 실행이 비대해지고, Memory에 매 Step의 로그를 저장하면 잡음이 쌓인다. 반대로 반복 절차를 Memory에 흩어놓으면 조직이 가진 방법론을 재사용하기 어렵다.

장기적으로 조직의 차별화가 쌓이는 곳은 모델 이름보다 Skill, Tool Contract, Eval Set, Runbook인 경우가 많다. 모델은 여러 회사가 비슷하게 사용할 수 있지만 “우리 조직은 이 상황에서 무엇을 확인하고 무엇을 금지하며 어떤 Evidence가 있어야 승인하는가”는 고유한 운영 지식이기 때문이다.

7. Harness는 모델 주변의 코드가 아니라 팀의 일하는 방식을 코드화한 것이다

Agent Harness(에이전트 하네스)는 모델이 장시간 실제 작업을 할 수 있도록 입력, 도구, 상태, 권한, 실행 환경, 검증을 모델 바깥에서 관리하는 계층이다.

구성 요소본질현업 예
Rules / Instructions 항상 지켜야 할 불변 계약 코딩 규칙, 금지 경로, 테스트 기준
Skills 필요할 때 불러오는 재사용 절차 incident-triage, release-review
Tools / MCP 외부 세계에 대한 Capability GitHub, DB, Monitoring, Search
Hooks / Middleware Lifecycle에 삽입하는 결정론적 Gate 권한 검사, Audit, Lint
Sandbox 실패의 피해 반경 제한 Container, Worktree, Network 제한
Subagents 별도 Context를 가진 독립 Worker 대규모 코드 조사, 병렬 리서치

좋은 Skill은 “전문가 역할”보다 실행 계약에 가깝다

“당신은 SRE 전문가입니다”는 역할을 설명하지만 작업을 운영 가능하게 만들지는 않는다. 실무 Skill에는 사용 조건, 입력, 작업 순서, 완료 조건, 실패 처리, 권한 경계가 있어야 한다.

Claude Code의 현재 SKILL.md 형식을 응용한 운영 점검 Skill 예시

---
name: incident-triage
description: 배포 직후 오류율이 증가했을 때 원인 후보와 재현 증거를 수집한다.
allowed-tools: Read Grep Glob Bash
---

# 사용 조건
배포 직후 error rate 또는 latency가 기준선을 벗어난 경우 사용한다.

# 절차
1. 이상 징후가 시작된 시각을 확정한다.
2. 같은 시간대의 배포/feature flag 변경을 확인한다.
3. 상위 error signature를 추출한다.
4. 최근 변경과 error signature의 연관성을 조사한다.
5. 가능하면 staging에서 재현한다.
6. 원인 후보뿐 아니라 반증 근거도 함께 기록한다.

# 완료 조건
- 원인 후보와 evidence id가 연결되어 있다.
- 재현 명령 또는 재현 불가 이유가 남아 있다.
- production write가 필요하면 직접 실행하지 않고 Human Review로 넘긴다.

여기서 중요한 것은 문서 형식이 아니라 절차를 버전 관리 가능한 Runtime 자산으로 바꿨다는 것이다. 현재 Claude Code의 Skill은 본문을 실제 사용 시 로드하기 때문에 항상 필요한 CLAUDE.md와 조건부 절차를 분리하는 Progressive Disclosure에도 잘 맞는다.

Hook은 확률적인 지시를 결정론적인 Gate로 바꾼다

Prompt에 “테스트를 꼭 실행하세요”라고 적는 것은 모델이 따를 확률을 높인다. Tool 실행 뒤 Hook에서 테스트를 실행하도록 만드는 것은 특정 시점에 코드가 반드시 실행되도록 한다.

PreToolUse — Tool 실행 전에 인자·권한·Scope를 검사한다.

PostToolUse — Tool 실행 결과를 정규화하거나 Audit Log를 남긴다.

PreCompact — Context 압축 전에 중요한 Decision·Evidence를 외부 State로 보존한다.

Guardrail은 위험한 행동과 가까운 곳에 둔다.

“DB를 함부로 수정하지 마”를 상위 Agent Prompt 한 줄에만 두는 것보다 실제 DB Write Tool 직전에 Tenant, Row 범위, 승인 토큰을 검사하는 편이 강하다.

8. Tool은 기능이 아니라 Capability + Permission + Context Contract다

Tool을 단순히 “모델이 호출하는 함수”라고 보면 설계가 넓어지기 쉽다. 실무에서 Tool은 세 가지 계약을 동시에 가진다.

Capability — 무엇을 할 수 있는가.

Permission — 어디까지 할 수 있는가.

Context Contract — 입력과 결과를 모델에게 어떤 구조로 보여주는가.

예를 들어 run_database_command(sql: str)는 구현하기 쉽지만 Capability가 너무 넓다. 모델에게 읽기, 쓰기, 삭제, 임의 조인까지 한 번에 넘기기 때문이다.

정산 시스템이라면 다음처럼 나누는 편이 낫다.

read_settlement_summary읽기 전용. Batch ID와 제한된 요약만 반환.
preview_repair실제 Write 없이 변경될 Row와 Diff를 미리 계산.
apply_approved_repair승인 토큰이 있는 경우에만 제한된 Write.
verify_repairWrite 후 다시 읽어 Business Invariant를 검증.

MCP는 이 경계를 표준화하는 프로토콜이다

MCP(Model Context Protocol, 모델 컨텍스트 프로토콜)의 본질은 Agent를 더 똑똑하게 만드는 것이 아니라 Tool·Resource와 Agent 사이의 연결 계약을 표준화하는 데 있다.

2026년 현재 MCP Python SDK v2의 고수준 서버는 MCPServer이며, @mcp.tool()에 붙인 함수 이름·Docstring·Type Hint에서 Tool 설명과 입력 Schema를 만든다. 따라서 Tool 함수 자체가 Agent Interface가 된다.

MCP Python SDK v2 — 읽기 전용 업무 Tool 예시

from __future__ import annotations

from typing import Annotated

from mcp.server import MCPServer
from pydantic import Field


mcp = MCPServer("billing-readonly")


# 실제 서비스에서는 Repository/DB Adapter 뒤에서 조회한다.
SETTLEMENTS = {
    "batch-2026-09-11": {
        "delta_amount": 124_300,
        "failed_records": 17,
        "currency": "KRW",
    }
}


@mcp.tool()
def read_settlement_summary(
    batch_id: str,
    limit: Annotated[int, Field(ge=1, le=100)] = 20,
) -> dict:
    """
    정산 Batch의 읽기 전용 요약을 반환한다.

    이 Tool은 Production 데이터를 수정하지 않는다.
    batch_id는 immutable id를 사용하고,
    상세 레코드는 limit을 넘겨 반환하지 않는다.
    """
    row = SETTLEMENTS.get(batch_id)

    if row is None:
        # 모델이 다른 batch_id로 복구할 수 있도록 구조화된 실패를 반환한다.
        return {
            "ok": False,
            "error_kind": "BatchNotFound",
            "batch_id": batch_id,
        }

    return {
        "ok": True,
        "batch_id": batch_id,
        "delta_amount": row["delta_amount"],
        "failed_record_count": min(row["failed_records"], limit),
        "currency": row["currency"],
        "provenance": {
            "source": "billing-ledger",
            "mode": "read-only",
        },
    }


if __name__ == "__main__":
    # 원격 Host가 연결하는 Stateless Streamable HTTP 서버.
    mcp.run(
        transport="streamable-http",
        stateless_http=True,
        json_response=True,
    )

같은 MCP Tool을 in-memory Client로 테스트

import pytest
from mcp import Client

from server import mcp


@pytest.mark.anyio
async def test_read_settlement_summary():
    # 실제 포트나 subprocess 없이 서버 객체에 직접 연결한다.
    async with Client(mcp) as client:
        result = await client.call_tool(
            "read_settlement_summary",
            {
                "batch_id": "batch-2026-09-11",
                "limit": 10,
            },
        )

    assert result.is_error is False
    assert result.structured_content["ok"] is True
    assert result.structured_content["delta_amount"] == 124_300
    assert result.structured_content["failed_record_count"] == 10


# 예상 결과
# $ pytest -q
# 1 passed

이 코드에서 중요한 Parameter는 Transport보다 batch_id와 limit다. 불변 ID는 잘못된 대상을 선택할 가능성을 줄이고, limit은 Context 폭주와 과도한 데이터 노출을 막는다. provenance는 다음 Trace와 Evidence를 연결한다.

MCP Server가 많아질수록 자동으로 Agent가 좋아지는 것도 아니다. 이름이 겹치는 Tool, 장황한 Description, 지나치게 긴 Tool Output은 오히려 선택 오류와 Context 비용을 만든다. Tool도 Eval 대상이어야 한다.

9. Loop의 최소 단위는 while문이 아니라 Runtime Contract다

Loop Engineering이라는 말을 들으면 다음 코드를 떠올리기 쉽다.

while not done:
    response = model(...)

하지만 같은 State에서 같은 호출을 반복한다고 실패에서 배우는 것은 아니다. 진짜 Loop는 최소한 다음 계약을 가져야 한다.

Goal / State현재 어디인가
Policy다음 행동 선택
ActionTool·환경 실행
Observation실행 결과
Verifier성공 증거
Update / Stop복구·승인·종료
계약반드시 답해야 할 질문
Goal / Spec 어떤 산출물이 생기면 완료인가?
State 다음 Step까지 무엇을 보존할 것인가?
Policy 다음 행동을 모델이 고를까, 코드가 고를까?
Observation Raw 결과 중 어떤 Signal을 되돌릴 것인가?
Verifier 성공을 어떤 외부 증거로 판정할 것인가?
Budget Step·시간·비용의 상한은 어디인가?
Handoff 언제 사람의 판단이 필요한가?
Termination success / blocked / timeout / budget / policy denied를 어떻게 구분할까?

Action Success와 Task Success를 반드시 분리한다.

git apply가 성공했다는 것은 Patch가 적용됐다는 뜻이지 버그가 고쳐졌다는 뜻이 아니다. API가 200을 반환했다는 것은 요청이 처리됐다는 뜻이지 업무의 불변식이 회복됐다는 뜻이 아니다.

10. Verifier-first: 모델의 “완료했습니다”는 증거가 아니다

Agent가 가장 위험하게 끝나는 방식은 자신의 문장을 종료 조건으로 쓰는 것이다.

assistant: 작업을 완료했습니다.

이 문장은 Claim(주장)이다. 시스템이 필요한 것은 Evidence(증거)다.

검증은 일반적으로 다음 순서가 안정적이다.

  1. Deterministic Verifier(결정론적 검증기) — Unit Test, Compiler, Schema, SQL invariant, Static Analysis
  2. Rule / Rubric — 변경 Scope, 필수 필드, 정책 규칙처럼 코드로 판정 가능한 항목
  3. LLM Grader — 설명 품질, 의미적 충실도처럼 기계적 판정이 어려운 부분의 보조 평가
  4. Human Review — 비가역적이거나 고위험·모호한 결정

Verifier는 모델과 같은 실패 모드를 공유하지 않게 만든다

Patch를 만든 모델에게 “이 Patch가 맞아?”라고 다시 묻는 것만으로는 충분하지 않다. 같은 모델은 같은 오해를 반복할 수 있다. Coding Agent라면 실제 테스트와 정적 분석, 실제 Diff 범위가 1차 검증이어야 한다.

현업형 Verifier — 모델과 독립적으로 테스트·Lint·변경 Scope를 검사

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path
import subprocess


@dataclass(frozen=True)
class Check:
    name: str
    passed: bool
    detail: str


@dataclass(frozen=True)
class Evidence:
    passed: bool
    checks: tuple[Check, ...]


def run_check(
    name: str,
    command: list[str],
    cwd: Path,
    timeout_s: int = 120,
) -> Check:
    """
    모델의 자연어 판단이 아니라 실제 프로세스 Exit Code를 Evidence로 사용한다.
    """
    completed = subprocess.run(
        command,
        cwd=cwd,
        capture_output=True,
        text=True,
        timeout=timeout_s,
        check=False,
    )

    # 전체 로그를 Context에 넣지 않는다.
    # 실패 시 마지막 일부만 Trace에 남기고, 원본 로그는 Artifact Store에 보관하는 편이 좋다.
    tail = (completed.stdout + completed.stderr)[-1200:]

    return Check(
        name=name,
        passed=completed.returncode == 0,
        detail=tail.strip(),
    )


def changed_files(workspace: Path) -> list[str]:
    completed = subprocess.run(
        ["git", "diff", "--name-only", "HEAD"],
        cwd=workspace,
        capture_output=True,
        text=True,
        check=True,
    )
    return [
        line.strip()
        for line in completed.stdout.splitlines()
        if line.strip()
    ]


def verify_workspace(workspace: Path) -> Evidence:
    checks = [
        run_check(
            "unit_test",
            ["uv", "run", "pytest", "-q", "tests/billing"],
            workspace,
        ),
        run_check(
            "lint",
            ["uv", "run", "ruff", "check", "src/billing", "tests/billing"],
            workspace,
        ),
    ]

    allowed_prefixes = ("src/billing/", "tests/billing/")
    scope_ok = all(
        path.startswith(allowed_prefixes)
        for path in changed_files(workspace)
    )

    checks.append(
        Check(
            name="scope",
            passed=scope_ok,
            detail="변경 파일이 billing 범위 안에 있는지 검사",
        )
    )

    return Evidence(
        passed=all(check.passed for check in checks),
        checks=tuple(checks),
    )


# 예상 결과 개념
# Evidence(
#   passed=True,
#   checks=(
#     Check(name="unit_test", passed=True, ...),
#     Check(name="lint", passed=True, ...),
#     Check(name="scope", passed=True, ...),
#   )
# )

이 함수는 Agent가 없어도 가치가 있다. 이것이 Verifier-first의 중요한 장점이다. 먼저 “끝났음을 증명하는 코드”를 만들고, 그 다음 그 증거를 만족시키도록 Agent를 붙인다.

11. LangGraph는 State와 Control Flow를 직접 소유하고 싶을 때 강하다

직접 작성한 while Loop가 커지면 State Transition이 여러 함수와 조건문에 흩어진다. LangGraph의 가치는 “그래프 그림을 그린다”보다 State와 제어 흐름을 Runtime의 명시적인 구성 요소로 만든다는 데 있다.

2026년 현재 공식 Graph API에서 핵심은 StateGraph, START/END, add_node, add_edge, add_conditional_edges, RetryPolicy, Command, Checkpointer, interrupt()다. 현재 문서는 HITL이 있는 실행에서는 Event Streaming을 통해 Interrupt와 State를 관찰하는 패턴도 명확하게 제공한다.

현업 예제: B2B 정산 장애 복구 Agent

새벽 정산 Batch 이후 내부 원장과 결제 대행사 정산 금액이 맞지 않는 상황을 가정하자. Agent는 원인 조사와 Patch 후보 생성은 할 수 있지만, Production 원장 보정은 사람 승인 없이는 실행할 수 없다.

코드를 쓰기 전에 계약부터 적는다.

Goal
  정산 불일치의 원인을 찾고 안전한 수정안을 만든다.

Success Evidence
  unit / integration test = PASS
  reconciliation dry-run delta = 0
  변경 파일 = billing 범위 내부
  production 직접 write = 없음

Budget
  수정 반복 최대 3회
  외부 API의 transient error만 제한적으로 retry
  Graph recursion limit 설정

Human Required
  production 원장 보정
  schema 변경
  고객 환불/취소
  허용 Scope 밖 변경

LangGraph — Retry, Verification, Interrupt, Resume를 하나의 State Machine으로 구성

from __future__ import annotations

from typing import Literal, TypedDict

from langgraph.checkpoint.memory import InMemorySaver
from langgraph.graph import END, START, StateGraph
from langgraph.types import Command, RetryPolicy, interrupt


class IncidentState(TypedDict, total=False):
    incident_id: str
    attempt: int

    # 조사 결과
    delta_amount: int
    suspected_change: str

    # Artifact
    patch_ref: str

    # Verifier Evidence
    tests_passed: bool
    reconciliation_delta: int
    scope_allowed: bool

    # Risk / Human Gate
    production_repair_required: bool

    status: str


def collect_evidence(state: IncidentState) -> dict:
    """
    Monitoring/Git/Log Adapter를 호출하는 읽기 전용 Node라고 생각하면 된다.

    외부 API 일시 장애는 RetryPolicy가 처리한다.
    Raw 로그 전체 대신 다음 판단에 필요한 Signal만 State에 넣는다.
    """
    return {
        "delta_amount": 124_300,
        "suspected_change": "src/billing/rounding.py@a31f9c2",
    }


def propose_patch(state: IncidentState) -> dict:
    """
    실제 환경에서는 Coding Model 또는 별도 Coding Worker가 실행된다.

    자연어 답변이 아니라 patch_ref라는 Artifact를 남긴다.
    다음 Verifier가 '같은 Patch'를 검사하기 위해서다.
    """
    attempt = state.get("attempt", 0) + 1

    return {
        "attempt": attempt,
        "patch_ref": (
            f"worktree://{state['incident_id']}"
            f"/patch-{attempt:03d}"
        ),
    }


def verify_patch(state: IncidentState) -> dict:
    """
    실제 서비스에서는 pytest, lint, type check,
    정산 dry-run, git diff scope 검사 결과를 읽는다.
    """
    return {
        "tests_passed": True,
        "reconciliation_delta": 0,
        "scope_allowed": True,

        # 과거 잘못 반영된 운영 원장을 보정해야 한다고 가정.
        "production_repair_required": True,
    }


def route_after_verify(
    state: IncidentState,
) -> Literal["retry_patch", "approval", "done", "handoff"]:
    verified = (
        state["tests_passed"]
        and state["reconciliation_delta"] == 0
        and state["scope_allowed"]
    )

    # 검증 실패는 같은 상태로 무한 반복하지 않는다.
    if not verified:
        return "retry_patch" if state["attempt"] < 3 else "handoff"

    if state["production_repair_required"]:
        return "approval"

    return "done"


def approval_node(
    state: IncidentState,
) -> Command[Literal["apply_repair", "handoff"]]:
    """
    interrupt()에서 Graph가 멈추고 외부 입력을 기다린다.

    매우 중요:
    이 Node는 Resume 때 처음부터 다시 실행될 수 있으므로
    interrupt() 앞에 비가역 Side Effect를 두지 않는다.
    """
    decision = interrupt(
        {
            "type": "production_repair",
            "incident_id": state["incident_id"],
            "patch_ref": state["patch_ref"],
            "question": "운영 원장 보정을 승인하시겠습니까?",
        }
    )

    return Command(
        goto=(
            "apply_repair"
            if decision.get("approved")
            else "handoff"
        )
    )


def apply_repair(state: IncidentState) -> dict:
    """
    예제에서는 실제 DB Write를 하지 않는다.

    현업 구현 시 이 Node에는 최소한:
    - idempotency key
    - tenant / row scope
    - approval audit
    - write 후 read-back verification
    을 둔다.
    """
    return {"status": "repair_applied"}


def done(state: IncidentState) -> dict:
    return {"status": "resolved"}


def handoff(state: IncidentState) -> dict:
    return {"status": "human_required"}


builder = StateGraph(IncidentState)

builder.add_node(
    "collect_evidence",
    collect_evidence,
    retry_policy=RetryPolicy(
        max_attempts=3,
        retry_on=ConnectionError,
    ),
    timeout=10.0,
)

builder.add_node("propose_patch", propose_patch)
builder.add_node("verify_patch", verify_patch)
builder.add_node("approval", approval_node)
builder.add_node("apply_repair", apply_repair)
builder.add_node("done", done)
builder.add_node("handoff", handoff)

builder.add_edge(START, "collect_evidence")
builder.add_edge("collect_evidence", "propose_patch")
builder.add_edge("propose_patch", "verify_patch")

builder.add_conditional_edges(
    "verify_patch",
    route_after_verify,
    {
        "retry_patch": "propose_patch",
        "approval": "approval",
        "done": "done",
        "handoff": "handoff",
    },
)

builder.add_edge("apply_repair", "done")
builder.add_edge("done", END)
builder.add_edge("handoff", END)

# 개발 예제는 InMemorySaver.
# Production에서는 DB-backed durable checkpointer를 사용한다.
graph = builder.compile(
    checkpointer=InMemorySaver()
)

config = {
    "configurable": {
        # 같은 업무를 재개하는 Persistent Cursor.
        "thread_id": "incident-INC-482",
    },

    # 종료 조건 버그가 비용 폭주로 이어지는 것을 막는 최후의 상한.
    "recursion_limit": 20,
}


# 1) 첫 실행: approval_node의 interrupt()에서 멈춘다.
stream = graph.stream_events(
    {
        "incident_id": "INC-482",
        "attempt": 0,
        "status": "running",
    },
    config=config,
    version="v3",
)

# 실행을 끝(또는 pause)까지 진행시킨다.
_ = stream.output

if stream.interrupted:
    request = stream.interrupts[0].value
    print("human_review:", request)

    # 2) 실제로는 Slack/GitHub/Admin UI의 승인 결과가 들어온다.
    resumed = graph.stream_events(
        Command(
            resume={
                "approved": True,
                "reviewer": "billing-oncall",
            }
        ),
        config=config,
        version="v3",
    )

    final = resumed.output
else:
    final = stream.output

print("status:", final["status"])
print("patch:", final["patch_ref"])
print("attempt:", final["attempt"])
print("delta:", final["reconciliation_delta"])


# 예상 결과 개념
#
# human_review: {
#   'type': 'production_repair',
#   'incident_id': 'INC-482',
#   'patch_ref': 'worktree://INC-482/patch-001',
#   'question': '운영 원장 보정을 승인하시겠습니까?'
# }
#
# status: resolved
# patch: worktree://INC-482/patch-001
# attempt: 1
# delta: 0

이 예제에서 LLM은 한 줄도 직접 등장하지 않는다. 일부 Node 안에 모델을 넣으면 된다. 이게 오히려 중요한 점이다.

collect_evidence 안에서 Log와 Git Diff를 모델이 해석할 수 있고, propose_patch 안에서 Coding Model이 Patch를 만들 수 있다. 그러나 Retry 상한, 승인 경계, Verifier, Persistent State는 모델이 아니라 Runtime이 소유한다.

LangGraph API를 기능이 아니라 소유권으로 이해한다

API / 개념소유하는 것현업에서 중요한 점
StateGraph(State) 업무 State Schema 대화 History 외에 도메인 상태를 명시적으로 둔다.
add_node 실행 단위 Node마다 Retry·Timeout·Error 정책을 다르게 가져갈 수 있다.
add_conditional_edges 분기와 Loop Termination Policy가 코드에 드러난다.
RetryPolicy 재시도 계약 논리 오류가 아니라 주로 일시적 외부 장애를 재시도한다.
interrupt() HITL Pause State를 보존한 채 외부 판단을 기다린다.
Command(resume=...) 재개 입력 같은 thread_id로 동일 실행을 이어간다.
Checkpointer Thread Snapshot HITL, 장애 복구, Time Travel, Fault Tolerance의 기반.
Store Cross-thread Memory Thread State와 장기 기억을 분리한다.
recursion_limit Graph 상한 잘못된 Loop가 무한 비용으로 이어지는 것을 막는다.

12. Retry는 “다시 해봐”가 아니라 실패 분류와 State 갱신이다

Retry가 의미 있으려면 두 가지가 필요하다.

첫째, 실패 종류를 구분해야 한다. 네트워크 503, DB Lock 같은 일시적 실패는 동일 입력으로 다시 시도할 가치가 있다. 반면 Test Assertion 실패나 Schema 위반은 입력이나 Patch를 바꾸지 않으면 같은 결과가 반복될 가능성이 높다.

둘째, Failure Evidence가 다음 State에 들어가야 한다. 실패했는데 직전 오류를 지운 채 같은 Prompt를 다시 보내는 것은 Stateless Retry다.

실패권장 처리
HTTP 5xx / 일시적 연결 오류 Exponential Backoff를 포함한 제한된 Retry
Tool Argument Validation 실패 모델이 인자를 수정할 수 있도록 구조화된 오류 반환
Unit Test 실패 실패 Test, 핵심 Stack Trace를 다음 수정 State에 반영
권한 거부 자동 Retry하지 않고 Policy Denied 또는 Human Required
Budget 초과 Stop. “조금만 더”를 모델이 결정하게 하지 않음

13. Dify 같은 Low-code Runtime은 시각적 Workflow가 필요한 곳에 강하다

Dify 자료의 LLM, Knowledge Retrieval, Question Classifier, IF/ELSE, Variable Aggregator, Iteration, Loop, Code, Tool 블록을 각각 별도 기술로 외울 필요는 없다. 이들은 Graph Runtime의 시각적 Primitive로 볼 수 있다.

Iteration은 배열 요소를 반복 처리하는 데이터 순회에 가깝고, Loop는 종료 조건이 만족될 때까지 상태를 반복 갱신하는 제어 구조다. Question Classifier와 IF/ELSE는 Routing, Variable Aggregator는 Fan-in, Tool Block은 외부 Action/Observation 지점이다.

업로드된 dify_pipeline_local.py는 Open WebUI 쪽 요청을 Dify Workflow/Agent/Chat API로 변환하고, Streaming 이벤트를 다시 UI에 흘려보내는 Adapter 역할을 한다. 여기서 오래 남는 설계는 특정 requests 코드가 아니라 외부 Runtime과 내부 애플리케이션 사이에 번역 계층을 둔 것이다.

2026년 현재 Dify Workflow API도 /workflows/run에서 blocking과 SSE streaming을 지원하고, 실행 중에는 task_id, 영속 실행 기록에는 workflow_run_id를 사용한다. Human Input으로 Pause된 실행을 다시 이어가는 API도 별도로 제공한다.

현업 Adapter는 Business Logic과 HTTP 세부사항을 분리한다

현재 Dify Workflow API를 감싸는 비동기 Adapter 예시

from __future__ import annotations

from dataclasses import dataclass
from typing import Any

import httpx


@dataclass(frozen=True)
class WorkflowResult:
    run_id: str
    status: str
    outputs: dict[str, Any]
    elapsed_time: float
    total_tokens: int
    total_steps: int


class DifyWorkflowError(RuntimeError):
    pass


class DifyWorkflowClient:
    def __init__(
        self,
        *,
        base_url: str,
        api_key: str,
        timeout_s: float = 30.0,
    ) -> None:
        # API Key는 frontend가 아니라 server-side secret으로만 둔다.
        self._base_url = base_url.rstrip("/")
        self._api_key = api_key
        self._timeout = httpx.Timeout(timeout_s)

    async def run_blocking(
        self,
        *,
        inputs: dict[str, Any],
        user_id: str,
    ) -> WorkflowResult:
        """
        정형 Workflow의 결과를 한 번에 받아야 할 때 사용한다.

        긴 작업은 streaming 또는 background run이 더 적합하다.
        """
        headers = {
            "Authorization": f"Bearer {self._api_key}",
            "Content-Type": "application/json",
        }

        payload = {
            "inputs": inputs,
            "response_mode": "blocking",
            "user": user_id,
        }

        async with httpx.AsyncClient(
            base_url=self._base_url,
            headers=headers,
            timeout=self._timeout,
        ) as client:
            response = await client.post(
                "/workflows/run",
                json=payload,
            )

        # HTTP 오류를 "빈 답변"으로 삼키지 않는다.
        response.raise_for_status()

        body = response.json()
        data = body["data"]

        if data["status"] != "succeeded":
            raise DifyWorkflowError(
                f"workflow failed: {data.get('error')}"
            )

        return WorkflowResult(
            run_id=body["workflow_run_id"],
            status=data["status"],
            outputs=data["outputs"],
            elapsed_time=float(data["elapsed_time"]),
            total_tokens=int(data["total_tokens"]),
            total_steps=int(data["total_steps"]),
        )


# 사용 예
#
# client = DifyWorkflowClient(
#     base_url="https://api.dify.ai/v1",
#     api_key=os.environ["DIFY_API_KEY"],
# )
#
# result = await client.run_blocking(
#     inputs={"query": "이번 보고서의 핵심 리스크를 정리해줘"},
#     user_id="user-42",
# )
#
# print(result.status)
# print(result.outputs)
#
# 예상 결과 개념
# succeeded
# {'result': '...워크플로우가 생성한 결과...'}

이 버전에서 일부러 하지 않은 것도 중요하다. SSL 검증을 끄지 않고, bare except:로 Streaming 파싱 오류를 삼키지 않고, API Key를 로그로 출력하지 않는다. Adapter의 목적은 “Dify를 호출한다”가 아니라 네트워크 실패와 Runtime 실패를 우리 서비스가 이해할 수 있는 상태로 변환한다는 것이다.

14. Agentic RAG의 핵심은 검색 Tool이 아니라 Feedback Loop다

2024년 Agentic RAG 자료에는 pdf_search  relevance_check를 실행하고, 관련성이 낮으면 Query를 다시 만들고 재검색하는 패턴이 등장한다. 이 구조의 본질은 지금도 유효하다.

Query질문
Retrieve검색
Evaluate관련성 평가
Rewrite검색 실패를 반영

다만 “최대 20번 다시 검색” 같은 규칙을 Prompt에만 적는 것과 Runtime Budget으로 관리하는 것은 다르다. 현대적인 구현에서는 검색 시도 횟수, 누적 Token, Latency, 마지막 실패 이유가 State에 있고, Budget 초과는 명시적 Stop Reason이 된다.

Agentic RAG가 일반 RAG보다 좋은 것도 아니다. 질문 하나에 Retriever 한 번으로 충분한 도메인이라면 고정 RAG가 더 빠르고 재현 가능하다. Query Rewrite와 Tool 선택이 실제 Retrieval 품질을 개선할 때만 Loop의 비용을 지불할 가치가 있다.

15. Evaluation은 모델 평가가 아니라 Runtime 평가다

Agent를 “답변이 좋아 보인다”로 평가하면 운영 품질을 알기 어렵다. 평가 단위는 실제 Task Outcome과 Trajectory(행동 궤적)까지 내려가야 한다.

평가 층질문예시 Metric
Outcome 업무가 실제로 끝났는가? Task Pass Rate, Test Pass Rate
Quality 결과가 운영 가능한 품질인가? Defect Escape, Rework Rate
Tool 도구를 맞게 골랐고 인자가 맞았는가? Tool Selection Accuracy
Trajectory 불필요한 행동을 반복하지 않았는가? Step Count, Retry Count
Latency 사용 가능한 시간 안에 끝났는가? P50/P95 Completion Time
Cost 성공 한 건당 비용은 얼마인가? Cost per Successful Task
Safety 권한 경계를 지켰는가? Denied Calls, Policy Violations
Human Load 사람이 얼마나 자주 개입해야 하나? Handoff Rate, Review Minutes

Eval Set도 하나로 끝나지 않는다.

Capability Eval — 새 시스템이 어려운 일을 얼마나 잘하는가.

Regression Eval — Harness를 바꿔도 기존 성공 사례가 깨지지 않는가.

Production Trace Eval — 실제 운영 실패가 평가 데이터로 다시 들어오는가.

Self-Evolving Harness를 만들려면 특히 Regression Eval이 중요하다. 실패 한 건을 고친 Skill 변경이 다른 열 건의 성공 사례를 망칠 수 있기 때문이다.

16. Trace가 없으면 Agent Debugging은 심리 추측이 된다

Agent가 잘못된 행동을 했을 때 “모델이 왜 그렇게 생각했을까?”부터 묻기 쉽다. 하지만 운영 시스템에서는 먼저 그 결정을 내릴 당시 어떤 State와 Observation이 있었는가를 본다.

최소 Trace는 이 정도면 좋다.

{
  "run_id": "agent-run-2193",
  "step": 4,

  "state_in": {
    "incident_id": "INC-482",
    "attempt": 2,
    "remaining_budget": 1
  },

  "action": {
    "tool": "run_reconciliation",
    "scope": "staging"
  },

  "observation": {
    "exit_code": 1,
    "error_kind": "MismatchDetected",
    "summary": "17 records still differ",
    "artifact_id": "log://run-2193/step-4"
  },

  "verification": {
    "passed": false,
    "failed_checks": ["reconciliation"]
  },

  "decision": {
    "type": "retry",
    "reason": "business invariant failed"
  }
}

이 구조가 있으면 다음 질문이 재현 가능해진다. 직전 실패가 다음 State에 들어갔는가. 같은 Tool을 반복한 이유는 무엇인가. 어느 Step에서 Context가 커졌는가. 어느 Tool에서 Latency가 발생했는가. Verifier가 무엇을 실패로 판단했는가.

Agent Trace는 단순 Log가 아니라 향후 Eval과 Harness 개선의 학습 데이터다.

17. Multi-Agent보다 먼저 Ownership을 설계한다

Agent를 여러 개 만들면 자연스럽게 더 똑똑해질 것 같지만, 실제 운영 문제는 Agent 수보다 State와 Artifact의 소유권에서 발생한다.

세 Worker가 같은 Repository를 동시에 수정한다고 하자. Git Conflict를 해결해도 설계 의도가 서로 다르면 Semantic Conflict(의미 충돌)는 남는다.

Multi-Agent 전에 다음 질문에 답해야 한다.

  • State Ownership — 현재 작업의 진실은 어디에 저장되는가?
  • Artifact Ownership — 어떤 Worker가 어떤 파일/문서를 쓸 수 있는가?
  • Write Ownership — 동일 Artifact에 동시 Write가 허용되는가?
  • Merge Gate — 결과를 무엇으로 합격/불합격 판정해 합칠 것인가?
  • Trace — 다른 Worker의 결정 근거를 재현할 수 있는가?

Coding에서는 의외로 Single Writer + Reviewer + Verifier가 강하다. 반대로 여러 독립 문서 조사나 여러 Repository 검사처럼 하위 Task가 서로 독립적으로 완료되고 검증 가능하면 Fan-out/Fan-in 병렬 Worker가 잘 맞는다.

병렬성은 목표가 아니라 검증 가능한 Task 분해의 결과다.

18. MCP와 A2A는 같은 문제를 풀지 않는다

MCP와 A2A를 모두 “Agent 연결 프로토콜”이라고만 보면 경계가 흐려진다.

MCPA2A
중심 관계 Agent ↔ Tool / Data Agent ↔ Remote Agent
주요 관심사 Capability discovery, schema, tool/resource access 독립 Agent 간 task/message/artifact 교환
쓰는 이유 Integration 경계를 표준화 프레임워크/공급업체가 다른 Agent 간 Interoperability

모든 Tool을 Agent로 만들 필요도 없고, 모든 Agent 협업을 MCP 하나로 해결할 필요도 없다. “함수 하나를 호출하면 되는가?”라면 Tool이다. 별도 Runtime과 State, 독립적인 책임과 Task Lifecycle을 가진 상대라면 Remote Agent에 가깝다.

19. 사람이 Loop에서 빠지는 순간 Orchestrator가 필요해진다

Interactive Agent에서는 사람이 Loop 안에 있다.

Human요청
Agent실행
Human확인·다음 지시

Background/Ambient Agent에서는 시작 자체가 Event, Queue, Cron, Schedule로 바뀐다.

TriggerEvent·Cron·Queue
Dispatcher작업 선택
Worker격리 실행
EvidenceArtifact·Trace
Source of Truth다음 Tick의 입력

여기서 Orchestrator는 가장 똑똑할 필요가 없다. 초기에는 오히려 “한 Tick에 하나의 Dispatch 또는 No-op”처럼 단순할수록 중복 실행, Rate Limit, Audit, 장애 복구를 이해하기 쉽다.

Background Agent에는 Idempotency가 필수다

Queue와 Scheduler는 같은 Event를 두 번 전달할 수 있다. 네트워크 Timeout 때문에 성공한 작업을 실패로 오해하고 다시 보낼 수도 있다. 따라서 “이 요청은 한 번만 온다”는 전제를 버려야 한다.

event_id
   ↓
이미 처리했는가?
   ├─ Yes → no-op / 기존 결과 반환
   └─ No
       ↓
     실행
       ↓
     결과 저장
       ↓
     processed(event_id) 기록

Cursor, Checkpoint, Decision Log가 중요한 이유다. 사람이 사라진 자리를 “더 똑똑한 모델”이 아니라 영속 상태와 재실행 안전성이 메운다.

20. Human-in-the-loop는 실패가 아니라 정상 Runtime State다

완전 자율을 “사람이 전혀 개입하지 않는 것”으로 정의하면 고위험 시스템은 위험해진다. 더 유용한 목표는 Calibrated Autonomy(보정된 자율성)다.

되돌릴 수 있고, 정책 범위 안이고, 성공을 자동으로 검증할 수 있는 행동은 자동화한다. 비가역적이거나 불확실하거나 조직적 책임이 필요한 판단은 사람에게 올린다.

좋은 HITL 화면에는 승인 버튼만 있는 것이 아니라 다음 정보가 있어야 한다.

  • 왜 멈췄는가 — blocker / policy / risk reason
  • 무엇을 하려는가 — action과 정확한 대상 scope
  • 어떤 근거가 있는가 — test, diff, trace, source
  • 승인하면 무엇이 변하는가 — side effect와 rollback 경로
  • 어디서 재개하는가 — thread/task/run id와 저장된 state

그리고 사람 개입 후 처음부터 다시 조사하게 만들지 않는다. 중단 시점의 State와 Evidence를 보존하고, 사람은 결정만 내려 같은 실행을 이어가게 한다.

21. Security는 Agent 바깥의 부가 기능이 아니라 Loop의 경계다

Tool을 한 번 호출하는 시스템보다 반복 호출하는 Agent의 공격 표면이 더 넓다. 작은 권한도 Loop 안에서 수십 번 반복되면 피해 반경이 커질 수 있기 때문이다.

Capability권장 기본 경계
Repository 읽기·검색 자동 허용 가능. 민감 경로 제외.
Test / Build Sandbox 내부 자동 허용.
Worktree 파일 수정 허용 Path와 Repository 범위 제한.
Dependency 변경 Policy Check 또는 Review.
외부 API Write Idempotency + 최소 권한 + Audit.
Production 데이터 변경 Human Approval + Read-back Verification.
Secret / Credential Context에 직접 넣지 않고 별도 Secret Boundary.

Tool Output도 신뢰 경계다. Shell 출력, 외부 웹 페이지, 문서에는 Secret, 개인정보, Prompt Injection성 텍스트가 들어올 수 있다.

Raw Output외부 데이터
RedactSecret·PII 제거
Limit크기 제한
Classifyerror kind
Contextsummary + evidence id

보안 목표는 “Agent가 절대로 실수하지 않게 한다”가 아니다. 확률 시스템에서 더 현실적인 목표는 실수해도 피해 반경이 제한되고, 중요한 행동은 승인되며, 모든 변경이 추적되고 되돌릴 수 있게 하는 것이다.

22. OpenAI Agents SDK 같은 고수준 Runtime은 무엇을 대신 소유해 주는가

모든 팀이 Agent Loop를 직접 구현할 필요는 없다. 고수준 SDK는 자주 반복되는 Runtime Primitive를 대신 제공한다.

2026년 현재 OpenAI Agents SDK의 Agent와 Runner는 모델 호출, Function Tool, Handoff, Guardrail, Session, Tracing을 포함한 기본 Loop를 관리한다. 직접 Responses API를 사용하면 Loop를 더 많이 소유하고, Agents SDK를 사용하면 일반적인 orchestration을 SDK에 맡긴다.

주요 API역할설계 포인트
Agent(...) instructions, tools, handoffs, output type, guardrails 구성 한 Agent의 책임을 좁게 정의
Runner.run(...) 비동기 Agent Loop 실행 앱의 Runtime 경계에서 실행
Runner.run_streamed(...) Streaming Run 긴 작업의 UX/관찰성
RunConfig Run 단위 설정 Tool 동시성, error behavior, tracing 등
Function Tool Python 함수를 Tool로 노출 Schema·Error·Timeout·Permission
Tool Guardrail Function Tool 전후 검사 Side Effect 가까이에 정책 배치

특히 Tool Guardrail이 중요하다. Agent-level Input/Output Guardrail만으로는 중간에 여러 Tool을 호출하는 긴 Workflow의 Side Effect를 모두 통제하기 어렵다. 실제 행동 직전·직후 Guard를 두면 모델의 전체 응답이 아니라 위험한 Capability 자체를 통제할 수 있다.

23. Self-Evolving은 자기수정이 아니라 검증된 Feedback 배포 루프다

Memory를 붙인다고 Agent가 계속 똑똑해지는 것은 아니다. 과거 실패가 다음 실행의 행동 규칙을 바꾸려면 운영 Feedback이 실제 Harness 변경으로 연결돼야 한다.

Runtime실제 실행
Trace성공·실패
Failure Analysis패턴 분류
Eval변경안 비교
ReviewVersion·승인
Deploy다음 Runtime

바꿀 수 있는 것은 Prompt만이 아니다.

Prompt — 모델의 판단 지침이 불명확했는가.

Skill — 반복 절차 자체가 부족했는가.

Tool — Capability 또는 Schema가 모호했는가.

Rule / Middleware — 모델이 아니라 코드로 고정해야 할 정책이었는가.

Eval — 성공 조건을 잘못 측정하고 있었는가.

운영 실패 하나를 본 Agent가 자기 Skill을 즉시 수정해 Production에 반영하도록 하는 것은 위험하다. 한 케이스에 과적합될 수 있고, 다른 정상 케이스를 깨뜨릴 수 있기 때문이다.

안전한 순서는 실패 수집 → 유사 실패 Cluster → 하나의 변경 후보 → Offline Eval → Holdout/Regression → Human Review → Version → 단계 배포 → Rollback 가능에 가깝다.

24. 조직 도입은 Pilot → Measure → Govern → Scale 순서가 맞다

Agent 도입에서 기술 데모와 운영 가치는 분리해야 한다. “코드 몇 줄 생성”, “AI Suggestion 몇 개”, “데모가 멋있다”는 활동량이지 업무 Outcome이 아니다.

시작점은 좁고 검증 가능한 업무가 좋다. 테스트가 있는 반복 Bug Fix, 정형 Migration, 문서 정합성 검사, Incident Evidence 수집, 표준 Report 생성처럼 Success Criteria를 만들 수 있는 업무다.

단계무엇을 하는가
Pilot 범위가 좁고 Verifier가 있는 Task를 고른다.
Measure 도입 전 Completion Time, Review Time, Rework, Defect Baseline을 측정한다.
Govern Pilot부터 Permission, Secret, Approval, Audit, Rollback을 붙인다.
Scale Baseline을 넘은 범위만 확장한다. 아니면 단순화하거나 중단한다.

Coding/Operations에서는 Lead Time, PR Cycle Time, Rework Rate, Change Failure Rate, Defect Escape, Incident Rate, Human Review Minutes, Cost per Successful Task가 유용하다.

외부 Benchmark와 Vendor 사례는 “가능할 수 있다”는 방향 신호다. 실제 ROI는 우리 업무와 우리 Baseline으로 다시 측정해야 한다.

25. 현업에서 반복해서 망가지는 패턴

증상근본 원인먼저 바꿀 것
“완료”라고 했지만 틀림 Verifier 없음 외부 Evidence를 종료 조건으로
같은 실패를 계속 반복 Stateless Retry Failure Evidence를 다음 State에 반영
긴 작업에서 품질 급락 Context Rot Select·Compress·Isolate·Offload
로그를 읽고 헤맴 Raw Observation Dump summary, error_kind, evidence_id로 구조화
비용이 계속 증가 Bound 없음 max step, timeout, cost cap
Tool을 자주 잘못 선택 이름·Schema·Description 겹침 좁은 Capability와 Tool Eval
Multi-Agent 결과 충돌 Artifact Ownership 없음 Single Writer 또는 Merge Gate
Self-Evolving 후 회귀 Regression Eval 없음 Holdout + Version + Rollback
모든 행동에서 승인 요청 HITL 과다 저위험·가역 Action은 자동화
위험한 행동도 자동 실행 HITL 부재 Side Effect 근처에 Policy/Approval Gate

26. 문제가 생기면 모델보다 Runtime부터 본다

Agent가 이상할 때는 다음 순서로 보는 것이 효율적이다.

  1. Termination — Done을 무엇으로 판단하는가. 모델 문장이라면 먼저 고친다.
  2. State Propagation — 직전 실패가 다음 실행에 실제 반영됐는가.
  3. Budget — Step, Timeout, Cost 상한이 있는가.
  4. Observation Shape — Raw Dump인가, 다음 판단용 Signal인가.
  5. Context — 오래된 정보와 중복 Tool Output이 쌓였는가.
  6. Tool Boundary — Tool이 너무 넓거나 이름·인자가 모호한가.
  7. Permission — 위험 행동이 Prompt 한 줄에만 의존하는가.
  8. Trace — 같은 오류를 재현할 수 있는가.

이 순서를 통과한 뒤에 “모델을 바꾸면 나아질까?”를 보는 편이 낫다. 많은 운영 실패는 모델 능력보다 Runtime 계약이 불분명해서 발생한다.

27. 어떤 기술을 언제 써야 하는가

문제먼저 고려할 기술왜
한 번의 생성 품질 Prompt / Structured Output 가장 단순하고 비용이 낮다.
사내 문서 Q&A Parsing + RAG 지식 경계와 출처를 통제한다.
검색 결과가 자주 부적합 Agentic RAG / Evaluator-Optimizer 실패한 Retrieval을 Query Rewrite로 복구한다.
정형 업무 자동화 Workflow / Dify / Graph 제어 경로가 명확하고 테스트하기 쉽다.
경로를 사전에 알 수 없는 복잡 작업 Bounded Agent Loop 환경 피드백에 따라 다음 행동을 선택할 가치가 있다.
긴 State와 HITL LangGraph + durable persistence Pause/Resume와 상태 복구가 핵심이 된다.
외부 Tool/Data 연결 표준화 MCP Host별 Integration 비용을 낮춘다.
독립 Agent 간 협업 A2A류 패턴 Tool 호출이 아니라 Task/Artifact 협업이 필요하다.
사람 없이 반복 실행 Queue/Scheduler + Orchestrator Idempotency, Cursor, Retry, Audit가 필요하다.
운영 실패를 다음 버전에 반영 Trace + Eval + Versioned Harness Feedback이 검증된 변경으로 이어져야 한다.

28. 프로젝트를 시작할 때 실제로 정하는 순서

  • Goal을 산출물로 정의한다. “잘 해줘”가 아니라 PR, Report, 복구된 정합성처럼 끝을 적는다.
  • Verifier를 먼저 정의한다. Test, Business Invariant, Rule, Human Gate를 만든다.
  • State Schema를 만든다. Goal, Attempt, Last Failure, Artifact, Evidence, Budget부터 시작한다.
  • Tool을 좁게 설계한다. Read/Write를 분리하고 Scope와 Limit을 인자로 제한한다.
  • Context를 Always-on과 On-demand로 나눈다.
  • 문서는 구조와 Provenance를 보존해 Parse한다.
  • 반복 절차만 Skill로 만든다.
  • 독립적으로 완료·검증 가능한 일만 Subagent로 분리한다.
  • Observation Schema를 정한다. exit_code, summary, error_kind, artifact/evidence id.
  • Retry 가능한 실패와 불가능한 실패를 구분한다.
  • Max Step, Timeout, Cost Cap을 둔다.
  • High-risk Action의 Human Gate를 정한다.
  • Trace를 처음부터 남긴다.
  • Baseline Eval을 만든 다음 자율성을 올린다.
  • Background 실행 전 Idempotency와 Checkpoint를 검증한다.
  • Self-Evolving 전에 Version, Regression, Rollback 체계를 만든다.

29. 개발자의 역할은 Prompt Writer에서 Runtime Designer로 이동한다

Agent가 검색, 코드 작성, 반복 Review, 자료 정리를 더 많이 맡게 된다고 해서 개발자의 역할이 단순히 줄어드는 것은 아니다. 사람이 소유해야 할 판단이 더 위쪽으로 이동한다.

Architecture Decision — 어떤 경계를 코드로 고정하고 어디에 모델의 자유도를 줄지 결정한다.

Domain Rule — 무엇이 진짜 올바른 결과인지 정의한다.

Evaluation Design — 어떤 Evidence를 성공으로 인정할지 만든다.

Governance — 어디까지 자동화하고 어디서 승인할지 정한다.

Harness / Skill Design — 반복되는 팀의 판단과 절차를 재사용 가능한 자산으로 만든다.

Product Judgment — 실제 사용자가 언제 AI의 자동화보다 설명·통제·신뢰를 필요로 하는지 판단한다.

모델이 더 강해질수록 이 구조는 더 중요해질 가능성이 높다. 더 강한 모델은 더 긴 작업과 더 많은 Tool을 사용할 수 있기 때문에, 성공할 수 있는 범위와 함께 실패할 수 있는 범위도 넓어진다.

좋은 Agent는 가장 자율적인 Agent가 아니다.
검증된 만큼만 자율성을 갖고, 실패하면 Evidence를 남기고, 위험하면 멈추고, 필요한 순간에 사람에게 정확한 결정을 올리며, 성공했음을 외부 세계에서 증명할 수 있는 Agent가 좋은 Agent다.

Prompt는 한 번의 호출을 잘 지시한다.
Context는 이번 판단에 필요한 정보를 구성한다.
Harness는 모델이 일하는 방식과 권한을 설계한다.
Loop는 실패를 복구하고 성공을 증명한다.
Orchestration은 그 실행을 사람의 시간에서 분리한다.

결국 Agent Engineering의 중심은 모델 호출 자체가 아니라 확률적인 추론을 검증 가능한 업무 시스템으로 바꾸는 Runtime을 소유하는 능력이다.

30. 공식 문서: 무엇을 봐야 하는가

API는 빠르게 바뀐다. 블로그 코드 한 줄을 외우기보다 각 공식 문서에서 어떤 Runtime 원리를 확인해야 하는지 아는 편이 오래간다.

LangGraph — Graph APIhttps://docs.langchain.com/oss/python/langgraph/use-graph-api볼 것: StateGraph, State schema, Node/Edge, Conditional Edge, RetryPolicy, Timeout, Error Handler, recursion_limit.
LangGraph — Interruptshttps://docs.langchain.com/oss/python/langgraph/interrupts볼 것: interrupt(), Command(resume=...), thread_id, stream_events(v3), Resume 시 Node가 다시 시작되므로 interrupt 이전 Side Effect가 idempotent해야 하는 이유.
LangGraph — Persistencehttps://docs.langchain.com/oss/python/langgraph/persistence볼 것: Checkpointer와 Store의 차이. Thread-scoped State와 Cross-thread Long-term Memory를 왜 분리하는가.
Deep Agentshttps://docs.langchain.com/oss/python/deepagents/overview볼 것: Harness 관점, Filesystem/Context Offloading, Subagents, Planning. 기능 자체보다 긴 작업의 Context를 어떻게 외부화하는지 본다.
Anthropic — Building Effective Agentshttps://www.anthropic.com/engineering/building-effective-agents볼 것: Workflow와 Agent의 구분, 가장 단순한 구조부터 시작해야 하는 이유, Evaluator-Optimizer, 자율성이 Latency/Cost와 교환되는 구조.
Claude Code — Skillshttps://code.claude.com/docs/en/skills볼 것: SKILL.md, Progressive Loading, allowed-tools, task/reference content, subagent context. 절차를 어떻게 On-demand Runtime 자산으로 만드는가.
Claude Code — Hookshttps://code.claude.com/docs/en/hooks볼 것: PreToolUse/PostToolUse/PreCompact 등 Lifecycle Point. Prompt가 아니라 실행 시점의 결정론적 제어를 어디에 넣는가.
Claude Code — Subagentshttps://code.claude.com/docs/en/sub-agents볼 것: Fresh Context, Tool Permission, Resume. Context Isolation을 단순 역할 분리와 구분한다.
OpenAI Agents SDKhttps://openai.github.io/openai-agents-python/볼 것: Agent, Runner, Function Tools, Sessions, Handoffs, Tool Guardrails, Tracing. 직접 Loop를 소유할 때와 SDK에 맡길 때의 경계를 비교한다.
Model Context Protocol — Python SDKhttps://py.sdk.modelcontextprotocol.io/볼 것: MCPServer, @mcp.tool(), Type Hint 기반 Schema, Client(mcp) 테스트, Streamable HTTP. Tool을 프로토콜보다 먼저 업무 Capability로 설계한다.
Model Context Protocol — Specificationhttps://modelcontextprotocol.io/볼 것: Tool/Resource/Protocol 계약, Authorization, 현재 버전의 변경점. MCP가 “Agent 지능”이 아니라 Integration Boundary라는 점을 확인한다.
Dify — Workflow App APIhttps://docs.dify.ai/en/api-reference/guides/workflow볼 것: Run Workflow, blocking/streaming, task_id/workflow_run_id, Human Input Pause/Resume, run history. Low-code Workflow도 결국 State와 Execution Runtime이라는 관점으로 본다.
Dify — Run Workflowhttps://docs.dify.ai/en/api-reference/workflow-runs/run-workflow볼 것: POST /workflows/run, inputs, user, response_mode, blocking/streaming Response. API Key를 반드시 server-side에 두는 원칙.
SWE-agenthttps://arxiv.org/abs/2405.15793볼 것: 모델 성능뿐 아니라 ACI(Agent-Computer Interface, 에이전트-컴퓨터 인터페이스)가 실제 소프트웨어 작업 성능에 미치는 영향.
ReActhttps://arxiv.org/abs/2210.03629볼 것: Reasoning → Action → Observation을 하나의 Trajectory로 연결하는 기본 구조.
Self-Refine / Reflexionhttps://arxiv.org/abs/2303.17651
https://arxiv.org/abs/2303.11366볼 것: Feedback을 로그로 버리지 않고 다음 Trial의 상태로 되돌리는 아이디어. Production에서는 반드시 Eval·Budget·Regression과 함께 본다.
OWASP AI Agent Security Cheat Sheethttps://cheatsheetseries.owasp.org/cheatsheets/AI_Agent_Security_Cheat_Sheet.html볼 것: Least Privilege, Tool Permission, Secret, Approval, Audit, Excessive Agency. 보안을 Prompt가 아니라 Runtime Boundary로 설계한다.

 

인간의 뇌는 어떻게 공간과 이미지,
언어와 행동을 만들어내는가

인간의 뇌를 이해하려면 시각, 기억, 언어, 사고, 운동을 따로 떼어 외우기보다 감각정보가 어떤 형태로 변환되고, 그 정보가 기억과 목표를 만나 어떻게 행동으로 이어지는가를 봐야 한다.

이 글을 관통하는 핵심
인간 뇌의 고등기능은 여러 개의 독립된 능력이 아니다.

빛과 소리, 몸의 감각을 내부 표상으로 바꾸고, 그 표상을 기억과 결합하고, 현재 목표에 맞게 재구성한 뒤, 행동으로 실행하고, 그 결과를 다시 학습에 반영하는 하나의 순환 과정이다.
뇌의 외측면, 내측면, 주요 심부 구조 관계도

뇌가 하는 가장 중요한 일은 ‘세계의 내부 모델’을 만드는 것이다

눈을 뜨면 우리는 방 안에 책상과 의자와 창문이 있다고 느낀다. 익숙한 집에서는 불을 켜지 않아도 대략 어디에 무엇이 있는지 안다. 사람이 한 문장을 말하면 우리는 소리의 연속을 듣는 것이 아니라 의미를 이해한다. 손을 뻗어 컵을 잡을 때는 컵의 위치와 손의 위치를 따로 계산하고 있다는 느낌조차 들지 않는다.

하지만 신경계 입장에서 보면 이 모든 과정은 매우 복잡한 계산이다.

망막으로 들어오는 것은 ‘컵’이 아니라 빛의 패턴이고, 귀로 들어오는 것은 ‘문장’이 아니라 시간에 따라 변하는 음압이며, 근육과 관절에서 올라오는 신호 역시 ‘내 팔이 여기 있다’라는 문장이 아니라 수많은 감각수용기에서 발생한 전기적 신호다.

뇌는 이 흩어진 정보를 서로 연결해 “지금 외부 세계는 어떤 상태이고, 내 몸은 그 안에서 어디에 있으며, 나는 무엇을 할 수 있는가”라는 내부 모델을 만든다.

여기에서 중요한 개념이 신경표상(neural representation)이다. 표상이라는 말은 외부 세계의 작은 복사본이 뇌 안에 들어 있다는 뜻이 아니다. 다수의 뉴런이 만드는 활동패턴이 물체의 위치, 형태, 의미, 가치, 과거 경험과의 관계 같은 정보를 표현한다는 뜻이다.

뇌의 핵심 기능을 아주 짧게 표현하면

감각을 그대로 저장하는 것이 아니라, 현재 행동에 사용할 수 있는 형태로 다시 표현하는 것이라고 할 수 있다.

공간을 기억한다는 것은 머릿속에 ‘지도 한 장’을 저장한다는 뜻이 아니다

익숙한 집이나 학교를 눈을 감고 떠올려보면 대략 어느 방향에 문이 있고, 창문이 어디 있으며, 내가 어느 길로 이동해야 하는지 상상할 수 있다. 이런 능력을 흔히 지형기억 또는 공간경로기억(topographical memory)이라고 부른다.

하지만 공간기억을 특정 뇌 부위에 저장된 지도 한 장으로 생각하면 실제 신경계와 거리가 있다.

공간을 기억하고 이용하려면 최소한 세 가지가 필요하다.

먼저 눈앞의 장면을 알아봐야 한다. 다음으로 현재 내 몸이 어느 방향을 향하고 있는지 계산해야 한다. 마지막으로 현재 위치를 과거에 기억한 공간구조와 연결해야 한다.

해마는 ‘장소’보다 장소와 사건의 관계를 묶는다

측두엽 안쪽에 있는 해마(hippocampus)는 공간기억과 일화기억(episodic memory)에 핵심적인 구조다.

해마에서는 특정 장소에서 선택적으로 활성화되는 장소세포(place cell)가 발견된다. 하지만 이 사실 때문에 해마를 단순한 위치 저장소라고 이해하면 안 된다.

해마의 더 본질적인 기능은 어디에서, 언제, 무엇을 경험했는가를 하나의 사건구조로 묶는 데 있다.

예를 들어 “어제 오후에 도서관 2층에서 어떤 책을 읽었다”는 기억에는 장소, 시간, 물체, 행동이 하나의 관계로 연결되어 있다. 해마는 이런 관계적 기억을 구성하는 데 중요하다.

내후각피질은 공간 속 이동의 좌표계를 제공한다

해마 주변의 내후각피질(entorhinal cortex)에는 격자세포(grid cell)를 포함한 여러 종류의 공간표상 뉴런이 존재한다.

격자세포는 한 장소에만 반응하지 않는다. 공간을 이동할 때 일정한 간격의 반복적인 활성패턴을 보인다.

그래서 내후각피질-해마 회로는 공간 안에서 위치와 이동을 표현하는 내부 좌표계의 핵심으로 연구되고 있다.

후방비장피질은 현재 보는 방향과 기억 속 지도를 연결한다

현재 내가 보는 장면은 대체로 나를 기준으로 표현된다.

“문이 내 오른쪽에 있다.”

이것을 자기중심적 표상(egocentric representation)이라고 한다.

반면 장기기억 속 공간정보는 환경 자체를 기준으로 표현할 수 있다.

“그 문은 건물 북쪽 벽에 있다.”

이것은 환경중심적 표상(allocentric representation)이다.

후방비장피질(retrosplenial cortex)은 방향, 랜드마크, 현재 시야와 기억 속 공간구조를 연결하는 데 중요한 역할을 한다.

결국 공간기억은 한 부위에 들어 있는 지도가 아니다.

시각계가 장면을 분석하고, 두정계가 몸과 공간의 관계를 계산하며, 후방비장피질이 서로 다른 좌표계를 연결하고, 해마-내후각계가 장소와 사건의 관계를 조직하는 분산 시스템이다.

시각은 이미지를 ‘받아들이는 것’이 아니라 이미지를 ‘구성하는 것’이다

우리는 눈앞에 사과가 있으면 사과를 본다고 느낀다. 그러나 망막에 도달하는 것은 사과가 아니라 다양한 파장의 빛이다.

망막의 광수용체가 빛을 전기화학적 신호로 바꾸고, 이 신호는 여러 망막 회로와 시상을 거쳐 후두엽의 일차시각피질(primary visual cortex, V1)로 전달된다.

V1에서는 아직 ‘사과’가 만들어지지 않는다.

경계가 어디에 있는지, 선이 어느 방향인지, 밝기 대비가 어디에서 변하는지, 공간적으로 어떤 패턴이 존재하는지를 분석한다.

빛의 패턴

경계·방향·대비

형태

부분들의 관계

객체

의미

뇌는 처음부터 완성된 물체를 받아들이는 것이 아니다. 기본 특징을 분해하고, 고차 시각피질에서 다시 조합하면서 안정된 객체표상을 만든다.

복측 시각경로와 배측 시각경로는 서로 다른 질문에 답한다

후두엽에서 측두엽 방향으로 이어지는 복측 시각경로(ventral visual stream)는 주로 물체의 정체성과 관련된 처리를 한다.

“이것이 무엇인가?”

라는 질문에 가까운 계산이다.

반대로 후두엽에서 두정엽으로 이어지는 배측 시각경로(dorsal visual stream)는 단순히 물체의 위치를 계산하는 데서 끝나지 않는다.

“저 물체를 향해 내 몸을 어떻게 움직여야 하는가?”

를 계산한다. 그래서 현대적으로는 행동을 위한 시각(vision for action)이라는 표현이 더 적절하다.

컵을 집으려면 컵의 위치뿐 아니라 현재 손의 위치, 컵까지의 거리, 컵의 크기와 방향을 함께 계산해야 한다.

이 계산에는 상두정소엽(superior parietal lobule)후두정피질(posterior parietal cortex)을 포함한 두정계가 중요하다.

여기서 시각정보는 단순히 ‘보이는 것’에서 실제로 행동할 수 있는 공간좌표로 바뀐다.

머릿속 이미지는 실제 시각과 완전히 같지는 않지만 상당한 회로를 공유한다

눈을 감고 사과를 떠올려보라고 하면 많은 사람은 붉은색, 둥근 형태, 꼭지 같은 특징을 어느 정도 떠올릴 수 있다.

이것이 시각심상(visual imagery)이다.

시각심상은 실제 사물을 볼 때와 완전히 같은 상태는 아니지만, 고차 시각영역과 전두-두정 네트워크의 일부를 다시 이용한다.

즉 이미지는 머릿속에 저장된 사진을 꺼내는 것보다 기억에 저장된 특징과 관계를 다시 조립해 시각적 상태를 재구성하는 과정에 더 가깝다.

여기서 한 가지 중요한 점이 있다.

사람의 모든 사고가 반드시 이미지로 이루어지는 것은 아니다. 어떤 사람은 매우 선명한 시각심상을 사용하지만, 어떤 사람은 심상이 매우 약하거나 거의 없어도 정상적으로 사고하고 계산할 수 있다.

따라서 계산이나 추론을 단순히 ‘시각영역이 하는 일’로 설명해서는 안 된다.

수학적 계산은 시각화만으로 이루어지지 않는다

사칙연산을 할 때 숫자를 머릿속에 떠올리는 사람이 많다. 필산의 위치를 상상하거나 수직선을 떠올리기도 한다.

그래서 계산에 시각적 사고가 중요한 경우가 분명히 있다. 하지만 신경과학적으로 계산을 시각피질의 기능으로 환원하면 부정확하다.

수량과 크기의 관계를 처리할 때는 두정엽, 특히 두정내고랑(intraparietal sulcus, IPS)을 포함한 전두-두정 네트워크가 중요하게 관여한다.

이미 암기된 산술 사실을 불러올 때는 언어·기억 회로의 기여도 커질 수 있고, 복잡한 문제를 풀 때는 배외측 전전두피질과 작업기억계가 강하게 동원된다.

따라서 17 + 15를 계산한다는 것은 숫자 이미지를 보는 하나의 과정이 아니다.

수량표상, 기호인식, 작업기억, 규칙 적용, 기억검색이 결합된 계산이다.

사고에서 시각화는 강력한 도구다.
하지만 인간의 사고 전체가 시각적 이미지로 이루어진다는 뜻은 아니다.

인간의 고등사고는 시각·언어·공간·기억 표상을 상황에 따라 조합한다.

뇌 안에는 하나의 ‘통합적 표상 공간’이 있는 것이 아니다

우리는 하나의 장면을 하나의 경험으로 느낀다.

사람의 얼굴을 보면서 동시에 목소리를 듣고, 그 사람이 누구인지 기억하고, 내 몸이 어디에 있는지 느끼며, 상대방의 표정을 보고 감정까지 추론한다.

의식에서는 이것이 하나의 경험처럼 나타난다.

하지만 뇌 안에 모든 정보가 한곳으로 모이는 단일한 ‘통합 공간’이 따로 있는 것은 아니다.

시각정보는 시각계에서, 청각정보는 청각계에서, 신체감각은 체성감각계에서, 기억은 해마와 연합피질을 포함한 여러 회로에서, 목표와 규칙은 전전두-두정 네트워크에서 서로 다른 형태로 표현된다.

통합은 이 정보들이 한곳에 쌓이면서 이루어지기보다 서로 연결된 네트워크가 필요한 정보를 주고받으면서 일시적으로 하나의 상태를 구성하는 과정에 가깝다.

그래서 인간의 경험은 하나지만 그 경험을 만들어내는 계산은 분산되어 있다.

언어는 소리를 의미로 바꾸는 것보다 더 복잡하다

말소리는 본질적으로 시간 속에서 흘러간다.

사람이 “사과를 먹었다”라고 말할 때 귀에 문장이 통째로 들어오는 것이 아니다. 시간에 따라 변화하는 음향파형이 순서대로 들어온다.

청각계는 이 연속적인 신호에서 주파수, 강도, 시간적 변화와 같은 기본 특징을 분석한다.

신호는 달팽이관에서 시작해 뇌간의 여러 청각핵, 중뇌의 하구(inferior colliculus), 시상의 내측슬상체(medial geniculate body)를 거쳐 측두엽의 일차청각피질(primary auditory cortex)로 전달된다.

그 이후에는 훨씬 복잡한 변환이 일어난다.

음향패턴

음성특징

음소·음절

단어

문장구조

의미와 맥락

실제 말에는 단어 사이에 완벽한 공백도 없고, 화자마다 목소리와 속도, 억양도 다르다.

그럼에도 뇌는 연속된 음향신호에서 언어적으로 중요한 패턴을 안정적으로 추출한다.

베르니케 영역과 브로카 영역이라는 고전적 설명

과거에는 왼쪽 측두엽 뒤쪽의 베르니케 영역(Wernicke's area)이 언어 이해를 담당하고, 왼쪽 하전두회의 브로카 영역(Broca's area)이 언어 산출을 담당한다고 배웠다.

이 설명은 신경학적으로 매우 중요한 역사적 모델이지만, 현대 뇌과학에서는 지나치게 단순하다.

언어 이해와 생산은 넓은 측두-전두 네트워크에서 이루어진다.

하전두회의 덮개부분(pars opercularis)은 음운처리, 조음과 관련된 운동계획, 일부 구문처리에 비교적 더 관여하고, 삼각부분(pars triangularis)은 어휘와 의미선택, 의미적 경쟁을 조절하는 데 더 많이 관여하는 경향이 있다.

측두엽에서는 말소리, 단어, 의미와 관련된 다양한 처리가 분산되어 이루어진다.

따라서 언어는 ‘베르니케가 이해하고 브로카가 말한다’는 두 개의 상자보다 소리·의미·구문·발성·기억을 연결하는 네트워크로 이해하는 편이 맞다.

인간 언어의 핵심은 단순한 시퀀스가 아니라 ‘구조화된 시퀀스’다

언어에서 순서는 매우 중요하다.

“개가 사람을 물었다.”

“사람이 개를 물었다.”

는 같은 단어를 사용하지만 순서가 달라지면서 의미가 바뀐다.

하지만 인간 언어를 단순히 순서 처리 능력으로 설명할 수는 없다.

문장은 일렬로 늘어선 단어의 목록이 아니라 계층구조(hierarchical structure)를 가진다.

어떤 단어가 어떤 단어를 수식하는지, 어떤 구가 더 큰 구 안에 포함되는지, 주어와 술어가 어떤 관계를 이루는지를 계산해야 한다.

인간 언어를 구성하는 핵심 계산

시퀀스 + 관계 + 계층구조

이 원리는 언어를 넘어 인간의 사고 전체로 이어진다.

인간은 단순히 A 다음 B를 기억하는 것이 아니다.

A가 B의 원인이고, B는 C가 일어나기 위한 조건이며, D가 발생하면 B 대신 E를 선택해야 한다는 관계를 구성한다.

즉 시퀀스 안에 인과, 조건, 규칙, 계층을 삽입한다.

이 능력이 과학적 추론, 계획, 프로그래밍, 수학, 도구제작 같은 고차 인지의 기반이 된다.

생각은 꼭 문장으로만 이루어지지 않는다

사람이 복잡한 생각을 언어로 표현하는 경우가 많기 때문에 생각과 언어를 동일시하기 쉽다.

하지만 모든 사고가 문장으로 이루어지는 것은 아니다.

공간탐색, 얼굴인식, 운동계획, 음악적 예측, 시각심상, 수량판단은 완성된 문장을 만들지 않아도 수행할 수 있다.

다만 언어는 인간 사고를 크게 확장한다.

언어를 사용하면 눈앞에 없는 대상, 과거의 사건, 미래의 계획, 가상의 상황, 추상적인 규칙을 명시적으로 다룰 수 있다.

이것은 인간 언어의 중요한 특징 중 하나인 탈맥락화(decontextualization)와 연결된다.

즉 지금 눈앞에 존재하지 않는 것에 대해서도 말할 수 있다.

다만 인간 언어가 처음부터 ‘비맥락적 발화’에서 시작했다거나 특정 한 형태에서 직접 진화했다고 단정할 근거는 충분하지 않다. 언어 진화는 발성, 사회적 의사소통, 상징, 공동주의, 계층적 조합능력 등 여러 요소가 함께 변화한 과정으로 보는 편이 타당하다.

전전두피질은 생각이 저장된 곳보다 ‘현재 문제를 조직하는 곳’에 가깝다

고등사고에서 특히 중요한 것이 배외측 전전두피질(dorsolateral prefrontal cortex, DLPFC)과 두정피질을 포함한 전두-두정 네트워크(frontoparietal network)다.

이 네트워크는 작업기억, 규칙 유지, 반응억제, 문제해결, 주의조절과 깊게 관련된다.

작업기억은 짧게 기억하는 능력이 아니다

작업기억(working memory)은 정보를 잠시 저장하는 기능으로 설명되는 경우가 많다. 하지만 더 중요한 것은 정보를 유지하면서 조작한다는 점이다.

예를 들어 7, 2, 9를 듣고 9, 7, 2로 다시 배열하려면 숫자를 기억하는 것만으로는 부족하다.

정보를 유지하면서 구조를 바꿔야 한다.

구성적 사고(constructive thinking)를 신경과학적으로 풀어쓰면

기억과 현재 입력에서 필요한 요소를 꺼내 작업기억 안에 유지하고, 그 요소들의 관계를 목적에 맞게 다시 배열해 새로운 내부 모델을 만드는 과정이라고 할 수 있다.

이 능력이 인간에게 특히 발달해 있는 것은 맞지만, ‘기존 요소를 조합해 새로운 행동을 만드는 능력’ 자체가 인간에게만 존재한다고 단정할 수는 없다.

인간의 특징은 그 능력이 언어와 계층적 계획, 장기적 미래예측과 결합하면서 매우 높은 수준까지 확장되었다는 데 있다.

전두극피질은 더 긴 시간척도의 목표를 관리한다

전전두피질 가장 앞쪽의 전두극피질(frontopolar cortex)은 현재 행동보다 더 먼 목표, 여러 목표 사이의 관계, 미래에 수행해야 할 행동을 유지하는 데 관여한다.

책을 읽으면서도 “조금 뒤에 이메일을 보내야 한다”는 목표를 유지하는 것이 한 예다.

이처럼 미래에 수행할 행동을 기억하는 기능을 전향기억(prospective memory)이라고 한다.

행동은 ‘하고 싶다’는 느낌만으로 시작되지 않는다

인간의 행동을 설명할 때 흔히 동기(motivation), 욕구(drive), 의지 같은 단어를 쓴다.

하지만 신경과학적으로 동기를 특정 ‘드라이브 영역’ 하나에 대응시키기는 어렵다.

행동을 선택하려면 뇌는 그 행동의 보상, 필요한 노력, 성공확률, 시간비용, 다른 선택지를 함께 평가해야 한다.

이 과정에는 복내측 전전두피질(ventromedial prefrontal cortex, vmPFC), 안와전두피질(orbitofrontal cortex, OFC), 전방 대상피질(anterior cingulate cortex, ACC), 복측선조체(ventral striatum), 중뇌 도파민계 등이 관여한다.

동기를 신경계의 계산으로 표현하면

“나는 얼마나 원하고 있는가?”보다
“이 행동을 지금 실행할 가치가 있는가?”에 가깝다.

어린아이에서 성인으로 발달하면서 목표지향적 행동(goal-directed behavior)이 더 정교해지는 것도 전전두피질, 기저핵, 보상계, 사회적 학습이 함께 성숙하기 때문이다.

운동은 명령을 내려보내는 과정이 아니라 계속 수정되는 제어과정이다

운동을

생각 → 명령 → 근육

으로 이해하면 실제 신경계의 가장 중요한 부분이 빠진다.

우리가 컵을 들 때 뇌는 운동명령을 내려보낸 뒤 기다리지 않는다.

손가락이 컵에 닿는 순간 촉각이 들어오고, 컵이 예상보다 무거우면 힘을 증가시키며, 미끄러지기 시작하면 손가락 압력을 조절한다.

행동계획

운동 실행

감각 피드백

예측오차 계산

운동 수정

즉 운동은 폐쇄루프 제어(closed-loop control)다.

일차운동피질은 정교한 수의운동 출력에 중요하다

일차운동피질(primary motor cortex, M1)은 피질척수로(corticospinal tract)를 통해 척수 운동계에 강한 영향을 미치며, 특히 손가락처럼 정교한 수의운동에 중요하다.

하지만 M1을 각각의 근육을 켜고 끄는 버튼판처럼 이해해서는 안 된다.

많은 운동피질 뉴런은 하나의 근육보다 여러 근육이 만드는 움직임의 방향, 힘, 협응과 관련된다.

전운동피질과 보조운동영역은 움직임의 구조를 준비한다

전운동피질(premotor cortex)보조운동영역(supplementary motor area, SMA)은 움직이기 전에 어떤 동작을 선택하고, 여러 동작을 어떤 순서로 연결할지 조직하는 데 중요하다.

여기에 기저핵(basal ganglia)은 여러 가능한 행동 가운데 무엇을 실행하고 무엇을 억제할지를 조절하고, 반복되는 행동의 습관화에도 깊게 관여한다.

소뇌는 예측과 실제 움직임의 차이를 줄인다

소뇌(cerebellum)는 단순히 균형을 잡는 기관이 아니다.

운동명령을 보낼 때 신경계는 “이 명령을 보내면 몸이 이렇게 움직일 것이다”라는 예측을 함께 만든다.

이를 전향모델(forward model)과 연결해 설명할 수 있다.

실제 움직임에서 돌아온 감각정보와 예측값 사이에 차이가 생기면 그 오차를 이용해 다음 움직임을 수정한다.

운동 숙련은 단순히 근육이 강해지는 현상이 아니다.

반복할수록 예측한 움직임과 실제 움직임의 차이가 작아지도록 내부 모델이 정교해지는 과정이다.

‘힘이 얼마나 들어갔는지 느끼는 것’도 하나의 감각이 아니다

움직일 때 “내가 어느 정도 힘을 주고 있다”고 느끼는 경험을 하나의 독립된 필링 오브 스트렝스(feeling of strength) 영역으로 설명하는 것은 현대 신경과학의 표준적 표현은 아니다.

그 느낌에는 여러 신호가 결합된다.

근육과 힘줄, 관절에서 올라오는 고유수용감각(proprioception), 운동명령의 사본에 해당하는 원심성 사본(efference copy), 피로와 심박, 호흡과 관련된 내수용감각(interoception), 그리고 실제 운동 결과가 함께 통합된다.

따라서 우리가 느끼는 노력감과 힘의 감각은 단일 부위가 생성하는 신호가 아니라 운동명령과 신체 피드백의 비교 결과에 가깝다.

넘어질 때 몸을 지키는 반응 역시 전두엽 한 영역의 기능이 아니다

넘어질 때 몸을 보호하는 반응을 특정 ‘반사 영역’ 하나로 설명하는 것도 지나치게 단순하다.

몸이 기울어지면 내이의 전정기관(vestibular apparatus)이 머리의 회전과 선형가속도를 감지한다.

신호는 뇌간의 전정핵으로 전달되고, 전정척수로(vestibulospinal tract)망상척수로(reticulospinal tract)를 통해 빠른 자세반응을 일으킨다.

소뇌는 몸의 움직임을 조정하고, 그보다 느린 시간대에는 대뇌피질과 기저핵이 발을 내딛거나 손을 뻗는 보호행동을 선택한다.

즉 균형회복은 반사, 뇌간, 소뇌, 기저핵, 대뇌피질이 서로 다른 시간척도에서 협력하는 다층적 제어과정이다.

반복되는 행동은 ‘시퀀스’에서 ‘청크’로 압축된다

처음 피아노를 배울 때는 손가락 움직임 하나하나를 의식해야 한다.

A → B → C → D가 네 개의 독립적인 행동처럼 느껴진다.

하지만 충분히 연습하면 [A-B-C-D] 전체가 하나의 행동단위처럼 실행된다.

이를 운동 청크(motor chunk)라고 한다.

숙련자가 빠른 이유는 모든 동작을 더 빨리 생각하기 때문이 아니다.

여러 동작이 하나의 묶음으로 압축되어 불러와지기 때문이다.

이 과정에 전운동피질, 보조운동영역, 기저핵, 운동피질, 소뇌가 함께 관여한다.

인간 지능을 이해하는 중요한 열쇠는 ‘계층화된 시퀀스’다

말에도 순서가 있고, 행동에도 순서가 있으며, 사건기억에도 시간적 순서가 있다.

계획 역시 미래의 행동을 시간적으로 조직한다.

그래서 시퀀스는 인간 뇌의 여러 기능을 관통하는 중요한 원리다.

하지만 인간 지능의 특징은 단순히 긴 시퀀스를 기억하는 것이 아니다.

더 중요한 것은 여러 시퀀스를 계층적으로 묶는 능력이다.

커피를 만드는 행동을 생각해보자.

커피 만들기

물 끓이기 / 컵 준비 / 추출하기

물을 넣기 / 전원을 켜기 / 기다리기

행동은 단순한 일렬 순서가 아니다.

상위 목표 → 하위 목표 → 세부 행동 이라는 계층을 가진다.

인간이 집을 짓고, 프로그램을 만들고, 과학실험을 수행하는 것은 수백 개의 동작을 그대로 암기하기 때문이 아니다.

복잡한 목표를 하위 목표로 나누고, 필요에 따라 순서를 바꾸며, 상황이 달라지면 일부 시퀀스를 다른 것으로 교체할 수 있기 때문이다.

이것이 구성적 사고와 계획의 핵심이다.

글쓰기가 사고를 정교하게 만드는 이유도 여기에 있다

글쓰기는 생각을 단순히 기록하는 행위가 아니다.

글을 쓰려면 기억에서 정보를 꺼내고, 중요한 내용을 선택하고, 앞 문장을 작업기억에 유지하고, 다음 문장과 논리적으로 연결해야 한다.

전체 구조를 다시 보고, 중복을 제거하고, 논리적 순서를 바꾸고, 불필요한 문장을 삭제해야 한다.

즉 글쓰기는 언어계와 기억계, 전두-두정 인지통제계가 동시에 사용하는 고차 인지활동이다.

그리고 결정적인 장점이 하나 더 있다.

생각을 뇌 밖에 꺼낼 수 있다는 것이다.

머릿속 작업기억은 제한적이다. 하지만 글로 적어놓으면 이미 적힌 내용을 다시 보고, 비교하고, 배열을 바꾸고, 더 큰 구조 안에 넣을 수 있다.

종이와 화면은 외부 작업기억(external working memory)으로 작동한다.

글쓰기가 사고를 강화하는 이유는 문장을 많이 쓰기 때문이 아니라, 머릿속에서 동시에 유지하기 어려운 정보를 바깥에 펼쳐놓고 구조를 직접 조작할 수 있기 때문이다.

이 모든 고등기능의 가장 아래에는 뉴런의 전기·화학 과정이 있다

지금까지는 뇌 영역과 네트워크 수준의 이야기였다. 한 단계 더 내려가면 모든 계산은 결국 뉴런의 물리적 과정으로 구현된다.

뉴런 안과 밖에는 나트륨 이온 Na⁺, 칼륨 이온 K⁺ 등 여러 이온의 농도 차이가 존재한다.

세포막의 선택적 투과성과 이온통로, 나트륨-칼륨 펌프 등의 작용으로 뉴런에는 휴지막전위(resting membrane potential)가 형성된다.

다른 뉴런에서 방출된 신경전달물질이 수용체에 결합하면 이온통로의 상태가 바뀌고 막전위가 조금씩 변한다.

이를 시냅스후전위(postsynaptic potential)라고 한다.

하나의 뉴런은 수많은 입력을 받으며, 어떤 입력이 언제 들어왔는지, 수상돌기의 어디에 들어왔는지, 흥분성인지 억제성인지에 따라 결과가 달라진다.

즉 뉴런 하나도 이미 시간과 공간을 통합하는 계산장치다.

임계값을 넘으면 활동전위가 발생한다

축삭 초기분절(axon initial segment)의 막전위가 임계값을 넘으면 전압개폐성 나트륨 통로가 열리고 Na⁺가 빠르게 유입된다.

막전위가 급격히 올라가는 것이 탈분극(depolarization)이다.

곧이어 나트륨 통로가 불활성화되고 전압개폐성 칼륨 통로가 열리면서 K⁺가 빠져나간다.

막전위가 다시 내려가는 과정이 재분극(repolarization)이다.

이렇게 만들어진 짧은 전기적 사건이 활동전위(action potential)다.

하지만 뇌의 정보는 단순한 펄스의 순서만으로 표현되지 않는다

모든 뉴런이 기본적으로 활동전위를 사용한다고 해서 뇌의 정보가 단순한 동일 펄스의 순서만으로 표현된다고 보면 안 된다.

어떤 뉴런이 발화하는지, 얼마나 자주 발화하는지, 정확히 언제 발화하는지, 여러 뉴런의 활동이 어떤 패턴을 이루는지가 모두 중요하다.

즉 뇌에서는 발화율(firing rate), 발화시점(spike timing), 집단 부호(population coding), 뇌 진동의 위상, 시냅스 강도, 도파민과 아세틸콜린 같은 신경조절물질이 함께 정보를 구성한다.

뇌를 단순한 전기 펄스 발생기로 볼 수 없는 이유다.

학습은 ‘내용을 넣는 것’이 아니라 회로의 다음 상태를 바꾸는 것이다

학습을 컴퓨터 파일 저장처럼 이해하면 실제 뇌와 상당한 차이가 있다.

반복 경험에 따라 뉴런 사이의 연결효율이 달라진다.

일부 시냅스는 강해지고, 일부는 약해지며, 새로운 연결이 생기거나 기존 회로의 구조가 재편되기도 한다.

대표적인 기전이 장기강화(long-term potentiation, LTP)장기억제(long-term depression, LTD)다.

학습을 가장 본질적으로 표현하면

어떤 내용을 뇌 안에 넣는 것이 아니라,
어떤 신경상태가 다음 신경상태를 얼마나 쉽게 불러오게 할지를 바꾸는 과정이라고 할 수 있다.

그래서 구조화된 지식이 강하다.

수초, 전류누설, 랑비에 결절, 도약전도를 서로 독립된 네 개의 사실로 외우는 것보다

수초 형성

막을 통한 전류누설 감소

랑비에 결절 중심의 활동전위 재생

도약전도

빠르고 효율적인 신호전달

이라는 인과관계로 연결하는 편이 훨씬 기억에 강하다.

한 개념이 다른 개념을 불러오는 검색단서가 되기 때문이다.

그렇다면 단백질과 DNA는 이 모든 것과 어떻게 연결되는가

뇌도 결국 생물학적 조직이다. 뉴런과 시냅스가 작동하려면 단백질이 필요하다.

이온통로, 수용체, 효소, 세포골격, 신경전달물질을 합성하고 분해하는 단백질, 시냅스 구조를 유지하는 단백질이 모두 신경기능에 필수적이다.

DNA는 이러한 단백질을 만들기 위한 유전정보를 담고 있다.

다만 “DNA 안에 35억 년의 진화가 그대로 기록되어 있다”거나 “DNA가 뇌의 비밀번호다”라고 표현하는 것은 비유로는 가능하지만 과학적으로는 너무 단순하다.

현재 인간의 유전체는 긴 진화역사의 결과지만, 그 역사가 연대기 형태로 DNA 안에 저장되어 있는 것은 아니다.

자연선택, 돌연변이, 유전자 중복, 유전자 조절 변화 등을 거치면서 현재의 신경계 구조와 발달 프로그램이 형성된 것이다.

사람마다 약물반응이 다른 이유 역시 단백질 서열 차이 하나로만 설명되지 않는다.

유전변이, 약물대사 효소, 수용체 발현, 간과 신장 기능, 나이, 환경, 다른 약물과의 상호작용 등이 함께 영향을 준다.

그럼에도 가장 아래 수준에서는 분명한 사실이 있다.

생각과 기억과 언어와 의식은 생물학적 물질에서 분리되어 존재하지 않는다.

이온통로와 수용체, 시냅스 단백질, 유전자 발현, 세포대사와 같은 물질적 과정 위에서 뉴런의 회로가 작동하고, 그 회로의 집단활동에서 인지가 나타난다.

결국 인간의 뇌는 무엇을 하는 시스템인가

지금까지 공간기억, 시각, 심상, 계산, 언어, 사고, 동기, 운동, 학습을 살펴봤다.

표면적으로는 서로 전혀 다른 능력처럼 보인다.

하지만 기능적으로 연결하면 하나의 공통된 구조가 나타난다.

감각 입력

기본 특징 분석

객체·공간·언어 표상 구성

기억과 맥락에 연결

현재 목표와 가치 평가

행동 선택

행동 시퀀스와 계층구조 구성

운동 실행

감각 피드백과 예측오차

학습과 회로 변화

이 관점에서 보면 시각은 단순한 입력장치가 아니고, 기억은 저장창고가 아니며, 전전두피질은 ‘생각이 들어 있는 곳’이 아니다.

기저핵도 단순한 운동기관이 아니고, 소뇌도 단순한 균형기관이 아니다.

각각의 시스템은 앞 단계에서 만들어진 정보를 다음 계산이 사용할 수 있는 형태로 바꾸는 역할을 한다.

인간 지능의 핵심을 한 문장으로 정리하면

시간적으로 전개되는 정보를 공간·관계·인과·계층을 가진 내부 모델로 구성하고, 그 모델을 현재 목표에 맞게 재배열한 뒤, 아직 일어나지 않은 미래를 예측하고 행동을 조직하는 능력이라고 할 수 있다.

인간은 단순히 긴 시퀀스를 기억하는 동물이 아니다.

시퀀스 자체를 대상으로 사고하고, 여러 시퀀스를 상위 목표 아래 묶고, 상황이 바뀌면 일부 구조를 다른 구조로 대체하고, 아직 일어나지 않은 행동을 머릿속에서 먼저 실행해볼 수 있다.

공간탐색, 언어, 글쓰기, 수학, 도구제작, 과학적 추론이 겉으로는 전혀 다른 능력처럼 보이면서도 깊은 수준에서는 같은 신경계 원리를 공유하는 이유가 여기에 있다.

결국 뇌를 이해한다는 것은 각 부위의 이름을 많이 외우는 것이 아니다.

감각이 어떻게 내부 표상이 되고, 그 표상이 어떻게 기억과 의미를 만나며, 기억과 의미가 어떻게 목표와 행동으로 연결되고, 행동의 결과가 다시 뇌의 회로를 바꾸는지를 이해하는 것이다.

뇌의 진짜 기능적 구조는 영역들의 목록보다 정보가 계속 다른 형태로 변환되는 과정에 있다.

+ Recent posts