C.W.K.
Stream
Lesson 02 of 05 · published

Tool calling 이전 — Workaround 들

~22 min · history, regex, react, scaffolding

Level 0호기심 많은 독자
0 XP0/48 lessons0/14 achievements
0/100 XP to next level100 XP to go0% complete

Tool calling 이 어떤 모델의 built-in feature 가 되기 한참 전에, 사람들은 이미 LLM 을 방에서 꺼내려고 발버둥치고 있었어. 옛날 workaround 를 알아두는 게 가치 있는 이유는 두 가지: (a) 옛날 코드에 아직 살아있고, (b) 오늘날의 깔끔한 API 가 왜 그렇게 안도감 주는지를 설명해주거든.

첫 번째 family 는 prompt-and-parse 였어: 모델한테 구조화된 문자열 — JSON, XML, 특별한 <action> 태그 — 를 토해내라고 하고, 그 출력에 regex 를 돌려서 'function 호출하고 싶다' 를 detect 해. 신뢰성 스토리는 비참했어. 모델은 중간에 format 을 까먹고, JSON 을 수다스러운 서론으로 감싸고, 따옴표 스타일 바꾸고, 필드를 hallucinate 했어. 모든 팀이 자기들만의 retry-and-repair loop 를 짰고, 모든 팀의 loop 가 코너 케이스를 흘렸어.

두 번째 family 는 ReAct 식 scaffolding 이었어: 모델한테 Thought / Action / Observation 라인을 번갈아 출력하라고 하고, stream 에서 Action 만 뽑아 실행하고, Observation 을 다시 집어넣어. ReAct 는 진짜 지적 도약이었어 — 추론과 행동이 sequential 하지 않고 interleaved 라는 걸 가르쳐줬거든 — 근데 engineering substrate 로는 종이처럼 얇았어. 모델은 여전히 모든 step 을 완벽하게 format 해야 했고, parser 는 시(詩) 에 대해 방어적이어야 했어.

세 번째 family 는 본격 agent framework: LangChain agents, AutoGPT, BabyAGI. Prompt-and-parse loop 를 OOP 기계장치로 감싸고, planner · memory · self-critique 를 얹었어. 동작할 땐 동작했어. 안 동작할 땐 화려하고 디버깅 불가능한 방식으로 실패했어 — 모든 layer 가 여전히 똑같이 부서지기 쉬운 '모델아 제발 format 좀 해줘' 토대 위에 쌓고 있었거든.

이 모든 것 안에 숨어있는 교훈이 — 우리가 곧 공부할 모든 protocol 의 교훈이야: contract 는 prose 아래에 살아야 해. Tool 호출이 영어 답변의 일부로 모델이 타이핑해주는 거인 한, 너는 모델의 기분에 도박하는 거야. Breakthrough 는 tool 호출을 API 자체의 first-class output 으로 만든 거야 — 모델이 적는 텍스트가 아니라, inference engine 이 토해내는 구조화된 필드.

Code

ReAct 풍 prompt-and-parse (옛날의 고통)·python
# LLM 한테 엄격한 format 을 요구. Regex 가 호출을 뽑음.
# 실제 시스템은 다 처리해야 했음: 추가 공백, 다른 JSON 따옴표,
# 새는 thought, 감싸인 코드 펜스, 중간에 끼어든 사과 등.
import re, json

prompt = '''You are an assistant with one tool: get_weather(location: str).
When you need it, output exactly:
ACTION: {"tool": "get_weather", "args": {"location": "<city>"}}
Otherwise reply normally.'''

raw = call_model(prompt + "\nUser: weather in Seoul?")
# raw 는 이런 식:
#   "Sure! ACTION: {\"tool\": \"get_weather\", \"args\": {\"location\":\"Seoul\"}}"
m = re.search(r"ACTION:\s*({.*})", raw)
if m:
    try:
        call = json.loads(m.group(1))
    except json.JSONDecodeError:
        call = repair_json(m.group(1))  # 모든 팀이 짜야 했던 함수

External links

Exercise

옛날 prompt-and-parse pipeline 을 하나 찾아 (직접 짠 거나 public repo 의 거나), 잘못된 모델 출력에 대비하는 방어 조치를 다 적어. 각 조치는 protocol 이라면 지울 수 있는 코드 한 줄이야. 그 숫자가 우리가 곧 공부할 breakthrough 의 가치야.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.