6장. 데이터 조회 도구 구현
반환값은 모델이 읽는다 — 실패도 사실로 돌려준다
한 줄 요약
도구 함수가 돌려준 딕셔너리는 그대로 모델이 읽는 글이 됩니다. 그래서 키 이름은 뜻이 드러나게 짓고, 조회 실패는 오류로 멈추는 대신 "찾을 수 없다"는 사실로 돌려주며, 필요한 것만 돌려줍니다.
1. 키 이름이 곧 설명이다
5장에서 실행 결과를 {"result": result}에 담아 모델에게 보냈습니다. 도구가 돌려준 딕셔너리는 JSON으로 바뀌어 모델에게 전달됩니다. 모델은 키 이름을 읽고 각 값이 무엇인지 압니다.
# 모델이 각 값의 뜻을 짐작해야 한다
return {"s": "배송중", "c": "우체국택배", "t": "83455521031", "d1": "2026-06-21"}
# 키 이름이 값의 뜻을 말해 준다
return {"status": "배송중", "courier": "우체국택배",
"tracking_no": "83455521031", "shipped_at": "2026-06-21"}
위쪽도 파이썬 코드로는 문제없이 실행됩니다. 그러나 모델은 "s는 status의 줄임"이라는 우리 머릿속 약속을 모릅니다.
반환값의 키 이름은 변수 이름이 아니라 모델에게 보내는 글입니다. 처음 보는 사람에게 건넬 표라고 생각하고 짓습니다.
2. 실패는 오류가 아니라 사실이다
보통의 파이썬 코드에서는 찾는 것이 없으면 예외를 던져 멈춥니다. 도구에서 그렇게 하면 왕복이 끊깁니다. 모델은 무슨 일이 있었는지 모르고, 고객은 답을 받지 못합니다.
고객이 주문번호를 잘못 적는 것은 프로그램의 오류가 아니라 늘 있는 일입니다. 늘 있는 일은 결과로 돌려줍니다.
row = ORDERS[ORDERS["order_id"] == order_id]
if row.empty:
return {"found": False, "message": f"주문번호 {order_id} 를 찾을 수 없습니다."}
| 칸 | 역할 |
|---|---|
found |
찾았는지를 참/거짓으로 알립니다. 모델이 가장 먼저 보는 칸입니다 |
message |
무슨 일인지 문장으로 알립니다 |
모델은 이것을 하나의 조회 결과로 받아 "주문번호를 다시 확인해 주시겠어요?"처럼 응대를 바꿉니다. 찾았을 때도 "found": True를 넣어, 두 경우의 모양을 맞춥니다.
3. 빈칸의 뜻은 코드가 해석한다
배송준비 상태의 주문에는 송장번호가 없습니다. 이것은 데이터가 빠진 것이 아니라 "아직 출고 전" 이라는 엄연한 상태입니다. 도구가 그 해석까지 해서 돌려줍니다.
if not isinstance(r["tracking_no"], str) or r["tracking_no"] == "":
return {
"found": True, "shipped": False,
"status": r["order_status"],
"message": "아직 출고 전이라 송장이 등록되지 않았습니다. "
"출고된 뒤 다시 조회하면 확인할 수 있습니다.",
}
| 상황 | 돌려주는 것 | 모델이 읽는 뜻 |
|---|---|---|
| 주문이 없다 | found: False + 안내 문장 |
주문번호를 다시 확인해야 한다 |
| 주문은 있고 출고 전이다 | found: True, shipped: False + 안내 문장 |
송장이 아직 없다 |
| 출고됐다 | found: True, shipped: True + 택배사, 송장번호, 출고일 |
배송 정보를 안내한다 |
세 경우를 코드가 갈라 주었기 때문에 모델은 갈라진 결과를 전하기만 하면 됩니다. 판단을 모델에게 넘기지 않고 코드가 한 것입니다.
4. 필요한 것만 돌려준다
orders.csv에는 수령인 이름과 배송지 주소가 있습니다. 두 도구는 이 열을 돌려주지 않습니다.
도구가 돌려준 값은 모델의 입력이 되고, 모델의 입력은 답변에 그대로 나갈 수 있습니다.
배송 상태를 안내하는 데 주소는 필요하지 않습니다. 필요 없는 정보를 넘기면, 주문번호만 아는 사람이 남의 주소를 알아낼 길이 생깁니다. 목적에 필요한 최소한만 돌려주는 것을 첫 도구부터 습관으로 들입니다. 개인정보를 다루는 방법은 8장에서 더 자세히 봅니다.
돌려주는 양은 비용과도 이어집니다. 반환값 전체가 두 번째 호출의 입력 토큰이 됩니다.
5. 도구를 둘로 나눈 이유
두 도구는 같은 CSV의 같은 줄을 읽습니다. 하나로 합쳐 모든 열을 돌려줘도 동작은 합니다. 나눈 이유는 관심사가 다르기 때문입니다.
get_order_status |
track_shipping |
|
|---|---|---|
| 답하는 질문 | 무엇을 샀고 어떤 단계인가 | 택배가 어디쯤인가 |
| 돌려주는 것 | 상품명, 옵션, 수량, 금액, 주문 일시, 상태 | 택배사, 송장번호, 출고일, 배송완료일, 상태 |
| 출고 전 처리 | 필요 없음 | shipped: False로 따로 알림 |
나누면 반환값이 작아지고, 각 도구의 설명이 또렷해집니다. 대신 모델이 둘 중 하나를 골라야 합니다. 고르는 근거는 설명뿐입니다. 이것이 다음 절의 내용입니다.
6. 누가 무엇을 판단했나
| 판단 | 누가 |
|---|---|
| 이 주문번호가 데이터에 있는가 | 코드 (row.empty) |
| 송장이 없는 것은 "출고 전"이라는 뜻이다 | 코드 (개발자가 정한 해석) |
| 주소와 수령인은 돌려주지 않는다 | 개발자 |
| 두 도구 중 어느 것을 부를 것인가 | 모델 |
| 받은 결과를 어떤 문장으로 전할 것인가 | 모델 |
사실을 가르는 일은 코드가, 말로 옮기는 일은 모델이 합니다.
핵심 정리
- 반환값의 키 이름은 모델이 읽는 글입니다. 줄이지 말고 뜻이 드러나게 짓습니다.
- 없는 주문 같은 일상적인 실패는 예외로 멈추지 않고
found: False와 안내 문장으로 돌려줍니다. - 빈칸의 뜻("아직 출고 전")은 코드가 해석해서 넘깁니다.
- 도구는 목적에 필요한 것만 돌려줍니다. 돌려준 값은 답변에 나갈 수 있습니다.
- 사실을 가르는 것은 코드, 말로 옮기는 것은 모델입니다.