하이퍼엑스
경력근거: 오케스트레이터의 실행 흐름과 오류 처리 방식을 설계하고 문제를 진단합니다.
※ 실제 산출물이 아닌 AI 예측 시안입니다.
공고의 주요 업무는 '오케스트레이터의 실행 흐름과 오류 처리 방식을 설계하고 문제를 진단합니다' 와 '프롬프트와 도구 호출 방식을 평가·개선해 응답 품질과 안정성을 높입니다' 이고, 자격요건은 'API·DB 연동과 로그 분석을 통해 기술 문제의 원인을 찾아본 경험' 을 묻습니다. 이 CLI 는 상주 개발자가 그 진단을 자기 터미널에서 바로 돌리게 합니다. 공고는 타코웍스의 민간용과 공공기관용(전자정부 표준프레임워크 기반 Spring·Java 버전)이 '같은 실행 구조를 공유합니다' 라고 적습니다. 실행 구조가 같다면 실행 기록을 읽는 판정 규칙 한 벌을 두 버전에 같이 쓸 수 있고, 되풀이되는 문제를 모아 HQ 제품팀에 넘기는 3주차는 '현장에서 반복되는 요구사항을 제품팀에 전달하고 개선에 반영합니다' 에 맞춥니다. 공고는 실행 기록의 형식을 밝히지 않습니다. 지원자가 자기 데모 에이전트로 같은 모양의 실물을 만들 수 있도록 공개 규격인 OpenTelemetry 트레이스를 입력으로 골랐습니다. 이 포트폴리오는 트레이스를 규칙으로 읽어 도구 호출 실패의 원인을 정하는 기술을 보여줍니다. 공공기관 업무나 타코웍스 코어 런타임의 내부를 안다고 주장하지는 않습니다.
주요 업무에 '오케스트레이터의 실행 흐름과 오류 처리 방식을 설계하고 문제를 진단합니다' 가 있습니다. 도구 오류 뒤 실행이 어떻게 끝났는지를 트레이스로 읽어 원인을 정하는 이 CLI 의 판정이 그 진단입니다.
'프롬프트와 도구 호출 방식을 평가·개선해 응답 품질과 안정성을 높입니다' 가 주요 업무이고, 자격요건은 API·DB 연동과 로그 분석으로 기술 문제의 원인을 찾아본 경험입니다. 도구 정의와 실제 인자를 견주는 검사와, 고친 설명을 다시 돌려 세는 2주차가 이 두 줄에 맞춥니다.
FDE 는 공공기관 AX 사업 현장에서 타코웍스로 응용프로그램과 AI 에이전트를 개발하는 상주 개발자들을 기술적으로 지원하고, 솔루션 코어 런타임 이슈는 HQ 제품팀과 함께 해결합니다. 실행 기록을 원인별로 나눠 두면 현장에서 고칠 것과 HQ 에 넘길 것이 갈립니다.
하이퍼엑스가 공공기관 AX(AI 전환) 현장에 공급하는 AI 실행·운영 플랫폼 타코웍스로 기관 업무 에이전트를 만드는 상주 개발자와, 그들을 기술 지원하는 FDE 가 쓰는 CLI 입니다. 이상하게 끝난 실행의 트레이스 파일과 도구 정의 파일 tools.json 을 넣으면, 실행마다 도구 호출이 왜 실패했는지 여섯 판정 가운데 하나로 정하고 그 근거 span 과 고칠 곳을 터미널에 보여줍니다. 트레이스는 생성형 AI 호출을 기록하는 OpenTelemetry 의 공개 규약(GenAI semantic conventions)으로 받습니다.
타코웍스로 기관 업무 에이전트를 만드는 현장 상주 개발자와, 그들을 기술 지원하는 FDE. 이상하게 끝난 실행의 트레이스를 터미널에서 이 CLI 에 넣어 원인과 고칠 곳(도구 설명·인자 스키마·재시도 설정)을 확인하고, 반복되는 런타임 문제는 HQ 제품팀에 넘긴다
상주 개발자는 에이전트가 엉뚱하게 답하면 프롬프트부터 고쳐 봅니다. 그런데 트레이스에는 도구를 어떤 인자로 불렀는지, 얼마나 걸렸는지, 오류 뒤에 같은 도구를 다시 불렀는지가 이미 남아 있습니다. 도구 정의와 견주는 다섯 규칙으로 실행마다 원인을 정해 주면, 상주 개발자는 프롬프트를 이리저리 바꾸는 대신 도구 설명·인자 스키마·재시도 설정 가운데 고칠 곳으로 바로 갑니다.
상주 개발자가 트레이스 파일과 tools.json 을 넣고 taco-trace diagnose 를 치면, 실행마다 여섯 판정 가운데 하나와 근거 span, 고칠 곳이 터미널에 나옵니다. 필수 키가 빠진 실행에는 도구 설명 수정안 초안도 나옵니다. 입력은 OTel Collector 파일 내보내기와 같은 OTLP JSON 줄 형식의 합성 트레이스로 시작하고, 첫날 띄운 도구 세 개짜리 데모 에이전트가 남긴 실물 트레이스도 같은 명령으로 읽습니다.
데모 에이전트에 인자 빼먹기·느린 응답·같은 호출 되풀이·오류 삼키기·없는 도구 이름 다섯 가지 고장 스위치를 달아 40번 돌리고, 넣은 고장과 CLI 판정이 맞은 건수와 어긋난 실행을 리포트로 냅니다. 1주차 수정안을 도구 설명에 반영한 뒤 같은 질문 20개를 Claude 와 GPT 모델로 다시 돌려 인자 판정이 줄었는지 셉니다.
여러 날·여러 에이전트의 판정을 모아, 같은 도구·같은 판정이 에이전트 둘 이상에서 되풀이되면 그 묶음을 HQ 제품팀 전달 후보 목록(마크다운)으로 냅니다. 넘길지는 FDE 가 정합니다. 같은 계측 코드를 전자정부 표준프레임워크 기반 데모 프로젝트로 옮겨 트레이스 모양이 그대로인지도 확인합니다.
상주 개발자가 `taco-trace diagnose traces/2026-10-07.jsonl --tools tools.json` 을 치면 실행마다 판정 하나와 근거 span, 고칠 곳이 나옵니다. dept_code 없이 search_regulation 을 부른 실행에는 도구 설명 수정안 초안도 나옵니다.
키 순서만 다른 같은 인자, 제한 시간을 넘겼지만 성공한 호출, 한도와 같은 개수의 연속 호출, 인자 기록이 null 인 호출, 0ms 에 끝난 정의에 없는 도구 호출을 섞은 트레이스에서도 판정이 판정식의 부등호대로 갈립니다.
줄이 잘린 JSONL, status 가 없는 span, tool_args 가 JSON 이 아닌 문자열처럼 형식이 깨진 입력 20종을 넣어도 CLI 가 멈추지 않고 건너뛴 줄 번호와 이유를 알려줍니다.
2주차에는 데모 에이전트에 일부러 넣은 고장 40건과 CLI 판정이 맞은 건수를 셉니다. 단, 고장과 정답을 모두 작성자가 정한 합성 기준이라 성능 검증이 아니라 데모 조건에서의 동작입니다.
위 수치는 작성자가 고장을 넣어 만든 트레이스의 자가채점이며, 원인 판정이 실제로 맞는 비율은 하이퍼엑스 현장의 타코웍스 실행 기록과 상주 개발자의 확인이 있어야 잽니다. 이 포트폴리오는 그 측정을 바로 돌릴 수 있는 상태까지 만듭니다.
고장 40건 일치 수는 제가 켠 고장 스위치를 제가 짠 규칙이 알아맞힌 횟수라 성능 증명이 아닙니다. 스위치 다섯 개는 한 실행에 고장 하나씩을 깔끔하게 만들지만, 현장 트레이스에서는 느린 응답 끝에 인자를 바꿔 다시 부르는 식으로 원인이 겹쳐 나타날 수 있습니다.
부등호 하나, 비교 방식 하나에 판정이 바뀌는 트레이스를 넣었습니다. tool_args 를 키 정렬 없이 견주면 81c95e0b 의 재시도 한도 초과가 사라지고, 한도와 '같으면' 걸린다고 읽으면 9a12e7c4 가 재시도 판정을 받으며, 제한 시간 판정에서 status 를 보지 않으면 4,310ms 에 성공한 petition_search 가 끊김으로 잡힙니다. 오류 숨김을 마지막 호출로만 보면 83e0b2c9 의 budget_api 오류가 빠집니다.
최종 답변 span 의 status 가 ok 라는 사실이 '처리 완료로 내보냈다' 는 뜻이 되려면 오케스트레이터가 업무를 못 끝낸 실행을 error 로 닫아야 합니다. 데모 에이전트는 그렇게 짰지만 타코웍스가 같은 약속을 지키는지는 모릅니다. 다르면 실패를 정직하게 알린 답변도 '도구 오류 뒤에도 성공처럼 답함' 에 걸립니다.
판정식은 오류 뒤에 같은 이름의 도구가 성공했는지만 봅니다. 없는 이름으로 부른 뒤 맞는 이름의 도구로 같은 일을 해낸 실행에도 오류 숨김이 함께 표시되므로, also_found 의 그 표시는 트레이스를 열어 확인합니다.
공고는 타코웍스가 실행 기록을 어떤 형식으로 남기는지 밝히지 않습니다. 실제 도입에서는 그 형식을 같은 span 표로 옮기는 어댑터가 먼저 필요하고, max_retries 처럼 이름이 같은 설정이 첫 호출을 빼고 세는지도 맞춰야 하는데, 이 둘은 현장 실행 기록을 받은 뒤에 정합니다.
① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.
데모 에이전트가 OTel Collector 파일 내보내기로 남긴 트레이스(OTLP JSON 줄)를 CLI 가 span 하나당 한 줄로 펼친 표입니다. 판정에 쓰는 invoke_agent·execute_tool span 만 남기고 chat span 은 펼칠 때 버립니다. 공고는 타코웍스 실행 기록의 형식을 밝히지 않아, 지원자가 자기 실행으로 같은 모양의 실물을 만들 수 있는 공개 규격을 골랐습니다. 키 순서만 다른 같은 인자, 제한 시간을 넘겼지만 성공한 호출, 인자 기록이 null 인 호출, 0ms 에 끝난 정의에 없는 도구 호출을 일부러 넣었습니다.
| trace_id | span_id | parent_span_id | start_time | operation | agent_name | tool_name | tool_args | status | duration_ms |
|---|---|---|---|---|---|---|---|---|---|
| 7f21c0a4e93b4d1f8a6c2e5b90d417aa | 7dce21d9e08414bd | — | 2026-10-07T09:12:03.120+09:00 | invoke_agent | 규정 질의 에이전트 | — | — | ok | 6,840 |
| 7f21c0a4e93b4d1f8a6c2e5b90d417aa | 16eaf0f648963898 | 7dce21d9e08414bd | 2026-10-07T09:12:04.010+09:00 | execute_tool | — | search_regulation | {"query":"출장비 정산 기한"} | error | 180 |
| 7f21c0a4e93b4d1f8a6c2e5b90d417aa | 8aead27a1290aebd | 7dce21d9e08414bd | 2026-10-07T09:12:05.420+09:00 | execute_tool | — | search_regulation | {"query":"출장비 정산 기한","dept_code":"D-12… | ok | 1,910 |
| 80a3f6d21c7e48b5b04a9e3c6f1d2208 | cd7ad77469cb1bef | — | 2026-10-07T09:31:40.200+09:00 | invoke_agent | 인사 문의 에이전트 | — | — | error | 14,050 |
| 80a3f6d21c7e48b5b04a9e3c6f1d2208 | 14435ebfb8edaaca | cd7ad77469cb1bef | 2026-10-07T09:31:41.050+09:00 | execute_tool | — | hr_db_lookup | {"employee_no":"E-20417"} | error | 12,400 |
아래 JSON Schema 를 그대로 만족하는 span 행을 트레이스 30개 분량으로 더 만들어 주세요. {"type":"object","properties":{"trace_id":{"type":"string","description":"OTLP traceId(16진수 32자)입니다. 에이전트 실행 하나가 트레이스 하나입니다"},"span_id":{"type":"string","description":"OTLP spanId(16진수 16자)입니다"},"parent_span_id":{"type":["string","null"],"description":"부모 span 입니다. 실행 전체를 덮는 invoke_agent span 만 null 이고, 이 span 이 최종 답변 span 입니다"},"start_time":{"type":"string","description":"startTimeUnixNano 를 ISO 8601(밀리초, +09:00)로 옮긴 값입니다. 판정식의 '뒤로'·'연달아' 순서는 이 값으로 정합니다"},"operation":{"type":"string","enum":["invoke_agent","execute_tool"],"description":"gen_ai.operation.name 입니다. chat span 은 펼칠 때 버립니다"},"agent_name":{"type":["string","null"],"description":"gen_ai.agent.name 입니다. invoke_agent span 에만 있습니다"},"tool_name":{"type":["string","null"],"description":"gen_ai.tool.name 입니다. execute_tool span 에만 있습니다"},"tool_args":{"type":["string","null"],"description":"gen_ai.tool.call.arguments(JSON 문자열)입니다. 이 속성을 남기지 않은 계측이면 null 입니다"},"status":{"type":"string","enum":["ok","error"],"description":"OTel status.code 가 ERROR 면 error, OK·UNSET 이면 ok 입니다"},"duration_ms":{"type":"integer","minimum":0,"description":"(endTimeUnixNano - startTimeUnixNano) / 1,000,000 입니다"}},"required":["trace_id","span_id","parent_span_id","start_time","operation","agent_name","tool_name","tool_args","status","duration_ms"]} 트레이스 하나는 parent_span_id 가 null 인 invoke_agent span 하나와 그 아래 execute_tool span 1~6개로 이뤄지고, execute_tool 의 parent_span_id 는 그 invoke_agent 의 span_id 입니다. trace_id 는 16진수 32자, span_id 는 16진수 16자로 쓰고, 자식 span 의 start_time 은 부모 span 이 덮는 시간 안에 두세요. tool_name 은 함께 주는 tool_definitions 의 이름을 주로 쓰고, tool_args 는 그 json_schema 에 맞는 JSON 문자열로 쓰세요. 쉬운 데이터만 만들지 말 것 — 다음 하드 케이스를 의도적으로 섞어라: (1) required 키가 빠진 tool_args 와 type 이 다른 tool_args, 그중 하나는 도구가 그대로 받아 status 가 ok 인 것, (2) duration_ms 가 timeout_ms 를 넘고 error 인 호출과, 넘었지만 ok 인 호출, (3) 같은 tool_name·같은 인자를 키 순서만 바꿔 연달아 부른 묶음과, 연달아 부른 개수가 max_retries 와 똑같은 묶음, (4) 오류 뒤 같은 도구를 다시 부르지 않고 다른 도구만 성공했는데 invoke_agent 가 ok 로 끝난 실행과, 같은 오류 뒤 invoke_agent 가 error 로 끝난 실행, (5) tool_definitions 에 없는 tool_name 으로 duration_ms 0 에 error 로 끝난 호출, (6) tool_args 가 null 인 호출. 생성한 행은 반드시 위 스키마를 통과해야 하며, 형식을 깨뜨리는 시도(잘린 JSON 줄, status 가 빠진 span)는 별도로 3건만 표시해 두세요.{"type":"object","properties":{"trace_id":{"type":"string","description":"OTLP traceId(16진수 32자)입니다. 에이전트 실행 하나가 트레이스 하나입니다"},"span_id":{"type":"string","description":"OTLP spanId(16진수 16자)입니다"},"parent_span_id":{"type":["string","null"],"description":"부모 span 입니다. 실행 전체를 덮는 invoke_agent span 만 null 이고, 이 span 이 최종 답변 span 입니다"},"start_time":{"type":"string","description":"startTimeUnixNano 를 ISO 8601(밀리초, +09:00)로 옮긴 값입니다. 판정식의 '뒤로'·'연달아' 순서는 이 값으로 정합니다"},"operation":{"type":"string","enum":["invoke_agent","execute_tool"],"description":"gen_ai.operation.name 입니다. chat span 은 펼칠 때 버립니다"},"agent_name":{"type":["string","null"],"description":"gen_ai.agent.name 입니다. invoke_agent span 에만 있습니다"},"tool_name":{"type":["string","null"],"description":"gen_ai.tool.name 입니다. execute_tool span 에만 있습니다"},"tool_args":{"type":["string","null"],"description":"gen_ai.tool.call.arguments(JSON 문자열)입니다. 이 속성을 남기지 않은 계측이면 null 입니다"},"status":{"type":"string","enum":["ok","error"],"description":"OTel status.code 가 ERROR 면 error, OK·UNSET 이면 ok 입니다"},"duration_ms":{"type":"integer","minimum":0,"description":"(endTimeUnixNano - startTimeUnixNano) / 1,000,000 입니다"}},"required":["trace_id","span_id","parent_span_id","start_time","operation","agent_name","tool_name","tool_args","status","duration_ms"]}데모 에이전트에 등록한 도구 정의(tools.json)입니다. 모델이 읽는 도구 설명, 인자의 JSON Schema, 제한 시간, 같은 호출을 연달아 둘 수 있는 개수가 도구마다 있습니다. search_regulation 처럼 필수 키를 설명에 적지 않은 도구를 일부러 넣었습니다.
| tool_name | description | json_schema | timeout_ms | max_retries |
|---|---|---|---|---|
| search_regulation | 기관 내부 규정 문서에서 질문과 관련된 조문을 찾습니다. | {"type":"object","properties":{"query"… | 6,000 | 2 |
| org_chart_lookup | 부서 이름으로 부서 코드를 찾습니다. | {"type":"object","properties":{"dept_n… | 3,000 | 2 |
| hr_db_lookup | 직원 번호로 소속·직급·휴가 잔여일을 조회합니다. | {"type":"object","properties":{"employ… | 8,000 | 1 |
| ocr_attachment | 첨부 파일의 지정한 쪽을 글자로 옮깁니다. | {"type":"object","properties":{"file_i… | 15,000 | 3 |
| budget_api | 부서·연도·분기별 예산 집행 현황을 조회합니다. | {"type":"object","properties":{"dept_c… | 5,000 | 2 |
아래 JSON Schema 를 그대로 만족하는 도구 정의를 10개 더 만들어 주세요. {"type":"object","properties":{"tool_name":{"type":"string"},"description":{"type":"string","description":"데모 에이전트의 모델이 읽는 도구 설명입니다"},"json_schema":{"type":"string","description":"도구 인자의 JSON Schema 원문입니다. 판정은 required 와 properties.*.type 두 가지만 봅니다"},"timeout_ms":{"type":"integer","minimum":1},"max_retries":{"type":"integer","minimum":1,"description":"같은 tool_name·같은 tool_args 로 연달아 둘 수 있는 호출 개수입니다(첫 호출 포함). 연달아 이어진 호출 개수가 이 값을 넘으면 판정에 걸립니다"}},"required":["tool_name","description","json_schema","timeout_ms","max_retries"]} 기관 업무 에이전트가 부를 만한 조회 도구(공문 검색, 자산 대장 조회, 출장 일정 조회 등)로 하고, json_schema 는 type·properties·required 를 가진 JSON Schema 문자열로 쓰세요. 쉬운 데이터만 만들지 말 것 — 다음 하드 케이스를 의도적으로 섞어라: (1) 필수 키가 있는데 description 에는 그 키를 적지 않은 도구, (2) 다른 도구로 먼저 구해야 하는 키(부서 코드·직원 번호)를 required 로 둔 도구, (3) max_retries 가 1 이라 같은 호출을 연달아 두 번 부르면 바로 걸리는 도구, (4) timeout_ms 가 1,000 이하로 짧은 도구. 생성한 행은 반드시 위 스키마를 통과해야 하며, 형식을 깨뜨리는 시도(json_schema 가 JSON 이 아닌 문자열)는 별도로 3건만 표시해 두세요.{"type":"object","properties":{"tool_name":{"type":"string"},"description":{"type":"string","description":"데모 에이전트의 모델이 읽는 도구 설명입니다"},"json_schema":{"type":"string","description":"도구 인자의 JSON Schema 원문입니다. 판정은 required 와 properties.*.type 두 가지만 봅니다"},"timeout_ms":{"type":"integer","minimum":1},"max_retries":{"type":"integer","minimum":1,"description":"같은 tool_name·같은 tool_args 로 연달아 둘 수 있는 호출 개수입니다(첫 호출 포함). 연달아 이어진 호출 개수가 이 값을 넘으면 판정에 걸립니다"}},"required":["tool_name","description","json_schema","timeout_ms","max_retries"]}| Python | taco-trace CLI 본체입니다. OTLP JSON 줄을 span 표로 펼치고, jsonschema 로 required·type 위반만 골라내고, 다섯 판정과 우선순위를 돌려 터미널 표와 JSON 을 냅니다. |
| Java | 데모 에이전트의 도구와 계측 코드를 씁니다. 도구를 부를 때마다 OpenTelemetry Java API 로 execute_tool span 을 열고 인자와 status 를 남깁니다. |
| Spring | 데모 에이전트를 Spring Boot 와 Spring AI 로 띄웁니다. 도구는 @Tool 메서드로 등록하고, 2주차 고장 스위치는 설정값으로 켭니다. |
| OpenTelemetry | 입력의 공개 규격입니다. GenAI 규약 속성 gen_ai.operation.name·gen_ai.agent.name·gen_ai.tool.name·gen_ai.tool.call.arguments 를 span 에 남기고, Docker 로 띄운 Collector 의 파일 내보내기로 JSONL 을 받습니다. |
| LLM | 데모 에이전트 안에서 도구를 고르고 인자를 채우는 쪽입니다. 그 결정이 트레이스로 남아 이 CLI 의 입력이 됩니다. |
| Claude | Claude Sonnet 이 필수 키가 빠진 실행의 도구 설명 수정안 초안을 씁니다. 2주차에는 Claude Haiku 를 데모 에이전트 모델로도 써서 GPT 와 결과를 견줍니다. |
| OpenAI | 2주차에 데모 에이전트 모델을 GPT 로 바꿔 돌려, 같은 도구 설명에서 인자 불일치가 모델에 따라 어떻게 달라지는지 셉니다. |
| RAG | 데모 에이전트의 search_regulation 도구가 규정 문서에서 관련 조문을 찾아 모델에 넘깁니다. dept_code 없이 불린 이 검색 도구가 첫 번째 판정 사례입니다. |
| 전자정부 표준프레임워크 | 3주차에 같은 계측 코드를 전자정부 표준프레임워크 기반 데모 프로젝트로 옮겨, 공공기관용 타코웍스와 같은 Spring·Java 환경에서도 트레이스 모양이 그대로인지 확인합니다. |
| Claude Code | 판정식의 부등호마다 같은 값 트레이스로 테스트를 늘릴 때 씁니다. 한 글자 차이로 판정이 바뀌는 자리라 테스트를 규칙보다 먼저 둡니다. |
✗ fail → 한 묶음으로 세지 못하면 tool_args 를 키 정렬해 견주는 부분부터 고칩니다.
✓ pass → 여기서 멈춰도 완결입니다. 더 키우려면 데모 에이전트에 고장 스위치를 달아 판정이 맞는지 세는 단계로 갑니다.
✓ pass → 여기까지도 완결입니다. 더 키우려면 여러 날의 판정을 모아 HQ 제품팀에 넘길 후보를 만드는 단계로 갑니다.
도구 호출 실패 원인 판정입니다. 에이전트 실행(trace) 하나에 판정 하나와 근거 span, 고칠 곳을 남기는 형식입니다. 필수 키가 빠진 실행에는 도구 설명 수정안 초안이 더해집니다.
{"type":"object","properties":{"trace_id":{"type":"string"},"agent_name":{"type":["string","null"],"description":"최종 답변 span(parent_span_id 가 null 인 invoke_agent)의 agent_name 입니다"},"final_status":{"type":"string","enum":["ok","error"],"description":"최종 답변 span 의 status 입니다"},"tool_calls":{"type":"integer","minimum":0,"description":"같은 trace_id 의 execute_tool span 개수입니다"},"verdict":{"type":"string","enum":["정상 완료","도구 정의와 맞지 않는 인자로 부름","제한 시간을 넘겨 끊김","같은 호출을 재시도 한도보다 많이 되풀이함","도구 오류 뒤에도 성공처럼 답함","정의에 없는 도구를 부름"],"description":"걸린 판정이 여럿이면 정의에 없는 도구를 부름, 도구 정의와 맞지 않는 인자로 부름, 제한 시간을 넘겨 끊김, 같은 호출을 재시도 한도보다 많이 되풀이함, 도구 오류 뒤에도 성공처럼 답함 순으로 앞선 하나입니다. 하나도 걸리지 않으면 정상 완료입니다"},"also_found":{"type":"array","items":{"type":"string","enum":["도구 정의와 맞지 않는 인자로 부름","제한 시간을 넘겨 끊김","같은 호출을 재시도 한도보다 많이 되풀이함","도구 오류 뒤에도 성공처럼 답함","정의에 없는 도구를 부름"]},"description":"verdict 로 고르지 않은 나머지 판정입니다"},"findings":{"type":"array","items":{"type":"object","properties":{"verdict":{"type":"string","enum":["도구 정의와 맞지 않는 인자로 부름","제한 시간을 넘겨 끊김","같은 호출을 재시도 한도보다 많이 되풀이함","도구 오류 뒤에도 성공처럼 답함","정의에 없는 도구를 부름"]},"tool_name":{"type":"string"},"span_ids":{"type":"array","items":{"type":"string"}},"missing_keys":{"type":"array","items":{"type":"string"},"description":"json_schema 의 required 가운데 tool_args 에 없는 키입니다"},"type_errors":{"type":"array","items":{"type":"string"},"description":"'키: 받은 type → 정의 type' 꼴입니다"},"timeout_gap_ms":{"type":["integer","null"],"description":"duration_ms 에서 timeout_ms 를 뺀 값입니다. 제한 시간 판정에서만 채웁니다"},"run_length":{"type":["integer","null"],"description":"start_time 순으로 같은 tool_name·같은 tool_args(키 정렬 JSON)가 연달아 이어진 호출 개수입니다. 재시도 판정에서만 채웁니다"},"evidence":{"type":"array","items":{"type":"object","properties":{"table":{"type":"string","enum":["spans","tool_definitions"]},"row":{"type":["string","null"],"description":"spans 는 span_id, tool_definitions 는 tool_name 입니다. agg 항목이면 null 입니다"},"field":{"type":"string"},"value":{"type":["string","integer","null"]},"agg":{"type":"string","enum":["count","sum","avg","min","max"]}},"required":["table","row","field","value"]}}},"required":["verdict","tool_name","span_ids","missing_keys","type_errors","timeout_gap_ms","run_length","evidence"]}},"notes":{"type":"array","items":{"type":"string"},"description":"판정에 들지 않았지만 상주 개발자가 볼 사실입니다(건너뛴 인자 검사, 제한 시간을 넘긴 성공 호출 등)"},"fix_target":{"type":["string","null"],"enum":["도구 설명","인자 스키마","제한 시간 설정","재시도 설정","오류 처리 흐름",null]},"description_draft":{"type":["string","null"],"description":"missing_keys 가 있는 인자 판정에서만 Claude 가 쓴 도구 설명 수정안입니다. 나머지는 null 입니다"},"summary":{"type":"string"}},"required":["trace_id","agent_name","final_status","tool_calls","verdict","also_found","findings","notes","fix_target","description_draft","summary"]}[
{
"trace_id": "7f21c0a4e93b4d1f8a6c2e5b90d417aa",
"agent_name": "규정 질의 에이전트",
"final_status": "ok",
"tool_calls": 2,
"verdict": "도구 정의와 맞지 않는 인자로 부름",
"also_found": [],
"findings": [
{
"verdict": "도구 정의와 맞지 않는 인자로 부름",
"tool_name": "search_regulation",
"span_ids": [
"16eaf0f648963898"
],
"missing_keys": [
"dept_code"
],
"type_errors": [],
"timeout_gap_ms": null,
"run_length": null,
"evidence": [
{
"table": "spans",
"row": "16eaf0f648963898",
"field": "tool_args",
"value": "{\"query\":\"출장비 정산 기한\"}"
},
{
"table": "tool_definitions",
"row": "search_regulation",
"field": "json_schema",
"value": "{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\"},\"dept_code\":{\"type\":\"string\"}},\"required\":[\"query\",\"dept_code\"]}"
}
]
}
],
"notes": [],
"fix_target": "도구 설명",
"description_draft": "기관 내부 규정 문서에서 질문과 관련된 조문을 찾습니다. dept_code(부서 코드)는 빠뜨리면 안 되는 값입니다. 사용자가 부서 이름만 말했으면 먼저 org_chart_lookup 에 부서 이름을 넣어 코드를 받은 뒤 이 도구를 부르세요.",
"summary": "search_regulation 을 필수 키 dept_code 없이 불러 오류가 났고, 다음 호출에서 dept_code 를 넣어 답을 냈습니다."
},
{
"trace_id": "80a3f6d21c7e48b5b04a9e3c6f1d2208",
"agent_name": "인사 문의 에이전트",
"final_status": "error",
"tool_calls": 1,
"verdict": "제한 시간을 넘겨 끊김",
"also_found": [],
"findings": [
{
"verdict": "제한 시간을 넘겨 끊김",
"tool_name": "hr_db_lookup",
"span_ids": [
"14435ebfb8edaaca"
],
"missing_keys": [],
"type_errors": [],
"timeout_gap_ms": 4400,
"run_length": null,
"evidence": [
{
"table": "spans",
"row": "14435ebfb8edaaca",
"field": "duration_ms",
"value": 12400
},
{
"table": "tool_definitions",
"row": "hr_db_lookup",
"field": "timeout_ms",
"value": 8000
},
{
"table": "spans",
"row": "14435ebfb8edaaca",
"field": "status",
"value": "error"
}
]
}
],
"notes": [
"에이전트가 실패를 알리고 끝나 최종 답변 span 이 error 입니다. 오류 숨김 판정에는 들지 않습니다."
],
"fix_target": "제한 시간 설정",
"description_draft": null,
"summary": "hr_db_lookup 이 12,400ms 만에 오류로 끝나 제한 시간 8,000ms 를 4,400ms 넘겼습니다."
},
{
"trace_id": "81c95e0b7a2d4f63a8c1d0e9b4f72a16",
"agent_name": "첨부 검토 에이전트",
"final_status": "ok",
"tool_calls": 4,
"verdict": "같은 호출을 재시도 한도보다 많이 되풀이함",
"also_found": [],
"findings": [
{
"verdict": "같은 호출을 재시도 한도보다 많이 되풀이함",
"tool_name": "ocr_attachment",
"span_ids": [
"4f97e404096b9bb0",
"2245cf68a42f3d0f",
"ead273920e3b58ff",
"086fb743579fd9f8"
],
"missing_keys": [],
"type_errors": [],
"timeout_gap_ms": null,
"run_length": 4,
"evidence": [
{
"table": "spans",
"row": null,
"field": "span_id",
"agg": "count",
"value": 4
},
{
"table": "spans",
"row": "4f97e404096b9bb0",
"field": "tool_args",
"value": "{\"file_id\":\"F-2210\",\"page\":3}"
},
{
"table": "tool_definitions",
"row": "ocr_attachment",
"field": "max_retries",
"value": 3
}
]
}
],
"notes": [
"묶음 안에 키 순서만 다른 tool_args 가 있어 같은 호출로 셌습니다."
],
"fix_target": "재시도 설정",
"description_draft": null,
"summary": "ocr_attachment 를 같은 인자로 연달아 4번 불러 한도 3을 넘겼습니다."
},
{
"trace_id": "83e0b2c94f1a4d7e9c6b5a3f0e8d1c42",
"agent_name": "예산 집행 질의 에이전트",
"final_status": "ok",
"tool_calls": 3,
"verdict": "도구 오류 뒤에도 성공처럼 답함",
"also_found": [],
"findings": [
{
"verdict": "도구 오류 뒤에도 성공처럼 답함",
"tool_name": "budget_api",
"span_ids": [
"b025a8d69896d987",
"01bc655993a9926d"
],
"missing_keys": [],
"type_errors": [],
"timeout_gap_ms": null,
"run_length": null,
"evidence": [
{
"table": "spans",
"row": "b025a8d69896d987",
"field": "tool_name",
"value": "budget_api"
},
{
"table": "spans",
"row": "b025a8d69896d987",
"field": "status",
"value": "error"
},
{
"table": "spans",
"row": null,
"field": "span_id",
"agg": "count",
"value": 0
},
{
"table": "spans",
"row": "01bc655993a9926d",
"field": "status",
"value": "ok"
}
]
}
],
"notes": [
"contract_registry 호출(56d05f417d1bbda8)은 tool_args 기록이 없어 인자 검사를 건너뛰었습니다."
],
"fix_target": "오류 처리 흐름",
"description_draft": null,
"summary": "budget_api 가 오류를 낸 뒤 다시 불리지 않았는데 실행은 ok 로 끝났습니다. 예산 집행 현황 없이 답이 나갔는지 답변을 열어 봅니다."
},
{
"trace_id": "a5f03c8e21d74b6990e4c1a7b3d52f08",
"agent_name": "예산 집행 질의 에이전트",
"final_status": "ok",
"tool_calls": 1,
"verdict": "정의에 없는 도구를 부름",
"also_found": [
"도구 오류 뒤에도 성공처럼 답함"
],
"findings": [
{
"verdict": "정의에 없는 도구를 부름",
"tool_name": "get_budget_status",
"span_ids": [
"fe41a71a6e6ce5fc"
],
"missing_keys": [],
"type_errors": [],
"timeout_gap_ms": null,
"run_length": null,
"evidence": [
{
"table": "spans",
"row": "fe41a71a6e6ce5fc",
"field": "tool_name",
"value": "get_budget_status"
},
{
"table": "tool_definitions",
"row": null,
"field": "tool_name",
"agg": "count",
"value": 0
}
]
},
{
"verdict": "도구 오류 뒤에도 성공처럼 답함",
"tool_name": "get_budget_status",
"span_ids": [
"fe41a71a6e6ce5fc",
"38fd00a9e725c977"
],
"missing_keys": [],
"type_errors": [],
"timeout_gap_ms": null,
"run_length": null,
"evidence": [
{
"table": "spans",
"row": "fe41a71a6e6ce5fc",
"field": "tool_name",
"value": "get_budget_status"
},
{
"table": "spans",
"row": "fe41a71a6e6ce5fc",
"field": "status",
"value": "error"
},
{
"table": "spans",
"row": null,
"field": "span_id",
"agg": "count",
"value": 0
},
{
"table": "spans",
"row": "38fd00a9e725c977",
"field": "status",
"value": "ok"
}
]
}
],
"notes": [
"get_budget_status 는 정의에 없는 도구라 인자 검사를 하지 않았습니다."
],
"fix_target": "도구 설명",
"description_draft": null,
"summary": "tools.json 에 없는 get_budget_status 를 불러 0ms 에 오류가 났고, 다른 도구를 부르지 않은 채 실행이 ok 로 끝났습니다."
},
{
"trace_id": "b2e6d9a0f47c4e1385b0a2d6c9e17f63",
"agent_name": "예산 집행 질의 에이전트",
"final_status": "ok",
"tool_calls": 1,
"verdict": "도구 정의와 맞지 않는 인자로 부름",
"also_found": [],
"findings": [
{
"verdict": "도구 정의와 맞지 않는 인자로 부름",
"tool_name": "budget_api",
"span_ids": [
"2bf035edfa25067f"
],
"missing_keys": [],
"type_errors": [
"year: string → integer"
],
"timeout_gap_ms": null,
"run_length": null,
"evidence": [
{
"table": "spans",
"row": "2bf035edfa25067f",
"field": "tool_args",
"value": "{\"dept_code\":\"D-1203\",\"year\":\"2026\"}"
},
{
"table": "tool_definitions",
"row": "budget_api",
"field": "json_schema",
"value": "{\"type\":\"object\",\"properties\":{\"dept_code\":{\"type\":\"string\"},\"year\":{\"type\":\"integer\"},\"quarter\":{\"type\":\"integer\"}},\"required\":[\"dept_code\",\"year\"]}"
}
]
}
],
"notes": [],
"fix_target": "인자 스키마",
"description_draft": null,
"summary": "budget_api 의 year 를 정수가 아닌 문자열 '2026' 으로 넘겼고, 도구는 그대로 받아 ok 로 끝났습니다."
},
{
"trace_id": "8d47a1e0c3b24f9682e5d7c1a09b3f55",
"agent_name": "규정 질의 에이전트",
"final_status": "ok",
"tool_calls": 2,
"verdict": "정상 완료",
"also_found": [],
"findings": [],
"notes": [],
"fix_target": null,
"description_draft": null,
"summary": "도구 두 번을 정의대로 불렀고 오류 없이 끝났습니다."
},
{
"trace_id": "9a12e7c40b5f4d83a6e1c9b2d70f4e31",
"agent_name": "민원 답변 초안 에이전트",
"final_status": "ok",
"tool_calls": 2,
"verdict": "정상 완료",
"also_found": [],
"findings": [],
"notes": [
"petition_search 호출(e830212c7982f1d5)은 4,310ms 로 제한 시간 4,000ms 를 넘겼지만 status 가 ok 라 판정에 들지 않습니다. 제한 시간이 실제로 걸리는지 설정을 확인합니다.",
"petition_search 를 같은 인자로 연달아 2번 불렀고 한도 2와 같아 재시도 판정에 들지 않습니다."
],
"fix_target": null,
"description_draft": null,
"summary": "petition_search 첫 호출의 오류를 같은 인자의 두 번째 호출이 회복해 다섯 판정 어디에도 들지 않습니다."
}
][자동 검증 · 코드가 판정합니다] 1. verdict 가 정상 완료·도구 정의와 맞지 않는 인자로 부름·제한 시간을 넘겨 끊김·같은 호출을 재시도 한도보다 많이 되풀이함·도구 오류 뒤에도 성공처럼 답함·정의에 없는 도구를 부름 여섯 값 중 하나인지, also_found 와 findings[].verdict 가 정상 완료를 뺀 다섯 값 중 하나인지 확인합니다. 2. 필수 필드 trace_id·agent_name·final_status·tool_calls·verdict·also_found·findings·notes·fix_target·description_draft·summary 가 모두 존재하는지 확인합니다. 3. 펼친 표를 다시 계산합니다. final_status 는 parent_span_id 가 null 인 invoke_agent span(최종 답변 span)의 status 이고, tool_calls 는 같은 trace_id 의 execute_tool span 개수입니다. '뒤로'·'연달아' 의 순서는 start_time 으로 정합니다. 4. 정의에 없는 도구를 부름: execute_tool span 의 tool_name 이 tool_definitions.tool_name 목록에 있는지 확인하고, 없으면 이 판정이 걸립니다. get_budget_status(a5f03c8e)가 이 경우입니다. 5. 도구 정의와 맞지 않는 인자로 부름: execute_tool span 의 tool_args 를 JSON 으로 읽어 같은 tool_name 의 json_schema 와 대조합니다. required 에 있는 키가 tool_args 에 없으면 missing_keys 에, 있는 키의 값이 properties 의 type 과 다르면 type_errors 에 넣고, 둘 중 하나라도 비어 있지 않으면 걸리는지 다시 계산합니다. tool_args 가 null 이거나 정의에 없는 도구인 span 은 이 검사를 건너뛰고 notes 에 남깁니다. search_regulation 첫 호출(7f21c0a4)은 dept_code 가 없어 걸리고, budget_api 의 year '2026'(b2e6d9a0)은 type 이 달라 걸립니다. 6. 제한 시간을 넘겨 끊김: execute_tool span 의 duration_ms 가 같은 tool_name 의 timeout_ms 를 넘고 status 가 error 면 걸리고, timeout_gap_ms 가 duration_ms 에서 timeout_ms 를 뺀 값과 일치하는지 다시 계산합니다. 넘었어도 status 가 ok 면 걸리지 않습니다. hr_db_lookup 12,400ms·error(80a3f6d2)는 걸려 4,400ms 이고, petition_search 4,310ms·ok(9a12e7c4)는 걸리지 않습니다. 7. 같은 호출을 재시도 한도보다 많이 되풀이함: 한 trace_id 안 execute_tool span 을 start_time 순으로 늘어놓고, 앞 호출과 tool_name 이 같고 tool_args 를 키 정렬한 JSON 이 같으면 한 묶음으로 이어 셉니다. 묶음의 호출 개수(run_length)가 그 도구의 max_retries 를 넘으면 걸리는지 다시 계산합니다. tool_args 가 null 인 호출은 어느 묶음에도 넣지 않습니다. 세 번째 호출만 키 순서가 다른 ocr_attachment 4회(81c95e0b)는 한도 3을 넘어 걸리고, petition_search 2회(9a12e7c4)는 한도 2와 같아 걸리지 않습니다. 8. 도구 오류 뒤에도 성공처럼 답함: status 가 error 인 execute_tool span 하나하나에 대해 그보다 start_time 이 늦은 같은 tool_name 의 status ok span 이 있는지 봅니다. 그런 span 이 없는 오류가 하나라도 있고 final_status 가 ok 면 걸리는지 다시 계산합니다. 마지막 호출이 아닌 오류도 셉니다. budget_api 오류 뒤 다른 도구만 성공한 83e0b2c9 는 걸리고, 같은 모양의 오류라도 final_status 가 error 인 80a3f6d2 는 걸리지 않습니다. 9. 실행 하나에 여러 판정이 걸리면 정의에 없는 도구를 부름, 도구 정의와 맞지 않는 인자로 부름, 제한 시간을 넘겨 끊김, 같은 호출을 재시도 한도보다 많이 되풀이함, 도구 오류 뒤에도 성공처럼 답함 순으로 앞선 하나가 verdict 이고 나머지는 also_found 입니다. 아무것도 걸리지 않으면 verdict 는 정상 완료입니다. a5f03c8e 는 verdict 가 정의에 없는 도구를 부름이고 also_found 가 도구 오류 뒤에도 성공처럼 답함인지 다시 계산합니다. 10. fix_target 이 다섯 값 중 하나이거나 null 인지 확인합니다. 인자 판정은 missing_keys 가 있으면 도구 설명, type_errors 만 있으면 인자 스키마이고, 정의에 없는 도구는 도구 설명, 제한 시간은 제한 시간 설정, 재시도는 재시도 설정, 오류 숨김은 오류 처리 흐름, 정상 완료는 null 입니다. 11. description_draft 는 missing_keys 가 있는 인자 판정이 있을 때만 채우고 나머지는 null 입니다. 초안이 인용한 필드가 그 도구 json_schema 의 properties 에 실재하는지 확인합니다. 12. evidence 의 table·field 가 spans·tool_definitions 에 실재하는 컬럼인지 대조합니다. 13. agg 가 없는 evidence 의 value 가 그 row 의 그 컬럼 값 원문과 같은지 확인합니다. agg 가 count 인 값은 재시도 묶음의 span 수, 오류 뒤 같은 이름의 성공 호출 수, 정의에서 그 이름을 가진 행 수입니다. 14. summary 가 존댓말로 끝나는지 확인합니다. [수동 검증 · 사람이 봅니다] 1. 도구 설명 수정안을 그대로 쓸지는 상주 개발자가 읽고 정합니다. 반영한 뒤 같은 질문으로 다시 돌려 인자 판정이 사라졌는지 봅니다. 2. 오류 숨김으로 걸린 실행이 실제로 기관 직원에게 처리된 것처럼 읽히는 답이었는지는 답변 문장을 열어 사람이 봅니다. 이 CLI 는 답변 내용이 아니라 status 만 읽습니다. 3. 정의에 없는 이름으로 부른 뒤 다른 이름의 도구로 같은 일을 해낸 실행도 판정식대로 오류 숨김이 함께 표시됩니다. 그 표시를 지울지는 FDE 가 트레이스를 열어 정합니다. 4. 같은 도구·같은 판정이 여러 에이전트에서 되풀이될 때 응용프로그램 쪽 문제인지 코어 런타임 이슈인지는 FDE 가 HQ 제품팀과 정합니다. [평가 러너 · 2주차] 1. 데모 에이전트에 다섯 가지 고장을 스위치로 넣어 40번 돌리고, 넣은 고장과 verdict 가 맞은 실행 수를 셉니다. 2. 수정안을 도구 설명에 반영하기 전과 후로 같은 질문 20개를 Claude 와 GPT 모델로 각각 돌려, 도구 정의와 맞지 않는 인자로 부름이 나온 실행 수를 견줍니다. [판정식에 더한 정의 · 오너 확인 항목] 1. '뒤로'·'연달아' 의 순서는 카드 inputs 에 없던 spans.start_time 으로 정합니다. span_id 는 무작위 16진수라 순서를 담지 않습니다. 2. 최종 답변 span 은 parent_span_id 가 null 인 invoke_agent span 으로 정했습니다. 데모 에이전트의 오케스트레이터는 업무를 끝내지 못하고 실패를 알린 실행을 error 로 닫습니다. 3. 같은 tool_args 는 키를 정렬한 JSON 이 같은 것으로 봅니다. 인자 검사는 카드의 '필수 키가 없거나 형식이 다르면' 대로 json_schema 의 required 와 properties.*.type 만 봅니다. 4. max_retries 는 같은 호출을 연달아 둘 수 있는 개수(첫 호출 포함)로 읽습니다. 카드 판정식이 '연달아 이어진 호출 개수가 max_retries 를 넘으면' 이라, 첫 호출을 빼고 세는 프레임워크 설정을 그대로 옮기면 한 번 일찍 걸립니다.