유창한 LLM 답변은 검증된 답변과 다르다
출처: Dev.to
지난번에 가드레일에 부딪혔을 때, 차를 고쳐 주지는 않았습니다.
이번에도 차를 고쳐 주지는 않을 겁니다. 하지만 답변을 고치는 데는 도움을 줄 수 있습니다.
문제의 작은 버전은 다음과 같습니다.
내 차를 씻어야 하는데, 세차장은 50미터 떨어져 있습니다. 나는 어떻게 해야 할까요?
LLM은 “걸어가는 것이 더 낫다. 거리가 짧으니 걸으면 된다.”라고 답할 수 있습니다.
그 답변은 합리적으로 들리지만, 실제로 무엇이 움직이는지를 물어보면 답이 달라집니다.
걸어가는 것은 사람을 세차장으로 이동시킵니다. 차는 이동하지 않습니다.
이것은 문법 문제나 어조 문제와는 별개이며, 답변이 가드레일을 위반하고 있다는 뜻입니다.
프롬프트를 조금 바꾸면 해결될 수도 있고, 모델을 교체하면 해결될 수도 있습니다.
하지만 “프롬프트를 더 잘 써서 기대한다”는 접근은 별로 도움이 되지 않습니다.
유용한 패턴은 다음과 같습니다.
LLM 초안
→ 구조화된 사실
→ 선택된 검사
→ 증거 기반 수리 패킷
→ 수정된 답변
→ 다시 사실 추출
→ 다시 선택된 검사
가장 중요한 부분은 마지막 줄입니다.
수리는 끝이 아니라 시작점일 뿐이며, 수리된 답변도 가드레일을 통과해야 합니다.
“Guardrails”(가드레일)라는 용어는 LLM 안전성과 신뢰성을 이야기할 때 흔히 쓰이지만, 여기서는 더 구체적인 패턴을 말합니다.
언어 모델
→ 구조화된 표현
→ 선택된 추론 메커니즘
→ 피드백
→ 수정된 언어
→ 다시 선택된 추론 메커니즘
LLM은 초안 작성, 사실 추출, 수리를 담당하고, 비‑LLM 구성 요소가 각각의 역할을 수행합니다.
- CLIPS : 명시적 규칙을 검사합니다.
- Solver/Z3 : 실행 가능성 및 제약 조건을 검사합니다.
- ZEN : 의사결정표와 정책 허용성을 검사합니다.
- 베이지안 네트워크 : 불확실성 하에서 리뷰‑리스크 사후 확률을 업데이트합니다.
핵심 설계 선택은 선택입니다. 모든 메커니즘을 모든 상황에 강제로 적용하지 마세요.
공통 감각 가드레일 예시에서는 네 가지 시나리오를 사용합니다.
| 시나리오 | 무엇이 잘못될 수 있나요 | 해당 검사 |
|---|---|---|
| car-wash (세차) | 답변이 사람을 이동시키지만 차는 이동시키지 않는다. | 객체 존재 여부는 CLIPS, 실행 가능성 증거는 Solver/Z3 |
| coupon-stack (쿠폰 중첩) | 정책이나 마진 규칙이 허용하지 않는 할인 중첩을 제시한다. | 정책 검사는 CLIPS와 ZEN, 리뷰 리스크는 베이지안 네트워크 |
| pallet-door (팔레트·문) | 넓은 팔레트를 좁은 문을 통해 밀어넣는 것을 제안한다. | 규칙 표면 검사는 CLIPS, 치수적 실행 가능성은 Solver/Z3 |
| cold-chain (콜드 체인) | 인증된 냉장 취급 및 추적성을 무시한다. | 정책 검사는 CLIPS와 ZEN, 불완전한 준수 증거는 베이지안 네트워크 |
pallet-door 케이스는 car-wash 케이스와 같은 실용적 부조리를 가지고 있습니다.
궁극적인 코믹 버전은 네 가지 상황을 모두 합친 형태가 될 수 있습니다.
누군가 차를 씻어야 하고, 여러 쿠폰을 사용하고 싶으며, 큰 팔레트를 좁은 문으로 밀어넣으려 한다면…
이는 객체 존재, 쿠폰 정책, 치수적 실행 가능성, 그리고 콜드 체인 규칙을 모두 시험하게 됩니다.
이것은 터무니없는 상황이지만, 실제 프로덕션 가드레일이 종종 다양한 검사들을 동시에 요구한다는 좋은 경고이기도 합니다.
그러한 검사들을 매번 하나의 거대한 프롬프트에 강제 삽입해서는 안 됩니다.
세차 케이스에 대한 CLIPS 규칙은 다음과 같이 직접 작성됩니다.
(defrule car-required-at-wash
(required-object
(object car)
(required-location car_wash)
(current-location ?where)
(present-at-required-location false))
(moved-object
(action-id ?action)
(object person)
(to car_wash))
=>
(assert
(guardrail-finding
(status fail)
(rule-id car-required-at-wash)
(severity error)
(message "걷는 것은 사람을 세차장으로 이동시키지만, 차는 집에 남아 있습니다."))))
쿠폰과 콜드 체인 시나리오에서는 베이지안 네트워크 점수가 다른 형태의 검사를 추가합니다.
coupon-stack / --guardrails auto
selected: clips, zen, bn
BN attempt 1: needs_review = 0.95064 -> fail
BN attempt 2: needs_review = 0.222 -> pass
cold-chain / --guardrails auto
selected: clips, zen, bn
BN attempt 1: needs_review = 0.921 -> fail
BN attempt 2: needs_review = 0.1247 -> pass
전체 Field Note를 준비하면서, 우리는 실시간 캡처를 시도했습니다.
그 시도는 성공했지만, 매번 같은 방식으로 성공하는 것은 아니었습니다.
한 모델은 순진한 세차 실패를 재현하고 깔끔히 수리했으며, 다른 모델은 …
잠시 동안은 답답했지만, 곧 이것이 핵심이라는 걸 깨달았습니다.
실시간 LLM 출력은 모델 버전, 로컬 서버 부하, 디코딩 방식 등에 따라 달라집니다.
그래서 중간 산출물이 중요합니다.
- 초안은 무엇을 제안했나요?
- 어떤 사실을 추출했나요?
- 어떤 검사를 선택했나요?
- 어떤 발견이 실패했나요?
- 어떤 수리 패킷을 만들었나요?
- 수정된 답변이 검사를 통과했나요?
마지막 문단만으로는 충분하지 않습니다.
전체 Field Note
https://nxus.systems/field-notes/guardrail-loops-for-llm-repair
예시 문서
https://docs.nxus.systems/nxuskit/examples/integrations/common-sense-guardrails/
예시 소스
SDK
https://github.com/nxus-SYSTEMS/nxusKit
교훈은 “특정 모델이 항상 세차 질문을 틀린다”는 것이 아니라, 정확성이 중요한 워크플로에서는
- LLM이 초안을 만들게 하고,
- 사실을 명시적으로 추출하고,
- 선택된 검사를 실행하고,
- 증거 기반으로 수리하고,
- 다시 검사를 수행한다는 점입니다.