본문으로 건너뛰기
5분 AI.
GITHUB TRENDING MONTHLY #4 딥다이브 · 2026-10-23 분석

hindsight 딥다이브
— 대화를 쌓는 AI에서 경험을 정리하는 AI로

메모리 서버

빠른 판단

무엇
경험을 사실로 정리하고 시간·관계·의미로 검색·재해석하는 에이전트 장기 기억 서버
이럴 때
대화가 바뀌어도 사용자 선호와 과거 경험의 근거를 찾아 응답에 반영하는 에이전트를 만들 때
입력
대화·경험 기록과 검색·재해석 요청
결과
사실·관계·시점이 연결된 기억과 근거 검색 결과
Hindsight는 AI 에이전트의 장기 기억을 관리하는 시스템입니다. 대화에서 사실을 추출하고, 시간·인물·관계를 연결하고, 여러 검색 결과를 합쳐 다음 답변에 필요한 근거를 꺼냅니다. Python API, PostgreSQL, Next.js 관리 화면, Rust CLI가 어떻게 하나의 제품으로 이어지는지 살펴봅니다. 초점은 기능 목록보다 설계 원리입니다. 저장소: vectorize-io/hindsight · ⭐52,915 · 포크 6,220 · MIT · 2026-10-23 GitHub 기준, 코드 인용은 커밋 8674354 기준입니다.
목차
  1. 프로젝트 한줄 요약
  2. 왜 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석
  5. 디렉토리 구조 해부
  6. 학습 포인트 (기술별)
  7. 하드웨어 / 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한줄 요약

대화가 끝나도 쓸 수 있는 기억을 만드는 서버

Hindsight는 에이전트가 겪은 일을 저장·검색·재해석하는 기억 계층입니다. 사용자가 “저는 매운 음식을 못 먹어요”라고 말하면, 다음 대화에서도 그 선호를 찾아 식당 추천에 반영할 수 있습니다. 앱은 필요한 시점에 API를 호출하거나 연동 도구로 기억 처리를 연결합니다.

핵심은 대화 전체를 매번 읽히는 대신, 필요한 사실과 그 근거를 찾아 모델에 건네는 것입니다. 실제 코드의 세 진입점도 MemoryEngine.retain_async(), recall_async(), reflect_async()로 나뉩니다. 모두 hindsight-api-slim/hindsight_api/engine/memory_engine.py에 있습니다.

한 문장 비유

대화 녹음기를 넘어, 근거 카드를 정리해 주는 연구 조교입니다

녹음기는 회의 한 시간을 그대로 보관합니다. 조교는 그 안에서 “민수는 Python을 선호한다”, “배포는 금요일이다”라는 카드를 뽑고, 같은 인물이 나온 카드를 연결합니다.

나중에 “민수에게 어떤 과제를 맡길까?”라고 물으면 관련 카드를 찾아 종합합니다. 다만 조교가 잘못 정리할 수 있으므로 원문·추출 사실·종합 결과를 구분해야 합니다. 이 구분이 저장소를 읽는 첫 번째 열쇠입니다.

동작하는 일읽기 시작할 함수
retain내용을 나누고 사실·임베딩·연결을 저장retain_batch_async() → hindsight-api-slim/hindsight_api/engine/retain/orchestrator.py:retain_batch()
recall질문과 관련된 기억을 찾아 순위를 매겨 반환recall_async() → hindsight-api-slim/hindsight_api/engine/search/retrieval.py
reflect기억 검색 도구를 사용하며 질문에 대한 답을 생성reflect_async() → hindsight-api-slim/hindsight_api/engine/reflect/agent.py:run_reflect_agent()
용어 풀이
기억 뱅크 (memory bank)
기억을 묶는 이름 있는 공간입니다. 사용자별·프로젝트별로 다른 bank_id를 쓸 수 있습니다. 파일철에 붙은 분류표와 비슷하지만, 분류표 자체가 출입 허가증은 아닙니다. 접근 권한은 인증·테넌트 정책과 함께 설계해야 합니다.

1-1. 무엇을 “기억”이라고 부르는가

계층쉬운 예코드에서의 구분
원문날짜가 붙은 대화·회의록·문서documents, chunks
world“지수는 서울에 산다”외부 세계에 관한 추출 사실
experience“에이전트가 배포 오류를 해결했다”행동·상호작용·경험에 관한 사실
observation여러 대화에서 종합한 선호나 반복 패턴fact_type='observation', 원천 기억 ID와 변경 이력
mental model“이 프로젝트의 배포 규칙”을 주제로 갱신하는 요약mental_models의 관리 가능한 종합 문서

hindsight-api-slim/hindsight_api/engine/consolidation/consolidator.py는 observation을 원시 사실에서 자동 생성하는 종합 결과로 설명합니다. mental model은 주제·질의를 정하고 갱신하는 별도 구조입니다. 두 이름을 모두 “요약”으로만 번역하면 갱신 시점과 책임의 차이를 놓치게 됩니다.

1-2. 가장 작은 사용 예

아래는 별도로 준비한 로컬 서버에 연결하는 Python SDK 예시입니다. recall은 검색 결과를, reflect는 기억을 활용한 생성 답변을 돌려준다는 차이를 관찰해 보세요.

from hindsight_client import Hindsight

client = Hindsight(base_url="http://localhost:8888")
client.retain(
    bank_id="study-user",
    content="지수는 Python으로 백엔드를 공부하고, 평일 저녁에 학습한다."
)
memories = client.recall(bank_id="study-user", query="지수는 무엇을 공부하나?")
answer = client.reflect(bank_id="study-user", query="지수의 학습 계획을 제안해 줘.")
학습 목표
LLM 주변의 시스템을 배우는 저장소

모델을 새로 만드는 프로젝트는 아닙니다. 입력 검증, 비동기 I/O, 검색 랭킹, 데이터 갱신, 작업 재시도, 관리 화면을 연결해 LLM 기능을 지속 가능한 서비스로 만드는 법을 공부하기 좋습니다.

2왜 주목받는가

장기 기억이라는 문제와, 제품으로 묶인 구현

2-1. 긴 프롬프트만으로 해결하기 어려운 문제

대화가 길어지면 모든 기록을 매 요청에 넣는 방식은 입력 토큰과 읽어야 할 내용이 함께 늘어납니다. 더 큰 문맥 창이 있어도 어떤 사실이 최신인지, 누가 말했는지, 무엇을 근거로 답했는지를 자동으로 관리해 주지는 않습니다. 기억 계층은 이 책임을 앱 바깥의 명시적인 서비스로 꺼냅니다.

Hindsight의 눈여겨볼 장점은 사실 추출부터 근거를 이용한 답변까지 하나의 공개된 코드 흐름으로 읽을 수 있다는 점입니다. 검색만 구현한 예제와 달리, 사실 수정·관찰 종합·백그라운드 처리·SDK·관리 UI가 함께 있습니다.

2-2. 연구와 제품 사이를 연결한다

논문 Hindsight is 20/20은 세계의 사실, 에이전트의 경험, 종합된 요약과 믿음을 구분하는 기억 구조와 retain·recall·reflect를 제안합니다. 논문의 논리적 구분을 현재 코드의 테이블 수와 그대로 대응시키면 안 됩니다. 현재 API가 검색하는 사실 유형은 world, experience, observation입니다.

README는 LongMemEval에서 높은 성능과 외부 재현 사례를 주장합니다. 다만 README의 비교 그림 설명은 2026년 1월 기준입니다. 10월의 모든 경쟁 제품보다 우수하다고 확대 해석할 수 없습니다. 모델, 데이터셋, 토큰 예산, 평가 판정 방식이 같아야 정확도를 비교할 수 있습니다.

월간 트렌딩 4위와 스타 52,915개는 관심의 크기를 보여줍니다. 관심을 끌 만한 요인으로는 에이전트 개인화 수요, 연구 결과의 공개, 여러 프레임워크와 코딩 도구에 붙일 수 있는 연동 폭을 꼽을 수 있습니다. 이는 기능과 공개 자료에 근거한 해석이며, 순위 상승의 인과관계를 입증하는 통계는 아닙니다.

2-3. 다른 선택지와 무엇을 비교해야 할까

