mateclaw/mateclaw-server/src/main/java/vip/mate/wiki/WikiProperties.java

182 lines
7.4 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package vip.mate.wiki;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Wiki 知识库配置
*
* @author MateClaw Team
*/
@Data
@ConfigurationProperties(prefix = "mate.wiki")
public class WikiProperties {
/** 是否启用 Wiki 知识库功能 */
private boolean enabled = true;
/**
* LLM 单次处理最大字符数(超过则分块)。
* <p>
* RFC-012默认从 30000 下调到 15000 —— 单 chunk 输出 tokens 砍半、并行饱和度更高、
* 质量也更稳定。中端模型qwen-plus/claude-sonnet建议 12000-20000
* 旗舰模型qwen-max/claude-opus可调大到 20000-30000。
*/
private int maxChunkSize = 15000;
/**
* 同一次 processAllPending 下同时处理的原始材料数上限。
* <p>
* RFC-012 Change 1保护共享的 @Async 线程池max=16不被 wiki 长时间占满,
* 同时给材料级并发定一个可控的上限,避免 LLM 提供方触发限流。
*/
private int maxParallelRawMaterials = 3;
/**
* Max parallel chunks within a single raw material.
* <p>
* RFC-047 P3: Changed from 5 to 1. Parallel chunks all share the same existingPagesIndex
* snapshot, so chunk N cannot see pages created by chunk N-1 — causing duplicate pages and
* stale-index collisions. Serializing chunks eliminates this class of bug. Document-level
* parallelism (maxParallelRawMaterials) is preserved, so overall throughput is unchanged
* for multi-document batches.
*/
private int maxParallelChunks = 1;
/**
* 单个 chunk 内 phase B 阶段的 page 并行处理数上限。
* <p>
* RFC-012 follow-up #3原实现 phase B 的 create / merge 循环逐页串行调用 LLM
* 单 chunk N 个 page 就要串行 N 次 LLM 调用——一个卡超时整条流水线停摆。
* 改为受此 Semaphore 控制的并行,默认 3。结合 maxParallelRawMaterials × maxParallelChunks
* × maxParallelPhaseBPages = 3 × 5 × 3 = 45 的理论最大并发,实际按 LLM 限流为准。
*/
private int maxParallelPhaseBPages = 3;
/** 注入 agent prompt 的最大字符数 */
private int maxContextChars = 10000;
/** 单个原始材料最多生成的 Wiki 页面数 */
private int maxPagesPerRaw = 15;
/** 上传后是否自动触发处理 */
private boolean autoProcessOnUpload = true;
/** 上传文件存储目录 */
private String uploadDir = "./data/wiki-uploads";
/** 目录扫描最大文件数 */
private int maxScanFiles = 500;
/** 扫描时跳过大于此大小的文件(字节),默认 50MB */
private long maxScanFileSize = 50 * 1024 * 1024;
/**
* Wiki LLM 重试最大尝试次数(含首次)。
* <p>
* RFC-012 M1旧实现无最大次数遇到 nginx 504 这种"反复瞬时"错误会永远重试。
* 设为 5 后单 chunk 最多走 5 轮,配合 llmMaxTotalDurationMs 共同保证有界停止。
*/
private int llmMaxAttempts = 5;
/**
* Wiki LLM 重试总耗时上限(毫秒),从首次调用开始计时。
* <p>
* RFC-012 M1单 chunk LLM 调用 + 重试的硬封顶,超过即放弃,让该 chunk 进入 failed 计数。
* 默认 4 分钟。
*/
private long llmMaxTotalDurationMs = 240_000;
/**
* RFC-047 P1: Max pages per BatchCreate LLM call.
* Pages planned by route are chunked into sub-batches of this size;
* a local liveIndex is updated between sub-batches so later pages can
* link to earlier ones created in the same chunk.
* Default 5: keeps output tokens per call predictable while covering
* the typical 35 creates per chunk in a single call.
*/
private int batchCreatePageSize = 3;
/**
* RFC-047: Minimum chunk length (chars) for the chunk-fallback mechanism.
* If route returns 0 create+update entries and the chunk exceeds this threshold,
* an overview page is auto-injected so no substantial content is silently dropped.
* Chunks shorter than this (e.g. TOC lines, blank pages) are allowed to produce nothing.
*/
private int chunkFallbackMinChars = 200;
/**
* 是否启用两阶段消化(路由 → 逐页 merge
* <p>
* RFC-012 M2true 时单 chunk 的 LLM 输出量大幅缩减,避免 nginx 60s 网关超时。
* 默认 trueM2 上线);遇问题可在 application.yml 配 mate.wiki.use-two-phase-digest=false 回退到旧行为。
*/
private boolean useTwoPhaseDigest = true;
// ==================== RFC-011: Embedding ====================
/** 嵌入模型名称DashScope */
private String embeddingModel = "text-embedding-v3";
/** 嵌入批量大小(一次 API 调用处理多少 chunk */
private int embeddingBatchSize = 16;
/**
* Embedding 模型单段最大字符数,超过则子段拆分 + 向量均值。
* <p>
* 默认 6000中文安全值对应 ~4000 token远小于 text-embedding-v3 的 8192 上限)。
* 纯英文场景可调大到 7500其他 embedding 模型切换时按该模型的 token 限制调整。
*/
private int embeddingMaxChars = 6000;
/** 混合搜索默认模式keyword / semantic / hybrid */
private String searchDefaultMode = "hybrid";
// ==================== RFC-031: Light processing tiers ====================
/** Whether to auto-dispatch a LIGHT_ENRICH job after heavy ingest completes */
private boolean lightEnrichEnabled = true;
/** Delay before light enrichment starts (ms) */
private long lightEnrichDelayMs = 2000;
/**
* Minimum ratio of enriched content length to original content length.
* If the LLM returns text shorter than this ratio, the enrichment is rejected.
*/
private double wikilinkMinContentRatio = 0.5;
/** Maximum characters for local repair single-page regeneration */
private int localRepairMaxChars = 8000;
/**
* Whether to run a document-level analysis pass before routing.
* When enabled, a single LLM call produces a concept map (topics + key_concepts)
* that is injected into every chunk's route prompt, giving the router global
* awareness of the document structure and reducing concept omissions.
* Adds ~1 LLM call and 10-20s per raw material.
*/
private boolean useDocumentAnalysis = true;
/**
* Max characters of document text fed to the analysis pass.
* Larger values improve coverage but increase prompt tokens.
* Default 15000 covers most documents while staying well within model limits.
*/
private int documentAnalysisSampleChars = 15000;
/**
* RFC-051 PR-6b: route-phase output binding. When {@code true}, the route
* LLM call uses a Spring AI {@code BeanOutputConverter<RouteResult>} —
* the format hint is injected into the user prompt and the response is
* parsed strictly into the DTO. Failures fall back to the legacy lenient
* JSON parser so a flaky model never blocks ingest.
* <p>
* Default {@code false} keeps existing behavior on first upgrade. Flip on
* once you've validated the route prompt against the models you actually
* run (DashScope / OpenAI / Anthropic / DeepSeek tend to be fine; Ollama
* and weaker models may need the fallback).
*/
private boolean useStructuredRoute = false;
}