18장. Project 03. 내 서버에서 일하는 AI Agent
프로토타입을 가볍고 빠르게
이삿짐을 쌀 때 모든 짐을 큰 트럭 한 대에 싣기보다, 자주 쓰는 것은 손가방에, 무거운 것은 트럭에 나눠 싣습니다. 에이전트도 모든 걸음을 가장 큰 모델과 가장 느린 길로 처리할 필요는 없습니다. 15장의 가벼운 모델, 16장의 미리 계산과 캐시, 9장의 걸음 한도를 함께 씁니다.
왼쪽부터 같은 계열의 작은 모델(또는 더 낮은 비트), 서버가 켜질 때 조항 임베딩을 한 번만 계산하기, 같은 검색어의 결과를 기억하기, 루프의 걸음 수를 정해 끝없이 돌지 않게 하기입니다. 모델을 줄이면 빨라지지만 도구를 고르는 실력이 떨어질 수 있으니, 끝 상태 채점으로 함께 잽니다. 여기서 손가방이 작은 모델이고, 트럭이 큰 모델입니다.
이 장에서 견주는 두 모델
| 모델 | 크기(Ollama, Q4) | 기대 | 걱정 |
|---|---|---|---|
qwen2.5:3b | 약 1.9GB | 도구를 잘 고른다 | 걸음마다 느리다 |
qwen2.5:1.5b | 약 1.0GB | 걸음마다 빠르다 | 도구를 덜 부르거나 인자를 틀린다 |
걸음 한도
def run_loop(decide, max_steps=5):
"""decide() 가 도구 이름을 돌려주면 계속, None 이면 끝. 한도에 닿으면 멈춘다"""
steps = []
for _ in range(max_steps):
tool = decide(steps)
if tool is None:
return "끝", steps
steps.append(tool)
return "걸음 한도", steps
print(run_loop(lambda s: "search_rules" if len(s) < 2 else None))
print(run_loop(lambda s: "search_rules")) # 같은 도구만 되풀이하는 모델첫 줄은 두 걸음 뒤 끝, 둘째 줄은 다섯 걸음 뒤 걸음 한도 로 멈춥니다. 작은 모델은 같은 도구를 되풀이하는 일이 있어, 한도가 없으면 GPU 를 붙잡은 채 돌지 않습니다.
코드에 나오는 함수
| 코드 | 쉬운 뜻 |
|---|---|
def run_loop(decide, max_steps=5) | 다음 도구를 정하는 함수 decide 를 받는다. 걸음 한도 max_steps 는 주지 않으면 5 다 |
for _ in range(max_steps) | 많아야 5번만 돈다. _ 는 반복 번호를 쓰지 않는다는 표시다 |
tool = decide(steps) | 지금까지의 걸음을 보여 주고 다음 도구 이름을 받는다. 실제 에이전트에서는 LLM 이 이 일을 한다 |
return "끝", steps | 더 부를 도구가 없다(None)고 하면 끝났다고 돌려준다 |
return "걸음 한도", steps | 반복을 한도까지 다 돌면 걸음 한도로 멈췄다고 돌려준다 |
lambda s: "search_rules" if len(s) < 2 else None | 두 번 부르기 전까지는 search_rules, 그 뒤에는 None 을 내는 가짜 LLM 이다 |
lambda s: "search_rules" | 늘 같은 도구만 내는 가짜 LLM 이다 |
이 코드가 뜻하는 것
전화 자동 응답(ARS, Automatic Response System)을 떠올려 봅니다. 메뉴 번호를 눌러 원하는 안내를 들으면 전화를 끊습니다. 엉뚱한 번호만 계속 누르면 정해진 횟수 뒤에 안내가 멈춥니다. 여기서 번호 한 번 누르기가 걸음, 정해진 횟수가 max_steps, 원하는 안내를 들은 것이 None 입니다.
| 줄 | 하는 일 | 쉽게 말하면 |
|---|---|---|
for _ in range(max_steps) | 많아야 다섯 번 돈다 | 다섯 번까지만 누를 수 있다 |
tool = decide(steps) | 다음 도구를 받는다 | 다음 번호를 누른다 |
if tool is None | 더 부를 도구가 없으면 끝낸다 | 원하는 안내를 듣고 끊는다 |
첫 print(run_loop(…)) | 두 걸음 뒤 None 을 받아 끝 이 된다 | 두 번 눌러 일을 마친다 |
둘째 print(run_loop(…)) | 다섯 걸음을 채우고 걸음 한도 가 된다 | 같은 번호만 누르다 횟수를 다 쓴다 |
결과의 둘째 줄에는 search_rules 가 다섯 번 들어 있습니다. 한도가 없었다면 이 목록은 끝없이 길어졌을 것입니다. 비유와 다른 점은, ARS 는 횟수를 다 쓰면 상담원에게 넘기기도 하지만 이 코드는 "걸음 한도"라고 알려 주기만 하므로 사람에게 넘기는 길은 따로 만들어야 한다는 것입니다.
주의할 점
- 걸음 한도에 닿으면 "처리하지 못했다"고 솔직히 답하고, 사람에게 넘기는 길을 엽니다.
- 속도만 보고 작은 모델을 고르지 않습니다. 쓰기 도구를 잘못 부르는 비용이 빨라진 시간보다 큽니다.
- 작은 모델에는 읽기를 맡기기보다, 서버가 본인의 데이터와 관련 조항을 미리 찾아 붙이고 LLM 에는 쓰기 도구만 고르게 하는 편이 낫기도 합니다. 프로젝트 1, 2의 판 2가 이 방식입니다.