알림이 안 보인다
이날은 폴백 알림 한 줄을 고친 날이다.
근데 그 한 줄을 고치려고 9일이 걸렸다.
알림을 사용자한테 보여주면서 동시에 LLM한테는 안 보이게 만드는 게 이렇게 어려울 줄 몰랐다.
폴백 플러그인은 모델이 실패하면 다른 모델로 전환한다.
이때 사용자한테 “모델을 바꿨다”고 알려줘야 한다.
안 그러면 갑자기 다른 모델이 답하는데 왜 그런지 모르니까. 근데 알림이 안 보였다.
코드는 들어있는데, 화면에 안 나온다.
원인을 추적해보니, 알림을 만드는 함수가 synthetic: true를 반환하고 있었다.
synthetic은 “가짜”라는 뜻이다.
이 플래그가 true면, 시스템이 그 부분을 사용자한테 안 보여준다.
왜 이렇게 했는가. LLM 컨텍스트에 알림이 들어가는 걸 막으려고였다.
알림 텍스트가 LLM한테 전달되면 토큰을 낭비하고 맥락을 오염시킨다.
그래서 알림을 LLM한테 안 보내려고 synthetic을 쓴 거다.
근데 synthetic은 사용자한테도 안 보인다.
LLM한테만 안 보내는 게 아니라, 사용자한테도 숨기는 거다.
이게 문제였다.
synthetic vs ignored
해결은 synthetic을 ignored로 바꾸는 거였다.
한 줄이다.
둘의 차이가 핵심이다.
synthetic은 사용자한테 숨기고 LLM한테도 안 보낸다.
ignored는 사용자한테 보여주되 회색으로 표시하고 LLM한테는 안 보낸다.
그러니까 ignored가 내가 원하던 거다.
사용자한테는 보여주되, LLM한테는 안 보낸다.
두 가지 목표를 동시에 달성하는 플래그였다.
9일간의 우회
이 한 줄을 고치기까지 9일이 걸렸다.
과정이 복잡했다.
처음에는 ignored 플래그를 썼다.
근데 호스트의 Go 코어가 ignored 플래그를 무시했다.
그러니까 ignored를 설정해도 LLM한테 알림이 전달됐다.
토큰이 낭비됐다.
그래서 전략을 바꿨다.
TUI 텍스트를 아예 빼고 토스트 알림만 썼다.
토스트는 LLM 컨텍스트에 안 들어가니까 토큰 낭비가 없다.
근데 토스트는 잠깐 뜨고 사라진다.
사용자가 놓치면 알림을 못 본다.
며칠 뒤에 noReply라는 옵션을 발견했다.
프롬프트를 보내되 LLM 호출은 안 하는 옵션이다.
이걸 쓰면 TUI에 텍스트를 보여주면서 LLM한테는 안 보낼 수 있다.
이제 TUI 알림을 다시 쓸 수 있게 됐다.
그런데 이번에는 synthetic 플래그 때문에 알림이 안 보였다.
noReply로 LLM 전달은 막았는데, synthetic으로 사용자 표시도 막힌 거다.
그래서 synthetic을 ignored로 바꿨다.
상충하는 두 가지 목표
이 문제가 어려운 이유는 두 가지 목표가 상충하기 때문이다.
첫째, 사용자한테 알림을 보여줘야 한다.
모델이 바뀌었다는 걸 알아야 한다.
둘째, 알림이 LLM한테 전달되면 안 된다.
토큰 낭비랑 맥락 오염을 막아야 한다.
이 두 가지를 동시에 만족하는 플래그가 필요한데, 처음에는 그런 게 없었다.
synthetic은 둘 다
숨긴다.
ignored는 호스트가 무시한다.
noReply는 새로 발견한 건데, synthetic이 또 문제를 만들었다.
결국 noReply랑 ignored를 같이 쓰면 두 목표가 동시에 달성된다.
근데 이걸 알아내는 데 9일이 걸렸다.
마무리
이 이야기의 교훈은 “플래그 하나의 의미를 정확히 알아야 한다”는 거다.
synthetic은 “LLM한테 안 보낸다”로 생각했다.
근데 실제로는 “사용자한테도 안 보인다”였다.
의미를 잘못 알고 쓰니까 알림이 안 보인 거다.
플래그의 문서를 읽고 소스 코드를 확인하고 실제로 어떻게 동작하는지 테스트해야 한다.
이름만 보고 추측하면 이런 일이 생긴다.
그리고 상충하는 목표가 있을 때, 둘 다
만족하는 하나의 해법을 찾아야 한다.
하나를 포기하면 다른 문제가 생긴다.
“사용자한테 안 보여도 되지” 하면 알림 기능이 의미가 없어진다.
“LLM한테 전달되도 감수하자” 하면 토큰이 낭비된다.
둘 다
포기하지 않고 해법을 찾는 게 중요했다.