본문으로 건너뛰기
AIPida
채택됨중급AI 개발

Claude tool_use가 안 잡히고 stop_reason이 end_turn으로 옵니다 (그냥 텍스트로만 답함)

Anthropic SDK(파이썬)로 에이전트를 만드는 중인데요. 툴 정의를 tools 파라미터로 넘기고 모델이 함수를 호출하길 기대하는데, 응답을 보면 stop_reasontool_use가 아니라 end_turn으로 오고 content에는 그냥 텍스트만 있습니다.

프롬프트에서 "이 도구를 써서 날씨를 조회해"라고 명시적으로 지시해도 절반은 그냥 텍스트로 "날씨를 조회하겠습니다"라고만 답하고 실제 tool_use 블록이 안 나옵니다.

resp = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=1024,
    tools=[weather_tool],
    messages=[{"role": "user", "content": "서울 날씨 알려줘"}],
)
print(resp.stop_reason)  # end_turn ...

description은 "도시 날씨를 조회한다" 한 줄로 넣었습니다. 뭐가 문제일까요?

답변 2

  • 채택된 답변에디터 검증

    십중팔구 description이 빈약해서입니다. Claude는 그 도구를 "언제 써야 하는지"를 거의 전적으로 description으로 판단해요. "도시 날씨를 조회한다" 한 줄이면 모델이 "이 정도는 그냥 내가 답해도 되겠네" 하고 텍스트로 때우는 쪽을 고릅니다.

    스키마부터 살을 붙이세요. 특히 언제 써라를 명령조로:

    weather_tool = {
        "name": "get_weather",
        "description": "특정 도시의 현재 날씨를 조회한다. 사용자가 날씨/기온/비·눈 여부를 물으면 추측하지 말고 항상 이 도구로 실제 데이터를 가져올 것.",
        "input_schema": {
            "type": "object",
            "properties": {
                "city": {"type": "string", "description": "도시 이름. 예: 서울, 부산"}
            },
            "required": ["city"],
        },
    }
    

    그리고 파싱 쪽도 문제예요. stop_reason만 보지 마세요. content는 텍스트 블록이랑 tool_use 블록이 섞여서 옵니다 — 모델이 "날씨를 조회하겠습니다" 텍스트 + tool_use를 같이 보내는 경우도 흔해서, stop_reason == end_turn만 보고 거르면 멀쩡한 tool_use를 놓칩니다. 블록을 순회해서 type으로 잡으세요:

    for block in resp.content:
        if block.type == "tool_use":
            print(block.name, block.input)
    

    그래도 무조건 매번 도구를 강제해야겠으면 tool_choice로요. {"type": "tool", "name": "get_weather"}면 그 도구를, {"type": "any"}면 "아무 도구든 반드시 하나"를 강제합니다. 디폴트가 {"type": "auto"}라 호출 여부가 모델 재량인 거예요. 다만 강제는 부작용 있으니(아랫분 답 참고) 저는 description 손보는 걸 먼저 권합니다.

  • 위 답이 정답이고, tool_choice 강제 쓸 때 주의점만 하나 보탤게요.

    any나 특정 tool로 강제하면 모델이 사용자한테 되묻거나 "정보가 부족합니다"라고 빠지는 경로가 막혀요. 그래서 필수 파라미터가 비었을 때 그냥 추측으로 채워 넣습니다. 날씨 예시면 도시 안 줬는데 멋대로 "서울"로 호출하는 식. 멀티턴 에이전트면 그 추측 인자로 엉뚱한 조회가 돌고 루프가 한 바퀴 헛돕니다.

    그래서 저는 auto 두고 description 빡세게 쓰는 쪽 선호해요. 그리고 강제 모드는 루프 끝에서 자연어 마무리("조회 결과 서울은 맑음입니다")를 못 하게 막을 수도 있어서, 종료 턴에선 auto로 풀어주는 식으로 단계별로 다르게 거는 것도 방법입니다.