Skip to content

[AI Run][P0] Agent 요청 Slot 조회·재호출 오케스트레이션 구현 #74

Description

@hywznn

한 줄 목표

Agent가 요구한 canonical Slot을 현재 사업장의 Worker DB에서 안전하게 조회하고, 같은 분석을 새로운 Attempt로 이어서 호출합니다.

Agent 분석만으로 Task를 자동 생성·승인·발송하지 않습니다.

쉽게 보는 흐름

PLAN: "발화문, INTENT_TAG" 분석
→ CONTEXT_REQUIRED: Agent가 필요한 Slot key 반환
→ Server: 사업장 안에서 근로자 확인 + 허용된 값만 DB 조회
→ ANALYZE: 같은 requestId·instruction으로 Agent 재호출
→ NEEDS_INFO 질문 또는 REVIEW_REQUIRED 후보

Agent는 SQL을 만들거나 Server DB에 직접 접근하지 않습니다.

확정한 계약

  • 통신: Server ↔ AI Runtime은 REST·JSON이며 #56의 AiRuntimeClient만 사용
  • 입력: 태그가 있으면 발화문, INTENT_TAG로 합친 instruction 문자열 하나만 전송
  • 별도 intentHint 필드와 Intent 불일치 필드는 만들지 않음
  • Runtime 식별자: PLAN과 ANALYZE는 같은 requestId를 전송
  • Attempt 식별자: Runtime 호출마다 새 attemptId를 Server 내부에 먼저 기록하고 AI JSON에는 넣지 않음
  • 대상: MVP에서는 요청 한 건당 Worker 한 명
  • 이름 규칙: Knowledge required_slots.yaml의 접두사 없는 canonical key 사용
    • 사용: worker_id, stay_expiry_date, contract_end_date
    • 사용하지 않음: worker.stay_expiry_date, DB column명, SQL 표현식
  • Resolver 허용 범위: Agent의 detectedIntent와 활성 Workflow Catalog로 결정
  • 반복 제한: 한 실행에서 자동 DB 보충은 최대 2회, 이후 HR 확인 상태로 전환
  • Client 진행 확인: #24의 202 + aiRunId와 GET polling 사용, SSE는 [AI Run][P1] Client용 AiRun 진행 상태 SSE 구독 추가 #75 후속 범위

Runtime 계약 예시

Agent가 DB 정보를 요청합니다.

{
  "outcome": "CONTEXT_REQUIRED",
  "contextRequirement": {
    "detectedIntent": "EXPIRY_RENEWAL",
    "confidence": 0.94,
    "targetDisplayName": "응웬반안",
    "extractedSlots": {},
    "requiredFieldKeys": [
      "worker_id",
      "stay_expiry_date",
      "contract_end_date"
    ]
  }
}

Server가 허용된 값만 넣어 재호출합니다.

{
  "requestId": "10000000-0000-0000-0000-000000000001",
  "phase": "ANALYZE",
  "analysisInput": {
    "instruction": "응웬반안 체류연장 준비해줘, EXPIRY_RENEWAL",
    "requestedFieldKeys": [
      "worker_id",
      "stay_expiry_date",
      "contract_end_date"
    ],
    "workers": [
      {
        "workerRef": "worker-uuid",
        "requestedFields": {
          "worker_id": "worker-uuid",
          "stay_expiry_date": "2026-09-30",
          "contract_end_date": "2026-08-31"
        }
      }
    ]
  }
}

Server 작업 범위

1. Slot Resolver

  • targetDisplayName을 현재 companyId 안에서 정확히 한 명의 Worker로 확인
  • 활성 Workflow Catalog에서 Intent별 Workflow와 조회 허용 Slot 계산
  • 고정된 Repository 조회와 switch 매핑으로 값 조회
  • resolvedFields, missingFieldKeys, forbiddenFieldKeys 구분
  • 허용되지 않은 key, 임의 SQL, 임의 DB column 요청 거부
  • 조회 원문은 일반 로그와 오류 메시지에 남기지 않음

2. Agent 재호출

  • 기존 PLAN의 단일 instructionrequestId 유지
  • 조회된 Worker context와 Workflow constraint로 ANALYZE 요청 생성
  • Runtime 호출 전에 새 attemptId를 발급·기록하는 Port 호출
  • 최대 보충 횟수와 전체 deadline 검사
  • CONTEXT_REQUIRED, NEEDS_INFO, REVIEW_REQUIRED 결과 구분
  • 투명 HTTP retry와 Task 자동 생성을 하지 않음

3. #24와 연결

#74에서는 Attempt 기록 Port와 오케스트레이션 규칙을 먼저 만들고 Fake로 순서를 검증합니다. #24가 V12 저장소를 구현할 때 이 Port를 PostgreSQL AiAttempt 기록으로 연결합니다.

테스트 완료 기준

  • A 회사 요청으로 A 회사 Worker 값만 조회
  • B 회사에만 있는 같은 이름 또는 Worker 값 차단
  • 대상 없음·동명이인·값 누락·금지 key를 서로 다른 안전한 결과로 구분
  • PLAN → CONTEXT_REQUIRED → ANALYZE에서 Runtime의 requestId는 같고 Server 내부 attemptId는 달라짐
  • PLAN의 합쳐진 instruction이 ANALYZE에도 그대로 유지됨
  • Attempt 기록이 Runtime HTTP 호출보다 먼저 실행됨
  • 2회를 넘는 자동 보충과 같은 Attempt 중복 호출 차단
  • Agent 결과만으로 Task·승인·발송이 생성되지 않음

현재 DB에서 조회 가능한 범위

  • worker_id
  • stay_expiry_date
  • contract_end_date

legal_name, 여권번호, 외국인등록번호, 전화번호 등은 현재 Worker 운영 테이블에 없으므로 DB에서 임의 생성하지 않습니다. 추후 별도 민감정보 저장 정책과 Schema가 확정되기 전에는 누락 값으로 처리합니다.

의존 관계

범위 밖

  • Agent Prompt·Provider·Plan-Act 내부 구현
  • Knowledge 원본 YAML 수정
  • Client SSE
  • 실제 개인정보 저장 정책
  • AI 결과 자동 승인·자동 발송·기관 자동 제출

Metadata

Metadata

Assignees

Labels

area:ai-integrationServer ↔ AI Runtime 내부 계약·Client·검증·trace 연동 영역; Prompt·모델·Provider 구현은 ai 저장소 소유area:serverSpring Boot API·도메인·DB·tenant·Task Workflow 영역; Prompt·모델·Provider 구현 제외priority:P0MVP 진행을 막는 최우선 핵심 작업security:privacy개인정보·접근권한·토큰·보안 영향이 있는 작업status:blocked선행 작업이나 외부 조건 때문에 현재 진행할 수 없는 작업type:integration외부 LLM·DB·스토리지 등 시스템 간 연동 작업

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions