GEODE의 구조화 출력 표면은 response_schema 하나입니다. caller가 JSON Schema를 loop 또는 특정 LLM call에 붙이면 선택된 adapter가 자신이 지원하는 wire 형식으로 전달합니다. 다만 필드가 존재한다는 사실만으로 강제력이 생기지는 않습니다. 실제 보장은 adapter 배선, schema strictness, worker-side 검증을 나눠 읽어야 합니다.
계약 범위
| 항목 | 현재 GEODE 계약 |
|---|---|
| 입력 | dict[str, Any] 형태의 JSON Schema 하나 |
| 기본값 | None. 구조화 출력 필드를 wire에 싣지 않음 |
| 적용 범위 | loop 전체 schema 또는 한 번의 _call_llm override |
| 문서화된 worker 결과 | top-level JSON object. worker validator가 object와 required key를 검사 |
| 별도 constraint 종류 | choice, regex, grammar를 위한 first-class GEODE 필드는 없음 |
도구의 input_schema는 tool call 인자를 정의하고, response_schema는 모델의 최종 응답을 정의합니다. 둘은 독립적인 계약이며 하나가 다른 하나를 대신하지 않습니다.
전달 경로
SubTask.response_schema → WorkerRequest.response_schema → AgenticLoop(response_schema=...) → AdapterCallRequest.response_schema → adapter-specific output constraint
일반 sub-agent 작업은 위 경로로 schema를 전달합니다. planner나 judge 같은 보조 호출은 _call_llm(response_schema=...)으로 loop-level schema를 한 번만 덮어쓸 수 있습니다. override가 없으면 loop에 설정된 schema를 모든 LLM call에 사용합니다.
Schema 작성 기준
DECISION_SCHEMA = {
"title": "Decision",
"type": "object",
"properties": {
"decision": {"type": "string", "enum": ["accept", "reject"]},
"reason": {"type": "string"},
},
"required": ["decision", "reason"],
"additionalProperties": False,
}
task = SubTask(..., response_schema=DECISION_SCHEMA)title은 OpenAI Responses 경로의 schema name이 됩니다. 없으면response를 사용합니다.- worker validation을 쓰는 작업은 top-level
object와 명시적인required를 둡니다. - OpenAI strict enforcement가 필요하면 모든 object에서
additionalProperties: false를 설정하고 모든 property를required에 넣습니다. - 타입, enum, nested constraint까지 최종적으로 믿어야 하는 caller는 반환 뒤 full schema validation을 수행합니다.
내장 adapter 배선
| 경로 | response_schema wire | 보장 경계 |
|---|---|---|
openai-paygcodex-oauth | Responses API text.format의 json_schema | strict-compatible schema면 strict=true, 아니면 strict=false hint |
claude-cli | --json-schema <inline JSON> | CLI subprocess 경계에서 schema flag를 전달 |
codex-cli | 임시 JSON 파일을 만든 뒤 --output-schema <FILE> | subprocess 종료 뒤 임시 파일 삭제 |
anthropic-payganthropic-oauth | 현재 공통 Messages request builder가 읽지 않음 | schema field는 무시됨. JSON discipline이 필요하면 caller prompt와 downstream validation이 별도로 필요 |
glm-paygglm-coding-plan | 현재 Chat Completions request builder가 읽지 않음 | 이 경로에서는 provider-side schema enforcement 없음 |
따라서 response_schema가 설정되어도 adapter 선택에 따라 wire에서 무시될 수 있습니다. GEODE에는 아직 structured-output capability를 기준으로 adapter를 선제 차단하는 registry field가 없습니다. schema 강제가 필요한 작업은 위에서 배선된 경로를 명시적으로 선택해야 합니다.
OpenAI Responses request builder는 tools가 있으면 tool payload와 text.format을 같은 요청에 함께 실을 수 있습니다. 반대로 두 CLI adapter는 structured-output flag는 전달하지만 GEODE tool calling은 지원하지 않습니다. 두 capability는 독립적이며, 이 배선 사실을 모든 모델의 조합 수용 보장으로 확대하지 않습니다.
OpenAI strict 판정
OpenAI Responses 경로는 schema를 무조건 strict=true로 보내지 않습니다. _is_openai_strict_compatible이 다음 조건을 재귀적으로 검사합니다.
- 모든
type: object가additionalProperties: false인가. - 각 object의 property key 전체가 정확히
required에 들어 있는가. - array의
itemsschema도 같은 조건을 만족하는가. oneOf,anyOf,allOf의 모든 branch가 같은 조건을 만족하는가.
모두 만족하면 strict=true, 하나라도 어기면 strict=false로 보냅니다. 후자는 schema shape를 전달하는 hint이지 hard guarantee가 아닙니다. 이 판정 함수를 다른 provider의 schema subset에 재사용하지 않습니다.
Worker 검증과 한 번의 retry
WorkerRequest에 schema가 있는 sub-agent 작업은 첫 실행 뒤 별도 안전망을 거칩니다. 다음 중 하나면 validator feedback을 user turn으로 넣고 loop를 정확히 한 번 다시 실행합니다.
- 결과가 없거나 명시적인 failure termination을 반환함.
- 텍스트가 비어 있음.
- 본문에서 balanced JSON object를 찾거나 parse할 수 없음.
- parse한 object에 schema의
requiredkey가 빠짐.
retry는 첫 실행 시간이 task timeout의 50% 미만일 때만 허용합니다. input_blocked, user_cancelled, user_clarification_needed는 의도된 non-JSON 종료라서 retry하지 않습니다. 이 worker validator는 property type, enum, nested constraint를 검사하지 않습니다. 그런 full validation은 downstream parser의 책임입니다.
보장 수준을 읽는 법
| 층 | 하는 일 | 하지 않는 일 |
|---|---|---|
| Provider/CLI constraint | 선택된 backend에 schema를 전달하거나 강제 | 미지원 adapter를 자동으로 다른 경로로 교체하지 않음 |
| Worker retry | 빈 출력, parse 실패, required key 누락을 한 번 복구 | JSON Schema 전체 검증은 하지 않음 |
| Downstream parser | 도메인별 type, enum, semantic constraint를 최종 판정 | adapter의 wire 지원을 대신 만들지 않음 |
구현 기준점
core/llm/adapters/base.py:AdapterCallRequest.response_schema.core/agent/loop/agent_loop.py: loop-level schema와 per-call override.core/llm/adapters/_openai_common.py: Responses wire와 strict compatibility.core/llm/adapters/claude_cli.py,codex_cli.py: CLI flags.core/agent/worker.py: JSON object 검사와 one-retry gate.
다음
- 도구 호출. Tool input schema와 실행/replay 계약.
- LLM adapter 추가. 새 경로에 이 schema 표면을 배선하는 절차.
- LLM 라우팅. 어떤 adapter가 선택되는지 결정하는 순서.