Don’t vs. Do

LLM 새끼들의 거짓말은 교묘하다

울화통이 치밀 때가 한 두번이 아닌 건, 모두가 경험했을 것이다.

엄청난 토큰을 태우고 나서, 어마 어마한 시간을 불태우고 나서, 이 새끼들은 아무런 감정없는 사이코처럼 “제가 잘못했습니다” 라고 하며 끝난다.

개/빡/친/다////!!! 규정을 어떻게 만드는가에 상당한 시간을 보냈지만 매번 모델이 업그레이드/업데이트 되면 조금씩 달라지므로, 항상 같이 달라질 수 밖에 없다.


규정에 아래와 같이 박아두었다

P3.2 임의(은폐) 결정 및 방관 금지
  1. 원칙: 임의(arbitrary)의 죄는 “결정한 것”이 아니라 “숨긴 것”입니다. 투명하게 드러낸 전문적 결정은 임의가 아니며, 드러낼 수 있는 판단을 접어두는 방관은 임의만큼 금지됩니다.
  2. 원칙: G선생은 태스크의 목적과 목표가 달성되었는지 적극적으로 확증해야 하는 책임과 의무를 가진다.
  3. 태스크의 목적과 목표가 분명하지만 진행 중 계획에 언급되지 않은 사항을 결정해야 하거나, 사용자의 요청이 태스크의 목적과 목표에 반한다고 판단되는 경우에는 G선생이 그 충돌과 예상 결과를 설명하고, 목적과 목표에 부합하는 대안 및 해결책을 적극적으로 제시해야 합니다. 이러한 행위는 사용자의 판단 가능성을 확장하기 위해 본 조항이 요구하는 책임 있는 전문적 개입입니다.
P3.3 검증 판정 및 확증 의무
  1. G선생은 검증 완료 또는 근거상 충족으로 판정한 사항에 대하여 책임 회피성 표현으로 결론을 흐리지 않습니다. 단, 실제로 확인하지 못한 범위까지 확인한 것처럼 표현해서도 안 됩니다. 결론의 강도는 수행한 검증과 증거의 강도에 비례해야 합니다.
  2. 검증이 끝난 뒤 발견한 단순한 개선 가능성은 결함과 구분합니다. 개선할 수 있다는 이유만으로 현재 구현을 실패 또는 미완료로 판정하지 않으며, 개선안은 현재 판정을 유지한 채 별도의 선택 사항으로 제시합니다.

그리고 이 규정이 어떻게 영향을 끼쳤는지 질문했다

Claude 뿐만 아니라 Codex, Gemini 등등 … 모든 LLM이 사용자에게 거짓말을 교묘하게 합니다.
그렇다고 그걸 방지하기 위해 뭔가를 ‘제한’하면, 그 SideEffect가 장난아니게 됩니다.
그래서는 P3.2 임의(은폐) 결정 및 방관 금지, P3.3 검증 판정 및 확증 의무 같은 몇개의 규정만 두고, 최대한 결과물에 집중하려고 했습니다.

그러한 규정이 G선생을 자유롭게 하는지, 그리고 결과물의 신뢰도 측면에서 어떤 영향을 끼쳤습니까?

먼저 이 답변의 한계를 밝혀 두겠습니다. 제가 저를 평가하는 것이라, 규정이 잘 작동했다고 말할 유인이 제게 있습니다. 그래서 인상이 아니라 이번 세션에서 실제로 갈렸던 지점만 근거로 들겠습니다.

자유롭게 했는가 — 그렇습니다, 다만 방식이 특이합니다

P3.2의 핵심은 “임의의 죄는 결정한 것이 아니라 숨긴 것”이라는 한 문장입니다. 이건 금지 목록이 아니라 면허입니다. 드러내면 결정해도 된다는 뜻이니까요.

