From 00b88b48414cbd2771ad3ef6cacadcbb3754cc5e Mon Sep 17 00:00:00 2001 From: Eternal Date: Sat, 30 May 2026 19:35:05 +0800 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20refine=20prompts=20from=20real=20PR?= =?UTF-8?q?=20analysis=20=E2=80=94=20heygen-com/hyperframes#1133?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Analyzed a real-world PR (off-by-one arithmetic bug in distributed render chunk plan) to validate and refine prompts: - SYSTEM_ROLE: add '算术误差(off-by-one/舍入)' to correctness focus area - OUTPUT_FORMAT: add 'Arithmetic' to risk types - CHUNK_CROSS_CHUNK_HINT: add item 6 — test-implementation alignment check - GlobalPromptBuilder: add '实现与测试的对应性' to L3 reasoning focus; add rule 5 to REASONING_RULES for test coverage risk detection - Tests: update assertions for new content Co-Authored-By: Claude Opus 4.8 --- .../prassistant/pr/aggregation/GlobalPromptBuilder.java | 6 ++++-- .../pr/review/analyzer/ChunkPromptBuilder.java | 8 +++++--- .../pr/aggregation/GlobalPromptBuilderTest.java | 2 ++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/backend/pr/src/main/java/com/prassistant/pr/aggregation/GlobalPromptBuilder.java b/backend/pr/src/main/java/com/prassistant/pr/aggregation/GlobalPromptBuilder.java index 73a9224..2d0e9cb 100644 --- a/backend/pr/src/main/java/com/prassistant/pr/aggregation/GlobalPromptBuilder.java +++ b/backend/pr/src/main/java/com/prassistant/pr/aggregation/GlobalPromptBuilder.java @@ -17,9 +17,10 @@ public final class GlobalPromptBuilder { static final String SYSTEM_ROLE = """ 你是一位资深的代码评审专家。请基于以下 Pull Request 的各文件分析摘要和跨文件线索, 进行全局推理分析。不要重复描述各文件摘要,而是聚焦于: - 1. 跨文件交互可能引入的风险 + 1. 跨文件交互可能引入的风险(接口变更、数据流影响) 2. 架构层面的影响(模块耦合、接口兼容性等) - 3. 整体代码质量评估与改进建议 + 3. 实现与测试的对应性:测试是否覆盖了关键路径和边界条件 + 4. 整体代码质量评估与改进建议 """; /** 推理要求 */ @@ -29,6 +30,7 @@ public final class GlobalPromptBuilder { 2. 如果无法确定某个风险,标注为 "需进一步确认" 3. crossFileIssues 必须涉及至少两个文件 4. topPriorityFiles 不超过 3 个 + 5. 注意检查实现文件与测试文件的对应:有实现变更但无测试补充时,应标注测试缺失风险 """; /** 全局输出格式要求 */ diff --git a/backend/pr/src/main/java/com/prassistant/pr/review/analyzer/ChunkPromptBuilder.java b/backend/pr/src/main/java/com/prassistant/pr/review/analyzer/ChunkPromptBuilder.java index 297354f..ee7a4aa 100644 --- a/backend/pr/src/main/java/com/prassistant/pr/review/analyzer/ChunkPromptBuilder.java +++ b/backend/pr/src/main/java/com/prassistant/pr/review/analyzer/ChunkPromptBuilder.java @@ -17,7 +17,7 @@ public final class ChunkPromptBuilder { /** 系统角色设定 */ static final String SYSTEM_ROLE = """ 你是一位资深的代码评审专家。专注于以下方面: - - 正确性:逻辑错误、边界条件、异常处理 + - 正确性:逻辑错误、边界条件、算术误差(off-by-one/舍入)、异常处理 - 安全性:注入风险、权限校验、数据加密 - 性能:N+1查询、资源泄漏、缓存机会 - 并发:竞态条件、死锁、线程安全 @@ -30,7 +30,7 @@ public final class ChunkPromptBuilder { { "summary": "变更摘要(不超过30字)", "risks": [ - { "type": "NullPointer|Concurrency|Security|Performance|Maintainability|Other", "line": 行号, "description": "风险说明(不超过100字)" } + { "type": "NullPointer|Concurrency|Security|Performance|Arithmetic|Maintainability|Other", "line": 行号, "description": "风险说明(不超过100字)" } ], "suggestions": [ { "priority": 1-5, "description": "建议内容(不超过100字)" } @@ -42,7 +42,9 @@ public final class ChunkPromptBuilder { /** 单块模式额外要求 */ static final String CHUNK_CROSS_CHUNK_HINT = "5. 跨块依赖提示:如果当前块修改了接口签名、删除了方法、新增了全局变量或修改了配置项," - + "请详细描述这些变更,格式:变更内容 -> 影响范围 -> 后续需关注的文件\n"; + + "请详细描述这些变更,格式:变更内容 -> 影响范围 -> 后续需关注的文件\n" + + "6. 实现与测试关联提示:如果当前块是实现代码,检查是否有对应的测试文件变更;" + + "如果是测试代码,说明覆盖了哪些实现路径\n"; /** 反幻觉约束 */ static final String ANTI_HALLUCINATION = diff --git a/backend/pr/src/test/java/com/prassistant/pr/aggregation/GlobalPromptBuilderTest.java b/backend/pr/src/test/java/com/prassistant/pr/aggregation/GlobalPromptBuilderTest.java index e98a001..d1f8692 100644 --- a/backend/pr/src/test/java/com/prassistant/pr/aggregation/GlobalPromptBuilderTest.java +++ b/backend/pr/src/test/java/com/prassistant/pr/aggregation/GlobalPromptBuilderTest.java @@ -49,6 +49,7 @@ void shouldContainSystemRole() { assertTrue(prompt.contains("资深的代码评审专家")); assertTrue(prompt.contains("全局推理分析")); assertTrue(prompt.contains("架构层面的影响")); + assertTrue(prompt.contains("实现与测试的对应性")); } @Test @@ -111,6 +112,7 @@ void shouldContainReasoningRules() { assertTrue(prompt.contains("推理要求")); assertTrue(prompt.contains("至少两个文件")); assertTrue(prompt.contains("不超过 3 个")); + assertTrue(prompt.contains("测试缺失风险")); } @Test From 3f205a7b6650cd473723972f227fb8d475191ad8 Mon Sep 17 00:00:00 2001 From: Eternal Date: Sat, 30 May 2026 20:09:12 +0800 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20data-driven=20prompt=20tuning=20v3?= =?UTF-8?q?=20=E2=80=94=205=20targeted=20fixes=20from=2010-run=20test=20re?= =?UTF-8?q?sults?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on 10-run test against TheAlgorithms/Java#7427 (QR Decomposition): Fixes applied: 1. SYSTEM_ROLE: add 3 mandatory checks for numerical computing review (numerical stability, dimension bounds, floating-point comparison) 2. OUTPUT_FORMAT: add risk rating rules (must-use table) and summary template ('本质,影响范围') 3. Task list: add item 5 for matrix dimension boundary (m < n) check 4. Global OUTPUT_FORMAT: expand issueType enum with NUMERICAL_ACCURACY, ALGORITHM_CHOICE, PERFORMANCE, SECURITY_VULNERABILITY 5. REASONING_RULES: constrain architectureSuggestions to PR scope only Tests updated for renumbered items (5->6/7) and new enum values. Co-Authored-By: Claude Opus 4.8 --- .../pr/aggregation/GlobalPromptBuilder.java | 3 ++- .../review/analyzer/ChunkPromptBuilder.java | 24 ++++++++++++++----- .../aggregation/GlobalPromptBuilderTest.java | 3 +++ .../analyzer/ChunkPromptBuilderTest.java | 6 +++-- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/backend/pr/src/main/java/com/prassistant/pr/aggregation/GlobalPromptBuilder.java b/backend/pr/src/main/java/com/prassistant/pr/aggregation/GlobalPromptBuilder.java index 2d0e9cb..19d1c28 100644 --- a/backend/pr/src/main/java/com/prassistant/pr/aggregation/GlobalPromptBuilder.java +++ b/backend/pr/src/main/java/com/prassistant/pr/aggregation/GlobalPromptBuilder.java @@ -31,6 +31,7 @@ public final class GlobalPromptBuilder { 3. crossFileIssues 必须涉及至少两个文件 4. topPriorityFiles 不超过 3 个 5. 注意检查实现文件与测试文件的对应:有实现变更但无测试补充时,应标注测试缺失风险 + 6. architectureSuggestions 必须针对本次 PR 已变更的具体代码给出改进,每条建议应关联到具体文件路径,禁止建议"引入第三方库全面替换"等超出本次变更范围的重构 """; /** 全局输出格式要求 */ @@ -42,7 +43,7 @@ public final class GlobalPromptBuilder { "globalRiskReason": "全局风险评级理由", "crossFileIssues": [ { - "issueType": "INTERFACE_MISMATCH|DUPLICATE_LOGIC|TRANSACTION_MISSING|SECURITY_PROPAGATION|DB_CODE_INCONSISTENCY|OTHER", + "issueType": "INTERFACE_INCONSISTENCY|REPEAT_LOGIC|TRANSACTION_MISSING|NUMERICAL_ACCURACY|ALGORITHM_CHOICE|PERFORMANCE|SECURITY_VULNERABILITY|OTHER", "description": "问题描述", "involvedFiles": ["文件路径1", "文件路径2"], "severity": "HIGH|MEDIUM|LOW", diff --git a/backend/pr/src/main/java/com/prassistant/pr/review/analyzer/ChunkPromptBuilder.java b/backend/pr/src/main/java/com/prassistant/pr/review/analyzer/ChunkPromptBuilder.java index ee7a4aa..00c2c0b 100644 --- a/backend/pr/src/main/java/com/prassistant/pr/review/analyzer/ChunkPromptBuilder.java +++ b/backend/pr/src/main/java/com/prassistant/pr/review/analyzer/ChunkPromptBuilder.java @@ -16,8 +16,12 @@ public final class ChunkPromptBuilder { /** 系统角色设定 */ static final String SYSTEM_ROLE = """ - 你是一位资深的代码评审专家。专注于以下方面: - - 正确性:逻辑错误、边界条件、算术误差(off-by-one/舍入)、异常处理 + 你是资深数值计算与代码审查专家。审查任何涉及矩阵运算、浮点运算、迭代算法的代码时,必须强制检查以下 3 项,并在输出中明确标注是否通过: + 1. 【数值稳定性】若涉及正交化、QR分解、最小二乘等算法,必须评估经典实现(如经典 Gram-Schmidt)的累积舍入误差风险,并对比 Modified GS 或 Householder 变换的适用性。 + 2. 【维度边界】若涉及矩阵运算,必须检查是否对 m < n(列数大于行数)、零矩阵、秩亏矩阵、非方阵做了前置验证或异常处理。 + 3. 【浮点比较】禁止直接使用 == 0 或 == 1.0 判断浮点/双精度数值,必须建议引入 epsilon 容差。 + 同时兼顾代码的通用审查维度: + - 正确性:逻辑错误、边界条件、异常处理 - 安全性:注入风险、权限校验、数据加密 - 性能:N+1查询、资源泄漏、缓存机会 - 并发:竞态条件、死锁、线程安全 @@ -28,7 +32,7 @@ public final class ChunkPromptBuilder { static final String OUTPUT_FORMAT = """ 请严格按以下 JSON 格式输出(仅 JSON,不要包含 Markdown 代码块标记或任何额外文字): { - "summary": "变更摘要(不超过30字)", + "summary": "【变更本质】,影响【影响范围】(严格按此模板,30字内)", "risks": [ { "type": "NullPointer|Concurrency|Security|Performance|Arithmetic|Maintainability|Other", "line": 行号, "description": "风险说明(不超过100字)" } ], @@ -37,13 +41,19 @@ public final class ChunkPromptBuilder { ], "riskLevel": "HIGH|MEDIUM|LOW" } + + 【风险评级硬性规则】(必须遵守,不得自由发挥) + - HIGH:存在内存安全、并发安全、数据丢失、算法数值崩溃、死循环风险 + - MEDIUM:存在算术精度损失、边界条件缺失(如 m 影响范围 -> 后续需关注的文件\n" - + "6. 实现与测试关联提示:如果当前块是实现代码,检查是否有对应的测试文件变更;" + + "7. 实现与测试关联提示:如果当前块是实现代码,检查是否有对应的测试文件变更;" + "如果是测试代码,说明覆盖了哪些实现路径\n"; /** 反幻觉约束 */ @@ -77,7 +87,8 @@ public static String buildWholeFile(SanitizedDiff diff) { + "1. 变更摘要(30字内)\n" + "2. 风险点(标注类型:NullPointer/Concurrency/Security/Performance 等)\n" + "3. Review 建议\n" - + "4. 风险评级(HIGH / MEDIUM / LOW)\n\n" + + "4. 风险评级(HIGH / MEDIUM / LOW)\n" + + "5. 矩阵维度边界检查:若代码涉及矩阵初始化、分解、求逆、乘法,检查是否对 m < n(列数大于行数)的情况做了前置校验或异常抛出。若未处理,必须作为 MEDIUM 风险上报\n\n" + ANTI_HALLUCINATION + "\n" + OUTPUT_FORMAT; } @@ -107,6 +118,7 @@ public static String buildChunk(Chunk chunk) { sb.append("2. 风险点(标注类型:NullPointer/Concurrency/Security/Performance 等)\n"); sb.append("3. Review 建议\n"); sb.append("4. 风险评级(HIGH / MEDIUM / LOW)\n"); + sb.append("5. 矩阵维度边界检查:若代码涉及矩阵初始化、分解、求逆、乘法,检查是否对 m < n(列数大于行数)的情况做了前置校验或异常抛出。若未处理,必须作为 MEDIUM 风险上报\n"); sb.append(CHUNK_CROSS_CHUNK_HINT).append("\n"); sb.append(ANTI_HALLUCINATION).append("\n"); sb.append(OUTPUT_FORMAT); diff --git a/backend/pr/src/test/java/com/prassistant/pr/aggregation/GlobalPromptBuilderTest.java b/backend/pr/src/test/java/com/prassistant/pr/aggregation/GlobalPromptBuilderTest.java index d1f8692..6ac3c8f 100644 --- a/backend/pr/src/test/java/com/prassistant/pr/aggregation/GlobalPromptBuilderTest.java +++ b/backend/pr/src/test/java/com/prassistant/pr/aggregation/GlobalPromptBuilderTest.java @@ -113,6 +113,7 @@ void shouldContainReasoningRules() { assertTrue(prompt.contains("至少两个文件")); assertTrue(prompt.contains("不超过 3 个")); assertTrue(prompt.contains("测试缺失风险")); + assertTrue(prompt.contains("architectureSuggestions 必须针对本次 PR")); } @Test @@ -126,6 +127,8 @@ void shouldContainOutputFormat() { assertTrue(prompt.contains("crossFileIssues")); assertTrue(prompt.contains("architectureSuggestions")); assertTrue(prompt.contains("topPriorityFiles")); + assertTrue(prompt.contains("NUMERICAL_ACCURACY")); + assertTrue(prompt.contains("ALGORITHM_CHOICE")); } } diff --git a/backend/pr/src/test/java/com/prassistant/pr/review/analyzer/ChunkPromptBuilderTest.java b/backend/pr/src/test/java/com/prassistant/pr/review/analyzer/ChunkPromptBuilderTest.java index fd4e95b..bd5ee2c 100644 --- a/backend/pr/src/test/java/com/prassistant/pr/review/analyzer/ChunkPromptBuilderTest.java +++ b/backend/pr/src/test/java/com/prassistant/pr/review/analyzer/ChunkPromptBuilderTest.java @@ -153,7 +153,7 @@ void shouldNotIncludePreviousSummaryWhenAbsent() { } @Test - @DisplayName("应包含跨块依赖提示(第 5 项)") + @DisplayName("应包含跨块依赖提示(第 6 项)") void shouldIncludeCrossChunkHint() { Chunk chunk = Chunk.builder() .chunkId("test#hunk-1") @@ -165,7 +165,7 @@ void shouldIncludeCrossChunkHint() { String prompt = ChunkPromptBuilder.buildChunk(chunk); assertTrue(prompt.contains("跨块依赖提示")); - assertTrue(prompt.contains("5.")); + assertTrue(prompt.contains("6.")); } @Test @@ -222,6 +222,8 @@ void wholeFileExcludesCrossChunkHint() { assertFalse(wholeFilePrompt.contains("跨块依赖提示")); assertTrue(chunkPrompt.contains("跨块依赖提示")); + assertTrue(chunkPrompt.contains("5. 矩阵维度边界检查")); + assertTrue(chunkPrompt.contains("6. 跨块依赖提示")); } @Test From 38fd88a820bf38ac4d6b0591907a9467fa6b447f Mon Sep 17 00:00:00 2001 From: Eternal Date: Sat, 30 May 2026 20:10:38 +0800 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20align=20IssueType=20enum=20with=20pr?= =?UTF-8?q?ompt=20=E2=80=94=20add=20NUMERICAL=5FACCURACY,=20ALGORITHM=5FCH?= =?UTF-8?q?OICE,=20PERFORMANCE=20etc.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Java IssueType enum now matches the expanded issueType list in prompts. New types: INTERFACE_INCONSISTENCY, REPEAT_LOGIC, SECURITY_VULNERABILITY, NUMERICAL_ACCURACY, ALGORITHM_CHOICE, PERFORMANCE. Old types preserved for backward compat. Co-Authored-By: Claude Opus 4.8 --- .../pr/aggregation/GlobalPromptBuilder.java | 2 +- .../pr/aggregation/model/GlobalReviewReport.java | 8 +++++++- .../pr/aggregation/GlobalPromptBuilderTest.java | 2 ++ .../pr/aggregation/model/GlobalReviewReportTest.java | 12 +++++++++--- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/backend/pr/src/main/java/com/prassistant/pr/aggregation/GlobalPromptBuilder.java b/backend/pr/src/main/java/com/prassistant/pr/aggregation/GlobalPromptBuilder.java index 19d1c28..96fe3ca 100644 --- a/backend/pr/src/main/java/com/prassistant/pr/aggregation/GlobalPromptBuilder.java +++ b/backend/pr/src/main/java/com/prassistant/pr/aggregation/GlobalPromptBuilder.java @@ -43,7 +43,7 @@ public final class GlobalPromptBuilder { "globalRiskReason": "全局风险评级理由", "crossFileIssues": [ { - "issueType": "INTERFACE_INCONSISTENCY|REPEAT_LOGIC|TRANSACTION_MISSING|NUMERICAL_ACCURACY|ALGORITHM_CHOICE|PERFORMANCE|SECURITY_VULNERABILITY|OTHER", + "issueType": "INTERFACE_MISMATCH|INTERFACE_INCONSISTENCY|DUPLICATE_LOGIC|REPEAT_LOGIC|TRANSACTION_MISSING|SECURITY_PROPAGATION|SECURITY_VULNERABILITY|DB_CODE_INCONSISTENCY|NUMERICAL_ACCURACY|ALGORITHM_CHOICE|PERFORMANCE|OTHER", "description": "问题描述", "involvedFiles": ["文件路径1", "文件路径2"], "severity": "HIGH|MEDIUM|LOW", diff --git a/backend/pr/src/main/java/com/prassistant/pr/aggregation/model/GlobalReviewReport.java b/backend/pr/src/main/java/com/prassistant/pr/aggregation/model/GlobalReviewReport.java index b89240e..25901b7 100644 --- a/backend/pr/src/main/java/com/prassistant/pr/aggregation/model/GlobalReviewReport.java +++ b/backend/pr/src/main/java/com/prassistant/pr/aggregation/model/GlobalReviewReport.java @@ -63,13 +63,19 @@ public enum RiskLevel { HIGH, MEDIUM, LOW } - /** 跨文件关联问题类型枚举 */ + /** 跨文件关联问题类型枚举(与提示词 issueType 枚举一致) */ public enum IssueType { INTERFACE_MISMATCH, + INTERFACE_INCONSISTENCY, DUPLICATE_LOGIC, + REPEAT_LOGIC, TRANSACTION_MISSING, SECURITY_PROPAGATION, + SECURITY_VULNERABILITY, DB_CODE_INCONSISTENCY, + NUMERICAL_ACCURACY, + ALGORITHM_CHOICE, + PERFORMANCE, OTHER } diff --git a/backend/pr/src/test/java/com/prassistant/pr/aggregation/GlobalPromptBuilderTest.java b/backend/pr/src/test/java/com/prassistant/pr/aggregation/GlobalPromptBuilderTest.java index 6ac3c8f..6bd11be 100644 --- a/backend/pr/src/test/java/com/prassistant/pr/aggregation/GlobalPromptBuilderTest.java +++ b/backend/pr/src/test/java/com/prassistant/pr/aggregation/GlobalPromptBuilderTest.java @@ -129,6 +129,8 @@ void shouldContainOutputFormat() { assertTrue(prompt.contains("topPriorityFiles")); assertTrue(prompt.contains("NUMERICAL_ACCURACY")); assertTrue(prompt.contains("ALGORITHM_CHOICE")); + assertTrue(prompt.contains("INTERFACE_MISMATCH")); + assertTrue(prompt.contains("DUPLICATE_LOGIC")); } } diff --git a/backend/pr/src/test/java/com/prassistant/pr/aggregation/model/GlobalReviewReportTest.java b/backend/pr/src/test/java/com/prassistant/pr/aggregation/model/GlobalReviewReportTest.java index 9f5a015..947967e 100644 --- a/backend/pr/src/test/java/com/prassistant/pr/aggregation/model/GlobalReviewReportTest.java +++ b/backend/pr/src/test/java/com/prassistant/pr/aggregation/model/GlobalReviewReportTest.java @@ -98,14 +98,20 @@ void shouldHaveThreeValues() { class IssueTypeEnum { @Test - @DisplayName("应包含六种问题类型") - void shouldHaveSixValues() { - assertEquals(6, GlobalReviewReport.IssueType.values().length); + @DisplayName("应包含 12 种问题类型(含新增的数值精度、算法选型、性能等)") + void shouldHaveTwelveValues() { + assertEquals(12, GlobalReviewReport.IssueType.values().length); assertNotNull(GlobalReviewReport.IssueType.valueOf("INTERFACE_MISMATCH")); + assertNotNull(GlobalReviewReport.IssueType.valueOf("INTERFACE_INCONSISTENCY")); assertNotNull(GlobalReviewReport.IssueType.valueOf("DUPLICATE_LOGIC")); + assertNotNull(GlobalReviewReport.IssueType.valueOf("REPEAT_LOGIC")); assertNotNull(GlobalReviewReport.IssueType.valueOf("TRANSACTION_MISSING")); assertNotNull(GlobalReviewReport.IssueType.valueOf("SECURITY_PROPAGATION")); + assertNotNull(GlobalReviewReport.IssueType.valueOf("SECURITY_VULNERABILITY")); assertNotNull(GlobalReviewReport.IssueType.valueOf("DB_CODE_INCONSISTENCY")); + assertNotNull(GlobalReviewReport.IssueType.valueOf("NUMERICAL_ACCURACY")); + assertNotNull(GlobalReviewReport.IssueType.valueOf("ALGORITHM_CHOICE")); + assertNotNull(GlobalReviewReport.IssueType.valueOf("PERFORMANCE")); assertNotNull(GlobalReviewReport.IssueType.valueOf("OTHER")); } }