선택지중심 역할Hindsight를 고를 이유·대가
pgvector 직접 사용PostgreSQL 안에서 벡터 저장·유사도 검색사실 추출·종합·추론 API를 직접 조립하는 부담이 줄어듭니다. 대신 큰 서비스의 설정과 수명주기를 이해해야 합니다.
Mem0add로 기억을 만들고 search로 문맥을 제공Hindsight에서는 observation 종합과 reflect 도구 루프를 함께 추적할 수 있습니다. 이것이 모든 앱에서 더 낫다는 뜻은 아닙니다.
Zep / Graphiti시간에 따라 변하는 사실·관계를 지식 그래프로 구성기본 PostgreSQL 경로에서 관계형 데이터·벡터·연결을 함께 읽고, 별도 종합 계층까지 공부할 수 있습니다.
Hindsight저장·복합 검색·기억 종합·생성 답변을 묶은 기억 서비스여러 계층을 함께 살펴볼 수 있습니다. LLM 호출 비용, 비동기 작업 지연, 운영할 부품도 늘어납니다.

각 도구의 중심 역할은 pgvector 공식 저장소, Mem0 공식 설명, Graphiti 공식 문서 기준입니다. Hindsight 쪽 선택 이유는 소스 구조에 근거한 비교입니다. 경쟁 도구에도 겹치는 검색·시간·엔티티 기능이 있으므로 기능의 유무를 단순한 승패 표로 만들지 않았습니다.

표현을 정확히 읽기
“학습한다”는 모델 가중치를 다시 훈련한다는 뜻이 아닙니다

핵심 동작은 기억 추출·저장·갱신·검색·종합입니다. 기본 흐름에 모델 파라미터를 학습하는 훈련 루프가 있는 것은 아닙니다. README의 “RAG와 지식 그래프의 한계를 없앤다”는 표현도 제품의 주장입니다. 실제 구현은 벡터·키워드·그래프 검색을 적극 활용합니다.

3기술 스택 전체 지도

의존성 선언 범위와 실제 잠긴 버전을 구분해서 읽기

>=는 최소 버전이고 ^는 호환 범위를 나타냅니다. 이것만 보고 실제 환경의 버전을 단정할 수 없습니다. 아래의 “잠금”은 커밋 8674354의 uv.lock 또는 루트 package-lock.json에서 읽은 값이며, 실행 환경을 측정한 값은 아닙니다.

3-1. 백엔드: Python 비동기 API와 모델 호출

기술선언 / 잠금이 저장소에서 맡은 일
Python>=3.11 / .python-version: 3.11핵심 메모리 엔진과 HTTP 서버
FastAPI>=0.120.3 / 0.136.3요청 검증·REST 라우팅·OpenAPI
Uvicorn>=0.38.0 / 0.38.0ASGI 서버: 비동기 Python 앱의 네트워크 입구
Pydantic>=2.0.0 / 2.12.5RecallRequest, RetainRequest 등 입력·출력 구조
asyncpg>=0.30.0 / 0.31.0PostgreSQL 비동기 연결과 쿼리
SQLAlchemy>=2.0.44,<2.1 / 2.0.44DB 모델·마이그레이션 기반. 검색 경로에는 직접 작성한 SQL도 사용
Alembic>=1.17.1 / 1.17.1DB 스키마 버전 관리
pgvector Python 패키지>=0.4.1 / 0.4.1벡터 값 처리. DB 서버 확장 자체의 버전과는 다름
FastMCP>=3.2.0 / 3.2.0AI 도구가 기억 API를 호출하는 MCP 접점
toktok-rs>=0.3.0 / 0.3.0토큰 수 계산과 문서 분할
LiteLLM>=1.95.1 / 1.104.0다양한 모델 제공자에 연결하는 선택지

근거 파일은 hindsight-api-slim/pyproject.toml과 uv.lock입니다. SQLAlchemy 상한에는 기본 PostgreSQL 드라이버 변경으로 설치가 깨지는 것을 막으려는 주석도 있습니다. 버전 제약은 단순한 숫자 목록을 넘어 호환성 판단의 기록입니다.

3-2. 로컬 모델은 선택 의존성이다

묶음실제 선언·잠금 예배울 점
local-mlSentenceTransformers >=5.0.0 → 5.7.0, Transformers >=5.5.0 → 5.12.1벡터 생성과 재순위 모델을 프로세스 내부에서 실행
PyTorch>=2.11.0 → 2.13.0 / 2.13.0+cpu잠금 파일에 환경·인덱스별 후보가 공존하므로 모두 동시에 설치된다는 뜻은 아님
local-onnxONNX Runtime >=1.17.0PyTorch와 다른 추론 실행 경로를 제공
embedded-dbpg0-embedded>=0.15.2 → 0.15.2개발용 PostgreSQL 수명주기를 패키지로 관리
oracleoracledb>=2.5.0DB 방언과 연결 계층을 분리하는 확장 사례

hindsight-api/pyproject.toml은 핵심 구현을 중복 보관하지 않고 hindsight-api-slim[all]==1.1.0에 의존합니다. 따라서 slim은 기능이 없는 서버가 아니라 로컬 모델 의존성을 선택할 수 있는 핵심 패키지로 읽어야 합니다. 가벼운 구성을 택하면 임베딩과 재순위 제공자를 따로 지정해야 합니다.

용어 풀이
임베딩과 재순위 모델
임베딩은 문장을 숫자 좌표로 바꿔 비슷한 뜻을 빨리 찾게 합니다. 재순위 모델은 후보를 찾은 뒤 질문과 각 후보를 더 자세히 비교합니다. 넓게 찾는 단계와 정밀하게 고르는 단계가 다른 것입니다.

3-3. 프론트엔드: 관리 화면도 하나의 서버다

기술선언 / 잠금역할
Next.js^16.3.8 / 16.3.8관리 화면과 서버 측 API 중계
React^19.2.0 / 19.2.3뱅크·문서·관찰·검색 진단 화면의 상태와 컴포넌트
TypeScript^5.9.3 / 5.9.3API 데이터와 화면 속성의 타입
Tailwind CSS^4.1.17 / 4.1.18관리 UI 스타일
Radix UIDialog ^1.1.15 → 1.1.15, Select ^2.2.6 → 2.2.6대화상자·선택 메뉴 같은 기본 상호작용
Recharts / SonnerRecharts ^3.5.1 → 3.6.0, Sonner ^2.0.7 → 2.0.7차트와 작업 결과 알림
Vitest^4.1.11 / 4.1.11프론트엔드 단위 검증

출처는 hindsight-control-plane/package.json과 루트 npm 잠금 파일입니다. hindsight-control-plane/src/lib/hindsight-client.ts는 서버 환경변수 HINDSIGHT_CP_DATAPLANE_API_URL과 HINDSIGHT_CP_DATAPLANE_API_KEY로 API 클라이언트를 만듭니다. 화면에서 쓰는 /api/recall은 Next.js 서버를 거쳐 Python API로 이어집니다.

3-4. 인프라·빌드·여러 언어의 접점

부품설정·의존성 값의미
Dockerpython:3.11-slim, node:24-slim, UI 전용 node:24-alpine다단계 빌드로 API·SDK·UI를 나눠 조립
외부 DB 예제pgvector/pgvector:pg${HINDSIGHT_DB_VERSION:-18}Compose 예제의 기본 PostgreSQL 주 버전은 18
Rust CLIedition 2021, Clap 4.5, Tokio 1, Ratatui 0.29명령 해석·비동기 통신·터미널 화면
Rust SDK 생성Progenitor 0.11, hindsight-clients/rust/build.rsOpenAPI를 빌드 시 Rust 클라이언트로 변환
Go SDKgo 1.18, hindsight-clients/go/go.modGo는 주 서버가 아니라 클라이언트 언어 중 하나
품질·배포pytest, Ruff, ty, GitHub Actions, Helm각 패키지 변경과 배포 경로를 독립적으로 관리

.github/workflows/test.yml은 변경 경로를 감지해 필요한 검증 작업을 고릅니다. 특히 Rust SDK가 읽는 hindsight-docs/static/openapi.json도 변경 감지 대상입니다. SDK 폴더를 고치지 않아도 API 명세 변경만으로 CLI가 깨질 수 있기 때문입니다.

.github/workflows/release.yml은 v* 태그로 릴리스를 시작하고, Python 클라이언트·핵심 서버·배포 묶음을 순서대로 빌드·게시합니다. uv 워크스페이스와 npm 워크스페이스가 공존하므로 “루트 설치 한 번이면 모든 언어가 빌드된다”고 가정하면 안 됩니다.

4아키텍처 심화 분석

요청 한 번이 어떤 계층을 통과하는지 따라가기

4-1. 전체 시스템 구조

다음 그림은 기본 PostgreSQL 구성을 단순화한 것입니다. 화살표는 주요 호출·데이터 흐름이며, 모든 요청이 모든 부품을 통과한다는 뜻은 아닙니다.

