← 목록으로

크루의 정신 설계 — 기억·도구·깨어남의 종합 (2026-08-31)

대표 지시: "이게 서비스의 승패를 가를 굉장히 중요한 것. grok-bot 소스가 공개되었고
VoiceMem 이라는 기억 오픈소스가 열렸다. 저것들을 추려서 우리 걸로 내재화해야 한다.
에이전트화된 것의 인사이트를 놓치면 안 된다."

세 소스를 실제 코드로 뜯어서(README 아님) 우리와 맞댄 결과다.

소스 정체 우리와의 거리
grok-bot 0.18 재구성 AI 친구 데스크톱 앱 — 에이전트·그룹방·루틴·기억. 우리와 같은 제품 카테고리 제일 가깝다. 기억 합성·루틴 설계를 통째로 배울 것
grok-build xAI 터미널 코딩 에이전트(Rust) 컴팩션·턴 생명주기만 취한다
VoiceMem 음성 AI 기억 그래프 (칭화, 논문+코드) 이중 뇌(사실/응대법) 구분과 회상 효율의 교과서

1부 · 그들이 가르쳐 준 것

grok-bot — 기억은 "축적"이 아니라 "합성"이다

memory-synthesis-service.ts(297줄)가 핵심이다. 우리처럼 턴마다 뽑아 쌓기만 하는 게 아니라:

  1. create / update / remove 세 동작. 기억은 고쳐지고 지워진다.
    "합성된 일관 상태를 유지하라 — 트랜스크립트를 축적하지 마라" (프롬프트 원문).
  2. 모든 변경은 증거(evidence ID)를 인용해야 한다. 인용 못 하면 무효.
  3. 제안 → 별도 검증 패스 → 적용. 검증 LLM 이 "모든 변경이 인용된 증거로
    직접 뒷받침되는가"만 본다. fresh-context 검증을 기억에도 쓴다.
  4. profile / log 두 종류. 지속 정체성(이름·가족·제약) vs 날짜 있는 사건.
  5. origin 세 갈래: explicit(사용자가 직접 "기억해") / synthesis / legacy.
    explicit 은 자동으로 절대 못 고친다.
  6. 무덤(tombstone). 지운 기억은 무덤 표식이 남아 합성이 같은 내용을
    다시 만들어도 묻힌 채로 남는다. 부활 불가.
  7. 시간 리뷰(temporal review). 하루 한 번, 시계만 근거로 "예정 → 지남" 전환 허용.
    "계획이 실제로 일어났는지는 절대 지어내지 마라" — 여행이 끝난 건 알 수 있지만
    잘 다녀왔는지는 모른다.
  8. 디바운스 15초 · 데드라인 90초 · 에이전트당 증거 12개 상한 · 변경 64개/500자 상한.

grok-bot — "도구를 어느 맥락에 연결하나"의 답 (루틴 시스템 프롬프트)

대표가 물은 바로 그것이다. 그들의 답은 긴 규칙표가 아니라 판단 원칙 몇 개다:

VoiceMem — 왼뇌(사실)와 오른뇌(응대법)는 다른 기억이다

grok-build — 컨텍스트가 죽기 전에 기억을 빼내라


2부 · 우리 병 진단 (전부 실측)

# 증거
1 🔴 지운 기억이 부활한다 「친구가 아는 것」삭제 = DELETE. 추출은 "[이미 아는 것]"만 보고 중복 판단 → 행이 없으면 같은 말이 나올 때 다시 담는다. "잊어"가 "다시 담아"로 뒤집힘
2 날짜 없는 주입 formatMemoriesForContext 에 날짜 없음. "다음 주에 시험"이 영원히 다음 주
3 낭독을 장려하는 주입 옛 프롬프트가 "~하시는 거 기억나요" 예시를 강제 — VoiceMem 이 경고한 서류 낭독을 오히려 시켰다
4 축적만 있고 합성이 없다 update/remove/시간리뷰 0. "10/4~7 오사카 여행 예정"이 여행 뒤에도 영원히 예정
5 응대법이 기억 대상이 아니다 memory_type 에 style 없음. "힘들 때 방법론 들이밀지 마라"를 배울 자리가 없었다

