# pragmatic-chunker **Repository Path**: wizard-lee/pragmatic-chunker ## Basic Information - **Project Name**: pragmatic-chunker - **Description**: Pragmatic Chunker 是一个基于 Java 17 的命令行工具,面向 RAG(Retrieval-Augmented Generation,检索增强生成)场景,把 Markdown / Java 源码按语义结构切成可独立理解、信息密度充分的文本块(chunk),并串联起「切片 → 嵌入向量 → 写入向量库 → 检索验证 → 供 AI Agent 检索」的完整流水线。 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 0 - **Created**: 2026-08-21 - **Last Updated**: 2026-10-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Pragmatic Chunker > 语义化文件切片与向量入库工具 —— 为检索而生 Pragmatic Chunker 是一个基于 Java 17 的命令行工具,面向 RAG(Retrieval-Augmented Generation,检索增强生成)场景,把 Markdown / Java 源码按语义结构切成可独立理解、信息密度充分的文本块(chunk),并串联起「切片 → 嵌入向量 → 写入向量库 → 检索验证 → 供 AI Agent 检索」的完整流水线。 ## 它是什么 对私有文档 / 代码做 RAG 检索,通常需要经过四个环节:**切分 → 向量化 → 入库 → 检索**。Pragmatic Chunker 把这条链路收敛到同一个可执行 JAR 中,每一步都产出自包含、可移植、可复现的中间文件: ``` 源文件 (.md / .java) │ chunk 文件切片(语义 chunk 化) ▼ *.chunks.json 切片中间文件(chunk 原文 + 元数据) │ embed 嵌入向量生成 ▼ *.embeddings.json 向量中间文件(向量 + 原文 + 完整元数据,自包含) │ push 推送到向量库 ▼ Qdrant 集合 向量数据入库(Point = 向量 + payload) │ search / mcp ▼ 检索验证 / AI Agent(RAG 检索环节) ``` ### 核心特性 | 能力 | 说明 | |------|------| | ✂️ 语义切片 | Markdown 按标题层级 + 原子块(代码块/表格/列表)切分;Java 按类 / 方法 / 逻辑块切分 | | 🧬 嵌入向量 | 支持本地 Ollama 与 OpenAI(含兼容协议服务),批次重试、连通性预检 | | 🚀 向量入库 | 首期支持 Qdrant,按 `source_file` 先删后加,重复推送幂等 | | 🔍 检索验证 | 单条查询快速验证检索效果,输出 `text` / `raw` / `payload` 三种格式 | | 🔌 MCP Server | 以 `mcp` 子命令启动,向 AI Agent 暴露只读检索工具(stdio / HTTP 双传输) | | 🧩 可扩展 | `FileChunker` / `EmbeddingProvider` / `VectorStore` 三套 SPI,新增类型/提供方零侵入 | ### 两种使用方式 - **交互式向导**:不带参数启动,按欢迎页提示逐步选择能力与配置; - **CLI 子命令**:`chunk` / `embed` / `push` / `search` / `mcp`,适合脚本集成与批量处理。 ## 环境要求 | 项目 | 要求 | 说明 | |------|------|------| | JDK | **17 及以上** | 运行与编译均要求 Java 17 | | 构建工具 | Maven 3.6+ | 仅编译打包时需要,运行只需 JRE | | 操作系统 | macOS / Linux / Windows | 输出路径统一使用 `/` 分隔符,跨平台一致 | **可选的外部服务**(按使用的命令决定是否必需): | 服务 | 命令 | 默认地址 | 说明 | |------|------|----------|------| | Ollama | `embed` / `search` / `mcp`(本地嵌入时) | `http://localhost:11434` | 本地嵌入向量服务 | | OpenAI / 兼容服务 | `embed` / `search` / `mcp`(外部嵌入时) | `https://api.openai.com/v1` | 需 API Key | | Qdrant | `push` / `search` / `mcp` | `http://localhost:6333` | 向量数据库 | ## 构建与打包 ```bash mvn clean package ``` 打包产物为可执行 fat JAR(`maven-shade-plugin`,主类 `io.pragmatic.chunker.cli.ChunkerCommand`): ```bash java -jar target/pragmatic-chunker-1.0-SNAPSHOT.jar --help ``` ## 快速开始 一个最小可用的完整流水线(本地 Ollama + Qdrant 已启动): ```bash # 1. 切片:把 docs 目录下的 Markdown 切成 chunk java -jar pragmatic-chunker.jar chunk -i ./docs/ -o ./output --type markdown # 2. 嵌入:把切片结果向量化(默认 Ollama / nomic-embed-text) java -jar pragmatic-chunker.jar embed -i ./output/markdown -o ./embeddings # 3. 推送:把向量写入 Qdrant 集合 java -jar pragmatic-chunker.jar push -i ./embeddings --collection my_docs # 4. 检索验证 java -jar pragmatic-chunker.jar search -q "切片的最大长度如何配置" ``` ## 使用方法 ### 运行形态 | 启动方式 | 行为 | |----------|------| | 无参数 | 进入交互式向导(欢迎页提供切片 / 嵌入 / 推送 / 检索验证四种能力) | | `chunk` 子命令 | 切片快捷模式 | | `embed` 子命令 | 嵌入生成快捷模式 | | `push` 子命令 | 推送到向量库 | | `search` 子命令 | 检索验证 | | `mcp` 子命令 | MCP Server 模式(stdio / HTTP) | | 带 `-i` 无子命令 | 向后兼容,等价于 `chunk` 子命令 | ### 切片(`chunk`) ```bash # 切片单个文件 / 整个目录(递归扫描) java -jar pragmatic-chunker.jar chunk -i ./docs/guide.md -o ./output java -jar pragmatic-chunker.jar chunk -i ./docs/ -o ./output --type markdown # 覆盖切片参数 java -jar pragmatic-chunker.jar chunk -i ./docs/ -o ./output \ --max-size 1000 --overlap-strategy sentence --content-format plain ``` 参数清单: | 参数 | 短参数 | 默认值 | 说明 | |------|--------|--------|------| | `--input` | `-i` | — | 输入文件或目录路径 | | `--output` | `-o` | `./output` | 输出目录 | | `--type` | — | 自动推断 | 文件类型:`markdown` / `java` | | `--config` | — | 自动查找 | 自定义切片配置文件路径 | | `--max-size` | `-s` | 配置文件值 | 单个 chunk 最大字符数 | | `--min-section-size` | — | 配置文件值 | 小 Section 合并阈值 | | `--overlap-strategy` | — | 配置文件值 | `paragraph` / `sentence` / `none` | | `--max-overlap` | — | 配置文件值 | Overlap 文本最大字符数 | | `--content-format` | — | 配置文件值 | `markdown` / `plain` | | `--no-context-prefix` | — | false | 关闭上下文前缀生成 | | `--keep-frontmatter` | — | false | 保留 frontmatter 在内容中 | | `--yes` | `-y` | false | 跳过确认步骤直接执行 | 输出:按文件类型创建子目录(如 `./output/markdown/`、`./output/java/`),每个源文件生成一个 `{原文件名}.chunks.json`。 ### 嵌入向量生成(`embed`) ```bash # 对目录下所有切片文件生成向量 java -jar pragmatic-chunker.jar embed -i ./output/markdown -o ./embeddings # 使用 OpenAI 并覆盖模型与批次大小 java -jar pragmatic-chunker.jar embed -i ./output -o ./embeddings \ --provider openai --model text-embedding-3-large --batch-size 32 ``` 参数清单: | 参数 | 短参数 | 默认值 | 说明 | |------|--------|--------|------| | `--input` | `-i` | —(必填) | 输入 `*.chunks.json` 文件或目录 | | `--output` | `-o` | `./embeddings` | 输出目录 | | `--config` | — | 自动查找 | 自定义嵌入配置文件路径 | | `--provider` | `-p` | 配置文件值 | `ollama` / `openai` | | `--model` | `-m` | 配置文件值 | 嵌入模型名 | | `--api-key` | — | 环境变量/配置文件 | OpenAI API Key | | `--base-url` | — | 配置文件值 | 服务地址 | | `--batch-size` | — | 配置文件值 | 批次大小 | | `--dimensions` | — | 配置文件值 | 输出向量维度(0=模型默认) | | `--yes` | `-y` | false | 跳过确认步骤直接执行 | 输出:`{原文件名}.embeddings.json`,自包含「向量 + 原文 + 完整元数据」。 ### 推送到向量库(`push`) ```bash # 推送到指定集合 java -jar pragmatic-chunker.jar push -i ./embeddings --collection my_docs # Qdrant Cloud(API Key 走环境变量) QDRANT_API_KEY=xxx java -jar pragmatic-chunker.jar push -i ./embeddings \ --base-url https://xxx.qdrant.io --collection my_docs ``` 参数清单: | 参数 | 短参数 | 默认值 | 说明 | |------|--------|--------|------| | `--input` | `-i` | —(必填) | 输入 `*.embeddings.json` 文件或目录 | | `--collection` | `-c` | 配置文件值 | 目标集合名 | | `--config` | — | 自动查找 | 自定义向量库配置文件路径 | | `--provider` | `-p` | 配置文件值 | 向量库提供方(当前仅 `qdrant`) | | `--base-url` | — | 配置文件值 | 向量库服务地址 | | `--api-key` | — | 环境变量/配置文件 | 向量库 API Key | | `--batch-size` | — | 配置文件值 | 每批次 upsert 的 point 数量 | | `--append` | — | false | 跳过先删后加的清理步骤,纯 upsert 覆盖 | | `--yes` | `-y` | false | 跳过确认步骤直接执行 | 更新语义:对同一 `source_file` 重复推送采用「先删后加」,保证集合状态与最新中间文件一致;同一 chunk 使用确定性 UUID v5,upsert 幂等。 ### 检索验证(`search`) ```bash # 单条查询(默认 text 格式,人类可读) java -jar pragmatic-chunker.jar search -q "切片的最大长度如何配置" # 返回向量库原始响应 java -jar pragmatic-chunker.jar search -q "切片长度" --format raw # 返回负载内容 JSON(供 AI 等下游消费) java -jar pragmatic-chunker.jar search -q "切片长度" --format payload | my-ai-tool ``` 参数清单: | 参数 | 短参数 | 默认值 | 说明 | |------|--------|--------|------| | `--query` | `-q` | —(必填) | 查询文本 | | `--collection` | `-c` | 配置文件值 | 目标集合名 | | `--top-k` | `-k` | 配置文件值 | Top-K 数量(1~20) | | `--format` | `-f` | `text` | `text` / `raw` / `payload` | | `--config` | — | 自动查找 | 向量库配置文件路径 | | `--embed-config` | — | 自动查找 | 嵌入配置文件路径(查询向量生成) | | `--provider` / `--base-url` / `--api-key` | `-p` 等 | 配置文件值 | 向量库连接覆盖 | 检索验证**只读**,不创建集合、不写入、不删除任何数据。 ### MCP Server(`mcp`) 以 MCP(Model Context Protocol)Server 形态运行,向 AI Agent(Qoder、Claude Desktop 等)暴露三个只读检索工具:`search_vector_store`、`list_collections`、`list_sources`。 ```bash # stdio 传输(AI 客户端拉起) java -jar pragmatic-chunker.jar mcp --collection pragmatic_docs # HTTP 传输(常驻服务,多客户端共享) java -jar pragmatic-chunker.jar mcp --transport http --port 8088 --auth-token my-secret-token ``` 参数清单: | 参数 | 短参数 | 默认值 | 说明 | |------|--------|--------|------| | `--config` | — | 自动查找 | 向量库配置文件路径 | | `--embed-config` | — | 自动查找 | 嵌入配置文件路径 | | `--collection` | `-c` | 配置文件值 | 默认检索集合 | | `--log-file` | — | stderr | 日志文件路径 | | `--transport` | — | `stdio` | `stdio` / `http` | | `--host` | — | `127.0.0.1` | HTTP 监听地址 | | `--port` | — | `8088` | HTTP 监听端口 | | `--auth-token` | — | 不启用 | HTTP Bearer Token 鉴权 | ## 配置 参数通过同目录下的 `.properties` 配置文件指定,四种配置相互独立: | 配置文件 | 用途 | |----------|------| | `markdown.properties` | Markdown 切片参数 | | `java.properties` | Java 切片参数 | | `embedding.properties` | 嵌入向量生成参数 | | `vectorstore.properties` | 向量库推送 + 检索验证 + MCP 实例参数 | **配置文件查找顺序**(找到第一个即停止): 1. 命令行 `--config ` 显式指定 2. JAR 文件所在目录 3. 当前工作目录 4. 代码内置默认值 **参数优先级**(从高到低):命令行参数 > 配置文件 > 内置默认值。配置文件不存在时使用内置默认值并提示;数值型/枚举型参数越界或非法时回退默认值并告警;未知 key 忽略并告警。 ### markdown.properties 关键项 | 配置项 | 默认值 | 范围/可选值 | 说明 | |--------|--------|-------------|------| | `max-chunk-size` | 800 | 100~10000 | 单个 chunk 最大字符数 | | `min-section-size` | 100 | 0~500 | 小 Section 合并阈值 | | `overlap-strategy` | paragraph | paragraph / sentence / none | Overlap 策略 | | `max-overlap-size` | 200 | 0~1000 | Overlap 文本最大字符数 | | `content-format` | markdown | markdown / plain | 内容输出格式 | | `include-context-prefix` | true | boolean | 是否生成上下文前缀 | | `strip-frontmatter` | true | boolean | 是否剥离 frontmatter | ### java.properties 关键项 | 配置项 | 默认值 | 可选值 | 说明 | |--------|--------|--------|------| | `max-chunk-size` | 1500 | 100~20000 | 单个 chunk 最大字符数 | | `chunk-granularity` | method | class / method / logical-block | 切片粒度 | | `include-imports` | true | boolean | 是否包含 import | | `include-class-javadoc` | true | boolean | 是否包含类级 Javadoc | | `include-package-declaration` | true | boolean | 是否包含 package 声明 | | `include-field-declarations` | true | boolean | method 粒度下是否携带字段声明 | | `inner-class-strategy` | separate | inline / separate | 内部类处理策略 | | `include-method-annotations` | true | boolean | 是否包含方法注解 | ### embedding.properties 关键项 | 配置项 | 默认值 | 说明 | |--------|--------|------| | `provider` | ollama | `ollama` / `openai` | | `ollama.url` / `ollama.model` | `http://localhost:11434` / `nomic-embed-text` | Ollama 地址与模型 | | `openai.base-url` / `openai.model` | `https://api.openai.com/v1` / `text-embedding-3-small` | OpenAI 地址与模型 | | `openai.api-key` | 空 | 建议改用环境变量 `OPENAI_API_KEY` | | `batch-size` | 16 | 每批次 chunk 数量(1~100) | | `max-retries` | 3 | 失败重试次数(指数退避) | | `timeout-seconds` | 60 | 单次请求超时 | ### vectorstore.properties 关键项 | 配置项 | 默认值 | 说明 | |--------|--------|------| | `provider` | qdrant | 向量库提供方(当前仅 `qdrant`) | | `collection` | pragmatic_docs | 目标集合名 | | `qdrant.url` | `http://localhost:6333` | Qdrant 服务地址 | | `qdrant.api-key` | 空 | 建议改用环境变量 `QDRANT_API_KEY` | | `batch-size` | 64 | 每批次 upsert 的 point 数量(1~512) | | `search.top-k` | 5 | 检索返回的 Top-K 数量(1~20) | | `search.query-prefix` | 空 | 查询侧前缀(实验开关) | | `mcp.server-name` / `mcp.tool-name` / `mcp.tool-description` | 空 | MCP 实例身份(一实例一知识库) | ### API Key 获取优先级 | Key | 优先级(从高到低) | |-----|--------------------| | OpenAI | `--api-key` > 环境变量 `OPENAI_API_KEY` > 配置文件 `openai.api-key` | | Qdrant | `--api-key` > 环境变量 `QDRANT_API_KEY` > 配置文件 `qdrant.api-key` | ## Exit Code 约定 `chunk` / `embed` / `push` / `search` 四个命令统一: | Exit Code | 含义 | |-----------|------| | 0 | 全部成功(含检索「未命中」,属正常结果) | | 1 | 存在失败文件(exit code = 失败文件数,上限 255) | | 2 | 致命错误(服务不可达、鉴权失败、模型/集合不存在、参数错误) | ## 项目结构 ``` src/main/java/io/pragmatic/chunker ├── cli/ # picocli 命令入口与子命令(chunk/embed/push/search/mcp) ├── app/ # 编排层:ChunkerApp / EmbeddingApp / PushApp / SearchApp / InteractiveRunner ├── chunker/ # 切片 SPI:MarkdownChunker / JavaChunker ├── embedding/ # 嵌入 SPI:OllamaProvider / OpenAiProvider ├── vectorstore/ # 向量库 SPI:QdrantStore ├── mcp/ # MCP Server:传输层 / 分发层 / 工具注册 ├── config/ # 配置加载与参数校验 ├── model/ # 数据模型(Chunk / EmbeddingEntry / VectorPoint 等) ├── output/ # JSON 中间文件写入(ChunkWriter / EmbeddingWriter) └── ui/ # 交互式向导页面 ```