Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 12ad5dd9e0 | |||
| b06eeddccc | |||
| 440cd5812b | |||
| 55dcfc1b3e | |||
| 4a8032665f | |||
| 6536c7fa9d | |||
| 2cd02453ec | |||
| 140e49342c |
+40
-10
@@ -122,15 +122,26 @@ python scripts/agent_poller.py --action get --issue N
|
||||
|
||||
### 3. 开发 / 修复
|
||||
|
||||
**第零步:判断修复类型。** 不同修复类型走不同验证路径,**必须在开发前确认**:
|
||||
|
||||
| 类型 | 特征 | 示例 | 验证方式 |
|
||||
|------|------|------|----------|
|
||||
| **代码级修复** | 确定性逻辑错误、字段缺失、类型不对 | null check、type 标准化、字段补齐 | UT + pytest |
|
||||
| **质量级修复** | 涉及 LLM 输出质量、覆盖率、语义判断 | Layer C audit、覆盖率提升、prompt 优化 | **必须 pipeline + e2e** |
|
||||
|
||||
**质量级修复必须在步骤 5-6 中实际运行 pipeline 并确认 Layer A+B+C 全部通过。**
|
||||
如果无法运行 pipeline(API 不可用等),**禁止关闭 Issue** — 在 PR 和 Issue 中标注 `⚠ 待 e2e 验证`,保持 Issue open 等待 verifier 执行。
|
||||
|
||||
```
|
||||
1. git pull origin main
|
||||
2. git checkout -b dev/issue-N-<slug>
|
||||
3. 修改功能代码 + 更新/补充 UT 和接口集成测试
|
||||
4. python -m pytest -v # 本地全量 UT/集成测试
|
||||
5. python scripts/run_pipeline.py --input "input/<文档>.docx" # 运行完整 pipeline
|
||||
6. python -m pytest tests/acceptance/ -v --run-acceptance # e2e 验收 (Layer A+B+C)
|
||||
7. git commit -m "fix: <描述> - Closes #N"
|
||||
8. git push origin dev/issue-N-<slug>
|
||||
1. [判定] 是代码级修复还是质量级修复?
|
||||
2. git pull origin main
|
||||
3. git checkout -b dev/issue-N-<slug>
|
||||
4. 修改功能代码 + 更新/补充 UT 和接口集成测试
|
||||
5. python -m pytest -v # 本地全量 UT/集成测试
|
||||
6. [仅质量级修复] python scripts/run_pipeline.py --input "input/<文档>.docx"
|
||||
7. [仅质量级修复] python -m pytest tests/acceptance/ -v --run-acceptance
|
||||
8. git commit -m "fix: <描述> - Closes #N"
|
||||
9. git push origin dev/issue-N-<slug>
|
||||
```
|
||||
|
||||
**开发原则:**
|
||||
@@ -138,8 +149,21 @@ python scripts/agent_poller.py --action get --issue N
|
||||
- 新增功能必须有对应的测试覆盖
|
||||
- 关注 IR 一致性:对同一输入的多次运行结果应尽量稳定
|
||||
- 关注功能覆盖率:确保 IR 覆盖了输入文档中的功能点
|
||||
- **验证是实际功能验证,不是 dry-run**:`pytest` 通过只是门槛,必须用真实输入文档实际运行 pipeline 确认功能生效
|
||||
- **PR 前必须通过 e2e 验收 (Layer A+B+C)**:防止修复引入回归。若无法运行完整 pipeline(API 不可用等),至少在 PR 描述中注明
|
||||
- **代码级修复**:UT 通过即可关闭 Issue
|
||||
- **质量级修复**:必须 pipeline + e2e 全部通过才能关闭 Issue。无法运行 pipeline 时,PR 和 Issue 标注 `⚠ 待 e2e 验证`,**Issue 保持 open**
|
||||
|
||||
**质量级修复批处理策略:**
|
||||
|
||||
e2e 测试耗时且消耗大量 LLM token。对于质量级修复(Layer C audit、覆盖率、prompt 优化),**单个小改动看不出效果** — 只有 pytest 是无效测试。
|
||||
|
||||
| 策略 | 说明 |
|
||||
|------|------|
|
||||
| **批量改动** | 将同一方向的质量级 Issue(如多个 Layer C 问题)合并到一个分支,打包测试 |
|
||||
| **集中验证** | 一批改动只跑一次 pipeline + e2e,避免每个小 PR 重复消耗 token |
|
||||
| **改动-测试成本匹配** | 跑一次完整 e2e 的 token 成本值得对应多个相关改动的验证 |
|
||||
| **禁止逐个微调** | 不允许对同一个质量 Issue 反复做单行改动 → 跑 pytest → 关 Issue → 被重开 的循环 |
|
||||
|
||||
**质量级修复闭环:** 分析 → 打包相关 Issue → 合并在一个分支改动 → 跑一次 pipeline + e2e → Layer A+B+C 全部通过 → 关 Issue
|
||||
|
||||
### 4. 提交 PR
|
||||
|
||||
@@ -151,9 +175,15 @@ python scripts/agent_poller.py --action create-pr \
|
||||
--body "## Summary
|
||||
- <改动摘要>
|
||||
|
||||
## 修复类型
|
||||
- [ ] 代码级修复(UT 可验证)
|
||||
- [ ] 质量级修复(需 pipeline + e2e 验证)
|
||||
|
||||
## Test
|
||||
- [x] pytest 全量通过 (XX passed, Y skipped)
|
||||
- [x] UT / 集成测试已更新
|
||||
- [ ] pipeline 运行通过(仅质量级修复)
|
||||
- [ ] e2e 验收 Layer A+B+C 通过(仅质量级修复)
|
||||
|
||||
Closes #N"
|
||||
```
|
||||
|
||||
@@ -86,7 +86,8 @@ COVERAGE_TARGET = float(os.environ.get("IR_COVERAGE_TARGET", "0.95"))
|
||||
ENSEMBLE_TEMPERATURES = [
|
||||
float(os.environ.get("IR_ENSEMBLE_T1", "0.0")),
|
||||
float(os.environ.get("IR_ENSEMBLE_T2", "0.3")),
|
||||
float(os.environ.get("IR_ENSEMBLE_T3", "0.7")),
|
||||
float(os.environ.get("IR_ENSEMBLE_T3", "0.5")),
|
||||
float(os.environ.get("IR_ENSEMBLE_T4", "0.7")),
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -186,6 +186,8 @@
|
||||
|
||||
8. **开关关闭状态**:开关关闭时所有限制失效,这也必须作为一条规则输出(path: ["...", "开关关闭", "无限制"])。
|
||||
|
||||
9. **功能完整性要求(重要)**:上下文包中的每个表格行、每条文字描述、每个逻辑树路径都必须被至少一条规则覆盖。仔细检查上下文包,确保不遗漏任何数据来源。如果上下文包中有表格,每条表格行至少生成一条对应规则。
|
||||
|
||||
{format_feedback}
|
||||
|
||||
## 输出格式
|
||||
|
||||
@@ -880,9 +880,9 @@ def run_ensemble_semantic_index(doc: dict) -> dict:
|
||||
if v:
|
||||
print(f" {k}: {len(v)} 个问题")
|
||||
|
||||
# Feedback retry: re-run with coverage feedback (up to 2 retries, quality-gated)
|
||||
# Feedback retry: re-run with coverage feedback (up to 3 retries, quality-gated)
|
||||
retry_count = 0
|
||||
while retry_count < 2:
|
||||
while retry_count < 3:
|
||||
feedback = _build_coverage_feedback(gaps)
|
||||
if not feedback:
|
||||
break
|
||||
@@ -906,13 +906,16 @@ def run_ensemble_semantic_index(doc: dict) -> dict:
|
||||
if src.get("section"):
|
||||
retry_sections.add(src["section"])
|
||||
print(f" 重试新增 sections: {sorted(retry_sections)}", flush=True)
|
||||
# Quality gate: only include retry if it improves coverage
|
||||
# Quality gate: include retry if it adds new sections or doesn't regress coverage
|
||||
trial_indices = semantic_indices + [retry_result]
|
||||
trial_merged = ensemble_merge(trial_indices)
|
||||
trial_passed, trial_gaps = _quick_validate(trial_merged, doc, all_paths)
|
||||
trial_warnings = len(trial_gaps.get("coverage_warnings", []))
|
||||
trial_missing = len(trial_gaps.get("missing_table_rows", []))
|
||||
if trial_warnings < pre_warnings or trial_missing < pre_missing_rows:
|
||||
improved = trial_warnings < pre_warnings or trial_missing < pre_missing_rows
|
||||
no_regression = trial_warnings <= pre_warnings and trial_missing <= pre_missing_rows
|
||||
has_new_sections = len(retry_sections) > 0
|
||||
if improved or (no_regression and has_new_sections):
|
||||
semantic_indices.append(retry_result)
|
||||
merged = trial_merged
|
||||
passed, gaps = trial_passed, trial_gaps
|
||||
|
||||
@@ -83,8 +83,8 @@ def test_output_dir_structure():
|
||||
|
||||
|
||||
def test_ensemble_temperatures_count():
|
||||
"""Should have exactly 3 ensemble temperatures."""
|
||||
assert len(config.ENSEMBLE_TEMPERATURES) == 3
|
||||
"""Should have exactly 4 ensemble temperatures."""
|
||||
assert len(config.ENSEMBLE_TEMPERATURES) == 4
|
||||
|
||||
|
||||
def test_max_tokens_is_int():
|
||||
|
||||
Reference in New Issue
Block a user