본문으로 건너뛰기
22/3030개 중 22장

AI agent란 무엇인가: 다섯 가지 고전 유형과 두 경쟁 정의

진공청소기 세계를 네 번 깨뜨리며 다섯 가지 고전 agent 유형을 얻고, 도구 하나가 39 token 호출을 420으로 바꾸는 과정을 봅니다.

이 페이지에서

같은 모델에 같은 질문을 두 번 던졌습니다. 가중치도 같고 greedy decoding도 같았습니다. 유일한 차이는 두 번째에는 카탈로그에 도구가 하나 있었다는 점입니다.

TEXT
no tools in the catalogue
  turn 1  prompt=  39  out=  8  finish=stop        TEXT "The capital of France is Paris."
  => model calls=1  prompt tokens=39  output=8  wall=974 ms

one tool in the catalogue: get_temperature(city)
  turn 1  prompt= 185  out= 20  finish=tool_calls  CALL get_temperature({"city": "Paris"})
          tool  get_temperature -> {"city":"Paris","celsius":11}
  turn 2  prompt= 235  out= 18  finish=stop        TEXT "The capital of France is Paris. It is
                                                        currently at 11 degrees Celsius."
  => model calls=2  prompt tokens=420  output=38  wall=6,685 ms

호출 하나가 둘이 됐습니다. input token 39개가 420개, 10.8배가 됐습니다. 1초 미만이던 시간이 거의 7초가 됐습니다. 그리고 답변에는 아무도 요청하지 않은 사실이 추가됐습니다. 날씨를 전혀 언급하지 않은 질문에 대해 모델이 스스로 호출하기로 고른 도구에서 온 사실이었습니다.

두 번째 시스템은 2026년 업계 대부분이 agent라고 부르는 것입니다. 또는 agent가 아닙니다. 가장 널리 읽히는 두 정의 중 어느 쪽을 여느냐에 따라 다릅니다. 그리고 그 둘은 같은 말을 하지 않습니다. 하나는 자기 자신과도 완전히 일치하지 않습니다.

이 장은 그 불일치에 관한 이야기입니다. 어휘 다툼이 아닙니다. 두 정의는 서로 다른 축에 경계를 긋고, 어떤 축을 고르느냐가 무엇을 만들지와 무엇에 비용을 낼지를 결정합니다. 둘 다 더 오래된 분류법 위에 서 있고, 그것을 얻는 가장 싼 방법은 세상에서 가장 형편없는 agent를 만들어 보는 것입니다.

세부 정보 보기

이 장이 앞 장들에서 필요로 하는 것.

  • **13장**은 단일 호출이 시간상 얼마의 비용을 갖는지 측정했습니다. 이 장은 그것에 턴 수를 곱합니다.
  • 15장: prompt는 모델의 완전한 상태입니다. 호출이 끝나면 아무것도 살아남지 않기 때문입니다.
  • 16장: input token은 대화의 제곱에 비례해 늘어납니다.
  • 18장: 도구 카탈로그, 그리고 모델이 요청하고 여러분의 코드가 실행하는 왕복 과정입니다.

여기에는 tensor가 없습니다. 이 장은 TypeScript로 되어 있습니다. 14장의 언어 규칙이 그 위치에 두었고, 이 장의 loop는 23장 loop의 직접적인 조상입니다.

이 분야에서 가장 오래된 예시는 A와 B라는 두 칸으로 된 세계의 진공청소기입니다. 각 칸은 깨끗하거나 더럽습니다.1 agent가 옳거나 틀릴 수 있는 가장 작은 세계이기 때문에 모든 교과서에 살아남았습니다.

percept는 한 쌍입니다. 내가 어디에 있는지, 그리고 여기가 더러운지입니다. action은 SUCK, LEFT, RIGHT입니다. 전체 프로그램은 한 줄입니다.

reflex.tsTS
type Percept = { dirty: boolean; where?: "A" | "B" };
type Action = "SUCK" | "LEFT" | "RIGHT";

const textbook = (p: Percept): Action =>
  p.dirty ? "SUCK" : p.where === "A" ? "RIGHT" : "LEFT";   

두 칸 세계의 모든 시작 configuration에 대해 실행해 봅니다.

TEXT
A dirty, B dirty, start A    -> steps=3 clean=true
A clean, B dirty, start A    -> steps=2 clean=true
A dirty, B clean, start B    -> steps=2 clean=true

이것이 simple reflex agent입니다. 이전에 있었던 어떤 것에 대한 memory 없이, 현재 percept만 보고 행동합니다. 장난감 같은 범주가 아닙니다. 온도조절기도 여기에 속하고, 대화가 붙지 않은 언어 모델 단일 호출도 마찬가지입니다.

이제 현실이 그러하듯 이것을 망가뜨려 봅니다. 실제 진공청소기 로봇에는 먼지 sensor와 bumper가 있지, 카펫 밑에 A라고 쓰인 칸이 있는 것이 아닙니다. percept에서 location을 빼고 나머지는 바꾸지 않습니다.

reflex.tsTS
const dirtOnly = (p: Percept): Action => (p.dirty ? "SUCK" : "RIGHT");
TEXT
A dirty, B dirty, start A    -> steps=3   clean=true   still dirty=0
      t=0 at=A percept={dirty:true}  -> SUCK
      t=1 at=A percept={dirty:false} -> RIGHT
      t=2 at=B percept={dirty:true}  -> SUCK

A dirty, B clean, start B    -> steps=500 clean=false  still dirty=1
      t=0 at=B percept={dirty:false} -> RIGHT
      t=1 at=B percept={dirty:false} -> RIGHT
      t=2 at=B percept={dirty:false} -> RIGHT
      t=3 at=B percept={dirty:false} -> RIGHT

같은 프로그램, 두 칸입니다. 한 시작 상태에서는 세 단계 만에 끝납니다. 다른 상태에서는 오른쪽 벽에 500번 들이받고, 배터리가 닳을 때까지 계속 그럴 것입니다. 두 상황의 차이를 지각할 수 없으므로 그 둘에서 다르게 행동할 수 없습니다. Russell과 Norvig는 일반 결과를 한 줄로 말합니다. 부분적으로 관찰 가능한 환경에서는 simple reflex agent에게 무한 loop가 종종 피할 수 없습니다.1

