fix(memory): 冷启动放宽改为一次性 + 试算轮区分「没候选」与「向量不可用」
review round1 的 p1/p2 收口(commit 5967272 之后)。
p1:旧实现 `warmed` 只在 2xx 之后才翻 ⇒ 注释里写的「只在第一次成功响应之前」
实际是「服务坏着的全部时间」。reviewer 实测「接受连接但永不回包」时**每次**调用
都等满 30s(fail-fast 变 fail-slow):审查 20s 预算被一次吃光、索引写入拖成
8×30s、开机探针阻塞 30s。
- `warmupLeft` 改为**一次性许可**(CompareAndSwap 取走即失效,成败都算花掉)
⇒ 挂死时只有第一个请求慢一次,此后一律 DefaultRequestTimeout。
- `warmupTimeout` 30s → 8s:与常态 5s 同一量级(≤2×),且严格小于审查总预算
20s(一次冷启动不许吃光整轮);两条界都由 TestDefaultRequestTimeout 守住。
- 放宽被花掉且没成功时留一条 WARN(事后可复核「第一个请求」这个判据)。
- 更正两处自述:api.go 的「不会被 30s 拖住」与 budget.go 的不变式说明(批次形状
永远按稳态超时推导;冷启动只放宽第一个请求的截止时刻)。
- p2:删掉零调用者的 `WithRequestTimeout` —— 单次超时只允许改常量,批次上限与它
同源并由编译期/常量断言复核。
p2:试算轮在向量源不可用时 `RecallMode` 与「没有候选可比」同为空串。
- `recallLedger` 增 `unavailable` 计数 + `noteUnavailable()`(strictRecall 失败
那一笔记一笔);试算汇总行新增 `recall_unavailable_partitions`,**成败都记**。
- 不扩 `recallMode` 取值集合:失败那一路不序列化 result(响应是
500 tidy_recall_unavailable),新取值只会出现在日志里却要动一次契约,不划算。
测试:三种失败形态 × 两次调用的耗时断言(连接被拒 / 500 / 永不回包),
试算轮的「不可用」与「没候选」两态日志断言;两处变异自证(warmupTimeout 调回
30s ⇒ TestDefaultRequestTimeout 红;去掉 noteUnavailable ⇒ 试算汇总行退化成
recall_mode="" + recall_unavailable_partitions=0)。
This commit is contained in:
1 parent
59672720bd
commit
6c30ca540a
7 files changed
+273
-72
No files matched your search
@@ -45,6 +45,16 @@ type recallLedger struct {
|
||||
// embedder」那种配置形态)。它把「没候选」(label 为空串)与「向量不可用」
|
||||
// (label 为 lexical 且 degraded > 0)分开 —— 这两件事在运维上不是一回事。
|
||||
degraded int
|
||||
// unavailable 是**尝试过召回但向量源不可用、且本轮不降级**(试算轮的严格口径)
|
||||
// 的分区数。它与 degraded 的区别是「有没有改用词项余弦」:生产轮会降级
|
||||
// (degraded),试算轮只报错。
|
||||
//
|
||||
// 🔴 它存在的理由(reviewer round1 的 p2):试算轮在向量源不可用时
|
||||
// `RecallMode` 与「没有候选可比」**同为空串**,两者在那个字段上分不开。
|
||||
// 现在 provenance 由 unavailablePartitions() 单独给出,日志行能区分;
|
||||
// 调用方(面板)那条路本来就有明确错误码(500 tidy_recall_unavailable),
|
||||
// 因此**没有**为此扩 recallMode 的取值集合(见 logDryRun 的说明)。
|
||||
unavailable int
|
||||
}
|
||||
|
||||
// noteEmbedding 记一笔「这个分区真的用了语义 embedding」。
|
||||
@@ -66,10 +76,22 @@ func (l *recallLedger) noteLexical(degraded bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// noteUnavailable 记一笔「这个分区尝试召回但向量源不可用,且本轮没有降级」
|
||||
// (试算轮的严格口径:宁可报错,也不把「没算出来」说成「算过了,没有」)。
|
||||
func (l *recallLedger) noteUnavailable() {
|
||||
if l != nil {
|
||||
l.unavailable++
|
||||
}
|
||||
}
|
||||
|
||||
// label 返回本轮**实际**的召回来源:
|
||||
// - "":没有任何分区真正算过相似度(没有候选可比)—— 「没候选」不是「降级」;
|
||||
// - embedding / lexical:所有算过的分区都走同一条路;
|
||||
// - mixed:两种都有(多分区里有一部分降级)。
|
||||
//
|
||||
// ⚠️ 「尝试过但不可用」**不改变** label:它没有产出任何相似度,报 embedding /
|
||||
// lexical 都是假的;它的存在由 unavailablePartitions() 单独给出(见 recallLedger
|
||||
// 的 unavailable 字段说明)。
|
||||
func (l *recallLedger) label() string {
|
||||
if l == nil {
|
||||
return ""
|
||||
@@ -94,6 +116,14 @@ func (l *recallLedger) degradedPartitions() int {
|
||||
return l.degraded
|
||||
}
|
||||
|
||||
// unavailablePartitions 返回本轮「尝试召回但向量源不可用、且没有降级」的分区数。
|
||||
func (l *recallLedger) unavailablePartitions() int {
|
||||
if l == nil {
|
||||
return 0
|
||||
}
|
||||
return l.unavailable
|
||||
}
|
||||
|
||||
// tidyPair 是一条被召回的候选对。
|
||||
type tidyPair struct {
|
||||
a, b MemoryItem
|
||||
|
||||
Reference in new issue
Block a user