Tool Registry — 포괄적 Agent 구현 구조
핵심 구조
사용자 채팅
↓
LLM (Tool Registry 참조, CoT)
↓
Tool call 생성
↓
execute_tool() → 실제 코드 실행
↓
결과 → 다시 LLM → 자연어 응답
↓
사용자
Tool Registry
사용 가능한 Tool들의 카탈로그. 새 Tool 추가 → 등록 → 자동 반영.
TOOLS = {
"download_file": {
"description": "파일을 다운로드한다",
"params": {"url": "str", "save_path": "str"},
"returns": "local_path: str",
"when_to_use": "사용자가 파일 저장을 요청할 때"
},
"query_db": {
"description": "DBMS에서 데이터를 조회한다",
"params": {"query": "str", "db_name": "str"},
"returns": "results: list",
"when_to_use": "데이터 조회가 필요할 때"
},
}
System prompt 자동 생성
Tool을 손으로 쓰지 않고 Registry에서 자동 생성:
def build_system_prompt(user_config):
tools_text = ""
for name, spec in TOOLS.items():
tools_text += f"""
## Tool: {name}
설명: {spec['description']}
입력: {spec['params']}
출력: {spec['returns']}
사용 시점: {spec['when_to_use']}
"""
return f"너는 사용자의 AI agent다.\n{tools_text}\n{user_config}"
대화 실행 흐름
def chat(user_message, history):
system = build_system_prompt(user_config)
response = llm.chat(system=system, messages=history + [user_message])
while response.has_tool_call():
result = execute_tool(response.tool_call.name, response.tool_call.params)
history.append({"role": "tool", "content": result})
response = llm.chat(system=system, messages=history)
return response.text
포괄성 확보 방법
1. Tool을 원자적으로 쪼개면 조합으로 대부분 커버
download_file + convert_to_md + index_to_rag
→ "파일 다운받아서 RAG에 넣어줘"
2. 없는 Tool은 명시적으로 알려주게 강제
System prompt 추가:
"요청한 작업을 수행할 Tool이 없으면
'현재 이 작업은 지원되지 않습니다: [이유]'라고 말해라.
없는 Tool을 만들어내지 말 것."
Skill의 위치
Skill = 자주 쓰는 Tool 조합을 미리 묶어둔 것. 없어도 작동하지만, 있으면 LLM이 더 빠르고 일관되게 선택.
Tool Registry → "무엇을 할 수 있는가"
Skill 정의 → "자주 쓰는 조합을 미리 정의"
대화 → LLM이 Registry + Skill 보고 판단
관련 개념
- tool-vs-skill-design — Tool/Skill 설계 원칙
- tool-system-prompt-design — Tool 명세 작성법
- skill-selection-mechanism — LLM이 Skill 선택하는 방법