[에이전트 / Python·TS·Go SDK / Rust CLI / MCP]
                         |
                         v
             [FastAPI API :8888] <--- [Next.js 관리 서버 :9999]
                         |                         ^
                 인증·요청 검증                     |
                         |                     [브라우저]
                         v
                   [MemoryEngine] ----> [LLM·임베딩·재순위 제공자]
             +-----------+-----------+
             |           |           |
           retain      recall      reflect
             |           |           |
        분할·사실 추출    질문 벡터화   검색 도구 호출 루프
        임베딩·연결       복합 검색     기억 근거로 답변 생성
             |           |           |
             +----- [MemoriesExtension]
                         |
                 [PostgresMemories]
                         |
                  [PostgreSQL]
       원문·청크 / 사실·엔티티·연결 / 벡터 / 작업 상태
                         ^
                         |
                  [WorkerPoller]
          async_operations에서 작업 선점·처리
                         |
                observation 종합·문서 갱신

기억 엔진은 처리 순서를 조정하고, 저장소 인터페이스는 데이터를 읽고 쓰는 책임을 맡습니다. 다만 기본 구성에서도 뱅크·작업 상태 같은 관리 데이터와 기억 데이터의 추상화 범위가 같지는 않습니다. 이를 구분해야 “저장소 교체”의 실제 범위를 이해할 수 있습니다.

4-2. 설계 패턴 ① 처리 파이프라인과 중간 상태 분리

retain_async()는 단일 입력을 리스트로 감싸 retain_batch_async()에 넘깁니다. 단건·다건 처리를 서로 다른 엔진으로 만들지 않는 구조입니다. 이어 hindsight-api-slim/hindsight_api/engine/retain/orchestrator.py:retain_batch()가 문서별 그룹, 변경 청크, 사실 추출, 저장 경로를 조정합니다.

# 소스의 핵심 호출을 학습용으로 축약한 흐름
retain_async(content)
    → retain_batch_async(contents=[content])
    → retain_batch(...)
    → extract_facts_from_contents(...)
    → generate_embeddings_batch(...)
    → 사실·엔티티·연결 저장
    → 후속 종합 작업 등록

_extract_and_embed()에서는 사실 추출 결과가 없으면 빈 결과를 바로 반환하고, 결과가 있으면 날짜 정보를 보강한 텍스트를 임베딩합니다. 큰 입력은 스트리밍 경로인 _streaming_retain_batch()에서도 처리하므로, 이 축약 흐름이 모든 경우에 한 번씩 직렬 실행된다고 이해하면 안 됩니다.

단계입출력 변화검토할 실패
분할긴 문서 → 청크와 위치 정보문맥이 잘려 사실의 주어·날짜를 잃는가
사실 추출청크 → 구조화된 사실·엔티티·날짜모델 출력이 스키마에 맞는가, 원문을 왜곡하는가
임베딩사실 문장 → 숫자 벡터벡터 차원과 저장소 설정이 맞는가
저장중간 결과 → 영속 데이터와 연결문서 재처리·재시도 때 중복이나 유실이 생기는가
종합여러 사실 → observation 갱신근거와 변화 이력을 유지하는가

_try_delta_retain()은 기존 문서의 청크와 새 청크를 비교해 바뀐 부분만 다시 처리하는 경로입니다. “같은 문서 ID면 무조건 공짜”가 아니라 변경 여부와 처리 전략에 따라 재사용 기회가 생긴다고 읽는 편이 정확합니다.

또한 기본 사실 추출 외에 hindsight-api-slim/hindsight_api/engine/retain/fact_extraction.py:_extract_facts_chunks()는 LLM 사실 추출 없이 청크 원문을 기억 단위로 만드는 모드입니다. 따라서 “retain은 언제나 LLM으로 사실을 추출한다”는 설명도 설정을 생략한 단정입니다.

비유

파이프라인은 세탁 공정과 비슷합니다. 세탁·건조·분류를 나누면 어느 단계에서 문제가 생겼는지 찾기 쉽습니다. 다만 단계마다 중간 결과가 생기므로, 작업이 끊겼을 때 어디부터 다시 시작할지도 함께 설계해야 합니다.

4-3. 설계 패턴 ② 여러 검색 전략을 합치는 계단식 검색

hindsight-api-slim/hindsight_api/engine/search/retrieval.py:retrieve_all_fact_types_parallel()은 시간 조건을 정리한 뒤 get_memories().recall_unified()에 검색을 맡깁니다. 기본 구현인 hindsight-api-slim/hindsight_api/engine/memories/postgres.py:PostgresMemories.recall_unified()가 실제 쿼리의 순서와 연결 사용을 관리합니다.

검색 갈래찾기 좋은 것왜 다른 갈래도 필요한가
semantic질문과 뜻이 비슷한 사실제품 코드·정확한 이름은 놓칠 수 있음
bm25 / 키워드같은 단어·식별자가 들어간 사실다르게 표현한 같은 의미에 약할 수 있음
graph검색된 사실과 연결된 주변 사실관계의 품질과 시작점 선택에 영향받음
temporal질문의 시간 범위에 맞는 사건항상 실행되지 않으며 날짜 해석도 필요

함수 이름에 parallel이 있어도 네 갈래가 동시에 독립 쿼리로 출발하는 것은 아닙니다. 현재 PostgreSQL 경로는 의미·키워드 UNION 쿼리 → 같은 연결의 시간 검색 → 연결 반환 → 사실 유형별 그래프 검색의 병렬 실행 순서입니다. 그래프는 앞서 얻은 의미 검색 결과를 시작점으로 이용합니다.

이름을 한 번 더 주의해서 읽을 부분도 있습니다. 키워드 갈래는 코드에서 bm25로 불리지만, 기본 HINDSIGHT_API_TEXT_SEARCH_EXTENSION=native 경로는 PostgreSQL의 tsvector와 ts_rank_cd()를 사용합니다. hindsight-api-slim/hindsight_api/engine/sql/postgresql.py:build_bm25_arm()에서 확인할 수 있으며, 기본 순위 함수 자체를 BM25라고 부르는 것은 부정확합니다.

hindsight-api-slim/hindsight_api/engine/memory_engine.py는 검색 결과를 기본적으로 hindsight-api-slim/hindsight_api/engine/search/fusion.py:reciprocal_rank_fusion()으로 합칩니다. 서로 척도가 다른 점수를 그대로 더하지 않고, 각 목록에서의 순위로 바꾸는 RRF입니다.

# 실제 fusion.py의 기본값과 계산식
k = 60
score = sum(1 / (k + rank) for rank in 등장한_목록별_순위)

# A: 의미 검색 1위, 키워드 검색 2위
A = 1/61 + 1/62        # 약 0.03252
# B: 의미 검색 2위, 다른 목록에는 없음
B = 1/62               # 약 0.01613

합친 후보는 cross-encoder로 다시 평가하고, 시간·최신성·근거 수 같은 요소를 반영할 수 있습니다. 마지막에는 max_tokens 예산 안에 결과를 담습니다. budget은 검색 작업량, max_tokens는 반환할 문맥량에 가까우므로 서로 다른 손잡이입니다.

모든 용도에 같은 결합법을 고집하지도 않습니다. interleave_fusion()은 목록별 1위, 2위를 번갈아 넣습니다. 종합 과정에서 이미 있는 관찰과 거의 같은 후보가 한 갈래에서만 높게 나올 때, RRF가 그 후보를 예산 밖으로 밀어 중복 관찰이 생길 수 있기 때문입니다.

4-4. 설계 패턴 ③ 인터페이스로 외부 구현을 감싸기

hindsight-api-slim/hindsight_api/engine/embeddings.py의 Embeddings 아래에 LocalSTEmbeddings, OnnxEmbeddings, OpenAIEmbeddings 등이 있습니다. 상위 처리 흐름은 “벡터를 얻는다”는 계약에 의존하고, 제공자별 통신·모델 로딩은 구체 구현이 맡습니다.

저장소도 hindsight-api-slim/hindsight_api/engine/memories/base.py:MemoriesExtension으로 경계를 만듭니다. HINDSIGHT_API_MEMORIES_EXTENSION으로 다른 구현을 지정할 수 있으며, 기억을 소유하는 저장소의 메서드를 통해 검색·쓰기·원문 조회를 수행합니다.

여기서 중요한 제한은 기억 저장소를 바꿔도 뱅크·작업·기타 관리 테이블까지 모두 사라지는 것은 아니라는 점입니다. 기본값은 PostgresMemories이며, 대체 구현의 성능·완전성은 해당 구현을 별도로 검증해야 합니다.

hindsight-api-slim/tests/test_store_table_boundary.py는 AST와 SQL 문자열을 검사해 기억 테이블을 허용된 저장소 계층 밖에서 직접 읽는 코드를 찾습니다. 인터페이스를 문서로만 권장하지 않고, 위반을 자동 검출하는 구조입니다.

용어 풀이
의존성 역전과 어댑터
핵심 로직이 특정 회사의 SDK를 직접 붙잡지 않고 “이런 입력에 이런 출력을 준다”는 약속을 바라보게 하는 설계입니다. 제공자마다 다른 플러그를 같은 소켓에 꽂을 수 있도록 어댑터를 두는 셈입니다.

4-5. 설계 패턴 ④ DB 작업 큐와 재시도 가능한 처리

hindsight-api-slim/hindsight_api/engine/task_backend.py는 테스트용 SyncTaskBackend, API용 BrokerTaskBackend, 워커용 WorkerTaskBackend를 구분합니다. 기본 분산 작업 흐름에서는 async_operations에 실행할 일과 상태를 보관하고 워커가 가져갑니다.

hindsight-api-slim/hindsight_api/worker/poller.py:WorkerPoller.claim_batch()는 작업을 원자적으로 선점합니다. PostgreSQL SQL 계층의 FOR UPDATE SKIP LOCKED는 다른 워커가 잡은 행을 기다리지 않고 건너뛰게 합니다. 테넌트 스키마 순환과 예약 슬롯도 있어 한 종류의 작업이 처리 기회를 독점하지 않도록 합니다.

API 요청
   |
   +-- 작업 등록: pending
                    |
             워커가 행 선점
                    v
                processing
                 /       \
            성공           실패·중단
             |                |
             v          재시도·복구 정책
          completed           |
                        재시도 가능 여부
                         /         \
                       가능        불가·횟수 소진
                        |              |
                        v              v
                     pending         failed

RetainRequest.operation_id는 비동기 retain의 작업 식별자(UUID)를 클라이언트가 지정하게 합니다. 응답이 유실되어 같은 ID로 재요청해도 원래 작업을 돌려주고 새 작업을 중복 등록하지 않도록 하는 계약입니다. 다른 작업의 ID를 재사용하면 409가 될 수 있으며, 동기 retain에서는 이 값이 무시됩니다.

저장 경로의 outbox_callback은 후속 작업 등록을 DB 쓰기와 연결하는 접점입니다. 하지만 큰 입력은 여러 배치와 체크포인트로 나뉩니다. retain_batch_async()의 설명에 있는 “한 트랜잭션”을 모든 대용량 요청 전체가 한 번에 원자적으로 완료된다는 보장으로 읽으면 안 됩니다.

4-6. reflect는 어떤 방식으로 답을 만드는가

hindsight-api-slim/hindsight_api/engine/reflect/agent.py:run_reflect_agent()는 검색 도구를 호출하고 결과를 다시 모델에 넣는 반복 흐름입니다. mental model, observation, 원시 사실 등 서로 다른 근거 계층을 이용합니다. 캐시된 종합 문서가 언제나 정답이라는 뜻은 아니며, 구체 질문과 신선도에 따라 필요한 근거가 달라집니다.

hindsight-api-slim/hindsight_api/config.py의 기본값은 DEFAULT_REFLECT_MAX_ITERATIONS = 10, DEFAULT_REFLECT_MAX_CONTEXT_TOKENS = 100_000입니다. 이는 무한 루프와 무제한 문맥 축적을 막는 예산입니다. 최대 문맥 수가 곧 매번 소비하는 토큰 수를 뜻하지는 않습니다.

_resolve_tool_arg_ceiling()은 남은 문맥 예산을 동시 도구 호출 수로 나눠 요청량을 조절합니다. 생성형 AI 기능에도 “최대로 얼마나 일을 시킬 것인가”라는 전통적인 자원 관리 설계가 필요하다는 점을 보여줍니다.

5디렉토리 구조 해부

비슷한 패키지 이름에 길을 잃지 않는 법

저장소는 여러 제품 부품을 한곳에서 관리하는 모노레포입니다. 가장 먼저 실제 구현, 배포용 묶음, 클라이언트, 검증 도구를 구분하세요. 이름이 더 짧은 hindsight-api/보다 hindsight-api-slim/에 핵심 코드가 있다는 점이 특히 중요합니다.

hindsight/
├── hindsight-api-slim/          핵심 Python 서버
│   ├── hindsight_api/
│   │   ├── main.py             서버 시작 진입점
│   │   ├── config.py           환경변수·기본값
│   │   ├── api/                HTTP·MCP 접점
│   │   ├── engine/
│   │   │   ├── memory_engine.py    처리 흐름 조정
│   │   │   ├── retain/             입력·분할·사실 추출
│   │   │   ├── search/             검색·결합·재순위
│   │   │   ├── reflect/            도구 호출 기반 답변
│   │   │   ├── consolidation/      observation 종합
│   │   │   ├── memories/           기억 저장소 인터페이스·구현
│   │   │   ├── db/                 DB 연결·작업 SQL
│   │   │   └── sql/                SQL 방언
│   │   ├── worker/             작업 선점·실행·복구
│   │   ├── extensions/         서버 확장 계약
│   │   └── alembic/            스키마 변경 이력
│   └── tests/                  엔진·API·회귀 검증
├── hindsight-api/              전체 서버 배포 패키지
├── hindsight-all/              Python 통합 사용 묶음
├── hindsight-all-slim/          가벼운 통합 사용 묶음
├── hindsight-all-npm/           Node.js 서버 수명주기 관리
├── hindsight-embed/             로컬 데몬·내장 사용 도구
├── hindsight-control-plane/     Next.js 관리 화면·API 중계
├── hindsight-cli/               Rust 명령줄 도구
├── hindsight-clients/           Python·TypeScript·Rust·Go SDK
├── hindsight-integrations/      프레임워크·에이전트별 연동
├── hindsight-extensions/        확장 구현 예제
├── hindsight-docs/              문서·OpenAPI 명세
├── hindsight-system-tests/      로컬 스텁 기반 외부 인터페이스 검증
├── hindsight-system-evals/      모델·데이터셋을 이용한 품질 평가
├── hindsight-integration-tests/ 실행 중인 서버와의 연동 검증
├── hindsight-dev/              개발 도구·성능 실험
├── docker/                     이미지·Compose 구성
├── helm/                       Kubernetes 배포 차트
├── scripts/                    개발·생성·릴리스 도구
└── .github/workflows/           CI·배포 자동화

5-1. 목적별로 찾아갈 곳

궁금한 것첫 파일다음에 볼 것
API 입력 형태hindsight-api-slim/hindsight_api/api/http.pyRecallRequest, MemoryItem, RetainRequest
검색 순서hindsight-api-slim/hindsight_api/engine/search/retrieval.pyhindsight-api-slim/hindsight_api/engine/memories/postgres.py와 hindsight-api-slim/hindsight_api/engine/search/fusion.py
종합 지식 갱신hindsight-api-slim/hindsight_api/engine/consolidation/consolidator.pyrun_consolidation_job(), 생성·수정·삭제 처리
화면의 검색 요청hindsight-control-plane/src/app/api/recall/route.tshindsight-control-plane/src/lib/hindsight-client.ts의 SDK 설정
서버 분리 배포helm/hindsight/values.yamlAPI·worker·controlPlane·PostgreSQL 자원 설정
실패 사례hindsight-api-slim/tests/기능 이름과 관련된 테스트의 입력·기대 결과

5-2. 코드 규모를 숫자로 읽기

다음은 추적 중인 파일의 확장자별 물리적 줄 수입니다. 개행 문자를 세었으며 빈 줄·주석·테스트·커밋된 생성 코드를 포함합니다. 문서 본문, JSON 잠금 파일, 이미지, 빌드 시 생성될 코드는 제외합니다. 따라서 실행 가능한 제품 구현만의 크기로 읽어서는 안 됩니다.

확장자파일 수약식 코드 규모
Python .py2,095608,827줄
TypeScript .ts606115,575줄
TSX .tsx14743,672줄
Go .go25383,473줄
Rust .rs3618,272줄
JavaScript / JSX382,864줄
셸 .sh728,773줄

Python 핵심 패키지 hindsight-api-slim/hindsight_api/는 367개 파일·180,280줄이고, 같은 패키지의 hindsight-api-slim/tests/는 690개 파일·221,740줄입니다. Python SDK 쪽도 66,045줄, Go SDK 쪽은 81,541줄에 이릅니다. SDK 생성 코드와 검증 코드가 전체 규모를 크게 늘립니다. 테스트 줄 수가 많다는 사실만으로 커버리지나 품질을 증명할 수는 없습니다.

