docs: 补全 README(bidding_general产线/12张bid_表/对账器bid_flow/QC门禁两级回退/门限参数/build.sh集成)

This commit is contained in:
yumoqing 2026-09-07 11:42:17 +08:00
parent 442de85cc3
commit ff20d6fa14

153
README.md
View File

@ -1,2 +1,153 @@
# pipeline-bidding
# pipeline-bidding — 投标产线模块
## 模块定位
产线平台pipeline-app / pipeline-core的第二条产线能力包**投标产线 `bidding_general`**。
验证并落地「产线能力包住自己仓库、宿主不装则零接触」的分层原则——能力模块全部住在本仓库,
不进 `pipeline-service`;宿主只要不 `import pipeline_bidding`,一切都不会发生。
模块 = 数据(`bid_*` 表 + CRUD+ 能力(`bid_*_capability`+ 流转(`bid_flow` 状态对账器)
+ 主 agent 能力包(`bid_ability`+ 角色技能(部署期随 pipeline-core skills_library 分发)。
**产线起点 = 上传招标文件**`import_tender_file` 无 project_id 时自动立项)。阶段链:
> 收到招标文件(自动立项)→ 解析(评分项/资质/投标文件要求/商务要素/章节骨架)
> → QC 契合度审核四类逐类10 分制,>9.5 放行)→ 资料准备 → 分角色并发编写
> business→bid_biz_writer / technical→bid_writer→ 章节评审(含篇幅门禁)→ 合成
> → 整书评分 → 交付确认。
核心机制:
- **角色任务流转不用 RoleSpec.next_role**(全留空):投标是「一章一任务 + 两级回退循环」
扇出结构,由 `bid_flow` 状态对账器(每 15s 一轮)补派,对账器是角色任务的**唯一创建者**。
- **阻塞门禁在创建源头**(对账器判 `pipeline_human_tasks.project_id + pending`
不写进引擎 poller SQL。`tenant_id=project_id` 只是角色任务约定,禁止写进引擎层。
- **两级回退循环**:章节级(得分率 < `bid_chapter_pass_ratio` 或篇幅不达标 rejected+意见
自动重写,超 `bid_max_revise` 抛人工);整书级(< `bid_pass_ratio` 或否决项未响应
`target_chapter_id` 打回 → 重写→重审→重合成→重评分,超 `bid_max_round` 抛人工)。
- **QC 门禁**:四类解析产出逐类审核落 `bid_qc_reviews`;不通过 → 清空该类产出 → 对账器重派
解析(`params.qc_redo=1` + 改进意见)→ 重审;轮次超 `bid_qc_max_round``qc_escalation`
阻塞人工(逃逸阀:人工修产出后在记录页把 passed 改 1 即生效)。
- **门限参数全部读 appbase `params` 表 + DEFAULT_PARAMS 兜底**,不硬编码:
`bid_chapter_pass_ratio`(0.8) / `bid_pass_ratio`(0.85) / `bid_max_revise`(3) /
`bid_max_round`(3) / `bid_qc_pass_score`(9.5) / `bid_qc_max_round`(3) /
`bid_chapter_min_words`(800) / `bid_chapter_min_words_biz`(500) / `bid_write_concurrency`(4)。
## 表清单models/*.json建表产物 mysql.ddl.sql
| 表名 | 说明 | 关键字段 |
|---|---|---|
| `bid_tenders` | 招标商务要素 | project_id, source, title, purchaser, tender_no, industry |
| `bid_tender_files` | 招标文件 | project_id, tender_id, file_name, file_path, file_type, content_text |
| `bid_scoring_items` | 评分项与得分规则 | project_id, section, item_no, item_name, max_score, scoring_rule, is_veto |
| `bid_qualifications` | 招标所需资质 | project_id, qual_name, requirement, is_mandatory, owner, kb_doc_id, match_status |
| `bid_doc_requirements` | 投标文件要求 | project_id, req_type, chapter_no, chapter_title, requirement, page_limit, source_ref |
| `bid_chapters` | 投标文件章节 | project_id, chapter_no, parent_no, title, section, outline, status, content, word_count, review_score |
| `bid_reviews` | 标书评审记录 | project_id, scope, chapter_id, document_id, round, reviewer, review_type |
| `bid_scores` | 标书评分明细 | project_id, review_id, scoring_item_id, item_name, score, max_score, reason |
| `bid_documents` | 合成标书 | project_id, version, doc_name, file_path, page_count, chapter_count, total_score |
| `bid_qc_reviews` | 解析产出 QC 审核记录 | project_id, qc_type, round, reviewer, review_type, fit_score, pass_score |
| `bid_kb_docs` | 公司投标知识库 | org_id, doc_type(sample_bid 等), doc_name, doc_no, tags, file_path, content_text |
| `bid_members` | 投标项目参与人员 | project_id, user_id, user_name, member_role, duty, status |
种子数据(`init/data.json`build.sh 幂等写入):`pipelines` 产线主记录 `bidding_general` +
`appcodes` 12 组码表bid_qc_type / bid_tender_source / bid_member_role / bid_file_type /
bid_scoring_section / bid_qual_match_status / bid_qual_owner / bid_req_type /
bid_chapter_status / bid_review_scope / bid_kb_doc_type / bid_doc_status
## 对外 API / dspy 端点wwwroot/
部署后挂载在宿主 `wwwroot/pipeline-bidding/`(软链):
- **api/bid_probe.dspy** — 服务内探针(诊断)。`?action=status` 返回模块装载状态 +
poller 心跳 + 活跃投标项目数;`?action=reconcile` 在服务进程内跑一轮全量对账返回动作明细。
- **api/bid_task_tree.dspy** — 任务树懒加载(根 → role:阶段 → 任务 → step:/del: 叶子)。
项目解析三级兜底session_settings(default_bidding_general) → agent_settings →
最近 in_progress 项目。
- **api/bid_task_io.dspy** — 任务树右侧详情面板:输入 = 任务描述 + QC 改进意见,
执行步骤,输出 = 交付件(复用 `pipeline_service/task_io_render.py` 统一渲染规范)。
- **bid_task_tree_popup.ui** — ResourceBrowser 复合 widget 弹窗(左树右详情联动)。
- **agent/index.ui** — 驾驶舱入口页(顶栏含任务树按钮)。
- **12 个 CRUD 目录**bid_tenders / bid_tender_files / bid_scoring_items /
bid_qualifications / bid_doc_requirements / bid_chapters / bid_reviews / bid_scores /
bid_documents / bid_qc_reviews / bid_kb_docs / bid_members— 每个含
index.ui + get/add/update/delete_*.dspy 标准五件套。
⚠️ RBAC 铁律:`/api/` 前缀不覆盖具体 dspy**新 API 必须逐条显式注册**scripts/load_path.py
否则 403注册后 redis db0 FLUSHDB 即生效。
## load 注册函数
宿主入口pipeline_app.py两步缺一不可
```python
from pipeline_bidding.init import load_pipeline_bidding
load_pipeline_bidding() # import 后必须再显式调用,漏了无任何日志(静默大坑)
```
`load_pipeline_bidding()`(幂等)做三件事:
1. `role_tool_schemas.register_role_tools()` — 把约 55 个投标角色工具 schema
read_tender_file / extract_* / add_* / patch_chapters / write_chapter /
review_chapter / start_qc / finish_qc / compose_bid / start_bid_score /
finalize_bid_score / dispatch_analysis_dim 等)注册进引擎
`pipeline_service.capability_tools.TOOL_SCHEMAS`(引擎 `exec_capability_tool`
`module` 支持全路径,裸名仍走 `pipeline_service.*`SDLC 零变化)。
2. `import bid_ability` — 主 agent 能力包 + slash 命令注册import 即注册)。
3. `bid_flow.start_poller()` — 状态对账器启动(`PIPELINE_MODE=web` 时不注册,
与引擎 poller 同款模式开关)。
角色工具装配链:角色技能 frontmatter `capability+tools``_capability_to_tools_map`
`TOOL_SCHEMAS`**两者交集才是可见工具**(技能声明了但 schema 没注册 = 工具静默缺失)。
独立脚本验证必须先显式调 `load_pipeline_bidding()`,仅 import 包不触发注册。
码表导入自持:`scripts/import_init_bidding.py`(幂等 + 废弃清理 + 产线描述),
不依赖宿主 `import_init.py` 的 INIT_MODULES。
## 宿主集成(部署)
在宿主应用pipeline-app根目录或本目录执行一键脚本
```bash
./build.sh
```
build.sh 职责(运行期禁止 schema 变更,建表只在部署期):
1. **建表**:读 `mysql.ddl.sql`json2ddl 产物),把 `drop table if exists` 剔除、
`CREATE TABLE` 改为 `CREATE TABLE IF NOT EXISTS` 幂等化,用宿主 config 的
`pipeline` 库连接执行。
2. **种子数据**`init/data.json` 幂等写入 pipelines 产线记录 + appcodes/appcodes_kv 码表。
3. **wwwroot 软链**`ln -sf 本仓库/wwwroot → $APP_ROOT/wwwroot/pipeline-bidding`
4. **pip install**`$APP_ROOT/py3/bin/pip install 本目录`(非 editable 安装)。
宿主负责的后续app 入口 import + 调用 `load_pipeline_bidding()`
RBAC 用 `scripts/load_path.py`(其中 set_role_perm.py 必须用宿主根**绝对路径**
i18n 合并用 merge_i18n.py。
## 部署注意(实测踩坑)
1. **非 editable 安装**:测试机只 `git pull` 仓库不会更新 site-packages改码后必须
`./py3/bin/pip install pkgs/pipeline-bidding` 再重启(可对比 site-packages 与仓库文件
md5 确认加载版本)。
2. **运行时技能树独立仓库**:在 `/d/pipeline/pipeline-app/skills/`git:
yumoqing/pipeline-sdlc.git不是 pipeline_core 的 skills_library改了 bid-workflow
等技能必须同步 SKILL.md 到 `pipelines/bidding_general/common/<技能名>/` 再重启。
3. **宿主入口漏调用 `load_pipeline_bidding()` 是静默大坑**:无任何日志。诊断走
`api/bid_probe.dspy?action=status` 心跳探针。
4. **RBAC 缓存**:新路径注册后 redis db0 FLUSHDB 即生效(旧说须重启已过时);
精确 path 匹配,父路径不覆盖子路径。
5. **角色任务 failed 必须是对账器阻塞态**:否则每 15s 重复造任务(机构未配 LLM 时必现);
测试环境无 LLM 模型时任务 failed 属预期。
6. **自动立项的项目不继承模型**:不带 default_model解析链兜底全局默认名可能不存在 → 401
建后必查/补 `sd_projects.default_model`
7. **bid_chapters 键归一**`resolve_project_id` 先按 id 校验、按 name 反查归一,
名字歧义拒绝(防「项目名当 project_id」写库产生孤儿骨架
8. 对账器结构铁律:维度过滤(等上游 QC 的不算掉链)必须在 `_open_orch_tasks` 判定前
无条件执行,编排任务创建/掉链计数留在「无编排任务在办」的 else 分支内,
否则每 15s 重复建编排任务堆积。
9. 共享工具 `create_task` 有产线角色校验守卫get_role_spec 查不到即拒绝),
`list_roles` 查看本产线可用角色。
详细设计见 `docs/DESIGN.md`;技能库见 pipeline-core
`skills_library/pipelines/bidding_general/`common 7 技能 + roles 9 角色含 bid_biz_writer