공개 과제 템플릿 roboco-io/officeagent-onboarding-challenge를 바탕으로 만든 개인 프로젝트입니다. 구현을 마친 상태는 GitHub Tags의
submission-final-locked-20260804(커밋15eb559)로 고정해 두었고, 그 뒤에는 문서만 보강했습니다.
사용자가 올린 문서(PDF·TXT·Markdown)를 근거로 질문에 답하는 API 서버입니다. 같거나 비슷한 질문이 다시 오면, 저장해 둔 답이 아직 유효한 경우 AI를 다시 부르지 않고 그 답을 돌려줍니다. 관련 내용을 찾지 못하면 AI를 부르지 않고 답할 수 없다고 알립니다. 답에는 AI에 보낸 조각마다 파일 이름·문서 version·위치를 출처로 붙입니다.
| 항목 | 내용 |
|---|---|
| 기간 | 2026.07.28 – 2026.08.04 |
| 역할 | 1인 수행: 설계·구현·테스트·문서 |
| 다룬 문제 | 문서가 바뀌거나 같은 문서가 동시에 올라올 때, 저장해 둔 예전 답이 다시 나가거나 저장된 데이터끼리 어긋나는 문제 |
| 기술 | Python · FastAPI · PostgreSQL 17 + pgvector · Psycopg 3 · FastEmbed · Codex App Server(답을 만드는 AI) · SSE · Docker Compose · GitHub Actions |
| 검증 | 테스트 함수 242개. GitHub Actions(quality-gates)가 PostgreSQL을 띄워 전체 테스트를 실행합니다 |
| AI 도구 | 코드는 코딩 도구 Codex와 함께 작성했습니다. 서버가 답을 만들 때 부르는 Codex App Server와는 쓰임이 다릅니다. 2026.10에 더한 「한눈에 보기」 절과 동작 원리 문서는 Claude Code로 작성하고 직접 검토했습니다 |
| 기능 | 지키는 규칙 | 설명 |
|---|---|---|
| 문서 저장 | 문서·조각·저장된 답의 변경이 한 transaction으로 함께 성공하거나 함께 취소됩니다 | 동작 원리 1 |
| 동시 업로드 | 같은 문서의 업로드 두 건이 겹쳐도, 한쪽이 오류로 끝나지 않고 차례로 처리됩니다 | 동작 원리 2 |
| 답 재사용 | 설정이 바뀌거나 문서가 갱신되면 저장된 예전 답을 재사용하지 않습니다 | 동작 원리 3 |
| 기권 | 관련 내용을 찾지 못하면 AI를 부르지 않고 답할 수 없다고 알립니다 | 동작 원리 4 |
| 스트리밍 | 첫 글자가 나가기 전에만 다시 시도해서, 화면에 두 답이 섞이지 않습니다 | 동작 원리 5 |
| 답변 중 문서 변경 | 답을 만드는 동안 문서가 바뀌면, 그 답을 저장해 두지 않습니다 | 동작 원리 6 |
전체 흐름과 낱말 풀이는 동작 원리 「처리 흐름」과 「용어」에 있습니다.
경계: 운영 환경에 배포한 서비스가 아닙니다. 성능 측정(benchmark)은 하지 않았고, 자동 장애 전환, 운영 환경의 고가용성(HA), OCR은 구현하지 않았습니다. 서버는 답의 문장마다 출처가 뒷받침하는지 검증하지 않습니다. 코드를 다시 읽으며 찾은 한계는 동작 원리 「알려진 한계」에 적었습니다.
PDF·TXT·Markdown 문서를 저장하고 PostgreSQL+pgvector에서 관련 내용을 검색하는 FastAPI 문서 Q&A 서버입니다. 근거가 없으면 답변하지 않으며, 근거가 있으면 Codex App Server 응답을 SSE로 전달하고 문서명·버전·청크 위치를 출처로 함께 반환합니다. 동일·유사 질문 cache와 문서 변경 시 cache 무효화를 지원합니다.
최신 실행 결과, 공식 과제 판정, 별도 내부 계약과 정직한 잔여 상태는 V2 Traceability가 소유합니다.
retros/는 생성 시점의 사실을 보존하는 이력이며 현재 상태 정본이 아닙니다.
| 독자의 목적 | 먼저 할 일 | 정상 결과 | 다음 문서 |
|---|---|---|---|
| 빠른 채점 | docker compose run --build --rm test |
exit code 0 |
V2 Traceability |
| Hosted CI | Draft PR의 quality-gates 확인 |
exact SHA의 check 성공 | workflow |
| 복구 가산점 검증 | uv run --frozen python -m officeagent.infrastructure.postgres_recovery_drill |
cleanup 뒤 JSON PASS |
Evaluator Manual §3.3 |
| standby 운영 경계 검증 | uv run --frozen python -m officeagent.infrastructure.postgres_ha_drill |
cleanup 뒤 제한된 JSON PASS |
Evaluator Manual §3.4 |
| 품질셋 검토 | uv run python -m officeagent.evaluation --split dev --verify-only --require-approved |
approved와 고정 dataset SHA |
Gold set v1 |
| 제품 실행 | 아래 제품 실행 순서로 DB와 API 시작 |
readiness 200, upload 201 |
Evaluator Manual |
| 설계 검토 | transaction·SSE·cache 경계 확인 | 선택 이유와 비범위 식별 | Architecture |
| prompt/LLM 검토 | schema·decoder·실패 의미 확인 | raw JSON 비노출·invalid no-cache | Prompt Design |
| 코드 탐색 | 관심 주장에 연결된 source/test 선택 | 한 request의 입구→출구 추적 | Repository Map |
처음 보는 독자는 Evaluator Manual을 사용하십시오. 사전 조건, 실행 순서, 예상 HTTP/SSE 응답, 실패 해석, cleanup과 외부 데이터 전송 경계를 단계별로 설명합니다. 이 README는 가장 짧은 실행 입구와 계약 요약을 소유합니다.
지원자 확인: 제공된 템플릿 8ca57661f7a9b54e8bac2ed8957e5c3dacc77502에서 증분 구현했으며, 기존 오픈소스 프로젝트를 통째로 복사하지 않았습니다. Python 제3자 패키지는 pyproject.toml과 uv.lock에 선언하고, Codex CLI와 PostgreSQL/pgvector image는 README와 compose.yaml에 고정했습니다.
현재 실행 영수증 범위는 WSL2에 통합된 Docker Desktop의 Linux x86_64
(linux/amd64) backend와 Compose v2입니다. 별도 WSL Docker Engine과 다른
architecture는 UNKNOWN입니다. 테스트 컨테이너는 Codex, Node, API key와
.codex mount 없이 실행되며 LLM과 embedding만 deterministic double로 교체합니다.
docker compose run --build --rm test이 명령은 임시 PostgreSQL database를 만들고 migration을 적용한 뒤 실제 PostgreSQL, pgvector, parser, cache transaction과 in-process FastAPI ASGI HTTP/SSE 계약으로 전체 suite를 실행하고 database를 제거합니다. 최신 실행 상태는 V2 Traceability에서 확인합니다.
Hosted quality-gates workflow는 같은 lock,
Ruff, host regression, Compose build, PostgreSQL migration, Docker suite와 실제
HTTP readiness를 순서대로 실행한 뒤 평가자 문서 링크와 상태 표현을 검사합니다.
Codex·배포·image publish를 호출하지 않습니다. workflow 파일의 존재는 구현
증거이고, VERIFIED 판정에는 해당 candidate SHA의 실제 GitHub check-run이
추가로 필요합니다.
별도 opt-in recovery drill은 제품 DB나 Codex를 사용하지 않는 합성 PostgreSQL 17
cluster에서 논리 복원과 physical PITR를 각각 실행합니다. random Compose project의
container·volume·전용 local image를 cleanup한 뒤에만 sanitized PASS를
출력합니다. 제품
migration runner로 발견된 모든 migration을 적용하고, 논리 복원과 PITR 양쪽의
head·checksum ledger와 chunking_version schema를 source와 대조합니다. 이 로컬 검증은
production HA, off-host backup, 보존 정책이나 RPO/RTO 증거가 아닙니다. 상세 안전
경계와 실패 정리는 Evaluator Manual §3.3이 소유합니다.
별도 opt-in standby drill은 같은 local Docker backend에 PostgreSQL 17 primary와
비동기 streaming standby를 만들고 WAL replay, old-primary stop, read-write route의
promotion 전 거절, 동일 route의 any fallback이 recovering standby에 연결되는지,
수동 pg_promote와 promotion 뒤
write를 순서대로 확인합니다. replication passfile은 standby의 runtime tmpfs에만
만들고 PGDATA에는 저장하지 않습니다. runner가 scoped container·volume·network·local
image의 부재를 재조회한 뒤에만 제한된 PASS를 출력합니다. 이는 automatic failover,
production HA, zero-loss, RPO/RTO 또는 서로 다른 failure domain의 증거가 아닙니다.
최초 workflow capsule은 exact head d86f4c4의
비공개 평가 저장소의 hosted run #2에서
전 단계를 통과했습니다. 이 실행은 이후 HEAD의 증거로 재사용하지 않으며, Draft PR의
현재 commit마다 새 check 결과를 확인합니다.
공개 저장소로 옮긴 뒤의 첫 실행(커밋 54e3c07)도
quality-gates run에서
전 단계를 통과했습니다.
제품 API와 Codex는 host에서, PostgreSQL/pgvector는 Docker에서 실행합니다. 로컬 Codex 로그인 상태를 컨테이너에 mount하지 않기 위한 의도적 경계입니다.
요구 환경:
- Python 3.11~3.13과 uv
- Docker Compose v2
- Node.js와 ChatGPT 구독으로 로그인한
@openai/codexCLI
Codex 설치·로그인은 최초 한 번 수행합니다.
npm install -g @openai/codex@0.146.0 && codex loginRetrobot은 해당 commit에 저장된 고정 skill, SHA·시각·aggregate shortstat와
WORKLOG의 최신 날짜 H2 하나만 외부 Codex에 보냅니다. 이전 로그·commit 제목·
파일명·작성자·diff는 전송하지 않으며 prompt 전체는 16 KiB, 로그 구간은 8 KiB로
제한합니다. 환경
allowlist, 빈 cwd, read-only sandbox, shell 비활성화, timeout과 출력 검증을
fail-closed로 적용합니다. 인증에는 실제 CODEX_HOME만 사용합니다. 구현·회귀와
Git object 검증 명령은 Retrobot 문서에 있습니다.
이후 제품은 다음 한 줄로 실행합니다.
uv sync --locked && docker compose up -d --wait db && uv run officeagentAPI를 중지한 뒤 docker compose down으로 PostgreSQL 컨테이너를 종료할 수 있습니다.
기본 15432 port가 사용 중이면 실행 전에 OFFICEAGENT_DB_PORT와
OFFICEAGENT_DATABASE_URL의 port를 같은 값으로 설정합니다.
uv run officeagent가 startup migration을 확인하고 기본 127.0.0.1:8000에
bind합니다. 다른 host에 공개해야 할 때만 OFFICEAGENT_API_HOST를, port를
바꿀 때는 OFFICEAGENT_API_PORT를 명시적으로 설정합니다. 로컬 접속 주소는
http://127.0.0.1:8000, OpenAPI 문서는 /docs입니다.
첫 문서 업로드나 질의에는 FastEmbed 모델 다운로드가 필요할 수 있습니다.
최종 HEAD가 바뀌면 아래 actual-live 명령을 포함한 여덟 evidence profile을 모두 그 정확한 SHA에서 다시 실행합니다. 과거 live 결과나 docs-only 동등성은 현재 제출 증거로 승계하지 않으며, 최신 판정은 V2 Traceability가 소유합니다.
uv run python -m scripts.live_smoke이 명령은 repository 밖의 일회용 workspace와
officeagent_test_<12hex> database를 만듭니다. 로컬 postgres admin
database에서만 생성·migration·사용한 뒤 실패해도 삭제하므로 기존 제품
database의 문서나 cache를 읽거나 변경하지 않습니다. admin target의 host가
127.0.0.1, localhost, ::1 중 하나가 아니거나 database가
postgres가 아니면 실행 전에 실패합니다.
live 계약은 citation, miss → exact cache-key hit → 문서 update → miss, 두 miss의
복수 plaintext SSE delta와 구조화 응답 검증을 모두 확인합니다. 따라서 초기
miss와 update 후 miss에서 실제 Codex 구독 호출이 발생합니다. 출력 JSON은 검증된 codex --version과
상태·출처 metadata만 담고 모델 답변·작업 경로·DB conninfo는 제외합니다.
검색 문맥은 외부 Codex 서비스로 전송되므로 승인된 샘플로만 실행합니다.
외부 LLM 호출 전 최종 감사용 내부 readiness smoke는 다음 명령으로 실행합니다.
uv run python -m scripts.live_smoke --readiness-only이 모드는 repository 밖 workspace와 일회용 local PostgreSQL database에서 실제
Uvicorn HTTP /health/ready만 확인하고 정리 완료 뒤 credential-free JSON 한 줄을
출력합니다. 감사 runner는 repository의 ignored .env를 읽지 않고 database URL과
admin URL만 환경 override로 허용합니다. Codex version, 샘플 문서와 질문·LLM
endpoint는 호출하지 않습니다.
문서 업로드:
curl -F "file=@sample-docs/company-policy.txt;type=text/plain" \
http://127.0.0.1:8000/v1/documents실시간 SSE:
curl -N -H "Content-Type: application/json" \
-d '{"question":"직무 관련 교육비의 연간 지원 한도는?"}' \
http://127.0.0.1:8000/v1/questions/stream비스트리밍 JSON:
curl -H "Content-Type: application/json" \
-d '{"question":"직무 관련 교육비의 연간 지원 한도는?"}' \
http://127.0.0.1:8000/v1/questionsDB·migration·pgvector readiness:
curl http://127.0.0.1:8000/health/ready기본 성공 응답은 credential 없이 status=ready, migration_head=0003,
vector_version=0.8.6만 반환하고,
DB·migration·pgvector 검사가 실패하거나 기본 5초 bound를 넘으면 내부 예외를 숨긴
503을 반환합니다. Codex 로그인과 LLM 호출은 readiness 조건이 아닙니다.
Fresh-run 감사가 OFFICEAGENT_READINESS_INSTANCE_NONCE에 64자 소문자 hex
상관관계 토큰을 지정한 경우만 응답에 instance_nonce를 추가합니다. 미지정
시 기존 3필드 계약이 유지되며, 이 값은 credential이 아닌 일회성 감사
식별자로서 로그와 오류에는 기록하지 않습니다.
SSE 이벤트 순서는 다음과 같습니다.
answer.started
answer.delta
answer.citation
answer.completed
실패가 stream 시작 뒤 발생하면 answer.error로 종료합니다. 모든 이벤트에는 같은
request_id가 있으며 started/completed에서 cache_hit, cache_match,
cache_written, cache_skip_reason을 확인할 수 있습니다.
answer.delta는 provisional이며 client는 answer.completed를 받아야 성공 답변으로
확정할 수 있습니다. 이미 받은 delta는 후속 오류 때 회수되지 않습니다.
answer.citation은 score gate와 prompt proxy budget을 통과한 검색 청크의 retrieval
provenance입니다. 모델이 모든 후보 청크를 사용했거나 각 생성 문장이 citation에
의해 entail된다는 검증은 아닙니다.
application service가 실행된 각 upload·JSON question·SSE question은 terminal
timing receipt를 한 번 만들고, 기본 logger는 이를 officeagent.pipeline_timing JSON
한 줄로 내보냅니다. timing payload에는 UUID request ID, operation/outcome, 실행된
stage의 millisecond duration, total, 제한된 cache/answer path와 오류 type만 있습니다.
질문, filename, 문서·prompt·answer, citation, DSN과 exception message는 payload에
넣지 않습니다. perf_counter_ns() 차이로 재므로 wall-clock 변경의 영향을 받지
않으며 LLM stage는 upstream delta를 기다린 시간만, total은 stream consumer가 일시
중단한 시간까지 포함한 pipeline wall time입니다. sink 실패 시 제품 결과를 보존해
receipt가 유실될 수 있으며, 이 log는 latency SLO나 성능 우위의 증거가 아닙니다.
| 관심사 | What | Why | How / Trade-off |
|---|---|---|---|
| 웹/API | FastAPI + async use case | HTTP/SSE와 application 규칙 분리 | 얇은 route지만 host Codex와 DB 두 runtime이 필요 |
| 추출·청킹 | pypdf + UTF-8 TXT/MD + tiktoken o200k_base proxy |
세 형식의 page/offset과 page-safe 이중 상한 | 기본 900자(code point)·900 proxy token, 150자 overlap; OCR·grapheme·semantic 경계는 비범위 |
| 임베딩 | FastEmbed 다국어 MiniLM 384차원 | 한국어 로컬 추론과 API-key 불필요 | 최초 모델 다운로드와 CPU 비용 |
| 저장·검색 | PostgreSQL 17.10 + pgvector 0.8.6 + Psycopg 3 | document/vector/cache/revision을 한 transaction에 유지 | Docker·migration 운영비, 단일 노드 |
| 캐시 | exact 우선, cosine similar 0.95, 세 version identity |
설정 변경 후 stale answer 재사용 방지 | cache reuse 감소, active row soft invalidation |
| prompt 크기 | tiktoken o200k_base proxy, 기본 4096 |
완성 prompt가 무제한 커지는 경로 제한 | Codex의 정확한 token/context 보장은 아님 |
| LLM | Codex App Server outputSchema + incremental decoder |
ChatGPT 구독 응답을 검증하고 plaintext SSE 유지 | host Node/Codex 로그인과 로컬 decoder 경계 의존 |
| 재현성 | digest-pinned DB image + isolated test database + hosted quality gate | evaluator와 CI의 검증 순서 고정 | API/Codex는 credential 격리를 위해 host 유지 |
배운 점은 기술 개수보다 실패 경계를 줄이는 것이 중요하다는 것입니다. SQLite+Chroma의 두 저장·복구 경계를 PostgreSQL transaction 하나로 줄였고, 성능 우위나 vendor SLA는 측정·계약 없이 주장하지 않습니다.
answer_cache는prompt_version,embedding_version,retrieval_version을 저장합니다.- exact/similar hit는 active row와 세 현재 version이 모두 일치할 때만 허용합니다.
PROMPT_TEMPLATE_VERSION의 단일 정본은src/officeagent/application/prompts.py입니다. 제품 cache의 effective prompt version은 template, tokenizer proxy identity digest와 input budget을 함께 묶습니다.- 제품 chunker는 page를 넘지 않고 Python 기준 900 Unicode code point와 900
tiktoken
o200k_baseproxy token을 모두 넘지 않는 경계를 선택하며, overlap은 150자로 계산합니다. 이는 semantic chunking이나 정확한 Codex tokenizer 계약이 아닙니다. - chunking policy ID는 algorithm, 문자·proxy-token 상한, overlap과 tokenizer
identity를 digest하고 retrieval cache identity에 포함됩니다. 동일한
filename·bytes도 저장된 policy와 다르면
UPDATED로 재청킹하고 active answer cache 전체를 무효화합니다. - chunk tokenizer의 load·prefix 산출이 실패하면 embedding·DB commit 전에
fail-closed하고 API는 내부 경로나 예외 메시지를 숨긴
502를 반환합니다. - score gate를 통과한 hit는 완성 prompt를 proxy로 셌을 때 들어가는 순서대로만
선택합니다. 하나도 들어가지 않으면 Codex와 cache를 호출하지 않고
cache_skip_reason="prompt_budget_exceeded"로 기권합니다. 일부만 들어가면 선택한 hit로 답하되 제외된 dependency를 숨긴 cache가 생기지 않도록cache_skip_reason="prompt_evidence_reduced"로 cache write를 생략합니다. - question, evidence text와 metadata는 하나의 JSON untrusted-data envelope로
직렬화하고
<,>,&를 JSON escape합니다. - delimiter breakout 회귀는 구조적 serialization을 증명하며 prompt injection의 의미적 완전 차단을 뜻하지 않습니다.
- Codex에는
{"answer": string}한 필드outputSchema를 요청합니다. 전용 incremental decoder만 JSON 문자열을 해석하고 client에는 answer text만 보냅니다. - 완료 시 전체 JSON을 중복 key까지 다시 검사합니다. malformed/incomplete/blank, NUL, 추가 field와 trailing data는 성공 완료·citation·cache write로 이어지지 않습니다.
- answer 65,536자, raw structured JSON 1,048,576자와 stdio line 8 MiB는 upstream 보장이 아니라 이 구현의 bounded-memory 정책입니다.
| 파일 | 실제 경계 |
|---|---|
tests/test_v2_offline_paths.py |
in-process FastAPI ASGI TXT/PDF 수집·SSE, parser, PostgreSQL/pgvector RAG, exact/similar cache, 갱신 무효화 |
tests/test_postgres_corpus_store.py |
transaction rollback, ready corpus, cache version, chunking/index-policy reupload, revision guard·동시성 |
tests/test_parsers_and_chunking.py |
page/offset, valid code-point 문자·proxy-token 이중 상한, policy/retrieval digest |
tests/test_migrations.py |
empty DB, 재실행, checksum/history fail-closed, rollback, advisory lock, 0002/0003 legacy backfill |
tests/test_test_container_isolation.py |
Node/Codex/API key/token/.codex 부재와 disposable effective libpq database target |
tests/test_prompts.py |
JSON round-trip, question/evidence/metadata delimiter breakout, version SSOT |
tests/test_prompt_packing.py |
완성 prompt proxy budget, ranked skip/keep, 선택 citation/cache와 budget 기권 |
tests/test_codex_protocol.py |
output schema, incremental JSON decoding, item binding, Unicode, timeout/retry와 invalid-output fail-closed |
tests/test_streaming.py |
malformed output의 SSE error·JSON 502·no-cache와 live/cache text parity |
tests/test_live_smoke.py |
disposable local DB, live citation/cache/update 전이, sanitized receipt의 offline 계약 |
tests/test_validate_documentation.py |
CI action pin·순서·secret 금지와 evaluator 문서 링크·상태 drift |
tests/test_timing_observability.py |
V1/V2·QA stage timing, cache/no-evidence/error/cancel, privacy와 recorder 장애 격리 |
tests/test_evaluation_*.py |
gold hash·승인·split, lexical metric, product boundary와 disposable local DB 격리 |
tests/test_postgres_recovery_drill.py |
local-only Docker target, credential 차단, 논리 복원/PITR 구분, target 경계와 cleanup 계약 |
tests/test_postgres_ha_drill.py |
local async streaming, route·fence·manual promotion, tmpfs passfile와 scoped cleanup 부재 증명 |
| 기존 V1 adapter tests | SQLite/Chroma 기준선 회귀; V2 제품 증거와 구분 |
evals/gold/v1은 실제 sample-docs와 byte-for-byte로
같은 dev corpus의 15건, 별도 합성 process-holdout corpus의 15건을 가집니다. 각
split은 answerable 10건과 문서 주제는 가깝지만 정답 사실이 없는
retrieval_negative 5건으로 구성됩니다. manifest가 case와 corpus bytes를 고정하고
두 split의 현재 dataset SHA는
2d5ddc3b03507618026c3126f5bffa8e53dad0f9e185cea2d558bc32efc6cd43입니다.
approval.json은 지원자가 검토한 위 exact hash를 approved로 고정합니다. 이는
데이터셋의 사람 채택을 뜻하지만 공개 holdout을 blind benchmark로 만들거나 아직
실행하지 않은 품질 결과와 제품 기본값을 정당화하지는 않습니다. metric은 retrieval
hit/MRR, lexical answer·citation claim coverage와 exact abstention입니다. lexical
coverage는 semantic entailment, NLI 또는 factuality 판정이 아닙니다.
실제 평가 CLI는 선택한 split마다 loopback PostgreSQL에 무작위 disposable database를
생성하고 migration 뒤 empty corpus를 확인하며 성공·실패 모두에서 삭제합니다. 실제
run은 선택한 평가 질문과 검색 문맥을 로컬 인증 Codex App Server에 보내고 사용자
구독을 사용합니다. CI와 이 변경의 검증은 --verify-only와 fake service 경계만
실행하며 실제 Codex 평가를 수행하지 않습니다. 실행·승인 절차와 exit code는
Gold set v1이 소유합니다.
host의 빠른 unit/legacy 회귀는 DB test를 skip합니다.
uv run pytest
uv run ruff check src tests scripts공식 PostgreSQL 경로는 위 Docker 한 줄 명령입니다.
모든 환경 변수는 OFFICEAGENT_ 접두사를 사용합니다.
| 변수 | 기본값 |
|---|---|
OFFICEAGENT_API_HOST |
127.0.0.1 |
OFFICEAGENT_API_PORT |
8000 (valid range 1..65535) |
OFFICEAGENT_DATABASE_URL |
postgresql://officeagent:…@127.0.0.1:15432/officeagent |
OFFICEAGENT_DATABASE_ADMIN_URL |
unset; live smoke만 로컬 product URL에서 postgres target을 유도 |
OFFICEAGENT_READINESS_TIMEOUT_SECONDS |
5 (maximum 30) |
OFFICEAGENT_MAX_UPLOAD_BYTES |
20,971,520 (20 MiB) |
OFFICEAGENT_CHUNK_SIZE / OFFICEAGENT_CHUNK_OVERLAP |
900 / 150 |
OFFICEAGENT_RETRIEVAL_LIMIT |
5 |
OFFICEAGENT_MINIMUM_RELEVANCE_SCORE |
0.30 |
OFFICEAGENT_CACHE_SIMILARITY_THRESHOLD |
0.95 |
OFFICEAGENT_PROMPT_INPUT_TOKEN_BUDGET |
4096 (tiktoken o200k_base proxy; valid range 512..65536) |
OFFICEAGENT_CODEX_FIRST_DELTA_TIMEOUT_SECONDS |
45 |
OFFICEAGENT_CODEX_OVERALL_TIMEOUT_SECONDS |
120 |
OFFICEAGENT_CODEX_MAX_CONCURRENT_REQUESTS |
2 |
900/150/0.30은 현재 구현의 초기 기본값입니다. 900은 chunk의
Unicode code-point 상한과 o200k_base proxy-token 상한에 같이 적용되고
150은 code-point overlap입니다. grapheme cluster 경계는 보장하지 않습니다.
gold v1 데이터셋은 사용자가 exact SHA를 승인했지만 실제 Codex evaluator는
실행하지 않았으므로, 이 값이 품질셋에서 최적화됐거나 기존 설정보다
우수하다고 주장하지 않습니다.
0002 migration은 기존 row의 chunking_version을
legacy-page-safe-character-v1:unknown-settings로, 0003은 indexing_version을
legacy-document-index-v1:unknown-settings로 표시합니다. 둘 다 기존 chunk와 cache
dependency를 보존하며 배경 재색인은 하지 않습니다. 같은 filename과 bytes를 다시
업로드해도 content hash, chunking policy, embedding을 포함한 indexing policy가 모두
같아야 UNCHANGED입니다. domain policy는 indexing ID를 chunking ID와 cache의 embedding
version에서 한 번만 계산합니다. 원래 identity 문자열은 저장하지 않지만 digest를
비밀화 수단으로 취급하지 않습니다.
chunking policy가 다르면 UPDATED로 재청킹하고, chunking은 같지만 indexing policy가
다르면 새 embedding으로 재색인합니다. 두 경로 모두 active answer cache를 전체
무효화합니다. 설정 변경 뒤 legacy row를 현재 policy로 이관하려면 각 파일을 같은
filename으로 명시적으로 재업로드해야 합니다.
DB port는 기본 127.0.0.1:15432에만 공개됩니다. migration 상태 검사는 다음
명령으로 수행합니다.
docker compose run --rm migrate officeagent-migrate --checkcurrent-SHA 실행 결과와 요구사항별 판정은 V2 Traceability에서 한 번만 관리합니다.
- timing log는 구현했지만 benchmark·단계별 성능 gate는 아직
PLANNED - 이미지 PDF OCR, 문서 삭제 API, 사용자별 corpus, automatic failover와 production HA
- backup schedule·보존·off-host copy·암호화·monitoring과 production RPO/RTO
- 동일 질문 cache miss single-flight, semantic answer-level entailment verifier와 정확한 Codex tokenizer/context headroom 계산
상세 근거: