|
|
@@ -0,0 +1,1154 @@
|
|
|
+<!DOCTYPE html>
|
|
|
+<html lang="zh-CN">
|
|
|
+<head>
|
|
|
+<meta charset="UTF-8">
|
|
|
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
+<title>auto_put_ad_mini · 新建子系统架构</title>
|
|
|
+<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
|
+<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
|
+<link href="https://fonts.googleapis.com/css2?family=Newsreader:opsz,wght,SOFT@6..72,300..800,0..100&family=IBM+Plex+Sans:wght@300;400;500;600&family=JetBrains+Mono:wght@400;500&family=Noto+Sans+SC:wght@300;400;500&family=Noto+Serif+SC:wght@300;400;500&display=swap" rel="stylesheet">
|
|
|
+<style>
|
|
|
+:root {
|
|
|
+ --paper: #F2EDE3;
|
|
|
+ --paper-warm: #EFE8DA;
|
|
|
+ --paper-line: #D4CDB8;
|
|
|
+ --ink: #0F1F2E;
|
|
|
+ --ink-2: #2D3D52;
|
|
|
+ --ink-3: #4A5870;
|
|
|
+ --ink-mute: #7A8294;
|
|
|
+ --accent: #C75D3F;
|
|
|
+ --accent-soft: #E8C7B5;
|
|
|
+ --moss: #5C7A52;
|
|
|
+ --gold: #B8902F;
|
|
|
+ --serif: "Newsreader", "Noto Serif SC", Georgia, serif;
|
|
|
+ --sans: "IBM Plex Sans", "Noto Sans SC", system-ui, sans-serif;
|
|
|
+ --mono: "JetBrains Mono", monospace;
|
|
|
+}
|
|
|
+
|
|
|
+* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
|
+
|
|
|
+body {
|
|
|
+ background: var(--paper);
|
|
|
+ color: var(--ink);
|
|
|
+ font-family: var(--sans);
|
|
|
+ line-height: 1.55;
|
|
|
+ min-height: 100vh;
|
|
|
+ background-image:
|
|
|
+ repeating-linear-gradient(0deg, transparent 0, transparent 39px, var(--paper-line) 39px, var(--paper-line) 40px),
|
|
|
+ repeating-linear-gradient(90deg, transparent 0, transparent 39px, var(--paper-line) 39px, var(--paper-line) 40px);
|
|
|
+ background-blend-mode: multiply;
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+
|
|
|
+body::before {
|
|
|
+ content: "";
|
|
|
+ position: fixed; inset: 0;
|
|
|
+ pointer-events: none;
|
|
|
+ opacity: 0.5;
|
|
|
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' /%3E%3CfeColorMatrix values='0 0 0 0 0.06 0 0 0 0 0.12 0 0 0 0 0.18 0 0 0 0.04 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
|
|
|
+ mix-blend-mode: multiply;
|
|
|
+ z-index: 1;
|
|
|
+}
|
|
|
+
|
|
|
+main {
|
|
|
+ position: relative; z-index: 2;
|
|
|
+ max-width: 1320px;
|
|
|
+ margin: 0 auto;
|
|
|
+ padding: 56px 48px 64px;
|
|
|
+}
|
|
|
+
|
|
|
+.head {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: baseline;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ padding-bottom: 24px;
|
|
|
+ border-bottom: 1px solid var(--ink);
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 24px;
|
|
|
+}
|
|
|
+
|
|
|
+.eyebrow {
|
|
|
+ font-family: var(--mono);
|
|
|
+ font-size: 11px;
|
|
|
+ letter-spacing: 0.3em;
|
|
|
+ color: var(--accent);
|
|
|
+ margin-bottom: 12px;
|
|
|
+ text-transform: uppercase;
|
|
|
+}
|
|
|
+
|
|
|
+h1 {
|
|
|
+ font-family: var(--serif);
|
|
|
+ font-size: clamp(40px, 5vw, 64px);
|
|
|
+ font-weight: 300;
|
|
|
+ line-height: 0.95;
|
|
|
+ letter-spacing: -0.025em;
|
|
|
+ font-variation-settings: "opsz" 64, "SOFT" 30;
|
|
|
+}
|
|
|
+
|
|
|
+h1 em {
|
|
|
+ font-style: italic;
|
|
|
+ color: var(--accent);
|
|
|
+ font-variation-settings: "opsz" 64, "SOFT" 100;
|
|
|
+}
|
|
|
+
|
|
|
+h2 {
|
|
|
+ font-family: var(--serif);
|
|
|
+ font-size: 28px;
|
|
|
+ font-weight: 400;
|
|
|
+ font-variation-settings: "opsz" 28, "SOFT" 50;
|
|
|
+ margin-top: 48px;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ letter-spacing: -0.01em;
|
|
|
+ color: var(--ink);
|
|
|
+}
|
|
|
+
|
|
|
+h2::before {
|
|
|
+ content: "§";
|
|
|
+ color: var(--accent);
|
|
|
+ font-style: italic;
|
|
|
+ margin-right: 12px;
|
|
|
+ font-variation-settings: "opsz" 28, "SOFT" 100;
|
|
|
+}
|
|
|
+
|
|
|
+h3 {
|
|
|
+ font-family: var(--mono);
|
|
|
+ font-size: 11px;
|
|
|
+ letter-spacing: 0.2em;
|
|
|
+ color: var(--ink-mute);
|
|
|
+ text-transform: uppercase;
|
|
|
+ margin-top: 24px;
|
|
|
+ margin-bottom: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.tagline {
|
|
|
+ font-family: var(--mono);
|
|
|
+ font-size: 11px;
|
|
|
+ letter-spacing: 0.15em;
|
|
|
+ color: var(--ink-mute);
|
|
|
+ text-align: right;
|
|
|
+ line-height: 1.7;
|
|
|
+}
|
|
|
+
|
|
|
+.subtitle {
|
|
|
+ font-family: var(--serif);
|
|
|
+ font-size: 18px;
|
|
|
+ font-style: italic;
|
|
|
+ color: var(--ink-2);
|
|
|
+ font-weight: 300;
|
|
|
+ margin: 16px 0 32px;
|
|
|
+ font-variation-settings: "opsz" 18, "SOFT" 60;
|
|
|
+ max-width: 920px;
|
|
|
+}
|
|
|
+
|
|
|
+.intro {
|
|
|
+ font-size: 14.5px;
|
|
|
+ color: var(--ink-2);
|
|
|
+ max-width: 980px;
|
|
|
+ margin-bottom: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.intro strong {
|
|
|
+ color: var(--ink);
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+
|
|
|
+.intro code {
|
|
|
+ font-family: var(--mono);
|
|
|
+ font-size: 12.5px;
|
|
|
+ background: var(--paper-warm);
|
|
|
+ padding: 1px 5px;
|
|
|
+ border: 1px solid var(--paper-line);
|
|
|
+ border-radius: 2px;
|
|
|
+ color: var(--accent);
|
|
|
+}
|
|
|
+
|
|
|
+.diagram-wrap {
|
|
|
+ background: var(--paper-warm);
|
|
|
+ border: 1px solid var(--ink);
|
|
|
+ padding: 36px 24px 24px;
|
|
|
+ margin: 24px 0 16px;
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+
|
|
|
+.diagram-wrap[data-tag]::before {
|
|
|
+ content: attr(data-tag);
|
|
|
+ position: absolute;
|
|
|
+ top: -12px;
|
|
|
+ left: 24px;
|
|
|
+ background: var(--paper);
|
|
|
+ padding: 0 12px;
|
|
|
+ font-family: var(--mono);
|
|
|
+ font-size: 11px;
|
|
|
+ letter-spacing: 0.2em;
|
|
|
+ text-transform: uppercase;
|
|
|
+ color: var(--ink-3);
|
|
|
+ border: 1px solid var(--ink);
|
|
|
+ height: 24px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+svg.arch {
|
|
|
+ display: block;
|
|
|
+ width: 100%;
|
|
|
+ height: auto;
|
|
|
+}
|
|
|
+
|
|
|
+svg.arch text {
|
|
|
+ font-family: var(--sans);
|
|
|
+ fill: var(--ink-2);
|
|
|
+ font-size: 13px;
|
|
|
+}
|
|
|
+
|
|
|
+svg.arch .title {
|
|
|
+ font-family: var(--serif);
|
|
|
+ font-weight: 500;
|
|
|
+ fill: var(--ink);
|
|
|
+ font-size: 18px;
|
|
|
+ font-variation-settings: "opsz" 18;
|
|
|
+}
|
|
|
+
|
|
|
+svg.arch .title-en {
|
|
|
+ font-family: var(--mono);
|
|
|
+ font-size: 10px;
|
|
|
+ fill: var(--ink-mute);
|
|
|
+ letter-spacing: 0.18em;
|
|
|
+ text-transform: uppercase;
|
|
|
+}
|
|
|
+
|
|
|
+svg.arch .agent-label {
|
|
|
+ font-family: var(--serif);
|
|
|
+ font-style: italic;
|
|
|
+ font-size: 14px;
|
|
|
+ fill: var(--ink-2);
|
|
|
+ font-variation-settings: "opsz" 14, "SOFT" 80;
|
|
|
+}
|
|
|
+
|
|
|
+svg.arch .body { font-size: 12px; fill: var(--ink-3); }
|
|
|
+svg.arch .body-strong { font-size: 12.5px; fill: var(--ink-2); font-weight: 500; }
|
|
|
+svg.arch .small { font-size: 10.5px; fill: var(--ink-mute); }
|
|
|
+svg.arch .mono { font-family: var(--mono); font-size: 11.5px; fill: var(--ink-2); }
|
|
|
+svg.arch .mono-mute { font-family: var(--mono); font-size: 10.5px; fill: var(--ink-mute); }
|
|
|
+
|
|
|
+svg.arch .layer-bg {
|
|
|
+ fill: var(--paper);
|
|
|
+ stroke: var(--ink);
|
|
|
+ stroke-width: 1;
|
|
|
+}
|
|
|
+svg.arch .layer-shared {
|
|
|
+ fill: #F8F4E8;
|
|
|
+ stroke: var(--ink);
|
|
|
+ stroke-width: 1.5;
|
|
|
+}
|
|
|
+svg.arch .layer-existing {
|
|
|
+ fill: var(--paper);
|
|
|
+ stroke: var(--ink-3);
|
|
|
+ stroke-width: 1.2;
|
|
|
+}
|
|
|
+svg.arch .layer-new {
|
|
|
+ fill: #FCEFE7;
|
|
|
+ stroke: var(--accent);
|
|
|
+ stroke-width: 1.5;
|
|
|
+}
|
|
|
+svg.arch .layer-coupling {
|
|
|
+ fill: var(--paper);
|
|
|
+ stroke: var(--gold);
|
|
|
+ stroke-width: 1.5;
|
|
|
+ stroke-dasharray: 5 3;
|
|
|
+}
|
|
|
+svg.arch .layer-stub {
|
|
|
+ fill: var(--paper-warm);
|
|
|
+ stroke: var(--ink-mute);
|
|
|
+ stroke-width: 1;
|
|
|
+ stroke-dasharray: 3 3;
|
|
|
+}
|
|
|
+svg.arch .pill-shared { fill: var(--moss); stroke: none; }
|
|
|
+svg.arch .pill-existing { fill: var(--ink-3); stroke: none; }
|
|
|
+svg.arch .pill-new { fill: var(--accent); stroke: none; }
|
|
|
+svg.arch .pill-coupling { fill: var(--gold); stroke: none; }
|
|
|
+svg.arch .pill-stub { fill: var(--ink-mute); stroke: none; }
|
|
|
+svg.arch .pill-text { fill: var(--paper); font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.1em; text-transform: uppercase; }
|
|
|
+
|
|
|
+svg.arch .arrow-data {
|
|
|
+ stroke: var(--moss);
|
|
|
+ stroke-width: 1.5;
|
|
|
+ fill: none;
|
|
|
+}
|
|
|
+svg.arch .arrow-act {
|
|
|
+ stroke: var(--accent);
|
|
|
+ stroke-width: 1.5;
|
|
|
+ fill: none;
|
|
|
+}
|
|
|
+svg.arch .arrow-internal {
|
|
|
+ stroke: var(--ink);
|
|
|
+ stroke-width: 1;
|
|
|
+ fill: none;
|
|
|
+ stroke-dasharray: 3 3;
|
|
|
+}
|
|
|
+svg.arch .arrow-coupling {
|
|
|
+ stroke: var(--gold);
|
|
|
+ stroke-width: 1.5;
|
|
|
+ fill: none;
|
|
|
+ stroke-dasharray: 6 3;
|
|
|
+}
|
|
|
+svg.arch .arrow-label {
|
|
|
+ font-family: var(--mono);
|
|
|
+ font-size: 10px;
|
|
|
+ fill: var(--ink-mute);
|
|
|
+ letter-spacing: 0.05em;
|
|
|
+}
|
|
|
+
|
|
|
+.legend {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
|
|
+ gap: 10px 32px;
|
|
|
+ margin-top: 20px;
|
|
|
+ padding-top: 16px;
|
|
|
+ border-top: 1px dashed var(--paper-line);
|
|
|
+ font-size: 12.5px;
|
|
|
+}
|
|
|
+
|
|
|
+.legend-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 12px;
|
|
|
+ color: var(--ink-2);
|
|
|
+}
|
|
|
+
|
|
|
+.legend-swatch {
|
|
|
+ width: 28px;
|
|
|
+ height: 12px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ border: 1px solid var(--ink);
|
|
|
+}
|
|
|
+.legend-swatch.shared { background: #F8F4E8; border-color: var(--ink); border-width: 1.5px; }
|
|
|
+.legend-swatch.existing { background: var(--paper); border-color: var(--ink-3); border-width: 1.2px; }
|
|
|
+.legend-swatch.new { background: #FCEFE7; border-color: var(--accent); border-width: 1.5px; }
|
|
|
+.legend-swatch.coupling { background: var(--paper); border-color: var(--gold); border-width: 1.5px; border-style: dashed; }
|
|
|
+.legend-swatch.stub { background: var(--paper-warm); border-color: var(--ink-mute); border-width: 1px; border-style: dashed; }
|
|
|
+
|
|
|
+.legend-line {
|
|
|
+ width: 32px;
|
|
|
+ height: 0; border-top-width: 2px; border-top-style: solid;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+.legend-line.data { border-color: var(--moss); }
|
|
|
+.legend-line.act { border-color: var(--accent); }
|
|
|
+.legend-line.internal { border-color: var(--ink); border-top-style: dashed; }
|
|
|
+.legend-line.coupling { border-color: var(--gold); border-top-style: dashed; }
|
|
|
+
|
|
|
+.table-wrap {
|
|
|
+ background: var(--paper-warm);
|
|
|
+ border: 1px solid var(--ink);
|
|
|
+ padding: 28px 24px 24px;
|
|
|
+ margin: 16px 0;
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+.table-wrap[data-tag]::before {
|
|
|
+ content: attr(data-tag);
|
|
|
+ position: absolute;
|
|
|
+ top: -12px;
|
|
|
+ left: 24px;
|
|
|
+ background: var(--paper);
|
|
|
+ padding: 0 12px;
|
|
|
+ font-family: var(--mono);
|
|
|
+ font-size: 11px;
|
|
|
+ letter-spacing: 0.2em;
|
|
|
+ text-transform: uppercase;
|
|
|
+ color: var(--ink-3);
|
|
|
+ border: 1px solid var(--ink);
|
|
|
+ height: 24px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+table.matrix {
|
|
|
+ width: 100%;
|
|
|
+ border-collapse: collapse;
|
|
|
+ font-size: 13px;
|
|
|
+}
|
|
|
+table.matrix th, table.matrix td {
|
|
|
+ text-align: left;
|
|
|
+ padding: 9px 12px;
|
|
|
+ border-bottom: 1px solid var(--paper-line);
|
|
|
+ vertical-align: top;
|
|
|
+}
|
|
|
+table.matrix th {
|
|
|
+ font-family: var(--serif);
|
|
|
+ font-weight: 500;
|
|
|
+ font-style: italic;
|
|
|
+ color: var(--ink);
|
|
|
+ font-size: 14px;
|
|
|
+ font-variation-settings: "opsz" 14, "SOFT" 60;
|
|
|
+ border-bottom: 1.5px solid var(--ink);
|
|
|
+}
|
|
|
+table.matrix td.mono {
|
|
|
+ font-family: var(--mono);
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+table.matrix td.shared { color: var(--moss); font-weight: 500; }
|
|
|
+table.matrix td.existing { color: var(--ink-3); }
|
|
|
+table.matrix td.new { color: var(--accent); font-weight: 500; }
|
|
|
+table.matrix td.muted { color: var(--ink-mute); }
|
|
|
+table.matrix tr:last-child td { border-bottom: none; }
|
|
|
+
|
|
|
+.gantt-bar {
|
|
|
+ position: relative;
|
|
|
+ height: 22px;
|
|
|
+ background: var(--paper);
|
|
|
+ border: 1px solid var(--ink-mute);
|
|
|
+ border-radius: 2px;
|
|
|
+ margin-bottom: 2px;
|
|
|
+}
|
|
|
+.gantt-fill {
|
|
|
+ position: absolute;
|
|
|
+ top: 0; bottom: 0;
|
|
|
+ background: var(--accent);
|
|
|
+ opacity: 0.85;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 0 8px;
|
|
|
+ font-family: var(--mono);
|
|
|
+ font-size: 10px;
|
|
|
+ color: var(--paper);
|
|
|
+ letter-spacing: 0.08em;
|
|
|
+ text-transform: uppercase;
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+.gantt-fill.shared-bar { background: var(--moss); }
|
|
|
+.gantt-fill.cross-bar { background: var(--gold); }
|
|
|
+
|
|
|
+footer {
|
|
|
+ margin-top: 48px;
|
|
|
+ padding-top: 16px;
|
|
|
+ border-top: 1px dashed var(--paper-line);
|
|
|
+ font-family: var(--mono);
|
|
|
+ font-size: 11px;
|
|
|
+ color: var(--ink-mute);
|
|
|
+ letter-spacing: 0.1em;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 12px;
|
|
|
+}
|
|
|
+footer .stamp {
|
|
|
+ font-family: var(--serif);
|
|
|
+ font-style: italic;
|
|
|
+ letter-spacing: 0.02em;
|
|
|
+}
|
|
|
+
|
|
|
+@keyframes drawIn {
|
|
|
+ from { opacity: 0; transform: translateY(8px); }
|
|
|
+ to { opacity: 1; transform: translateY(0); }
|
|
|
+}
|
|
|
+.head, .subtitle, .intro, .diagram-wrap, .table-wrap, footer {
|
|
|
+ animation: drawIn 0.55s ease-out backwards;
|
|
|
+}
|
|
|
+.head { animation-delay: 0.05s; }
|
|
|
+.subtitle { animation-delay: 0.12s; }
|
|
|
+
|
|
|
+@media (max-width: 700px) {
|
|
|
+ main { padding: 32px 20px; }
|
|
|
+ .head { flex-direction: column; }
|
|
|
+ .tagline { text-align: left; }
|
|
|
+}
|
|
|
+</style>
|
|
|
+</head>
|
|
|
+<body>
|
|
|
+
|
|
|
+<main>
|
|
|
+
|
|
|
+<header class="head">
|
|
|
+ <div>
|
|
|
+ <div class="eyebrow">解耦架构 · 调控 + 新建 双子系统</div>
|
|
|
+ <h1>新建广告 <em>·</em> 新建创意 · 架构设计</h1>
|
|
|
+ </div>
|
|
|
+ <div class="tagline">
|
|
|
+ 项目代号 auto_put_ad_mini<br>
|
|
|
+ plan v2 · 2026-06-05
|
|
|
+ </div>
|
|
|
+</header>
|
|
|
+
|
|
|
+<p class="subtitle">
|
|
|
+现有"调控子系统"做减法 — <strong style="color:var(--ink);font-style:normal">关停 / 调价 / 扩量</strong>;新增"新建子系统"做加法 — <strong style="color:var(--accent);font-style:normal">建广告 / 挂创意</strong>。两者共享数据 + 平台 API + 基础知识,但各自的<strong style="color:var(--ink);font-style:normal">脑子 (skill + prompt)</strong>独立,避免互相污染。
|
|
|
+</p>
|
|
|
+
|
|
|
+<p class="intro">
|
|
|
+本文档展示 <strong>6 张图</strong>:① 三层架构(共享 infra · 双子系统 · 关联点) · ② 数据契约流向 · ③ 关联点放大图 · ④ 模块 A/B 内部流水线 · ⑤ 决策框架 L1/L2/L3 · ⑥ 实施甘特图。配色:<code>cream</code> 为共享 infra,<code>navy</code> 既有调控,<code>terracotta</code> 新建子系统,<code>gold</code> 跨系统关联点。
|
|
|
+</p>
|
|
|
+
|
|
|
+<div style="background:#FCEFE7;border-left:4px solid var(--accent);padding:14px 20px;margin:16px 0 8px;font-size:13.5px;color:var(--ink-2)">
|
|
|
+<strong style="color:var(--accent);font-family:var(--serif);font-style:italic;font-size:15px">关键约束 · 一账一人群包(2026-06-05 锁定)</strong><br>
|
|
|
+一个账户固定一个 <code>custom_audience</code>(人群包),即使有多个广告也不变。这意味着 <strong>audience 不参与广告差异化</strong>,跨 tier 测试通过<strong>跨账户</strong>实现。单账户内唯一性差异化维度退化为 <code>site_set × age × geo</code> 三维,可建 <code>4×4×4 = 64</code> 种 unique 组合,起步 5-15 条远未饱和。账户与人群包映射由 <code>ACCOUNT_AUDIENCE_PACK_MAPPING[account_id]</code> 在配置中预设,LLM 不参与选择。
|
|
|
+</div>
|
|
|
+
|
|
|
+<!-- ════════════════════════════════════════════════════ -->
|
|
|
+<!-- FIGURE 1 · 三层架构总图 -->
|
|
|
+<!-- ════════════════════════════════════════════════════ -->
|
|
|
+<h2>图一 · 三层架构总览</h2>
|
|
|
+
|
|
|
+<div class="diagram-wrap" data-tag="FIG · 01 · LAYERED ARCHITECTURE">
|
|
|
+<svg class="arch" viewBox="0 0 1260 760" xmlns="http://www.w3.org/2000/svg">
|
|
|
+ <defs>
|
|
|
+ <marker id="arr-data" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#5C7A52"/></marker>
|
|
|
+ <marker id="arr-act" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#C75D3F"/></marker>
|
|
|
+ <marker id="arr-int" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="5" markerHeight="5" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#0F1F2E"/></marker>
|
|
|
+ <marker id="arr-cpl" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#B8902F"/></marker>
|
|
|
+ </defs>
|
|
|
+
|
|
|
+ <!-- =========== Layer 1 · 共享基础设施 =========== -->
|
|
|
+ <rect x="40" y="40" width="1180" height="170" class="layer-shared" rx="3"/>
|
|
|
+ <rect x="56" y="32" width="180" height="20" fill="#5C7A52" rx="2"/>
|
|
|
+ <text x="146" y="46" class="pill-text" text-anchor="middle">Layer 1 · Shared Infra</text>
|
|
|
+
|
|
|
+ <text x="630" y="78" class="title" text-anchor="middle">共享基础设施</text>
|
|
|
+ <text x="630" y="98" class="agent-label" text-anchor="middle">两个子系统都依赖的"地基"— 数据 · 能力 · 知识 · 配置</text>
|
|
|
+
|
|
|
+ <!-- 4 columns -->
|
|
|
+ <rect x="76" y="118" width="270" height="78" class="layer-bg" rx="2"/>
|
|
|
+ <text x="90" y="138" class="mono-mute">DATA 数据层</text>
|
|
|
+ <text x="90" y="156" class="body-strong">data_query · roi_calculator</text>
|
|
|
+ <text x="90" y="172" class="body">creative_metrics · portfolio_metrics</text>
|
|
|
+ <text x="90" y="186" class="small">→ metrics_{date}.csv · portfolio_summary.json</text>
|
|
|
+
|
|
|
+ <rect x="358" y="118" width="270" height="78" class="layer-bg" rx="2"/>
|
|
|
+ <text x="372" y="138" class="mono-mute">CAPABILITY 能力层</text>
|
|
|
+ <text x="372" y="156" class="body-strong">ad_api (腾讯 v3.0)</text>
|
|
|
+ <text x="372" y="172" class="body">im_approval (飞书基类) · execution_engine</text>
|
|
|
+ <text x="372" y="186" class="small">QPS · retry · audit log 公共部分</text>
|
|
|
+
|
|
|
+ <rect x="640" y="118" width="270" height="78" class="layer-bg" rx="2"/>
|
|
|
+ <text x="654" y="138" class="mono-mute">KNOWLEDGE 知识层</text>
|
|
|
+ <text x="654" y="156" class="body-strong">skills/ad_domain.md</text>
|
|
|
+ <text x="654" y="172" class="body">skills/platform_rules.md</text>
|
|
|
+ <text x="654" y="186" class="small">两个 Agent 系统 prompt 都注入</text>
|
|
|
+
|
|
|
+ <rect x="922" y="118" width="270" height="78" class="layer-bg" rx="2"/>
|
|
|
+ <text x="936" y="138" class="mono-mute">CONFIG 配置层</text>
|
|
|
+ <text x="936" y="156" class="body-strong">config.py [SHARED] 段</text>
|
|
|
+ <text x="936" y="172" class="body">账户白名单 · QPS · 时区 · 数据窗口</text>
|
|
|
+ <text x="936" y="186" class="small">基础阈值 · 冷启动天数 · 最低统计门槛</text>
|
|
|
+
|
|
|
+ <!-- 共享层 → 两个子系统的分流箭头 -->
|
|
|
+ <path class="arrow-data" d="M 350 210 L 350 250" marker-end="url(#arr-data)"/>
|
|
|
+ <path class="arrow-data" d="M 910 210 L 910 250" marker-end="url(#arr-data)"/>
|
|
|
+
|
|
|
+ <!-- =========== Layer 2a · 调控子系统(现有)=========== -->
|
|
|
+ <rect x="40" y="260" width="580" height="350" class="layer-existing" rx="3"/>
|
|
|
+ <rect x="56" y="252" width="220" height="20" fill="#4A5870" rx="2"/>
|
|
|
+ <text x="166" y="266" class="pill-text" text-anchor="middle">Layer 2a · 调控子系统(现有)</text>
|
|
|
+
|
|
|
+ <text x="330" y="296" class="title" text-anchor="middle">调控子系统</text>
|
|
|
+ <text x="330" y="316" class="agent-label" text-anchor="middle" style="fill:var(--ink-3)">"做减法 + 微调"— 完全保留,本期几乎不动</text>
|
|
|
+
|
|
|
+ <rect x="60" y="340" width="540" height="36" class="layer-bg" rx="2"/>
|
|
|
+ <text x="74" y="362" class="mono-mute">ENTRYPOINT</text>
|
|
|
+ <text x="220" y="362" class="body-strong" style="font-family:var(--mono);font-size:13px">execute_once.py</text>
|
|
|
+ <text x="430" y="362" class="small">每日 02:00 UTC (K8s cronjob)</text>
|
|
|
+
|
|
|
+ <rect x="60" y="386" width="540" height="60" class="layer-bg" rx="2"/>
|
|
|
+ <text x="74" y="406" class="mono-mute">BRAIN · CODE</text>
|
|
|
+ <text x="74" y="424" class="body">tools/ad_decision.py · execution_engine 现有 dispatch</text>
|
|
|
+ <text x="74" y="438" class="small">VALID_ACTIONS = pause / bid_down / bid_up / scale_up / observe / hold / creative_adjust</text>
|
|
|
+
|
|
|
+ <rect x="60" y="456" width="540" height="60" class="layer-bg" rx="2"/>
|
|
|
+ <text x="74" y="476" class="mono-mute">BRAIN · KNOWLEDGE</text>
|
|
|
+ <text x="74" y="494" class="body-strong">prompts/system.prompt</text>
|
|
|
+ <text x="74" y="508" class="body">skills/decision_strategy.md · posterior_wisdom.md</text>
|
|
|
+
|
|
|
+ <rect x="60" y="526" width="540" height="68" class="layer-bg" rx="2"/>
|
|
|
+ <text x="74" y="546" class="mono-mute">OUTPUT · APPROVAL · EXECUTION</text>
|
|
|
+ <text x="74" y="562" class="body">→ outputs/reports/llm_decisions_{date}.csv</text>
|
|
|
+ <text x="74" y="576" class="body">→ outputs/reports/decision_{date}.xlsx · <tspan style="font-family:var(--mono);font-size:11.5px">FEISHU_OPERATOR_CHAT_ID</tspan></text>
|
|
|
+ <text x="74" y="588" class="small">→ outputs/execution_log/exec_{date}.jsonl(审计)</text>
|
|
|
+
|
|
|
+ <!-- =========== Layer 2b · 新建子系统(新增)=========== -->
|
|
|
+ <rect x="640" y="260" width="580" height="350" class="layer-new" rx="3"/>
|
|
|
+ <rect x="656" y="252" width="220" height="20" fill="#C75D3F" rx="2"/>
|
|
|
+ <text x="766" y="266" class="pill-text" text-anchor="middle">Layer 2b · 新建子系统(新增)</text>
|
|
|
+
|
|
|
+ <text x="930" y="296" class="title" text-anchor="middle" style="fill:var(--accent)">新建子系统</text>
|
|
|
+ <text x="930" y="316" class="agent-label" text-anchor="middle" style="fill:var(--ink-3)">"做加法"— 全新独立 entrypoint,与调控并行</text>
|
|
|
+
|
|
|
+ <rect x="660" y="340" width="540" height="36" class="layer-bg" rx="2" style="stroke:var(--accent);stroke-width:1.2"/>
|
|
|
+ <text x="674" y="362" class="mono-mute">ENTRYPOINT</text>
|
|
|
+ <text x="820" y="362" class="body-strong" style="font-family:var(--mono);font-size:13px;fill:var(--accent)">execute_creation_once.py</text>
|
|
|
+ <text x="1030" y="362" class="small">每日 02:30 UTC (新 cronjob)</text>
|
|
|
+
|
|
|
+ <rect x="660" y="386" width="540" height="60" class="layer-bg" rx="2" style="stroke:var(--accent);stroke-width:1.2"/>
|
|
|
+ <text x="674" y="406" class="mono-mute">BRAIN · CODE(全新 8 个模块)</text>
|
|
|
+ <text x="674" y="422" class="body" style="font-size:11.5px">creation_decision · ad_creation · creative_creation</text>
|
|
|
+ <text x="674" y="436" class="body" style="font-size:11.5px">material_recall · material_recall_sources · dedup_check<tspan style="fill:var(--ink-mute)"> (stub)</tspan> · uniqueness_check · audience_demand</text>
|
|
|
+
|
|
|
+ <rect x="660" y="456" width="540" height="60" class="layer-bg" rx="2" style="stroke:var(--accent);stroke-width:1.2"/>
|
|
|
+ <text x="674" y="476" class="mono-mute">BRAIN · KNOWLEDGE(独立 prompt + skill)</text>
|
|
|
+ <text x="674" y="494" class="body-strong" style="fill:var(--accent)">prompts/system_creation.prompt</text>
|
|
|
+ <text x="674" y="508" class="body">skills/creation_strategy.md(新增)</text>
|
|
|
+
|
|
|
+ <rect x="660" y="526" width="540" height="68" class="layer-bg" rx="2" style="stroke:var(--accent);stroke-width:1.2"/>
|
|
|
+ <text x="674" y="546" class="mono-mute">OUTPUT · APPROVAL · EXECUTION</text>
|
|
|
+ <text x="674" y="562" class="body">→ outputs/reports/creation_decisions_{date}.csv</text>
|
|
|
+ <text x="674" y="576" class="body">→ outputs/reports/creation_{date}.xlsx · <tspan style="font-family:var(--mono);font-size:11.5px;fill:var(--accent)">FEISHU_CREATION_CHAT_ID</tspan></text>
|
|
|
+ <text x="674" y="588" class="small">→ outputs/execution_log/creation_exec_{date}.jsonl(独立审计)</text>
|
|
|
+
|
|
|
+ <!-- =========== Layer 3 · 最小耦合点 =========== -->
|
|
|
+ <rect x="40" y="640" width="1180" height="100" class="layer-coupling" rx="3"/>
|
|
|
+ <rect x="56" y="632" width="200" height="20" fill="#B8902F" rx="2"/>
|
|
|
+ <text x="156" y="646" class="pill-text" text-anchor="middle">Layer 3 · Minimal Coupling</text>
|
|
|
+
|
|
|
+ <text x="630" y="670" class="title" text-anchor="middle" style="fill:var(--gold)">关联点(本期实现:单向)</text>
|
|
|
+ <text x="630" y="690" class="body" text-anchor="middle">新建子系统启动时只读调控的 <tspan style="font-family:var(--mono)">llm_decisions_{LATEST}.csv</tspan>,
|
|
|
+ 提取 <tspan style="font-family:var(--mono);fill:var(--ink)">{ad_id where action=='pause'}</tspan> 加入 <tspan style="font-family:var(--mono);fill:var(--accent)">excluded_ad_ids</tspan> 黑名单</text>
|
|
|
+ <text x="630" y="710" class="small" text-anchor="middle">add_creative 候选标记阶段硬过滤 · 不给"即将被关停的广告"补创意 · 反向耦合(调控读新建)留下期</text>
|
|
|
+
|
|
|
+ <!-- 关联点箭头 -->
|
|
|
+ <path class="arrow-coupling" d="M 330 610 L 330 640" marker-end="url(#arr-cpl)"/>
|
|
|
+ <text x="340" y="628" class="arrow-label" style="fill:var(--gold)">latest_decisions</text>
|
|
|
+
|
|
|
+ <path class="arrow-coupling" d="M 930 640 L 930 610" marker-end="url(#arr-cpl)"/>
|
|
|
+ <text x="888" y="630" class="arrow-label" style="fill:var(--gold)" text-anchor="end">excluded_ad_ids</text>
|
|
|
+</svg>
|
|
|
+
|
|
|
+<div class="legend">
|
|
|
+ <div class="legend-item"><span class="legend-swatch shared"></span>共享 infra(数据 / API / 基础 skill)</div>
|
|
|
+ <div class="legend-item"><span class="legend-swatch existing"></span>调控子系统(现有 · 不动)</div>
|
|
|
+ <div class="legend-item"><span class="legend-swatch new"></span>新建子系统(全新)</div>
|
|
|
+ <div class="legend-item"><span class="legend-swatch coupling"></span>跨系统关联点(单向 · 最小)</div>
|
|
|
+ <div class="legend-item"><span class="legend-line data"></span>数据流(共享 → 子系统)</div>
|
|
|
+ <div class="legend-item"><span class="legend-line coupling"></span>关联流(单向只读)</div>
|
|
|
+</div>
|
|
|
+</div>
|
|
|
+
|
|
|
+<!-- ════════════════════════════════════════════════════ -->
|
|
|
+<!-- FIGURE 2 · 数据契约流向 -->
|
|
|
+<!-- ════════════════════════════════════════════════════ -->
|
|
|
+<h2>图二 · 数据契约 — 文件级数据流</h2>
|
|
|
+
|
|
|
+<p class="intro">
|
|
|
+两个子系统通过<strong>文件系统</strong>通信,**互不调用对方 API**。所有产物文件都在 <code>outputs/</code> 下,可单独审计。共享只读输入由调控子系统在 02:00 写出 → 新建子系统在 02:30 读入。
|
|
|
+</p>
|
|
|
+
|
|
|
+<div class="diagram-wrap" data-tag="FIG · 02 · DATA CONTRACTS">
|
|
|
+<svg class="arch" viewBox="0 0 1260 620" xmlns="http://www.w3.org/2000/svg">
|
|
|
+ <defs>
|
|
|
+ <marker id="arr-data2" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#5C7A52"/></marker>
|
|
|
+ <marker id="arr-int2" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="5" markerHeight="5" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#0F1F2E"/></marker>
|
|
|
+ <marker id="arr-cpl2" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#B8902F"/></marker>
|
|
|
+ </defs>
|
|
|
+
|
|
|
+ <!-- ============ 共享只读输入(上方) ============ -->
|
|
|
+ <rect x="40" y="40" width="1180" height="120" class="layer-shared" rx="3"/>
|
|
|
+ <text x="60" y="62" class="mono-mute">SHARED READ-ONLY INPUTS · 共享只读输入(由调控产 / 新建读)</text>
|
|
|
+
|
|
|
+ <rect x="60" y="78" width="260" height="68" class="layer-bg" rx="2"/>
|
|
|
+ <text x="74" y="96" class="mono">metrics_{date}.csv</text>
|
|
|
+ <text x="74" y="112" class="small">广告级 + 创意级 ROI</text>
|
|
|
+ <text x="74" y="126" class="small">候选标记(roi_low / decay_signal / ...)</text>
|
|
|
+ <text x="74" y="140" class="small">由 roi_calculator.py 产</text>
|
|
|
+
|
|
|
+ <rect x="340" y="78" width="260" height="68" class="layer-bg" rx="2"/>
|
|
|
+ <text x="354" y="96" class="mono">portfolio_summary_{date}.json</text>
|
|
|
+ <text x="354" y="112" class="small">tier 基线 channel_p50 / tier_fission_mean</text>
|
|
|
+ <text x="354" y="126" class="small">渠道 P25/50/75 分位</text>
|
|
|
+ <text x="354" y="140" class="small">由 portfolio_metrics.py 产</text>
|
|
|
+
|
|
|
+ <rect x="620" y="78" width="260" height="68" class="layer-bg" rx="2"/>
|
|
|
+ <text x="634" y="96" class="mono">ad_status_{date}.csv</text>
|
|
|
+ <text x="634" y="112" class="small">广告状态快照(活跃 / pause / 删除)</text>
|
|
|
+ <text x="634" y="126" class="small">出价 · 预算 · 定向</text>
|
|
|
+ <text x="634" y="140" class="small">由 data_query.py 产</text>
|
|
|
+
|
|
|
+ <rect x="900" y="78" width="300" height="68" class="layer-bg" rx="2"/>
|
|
|
+ <text x="914" y="96" class="mono">creative_pause_history.json</text>
|
|
|
+ <text x="914" y="112" class="mono" style="font-size:10.5px">adjustment_history.json</text>
|
|
|
+ <text x="914" y="128" class="small">操作级频次(7 日窗口)</text>
|
|
|
+ <text x="914" y="142" class="small">两子系统都读以避免频次违规</text>
|
|
|
+
|
|
|
+ <!-- ============ 调控子系统产物(左下) ============ -->
|
|
|
+ <rect x="40" y="200" width="540" height="200" class="layer-existing" rx="3"/>
|
|
|
+ <text x="56" y="222" class="mono-mute">ADJUSTMENT SUBSYSTEM OUTPUTS</text>
|
|
|
+ <text x="56" y="240" class="title">调控产物(现有)</text>
|
|
|
+
|
|
|
+ <rect x="60" y="256" width="500" height="36" class="layer-bg" rx="2"/>
|
|
|
+ <text x="74" y="276" class="mono">outputs/reports/llm_decisions_{date}.csv</text>
|
|
|
+ <text x="380" y="276" class="small">每行一条决策(7 种 action)</text>
|
|
|
+
|
|
|
+ <rect x="60" y="300" width="500" height="36" class="layer-bg" rx="2"/>
|
|
|
+ <text x="74" y="320" class="mono">outputs/reports/decision_{date}.xlsx</text>
|
|
|
+ <text x="380" y="320" class="small">飞书审批表(调控群)</text>
|
|
|
+
|
|
|
+ <rect x="60" y="344" width="500" height="36" class="layer-bg" rx="2"/>
|
|
|
+ <text x="74" y="364" class="mono">outputs/execution_log/exec_{date}.jsonl</text>
|
|
|
+ <text x="380" y="364" class="small">API 调用审计</text>
|
|
|
+
|
|
|
+ <!-- ============ 新建子系统产物(右下) ============ -->
|
|
|
+ <rect x="640" y="200" width="580" height="280" class="layer-new" rx="3"/>
|
|
|
+ <text x="656" y="222" class="mono-mute" style="fill:var(--accent)">CREATION SUBSYSTEM OUTPUTS</text>
|
|
|
+ <text x="656" y="240" class="title" style="fill:var(--accent)">新建产物(全新)</text>
|
|
|
+
|
|
|
+ <rect x="660" y="256" width="540" height="36" class="layer-bg" rx="2" style="stroke:var(--accent)"/>
|
|
|
+ <text x="674" y="276" class="mono" style="fill:var(--accent)">outputs/reports/creation_decisions_{date}.csv</text>
|
|
|
+ <text x="990" y="276" class="small">action ∈ {create_ad, add_creative}</text>
|
|
|
+
|
|
|
+ <rect x="660" y="300" width="540" height="36" class="layer-bg" rx="2" style="stroke:var(--accent)"/>
|
|
|
+ <text x="674" y="320" class="mono" style="fill:var(--accent)">outputs/reports/creation_{date}.xlsx</text>
|
|
|
+ <text x="990" y="320" class="small">飞书审批表(新建群)</text>
|
|
|
+
|
|
|
+ <rect x="660" y="344" width="540" height="36" class="layer-bg" rx="2" style="stroke:var(--accent)"/>
|
|
|
+ <text x="674" y="364" class="mono" style="fill:var(--accent)">outputs/execution_log/creation_exec_{date}.jsonl</text>
|
|
|
+ <text x="990" y="364" class="small">独立审计</text>
|
|
|
+
|
|
|
+ <rect x="660" y="388" width="260" height="80" class="layer-bg" rx="2" style="stroke:var(--accent);stroke-dasharray:3 3"/>
|
|
|
+ <text x="674" y="406" class="mono" style="font-size:10.5px;fill:var(--accent)">outputs/data/ad_fingerprint_cache.json</text>
|
|
|
+ <text x="674" y="422" class="small">营销内容指纹(唯一性预校验)</text>
|
|
|
+ <text x="674" y="436" class="small" style="font-style:italic">每次新建广告前先比对此缓存</text>
|
|
|
+ <text x="674" y="450" class="small" style="font-style:italic">+ 调 ads_get 同步</text>
|
|
|
+
|
|
|
+ <rect x="940" y="388" width="260" height="80" class="layer-bg" rx="2" style="stroke:var(--accent);stroke-dasharray:3 3"/>
|
|
|
+ <text x="954" y="406" class="mono" style="font-size:10.5px;fill:var(--accent)">creative_add_history.json</text>
|
|
|
+ <text x="954" y="422" class="mono" style="font-size:10.5px;fill:var(--accent)">ad_creation_history.json</text>
|
|
|
+ <text x="954" y="440" class="small">7 日累计护栏数据源</text>
|
|
|
+ <text x="954" y="454" class="small" style="font-style:italic">类比现有 creative_pause_history</text>
|
|
|
+
|
|
|
+ <!-- ============ 数据流箭头 ============ -->
|
|
|
+ <!-- 共享 → 调控 -->
|
|
|
+ <path class="arrow-data" d="M 180 158 L 180 200" marker-end="url(#arr-data2)"/>
|
|
|
+ <!-- 共享 → 新建 -->
|
|
|
+ <path class="arrow-data" d="M 770 158 L 770 200" marker-end="url(#arr-data2)"/>
|
|
|
+
|
|
|
+ <!-- 调控 → 新建(关联点:单向只读) -->
|
|
|
+ <path class="arrow-coupling" d="M 560 278 C 600 278 600 278 640 278" marker-end="url(#arr-cpl2)"/>
|
|
|
+ <text x="582" y="271" class="arrow-label" text-anchor="middle" style="fill:var(--gold)">read pause ad_id</text>
|
|
|
+
|
|
|
+ <!-- 注释:反向耦合留下期 -->
|
|
|
+ <line x1="640" y1="320" x2="560" y2="320" stroke="#7A8294" stroke-width="0.6" stroke-dasharray="2 4"/>
|
|
|
+ <text x="600" y="334" class="small" text-anchor="middle" style="font-style:italic;font-size:9.5px">反向耦合(调控读新建)留下期</text>
|
|
|
+
|
|
|
+ <!-- ============ 关联点细节(底部说明) ============ -->
|
|
|
+ <rect x="40" y="510" width="1180" height="86" class="layer-coupling" rx="3"/>
|
|
|
+ <text x="58" y="532" class="mono-mute" style="fill:var(--gold)">LAYER 3 · COUPLING DETAIL</text>
|
|
|
+ <text x="58" y="550" class="body-strong" style="fill:var(--ink)">新建子系统 Step 1:</text>
|
|
|
+ <text x="58" y="568" class="body" style="font-family:var(--mono);font-size:11.5px">excluded_ad_ids = read_pause_ad_ids(latest_llm_decisions)</text>
|
|
|
+ <text x="58" y="584" class="body">→ 传给 LLM prompt + 候选标记代码(<tspan style="font-family:var(--mono);font-size:11.5px;fill:var(--accent)">creation_decision.mark_add_creative_candidates</tspan>)</text>
|
|
|
+
|
|
|
+ <text x="700" y="550" class="body-strong" style="fill:var(--ink)">空盘场景(常态):</text>
|
|
|
+ <text x="700" y="568" class="body">如果调控 latest 无 pause 决策 → <tspan style="font-style:italic">excluded_ad_ids = ∅</tspan></text>
|
|
|
+ <text x="700" y="584" class="body">新建子系统照常按自己的候选 + LLM 决策跑</text>
|
|
|
+</svg>
|
|
|
+</div>
|
|
|
+
|
|
|
+<!-- ════════════════════════════════════════════════════ -->
|
|
|
+<!-- FIGURE 3 · 模块 A + B 内部流水线 -->
|
|
|
+<!-- ════════════════════════════════════════════════════ -->
|
|
|
+<h2>图三 · 模块 A 广告新建 · 内部流水线</h2>
|
|
|
+
|
|
|
+<div class="diagram-wrap" data-tag="FIG · 03 · MODULE A · NEW AD PIPELINE">
|
|
|
+<svg class="arch" viewBox="0 0 1260 540" xmlns="http://www.w3.org/2000/svg">
|
|
|
+ <defs>
|
|
|
+ <marker id="arr-act3" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#C75D3F"/></marker>
|
|
|
+ <marker id="arr-int3" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="5" markerHeight="5" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#0F1F2E"/></marker>
|
|
|
+ </defs>
|
|
|
+
|
|
|
+ <!-- Top: 触发候选标记 (L1) -->
|
|
|
+ <rect x="40" y="40" width="1180" height="90" class="layer-bg" rx="3"/>
|
|
|
+ <text x="58" y="62" class="mono-mute">STEP 1 · 候选标记(L1 代码层 · 每 tier 硬算 6 信号)</text>
|
|
|
+ <text x="58" y="80" class="body-strong" style="font-family:var(--mono);font-size:12.5px;fill:var(--accent)">tools/creation_decision.py::mark_create_ad_candidates(portfolio_summary, ads_snapshot, history)</text>
|
|
|
+
|
|
|
+ <rect x="60" y="92" width="190" height="32" class="layer-bg" rx="2"/>
|
|
|
+ <text x="68" y="111" class="small" style="font-family:var(--mono);font-size:10.5px">tier_active_low</text>
|
|
|
+ <rect x="260" y="92" width="190" height="32" class="layer-bg" rx="2"/>
|
|
|
+ <text x="268" y="111" class="small" style="font-family:var(--mono);font-size:10.5px">tier_pause_burst</text>
|
|
|
+ <rect x="460" y="92" width="190" height="32" class="layer-bg" rx="2"/>
|
|
|
+ <text x="468" y="111" class="small" style="font-family:var(--mono);font-size:10.5px">tier_creative_refresh_failed</text>
|
|
|
+ <rect x="660" y="92" width="190" height="32" class="layer-bg" rx="2"/>
|
|
|
+ <text x="668" y="111" class="small" style="font-family:var(--mono);font-size:10.5px">tier_uniqueness_slots_available</text>
|
|
|
+ <rect x="860" y="92" width="160" height="32" class="layer-bg" rx="2"/>
|
|
|
+ <text x="868" y="111" class="small" style="font-family:var(--mono);font-size:10.5px">tier_roi_healthy</text>
|
|
|
+ <rect x="1030" y="92" width="170" height="32" class="layer-bg" rx="2"/>
|
|
|
+ <text x="1038" y="111" class="small" style="font-family:var(--mono);font-size:10.5px">account_quota_remaining</text>
|
|
|
+
|
|
|
+ <path class="arrow-internal" d="M 630 130 L 630 154" marker-end="url(#arr-int3)"/>
|
|
|
+ <text x="640" y="148" class="arrow-label">任 4 项命中 → 候选</text>
|
|
|
+
|
|
|
+ <!-- Step 2: LLM 综合判断 (L2) -->
|
|
|
+ <rect x="40" y="160" width="1180" height="60" class="layer-bg" rx="3" style="stroke:var(--accent);stroke-width:1.5"/>
|
|
|
+ <text x="58" y="182" class="mono-mute" style="fill:var(--accent)">STEP 2 · LLM 综合判断(L2 · skill 启发式)</text>
|
|
|
+ <text x="58" y="200" class="body-strong" style="fill:var(--accent)">skills/creation_strategy.md</text>
|
|
|
+ <text x="58" y="214" class="body" style="font-size:11.5px">看 6 个候选 + tier 趋势 + 7 日累计配额,综合决定 "create_ad(tier_X, N 条)" + reason 5 元组 + confidence</text>
|
|
|
+
|
|
|
+ <path class="arrow-internal" d="M 630 220 L 630 244" marker-end="url(#arr-int3)"/>
|
|
|
+
|
|
|
+ <!-- Step 3: 唯一性枚举搜索 -->
|
|
|
+ <rect x="40" y="250" width="1180" height="120" class="layer-bg" rx="3"/>
|
|
|
+ <text x="58" y="272" class="mono-mute">STEP 3 · 唯一性枚举搜索(避免 1901634)· 约束:一账一包,audience 账户级固定</text>
|
|
|
+ <text x="58" y="290" class="body-strong" style="font-family:var(--mono);font-size:12.5px">tools/ad_creation.py::enumerate_new_ad_candidates(account_id, N)</text>
|
|
|
+ <text x="58" y="308" class="body" style="font-size:11.5px">笛卡尔积 <tspan style="font-family:var(--mono);fill:var(--accent)">site_set × age × geo</tspan>(3 维,共 4×4×4=64 组合) → 过滤已有 fingerprint → 取前 N</text>
|
|
|
+
|
|
|
+ <rect x="60" y="320" width="220" height="42" class="layer-bg" rx="2"/>
|
|
|
+ <text x="70" y="338" class="small" style="font-family:var(--mono);font-size:10.5px">site_set: 知乎信息流 · 朋友圈</text>
|
|
|
+ <text x="70" y="354" class="small" style="font-family:var(--mono);font-size:10.5px">微信公众号 · 优量汇 ...(4)</text>
|
|
|
+
|
|
|
+ <rect x="290" y="320" width="220" height="42" class="layer-bg" rx="2"/>
|
|
|
+ <text x="300" y="338" class="small" style="font-family:var(--mono);font-size:10.5px">age 离散段: 18-25 / 26-35 /</text>
|
|
|
+ <text x="300" y="354" class="small" style="font-family:var(--mono);font-size:10.5px">36-45 / 46-55(4)</text>
|
|
|
+
|
|
|
+ <rect x="520" y="320" width="220" height="42" class="layer-bg" rx="2"/>
|
|
|
+ <text x="530" y="338" class="small" style="font-family:var(--mono);font-size:10.5px">geo 离散段: 全国 / 一线 /</text>
|
|
|
+ <text x="530" y="354" class="small" style="font-family:var(--mono);font-size:10.5px">二线 / 三四线(4)</text>
|
|
|
+
|
|
|
+ <rect x="760" y="320" width="440" height="42" class="layer-bg" rx="2" style="stroke:var(--gold)"/>
|
|
|
+ <text x="770" y="338" class="small" style="font-family:var(--mono);font-size:10.5px;fill:var(--gold)">audience 已由 ACCOUNT_AUDIENCE_PACK_MAPPING 固定</text>
|
|
|
+ <text x="770" y="354" class="small" style="font-style:italic">+ fingerprint_cache + ads_get(account_id) → 单账户 64 组合中取 N 个 unique</text>
|
|
|
+
|
|
|
+ <path class="arrow-internal" d="M 630 370 L 630 394" marker-end="url(#arr-int3)"/>
|
|
|
+
|
|
|
+ <!-- Step 4: 出价 + 预算 + 命名 -->
|
|
|
+ <rect x="40" y="400" width="1180" height="86" class="layer-bg" rx="3"/>
|
|
|
+ <text x="58" y="422" class="mono-mute">STEP 4 · 出价基准三层降级 + 预算 + 命名</text>
|
|
|
+ <text x="58" y="438" class="body-strong" style="font-family:var(--mono);font-size:12px">tools/ad_creation.py::compute_target_bid(tier, site_set, age, geo)</text>
|
|
|
+
|
|
|
+ <rect x="58" y="448" width="290" height="32" class="layer-bg" rx="2"/>
|
|
|
+ <text x="68" y="466" class="small" style="font-family:var(--mono);font-size:10.5px">① combo_median (≥3 历史)→ factor 1.20</text>
|
|
|
+ <rect x="358" y="448" width="290" height="32" class="layer-bg" rx="2"/>
|
|
|
+ <text x="368" y="466" class="small" style="font-family:var(--mono);font-size:10.5px">② tier_history_median → factor 1.30</text>
|
|
|
+ <rect x="658" y="448" width="290" height="32" class="layer-bg" rx="2"/>
|
|
|
+ <text x="668" y="466" class="small" style="font-family:var(--mono);font-size:10.5px">③ channel_p50(兜底)→ factor 1.50</text>
|
|
|
+ <rect x="958" y="448" width="244" height="32" class="layer-bg" rx="2"/>
|
|
|
+ <text x="968" y="466" class="small" style="font-family:var(--mono);font-size:10.5px">budget = combo_median × 0.5</text>
|
|
|
+
|
|
|
+ <path class="arrow-act" d="M 630 486 L 630 510" marker-end="url(#arr-act3)"/>
|
|
|
+
|
|
|
+ <!-- Step 5: 输出 -->
|
|
|
+ <rect x="40" y="510" width="1180" height="20" class="layer-new" rx="2"/>
|
|
|
+ <text x="630" y="525" text-anchor="middle" class="body-strong" style="fill:var(--accent);font-size:11.5px">→ 写一行到 creation_decisions_{date}.csv · action_type='create_ad' · 等飞书审批 · 通过则调 ad_api.ad_create()</text>
|
|
|
+</svg>
|
|
|
+</div>
|
|
|
+
|
|
|
+<h2>图四 · 模块 B 创意新建 · 内部流水线</h2>
|
|
|
+
|
|
|
+<div class="diagram-wrap" data-tag="FIG · 04 · MODULE B · NEW CREATIVE PIPELINE">
|
|
|
+<svg class="arch" viewBox="0 0 1260 580" xmlns="http://www.w3.org/2000/svg">
|
|
|
+ <defs>
|
|
|
+ <marker id="arr-act4" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#C75D3F"/></marker>
|
|
|
+ <marker id="arr-int4" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="5" markerHeight="5" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#0F1F2E"/></marker>
|
|
|
+ <marker id="arr-cpl4" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#B8902F"/></marker>
|
|
|
+ </defs>
|
|
|
+
|
|
|
+ <!-- Step 1: 候选标记 (L1) -->
|
|
|
+ <rect x="40" y="40" width="1180" height="100" class="layer-bg" rx="3"/>
|
|
|
+ <text x="58" y="62" class="mono-mute">STEP 1 · 候选标记(L1 代码层 · 每广告硬算 7 信号)</text>
|
|
|
+ <text x="58" y="80" class="body-strong" style="font-family:var(--mono);font-size:12.5px;fill:var(--accent)">tools/creation_decision.py::mark_add_creative_candidates(metrics, excluded_ad_ids, history, tier_summary)</text>
|
|
|
+
|
|
|
+ <rect x="58" y="92" width="160" height="38" class="layer-bg" rx="2"/>
|
|
|
+ <text x="66" y="108" class="small" style="font-family:var(--mono);font-size:10.5px">decay_signal</text>
|
|
|
+ <text x="66" y="122" class="small">(复用现有)</text>
|
|
|
+ <rect x="228" y="92" width="160" height="38" class="layer-bg" rx="2"/>
|
|
|
+ <text x="236" y="108" class="small" style="font-family:var(--mono);font-size:10.5px">creative_count_low</text>
|
|
|
+ <text x="236" y="122" class="small">< 15</text>
|
|
|
+ <rect x="398" y="92" width="160" height="38" class="layer-bg" rx="2"/>
|
|
|
+ <text x="406" y="108" class="small" style="font-family:var(--mono);font-size:10.5px">creative_age_old</text>
|
|
|
+ <text x="406" y="122" class="small">中位 ≥ 7 天</text>
|
|
|
+ <rect x="568" y="92" width="160" height="38" class="layer-bg" rx="2"/>
|
|
|
+ <text x="576" y="108" class="small" style="font-family:var(--mono);font-size:10.5px">not_recently_added</text>
|
|
|
+ <text x="576" y="122" class="small">7 天未补过</text>
|
|
|
+ <rect x="738" y="92" width="160" height="38" class="layer-bg" rx="2"/>
|
|
|
+ <text x="746" y="108" class="small" style="font-family:var(--mono);font-size:10.5px">ad_alive_and_healthy</text>
|
|
|
+ <text x="746" y="122" class="small">ROI ≥ P50 × 0.90</text>
|
|
|
+ <rect x="908" y="92" width="146" height="38" class="layer-bg" rx="2" style="stroke:var(--gold);stroke-width:1.2"/>
|
|
|
+ <text x="916" y="108" class="small" style="font-family:var(--mono);font-size:10.5px;fill:var(--gold)">tier_not_declining</text>
|
|
|
+ <text x="916" y="122" class="small">tier 趋势护栏(深度补)</text>
|
|
|
+ <rect x="1064" y="92" width="140" height="38" class="layer-bg" rx="2" style="stroke:var(--gold);stroke-width:1.2"/>
|
|
|
+ <text x="1072" y="108" class="small" style="font-family:var(--mono);font-size:10.5px;fill:var(--gold)">not_in_excluded</text>
|
|
|
+ <text x="1072" y="122" class="small">关联点过滤</text>
|
|
|
+
|
|
|
+ <path class="arrow-internal" d="M 630 140 L 630 164" marker-end="url(#arr-int4)"/>
|
|
|
+ <text x="640" y="158" class="arrow-label">任 4 项命中 → 候选</text>
|
|
|
+
|
|
|
+ <!-- Step 2: LLM (L2) -->
|
|
|
+ <rect x="40" y="170" width="1180" height="60" class="layer-bg" rx="3" style="stroke:var(--accent);stroke-width:1.5"/>
|
|
|
+ <text x="58" y="192" class="mono-mute" style="fill:var(--accent)">STEP 2 · LLM 综合判断(L2 · skill 启发式)</text>
|
|
|
+ <text x="58" y="210" class="body-strong" style="fill:var(--accent)">skills/creation_strategy.md</text>
|
|
|
+ <text x="58" y="224" class="body" style="font-size:11.5px">综合候选 + tier 趋势 + 频次 + 配额 → 决定 "add_creative(ad_X, ≤ 5 条)" + 三路素材配比 + reason + confidence</text>
|
|
|
+
|
|
|
+ <path class="arrow-internal" d="M 630 230 L 630 254" marker-end="url(#arr-int4)"/>
|
|
|
+
|
|
|
+ <!-- Step 3: 三路素材召回 -->
|
|
|
+ <rect x="40" y="260" width="1180" height="120" class="layer-bg" rx="3"/>
|
|
|
+ <text x="58" y="282" class="mono-mute">STEP 3 · 三路素材召回(黑盒 API + 排序加权)</text>
|
|
|
+ <text x="58" y="300" class="body-strong" style="font-family:var(--mono);font-size:12.5px">tools/material_recall.py::recall_materials(audience_demand, top_k=50, sources, weights)</text>
|
|
|
+
|
|
|
+ <rect x="58" y="312" width="380" height="60" class="layer-bg" rx="2"/>
|
|
|
+ <rect x="58" y="312" width="36" height="60" fill="#5C7A52" rx="2"/>
|
|
|
+ <text x="76" y="346" text-anchor="middle" class="pill-text" style="fill:var(--paper)" transform="rotate(-90 76 346)">50%</text>
|
|
|
+ <text x="106" y="332" class="body-strong" style="font-size:13px">① 历史投放素材</text>
|
|
|
+ <text x="106" y="350" class="small" style="font-family:var(--mono);font-size:10.5px">HistorySource</text>
|
|
|
+ <text x="106" y="364" class="small">score = 0.3×cost + 0.4×CTR + 0.3×ROI(标准化)</text>
|
|
|
+
|
|
|
+ <rect x="448" y="312" width="380" height="60" class="layer-bg" rx="2"/>
|
|
|
+ <rect x="448" y="312" width="36" height="60" fill="#5C7A52" rx="2"/>
|
|
|
+ <text x="466" y="346" text-anchor="middle" class="pill-text" style="fill:var(--paper)" transform="rotate(-90 466 346)">30%</text>
|
|
|
+ <text x="496" y="332" class="body-strong" style="font-size:13px">② 合作方即转卡片</text>
|
|
|
+ <text x="496" y="350" class="small" style="font-family:var(--mono);font-size:10.5px">PartnerSource</text>
|
|
|
+ <text x="496" y="364" class="small">score = 卡片点击率</text>
|
|
|
+
|
|
|
+ <rect x="838" y="312" width="380" height="60" class="layer-bg" rx="2"/>
|
|
|
+ <rect x="838" y="312" width="36" height="60" fill="#5C7A52" rx="2"/>
|
|
|
+ <text x="856" y="346" text-anchor="middle" class="pill-text" style="fill:var(--paper)" transform="rotate(-90 856 346)">20%</text>
|
|
|
+ <text x="886" y="332" class="body-strong" style="font-size:13px">③ AI 改写 (取 ① top 5)</text>
|
|
|
+ <text x="886" y="350" class="small" style="font-family:var(--mono);font-size:10.5px">RewriteSource · uses LLM</text>
|
|
|
+ <text x="886" y="364" class="small">light:同义改写 · medium:句式重组</text>
|
|
|
+
|
|
|
+ <path class="arrow-internal" d="M 630 380 L 630 404" marker-end="url(#arr-int4)"/>
|
|
|
+
|
|
|
+ <!-- Step 4: 判重 stub + AI 改写升档 -->
|
|
|
+ <rect x="40" y="410" width="580" height="100" class="layer-bg" rx="3" style="stroke:var(--ink-mute);stroke-width:1;stroke-dasharray:3 3"/>
|
|
|
+ <text x="58" y="432" class="mono-mute">STEP 4 · 4+M 判重(本期 STUB)</text>
|
|
|
+ <text x="58" y="450" class="body-strong" style="font-family:var(--mono);font-size:12px">tools/dedup_check.py::check_material_duplicate(...)</text>
|
|
|
+ <text x="58" y="468" class="body" style="font-size:11.5px">DEDUP_ENABLED=False · always returns not_duplicate</text>
|
|
|
+ <text x="58" y="486" class="body" style="font-size:11.5px">本地预筛:同广告下 <tspan style="font-family:var(--mono)">md5(image_id+title+desc)</tspan> 去重</text>
|
|
|
+ <text x="58" y="502" class="small" style="font-style:italic">→ 后续接 4+M 云服务,只改本函数实现,接口不变</text>
|
|
|
+
|
|
|
+ <rect x="640" y="410" width="580" height="100" class="layer-bg" rx="3"/>
|
|
|
+ <text x="658" y="432" class="mono-mute">STEP 5 · AI 改写命中重复时升档</text>
|
|
|
+ <text x="658" y="450" class="body-strong">light 改写 → 命中重复 → medium → skip</text>
|
|
|
+ <text x="658" y="468" class="body" style="font-size:11.5px">最多尝试 2 次(<tspan style="font-family:var(--mono)">AI_REWRITE_MAX_ATTEMPTS_PER_MATERIAL=2</tspan>)</text>
|
|
|
+ <text x="658" y="486" class="body" style="font-size:11.5px">改写后再走判重 → 才上传 / 挂载</text>
|
|
|
+ <text x="658" y="502" class="small" style="font-style:italic">heavy 级(图像重新生成)留下期</text>
|
|
|
+
|
|
|
+ <!-- Step 6: 渐进式 + 上限 -->
|
|
|
+ <path class="arrow-act" d="M 630 510 L 630 534" marker-end="url(#arr-act4)"/>
|
|
|
+ <rect x="40" y="540" width="1180" height="32" class="layer-new" rx="2"/>
|
|
|
+ <text x="630" y="560" text-anchor="middle" class="body-strong" style="fill:var(--accent);font-size:12px">渐进式控制 · 单次 ≤ 5 · 单广告 7 日累计 ≤ 8 · 已有 ≥ 30 不触发 → 写 creation_decisions / 飞书审批 / creative_create()</text>
|
|
|
+</svg>
|
|
|
+</div>
|
|
|
+
|
|
|
+<!-- ════════════════════════════════════════════════════ -->
|
|
|
+<!-- FIGURE 5 · 决策框架 L1 / L2 / L3 -->
|
|
|
+<!-- ════════════════════════════════════════════════════ -->
|
|
|
+<h2>图五 · 决策框架:代码 vs 知识 三层分工</h2>
|
|
|
+
|
|
|
+<p class="intro">
|
|
|
+两个子系统都遵循同一套<strong>三层分工</strong> — L1 候选标记代码(确定性 · 可单测)/ L2 LLM skill(启发式 · 灰色地带)/ L3 兜底护栏代码(确定性 · 边界)。这是分离架构的核心:**skill 不是简单等于一段话,是 LLM 的推理框架,各子系统必须独立**。
|
|
|
+</p>
|
|
|
+
|
|
|
+<div class="diagram-wrap" data-tag="FIG · 05 · L1 / L2 / L3 DECISION LAYERS">
|
|
|
+<svg class="arch" viewBox="0 0 1260 500" xmlns="http://www.w3.org/2000/svg">
|
|
|
+
|
|
|
+ <!-- L1 lane -->
|
|
|
+ <rect x="40" y="40" width="1180" height="130" class="layer-bg" rx="3"/>
|
|
|
+ <rect x="56" y="32" width="180" height="20" fill="#4A5870" rx="2"/>
|
|
|
+ <text x="146" y="46" class="pill-text" text-anchor="middle">L1 · CANDIDATE MARKING</text>
|
|
|
+
|
|
|
+ <text x="60" y="76" class="mono-mute">代码层 · 确定性 · 可单测 · 可回放</text>
|
|
|
+ <text x="60" y="98" class="title" style="font-size:16px">候选标记</text>
|
|
|
+
|
|
|
+ <rect x="60" y="108" width="560" height="52" class="layer-existing" rx="2"/>
|
|
|
+ <text x="76" y="126" class="body-strong">调控:tools/ad_decision.py</text>
|
|
|
+ <text x="76" y="142" class="small" style="font-family:var(--mono);font-size:10.5px">roi_low · decay_signal · bid_up_candidate · bid_down_candidate · scale_up_candidate</text>
|
|
|
+ <text x="76" y="156" class="small">(5 个,现有不动)</text>
|
|
|
+
|
|
|
+ <rect x="640" y="108" width="560" height="52" class="layer-new" rx="2"/>
|
|
|
+ <text x="656" y="126" class="body-strong" style="fill:var(--accent)">新建:tools/creation_decision.py</text>
|
|
|
+ <text x="656" y="142" class="small" style="font-family:var(--mono);font-size:10.5px">add_creative 7 信号 + create_ad 6 信号(L1 全新)</text>
|
|
|
+ <text x="656" y="156" class="small">含 tier 级护栏 + 关联点过滤(深度补全)</text>
|
|
|
+
|
|
|
+ <!-- L2 lane -->
|
|
|
+ <rect x="40" y="190" width="1180" height="130" class="layer-bg" rx="3" style="stroke:var(--accent);stroke-width:1.5"/>
|
|
|
+ <rect x="56" y="182" width="180" height="20" fill="#C75D3F" rx="2"/>
|
|
|
+ <text x="146" y="196" class="pill-text" text-anchor="middle">L2 · LLM HEURISTIC</text>
|
|
|
+
|
|
|
+ <text x="60" y="226" class="mono-mute" style="fill:var(--accent)">知识层 · 启发式 · 灰色地带 · 综合权衡</text>
|
|
|
+ <text x="60" y="248" class="title" style="font-size:16px;fill:var(--accent)">LLM 综合判断(skill 注入)</text>
|
|
|
+
|
|
|
+ <rect x="60" y="258" width="560" height="52" class="layer-existing" rx="2"/>
|
|
|
+ <text x="76" y="276" class="body-strong">调控:skills/decision_strategy.md</text>
|
|
|
+ <text x="76" y="292" class="small">"任 X 项命中倾向触发" · 裂变 vs ROI 冲突 · reason 5 元组</text>
|
|
|
+ <text x="76" y="306" class="small">→ 只注入 调控 Agent prompt</text>
|
|
|
+
|
|
|
+ <rect x="640" y="258" width="560" height="52" class="layer-new" rx="2"/>
|
|
|
+ <text x="656" y="276" class="body-strong" style="fill:var(--accent)">新建:skills/creation_strategy.md(新)</text>
|
|
|
+ <text x="656" y="292" class="small">"任 4 项命中倾向触发" · 三路素材配比 · 出价 factor 选择</text>
|
|
|
+ <text x="656" y="306" class="small" style="fill:var(--accent)">→ 只注入 新建 Agent prompt · 不污染调控</text>
|
|
|
+
|
|
|
+ <!-- L3 lane -->
|
|
|
+ <rect x="40" y="340" width="1180" height="130" class="layer-bg" rx="3"/>
|
|
|
+ <rect x="56" y="332" width="180" height="20" fill="#B8902F" rx="2"/>
|
|
|
+ <text x="146" y="346" class="pill-text" text-anchor="middle">L3 · HARDCODED GUARDS</text>
|
|
|
+
|
|
|
+ <text x="60" y="376" class="mono-mute" style="fill:var(--gold)">代码层 · 确定性 · 边界硬约束 · 不可绕过</text>
|
|
|
+ <text x="60" y="398" class="title" style="font-size:16px">兜底护栏</text>
|
|
|
+
|
|
|
+ <rect x="60" y="408" width="560" height="52" class="layer-existing" rx="2"/>
|
|
|
+ <text x="76" y="426" class="body-strong">调控:tools/guardrails.py(现有)</text>
|
|
|
+ <text x="76" y="442" class="small" style="font-family:var(--mono);font-size:10.5px">BID_FLOOR/CEILING · MAX_ADJUSTMENTS_PER_AD_PER_DAY · 数据新鲜度</text>
|
|
|
+ <text x="76" y="456" class="small">+ CreativePauseHistory 7 天去重</text>
|
|
|
+
|
|
|
+ <rect x="640" y="408" width="560" height="52" class="layer-new" rx="2"/>
|
|
|
+ <text x="656" y="426" class="body-strong" style="fill:var(--accent)">新建:guardrails 扩展 + creation_history(新)</text>
|
|
|
+ <text x="656" y="442" class="small" style="font-family:var(--mono);font-size:10.5px">MAX_NEW_ADS_PER_TIER_PER_7D · uniqueness_check · 创意数上限</text>
|
|
|
+ <text x="656" y="456" class="small" style="fill:var(--accent)">+ CreativeAddHistory · AdCreationHistory(深度补全:7 日累计)</text>
|
|
|
+</svg>
|
|
|
+</div>
|
|
|
+
|
|
|
+<!-- ════════════════════════════════════════════════════ -->
|
|
|
+<!-- FIGURE 6 · 关联点放大图(时间序) -->
|
|
|
+<!-- ════════════════════════════════════════════════════ -->
|
|
|
+<h2>图六 · 关联点放大 — 时序图</h2>
|
|
|
+
|
|
|
+<div class="diagram-wrap" data-tag="FIG · 06 · COUPLING POINT · TIME SEQUENCE">
|
|
|
+<svg class="arch" viewBox="0 0 1260 380" xmlns="http://www.w3.org/2000/svg">
|
|
|
+ <defs>
|
|
|
+ <marker id="arr-int6" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="5" markerHeight="5" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#0F1F2E"/></marker>
|
|
|
+ <marker id="arr-cpl6" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#B8902F"/></marker>
|
|
|
+ </defs>
|
|
|
+
|
|
|
+ <!-- Timeline -->
|
|
|
+ <line x1="80" y1="60" x2="1180" y2="60" stroke="#0F1F2E" stroke-width="1.5"/>
|
|
|
+ <text x="80" y="44" class="mono-mute">UTC 02:00</text>
|
|
|
+ <text x="600" y="44" class="mono-mute" text-anchor="middle">UTC 02:30</text>
|
|
|
+ <text x="1180" y="44" class="mono-mute" text-anchor="end">UTC 04:00+</text>
|
|
|
+
|
|
|
+ <circle cx="80" cy="60" r="6" fill="#4A5870"/>
|
|
|
+ <circle cx="600" cy="60" r="6" fill="#C75D3F"/>
|
|
|
+ <circle cx="1180" cy="60" r="6" fill="#0F1F2E"/>
|
|
|
+
|
|
|
+ <!-- 调控 swimlane -->
|
|
|
+ <rect x="40" y="100" width="1180" height="100" class="layer-existing" rx="3"/>
|
|
|
+ <text x="60" y="122" class="mono-mute">ADJUSTMENT LANE · 调控子系统</text>
|
|
|
+
|
|
|
+ <rect x="80" y="140" width="200" height="42" class="layer-bg" rx="2"/>
|
|
|
+ <text x="92" y="158" class="body-strong" style="font-size:12px">execute_once.py</text>
|
|
|
+ <text x="92" y="174" class="small">数据→决策→审批→执行</text>
|
|
|
+
|
|
|
+ <rect x="290" y="140" width="320" height="42" class="layer-bg" rx="2"/>
|
|
|
+ <text x="302" y="158" class="body" style="font-size:11.5px">02:30 之前:产物落地</text>
|
|
|
+ <text x="302" y="174" class="small" style="font-family:var(--mono);font-size:10.5px">outputs/reports/llm_decisions_{date}.csv</text>
|
|
|
+
|
|
|
+ <rect x="620" y="140" width="560" height="42" class="layer-bg" rx="2" style="stroke-dasharray:2 4"/>
|
|
|
+ <text x="632" y="158" class="body" style="font-size:11.5px;fill:var(--ink-mute)">飞书审批进行中(120 min 阻塞 · 与新建并行)</text>
|
|
|
+ <text x="632" y="174" class="small" style="font-style:italic">审批通过后执行 · 此期间不影响新建子系统启动</text>
|
|
|
+
|
|
|
+ <!-- 新建 swimlane -->
|
|
|
+ <rect x="40" y="220" width="1180" height="140" class="layer-new" rx="3"/>
|
|
|
+ <text x="60" y="242" class="mono-mute" style="fill:var(--accent)">CREATION LANE · 新建子系统</text>
|
|
|
+
|
|
|
+ <rect x="600" y="260" width="200" height="42" class="layer-bg" rx="2" style="stroke:var(--accent)"/>
|
|
|
+ <text x="612" y="278" class="body-strong" style="font-size:12px;fill:var(--accent)">execute_creation_once.py</text>
|
|
|
+ <text x="612" y="294" class="small">02:30 启动</text>
|
|
|
+
|
|
|
+ <rect x="600" y="312" width="580" height="42" class="layer-bg" rx="2" style="stroke:var(--gold);stroke-width:1.5"/>
|
|
|
+ <text x="612" y="330" class="body-strong" style="font-size:11.5px;fill:var(--gold)">Step 1 · 读调控 latest_decisions</text>
|
|
|
+ <text x="612" y="346" class="small" style="font-family:var(--mono);font-size:10.5px">excluded_ad_ids = {ad_id where action=='pause' in llm_decisions_{date}.csv}</text>
|
|
|
+
|
|
|
+ <!-- 关联点箭头(调控 → 新建)-->
|
|
|
+ <path class="arrow-coupling" d="M 380 200 C 380 235 480 220 600 330" marker-end="url(#arr-cpl6)"/>
|
|
|
+ <text x="430" y="218" class="arrow-label" style="fill:var(--gold)">latest_decisions(只读)</text>
|
|
|
+
|
|
|
+ <!-- 注释:之后新建跑完自己的流水线 -->
|
|
|
+ <text x="810" y="285" class="body" style="font-size:11.5px">→ 候选标记(7 信号)→ LLM 决策 → 唯一性校验 → 飞书新建审批表 → ad_create / creative_create</text>
|
|
|
+</svg>
|
|
|
+</div>
|
|
|
+
|
|
|
+<!-- ════════════════════════════════════════════════════ -->
|
|
|
+<!-- FIGURE 7 · 实施甘特图 -->
|
|
|
+<!-- ════════════════════════════════════════════════════ -->
|
|
|
+<h2>图七 · 实施甘特图(10 阶段)</h2>
|
|
|
+
|
|
|
+<div class="table-wrap" data-tag="FIG · 07 · IMPLEMENTATION ROADMAP">
|
|
|
+<table class="matrix">
|
|
|
+ <colgroup>
|
|
|
+ <col style="width:48px"/>
|
|
|
+ <col style="width:130px"/>
|
|
|
+ <col style="width:auto"/>
|
|
|
+ <col style="width:280px"/>
|
|
|
+ <col style="width:80px"/>
|
|
|
+ </colgroup>
|
|
|
+ <thead>
|
|
|
+ <tr><th>阶</th><th>名称</th><th>内容</th><th>关键产出</th><th>类别</th></tr>
|
|
|
+ </thead>
|
|
|
+ <tbody>
|
|
|
+ <tr><td class="mono">a</td><td>共享 infra 抽取</td><td>im_approval.py 抽 FeishuApprovalBase · execution_engine 抽公共部分 · config.py 拆 [SHARED]/[ADJUSTMENT]/[CREATION] 三段</td><td class="mono">FeishuApprovalBase · config 重排</td><td class="shared">共享</td></tr>
|
|
|
+ <tr><td class="mono">b</td><td>适配层 stub</td><td>5 个适配模块接口签名:audience_demand · material_recall · dedup_check · uniqueness_check · creation_history</td><td class="mono">5 个新文件 + 单测</td><td class="new">新建</td></tr>
|
|
|
+ <tr><td class="mono">c</td><td>模块 A 内核</td><td>ad_creation.py 真实化:唯一性预校验 + 出价基准三层 + 命名 + ad_api.ad_create() 调用</td><td class="mono">tools/ad_creation.py</td><td class="new">新建</td></tr>
|
|
|
+ <tr><td class="mono">d</td><td>模块 B 内核</td><td>creative_creation.py 真实化:三路召回(history 路先做)+ AI 改写(light)+ 渐进式控制 + ad_api.creative_create()</td><td class="mono">tools/creative_creation.py</td><td class="new">新建</td></tr>
|
|
|
+ <tr><td class="mono">e</td><td>新建 Agent 框架</td><td>prompts/system_creation.prompt + skills/creation_strategy.md + creation_decision.py 候选标记 + 工具白名单</td><td class="mono">prompt + skill + L1 标记代码</td><td class="new">新建</td></tr>
|
|
|
+ <tr><td class="mono">f</td><td>新建子系统入口</td><td>execute_creation_once.py 完整流水线:关联点过滤 → Agent → 决策落地 → 审批发送</td><td class="mono">execute_creation_once.py</td><td class="new">新建</td></tr>
|
|
|
+ <tr><td class="mono">g</td><td>飞书审批扩展</td><td>FeishuCreationApproval 子类 · 新 chat_id 配置 · 新 APPROVAL_COLUMNS</td><td class="mono">tools/im_approval.py 重构</td><td class="shared">共享</td></tr>
|
|
|
+ <tr><td class="mono">h</td><td>执行 dispatch</td><td>execution_engine 加 _execute_create_ad() · _execute_add_creative()(新建独占)</td><td class="mono">execution_engine 新分支</td><td class="new">新建</td></tr>
|
|
|
+ <tr><td class="mono">i</td><td>端到端 + 关联点验证</td><td>execution_enabled=true · 单一测试账户跑 · 验证唯一性 / 创意数 / 关联点过滤 / 调控不受影响</td><td class="mono">回归测试 + 手工 checklist</td><td class="muted">验证</td></tr>
|
|
|
+ <tr><td class="mono">j</td><td>K8s + 文档</td><td>k8s/cronjob_creation.yaml · 更新 CLAUDE.md · 监控告警</td><td class="mono">cronjob 上线 · 稳定跑 1 周</td><td class="muted">交付</td></tr>
|
|
|
+ </tbody>
|
|
|
+</table>
|
|
|
+
|
|
|
+<div style="margin-top:24px">
|
|
|
+<h3>阶段甘特(相对工作量,水平比例示意)</h3>
|
|
|
+<div style="display:grid;grid-template-columns:60px 1fr;gap:6px;align-items:center;margin-top:8px">
|
|
|
+ <span class="mono" style="font-size:11px;color:var(--ink-mute)">阶 a</span>
|
|
|
+ <div class="gantt-bar"><div class="gantt-fill shared-bar" style="left:0%;width:12%">a · 抽 infra</div></div>
|
|
|
+
|
|
|
+ <span class="mono" style="font-size:11px;color:var(--ink-mute)">阶 b</span>
|
|
|
+ <div class="gantt-bar"><div class="gantt-fill" style="left:10%;width:8%">b · stub</div></div>
|
|
|
+
|
|
|
+ <span class="mono" style="font-size:11px;color:var(--ink-mute)">阶 c</span>
|
|
|
+ <div class="gantt-bar"><div class="gantt-fill" style="left:18%;width:18%">c · 模块 A</div></div>
|
|
|
+
|
|
|
+ <span class="mono" style="font-size:11px;color:var(--ink-mute)">阶 d</span>
|
|
|
+ <div class="gantt-bar"><div class="gantt-fill" style="left:25%;width:20%">d · 模块 B</div></div>
|
|
|
+
|
|
|
+ <span class="mono" style="font-size:11px;color:var(--ink-mute)">阶 e</span>
|
|
|
+ <div class="gantt-bar"><div class="gantt-fill" style="left:38%;width:14%">e · Agent 框架</div></div>
|
|
|
+
|
|
|
+ <span class="mono" style="font-size:11px;color:var(--ink-mute)">阶 f</span>
|
|
|
+ <div class="gantt-bar"><div class="gantt-fill" style="left:50%;width:14%">f · 子系统入口</div></div>
|
|
|
+
|
|
|
+ <span class="mono" style="font-size:11px;color:var(--ink-mute)">阶 g</span>
|
|
|
+ <div class="gantt-bar"><div class="gantt-fill shared-bar" style="left:55%;width:10%">g · 飞书</div></div>
|
|
|
+
|
|
|
+ <span class="mono" style="font-size:11px;color:var(--ink-mute)">阶 h</span>
|
|
|
+ <div class="gantt-bar"><div class="gantt-fill" style="left:64%;width:10%">h · execute</div></div>
|
|
|
+
|
|
|
+ <span class="mono" style="font-size:11px;color:var(--ink-mute)">阶 i</span>
|
|
|
+ <div class="gantt-bar"><div class="gantt-fill cross-bar" style="left:74%;width:14%">i · e2e 验证</div></div>
|
|
|
+
|
|
|
+ <span class="mono" style="font-size:11px;color:var(--ink-mute)">阶 j</span>
|
|
|
+ <div class="gantt-bar"><div class="gantt-fill cross-bar" style="left:86%;width:14%">j · K8s + 文档</div></div>
|
|
|
+</div>
|
|
|
+
|
|
|
+<div class="legend" style="margin-top:24px">
|
|
|
+ <div class="legend-item"><span class="legend-line" style="border-color:var(--moss);border-top-style:solid"></span>共享 infra 改动(影响调控,需回归)</div>
|
|
|
+ <div class="legend-item"><span class="legend-line act"></span>新建子系统独占改动</div>
|
|
|
+ <div class="legend-item"><span class="legend-line" style="border-color:var(--gold);border-top-style:solid"></span>验证 / 交付</div>
|
|
|
+</div>
|
|
|
+</div>
|
|
|
+</div>
|
|
|
+
|
|
|
+<!-- ════════════════════════════════════════════════════ -->
|
|
|
+<!-- 关键设计原则速查 -->
|
|
|
+<!-- ════════════════════════════════════════════════════ -->
|
|
|
+<h2>设计原则速查</h2>
|
|
|
+
|
|
|
+<div class="table-wrap" data-tag="DESIGN PRINCIPLES">
|
|
|
+<table class="matrix">
|
|
|
+ <colgroup><col style="width:280px"/><col style="width:auto"/></colgroup>
|
|
|
+ <tbody>
|
|
|
+ <tr><td class="new">代码 vs 知识 分离</td><td>工具 / 数据(代码)是<strong>确定性</strong>的,复用零风险;Skill(LLM 推理框架)是<strong>启发式</strong>的,共用会污染。Q5/Q6 改方向的核心理由。</td></tr>
|
|
|
+ <tr><td class="new">分离但不盲</td><td>两个子系统通过文件系统通信,**最小耦合**:新建启动只读调控当日 latest_decisions 黑名单,避免给即将 pause 的广告补创意。</td></tr>
|
|
|
+ <tr><td class="new">L1 / L2 / L3 三层分工</td><td>L1 候选标记(代码,可单测)/ L2 LLM skill(启发式)/ L3 兜底护栏(代码,边界)。两子系统共用这套分工模式。</td></tr>
|
|
|
+ <tr><td class="new">YAGNI 严格执行</td><td>本期不做 reshuffle / 重度 AI 改写 / 跨账户素材 / 调控读新建 / 联合审批 / 学习期细粒度保护。接口预留,实现等下期。</td></tr>
|
|
|
+ <tr><td class="new">深度思考补全(全启用)</td><td>tier 级护栏 · 渐进式挂创意(≤5/次)· 7 日累计上限 · 出价基准三层降级 · 关联点过滤 · confidence 量纲校准。</td></tr>
|
|
|
+ <tr><td class="new">回滚边界清晰</td><td>新建子系统失败 → 删 execute_creation_once.py 即可;CREATION_ENABLED=False 总开关;调控完全不受影响。</td></tr>
|
|
|
+ </tbody>
|
|
|
+</table>
|
|
|
+</div>
|
|
|
+
|
|
|
+<!-- ════════════════════════════════════════════════════ -->
|
|
|
+<footer>
|
|
|
+ <div>auto_put_ad_mini · v2 解耦架构 · brain 独立 · infra 共享</div>
|
|
|
+ <div class="stamp">drafted 2026-06-05 · plan approved · 待实施</div>
|
|
|
+</footer>
|
|
|
+
|
|
|
+</main>
|
|
|
+
|
|
|
+</body>
|
|
|
+</html>
|