더 똑똑한 것에 손대기 전에 측정해 볼 가치가 있는, 한 줄짜리이자 memory가 필요 없는 수정이 있습니다.

reflex.tsTS
let seed = 12345;
const rnd = () => ((seed = (seed * 1103515245 + 12345) & 0x7fffffff) / 0x7fffffff);

const coin = (p: Percept): Action => (p.dirty ? "SUCK" : rnd() < 0.5 ? "LEFT" : "RIGHT");  

모든 방이 더러운 복도에서 세 가지 크기로 2,000번 실행했습니다. 전체에 같은 seeded generator를 썼습니다.

roomsmean stepsmedianworst of 2,000never finished
24.04130
416.614810
868.7523060

무작위화는 loop를 완전히 제거합니다. 또한 비용도 듭니다. 무엇을 해야 하는지 알고 있다면 방 8개에는 이동 15번이면 충분하지만, 이 agent는 평균 68.7번 움직였고 한 번은 306번 걸렸습니다. 이것이 이 장 전체의 축소판입니다. 우리가 추가하는 모든 능력은 이전 agent가 처리할 수 없던 경우의 정확성을 사 오고, 그 대가를 먼저 이름 붙여야 하는 어떤 통화로 청구합니다.

필요한 순간에 부품 이름 붙이기

섹션 링크: 필요한 순간에 부품 이름 붙이기

agentsensor를 통해 환경을 지각하고 actuator를 통해 행동합니다. agent program은 percept에서 action으로 가는 함수입니다. 위의 모든 listing이 하나의 agent program입니다. percept sequence는 지금까지 지각한 모든 것이며, simple reflex agent는 마지막 항목을 제외한 전부를 무시합니다.

합리성은 대부분의 글이 잘못 이해하는 단어이며, 이것을 제대로 이해해야 이 장의 나머지를 쓸 수 있습니다. agent는 그 자체로 합리적이거나 비합리적인 것이 아닙니다. Russell과 Norvig는 rational agent를, 가능한 각 percept sequence에 대해 그 sequence의 증거와 agent가 가진 내장 지식이 주어졌을 때 performance measure를 극대화할 것으로 기대되는 action을 선택하는 agent로 정의합니다.1 performance measure는 agent 안에 있지 않습니다. 그것은 설계자의 것입니다. rationality는 그것에 상대해서만 정의됩니다.

명세는 관례적으로 네 가지, PEAS로 씁니다. performance measure, environment, actuators, sensors입니다.

진공청소기 로봇운영 중인 지원 agent
Performance measure배터리 단위당 깨끗한 칸달러당 해결된 티켓, escalation 없이
Environment바닥, 먼지, 가구, 카펫티켓 queue, 여러분의 database, 고객
Actuators바퀴, 흡입도구 호출
Sensors먼지 sensor, bumper사용자 메시지, 도구 결과

어느 행이 튀는지 보세요. 2026년에 agent를 만드는 거의 모든 팀은 E, A, S를 적습니다. 도구 schema, integration, 메시지 format입니다. 코드가 그것들 없이는 실행되지 않기 때문입니다. 거의 아무도 P를 적지 않습니다. 그것이 없으면 “우리 agent가 잘하고 있다”는 누구도 확인할 수 있는 의미를 갖지 못하고, “rational”은 시스템 전체에 적용될 수 없으며 시연에만 적용될 수 있습니다. 29장은 P를 숫자로 바꾸는 일에 관한 장이고, 그래서 존재합니다.

TEXT
    ┌───────────────────────── the environment ─────────────────────────┐
    │                                                                   │
    │   ┌──────────────────────── the agent ─────────────────────┐      │
    │   │                                                        │      │
 ───┼──►│  sensors  ──►  the agent program  ──►  actuators  ─────┼──────┼──►
percept │                                                        │    action
    │   └────────────────────────────────────────────────────────┘      │
    └───────────────────────────────────────────────────────────────────┘

              the performance measure lives out here, in the head of
              whoever built the thing, and the agent cannot change it

task environment는 다시 일곱 가지 축으로 분류되며, 그중 다섯 가지가 여기서 대부분의 난이도를 결정합니다. 완전 관찰 가능 또는 부분 관찰 가능, deterministic 여부, episodic 또는 sequential, static 또는 dynamic, known 또는 unknown입니다.1 실제 network 위의 실제 도구와 대화하는 agent는 이 다섯 축 모두에서 어려운 구석에 있습니다. temperature 0에서도 non-deterministic이고(17장), 과소평가되는 하나는 unknown이라는 점입니다. 여러분은 자기 도구가 세계에 무엇을 하는지에 대한 신뢰할 만한 모델이 없습니다. 그래서 23장의 loop에는 planning보다 error handling이 더 필요합니다.

memory를 추가하고 다음 벽을 찾기

섹션 링크: memory를 추가하고 다음 벽을 찾기

실제 바닥은 1차원이 아니므로 세계를 평면도로 승격합니다. hash mark는 벽, asterisk는 먼지이고, 로봇은 가운데 방에서 시작합니다.

TEXT
        col  0 1 2 3 4 5 6
      row 0  * . . # . . *
      row 1  . # . # . # .
      row 2  . # . S . # .        S = the robot starts here
      row 3  . # . # . # .
      row 4  * . . # . . *

명백한 업그레이드는 memory입니다. agent는 map을 유지합니다. 자신이 서 있었던 모든 칸과 bumper가 작동한 모든 칸입니다. 규칙은 방문하지 않은 인접 칸으로 걸어가는 것입니다. 오른쪽, 아래, 왼쪽, 위 순서로 시도하고, 주변이 모두 알려져 있으면 물러섭니다. 이것이 model-based reflex agent입니다. percept history에서 internal state를 유지하므로 지금 볼 수 없는 것에 근거해 행동할 수 있습니다.

실제 개선이지만, 여전히 충분하지 않습니다.

TEXT
5,000 steps allowed -> steps=5,000  distinct squares visited=13/25  still dirty=2/4

