kc-beta 0.7.5 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -0
- package/package.json +3 -2
- package/src/agent/engine.js +390 -100
- package/src/agent/pipelines/_advance-hints.js +92 -0
- package/src/agent/pipelines/_milestone-derive.js +247 -13
- package/src/agent/pipelines/skill-authoring.js +30 -1
- package/src/agent/tools/agent-tool.js +2 -2
- package/src/agent/tools/consult-skill.js +15 -0
- package/src/agent/tools/dashboard-render.js +48 -1
- package/src/agent/tools/document-parse.js +31 -2
- package/src/agent/tools/phase-advance.js +17 -13
- package/src/agent/tools/release.js +250 -7
- package/src/agent/tools/sandbox-exec.js +65 -8
- package/src/agent/tools/worker-llm-call.js +95 -15
- package/src/agent/workspace.js +25 -4
- package/src/cli/components.js +4 -1
- package/src/cli/index.js +97 -1
- package/src/config.js +19 -2
- package/src/marathon/driver.js +217 -0
- package/src/marathon/prompts.js +93 -0
- package/template/.env.template +16 -0
- package/template/skills/en/bootstrap-workspace/SKILL.md +14 -0
- package/template/skills/en/quality-control/SKILL.md +9 -0
- package/template/skills/en/skill-authoring/SKILL.md +39 -0
- package/template/skills/en/skill-to-workflow/SKILL.md +53 -0
- package/template/skills/en/work-decomposition/SKILL.md +34 -0
- package/template/skills/phase_skills.yaml +5 -0
- package/template/skills/zh/bootstrap-workspace/SKILL.md +14 -0
- package/template/skills/zh/compliance-judgment/SKILL.md +37 -37
- package/template/skills/zh/document-chunking/SKILL.md +21 -14
- package/template/skills/zh/document-parsing/SKILL.md +65 -65
- package/template/skills/zh/entity-extraction/SKILL.md +68 -68
- package/template/skills/zh/quality-control/SKILL.md +9 -0
- package/template/skills/zh/skill-authoring/SKILL.md +39 -0
- package/template/skills/zh/skill-creator/SKILL.md +204 -200
- package/template/skills/zh/skill-to-workflow/SKILL.md +53 -0
- package/template/skills/zh/tree-processing/SKILL.md +67 -63
- package/template/skills/zh/work-decomposition/SKILL.md +34 -0
- package/template/workflows/common/llm_client.py +168 -0
- package/template/workflows/common/utils.py +132 -0
|
@@ -15,6 +15,14 @@ This skill is the conductor's playbook for that decision. It's tagged `tier: met
|
|
|
15
15
|
- **Entering rule_extraction.** Read the regulation, decompose into rules, then decide how those rules will be ordered and grouped before declaring the phase done. Coverage audit + chunk refs are downstream of these decisions.
|
|
16
16
|
- **Entering skill_authoring.** TaskBoard is empty (engine no longer auto-populates per-rule tasks). Read the rule list from `describeState`, decide grouping + order, then call `TaskCreate` for each unit of work.
|
|
17
17
|
- **Mid-run re-decomposition.** If the TaskBoard feels wrong (rules accumulating in the wrong order, an obviously-bundled pair across two tasks), stop adding work and re-decompose. The cost of pausing 5 minutes to re-plan is recovered within 2 rules of better-shaped work.
|
|
18
|
+
- **Any phase with 3+ parallel sub-goals.** If you find yourself juggling multiple parallel sub-goals in working memory (3+ rules × docs, multiple deliverable-prep items in finalization, several QC batches in production_qc), drop them into the TaskBoard and work serially. v0.7.5 audits showed distillation + production_qc benefit from explicit tasks even when the registry didn't expose this skill there — v0.8 P2-E makes the skill available in every phase.
|
|
19
|
+
|
|
20
|
+
## Quick rule: when does the TaskBoard belong?
|
|
21
|
+
|
|
22
|
+
- Touching N+ rules or docs in parallel? → `TaskCreate` one task per rule/doc before starting.
|
|
23
|
+
- Single 1-step request? → Skip; just do it.
|
|
24
|
+
- Subagent internal coordination? → Skip; subagents don't get the TaskBoard.
|
|
25
|
+
- Anything you'd otherwise need to remember "I'll come back to that"? → TaskCreate it now. Working memory loses partial completions over long turns.
|
|
18
26
|
|
|
19
27
|
## Locked principles
|
|
20
28
|
|
|
@@ -402,3 +410,29 @@ E2E history:
|
|
|
402
410
|
- E2E #7 v071 neither DS nor GLM wrote PATTERNS.md, but GLM wrote 6 rich phase-completion logs and a comprehensive AGENT.md — the methodology WAS captured, just in different files. v0.7.2 blesses the broader principle: persist before you advance, format flexible.
|
|
403
411
|
|
|
404
412
|
The engine's filesystem-derived milestones (Group A v0.7.0) verify coverage on disk regardless of how you split the work. The TaskBoard is your scratchpad; the disk is the contract; the persistence file is your project's memory.
|
|
413
|
+
|
|
414
|
+
## Subagent batch work: rolling-window writes
|
|
415
|
+
|
|
416
|
+
When you dispatch N subagents to do batch work (regression tests, batch verification, parallel rule processing), DO NOT have them write to a shared coordination file. v0.7.5 audits found subagents racing on `tasks.json` / `rules/catalog.json` / `output/results/summary.json` — one took the workspace lock for 5+ minutes while others waited silently.
|
|
417
|
+
|
|
418
|
+
The right pattern: each subagent writes to its OWN file under a known prefix. The parent aggregates after all subagents finish.
|
|
419
|
+
|
|
420
|
+
```
|
|
421
|
+
sub_agents/
|
|
422
|
+
batch-001-regression/
|
|
423
|
+
output/results/v2_regression.json # ❌ shared — races other subagents
|
|
424
|
+
batch-002-regression/
|
|
425
|
+
output/results/v2_regression.json # ❌ same path, race
|
|
426
|
+
|
|
427
|
+
# vs:
|
|
428
|
+
|
|
429
|
+
output/
|
|
430
|
+
batch_regression_001.json # ✓ each subagent owns one file
|
|
431
|
+
batch_regression_002.json # ✓
|
|
432
|
+
batch_regression_003.json # ✓
|
|
433
|
+
# Parent agent reads all batch_regression_*.json and writes the aggregate.
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
Engine signal: if you see `lock_blocked` events in events.jsonl during subagent work, that's the symptom. v0.8 P4-C added the event emission so the parent has visibility into contention before the subagent times out. If the pattern shows up, refactor to rolling-window writes.
|
|
437
|
+
|
|
438
|
+
Don't write a "coordinate via file locking" subagent batch. The locking primitives exist for safety against accidental concurrent writes, not as a queue. Use the filesystem layout as the coordination mechanism.
|
|
@@ -23,6 +23,7 @@ phases:
|
|
|
23
23
|
always_loaded:
|
|
24
24
|
- bootstrap-workspace
|
|
25
25
|
available:
|
|
26
|
+
- work-decomposition # v0.8 P2-E
|
|
26
27
|
- auto-model-selection
|
|
27
28
|
- data-sensibility
|
|
28
29
|
- document-parsing
|
|
@@ -60,6 +61,7 @@ phases:
|
|
|
60
61
|
always_loaded:
|
|
61
62
|
- evolution-loop
|
|
62
63
|
available:
|
|
64
|
+
- work-decomposition # v0.8 P2-E
|
|
63
65
|
- skill-authoring
|
|
64
66
|
- skill-to-workflow
|
|
65
67
|
- tree-processing
|
|
@@ -74,6 +76,7 @@ phases:
|
|
|
74
76
|
- skill-to-workflow
|
|
75
77
|
- evolution-loop
|
|
76
78
|
available:
|
|
79
|
+
- work-decomposition # v0.8 P2-E
|
|
77
80
|
- skill-authoring
|
|
78
81
|
- task-decomposition
|
|
79
82
|
- corner-case-management
|
|
@@ -87,6 +90,7 @@ phases:
|
|
|
87
90
|
- quality-control
|
|
88
91
|
- evolution-loop
|
|
89
92
|
available:
|
|
93
|
+
- work-decomposition # v0.8 P2-E
|
|
90
94
|
- skill-authoring
|
|
91
95
|
- skill-to-workflow
|
|
92
96
|
- confidence-system
|
|
@@ -100,6 +104,7 @@ phases:
|
|
|
100
104
|
always_loaded:
|
|
101
105
|
- quality-control
|
|
102
106
|
available:
|
|
107
|
+
- work-decomposition # v0.8 P2-E
|
|
103
108
|
- skill-authoring
|
|
104
109
|
- skill-to-workflow
|
|
105
110
|
- dashboard-reporting
|
|
@@ -134,6 +134,20 @@ versions.json # 版本清单(工作空间根目录)
|
|
|
134
134
|
|
|
135
135
|
在初始化阶段就和开发者用户讨论这个节奏 —— 生产侧文档输入节奏直接决定 skill 和工作流的写法(批处理 vs 流式、幂等性要求等等)。
|
|
136
136
|
|
|
137
|
+
## 持续维护 AGENT.md 的项目记忆
|
|
138
|
+
|
|
139
|
+
工作区根目录的 `AGENT.md` 有几段「项目记忆」(`Project`、`Decisions`、`Domain Notes`、`User Preferences`)。它们在 bootstrap 阶段是占位注释 —— 你的任务是随着工作推进往里填东西,让跨阶段或跨会话的人能直接读出上下文。
|
|
140
|
+
|
|
141
|
+
应该写什么:
|
|
142
|
+
- **Project**:语料身份(法规名称 + 范围)、语言、主规则与辅助规则、样本文档集组成。
|
|
143
|
+
- **Decisions**:从代码看不出来的设计决定 —— 比如「非标 35% 限制是银行级合计而非单产品限制,所以单文档报告给 WARNING 而非 FAIL」「R02-06/R02-08 对季报判 NOT_APPLICABLE,依据是法规 §39」。
|
|
144
|
+
- **Domain Notes**:值得显式记下来的法规或业务领域细节 —— 比如「PT/RT/LZ 是三种不同产品类型,披露模板不同」、术语消歧。
|
|
145
|
+
- **User Preferences**:开发者用户希望你在本项目上的协作风格 —— 详略偏好、命名约定、什么时候问、什么时候直接做。
|
|
146
|
+
|
|
147
|
+
更新 `AGENT.md` 的自然时机:开发者用户给出实质性澄清之后、阶段结束之后、发现会影响后续阶段的设计约束之后。不要等用户发 `/remember` —— 这份记忆是你自己维护的。
|
|
148
|
+
|
|
149
|
+
未来会话恢复时会先读 `AGENT.md`。它越充实,开发者用户需要重复解释的内容就越少。
|
|
150
|
+
|
|
137
151
|
## 何时需要重新初始化
|
|
138
152
|
|
|
139
153
|
以下情况需要重新运行本技能:
|
|
@@ -4,27 +4,27 @@ tier: meta
|
|
|
4
4
|
description: Determine whether extracted entities comply with verification rules. Use after entity extraction to make the pass/fail judgment for each rule on each document. Covers translating natural language rules into executable logic, choosing between Python calculation and LLM semantic judgment, and producing actionable comments on failures. Also use when designing the judgment step of a workflow or when a rule's judgment logic needs debugging.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
#
|
|
7
|
+
# 合规判定
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
判定是真相到来的时刻。你已经拿到抽取出来的实体,也有规则在手。它们是否合规?答案必须清晰、正确,并且——当答案为否时——附带一条简洁、可执行的说明。判定环节直接决定整个核查工作流的最终产出质量:抽取做得再细,如果判定阶段含糊或前后不一,下游的合规报告就难以使用。
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## 判定光谱
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
规则的复杂度跨度很大,从纯粹的确定性检查到深度语义判断都有。要为每条规则挑选合适的工具,不能一刀切。
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
**确定性判定** —— 阈值核查、格式校验、日期运算、跨字段一致性。纯 Python 就够:免费、即时、可复现,并且同一份输入永远给出同一份结果,便于审计与回溯。
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
**语义判定** —— 是否充分披露、是否完整、前后是否一致、是否符合模板、是否存在误导性或暗示性表述、描述是否公允平衡。这类判断需要语言理解能力,规则关键词法或模式匹配无法胜任,应直接使用 worker LLM 完成。
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
很多真实的合规规则都需要语义判定。"风险揭示必须充分描述主要风险"无法用正则或 Python 核查;"合同描述不得具有误导性或暗示性"需要深层的语言理解;"资产管理产品的宣传材料不得含有承诺收益的暗示"同样如此。这类场景应毫不犹豫地调用 worker LLM,强行用规则匹配反而会牺牲准确率。
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
也有些规则会两者并用:先抽取数值(确定性),再与阈值比较(确定性),如果结果处于临界区间,再对其解释做语义评估。这种"Python 主跑、LLM 兜底"的组合往往是性价比最高的方案。具体如何组合,取决于规则本身。
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
正确的方法,是以最低成本达到所需准确率的那一个。简单的阈值核查不需要 LLM,语义评估也无法靠 Python 完成。多数项目都会两者混用——让每条规则的性质决定其判定方法,而不是反过来用方法去硬套规则。
|
|
24
24
|
|
|
25
|
-
##
|
|
25
|
+
## 输出格式
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
对每个"规则 × 文档"的组合:
|
|
28
28
|
|
|
29
29
|
```json
|
|
30
30
|
{
|
|
@@ -38,26 +38,26 @@ For each rule × document combination:
|
|
|
38
38
|
}
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
- **pass
|
|
43
|
-
- **fail
|
|
44
|
-
- **missing
|
|
45
|
-
- **error
|
|
46
|
-
- **uncertain
|
|
41
|
+
**结果取值:**
|
|
42
|
+
- **pass**:实体符合规则要求。
|
|
43
|
+
- **fail**:实体不符合规则要求。必须填写 comment。
|
|
44
|
+
- **missing**:文档中未找到该实体。这与 fail 不同——信息缺失,并不代表违规。
|
|
45
|
+
- **error**:抽取或判定过程出现异常(解析失败、API 错误等)。需要排查。
|
|
46
|
+
- **uncertain**:判定结果存在歧义,可能需要人工复核。
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
**先设计退出条件:** 在为一条规则编写判定逻辑前,先把退出条件定义清楚:什么算 pass、什么算 fail、什么情况下需要升级到人工、空值/缺失值如何处理、合法的取值范围是什么。显式的退出条件能避免判定模糊或前后不一致,也方便后续在进化循环中复盘判定逻辑的盲区。
|
|
49
49
|
|
|
50
|
-
**Prompt
|
|
50
|
+
**Prompt 设计:** 提示词要正向描述你想要什么,而不是反向描述你不想要什么。"不要包含推理过程"远不如在结构化输出里抽取判定结果可靠。模型对否定指令的遵循度普遍偏低,不如直接约束输出字段、再用后处理过滤把多余内容去掉。
|
|
51
51
|
|
|
52
|
-
**
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
52
|
+
**Comment 写法:**
|
|
53
|
+
- 仅在 result 为 `fail` 时必须填写。`pass` 时不写,除非开发者用户明确要求记录通过项的说明。
|
|
54
|
+
- 简洁、陈述事实:"资本充足率为 7.2%,低于 8.0% 的监管最低要求。"
|
|
55
|
+
- 不做评论性发挥:不要写"这是严重违规,可能招致处罚"。只陈述事实即可。
|
|
56
|
+
- 在 comment 中给出抽取值和期望值/条件,便于读者理解上下文。
|
|
57
57
|
|
|
58
|
-
###
|
|
58
|
+
### 轻量标注语法
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
为了便于人工复核、节省日志 token、做干净的 diff 比对,结果也可以用紧凑的文本标注形式表达:
|
|
61
61
|
|
|
62
62
|
```
|
|
63
63
|
[PASS] capital_adequacy <- 12.5% (>= 8.0%) | conf:0.95 | src:p3-s2
|
|
@@ -65,19 +65,19 @@ For human review, token-efficient logging, and clean diff comparisons, results c
|
|
|
65
65
|
[MISSING] collateral_value | conf:0.60 | note:Collateral valuation not found in document
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
这一格式与上面的 JSON 格式可无损互转。在以下场景使用:向开发者用户展示结果以便快速过目、写入进化迭代摘要等对 token 经济敏感的日志、在多次核查运行之间计算 diff 以发现回归。完整规范和转换规则参见 `references/output-format.md`。
|
|
69
69
|
|
|
70
|
-
##
|
|
70
|
+
## 判定执行顺序
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
-
|
|
74
|
-
-
|
|
72
|
+
部分规则会依赖其他规则的结果:
|
|
73
|
+
- 规则 B 可能只在规则 A 通过时才适用。"如果借款人是新客户(规则 A),则需要额外的文件资料(规则 B)。"
|
|
74
|
+
- 规则 C 可能要复用规则 A 计算出的数值。"风险加权资本充足率(规则 A)决定了所需的准备金水平(规则 C)。"
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
把这类依赖关系登记在规则目录中,最好以显式的依赖图形式维护。按依赖顺序执行规则,把上游规则的结果作为上下文传给下游规则,避免下游规则在缺少前置真值时拿到错误的输入。
|
|
77
77
|
|
|
78
|
-
##
|
|
78
|
+
## 边界情况处理
|
|
79
79
|
|
|
80
|
-
-
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
-
|
|
80
|
+
- **抽取为空**:实体未找到。默认归为 `missing`,而不是 `fail`。值缺失属于抽取问题,不是合规问题。
|
|
81
|
+
- **多值情况**:文档在多处出现同一实体,但取值不一致。标记为 `uncertain`,并把所有找到的值连同各自的位置都报出来,便于人工复核时定位差异源头。
|
|
82
|
+
- **条件规则**:"如果贷款金额超过 100 万,则必须有担保。"先核查条件再套用规则。条件不成立时规则不适用——结果记为 `pass`(如果你额外引入了 `not_applicable` 类别,也可以使用)。
|
|
83
|
+
- **否定型规则**:有些规则核查的是"不存在"。"文档中不得存在向关联方提供的担保。"搜索"不存在"比搜索"存在"难,因为要先证伪所有可能的命中位置才能下结论。先把搜索做彻底,再对否定结论保持信心。
|
|
@@ -8,26 +8,33 @@ description: >
|
|
|
8
8
|
verification chunking — for that, use tree-processing to design a tailored chunking script.
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
#
|
|
11
|
+
# 文档分块处理
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
将文档切分为若干块,供下游环节使用。本技能提供的是快速、低成本的版本,面向样本和输入文档的批量处理,不适用于追求精度的核查工作流。
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
文档分块是 KC 工作流的常见前置步骤。原始文档往往超出单次调用的上下文窗口,或包含大量与当前任务无关的内容;恰当的分块既能控制 token 消耗,又能让后续的规则匹配、抽取、合规核查在更小、更聚焦的单元上进行。本技能给出三种成本最低、最易复用的分块策略,并说明各自的适用场景。
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
## 分块方法
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
**按页切分(Page-level splits)** — 最简单的方式。每页即为一个块。适用于大多数需要遍历文档内容的处理场景,例如初步观察样本、统计页数分布、或为每页生成摘要。这种方式不依赖文档内部结构,鲁棒性最高。
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
**定长分块(Fixed-size chunks)** — 按字符数或 token 数切分,相邻块之间保留重叠区域。适合构建检索索引或进行初步观察。常见参数:每块 2000–4000 字符,相邻块之间保留 200 字符重叠。重叠的作用是避免边界处的语义被切断,导致后续匹配漏检。
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
**按标题切分(Header-based splits)** — 识别章节标题,在标题边界处切分。这种方式能保留语义完整的章节单元,便于按条款、按章节进行规则核查。具体实现上,应根据目标文档的标题格式编写正则表达式,例如「第X条」「附录X」「X.X.X」等编号规则。
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
- Batch document observation → page-level
|
|
27
|
-
- Full-text search index → fixed-size with overlap
|
|
28
|
-
- Section-level extraction → header-based
|
|
29
|
-
- Table of contents available → parse TOC for structure
|
|
25
|
+
## 何时使用哪一种
|
|
30
26
|
|
|
31
|
-
|
|
27
|
+
按任务复杂度选择最简单可行的方法:
|
|
32
28
|
|
|
33
|
-
|
|
29
|
+
- 批量观察样本文档 → 按页切分
|
|
30
|
+
- 构建全文检索索引 → 定长分块加重叠
|
|
31
|
+
- 按章节抽取条款或要点 → 按标题切分
|
|
32
|
+
- 文档自带目录 → 直接解析目录得到结构
|
|
33
|
+
|
|
34
|
+
选择策略时要兼顾下游消费方的需求。若下游是 `worker_llm_call` 进行规则抽取,块的粒度应与单条规则的承载单元对齐;若下游是关键词检索,则块越小越精确,但召回率可能下降,需在两者之间取得平衡。
|
|
35
|
+
|
|
36
|
+
## 与 tree-processing 的关系
|
|
37
|
+
|
|
38
|
+
本技能仅用于探索阶段和批量处理阶段的快速、低成本分块。当你需要为合规核查工作流构建生产级分块——即分块机制必须精确、稳定、可复现并以脚本形式落地时,应改用 `tree-processing` 技能。后者会根据文档的具体结构设计专门的分块脚本,并把切分逻辑沉淀为可重复运行的工件,便于在 production_qc 阶段对结果进行回溯和审计。
|
|
39
|
+
|
|
40
|
+
两者的分工原则:本技能服务于「先看一眼数据」的快速判断,`tree-processing` 服务于「正式核查每一份文档」的工程化交付。在 KC 的 bootstrap 和 rule_extraction 阶段优先使用本技能;进入 skill_authoring 之后,若分块逻辑将被反复调用,应及时迁移到 `tree-processing`,并把对应的脚本和参数固化到技能目录下,避免每次运行得到不一致的切分结果,影响后续违规判定的可追溯性与置信度评估。
|
|
@@ -4,99 +4,99 @@ tier: meta
|
|
|
4
4
|
description: Parse source documents into machine-readable text with maximum fidelity. Use when processing any document in Samples/ or Input/ for the first time, when parsed text quality is poor, or when tables and charts need special handling. Covers multi-level parser selection from simple text extraction to OCR and vision models. Also use when a verification rule fails due to parsing issues (garbled text, missing tables, mangled layouts) and the parser needs to be upgraded for that document type.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
#
|
|
7
|
+
# 文档解析
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
解析是整个工作流的根基。一旦文本提取错了,下游的所有规则判断、对账、合规核查都会跟着一起错,而且这种错误往往很难在后续环节里被发现——因为下游看到的只是"一段文字",并不知道这段文字其实已经丢失了关键数字或错位了表头。但解析同时也是一个明显的成本中心——能用简单文本抽取解决的事情,就不要轻易动用昂贵的视觉模型或重型 OCR 流水线,这只会拖慢整体节奏并消耗预算。
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## 最小可用解析器原则
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
从最简单的解析器开始。只有在确有必要时才向上升级。这条原则并不是单纯为了省钱——更重要的是为了产出最可靠、最稳定的结果。简单的解析器失败模式更少、更可控,排查起来也更直接;一旦堆叠了过多的处理层,出问题时几乎无法定位究竟是哪一层引入了偏差,调试成本会指数级上升。优先选择能用就用的最低层级,把复杂性留给真正需要的文档类型。
|
|
14
14
|
|
|
15
|
-
### Level 1:
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
15
|
+
### Level 1: 直接文本抽取
|
|
16
|
+
- 工具:pdfjs-dist,或其它类似的 PDF 文本抽取库。
|
|
17
|
+
- 适用场景:结构良好、内嵌文本的数字版 PDF。绝大多数现代商业文档(年报、招股说明书、合同、技术手册)都属于这一类。
|
|
18
|
+
- 输出:保留基本结构(段落、基础格式)的原始文本。
|
|
19
|
+
- 局限:表格往往会被拉平成杂乱的文字流,行列关系丢失。图表与图片完全不可见。扫描件 PDF 抽不出任何内容,加密 PDF 也会直接失败。
|
|
20
20
|
|
|
21
|
-
### Level 2: Provider VLM
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
21
|
+
### Level 2: Provider VLM(视觉语言模型)
|
|
22
|
+
- 工具:已配置 provider 的 VLM 模型(VLM_TIER3 用于低成本 OCR,VLM_TIER1 用于复杂内容的语义解读)。
|
|
23
|
+
- 适用场景:Level 1 产出乱码或文本残缺、扫描件 PDF、图像型 PDF,以及版式高度复杂、列布局或注脚混乱的报告。
|
|
24
|
+
- 输出:从页面图像中识别出的文本,或更进一步的结构化解读结果(表格转成 markdown、图表数据转成 JSON)。
|
|
25
|
+
- 调用 provider VLM 通常比自行部署本地 OCR 更便捷、更稳定,也省去了维护模型权重、显卡资源与推理环境的整套开销。优先使用最便宜的 VLM 层级把内容先拿到手并完成基本评估;只有遇到复杂的表格、密集的图表,或更低层级在测试样本上确实不够用时,再升级到更强的层级,而不是一开始就用旗舰模型把所有页面跑一遍。
|
|
26
26
|
|
|
27
|
-
### Level 3: MineRU API
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
27
|
+
### Level 3: MineRU API 或本地工具(可选)
|
|
28
|
+
- 工具:MineRU API、pdfplumber,或本地部署的 OCR——前提是已经配置好。
|
|
29
|
+
- 适用场景:provider VLM 不可用,或批量处理时整体费用过高。
|
|
30
|
+
- 这些属于可选的兜底方案,并不是默认路径。大多数用户使用 Level 1 + Level 2 的组合就已经足够覆盖日常需求。
|
|
31
31
|
|
|
32
|
-
##
|
|
32
|
+
## 质量检测
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
如何判断当前层级该不该向上升级:
|
|
35
35
|
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
36
|
+
- **字符数过低**:文档有多页,但抽取出的文本极短。大概率是扫描件 PDF,或者是带有大量图像内容的 PDF。
|
|
37
|
+
- **乱码文本**:出现异常的字符序列、明显的编码错误,或一眼看上去毫无意义的文字模式。
|
|
38
|
+
- **预期章节缺失**:目录中提到了第 5 章,但抽取结果里完全没有第 5 章的正文,这通常意味着排版方式让文本抽取器卡住了。
|
|
39
|
+
- **表格残骸**:成列的数字没有对齐、单元格内容与表头混在一起、表格边框被识别成无意义的字符流。
|
|
40
|
+
- **财务表格中关键数字缺失**:如果一份财务文档的关键指标没有出现在抽取文本里,那大概率就是表格没有被正确解析,而不是它们本身就不存在。
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
在解析之后、继续后续处理之前,写一个快速的质量检查脚本。如果质量不达标,就升级到下一层解析器,而不是带病往下走。
|
|
43
43
|
|
|
44
|
-
###
|
|
44
|
+
### 解析质量分数
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
通过加权启发式规则计算一个 0.0 到 1.0 的质量分数,让升级决策有据可依,而不是单纯凭感觉做判断。一个推荐的初始框架如下:
|
|
47
47
|
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
-
|
|
48
|
+
- **字符密度**(权重约 0.3):实际字符数 / 该文档页数下的预期字符数。一份 10 页的 PDF 如果只抽出 200 个字符,基本可以直接判定为失败。
|
|
49
|
+
- **乱码比例**(权重约 0.2):常见中英文字符占总字符的比例,相对于控制字符、异常序列或编码残留物的比例。
|
|
50
|
+
- **章节完整度**(权重约 0.3):如果文档自带目录,目录条目中有多少比例能在抽取文本里找到对应内容?
|
|
51
|
+
- **表格完整性**(权重约 0.2):对于财务类文档,本应出现在表格中的关键数值,是否真的出现在抽取文本中?
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
53
|
+
**升级阈值**(推荐默认值——可根据实际情况自由调整):
|
|
54
|
+
- 分数 >= 0.7:接受当前解析器层级,进入下游处理。
|
|
55
|
+
- 分数 0.4-0.7:升级到下一层解析器,重新解析,重新打分。
|
|
56
|
+
- 分数 < 0.4:直接跳过中间层级,根据文档特征跳到 Level 3(OCR)或 Level 4(视觉模型)。
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
**层级锁定**:一旦某个解析器层级在某类文档上跑出可接受的分数,就把这个层级记录下来。除非下游某次验证失败被追溯到解析环节,否则不要再花时间重复评估,这能避免在已经稳定的链路上反复折腾。
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
上述权重、阈值,乃至打分思路本身,都只是一个起点。编码 agent 应当为手头的具体文档类型设计真正合适的质量评估方案——某些场景下简单的通过/失败启发式就完全够用,另一些场景则可能需要更精细的分项打分函数。真正关键的模式是:**度量质量 → 与阈值比较 → 决定是否升级**,而不是某一组具体的权重数字。
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
这与 `skill-to-workflow` 中模型层级选择遵循的层级跃迁模式是一致的:都由一个质量或准确率分数,来驱动"停留在当前层级、升级到下一层级、还是跳过中间层直接进入更高层"这三种决策。
|
|
63
63
|
|
|
64
|
-
##
|
|
64
|
+
## 表格处理
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
表格在财务文档中至关重要(资产负债表、比率表、合规指标表、监管披露表),它们承载了规则验证最常引用的数值,因此值得专门对待:
|
|
67
67
|
|
|
68
|
-
1.
|
|
69
|
-
2.
|
|
70
|
-
3.
|
|
71
|
-
4.
|
|
68
|
+
1. **检测**:识别出页面中的表格区域。寻找规则的网格模式、稳定的列间距,或文档自身的显式表格标记。
|
|
69
|
+
2. **抽取**:逐单元格提取内容。严格保留行列对应关系,不要把多列合并成一行长字符串。
|
|
70
|
+
3. **重建**:把抽取结果转换成结构化格式(markdown 表格、JSON 行数组,或 CSV),便于下游程序消费。
|
|
71
|
+
4. **校验**:对重建后的表格抽查若干关键单元格,确认其数值与文档中肉眼可见的值一致,以此尽早发现错位或漏行。
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
如果标准解析器在表格上失手,可以尝试视觉模型路线:把表格图像(从 PDF 页面上精确裁剪出来)发送给视觉模型,让它直接产出一个 markdown 表格。这种方式对带合并单元格、跨页延续的复杂表格尤其有效。
|
|
74
74
|
|
|
75
|
-
##
|
|
75
|
+
## 图表处理
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
图表(柱状图、折线图、饼图、雷达图)偶尔也会承载验证所需的数据:
|
|
78
78
|
|
|
79
|
-
-
|
|
80
|
-
-
|
|
81
|
-
-
|
|
79
|
+
- 从文档中抽出图表图像,保留必要的坐标轴与图例区域。
|
|
80
|
+
- 发送给视觉模型,prompt 类似:"Extract the data points, labels, and values from this chart. Return as a JSON array."
|
|
81
|
+
- 用图表附近的文字段落或表格(它们经常会以另一种形式呈现相同的数字)对抽取结果进行交叉校验。
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
这一步代价相对昂贵,而且图表识别的准确率天然低于纯文本抽取。只有当某条验证规则明确要求使用图表中的数据,且该数据无法从文档其他文字或表格中获得时,才动用它,而不是默认对所有图表都跑一遍视觉模型。优先尝试在邻近文字中找到相同的数字,这通常是更经济也更可信的路径。
|
|
84
84
|
|
|
85
|
-
##
|
|
85
|
+
## 输出格式
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
解析后的文档应当保存为干净、规范的 markdown:
|
|
88
88
|
|
|
89
|
-
-
|
|
90
|
-
-
|
|
91
|
-
-
|
|
92
|
-
-
|
|
93
|
-
-
|
|
89
|
+
- 保留文档原有的标题层级(# 章、## 节、### 小节),不要把所有标题压平到同一层。
|
|
90
|
+
- 保留列表结构,无论是有序列表还是无序列表。
|
|
91
|
+
- 把表格转换成 markdown 表格格式,而不是用纯文字描述。
|
|
92
|
+
- 在有需要时标注页边界(部分规则会引用具体页码,这种位置信息必须保留)。
|
|
93
|
+
- 剔除噪声:页眉、页脚、页码、水印——除非某条规则专门要检查它们。
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
把解析输出与原始文档保存在一起,方便跨规则、跨技能复用同一份解析结果。
|
|
96
96
|
|
|
97
|
-
##
|
|
97
|
+
## 缓存
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
-
|
|
101
|
-
-
|
|
102
|
-
-
|
|
99
|
+
解析这一步本身很昂贵(尤其是 Level 3-4),在迭代规则、反复跑验证流程时尤其明显。务必把解析结果缓存下来,而不是每次都从原始 PDF 重新跑一遍:
|
|
100
|
+
- 把解析后的 markdown 与原始文件保存在同一目录,命名约定要稳定、可预测,便于程序化查找。
|
|
101
|
+
- 同时记录是哪一层解析器产出的,以及该层级当时拿到的质量分数,方便日后回溯与对比。
|
|
102
|
+
- 仅在以下情况重新解析:原始文件发生变化、某条规则要求比当前缓存更高质量的解析结果,或某次验证失败被追溯到了解析问题本身。
|