AI 에이전트는 어디에나 있지만, 실제로 AI 에이전트란 무엇인가?

발행: (2025년 12월 14일 오후 06:27 GMT+9)
9 min read
원문: Dev.to

Source: Dev.to

AI 에이전트는 오늘날 어디에나 존재합니다.

이미지 생성부터 콘텐츠 제작, 코딩 도우미부터 자율 연구 도구에 이르기까지, 에이전트라는 단어는 챗봇보다 조금 더 능력 있는 무언가를 지칭하는 기본 라벨이 되었습니다.

하지만 대부분의 설명을 자세히 살펴보면 뭔가 빠져 있다는 느낌이 듭니다. 우리는 명확한 정신 모델 없이 프레임워크, 추상화, 적용 사례로 바로 뛰어들곤 합니다.

그럼 천천히 실제 질문을 해봅시다:

에이전트를 에이전트로 만드는 실제 요소는 무엇일까요?

이 글은 AI 에이전트에 관한 3부 시리즈 중 첫 번째입니다. 여기서는 기본 개념을 정립하고, 이후 시리즈에서는 아키텍처 패턴, 제어 흐름, 상태 관리 등을 다룰 예정입니다.

가장 단순한 상호작용부터 시작해봅시다

모델로 할 수 있는 가장 기본적인 일은 프롬프트를 주는 것입니다.

import OpenAI from "openai";

const client = new OpenAI();

const response = await client.chat.completions.create({
  model: "gpt-5.1",
  messages: [
    { role: "user", content: "Summarize the concept of AI agents" }
  ]
});

console.log(response.choices[0].message.content);

모델이 응답합니다. 추론이 탄탄할 수도 있고, 출력이 인상적일 수도 있습니다.

그리고… 모든 것이 멈춥니다.

  • 아무것도 기억되지 않습니다.
  • 아무것도 계속되지 않습니다.
  • 다음 결정이 이루어지지 않습니다.

모델이 얼마나 정교하든, 프롬프트를 얼마나 신중히 설계했든, 이 상호작용은 단일 요청‑응답 경계 안에서만 존재합니다. 모델은 추론하고, 설명하고, 계획까지 할 수 있지만, 응답이 생성되면 계산은 끝납니다.

프롬프트 엔지니어링은 모델이 말하는 내용을 개선할 수 있지만, 시스템 동작 방식을 바꾸지는 못합니다.

따라서 자연스러운 다음 질문은:

모델에게 단순히 응답하는 것 이상을 시키면 어떻게 될까요? 그것이 에이전트가 될까요?

모델에게 행동을 부여한다면?

다음 단계는 모델에게 행동 능력을 부여하는 것입니다. 파일을 읽고, 출력을 쓰고, 웹을 검색하거나 API를 호출할 수 있는 도구(함수)를 공개하고, 모델이 이를 호출하도록 허용합니다.

const tools = [
  {
    type: "function",
    function: {
      name: "readFile",
      description: "Read a file from disk",
      parameters: {
        type: "object",
        properties: {
          path: { type: "string" }
        },
        required: ["path"]
      }
    }
  }
];

const response = await client.chat.completions.create({
  model: "gpt-5.1",
  messages: [
    { role: "user", content: "Read README.md and summarize it" }
  ],
  tools
});

이제 모델은 readFile을 호출하기로 결정하고, 애플리케이션이 이를 실행한 뒤 결과를 모델에 다시 전달합니다.

이것은 큰 업그레이드입니다. 시스템이 단순히 설명하는 것이 아니라 실제 세계와 상호작용할 수 있게 된 것이죠.

하지만 여기에도 미묘한 부족함이 있습니다. 모델은 결정을 내리고, 행동을 트리거하고, 응답을 만든 뒤 종료됩니다. 행동이 충분했는지 반성하지도, 추가 단계가 필요한지 판단하지도, 복구·적응하지도 않습니다. 행동은 할 수 있지만, 프로세스를 스스로 소유하지는 못합니다. 많은 시스템이 여기서 멈추고, 많은 “에이전트”가 조용히 에이전트가 되지 못하는 이유이기도 합니다.

