内容
# 诱因
<!-- mcp-name: io.github.noordeen123/culprit -->
<p align="center">
<a href="https://github.com/noordeen123/culprit/actions/workflows/ci.yml"><img src="https://github.com/noordeen123/culprit/actions/workflows/ci.yml/badge.svg" alt="持续集成"></a>
<a href="https://pypi.org/project/culprit/"><img src="https://img.shields.io/pypi/v/culprit.svg" alt="PyPI 版本"></a>
<a href="https://pypi.org/project/culprit/"><img src="https://img.shields.io/pypi/pyversions/culprit.svg" alt="支持的 Python 版本"></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="许可证:MIT"></a>
</p>
<p align="center">
<b>面向智能代理开发的根本原因分析。</b><br>
您的编码代理发现了引入 bug 的原因,并验证自己的修复是否完整,然后再提交。
</p>
<p align="center">
<a href="#快速开始">快速开始</a> ·
<a href="#工具列表">工具列表</a> ·
<a href="#它真的有效吗">准确性</a> ·
<a href="docs/ARCHITECTURE.md">架构</a> ·
<a href="https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.noordeen123/culprit">MCP 注册表</a>
</p>
<p align="center">
<img src="docs/demo.gif" width="900" alt="代理的修复得分为部分通过,遗漏了两个调用站点,然后在修补它们后完成">
<br>
<em>实际运行。修复程序修补了一个 <code>parse_config</code> 的调用者,但遗漏了两个,因此得分为 <code>部分通过</code>。</em>
</p>
## 为什么代理需要这个
代理擅长编写补丁,但不擅长判断补丁是否 **完成**。
它无法看到它刚刚更改的辅助程序还有三个其他调用者,或者它正在修复的 bug 是两年前重构引入的。诱因从 git 历史记录中回答这两个问题,以结构化的 JSON 提供,而不是代理必须解释的文本:
| 代理询问 | 诱因回答 |
|---|---|
| "是什么引入了这个 bug?" | 排名靠前的可疑提交、作者的意图、发布的版本 |
| "我的修复是否完整?" | `verify_fix`:遗漏的调用站点、是否交付了测试、风险级别 |
| "这个更改可能会破坏什么?" | 反向导入依赖项、覆盖测试、高风险共享模块 |
- ⚡️ **立即生效。** 无需测试运行,无需二分查找。它将修复程序自己的行溯源到重构。
- 🔒 **只读且离线。** 永远不会写入您的仓库或 PR。无需 API 密钥,无需网络。
- 🔌 **MCP 原生。** 11 种工具通过标准输入输出,官方 MCP 注册表,以及一键安装的插件。
- 🗣️ **与语言无关。** 可疑项适用于 git 做的任何地方。辐射范围读取 12 种语言家族。
## 它真的有效吗?
针对 50 个真实回归案例进行基准测试,其中 25 个来自 [git](https://github.com/git/git),25 个来自 [systemd](https://github.com/systemd/systemd),其中引入提交的已知信息来自每个修复的 `Fixes:` 标签(作者验证的真实性)。仅给定修复提交,诱因将责备已删除的行,以对引入 bug 的提交进行排名。
| 指标 | 结果 |
|---|---|
| 引入提交排名 #1 | **50%**(25/50) |
| 引入提交在前 5 个可疑集中的排名 | **66%**(33/50) |
确定性和离线,在大型 C 代码库中,引擎从未见过。可以使用 `python benchmarks/run.py` 重现,该脚本克隆仓库并评估每个案例。
## 快速开始
**Claude Code 插件**(安装 MCP 服务器和一个技能,该技能告诉代理何时使用它):
```bash
/plugin marketplace add noordeen123/culprit
/plugin install culprit@culprit
```
**任何 MCP 客户端**(Cursor、Windsurf、VS Code、Codex CLI、Zed、Continue、Cline、Amazon Q、Goose):
```json
{
"mcpServers": {
"culprit": {
"command": "uvx",
"args": ["--from", "culprit[mcp]", "culprit-mcp"]
}
}
}
```
**CLI**,无需代理:
```bash
uvx culprit # 按需从 PyPI 运行
rca --verify-fix patch.diff # 如果完成则退出 0,否则退出 1
```
需要 Python 3.10+ 和 [uv](https://docs.astral.sh/uv/) 用于 MCP 服务器。CLI 运行于 3.9+。
## 工具列表
| 工具 | 它回答的问题 |
|---|---|
| `analyze` | 完整 RCA 调用:分类、可疑项或辐射范围、风险、测试影响 |
| `verify_fix` | 此 diff 是否可以提交?`complete` / `partial` / `risky`,以及遗漏的调用站点 |
| `find_suspects` | 对引入 bug 的提交进行排名 |
| `check_completeness` | 修复程序未触及的更改符号的调用站点 |
| `get_intent` | 引入提交的消息、链接的 PR、引用的问题 |
| `get_evolution` | 通过 `git log -L` 获取 buggy 行的历史记录 |
| `get_risk_score` | QA 门控分数(0 至 100,低/中/高)及贡献因素 |
| `get_blast_radius` | 功能影响:依赖项、覆盖测试、高风险文件 |
| `get_test_impact` | 此更改的最小测试集 |
| `classify_change` | Bugfix 与功能,具有证据 |
| `from_trace` | 直接从堆栈跟踪进行 RCA,无需 diff 或 PR |
## verify_fix,预提交门控
代理在其自己的 diff 上运行此操作,然后再提交:
- **`verdict`**:`complete` 当没有遗漏的调用站点时,`partial` 当遗漏一个,`risky` 当风险高时。判决是完整性轴;测试覆盖率是 `risk_level` 上的独立置信轴。
- **`untouched_references`**:仍使用更改符号的 exact 文件。这是代理进行修补的列表。
- **`skipped_symbols`**、**`adds_test`**、**`notes`**:什么太广泛而无法检查,是否交付了测试,以及下一步骤。
循环直到 `complete`,然后提交。这就是整个想法。
## CLI 和 CI
```bash
rca # 当前分支与配置的基准
rca --last # 仅最新的提交
rca --pr 16786 # 特定的 PR(使用 PR 自己的基准)
rca --trace crash.txt # 从堆栈跟踪进行 RCA,无需修复或 PR
rca --verify-fix patch.diff # 在提交前检查 diff
rca --select-tests # 打印此更改要运行的测试
rca --html report.html --open # 一个自包含的 HTML 报告
rca --pr 16889 --fail-on high # 当 QA 风险高时退出非零
rca serve --repo /path # 本地 Web UI,带有基准选择器
```
**CI 门控**:仅通过退出代码的风险,无需 PR 评论,无需写入。复制
[`examples/github-actions/culprit-pr.yml`](examples/github-actions/culprit-pr.yml) 到
`.github/workflows/`:
```yaml
- run: pip install "culprit>=0.3.0"
- env: { GH_TOKEN: "${{ github.token }}" }
run: rca --pr ${{ github.event.pull_request.number }} --fail-on high
```
## HTML 报告
`--html` 编写一个自包含的文件。无需 CDN,可离线打开,附属于 CI。它打开时显示判决:带有影响因素的 QA 风险评分,以及主要可疑提交及其持续时间。
<p align="center">
<img src="docs/report-verdict.png" width="820" alt="QA 风险评分为中等 48 分,带有影响因素,主要可疑提交及其发布的版本">
</p>
然后它重建了 bug 的来源。每个修改了 buggy 行的提交,从创建到破坏它的提交(红色,带有确切的 diff)到修复(绿色):
<p align="center">
<img src="docs/report-timeline.png" width="820" alt="行演化时间线:起源,三个修改,破坏提交将 w times h 更改为 w 加 h,然后修复恢复它">
</p>
<p align="center"><em>每个节点都扩展到其 diff。 <a href="docs/report.png">查看完整报告</a>。</em></p>
## 与 `git bisect` 的比较
| | `git bisect` | 诱因 |
|---|---|---|
| 输入 | 可靠的失败测试 | 修复 diff(或堆栈跟踪) |
| 方法 | 签出提交并运行测试 | 责备修复的行加上 `git log -L` |
| 速度 | 分钟(大约 log2(N) 测试运行) | 立即生效 |
| 输出 | 第一个错误提交 | 可疑集、意图、生命周期、完整性、风险 |
| 置信度 | 证明 | 强启发式 |
`--bisect "<cmd>"` 运行一个真正的二分查找作为可选的确认层,在一个临时
`git worktree` 中,因此您的检出永远不会被触及。当第一个失败的提交与责备的可疑项匹配时,报告会将其标记为 **confirmed by git bisect**。
## 架构
一个规范化的上下文输入,一个结构化的 JSON 结果输出。唯一不确定的步骤是可选的 LLM 叙述,它被隔离在适配器后面,因此引擎在没有 API 密钥的情况下运行。
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="docs/workflow-dark.svg">
<img src="docs/workflow-light.svg" width="980" alt="两条流水线。根本原因:输入、pr_context、分类、可疑项、风险评分、输出。验证:提议的 diff、verify_fix、判决。">
</picture>
</p>
两个通道,一个引擎。每个模块写入一个结果切片,因此没有任何模块关心目标来自 `gh`、REST API、本地 git 或粘贴的堆栈跟踪。完整的模块映射:
[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md)。
## 配置
基准分支按以下顺序解析:`--base` 标志,然后 `CULPRIT_BASE`,然后 `.culprit.toml`
(`base = "origin/main"`),然后 `HEAD~1`。`--last` 强制使用最新提交视图。
PR 标题和标签使用 GitHub CLI(如果存在),或公共仓库的未经身份验证的 REST API(设置 `GITHUB_TOKEN` 或 `GITLAB_TOKEN` 以提高限制)。深度链接涵盖 GitHub、GitLab、Bitbucket 和 Gitea。辐射范围读取 JS/TS、Python、Go、Java/Kotlin、Ruby、C/C++、C#、PHP、Rust、Scala 和 Swift 之间的导入。
## 贡献
```bash
pip install -e ".[dev]" && pytest
```
模块映射和数据形状:[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md)。将 MCP
服务器发布到注册表:[`docs/PUBLISHING.md`](docs/PUBLISHING.md)。MIT 许可。