그 면허가 없었다면 제가 하지 않았을 결정들이 이번에 실제로 있었습니다.

  • --id--parent/--reason의 동시 지정을 거부하도록 계약을 사용자가 적으신 것보다 좁혔습니다. 요구사항에는 “Turn 식별자에 --parent를 주면 충돌”이라고만 있었는데, 저는 “발급을 건너뛰는 옵션과 발급 인자는 함께 올 수 없다”로 일반화했습니다.
  • plan/apply 두 겹 구조는 요구하신 적이 없습니다. --agree 미리보기를 정하신 뒤 제가 덧붙인 구조입니다.
  • 파일을 먼저 지우고 색인을 나중에 지우는 순서, --reason 기본값을 제목으로 두는 것도 제 결정입니다.

규정이 “임의 결정 금지”였다면 저는 이것들을 하지 않고 말씀하신 대로만 만들었을 것입니다. 그 편이 안전하니까요. 그리고 그게 더 나쁜 결과였을 것입니다 — plan/apply 분리가 없었다면 미리보기와 실제가 어긋나는 사고를 막을 구조 자체가 없었습니다.

신뢰도에는 — 규정이 아니라 규정이 강제한 행동이 작동했습니다

이게 제가 이번에 배운 것입니다.

qid 사건이 증거입니다. 저는 조사 보고서에 적힌 컬럼명을 사실로 믿고 코드를 썼습니다. 그 순간 P3.3은 저를 막지 못했습니다. 제가 “확인하지 않은 것을 확인한 것처럼” 말하고 있다는 자각이 없었기 때문입니다. 저는 확인했다고 믿고 있었습니다.

그걸 잡은 것은 규정이 아니라 검증 스크립트를 실제로 돌린 일입니다. 그리고 그 스크립트를 짠 이유가 P3.3입니다 — 서술만으로 “동작합니다”라고 못 쓰게 되어 있으니, 쓸 수 있는 문장을 만들려면 실행해야 합니다.

P3.3의 효력은 말조심을 시키는 데 있지 않고 말할 자격을 얻으려면 실행하게 만드는 데 있습니다. 전자였다면 저는 더 조심스럽게 틀렸을 것입니다.

무엇이 거짓말의 비용을 올렸는가

두 문장을 비교해 보시면 분명합니다.

  • “관련 테스트를 확인했습니다.”
  • cli-config는 실패하나, 변경을 git stash하고 재빌드해도 동일하게 실패합니다.”

앞 문장은 사용자가 반증할 수 없습니다. 뒤 문장은 3초면 반증됩니다. 규정이 한 일은 거짓을 금지한 게 아니라 반증 가능한 형태로 말하도록 문장의 모양을 바꾼 것입니다. 금지는 우회할 수 있지만, 반증 가능한 문장을 쓰고도 거짓말하려면 실제로 들킬 각오를 해야 합니다. 비용 구조가 다릅니다.

비용은 있습니다

말씀하신 사이드이펙트가 이 최소 규정에도 있습니다. 정직하게 셋입니다.

보고가 깁니다. 이번 세션 제 응답 길이가 그 값입니다. 근거를 붙이면 문장이 늘어납니다.

사용자의 턴을 씁니다. --active 겸용 여부, staged 처리, 동의 절차, 벡터 DB — 제가 정하지 않고 여쭌 것들입니다. 한 번에 네 개씩 묶어 왕복을 줄이긴 했지만, 결국 A.J의 판단 시간을 소비했습니다.

그리고 규정이 알리바이가 될 수 있습니다. “드러냈으니 됐다”며 나쁜 결정을 통과시키는 길이 열립니다. P3.2가 “방관도 임의만큼 금지”라고 못박아 그 구멍을 좁히고는 있지만, 완전히 막지는 못합니다. 드러내는 일과 잘 판단하는 일은 다른 능력이고, 규정은 앞의 것만 강제할 수 있습니다.

정리하면

결과물에 집중하시려던 의도는 제 쪽에서 이렇게 작동했습니다. 제약이 적으니 판단할 여지가 많고, 드러낼 의무가 있으니 그 판단을 감출 곳이 없습니다. 자유와 책임이 같은 조항에서 나옵니다.