그렇다면… 실제로 무언가를 에이전트라 부르게 하는 요소는?

에이전트는 자신의 상태를 지속적으로 관찰하고, 행동을 결정하며, 그 행동을 실행하고, 결과를 통합한 뒤 다시 결정을 내리는 시스템입니다.

OpenAI와 EurekaLabs 공동 설립자인 Andrej Karpathy는 AI 에이전트를 이렇게 정의합니다:

“에이전트는 본질적으로 도구와 메모리에 접근할 수 있는 루프 안에서 실행되는 언어 모델입니다.”

여기서 핵심 단어는 루프입니다. 코드에 루프를 작성할 수 있다면, 이미 에이전트의 핵심 아이디어를 이해한 것입니다. 루프가 없으면 에이전트도 없습니다.

루프가 바로 행동이다

Agent Core loop

에이전트는 프롬프트, 도구, 프레임워크에 의해 정의되는 것이 아니라, 첫 번째 행동 이후에 일어나는 일에 의해 정의됩니다.

에이전트는 반복합니다:

  1. 현재 상태에 대해 추론하고,
  2. 다음에 할 일을 결정하고,
  3. 행동을 실행하고,
  4. 결과를 관찰하고,
  5. 그 결과를 다음 결정에 반영합니다.

이 아이디어는 흔히 ReAct 패턴(Reason + Act)으로 나타나며, 추론·행동·관찰이 연속적인 사이클로 얽혀 있습니다. 이름은 크게 중요하지 않으며, 반복이 핵심입니다.

이 루프가 존재하면 모델은 수동적인 응답자가 아니라 자신의 실행을 스스로 조정할 수 있는 시스템으로 변합니다.

간단한 에이전트를 만들어보며 (동작 원리 학습)

실제 간단한 에이전트를 JavaScript로 구현해 개념을 적용해 보겠습니다. 목표는 간단합니다: 디렉터리를 탐색하고 모든 마크다운 파일의 요약을 생성합니다.

의존성

npm install openai

도구 (실제 함수)

import fs from "fs/promises";

async function listFiles(dir) {
  return await fs.readdir(dir);
}

async function readFile(filePath) {
  return await fs.readFile(filePath, "utf-8");
}

도구 정의

const tools = [
  {
    type: "function",
    function: {
      name: "listFiles",
      description: "List files in a directory",
      parameters: {
        type: "object",
        properties: {
          dir: { type: "string" }
        },
        required: ["dir"]
      }
    }
  },
  {
    type: "function",
    function: {
      name: "readFile",
      description: "Read a text file",
      parameters: {
        type: "object",
        properties: {
          filePath: { type: "string" }
        },
        required: ["filePath"]
      }
    }
  }
];

에이전트 루프

import OpenAI from "openai";

const client = new OpenAI();

async function runAgent(goal) {
  const messages = [
    {
      role: "system",
      content:
        "You are an agent. Decide what action to take next and continue until the task is complete."
    },
    { role: "user", content: goal }
  ];

  let done = false;

  while (!done) {
    const response = await client.chat.completions.create({
      model: "gpt-4.1",
      messages,
      tools
    });

    const message = response.choices[0].message;
    messages.push(message);

    if (message.tool_calls) {
      for (const call of message.tool_calls) {
        const args = JSON.parse(call.function.arguments);

        let result;
        if (call.function.name === "listFiles") {
          result = await listFiles(args.dir);
        } else if (call.function.name === "readFile") {
          result = await readFile(args.filePath);
        }

        messages.push({
          role: "tool",
          tool_call_id: call.id,
          content: JSON.stringify(result)
        });
      }
    } else {
      done = true;
      console.log(message.content);
    }
  }
}
runAgent("Summarize all markdown files inside the ./docs directory");

이것은 도구나 모델 때문에 에이전트가 된 것이 아니라, 시스템이 계속해서 결정을 내리기 때문입니다. 루프가 능력을 행동으로 바꾸는 것입니다.

에이전트와 워크플로우

(섹션은 계속됩니다…)

Back to Blog

관련 글

더 보기 »