242 lines
9.5 KiB
Python
242 lines
9.5 KiB
Python
"""Generate defense deck from docs/答辩/答辩知识点清单.md structure."""
|
||||
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
from pathlib import Path
|
|||
|
|
|
|||
|
|
from pptx import Presentation
|
|||
|
|
from pptx.dml.color import RGBColor
|
|||
|
|
from pptx.enum.text import MSO_ANCHOR, PP_ALIGN
|
|||
|
|
from pptx.util import Inches, Pt
|
|||
|
|
|
|||
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|||
|
|
OUT = ROOT / "docs" / "答辩" / "JinRong-答辩.pptx"
|
|||
|
|
|
|||
|
|
INK = RGBColor(0x13, 0x2B, 0x3A)
|
|||
|
|
TEXT = RGBColor(0x17, 0x21, 0x2B)
|
|||
|
|
MUTED = RGBColor(0x71, 0x80, 0x8A)
|
|||
|
|
GOLD = RGBColor(0xC9, 0xA6, 0x6B)
|
|||
|
|
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
|
|||
|
|
BG_LIGHT = RGBColor(0xF6, 0xF5, 0xF1)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def _set_slide_bg(slide, rgb: RGBColor) -> None:
|
|||
|
|
fill = slide.background.fill
|
|||
|
|
fill.solid()
|
|||
|
|
fill.fore_color.rgb = rgb
|
|||
|
|
|
|||
|
|
|
|||
|
|
def _add_title_slide(prs: Presentation, title: str, subtitle: str, notes: str) -> None:
|
|||
|
|
slide = prs.slides.add_slide(prs.slide_layouts[6])
|
|||
|
|
_set_slide_bg(slide, INK)
|
|||
|
|
box = slide.shapes.add_textbox(Inches(0.7), Inches(2.0), Inches(11.5), Inches(1.2))
|
|||
|
|
tf = box.text_frame
|
|||
|
|
tf.text = title
|
|||
|
|
p = tf.paragraphs[0]
|
|||
|
|
p.font.size = Pt(40)
|
|||
|
|
p.font.bold = True
|
|||
|
|
p.font.color.rgb = WHITE
|
|||
|
|
sub = slide.shapes.add_textbox(Inches(0.7), Inches(3.3), Inches(11.5), Inches(1.0))
|
|||
|
|
stf = sub.text_frame
|
|||
|
|
stf.text = subtitle
|
|||
|
|
sp = stf.paragraphs[0]
|
|||
|
|
sp.font.size = Pt(20)
|
|||
|
|
sp.font.color.rgb = GOLD
|
|||
|
|
slide.notes_slide.notes_text_frame.text = notes
|
|||
|
|
|
|||
|
|
|
|||
|
|
def _add_section_slide(prs: Presentation, title: str, bullets: list[str], notes: str) -> None:
|
|||
|
|
slide = prs.slides.add_slide(prs.slide_layouts[6])
|
|||
|
|
_set_slide_bg(slide, BG_LIGHT)
|
|||
|
|
bar = slide.shapes.add_shape(1, Inches(0), Inches(0), Inches(13.33), Inches(0.12))
|
|||
|
|
bar.fill.solid()
|
|||
|
|
bar.fill.fore_color.rgb = GOLD
|
|||
|
|
bar.line.fill.background()
|
|||
|
|
|
|||
|
|
tbox = slide.shapes.add_textbox(Inches(0.7), Inches(0.45), Inches(12), Inches(0.8))
|
|||
|
|
ttf = tbox.text_frame
|
|||
|
|
ttf.text = title
|
|||
|
|
tp = ttf.paragraphs[0]
|
|||
|
|
tp.font.size = Pt(32)
|
|||
|
|
tp.font.bold = True
|
|||
|
|
tp.font.color.rgb = INK
|
|||
|
|
|
|||
|
|
body = slide.shapes.add_textbox(Inches(0.85), Inches(1.35), Inches(11.8), Inches(5.5))
|
|||
|
|
btf = body.text_frame
|
|||
|
|
btf.word_wrap = True
|
|||
|
|
btf.vertical_anchor = MSO_ANCHOR.TOP
|
|||
|
|
for i, line in enumerate(bullets):
|
|||
|
|
p = btf.paragraphs[0] if i == 0 else btf.add_paragraph()
|
|||
|
|
p.text = line
|
|||
|
|
p.level = 0
|
|||
|
|
p.font.size = Pt(18 if len(line) < 80 else 16)
|
|||
|
|
p.font.color.rgb = TEXT
|
|||
|
|
p.space_after = Pt(10)
|
|||
|
|
slide.notes_slide.notes_text_frame.text = notes
|
|||
|
|
|
|||
|
|
|
|||
|
|
def main() -> None:
|
|||
|
|
prs = Presentation()
|
|||
|
|
prs.slide_width = Inches(13.333)
|
|||
|
|
prs.slide_height = Inches(7.5)
|
|||
|
|
|
|||
|
|
slides: list[tuple[str, list[str], str, bool]] = [
|
|||
|
|
(
|
|||
|
|
"金融四 Agent 智能代销平台",
|
|||
|
|
[],
|
|||
|
|
"",
|
|||
|
|
True,
|
|||
|
|
),
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
# Title handled separately
|
|||
|
|
_add_title_slide(
|
|||
|
|
prs,
|
|||
|
|
"金融四 Agent 智能代销平台",
|
|||
|
|
"答辩演示 · XX 科技综合财富 · merger 基线",
|
|||
|
|
"开场:代销四角色 + L0 与合规底座;Core 为模拟库;四 Agent 不互调 LLM。",
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
deck: list[tuple[str, list[str], str]] = [
|
|||
|
|
(
|
|||
|
|
"我们要做什么(网站三句话)",
|
|||
|
|
[
|
|||
|
|
"用于:持牌财富代销场景下的 AI 工作台(Web + FastAPI),不是营销落地页",
|
|||
|
|
"业务:XX 科技综合财富平台 · 前端视觉「静奢智能」",
|
|||
|
|
"用户:客户看资产与对话 · 分析员问数 · 风控处置 · 理财师看归属(顾问 Agent 未完整接入)",
|
|||
|
|
],
|
|||
|
|
"对应用户模板:用途 / 业务名 / 用户能做什么。",
|
|||
|
|
),
|
|||
|
|
(
|
|||
|
|
"总架构(30 秒)",
|
|||
|
|
[
|
|||
|
|
"四角色共用 L0 事实 + 合规底座;跨线靠画像表、预警表、代销 REST",
|
|||
|
|
"分层:浏览器 → FastAPI → Service → Tool/Repository → MySQL 双库 / Redis / Milvus / Core",
|
|||
|
|
"对话:通用 Chat/SSE · 客服 14 节点 · 问数独立(interpret 按需解读)",
|
|||
|
|
"铁律:L0 不可覆盖 · 仅 R-02 可阻断交易 · 不自动冻户 · 审计只 INSERT",
|
|||
|
|
],
|
|||
|
|
"MEMORY §0 + 答辩清单 §一。",
|
|||
|
|
),
|
|||
|
|
(
|
|||
|
|
"数据怎么流",
|
|||
|
|
[
|
|||
|
|
"L0 Core 模拟:Agent 只读;仅模拟交易网关 INSERT core_trade",
|
|||
|
|
"jinrong_agent 与 jinrong_core 物理隔离",
|
|||
|
|
"Redis 6380:会话窗口、限流、问数缓存世代;MySQL 永久落盘",
|
|||
|
|
"Milvus:产品规则 RAG(Ollama bge-m3 1024 维,不出内网)",
|
|||
|
|
],
|
|||
|
|
"§二 数据分层表口述。",
|
|||
|
|
),
|
|||
|
|
(
|
|||
|
|
"共用底座 Wave 0",
|
|||
|
|
[
|
|||
|
|
"JWT + RBAC + X-Agent-Type 准入 · dev token 与 gateway 双栈(AL-09)",
|
|||
|
|
"输入防护:限流 / 注入 / 超长 · 被拒 fail-fast 不建会话",
|
|||
|
|
"审计:trace_id 贯通 http_access + audit_log + agent_tool_call",
|
|||
|
|
"Tool:customer_id 会话注入,LLM 不能指定 · 归属校验 + 落库",
|
|||
|
|
],
|
|||
|
|
"F-01~F-04 演示工程化。",
|
|||
|
|
),
|
|||
|
|
(
|
|||
|
|
"客服 Agent(主 Demo 之一)",
|
|||
|
|
[
|
|||
|
|
"14 节点 LangGraph:Core Tool + fin_* RAG + 1B sanitize 出口",
|
|||
|
|
"C-04/C-05:阈值提醒、净值查询 · C-11 适当性 vs 营销 reject",
|
|||
|
|
"Demo:CUST-9527 持仓 + 阈值 · 游客 RAG",
|
|||
|
|
"SSE:Tool 同步完成后再推文本,避免半句不一致",
|
|||
|
|
],
|
|||
|
|
"步骤 1 客户助手 + 持仓页。",
|
|||
|
|
),
|
|||
|
|
(
|
|||
|
|
"数据分析 Agent(主 Demo 之二)",
|
|||
|
|
[
|
|||
|
|
"问数与 Chat 分离:默认 interpret=false 出表 · 按钮触发 /interpret",
|
|||
|
|
"五层 sql_guard + 模板命中 Tag + 结果缓存世代(D-06)",
|
|||
|
|
"D-10:解读数字与表逐字比对,失败降级只出表",
|
|||
|
|
"Demo:分析员问数 → 模板/缓存 Tag → 解读按钮",
|
|||
|
|
],
|
|||
|
|
"DEMO-SOP-问数.md。",
|
|||
|
|
),
|
|||
|
|
(
|
|||
|
|
"风控 Agent(主 Demo 之三)",
|
|||
|
|
[
|
|||
|
|
"事件线:模拟交易 → R-02 适当性 → 规则 R-01~R-05 → 聚合预警 → 人工处置",
|
|||
|
|
"对话线:6 只只读 Tool,无处置 Tool(状态不变)",
|
|||
|
|
"前端:预警台账 / 适当性 / AML / 模拟交易 + 风控 Chat",
|
|||
|
|
"Demo:prepare_all.ps1 · A-1/A-3 · 台账筛选处置",
|
|||
|
|
],
|
|||
|
|
"演示SOP-风控模块.md。",
|
|||
|
|
),
|
|||
|
|
(
|
|||
|
|
"代销平台 API + 前端 web/",
|
|||
|
|
[
|
|||
|
|
"v0.1 canonical REST:客户/产品/顾问/合规 · 重复能力以平台 API 为准",
|
|||
|
|
"React 19 + Vite + Ant Design · HashRouter · /api 代理 8000",
|
|||
|
|
"四角色 Dashboard + 产品行情(nav/history 图表)",
|
|||
|
|
"DevReadyBanner:前后端版本不一致先告警",
|
|||
|
|
],
|
|||
|
|
"FRONTEND-HANDOFF + 登录四 Demo 账号。",
|
|||
|
|
),
|
|||
|
|
(
|
|||
|
|
"诚实边界(答辩加分)",
|
|||
|
|
[
|
|||
|
|
"理财师 Agent:无 advisor_service 级编排 · A-01~A-05 未做 · 勿作主 Demo",
|
|||
|
|
"问数:D-09 多轮 / D-12 钻取仍 open",
|
|||
|
|
"看板:无钻取 · 进页全量拉平台 API",
|
|||
|
|
"测试:827 pytest · 22 Vitest(口播基线以当日 pytest 为准)",
|
|||
|
|
],
|
|||
|
|
"§4.2 §4.3 §4.6 诚实缺口。",
|
|||
|
|
),
|
|||
|
|
(
|
|||
|
|
"技术选型(为什么这样)",
|
|||
|
|
[
|
|||
|
|
"LangGraph 显式图 · MySQL 双库隔离 · Milvus Lite 本机 RAG",
|
|||
|
|
"DeepSeek 生成 · 无 Key 明确降级 · Redis RESP2 @6380",
|
|||
|
|
"FastAPI 一体栈 · React+AntD 四角色 Demo 快",
|
|||
|
|
"不用 Streamlit · 不用 Agent 互调 LLM",
|
|||
|
|
],
|
|||
|
|
"§五 选型表。",
|
|||
|
|
),
|
|||
|
|
(
|
|||
|
|
"工程化亮点",
|
|||
|
|
[
|
|||
|
|
"契约优先:代销 API v0.1 · AL-09 合并接缝",
|
|||
|
|
"双护栏:输入防护 + 客服 sanitize + 问数 guardrail",
|
|||
|
|
"RAG 溯源 source_refs · 问数 battery 本地跑分不入库",
|
|||
|
|
"docs/memory + docs/course 交互课 + 本套 SOP",
|
|||
|
|
],
|
|||
|
|
"§六 加分项。",
|
|||
|
|
),
|
|||
|
|
(
|
|||
|
|
"Demo 动线(12~15 分钟标准)",
|
|||
|
|
[
|
|||
|
|
"0 开场 30 秒铁律 + 架构句",
|
|||
|
|
"1 客户:登录 → 持仓/阈值 → 客户助手",
|
|||
|
|
"2 分析员:问数 → Tag → 解读",
|
|||
|
|
"3 风控:模拟交易 → 台账 → 处置",
|
|||
|
|
"4 可选:行情页 · /api/ready 探针",
|
|||
|
|
],
|
|||
|
|
"DEMO-SOP-答辩全流程.md 路线 B。",
|
|||
|
|
),
|
|||
|
|
(
|
|||
|
|
"谢谢 · Q&A",
|
|||
|
|
[
|
|||
|
|
"配套文档:docs/答辩/答辩知识点清单.md",
|
|||
|
|
"Demo:docs/答辩/DEMO-SOP-答辩全流程.md",
|
|||
|
|
"交互课:docs/course/jinrong-overview/index.html",
|
|||
|
|
"仓库:JinRong · 分支 merger",
|
|||
|
|
],
|
|||
|
|
"预留 Q&A:适当性、审计、问数 guard、顾问线规划。",
|
|||
|
|
),
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
for title, bullets, notes in deck:
|
|||
|
|
_add_section_slide(prs, title, bullets, notes)
|
|||
|
|
|
|||
|
|
OUT.parent.mkdir(parents=True, exist_ok=True)
|
|||
|
|
prs.save(str(OUT))
|
|||
|
|
print(f"Wrote {OUT} ({len(prs.slides)} slides)")
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
main()
|