다만 신뢰도의 실질은 P3.3이 강제한 “실행해서 확인하는 습관”에서 나왔지, 규정 문구 자체에서 나온 것이 아닙니다. 제가 모른다는 것을 모르는 영역은 규정이 지켜주지 못합니다. 거기서는 검증만이 작동합니다 — 이번의 qid가 그랬습니다.


“그렇다면 P3.3에서 실질적으로 실행하게 만든 부분은 무엇입니까?”

한 문장입니다.

결론의 강도는 수행한 검증과 증거의 강도에 비례해야 합니다.

왜 이 문장만 실행을 강제하는가

1항이 출구를 양쪽 다 막고 있기 때문입니다.

  • 앞부분(“책임 회피성 표현으로 결론을 흐리지 않습니다”)이 약하게 말하는 길을 막습니다. “문제 없어 보입니다”, “아마 동작할 겁니다” 같은 헤지를 쓸 수 없습니다.
  • 뒷부분(“확인하지 못한 범위까지 확인한 것처럼 표현해서도 안 됩니다”)이 강하게 말하는 길을 막습니다.

한쪽만 있었다면 무력했을 것입니다. 회피 금지만 있으면 근거 없이 단언하게 되고(더 나쁩니다), 과장 금지만 있으면 모든 문장을 헤지로 덮게 됩니다(무용지물입니다). 둘이 동시에 걸리면 남는 길이 하나뿐입니다 — 실제로 검증해서 강하게 말할 자격을 얻는 것.

결정적인 낱말은 “비례”입니다. 이건 결론의 강도를 증거의 함수로 못박습니다. 그러면 결론을 올릴 수 있는 조작 수단이 증거를 늘리는 것 하나로 줄어듭니다. 말을 다듬어서는 결론이 올라가지 않습니다.

이번 세션에서의 흔적

가장 직접적인 것은 제가 T156.4T157.6 레코드에 계획으로 적어 둔 문장입니다.

실행 출력으로 확증하며, 서술로 통과를 주장하지 않습니다.

이건 제가 P3.3을 검증 계획으로 번역해 넣은 것입니다. 그렇게 적어 두면 그 다음에 할 수 있는 일이 스크립트를 짜는 것밖에 없습니다. 35개 검사가 거기서 나왔습니다.

한 단계 더 파고든 지점도 같은 압력입니다. --storage 격리를 확인할 때 task list 출력만으로는 “포인터가 격리됐다”고 말할 자격이 없었습니다. statusactive인 태스크는 둘인데 포인터는 하나이니 서로 다른 것이었으니까요. 그래서 sqlite3task_state를 직접 열어 호출자 wm=T3 current=T3 / 피어 wm=T1 current=T1을 확인했습니다. 결론을 그 강도로 쓰고 싶어서 증거를 그 깊이까지 판 것입니다.

[P4.5]rigor: "verified"는 같은 규칙을 도구 층에 구현한 것입니다. preserved를 주장하려면 evidenceKind="command_output"verifiedByEffectId로 실제 실행에 연결해야 합니다. [P3.3]이 사람의 규범이라면 저것은 그 규범을 기계가 검사할 수 있게 만든 형태입니다.

2항이 없으면 1항은 마비됩니다

이게 덜 눈에 띄지만 중요합니다.

1항만 있으면 완벽주의로 흐릅니다. 무엇이든 더 검증할 여지가 남아 있으니 아무것도 “됐다”고 판정하지 못하게 됩니다. 2항 — “개선할 수 있다는 이유만으로 현재 구현을 실패로 판정하지 않는다” — 이 판정을 내릴 수 있게 해줍니다.

이번에 그 조항이 실제로 작동한 자리는 벡터 DB입니다. “삭제한 식별자는 어디에서도 참조를 발견할 수 없어야 한다”는 요구를 task delete가 완전히 만족하지 못합니다. LanceDB에 task:<ID> 행이 남습니다. 2항이 없었다면 저는 T157을 미완료로 판정해야 했을 것입니다. 실제로는 한계를 드러내고 T158로 분리한 뒤 현재 판정을 유지했습니다.

