spec(p9-fb-15): RAG multi-turn 정책 + answer.v1 conversation_id/turn_index #59
Reference in New Issue
Block a user
Delete Branch "spec/p9-fb-15-multi-turn-ask"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
도그푸딩 항목 13 (ask 의 꼬리 물기) — multi-turn surface 의 frozen design + wire schema spec PR. 후속 4 impl PR (p9-fb-15 RAG core / p9-fb-16 TUI UI / p9-fb-17 V004 chat sessions / p9-fb-18 CLI session/repl) 의 contract.
변경
Frozen design §3.8
Answerstruct 에 두 optional field:conversation_id: Option<String>,turn_index: Option<u32>.Turnstruct 신설 (history 가 prompt 에 들어갈 때 한 turn).kebab-rag::ask(single-shot, 기존) vsask_with_history(multi-turn) 두 entry.system + new_question(필수) → retrieved chunks (k 줄여 fit) → history (newest 우선, oldest drop).grounded=false+ newLlmStreamAbortedrefusal_reason variant (impl PR 에서 함께 추가).Wire schema §2.3 (
answer.v1)기존 single-shot 소비자 (외부 wrapper / Claude Code skill / MCP) 영향 0 — 두 필드 모두 optional, default null.
Out of scope (impl PR 들에서 처리)
kebab-rag::ask_with_historyimpl + token budget enforcement → p9-fb-15Answer::conversation_id / turn_index채움 + RAG facade signature → p9-fb-15--session/--repl→ p9-fb-18Test plan
코드 변경 없음. doc + JSON Schema 만.
answer.v1와 backward-compat (두 새 필드 optional)도그푸딩 후 추가된 ask multi-turn (꼬리 물기) surface 를 frozen design + wire schema 에 명시. p9-fb-15 (RAG core) + p9-fb-16 (TUI UI) + p9-fb-17 (V004 chat sessions) + p9-fb-18 (CLI session/repl) 의 spec PR — impl PR 들이 이어진다. 변경: - §2.3 Answer wire schema: conversation_id (String?) + turn_index (u32?) 두 optional 필드. 기존 single-shot 소비자 (외부 wrapper) 영향 없음 — 두 필드 모두 optional. - §3.8 RAG types: - Answer struct 에 conversation_id / turn_index field 추가. - Turn struct 신설 (history 가 prompt 에 들어갈 때 한 turn). - §3.8 \"Multi-turn behaviour\" 신설 절: - kebab-rag::ask vs ask_with_history 두 entry. - prompt 빌드 priority: system+question (필수) → retrieved chunks (k 줄여 fit) → history (newest 우선, oldest drop). - retrieval query expansion (직전 answer 첫 200자 concat). - Aborted vs Completed semantics — ask 는 single-shot 이라 cancel 시 partial token + grounded=false + LlmStreamAborted refusal (variant 추가는 p9-fb-15 impl 가 함께). - docs/wire-schema/v1/answer.schema.json: 두 필드 추가 + created_at 에 format: date-time (sibling ingest_progress.v1 와 일관). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>회차 1 — formatting nit 1건 + RefusalReason variant 미정의 1건 + 칭찬 3건.
핵심 actionable:
Aborted vs Completed semantics절 끝 빈 줄 2 → 1.RefusalReasonenum 에LlmStreamAbortedvariant 추가 — 본 spec PR 이 self-contained 가 되어야 p9-fb-15 impl PR 이 spec 변경 없이 진행 가능.총평: 두 optional 필드의 backward-compat / prompt 빌드 priority 의 trade-off 명시 / ingest vs ask cancel semantics 비교 — spec 본문이 미래 review 부담을 사전 차단. 위 actionable 2 건만 정리하면 머지.
(칭찬) 두 optional 필드 (
conversation_id/turn_index) backward-compat 명시 — "두 필드 모두 optional 이라 기존answer.v1소비자 (외부 wrapper) 영향 없음. multi-turn 모르는 wrapper 는 그냥 무시". external integration (Claude Code skill / MCP) 의 회귀 안전 보장이 spec 옆에서 명시. wire schema 의["string", "null"]/["integer", "null"]와 일치.(칭찬) prompt 빌드 priority 의 명확한 3 단 + 이유 한 줄.
system+question(필수) →retrieved chunks(k 줄여 fit) →history(newest 우선, oldest drop). 이유 명시: "history 의 가치는 보통 직전 1~2 turn 이 가장 큼. 오래된 turn 이 retrieved chunk 에 비해 marginal 가치라 trade-off 시 history 양보". 미래 reader 가 "왜 history 가 chunks 보다 후순위?" 의문 즉시 차단 — impl PR review 시 trade-off 설명 부담 ↓.(완전성 / RefusalReason variant 미정의) Multi-turn behaviour 절이
refusal_reason=Some(LlmStreamAborted)라는 variant 를 명시하지만 §3.8 의pub enum RefusalReason { ScoreGate, LlmSelfJudge, NoIndex, NoChunks }에 추가 안 함. spec PR 가 enum 까지 갱신해야 impl PR 가 spec 변경 없이 진행 가능 — frozen design contract 의 self-contained 원칙.Why: spec PR / impl PR 분리 룰의 핵심은 "impl PR 이 spec 변경 안 함". 새 variant 가 본 PR 안에 정의되어 있어야 p9-fb-15 impl PR 이 spec 무수정 진행 가능.
How to apply 두 가지 중:
pub enum RefusalReason { ScoreGate, LlmSelfJudge, NoIndex, NoChunks, LlmStreamAborted }로 같은 PR 에 추가 + wire schemarefusal_reasonenum 추가 (현재 freestring이라 새 값도 자동 통과 — wire 변경 불필요).(p9-fb-15 가 새 RefusalReason variant 또는 별 boolean field 로 처리)로 약화 + impl PR 이 spec 변경하지 않도록LlmStreamAborted명시 자체를 빼기.권장: 1 — variant 한 줄 추가가 가장 작은 surface.
(칭찬) ingest cancel 의 "Aborted =
Ok(IngestReport)정상 반환" semantics 와 ask cancel 의 "partial token +grounded=false+ refusal" semantics 의 차이를 spec 옆에서 구분. 두 surface 가 다른 contract 를 갖는 이유 (ingest = 부분 commit + idempotent re-run; ask = single-shot stream) 가 spec 의 같은 위치에서 비교 가능 — 미래 누군가 "왜 ingest 는 Ok 반환인데 ask 는 grounded=false?" 의문 즉시 답.(nit / 가독성)
Aborted vs Completed semantics절 끝에 빈 줄 2 줄 (+두 번 line 75-76 in diff). 한 줄이면 충분 — 다른 절 사이는 모두 1 줄.Why: markdown 자체 렌더링은 영향 없지만 raw spec 의 일관성 ↓. spec PR #51 머지 후속도 같은 nit 이 회차 1 에 잡혔던 이력 (
§10 long-running 절빈 줄 3→1).How to apply: 빈 줄 1 줄 제거.
회차 2 — RefusalReason::LlmStreamAborted variant 추가 + 빈 줄 정리. spec PR self-contained 원칙 정확. APPROVE.