189 lines
8.1 KiB
Python
189 lines
8.1 KiB
Python
from __future__ import annotations
|
||
|
||
from .shared import *
|
||
|
||
from .charter_seed_utils import _build_signal_context_text, _to_bullet_text, _to_string_list
|
||
from .charter_prefill_utils import _default_ai_validations, _default_escalation_trigger, _generate_charter_seed
|
||
|
||
async def _build_ai_first_charter_content(
|
||
*,
|
||
db: AsyncSession,
|
||
tenant_id: int,
|
||
project_id: int,
|
||
signal_rows: list[Signal],
|
||
signal_ids: list[int],
|
||
raw_text: str = "",
|
||
) -> dict[str, Any]:
|
||
signal_context = _build_signal_context_text(signal_rows, raw_text=raw_text)
|
||
seed = await _generate_charter_seed(
|
||
db=db,
|
||
tenant_id=tenant_id,
|
||
project_id=project_id,
|
||
signal_context=signal_context,
|
||
)
|
||
|
||
summary = str(seed.get("summary") or "").strip()
|
||
background = str(seed.get("background") or "").strip()
|
||
objectives = _to_string_list(seed.get("objectives"))
|
||
scope = str(seed.get("scope") or "").strip()
|
||
in_scope_items = _to_string_list(seed.get("in_scope"))
|
||
out_of_scope_items = _to_string_list(seed.get("out_of_scope"))
|
||
success_metrics = _to_string_list(seed.get("success_metrics"))
|
||
risks = _to_string_list(seed.get("risks"))
|
||
dependencies = _to_string_list(seed.get("dependencies"))
|
||
primary_model = str(seed.get("primary_model") or "").strip()
|
||
fallback_model = str(seed.get("fallback_model") or "").strip()
|
||
|
||
if not summary:
|
||
summary = "目标用户在当前流程中存在效率损耗,需要通过 AI 驱动的流程优化提升交付质量与速度。"
|
||
if not background:
|
||
background = signal_context[:500] or "基于已绑定信号源自动生成。"
|
||
if not objectives:
|
||
objectives = ["缩短端到端交付周期", "提升关键路径质量稳定性", "降低跨角色协同成本"]
|
||
if not success_metrics:
|
||
success_metrics = ["需求到上线周期缩短 >= 30%", "关键任务按期交付率 >= 90%", "线上回滚率 <= 3%"]
|
||
if not in_scope_items:
|
||
in_scope_items = ["需求澄清与宪章生成自动化", "任务拆解与负责人推荐", "对齐状态自动追踪与留痕"]
|
||
if not out_of_scope_items:
|
||
out_of_scope_items = ["替代团队组织架构决策", "绕过人工否决机制自动上线", "非项目相关流程改造"]
|
||
if not risks:
|
||
risks = ["需求波动导致范围蔓延", "模型能力边界与输入复杂度不匹配", "关键成员负载过高导致延期"]
|
||
if not dependencies:
|
||
dependencies = ["FastAPI", "React", "LLM 推理服务", "项目知识库/日志系统"]
|
||
if not primary_model:
|
||
primary_model = "待 AI 评估后绑定"
|
||
if not fallback_model:
|
||
fallback_model = "同供应商低成本模型"
|
||
|
||
source_refs = [f"signal:{sid}" for sid in signal_ids]
|
||
now_iso = now_cn_aware().isoformat()
|
||
validations_m1 = _default_ai_validations("模块1:触发与目标")
|
||
validations_m2 = _default_ai_validations("模块2:范围与对齐")
|
||
validations_m3 = _default_ai_validations("模块3:模型与依赖")
|
||
validations_m4 = _default_ai_validations("模块4:计划与资源")
|
||
validations_m5 = _default_ai_validations("模块5:风险与兜底")
|
||
validations_m6 = _default_ai_validations("模块6:附件与治理")
|
||
escalation = _default_escalation_trigger()
|
||
|
||
alignment_qa = _to_bullet_text(
|
||
[
|
||
f"核心用户与痛点:{summary}",
|
||
"上线时间与硬约束:由里程碑计划自动回填并持续校验",
|
||
f"明确不做项:{'; '.join(out_of_scope_items[:3])}",
|
||
f"关键依赖:{'; '.join(dependencies[:4])}",
|
||
f"核心风险与缓解:{'; '.join(risks[:3])}",
|
||
]
|
||
)
|
||
|
||
modules = {
|
||
"module_1": {
|
||
"problem_statement": summary,
|
||
"goal_statement": _to_bullet_text(objectives),
|
||
"kpis": _to_bullet_text(success_metrics),
|
||
"ai_validations": validations_m1,
|
||
"escalation_trigger": escalation,
|
||
},
|
||
"module_2": {
|
||
"in_scope": _to_bullet_text(in_scope_items),
|
||
"out_of_scope": _to_bullet_text(out_of_scope_items),
|
||
"alignment_qa": alignment_qa,
|
||
"ai_validations": validations_m2,
|
||
"escalation_trigger": escalation,
|
||
},
|
||
"module_3": {
|
||
"primary_model": primary_model,
|
||
"fallback_model": fallback_model,
|
||
"capability_table": _to_bullet_text(
|
||
[
|
||
"上下文窗口/并发/延迟由模型能力中心实时读取",
|
||
"按 P50/P90 工作负载自动估算 token 与成本",
|
||
"超边界输入自动触发替代模型建议",
|
||
]
|
||
),
|
||
"dependency_map": _to_bullet_text(dependencies),
|
||
"business_view": "以业务术语展示能力上限、成本区间与上线风险。",
|
||
"engineering_view": "以工程参数展示 context window、QPS、成本与错误预算。",
|
||
"ai_validations": validations_m3,
|
||
"escalation_trigger": escalation,
|
||
},
|
||
"module_4": {
|
||
"milestones": _to_bullet_text(
|
||
[
|
||
"需求冻结 -> 技术评审 -> 开发完成 -> QA 验收 -> 发布上线",
|
||
"关键依赖阻塞超过阈值自动重排计划",
|
||
]
|
||
),
|
||
"role_effort_estimates": _to_bullet_text(
|
||
[
|
||
"产品/PM:需求澄清与验收口径",
|
||
"前后端工程:核心功能开发与联调",
|
||
"AI 工程:模型评估、提示词与推理链路优化",
|
||
]
|
||
),
|
||
"capability_owner_assignment": "负责人由能力图谱自动推荐并可人工否决。",
|
||
"buffer_policy": "默认 15% 进度缓冲,关键路径超阈值触发自动预警。",
|
||
"ai_validations": validations_m4,
|
||
"escalation_trigger": escalation,
|
||
},
|
||
"module_5": {
|
||
"risk_register": _to_bullet_text(risks),
|
||
"trigger_rules": _to_bullet_text(
|
||
[
|
||
"进度偏差 > 15%",
|
||
"关键接口错误率连续超过阈值",
|
||
"模型调用成本超预算预警线",
|
||
]
|
||
),
|
||
"execution_rule": _to_bullet_text(
|
||
[
|
||
"触发后优先执行预设 fallback",
|
||
"自动通知责任人并写入审计日志",
|
||
"连续失败时升级到人工决策",
|
||
]
|
||
),
|
||
"ai_validations": validations_m5,
|
||
"escalation_trigger": escalation,
|
||
},
|
||
"module_6": {
|
||
"attachment_metadata": _to_bullet_text(
|
||
[
|
||
"原始信号记录",
|
||
"需求讨论记录",
|
||
"设计与评审文档",
|
||
"发布与复盘材料",
|
||
]
|
||
),
|
||
"attachment_summary": "AI 自动提炼附件决策结论并关联到对应模块字段。",
|
||
"search_tags": _to_bullet_text(["需求宪章", "AI First", "SSTC", "对齐记录"]),
|
||
"ai_validations": validations_m6,
|
||
"governance_rule": "附件仅作证据引用,核心事实字段以模块1-5为准。",
|
||
},
|
||
}
|
||
|
||
return {
|
||
"schema_version": "charter_ai_first_v1",
|
||
"auto_generated_by_ai": True,
|
||
"metadata": {
|
||
"status": "draft",
|
||
"confidence_score": 0.82 if seed else 0.72,
|
||
"last_validated_at": now_iso,
|
||
"evidence_refs": source_refs,
|
||
"escalation_reason": None,
|
||
},
|
||
"modules": modules,
|
||
"signal_ids": signal_ids,
|
||
"summary": summary,
|
||
"background": background,
|
||
"objectives": objectives,
|
||
"scope": scope,
|
||
"success_metrics": success_metrics,
|
||
"core_metrics": success_metrics,
|
||
"rationale": summary,
|
||
"decision": _to_bullet_text(objectives),
|
||
"in_scope": in_scope_items,
|
||
"out_of_scope": out_of_scope_items,
|
||
"risks": risks,
|
||
"raw_source_text": raw_text.strip() or None,
|
||
}
|
||
|