ci / go (push) Waiting to run
ci / go-db (agent) (push) Waiting to run
ci / go-db (config) (push) Waiting to run
ci / go-db (db) (push) Waiting to run
ci / go-db (evidence) (push) Waiting to run
ci / go-db (llmrec) (push) Waiting to run
ci / go-db (server) (push) Waiting to run
detections / detections (push) Waiting to run
web / web (push) Waiting to run
docs / links (push) Canceled after 0s
61 lines
9.6 KiB
Markdown
61 lines
9.6 KiB
Markdown
# 곁질문 장문 대화와 컨텍스트 예산
|
|
|
|
한국어 · [中文](CONTEXT_BUDGET.zh.md)
|
|
|
|
2026-09-11 수정. 이전 구현은 요청 JSON 의 글자 수를 그대로 토큰 수로 간주했고 메인 작업의 32K 출력 예약량을 그대로 물려받았기 때문에, HTML·JS·도구 결과가 많을 때 정상적인 곁질문을 미리 거부하는 문제가 있었습니다.
|
|
|
|
> 이 문서는 원본 중국어 문서(`CONTEXT_BUDGET.zh.md`)를 한국어로 옮긴 것입니다. 상류(upstream) 저장소의 변경을 대조하기 쉽도록 원본은 그대로 보존합니다.
|
|
|
|
## 오픈소스 구현 대조
|
|
|
|
- [Grok CLI 곁질문 컨텍스트](https://github.com/superagent-ai/grok-cli/blob/fb97af83f06dca873281d60168430f06c8de6324/src/agent/agent.ts#L739): 가장 최근의 사용자·어시스턴트 텍스트에서 일부 조각을 발췌하며, 글자 예산은 약 2000 자이고 한 건당 최대 400 자까지 잘라냅니다. 이 경로에서는 연속된 곁질문 문답 기록을 유지하지 않습니다.
|
|
- [Grok CLI 독립 요청](https://github.com/superagent-ai/grok-cli/blob/fb97af83f06dca873281d60168430f06c8de6324/src/utils/side-question.ts): 취소 신호를 따로 둡니다. 모델이 지원하면 출력 상한은 2048 토큰입니다. 도구는 제공하지 않습니다.
|
|
- [Grok CLI 메인 세션 압축](https://github.com/superagent-ai/grok-cli/blob/fb97af83f06dca873281d60168430f06c8de6324/src/agent/compaction.ts): 토큰을 추정하고, 최근 내용을 남기고, 새 내용을 이전 요약에 반영하며, 턴 경계를 넘는 잘림을 처리합니다.
|
|
- [OpenCode 세션 압축](https://github.com/anomalyco/opencode/blob/b3f1a96c6dd7adeb28b36dd11add1998fc84d67b/packages/core/src/session/compaction.ts): 요청 전체를 추정하고, 출력·버퍼를 예약하며, 최근 내용에 롤링 요약을 더하고, 도구 없는 요약 요청을 보냅니다. 이 구현은 기본적으로 최근 예산 8000, 요약 출력 상한 4096 토큰을 씁니다.
|
|
- [OpenCode 오버플로 복구](https://github.com/anomalyco/opencode/blob/b3f1a96c6dd7adeb28b36dd11add1998fc84d67b/packages/core/src/session/runner/llm.ts): 어시스턴트 출력이 아직 시작되지 않았을 때만 오버플로 복구를 시도하고, 복구한 뒤의 호출은 같은 오버플로 복구 경로로 다시 들어가지 않습니다.
|
|
|
|
ARTEX 는 독립 출력 예산, 최근 내용과 롤링 요약, 제한된 복구라는 방식을 참고했습니다. norma v0.3.6 의 구조화 메시지와 도구 짝 맞추기는 그대로 유지하되 Grok 의 텍스트 발췌 방식은 그대로 가져오지 않았고, OpenCode 의 메인 세션 압축 이벤트를 ARTEX 메인 transcript 에 기록하지도 않습니다.
|
|
|
|
## 요청 예산과 실행
|
|
|
|
- 메시지는 norma 의 방식을 그대로 써서 내용 블록 단위로 UTF-8 바이트를 추정하고 4/3 여유분을 더합니다. 여기에 시스템 프롬프트, 도구 schema, 메시지 포장 오버헤드를 추가로 셈합니다. 이 추정값은 모델의 정확한 토큰 수가 아닙니다.
|
|
- 곁질문 출력은 기본적으로 최대 8192 토큰이며, 메인 설정에 이미 정해진 출력 상한도 넘지 않습니다. 서비스 환경 변수 `ARTEX_BTW_MAX_OUTPUT_TOKENS` 로 256–32768 범위의 상한을 설정할 수 있고, 제품 기본 모델이나 메인 작업 파라미터는 바꾸지 않습니다.
|
|
- 입력 예산은 컨텍스트 창에서 출력 상한과 안전 여유분을 뺀 값이며, 창 크기를 모를 때는 플랫폼 기본값인 200K 를 씁니다. 안전 여유분은 창의 5% 이고, 최소 128 토큰, 최대 8192 토큰입니다.
|
|
- 성공한 문답은 증가하는 순번에 따라 한 번에 최대 20 묶음까지 불러옵니다. 원문은 최대 20 묶음까지 남기며, 그 토큰 예산은 입력 예산의 1/4 이내이고 16K 를 넘지 않습니다.
|
|
- 예산을 넘긴 문답은 롤링 요약으로 반영합니다. 요약에는 출처 기록과 컨텍스트 시점을 함께 담습니다. 과거의 어시스턴트 답변은 새로운 도구 증거와 같지 않으므로, 충돌이 생기면 가장 최신 메인 스냅샷을 우선합니다.
|
|
- 메인 컨텍스트가 그래도 너무 길면 사본의 오래된 메시지만 요약하고 최근 내용은 최대 8K 토큰까지 남깁니다. 자르는 지점은 도구 호출과 그 결과를 쪼개지 않습니다. 하나의 묶음이 너무 크면 그 묶음 전체를 요약에 넣습니다.
|
|
- 요약 입력은 실제로 남은 창 크기에 맞춰 UTF-8 기준으로 안전하게 나누며, 출력 상한은 2048 토큰입니다. 빈 요약, 잘린 응답, 도구 호출, 요약 예산 초과는 모두 캐시에 쓰지 않습니다. 한 번의 곁질문에서 요약 호출은 최대 12 회이며 동일한 120 초 제한 시간을 함께 적용받습니다. 상한에 이르면 무한히 반복하지 않고 명확히 실패로 끝냅니다.
|
|
- 모델이 처음으로 컨텍스트 초과를 반환하고 아직 텍스트나 도구 호출을 내보내지 않았다면, 더 줄인 뒤 최대 한 번만 다시 시도합니다. 추정 크기가 줄지 않으면 복구를 즉시 멈춥니다. 그 밖의 모델 오류나 일부만 스트리밍된 출력은 이 복구를 일으키지 않습니다.
|
|
- 요약, 실패한 시도, 취소 시점의 사용량을 포함해 이미 집계된 모든 사용량은 같은 곁질문 요청에 누적합니다. Provider 가 사용량을 돌려주지 않으면 0 으로만 기록하며, 추정값을 실제 사용량인 것처럼 꾸미지 않습니다.
|
|
|
|
## 영속화와 화면
|
|
|
|
`side_question_sessions.memory` 에는 오래된 문답 요약, 반영된 순번(ordinal), 그리고 스냅샷 신원별로 캐시한 메인 컨텍스트 요약을 저장합니다. `side_question_requests.context_info` 에는 준비 단계, 실제로 다시 실은 묶음 수, 요약 사용 내역, 예산 추정값을 저장합니다.
|
|
|
|
요약은 원래 요청이 아직 실행 중이고 정리 버전이 일치할 때만 저장합니다. 비우기는 캐시도 함께 지우며, 뒤늦게 도착한 쓰기가 이미 정리된 데이터를 되살리지 않습니다. 새 스냅샷은 이전 스냅샷의 요약을 재사용하지 않습니다. 요약 필드는 v3 작업 아카이브와 함께 저장하며, 필드가 빠진 오래된 v3 를 복원할 때는 빈 객체로 채우고 v1·v2 는 계속 호환합니다.
|
|
|
|
POST 는 요청을 먼저 받아들여 돌려주고, 준비와 압축은 백그라운드에서 실행하며 수용 잠금(admission lock)이나 데이터베이스 트랜잭션을 쥐지 않습니다. SSE 와 기록 화면은 준비, 문답 정리, 사본 압축, 응답 단계를 표시합니다. 압축 실패는 해당 곁질문 요청의 실패 종료 상태로 저장합니다. 프런트엔드는 오류를 남기고 이번에 실패한 질문의 초안을 복구하며, 떠 있는 알림으로 입력창을 가리지 않습니다. 기록 폴링도 더 이상 제출 오류를 지우지 않습니다.
|
|
|
|
## 검증 기록
|
|
|
|
- 19·20·21·50 묶음 재생, 20 묶음을 넘는 오래된 결론 보존, 요약 캐시의 재시작 후 재사용: 자동화 통과.
|
|
- 아주 긴 중국어 답변과 코드 컨텍스트, 요청 예산 분할, 도구 짝 맞추기, 스냅샷 불변, 새 스냅샷의 캐시 무효화: 자동화 통과.
|
|
- 요약 실패·취소·잘림·초과 길이·도구 반환, 비우기 경쟁, 호출 상한, 단 한 번의 오버플로 복구와 일부 스트림 재시도 안 함: 자동화 통과.
|
|
- 독립 PostgreSQL 에서의 페이지 나누기, 재시작, v1·v2·v3 아카이브, 요약 캐시와 예산 메타데이터의 아카이브 복원, 새 필드가 없는 오래된 v3, 20 개 부모 세션이 네 개의 동시 실행 자리를 공유하는 경우: 통과.
|
|
- Go 후보 서비스 빌드, 프런트엔드 TypeScript 검사, 수정한 컴포넌트의 Biome 검사, 그리고 독립 디렉터리에서의 Next.js 프로덕션 빌드: 통과.
|
|
- 내장 브라우저로 독립 UI 픽스처를 써서 1280×720 과 390×844 해상도에서 문답 정리 단계, 요약 범위 안내, 실패 후 초안 복구, 떠 있는 오류 알림이 없는지, 가로 넘침이 없는지, 콘솔 오류가 없는지를 검증했습니다. 임시 픽스처는 제거했습니다.
|
|
- 로컬에 이미 있는 Worker 스냅샷을 읽기 전용으로 재생했을 때 새 예산 검사가 통과했습니다. 예를 들어 Worker #3 의 293085 자 스냅샷은 더 이상 로컬 글자 수 계산 때문에 잘못 거부되지 않습니다. 이 항목에는 외부 모델 호출이 없었습니다.
|
|
- 이번에 비공개 Worker 스냅샷을 Grok 으로 보내려던 실제 대화 테스트는 자동 승인 심사에서 거부되어 실행되지 않았으므로, 통과 항목으로 치지 않습니다.
|
|
- 2026-09-11 00:37 에 사용자 요청으로 로컬 백엔드를 재시작했고, 원래의 데이터베이스·데이터 디렉터리·로그인 설정을 그대로 썼습니다. 실행 파일과 후보 바이너리의 SHA-256 이 일치했고, 백엔드와 프런트엔드 프록시의 `/api/health` 가 모두 정상을 반환했습니다.
|
|
|
|
검증 명령(독립 테스트 DB 만 사용):
|
|
|
|
```sh
|
|
go test -race ./sidequestion ./db ./server -run 'TestSide|TestCheckpoint|TestSnapshot|TestBuildRequest|TestService|TestMainSide|TestTaskArchive' -count=1
|
|
go build ./cmd/artex
|
|
npx tsc --noEmit
|
|
npm run build -- --webpack
|
|
```
|
|
|
|
프런트엔드 프로덕션 빌드는 독립 사본을 써서 현재 미리 보기의 `.next` 를 덮어쓰지 않도록 했습니다. 후보 서비스는 `/private/tmp/artex-btw-budget-candidate` 에 있고, `/private/tmp/artex-btw-preview/artex` 로 복사해 실행했습니다. 원래 바이너리는 같은 디렉터리의 `artex.before-context-budget` 로 백업했습니다.
|