# https://github.com/rafal-qa/slopo 项目说明书

生成时间：2026-07-02 14:57:06 UTC

## 目录

- [项目概览、安装与快速开始](#page-1)
- [系统架构与数据流水线](#page-2)
- [相似度、聚类、重排序与 v0.2.0 精确副本处理](#page-3)
- [配置参数、Markdown 报告与团队协作工作流](#page-4)

<a id='page-1'></a>

## 项目概览、安装与快速开始

### 相关页面

相关主题：[系统架构与数据流水线](#page-2)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/rafal-qa/slopo/blob/main/README.md)
- [src/slopo/cli.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/cli.py)
- [src/slopo/config.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/config.py)
- [src/slopo/analysis/report/filesystem.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/report/filesystem.py)
- [src/slopo/analysis/ignore.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/ignore.py)
- [src/slopo/indexing/parsing/lang/python.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/indexing/parsing/lang/python.py)
- [src/slopo/indexing/parsing/lang/typescript.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/indexing/parsing/lang/typescript.py)
- [doc/example-report/cluster-03.md](https://github.com/rafal-qa/slopo/blob/main/doc/example-report/cluster-03.md)
- [doc/example-report/cluster-01.md](https://github.com/rafal-qa/slopo/blob/main/doc/example-report/cluster-01.md)

</details>

# 项目概览、安装与快速开始

## 1. 项目定位与适用场景

Slopo 是一款**轻量级的命令行工具**，专注于使用**嵌入模型（embedding models）** 检测**非精确复制的代码重复**（non-exact code duplication）。它针对的是传统工具难以发现的痛点：写法相似但位于代码库远端、分散在不同模块或被大段代码隔开的相似片段。

资料来源：[README.md](https://github.com/rafal-qa/slopo/blob/main/README.md)

- **精确复制粘贴**：由其他工具更擅长检测
- **近距离相似**：人类或 AI 易于识别
- **Slopo 聚焦**：相似写法 + 远距离定位 = 重构价值最高的重复

Slopo 当前的官方文档支持 **Python、TypeScript、JavaScript、Java、Kotlin、C#、Go、Rust** 八种语言。每种语言均通过独立的 [tree-sitter](https://tree-sitter.github.io/) 解析器处理：例如 Python 使用 `tree_sitter_python`（资料来源：[src/slopo/indexing/parsing/lang/python.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/indexing/parsing/lang/python.py)），TypeScript 使用 `tree_sitter_typescript`（资料来源：[src/slopo/indexing/parsing/lang/typescript.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/indexing/parsing/lang/typescript.py)），解析粒度到函数/方法/闭包层级。

## 2. 安装与初始化

### 通过 uv 安装

Slopo 通过 [uv](https://docs.astral.sh/uv/getting-started/installation/) 从 PyPI 安装，无需单独准备 Python 环境：

```bash
uv tool install slopo
```

uv 会将 Slopo 安装到独立的虚拟环境中。资料来源：[README.md](https://github.com/rafal-qa/slopo/blob/main/README.md)

### 生成配置模板

执行 `slopo init` 后，CLI 调用 `write_config_template` 在默认路径生成 YAML 配置模板（资料来源：[src/slopo/cli.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/cli.py)）。配置模板由 `_CONFIG_TEMPLATE` 常量定义，至少需要填写 `source_dir` 与嵌入模型相关字段（资料来源：[src/slopo/config.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/config.py)）。

完整配置字段还包括 `source_dir_exclude`、`db_file`、`report_dir`、`ignore_file`、`embedding_model`、`embedding_dimensions`、`embedding_api_key`、`embedding_batch_size`、`embedding_batch_chars`、`similarity_threshold`、`rerank_threshold`、`body_node_count_threshold`。

> ⚠️ **不可变字段**：首次索引后，`source_dir`、`embedding_model`、`embedding_dimensions`、`body_node_count_threshold` 不允许修改。如需变更必须删除 `slopo.db` 并从头执行 `slopo index`。资料来源：[README.md](https://github.com/rafal-qa/slopo/blob/main/README.md)

### 校验配置

`slopo show-config` 命令会加载配置并逐字段打印输出。其中 `embedding_api_key` 由 `mask_api_key` 进行脱敏处理，避免敏感信息泄露。资料来源：[src/slopo/cli.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/cli.py)

## 3. 嵌入模型与完整工作流

README 推荐使用面向代码的嵌入模型，如 [Voyage AI](https://docs.voyageai.com/docs/embeddings)，即便维度较低（如 `512`）也能取得良好效果；同时兼容所有 [LiteLLM](https://docs.litellm.ai/docs/embedding/supported_embedding) 支持的嵌入提供方。API 密钥可通过配置文件的 `embedding_api_key` 字段，或环境变量 `SLOPO_EMBEDDING_API_KEY`（也可从当前目录 `.env` 自动加载）提供。资料来源：[README.md](https://github.com/rafal-qa/slopo/blob/main/README.md)、[src/slopo/cli.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/cli.py)

### 端到端工作流

```mermaid
flowchart LR
    A["slopo init<br/>生成配置模板"] --> B["编辑配置<br/>source_dir / embedding_model"]
    B --> C["slopo show-config<br/>校验配置"]
    C --> D["slopo index<br/>解析 + 计算嵌入"]
    D --> E[("slopo.db<br/>SQLite")]
    E --> F["聚类 & 打分"]
    F --> G["Markdown 报告<br/>report_dir/"]
    G --> H["人工/AI 复核"]
    H -->|忽略| I["ignore file"]
    H -->|重构| J["交由 AI Agent"]
```

`slopo index` 的实现包含以下检查：若 `source_dir` 不是有效目录则报错并以退出码 `1` 退出；若 `slopo.db` 已存在，则调用 `verify_source_dir` 校验路径一致性，发现 `ConfigurationMismatchError` 时打印不匹配信息并退出。资料来源：[src/slopo/cli.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/cli.py)

## 4. 报告与忽略机制

### 报告写入

`write_report` 函数负责将分析结果写入磁盘。它先清理 `report_dir` 中旧有的 `index.md` 与符合 `CLUSTER_FILE_GLOB` 的聚类文件，再生成新的 `index.md` 以及每个聚类的 Markdown 文件。命名规则由 `cluster_filename` 提供（资料来源：[src/slopo/analysis/report/filesystem.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/report/filesystem.py)）。

### 忽略文件

`src/slopo/analysis/ignore.py` 模块基于聚类哈希提供「忽略清单」功能。`cluster_hash` 将每个单元的 `file_path` 与 `body_hash` 排序后拼接成 SHA-256 摘要，取前 12 位作为聚类哈希。`load_ignored` 解析忽略文件中以换行分隔的哈希集合（支持 `#` 注释）。一旦代码或相对路径发生变化，哈希就会改变，使该聚类重新出现在报告中。资料来源：[src/slopo/analysis/ignore.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/ignore.py)

### v0.2.0 社区行为变更

依据社区上下文，从 **v0.2.0** 起，**精确复制副本（exact-copy duplicates）的处理统一为「始终包含在报告中」**，并以低噪方式呈现。这避免了此前「默认排除」时可能遗漏的关键重复片段。

## 5. 示例：Slopo 自检报告

`doc/example-report/cluster-03.md` 展示了跨语言精确副本聚类：八个语言的解析器中存在完全相同的 `parse(source: bytes) -> list[CodeUnit]` 助手函数，被识别为同一聚类。资料来源：[doc/example-report/cluster-03.md](https://github.com/rafal-qa/slopo/blob/main/doc/example-report/cluster-03.md)

`doc/example-report/cluster-01.md` 则呈现了「几乎一致但存在细微差异」的聚类，例如 Python 版本的 `_count_named_nodes` 额外跳过 docstring，但仍被识别为高度相似。资料来源：[doc/example-report/cluster-01.md](https://github.com/rafal-qa/slopo/blob/main/doc/example-report/cluster-01.md)

## 6. 推荐实践

1. **版本控制**：`ignore_file` 与不含 API 密钥的配置文件可以提交到 Git，以便团队共享审查结果；`slopo.db` 属于本地数据，不应提交。
2. **AI Agent 工作流**：完整报告（含未忽略聚类）可作为 AI Agent 重构建议的输入。
3. **探索参数**：随时运行 `slopo --help` 与 `slopo show-config` 查看最新可用选项。资料来源：[README.md](https://github.com/rafal-qa/slopo/blob/main/README.md)

---

## See Also

- [项目主仓库](https://github.com/rafal-qa/slopo)
- [示例报告目录](https://github.com/rafal-qa/slopo/tree/main/doc/example-report)

---

<a id='page-2'></a>

## 系统架构与数据流水线

### 相关页面

相关主题：[项目概览、安装与快速开始](#page-1), [相似度、聚类、重排序与 v0.2.0 精确副本处理](#page-3)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/slopo/cli.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/cli.py)
- [src/slopo/config.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/config.py)
- [src/slopo/analysis/report/filesystem.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/report/filesystem.py)
- [src/slopo/analysis/ignore.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/ignore.py)
- [src/slopo/indexing/parsing/lang/python.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/indexing/parsing/lang/python.py)
- [src/slopo/indexing/parsing/lang/rust.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/indexing/parsing/lang/rust.py)
- [README.md](https://github.com/rafal-qa/slopo/blob/main/README.md)
</details>

# 系统架构与数据流水线

## 概述

Slopo 是一个轻量级命令行工具，旨在利用嵌入模型检测代码库中的**非精确重复**（non-exact duplication）。与传统的逐字比对不同，Slopo 通过对每个解析出的代码单元（CodeUnit）计算向量嵌入，然后基于余弦相似度寻找结构相似但相隔较远的代码片段，最终输出可被 AI 智能体消费的聚类报告 资料来源：[README.md:1-19]()。

整个系统是一条单向的数据流水线，由 CLI 层驱动，经过配置加载、源码扫描、AST 解析、嵌入计算、相似度过滤、距离重排序、聚类合并，最后落到 Markdown 报告与忽略文件（ignore file）上。下图展示了完整的数据流。

```mermaid
flowchart LR
    A[CLI: slopo index] --> B[Config 加载]
    B --> C[扫描 source_dir]
    C --> D[Tree-sitter 解析]
    D --> E[CodeUnit 提取 + body_hash]
    E --> F[LiteLLM 嵌入计算]
    F --> G[余弦相似度过滤]
    G --> H[聚类 + 距离重排序]
    H --> I[忽略列表比对]
    I --> J[Markdown 报告]
```

## 流水线阶段

### 配置与初始化

CLI 通过 Typer 暴露 `init`、`show-config`、`index` 三个子命令。`init` 调用 `write_config_template` 生成 YAML 配置模板，模板中明确标注了必填字段（`source_dir`、`embedding_model`、`embedding_dimensions`、`embedding_api_key`）和可选字段 资料来源：[src/slopo/config.py:1-25]()。

`show-config` 在打印时调用 `mask_api_key` 对密钥进行脱敏（少于 12 字符全掩码，否则保留首尾各 5 位） 资料来源：[src/slopo/config.py:99-104]()。`index` 是流水线主入口，会先验证 `source_dir` 是否为目录，再调用 `verify_source_dir` 校验已存在数据库与配置的一致性 资料来源：[src/slopo/cli.py:43-58]()。

需要特别注意：**`source_dir`、`embedding_model`、`embedding_dimensions`、`body_node_count_threshold` 在首次索引后不能更改**，必须删除 `slopo.db` 重新开始 资料来源：[README.md:69-73]()。

### 索引与解析

解析层基于 tree-sitter，按语言拆分独立模块。每种语言（Python、TypeScript、JavaScript、Java、Kotlin、C#、Go、Rust）都实现统一的 `parse(source: bytes) -> list[CodeUnit]` 接口 资料来源：[src/slopo/indexing/parsing/lang/python.py:1-11]()。

解析过程会递归遍历 AST 节点，依据语言相关的 `_UNIT_TYPES` 集合（如 Rust 的 `function_item`、`function_signature_item`、`closure_expression`）筛选目标单元 资料来源：[src/slopo/indexing/parsing/lang/rust.py:7-15]()。每个 CodeUnit 包含 `name`、`body`、`start_line`、`end_line`、`body_node_count`、`body_hash` 等字段 资料来源：[src/slopo/indexing/parsing/lang/python.py:13-25]()。

`body_node_count_threshold`（默认 10）控制 AST 节点复杂度下限，避免过小的代码单元进入报告 资料来源：[src/slopo/config.py:79-82]()。

### 嵌入与相似度计算

嵌入计算依赖外部 LiteLLM 兼容提供商（如 Voyage AI），通过 `embedding_batch_size`（默认 100）和 `embedding_batch_chars`（默认 100,000）进行批量请求优化 资料来源：[src/slopo/config.py:72-77]()。

API 密钥既可写在配置文件，也可通过 `SLOPO_EMBEDDING_API_KEY` 环境变量注入，并支持从当前目录的 `.env` 文件读取 资料来源：[README.md:65-68]()。

相似度阶段使用 `similarity_threshold`（默认 0.92）过滤余弦相似度不足的 CodeUnit 对，余弦值取值范围 `-1` 到 `1`，`1` 表示完全相同 资料来源：[README.md:88-91]()。

### 聚类、重排序与报告生成

通过初筛的 CodeUnit 对被聚类为 Cluster。每个 Cluster 都会调用 `cluster_hash` 生成 12 位的 SHA-256 摘要，摘要基于所有单元的文件路径与 `body_hash` 排序后拼接计算 资料来源：[src/slopo/analysis/ignore.py:7-17]()。该哈希会与 `slopo.ignore.txt` 中的已审阅条目比对，命中即从报告中剔除 资料来源：[src/slopo/analysis/ignore.py:20-29]()。

重排序阶段引入基于距离的加分：跨目录跳转最多加 15%，同文件内按行距加分最多 10%；`rerank_threshold`（默认 0.94）过滤掉加分后仍不足的 Cluster 资料来源：[README.md:92-99]()。

`write_report` 在输出目录写入 `index.md` 与若干 `cluster-NN.md`，每次生成前会清理旧的索引与聚类文件 资料来源：[src/slopo/analysis/report/filesystem.py:14-31]()。报告示例（[doc/example-report](https://github.com/rafal-qa/slopo/tree/main/doc/example-report)）展示了如何在真实 Slopo 源码上识别出解析器模块间的重复模式 资料来源：[README.md:14-22]()。

## 关键数据模型与默认值

| 参数 | 默认值 | 是否首索引后不可改 |
|------|--------|-------------------|
| `similarity_threshold` | 0.92 | 否 |
| `rerank_threshold` | 0.94 | 否 |
| `embedding_batch_size` | 100 | 否 |
| `embedding_batch_chars` | 100000 | 否 |
| `body_node_count_threshold` | 10 | **是** |
| `db_file` | `slopo.db` | — |
| `ignore_file` | `slopo.ignore.txt` | — |
| `report_dir` | `slopo-report` | — |

资料来源：[src/slopo/config.py:58-84]()。

## 社区关注的变更（v0.2.0）

最新发布统一了**精确副本（exact-copy duplicate）**的处理方式：无论配置如何，完全相同的代码单元始终会被纳入报告，但通过聚类方式呈现以避免噪音 资料来源：[README.md:88-99]()（结合社区上下文）。这意味着用户不再需要在"排除"与"包含"之间二选一，但 `body_node_count_threshold` 等结构性参数仍需在首次索引时确定 资料来源：[README.md:69-73]()。

## 参见

- [README.md](https://github.com/rafal-qa/slopo/blob/main/README.md) — 项目概览与使用示例
- [doc/example-report](https://github.com/rafal-qa/slopo/tree/main/doc/example-report) — 真实报告样例
- 配置加载与校验：[src/slopo/config.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/config.py)
- 忽略文件机制：[src/slopo/analysis/ignore.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/ignore.py)
- 报告写入：[src/slopo/analysis/report/filesystem.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/report/filesystem.py)

---

<a id='page-3'></a>

## 相似度、聚类、重排序与 v0.2.0 精确副本处理

### 相关页面

相关主题：[系统架构与数据流水线](#page-2), [配置参数、Markdown 报告与团队协作工作流](#page-4)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/slopo/analysis/command.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/command.py)
- [src/slopo/analysis/similarity.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/similarity.py)
- [src/slopo/analysis/clustering.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/clustering.py)
- [src/slopo/analysis/rerank.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/rerank.py)
- [src/slopo/analysis/boost.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/boost.py)
- [src/slopo/analysis/dedup.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/dedup.py)
- [src/slopo/cli.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/cli.py)
- [src/slopo/config.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/config.py)
- [src/slopo/analysis/ignore.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/ignore.py)
- [src/slopo/analysis/report/filesystem.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/report/filesystem.py)
- [README.md](https://github.com/rafal-qa/slopo/blob/main/README.md)
- [doc/example-report/cluster-01.md](https://github.com/rafal-qa/slopo/blob/main/doc/example-report/cluster-01.md)
- [doc/example-report/cluster-03.md](https://github.com/rafal-qa/slopo/blob/main/doc/example-report/cluster-03.md)
- [doc/example-report/cluster-05.md](https://github.com/rafal-qa/slopo/blob/main/doc/example-report/cluster-05.md)
</details>

# 相似度、聚类、重排序与 v0.2.0 精确副本处理

## 概述与流水线

Slopo 在完成源代码解析、嵌入向量生成之后，会进入分析阶段：先用相似度阈值筛掉明显不相关的代码单元对，再把余下的相似对聚合到簇中，最后通过考虑代码在仓库中"距离远近"的 boost 机制对簇内分数做重排序。两道阈值分别为 `similarity_threshold` 与 `rerank_threshold`，它们都定义在 [src/slopo/config.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/config.py) 的 `Config` 数据类中，并由 `slopo index` 命令触发执行 [src/slopo/cli.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/cli.py)。

```mermaid
flowchart LR
    A[解析代码单元] --> B[嵌入向量]
    B --> C{similarity_threshold<br/>余弦相似度}
    C -- 通过 --> D[合并相似对为簇]
    D --> E[Boost 重排序<br/>目录跳数 / 文件行距]
    E --> F{rerank_threshold}
    F -- 通过 --> G[生成 Markdown 报告]
    F -- 丢弃 --> H[不进入报告]
```

## 相似度计算与初筛

第一阶段使用余弦相似度衡量两个嵌入向量之间的距离，取值范围 `-1` 到 `1`，其中 `1` 表示完全相同。`similarity_threshold` 控制最小可接受相似度，低于该值的代码单元对会直接被丢弃。这一步骤让分析阶段不必处理所有 N² 个组合，把候选规模压缩到可处理的水平。该阈值在 `Config.similarity_threshold` 中声明，并随 YAML 配置文件持久化。

资料来源：[src/slopo/config.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/config.py) · [README.md](https://github.com/rafal-qa/slopo/blob/main/README.md)

## 聚类与基于距离的 Boost 重排序

通过初筛的代码单元对会被合并到簇中。Slopo 关注的重点是分散在不同模块的大型代码库里那些"看起来很像、但分布在不同位置"的代码，因此每个簇在排序时都应用一次 boost：

- **跨文件 boost**：基于到达另一文件所需的目录跳数，最大可贡献 `15%` 的额外分数。
- **同文件 boost**：基于同一文件中两个单元之间的行数距离，最大可贡献 `10%` 的额外分数。

然后 `rerank_threshold` 过滤掉 boost 之后最高分仍不达标的簇。`body_node_count_threshold` 进一步过滤掉体量过小的代码单元，按 AST body 节点数（而不是文本长度）衡量复杂度，避免报告中充斥一行函数或简单 getter。README 明确指出，**`source_dir`、`embedding_model`、`embedding_dimensions`、`body_node_count_threshold` 在首次索引后即被锁定**，若要修改需要删除 `slopo.db` 重新开始。

资料来源：[README.md](https://github.com/rafal-qa/slopo/blob/main/README.md) · [src/slopo/config.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/config.py)

## v0.2.0 精确副本处理

在 v0.2.0 之前，精确副本（body_hash 完全一致的代码单元）既可以被排除（默认行为），也可以被包含进来。v0.2.0 的发布说明指出：现在**精确副本始终被包含**，但以一种不会给报告增加噪音的方式呈现——它们与普通相似副本一同进入相同的聚类与排序流水线，而不是被单独列出或额外标注。这让行为变得可预测：用户不必再在配置中权衡"是否包含精确副本"，得到的报告始终是"全部相似代码的全集"。

从 v0.2.0 的自报告示例可以印证这一点：[doc/example-report/cluster-03.md](https://github.com/rafal-qa/slopo/blob/main/doc/example-report/cluster-03.md) 是一个 score `1.00-1.00` 的完美相似簇，它与其他分数接近 `0.95-1.00` 的簇以相同的 Markdown 格式呈现，没有额外噪音区块。`[doc/example-report/cluster-05.md](https://github.com/rafal-qa/slopo/blob/main/doc/example-report/cluster-05.md)` 等簇也展示出"精确+近似变体"混合在同一簇内的统一呈现方式。

资料来源：[README.md](https://github.com/rafal-qa/slopo/blob/main/README.md) · [doc/example-report/cluster-03.md](https://github.com/rafal-qa/slopo/blob/main/doc/example-report/cluster-03.md) · [doc/example-report/cluster-05.md](https://github.com/rafal-qa/slopo/blob/main/doc/example-report/cluster-05.md)

## 报告、簇哈希与忽略机制

分析结果以 Markdown 文件形式写入 `report_dir`。`write_report` 先调用 `_clean_report_dir` 删除旧的 `index.md` 与所有符合 `CLUSTER_FILE_GLOB` 的簇文件，再写入新内容，确保报告目录始终与最新分析结果一致 [src/slopo/analysis/report/filesystem.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/report/filesystem.py)。

每个簇生成一个 12 字符的 SHA256 前缀作为哈希。哈希覆盖每个单元的代码体哈希及其相对于索引根的路径，按字典序排序后规范化生成。当代码体或路径发生变化时，哈希会随之改变，使该簇在忽略列表失效后重新出现在报告中；这正是 v0.2.0 统一精确副本处理后仍能依靠忽略机制管理噪音的关键设计。被忽略的哈希存放在 `ignore_file`，配置文件中不带 API key 的版本可以安全提交到 Git 以便团队协作。

资料来源：[src/slopo/analysis/ignore.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/ignore.py) · [src/slopo/analysis/report/filesystem.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/report/filesystem.py) · [doc/example-report/cluster-01.md](https://github.com/rafal-qa/slopo/blob/main/doc/example-report/cluster-01.md)

## 配置项总览

| 参数 | 含义 |
|------|------|
| `similarity_threshold` | 初筛用的最小余弦相似度 |
| `rerank_threshold` | 应用 boost 后的最小簇分数 |
| `body_node_count_threshold` | 代码单元 AST body 最小节点数 |
| `source_dir` / `embedding_model` / `embedding_dimensions` | 首次索引后不可变 |

## 参见

- 配置加载与校验：[src/slopo/config.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/config.py)
- CLI 子命令入口：[src/slopo/cli.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/cli.py)
- 报告落盘逻辑：[src/slopo/analysis/report/filesystem.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/report/filesystem.py)
- 忽略列表与簇哈希：[src/slopo/analysis/ignore.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/ignore.py)
- 项目概览与阈值说明：[README.md](https://github.com/rafal-qa/slopo/blob/main/README.md)

---

<a id='page-4'></a>

## 配置参数、Markdown 报告与团队协作工作流

### 相关页面

相关主题：[项目概览、安装与快速开始](#page-1), [相似度、聚类、重排序与 v0.2.0 精确副本处理](#page-3)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/slopo/config.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/config.py)
- [src/slopo/cli.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/cli.py)
- [src/slopo/analysis/report/filesystem.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/report/filesystem.py)
- [src/slopo/analysis/report/markdown.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/report/markdown.py)
- [src/slopo/analysis/report/naming.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/report/naming.py)
- [src/slopo/analysis/ignore.py](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/ignore.py)
- [README.md](https://github.com/rafal-qa/slopo/blob/main/README.md)
- [doc/example-report/index.md](https://github.com/rafal-qa/slopo/blob/main/doc/example-report/index.md)
- [doc/example-report/cluster-01.md](https://github.com/rafal-qa/slopo/blob/main/doc/example-report/cluster-01.md)
</details>

# 配置参数、Markdown 报告与团队协作工作流

Slopo 是一个基于嵌入向量的非精确代码重复检测 CLI 工具。本页聚焦其配置体系、Markdown 报告格式以及支持团队协作（共享忽略列表与配置文件）的相关机制。

## 概述

Slopo 的运行完全由一份 YAML 配置文件驱动；运行结束后会在报告目录输出 Markdown 索引和若干聚类文件。配置文件（可去除密钥后）和忽略文件适合提交到 Git 仓库，让团队成员共享相同的重复检测基线，而 SQLite 数据库 `slopo.db` 仅为本地数据，不应共享（[README.md:1-120]）。社区在 v0.2.0 发布说明中提到，exact-copy（完全相同副本）现在统一处理：始终纳入聚类，但在报告中以低噪声方式呈现，方便 AI 代理或审查者识别。

## 配置参数详解

Slopo 提供一个强类型的 `Config` dataclass，所有参数以及默认值、校验逻辑都集中在 [`src/slopo/config.py`](https://github.com/rafal-qa/slopo/blob/main/src/slopo/config.py) 中。通过 `slopo init` 可生成配置模板（[src/slopo/cli.py:1-90]）。

| 参数 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `source_dir` | Path | 必填 | 待索引源代码目录，绝对路径或相对路径均可（[src/slopo/config.py:1-160]）。 |
| `source_dir_exclude` | list[str] | `[]` | `.gitignore` 风格的排除模式列表。 |
| `db_file` | Path | `slopo.db` | SQLite 数据库文件，存储嵌入和元数据。 |
| `report_dir` | Path | `slopo-report` | 报告输出目录（[src/slopo/analysis/report/filesystem.py:1-30]）。 |
| `ignore_file` | Path | `slopo.ignore.txt` | 已审查聚类的忽略列表（[src/slopo/analysis/ignore.py:1-50]）。 |
| `embedding_model` | str | 必填 | LiteLLM 格式的嵌入模型名称，例如 `voyage/voyage-code-3`。 |
| `embedding_dimensions` | int | 必填 | 与所选模型匹配的嵌入维度。 |
| `embedding_api_key` | str | 必填（或环境变量） | 嵌入服务 API 密钥；可用 `SLOPO_EMBEDDING_API_KEY` 环境变量替代，且支持 `.env` 文件（[README.md:1-160]）。 |
| `embedding_batch_size` | int | `100` | API 批请求大小。 |
| `embedding_batch_chars` | int | `100_000` | API 批请求字符数。 |
| `similarity_threshold` | float | `0.92` | 余弦相似度下限，低于此值视为不相似（[README.md:1-200]）。 |
| `rerank_threshold` | float | `0.94` | 加入代码库距离加成（最多 +15% 目录跳跃、+10% 同文件距离）后的过滤门槛。 |
| `body_node_count_threshold` | int | `10` | 函数体内 AST 节点数下限，控制纳入检测的代码单元最小复杂度（[src/slopo/config.py:1-200]）。 |

> ⚠️ **不可更改参数**：`source_dir`、`embedding_model`、`embedding_dimensions`、`body_node_count_threshold` 一旦索引后便不可更改；需删除 `slopo.db` 并从头重新执行 `slopo index`（[README.md:1-160]）。

## Markdown 报告生成流程

报告生成由 [`src/slopo/analysis/report/filesystem.py`](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/report/filesystem.py) 协调，主要步骤如下：

```mermaid
flowchart TD
    A[slopo index 完成聚类] --> B[write_report 写入磁盘]
    B --> C[清理旧报告 _clean_report_dir]
    C --> D[生成 index.md 索引]
    C --> E[生成 cluster-XX.md 每个聚类]
    D --> F[Markdown 渲染<br/>build_index_markdown]
    E --> G[Markdown 渲染<br/>build_cluster_markdown]
    F --> H[查看器/AI 代理读取]
    G --> H
```

`write_report` 会先确保目录存在，然后清理已有的 `index.md` 以及匹配 `CLUSTER_FILE_GLOB`/`CLUSTER_FILE_RE` 的旧聚类文件（[src/slopo/analysis/report/filesystem.py:1-30]）。`index.md` 通过 `build_index_markdown` 生成，包含聚类总数、相似度区间、文件路径与行号摘要；每个聚类文件则由 `build_cluster_markdown` 生成，列出全部成员、代码片段以及该聚类的稳定哈希（[doc/example-report/cluster-01.md:1-30]、[doc/example-report/cluster-03.md:1-20]）。文件名由 `cluster_filename(i, total)` 决定（在 [`src/slopo/analysis/report/naming.py`](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/report/naming.py) 中实现），便于按编号排序浏览。

## 团队协作工作流

Slopo 的协作模型基于三类**可共享资产**：

1. **去除密钥后的配置文件**：保留路径与阈值，可提交至仓库。
2. **`ignore_file`**：列出已审查并标记为忽略的聚类哈希，新成员复用同一基线（[src/slopo/analysis/ignore.py:1-50]）。
3. **`slopo.db`**：本地缓存，不共享；成员各自执行 `slopo index` 重建。

聚类哈希在 [`cluster_hash`](https://github.com/rafal-qa/slopo/blob/main/src/slopo/analysis/ignore.py) 中按成员文件相对路径与 `body_hash` 的规范字符串取 SHA-256 前 12 位；任何代码或路径变动都会改变哈希，使已被忽略的聚类在修改后重新出现。`load_ignored` 会读取忽略文件并支持 `#` 注释，`ensure_ignore_file` 在首次未存在时写入提示头（[src/slopo/analysis/ignore.py:1-50]）。

```text
典型协作循环：
  1. 一名成员运行 slopo index，生成报告。
  2. 团队（人 + AI 代理）一起审查 cluster-XX.md，把确认无需重构的聚类哈希加入 ignore_file。
  3. ignore_file 提交到 Git；其它成员拉取后下次报告自动跳过这些聚类。
  4. 修改代码导致哈希变化时，相关聚类会自动重新浮现。
```

该机制使审查成为"流程状态"，而非一次性结果。配合 v0.2.0 起完全相同副本的合并展示策略，报告可在不增加噪音的前提下让所有成员快速锁定值得重构的聚类。

## 常见使用模式与注意事项

- **空报告与首次运行**：`index` 在已存在数据库时会校验 `source_dir` 是否与首次索引一致；若不一致会抛出 `ConfigurationMismatchError`（[src/slopo/cli.py:1-200]）。
- **阈值调优**：若发现太多琐碎片段，提高 `body_node_count_threshold`；若漏检较长的相似代码，可下调 `similarity_threshold`，但优先尝试下调 `rerank_threshold` 以保留更多跨文件信号。
- **安全性**：`mask_api_key` 仅保留首尾各 5 字符，便于 `show-config` 时安全回显（[src/slopo/config.py:1-200]）；密钥优先用环境变量注入。
- **报告可移植性**：所有片段使用纯 Markdown + 代码块，AI 代理可直接抓取并判断是否为真实重复（[doc/example-report/cluster-05.md:1-40]）。

## See Also

- README 主页：项目介绍与快速开始
- 主页 Wiki：[解析与嵌入管线]
- 主页 Wiki：[聚类与阈值策略]
- 示例报告目录：`doc/example-report/index.md`

---

<!-- evidence_pipeline_checked: true -->
<!-- evidence_injected: true -->

---

## Doramagic 踩坑日志

项目：rafal-qa/slopo

摘要：发现 6 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：能力坑 - 能力判断依赖假设。

## 1. 能力坑 · 能力判断依赖假设

- 严重度：medium
- 证据强度：source_linked
- 发现：README/documentation is current enough for a first validation pass.
- 对用户的影响：假设不成立时，用户拿不到承诺的能力。
- 证据：capability.assumptions | https://news.ycombinator.com/item?id=48762038 | README/documentation is current enough for a first validation pass.

## 2. 维护坑 · 维护活跃度未知

- 严重度：medium
- 证据强度：source_linked
- 发现：未记录 last_activity_observed。
- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。
- 证据：evidence.maintainer_signals | https://news.ycombinator.com/item?id=48762038 | last_activity_observed missing

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 证据：downstream_validation.risk_items | https://news.ycombinator.com/item?id=48762038 | no_demo; severity=medium

## 4. 安全/权限坑 · 存在评分风险

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：风险会影响是否适合普通用户安装。
- 证据：risks.scoring_risks | https://news.ycombinator.com/item?id=48762038 | no_demo; severity=medium

## 5. 维护坑 · issue/PR 响应质量未知

- 严重度：low
- 证据强度：source_linked
- 发现：issue_or_pr_quality=unknown。
- 对用户的影响：用户无法判断遇到问题后是否有人维护。
- 证据：evidence.maintainer_signals | https://news.ycombinator.com/item?id=48762038 | issue_or_pr_quality=unknown

## 6. 维护坑 · 发布节奏不明确

- 严重度：low
- 证据强度：source_linked
- 发现：release_recency=unknown。
- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。
- 证据：evidence.maintainer_signals | https://news.ycombinator.com/item?id=48762038 | release_recency=unknown

<!-- canonical_name: rafal-qa/slopo; human_manual_source: deepwiki_human_wiki -->
