툴 목록을 시스템 프롬프트에 적어주고,
LLM에게 'JSON으로 무엇을 부를지' 답하라고 시킨다.
우리는 그 JSON을 파싱해 실제로 함수를 부른다.
코드는 LLM이 어떤 툴을 골랐는지 모른다.
그저 JSON을 파싱해 TOOLS[name] 에서 함수를 꺼내 호출할 뿐.
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을 안정적으로 뱉는다.
코드펜스 금지, 객체 하나만 같은 지시가 중요.
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
{"tool":"execute_sql", "params":{"sql_query":"SELECT * FROM job_posting"}}{"tool":"retrieve_from_rag", "params":{"query":"임베디드"}}코드펜스(```json)를 붙이거나 JSON 앞뒤에 설명을 다는 경우. json.loads()가 터진다.
한 호출에 결정이 하나. 툴 실행 결과를 보고 다음 툴을 부르려면 다시 호출해야 한다.
OpenAI 호환 API의 tools 파라미터로 같은 패턴을 더 깔끔하게.
JSON 파싱 위험 없이.