OpenAI 함수콜링 → Claude tool use 마이그레이션, 스키마 형식 차이 정리 좀
GPT-4o로 만든 에이전트를 비용/품질 때문에 Claude로 옮기는 중입니다. 함수 정의 부분에서 두 API JSON 형태가 미묘하게 달라서 자꾸 헷갈리네요.
OpenAI는 tools: [{type: "function", function: {name, description, parameters}}] 이런 식이고, 응답도 tool_calls 배열에 arguments가 문자열로 옵니다.
Claude로 그대로 보내니까 tools.0.input_schema: Field required 에러가 나는데, 두 포맷 매핑 깔끔하게 정리해주실 분 있을까요. 특히 멀티턴에서 tool 결과 돌려주는 부분이 제일 헷갈립니다.
답변 2개
- 채택된 답변에디터 검증
그 에러(
input_schema: Field required) 딱 그거 한 번 맞으면 매핑 감이 옵니다. 둘 다 같은 개념인데 키 이름이랑 nesting만 다릅니다.도구 정의
- OpenAI:
{type: "function", function: {name, description, parameters: <JSON Schema>}} - Claude:
{name, description, input_schema: <JSON Schema>}←function래퍼 없고parameters가input_schema로 이름만 바뀜. 스키마 본문(type: object,properties,required)은 그대로 복붙해도 됩니다.
모델이 도구 부를 때
- OpenAI:
message.tool_calls[].function.arguments가 JSON 문자열이라json.loads()한 번 거쳐야 함 - Claude:
content의tool_use블록에.input이 이미 파싱된 dict로 옵니다. 여기서 실수 자주 하는데, 직렬화된 문자열을 raw로 매칭하지 말고 그냥.input쓰세요
결과 돌려주기 — 여기가 진짜 함정입니다.
- OpenAI:
{role: "tool", tool_call_id, content}메시지를 그냥 하나 더 append - Claude:
user역할 메시지 안에tool_result블록으로 넣습니다. role이 tool 아니라 user인 게 헷갈리는 포인트
messages.append({"role": "assistant", "content": response.content}) # tool_use 블록 통째 보존 messages.append({"role": "user", "content": [ {"type": "tool_result", "tool_use_id": block.id, "content": result} ]})제가 마이그레이션하면서 두 번 데인 부분:
- assistant 응답을
response.content통째로 다시 append 안 하면 다음 턴에서tool_use블록이 빠져서tool_result가 매칭 안 된다고 400 납니다. text만 뽑아서 넣으면 이 사고 남 - 한 응답에 tool_use가 여러 개 오면 결과를 한 user 메시지에 다 모아서 돌려줘야 함. 하나씩 따로 append하면 깨져요
루프 직접 짜기 귀찮으면 Python SDK의
client.beta.messages.tool_runner()(@beta_tool데코레이터)가 이 왕복을 알아서 처리해줍니다. 근데 처음 한 번은 손으로 짜보는 걸 추천. 위 두 함정을 몸으로 알게 됨. - OpenAI:
윗분 답변에
tool_choice도 형태 다른 거 하나 추가합니다.- OpenAI:
"auto" | "required" | {type: "function", function: {name}} - Claude:
{type: "auto"} | {type: "any"} | {type: "tool", name} | {type: "none"}
required↔{type: "any"}대응이고, 특정 도구 강제는{type: "tool", name}. 병렬 호출 끄려면 어느 값이든disable_parallel_tool_use: true같이 넣으면 됩니다.그리고 잘 안 알려진 거 하나 — 에러 결과 돌려줄 땐
tool_result에"is_error": true붙이세요. 안 붙이면 모델이 실패한 줄 모르고 그 쓰레기값으로 계속 진행합니다. 붙이면 다른 접근 시도해요.- OpenAI: