feat(runtime): 文档摄取①(抽取器 + sidecar + 装配期 resolveDocuments)(design/24 S3-A)
- 抽取器零新依赖纯函数:UTF-8 清洗、CSV/TSV 行数列名摘要、64K rune 安全截断;PDF/Office/二进制走哨兵错误诚实拒绝(不引解析库)。 - sidecar:<DataDir>/extracted/<存储名>.txt,首行紧凑 JSON 元数据 + 正文;临时文件 + rename 原子落定;只抽一次(删原文件仍出正文);版本不匹配/坏缓存重抽。 - 装配期 resolveDocuments(resolveImages 同位,每步对模型可见视图注入):清单恒在(解析器缺席/报错也在)、截断带续读游标、失败诚实标记 + status=unreadable、回合继续;文档部件永不抵达编码器(负例钉住)。 - 修 S2 移交的两处静默吞掉:checkpoint 比较键纳入文档引用、compactor token 估算计入文档部件(不是免费的)。 - 主会话独立验收:隔离 worktree(HEAD + 本切片)build/vet 绿、全树 59 包 0 FAIL、linux/amd64 + darwin/arm64 交叉编译绿、documents+loop 两包 167 条 PASS;变异独立复现(resolveDocuments 短路 ⇒ 3 条红,含「文档部件仍抵达下游」)。
This commit is contained in:
1 parent
834ef3683e
commit
a8851dc0a2
12 files changed
+2008
-7
No files matched your search
@@ -174,7 +174,7 @@ func findKeepStart(messages []model.Message, from, keepTokens int) int {
|
||||
}
|
||||
|
||||
// estimateContextTokens 返回 messages 的保守 token 估算。它是
|
||||
// 启发式(字符 ÷ charsPerToken,加上每条消息与每个图像的开销),
|
||||
// 启发式(字符 ÷ charsPerToken,加上每条消息、每个图像与每个文档的开销),
|
||||
// 因此无依赖且离线,但单调性足够驱动
|
||||
// 压缩决策。
|
||||
func estimateContextTokens(messages []model.Message) int {
|
||||
@@ -187,12 +187,37 @@ func estimateContextTokens(messages []model.Message) int {
|
||||
total += estimateStringTokens(part.Text)
|
||||
case model.ContentTypeImage:
|
||||
total += imageTokens
|
||||
case model.ContentTypeDocument:
|
||||
total += documentPartTokens(part)
|
||||
}
|
||||
}
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
// documentPartTokens 估算一个文档部件在装配后可能占用的 token。窗口里只有
|
||||
// 引用(design/24 §2.4),正文要等装配期才注入,因此这里按「原文件字节数
|
||||
// (UTF-8 文本下 ≈ 字符数),上限为注入预算」估算。
|
||||
//
|
||||
// 关键是文档部件**不是免费的**:只认 ContentTypeImage 的分支会让纯文档回合
|
||||
// 被估成 0 token,在压缩里等同于空内容(design/24 §9.5 移交的静默吞掉)。
|
||||
// 大文件(尤其在预算处截断注入、或压根读不到)会被这个估计偏高地计入,方向
|
||||
// 是「少放内容进上下文」——保守收紧,而不是溢出模型窗口。
|
||||
func documentPartTokens(part model.Content) int {
|
||||
chars := part.DocumentSize
|
||||
if chars > documentInjectedCharsCap {
|
||||
chars = documentInjectedCharsCap
|
||||
}
|
||||
if chars < 0 {
|
||||
chars = 0
|
||||
}
|
||||
t := int(chars) / charsPerToken
|
||||
if t < documentMinTokens {
|
||||
return documentMinTokens
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// estimateStringTokens 是单个文本字符串的字符级 token 估算,
|
||||
// 把宽字符(CJK)rune 计为双倍权重再除以 charsPerToken。空字符串
|
||||
// 不花费任何 token;非空至少花费一个 token。
|
||||
|
||||
Reference in new issue
Block a user