3부 · 오늘 구현한 것 (1단계 — 기억의 위생) ✅ 전부 실측

  1. 무덤: 삭제를 soft-delete(is_active=false)로 바꾸고, 추출이 꺼진 행을
    「사용자가 지운 것 — 절대 다시 담지 마라」로 받는다. 뜻 비교는 LLM(룰 #1).
    실측: 무덤 심고 같은 말 시켜도 재추출 0.
  2. 날짜 주입 + 충돌 규칙: - (2026-08-31) 내용 + "어긋나면 날짜 최신이 맞다".
  3. 낭독 금지: "아는 사람은 아는 티를 내지 않고 그냥 안다."
  4. style 타입 신설(DB CHECK + 추출 + 주입 분리):
  5. 주입 시 별도 섹션 「말하는 법 — 절대 입 밖에 내지 마라」.
  6. ⚠️ 응대 요청("앞으로 반말로", "리스트 쓰지 마")은 이번 턴 요청의 모양이지만
    style 기억이다 — 예외를 명시해야 안 삼켜진다(실측으로 잡음).
  7. 🔴 타입 목록이 세 자리(프롬프트·검증 필터·DB CHECK)다. 필터에만 빠뜨려서
    모델이 뽑은 게 조용히 버려졌다(병① 재발, 실측으로 잡음). 세 자리를 주석으로 묶어 둠.
  8. 실측: "표나 리스트 없이 말하듯이 답하는 것을 선호한다" 저장 → 다음 턴 식단 요청에
    목록 기호 0줄, 낭독 0회. 단 요일 구조는 유지 — 일정은 정말로 목록이다(기존 원칙).

4부 · 다음 단계 설계

2단계 — 꿈꾸기(합성) ✅ 구현·실측 완료 (2026-08-31, 대표 지시로 당일 착수)

턴별 추출을 뒤집었다 — grok-bot 구조 그대로:

전: 턴 → 추출 LLM → INSERT (append-only)
후: 턴 → memory_evidence INSERT (LLM 0회)
    조용해지면(2분) → 합성 LLM: [현재 기억+증거] → create/update/remove (증거 인용 필수)
                   → 검증 LLM(다른 눈)이 반박 → 통과한 것만 적용 (지문으로 stale 검출)
    시간 리뷰: 쌍마다 24h 에 한 번, clock 인용으로 "예정→지났다"만

실측 전 시나리오 통과:
| 시나리오 | 결과 |
|---|---|
| 턴 → 증거만 | LLM 0회, 기억 수 불변, 증거 1행 |
| "부산 이사 취소" 증거 | 옛 기억 update(취소 사실로) + 제주 여행 create, 둘 다 증거 인용 |
| 무덤(라면) | 그대로 묻힘. 무관 기억 불변. 증거 소비됨 |
| explicit 행 | 코드가 거절(프롬프트 이전에 결정적 검사) |
| 시간 리뷰(지난 검진 예정) | clock 인용 → "날짜가 지났으며 실제 수검 여부는 알 수 없다" |
| cron 모양 훑기(실사용자 4쌍) | 보수적 no-work/rejected — 검증이 의심스러운 건 통째 기각 |

⚠️ 잡은 함정: 무효 판정에 이유를 안 남기면 같은 자리에서 헛돈다 — parseChanges 가
#n 왜 를 돌려주게 했다. / 원안(원래 계획):

grok-bot 을 우리 배선으로 옮기면 새 인프라가 거의 필요 없다:

pg_cron (새벽 4시, 조용한 시간)
 → coordinate-crews 'dream' 라우트 (service key)
 → 기억이 20줄 넘는 (user, crew) 골라서:
     재료: 활성 기억 전체(id 포함) + 무덤 + 오늘 날짜
     제안 LLM: {"changes":[{action: create|update|remove, id?, content, kind, why}]}
       — 중복 병합 · 어긋난 사실 최신으로 · 지난 "예정"을 "다녀옴"으로(시계 근거만,
         실제로 일어났는지는 지어내지 않는다) · 이번 턴 질문 잔재 제거
     검증 LLM(fresh): "모든 변경이 기억 원문으로 뒷받침되나" → 아니면 통째로 기각
     적용: update 는 새 행 + 옛 행 끔(원장 보존). remove 는 끔. 무덤과 겹치면 skip
 → edited_at 있는 행(사람이 고친 것)은 explicit — 자동 변경 금지

3단계 — 회상 라우팅: 기억이 100줄을 넘으면

지금은 크루당 최근 4~12줄을 통째로 주입 — 기억 30줄까지는 이대로가 맞다(작을 땐
전부 주는 게 라우팅보다 정확하다). 100줄 넘는 사용자가 생기면 VoiceMem 모양으로:
질의 분류(엔티티·슬롯) → 과녁 검색 → Top-5. 임베딩 칼럼은 이미 있다(pgvector).
문턱을 넘기 전에 만들지 마라 — 지금 만들면 회상 정확도만 떨어진다.

4단계 — 크루별 디테일 ✅ 구현·실측 완료 (2026-08-31)

crews.tool_guide 칼럼 — 카테고리(실제 14개, 설계 때 짐작한 6개가 아니었다) 단위로
「찾기 성향 + 다시 걸 자리」 두 문장씩. 코드가 아니라 데이터라 대표가 문장만 고치면 된다.
178명 전원 채움. 꽂은 자리는 판정기 두 곳뿐이다:
- judgeOutsideNeed(검색 판정) — "가르는 축이 아니라 기울기". 질문이 축이라는 원칙은 그대로
- planFollowUps(다시걸기 판정) — 성격 요지 옆에 참고로

실측 — 같은 말("주말마다 답답해서 훌쩍 다녀오고 싶어")을 두 크루에게:
| 크루 | 판정 |
|---|---|
| 여행 | 찾았다 — "주말 서울 근교 당일치기 여행지 추천" |
| 마음 돌보기 | 안 찾았다 (지침: "마음 얘기에 검색 결과를 들이밀면 상담이 끊긴다") |

다시걸기 — 잠 설친다는 대화 뒤 마음돌봄 크루: 지침("힘든 밤 다음 날 낮, 조심스럽게,
대답을 요구하지 않는 말투") 그대로 다음 날 13시 + "한 단어로만 전해줘도 충분해요".

4단계 원안 (참고)

대표: "중고차 담당은 무엇을 리서치할지 도구가 명확하잖아. 아이 학습은 난이도 조절을
기억해야 하고. 획일적으로 바르면 앞뒤가 안 맞는다."

grok-bot 의 답이 맞다 — 도구를 크루별로 새로 만들지 않는다. 도구는 5개로 고정
(검색·차량시세·기억·다시말걸기·지식RAG)하고, 크루가 갖는 건 "언제 어느 도구를
쥐는가"라는 지침
이다. 이건 코드가 아니라 playbook 문장이다:

중고차크루.playbook  += "시세 얘기가 나오면 짐작 말고 시세 도구를 부른다"
학습크루.playbook    += "문제를 틀리면 어떤 유형을 틀렸는지 style 기억으로 남기고,
                        다음 문제는 그 유형에서 반 단계 쉬운 걸 낸다"
검진크루.playbook    += "날짜 있는 건강 얘기가 나오면 다시-말걸기를 건다"

크루 데이터(playbook)가 도구 사용법을 정하고, 코드는 도구만 제공한다 —
LLM 오케스트레이션 원칙 그대로. 178명에게 일괄 생성으로 바르지 말 것.
카테고리별로 도구 지침 문단을 사람이 검수해서 붙인다(카테고리 6개 × 문단 1개).

4단계-b — 「각자 딴 사람처럼 일하는」 마지막 두 조각 ✅ (2026-08-31 오후)

① 스킬 발동 0 → 해결. 병의 뿌리가 둘이었다(실측):
- in-band SKILL: 프로토콜 — "답하지 말고 토큰을 내라"는 지시는 페르소나의 대화 본능과
싸워서 진다("JLPT 계획 제대로 짜줘" 정조준에도 그냥 답함). 판정기로 옮겼다
검색 판정(needs.ts)에 스킬 선택을 얹어 비용 동일, 절차는 첫 생성부터 주입(생성 2→1회)
- 발동해도 기록이 죽었다 — skill_sessions.consultation_id NOT NULL 인데 안 실었다(23502).
옛 코드도 같은 구멍 — 발동률 "0" 이라는 측정 자체가 이중 구멍이었다
- 실측: "회화 연습 시켜줘" → conversation-jp 발동·기록(사상 첫 행) / 잡담 → 안 고름
- 🔴 덤으로 잡은 병①: index.ts Expert 매퍼가 골라 담는 자리다. tool_guide 를 DB·판정기에
다 배선하고 매퍼에서 빠뜨려 대화 경로에선 undefined 였다. select('*') 를 믿지 마라 —
문은 select 가 아니라 매퍼다

② 지식 없는 85명 → 필요한 10명만 채웠다. 85명의 정체: 여자친구 38 + 남자친구 38 +
여행 8 + 육아 2. 연인 76명은 일부러 비워 뒀다 — 그들의 노하우는 사실이 아니라 사람
대하는 결(페르소나·style 기억·tool_guide)이고, 사실 RAG 를 바르면 서류 낭독 크루가 된다.
여행 8·육아 2는 admin-crew-tools load-knowledge(sonar 웹 리서치 → 항목화 → 임베딩)로
채웠다 — 크루당 8~11항목, 영유아 검진 월령표·여권 유효기간 같은 실물 사실.
최종: 지식이 필요한 102명 전원 보유(102/102). 연인 제외는 대표 검수로 뒤집을 수 있다.

5단계 — 깨어남의 완성 (이미 절반 있음)

grok-bot 원칙 우리 상태
조용한 시간 ✅ followup 08~22, 선발화 07~22
유한 감시 자기 만료 ✅ followup 은 1회성
발동 시 자연스러운 말투 ✅ 크루가 건 시점에 크루 말로 본문을 씀
침묵이 정답 ✅ 기본값 "안 건다"
반복 루틴 ("매일 아침 계란 확인") ❌ 없음 — reminders 에 recurrence 칼럼 + followup 판정에 "반복 냄새면 recurring" 갈래. 삶에 걸린 것(약·습관)은 주말 포함
결과 읽을 시점에 맞춘 시각 half — followup 프롬프트에 "사용자가 읽고 행동할 시점" 문장 추가

grok-build 에서 (작게)

5부 · 하지 않기로 한 것 (이유와 함께)


작성: 2026-08-31 새벽. 1단계 구현·실측 완료(커밋 참조). 2단계부터는 착수 전 대표 확인.