Merge pull request #146 from gesi519/fix-incremental-same-named-functions Fix incremental selection of same-named methods
Merge pull request #146 from gesi519/fix-incremental-same-named-functions
Fix incremental selection of same-named methods
English | 中文
官网 · 论文
FM-Agent 是首个实现大规模系统正确性全自动推理的框架,支持的软件包括14万行代码的 Claude C Compiler。
它包含三个步骤:
FM-Agent 的官方网站提供了在线代码库推理服务,欢迎体验!
⚠️ 注意:本框架的推理效果受所使用模型的能力影响较大。使用能力较弱的模型时,可能出现幻觉(hallucination),导致错误的推理结论。建议使用推理能力较强的模型(例如Claude Sonnet 4.6)以获得更可靠的结果。
|-- main.py # 程序入口 —— 编排整个流水线 |-- dashboard.py # 独立的实时 TUI 监控面板 |-- config.py # 配置(模型、粒度、并发、超时等) |-- install.sh # 依赖安装脚本 |-- pyproject.toml / uv.lock # Python 项目元数据与锁定的依赖(uv) |-- .env.example # .env 运行时配置模板 |-- src/ # 核心源码模块(提取、推理、LLM 交互等) |-- md/ # 引导 Agent 推理的工作流说明文档 |-- docs/ # 补充文档(如 OpenCode/LLM provider 配置)
bunx
rebar.config
./install.sh --with-erlang
以下 macOS 环境已使用安装脚本测试:
设置 FM-Agent 和 OpenCode 共用的 LLM API 密钥。推荐使用 OpenRouter:FM-Agent 会并发调用 LLM,而 OpenRouter 的 RPM(每分钟请求数)和 TPM(每分钟 Token 数)限制更宽松——不过任何兼容的 provider 都可以。
把 API 密钥放进 .env(已 gitignore,FM-Agent 通过 python-dotenv 自动加载);其余所有配置在 fm-agent.toml 里都有 committed 的默认值。复制模板:
.env
fm-agent.toml
cp .env.example .env # 然后编辑 .env,填入 LLM_API_KEY
# .env(只放密钥) LLM_API_KEY=your-api-key-here
非密钥配置——模型、endpoint、backend、provider 等——在 fm-agent.toml 的 [llm] 段,直接改它是永久生效的做法。若不想动这个被 git 跟踪的文件(比如你是 git clone、之后会 git pull 更新),可以用对应的环境变量覆盖,写在 .env 或 shell 里即可。优先级为 env > .env > fm-agent.toml;由于 .env 会盖过 toml,残留的旧值会覆盖你后来对 toml 的修改——所以改了 toml 不生效时,先检查 .env。详情及 OpenCode provider 配置见 docs/config_llm.md。
[llm]
git pull
env > .env > fm-agent.toml
上述所有依赖(Ubuntu 和 Python 除外)均可通过以下脚本一键安装:
./install.sh
Erlang 工具链不影响其他语言,因此默认不安装。如需自动安装或检查 Erlang/OTP 26+、rebar3 3.24.0+ 和兼容的 ELP 发布包,请运行:
该选项在 macOS 上使用 Homebrew;在 Ubuntu 上,当系统 OTP 缺失或版本过低时使用 RabbitMQ Team Erlang PPA。Ubuntu 配置已使用 Erlang/OTP 26+ 验证;macOS Erlang 配置尚未测试,将使用 Homebrew 选择的当前公式版本。Linux 下的 rebar3 和 ELP 会安装到 ~/.local/bin,请确保新终端的 PATH 包含该目录。你也可以手动安装这些工具,确认 rebar3 version 和 elp version 可执行,并在需要时将 ELP_COMMAND 设置为 ELP 的绝对路径。
~/.local/bin
PATH
rebar3 version
elp version
ELP_COMMAND
FM-Agent 会从 fm-agent.toml 自动配置 OpenCode 的 provider,因此无需手动编辑 ~/.config/opencode/opencode.json 来设置模型或密钥(见 docs/config_llm.md)。
~/.config/opencode/opencode.json
重要提示: FM-Agent 会根据推理过程自动生成测试用例,以触发潜在 Bug,帮助开发者定位和修复问题。运行 FM-Agent 前,请确保目标代码库的测试环境已就绪。如需提供项目特定的验证指令,请使用 --bug-validator;否则,Agent 将自主决定测试用例的执行方式。
--bug-validator
配置项都在 fm-agent.toml 里(每一项都有就近注释),也可用对应的环境变量覆盖。完整参数、默认值与描述的参考表见 docs/configuration_zh.md。
重要说明: 强烈建议使用 Claude Sonnet 4.6 等能力较强的模型,其他模型可能推理能力,无法有效发现 Bug。此外,请使用有权限访问 Claude 模型的 API 密钥,因为 FM-Agent 调用的 OpenCode 可能会使用 Claude 模型。
(可选)FM-Agent 使用 oh-my-openagent 插件增强 OpenCode。该插件内置的 comment-checker 钩子应当禁用,否则它会拦截 FM-Agent 写入的每一个注释块(这些注释是函数的正确性规约),并迫使 Agent 消耗大量 Token 去论证注释的必要性或将其删除。 请打开 oh-my-openagent 配置文件(通常位于 ~/.config/opencode/oh-my-openagent.json),添加 disabled_hooks:
~/.config/opencode/oh-my-openagent.json
disabled_hooks
{ "disabled_hooks": ["comment-checker"], }
uv run python main.py <proj_dir> [--resume] [--domain-knowledge FILE ...] [--bug-validator FILE] [--submodule PATH [PATH ...]]
proj_dir
--resume
--incremental INTENT_FILE
--domain-knowledge FILE [FILE ...]
--knowledge
--bug-validator FILE
md/bug_validator.md
--isolate
--submodule PATH [PATH ...]
--extra-edge FILE
--only-spec
--incremental
proj_dir 必须是一个 git 仓库。
如需在不修改 FM-Agent 内置提示词的情况下提供项目特定领域知识,可传入一个或多个 Markdown 文件:
uv run python main.py <proj_dir> --domain-knowledge docs/invariants.md docs/protocol.md
FM-Agent 会将这些文件暂存到 fm_agent/spec_prompts/domain_context/user_knowledge/,并在本次运行中让相关 Agent 读取。也可以通过 FM_AGENT_DOMAIN_KNOWLEDGE 提供使用 os.pathsep 分隔的 Markdown 文件列表。
fm_agent/spec_prompts/domain_context/user_knowledge/
FM_AGENT_DOMAIN_KNOWLEDGE
os.pathsep
如需自定义候选 Bug 的测试与确认方式,可通过 --bug-validator 指定 Markdown 文件:
uv run python main.py <proj_dir> --bug-validator prompts/compiler_bug_validator.md
该文件会替代内置 md/bug_validator.md 的验证指令。--bug-validator 的相对路径以启动 FM-Agent 命令时的当前目录为基准,而不是以 proj_dir 为基准。FM-Agent 仍会在每个 Bug 验证提示词中加入当前 Bug ID、目标验证结果,以及通过 --domain-knowledge 提供的领域知识。
--domain-knowledge
使用 --submodule 可以把完整运行或增量运行限制到指定项目子目录:
--submodule
uv run python main.py <proj_dir> --submodule src/core src/runtime uv run python main.py <proj_dir> --incremental intent.md --submodule src/core src/runtime
--submodule 路径必须是 proj_dir 内部目录。该参数可与 --resume、--isolate 和 --incremental 一起使用,但不能与 --entry-func 一起使用。
--entry-func
默认情况下,每次运行都会清空已有的 fm_agent/ 目录并从头开始,因此一旦运行中断,之前的所有进度都会丢失。可通过 --resume 参数(或设置环境变量 FM_AGENT_RESUME=1)从上一次中断处继续。在续跑模式下,FM-Agent 会保留已有的 fm_agent/ 目录,只执行剩余的工作。
fm_agent/
FM_AGENT_RESUME=1
使用 --only-spec 可以在生成行为规约后即停止,跳过推理与 Bug 验证阶段。它会为每个函数生成相邻的 .spec.json 和 .info.json 元数据文件,而不在验证上花费时间,适用于只需要规约、或希望先审阅规约再运行完整分析的场景。该参数不能与 --incremental 一起使用,因为增量模式本质上是一个推理/Bug 验证流程。
.spec.json
.info.json
uv run python main.py <proj_dir> --only-spec
当静态解析无法看到关键调用关系时(例如间接 syscall 分发),可使用 --extra-edge FILE。补充边会同时作用于完整运行、入口函数范围运行和增量运行。JSON 格式如下:
{ "edges": [ { "caller": { "fqn": "third_party::musl::src::time::nanosleep-c::nanosleep", "callsite_names": ["nanosleep"] }, "callee": { "fqn": "kernel::liteos_a::syscall::time_syscall-c::SysNanoSleep", "info_names": ["__NR_nanosleep", "SYS_nanosleep", "nanosleep"] } } ] }
Extra-edge 字段规则:
caller.fqn
callee.fqn
caller.callsite_names
callee.info_names
增量模式会复用上一次运行的结果,仅重新检测发生变化的部分。它将当前代码与上一次运行记录在 fm_agent/version.log 中的提交进行 diff。每次运行都会把所处理的提交 id 写入该文件,因此后续的 --incremental 运行会自动读取它:
fm_agent/version.log
python3 main.py <proj_dir> --incremental <intent_file>
如果 fm_agent/version.log 不存在(没有可供比较的历史运行),FM-Agent 会回退为完整运行。
FM-Agent 自带一个独立的实时 TUI 监控面板(dashboard.py),用于在运行过程中可视化展示:各阶段进度、Token 用量与花费、prompt 缓存命中率,以及 Bug 验证结果。它读取 FM-Agent 写入 fm_agent/ 目录下的 trace 文件,因此可在 main.py 运行期间于另一个终端中启动:
main.py
uv run python dashboard.py <proj_dir>
<proj_dir>/fm_agent/
trace/
按 Ctrl-C 退出监控面板,不会影响正在运行的流水线。
Ctrl-C
FM-Agent 会在代码库目录下创建 fm_agent/ 目录,主要输出内容如下:
fm_agent/bug_validation/<bug_id>.md
每个已确认或经过排查的 Bug 都会生成一份 Markdown 报告,包含以下内容:
fm_agent/bug_validation/ 目录下的 summary.json 文件汇总了所有 Bug 结果,包括报告的Bug总数、已确认Bug数、未确认Bug数。
fm_agent/bug_validation/
summary.json
fm_agent/fm_agent.log
单一日志文件记录完整的流水线执行过程,包括文件提取进度、推理任务的提交与完成情况、网络错误与重试,以及最终的推理统计摘要。日志级别为 INFO,格式为 %(asctime)s [%(levelname)s] %(message)s。
INFO
%(asctime)s [%(levelname)s] %(message)s
md/
如果您使用了 FM-Agent,请引用我们的论文:
@misc{ding2026fmagent, Author = {Haoran Ding and Zhaoguo Wang and Haibo Chen}, Title = {FM-Agent: Scaling Formal Methods to Large Systems via LLM-Based Hoare-Style Reasoning}, Year = {2026}, Eprint = {arXiv:2604.11556}, }
如有任何问题,欢迎提交 Issue 或发送邮件联系。
版权所有:中国计算机学会技术支持:开源发展技术委员会 京ICP备13000930号-9 京公网安备 11010802047560号
FM-Agent:通过基于大模型的霍尔逻辑推理将形式化方法扩展至大规模系统软件
English | 中文
官网 · 论文
FM-Agent 是首个实现大规模系统正确性全自动推理的框架,支持的软件包括14万行代码的 Claude C Compiler。
它包含三个步骤:
FM-Agent 的官方网站提供了在线代码库推理服务,欢迎体验!
目录
文件结构
环境配置
依赖要求
bunx安装)rebar.config的项目时,要求 rebar3 3.24.0 或更高版本。./install.sh --with-erlang会安装 Homebrew 当前提供的公式版本。已测试macOS环境
以下 macOS 环境已使用安装脚本测试:
安装依赖
设置 FM-Agent 和 OpenCode 共用的 LLM API 密钥。推荐使用 OpenRouter:FM-Agent 会并发调用 LLM,而 OpenRouter 的 RPM(每分钟请求数)和 TPM(每分钟 Token 数)限制更宽松——不过任何兼容的 provider 都可以。
把 API 密钥放进
.env(已 gitignore,FM-Agent 通过 python-dotenv 自动加载);其余所有配置在fm-agent.toml里都有 committed 的默认值。复制模板:非密钥配置——模型、endpoint、backend、provider 等——在
fm-agent.toml的[llm]段,直接改它是永久生效的做法。若不想动这个被 git 跟踪的文件(比如你是 git clone、之后会git pull更新),可以用对应的环境变量覆盖,写在.env或 shell 里即可。优先级为env > .env > fm-agent.toml;由于.env会盖过 toml,残留的旧值会覆盖你后来对 toml 的修改——所以改了 toml 不生效时,先检查.env。详情及 OpenCode provider 配置见 docs/config_llm.md。上述所有依赖(Ubuntu 和 Python 除外)均可通过以下脚本一键安装:
Erlang 工具链不影响其他语言,因此默认不安装。如需自动安装或检查 Erlang/OTP 26+、rebar3 3.24.0+ 和兼容的 ELP 发布包,请运行:
该选项在 macOS 上使用 Homebrew;在 Ubuntu 上,当系统 OTP 缺失或版本过低时使用 RabbitMQ Team Erlang PPA。Ubuntu 配置已使用 Erlang/OTP 26+ 验证;macOS Erlang 配置尚未测试,将使用 Homebrew 选择的当前公式版本。Linux 下的 rebar3 和 ELP 会安装到
~/.local/bin,请确保新终端的PATH包含该目录。你也可以手动安装这些工具,确认rebar3 version和elp version可执行,并在需要时将ELP_COMMAND设置为 ELP 的绝对路径。FM-Agent 会从
fm-agent.toml自动配置 OpenCode 的 provider,因此无需手动编辑~/.config/opencode/opencode.json来设置模型或密钥(见 docs/config_llm.md)。重要提示: FM-Agent 会根据推理过程自动生成测试用例,以触发潜在 Bug,帮助开发者定位和修复问题。运行 FM-Agent 前,请确保目标代码库的测试环境已就绪。如需提供项目特定的验证指令,请使用
--bug-validator;否则,Agent 将自主决定测试用例的执行方式。参数配置
配置项都在
fm-agent.toml里(每一项都有就近注释),也可用对应的环境变量覆盖。完整参数、默认值与描述的参考表见 docs/configuration_zh.md。重要说明: 强烈建议使用 Claude Sonnet 4.6 等能力较强的模型,其他模型可能推理能力,无法有效发现 Bug。此外,请使用有权限访问 Claude 模型的 API 密钥,因为 FM-Agent 调用的 OpenCode 可能会使用 Claude 模型。
(可选)FM-Agent 使用 oh-my-openagent 插件增强 OpenCode。该插件内置的 comment-checker 钩子应当禁用,否则它会拦截 FM-Agent 写入的每一个注释块(这些注释是函数的正确性规约),并迫使 Agent 消耗大量 Token 去论证注释的必要性或将其删除。 请打开 oh-my-openagent 配置文件(通常位于
~/.config/opencode/oh-my-openagent.json),添加disabled_hooks:快速开始
proj_dir--resume--incremental INTENT_FILE--domain-knowledge FILE [FILE ...]--knowledge;可重复传入。--bug-validator FILEmd/bug_validator.md。--isolate--submodule PATH [PATH ...]proj_dir中一个或多个子目录下的源代码。--extra-edge FILE--only-spec--incremental一起使用。proj_dir必须是一个 git 仓库。如需在不修改 FM-Agent 内置提示词的情况下提供项目特定领域知识,可传入一个或多个 Markdown 文件:
FM-Agent 会将这些文件暂存到
fm_agent/spec_prompts/domain_context/user_knowledge/,并在本次运行中让相关 Agent 读取。也可以通过FM_AGENT_DOMAIN_KNOWLEDGE提供使用os.pathsep分隔的 Markdown 文件列表。如需自定义候选 Bug 的测试与确认方式,可通过
--bug-validator指定 Markdown 文件:该文件会替代内置
md/bug_validator.md的验证指令。--bug-validator的相对路径以启动 FM-Agent 命令时的当前目录为基准,而不是以proj_dir为基准。FM-Agent 仍会在每个 Bug 验证提示词中加入当前 Bug ID、目标验证结果,以及通过--domain-knowledge提供的领域知识。使用
--submodule可以把完整运行或增量运行限制到指定项目子目录:--submodule路径必须是proj_dir内部目录。该参数可与--resume、--isolate和--incremental一起使用,但不能与--entry-func一起使用。默认情况下,每次运行都会清空已有的
fm_agent/目录并从头开始,因此一旦运行中断,之前的所有进度都会丢失。可通过--resume参数(或设置环境变量FM_AGENT_RESUME=1)从上一次中断处继续。在续跑模式下,FM-Agent 会保留已有的fm_agent/目录,只执行剩余的工作。使用
--only-spec可以在生成行为规约后即停止,跳过推理与 Bug 验证阶段。它会为每个函数生成相邻的.spec.json和.info.json元数据文件,而不在验证上花费时间,适用于只需要规约、或希望先审阅规约再运行完整分析的场景。该参数不能与--incremental一起使用,因为增量模式本质上是一个推理/Bug 验证流程。当静态解析无法看到关键调用关系时(例如间接 syscall 分发),可使用
--extra-edge FILE。补充边会同时作用于完整运行、入口函数范围运行和增量运行。JSON 格式如下:Extra-edge 字段规则:
caller.fqn:单个 caller 的精确 caller FQN,补一条到callee.fqn的边。可以为空。caller.callsite_names:源码 callsite 函数名。源码中包含这些 callsite 的函数都会作为 caller,补一条到callee.fqn的边。可以为空。caller.fqn和caller.callsite_names至少有一个非空。callee.fqn:单个 callee 的精确 FQN。callee.info_names:可选,用于匹配生成的.info.json中指代该 callee 的条目。它只用于.info.json匹配和传递调用者期望。增量模式
增量模式会复用上一次运行的结果,仅重新检测发生变化的部分。它将当前代码与上一次运行记录在
fm_agent/version.log中的提交进行 diff。每次运行都会把所处理的提交 id 写入该文件,因此后续的--incremental运行会自动读取它:如果
fm_agent/version.log不存在(没有可供比较的历史运行),FM-Agent 会回退为完整运行。实时监控面板
FM-Agent 自带一个独立的实时 TUI 监控面板(dashboard.py),用于在运行过程中可视化展示:各阶段进度、Token 用量与花费、prompt 缓存命中率,以及 Bug 验证结果。它读取 FM-Agent 写入
fm_agent/目录下的 trace 文件,因此可在main.py运行期间于另一个终端中启动:proj_dirmain.py相同的代码库目录(监控<proj_dir>/fm_agent/)。也可直接指向任意包含trace/子目录的工作区目录,例如已归档的运行按
Ctrl-C退出监控面板,不会影响正在运行的流水线。输出说明
FM-Agent 会在代码库目录下创建
fm_agent/目录,主要输出内容如下:Bug 报告(
fm_agent/bug_validation/<bug_id>.md)每个已确认或经过排查的 Bug 都会生成一份 Markdown 报告,包含以下内容:
fm_agent/bug_validation/目录下的summary.json文件汇总了所有 Bug 结果,包括报告的Bug总数、已确认Bug数、未确认Bug数。日志文件(
fm_agent/fm_agent.log)单一日志文件记录完整的流水线执行过程,包括文件提取进度、推理任务的提交与完成情况、网络错误与重试,以及最终的推理统计摘要。日志级别为
INFO,格式为%(asctime)s [%(levelname)s] %(message)s。注意事项
fm_agent/目录,请确保不存在命名冲突。md/目录下的 Markdown 文件提供了引导 Agent 推理过程的通用说明。针对项目特定的上下文(如不变量、协议、编码规则、领域术语),优先使用--domain-knowledge。对于项目特定的 Bug 验证流程,请使用--bug-validator,无需直接修改内置提示词;例如,编译器项目的自定义 validator 可以要求 Agent 将输出与 GCC 等参考实现进行对比。论文引用
如果您使用了 FM-Agent,请引用我们的论文:
联系方式
如有任何问题,欢迎提交 Issue 或发送邮件联系。