읽는 순서
가장 큰 파일을 첫 줄부터 읽지 마세요

hindsight-api-slim/hindsight_api/engine/memory_engine.py에서 모든 기능을 이해하려 하면 흐름을 잃기 쉽습니다. 먼저 작은 순수 함수인 reciprocal_rank_fusion()을 읽고, 호출하는 곳을 거슬러 올라가세요. 질문 하나에 필요한 경로만 좁혀 읽는 편이 학습 효율이 좋습니다.

6학습 포인트 (기술별)

파일을 읽은 뒤 직접 설명하거나 작게 재현할 수 있어야 한다

이 저장소를 공부할 때의 목표는 라이브러리 이름을 외우는 것이 아니라, 각 계층이 어떤 실패를 막는지 설명하는 것입니다. 기술마다 “읽을 코드 → 배울 개념 → 작은 실험”을 한 묶음으로 진행하세요.

6-1. Python asyncio: 기다림과 계산을 구별하기

async def는 함수를 자동으로 빠르게 만들지 않습니다. DB·외부 API 응답을 기다리는 동안 다른 작업을 진행하게 합니다. 반면 모델 추론이나 큰 텍스트 처리는 CPU 자원을 소비하므로, 비동기 함수 안에서도 동시 실행량과 실행 위치를 고려해야 합니다.

읽을 곳은 hindsight-api-slim/hindsight_api/engine/retain/orchestrator.py의 asyncio.gather(), 세마포어, 스트리밍 생산자·소비자 흐름입니다. 이어 hindsight-api-slim/hindsight_api/engine/retain/memory_budget.py:RetainMemoryBudget을 보세요. 청크 개수뿐 아니라 추출한 사실과 벡터의 추정 바이트 크기를 기준으로 생산 속도를 늦춥니다.

[생산자: 사실 추출] -- 중간 결과 --> [소비자: DB 쓰기]
          |                                |
          +-- 바이트 예산 확보             +-- 커밋 후 예산 반환
          |
       예산이 부족하면 대기

청크가 10개라는 조건만으로는 메모리 사용량을 알 수 없음
청크마다 사실 수·텍스트 길이·벡터 크기가 다르기 때문

작은 실험: 같은 청크 수에서 사실이 1개일 때와 50개일 때 필요한 벡터 저장 공간을 계산해 보세요. estimate_chunk_bytes()와 hindsight-api-slim/tests/test_retain_memory_budget.py가 무엇을 세고 무엇을 생략하는지 설명하면 됩니다.

용어 풀이
역압 (backpressure)
뒤쪽 처리 속도가 느릴 때 앞쪽 생산을 늦추는 제어입니다. DB가 초당 10개를 쓰는데 모델이 초당 100개를 만들면 중간 대기열이 계속 커집니다. 대기열의 개수나 바이트 예산을 제한해 시스템이 감당할 속도로 맞춥니다.

6-2. FastAPI와 Pydantic: 입력 계약을 먼저 설계하기

hindsight-api-slim/hindsight_api/api/http.py:RecallRequest에는 budget='mid', max_tokens=4096, trace=False 같은 기본값이 있습니다. MemoryItem은 본문뿐 아니라 문서 ID·시각·문맥·태그를 받습니다. API 설계에서 “본문 문자열만 있으면 충분하다”는 가정이 왜 금방 깨지는지 보여줍니다.

작은 실험: timestamp를 생략할 때, 명시적인 날짜를 줄 때, 문자열 unset을 줄 때의 의도를 표로 정리하세요. 소스상 생략은 현재 시각을 사용하고, unset은 시간을 부여하지 않는 용도입니다. 사건의 시각과 저장된 시각이 다른 문제를 함께 생각할 수 있습니다.

타입이 맞는 요청도 업무적으로는 틀릴 수 있습니다. 예를 들어 다른 사람의 bank_id를 넣은 문자열은 문법상 유효할 수 있으므로, 요청 검증과 접근 권한 검증은 각각 필요합니다.

6-3. PostgreSQL: 벡터와 관계형 데이터를 함께 다루기

기본 저장 구조에서 memory_units는 사실, entities는 사람·장소 같은 대상, unit_entities는 사실과 대상의 연결, memory_links는 기억 사이의 연결을 나타냅니다. 그래프 기능이 있다고 반드시 별도 그래프 DB가 필요한 것은 아니라는 사례입니다.

읽을 곳은 hindsight-api-slim/hindsight_api/engine/memories/pg/recall.py:retrieve_semantic_bm25_combined_sql()과 hindsight-api-slim/hindsight_api/engine/sql/postgresql.py입니다. 공통적인 검색 의도와 DB별 SQL 문법을 어디서 나누는지 보세요. Alembic 변경 파일은 스키마를 운영 중에 어떻게 진화시키는지도 보여줍니다.

작은 실험: “질문과 비슷한 사실을 찾는다”와 “그 사실에 등장한 사람의 다른 사실을 찾는다”를 서로 다른 SQL 단계로 써 보세요. 벡터 거리와 관계 탐색의 역할이 분리되면 그래프 검색의 이유가 명확해집니다.

6-4. 정보 검색: 후보 수집과 순위 결합을 나누기

hindsight-api-slim/hindsight_api/engine/search/fusion.py는 모델 API가 없어도 읽고 계산할 수 있는 좋은 출발점입니다. RRF가 사용하는 것은 벡터 유사도 자체가 아니라 순위입니다. cap_per_source()는 한 검색 갈래가 지나치게 많은 후보를 내어 전체 후보 예산을 잠식하는 일을 줄입니다.

작은 실험: 의미 검색과 키워드 검색에 서로 다른 5개 문서 순위를 주고 RRF와 interleave_fusion()을 손으로 비교하세요. 정답 문서가 한 갈래에서만 1위인 경우와 두 갈래에서 2위인 경우를 구분하면 검색 목적에 따라 결합법을 달리하는 이유가 보입니다.

6-5. LLM 앱 설계: 추출·검색·생성의 오류를 분리하기

틀린 답이 나왔다고 모두 프롬프트 문제는 아닙니다. 원문에 정보가 없었는지, 추출 때 사라졌는지, 검색에서 밀렸는지, 최종 생성에서 왜곡됐는지를 나눠야 합니다. recall과 reflect가 별도 API인 구조는 이런 구분에 도움이 됩니다.

읽을 곳은 hindsight-api-slim/hindsight_api/engine/reflect/agent.py, hindsight-api-slim/hindsight_api/engine/reflect/tools.py, hindsight-api-slim/hindsight_api/engine/consolidation/consolidator.py입니다. observation의 source_memory_ids와 변경 이력은 요약 결과를 원천 사실에 연결하는 장치입니다. 근거가 추적된다고 그 근거 자체가 참이라고 보장되는 것은 아닙니다.

작은 실험: “예전에는 야간 근무, 지금은 주간 근무”처럼 변하는 정보를 두 날짜로 나눠 적으세요. “현재”와 “지난달” 질문의 올바른 답을 먼저 정의한 뒤, 필요한 원문·날짜·관찰을 역으로 설계해 보세요.

6-6. TypeScript·React: API 중계에서 데이터 손실 막기

hindsight-control-plane/src/app/api/recall/route.ts:POST()는 요청을 SDK 호출로 바꾸고 response.data 전체를 반환합니다. 일부 필드만 다시 골라 응답하던 방식이 source_facts 같은 필드를 누락시켰다는 주석이 있습니다. 중간 계층도 데이터 계약을 깨뜨릴 수 있다는 사례입니다.

작은 실험: 검색 결과에 새로운 필드를 하나 추가한다고 가정하고 Python 응답 모델 → OpenAPI → TypeScript SDK → Next.js 중계 → 화면에서 통과해야 할 지점을 그려 보세요. 타입 검사만으로 모든 런타임 누락을 막을 수 있는지도 검토하세요.

6-7. Rust·OpenAPI·CI: 생성 코드의 경계를 이해하기

hindsight-clients/rust/build.rs는 Progenitor가 이해할 수 있도록 명세를 변환하고, 지원하지 않는 multipart 경로를 걸러내는 처리도 합니다. 명세를 입력하면 모든 언어의 모든 기능이 완벽히 생성된다고 가정하면 안 되는 이유입니다.

작은 실험: API에 선택적 쿼리 매개변수가 하나 늘어날 때 어떤 클라이언트와 CLI 호출이 영향을 받는지 적어 보세요. .github/workflows/test.yml에서 OpenAPI 변경을 Rust 검증의 입력으로 넣은 이유를 자신의 말로 설명하면 됩니다.

검증 관점
동작 테스트, 구조 테스트, 품질 평가는 질문이 다릅니다