5,000번 움직였지만 바닥의 절반은 한 번도 보지 못했습니다. map은 맞고 규칙도 맞습니다. agent가 하지 못하는 것은 map을 사용해 어딘가로 가는 일입니다. 규칙은 언제나 “내 네 이웃 중 어느 칸으로 들어가야 하는가”에만 답하므로, 주변에 방문하지 않은 칸이 떨어지면 여덟 번 움직이면 닿는 곳에 방문하지 않은 칸이 있고 나는 거기에 서 있고 싶다라는 생각을 표현할 방법이 없습니다. agent는 자신이 어디 있는지 압니다. 어디 있고 싶은지는 모릅니다.

goal, 그리고 한 경로를 다른 경로보다 선호할 이유

섹션 링크: goal, 그리고 한 경로를 다른 경로보다 선호할 이유

goal-based agent는 세계 모델 위에 자신이 가져오고 싶은 상황에 대한 설명을 들고, 그곳에서 끝나는 sequence를 찾을 때까지 action sequence를 search하여 action을 선택합니다. goal은 action selection을 lookup에서 search로 바꿉니다.

목표는 “더러운 칸이 하나도 남지 않음”입니다. search는 가장 가까운 더러운 칸까지 breadth-first로 걷는 것이고, 그것이 반환하는 path가 plan입니다.

TEXT
goal-based (fewest moves)      -> moves=27  battery=52  still dirty=0
      from 2,3 -> 4,6 via 5 moves:  2,3 2,4 3,4 4,4 4,5 4,6
      from 4,6 -> 0,6 via 4 moves:  4,6 3,6 2,6 1,6 0,6
      from 0,6 -> 4,0 via 10 moves: 0,6 0,5 0,4 1,4 2,4 2,3 2,2 3,2 4,2 4,1 4,0
      from 4,0 -> 0,0 via 4 moves:  4,0 3,0 2,0 1,0 0,0

27번 움직였고 바닥은 깨끗합니다. 하지만 배터리 열과 plan의 마지막 구간을 보세요. 0번 열은 카펫입니다. 카펫 칸을 건너면 배터리 6단위가 들고, 타일 칸은 1단위가 듭니다. agent는 0번 열로 올라가 집에 갔습니다. 여덟 번 대신 네 번 움직이면 되기 때문입니다. 하지만 그 네 번의 카펫 이동은 24가 들었고, 여덟 번 돌아가는 길은 13이면 됐습니다.

다르게 할 수 없습니다. goal은 binary test입니다. 바닥이 깨끗하거나 그렇지 않거나입니다. 깨끗한 바닥으로 끝나는 모든 plan은 똑같이 goal을 만족하므로, 여러 plan이 성공하면 agent는 그중 무엇을 고를 이유가 없습니다. 한 성공을 다른 성공보다 선호하려면 outcome 위의 숫자가 필요하고, 그 숫자가 utility function입니다. 그것을 극대화하는 agent가 utility-based agent입니다.

코드의 변화는 search 안의 한 항입니다. breadth-first search는 이동 횟수를 셉니다. 대신 비용을 세게 만들면 Dijkstra algorithm이 되고, 다른 agent가 됩니다.

search.tsTS
const nd = dist.get(k)! + (byCost ? cell.cost : 1);   // <- the entire difference
TEXT
goal-based    (fewest moves)   -> moves=27  battery=52  still dirty=0
utility-based (cheapest route) -> moves=31  battery=41  still dirty=0
      from 4,0 -> 0,0 via 8 moves: 4,0 4,1 4,2 3,2 2,2 1,2 0,2 0,1 0,0

네 번 더 움직였고 배터리 11단위를 덜 썼습니다. 21퍼센트 더 쌉니다. 같은 goal, 같은 map, 한 항만 제외하고 같은 코드입니다. 두 agent는 자신이 무엇을 잘하려고 하는지만 다르고, 집으로 가는 경로도 달라집니다.

이 지점은 agent가 스스로 만들 수 없는 무언가를 처음으로 필요로 하는 지점이기도 합니다. 누군가는 이동 한 번에 비해 배터리 한 단위의 가치가 얼마인지 결정해야 합니다. utility는 agent가 계산할 수 있는 형태로 쓰인 performance measure이고, 그것을 쓰는 것은 설계자의 일입니다. 사람들이 agent가 “잘못된 것을 최적화했다”고 말할 때 그것은 거의 버그를 뜻하지 않습니다. 이 줄을 부주의하게 썼다는 뜻입니다.

다섯 번째 유형, 그리고 그것이 잘못되는 방식

섹션 링크: 다섯 번째 유형, 그리고 그것이 잘못되는 방식

이제 먼지가 다시 생기게 합니다. 네 방은 서로 다른 네 속도로 다시 더러워지고, agent는 그 속도를 듣지 못합니다. agent는 tick마다 방 하나를 방문하고 그 방만 봅니다. performance measure는 4,000 tick 동안 방이 더러운 채로 보낸 room-tick입니다. 낮을수록 좋습니다.

교과서의 분해에서 learning agent는 위 유형 중 어느 것이든 세 부분이 더해진 것입니다. agent를 바꾸는 learning element, 고정된 performance standard에 비춰 agent가 얼마나 잘하는지 알려 주는 critic, 그리고 무엇을 가르쳐 줄 수 있는지를 기준으로 시도할 만한 action을 제안하는 problem generator입니다.1 같은 환경의 세 policy입니다. 첫 번째는 학습하지 않습니다. 두 번째와 세 번째는 같은 것을 학습하지만 다르게 사용합니다.

policydirty-room-ticks over 4,000versus the patrol
고정 round-robin 순찰, 학습 없음2,290
learner A: 각 방의 먼지 발생률을 추정한 뒤 먼지가 가장 있을 법한 곳으로 감11,8205.2× worse
learner B: 같은 추정치에 마지막 방문 이후 시간을 가중1,57631 % better

