Indie Hackers

My AI agent could "see" the fact — it just never wrote it down

AI 에이전트가 사실을 읽고도 기록하지 않은 이유

회의록을 전략 보고서로 바꾸는 멀티 에이전트 파이프라인에서, 전체 점수는 양호했지만 경쟁사 관련 사실이 반복해서 누락됐습니다. 작성자는 중간 단계의 분류 기준에서 누락 원인을 찾고 수정했으며, 항목별 평가와 작은 표본의 한계도 함께 짚습니다.

AI 요약

AnchorStrategy는 회의록을 읽고 여러 AI 에이전트가 경쟁사, 고객, 다른 업종의 사례를 조사한 뒤 전략 보고서를 작성하는 파이프라인입니다. 작성자는 일본어 사례로 진행하던 검증에 언어 특유의 문제가 있는지 확인하려고 영어 사례를 새로 만들었습니다. 저작권 문제를 피하려고 NIST의 Baldrige National Quality Award 자료에서 사실만 추려 새로운 사례 서술을 작성했습니다. 가상의 기업 Company A는 텍사스의 금속 명판·라벨 제조사로, 1940년대부터 가족이 운영해 온 업체입니다.

평가는 생성 모델과 채점 모델을 나눠 Gemini가 보고서를 만들고 Claude가 채점하도록 구성했습니다. 채점기는 작성자의 프롬프트나 의도를 보지 않고 질문, 공식 채점 근거, 필수 요소 체크리스트, 생성된 보고서만 확인합니다. 평가 기준은 전략의 품질이 아니라 보고서가 요구된 사실을 다뤘는지 여부입니다.

평균 점수에 가려진 누락

같은 사례와 설정으로 다섯 번 실행한 결과 평균은 78점, 범위는 73.5~86.5점이었습니다. 일본어 사례에서 보던 변동과 비슷해 겉으로는 문제가 드러나지 않았습니다. 하지만 질문별로 점수를 나누자 40점짜리 3C 분석 문항의 세부 항목 중 하나가 보였습니다. 경쟁사 관련 사실을 언급해야 하는 항목은 다섯 번 중 네 번 0점이었습니다. 나머지 항목에서 점수를 얻어 전체 합계는 괜찮아 보였지만, 특정 요구사항은 대부분의 실행에서 실패했습니다.

사례에는 텍사스에 직접 경쟁사가 없고 가장 가까운 경쟁사는 다른 주에 있다는 내용, 부채가 거의 없고 자체 재고와 설비를 보유한다는 내용, 경쟁사 7곳을 매년 미스터리 쇼퍼 방식으로 평가한다는 내용이 들어 있었습니다. 그런데 첫 실행 결과는 CEO가 언급한 스프레드시트 문제만 분석했습니다. 다른 실행에서는 입력 자료에 개별 경쟁사 정보가 없다고 적기도 했습니다.

누락은 첫 요약 단계에서 시작됐습니다

작성자는 파이프라인의 중간 결과를 노드별로 확인했습니다. 경쟁사 분석 노드에 도달하기도 전에 첫 번째 회의록 요약 노드인 minutes_ingest에서 해당 정보가 빠져 있었습니다. 요약 노드는 숫자와 고유명사를 추출하도록 설계됐지만, 경쟁사를 특정하지 않고 자사의 상대적 강점을 설명하는 사실은 어느 기준에도 들어맞지 않았습니다.

다음 경쟁사 분석 노드에도 분류 기준의 빈틈이 있었습니다. 입력을 ‘업계 평균’과 ‘이름이 명시된 경쟁사 데이터’로 나눴는데, 경쟁사를 밝히지 않은 상대적 경쟁 우위는 두 범주 어디에도 속하지 않았습니다. 정보는 인식된 뒤 사라진 게 아니라, 기록할 대상으로 분류되지 않아 추출 단계부터 누락됐습니다.

작성자는 요약 단계의 추출 범위를 숫자와 고유명사에서 인과 관계와 제삼자 사업 구조에 관한 맥락까지 넓혔습니다. 경쟁사 분석 노드에는 ‘특정 경쟁사 이름 없이 제시된 상대적 경쟁 위치’ 범주를 추가하고, 입력에 명시된 경우에만 적용하도록 제한했습니다. 수정 과정에서 최종 보고서 포맷 노드가 범주 목록을 코드에 고정해 둔 사실도 발견했습니다. 상류 노드에 새 범주를 추가해도 출력에 반영되지 않아, 이 목록도 함께 수정했습니다.

수정 결과와 남은 문제

