Obviously-Not/concept-scanner

GitHub: Obviously-Not/concept-scanner

基于本地 LLM 的代码库工程概念扫描器,自动提取并评估独特的技术机制,输出结构化评审结果。

Stars: 0 | Forks: 0

# 概念扫描器 本地优先的**工程概念扫描器**,用于代码库分析。将其指向某个代码仓库或目录,它会提取出独特的技术机制(即“概念”),并根据四个核心工程质量维度(技术独特性、实现深度、问题特异性、通用性)及补充信号对它们进行评分,最后将结果保存在本地供您审查。 JSON 输出与 [Obviously-Not 平台](https://github.com/Obviously-Not) 的 `code_scan` 流水线(`CharacterizationOutputSchema` v1.3.0)在数据结构上完全匹配——仅包含工程词汇,不涉及法律术语。目前的兼容性是通过字段级别的检查来确认的;尚未针对线上平台的解析器进行实际验证。法律审查是由具备专业资质的人员单独执行的下游步骤。 默认情况下,所有分析都通过本地的 [Ollama](https://ollama.ai) 模型运行,因此**您的代码会保留在您的机器上**:无需 API 密钥,不进行云端调用,也没有单次扫描成本。您也可以选择将其指向远程的 OpenAI 兼容提供商(`--provider openai-compatible`),这会将您的源代码发送到该端点;详情请参阅 [PROVIDERS.md](PROVIDERS.md)。 ## 快速开始 ``` # 安装并启动 Ollama (https://ollama.ai) ollama serve # 构建 scanner go build -o concept-scanner . # 扫描本地目录(或远程 repo URL)。 # 首次运行时,具有 memory-aware 的交互式 picker 会帮助您选择模型。 ./concept-scanner scan ./my-project # 以交互方式查看发现的 concepts ./concept-scanner review # 将已批准的 concept 导出为 JSON 草稿 ./concept-scanner submit ``` ## 在 Docker 中运行 预构建的镜像已发布至 GHCR 和 Docker Hub: ``` docker pull ghcr.io/obviously-not/concept-scanner:v1 # 或者:docker pull leegitw/concept-scanner:v1 ``` 扫描器将连接您**主机上的 Ollama**。在容器内部,`localhost` 指向的是容器自身的环回地址,而非宿主机,因此需要将 `--ollama-host` 指向宿主机: ``` # macOS / Windows (Docker Desktop): docker run --rm -v "$PWD:/workspace" ghcr.io/obviously-not/concept-scanner:v1 \ scan /workspace --ollama-host http://host.docker.internal:11434 # Linux:添加 host-gateway 映射(或使用 --network host): docker run --rm --add-host=host.docker.internal:host-gateway \ -v "$PWD:/workspace" ghcr.io/obviously-not/concept-scanner:v1 \ scan /workspace --ollama-host http://host.docker.internal:11434 ``` 如果希望使用远程提供商而不是宿主机的 Ollama,请传入 `--provider openai-compatible --base-url ... --primary-model ...` 以及 API 密钥环境变量(`-e OPENROUTER_API_KEY=...`)。请参阅 [PROVIDERS.md](PROVIDERS.md)。 若要将 Ollama 与扫描器打包在一起运行(无需宿主机 Ollama),可以使用内置的 [`docker-compose.yml`](docker-compose.yml)。注意:除非进行 GPU 直通(仅限 NVIDIA/Linux;Apple Silicon 上的 Docker 无法进行 GPU 直通),否则容器中的 Ollama 只能使用 CPU。因此在 Mac 上,上述使用宿主机 Ollama 的方法通常会更快。 ## GitHub Action 在 CI 中运行概念扫描。这是一个 Docker action,因此仅在 **Linux runner** 上运行。GitHub 托管的 runner 无法运行本地 LLM,因此在那里必须使用远程的 OpenAI 兼容提供商;而在带有 Ollama 的自托管 runner 上,您可以改用本地、无外网请求的模式。 ``` # .github/workflows/concept-scan.yml name: concept-scan on: [workflow_dispatch] jobs: scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: Obviously-Not/concept-scanner@v1 with: provider: openai-compatible base-url: # see PROVIDERS.md model: # see PROVIDERS.md api-key: ${{ secrets.OPENROUTER_API_KEY }} # a secret, never inline ``` 输入参数:`repo-path`(默认为 `.`)、`provider`、`base-url`、`model`、`ollama-host`、`api-key`、`extra-args`。`api-key` 必须作为 secret 传入。具体的端点和模型字符串请参见 [PROVIDERS.md](PROVIDERS.md)。该 action 不附带默认的提供商或密钥:由您自己提供后端,这与本地运行的方式完全一致。 ## 选择模型 首次交互式运行时会显示一个**内存感知选择器**,它会检测您的 RAM 并 推荐合适的配置方案,同时会标记出任何对您的机器而言过大的选项。您的选择 将被保存到 `data/config.json` 并在后续运行中复用。随时可以通过 `concept-scanner init` 重新选择。 | 配置方案 | 模型 | 预估 RAM | 备注 | |---------|----------|-------------|-------| | **Fast** | `qwen2.5-coder:7b` | ~7 GB | 适用于任何笔记本电脑的快速扫描 | | **Balanced**(推荐) | `qwen3-coder:30b` | ~22 GB | 能力与体积的最佳平衡 | | **Validated** | `qwen3-coder:30b` + `gpt-oss:20b` | ~38 GB | 增加了一个 Pass 2 验证模型 | | **Thorough** | `qwen3-coder-next` | ~50 GB | 更大的 MoE 模型,速度较慢 | | **Custom** | 任何 Ollama tag | — | 输入您自定义的模型 | 模型解析优先级:显式参数(`--primary-model` / `--multi-model`) → 已保存的 `data/config.json` → 交互式选择器(仅限 TTY) → 内置默认值。要在 非交互式环境(CI、脚本)中运行,请传入带 `--primary-model` 的 `--no-interactive`: ``` # 使用特定的已安装模型,无提示(支持 single-pass 或 multi-model) ./concept-scanner scan ./my-project --no-interactive --primary-model qwen2.5-coder:7b # 并行使用两个模型并进行 merge 步骤 ./concept-scanner scan ./my-project --multi-model \ --primary-model qwen3-coder:30b --secondary-model gpt-oss:20b ``` 除非您传入 `--no-auto-pull`,否则缺失的模型会在首次使用时自动下载。 接受任何已安装的 Ollama 模型;无法识别的 tag 会提示一行注意事项,并按原样运行。 ## 工作原理 1. **收集**源代码文件(跳过 `vendor`、`node_modules`、`.git` 等)。 2. 在扫描前**验证**目标——包括符号链接逃逸、设备文件和 zip 炸弹检查(远程克隆的代码库还会受到仓库大小/文件数量的限制)。 3. 通过本地模型利用基于原则的提取(PBD)来**提炼**每个文件。 4. **合成**候选概念。 5. 从四个核心工程维度(技术独特性、实现深度、问题特异性、通用性)以及补充信号(普遍性、范式转变)对每个概念进行**刻画**。商业维度(产品核心性、可防御性)会输出为 `null`——因为概念扫描器没有您的市场上下文信息,所以这些字段需要由下游的使用者(您的审查流程或平台入口)来填充。输出结果还会包含该概念的关键见解、输入/输出、组件以及可比的技术。 6. 结合依赖许可证风险和 git 作者信息进行**丰富**。 7. 将结果**保存**到 `./data/scans/` 目录下,同时生成一个 `SUMMARY.md`,并将溯源审计日志保存在 `./data/audit/` 下。 当生成过程触及 token 上限时会**直接报错**,而不是静默截断,并且所有 输出的文本都会经过一层输出检查,以确保结果中不包含法律术语。 ## 命令 | 命令 | 用途 | |---------|---------| | `scan ` | 扫描目录或远程代码仓库以提取概念 | | `review ` | 逐步检查发现的概念并进行批准/拒绝操作 | | `submit ` | 将已批准的概念导出为符合平台规范的 JSON 草稿 | | `triage --workspace ` | 在已完成的扫描上重新运行溯源分类(`scan` 会自动运行它;这主要用于在更改模型/提示词后重新运行) | | `bridges ` | 在已完成的扫描上发现跨概念桥梁(Pass 3 组合) | | `models` | 列出推荐的模型方案,并显示哪些已经下载到本地 | | `init` | 重新运行内存感知模型选择器并保存选择 | | `version` | 打印版本信息和默认模型 | ## 常用参数 (`scan`) | 参数 | 描述 | |------|-------------| | `--primary-model` / `--secondary-model` | 显式选择模型(可以是任何已安装的 Ollama tag) | | `--multi-model` | 并行运行两个本地模型并合并结果 | | `--no-interactive` | 跳过首次运行时的选择器;使用已保存的配置或默认值(适用于 CI/脚本) | | `--skip-review` | 仅进行单次扫描——跳过 Pass 2 验证模型(速度更快) | | `--thorough` | 使用体积更大、质量更高的模型 | | `--include-textbook` | 同时输出被分类为 `textbook` 的概念(默认行为:对所有机制进行分类,但暂不发 `textbook` 的概念——见下文) | | `--two-phase` | 实验性功能。将生成过程分为两次调用执行(自由格式提炼,然后是结构化提取),而不是一次受语法限制的调用(见下文的“两阶段生成”)。也可以通过 `CS_TWO_PHASE=1` 来设置。 | | `--extract-model` | `--two-phase` 使用的第二阶段提取模型(默认为 `gpt-oss:20b`)。也可使用 `CS_EXTRACT_MODEL`。 | | `--timeout` | 单次请求的推理超时时间(单次调用默认为 10m,在 `--two-phase` 下为 30m)。针对慢速模型或大批量任务可适当调大。 | | `--no-triage` | 跳过针对每个概念的溯源分类阶段(速度更快;会将未落地的概念标记为 `pending`,而不是 `file_missing` 或 `rescued`) | | `--no-auto-pull` | 如果模型缺失则直接报错,而不是自动下载 | | `--ollama-host` | Ollama API URL(默认为 `http://localhost:11434`) | | `--full-history` | 获取完整的 git 历史记录,以获得更丰富的文件溯源信息 | | `--json` | 输出机器可读的 `{ data, next_steps, notice }` 数据封装(见“机器可读输出”) | | `-v, --verbose` | 详细的进度输出 | 运行 `./concept-scanner scan --help` 获取完整列表。 ## 概念输出与落地状态 每个发现的概念都会附带一个 `grounding` 字段,用于记录 扫描器是如何验证其 `location.file` 的: | 状态 | 含义 | |-------|---------| | `grounded` | 模型输出的路径在当前工作区中原样解析为了一个真实存在的文件。 | | `repaired` | 模型输出的路径格式错误,最终处理阶段自动进行了修复(例如 `src/foo.ts` → `app/src/foo.ts`)。 | | `rescued` | 通过模糊文件名搜索或 LLM 分类调用,找到了该概念实际所在的真实文件。最初 LLM 输出的路径会保存在 `grounding_original_file` 中。 | | `file_missing` | 分类阶段搜索了候选文件,但无法在任何地方将该概念落地——极有可能是模型幻觉。 | | `uncertain` | 运行了分类阶段,但模型无法给出明确结论。 | | `pending` | 跳过了分类阶段(`--no-triage`)。 | 下游消费者通常会筛选出 `grounded`、`repaired` 或 `rescued` 状态的概念, 并对 `file_missing` / `uncertain` 状态的概念保持应有的怀疑态度。 ## 分类(`distinctive` / `borderline` / `textbook`) 扫描器会**提取并分类它发现的每一个机制——它绝不会 默默地丢弃任何一个。** 每个概念都包含一个 `classification` 字段: | 类别 | 含义 | |-------|---------| | `distinctive` | 同时满足所有三个工程维度的门槛(技术独特性、实现深度、问题特异性)。 | | `borderline` | 满足其中一个或两个维度,或者虽然是常见模式但属于非常强的实例。 | | `textbook` | 标准库用法、常见设计模式或常规的实现。 | 保留还是丢弃的决策是一个**下游的、可调的步骤**,而不是模型 在提示词中执行的操作:默认情况下,结果会包含 `distinctive` + `borderline` 并**保留 `textbook` 不输出**(但仍会报告它们的数量,因此没有任何内容被隐藏)。传入 `--include-textbook` 可将它们包含在结果中。正因如此,当强大的前沿模型面对一个浅薄的代码库时,不再会返回空集——它会将标准模式 分类为 `textbook`,而不是自我审查到什么都不输出。 ## 两阶段生成(`--two-phase`,实验性功能) 默认情况下,每个生成阶段(发现、刻画、桥梁合成) 都是一次单独的调用,其解码过程受到 JSON schema 的语法限制。这对于 指令/代码模型来说既快速又可靠,但这没有给推理模型留下 任何推理空间(schema 会强制从第一个 token 开始就是 JSON token),而且在远程 提供商上,往往会导致描述性字段的内容不够丰富。 `--two-phase` 会将这些阶段中的每一个拆分为**两次**调用执行: 1. **提炼(自由格式):** 主模型用散文形式描述该机制, 不受 schema 约束,因此推理模型可以真正进行推理。 2. **提取(结构化):** 一个快速的指令模型(`--extract-model`,默认为 `gpt-oss:20b`)将该段散文转换为符合 schema 结构的 JSON。 这与扫描器所匹配的模式相呼应,预期这将允许 推理模型参与到发现过程中,并自然地填充描述性字段 (从而淘汰远程刻画的补全回退机制)。这会使得每项 消耗两次调用而不是一次;但提取调用的体量很小且速度很快。 该模式**默认关闭**,目前正在与单次调用路径进行 A/B 测试, 之后才会考虑将其为默认值。使用 `--two-phase`(或 `CS_TWO_PHASE=1`)启用它,并 通过 `--extract-model `(或 `CS_EXTRACT_MODEL`)选择提取器。它 目前适用于单模型路径以及刻画和桥梁 合成阶段;多模型(`--multi-model`)的 Pass 1 发现阶段暂不支持两阶段模式。 自由格式的提炼在每个批次上花费的时间更长(因为它生成的是散文,而且推理 模型的推理过程通常很长),因此 `--two-phase` 将单次请求的超时底线 提高到了 **30 分钟**,以确保大批量任务能够跑完,而不是在提炼过程中被强制终止。 如果您的模型需要更多时间,请使用 `--timeout` 覆盖该设置,并注意,由于每项 需要进行两次调用,其实际耗时明显高于单次调用路径。 ## 机器可读输出(`--json`) 每个产生输出的命令(`scan`、`review`、 `submit`、`bridges`、`triage`)都支持 `--json`,并发出与平台对齐的 HATEOAS 数据封装——在成功和失败时保持相同的数据结构,因此一个解析器即可处理所有情况。 进度信息会输出到 stderr,因此 stdout 是纯 JSON。(`review --json` 是一个 非交互式的**状态**投影——它报告当前的审查状态, 而不是提示用户进行操作。) ``` { "data": { "scan_id": "...", "concepts": [ ... ], "textbook_held": 12 }, "next_steps": [ { "action": "Review the discovered concepts", "command": "concept-scanner review ", "priority": "high", "reason": "Approval gates submission", "timing": "soon" } ], "notice": "12 textbook-classified concept(s) held back (use --include-textbook to include them)." } ``` 失败时,`data` 为 `null`,错误信息包含在 `notice` 中。每个命令的输出 (以及每个错误)都至少包含两个优先级排序的 `next_steps`,附带原因和 可直接运行的 `command`,因此无论是人类还是 AI agent 都能随时知道下一步 该做什么——即使在返回零个概念时也是如此。 ## 环境要求 - 本地运行 [Ollama](https://ollama.ai) - Go 1.25+(用于从源码构建) - 足够的 RAM/VRAM 来支撑所选的模型。选择器会标记超出您 检测到的内存上限的配置方案;**Fast** 方案(`qwen2.5-coder:7b`)可以在大多数笔记本电脑上运行。 ## 隐私 - 不会对外部服务发起 API 调用 - 所有处理过程都在您的机器上本地进行 - 代码绝对不会离开您的本地环境 - 无限次扫描(无单次调用成本) 该隐私保证的前提是 Ollama 在本地运行。如果您将 `--ollama-host` 指向了一个远程地址(除了 `localhost` / `127.0.0.1` 之外的任何地址),扫描器在启动时会记录一条警告——但请求 仍会被发送出去。**请在同一台机器上运行 Ollama,以确保隐私承诺成立。** ## 贡献与社区 - [CONTRIBUTING.md](CONTRIBUTING.md) — 开发环境设置、您在提交 PR 时 可能会遇到的测试检查,以及在这里什么样的改动才是好的改动 - [SECURITY.md](SECURITY.md) — 如何私下报告安全问题 - [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) — Contributor Covenant 2.1 - [patent-skills](https://github.com/Obviously-Not/patent-skills) — ObviouslyNot 生态系统中的一个 开源姊妹项目(用于专利扫描的 AI agent 技能)。此链接 仅作为背景参考,并非依赖项:concept-scanner 可以完全独立运行。 ## 开源许可 Apache-2.0 — 请参阅 [LICENSE](LICENSE)。
标签:AI风险缓解, Clair, EVTX分析, GitHub Action, Go语言, LLM评估, Ollama, 代码质量评估, 日志审计, 本地大模型, 程序破解, 请求拦截, 错误基检测, 静态代码分析