숨은 rate는 부엌 0.35, hall 0.05, 서재 0.02, 다락 0.01이었습니다. 그리고 learner A는 그것들을 찾아냈습니다. 집에서 부엌이 가장 더러운 방이라는 것을 정확히 식별한 뒤, simulation의 나머지 tick마다 부엌으로 갔고, 다른 세 방은 영원히 더러운 채로 남았습니다. 전혀 학습하지 않는 것보다 다섯 배 나쁘며, 고장 난 것도 아닙니다.

교훈은 utility section의 교훈입니다. learner A는 “내가 막 방문하려는 방이 더러울 확률”을 극대화했습니다. performance measure는 “방이 더러운 채로 보낸 room-tick”이었습니다. 서로 다른 숫자입니다. critic이 점수 매긴 것은 두 번째였고, 아무도 agent에게 말해 주지 않았습니다. learner B는 같은 학습 rate에 마지막 방문 이후 시간을 곱합니다. 먼지를 찾을 확률이 아니라 찾을 것으로 예상되는 먼지입니다. 그리고 출발점이던 patrol을 이깁니다.

구현 세부사항 하나가 결과를 결정했습니다. learner B의 첫 버전에서는 세 번 방문해도 먼지가 나오지 않은 방의 rate가 정확히 0이 됐습니다. 그리고 0에 무엇을 곱해도 0이므로, 그 방은 다시 방문되지 않았고 estimate도 절대 수정될 수 없었습니다. 분수에 smoothing을 적용해 성공 수 더하기 1을 trial 수 더하기 2로 나누자 11,895가 1,576으로 바뀌었습니다. “아직 관찰되지 않음”과 “측정했더니 0으로 나옴”은 서로 다른 주장입니다. 그것을 같은 field에 저장하는 시스템은 되돌릴 수 없는 결정을 내립니다.

다섯 유형, 그리고 2026년의 모습

섹션 링크: 다섯 유형, 그리고 2026년의 모습
TEXT
  1  simple reflex    percept ────────────────────────────────► rules ────► action
  2  model-based      percept ──► [state] ──────────────────► rules ────► action
  3  goal-based       percept ──► [state] ──► [goal] ──────► search ───► action
  4  utility-based    percept ──► [state] ──► [goal] ──► [U] ──► argmax ► action
  5  learning         all of the above, plus [critic] ──► changes the parts above

다섯 가지 모두가 오늘날 production에서 다른 이름으로 쓰이고 있습니다.

classic typepercept 사이에 가지고 다니는 것2026년의 형태할 수 없는 것
simple reflex없음history 없는 모델 호출 하나: classifier, extraction endpoint, single-turn completion이전 턴에 의존하는 것
model-based reflexpercept history에서 만들어진 internal statechat: transcript 전체를 매 호출마다 다시 보냄대화가 어디서 끝나야 할지 선택하기
goal-basedstate와 원하는 상황에 대한 설명stopping condition이 있는 reason-and-act loop2성공한 plan들 사이에서 선호하기
utility-basedstate, goal, outcome 위의 숫자evaluator–optimiser loop, 그리고 쓰인 criterion으로 candidate answer를 ranking하기(25장)criterion을 발명하기
learning위 전부에 critic과 problem generator 추가weights를 업데이트하는 대신 episodic buffer에 자기 교훈을 쓰는 Reflexion;3 persistent user memory(24장)critic이 점수 매길 standard를 선택하기

두 행은 비용이 드는 방식으로, 단순한 비유보다 더 가깝습니다.

chat은 model이 internal이 아닌 model-based reflex agent입니다. 교과서에서 state는 agent program 안의 변수입니다. chat에서는 transcript입니다. 그것은 여러분 쪽에 살고, 매 호출마다 전체가 다시 전송되며, 매번 모델 안에서 처음부터 다시 구축됩니다. 그것이 16장의 quadratic 청구서이고, 교과서가 “state”라고 붙은 상자로 그린 바로 그 객체입니다. 다음은 이전 두 메시지가 있을 때와 없을 때 같은 follow-up question 하나에서 측정한 차이입니다.

TEXT
with the transcript      prompt=67  "The current temperature in Lisbon, Portugal is 15°C."
without the transcript   prompt=29  "Lisbon is the capital of Portugal, not a city in Portugal."

같은 모델, 같은 세 단어짜리 사용자 입력입니다. 그리고 두 번째는 복도 로봇이 벽에 들이받는 상황입니다. 그 run에는 도구가 없었으므로 15는 지어낸 숫자입니다. 하지만 state가 있어야 follow-up이 의미를 갖습니다. 여러분은 매번 그것을 다시 만들고, 두 턴 대화에서 input token을 2.3배 지불합니다. 16장은 그 multiplier가 40턴에서 어디까지 가는지 측정했습니다.

Reflexion은 프로그램이 아니라 입력을 바꾸는 learning agent입니다. 교과서 분해에서 learning element는 performance element를 수정합니다. Reflexion은 weights를 그대로 두고 다음 attempt가 읽을 episodic buffer에 reflective text를 씁니다.3 learning element는 prompt이고, memory는 database row이며, performance element는 frozen model입니다. 그리고 diagram은 교과서의 것 그대로입니다.

그리고 mapping의 정직한 한계가 여기 있습니다. 다섯 유형은 agent program을 분류합니다. 2026년에 그 program은 정중앙에서 갈라져 있습니다. 일부는 여러분의 코드이고, 일부는 여러분이 train하지 않은 weights 안에 있습니다. 모델이 스스로 도구를 호출하기로 결정할 때, goal test는 여러분의 program에 있습니까, 모델 안에 있습니까? taxonomy에는 답이 없습니다. 그것이 쓰였을 때는 goal test가 있을 다른 곳이 없었기 때문입니다. 바로 그 질문에서 두 현대적 정의가 갈라집니다.

한 trace 안의 답변, 호출, 정지

섹션 링크: 한 trace 안의 답변, 호출, 정지

정의는 행동에 대한 논쟁이고, trace를 앞에 두면 훨씬 판단하기 쉽습니다.

아래 loop는 대화를 모델에 보냅니다. reply에 도구 호출이 들어 있으면 도구를 실행하고, 결과를 append한 뒤 전체를 다시 보냅니다. 이 machine에서 OpenAI 모양 endpoint 뒤에 있는 local Qwen2.5-0.5B-Instruct에 대해 실행합니다. 14장의 seam이므로 loop는 port 뒤에 무엇이 있는지 알지도 신경 쓰지도 않습니다.

