如何在 Reasonix 中使用 CodeGraph 以及 CodeGraph 效果实测经验分享
实测日期:2026-05-31
项目:星火甄选系统(基于 RuoYi-Vue 二次开发,~1,300 个源文件)
AI 客户端:Reasonix Code
一、什么是 CodeGraph
CodeGraph 是一个开源的代码知识图谱 MCP 服务器(34k+ Stars),核心思路是:提前把代码的符号关系建好索引,让 AI 代理直接查询图谱,而不是每次从头扫描文件。
工作原理:
AI Agent (Reasonix Code)
│ codegraph_context / codegraph_trace / codegraph_explore
▼
CodeGraph MCP Server
│ SQLite 知识图谱(符号 + 边 + 全文索引)
▼
Tree-sitter 解析 AST → 提取函数/类/方法/调用/继承关系
│
▼
项目源代码(Java / Vue / JS / XML / YAML 等)
关键特性:
- 支持 20+ 语言(包括 Java、JavaScript、TypeScript、Vue 等)
- 完整的调用图(callers / callees / trace)
- 影响范围分析(impact)
- 文件监听自动同步(OS 原生事件,2 秒去抖)
- 100% 本地运行,无外部 API
二、安装步骤
2.1 全局安装
bash
# 使用 npx 零安装(推荐)
npx @colbymchenry/codegraph
安装器会交互式选择要配置的 AI 客户端。目前支持:Claude Code、Cursor、Codex CLI、Gemini CLI、OpenCode、Hermes Agent 等。Reasonix Code 不在自动配置列表中,需手动注册。
2.2 在项目根目录创建索引
bash
cd your-project
codegraph init -i
-i 参数表示初始化后立即建索引。执行后在项目根目录生成 .codegraph/ 目录,其中包含 SQLite 数据库(codegraph.db)。
2.3 在 Reasonix Code 中手动注册 MCP 服务
由于 Reasonix Code 未被自动配置工具识别,需要手动添加 MCP 服务配置。Reasonix Code 的 add_mcp_server 工具可以自动完成此操作:
json
{
"name": "codegraph",
"transport": "stdio",
"command": "codegraph",
"args": ["serve", "--mcp"]
}
注册成功后,重启 Reasonix Code 即可生效。可通过 codegraph_codegraph_status 工具验证索引状态。
三、CodeGraph 提供的工具集
CodeGraph 注册后暴露以下 MCP 工具:
| 工具名 | 用途 | 对标传统操作 |
|---|---|---|
codegraph_context |
首要调用--- 输入任务描述,返回入口点 + 相关符号 + 代码 | 相当于 search_content+read_file 组合 |
codegraph_trace |
追踪两个符号之间的调用路径 | 需要手动逐层阅读代码推理 |
codegraph_explore |
一次查询获取多个文件的源码(内联返回,行号精确) | 单个 read_file× N |
codegraph_search |
按符号名快速搜索 | search_files |
codegraph_callers |
列出调用某个函数的所有调用者 | search_content 搜方法名 |
codegraph_callees |
列出某个函数调用的所有子函数 | 逐行阅读代码 |
codegraph_impact |
修改某个符号前分析影响范围 | 手动 grep + 推理 |
codegraph_node |
获取单个符号的详细信息 | read_file 定位 |
codegraph_files |
展示项目文件树 | directory_tree |
codegraph_status |
查看索引健康状态 | --- |
四、实测对比方案
测试任务
追踪
PUT /system/colonelActivity/changeSyncProduct接口的完整后端调用链路。
需要回答:
- HTTP 请求从进入 Spring Boot 到最终响应,经过了哪些拦截器/过滤器?
- Controller → Service → Mapper 的每一层调用了什么方法?
- 当
isSyncProduct=Y时,RocketMQ 消息是如何被发出的? - 涉及哪些异常/校验逻辑?
- 操作日志如何被记录?
衡量指标
- 工具调用次数
- 实际文件读取数
- 答案完整性与准确性
基线流程(未安装 CodeGraph)
- 阅读
SysColonelActivityController.java→ 发现调用了colonelActivityService.changeSyncProduct() - 阅读
ISysColonelActivityService.java→ 发现接口定义 - 阅读
SysColonelActivityServiceImpl.java→ 理解业务逻辑、事务、校验、分支路径 - 发现调用
productSyncService.sendNonPendingActivityProductSyncMessage()→ 阅读DoudianColonelActivityProductSyncService.java - 发现调用
mqProducer.sendAsyncMessage()→ 阅读MqProducer.java - 查看
MqTopicConstant.java→ 确认 Topic 名称 - 查看
SecurityConfig.java→ 理解过滤器链 - 查看
JwtAuthenticationTokenFilter.java→ JWT 认证流程 - 查看
PermissionService.java→@PreAuthorize权限校验 - 查看
LogAspect.java→@Log操作日志 AOP - 查看
GlobalExceptionHandler.java→ 异常处理 - 查看
BaseController.java→getUsername()/toAjax()父类方法 - 查看
SysColonelActivityMapper.java→ MyBatis-Plus Mapper - 查看
ColonelActivitySyncProductUpdateParam.java→ 参数校验注解 - 手动整合各层调用关系
CodeGraph 流程
codegraph_context--- 输入任务描述,自动返回入口点 + 相关符号 + 代码片段(覆盖 3 个文件源码)codegraph_trace("changeSyncProduct", "sendNonPendingActivityProductSyncMessage")--- 自动输出完整调用路径codegraph_explore--- 一次查询返回 8 个关键文件的完整源码(SecurityConfig、PermissionService、MqProducer、BaseController 等)codegraph_explore--- 另一次查询补充 LogAspect、GlobalExceptionHandler、SysColonelActivityServiceImpl、SysColonelActivityMapper
五、实测数据对比
| 指标 | 未安装 CodeGraph(基线) | 已安装 CodeGraph | 提升幅度 |
|---|---|---|---|
| 工具调用总数 | 16 次 | 5 次 | ↓69% |
| read_file 调用 | 12 次 | 0 次 | ↓100% |
| search_content 调用 | 1 次 | 0 次 | ↓ 100% |
| search_files 调用 | 3 次 | 0 次 | ↓ 100% |
| codegraph_* 调用 | 0 次 | 5 次 | --- |
| 文件读取数 | 12 个 | 0 个(源码内联) | ↓100% |
| 调用链串联方式 | 手动逐层推理 | trace 一键自动输出 |
🚀 |
| 答案完整性 | 覆盖 7 层 | 覆盖 7 层 | 持平 ✅ |
| 文件行号准确性 | 全部精确 | 全部精确 | 持平 ✅ |
核心体验差异
1. 零文件读取 --- 从 12 次 read_file 降为 0
基线时需要逐个文件打开阅读:
SysColonelActivityController.java → ISysColonelActivityService.java →
SysColonelActivityServiceImpl.java → DoudianColonelActivityProductSyncService.java →
MqProducer.java → SecurityConfig.java → JwtAuthenticationTokenFilter.java →
PermissionService.java → LogAspect.java → GlobalExceptionHandler.java →
BaseController.java → SysColonelActivityMapper.java
CodeGraph 通过 codegraph_explore 批量将源码内联到工具响应中,无需手动 read_file。
2. 调用链一键追踪
基线时需手动推理每层的调用关系。codegraph_trace 一个调用自动输出:
changeSyncProduct (Controller:62)
↓ @71 calls
sendNonPendingActivityProductSyncMessage (Service:103)
↓ @105 calls
sendActivityProductSyncMessage (Service:120)
↓ @123 calls
MqProducer.sendAsyncMessage (MqProducer:58-81)
↓ calls
RocketMQTemplate.asyncSend(topic, message, callback)
→ Topic: "ruoyi-doudian-colonel-activity-product-sync-topic"
3. 调用关系一目了然
codegraph_context 自动列出 changeSyncProduct 调用的所有子方法路径,无需逐行扫描。
六、CodeGraph 完整的 7 层调用链路(测试答案)
第 1 层:Spring Security 过滤器链
SecurityConfig.filterChain() [SecurityConfig.java:97]
├─ CorsFilter (跨域) [line 162-163]
├─ JwtAuthenticationTokenFilter (JWT 认证) [JwtAuthenticationTokenFilter.java:31]
│ └─ TokenService.getLoginUser(request) → 解析 JWT Token
│ └─ TokenService.verifyToken(loginUser) → 刷新 Token 有效期
│ └─ 设置 SecurityContextHolder → 注入 LoginUser
└─ @PreAuthorize 拦截 [SecurityConfig.java:29 @EnableMethodSecurity]
第 2 层:权限校验
@PreAuthorize("@ss.hasPermi('system:colonelActivity:edit')")
└─ PermissionService.hasPermi() [PermissionService.java:27]
└─ SecurityUtils.getLoginUser() → 从 SecurityContext 获取
└─ loginUser.getPermissions() → 获取用户权限集
└─ hasPermissions(permissions, permission) → 检查是否包含(含 ALL_PERMISSION 超级权限)
└─ 失败 → AccessDeniedException
└─ GlobalExceptionHandler.handleAccessDeniedException() → 403
第 3 层:参数校验
@Validated @RequestBody ColonelActivitySyncProductUpdateParam
activityRecordId: @NotNull(message = "活动记录ID不能为空")
isSyncProduct: @NotBlank + @Pattern(regexp = "^[YN]$")
└─ 校验失败 → MethodArgumentNotValidException
└─ GlobalExceptionHandler.handleMethodArgumentNotValidException() → 返回错误信息
第 4 层:Controller 入口
SysColonelActivityController.changeSyncProduct() [Controller.java:62]
├─ @PreAuthorize("@ss.hasPermi('system:colonelActivity:edit')")
├─ @Log(title = "团长活动管理", businessType = BusinessType.UPDATE)
├─ @PutMapping("/changeSyncProduct")
├─ int rows = colonelActivityService.changeSyncProduct(param, getUsername())
├─ if (rows > 0 && YES.equals(param.getIsSyncProduct()))
│ └─ productSyncService.sendNonPendingActivityProductSyncMessage(activityRecordId)
└─ return toAjax(rows) → BaseController.toAjax() [BaseController.java:161]
第 5 层:Service 业务逻辑
SysColonelActivityServiceImpl.changeSyncProduct() [ServiceImpl.java:64]
├─ @Transactional(rollbackFor = Exception.class)
├─ requireActivity(activityRecordId) → 校验活动记录存在 + authId/activityId 非空
├─ assertSelfOwnedColonel(activity) → [Y 路径] 校验授权未过期 + 自有团长
│ └─ colonelAuthService.getById(authId)
├─ updateById(activity) → 写入 DB(update_time, update_by)
└─ [Y→N 转换路径] 清理关联数据:
├─ colonelActivityProductService.deleteByActivityRecordId()
├─ talentProductDetailService.deleteByActivityRecordId()
├─ productSkuService.clearProductSkus()
└─ pendingProductService.deleteByActivityRecordId()
第 6 层:RocketMQ 消息发送(Y 路径)
DoudianColonelActivityProductSyncService
└─ sendNonPendingActivityProductSyncMessage(id) [SyncService.java:103]
└─ sendActivityProductSyncMessage(id, NON_PENDING) [SyncService.java:120]
└─ mqProducer.sendAsyncMessage(topic, jsonMsg) [SyncService.java:123]
└─ MqProducer.sendAsyncMessage() [MqProducer.java:58]
└─ rocketMQTemplate.asyncSend(topic, message, callback)
└─ Topic: "ruoyi-doudian-colonel-activity-product-sync-topic"
第 7 层:操作日志(AOP 切面)
LogAspect [LogAspect.java]
├─ @Before: doBefore() → 记录开始时间 (ThreadLocal)
├─ @AfterReturning: doAfterReturning()
└─ handleLog() → 构建 SysOperLog
├─ 获取用户、IP、URL、方法名
├─ 读取 @Log 注解(title=团长活动管理, businessType=UPDATE)
├─ 序列化请求参数 / 返回值
└─ AsyncManager.me().execute(AsyncFactory.recordOper(operLog))
→ 异步写入数据库
七、经验总结
适合 CodeGraph 的场景
| 场景 | 效果 |
|---|---|
| 大项目(500+ 文件) | 🚀 显著,节省 70%+ 工具调用 |
| 跨模块追踪调用链 | 🚀trace 比手动推理高效数倍 |
| 修改前的影响分析 | 🚀impact 自动输出影响半径 |
| 理解不熟悉的模块架构 | 🚀context 一次性给出全景 |
| 小的独立模块(50- 文件) | ⚠️ 收益有限,当前工具已够用 |
| 首次建立索引(冷启动) | ⚠️ 需要几分钟建索引时间 |
注意事项
- 首次索引需要时间:本项目 1,300 个文件索引约需 1-2 分钟
- 文件变更后自动同步:OS 文件监听有 2 秒去抖窗口,期间有脏读风险(CodeGraph 会显示 ⚠️ 横幅提醒)
- Reasonix 不在自动配置列表 :需手动通过
add_mcp_server注册 - CodeGraph 与项目
.gitignore:.codegraph/ 目录建议加入.gitignore(避免提交数据库文件) - 工具调用次数不是唯一指标 :虽然从 16 次降到 5 次,但每次
codegraph_explore返回的数据量更大
八、总结
CodeGraph 在本次实测中对 Reasonix Code 的代码探索效率有显著提升:
- 工具调用减少 69% ,其中文件读取从 12 次降为 0 次
- 调用链追踪从手动推理变为一键输出
- 代码覆盖面更广 (一次
explore覆盖约 6 个文件的完整源码) - 答案质量完全持平甚至更优(图谱结构确保不会遗漏关键路径)
对于星火甄选这样的中大型项目(1,300 文件、多模块依赖、跨语言),CodeGraph 的收益是明确的。
九、后续使用计划回答
1. 在后续使用 Reasonix 开发的过程中会自动使用 CodeGraph 吗?
会,但策略性地使用。
具体来说:
- 当遇到需要跨模块/跨文件追踪的问题时 (如"这个 Controller 的请求最终调用了哪个 Mapper 的什么方法"、"修改这个 Service 会影响哪些前端页面"),我会优先使用
codegraph_context和codegraph_trace,因为它们比手动 read_file 串联高效得多。 - 当需要理解不熟悉的模块架构时 ,我会用
codegraph_context快速获取全景图,而不是先 grep 再逐个读文件。 - 但在简单场景下 (如"某个类里有什么方法"、"某个文件的全部内容是什么"),直接使用
read_file和get_symbols可能更直接,因为调用codegraph_explore有一次额外的索引查询开销。 - 对于影响范围分析 ("如果修改 X 函数,哪些地方需要同步修改?"),
codegraph_impact将成为首选工具,因为它在人工推理中很容易遗漏间接调用者。
总的来说,CodeGraph 不会完全替代现有的文件读写工具,但在需要理解代码关系和调用结构的场景下,它会成为工作的主力工具。