Wiki 生成

Wiki 生成是长任务:采集资料 → 压缩 → 规划目录 → 并发生成每一页 → 生成总览页 → 整套落库。它的难点不在单页文案,而在「一次生成 4–10 页、每页可能被续写补全、部分页失败不能拖垮整套」这条工程链上。

采集资料 项目目录 · 代码上下文 语义命中 10 条 / 页 压缩 BaseContext rawCodeContext 规划 2–4 章 / 每章 1–3 页 总 4–10 页 · maxTokens 3072 并发生成主题页 并发 4 · 单页上限 8192 token 截断则续写(最多 4 轮) 总览页 必含「总体架构」+ Mermaid 末节「文档导航」 落库:一套多页 同一 SetId · 总览 SortOrder = 0 · 主题页 = 规划序 + 1 任务状态:0 排队 / 1 运行 / 2 完成 / 3 失败
阶段顺序固定:规划先于生成、总览最后写;任何一页失败都会进入警告集合,而不是中断整套。

触发与任务模型

端点说明
POST /api/wiki/projects/{projectId}/generate入队整套生成,请求体 { modelId? }
POST /api/wiki/{id}/regenerate重生成单页,复用该页规划阶段的 Brief
GET /api/wiki · GET /api/wiki/sets · GET /api/wiki/{id}页面列表 / 套件列表 / 单页详情,均可按 projectId 过滤
GET /api/wiki/jobs · GET /api/wiki/jobs/{id}生成任务列表与详情(阶段、进度、错误、警告)
GET /api/wiki/sets/{setId}/export导出 zip:每页一个 Markdown(00-…md、01-…md)+ 一个 README.md 索引
DELETE /api/wiki/{id} · DELETE /api/wiki/sets/{setId}删除单页 / 整套

后台任务类型是 WikiGenerate,模型 id 通过任务元数据传递(Guid.TryParse(item.Metadata))。同一个项目若已有排队中或运行中的生成任务,EnqueueGenerateAsync 直接返回那条任务,不重复排队。前端在项目页跳转 /wiki?project=…&generate=1 会进入后自动触发一次生成并清掉参数;模型选择器只列非 embedding 用途的模型,留空表示用默认补全模型。

资料采集与压缩

  • 采集器负责把「受管项目」变成资料:本地目录或远端工作项目、基础资料与代码上下文。
  • 代码语义索引可用时按语义命中取片段,每页约 10 条(SemanticHitsPerPage = 10);索引不可用时回退源码采样。
  • 送进模型前对 BaseContext 与 rawCodeContext 各跑一次压缩管道(同样受 Enabled / Mode / 节点配置影响)。
  • 采集失败会直接返回错误且不入后台队列:本地目录不存在、远端连接失败、工作项目未找到、目录为空各有独立文案。

规划阶段

项取值
返回结构{ chapters: [{ title, pages: [{ title, brief }] }] }
规模约束2–4 章,每章 1–3 页,总 4–10 页(上限常量 MaxModulePages = 10)
规划 token 上限3072
规划失败异常被捕获后回退默认四页:项目概述与技术栈 / 目录结构 / 核心模块详解 / 快速开始与配置,不阻塞整套生成

Brief 会落库,成为该页的写作要点;单页重生成时直接复用它,因此重生成不会偏离原规划。

生成阶段

机制取值 / 行为
并发MaxPageConcurrency = 4
单页输出上限ContentMaxTokens = 8192
续写触发结束原因是 length / max_tokens,或代码围栏未闭合(围栏计数为奇数)
续写上限MaxContinueRounds = 4,续写提示会带上已生成的全部内容
续写容错续写结果里出现「已有内容」/「未提供」/「无法判断」等元话术时直接丢弃这一段
单页重试PageRetryCount = 1,退避 800ms
正文要求Markdown、中文、只能依据资料不得编造、结构/流程/模块关系必须配 Mermaid 图、目录树用 text 代码块、路径与类型用行内代码
页间协作提示词会列出同套其他页面,允许相互引用

总览页单独生成:要求含项目简介、核心特性、技术栈、## 总体架构(必须带 Mermaid graph / flowchart)与末节 ## 文档导航(按章节层级原样列出)。总览页失败时回退为纯文本总览(项目简介 + 文档导航)。

落库、套件与过期判定

字段 / 规则说明
WikiDocumentProjectId · SetId · SortOrder · Title · Chapter · Brief · Content
WikiGenerationJobStatus(0 排队 / 1 运行 / 2 完成 / 3 失败) · Stage · Progress · TotalPages · DonePages · ErrorMessage · WarningMessage · ModelId · SetId · CompletedAt
写入顺序先把主题页生成完并汇总,再生成总览页,最后一次性写库:总览 SortOrder = 0,主题页 = 规划序 + 1
套件聚合GetAllAsync 按 SetId 分组、组内按 SortOrder 排序,总览页恒在最前
过期判定GetSetsAsync 调用上下文采集器的过期计算,填充 IsStale 与 StaleFileCount(项目文件变动后提示重新生成)

失败与降级

情况行为
没有可用模型任务失败,记录 wiki.modelNotConfigured
单页内容为空记警告并按 PageRetryCount 重试;仍为空则该页失败,进入 failedPages
部分页失败整套仍写库,失败页写入 WarningMessage(前端橙色提示),不影响已成功的页
全部主题页失败抛 wiki.allPagesFailed
总览页失败回退纯文本总览(项目简介 + 文档导航)
单页重生成失败返回 wiki.regenerateFailed
后台任务被停止打断 / 主动取消同图谱任务:停止则重新排队,主动取消记失败

观测

  • 前端任务条:stage + donePages/totalPages + 百分比;失败红色条带 errorMessage;部分失败橙色提示带 warningMessage。
  • 阶段文案来自本地化键:wiki.stageQueued、stageStarting、stageCollecting、stagePlanning、stageGeneratingPages、stageOverview、stageCompleted。
  • 用量来源 Wiki:输入 token、压缩后 token、延迟。
  • 没有页面级耗时字段:目前只有任务级的进度与阶段,页级排查看日志。

实作要点

  • 规划质量决定整套质量:规划若是泛泛而谈,后面每页都会泛。想调整结构,先改规划阶段的提示词与规模约束。
  • 续写是「补全」不是「重写」:它把已生成内容一并送回模型,所以 ContentMaxTokens 越小续写轮次越多、上下文越贵。
  • 部分页失败不是事故:整套仍可用,直接对失败页点「重生成」即可。
  • 导出 zip 的文件名以序号开头(00-、01-),保证在文件管理器里与站内顺序一致。
  • 换了压缩管道配置会改变送进模型的资料,从而影响 Wiki 内容;排查「内容不如以前」时把这条算进去。