퓨전 함수 검증은 “주어진 순위를 올바르게 합치는가”, 저장소 경계 검증은 “계층을 우회하지 않는가”, 모델 평가는 “사람이 기대한 답을 내는가”를 묻습니다. 하나가 통과했다고 나머지도 증명되는 것은 아닙니다.

7하드웨어 / 시스템 요구사항

API 서버, 기억용 모델, 생성 모델의 자원을 따로 계산하기

GPU 필요 여부는 Hindsight라는 이름보다 어떤 모델을 어디에서 실행하는지에 따라 달라집니다. 외부 LLM API와 작은 로컬 임베딩·재순위 모델을 쓰는 구성, 모든 모델을 별도 로컬 서버에서 실행하는 구성은 요구 자원이 크게 다릅니다.

7-1. 공식 설치 문서의 메모리 가이드

아래 값은 hindsight-docs/docs/developer/installation.md에 적힌 구성 요소별 가이드입니다. 처리량 보증이나 모든 입력에 대한 최대 사용량은 아닙니다. 한 컴퓨터에서 함께 실행하면 각 구성 요소의 사용량과 운영체제 여유분을 더해야 합니다.

구성 요소최소 / 권장 RAM조건
API 전체 이미지1.5 GB / 2 GB로컬 임베딩·재순위 모델과 실행 런타임 포함
API slim 이미지512 MB / 1 GB임베딩·재순위를 외부 제공자로 분리
관리 UI128 MB / 256 MBNext.js 실행 프로세스 기준의 가이드
분리 워커선택한 API 이미지와 동일워커도 같은 로컬 모델을 적재할 수 있음
PostgreSQL512 MB / 1 GB 이상기억 수·벡터·인덱스 규모에 따라 증가

문서는 개발·기본 부하에 CPU 2 vCPU도 사용할 수 있다고 설명합니다. 생성 LLM을 같은 기기에서 돌릴 자원은 별도입니다. full Docker 이미지가 로컬 임베딩을 포함한다고 해서 대형 생성 모델까지 이미지 안에서 자동 실행되는 것은 아닙니다.

디스크도 RAM과 구분하세요. 설치 문서는 full 이미지의 압축 해제 크기를 약 9 GB로 안내합니다. 여기에 DB, 벡터 인덱스, 모델 캐시, 로그, 백업 공간이 추가됩니다. 다운로드 크기와 실행 후 사용량은 이미지 버전과 플랫폼에 따라 달라집니다.

7-2. 소스 기본값으로 확인하는 모델 구성

설정hindsight-api-slim/hindsight_api/config.py 기본값실전 의미
임베딩 제공자local서버 프로세스 안에서 모델 사용
로컬 임베딩 모델BAAI/bge-small-en-v1.5한국어 자료라면 다국어 검색 품질을 별도 평가
벡터 차원384모델을 바꿀 때 저장된 벡터와 차원·의미 공간 호환성 확인
재순위 제공자·모델local / cross-encoder/ms-marco-MiniLM-L-6-v2후보가 많을수록 모델 비교 작업이 증가
로컬 재순위 동시 실행4요청 수와 CPU 경쟁의 균형을 조절
재순위 후보 상한300기본 후보 예산. 실제 사용량은 검색·설정 경로에 영향받음
retain 중간 상태 예산128 MiB문서별 스트리밍 처리 하나의 추출 후 미저장 상태에 대한 추정 예산

RetainMemoryBudget은 프로세스 전체 RAM 제한이 아닙니다. 설정값 128에 1024 × 1024를 곱한 바이트 수이며, 문서 그룹을 병렬 처리하면 예산도 각각 적용됩니다. 벡터·문자열 등을 추정하며, 일부 비라틴 문자 메모리를 낮게 추정할 수 있다는 주석도 있습니다. 진행이 영원히 막히지 않도록 빈 상태에서 단일 초대형 예약을 허용하는 예외가 있어, 이 수치를 엄격한 RSS 상한으로 쓰면 안 됩니다.

7-3. Helm의 자원 설정은 또 다른 기준이다

구성CPU 요청 / 제한RAM 요청 / 제한
API500m / 2000m1Gi / 4Gi
워커500m / 2000m1Gi / 4Gi
관리 UI250m / 1000m512Mi / 2Gi
PostgreSQL250m / 1000m256Mi / 1Gi

출처는 helm/hindsight/values.yaml입니다. 요청값은 스케줄링에 쓰는 예약량이고 제한값은 컨테이너의 자원 경계입니다. 공식 설치 가이드의 최소 사양과 같지 않습니다. 차트에는 PostgreSQL 저장 공간 8Gi, 선택적 모델 캐시 볼륨 5Gi도 있으며, 전용 워커는 기본적으로 꺼져 있습니다.

용어 풀이
CPU의 m, 메모리의 Mi·Gi
1000m은 CPU 1개에 해당하는 Kubernetes 단위이고 500m은 그 절반입니다. Mi와 Gi는 2의 거듭제곱을 기준으로 한 메모리 단위입니다. CPU 요청을 500m로 정했다고 항상 절반 코어만 쓰는 것은 아니며 제한값과 실제 경쟁 상황도 봐야 합니다.

7-4. 소프트웨어와 운영 조건

한국어 실습의 변수
기본 모델이 한국어 검색의 최적 설정이라는 보장은 없습니다

기본 임베딩 모델 이름의 en과 재순위 모델의 학습 대상을 확인하세요. 기본 키워드 검색의 언어 설정도 english입니다. 한국어·영어 혼합 질문, 사람 이름, 날짜, 코드 식별자를 포함한 소형 평가 세트를 먼저 만드는 편이 좋습니다. 모델 교체는 차원뿐 아니라 저장된 벡터의 의미 공간도 바꾸므로 기존 데이터 재임베딩 계획이 필요할 수 있습니다.

8직접 해볼 수 있는 실습 과제

작은 정답표에서 시작해 검색·일관성·자원 관리로 넓히기

아래 과제는 개인 로컬 환경과 가상의 대화를 전제로 합니다. 먼저 기대 결과를 적고, 관찰 결과와 비교하세요. 모델을 부르는 과제에는 API 비용과 출력 변동이 있으므로 원문·질문·설정·모델 이름을 함께 기록해야 비교가 가능합니다.

과제 1

기억 수명주기 지도 만들기 입문 · 서버 없이 가능

목표: retain·recall·reflect의 입력과 출력을 구분합니다. “지수는 Python을 선호한다”라는 한 문장이 어느 함수와 데이터 구조를 통과하는지 화살표로 그리세요.

읽을 곳: hindsight-api-slim/hindsight_api/api/http.py의 요청 모델, hindsight-api-slim/hindsight_api/engine/memory_engine.py:retain_async(), hindsight-api-slim/hindsight_api/engine/retain/orchestrator.py:_extract_and_embed().

완료 기준: 원문, 사실, 임베딩, observation을 서로 다른 상자로 그리고, LLM이 호출되는 단계와 DB가 쓰이는 단계를 표시합니다. 추출 사실이 하나도 없는 경우의 흐름도 포함하세요.

과제 2

작은 한국어 기억 뱅크 실험 입문 · 로컬 서버 필요

목표: 같은 정보가 검색 결과와 생성 답변에서 어떻게 달라지는지 관찰합니다. 가상의 사용자 1명에 대해 날짜·선호·프로젝트 결정 3종류의 문장을 저장하세요.

진행: 아래 REST 요청 형태로 동기 retain 후 recall을 수행합니다. trace를 켜고 어떤 후보가 선택됐는지 확인한 뒤 같은 질문을 reflect에 보냅니다.

완료 기준: 질문 5개에 대해 기대 사실, 실제 검색 사실, 생성 답변의 근거 일치 여부를 표로 만듭니다. 관찰 종합은 별도 작업일 수 있으므로 retain 완료와 observation 갱신 완료를 구분하세요.

# 개인 로컬 서버가 준비된 뒤 사용하는 요청 예시
curl -X POST http://localhost:8888/v1/default/banks/study-user/memories \
  -H 'Content-Type: application/json' \
  -d '{"items":[{"content":"지수는 Python을 선호한다.",
       "context":"가상의 학습 상담", "document_id":"study-note-1"}],
       "async":false}'

curl -X POST http://localhost:8888/v1/default/banks/study-user/memories/recall \
  -H 'Content-Type: application/json' \
  -d '{"query":"지수에게 어떤 언어 과제를 줄까?", "budget":"mid",
       "max_tokens":2048, "trace":true}'

