주성진·study·2026.09.18·6 min read·조회수241
매일 쓰는 Claude Code가 궁금해서 들은 허깅페이스 AI 에이전트 과정
Claude Code를 매일 쓰면서도 에이전트가 어떻게 돌아가는지는 막연하게만 알고 있었습니다. 허깅페이스 에이전트 과정에서 배운 생각, 행동, 관찰 루프와 도구 설계를 smolagents 예제로 정리했습니다.
프론트엔드 개발자의 AI 기초· 3 / 3펼치기접기
- 1. Anthropic AI Fluency 수강 후기, 4D 프레임워크를 개발 업무에 대입해 보기
- 2. LLM 관리자 화면을 만들다가 공부한 토큰, 컨텍스트, 임베딩, RAG
- 3. 매일 쓰는 Claude Code가 궁금해서 들은 허깅페이스 AI 에이전트 과정
Claude Code를 메인 개발 도구로 쓴 지 몇 달 됐는데, 정작 에이전트가 안에서 어떻게 돌아가는지는 잘 몰랐습니다. "알아서 파일 읽고, 고치고, 테스트 돌리네" 정도였죠. 그러다 보니 에이전트가 이상하게 굴 때 왜 그런지 짐작이 잘 안 됐습니다.
그래서 허깅페이스의 AI 에이전트 과정을 들었습니다. 이 글에서는 과정에서 배운 에이전트의 기본 구조와 도구 설계를 정리하고, 그게 실무에서 쓰는 코딩 에이전트와 어떻게 연결되는지 이야기해 보겠습니다.
1. 에이전트는 LLM, 도구, 루프로 이뤄집니다
과정에서 내리는 정의는 생각보다 단순합니다. 에이전트는 LLM으로 추론해서 계획을 세우고, 도구를 호출해서 바깥 환경과 주고받는 시스템입니다. LLM이 두뇌라면 도구는 손과 눈인 셈입니다.
핵심은 아래 루프입니다.
┌──────────────┐
│ Thought │ 지금 무엇을 해야 하지? (LLM의 추론)
└──────┬───────┘
▼
┌──────────────┐
│ Action │ 도구 호출 (예: 파일 읽기, 검색, 코드 실행)
└──────┬───────┘
▼
┌──────────────┐
│ Observation │ 도구 결과를 다시 컨텍스트에 넣는다
└──────┬───────┘
└──────→ 목표를 이룰 때까지 반복이걸 보고 나서 Claude Code로 버그를 고치던 장면을 떠올려 보니 딱 들어맞았습니다. "테스트가 왜 깨졌는지 보려면 이 함수를 읽어야겠다"(Thought) 하고 파일 읽기 도구를 부릅니다(Action). 파일 내용이 대화에 들어오면(Observation), "null 체크가 빠졌네, 고치고 테스트를 다시 돌리자" 하고 또 다음 행동으로 넘어갑니다.
품질 게이트 글에서 typecheck와 e2e를 강조했던 이유가 여기서 더 분명해졌습니다. 게이트 결과는 에이전트에게 좋은 관찰(Observation)입니다. 관찰이 정확할수록 다음 판단도 정확해집니다.
2. 도구 설명이 곧 프롬프트입니다
LLM은 함수를 직접 실행하지 못합니다. 대신 도구의 이름과 설명, 입력 형식을 텍스트로 받고, "이 도구를 이 인자로 부르겠다"를 출력합니다. 실제로 실행하는 건 에이전트 프레임워크입니다.
그래서 도구를 어떻게 설명하느냐가 곧 프롬프트입니다. 과정 실습에서 쓴 smolagents 예제를 제 업무에 맞게 조금 바꿔 봤습니다.
from smolagents import CodeAgent, InferenceClientModel, tool
@tool
def get_parking_occupancy(lot_name: str) -> str:
"""주차장의 현재 점유 현황을 돌려준다.
Args:
lot_name: 주차장 이름. 예: "중앙시장 공영주차장"
"""
# 실제로는 주차면 분석 솔루션 API를 호출한다고 가정
data = {"중앙시장 공영주차장": (82, 120)}
used, total = data.get(lot_name, (0, 0))
return f"{lot_name}: {used}/{total}면 사용 중 ({used / total:.0%})" if total else "알 수 없는 주차장"
agent = CodeAgent(tools=[get_parking_occupancy], model=InferenceClientModel())
agent.run("중앙시장 공영주차장이 80% 이상 찼으면 '혼잡', 아니면 '여유'라고 알려 줘.")@tool은 docstring과 타입 힌트로 도구 설명을 만듭니다. 실습하면서 Args: 설명을 빼먹은 적이 있는데, 그때 에이전트가 인자를 엉뚱하게 넣는 일이 자주 생겼습니다. 사람이 읽어도 헷갈리는 설명은 LLM도 헷갈린다는 걸 몸으로 배웠습니다.
3. JSON으로 부르느냐, 코드로 부르느냐
과정에서 재미있었던 부분은 행동을 표현하는 두 가지 방식이었습니다. 하나는 {"tool": "get_parking_occupancy", "args": {...}}처럼 도구 호출을 JSON으로 내보내는 방식이고, 다른 하나는 행동을 아예 파이썬 코드로 쓰는 방식(CodeAgent)입니다. 코드로 쓰면 반복문이나 조건문, 여러 도구 조합을 한 번에 표현할 수 있습니다.
# CodeAgent가 실제로 만들어 내는 행동의 예
result = get_parking_occupancy("중앙시장 공영주차장")
ratio = int(result.split("(")[1].rstrip("%)")) / 100
final_answer("혼잡" if ratio >= 0.8 else "여유")코드로 행동하면 단계가 줄어서 토큰과 시간이 아껴집니다. 대신 만들어진 코드를 안전하게 돌릴 환경, 그러니까 샌드박스나 허용된 import 목록이 필요합니다. Claude Code가 명령을 실행하기 전에 권한을 묻는 것도 같은 이유라는 걸 이때 이해했습니다.
4. 실무로 돌아와서 바뀐 것
과정을 듣고 나서 에이전트를 대하는 방식이 조금 바뀌었습니다.
이제는 관찰을 일부러 설계합니다. 테스트 출력이나 린트 결과, 스크린샷처럼 에이전트가 읽을 수 있는 결과를 의도적으로 만들어 줍니다. 그리고 도구를 줄입니다. 도구 설명은 매번 컨텍스트에 들어가니까, 지금 작업에 필요 없는 MCP 서버는 꺼 둡니다.
목표를 줄 때도 확인할 수 있게 줍니다. "고쳐 줘"보다 "이 테스트가 통과하게 고쳐 줘"라고 하면 루프가 언제 끝나야 하는지가 분명해집니다.
마치며
에이전트를 블랙박스로 쓸 때보다, 루프 구조를 알고 쓰니 에이전트가 헤맬 때 왜 헤매는지 조금은 보이기 시작했습니다. 대부분은 관찰이 부족하거나 목표가 모호할 때였습니다.
코딩 에이전트를 매일 쓰는데 가끔 이유를 알 수 없이 헛돈다고 느끼신다면, 이 과정의 첫 몇 단원만이라도 들어 보시길 권합니다. 다음엔 이 원리로 사내 데이터를 조회하는 작은 에이전트를 직접 만들어 볼 생각입니다.
Comments (0)