review(p9-fb-18): 회차 1 nit 반영
- `App::build_retriever(mode) -> Result<Arc<dyn Retriever>>` 추출. `ask` 와 `ask_with_session` 모두 사용. 35+ 줄 retriever stack 중복 제거 — 미래 retriever 변경이 한 곳만. - V005 migration `chat_sessions.sql` 의 `citations_json` doc 수정: `Vec<Citation>` → `Vec<AnswerCitation>` (실제 stored type 과 일치). AnswerCitation 가 marker + Citation 등 포함하므로 deserialize 시 type mismatch 회피. 15 app lib + 9 store chat_sessions + clippy 통과. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -254,7 +254,20 @@ impl App {
|
|||||||
/// Run a RAG `ask` against the configured retriever + LLM. Reuses
|
/// Run a RAG `ask` against the configured retriever + LLM. Reuses
|
||||||
/// the memoized embedder / vector / LLM where applicable.
|
/// the memoized embedder / vector / LLM where applicable.
|
||||||
pub fn ask(&self, query: &str, opts: AskOpts) -> Result<Answer> {
|
pub fn ask(&self, query: &str, opts: AskOpts) -> Result<Answer> {
|
||||||
let retriever: Arc<dyn Retriever> = match opts.mode {
|
let retriever = self.build_retriever(opts.mode)?;
|
||||||
|
let llm = self.llm()?;
|
||||||
|
let pipeline =
|
||||||
|
RagPipeline::new(self.config.clone(), retriever, llm, self.sqlite.clone());
|
||||||
|
pipeline.ask(query, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// p9-fb-18: shared retriever-stack builder used by [`Self::ask`]
|
||||||
|
/// and [`Self::ask_with_session`]. Lexical mode uses the FTS5
|
||||||
|
/// retriever directly; vector / hybrid require embeddings (and
|
||||||
|
/// surface the same "switch to --mode lexical" error from
|
||||||
|
/// [`Self::require_embeddings`] when disabled).
|
||||||
|
fn build_retriever(&self, mode: SearchMode) -> Result<Arc<dyn Retriever>> {
|
||||||
|
Ok(match mode {
|
||||||
SearchMode::Lexical => Arc::new(LexicalRetriever::with_settings(
|
SearchMode::Lexical => Arc::new(LexicalRetriever::with_settings(
|
||||||
self.sqlite.clone(),
|
self.sqlite.clone(),
|
||||||
lexical_index_version(&self.config),
|
lexical_index_version(&self.config),
|
||||||
@@ -292,12 +305,7 @@ impl App {
|
|||||||
)) as Arc<dyn Retriever>;
|
)) as Arc<dyn Retriever>;
|
||||||
Arc::new(HybridRetriever::new(&self.config, lex, vec_retr))
|
Arc::new(HybridRetriever::new(&self.config, lex, vec_retr))
|
||||||
}
|
}
|
||||||
};
|
})
|
||||||
|
|
||||||
let llm = self.llm()?;
|
|
||||||
let pipeline =
|
|
||||||
RagPipeline::new(self.config.clone(), retriever, llm, self.sqlite.clone());
|
|
||||||
pipeline.ask(query, opts)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// p9-fb-18: ask under a persistent chat session. Loads the
|
/// p9-fb-18: ask under a persistent chat session. Loads the
|
||||||
@@ -353,46 +361,9 @@ impl App {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Build the retriever stack the same way `ask` does.
|
// p9-fb-18 R1: shared retriever builder removes the prior
|
||||||
let retriever: Arc<dyn Retriever> = match opts.mode {
|
// copy of `ask`'s 35-line stack — see [`Self::build_retriever`].
|
||||||
SearchMode::Lexical => Arc::new(LexicalRetriever::with_settings(
|
let retriever = self.build_retriever(opts.mode)?;
|
||||||
self.sqlite.clone(),
|
|
||||||
lexical_index_version(&self.config),
|
|
||||||
self.config.search.snippet_chars,
|
|
||||||
)),
|
|
||||||
SearchMode::Vector => {
|
|
||||||
let (emb, vec_store) = self.require_embeddings()?;
|
|
||||||
let vec_iv = vector_index_version(emb.as_ref());
|
|
||||||
let vec_dyn: Arc<dyn VectorStore + Send + Sync> = vec_store;
|
|
||||||
let emb_dyn: Arc<dyn Embedder> = emb;
|
|
||||||
Arc::new(VectorRetriever::with_settings(
|
|
||||||
vec_dyn,
|
|
||||||
emb_dyn,
|
|
||||||
self.sqlite.clone(),
|
|
||||||
vec_iv,
|
|
||||||
self.config.search.snippet_chars,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
SearchMode::Hybrid => {
|
|
||||||
let lex = Arc::new(LexicalRetriever::with_settings(
|
|
||||||
self.sqlite.clone(),
|
|
||||||
lexical_index_version(&self.config),
|
|
||||||
self.config.search.snippet_chars,
|
|
||||||
)) as Arc<dyn Retriever>;
|
|
||||||
let (emb, vec_store) = self.require_embeddings()?;
|
|
||||||
let vec_iv = vector_index_version(emb.as_ref());
|
|
||||||
let vec_dyn: Arc<dyn VectorStore + Send + Sync> = vec_store;
|
|
||||||
let emb_dyn: Arc<dyn Embedder> = emb;
|
|
||||||
let vec_retr = Arc::new(VectorRetriever::with_settings(
|
|
||||||
vec_dyn,
|
|
||||||
emb_dyn,
|
|
||||||
self.sqlite.clone(),
|
|
||||||
vec_iv,
|
|
||||||
self.config.search.snippet_chars,
|
|
||||||
)) as Arc<dyn Retriever>;
|
|
||||||
Arc::new(HybridRetriever::new(&self.config, lex, vec_retr))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let llm = self.llm()?;
|
let llm = self.llm()?;
|
||||||
let pipeline =
|
let pipeline =
|
||||||
RagPipeline::new(self.config.clone(), retriever, llm, self.sqlite.clone());
|
RagPipeline::new(self.config.clone(), retriever, llm, self.sqlite.clone());
|
||||||
|
|||||||
@@ -25,9 +25,10 @@
|
|||||||
-- max_context_tokens that produced the session so a retroactive
|
-- max_context_tokens that produced the session so a retroactive
|
||||||
-- answer-quality regression can be re-traced.
|
-- answer-quality regression can be re-traced.
|
||||||
--
|
--
|
||||||
-- * `citations_json` carries `Vec<Citation>` so the answer can be
|
-- * `citations_json` carries `Vec<AnswerCitation>` (per p9-fb-18) —
|
||||||
-- redisplayed with the same citation markers a future session
|
-- each AnswerCitation holds a `Citation` plus `marker`, so the
|
||||||
-- sees on resume.
|
-- answer can be redisplayed with the same citation markers a
|
||||||
|
-- future session sees on resume.
|
||||||
--
|
--
|
||||||
-- * `INTEGER` timestamps (unix epoch seconds) — same convention the
|
-- * `INTEGER` timestamps (unix epoch seconds) — same convention the
|
||||||
-- rest of the schema uses (P1-7 baselines this).
|
-- rest of the schema uses (P1-7 baselines this).
|
||||||
|
|||||||
Reference in New Issue
Block a user