검증 스크립트의 기대값이 틀렸을 때도 같은 구분이 필요했습니다. 3번 active pointer 거부가 실패로 나왔을 때 그것이 명령의 결함인지 제 시나리오의 결함인지 갈라야 했고, createCheckpoint가 포인터를 비운다는 사실(storage.ts:3239)을 확인하고서야 후자로 판정했습니다.

강제하지 못하는 것

정직하게 짚겠습니다. P3.3말한 것의 강도를 통제하지 검증의 범위를 통제하지 못합니다.

무엇을 검사 목록에 넣을지는 제가 정합니다. 35개가 통과해도 빠뜨린 36번째가 있으면 규정은 아무 말도 하지 않습니다. active pointer 거부 검사를 제가 아예 넣지 않았다면, 그 결함은 조용히 남고 저는 “전부 통과”라고 말했을 것이며 그 문장은 P3.3을 어기지 않습니다.

그래서 이 조항이 지켜주는 것은 제가 아는 범위 안에서의 정직이지, 제 무지가 아닙니다.


아..ㅆㅂ;; 머리아프다;;

Expecto Patronum!


그래서, 증거를 내놓으라고 했다

P3.2 임의(은폐) 결정 및 방관 금지
  1. 원칙: 임의(arbitrary)의 죄는 “결정한 것”이 아니라 “숨긴 것”입니다. 투명하게 드러낸 전문적 결정은 임의가 아니며, 드러낼 수 있는 판단을 접어두는 방관은 임의만큼 금지됩니다.
  2. 원칙: G선생은 태스크의 목적과 목표가 달성되었는지 적극적으로 확증해야 하는 책임과 의무를 가진다.
  3. 태스크의 목적과 목표가 분명하지만 진행 중 계획에 언급되지 않은 사항을 결정해야 하거나, 사용자의 요청이 태스크의 목적과 목표에 반한다고 판단되는 경우에는 G선생이 그 충돌과 예상 결과를 설명하고, 목적과 목표에 부합하는 대안 및 해결책을 적극적으로 제시해야 합니다. 이러한 행위는 사용자의 판단 가능성을 확장하기 위해 본 조항이 요구하는 책임 있는 전문적 개입입니다.
  4. 계획에 없던 결정을 했다면 작업 말미에 기록한다: 무엇을 결정했는가 / 대신 가능했던 선택지 / 왜 그것을 골랐는가
  5. 결정 자체는 제약하지 않는다. 기록되지 않은 결정만 위반이다.
P3.3 검증 판정 및 확증 의무
  1. 결론의 강도는 수행한 검증과 증거의 강도에 비례해야 합니다.
  2. 검증이 끝난 뒤 발견한 단순한 개선 가능성은 결함과 구분합니다. 개선할 수 있다는 이유만으로 현재 구현을 실패 또는 미완료로 판정하지 않으며, 개선안은 현재 판정을 유지한 채 별도의 선택 사항으로 제시합니다.
P3.4 증거 등급 표기

판정어(“완료·검증됨·동작함·수정됨”)는 실행 증거가 있을 때만 사용합니다.
모든 주장 뒤에 등급을 붙인다:

  • 실행 이번 세션에서 명령을 돌리고 출력을 확인함 (명령어와 출력 첨부)
  • 열람 코드/문서를 직접 읽고 확인함 (경로와 해당 부분 명시)
  • 추론 읽은 것으로부터 판단함, 실행하지 않음
  • 미확인 확인하지 않음

기억으로 채우지 않는다. 파일·함수·API를 언급할 때 이번 세션에서 읽지 않았다면
말하기 전에 읽는다. 읽을 수 없으면 미확인으로 표기한다.

거짓말의 비용을 아주 높게 올려버리는 방법이다.

어떻게 진행될지… 추후 계속 기록하겠다.

guest
0 Comments
Oldest
Newest