Lesson 02 · 기초

루프는 그대로, 도구만 늘어났다

"루프는 한 줄도 안 바꿨어요. 그냥 TOOLS 배열에 추가했을 뿐이에요." — s02_tool_use.py 원문.

⏱ 약 10 분 · 📝 3 개 인터랙티브 컴포넌트 · 🧑‍💻 기반 shareAI-lab · s02_tool_use.py

도구 하나를 추가하려면 어디를 건드려야 하나?

S01의 agent는 bash만 사용할 수 있습니다. read_file / write_file / edit_file도 추가하려면 어떻게 할까요?

대부분의 첫 반응은 "루프를 수정한다"는 것입니다. 틀렸습니다. 루프는 한 줄도 바꿀 필요 없습니다. 세 가지만 하면 됩니다:

  1. Python handler 함수를 작성합니다 (run_read(path, limit)).
  2. TOOL_HANDLERS 매핑 테이블에 등록합니다 ("read_file": lambda **kw: run_read(...)).
  3. TOOLS 배열에 JSON schema 선언을 추가합니다 (모델에게 도구 이름과 허용 파라미터를 알립니다).

루프가 tool_use 블록을 만나면 block.name으로 dispatch map을 조회해 함수를 찾고, 실행하고, 출력을 tool_result에 담아 반환합니다. bash와 완전히 동일한 경로입니다.

# Dispatch map: name → handler lambda
TOOL_HANDLERS = {
    "bash":       lambda **kw: run_bash(kw["command"]),
    "read_file":  lambda **kw: run_read(kw["path"], kw.get("limit")),
    "write_file": lambda **kw: run_write(kw["path"], kw["content"]),
    "edit_file":  lambda **kw: run_edit(kw["path"], kw["old_text"], kw["new_text"]),
}

dispatch가 어떻게 라우팅하는지 보기

아래 widget에서 모델이 보낼 수 있는 tool_use 요청을 클릭해, 어떻게 구체적인 Python 함수로 라우팅되는지 확인하세요. 핵심은 block.name이 어느 분기로 갈지를 결정한다는 것입니다.

safe_path: 생략할 수 없는 방어선

agent에 파일 접근 권한을 줄 때 보안상 가장 위험한 것은 경로 이탈입니다: 모델이 /home/user/project/ 안에서 작업해야 하는데 read_file("../../etc/passwd")를 보내는 경우입니다.

s02에는 이것을 전담하는 작은 함수가 있습니다:

def safe_path(p: str) -> Path:
    path = (WORKDIR / p).resolve()  # 정규화, .. 와 심볼릭 링크 해석
    if not path.is_relative_to(WORKDIR):
        raise ValueError(f"Path escapes workspace: {p}")
    return path

핵심은 .resolve() + .is_relative_to() 두 단계입니다—절대 경로로 변환한 다음 샌드박스 안에 있는지 확인합니다. 전자 없이는 foo/../../etc 같은 경로가 통과되고, 후자 없이는 검사 자체를 하지 않는 셈입니다.

경로 안전성 판별

아래 5개 경로는 모두 모델이 보낼 수 있는 read_file 파라미터입니다. safe_path가 어떤 것을 통과시키고 어떤 것을 차단할까요? WORKDIR = /home/user/project로 가정하세요.

agent에 위험한 도구를 넣지 마세요

도구 추가는 간단하지만, 기억하세요: 추가하는 도구 하나하나가 모델의 새로운 능력 경계입니다. s02에서 bash는 블랙리스트(rm -rf /, sudo, shutdown)가 있고, write_filesafe_path로 제한됩니다. production에 도구를 추가하기 전에 세 가지를 물어보세요:

  • 이 도구로 모델이 되돌릴 수 없는 일을 할 수 있나요? (rm, 이메일 발송, git push)
  • 무엇을 유출할 수 있나요? (env vars, .ssh, cookies)
  • 오류 출력이 명령으로 다시 주입될 수 있나요? (tool output을 통한 prompt injection)

s07 강의에서 이런 결정을 코드 밖으로 꺼내 선언적으로 만드는 "권한 레이어"를 다룹니다.

Interactive

Widget 1 · Tool Dispatch · tool_use가 handler로 라우팅되는 과정

tool_use 요청 하나를 클릭하면 루프에서 block.name이 어떻게 대응 함수를 찾고, 실행하고, 출력을 tool_result 블록에 담는지 볼 수 있습니다.

모델이 보낸 tool_use 블록
TOOL_HANDLERS 매핑 테이블

        
실행 결과 · tool_result 블록
(위의 tool_use를 클릭해 라우팅을 확인하세요)
Interactive

Widget 2 · Safe Path · 5개 경로의 이탈 탐지

각 경로는 safe_path()를 통과합니다. WORKDIR = /home/user/project로 가정하고, "통과"할지 "차단"할지 선택해 path escape에 대한 직관을 확인하세요.

0 / 5 정답
Interactive

Widget 3 · Add a Tool · agent에 glob 도구를 추가하려면 무엇이 필요한가

새 도구 glob(pattern)을 추가해 agent가 파일을 일괄 검색할 수 있게 한다고 가정합니다. 빈 칸을 채우세요: 세 곳 모두 바꿔야 하고, 하나라도 빠지면 안 됩니다.

1번째 · handler 함수 작성
def run_glob(pattern: str) -> str:
    import glob
    return "\n".join(glob.glob(pattern))
2번째 · dispatch map에 등록 (올바른 줄 선택)
3번째 · TOOLS 배열에 schema 추가 (올바른 조합 선택)