Repository Wiki
LYOfficial/OneDocs

分析计划、分块与进度管理

本文说明文档分析如何建立本地分段计划,以及当前 useAnalysis 全量章节管道如何切片、批处理并报告进度。两条路径使用不同的分块表示:不要把计划中的 ChunkPlan 误认为章节管道实际发送的 RAG 文本片段。

Purpose and Scope

本页聚焦 analysisWorkflow.ts 的计划与提示词辅助函数,及 useAnalysis.ts 中已读到的章节管道、批次进度与错误降级。文档提取、模型供应商配置、图片后处理、结果归档和 RAG 嵌入的内部实现属于相邻主题;这里仅解释它们与分块工作流接触的边界。特别注意:已读取的 useAnalysis 片段导入了图片辅助函数,而没有导入 buildLocalWorkflowPlan 或 buildChunkPlan;因此不能断言章节管道直接执行计划器。

Overview

计划辅助函数可按页文本建立 ChunkPlan[],以最多四页或累计至少 7000 字符为分段边界,页文本缺失时按字符长度退化切分;它还能把规划 JSON 与本地默认计划合并,并构造分段写作及最终整合提示词。另一方面,runSectionPipeline 调用 chunkText 产生更小的片段,对每个章节任务遍历全部片段,按字符预算打包送往模型;其进度由任务和批次位置推算,而非模型完成百分比。计划构建 · 章节管道。

Architecture

Loading diagram...

Sources: analysisWorkflow.ts, useAnalysis.ts

图上两组没有连接线:源码中确实存在计划、分段与合成辅助函数,但本次查看的章节管道直接使用 chunkText,并未展示调用这些计划函数。Parse 到两个提示词构造器的箭头表示计划数据可作为它们的参数,不表示已经证实有运行时调用链。章节管道的模型设置来自调用参数 settings,currentProvider 则取自 store。调用签名 · 模型调用。

计划生成与解析

本地计划与边界选择

buildLocalWorkflowPlan(bundle, fileName, fileType) 首先用 buildChunkPlan 生成分段,再按 bundle.images 形成 imagePlacementHints,每张图从对应页文本推断建议章节:含“例题/习题/答案”标作“典型例题”,否则标作“基础知识”。它生成概览以及保留定义、公式、图片和推导的完成要求。页数大于零时概览记录页数与段数,否则说明按字符分段。本地计划 · 章节推断。

buildChunkPlan 在 pageTexts 为空时直接转向文本回退;否则按页累积文本长度,并在页数达到 4、字符数达到 7000 或到达最后一页时封段。每段的起止页连续递增,图片页码从该范围内的 bundle.images 取得,关注点来自 inferChunkFocus;图片页码可能因多张同页图片重复出现(源码未去重)。字符阈值是封段触发条件,不是硬上限:一页超过阈值仍会作为完整页纳入该段。分段算法。

typescript
1const PAGE_IMAGE_TOKEN_PREFIX = "[[PAGE_IMAGE_"; 2const DEFAULT_PAGE_CHUNK_SIZE = 4; 3const DEFAULT_CHAR_CHUNK_SIZE = 7000; 4 5export const WORKFLOW_PLANNER_MODEL = "openai/gpt-oss-120b:free"; 6export const WORKFLOW_COMPOSER_MODEL = "minimax/minimax-m2.5:free";

Source: analysisWorkflow.ts

这两个模型常量在辅助模块中声明;在已读取的章节管道里,实际请求使用 settings.model,不能把这些常量当作该管道运行时的默认模型。模型请求。

文本退化切分与规划结果容错

splitTextIntoChunks(text, maxChunkLength = 7000) 先去首尾空白;空字符串返回 [],短文本返回单元素数组。长文本尝试在当前长度上限之前、且超过本段半个预算处的最后一个空段落处切开,否则直接按长度截断;每片再次 trim() 并忽略空片。buildTextFallbackChunkPlan 将每片转换为顺序编号的段,合成的 pageStart/pageEnd 是片段序号,并非真实页码。退化切分。

parseWorkflowPlan(content, fallbackPlan) 先剥除完整 Markdown 代码围栏,空文本直接返回回退计划;解析成功时合并顶层属性,并对 chunks、图片提示和完成要求作字段级回退/类型清洗;解析失败记录 console.warn 后返回回退计划。它对 pageStart/pageEnd 使用 Number(value) || fallback || 1,并没有在这些行进行页范围有序性或文档页数约束检查,调用方不应视之为严格验证器。解析逻辑 · 字段合并。

typescript
1 if (bundle.pageTexts.length === 0) { 2 return buildTextFallbackChunkPlan(bundle.text); 3 } 4 5 const chunks: ChunkPlan[] = []; 6 let startPage = 1; 7 let currentLength = 0;

Source: analysisWorkflow.ts

分段写作和整合提示词

buildChunkPrompt 接收源提示词、计划、当前段、当前文字、文件名及图片 token;提示模型只写当前页范围,保留原文专业术语、公式与例题步骤。includeImages 默认为 true,关闭时省略图片 token 提示。buildComposerPrompt 则收集所有段落结果,以 \n\n---\n\n 分隔,要求按顺序整合为 Markdown;打开图片选项时给出 token 到 localPath || dataUrl 的映射。这些是提示词构造器,是否被调用及最终模型行为取决于外部调用点。分段提示 · 整合提示。

Core Flow:全量章节管道与进度

Loading diagram...

Source: useAnalysis.ts

这里的 400/60/60 是传给 chunkText 的 targetChunkSize/overlapChars/minChunkSize,并不是 buildChunkPlan 的四页/7000 字符阈值;chunkText 的内部切割细节未在已读源码中核实。分块调用。

每个章节任务都取 effectiveChunks = allChunks,没有关键字过滤。管道先预计算批次数用于进度,再以相同的 MAX_CHARS_PER_BATCH = 8000 规则顺序打包;只有当前批非空时才溢出到下一批,因此单个超过 8000 字符的片段不会被此循环再次拆开。片段附带 [片段N(第X页)] 标记。批次提示中的图片标签仅根据这些页码标记选取同页图片,减少无关图片标签。全部片段 · 图片范围。

进度在嵌入阶段设置为 progressStart,章节起点从区间 [progressStart, progressEnd] 的 5% 处开始,每任务按 taskIdx / totalSteps 递进,批内按 batchIdx / max(totalBatches, 1) 在该任务对应进度区间插值。故进度显示是阶段/批次估算,而不是按完成 token 或最终字数计量。计算位置 · 批次插值。

Usage Examples:源码中的调用方式

以下示例均摘自现有实现;它们展示工作流内部的真实用法,而不是另外编造的外部调用程序。

基于文档内容生成待处理片段

typescript
1 const allChunks = chunkText(analysisBundle.text, analysisBundle.pageTexts, { 2 targetChunkSize: 400, 3 overlapChars: 60, 4 minChunkSize: 60, 5 });

Source: useAnalysis.ts

这一步只负责取得章节管道的片段集合。嵌入向量的生成可用时会尝试一次,但后续任务仍遍历 allChunks;嵌入失败仅记警告,不中断此处已读取的流程。嵌入降级。

根据当前章节和批次更新进度

typescript
1 const batchProgressBase = Math.round(sectionProgressStart + (taskIdx / totalSteps) * (sectionProgressEnd - sectionProgressStart)); 2 const batchProgressNext = Math.round(sectionProgressStart + ((taskIdx + 1) / totalSteps) * (sectionProgressEnd - sectionProgressStart)); 3 setAnalysisProgress({ 4 percentage: Math.round(batchProgressBase + (batchIdx / Math.max(totalBatches, 1)) * (batchProgressNext - batchProgressBase)), 5 message: `正在生成「${sectionHeader}」批次 ${batchIdx + 1}/${totalBatches}...`, 6 });

Source: useAnalysis.ts

按章节顺序合并非空输出

typescript
1 const assembledParts: string[] = []; 2 for (const header of sectionHeaders) { 3 const output = sectionOutputs[header]; 4 if (output) { 5 assembledParts.push(`# ${header}\n\n${output}`); 6 } 7 } 8 9 let finalContent = assembledParts.join("\n\n");

Source: useAnalysis.ts

未获得内容的章节不被加入最终文本;此处不会生成空标题。图片插入在这一函数之外处理,源码注释指出在 analyzeDocument 完成管道之后进行。图片处理边界。

Configuration Options

选项/参数类型已读源码中的值/默认值作用
DEFAULT_PAGE_CHUNK_SIZEnumber4本地页码计划的页数封段阈值。
DEFAULT_CHAR_CHUNK_SIZEnumber7000本地页码计划的累计字符阈值,也是文本退化切分默认长度。
targetChunkSize / overlapChars / minChunkSizenumber调用处为 400 / 60 / 60传入 chunkText 的章节管道切片参数;不应当作其内部默认值。
MAX_CHARS_PER_BATCHnumber8000章节模型请求批次的累计字符预算,定义在任务循环内。
progressStart / progressEndnumber函数参数默认 20 / 85章节管道估算进度的起止区间。
includeImagesboolean提示词构造器参数默认 true决定是否向分段/整合提示词加入图片相关内容。

