2026.10.23 금
TenseMem: 에이전트의 기억을 규칙으로 갱신하기
오늘의 픽: TenseMem
TenseMem 은 AI 에이전트의 기억을 SQLite 파일에 저장하고 항목마다 현재 값을 하나만 유지하는 프로덕트다.
오늘의 픽으로 선정한 이유는 어느 값이 현재 값인지를 모델 대신 규칙이 정하기 때문이다.
- 출처
- Show HN
- 만든 방식
- Python, SQLite, Cursor
무엇이 문제인가
AI 에이전트가 기억하는 사용자 정보는 시간이 지나면 바뀐다. 사용자가 Delhi 에 살다가 Bangalore 로 이사하면, 에이전트는 이전 기억과 새 기억 가운데 지금 유효한 쪽을 사용해야 한다. Anthropic 의 Claude 도움말에 따르면 Claude 의 지난 대화 검색은 RAG질문과 관련된 문서를 먼저 검색해 LLM 의 입력에 함께 넣고 답을 생성하는 방식. 검색 증강 생성이라고도 한다. 로 관련 대화를 찾아 온다. 메모리는 Claude 가 대화 중에 주제별로 스스로 저장한다. TenseMem 의 제작자는 README 에서 유사도 검색문장을 숫자 벡터로 바꾼 뒤, 질문의 벡터와 가까운 기록을 찾아 반환하는 검색. 뜻이 비슷하면 오래된 기록도 함께 가져온다.이 "I live in Delhi" 와 "I moved to Bangalore" 를 둘 다 반환한다고 했다. 어느 쪽이 유효한지는 모델이 추측해야 한다.
어떻게 해결했나
제작자 Shubham Singh 은 2026년 10월 22일 Hacker News 에 Show HN개발자 커뮤니티 Hacker News 에서 자신이 만든 프로덕트를 소개하는 글. 제목이 "Show HN:"으로 시작한다. 글로 TenseMem 을 공개했다. TenseMem 은 사용자 정보를 항목(예: lives_in)마다 현재 값 하나로 유지한다. LLM대규모 언어 모델. 많은 글로 학습해 글을 이해하고 생성하는 AI 모델이다. 은 사용자의 말에서 정보를 찾아 정해진 형식의 연산으로 제안하기만 한다. 연산에는 주어, 항목, 값, 근거 문장이 들어간다. 그 연산을 적용할지는 결정적같은 입력을 넣으면 항상 같은 결과가 나오는 성질. 실행할 때마다 결과가 달라질 수 있는 LLM 의 출력과 대비된다. 규칙이 판정한다. 새 도시가 들어오면 이전 도시는 이력으로 옮겨진다. 에이전트는 이 이력으로 "전에 어디 살았나"에 답할 수 있다.
기억을 조회할 때마다 신선도 정보가 함께 반환된다. 아직 처리하지 못한 메시지가 있으면 is_current 는 False 가 된다. TenseMem 은 에이전트에게 넘기는 기억을 <tensemem-context> 태그로 감싼다. 에이전트가 이 기억이 들어간 대화를 add() 로 다시 넘기면, TenseMem 은 태그 안의 내용을 지운 뒤에 정보를 찾는다. 자신이 에이전트에게 넘긴 기억을 새 정보로 다시 저장하지 않기 위해서다.
무엇이 다른가
첫째, 현재 값을 결정하는 주체가 다르다. Claude 의 메모리는 Claude 가 대화 중에 스스로 저장하고 갱신한다. TenseMem 에서는 모델이 연산을 제안하고 규칙이 적용 여부를 판정하므로, 같은 연산에는 항상 같은 상태가 나온다. 트레이드오프는 범위다. register_predicate 로 미리 등록한 항목만 저장된다.
둘째, 기억을 조회하는 방식이 다르다. 유사도 검색은 이전 값도 질문과 비슷하면 함께 가져온다. TenseMem 의 context() 는 항목마다 현재 값만 반환하고, 이전 값은 history() 로 따로 조회한다. 제작자가 대화 101개로 만든 TenseBench 를 규칙 추출기로 채점하면 TenseMem 의 현재 상태 정확도는 1.000 이다. 사용자 발화 전체를 이어 붙인 방식과 질문과 단어가 많이 겹치는 발화를 고른 방식은 0.368 이었다. 트레이드오프는 토큰이다. 모델에 넘기는 기억은 TenseMem 이 평균 48.1 토큰, 비교한 두 방식은 20.2 토큰과 19.6 토큰이었다.
셋째, 기억을 관리하는 위치가 다르다. Claude 의 메모리는 Anthropic 의 서비스 안에서 관리된다. TenseMem 의 기억은 애플리케이션 안에서 SQLite 파일로 관리되고, 별도 서버가 필요 없다. 트레이드오프는 저장소다. README 에 따르면 아직 SQLite 만 지원한다.
무엇이 편해지나
- 사용자 정보를 오래 기억하는 에이전트를 만드는 개발자. 이사나 이직처럼 바뀌는 정보를 처리하는 규칙을 직접 작성하지 않아도 된다. 오늘 실제 모델을 연결한 상태에서 이사했다는 문장을 넣자 현재 값이 바뀌고 이전 값은 이력으로 옮겨졌다.
- 사용자가 메시지에 시크릿을 붙여 넣을 수 있는 서비스. 제작자는 SECURITY.md 에서
add()가 메시지를 저장하거나 모델에 보내기 전에 흔히 쓰이는 형식의 시크릿을 마스킹한다고 했다. 오늘 가짜 AWS 액세스 키를 넣어 요청과 데이터베이스 어디에도 남지 않는 것을 확인했다.
어떻게 만들었나
- 커밋 57개는 2026년 10월 17일부터 닷새 동안 작성됐다(작성자 시간대 기준). 이 가운데 49개는 메시지 끝에 Cursor 에이전트와 함께 작성했다는 Co-authored-by 트레일러가 있다.
src의 Python 코드는 12,969줄이다. 런타임 의존성은 네 개다.- README 에 따르면 기본 테스트는 API 키 없이 실행되고 호스팅 모델을 호출하지 않는다.
실행해 보니
격리 환경에 PyPI 로 설치하고 아래 순서로 시험했다.
- 설치.
pip install "tensemem[openai]"가 7초 만에 끝났다. - README 예제. 모델 없이 규칙으로 추출하는
FakeExtractor로 실행했다. Delhi 를 넣고 Bangalore 로 바꾸자 이력에 Delhi 는 SUPERSEDED, Bangalore 는 ACTIVE 로 저장됐다.correct()로 Bangalore 가 틀렸다고 정정하자 현재 값이 이전 값 Delhi 로 돌아왔다. - 재구성.
rebuild()는 저장된 메시지 기록에서 상태를 처음부터 다시 계산한다. 호출한 직후 상태는 비어 있었고, 신선도는is_currentFalse,pending1 이었다.rebuild()는 기본 설정에서 비동기로 실행된다. 처리가 끝난 뒤 상태에는 정정한 값 Delhi 가 유지됐다. - TenseBench.
tensemem bench가 23초 만에 대화 101개를 채점했다. 결과는 README 의 표와 같았다. - 실제 모델. 추출 모델로 OpenRouter 를 거쳐 Claude Haiku 5.5 를 연결했다. "I live in Delhi and I work at Infosys." 에서
lives_in과works_at이 추출됐다. "Last month I moved to Bangalore." 를 넣자lives_in의 현재 값이 Bangalore 로 바뀌었다. - 피드백 루프.
context()가 반환한 기억 블록에서 Bangalore 만 Chennai 로 바꿔add()로 다시 넣었다. TenseMem 이 블록 안의 내용을 기억으로 저장한다면 현재 값이 Chennai 로 바뀐다. 모델 요청은 발생하지 않았고 상태도 바뀌지 않았다. - 다른 사람. "My friend Ravi lives in Mumbai and works at TCS." 에서 추출한 정보는
user.friend를 주어로 저장됐다. 사용자의lives_in과works_at현재 값은 바뀌지 않았다. - 시크릿. 가짜 AWS 액세스 키가 든 문장을 넣었다. 모델로 보낸 요청과 데이터베이스 어디에도 키가 없었다. 키 대신
[REDACTED]가 들어 있었다. - 비용. 메시지 다섯 개에 요청 4건, 12,067 토큰, $0.001815 가 들었다.
README 에 적힌 세 가지는 실행에서 모두 확인됐다.
1 add: state={'lives_in': 'Delhi', 'works_at': 'Infosys'} fresh=True failed=0
2 move: state={'lives_in': 'Bangalore', 'works_at': 'Infosys'} fresh=True failed=0
history lives_in: [('Delhi', 'SUPERSEDED'), ('Bangalore', 'ACTIVE')]
3 echo: state={'lives_in': 'Bangalore', 'works_at': 'Infosys'} fresh=True failed=0
4 other person: state={'lives_in': 'Bangalore', 'works_at': 'Infosys'} fresh=True failed=0
확인하지 못한 것
- 실제 모델로 채점한 TenseBench. TenseBench 의 대화를 실제 모델로 채점해 README 의 표와 비교하자.
- Studio 와 MCPModel Context Protocol. AI 모델을 외부 도구와 데이터에 연결하는 방식을 정의한 규격이다. 서버. Studio 는
tensemem serve의 REST 서버에 연결하는 로컬 웹 화면이다.tensemem serve와 Studio 를 실행해 기억을 조회해 보고,tensemem mcp도 확인하자.
판정
작동한다. 실제 모델로도 현재 값과 이력이 구분돼 저장됐다. 다만 기억할 항목을 개발자가 미리 등록해야 한다. 아직 0.1.0 알파 버전이다. 사용자 정보가 자주 바뀌는 에이전트를 만들고, 그 정보의 현재 값을 확실히 알아야 하는 경우에 써 볼 만하다. 대화의 맥락을 항목으로 나누지 않고 그대로 기억해야 한다면 이 프로덕트는 적합하지 않다.
얻어갈 것
- 어느 값이 현재 값인지 정하는 일은 모델이 아니라 규칙에 맡기자. 오늘 실제 모델을 연결했을 때도 규칙이 Delhi 를 이력으로 옮기고 Bangalore 를 현재 값으로 정했다.
- 에이전트에게 넘긴 기억은 다시 저장하지 않도록 표시해 두자. TenseMem 은 기억 블록을 태그로 감싸 피드백 루프를 막았다.
시작하기
pip install "tensemem[openai]"python -c "from tensemem import FakeExtractor, Memory; m = Memory(llm=FakeExtractor()); m.register_predicate(\"lives_in\"); m.add(\"u1\", \"I live in Delhi\")"
- 필요한 것
- Python 3.11 이상 · 실제 추출에는 OpenAI, Anthropic, Gemini, Ollama, LiteLLM 가운데 하나. FakeExtractor 는 키 없이 규칙으로 추출한다
- 비용
- Apache-2.0, 무료. 호스팅 모델로 추출하면 제공자의 모델 비용이 따로 든다.
기억할 항목은 register_predicate 로 미리 등록한다. 등록하지 않은 항목은 저장하지 않는다.
실행해서 확인한 절차다.
진행
- 3일커밋 있음
- 7일예정
- 15일예정
- 30일예정
- 90일예정
- 180일예정
- 365일예정
최근 확인 3일, 2026.10.25 일
- 런칭 이후 커밋
- 0 → 1
- 스타
- 3 → 5
- 마지막 커밋
- 2026.10.23
커밋 1개가 있었지만 요약할 만한 변화는 없다.