같은 사례를 세 번 다시 실행하자 경쟁사 분석은 세 번 모두 만점을 받았고, 전체 평균은 89.3점으로 올랐습니다. “텍사스에는 화학 에칭 사업자가 없고 가장 가까운 직접 경쟁사는 이웃 주에 있다”는 사실도 매번 보고서에 포함됐습니다. 다만 경쟁사 7곳을 매년 평가한다는 사실은 수정 뒤에도 세 번 모두 누락됐습니다. 해당 질문은 세 가지 사실 중 하나만 요구해 점수에는 영향을 주지 않았지만, 기존 추출 범주로 설명되지 않는 누락 사례가 남았습니다.

작성자는 범주를 발견할 때마다 하나씩 덧붙이는 방식이 사후 대응에 그친다고 봅니다. 이번에는 세 범주에서 네 범주로 늘렸지만, 아직 분류하지 못한 사실 유형이 더 있을 가능성을 인정했습니다. 인용 충실도를 확인하는 가드레일도 영어 사례 다섯 번 중 세 번 작동했습니다. 일본어 사례보다 높은 비율이지만, 영어 사례를 작성자가 직접 썼고 표본도 작아 언어 문제인지 우연인지 판단하기 어렵다고 밝혔습니다.

점수 하나로 평가하지 않기

글의 주된 교훈은 총점이 개별 항목의 반복적인 실패를 숨길 수 있다는 점입니다. 여러 평가 요소를 합산하면 한 항목이 거의 매번 실패해도 나머지 점수에 묻힙니다. 작성자는 문항별 점수를 확인한 뒤에야 문제를 찾았으며, 앞으로는 필수 기준별 통과 여부를 따로 보려 합니다. 실제 실행 경로에서도 사실이 어느 노드에서 빠졌는지 추적해야 했습니다. 경쟁사 분석 노드만 살폈다면, 그보다 앞선 요약 단계에서 정보가 사라졌다는 사실을 발견하기 어려웠습니다.

댓글에서는 필수 기준에 최소 통과 점수를 두고, 각 중간 단계에서 사실이 사라지면 즉시 실패하도록 검사하자는 제안이 나왔습니다. 사실의 포함 여부와 정확한 표현, 최종 보고서의 유용성을 서로 다른 지표로 관리하자는 의견도 있었습니다. 작성자는 이 사례가 같은 입력을 고친 뒤 다시 실행한 결과라서 새 사례에도 일반화된다고 보기 어렵다고 답했습니다. 다른 업종의 사례와 별도의 테스트 세트로 검증해야 하며, 수정 전후 결과를 가리고 비교하는 절차도 필요하다는 지적을 받아들였습니다.