curl -X POST http://localhost:8888/v1/default/banks/study-user/reflect \
  -H 'Content-Type: application/json' \
  -d '{"query":"지수의 선호를 근거로 학습 과제를 추천해 줘."}'

이 예시는 인증을 별도로 구성하지 않은 개인 로컬 환경의 요청 형태입니다. 실제 서비스에서는 인증 방식에 맞는 헤더를 추가해야 합니다. 응답 JSON의 세부 필드는 같은 커밋의 OpenAPI 명세와 대조하세요.

과제 3

RRF와 교차 배치의 차이 재현 중급 · 모델 없이 가능

목표: 좋은 검색 결과는 높은 유사도 하나로만 결정되지 않음을 이해합니다. hindsight-api-slim/hindsight_api/engine/search/fusion.py의 두 결합법에 해당하는 순위표를 만드세요.

진행: 문서 A는 의미 검색 1위에만, 문서 B는 세 갈래 2위에 등장하도록 합니다. 각 방식에서 A·B 순위가 어떻게 달라지는지 계산하고, 종합 중복 탐지와 일반 질문에 어떤 방식이 유리할지 가설을 세우세요.

완료 기준: RRF 점수 계산표, 교차 배치 순서표, 후보 예산을 1·3·5개로 바꾼 비교를 제출합니다. hindsight-api-slim/tests/test_interleave_fusion.py의 중복 제거 기대값도 설명하세요.

# 독립적인 학습용 의사 코드: 저장소의 객체 타입은 생략
rankings = [["A", "B"], ["C", "B"], ["D", "B"]]
scores = {}
for results in rankings:
    for rank, doc_id in enumerate(results, start=1):
        scores[doc_id] = scores.get(doc_id, 0) + 1 / (60 + rank)
# B = 3/62, A = 1/61: B의 결합 점수가 더 높다.
# 교차 배치는 A, C, D를 먼저 배치한 뒤 B를 넣는다.
과제 4

문서 갱신과 비동기 재요청 분석 중급 · 격리된 실습 DB

목표: 문서의 정체성과 작업의 정체성이 다름을 이해합니다. 같은 document_id의 본문을 일부 수정한 경우와 같은 비동기 operation_id를 다시 보낸 경우를 나누세요.

진행: RetainRequest의 ID 계약, _try_delta_retain(), hindsight-api-slim/tests/test_delta_retain.py를 먼저 읽습니다. 문서 변경 전후의 청크·사실, 재요청 전후의 작업 수를 별도 지표로 기록하세요.

완료 기준: “문서 변경 최적화”와 “같은 작업 재등록 방지”를 각각 한 문장으로 설명합니다. 실패나 재시도가 있어도 기억이 정확히 한 번만 만들어진다고 성급히 결론내리지 마세요.

과제 5

느린 저장소에서도 버티는 파이프라인 설계 고급 · 가짜 저장소로 시작

목표: 처리량, 지연, 메모리가 서로 영향을 주는 방식을 이해합니다. 모델 호출 없이 가짜 생산자가 결과를 만들고 느린 소비자가 저장하는 작은 모형을 작성하세요.

진행: RetainMemoryBudget을 읽고 바이트 예산을 적용합니다. 예산보다 큰 단일 항목과, 소비자가 덜 찬 배치를 쥔 채 생산자를 기다리는 경우를 각각 설계하세요.

완료 기준: 예산 초과 대기, 단일 큰 항목의 진행, 소비자 조기 쓰기 조건을 설명합니다. 이어 WorkerPoller.claim_batch()의 행 잠금과 연결해 프로세스 내부 제어와 여러 워커 사이 제어의 차이를 그리세요.

성능을 비교할 때는 정답률만 남기지 마세요. 검색 후보 수, 반환 토큰, 지연, 모델 호출 수, 비용도 함께 적으면 어떤 품질을 얻기 위해 어떤 자원을 지불했는지 설명할 수 있습니다.

9관련 기술 심화 학습 로드맵

6주 동안 한 경로씩 넓혀 가는 읽기 계획

Python의 함수·클래스·예외, JSON, HTTP 요청을 어느 정도 읽을 수 있다는 전제로 시작합니다. 아직 낯설다면 1주차를 더 길게 잡으세요. 모든 모듈을 끝내는 대신 매주 설명 가능한 결과물 하나를 만드는 것이 목표입니다.

작동 화면을 보는 것보다 입력이 어디서 변하고 실패가 어디서 복구되는지 그릴 수 있는 상태를 목표로 삼으세요.

주차학습 주제읽을 곳과 실습완료 결과물
1주차HTTP·JSON·입력 모델hindsight-api-slim/hindsight_api/api/http.py의 요청 모델과 retain·recall 라우트. 필수값·기본값·검증 실패 구분요청·응답 계약표와 단일 기억 흐름도
2주차asyncio·역압hindsight-api-slim/hindsight_api/engine/retain/orchestrator.py, hindsight-api-slim/hindsight_api/engine/retain/memory_budget.py. 생산자·소비자와 바이트 예산 모형느린 DB에서 메모리가 늘어나는 이유와 제어 설명
3주차관계형 DB·벡터·날짜hindsight-api-slim/hindsight_api/engine/memories/pg/recall.py, hindsight-api-slim/hindsight_api/engine/sql/postgresql.py, Alembic. 사실·엔티티·연결 관계 그리기간단한 데이터 관계도와 두 단계 검색 계획
4주차랭킹·검색 평가hindsight-api-slim/hindsight_api/engine/search/fusion.py, hindsight-api-slim/hindsight_api/engine/search/reranking.py. RRF·교차 배치·후보 예산 비교질문 10개와 정답 근거, 검색 실패 분류표
5주차LLM 도구 루프·종합hindsight-api-slim/hindsight_api/engine/reflect/agent.py, hindsight-api-slim/hindsight_api/engine/consolidation/consolidator.py. 사실과 종합 문서의 근거 추적틀린 답의 원인을 추출·검색·생성으로 나눈 보고서
6주차SDK·UI·운영hindsight-control-plane/, Rust hindsight-clients/rust/build.rs, CI, Helm. API 변경이 전파되는 경로 검토서비스 구성도와 자원·실패·배포 체크 항목

주차별 학습 자료는 마지막 참고 링크의 Python·FastAPI·PostgreSQL 공식 문서로 보충할 수 있습니다.

9-1. 검색 평가는 정답 문장보다 근거 ID부터

문장이 자연스럽다고 올바른 기억을 쓴 것은 아닙니다. 각 질문에 필요한 원천 사실을 미리 정하고, 그 사실이 검색 결과에 들어왔는지 확인하세요. 검색이 성공한 뒤에도 답이 틀리면 생성·추론 경로를 따로 살펴볼 수 있습니다.

관찰가능한 원인다음 확인
원문에도 답이 없음수집 누락 또는 답할 수 없는 질문모르는 것을 인정하도록 기대 답 정의
원문에는 있지만 사실에 없음추출·분할 과정의 정보 손실청크 경계와 추출 결과 비교
사실은 있지만 결과에 없음필터·검색·랭킹·토큰 예산 문제검색 추적과 후보 순위 확인
근거는 맞지만 답이 틀림생성·종합·시간 해석 문제reflect의 도구 결과와 최종 답 비교

9-2. 품질 평가와 성능 평가는 분리하기

hindsight-system-tests/는 스텁 모델을 이용해 외부 인터페이스의 동작을 검증하는 경로입니다. hindsight-system-evals/는 실제 제공자와 품질 평가를 다루며, README는 주요 데이터셋의 소유·판정·채점을 별도 Agent Memory Benchmark 프로젝트에 맡기는 구조를 설명합니다.

스텁은 응답을 일정하게 만들어 오류를 재현하기 좋지만 실제 언어 이해 품질을 증명하지는 않습니다. 반대로 실제 모델 평가의 정확도만으로 DB 잠금이나 작업 복구가 올바른지도 알 수 없습니다. 서로 다른 질문에 맞는 검증 방법을 선택하세요.

공부 순서 비유

도시를 공부할 때 모든 건물 주소부터 외우지 않습니다. 먼저 집에서 학교까지 길 하나를 익히고, 그 길의 버스·교차로·우회로를 이해한 뒤 지도를 넓힙니다. 코드도 요청 하나를 따라가는 경로를 만든 뒤, 그 경로의 실패와 대체 구현을 더해 가면 됩니다.

10핵심 키워드 사전

