14 KiB
14 KiB
tags: [robeing, infra, operations, response-failure, research, root-cause]
260307 23서버 인프라점검 응답실패 원인확정 리서치
1) 목적
- 대상 문제 1개만 원인 확정:
- 사용자가
23 서버 잘 돌아가는지 체크해줘,아이피는 뭐야?라고 물었을 때 로빙이 실행형 답변 대신 재질문/무근거 단정을 반환한 문제
- 목표: 이 실패가 어디서 만들어졌는지 코드, 실행 로그, 문서, 커밋 이력, 외부 1차 자료를 기준으로 단일 원인 사슬로 좁힌다.
2) 범위 / 비범위
- 범위:
rb8001의 메시지 처리 경로, 의도 분류, 질문 확장, 내부 LLM 호출, 시스템 프롬프트, 관련 리서치/트러블슈팅 문서 - 비범위:
23 서버실제 장애 여부, nginx/docker/postgresql 상태 자체, 51124 배포 문제, 다른 도메인 프로젝트
3) 사실(Facts)
3-1. 실제 실패 대화 사실
- 사용자 발화 순서:
23 서버잘 돌아가는 지 체크해줘어떻게 돌아가는데? 아이피는 뭐야?
- 로빙 응답 순서:
이사님, 23번 서버에 대해 어떤 정보가 필요하신가요?이사님, 현재 인프라가 잘 작동하고 있다는 점을 확인했습니다. 혹시 더 구체적으로 확인하고 싶으신 부분이 있으신가요?이사님, 현재 인프라가 잘 작동하고 있다는 점을 확인했습니다. 혹시 특정 서버의 IP 주소를 확인하고 싶으신가요?
3-2. 실행 환경 사실
rb8001컨테이너 환경값:DEFAULT_LLM_MODEL=gemini-2.5-flash-liteINTENT_ENGINE=v1INTENT_USE_COT=falseINTENT_USE_LANGGRAPH=falseROBEING_ID=rb8001STATE_SERVICE_URL=http://localhost:9024
- 의미:
- 이 시점의 질의 처리는 LangGraph 워크플로우가 아니라
message_service.py직행 경로에서 수행됐다.
- 이 시점의 질의 처리는 LangGraph 워크플로우가 아니라
3-3. 실행 로그 사실 (2026-03-07 15:43-15:44 KST)
23 서버app.services.brain.decision_engine:의도 매칭 실패 - UNKNOWN으로 처리: '23 서버'app.services.message_service:[Question Expansion] '23 서버' → '23번 서버 상태를 확인해 드릴까요?'Router result:intent.type='unknown',skills=[{'skill': 'llm', 'action': 'understand'}]- 최종 응답:
이사님, 23번 서버에 대해 어떤 정보가 필요하신가요?
잘 돌아가는 지 체크해줘app.services.brain.decision_engine: 두 차례 모두UNKNOWNRouter result:intent.type='unknown',requires_clarification=True,action='understand'- 최종 응답:
현재 인프라가 잘 작동하고 있다는 점을 확인했습니다...
어떻게 돌아가는데? 아이피는 뭐야?app.services.brain.decision_engine: 두 차례 모두UNKNOWNRouter result:intent.type='unknown',requires_clarification=True,action='understand'- 최종 응답:
현재 인프라가 잘 작동하고 있다는 점을 확인했습니다. 혹시 특정 서버의 IP 주소를 확인하고 싶으신가요?
- 같은 로그 구간 어디에도 실제 서버 점검 실행, IP 조회, 서비스 상태 수집, 도구 호출 결과는 없다.
3-4. 질문 확장 코드 사실
rb8001/app/services/message_service.py:194-214INTENT_USE_LANGGRAPH=false일 때len(resolved_message.strip()) <= 10이면LLMService.expand_question()을 호출한다.
rb8001/app/services/llm/llm_service.py:54-130expand_question()는 최근 대화와 슬롯을 넣고 LLM에게완전한 질문으로 확장을 요청한다.- 예시는
"어디서?" → "회의는 어디서 하나요?","그거 어떻게 됐어?" → "이메일 발송은 어떻게 됐어요?"처럼 후속질문 중심이다.
- 실제 로그에서
23 서버는 이 경로를 통해23번 서버 상태를 확인해 드릴까요?로 바뀌었다. - 이 확장 결과는 사용자 요구를 실행 명령으로 구체화하지 않고, 로빙의 확인 질문 형태로 뒤집었다.
3-5. 의도 분류 코드 사실
rb8001/app/services/brain/decision_engine.py:29-74- 정의된 의도는 이메일, 뉴스, 슬랙, 캘린더, 웹검색, 문서분석, 스탯, 일반대화, 컨텍스트 후속질문 등이다.
rb8001/app/services/brain/decision_engine.py:116-214intent_patterns에서버 상태,인프라 점검,IP 조회,서비스 헬스체크에 해당하는 의도 패턴이 없다.
rb8001/app/services/brain/decision_engine.py:500-501- 매칭 실패 시
IntentType.UNKNOWN, 0.3을 반환한다.
- 매칭 실패 시
rb8001/app/services/brain/decision_engine.py:613-614IntentType.UNKNOWN의 스킬 시퀀스는{'skill': SkillType.LLM, 'action': 'understand'}하나다.
3-6. UNKNOWN 이후 LLM 일반채팅화 사실
rb8001/app/services/llm/internal_llm_service.py:35-43task_type == "understand"면chat으로 바꾼다.show_stats,provide_info도chat으로 바꾼다.
rb8001/app/router/router.py:176-180action in ("understand", "chat", None, "")이면 내부 LLMchat경로로 보낸다.
- 결과적으로
UNKNOWN은 "추가 사실 확인을 위한 운영 프로토콜"이 아니라 "일반 대화 생성"으로 흘러간다.
3-7. 시스템 프롬프트 사실
rb8001/app/services/llm/gemini_handler.py:604-646- 금지 규칙: 앵무새 응답 금지, 무의미한 질문 반복 금지, 모르는 것을 아는 척하지 말 것, 절대 거짓말 금지
- 직전 대화 맥락 최우선, 존댓말, 간결/실용 응답 규칙 포함
- 그러나 아래 규칙은 없다:
- 운영 점검 질의 시 가능한 범위의 사실 확인을 먼저 수행하라
- 확인하지 않은 상태를
확인했습니다라고 단정하지 말라 IP,상태,헬스체크같은 운영 질의는 고정 런북 순서로 답하라
3-8. 기존 내부 문서 사실
robeing/DOCS/journey/research/context_followup_question_solutions.md- 짧은 후속 질문 실패를 해결하기 위해 질문 확장을 도입해야 한다고 정리한다.
- 범위는
어디서?,언제?,그거 어떻게 됐어?같은 맥락 의존 후속질문이다.
- 현재 문제의
23 서버,잘 돌아가는 지 체크해줘,아이피는 뭐야?는 "후속질문 복원"과 일부 겹치지만, 본질은운영 점검 실행 요청이다. - 따라서 기존 문서는 현재 실패의 일부 배경은 설명하지만, 이 문제의 주 원인을 단독으로 설명하지는 못한다.
3-9. 커밋 이력 사실
9c89e81 feat: Phase 1 LLM 질문 확장 기능 구현 (TDD)message_service.py,llm_service.py에 질문 확장 로직이 추가됐다.
cf36baf feat: Phase 2 LLM 의도 분류 강화 구현 (TDD) - 맥락 포함 재분류- 메시지 처리 경로의 맥락 보강이 추가됐다.
3b96ff0 fix: Phase 1 중복 실행 방지 - LangGraph 워크플로우 활성화 시 message_service의 질문 확장 건너뛰기- 질문 확장 기능이 현재 아키텍처에서 여전히 핵심 경로임을 보여준다.
69e201c fix(llm): normalize 'show_stats'/'provide_info' to 'chat' in internal LLM task mapping to prevent validation errors- 정보성 액션을 일반
chat으로 흡수하는 방향이 강화됐다.
- 정보성 액션을 일반
- 확인된 커밋 이력 어디에도
인프라 점검,서버 상태,IP 조회,운영 런북 응답의도 추가는 없다.
3-10. 외부 1차 자료 사실
- OpenAI Model Spec (2025-09-12):
- 모델은 불확실성을 숨기지 말고, 필요할 때만 질문해야 하며, 가능한 경우 사용 가능한 맥락과 도구를 활용해 직접 도움을 주는 방향을 권장한다.
- OpenAI GPT-5.2 Prompting Guide:
- 모호성이 치명적이지 않으면 합리적 가정을 두고 진행하고, 불필요한 재질문을 줄이는 방향을 권장한다.
- 이 외부 원칙은 이번 문제의 직접 원인은 아니지만, 로빙의 현재 동작이 일반적인 에이전트 운영 원칙에도 어긋난다는 비교 기준이 된다.
3-11. 외부 에이전트 처리 흐름 및 OpenClaw 비교 사실
- 일반적인 에이전트 운영 원칙은 아래 순서에 가깝다.
- 직전 대화 맥락을 유지한다.
- 가능한 범위에서 먼저 관측/도구 실행을 시도한다.
- 확인된 사실만 보고한다.
- 정말 필요한 경우에만 짧게 명확화 질문을 한다.
- OpenClaw 공식 문서 요약 기준:
- Gateway가 세션·라우팅·이벤트의 단일 진실 원천이다.
exec,browser,web_search,sessions_*등 도구를 통해 실제 관측/실행이 가능하다.- 반복 무진전 루프는 tool-loop detection으로 제한한다.
- 비교 결과:
- OpenClaw 계열 흐름이라면 이 질의는 같은 세션의 운영 태스크로 유지하고, 가능한
status/IP관측을 먼저 수행하거나, 도구가 없으면 그 부재를 명시하는 쪽이 자연스럽다. - 이번 로빙 응답처럼 재질문과 가짜 안정 문구로 빈칸을 메우는 방식은 외부 에이전트 일반 흐름과도 어긋난다.
- OpenClaw 계열 흐름이라면 이 질의는 같은 세션의 운영 태스크로 유지하고, 가능한
4) 해석(Interpretation)
4-1. 1차 원인: 문제 유형을 잘못 분류했다
- 현재 구조는 짧은 표현을 보면 먼저
후속질문 복원문제로 다룬다. - 그러나
23 서버와 뒤이은 발화는 실제로는운영 점검 실행 요청이다. - 즉, 이 실패의 시작점은 사용자의 문제를
인프라 운영 태스크로 잡지 못하고짧은 애매한 질문으로 취급한 것이다.
4-2. 2차 원인: 질문 확장이 사용자 의도를 실행형으로 보강하지 못하고 확인질문형으로 변형했다
expand_question()의 설계 목적은 짧은 후속질문 복원이다.- 이 설계를
23 서버같은 운영 명령에 그대로 적용하면서, 사용자 명령이23번 서버 상태를 확인해 드릴까요?라는 로빙 발화형 문장으로 바뀌었다. - 이 변형은 의도 분류 정확도를 높이지 못했고, 오히려 실행 요청을 또 다른 확인 질문으로 약화시켰다.
4-3. 3차 원인: 인프라 점검 전용 의도와 실행 경로가 없다
DecisionEngine에는 웹검색, 이메일, 캘린더 등은 있어도server_status_check,infra_health_check,server_ip_lookup같은 의도가 없다.- 그래서
23 서버,잘 돌아가는 지 체크해줘,아이피는 뭐야?는 모두UNKNOWN으로 떨어진다. - 이 단계에서 이미 로빙은 서버 점검을 수행할 구조적 수단을 잃는다.
4-4. 4차 원인: UNKNOWN이 일반채팅으로 흘러가면서 무근거 응답을 생성했다
UNKNOWN -> understand -> chat경로는 실행보다 대화 생성에 최적화되어 있다.- 이 경로는 "도구를 써서 점검"이 아니라 "맥락상 그럴듯한 답을 생성"하는 쪽으로 작동한다.
- 그래서 실제 확인이 없는데도
확인했습니다같은 표현이 생성됐다.
4-5. 5차 원인: 시스템 프롬프트에 운영형 질의 프로토콜이 없다
- 현재 프롬프트는 거짓말 금지, 무의미한 재질문 금지는 말하지만, 운영 질의에서 무엇을 먼저 해야 하는지까지는 고정하지 않는다.
- 따라서
UNKNOWN -> chat상황에서 모델이 보수적으로 확인 질문을 하거나, 반대로 근거 없는 안정 문구를 생성할 여지가 남아 있다.
4-6. 이번 문제의 본질
- 이번 실패는 단일 모델 품질 문제가 아니다.
- 원인 사슬은
운영 점검 의도 부재 -> 짧은 질문 확장 오적용 -> UNKNOWN -> 일반 chat 폴백 -> 운영 응답 프로토콜 부재다. - 따라서 증상은 대화 품질 저하처럼 보이지만, 본질은 라우팅/의도 설계/프롬프트 가드레일의 구조적 결손이다.
4-7. 외부 기준과의 차이
- 외부 기준에서는
모르면 재질문이 기본이 아니라할 수 있는 관측을 먼저 하고, 그 뒤에도 부족할 때만 질문이 기본에 가깝다. - 이번 로빙은
UNKNOWN이후 관측 우선 흐름으로 가지 않고 일반 대화 생성으로 이동했다. - 그래서 이번 문제는 단순한 의도 분류 실패가 아니라, 에이전트 기본 동작 순서 자체가 뒤집힌 사례로 볼 수 있다.
5) 결론(Conclusion)
- 확정 원인:
23 서버계열 요청을 처리할 인프라 운영 의도와 실행 경로가 없다.- 짧은 질문 확장 기능이 이 요청을 후속질문 복원 문제로 잘못 취급했고, 실제로는 확인질문형 문장으로 왜곡했다.
UNKNOWN이 내부 LLM 일반채팅으로 정규화되면서, 점검 없는 상태 단정 응답이 생성됐다.- 시스템 프롬프트와 운영 규칙에 "운영 점검 질의는 사실 확인을 먼저 수행한다"는 강한 가드레일이 없다.
- 따라서 이 문제는
질문을 한 번 잘못 이해했다가 아니라, 현재 robeing 아키텍처가운영 점검 요청을 독립된 작업 타입으로 모델링하지 않은 데서 생긴 구조적 실패다.
6) 미확정 항목(Unresolved)
- 본 문서는 원인 확정 문서이며, 수정안 우선순위와 구현안 비교는 별도 계획 문서에서 다루는 것이 맞다.
- 다만 아래는 아직 이 문서에서 확정하지 않았다:
- 인프라 점검 의도를 FastPath 정규식으로 먼저 추가할지
- 별도 tool-calling 경로로 설계할지
- 프롬프트 가드레일만으로 일부 증상을 먼저 막을지
7) 비영향 범위
- 이번 실패는
23 서버자체 장애의 증거가 아니다. - 이번 실패는
INTENT_USE_LANGGRAPH=false환경에서 발생했으므로 LangGraph 재진입 문제의 재발이 아니다. - 이번 실패는 gateway/nginx/postgresql의 실제 상태와 무관하게,
rb8001의 질의 해석 구조 안에서 재현 가능한 문제다.