← Hub ← 06 08 →
07
Chapter 07 · Decision

결정 권한을
처음으로
LLM에게.

툴 목록을 시스템 프롬프트에 적어주고,
LLM에게 'JSON으로 무엇을 부를지' 답하라고 시킨다.
우리는 그 JSON을 파싱해 실제로 함수를 부른다.

·
고정 vs 자율

코드는 하나,
요청은 무한.

구분
Chapter 06 (고정)
Chapter 07 (자율)
툴 순서
개발자가 코드로 박음
LLM이 요청 보고 선택
유연성
결과 바뀌면 코드 수정
프롬프트만 바꾸면 됨
코드량
시나리오마다 함수
하나로 모든 요청 처리
·
기본 흐름

LLM의 답을
JSON으로 받는다.

사용자 요청 LLM 툴+params → JSON json.loads 파싱 TOOLS[name](**params) 실제 실행 결과

코드는 LLM이 어떤 툴을 골랐는지 모른다.
그저 JSON을 파싱해 TOOLS[name] 에서 함수를 꺼내 호출할 뿐.

·
Code · 시스템 프롬프트

툴 카탈로그를
프롬프트에 적는다.

system_prompt = """
당신은 채용 업무를 처리하는 AI 어시스턴트입니다.
사용자의 요청에 맞는 툴을 선택하고 결과를 해석하여 답변합니다.

사용 가능한 툴:
- execute_sql(sql_query): DB에서 이력서/공고 조회.
- retrieve_from_rag(query): 의미 기반 이력서 검색.
- get_confluence_page_content(page_id): 위키 페이지 조회.
- save_excel(data): 평가결과 엑셀 저장.
- send_email(content): HTML 메일 발송.

출력 규칙:
1. 응답은 반드시 JSON 객체 하나만 출력하세요.
   {"tool": "툴이름", "params": {...}, "label": "설명"}
2. 툴이 필요 없으면:
   {"tool": null, "params": {}, "reply": "...", "label": "..."}
3. JSON 앞뒤에 어떤 설명, 코드펜스도 추가하지 마세요.
"""

규칙이 명시적일수록 LLM이 JSON을 안정적으로 뱉는다.
코드펜스 금지, 객체 하나만 같은 지시가 중요.

·
Code · 한 번의 요청 처리

파싱 → dispatch →
히스토리 누적.

def handle_request(user_prompt, history):
    history.append({"role": "user", "content": user_prompt})

    # 1. LLM이 JSON으로 답
    llm_response = generate_response(history, stream=False)
    decision = json.loads(llm_response)

    tool_name = decision.get("tool")
    params    = decision.get("params", {})

    if tool_name and tool_name in TOOLS:
        # 2. 툴 실행
        tool_result = TOOLS[tool_name](**params)
        history.append({"role": "tool", "content": str(tool_result)})
    else:
        history.append({"role": "assistant", "content": decision["reply"]})

    return history
·
실제 흐름

요청이 달라도
함수는 하나.

USER채용공고 보여줘
LLM{"tool":"execute_sql", "params":{"sql_query":"SELECT * FROM job_posting"}}
TOOL · execute_sql[{department: "...", job_description: "..."}, ...]
USER임베디드 경험자 찾아
LLM{"tool":"retrieve_from_rag", "params":{"query":"임베디드"}}
TOOL · retrieve_from_rag[{resume_id: 24647, ...}, ...]
·
JSON 방식의 약점

하지만
LLM은 가끔 어긋난다.

파싱 실패

코드펜스(```json)를 붙이거나 JSON 앞뒤에 설명을 다는 경우. json.loads()가 터진다.

한 번에 한 툴만

한 호출에 결정이 하나. 툴 실행 결과를 보고 다음 툴을 부르려면 다시 호출해야 한다.

툴 실행 후 LLM을 한 번 더 부르면, 결과를 보고 답변을 만들거나 다음 툴을 고른다.
이 반복이 곧 피드백 루프. 다음 챕터의 주제.
Chapter 07 · 마무리

JSON 방식은 됐다.
API가 도와주면
더 안정적.

OpenAI 호환 API의 tools 파라미터로 같은 패턴을 더 깔끔하게.
JSON 파싱 위험 없이.

Next · Chapter 08
피드백 루프 · Tool Calling