来源:阈值 · 切片与进度默认值 · 批次阈值 · 图片选项。这些值是源码常量、函数默认值或调用参数;已读取代码没有证明它们都可在 UI 中修改。

API Reference

API输入返回/行为
buildLocalWorkflowPlan(bundle: DocumentAnalysisBundle, fileName: string, fileType: SupportedFileType): AnalysisWorkflowPlan文档分析数据、文件名、文件类型生成本地段计划、图片定位提示与完成要求。
buildChunkPlan(bundle: DocumentAnalysisBundle): ChunkPlan[]文档分析数据有页文本按页封段,无页文本按字符退化;无内容可能为空数组。
parseWorkflowPlan(content: string, fallbackPlan: AnalysisWorkflowPlan): AnalysisWorkflowPlan模型计划文本与回退计划空文本或 JSON 解析失败返回回退计划;成功则清洗并合并字段。
splitTextIntoChunks(text: string, maxChunkLength = DEFAULT_CHAR_CHUNK_SIZE): string[]待切文本、可选长度返回裁剪空白后的片段;空输入返回空数组。
buildChunkPrompt({...}): string源提示、计划、段、文本、文件名、图片 token、可选 includeImages返回当前分段写作提示文本。
buildComposerPrompt({...}): string源提示、计划、结果片段、文件名、图片清单、可选 includeImages返回整合提示文本。
runSectionPipeline(...) : Promise<string>文件、章节提示配置、模型连接设置、分析数据、可选进度区间按 chunkTasks 依次生成章节并返回组装的 Markdown;为 useAnalysis 内部函数。

签名及行为:计划/解析 · 提示词 · 内部章节管道。已读取实现没有为这些函数声明专门的异常类型;runSectionPipeline 批次调用会在内部捕获模型错误,但不要据此推断所有外部依赖都不会抛错。

Failure Modes, Edge Cases & Concurrency

  • 计划解析失败:JSON.parse 出错后告警并整体回退;字段清洗使用宽松转换,而非严格 schema 校验。解析。
  • 模型输出为空:先剥离思考标签、代码围栏和格式标记,再移除重复章节标题;若为空,用更明确的提示词重试一次。重试仍空或重试抛错仅记警告,本批不加入输出。主调用抛错也仅记录批次失败。因而最终结果可能缺失某些批次或整个章节。模型处理。
  • 嵌入不可用或失败:不可用时跳过,失败时记警告;主章节流程继续,且不根据相似度选 top-K。嵌入与全量覆盖 · 全量循环。
  • 顺序与并发:任务循环、批次发送都使用串行 await;已读管道没有显示并发批次请求。两轮遍历(预计算批次与真正发送)使用同一预算规则,批次结果按返回顺序追加。任务/批次遍历 · 实际刷新。
  • 启动校验:analyzeDocument 在无文件或需要但未提供 API Key 时 toast 提示并返回;通过后才设置 isAnalyzing(true)。多文件情况下源码为每文件计算 fileBase/fileSpan;本页所读截断于后续进度映射之前,不推断整体百分比计算方式。入口校验。

Performance, Operations & Extension Points

每个 chunkTasks 都覆盖全部片段,模型调用次数随章节任务数与每任务批次数增长;顺序调用可保留片段和章节顺序,但延长总等待时间。批次只带本批页码对应的图片标签以减少提示词冗余;图片本身不传给模型,而在后处理插入。调用次数结构 · 图片处理说明。嵌入记录 durationMs、模型、片段数及免费额度信息;章节也记录任务、总片段、每章节批次和产出数量,便于定位降级与缺失内容。日志 · 章节日志。

若要改变本地计划的分段粒度,修改 analysisWorkflow 的两个阈值或独立传给 splitTextIntoChunks 的长度;若要改变实际章节管道输入粒度,应查看 chunkText 参数与 MAX_CHARS_PER_BATCH,不能只调本地计划阈值。章节任务和标题来自 promptConfig.chunkTasks/sectionHeaders,实际模型由传入 settings 决定。规划阈值 · 管道参数 · 任务配置使用。

  • 文档处理入口:选择文件、取得设置并启动分析;其余处理与归档属于相邻主题。
  • 嵌入与分块说明:RAG 背景;本页的章节生成实际采用全量片段遍历,而非 top-K 检索。
  • 快速开始:面向用户的分析启动与进度条说明。

Sources

(2 files)