从 0 学习 Alibaba Open Code Review(八):实现 Git Diff 到 Markdown 报告的 Agent MVP
一、前言
第七篇已经完成了 Code Review Agent MVP 的设计和项目骨架。
第七篇重点讲的是:
为什么要新建独立项目
为什么不直接改 OpenCodeReview 源码
为什么要拆成 git_tools / ocr_tools / report_tools / agent_graph
AgentState 为什么重要
这一篇继续往前走:把这个 MVP 真正跑起来。
这篇文章的目标不是再讲设计,而是验证这条链路是否真的可以工作:
Git 变更检测
↓
OpenCodeReview JSON
↓
解析结构化结果
↓
生成 Markdown 报告
项目目录是:
D:\agent\open-code-review-agent-mvp
本篇会基于这个项目实际运行命令,并把运行结果写下来。
二、本篇目标
本篇主要完成 6 件事:
- 检查 MVP 项目目录是否完整。
- 检查 Python 代码语法是否正确。
- 查看
agent_graph.py支持哪些命令行参数。 - 使用已有 OCR JSON 做一次离线运行。
- 查看生成的
review-result.json。 - 查看生成的
review-report.md。
为什么先用已有 JSON 做离线运行?
因为完整执行:
ocr review --format json
会调用 LLM,可能消耗接口额度,也可能受网络影响。
所以开发阶段更适合先使用:
--use-existing-json
这样可以先验证“JSON 到 Markdown 报告”的本地逻辑。
三、回顾项目结构
先查看项目目录:
Get-ChildItem -Recurse -LiteralPath 'D:\agent\open-code-review-agent-mvp' | Select-Object FullName,Length,LastWriteTime
实际输出的核心文件如下:
D:\agent\open-code-review-agent-mvp\.gitignore
D:\agent\open-code-review-agent-mvp\agent_graph.py
D:\agent\open-code-review-agent-mvp\README.md
D:\agent\open-code-review-agent-mvp\requirements.txt
D:\agent\open-code-review-agent-mvp\tools\__init__.py
D:\agent\open-code-review-agent-mvp\tools\git_tools.py
D:\agent\open-code-review-agent-mvp\tools\ocr_tools.py
D:\agent\open-code-review-agent-mvp\tools\report_tools.py
对应结构是:
open-code-review-agent-mvp
├── agent_graph.py
├── tools
│ ├── __init__.py
│ ├── git_tools.py
│ ├── ocr_tools.py
│ └── report_tools.py
├── README.md
├── requirements.txt
└── .gitignore
每个文件的职责再简单回顾一下:
| 文件 | 作用 |
|---|---|
agent_graph.py |
串联整个 Agent Workflow |
tools/git_tools.py |
检测 Git 仓库和变更文件 |
tools/ocr_tools.py |
调用 OpenCodeReview CLI,读取和解析 JSON |
tools/report_tools.py |
把 OCR JSON 转成 Markdown 报告 |
.gitignore |
排除缓存、环境文件和输出文件 |
README.md |
项目说明文档 |
requirements.txt |
依赖说明,当前只使用标准库 |
这篇的重点就是验证这些文件是否能配合工作。
四、先做语法检查
我一开始直接执行:
python -B -m py_compile D:\agent\open-code-review-agent-mvp\agent_graph.py D:\agent\open-code-review-agent-mvp\tools\git_tools.py D:\agent\open-code-review-agent-mvp\tools\ocr_tools.py D:\agent\open-code-review-agent-mvp\tools\report_tools.py
但是实际遇到了一个 Windows 权限问题:
PermissionError: [WinError 5] 拒绝访问: 'D:\agent\open-code-review-agent-mvp\__pycache__'
原因是 py_compile 会尝试在源码目录下创建 __pycache__,而当前环境对 D:\agent\open-code-review-agent-mvp 没有写入 pyc 缓存的权限。
这不是代码语法错误,而是语法检查方式会写文件。
所以改成内存编译,不写 __pycache__:
python -B -c "from pathlib import Path; files=[r'D:\agent\open-code-review-agent-mvp\agent_graph.py',r'D:\agent\open-code-review-agent-mvp\tools\git_tools.py',r'D:\agent\open-code-review-agent-mvp\tools\ocr_tools.py',r'D:\agent\open-code-review-agent-mvp\tools\report_tools.py']; [compile(Path(f).read_text(encoding='utf-8'), f, 'exec') for f in files]; print('syntax ok:', len(files), 'files')"
实际输出:
syntax ok: 4 files
这说明 4 个核心 Python 文件语法没有问题。
五、查看命令行帮助
接着查看 agent_graph.py 支持哪些参数:
python -B D:\agent\open-code-review-agent-mvp\agent_graph.py --help
实际输出:
usage: agent_graph.py [-h] [--repo REPO] [--output-dir OUTPUT_DIR]
[--ocr-bin OCR_BIN] [--exclude EXCLUDE]
[--timeout-seconds TIMEOUT_SECONDS]
[--use-existing-json USE_EXISTING_JSON]
Run the OpenCodeReview Agent MVP workflow.
optional arguments:
-h, --help show this help message and exit
--repo REPO Target Git repository. Defaults to current directory.
--output-dir OUTPUT_DIR
Directory for JSON and Markdown outputs.
--ocr-bin OCR_BIN OpenCodeReview executable name or path.
--exclude EXCLUDE Pattern passed to OCR --exclude. Can be repeated.
--timeout-seconds TIMEOUT_SECONDS
OCR command timeout in seconds.
--use-existing-json USE_EXISTING_JSON
Skip OCR and generate a report from an existing OCR
JSON file.
这些参数可以分成 4 类:
| 参数 | 作用 |
|---|---|
--repo |
指定要审查的 Git 仓库 |
--output-dir |
指定输出目录 |
--ocr-bin |
指定 OCR 命令路径,默认是 ocr |
--exclude |
传给 OCR 的排除规则 |
--timeout-seconds |
OCR 命令超时时间 |
--use-existing-json |
使用已有 JSON,不重新调用 LLM |
这里最重要的是 --use-existing-json。
它把“外部 LLM 调用”和“本地报告生成”拆开了。
六、先看当前 Demo 仓库状态
测试仓库是:
D:\agent\open-code-review-main\ocr-practice-demo
先查看当前 Git 变更:
git -C D:\agent\open-code-review-main\ocr-practice-demo status --porcelain
实际输出:
?? outputs-review-result.json
这说明当前工作区里只有一个未跟踪文件:
outputs-review-result.json
再执行 OpenCodeReview preview:
ocr review --preview
实际输出的关键信息是:
Preview: 1 file(s) changed | +41 -0
Will review (1):
[A] outputs-review-result.json +41 -0
这里还有一个 warning:
[ocr session] warning: failed to create session writer: open session file: ... Access is denied.
这个 warning 和审查范围无关,只是本地 session 文件写入权限问题,不影响 preview 结果。
更重要的是:outputs-review-result.json 被纳入了当前 diff。
这再次说明,生成物必须通过 .gitignore 或 --exclude 排除,否则下一次 Review 很容易审查到上一次的结果文件。
七、使用已有 JSON 做离线测试
这次先不重新调用 LLM,而是使用已有 OCR JSON:
D:\agent\open-code-review-main\ocr-practice-demo\outputs-review-result.json
执行命令:
python -B D:\agent\open-code-review-agent-mvp\agent_graph.py --repo D:\agent\open-code-review-main\ocr-practice-demo --output-dir "C:\Users\ad\Documents\New project\mvp-blog8-output" --use-existing-json D:\agent\open-code-review-main\ocr-practice-demo\outputs-review-result.json
实际输出:
Code Review Agent MVP finished.
Repo: D:\agent\open-code-review-main\ocr-practice-demo
Changed files: 1
JSON: C:\Users\ad\Documents\New project\mvp-blog8-output\review-result.json
Report: C:\Users\ad\Documents\New project\mvp-blog8-output\review-report.md
这说明工作流已经跑通:
读取已有 OCR JSON
↓
解析 JSON
↓
生成 review-result.json
↓
生成 review-report.md
这里有一个细节:输出里显示 Changed files: 1。
这是因为 changed_files 来自当前 Git 工作区,而 --use-existing-json 读取的是历史 OCR JSON。
所以离线测试时可能出现这种情况:
当前 changed files:outputs-review-result.json
历史 OCR findings:s01/src/user.js
这不代表报告生成逻辑错了,而是说明 --use-existing-json 适合验证 JSON 到 Markdown 的纯本地流程。
如果要审查当前 diff,就应该运行不带 --use-existing-json 的完整命令。
八、查看输出目录
输出目录是:
C:\Users\ad\Documents\New project\mvp-blog8-output
查看文件:
Get-ChildItem -LiteralPath 'C:\Users\ad\Documents\New project\mvp-blog8-output' | Select-Object Name,Length,LastWriteTime,FullName
实际输出:
Name Length FullName
---- ------ --------
review-report.md 1749 C:\Users\ad\Documents\New project\mvp-blog8-output\review-report.md
review-result.json 1809 C:\Users\ad\Documents\New project\mvp-blog8-output\review-result.json
两个核心产物都生成了:
review-result.json
review-report.md
这就是第八篇要验证的最小闭环。
九、查看 review-result.json
打开生成的 JSON:
Get-Content -LiteralPath 'C:\Users\ad\Documents\New project\mvp-blog8-output\review-result.json' -Encoding UTF8
核心内容如下:
{
"status": "success",
"summary": {
"files_reviewed": 2,
"comments": 2,
"total_tokens": 65929,
"input_tokens": 61803,
"output_tokens": 4126,
"cache_read_tokens": 35328,
"elapsed": "1m33s"
},
"tool_calls": {
"total": 14,
"by_tool": {
"code_comment": 2,
"code_search": 3,
"file_find": 1,
"file_read": 6,
"file_read_diff": 2
}
},
"comments": [
{
"path": "s01/src/user.js",
"content": "**SQL Injection Vulnerability**: ...",
"suggestion_code": "db.query('UPDATE users SET email = $1 WHERE id = $2', [email, userId]);",
"existing_code": "db.query(\"UPDATE users SET email = '\" + email + \"' WHERE id = \" + userId);",
"start_line": 37,
"end_line": 37
}
]
}
这个 JSON 和第六篇分析过的结构一致,仍然是三块核心数据:
summary 本次审查统计
tool_calls Agent 工具调用统计
comments 具体审查意见
这里可以看到:
| 字段 | 值 |
|---|---|
files_reviewed |
2 |
comments |
2 |
total_tokens |
65929 |
tool_calls.total |
14 |
这说明 ocr_tools.py 成功读取了 OCR JSON,并且 agent_graph.py 成功把它保存到了新的输出目录。
十、查看 review-report.md
再打开 Markdown 报告:
Get-Content -LiteralPath 'C:\Users\ad\Documents\New project\mvp-blog8-output\review-report.md' -Encoding UTF8
生成的报告核心内容如下:
# AI Code Review Report
- Generated at: 2026-07-07 13:42:37
- Status: success
## Summary
- Files reviewed: 2
- Comments: 2
- Total tokens: 65929
- Input tokens: 61803
- Output tokens: 4126
- Cache read tokens: 35328
- Cache write tokens: 0
- Elapsed: 1m33s
## Changed Files
- `outputs-review-result.json`
## Tool Calls
| Tool | Count |
|---|---:|
| `file_read` | 6 |
| `code_search` | 3 |
| `code_comment` | 2 |
| `file_read_diff` | 2 |
| `file_find` | 1 |
## Findings
### 1. `s01/src/user.js:37-37`
**Issue**
**SQL Injection Vulnerability**: The `email` and `userId` parameters are directly concatenated into the SQL query string without any sanitization or parameterization.
**Existing Code**
```js
db.query("UPDATE users SET email = '" + email + "' WHERE id = " + userId);
```
**Suggestion**
```js
db.query('UPDATE users SET email = $1 WHERE id = $2', [email, userId]);
```
这个报告已经比原始 JSON 更适合人阅读。
它把 JSON 中的字段转成了几个固定区域:
Summary
Changed Files
Tool Calls
Findings
其中 Findings 是最关键的区域,因为它直接面向开发者。
十一、报告字段是怎么映射的
从 JSON 到 Markdown 的映射关系如下:
| JSON 字段 | Markdown 区域 |
|---|---|
status |
报告顶部状态 |
summary.files_reviewed |
Summary 的 Files reviewed |
summary.comments |
Summary 的 Comments |
summary.total_tokens |
Summary 的 Total tokens |
summary.elapsed |
Summary 的 Elapsed |
tool_calls.by_tool |
Tool Calls 表格 |
comments[].path |
Findings 标题 |
comments[].start_line |
Findings 标题行号 |
comments[].end_line |
Findings 标题行号 |
comments[].content |
Issue 正文 |
comments[].existing_code |
Existing Code 代码块 |
comments[].suggestion_code |
Suggestion 代码块 |
这就是 report_tools.py 的价值。
它把机器友好的 JSON 转成了人友好的 Markdown。
后续如果接 GitHub Actions,可以直接把 review-report.md 作为 artifact 上传。
十二、agent_graph.py 如何串联流程
第七篇已经讲过 agent_graph.py 的设计,这里结合运行结果再看一次。
核心流程是:
state.changed_files = get_changed_files(repo_root)
if use_existing_json:
state.review_data = load_review_json(use_existing_json)
elif not state.changed_files:
state.review_data = skipped_result
else:
state.review_data = run_ocr_review(...)
markdown = generate_markdown_report(state.review_data, changed_files=state.changed_files)
save_markdown_report(markdown, state.review_report_path)
对应本次运行:
get_changed_files
-> 得到 outputs-review-result.json
load_review_json
-> 读取历史 OCR JSON
generate_markdown_report
-> 生成 Markdown 报告
save_markdown_report
-> 保存 review-report.md
也就是说,agent_graph.py 不负责具体实现细节,只负责编排步骤。
这就是它作为 workflow 入口的意义。
十三、git_tools.py 在本次运行中的作用
本次运行中,git_tools.py 主要做了两件事。
第一,确认目标目录是 Git 仓库:
result = run_git(repo_path, ["rev-parse", "--is-inside-work-tree"])
第二,获取当前变更文件:
result = run_git(repo_dir, ["status", "--porcelain"])
本次输出:
Changed files: 1
对应当前 Git 状态:
?? outputs-review-result.json
这里也暴露了一个工程问题:当前工作区里的生成物没有被忽略,所以它成为了 changed file。
这就是为什么 .gitignore 和 --exclude 很重要。
十四、ocr_tools.py 在本次运行中的作用
因为这次用了:
--use-existing-json
所以没有调用 run_ocr_review,而是调用了:
state.review_data = load_review_json(use_existing_json)
load_review_json 内部会读取 JSON 文件并解析:
def load_review_json(path: str | Path) -> dict[str, Any]:
return parse_review_json_text(read_text_with_fallback(path))
这里最重要的是 read_text_with_fallback。
因为之前实际遇到过 PowerShell 重定向保存的 JSON 可能是 UTF-16 的问题。
所以代码做了多个编码尝试:
for encoding in ("utf-8", "utf-8-sig", "utf-16", "utf-16-le", "utf-16-be"):
try:
return data.decode(encoding)
except UnicodeDecodeError:
continue
这保证了无论历史 JSON 是 UTF-8 还是 UTF-16,MVP 都能尽量读取。
这个细节很适合写进项目亮点里:
兼容 Windows PowerShell 重定向产生的 UTF-16 JSON 文件。
十五、report_tools.py 在本次运行中的作用
本次最终生成的 review-report.md 来自:
markdown = generate_markdown_report(state.review_data, changed_files=state.changed_files)
save_markdown_report(markdown, state.review_report_path)
其中 generate_markdown_report 做了这些事情:
- 读取
status。 - 读取
summary。 - 读取
tool_calls。 - 读取
comments。 - 渲染 Markdown 标题、列表、表格和代码块。
对每条 comment,会调用:
render_comment(index, comment)
它会把一条 OCR 评论转成:
### 文件路径:开始行-结束行
Issue
Existing Code
Suggestion
还有一个小细节是:
def fenced_code(code: str, language: str = "") -> str:
fence = "```"
if "```" in code:
fence = "````"
return f"{fence}{language}\n{code.rstrip()}\n{fence}"
如果模型建议代码里本身包含三个反引号,就改用四个反引号包裹,避免 Markdown 格式被破坏。
这是报告生成时必须考虑的边界问题。
十六、为什么离线模式很重要
本次实际运行的是离线模式:
--use-existing-json
它不会重新调用 LLM。
好处有三个:
- 不消耗 LLM 接口额度。
- 不依赖网络和模型服务状态。
- 可以反复调试 Markdown 报告格式。
这和真实工程里的测试思路是一样的:
外部昂贵调用:尽量少跑
本地纯逻辑:可以反复跑
在这个项目里:
OCR Review 是外部昂贵调用
JSON -> Markdown 是本地纯逻辑
所以先把本地纯逻辑跑稳,是更合理的工程步骤。
十七、真正调用 LLM 跑完整链路
前面的离线模式已经证明:
已有 OCR JSON
↓
Markdown 报告
可以正常工作。
但第八篇还需要验证一次真正的端到端链路:
Git diff
↓
OpenCodeReview Agent
↓
LLM Review
↓
review-result.json
↓
review-report.md
1. 准备真实业务代码 diff
当前 demo 仓库原本只有一个生成文件变更:
outputs-review-result.json
如果直接跑 OCR,很可能审查的是这个 JSON 文件,而不是业务代码。
所以在 s01/src/user.js 中新增了一个示例函数:
function resetUserPassword(db, userId, newPassword) {
db.query("UPDATE users SET password = '" + newPassword + "' WHERE id = " + userId);
return true;
}
并导出:
module.exports = {
getUserName,
login,
buildUserQuery,
fetchUser,
deleteUser,
updateUserEmail,
resetUserPassword
};
这个变更故意保留了 SQL 拼接问题,用来测试 OpenCodeReview 是否能发现风险。
查看当前 Git 状态:
git -C D:\agent\open-code-review-main\ocr-practice-demo status --porcelain
输出:
M s01/src/user.js
?? outputs-review-result.json
这说明现在既有业务代码变更,也有历史生成文件。
2. Preview 确认审查范围
为了避免审查 outputs-review-result.json,执行 preview 时加上 exclude:
ocr review --preview --exclude outputs-review-result.json
实际输出的关键信息是:
Preview: 2 file(s) changed | +50 -3
Will review (1):
[M] s01/src/user.js +9 -3
Excluded from review (1):
[A] outputs-review-result.json (user_exclude)
这一步很重要。
它确认了真正会进入 OCR/LLM 审查的是:
s01/src/user.js
而不是生成的 JSON 文件。
3. 第一次完整运行失败:Python 找不到 ocr
先执行了这个命令:
python -B D:\agent\open-code-review-agent-mvp\agent_graph.py --repo D:\agent\open-code-review-main\ocr-practice-demo --output-dir "C:\Users\ad\Documents\New project\mvp-blog8-llm-output" --exclude outputs/** --exclude outputs-review-result.json
结果失败了,核心错误是:
FileNotFoundError: [WinError 2] 系统找不到指定的文件
原因不是 OpenCodeReview 本身失败,而是 Windows 下 PowerShell 能识别 ocr.ps1,但 Python subprocess.run 更适合调用可执行的 .cmd 文件。
查看本地 OCR 命令:
Get-Command ocr
可以看到 PowerShell 找到的是:
C:\Users\ad\AppData\Roaming\npm\ocr.ps1
再查看 npm 目录:
Get-ChildItem -LiteralPath 'C:\Users\ad\AppData\Roaming\npm' -Filter 'ocr*'
可以看到同时存在:
ocr
ocr.cmd
ocr.ps1
所以在 Python 里更稳的方式是显式指定:
C:\Users\ad\AppData\Roaming\npm\ocr.cmd
4. 使用 ocr.cmd 真正调用 LLM
修正后执行:
python -B D:\agent\open-code-review-agent-mvp\agent_graph.py --repo D:\agent\open-code-review-main\ocr-practice-demo --output-dir "C:\Users\ad\Documents\New project\mvp-blog8-llm-output" --ocr-bin C:\Users\ad\AppData\Roaming\npm\ocr.cmd --exclude outputs/** --exclude outputs-review-result.json
这次没有使用 --use-existing-json。
所以它会真正调用:
OpenCodeReview Agent
↓
LLM Review
实际输出:
Code Review Agent MVP finished.
Repo: D:\agent\open-code-review-main\ocr-practice-demo
Changed files: 2
JSON: C:\Users\ad\Documents\New project\mvp-blog8-llm-output\review-result.json
Report: C:\Users\ad\Documents\New project\mvp-blog8-llm-output\review-report.md
这说明完整链路已经跑通。
输出目录里生成了:
review-result.json 1332 bytes
review-report.md 1349 bytes
5. 查看真实 LLM 生成的 review-result.json
打开 JSON:
Get-Content -LiteralPath 'C:\Users\ad\Documents\New project\mvp-blog8-llm-output\review-result.json' -Encoding UTF8
核心结果如下:
{
"status": "success",
"summary": {
"files_reviewed": 1,
"comments": 1,
"total_tokens": 49227,
"input_tokens": 48151,
"output_tokens": 1076,
"cache_read_tokens": 26368,
"elapsed": "21s"
},
"tool_calls": {
"total": 11,
"by_tool": {
"code_comment": 1,
"code_search": 3,
"file_find": 4,
"file_read": 3
}
},
"comments": [
{
"path": "s01/src/user.js",
"content": "**SQL Injection Vulnerability:** ...",
"existing_code": "function resetUserPassword(db, userId, newPassword) {\n db.query(\"UPDATE users SET password = '\" + newPassword + \"' WHERE id = \" + userId);\n return true;\n}",
"start_line": 41,
"end_line": 44
}
]
}
这次真正调用 LLM 后,OpenCodeReview 发现了新增函数里的 SQL 注入风险。
关键信息如下:
| 字段 | 值 |
|---|---|
files_reviewed |
1 |
comments |
1 |
total_tokens |
49227 |
tool_calls.total |
11 |
elapsed |
21s |
工具调用统计是:
| Tool | Count |
|---|---|
file_find |
4 |
code_search |
3 |
file_read |
3 |
code_comment |
1 |
这说明本次并不是简单 Prompt 审查,而是实际发生了 Agent 工具调用。
6. 查看真实生成的 Markdown 报告
打开报告:
Get-Content -LiteralPath 'C:\Users\ad\Documents\New project\mvp-blog8-llm-output\review-report.md' -Encoding UTF8
核心内容如下:
# AI Code Review Report
- Generated at: 2026-07-07 13:58:12
- Status: success
## Summary
- Files reviewed: 1
- Comments: 1
- Total tokens: 49227
- Input tokens: 48151
- Output tokens: 1076
- Cache read tokens: 26368
- Cache write tokens: 0
- Elapsed: 21s
## Changed Files
- `outputs-review-result.json`
- `s01/src/user.js`
## Tool Calls
| Tool | Count |
|---|---:|
| `file_find` | 4 |
| `code_search` | 3 |
| `file_read` | 3 |
| `code_comment` | 1 |
## Findings
### 1. `s01/src/user.js:41-44`
**Issue**
**SQL Injection Vulnerability:** The `newPassword` and `userId` values are directly concatenated into the SQL query string, allowing an attacker to craft malicious input that modifies the SQL statement's behavior.
**Existing Code**
```js
function resetUserPassword(db, userId, newPassword) {
db.query("UPDATE users SET password = '" + newPassword + "' WHERE id = " + userId);
return true;
}
```
到这里,完整链路就不是“只读取历史 JSON”了,而是:
真实 Git diff
↓
真实 OpenCodeReview Agent 审查
↓
真实 LLM 输出 JSON
↓
我的 MVP 生成 Markdown 报告
7. 一个新的工程发现
这次真实运行还暴露了一个小问题。
review-result.json 里显示:
files_reviewed: 1
说明 OpenCodeReview 实际只审查了:
s01/src/user.js
但是 Markdown 报告的 Changed Files 显示:
outputs-review-result.json
s01/src/user.js
原因是:
OCR 的 --exclude 只影响 OpenCodeReview 审查范围
MVP 的 changed_files 来自 git status --porcelain,还没有按 exclude 过滤
这不影响 OCR 审查结果,但会影响报告展示。
所以后续可以优化 git_tools.py 或 agent_graph.py:
Changed Files 展示时也应用 exclude 规则
这个问题很适合作为下一版工程优化点。
十八、outputs 为什么要排除
项目里的 .gitignore 是:
__pycache__/
*.py[cod]
.pytest_cache/
.mypy_cache/
.ruff_cache/
.venv/
venv/
.env
outputs/
*.review.json
*.review.md
其中最关键的是:
outputs/
*.review.json
*.review.md
原因已经在实际运行中看到了:当前 demo 仓库里 outputs-review-result.json 进入了 Git diff。
如果不排除生成物,AI Code Review 会审查上一次生成的结果文件。
这会造成两个问题:
- 审查范围被污染。
- LLM token 被浪费。
所以输出目录必须排除。
这不是小优化,而是 AI Code Review 工程化必须处理的边界。
十九、本篇遇到的工程问题
本篇实际运行中遇到了几个值得记录的问题。
1. py_compile 写 pycache 权限失败
问题:
PermissionError: [WinError 5] 拒绝访问: 'D:\agent\open-code-review-agent-mvp\__pycache__'
解决:
改用 compile() 做内存语法检查,不写 pyc 文件。
2. OCR session writer 权限 warning
问题:
[ocr session] warning: failed to create session writer: ... Access is denied.
这个 warning 不影响 ocr review --preview 的审查范围输出。
3. PowerShell JSON 编码问题
问题:
PowerShell 重定向保存的 JSON 可能是 UTF-16。
解决:
read_text_with_fallback 同时尝试 utf-8、utf-8-sig、utf-16、utf-16-le、utf-16-be。
4. 离线 JSON 和当前 diff 可能不一致
问题:
--use-existing-json 读取的是历史 OCR JSON,changed_files 读取的是当前 Git 工作区。
所以报告里可能出现:
Changed Files: outputs-review-result.json
Findings: s01/src/user.js
这不是解析错误,而是离线测试模式的特点。
真正审查当前 diff 时,应运行完整 OCR 命令。
二十、这个 MVP 已经完成了什么
到这里,V1 已经完成:
Git 状态检测
↓
读取 OCR JSON
↓
解析 summary / tool_calls / comments
↓
生成 Markdown 报告
从产物看,已经生成:
review-result.json
review-report.md
从工程能力看,已经具备:
| 能力 | 是否完成 |
|---|---|
| 检测 Git 仓库 | 已完成 |
| 检测 changed files | 已完成 |
| 调用 OCR CLI | 已完成并通过真实 LLM 调用验证 |
| 使用已有 JSON 离线测试 | 已验证 |
| 解析 OCR JSON | 已验证 |
| 生成 Markdown 报告 | 已通过离线模式和真实 LLM 模式验证 |
| 处理 Windows 编码问题 | 已完成 |
| 排除输出目录 | 已设计,真实运行中验证了 OCR exclude 生效 |
所以第八篇的结论是:MVP 的本地闭环已经跑通。
二十一、当前版本的不足
当前 V1 仍然有一些不足:
- 还没有引入 LangGraph。
- 还没有风险分级。
- 还没有审查历史数据库。
- 还没有 GitHub Actions。
- 还没有 PR 行内评论。
--use-existing-json模式下,历史 JSON 和当前 diff 可能不一致。- 对 OCR 执行失败的展示还比较简单。
但这正是 MVP 的意义:先跑通最小闭环,再逐步扩展。
二十二、本篇用到的命令
查看项目结构:
Get-ChildItem -Recurse -LiteralPath 'D:\agent\open-code-review-agent-mvp' | Select-Object FullName,Length,LastWriteTime
内存语法检查:
python -B -c "from pathlib import Path; files=[r'D:\agent\open-code-review-agent-mvp\agent_graph.py',r'D:\agent\open-code-review-agent-mvp\tools\git_tools.py',r'D:\agent\open-code-review-agent-mvp\tools\ocr_tools.py',r'D:\agent\open-code-review-agent-mvp\tools\report_tools.py']; [compile(Path(f).read_text(encoding='utf-8'), f, 'exec') for f in files]; print('syntax ok:', len(files), 'files')"
查看帮助:
python -B D:\agent\open-code-review-agent-mvp\agent_graph.py --help
查看 demo 仓库状态:
git -C D:\agent\open-code-review-main\ocr-practice-demo status --porcelain
预览 OCR 审查范围:
ocr review --preview
离线运行 MVP:
python -B D:\agent\open-code-review-agent-mvp\agent_graph.py --repo D:\agent\open-code-review-main\ocr-practice-demo --output-dir "C:\Users\ad\Documents\New project\mvp-blog8-output" --use-existing-json D:\agent\open-code-review-main\ocr-practice-demo\outputs-review-result.json
真实调用 OCR/LLM:
python -B D:\agent\open-code-review-agent-mvp\agent_graph.py --repo D:\agent\open-code-review-main\ocr-practice-demo --output-dir "C:\Users\ad\Documents\New project\mvp-blog8-llm-output" --ocr-bin C:\Users\ad\AppData\Roaming\npm\ocr.cmd --exclude outputs/** --exclude outputs-review-result.json
查看 JSON:
Get-Content -LiteralPath 'C:\Users\ad\Documents\New project\mvp-blog8-output\review-result.json' -Encoding UTF8
查看 Markdown 报告:
Get-Content -LiteralPath 'C:\Users\ad\Documents\New project\mvp-blog8-output\review-report.md' -Encoding UTF8
二十三、本篇总结
这一篇完成了 Code Review Agent MVP 的第一次实际运行。
核心结论是:
D:\agent\open-code-review-agent-mvp项目结构完整。- 4 个核心 Python 文件通过了内存语法检查。
agent_graph.py --help可以正常输出参数说明。- 使用
--use-existing-json可以不调用 LLM,直接验证 JSON 到 Markdown 的链路。 - 已成功生成
review-result.json和review-report.md。 - 已真实调用 OpenCodeReview/LLM,并发现新增
resetUserPassword函数的 SQL 注入风险。 - Markdown 报告已经包含 Summary、Changed Files、Tool Calls、Findings。
- Windows 下需要处理 JSON 编码、pyc 缓存写入和
ocr.cmd调用问题。 - 输出文件必须排除,否则可能进入下一次 diff。
到这里,MVP V1 可以总结为:
OpenCodeReview 负责 AI Review
我的 Agent MVP 负责编排、保存、解析和报告生成
这已经是一个可以继续扩展的 Agent Workflow 项目。
二十四、下一篇计划
下一篇可以进入 V2:
从 0 学 OpenCodeReview:为 Code Review Agent 增加风险分级
下一篇可以做:
读取 comments
↓
根据规则识别风险等级
↓
Critical / Warning / Suggestion
↓
在 Markdown 报告中展示风险等级
再下一步再考虑 LangGraph。
更稳的路线是:
第八篇:跑通 MVP
第九篇:风险分级
第十篇:LangGraph 状态管理
第十一篇:GitHub Actions
第十二篇:PR 自动评论 / 多 Agent 设计
更多推荐



所有评论(0)