关于 overllm
overllm 是用于 Python、JavaScript 和 TypeScript 的静态分析工具,可发现代码中不必要或配置错误的 LLM 调用。它也提供 MCP 服务,让 Agent 扫描文件或代码片段,并给出具体替代方案。
主要功能
- 01识别可由普通代码替代的模型调用
- 02检测循环调用及提示词注入风险
- 03检查模型 ID 与参数配置
- 04支持基线、修复和多种输出格式
- 05本地分析,不调用模型或上传代码
适用场景
- 01在提交或 CI 检查中拦截问题
- 02审查项目中的不必要 LLM 调用
- 03通过 MCP 扫描文件或代码片段
MCP 相关
MCP 服务提供 scan_path 和 scan_code 两个工具,可扫描磁盘上的文件或目录,以及内联代码片段。返回规则、位置和建议替代方案,不会修改内容。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
overllm
找出那些本不必发起的 LLM/AI 调用。
overllm 是一款小巧、快速的代码检查工具,只做一件事:找出代码中那些用 AI 模型处理时不如普通代码处理好的地方。你调用 GPT 来解析日期,调用模型提取 json.loads 已经能处理的 JSON。你为了一个正则表达式,付出了延迟、金钱和不确定性的代价。
它使用真正的解析器读取代码:Python 使用标准库 ast,JavaScript 和 TypeScript 使用 tree-sitter。不运行模型,不联网,也不需要 API 密钥。相同的代码输入,得到相同的结果。速度足够快,适合用作提交前钩子。
成本仪表板和缓存处理的是你已经决定要发起的调用。overllm 会更早地提出问题——这次调用真的有必要吗——并在你运行任何操作之前,根据源代码给出答案。其他工具都在检查 AI 写出的代码;overllm 则会找出你在哪些地方花钱让 AI 做库已经能做的事。
安装
pip install overllm # Python
pip install "overllm[js]" # adds JavaScript / TypeScript support
使用
先对单个文件运行,看看它会标出什么,再对所有文件运行:
overllm app.py # one file
overllm src/ # a folder
overllm . # the whole project
它会读取你的代码并打印发现的问题。默认情况下,它不会写入或修改任何内容——直接运行最坏也只会输出几行内容。唯一会编辑文件的模式是选择启用的 --fix(见下文),且仅适用于两种机械式安全修复。
示例输出:
app.py:42:5 llm-mechanical LLM call asks the model to sort
resp = client.chat.completions.create(model="gpt-4o", messages=[...])
-> use sorted()
app.py:88:1 llm-in-loop LLM call inside a loop: one API round-trip per iteration
completion(model="gpt-4o", messages=[{"role": "user", "content": f"tag {x}"}])
-> batch the inputs into a single call, cache repeated results, or use a function
2 needless LLM calls in 1 file.
默认情况下它不会输出任何信息。只显示 warning 和 error 级别的问题,因此干净的项目不会打印任何内容,并以 0 退出——大多数代码库只会发现少数问题,甚至没有问题。如果它输出过多,请将其视为 bug 并提交问题。
overllm 发现问题时会以非零状态退出,因此可以用来拦截提交或 CI 检查。传入 --exit-zero 即可只报告问题而不导致失败。
你的代码会留在自己的设备上
overllm 是静态分析工具。它会在本地解析文件,然后打印发现的问题。它绝不会上传你的代码、调用 API、索要密钥或发送遥测数据——整个过程中没有模型参与,也不会向外发送任何数据。拔掉网线,它的运行结果也完全一样。
核心部分只有几千行 Python 代码,没有必需的依赖项,因此你可以先通读全部代码,再决定是否信任它。overllm[js] 会添加用于解析 JavaScript 和 TypeScript 的 tree-sitter;这是唯一的可选依赖项。
规则
每条规则只会在遇到明确的代码模式时触发,并且每条发现都会给出确定的替代方案。无法确定时,它会保持沉默。
默认情况下,overllm 只会报告 warning 及以上级别,因此不会打扰日常编码。static-prompt 的级别是 info,除非你通过 --all 或 --min-severity info 请求检查,否则它会保持沉默。
| 规则 | 严重级别 | 触发条件 | 建议 |
|---|---|---|---|
llm-mechanical | error | 提示词要求进行机械式转换:排序、反转、计数、求和、去重、大小写转换、base64、对字面量进行算术运算。 | 一行标准库等效代码 |
llm-extraction | error | 提示词要求模型提取电子邮件地址、URL、日期或数字。 | 正则表达式、datetime 或 urllib.parse |
prompt-injection | error | 不可信的 Web 请求输入(request.args、request.json 等)直接流入提示词。 | 将其放在单独的用户消息中,验证输入,并限制模型 |
llm-in-loop | warning | 每次循环迭代都会运行一次大模型调用(实际调用 N 次,不是流式传输)。 | 批处理、缓存,或将调用移出循环 |
deprecated-model | error / warning | model ID 是已退役的模型(调用会返回 404),或已弃用且计划移除的模型。 | 切换到它所指出的当前模型 |
unsupported-params | warning | 在不支持这些参数的模型上设置了 temperature / top_p / top_k——OpenAI 推理系列(o1、o3 等)以及最新的 Anthropic 模型。 | 移除该参数,改用提示词引导 |
json-mode-missing-json | error | 设置了 response_format={"type": "json_object"},但完全静态的提示词从未包含单词 "json"——这必定会导致 OpenAI 返回 400。 | 在消息中加入 "json",或使用 json_schema 格式 |
static-prompt | info | 用户提示词是编译时常量,不含变量。输入固定不变,因此这次调用没有收益。 | 预先计算或缓存结果 |
最后两条规则检查的是调用本身,而不是提示词:模型 ID 已不存在,或模型会忽略某个参数。两者都只会与已知列表进行精确匹配,因此不会误报仍在使用的模型或别名。列表会跟踪服务提供商的弃用页面,并需要随时间更新。
它可检测 Python 中 OpenAI、Anthropic、Google、Mistral、Cohere、Groq、AWS Bedrock、HuggingFace、Replicate、LangChain、LiteLLM 和 Ollama SDK,以及 JavaScript 和 TypeScript 中的 Vercel AI SDK(generateText、streamText、generateObject)和 openai / anthropic node SDK,还能检测向这些主机发出的原始 HTTP 请求。它还会跟踪模型在 LCEL 组合 中的传递过程——例如 chain = prompt | model | parser 管道、绑定模型(.with_structured_output(...))或别名——因此也能识别 chain.invoke(...);嵌入调用(embeddings.create)也会计入。如果调用经过自定义封装或 overllm 无法识别的框架,请在 llm_calls(见下文)中为其命名。
忽略误报
resp = client.chat.completions.create(...) # overllm: ignore
resp = client.chat.completions.create(...) # overllm: ignore=llm-in-loop
在文件顶部添加 # overllm: ignore-file,即可跳过整个文件。
配置
在 pyproject.toml 中(Python 3.11+):
[tool.overllm]
ignore = ["llm-in-loop"]
exclude = ["examples/", "migrations/"]
llm_calls = ["myapp.llm.ask", "chat_service.complete"]
也可以在命令行中使用:--select、--ignore、--min-severity、--all 和 --config PATH(exclude 只能在配置中设置)。运行 overllm --help 查看完整列表。
让 overllm 识别你自己的封装
大多数代码不会直接调用 SDK,而是通过封装调用它(def ask(prompt): client.chat.completions.create(...))。如果封装和调用位于同一文件中,overllm 会自动跟踪该封装。如果调用经过框架、服务提供商层,或 **kwargs 展开,overllm 就无法识别 SDK 调用,因此请在 llm_calls 中填写封装名称。此后,ask(...) 调用会被视为大模型调用——overllm 会读取提示词参数,并运行循环和成本规则。名称可以是简单名称(ask)、点分名称(myapp.llm.ask),也可以是以简短名称导入的点分路径。
在现有代码库中采用(基线)
在旧仓库上运行 overllm,会得到一大堆你永远也处理不完的问题。只需快照一次,让 CI 只标记此后新增的问题:
overllm . --write-baseline # writes overllm-baseline.json — commit it
overllm . --baseline # reports only findings new since the snapshot
overllm . --update-baseline # ratchet: also drop entries you've since fixed
快照使用规则 + 文件 + 代码 + 模型作为每个问题的标识,而不是行号,因此上方无关的编辑不会导致标识失效。它还会统计每个问题出现的次数,而不是只比较总数,因此即使你恰好在其他地方删掉了一个旧问题,新增的不当调用仍会触发检查。
修复安全的问题(--fix)
其中两条规则各自都有一个明确的修复方案,因此 overllm 可以直接替你完成:
overllm . --fix # drop a sampling param the model rejects (safe)
overllm . --fix --unsafe-fixes # also swap a retired model id for its replacement
overllm . --fix --diff # print the patch, don't touch anything
单独使用 --fix 只会执行安全的修复(unsupported-params)。替换模型 ID 会改变代码在运行时的实际行为,因此需要使用 --unsafe-fixes。修复会编辑语法树,而不是原始文本,因此注释和字符串不会受到影响;此外,overllm 会在保存前重新解析文件,如果编辑会导致解析失败,就会放弃此次修改。其余五条规则需要人工判断,因此 overllm 不会修改它们。
Pre-commit 钩子
在 .pre-commit-config.yaml 中:
repos:
- repo: https://github.com/theadamdanielsson/overllm
rev: v0.6.0
hooks:
- id: overllm
GitHub Action
overllm 提供一个 Action,用于扫描拉取请求并留下一条有依据的评论。如果没有需要说明的问题,它就会保持安静。
name: overllm
on:
pull_request:
permissions:
contents: read
pull-requests: write
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: theadamdanielsson/overllm@v1
with:
paths: "."
其他输出格式
overllm --format json . # machine-readable
overllm --format sarif . # upload to GitHub code scanning
overllm --format github . # GitHub Actions inline annotations
overllm --format markdown . # the PR-comment body
GitHub 代码扫描(SARIF)
overllm 可以输出 SARIF,因此问题会显示在 Security 选项卡和差异内联视图中。它在公开仓库中免费使用:
name: overllm-scan
on: [push, pull_request]
permissions:
contents: read
security-events: write # required to upload results
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pipx run overllm . --format sarif --exit-zero > overllm.sarif
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: overllm.sarif
category: overllm
从 Agent 使用(MCP 服务)
overllm 提供 MCP 服务,因此 AI Agent(Claude Desktop、Cursor 或任何支持 MCP 的工具)都可以调用它,检查代码中不必要的模型调用。它提供两个工具:scan_path(磁盘上的文件或目录)和 scan_code(以内联方式传入的代码片段)。两者都会返回与 CLI 相同的问题,包括规则、位置和具体的替代方案,并且都不会写入或更改任何内容。
安装服务版本并将客户端指向它(服务需要 Python 3.10+;检查器本身仍可在 3.9 上运行):
pip install "overllm[mcp]"
{
"mcpServers": {
"overllm": {
"command": "uvx",
"args": ["--from", "overllm[mcp]", "overllm-mcp"]
}
}
}
然后向 Agent 提出类似“扫描此仓库,找出不必要的大模型调用”或“这个函数是不是浪费了一次模型调用?”的问题,它就会给出有依据、确定的检查结果,而不是猜测。
为什么不直接使用 AI 代码审查工具?
AI 审查工具和 AI 代码垃圾检查器关注的是模型生成的代码:注释、死代码和结构。它们都不会提出 overllm 关注的问题:是否根本不需要调用模型。这是一个不同的维度,而普通静态分析就能以很高的准确率、零成本回答这个问题。
贡献
你最能帮上忙的是报告误报:提供一行真实代码,说明 overllm 错误标记了不该标记的调用。只有结果准确,检查器才值得使用,因此一个具体的错误标记比功能请求更有价值。CONTRIBUTING.md 介绍了如何报告误报以及如何运行测试。
以往的版本发布记录和变更内容见 CHANGELOG.md。
许可证
MIT © Adam Danielsson
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。