loop.tsTS
const BASE = process.env.LLM_BASE_URL ?? "http://127.0.0.1:8799/v1";

async function loop(question: string, maxTurns = 6) {
  const messages: Msg[] = [
    { role: "system", content: SYSTEM },
    { role: "user", content: question },
  ];

  for (let turn = 1; turn <= maxTurns; turn++) {
    const reply = await call(messages, TOOLS);
    const calls = reply.choices[0].message.tool_calls ?? [];
    messages.push(reply.choices[0].message);

    if (!calls.length) return messages;                      

    for (const c of calls) {
      const out = runTool(c.function.name, JSON.parse(c.function.arguments));
      messages.push({ role: "tool", name: c.function.name, content: out });
    }
  }
  throw new Error("turn cap reached");                       
}

두 줄이 전체 아이디어를 담고 있고, 둘 다 표시되어 있습니다. 나머지는 bookkeeping입니다. 세 가지 행동이 한 run에서 모두 보입니다. 스스로 할 수 있는 것을 물으면 모델은 답합니다. 할 수 없는 것을 물으면 호출합니다.

TEXT
=== a question the model cannot answer, one tool available
  turn 1  prompt= 187  out= 21  finish=tool_calls  CALL get_temperature({"city": "Oslo"})
          tool  get_temperature -> {"city":"Oslo","celsius":4}
  turn 2  prompt= 238  out= 12  finish=stop        TEXT "The current temperature in Oslo is 4
                                                        degrees Celsius."
  => model calls=2  prompt tokens=425  output=33  wall=6,257 ms
  => stopped by: the model produced text instead of a call

그리고 멈춥니다. 세 번째 행동이며, 아무 일도 일어나지 않는 것처럼 보이기 때문에 가장 놓치기 쉽습니다. turn 2가 도구 호출 없이 돌아왔기 때문에 loop가 끝납니다. 아무도 그것을 결정하지 않았습니다. 모델이 prose를 내보내며 결정했습니다. 이 program의 termination condition은 부재의 신호입니다.

두 run을 더 볼 가치가 있습니다. 두 도시를 비교해 달라고 하자 모델은 한 턴에 도구 호출을 모두 내고, 두 측정값을 모두 받은 뒤 비교를 틀립니다.

TEXT
  turn 1  prompt= 188  out= 43  finish=tool_calls  CALL get_temperature({"city": "Oslo"}),
                                                        get_temperature({"city": "Lisbon"})
          tool  get_temperature -> {"city":"Oslo","celsius":4}
          tool  get_temperature -> {"city":"Lisbon","celsius":19}
  turn 2  prompt= 284  out= 13  finish=stop        TEXT "Oslo is currently warmer than Lisbon
                                                        at 4°C."

도구는 작동했습니다. parallel call도 작동했습니다. loop도 작동했습니다. 답은 거짓이고, transcript에는 정확한 숫자 둘이 모두 놓여 있습니다. 모델을 loop로 감싼다고 reasoning이 생기지는 않습니다. 틀린 모델에게 틀린 것에 따라 행동할 능력을 줄 뿐입니다. 이는 30장의 예고이자, 29장의 절반입니다.

이제 표시된 return를 삭제하고 loop가 cap까지 실행되게 둡니다. 같은 질문, 같은 모델입니다.

TEXT
  turn 1  prompt= 187  out= 21  CALL get_temperature({"city": "Oslo"})
  turn 2  prompt= 238  out= 12  TEXT "The current temperature in Oslo is 4 degrees Celsius."
  turn 3  prompt= 261  out= 30  TEXT "Could you please specify the exact location you're..."
  turn 4  prompt= 302  out= 14  TEXT "Sure! Could you tell me which city you're interested in?"
  turn 5  prompt= 327  out= 35  TEXT "I'm sorry, but I need more details to provide an..."
  turn 6  prompt= 373  out= 12  TEXT "Which city would you like to know the temperature for?"
  => model calls=6  prompt tokens=1,688  output=124  wall=25,261 ms  stopped by: turn cap

input token은 네 배, wall clock도 네 배가 되었고, 끝에는 agent가 자신이 무엇을 질문받았는지 잊고 turn one에서 사용자가 이미 답한 질문을 되묻고 있습니다. 정답은 turn 2에서 화면에 있었고, 그 이후 모든 턴은 transcript를 더 나쁘게 만들었습니다.

따라서 agent는 loop가 아닙니다. 나가는 규칙이 있는 loop입니다. 그리고 이 loop에는 정확히 그런 규칙이 하나 있습니다. 23장은 다섯 가지를 찾고, 각각이 없을 때 무엇이 깨지는지 보여 줍니다.

혼란은 paraphrase에서 만들어지므로, 둘 다 paraphrase하지 않고 인용합니다.

첫 번째 정의는 흐름을 누가 제어하는지에 경계를 둡니다. Anthropic의 Building effective agents는 모호성을 지명하고 판정합니다.

“Anthropic에서 우리는 이 모든 변형을 agentic systems로 분류하지만, workflow와 agent 사이에 중요한 architecture상의 구분을 둡니다. Workflow는 LLM과 도구가 미리 정의된 code path를 통해 orchestrate되는 시스템입니다. 반면 agent는 LLM이 자신의 process와 도구 사용을 동적으로 지시하며 task를 어떻게 달성할지에 대한 control을 유지하는 시스템입니다.”4

test는 여러분의 source code에 대한 질문입니다. 다음 단계를 누가 골랐는가? 여러분의 program 안의 switch라면 workflow입니다. 모델이라면 agent입니다. 같은 문서는 agent가 “일반적으로 environment feedback에 기반해 loop 안에서 도구를 사용하는 LLM일 뿐”이라고 말합니다. 이는 정확히 위 listing입니다.

두 번째 정의는 사용자로부터의 독립성에 경계를 둡니다. OpenAI의 A practical guide to building agents는 정의 페이지를 이렇게 엽니다.

“기존 software가 사용자가 workflow를 streamline하고 automate할 수 있게 하는 반면, agent는 높은 수준의 독립성을 가지고 사용자를 대신해 같은 workflow를 수행할 수 있습니다. Agent는 사용자를 대신해 task를 독립적으로 완수하는 시스템입니다.”5

같은 페이지에서 두 문장 뒤에는 다음을 제외합니다.

“LLM을 통합하지만 workflow execution을 제어하는 데 사용하지 않는 application—simple chatbot, single-turn LLM, sentiment classifier를 생각해 보세요—은 agent가 아닙니다.”5

그 인용들을 순서대로 읽어 보세요. 첫 문장들은 선을 독립성에 긋습니다. 이 것이 나 없이 가서 일을 끝내는가? 네 번째 문장은 execution의 control에 선을 긋습니다. 이는 Anthropic의 선과 정확히 같습니다. 같은 페이지에 다른 test가 있고, 실제 시스템 중에는 그 둘이 불일치하는 경우가 있습니다.

그 아래에는 어휘 충돌이 있으며, 실제 회의에서 논쟁을 일으킵니다. 첫 번째 문서에서 workflow는 architecture이고, agent가 아닌 것입니다. 두 번째 문서에서 workflow는 “사용자의 goal을 달성하기 위해 실행되어야 하는 단계의 sequence”입니다. 곧 모든 agent가 하나씩 갖는 일 자체입니다. “우리는 workflow를 agent로 대체했다”는 첫 번째 정의 아래에서는 일관된 말이고, 두 번째 정의 아래에서는 거의 무의미합니다.

세 시스템, 두 번 분류하기

섹션 링크: 세 시스템, 두 번 분류하기

2026년에 존재하는 세 시스템을 두 정의 아래에서 봅니다.

여러분이 task를 설명합니다. agent는 file을 읽고, test suite를 실행하고, edit하고, 다시 실행하고, pass하거나 포기할 때 멈춥니다. 다음 단계가 “test를 실행”이라고 결정하는 것은 여러분의 코드 어디에도 없습니다. 마지막 도구가 반환한 내용으로부터 모델이 결정합니다.

정의 1: agent입니다. 모델이 자신의 process를 지시하기 때문입니다. 정의 2: agent입니다. task를 독립적으로 완수하고, completion을 인식하고, control을 돌려주기 때문입니다. 두 문서 모두 이 형태를 중심 예시로 듭니다.

새 support ticket마다 고정 순서의 모델 호출 세 번입니다. classify, field extract, reply draft를 한 뒤 보냅니다. 어떤 모델도 다음에 무슨 일이 일어날지 고르지 않습니다. for loop가 합니다. 03:00에 실행되고 아무도 지켜보지 않습니다.

정의 1: agent가 아닙니다. 이름 그대로 prompt chaining이며 workflow로 열거됩니다. 정의 2: 두 답 모두입니다. 첫 문장들에 따르면 사용자를 대신해 task를 독립적으로 완수합니다. 네 번째 문장에 따르면 모델을 workflow execution control에 사용하지 않으므로 제외됩니다. 이 시스템이 바로 pull quote만이 아니라 페이지 전체를 읽어야 하는 이유입니다.

search 도구가 있는 chat assistant

섹션 링크: search 도구가 있는 chat assistant

사용자 턴 하나입니다. 모델은 답하기 전에 search할지 스스로 결정한 뒤 답하고 여러분을 기다립니다.

정의 1: agent입니다. 모델이 environment에서 온 결과에 따라 자신의 도구 사용을 동적으로 지시하기 때문이고, 그것이 명시된 test입니다. 정의 2: agent가 아닙니다. 독립성이 없기 때문입니다. 한 턴 뒤 control을 돌려주며, “simple chatbots”는 exclusion list에 이름으로 들어 있습니다.

세 개 중 둘은 편을 바꿉니다. 이것은 어느 문서의 실패도 아닙니다. 시스템이 무엇을 하는지에 대해 완전히 동의하는 두 사람이 그것을 무엇이라 부를지를 두고 한 시간을 다투는 종류의 회의에 대한 경고입니다.

탈출구는 하나의 축이 아니라 두 축입니다

섹션 링크: 탈출구는 하나의 축이 아니라 두 축입니다

각 정의가 서로 독립적인 두 질문을 한 단어로 접기 때문에 정의가 충돌합니다. 둘을 분리하면 불일치는 verdict보다 훨씬 유용한 table이 됩니다.

여러분의 코드가 다음 단계를 고름모델이 다음 단계를 고름
사람이 매 턴을 지켜봄안에 모델이 든 form: classifier, extraction, single-turn completion도구가 있는 chat — 정의 1은 agent라고 하고, 정의 2는 아니라고 함
끝날 때까지 아무도 지켜보지 않음pipeline — 정의 2의 첫 문장은 agent라고 하고, 네 번째 문장은 아니라고 함모두 동의: agent

각 정의는 서로 다른 cell에 이의를 제기하고, 나머지 둘은 전혀 논쟁적이지 않습니다. 그래서 label이 중요할 때, 예컨대 계약, risk review, postmortem에서 써야 할 두 문장은 “이것이 agent인가”가 아니라 다음 단계를 누가 골랐는가누가 지켜보고 있었는가입니다. 둘 다 코드를 읽으면 답할 수 있고, 어느 쪽도 누군가의 정의를 필요로 하지 않으며, 함께 label이 대신하던 모든 결과를 담습니다.

이 중 새것은 없습니다. Wooldridge와 Jennings는 1995년에 “agent”의 경쟁적인 의미를 survey했습니다.6 Franklin과 Graesser는 1996년에 이 장의 질문을 던지고, 당시 유통되던 정의들을 모아 서로 불일치한다는 것을 발견했습니다.7 2023년 survey도 여전히 agent를 first principles에서 정의합니다. “환경을 감지하고, 결정을 내리고, 행동하는 인공 entity”라고요.8 인용할 합의된 정의가 없었기 때문입니다. CoALA는 아예 경계를 긋기보다 parts를 설명합니다.9 30년 동안 합의를 거부했다는 사실은 그 단어가 둘 이상의 일을 하고 있음을 말합니다.