Indie Hackers 반응

  • @Agiloop — 종합 점수는 중요한 실패 하나를 가릴 수 있습니다. 전체 점수와 함께 중요한 기준에는 최소 통과선을 두는 편이 좋습니다. 점수는 요약일 뿐이고, 결정은 근거와 개별 결과를 봐야 합니다.
    • @tosh_vance — 저도 전체 점수만 보지 않고 기준별 최소 통과선을 두는 방향으로 이미 움직이고 있습니다. 이번 사례에서는 요약 점수가 실제로 “괜찮아 보이는” 결과를 냈습니다. 총점이 아니라 문항별로 쪼개 보고서야 거의 매번 실패하는 기준을 찾았습니다. Agiloop은 어떤 기준에 통과선을 둘지 어떻게 정하나요? 평가 유형마다 고정하나요, 아니면 프로젝트마다 조정하나요?
  • @rcaiptv — 사실을 알아차리는 것과 실제로 저장하는 것 사이의 간극은 미묘한 실패 유형이네요. 메모리나 컨텍스트 문제인지, 에이전트가 무엇을 기록할지 결정하는 방식의 문제인지 추적했나요?
    • @tosh_vance — 메모리나 컨텍스트 문제는 아닙니다. 잘리거나 컨텍스트 창에서 빠진 게 아니었습니다. 애초에 무엇을 기록할 가치가 있다고 판단하는지의 문제였습니다. 회의록 요약 단계의 추출 기준은 숫자와 고유명사에 맞춰져 있었고, 경쟁사를 특정하지 않고 제시한 사실은 둘 중 어디에도 들어맞지 않았습니다. 기록 대상으로 포착된 뒤 누락된 게 아니라, 처음부터 기록 대상으로 표시되지 않았습니다. 다음 단계에서도 같은 일이 반복됐습니다. 기억력 문제라기보다 분류 체계의 문제였고, 두 번 연속 발생했습니다.
  • @lotus_builds — 평균 점수가 체계적인 실패를 숨긴다는 메타 교훈이 가장 유용합니다. 매번 분류 범위를 넓히기보다, 후보가 될 만한 사실을 우선 구조화되지 않은 목록에 전부 모은 뒤 분류하면 어떨까요? ‘미분류’ 항목을 두고 검토하면 조용히 버려지는 대신 눈에 띕니다. 표본이 5회에서 3회로 줄어든 만큼 주장을 뒷받침하기에도 부족합니다. 매번 평균과 함께 범위도 공개하세요.
    • @tosh_vance — 사실을 먼저 모으고 미분류 항목을 두는 방식이 지금보다 낫습니다. 지금은 빠진 유형을 발견할 때마다 기준을 덧붙입니다. 그래서 아직 기준에 들어맞지 않는 정보는 조용히 사라지고, 문제가 생긴 뒤 중간 상태를 직접 따라가야 알아차립니다. 미분류 대기열을 두면 ‘아마 다섯 번째 유형이 있을 것’이라는 문제를 패치로 덮지 않고 드러낼 수 있습니다. 영어 사례를 제가 직접 썼다는 교란 요인도 지적이 정확합니다. 수정 전후를 가린 채 평가했는지 확인해야 합니다. 표본이 세 번뿐인데 ‘고쳤다’고 단정한 것도 성급했습니다.
  • @mehdizare — 점수와 커버리지 계약을 구분하면 좋겠습니다. 사례마다 반드시 살아남아야 하는 사실을 출처 위치와 함께 정해 두고, 최종 보고서 전에 하나라도 사라지면 실행을 실패 처리하는 방식입니다. 그러면 사실이 다음 단계로 전달되지 않은 문제를 프롬프트 패치가 아니라 테스트 가능한 인계 실패로 다룰 수 있습니다. 계약은 프롬프트와 별도로 버전 관리하면 좋겠습니다.
  • @brianainews — 종합 점수는 반복되는 실패를 숨길 수 있습니다. 각 노드에 작은 불변 조건을 두고 필수 사실이 사라지면 크게 실패하게 만들면 좋겠습니다. 최종 보고서 포맷에 목록이 하드코딩돼 있는 문제도 정말 흔합니다.
    • @tosh_vance — “크게 실패하게 만들기”가 중요합니다. 지금은 사실이 사라져도 조용히 실패하고, 몇 문항 뒤에 평균 점수만 낮춥니다. 마지막에 한 번 확인하는 대신 각 노드에 불변 조건을 두는 게 맞습니다. 포맷 노드의 하드코딩 문제도 저만 겪는 실수가 아니라 흔한 형태라는 말이 위안이 됩니다.
  • @LFH_austin — 중간 변환을 각각 계약처럼 다루는 방법이 좋습니다. 필수 사실을 목록으로 만들고 모든 노드에서 유지되는지 확인하며, 종단 간 테스트 사례도 하나 둡니다. 최종 유용성과 별도로 커버리지와 충실도를 채점하면 프롬프트를 임시로 고치는 대신 회귀를 찾기 쉽습니다.
    • @tosh_vance — 노드별 계약은 제가 의심이 생긴 뒤 손으로 하던 추적을 더 정확하게 만든 방식입니다. minutes_ingest에서 빠진 사실을 자동으로 알리는 장치가 없어 한참 지나서야 수동으로 찾았습니다. 커버리지, 충실도, 최종 유용성을 나눠 점수화하자는 제안도 필요합니다. 필수 사실이 남았는지와 사실을 정확하게 표현했는지를 지금까지 거의 같은 신호로 봤습니다. 미스터리 쇼퍼 사실은 커버리지 실패지만, 사실이 남아도 다음 단계에서 미묘하게 왜곡되는 건 다른 실패입니다.
  • @aryan_sinh — 수정 뒤 점수는 좋아 보이지만, 이미 발견한 실패 유형에 맞춘 개선인지 새로운 사례에도 일반화되는지 어떻게 구분하나요?
    • @tosh_vance — 가장 자신 없는 부분입니다. 수정 뒤 세 번의 실행은 버그를 찾을 때 쓴 같은 사례로 진행했습니다. 이 결과만으로 한 사례의 패턴에 과적합하지 않았다고 할 수 없습니다. 업종과 경쟁 구조가 다른 사례에서도 누락률이 유지되는지 확인해야 합니다. 개별 실행을 살피는 대신 별도의 홀드아웃 테스트 세트도 만들 계획입니다.

원문: Indie Hackers / 번역·요약: Trawling