diff --git a/solution/backend/services/prompts/agent.py b/solution/backend/services/prompts/agent.py index 5db2d56..364c349 100644 --- a/solution/backend/services/prompts/agent.py +++ b/solution/backend/services/prompts/agent.py @@ -20,14 +20,22 @@ RESPONSE_SCHEMA = { "tool": {"type": "string"}, # ★ strict 모드는 모든 프로퍼티를 required 로 만든다(llm/openai._to_strict_schema). # 그래서 안 쓰는 인자는 빈 문자열로 온다 — 도구는 "" 를 '없음' 으로 읽는다. + # ★ 여기 없는 이름은 모델이 채울 자리가 없다 — 도구가 아무리 선언해도 빈손으로 온다. + # 실측(2026-09-28, 킹서버): move_section 이 {name,to} 를 받는데 스키마에 그 칸이 없어 + # {key,value} 로 왔고, 도구는 "어느 부분인지 못 찾았어요" 로 끝났다. 도구 선택은 + # 6/6 정확했는데도 그랬다 — 단위 테스트는 _choose 를 대신해서 이 층을 건너뛴다. + # 그래서 `test_도구가_선언한_인자는_응답_스키마에_있다` 가 소스로 대조한다. "args": { "type": "object", "properties": { "key": {"type": "string"}, "value": {"type": "string"}, "keyword": {"type": "string"}, + "name": {"type": "string"}, + "to": {"type": "string"}, + "enabled": {"type": "string"}, }, - "required": ["key", "value", "keyword"], + "required": ["key", "value", "keyword", "name", "to", "enabled"], }, # 도구를 못 고른 경우에만 쓴다(되묻기·안내). "message": {"type": "string"}, diff --git a/solution/backend/tests/test_agent_runtime.py b/solution/backend/tests/test_agent_runtime.py index d9302ec..597fbac 100644 --- a/solution/backend/tests/test_agent_runtime.py +++ b/solution/backend/tests/test_agent_runtime.py @@ -463,3 +463,17 @@ async def test_업로드_도구는_만들지_않았다(): assert tools.REGISTRY["list_photos"].grade == ToolGrade.READ assert tools.REGISTRY["hide_photo"].grade == ToolGrade.REVERSIBLE assert tools.REGISTRY["set_primary_photo"].grade == ToolGrade.REVERSIBLE + + +def test_도구가_선언한_인자는_응답_스키마에_있다(): + """★ 스키마에 없는 이름은 모델이 채울 자리가 없다 — 도구가 선언해도 빈손으로 온다. + + 실측(2026-09-28, 킹서버): move_section 이 {name,to} 를 받는데 스키마에 그 칸이 없어 + {key,value} 로 왔고 도구는 "못 찾았어요" 로 끝났다. **도구 선택은 6/6 정확했는데도** 그랬다 — + 다른 테스트는 `_choose` 를 monkeypatch 해서 이 층을 통째로 건너뛰므로 아무도 못 잡는다.""" + from services.prompts import agent as prompt + + allowed = set(prompt.RESPONSE_SCHEMA["properties"]["args"]["properties"]) + for name, tool in tools.REGISTRY.items(): + missing = set(tool.args) - allowed + assert not missing, f"{name} 이 선언한 인자가 응답 스키마에 없다: {missing}"