agent는 하나의 호출이 아니라 N개의 호출입니다

섹션 링크: agent는 하나의 호출이 아니라 N개의 호출입니다

이제 철학보다 먼저 도착하는 결과, 즉 청구서입니다.

여기의 모든 측정은 같은 모양입니다. 단일 호출은 input token 39개의 비용이 들었습니다. 같은 질문에 도구 하나를 붙이면 두 호출에 걸쳐 420개가 들었습니다. stopping rule을 제거한 loop는 여섯 호출에 걸쳐 1,688개가 들었습니다. 성장은 선형보다 나쁩니다. turn n이 이전 모든 턴을 들고 가기 때문입니다. 그 여섯 턴 run의 prompt 열은 187, 238, 261, 302, 327, 373입니다. 16장은 총량이 Θ(n2)\Theta(n^2)임을 유도하고 실제 대화에서 curve를 fitting했습니다. agent는 사람이 보든 보지 않든 모든 task를 그 대화로 바꿉니다.

측정된 token count가 2026년 9월 6일 16장이 읽은 요금, input token 100만 개당 $2.00 및 output 100만 개당 $12.00로 commercial endpoint에 갔다면, 네 run의 가격은 다음과 같습니다.

runmodel callsinput tokensoutput tokenscost
질문, 도구 없음1398$0.000174
같은 질문, 카탈로그에 도구 하나242038$0.001296
도구가 필요한 질문242533$0.001246
같은 질문, stopping rule 제거61,688124$0.004864

두 번째 행을 첫 번째 행과 비교한 숫자를 기억해야 합니다. 모델이 이미 알고 있던 질문에 더 나쁜 답을 하기 위해 비용은 7.5배가 됐습니다. 잘못 configuration된 것은 없었습니다. 도구가 있었으므로 모델이 사용했습니다. 그리고 카탈로그의 정확도가 아니라 카탈로그의 가격이 아프다는 18장의 발견은, 도구 하나짜리 카탈로그로 여기서 가장 싼 시연을 얻습니다.

그래서 두 문서 모두에서 유용한 절반은 이것을 만들지 말라는 절반입니다. Anthropic은 직설적입니다. 가능한 가장 단순한 solution을 찾고 필요할 때만 complexity를 더하라며, 이는 “agentic system을 아예 만들지 않는 것”을 뜻할 수 있다고 합니다. agentic system은 “더 나은 task performance와 latency 및 cost를 교환”하고, “많은 application에서는 retrieval과 in-context example로 single LLM call을 최적화하는 것만으로도 보통 충분”하기 때문입니다.4 agent를 만들 이유는 좁습니다. step 수를 예측할 수 없고 path를 hardcode할 수 없는 open-ended problem, 신뢰하는 environment, 그리고 “더 높은 비용과 error가 compounding될 가능성”을 받아들이는 경우입니다.4 OpenAI의 screen은 거울상입니다. complex judgement, 유지 불가능한 rule set, unstructured data입니다. 그리고 같은 식으로 끝납니다. “그렇지 않다면 deterministic solution으로 충분할 수 있다.”5

따라서 이 장의 taxonomy로 말하면, 고정된 순서의 고정된 단계 수는 pipeline이며, 그것을 agent라고 불러도 더 빨라지지 않습니다. 단계 수가 길에서 발견하는 것에 달려 있다면 loop가 필요합니다. 그리고 그 flexibility는 N개 호출, quadratic transcript, 한 번이 아니라 N번 틀릴 수 있는 시스템으로 사는 것입니다.

이제 taxonomy, 두 현대적 정의, 그것들을 양립 가능하게 만드는 두 축, 그리고 답하고 호출하고 멈추는 짧은 loop를 얻었습니다.

그 loop가 끝나는 방법은 하나뿐입니다. 모델이 도구 요청을 멈추는 것입니다. 23장은 그것을 일부러 일곱 번 깨뜨리고, 깨질 때마다 조각 하나를 더합니다. 불가능한 task라서 끝나지 않습니다 — turn cap. 밤새 실행되고 청구서가 도착합니다 — dollar budget. 도구가 실패합니다 — 모델이 대응할 수 있는 error. 같은 호출이 두 번 나갑니다 — idempotency key. 건드리면 안 되는 file을 건드립니다 — human approval. 중간에 restart됩니다 — session persistence. 도구가 3분 동안 조용히 걸립니다 — progress와 cancellation. 그 결과물이 harness, 이 course의 나머지가 실행되는 file입니다.

그러면 이 장의 disputed diagonal이 사실 묻고 있던 질문이 남습니다. 자신의 다음 단계를 결정하는 loop는 언제 멈출지도 결정해야 하고, 우리는 그것이 할 수 없을 때 어떤 일이 일어나는지 방금 봤습니다. 여섯 턴, 네 배의 청구서, 이미 답한 질문에 대해 사용자를 interrogate하는 agent입니다. stopping은 조건 하나가 아닙니다. 몇 개가 있고, 어느 것이 먼저 fire할까요?


Lilian Weng의 LLM Powered Autonomous Agents (2023)는 language agent를 planning, memory, tool use로 분해한 가장 잘 알려진 글이며, 두 vendor 문서와 함께 읽을 다음 자료로 알맞습니다. 세 component는 이 course의 23장, 24장, 18장에 해당하며, 순서도 그렇습니다.