코드에서 마주칠 단어를 쉬운 말로 바꾸기
용어쉬운 설명
에이전트 메모리에이전트가 다음 세션에서도 활용할 수 있도록 경험·사실을 저장하고 꺼내는 계층입니다.
문맥 창모델이 한 번의 요청에서 읽을 수 있는 입력 공간입니다. 장기 저장소와 역할이 다릅니다.
토큰모델이 텍스트를 처리하는 조각입니다. 글자 수와 정확히 같지 않으며 언어·인코딩 방식에 따라 달라집니다.
memory bank사용자나 프로젝트 등 기억을 묶는 공간입니다. 코드에서는 bank_id로 식별합니다.
retain새 내용을 기억으로 받아들이는 쓰기 동작입니다. 설정에 따라 사실 추출 또는 청크 저장 경로를 사용합니다.
recall질문에 관련된 기억을 찾아 돌려주는 검색 동작입니다.
reflect기억 검색 도구와 모델 추론을 이용해 질문에 대한 답을 만드는 동작입니다.
world / experience외부 세계의 사실과 에이전트가 겪은 경험을 나누는 사실 유형입니다.
observation여러 사실을 근거로 자동 생성·갱신하는 종합 지식입니다. 원시 사실과 구분됩니다.
mental model정해진 주제·질의를 중심으로 유지·갱신하는 종합 문서입니다.
consolidation새 사실을 기존 관찰과 비교하고 종합 지식을 만들거나 고치는 과정입니다.
chunk긴 문서를 처리하기 좋게 나눈 조각입니다. 너무 짧으면 문맥이, 너무 길면 처리 효율이 문제될 수 있습니다.
entity사람·장소·조직·개념처럼 문장에서 따로 식별하는 대상입니다.
entity resolution서로 다른 표현이 같은 대상을 가리키는지 판단해 연결하는 일입니다.
embedding문장을 숫자 벡터로 표현한 값입니다. 의미가 비슷한 문장을 가까운 좌표로 찾는 데 씁니다.
vector dimension벡터를 이루는 숫자의 개수입니다. 차원이 같아도 다른 모델의 의미 공간이 호환된다는 보장은 없습니다.
pgvectorPostgreSQL에 벡터 자료형과 유사도 검색 기능을 더하는 확장입니다.
BM25단어의 등장 빈도와 문서 길이 등을 고려하는 키워드 검색 방식입니다. 저장소의 키워드 경로는 선택한 검색 백엔드에도 영향을 받습니다.
그래프 검색기억 사이의 연결을 따라 관련 정보를 넓혀 찾는 방식입니다.
시간 검색질문의 날짜·기간과 기억의 사건 시각을 맞춰 후보를 찾는 방식입니다.
hybrid search의미·키워드·연결 등 여러 신호를 함께 사용해 찾는 검색입니다.
RRF서로 다른 검색 목록의 순위를 역수 점수로 바꿔 합치는 방식입니다.
reranking이미 찾은 후보를 더 자세히 비교해 순서를 다시 매기는 단계입니다.
cross-encoder질문과 후보 텍스트를 함께 읽어 관련성을 평가하는 모델 방식입니다.
provenance이 정보가 어떤 원문과 사실에서 왔는지 이어지는 출처 관계입니다.
asyncioPython에서 I/O 대기 중 다른 작업을 진행하도록 조정하는 비동기 실행 도구입니다.
backpressure소비자가 느릴 때 생산자를 늦춰 대기열과 메모리 증가를 제어하는 방식입니다.
transaction정해진 DB 변경들을 하나의 성공·실패 단위로 묶는 처리입니다. 전체 요청과 범위가 같지는 않을 수 있습니다.
idempotency같은 요청을 반복해도 의도한 효과가 중복으로 늘지 않게 하는 성질입니다. 어떤 식별자와 동작에 적용되는지 확인해야 합니다.
outbox데이터 변경과 후속 작업 등록의 일관성을 맞추는 설계입니다. 후속 작업이 반드시 한 번만 실행된다는 뜻은 아닙니다.
SKIP LOCKED다른 트랜잭션이 잠근 행을 기다리지 않고 건너뛰는 SQL 옵션입니다. 여러 워커의 작업 선점에 유용합니다.
migrationDB의 테이블·인덱스 구조가 바뀌는 과정을 버전별로 기록하고 적용하는 일입니다.
adapter서로 다른 모델·저장소를 공통 인터페이스에 맞춰 연결하는 구현입니다.
OpenAPIHTTP API의 경로·매개변수·응답을 기계가 읽을 수 있게 적은 명세입니다.
MCPAI 애플리케이션이 외부 도구를 발견하고 호출하도록 연결하는 프로토콜입니다.
모노레포서버·UI·SDK 등 여러 부품을 하나의 저장소에서 관리하는 구조입니다.
lockfile의존성을 해석한 구체 버전을 기록하는 파일입니다. 플랫폼별로 여러 후보가 있을 수도 있습니다.

용어를 외웠는지는 “벡터 검색이 실패했으니 후보 수를 늘리자”라는 말에 질문을 덧붙일 수 있는지로 확인할 수 있습니다. 어떤 사실 유형을 찾는지, 시간·태그 필터가 맞는지, 재순위 예산인지 반환 토큰 예산인지부터 구분할 수 있어야 합니다.

11참고 링크

공식 자료와 커밋에 고정된 소스 탐색 경로

11-1. 프로젝트 공식 자료

11-2. 설명과 바로 연결되는 핵심 코드

11-3. 관련 기술의 공식 학습 자료

11-4. 현재 상태 (2026-10-23 확인)

항목상태
선정GitHub Trending Monthly #4 · 2026-10-23 분석
저장소·설명vectorize-io/hindsight · Hindsight: Agent Memory That Learns
스타 / 포크52,915 / 6,220 · 2026-10-23 GitHub 기준
주 언어Python
생성일2025-10-30
최근 push2026-10-23
최신 릴리스v1.1.0 · 2026-10-21
최근 커밋8674354 · 2026-10-23 · release(openclaw): v1.1.1
버전 해석커밋 제목의 v1.1.1은 OpenClaw 연동 릴리스입니다. 핵심 Python 패키지·관리 UI의 선언 버전은 1.1.0입니다.
코드 규모Python 약 60.9만 줄, TS·TSX 약 15.9만 줄, Go 약 8.35만 줄, Rust 약 1.83만 줄. 테스트·커밋된 생성 코드 포함, 개행 수 기준
핵심 코드Python 서버 패키지 367개 파일·180,280줄, 해당 패키지 테스트 690개 파일·221,740줄
라이선스루트 LICENSE는 MIT. 관리 UI의 hindsight-control-plane/package.json에는 별도로 ISC가 표기되어 있음
기본 구성FastAPI·PostgreSQL/pgvector·로컬 임베딩/재순위·외부 또는 별도 로컬 LLM
제공 접점REST·MCP·Python/TypeScript/Go/Rust 클라이언트·Rust CLI·Next.js 관리 UI

버전·모델·검색 예산·원문 데이터가 달라지면 같은 기억 시스템이라도 결과와 비용이 달라집니다. 스타 수와 릴리스 날짜는 해당 날짜의 GitHub 상태이고, 의존성·기본값·코드 규모는 커밋 8674354의 스냅샷입니다. 링크된 온라인 문서는 이후 바뀔 수 있으므로 재현에는 커밋에 고정된 파일을 기준으로 삼으세요.

쓰기 전에 알아둘 한계
기억 시스템도 잘못 기억하고, 늦게 갱신하고, 비용을 씁니다

정확성: LLM 사실 추출과 관찰 종합은 원문을 왜곡할 수 있습니다. 근거 ID와 원문을 확인할 수 있는 흐름을 유지하고, 중요한 판단은 추출 문장 하나에만 맡기지 마세요.

일관성: 원시 사실 저장과 백그라운드 종합은 완료 시점이 다를 수 있습니다. 재시도·복구 경로가 있다는 사실은 모든 부작용이 정확히 한 번만 발생한다는 보장이 아닙니다.

범위: 기본값은 모든 조직·언어·데이터 규모에 최적화된 설정이 아닙니다. PostgreSQL 경로를 중심으로 한 구조 설명을 Oracle이나 별도 기억 저장소의 완전한 기능·성능 검증으로 확대하면 안 됩니다.

데이터와 접근: 외부 LLM·임베딩·재순위 제공자를 쓰면 선택한 데이터가 외부로 전달됩니다. 뱅크 ID와 태그는 권한 검증을 대신하지 않으며, 원문·벡터·종합 문서·백업의 보관 정책을 함께 고려해야 합니다.

수치: 하드웨어 표는 공식 문서의 가이드이며 부하 측정 보증이 아닙니다. README의 벤치마크 주장은 평가 조건을 확인해야 하고, 전체 커밋 수·장기간 운영 안정성·성능 우위는 코드 줄 수로 판단할 수 없습니다.