이 장의 모든 숫자는 이 machine에서 생성됐고 추정된 것은 없습니다. corridor, floor plan, 그 위를 걷는 네 agent, 세 patrol policy는 위의 TypeScript이며 Node 22에서 실행했습니다. randomized agent의 수치는 각각 seeded run 2,000번의 mean이고, patrol 수치는 4,000 tick의 single seeded run입니다. model trace는 CPU에서 float32로 greedy decoding한 Qwen2.5-0.5B-Instruct에서 나왔고, weights를 load하고 OpenAI chat-completions shape로 말하는 작은 local Python endpoint가 loopback으로 serving했습니다. 다시 seam입니다. tensor는 Python 쪽에 있고 loop는 TypeScript 쪽에 있습니다. 따라서 token count는 그 모델의 tokenizer 기준이고 latency는 그 machine 기준입니다. 외부에서 가져온 유일한 수치는 cost table의 두 가격입니다. 이는 2026년 9월 6일 16장이 OpenAI pricing page에서 읽은 rate이며, 여기서는 locally measured token count에 illustration으로 적용한 것이지 observed invoice가 아닙니다.

  1. Russell, S. and Norvig, P. Artificial Intelligence: A Modern Approach, 4th edition, chapter 2, Intelligent Agents. vacuum world, PEAS specification, performance measure에 상대적인 rationality 정의, task environment의 일곱 properties, 여기서 사용한 다섯 agent 유형, 그리고 부분적으로 관찰 가능한 환경에서는 simple reflex agent에게 infinite loop가 종종 피할 수 없다는 관찰의 출처입니다. 이 책의 companion code는 GitHub의 aimacode/aima-python입니다(별 8,806개, 마지막 push 2026년 6월 30일, 2026년 9월 7일 읽음). 그것이 무엇인지 정확히 이름 붙일 가치가 있습니다. 이는 책의 accompanying repository이지, 다른 project가 karpathy/micrograd(17,412)와 karpathy/nanoGPT(62,852)처럼 그 위에 build하는 reference implementation이 아닙니다. 그래서 이 장은 그것을 translate하지 않고 cite 및 link하며, 5장을 Python에 남겨 둔 ecosystem argument가 여기에는 적용되지 않습니다. 이 장의 어떤 것도 tensor를 건드리지 않고, 위에 쓴 loop는 23장의 직접적인 조상입니다. 2 3 4 5

  2. Yao, S., Zhao, J., Yu, D., Du, N., Shafran, I., Narasimhan, K. and Cao, Y. ReAct: Synergizing Reasoning and Acting in Language Models. arXiv:2210.03629 (2022). mapping table의 goal-based row가 가리키는 reasoning trace와 action의 interleaving입니다.

  3. Shinn, N., Cassano, F., Berman, E., Gopinath, A., Narasimhan, K. and Yao, S. Reflexion: Language Agents with Verbal Reinforcement Learning. arXiv:2303.11366 (2023). 이 mechanism을 learning agent에 mapping하는 이유는 paper 자신의 summary에 있습니다. agent를 “weights를 업데이트하는 것이 아니라 linguistic feedback을 통해” reinforce하며, agent는 “task feedback signal에 대해 말로 reflect한 다음 subsequent trial에서 더 나은 decision-making을 유도하기 위해 자신의 reflective text를 episodic memory buffer에 유지”합니다. 2

  4. Anthropic, Building effective agents, 19 December 2024, anthropic.com/engineering/building-effective-agents, 2026년 9월 7일 읽음. 위에서 인용한 workflow/agent distinction, 포괄어 “agentic systems”, agent를 “일반적으로 environment feedback에 기반해 loop 안에서 도구를 사용하는 LLM일 뿐”이라고 한 description, 가능한 가장 단순한 solution을 찾으라는 guidance와 그것이 “agentic systems를 아예 만들지 않는 것”을 뜻할 수 있다는 말, 그리고 “higher costs, and the potential for compounding errors”와 control 유지를 위한 “such as a maximum number of iterations” 같은 stopping condition recommendation을 포함한 agent 찬반 논거의 출처입니다. 2 3

  5. OpenAI, A practical guide to building agents, pages 4 to 7, 2026년 9월 7일 읽음. “Agents are systems that independently accomplish tasks on your behalf”, “simple chatbots, single-turn LLMs, or sentiment classifiers”의 exclusion, workflow를 “a sequence of steps that must be executed to meet the user's goal”로 정의한 내용, agent의 두 core characteristics, 세 component — model, tools, instructions — 그리고 agent를 언제 만들지에 대한 screening criteria와 “otherwise, a deterministic solution may suffice”로 끝나는 지침의 출처입니다. 2 3

  6. Wooldridge, M. and Jennings, N. R. Intelligent Agents: Theory and Practice. The Knowledge Engineering Review, volume 10, issue 2 (1995). 이 분야의 usage를 agency의 weak notion — autonomy, social ability, reactivity, pro-activeness — 과 mental vocabulary를 빌린 stronger notion으로 나눈 survey입니다. 오늘 읽으면, 이 장의 두 문서가 여전히 벌이고 있는 같은 논쟁의 기록입니다.

  7. Franklin, S. and Graesser, A. Is It an Agent, or Just a Program? A Taxonomy for Autonomous Agents. Proceedings of the Third International Workshop on Agent Theories, Architectures, and Languages, Springer (1996). 여기서는 인용문 때문이 아니라 그것이 무엇인지 때문에 cite했습니다. 당시 유통되던 “agent”의 정의를 모아 서로 불일치한다는 것을 발견하고, 논쟁을 대체할 taxonomy를 제안한 survey입니다. 30년 뒤 논쟁은 더 잘 설계된 documentation 안에 있을 뿐, 그 밖에는 변하지 않았습니다.

  8. Xi, Z. et al. The Rise and Potential of Large Language Model Based Agents: A Survey. arXiv:2309.07864 (2023). 위에서 opening definition, “AI agents are artificial entities that sense their environment, make decisions, and take actions”를 인용했습니다. 이는 인용할 합의된 현대적 정의가 없었기 때문에 2023년에 교과서적 정의를 다시 쓴 것입니다.

  9. Sumers, T. R., Yao, S., Narasimhan, K. and Griffiths, T. L. Cognitive Architectures for Language Agents. arXiv:2309.02427 (2023). language agent를 “internal memory와 external environment와 상호작용하기 위한 modular memory components, structured action space, 그리고 action을 선택하기 위한 generalized decision-making process”로 organize하고, symbolic AI와 cognitive science의 역사 속에 명시적으로 위치시킵니다. memory taxonomy는 24장에서 돌아오며, three-store table은 그 practical shadow입니다.

이제 모델 선택은 LIA에게 맡기세요

모든 AI 모델을 한곳에서. 오늘 무료로 시작하세요.