| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817 |
- <!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=Fraunces:opsz,wght,SOFT@9..144,300..900,0..100&family=IBM+Plex+Sans:wght@300;400;500;600&family=JetBrains+Mono:wght@400;500;700&family=Noto+Serif+SC:wght@400;500;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
- <style>
- :root {
- --bg: #0E141B;
- --bg-alt: #141C26;
- --panel: #1A2330;
- --panel-hi: #212C3D;
- --border: #2A3849;
- --border-hi: #3D5066;
- --text: #E8E1D3;
- --text-dim: #B8B0A1;
- --text-muted: #7A8294;
- --grid: #1F2A38;
- --tools: #E0A458;
- --tools-soft: #E0A45822;
- --skills: #A4B494;
- --skills-soft: #A4B49422;
- --decisions: #5BC0BE;
- --decisions-soft: #5BC0BE22;
- --rules: #F25F5C;
- --rules-soft: #F25F5C22;
- --data: #6B9FB5;
- --data-soft: #6B9FB522;
- --gold: #D4AF37;
- --serif: "Fraunces", "Noto Serif SC", Georgia, serif;
- --sans: "IBM Plex Sans", "Noto Sans SC", system-ui, sans-serif;
- --mono: "JetBrains Mono", "SF Mono", Consolas, monospace;
- }
- * { box-sizing: border-box; margin: 0; padding: 0; }
- html { scroll-behavior: smooth; }
- body {
- background: var(--bg);
- color: var(--text);
- font-family: var(--sans);
- font-weight: 400;
- line-height: 1.6;
- letter-spacing: 0.005em;
- min-height: 100vh;
- overflow-x: hidden;
- background-image:
- radial-gradient(at 20% 0%, rgba(91, 192, 190, 0.08) 0px, transparent 40%),
- radial-gradient(at 80% 100%, rgba(224, 164, 88, 0.06) 0px, transparent 50%),
- linear-gradient(0deg, var(--bg) 0%, #0A0F15 100%);
- }
- /* Subtle grain overlay */
- body::before {
- content: "";
- position: fixed;
- inset: 0;
- pointer-events: none;
- z-index: 1;
- opacity: 0.025;
- 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.9' /%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
- }
- main { position: relative; z-index: 2; }
- /* ====== HEADER ====== */
- .hero {
- padding: 80px 60px 100px;
- border-bottom: 1px solid var(--border);
- position: relative;
- overflow: hidden;
- }
- .hero::before {
- content: "";
- position: absolute;
- inset: 0;
- background:
- repeating-linear-gradient(0deg, transparent 0, transparent 49px, var(--grid) 49px, var(--grid) 50px),
- repeating-linear-gradient(90deg, transparent 0, transparent 49px, var(--grid) 49px, var(--grid) 50px);
- opacity: 0.4;
- pointer-events: none;
- mask-image: radial-gradient(ellipse at 30% 50%, black 30%, transparent 80%);
- }
- .hero-inner { position: relative; max-width: 1400px; margin: 0 auto; }
- .eyebrow {
- font-family: var(--mono);
- font-size: 11px;
- text-transform: uppercase;
- letter-spacing: 0.25em;
- color: var(--tools);
- margin-bottom: 28px;
- display: flex;
- align-items: center;
- gap: 12px;
- }
- .eyebrow::before {
- content: "";
- display: block;
- width: 32px;
- height: 1px;
- background: var(--tools);
- }
- h1.title {
- font-family: var(--serif);
- font-weight: 300;
- font-size: clamp(48px, 8vw, 112px);
- line-height: 0.95;
- letter-spacing: -0.03em;
- color: var(--text);
- margin-bottom: 24px;
- font-feature-settings: "ss01", "ss02";
- font-variation-settings: "opsz" 144, "SOFT" 30;
- }
- h1.title em {
- font-style: italic;
- color: var(--tools);
- font-variation-settings: "opsz" 144, "SOFT" 100;
- }
- .tagline {
- font-family: var(--serif);
- font-size: 24px;
- font-weight: 300;
- font-style: italic;
- color: var(--text-dim);
- max-width: 720px;
- margin-bottom: 48px;
- line-height: 1.4;
- font-variation-settings: "opsz" 24;
- }
- .meta-grid {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
- gap: 32px 48px;
- padding-top: 32px;
- border-top: 1px solid var(--border);
- max-width: 1100px;
- }
- .meta-item {
- display: flex;
- flex-direction: column;
- gap: 6px;
- }
- .meta-label {
- font-family: var(--mono);
- font-size: 10px;
- text-transform: uppercase;
- letter-spacing: 0.18em;
- color: var(--text-muted);
- }
- .meta-value {
- font-family: var(--mono);
- font-size: 14px;
- color: var(--text);
- font-weight: 500;
- }
- .meta-value.accent { color: var(--tools); }
- /* ====== SECTIONS ====== */
- section {
- padding: 100px 60px;
- max-width: 1400px;
- margin: 0 auto;
- border-bottom: 1px solid var(--border);
- }
- .section-head {
- display: flex;
- align-items: baseline;
- justify-content: space-between;
- margin-bottom: 60px;
- gap: 40px;
- flex-wrap: wrap;
- }
- .section-num {
- font-family: var(--mono);
- font-size: 13px;
- color: var(--text-muted);
- letter-spacing: 0.2em;
- }
- .section-title {
- font-family: var(--serif);
- font-weight: 300;
- font-size: clamp(36px, 5vw, 64px);
- line-height: 1.05;
- letter-spacing: -0.02em;
- flex: 1;
- font-variation-settings: "opsz" 96, "SOFT" 40;
- }
- .section-title em {
- font-style: italic;
- font-variation-settings: "opsz" 96, "SOFT" 100;
- }
- .section-title.tools em { color: var(--tools); }
- .section-title.skills em { color: var(--skills); }
- .section-title.decisions em { color: var(--decisions); }
- .section-title.rules em { color: var(--rules); }
- .section-title.data em { color: var(--data); }
- .section-desc {
- font-family: var(--serif);
- font-style: italic;
- font-size: 16px;
- color: var(--text-dim);
- max-width: 480px;
- font-weight: 300;
- line-height: 1.5;
- }
- /* ====== ARCHITECTURE LAYERS ====== */
- .layer-stack {
- display: grid;
- gap: 24px;
- }
- .layer {
- display: grid;
- grid-template-columns: 180px 1fr;
- gap: 32px;
- padding: 32px 36px;
- background: var(--panel);
- border: 1px solid var(--border);
- border-left-width: 3px;
- position: relative;
- transition: all 0.3s ease;
- }
- .layer:hover {
- background: var(--panel-hi);
- border-left-width: 6px;
- }
- .layer-1 { border-left-color: var(--tools); }
- .layer-2 { border-left-color: var(--skills); }
- .layer-3 { border-left-color: var(--decisions); }
- .layer-4 { border-left-color: var(--rules); }
- .layer-id {
- font-family: var(--mono);
- font-size: 12px;
- letter-spacing: 0.15em;
- color: var(--text-muted);
- text-transform: uppercase;
- margin-bottom: 8px;
- }
- .layer-name {
- font-family: var(--serif);
- font-size: 28px;
- font-weight: 400;
- line-height: 1.1;
- letter-spacing: -0.01em;
- font-variation-settings: "opsz" 32;
- }
- .layer-content { font-size: 14px; line-height: 1.7; }
- .layer-content code {
- font-family: var(--mono);
- font-size: 12.5px;
- color: var(--tools);
- background: var(--bg-alt);
- padding: 2px 6px;
- border-radius: 2px;
- }
- .layer-content ul {
- list-style: none;
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
- gap: 12px;
- margin-top: 8px;
- }
- .layer-content ul li {
- padding: 10px 14px;
- background: var(--bg-alt);
- border-left: 2px solid var(--border-hi);
- font-size: 13px;
- color: var(--text-dim);
- }
- .layer-content ul li strong {
- color: var(--text);
- font-weight: 500;
- }
- /* ====== PIPELINE ====== */
- .pipeline {
- display: grid;
- gap: 0;
- position: relative;
- }
- .pipeline-step {
- display: grid;
- grid-template-columns: 80px 1fr 280px;
- gap: 32px;
- padding: 32px 0;
- border-top: 1px solid var(--border);
- position: relative;
- transition: background 0.25s ease;
- }
- .pipeline-step:hover { background: rgba(91, 192, 190, 0.03); }
- .pipeline-step:last-child { border-bottom: 1px solid var(--border); }
- .step-num {
- font-family: var(--serif);
- font-style: italic;
- font-size: 88px;
- line-height: 0.9;
- font-weight: 300;
- color: var(--decisions);
- letter-spacing: -0.04em;
- font-variation-settings: "opsz" 144, "SOFT" 80;
- opacity: 0.85;
- }
- .step-body { padding-top: 16px; }
- .step-name {
- font-family: var(--serif);
- font-size: 26px;
- font-weight: 400;
- margin-bottom: 8px;
- letter-spacing: -0.01em;
- font-variation-settings: "opsz" 32;
- }
- .step-tool {
- display: inline-block;
- font-family: var(--mono);
- font-size: 11.5px;
- color: var(--tools);
- background: var(--tools-soft);
- padding: 3px 10px;
- margin-bottom: 14px;
- border: 1px solid var(--tools);
- border-radius: 2px;
- }
- .step-desc {
- font-size: 14.5px;
- color: var(--text-dim);
- line-height: 1.65;
- max-width: 600px;
- }
- .step-io {
- padding-top: 18px;
- font-family: var(--mono);
- font-size: 11.5px;
- color: var(--text-muted);
- display: grid;
- gap: 6px;
- }
- .step-io span {
- display: flex;
- gap: 8px;
- }
- .step-io span::before {
- content: "→";
- color: var(--data);
- font-weight: bold;
- }
- .step-io.input span::before { content: "↓"; color: var(--data); }
- .step-io.output span::before { content: "↑"; color: var(--decisions); }
- /* ====== SKILLS GRID ====== */
- .skills-grid {
- display: grid;
- grid-template-columns: repeat(2, 1fr);
- gap: 4px;
- background: var(--border);
- border: 1px solid var(--border);
- }
- .skill-card {
- background: var(--panel);
- padding: 36px 36px 32px;
- position: relative;
- transition: all 0.3s ease;
- cursor: default;
- }
- .skill-card:hover {
- background: var(--panel-hi);
- transform: translateZ(0);
- }
- .skill-card.featured {
- grid-column: span 2;
- background: linear-gradient(135deg, var(--panel) 0%, #1F2A36 100%);
- }
- .skill-rank {
- position: absolute;
- top: 24px;
- right: 28px;
- font-family: var(--mono);
- font-size: 11px;
- letter-spacing: 0.15em;
- color: var(--text-muted);
- text-transform: uppercase;
- }
- .skill-rank.core {
- color: var(--gold);
- }
- .skill-rank.core::before {
- content: "◆ ";
- color: var(--gold);
- }
- .skill-name {
- font-family: var(--mono);
- font-size: 13px;
- letter-spacing: 0.1em;
- color: var(--skills);
- margin-bottom: 14px;
- }
- .skill-headline {
- font-family: var(--serif);
- font-size: 28px;
- font-weight: 400;
- line-height: 1.15;
- letter-spacing: -0.01em;
- margin-bottom: 16px;
- font-variation-settings: "opsz" 32, "SOFT" 30;
- }
- .skill-card.featured .skill-headline {
- font-size: 36px;
- font-style: italic;
- font-variation-settings: "opsz" 48, "SOFT" 80;
- }
- .skill-meta {
- font-family: var(--mono);
- font-size: 11px;
- color: var(--text-muted);
- margin-bottom: 18px;
- letter-spacing: 0.05em;
- }
- .skill-desc {
- font-size: 14px;
- color: var(--text-dim);
- line-height: 1.7;
- margin-bottom: 20px;
- }
- .skill-sections {
- display: flex;
- flex-wrap: wrap;
- gap: 6px;
- }
- .skill-tag {
- font-family: var(--mono);
- font-size: 10.5px;
- padding: 4px 10px;
- background: var(--bg-alt);
- color: var(--text-dim);
- border: 1px solid var(--border);
- letter-spacing: 0.03em;
- }
- .skill-card.featured .skill-tag {
- border-color: var(--decisions);
- color: var(--decisions);
- }
- /* ====== TOOLS NETWORK ====== */
- .tools-table {
- display: grid;
- grid-template-columns: 1fr;
- gap: 0;
- border: 1px solid var(--border);
- background: var(--panel);
- }
- .tools-row {
- display: grid;
- grid-template-columns: 240px 200px 1fr 140px;
- gap: 24px;
- padding: 18px 28px;
- border-bottom: 1px solid var(--border);
- align-items: center;
- transition: background 0.2s;
- }
- .tools-row:last-child { border-bottom: none; }
- .tools-row:hover { background: var(--panel-hi); }
- .tools-row.head {
- background: var(--bg-alt);
- border-bottom: 2px solid var(--border-hi);
- }
- .tools-row.head > div {
- font-family: var(--mono);
- font-size: 10.5px;
- text-transform: uppercase;
- letter-spacing: 0.18em;
- color: var(--text-muted);
- }
- .tool-file {
- font-family: var(--mono);
- font-size: 13px;
- color: var(--tools);
- }
- .tool-cat {
- font-family: var(--mono);
- font-size: 11.5px;
- letter-spacing: 0.05em;
- text-transform: uppercase;
- }
- .tool-cat.data { color: var(--data); }
- .tool-cat.compute { color: var(--decisions); }
- .tool-cat.decide { color: var(--skills); }
- .tool-cat.execute { color: var(--rules); }
- .tool-cat.report { color: var(--gold); }
- .tool-fn {
- font-size: 13px;
- color: var(--text-dim);
- line-height: 1.6;
- }
- .tool-fn code {
- font-family: var(--mono);
- font-size: 12px;
- color: var(--text);
- background: var(--bg);
- padding: 1px 6px;
- border-radius: 2px;
- }
- .tool-step {
- font-family: var(--mono);
- font-size: 11px;
- color: var(--text-muted);
- text-align: right;
- }
- /* ====== DECISION FRAMEWORK ====== */
- .decision-arch {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 60px;
- align-items: start;
- }
- .decision-tower {
- display: grid;
- gap: 12px;
- }
- .tier {
- position: relative;
- padding: 28px 32px;
- background: var(--panel);
- border: 1px solid var(--border);
- }
- .tier::before {
- content: "";
- position: absolute;
- left: 0;
- top: 0;
- bottom: 0;
- width: 4px;
- }
- .tier-1::before { background: var(--rules); }
- .tier-2::before { background: var(--data); }
- .tier-3::before { background: var(--decisions); }
- .tier-4::before { background: var(--skills); }
- .tier-label {
- font-family: var(--mono);
- font-size: 11px;
- letter-spacing: 0.2em;
- margin-bottom: 6px;
- text-transform: uppercase;
- }
- .tier-1 .tier-label { color: var(--rules); }
- .tier-2 .tier-label { color: var(--data); }
- .tier-3 .tier-label { color: var(--decisions); }
- .tier-4 .tier-label { color: var(--skills); }
- .tier-name {
- font-family: var(--serif);
- font-size: 22px;
- font-weight: 400;
- margin-bottom: 8px;
- font-variation-settings: "opsz" 24;
- }
- .tier-desc {
- font-size: 13.5px;
- color: var(--text-dim);
- line-height: 1.65;
- }
- .tier-desc code {
- font-family: var(--mono);
- font-size: 12px;
- color: var(--text);
- background: var(--bg-alt);
- padding: 1px 5px;
- border-radius: 2px;
- }
- /* Actions panel */
- .actions-panel {
- background: var(--panel);
- border: 1px solid var(--border);
- padding: 32px;
- }
- .actions-head {
- font-family: var(--serif);
- font-size: 22px;
- font-weight: 400;
- margin-bottom: 24px;
- font-variation-settings: "opsz" 24;
- }
- .actions-list { display: grid; gap: 14px; }
- .action-row {
- display: grid;
- grid-template-columns: 110px 1fr;
- gap: 16px;
- padding: 12px 0;
- border-bottom: 1px solid var(--border);
- }
- .action-row:last-child { border-bottom: none; }
- .action-name {
- font-family: var(--mono);
- font-size: 13px;
- letter-spacing: 0.05em;
- display: flex;
- align-items: baseline;
- gap: 8px;
- }
- .action-name .dot {
- display: inline-block;
- width: 8px;
- height: 8px;
- border-radius: 50%;
- }
- .action-name.pause .dot { background: var(--rules); }
- .action-name.bid_down .dot { background: #FFA94D; }
- .action-name.bid_up .dot { background: var(--decisions); }
- .action-name.scale_up .dot { background: var(--skills); }
- .action-name.creative_adjust .dot { background: var(--gold); }
- .action-name.observe .dot { background: var(--data); }
- .action-name.hold .dot { background: var(--text-muted); }
- .action-name code {
- color: var(--text);
- }
- .action-rule {
- font-size: 13px;
- color: var(--text-dim);
- line-height: 1.55;
- }
- /* ====== THRESHOLDS ====== */
- .thresholds-grid {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
- gap: 4px;
- background: var(--border);
- border: 1px solid var(--border);
- }
- .threshold-card {
- background: var(--panel);
- padding: 28px;
- position: relative;
- transition: background 0.25s;
- }
- .threshold-card:hover { background: var(--panel-hi); }
- .threshold-key {
- font-family: var(--mono);
- font-size: 11.5px;
- color: var(--text-muted);
- letter-spacing: 0.08em;
- margin-bottom: 14px;
- }
- .threshold-value {
- font-family: var(--serif);
- font-size: 56px;
- font-weight: 300;
- line-height: 1;
- font-style: italic;
- letter-spacing: -0.03em;
- font-variation-settings: "opsz" 96, "SOFT" 100;
- margin-bottom: 6px;
- }
- .threshold-value.tools { color: var(--tools); }
- .threshold-value.decisions { color: var(--decisions); }
- .threshold-value.rules { color: var(--rules); }
- .threshold-value.skills { color: var(--skills); }
- .threshold-unit {
- font-family: var(--mono);
- font-size: 13px;
- color: var(--text-muted);
- margin-left: 6px;
- font-style: normal;
- font-weight: 400;
- }
- .threshold-meaning {
- font-size: 13px;
- color: var(--text-dim);
- line-height: 1.5;
- margin-top: 14px;
- padding-top: 14px;
- border-top: 1px solid var(--border);
- }
- /* ====== DATA FLOW ====== */
- .flow-svg {
- width: 100%;
- height: auto;
- background: var(--panel);
- border: 1px solid var(--border);
- padding: 20px;
- }
- .flow-svg text {
- font-family: var(--mono);
- font-size: 11px;
- fill: var(--text-dim);
- }
- .flow-svg .node {
- fill: var(--bg-alt);
- stroke: var(--border-hi);
- stroke-width: 1;
- }
- .flow-svg .node-data { stroke: var(--data); }
- .flow-svg .node-tool { stroke: var(--tools); }
- .flow-svg .node-decide { stroke: var(--decisions); }
- .flow-svg .node-act { stroke: var(--rules); }
- .flow-svg .label-bold {
- font-family: var(--serif);
- font-size: 13px;
- fill: var(--text);
- font-weight: 500;
- }
- .flow-svg .arrow {
- stroke: var(--border-hi);
- stroke-width: 1.5;
- fill: none;
- marker-end: url(#arrowhead);
- }
- .flow-svg .arrow-data { stroke: var(--data); }
- .flow-svg .arrow-decide { stroke: var(--decisions); }
- /* ====== DEPLOYMENT ====== */
- .deploy-grid {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 32px;
- }
- .deploy-card {
- padding: 32px;
- background: var(--panel);
- border: 1px solid var(--border);
- }
- .deploy-mode {
- font-family: var(--mono);
- font-size: 11px;
- letter-spacing: 0.2em;
- color: var(--gold);
- text-transform: uppercase;
- margin-bottom: 12px;
- }
- .deploy-name {
- font-family: var(--serif);
- font-size: 26px;
- font-weight: 400;
- margin-bottom: 16px;
- font-variation-settings: "opsz" 32;
- }
- .deploy-desc {
- font-size: 14px;
- color: var(--text-dim);
- line-height: 1.7;
- margin-bottom: 20px;
- }
- .deploy-files { display: grid; gap: 6px; }
- .deploy-files code {
- font-family: var(--mono);
- font-size: 12px;
- color: var(--text);
- display: flex;
- align-items: center;
- gap: 12px;
- padding: 8px 12px;
- background: var(--bg-alt);
- border-left: 2px solid var(--gold);
- }
- .deploy-files code span {
- color: var(--text-muted);
- font-size: 11px;
- }
- /* ====== FOOTER ====== */
- footer {
- padding: 60px;
- text-align: center;
- border-top: 1px solid var(--border);
- color: var(--text-muted);
- font-family: var(--mono);
- font-size: 12px;
- letter-spacing: 0.1em;
- position: relative;
- z-index: 2;
- }
- footer p { margin-bottom: 8px; }
- footer .stamp {
- display: inline-block;
- margin-top: 24px;
- padding: 8px 16px;
- border: 1px solid var(--border);
- font-family: var(--serif);
- font-style: italic;
- font-size: 13px;
- letter-spacing: 0.03em;
- color: var(--text-dim);
- }
- /* ====== ANIMATIONS ====== */
- @keyframes fadeUp {
- from { opacity: 0; transform: translateY(20px); }
- to { opacity: 1; transform: translateY(0); }
- }
- .hero-inner > * {
- animation: fadeUp 0.8s ease-out backwards;
- }
- .hero-inner > *:nth-child(1) { animation-delay: 0.05s; }
- .hero-inner > *:nth-child(2) { animation-delay: 0.15s; }
- .hero-inner > *:nth-child(3) { animation-delay: 0.25s; }
- .hero-inner > *:nth-child(4) { animation-delay: 0.35s; }
- /* Responsive */
- @media (max-width: 900px) {
- section, .hero { padding-left: 28px; padding-right: 28px; }
- .layer { grid-template-columns: 1fr; }
- .pipeline-step { grid-template-columns: 60px 1fr; }
- .step-io { grid-column: 1 / -1; padding-left: 0; padding-top: 8px; }
- .skills-grid, .deploy-grid { grid-template-columns: 1fr; }
- .skill-card.featured { grid-column: span 1; }
- .decision-arch { grid-template-columns: 1fr; }
- .tools-row { grid-template-columns: 1fr; gap: 4px; }
- .tools-row > div { padding: 2px 0; }
- .tool-step { text-align: left; }
- }
- </style>
- </head>
- <body>
- <main>
- <!-- ====== HERO ====== -->
- <header class="hero">
- <div class="hero-inner">
- <div class="eyebrow">Reson Agent · 业务示例 · v0.4.27</div>
- <h1 class="title">auto_put_ad<em>_mini</em></h1>
- <p class="tagline">数据驱动的广告调控 Agent —— 把 ODPS 裂变数据、动态 ROI、规则候选与 LLM 综合判断,串成单向链路的 ROI 优化系统。</p>
- <div class="meta-grid">
- <div class="meta-item">
- <span class="meta-label">业务场景</span>
- <span class="meta-value">微信小程序投流</span>
- </div>
- <div class="meta-item">
- <span class="meta-label">承载类型</span>
- <span class="meta-value">MARKETING_CARRIER_TYPE_<br>MINI_PROGRAM_WECHAT</span>
- </div>
- <div class="meta-item">
- <span class="meta-label">出价模式</span>
- <span class="meta-value">BID_MODE_OCPM</span>
- </div>
- <div class="meta-item">
- <span class="meta-label">LLM 后端</span>
- <span class="meta-value accent">OpenRouter · Claude Sonnet 4.5</span>
- </div>
- <div class="meta-item">
- <span class="meta-label">数据窗口</span>
- <span class="meta-value">14 天 / 7 日均值</span>
- </div>
- <div class="meta-item">
- <span class="meta-label">执行开关</span>
- <span class="meta-value">EXECUTION_ENABLED = False</span>
- </div>
- <div class="meta-item">
- <span class="meta-label">入口</span>
- <span class="meta-value">run.py · execute_once.py</span>
- </div>
- <div class="meta-item">
- <span class="meta-label">部署</span>
- <span class="meta-value">K8s CronJob · 02:00 UTC</span>
- </div>
- </div>
- </div>
- </header>
- <!-- ====== 01 · ARCHITECTURE LAYERS ====== -->
- <section id="architecture">
- <div class="section-head">
- <div>
- <div class="section-num">§ 01 — 整体架构</div>
- <h2 class="section-title tools">框架与业务的<em>双层解耦</em></h2>
- </div>
- <p class="section-desc">框架(<code>agent/</code>)只关心 LLM 调度 + 工具调度 + 持久化,完全不感知业务。业务层通过 <code>@tool</code> 装饰器和 <code>.md</code> skill 单向注入,从不反向依赖。</p>
- </div>
- <div class="layer-stack">
- <div class="layer layer-1">
- <div>
- <div class="layer-id">L1 · Framework</div>
- <div class="layer-name">Reson Agent</div>
- </div>
- <div class="layer-content">
- <p>通用 Agent 框架,只读,业务零侵入。</p>
- <ul>
- <li><strong>AgentRunner</strong> · ReAct 主循环 · new/resume/rewind</li>
- <li><strong>ToolRegistry</strong> · @tool 装饰器 + JSON Schema</li>
- <li><strong>SkillLoader</strong> · 扫 .md + frontmatter 注入 prompt</li>
- <li><strong>FileSystemTraceStore</strong> · 持久化 .trace/ + 侧分支</li>
- <li><strong>LLM 适配层</strong> · OpenRouter / Qwen / Gemini</li>
- </ul>
- </div>
- </div>
- <div class="layer layer-2">
- <div>
- <div class="layer-id">L2 · Skills</div>
- <div class="layer-name">领域知识</div>
- </div>
- <div class="layer-content">
- <p>4 份 markdown,启动时注入 system prompt,定义业务术语 + 决策原则 + 平台硬约束。</p>
- <ul>
- <li><strong>ad_domain</strong> · R 值人群 + 裂变变现模型</li>
- <li><strong>platform_rules</strong> · 腾讯平台硬约束(优先级最高)</li>
- <li><strong>decision_strategy</strong> · 7 action 决策框架(核心 19.5K)</li>
- <li><strong>posterior_wisdom</strong> · 后验经验查询入口</li>
- </ul>
- </div>
- </div>
- <div class="layer layer-3">
- <div>
- <div class="layer-id">L3 · Tools</div>
- <div class="layer-name">业务工具</div>
- </div>
- <div class="layer-content">
- <p>10+ 个工具组成 10 步流水线,从数据采集到决策执行单向流转。</p>
- <ul>
- <li><strong>data_query</strong> · ODPS 拉数 + 多日合并</li>
- <li><strong>roi_calculator</strong> · 创意聚合 + 动态 ROI</li>
- <li><strong>portfolio_metrics</strong> · 渠道 P50 + tier 基线</li>
- <li><strong>ad_decision</strong> · 候选标记 + 决策合并</li>
- <li><strong>guardrails</strong> · 护栏校验</li>
- <li><strong>execution_engine</strong> · 分级执行 + 审计</li>
- <li><strong>im_approval</strong> · 飞书审批 + 阻塞 polling</li>
- <li><strong>report_generator</strong> · Excel 决策表</li>
- <li><strong>feishu_doc</strong> · 飞书文档 + IM 推送</li>
- <li><strong>ad_api</strong> · 腾讯广告 API 封装</li>
- </ul>
- </div>
- </div>
- <div class="layer layer-4">
- <div>
- <div class="layer-id">L4 · Config</div>
- <div class="layer-name">硬约束与开关</div>
- </div>
- <div class="layer-content">
- <p>所有阈值、白名单、执行开关集中于 <code>config.py</code>。运行时可被数据库覆盖。</p>
- <ul>
- <li><strong>ROI 阈值</strong> · ROI_LOW_FACTOR = 0.75</li>
- <li><strong>调价边界</strong> · BID_FLOOR/CEILING = 0.05/1.00 元</li>
- <li><strong>年龄保护</strong> · COLD_START_DAYS = 3, EARLY_GROWTH_DAYS = 7</li>
- <li><strong>频率限制</strong> · MAX_ADJUSTMENTS_PER_AD_PER_DAY = 2</li>
- <li><strong>执行开关</strong> · EXECUTION_ENABLED = False</li>
- </ul>
- </div>
- </div>
- </div>
- </section>
- <!-- ====== 02 · PIPELINE ====== -->
- <section id="pipeline">
- <div class="section-head">
- <div>
- <div class="section-num">§ 02 — 数据流水线</div>
- <h2 class="section-title decisions">十步,从 ODPS <em>到飞书</em></h2>
- </div>
- <p class="section-desc">单向链路:数据采集 → 指标计算 → 候选筛选 → LLM 推理 → 决策合并 → 护栏 → 审批 → 执行 → 报告。每步前置依赖严格。</p>
- </div>
- <div class="pipeline">
- <div class="pipeline-step">
- <div class="step-num">01</div>
- <div class="step-body">
- <div class="step-name">fetch_creative_data</div>
- <span class="step-tool">tools/data_query.py</span>
- <p class="step-desc">从 ODPS 表 <code>loghubods.touliu_data</code> 增量拉取 14 天创意级原始数据(消耗、首层打开数、T0 裂变数、总回流人数、总收入)。已存在的日期文件自动跳过。</p>
- </div>
- <div class="step-io">
- <span class="output">outputs/raw/creative_{date}.csv</span>
- <span class="output">outputs/ad_status/ad_status_{date}.csv</span>
- </div>
- </div>
- <div class="pipeline-step">
- <div class="step-num">02</div>
- <div class="step-body">
- <div class="step-name">merge_creative_data</div>
- <span class="step-tool">tools/data_query.py</span>
- <p class="step-desc">每日 raw + 广告状态做 left join,前置过滤 DELETED/SUSPEND 状态。生成单日 merged CSV。</p>
- </div>
- <div class="step-io">
- <span class="output">outputs/merged/merged_{date}.csv</span>
- </div>
- </div>
- <div class="pipeline-step">
- <div class="step-num">03</div>
- <div class="step-body">
- <div class="step-name">calculate_roi_metrics</div>
- <span class="step-tool">tools/roi_calculator.py</span>
- <p class="step-desc">加载 30 天 merged · 创意 → 广告聚合 · 计算 <code>动态ROI = 当日裂变收益率 × 裂变效率稳定因子</code> · 7 日滚动均值(min_periods=3)· 日消耗 < 100 元的天数标 NaN 不入均值。<strong>含临时 TEMP 块过滤近 7 天累计消耗 = 0 的广告</strong>。</p>
- </div>
- <div class="step-io">
- <span class="output">outputs/metrics_{date}.csv (广告级)</span>
- </div>
- </div>
- <div class="pipeline-step">
- <div class="step-num">04</div>
- <div class="step-body">
- <div class="step-name">portfolio_metrics</div>
- <span class="step-tool">tools/portfolio_metrics.py</span>
- <p class="step-desc">在 calculate_roi_metrics 内自动调用。计算渠道 P25/P50/P75 ROI 基线 + 人群包(tier)级 fission/CTR/bid 均值,作为决策对比基准。</p>
- </div>
- <div class="step-io">
- <span class="output">outputs/portfolio_summary/portfolio_summary_{date}.json</span>
- </div>
- </div>
- <div class="pipeline-step">
- <div class="step-num">05</div>
- <div class="step-body">
- <div class="step-name">get_ads_for_review</div>
- <span class="step-tool">tools/ad_decision.py</span>
- <p class="step-desc">三层分类:零消耗待关停 / 候选广告 / 正常运行。计算 5 个候选标记:<code>roi_low</code>、<code>decay_signal</code>、<code>bid_up_candidate</code>(双分支)、<code>bid_down_candidate</code>、<code>scale_up_candidate</code>。年龄保护:≤3 天剔除,4-7 天屏蔽负向标记。按 audience_tier 分批返回。</p>
- </div>
- <div class="step-io">
- <span class="output">JSON: tier_batches[ ]</span>
- </div>
- </div>
- <div class="pipeline-step">
- <div class="step-num">06</div>
- <div class="step-body">
- <div class="step-name">LLM 推理(分批)</div>
- <span class="step-tool">主 Agent</span>
- <p class="step-desc">按 tier 分批调用,降低单次输入 60-80%(避免 lost in the middle)。每批 LLM 输出决策 JSON 数组(<code>action</code>/<code>dimension</code>/<code>reason</code>/<code>confidence</code>/<code>recommended_change_pct</code>)。<strong>禁止多次调 apply_decisions</strong>(后调吞前调)。</p>
- </div>
- <div class="step-io">
- <span class="output">JSON 累积数组(全部 tier)</span>
- </div>
- </div>
- <div class="pipeline-step">
- <div class="step-num">07</div>
- <div class="step-body">
- <div class="step-name">apply_decisions</div>
- <span class="step-tool">tools/ad_decision.py</span>
- <p class="step-desc">合并三类决策来源:零消耗自动关停(规则) + LLM 输出(主) + 正常运行兜底 hold(规则)。<strong>左连接 metrics CSV 补全</strong>(ad_name / ad_age_days / cost_7d_avg / 动态ROI / audience_tier 等 20+ 字段)。</p>
- </div>
- <div class="step-io">
- <span class="output">outputs/reports/llm_decisions_{date}.csv</span>
- </div>
- </div>
- <div class="pipeline-step">
- <div class="step-num">08</div>
- <div class="step-body">
- <div class="step-name">validate_decisions</div>
- <span class="step-tool">tools/guardrails.py</span>
- <p class="step-desc">护栏校验:冷启动保护、出价上下界(0.05-1.00 元)、单日调整频率(≤2 次)、单次累计变化(≤20%)、数据新鲜度(≤96h)。失败的决策会被强制改 hold + 记录原因。</p>
- </div>
- <div class="step-io">
- <span class="output">outputs/reports/validated_decisions_{date}.csv</span>
- </div>
- </div>
- <div class="pipeline-step">
- <div class="step-num">09</div>
- <div class="step-body">
- <div class="step-name">send_approval_request</div>
- <span class="step-tool">tools/im_approval.py · feishu_doc.py</span>
- <p class="step-desc">前置过滤 <code>FEISHU_EXCLUDE_ACTIONS = {hold, observe, scale_up, bid_up}</code>(消息和表格用同一份过滤后数据,数字一致)。生成审批 xlsx 上传飞书文档,带预览链接的卡片推送给操作员私聊 + 项目群,阻塞轮询 chat_history 等回复(超时 120 分钟)。</p>
- </div>
- <div class="step-io">
- <span class="output">飞书 sheets URL · approvals/{request_id}/</span>
- </div>
- </div>
- <div class="pipeline-step">
- <div class="step-num">10</div>
- <div class="step-body">
- <div class="step-name">execute_decisions + send_feishu_text_message</div>
- <span class="step-tool">tools/execution_engine.py · ad_api.py</span>
- <p class="step-desc">分级执行(tier 1 自动 / tier 2-3 审批通过)。<code>EXECUTION_ENABLED=False</code> 时仅 log 不调腾讯 API。完成后发送简单文字摘要("已执行 N 条:关停 X / 降价 Y"),不再发完整报告。</p>
- </div>
- <div class="step-io">
- <span class="output">outputs/execution_log/{date}.csv</span>
- <span class="output">飞书文字消息</span>
- </div>
- </div>
- </div>
- </section>
- <!-- ====== 03 · SKILLS ====== -->
- <section id="skills">
- <div class="section-head">
- <div>
- <div class="section-num">§ 03 — 领域知识(Skills)</div>
- <h2 class="section-title skills">注入 prompt 的<em>四份手册</em></h2>
- </div>
- <p class="section-desc">.md + YAML frontmatter,框架启动时按 <code>name</code> 索引,内容拼接到 system prompt 末尾。冲突优先级:platform-rules > decision-strategy > posterior-wisdom > ad-domain。</p>
- </div>
- <div class="skills-grid">
- <div class="skill-card featured">
- <span class="skill-rank core">CORE</span>
- <div class="skill-name">decision_strategy.md</div>
- <h3 class="skill-headline">决策的判断框架与 reason 输出规范</h3>
- <div class="skill-meta">19.5 KB · 约 570 行 · 决策 80% 重量</div>
- <p class="skill-desc">真正的"作战手册"。三层架构(规则候选 → LLM → 输出规范),三维对比基准(ROI 看渠道P50,裂变看同类,CTR 看同类),7 种 action 详解 × 触发前提 × 综合权衡 × pct 要求 × 禁用场景。reason 5 元组模板 + 提交前自检 5 问。</p>
- <div class="skill-sections">
- <span class="skill-tag">§一 · 角色与原则</span>
- <span class="skill-tag">§二 · 候选标记解读</span>
- <span class="skill-tag">§三 · 年龄策略</span>
- <span class="skill-tag">§四 · 决策思考 5 步</span>
- <span class="skill-tag">§五 · 7 action 详解</span>
- <span class="skill-tag">§六 · 多因素权衡 + 冲突表</span>
- <span class="skill-tag">§七 · 输出规范 + 自检</span>
- </div>
- </div>
- <div class="skill-card">
- <span class="skill-rank">DOMAIN</span>
- <div class="skill-name">ad_domain.md</div>
- <h3 class="skill-headline">微信小程序投流的业务模型</h3>
- <div class="skill-meta">6.5 KB · 业务知识基底</div>
- <p class="skill-desc">解释裂变变现模型("每一层都在变现",非线性漏斗)、R 值人群含义(R500/R330+/R330/R180/R100/R50/R10/R2 的带人能力 + 投放单价 + 当日 ROI 表现)、动态 ROI 公式与字段定义。</p>
- <div class="skill-sections">
- <span class="skill-tag">变现模型</span>
- <span class="skill-tag">R 值对照表</span>
- <span class="skill-tag">动态 ROI 公式</span>
- <span class="skill-tag">字段定义</span>
- </div>
- </div>
- <div class="skill-card">
- <span class="skill-rank">PLATFORM</span>
- <div class="skill-name">platform_rules.md</div>
- <h3 class="skill-headline">腾讯广告平台硬约束</h3>
- <div class="skill-meta">5.3 KB · 优先级最高</div>
- <p class="skill-desc">oCPM 学习期(前 5 转化 / 24h 内 ≤2 次调整)、调价幅度上限(单次 ≤30%)、少广告多素材策略(单广告创意数 ≥5)、素材疲劳识别、数据口径(T+1 而非实时)、API QPS 与批量限制。</p>
- <div class="skill-sections">
- <span class="skill-tag">学习期保护</span>
- <span class="skill-tag">调价上限</span>
- <span class="skill-tag">数据口径</span>
- <span class="skill-tag">API 约束</span>
- </div>
- </div>
- <div class="skill-card">
- <span class="skill-rank">POSTERIOR</span>
- <div class="skill-name">posterior_wisdom.md</div>
- <h3 class="skill-headline">后验经验查询入口</h3>
- <div class="skill-meta">0.8 KB · 待积累</div>
- <p class="skill-desc">通过 <code>ask_knowledge()</code> 查询历史投放案例。当前系统尚未积累足够后验数据,提供查询模板:周期性效应、调价效果、人群包对比、异常模式、创意冷启动等。</p>
- <div class="skill-sections">
- <span class="skill-tag">ask_knowledge</span>
- <span class="skill-tag">查询模板</span>
- </div>
- </div>
- </div>
- </section>
- <!-- ====== 04 · TOOLS ====== -->
- <section id="tools">
- <div class="section-head">
- <div>
- <div class="section-num">§ 04 — 工具清单</div>
- <h2 class="section-title tools">十二个 <em>tool</em> · 按数据流向排序</h2>
- </div>
- <p class="section-desc">每个工具用 <code>@tool</code> 装饰注册到 ToolRegistry,JSON Schema 自动生成。隐藏参数(context、trace_id)由 Runner 注入,LLM 看不到。</p>
- </div>
- <div class="tools-table">
- <div class="tools-row head">
- <div>文件 / 函数</div>
- <div>分类</div>
- <div>职责</div>
- <div>所属步骤</div>
- </div>
- <div class="tools-row">
- <div class="tool-file">data_query.py</div>
- <div class="tool-cat data">DATA</div>
- <div class="tool-fn"><code>fetch_creative_data</code> + <code>merge_creative_data</code> · 从 ODPS 拉创意级原始数据,合并多日 + 广告状态。</div>
- <div class="tool-step">Step 01—02</div>
- </div>
- <div class="tools-row">
- <div class="tool-file">roi_calculator.py</div>
- <div class="tool-cat compute">COMPUTE</div>
- <div class="tool-fn"><code>calculate_roi_metrics</code> · 创意 → 广告聚合,计算动态 ROI(7 日均值 + 裂变效率稳定因子)。</div>
- <div class="tool-step">Step 03</div>
- </div>
- <div class="tools-row">
- <div class="tool-file">portfolio_metrics.py</div>
- <div class="tool-cat compute">COMPUTE</div>
- <div class="tool-fn"><code>_describe_group</code> + <code>_compute_daily_tier_snapshot</code> + <code>_compute_market_signal</code> · 渠道 P25/P50/P75 + tier 均值,作为决策基线。</div>
- <div class="tool-step">Step 04</div>
- </div>
- <div class="tools-row">
- <div class="tool-file">ad_decision.py</div>
- <div class="tool-cat decide">DECIDE</div>
- <div class="tool-fn"><code>get_ads_for_review</code> + <code>apply_decisions</code> + <code>query_ad_detail</code> + <code>modify_decisions</code> · 候选标记 + 三层分类 + LLM 决策合并。</div>
- <div class="tool-step">Step 05, 07</div>
- </div>
- <div class="tools-row">
- <div class="tool-file">guardrails.py</div>
- <div class="tool-cat decide">VALIDATE</div>
- <div class="tool-fn"><code>validate_decisions</code> · 冷启动 / 出价边界 / 频率 / 数据新鲜度 多重护栏校验,失败强制改 hold。</div>
- <div class="tool-step">Step 08</div>
- </div>
- <div class="tools-row">
- <div class="tool-file">execution_engine.py</div>
- <div class="tool-cat execute">EXECUTE</div>
- <div class="tool-fn"><code>execute_decisions</code> + <code>_classify_tier</code> · 分级执行,EXECUTION_ENABLED 控制是否真改腾讯 API。</div>
- <div class="tool-step">Step 10</div>
- </div>
- <div class="tools-row">
- <div class="tool-file">im_approval.py</div>
- <div class="tool-cat execute">EXECUTE</div>
- <div class="tool-fn"><code>send_approval_request</code> + <code>send_feishu_text_message</code> · 飞书审批阻塞轮询,FEISHU_EXCLUDE_ACTIONS 前置过滤。</div>
- <div class="tool-step">Step 09—10</div>
- </div>
- <div class="tools-row">
- <div class="tool-file">report_generator.py</div>
- <div class="tool-cat report">REPORT</div>
- <div class="tool-fn"><code>generate_report</code> · 带条件格式的 Excel 决策表(action 颜色编码)。</div>
- <div class="tool-step">Step 10</div>
- </div>
- <div class="tools-row">
- <div class="tool-file">feishu_doc.py</div>
- <div class="tool-cat report">REPORT</div>
- <div class="tool-fn"><code>import_to_feishu</code> · 上传 xlsx 到飞书文档,设置权限,带预览链接的 IM 卡片推送。</div>
- <div class="tool-step">Step 09</div>
- </div>
- <div class="tools-row">
- <div class="tool-file">ad_api.py</div>
- <div class="tool-cat execute">EXECUTE</div>
- <div class="tool-fn">腾讯广告 Marketing API v3.0 封装(/v3.0/adgroups/get / update),指数退避 + 操作幂等键。</div>
- <div class="tool-step">Step 10</div>
- </div>
- <div class="tools-row">
- <div class="tool-file">creative_metrics.py</div>
- <div class="tool-cat compute">COMPUTE</div>
- <div class="tool-fn">创意级数据指标聚合,服务于 ROI 计算上游。</div>
- <div class="tool-step">Step 03 (内部)</div>
- </div>
- <div class="tools-row">
- <div class="tool-file">odps_module.py</div>
- <div class="tool-cat data">DATA</div>
- <div class="tool-fn">ODPS 客户端封装,SQL 模板执行 + tunnel session 下载。</div>
- <div class="tool-step">Step 01 (内部)</div>
- </div>
- </div>
- </section>
- <!-- ====== 05 · DECISION FRAMEWORK ====== -->
- <section id="decision">
- <div class="section-head">
- <div>
- <div class="section-num">§ 05 — 决策框架</div>
- <h2 class="section-title decisions">规则与 LLM 的<em>四层协作</em></h2>
- </div>
- <p class="section-desc">规则定"是否评估",LLM 定"如何操作"。年龄保护是硬约束,候选标记决定进入 LLM 的范围,LLM 在已限定的边界内做综合判断,兜底层覆盖未决策广告。</p>
- </div>
- <div class="decision-arch">
- <div class="decision-tower">
- <div class="tier tier-1">
- <div class="tier-label">L1 · Hard Gate</div>
- <div class="tier-name">年龄保护(硬约束)</div>
- <p class="tier-desc">≤<code>COLD_START_DAYS</code>(3 天):完全剔除,不评估。<br>4-<code>EARLY_GROWTH_DAYS</code>(7 天):屏蔽 <code>roi_low</code> / <code>decay_signal</code> / <code>bid_down_candidate</code>,只放过提价/扩量信号。</p>
- </div>
- <div class="tier tier-2">
- <div class="tier-label">L2 · Rule</div>
- <div class="tier-name">候选标记(5 个 flag)</div>
- <p class="tier-desc">规则层在 <code>get_ads_for_review</code> 中输出 <code>roi_low</code> / <code>decay_signal</code> / <code>bid_up_candidate</code>(双分支:唤醒沉默 + 优质放量) / <code>bid_down_candidate</code> / <code>scale_up_candidate</code>。决定哪些广告进入 LLM。</p>
- </div>
- <div class="tier tier-3">
- <div class="tier-label">L3 · LLM</div>
- <div class="tier-name">综合判断(7 action)</div>
- <p class="tier-desc">LLM 看候选标记 + 同类基线 + 调价历史 + tier 组合,从 7 种 action 中选一个 + 写 reason(5 元组规范)。可"越权":如规则没标但有强烈信号。</p>
- </div>
- <div class="tier tier-4">
- <div class="tier-label">L4 · Fallback</div>
- <div class="tier-name">兜底检查(规则)</div>
- <p class="tier-desc"><code>apply_decisions</code> 末尾,所有未被 LLM 覆盖的广告自动归 <code>hold</code>(<code>source=规则判断</code>)。确保所有候选都有决策落盘,无遗漏。</p>
- </div>
- </div>
- <div class="actions-panel">
- <div class="actions-head">7 种 Action 触发条件</div>
- <div class="actions-list">
- <div class="action-row">
- <div class="action-name pause"><span class="dot"></span><code>pause</code></div>
- <div class="action-rule"><code>roi_low=True</code> + LLM 综合判断(双低/调价无效);或 7 日均消耗<10 自动关停。pct = 0。</div>
- </div>
- <div class="action-row">
- <div class="action-name bid_down"><span class="dot"></span><code>bid_down</code></div>
- <div class="action-rule"><code>bid_down_candidate=True</code> + 裂变低于同类 + 成熟期 + 7 日均消耗 ≥500。pct ∈ [-5%, -3%]。</div>
- </div>
- <div class="action-row">
- <div class="action-name bid_up"><span class="dot"></span><code>bid_up</code></div>
- <div class="action-rule"><code>bid_up_candidate=True</code>(仅 4-7 天)。分支 A 唤醒沉默(低消耗 + CTR 正常)/ 分支 B 优质放量(高 ROI + 高裂变)。pct ∈ [+5%, +10%]。</div>
- </div>
- <div class="action-row">
- <div class="action-name scale_up"><span class="dot"></span><code>scale_up</code></div>
- <div class="action-rule"><code>scale_up_candidate=True</code>(成熟 >7 天 + 稳定 ≥7 天 + 高消耗 >1000 + ROI ≥ P50×0.9)。pct = 0(由运营新增广告/创意)。</div>
- </div>
- <div class="action-row">
- <div class="action-name creative_adjust"><span class="dot"></span><code>creative_adjust</code></div>
- <div class="action-rule">ROI 达标但消耗起不来 / CTR + CVR 同跌(素材疲劳)/ 已换创意但裂变仍低。pct = 0,人工换素材。</div>
- </div>
- <div class="action-row">
- <div class="action-name observe"><span class="dot"></span><code>observe</code></div>
- <div class="action-rule">数据不充分(roi_valid_days <5)/ 7 天内已调价(等效果显现)/ 信号冲突(ROI 低但裂变好)。pct = 0。</div>
- </div>
- <div class="action-row">
- <div class="action-name hold"><span class="dot"></span><code>hold</code></div>
- <div class="action-rule">无异常信号(默认兜底)。pct = 0。</div>
- </div>
- </div>
- </div>
- </div>
- </section>
- <!-- ====== 06 · THRESHOLDS ====== -->
- <section id="thresholds">
- <div class="section-head">
- <div>
- <div class="section-num">§ 06 — 关键阈值</div>
- <h2 class="section-title rules">决策的<em>数值边界</em></h2>
- </div>
- <p class="section-desc">所有阈值集中在 <code>config.py</code>,部分可被数据库 <code>tencent_ad_autoput.config</code> 表覆盖。修改前应通过 evaluation 验证。</p>
- </div>
- <div class="thresholds-grid">
- <div class="threshold-card">
- <div class="threshold-key">ROI_LOW_FACTOR</div>
- <div class="threshold-value rules">0.75</div>
- <p class="threshold-meaning">关停线乘子 · 动态ROI < 渠道P50×0.75 → 候选关停</p>
- </div>
- <div class="threshold-card">
- <div class="threshold-key">BID_DOWN_ROI_FACTOR</div>
- <div class="threshold-value tools">0.90</div>
- <p class="threshold-meaning">降价线乘子 · ROI < P50×0.90 + 裂变低 → 候选降价</p>
- </div>
- <div class="threshold-card">
- <div class="threshold-key">BID_UP_ROI_FACTOR</div>
- <div class="threshold-value decisions">1.05</div>
- <p class="threshold-meaning">提价线乘子 · ROI > P50×1.05 + 早期成长期 → 候选提价</p>
- </div>
- <div class="threshold-card">
- <div class="threshold-key">COLD_START_DAYS</div>
- <div class="threshold-value rules">3 <span class="threshold-unit">天</span></div>
- <p class="threshold-meaning">冷启动期 · 完全保护,不评估,不调整</p>
- </div>
- <div class="threshold-card">
- <div class="threshold-key">EARLY_GROWTH_DAYS</div>
- <div class="threshold-value skills">7 <span class="threshold-unit">天</span></div>
- <p class="threshold-meaning">早期成长期 · 仅允许 bid_up / scale_up</p>
- </div>
- <div class="threshold-card">
- <div class="threshold-key">MIN_DAILY_COST</div>
- <div class="threshold-value tools">100 <span class="threshold-unit">元</span></div>
- <p class="threshold-meaning">日消耗 < 100 元 → ROI 当日数据不入 7 日滚动均值</p>
- </div>
- <div class="threshold-card">
- <div class="threshold-key">NO_SPEND_THRESHOLD</div>
- <div class="threshold-value rules">10 <span class="threshold-unit">元</span></div>
- <p class="threshold-meaning">7 日均消耗 < 10 → 自动 pause(年龄>7 天)</p>
- </div>
- <div class="threshold-card">
- <div class="threshold-key">BID_DOWN range</div>
- <div class="threshold-value tools">3 — 5<span class="threshold-unit">%</span></div>
- <p class="threshold-meaning">降价幅度 · 单次绝对值上限 5%(更严守)</p>
- </div>
- <div class="threshold-card">
- <div class="threshold-key">BID_UP range</div>
- <div class="threshold-value decisions">5 — 10<span class="threshold-unit">%</span></div>
- <p class="threshold-meaning">提价幅度 · 单次绝对值上限 10%(可放宽)</p>
- </div>
- <div class="threshold-card">
- <div class="threshold-key">BID_FLOOR / CEILING</div>
- <div class="threshold-value skills">0.05 — 1.00<span class="threshold-unit">元</span></div>
- <p class="threshold-meaning">出价硬边界 · 任何调整不得突破</p>
- </div>
- <div class="threshold-card">
- <div class="threshold-key">MAX_ADJUSTMENTS_PER_AD_PER_DAY</div>
- <div class="threshold-value rules">2</div>
- <p class="threshold-meaning">单广告每日最大调整次数 · 平台学习期防抖</p>
- </div>
- <div class="threshold-card">
- <div class="threshold-key">EXECUTION_ENABLED</div>
- <div class="threshold-value rules">false</div>
- <p class="threshold-meaning">执行开关 · 默认关闭,所有操作走审批不真改</p>
- </div>
- </div>
- </section>
- <!-- ====== 07 · DATA FLOW ====== -->
- <section id="dataflow">
- <div class="section-head">
- <div>
- <div class="section-num">§ 07 — 数据流向</div>
- <h2 class="section-title data">从 ODPS 到<em>腾讯广告 API</em></h2>
- </div>
- <p class="section-desc">外部数据源 → 本地落盘 → 内存计算 → LLM 调用 → 飞书人机交互 → 腾讯广告写入。所有中间产物均落盘,可独立回放。</p>
- </div>
- <svg class="flow-svg" viewBox="0 0 1200 580" xmlns="http://www.w3.org/2000/svg">
- <defs>
- <marker id="arrowhead" 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="currentColor"/>
- </marker>
- <pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
- <path d="M 40 0 L 0 0 0 40" fill="none" stroke="#1F2A38" stroke-width="0.5"/>
- </pattern>
- </defs>
- <rect width="1200" height="580" fill="url(#grid)" opacity="0.5"/>
- <!-- Layers labels -->
- <text x="20" y="40" class="label-bold" fill="#94A3B0">EXTERNAL</text>
- <text x="20" y="170" class="label-bold" fill="#94A3B0">FILESYSTEM</text>
- <text x="20" y="320" class="label-bold" fill="#94A3B0">COMPUTE</text>
- <text x="20" y="450" class="label-bold" fill="#94A3B0">HUMAN + ACT</text>
- <!-- External data sources -->
- <rect x="160" y="20" width="160" height="50" class="node node-data" rx="2"/>
- <text x="240" y="42" text-anchor="middle" class="label-bold">ODPS</text>
- <text x="240" y="58" text-anchor="middle">loghubods.touliu_data</text>
- <rect x="380" y="20" width="160" height="50" class="node node-data" rx="2"/>
- <text x="460" y="42" text-anchor="middle" class="label-bold">腾讯广告 API</text>
- <text x="460" y="58" text-anchor="middle">/adgroups/get</text>
- <rect x="600" y="20" width="160" height="50" class="node node-data" rx="2"/>
- <text x="680" y="42" text-anchor="middle" class="label-bold">RDS MySQL</text>
- <text x="680" y="58" text-anchor="middle">config + whitelist</text>
- <rect x="820" y="20" width="160" height="50" class="node node-data" rx="2"/>
- <text x="900" y="42" text-anchor="middle" class="label-bold">飞书 IM</text>
- <text x="900" y="58" text-anchor="middle">app + chat_history</text>
- <!-- Filesystem layer -->
- <rect x="80" y="150" width="180" height="40" class="node" rx="2"/>
- <text x="170" y="174" text-anchor="middle">outputs/raw/</text>
- <rect x="280" y="150" width="180" height="40" class="node" rx="2"/>
- <text x="370" y="174" text-anchor="middle">outputs/merged/</text>
- <rect x="480" y="150" width="180" height="40" class="node" rx="2"/>
- <text x="570" y="174" text-anchor="middle">outputs/metrics_*.csv</text>
- <rect x="680" y="150" width="180" height="40" class="node" rx="2"/>
- <text x="770" y="174" text-anchor="middle">portfolio_summary/</text>
- <rect x="880" y="150" width="220" height="40" class="node" rx="2"/>
- <text x="990" y="174" text-anchor="middle">outputs/reports/</text>
- <!-- Compute layer -->
- <rect x="80" y="290" width="220" height="50" class="node node-tool" rx="2"/>
- <text x="190" y="312" text-anchor="middle" class="label-bold">data_query</text>
- <text x="190" y="328" text-anchor="middle">fetch + merge</text>
- <rect x="320" y="290" width="220" height="50" class="node node-tool" rx="2"/>
- <text x="430" y="312" text-anchor="middle" class="label-bold">roi_calculator</text>
- <text x="430" y="328" text-anchor="middle">动态 ROI 7 日均值</text>
- <rect x="560" y="290" width="220" height="50" class="node node-decide" rx="2"/>
- <text x="670" y="312" text-anchor="middle" class="label-bold">ad_decision</text>
- <text x="670" y="328" text-anchor="middle">候选标记 + 决策合并</text>
- <rect x="800" y="290" width="220" height="50" class="node node-decide" rx="2"/>
- <text x="910" y="312" text-anchor="middle" class="label-bold">LLM (Sonnet 4.5)</text>
- <text x="910" y="328" text-anchor="middle">action + reason</text>
- <!-- Human + Act layer -->
- <rect x="200" y="430" width="200" height="50" class="node node-act" rx="2"/>
- <text x="300" y="452" text-anchor="middle" class="label-bold">guardrails</text>
- <text x="300" y="468" text-anchor="middle">护栏校验</text>
- <rect x="450" y="430" width="200" height="50" class="node node-act" rx="2"/>
- <text x="550" y="452" text-anchor="middle" class="label-bold">im_approval</text>
- <text x="550" y="468" text-anchor="middle">飞书审批 + 阻塞</text>
- <rect x="700" y="430" width="200" height="50" class="node node-act" rx="2"/>
- <text x="800" y="452" text-anchor="middle" class="label-bold">execution_engine</text>
- <text x="800" y="468" text-anchor="middle">EXECUTION_ENABLED?</text>
- <rect x="950" y="430" width="200" height="50" class="node node-act" rx="2"/>
- <text x="1050" y="452" text-anchor="middle" class="label-bold">ad_api</text>
- <text x="1050" y="468" text-anchor="middle">/adgroups/update</text>
- <!-- Connections -->
- <g style="color:#6B9FB5">
- <path class="arrow arrow-data" d="M 240 70 L 240 145 L 170 145 L 170 150"/>
- <path class="arrow arrow-data" d="M 460 70 L 460 145 L 370 145 L 370 150"/>
- </g>
- <g style="color:#3D5066">
- <path class="arrow" d="M 170 190 L 170 285 L 190 290"/>
- <path class="arrow" d="M 370 190 L 370 290 L 430 290"/>
- <path class="arrow" d="M 570 190 L 570 285 L 670 290"/>
- <path class="arrow" d="M 770 190 L 770 285 L 870 290"/>
- </g>
- <!-- Compute connections -->
- <g style="color:#3D5066">
- <path class="arrow" d="M 300 315 L 320 315"/>
- <path class="arrow" d="M 540 315 L 560 315"/>
- <path class="arrow" d="M 780 315 L 800 315"/>
- </g>
- <!-- Compute → Output -->
- <g style="color:#3D5066">
- <path class="arrow" d="M 190 290 L 190 195"/>
- <path class="arrow" d="M 430 290 L 430 195"/>
- <path class="arrow" d="M 670 290 L 670 195"/>
- <path class="arrow" d="M 910 290 L 990 195"/>
- </g>
- <!-- LLM → guardrails / approval -->
- <g style="color:#5BC0BE">
- <path class="arrow arrow-decide" d="M 910 340 L 910 410 L 300 410 L 300 430"/>
- <path class="arrow arrow-decide" d="M 300 480 L 300 510 L 550 510 L 550 480"/>
- </g>
- <!-- approval → execution -->
- <g style="color:#3D5066">
- <path class="arrow" d="M 650 455 L 700 455"/>
- <path class="arrow" d="M 900 455 L 950 455"/>
- </g>
- <!-- Feishu connection -->
- <g style="color:#6B9FB5">
- <path class="arrow arrow-data" d="M 900 70 L 900 105 L 550 105 L 550 430"/>
- </g>
- <!-- ad_api → 腾讯 -->
- <g style="color:#F25F5C">
- <path class="arrow" d="M 1050 430 L 1050 105 L 460 105 L 460 70" stroke-dasharray="4 4"/>
- </g>
- <!-- Legend -->
- <g transform="translate(900, 530)">
- <text x="0" y="0" font-family="JetBrains Mono" font-size="10" fill="#94A3B0">EXECUTION_ENABLED=False</text>
- <text x="0" y="14" font-family="JetBrains Mono" font-size="10" fill="#F25F5C">→ ad_api 仅 log,不真改</text>
- </g>
- </svg>
- </section>
- <!-- ====== 08 · DEPLOYMENT ====== -->
- <section id="deployment">
- <div class="section-head">
- <div>
- <div class="section-num">§ 08 — 部署形态</div>
- <h2 class="section-title rules">两种<em>运行模式</em></h2>
- </div>
- <p class="section-desc">本地交互(REPL,人工触发分析)+ K8s CronJob(每日 02:00 UTC 自动跑)。共享同一份代码 + skill + tool。</p>
- </div>
- <div class="deploy-grid">
- <div class="deploy-card">
- <div class="deploy-mode">Mode A · Interactive</div>
- <div class="deploy-name">run.py · REPL</div>
- <p class="deploy-desc">手工启动 Agent,交互式问答。适合临时分析单个广告 / 修改决策 / 调试 skill。Agent 在每轮等待用户输入,可执行任意工具。</p>
- <div class="deploy-files">
- <code><span>$</span> .venv/bin/python3 run.py</code>
- </div>
- </div>
- <div class="deploy-card">
- <div class="deploy-mode">Mode B · Batch</div>
- <div class="deploy-name">execute_once.py · 单次执行</div>
- <p class="deploy-desc">一次性走完 10 步流水线,自动取 T-1(昨天)作为数据日期。K8s CronJob 直接调度,可手工调试。完成后退出。</p>
- <div class="deploy-files">
- <code><span>$</span> .venv/bin/python3 execute_once.py</code>
- <code><span>cron</span> 0 2 * * * UTC (每日 02:00)</code>
- </div>
- </div>
- </div>
- <div style="margin-top: 32px; padding: 24px 28px; background: var(--bg-alt); border-left: 3px solid var(--gold); font-size: 13.5px; color: var(--text-dim); line-height: 1.7;">
- <strong style="color: var(--gold); font-family: var(--mono); font-size: 11px; letter-spacing: 0.15em; text-transform: uppercase; display: block; margin-bottom: 8px;">K8s 资源</strong>
- <span style="color: var(--text);">deployment.yaml</span> · 1 副本 + Service + PVC(挂 /app/outputs)<br>
- <span style="color: var(--text);">cronjob.yaml</span> · 02:00 UTC + forbidConcurrent + 2h deadline<br>
- <span style="color: var(--text);">configmap.yaml</span> · 公开环境变量<br>
- <span style="color: var(--text);">secret.yaml</span> · ODPS / Feishu / 腾讯广告 凭证<br>
- <span style="color: var(--text);">network-policy.yaml</span> · 限制 Pod 出入流量
- </div>
- </section>
- <!-- ====== 09 · 输出层 ====== -->
- <section id="outputs">
- <div class="section-head">
- <div>
- <div class="section-num">§ 09 — 输出物</div>
- <h2 class="section-title skills">每次执行<em>留下的痕迹</em></h2>
- </div>
- <p class="section-desc">所有中间产物均落盘到 <code>outputs/</code>,可独立回放或调试。生产环境通过 PVC 持久化。</p>
- </div>
- <div class="tools-table">
- <div class="tools-row head">
- <div>路径</div>
- <div>类型</div>
- <div>用途</div>
- <div>持久化</div>
- </div>
- <div class="tools-row">
- <div class="tool-file">outputs/raw/</div>
- <div class="tool-cat data">CSV (per day)</div>
- <div class="tool-fn">ODPS 创意级原始数据。增量缓存,已存在跳过。</div>
- <div class="tool-step">14 天</div>
- </div>
- <div class="tools-row">
- <div class="tool-file">outputs/merged/</div>
- <div class="tool-cat data">CSV (per day)</div>
- <div class="tool-fn">合并多日 + 广告状态快照。下游 ROI 计算的输入。</div>
- <div class="tool-step">30 天</div>
- </div>
- <div class="tools-row">
- <div class="tool-file">outputs/metrics_*.csv</div>
- <div class="tool-fn"><code class="tool-cat compute">CSV (latest)</code></div>
- <div class="tool-fn">广告级指标:动态 ROI 7 日均值、cost_7d_avg、ad_age_days、creative_count 等 30+ 字段。</div>
- <div class="tool-step">每日</div>
- </div>
- <div class="tools-row">
- <div class="tool-file">outputs/portfolio_summary/</div>
- <div class="tool-cat compute">JSON</div>
- <div class="tool-fn">渠道 P25/P50/P75 + tier 级 fission/CTR/bid 均值。</div>
- <div class="tool-step">每日</div>
- </div>
- <div class="tools-row">
- <div class="tool-file">outputs/reports/llm_decisions_*.csv</div>
- <div class="tool-cat decide">CSV</div>
- <div class="tool-fn">LLM 输出 + 规则补全的完整决策表。20+ 字段。</div>
- <div class="tool-step">每日</div>
- </div>
- <div class="tools-row">
- <div class="tool-file">outputs/reports/validated_decisions_*.csv</div>
- <div class="tool-cat decide">CSV</div>
- <div class="tool-fn">护栏校验后的决策表(失败的强制改 hold)。</div>
- <div class="tool-step">每日</div>
- </div>
- <div class="tools-row">
- <div class="tool-file">outputs/approvals/{request_id}/</div>
- <div class="tool-cat execute">XLSX + JSON</div>
- <div class="tool-fn">飞书审批表 + 请求/响应缓存。</div>
- <div class="tool-step">永久</div>
- </div>
- <div class="tools-row">
- <div class="tool-file">outputs/execution_log/</div>
- <div class="tool-cat execute">CSV</div>
- <div class="tool-fn">执行审计:每条决策的 API 调用结果。</div>
- <div class="tool-step">永久</div>
- </div>
- <div class="tools-row">
- <div class="tool-file">.trace/{trace_id}/</div>
- <div class="tool-cat report">JSON</div>
- <div class="tool-fn">框架 Trace 持久化:meta + GoalTree + 所有 messages + events。</div>
- <div class="tool-step">永久</div>
- </div>
- </div>
- </section>
- <footer>
- <p>auto_put_ad_mini · system architecture map · v0.4.27</p>
- <p>generated by structural analysis from agent/ + examples/auto_put_ad_mini/ source</p>
- <span class="stamp">作为 Monitor/调控 Agent 的最小业务单元 · 后续将接入 auto_put_ad 完整体系</span>
- </footer>
- </main>
- <script>
- // Subtle scroll-triggered fade for sections
- const observer = new IntersectionObserver((entries) => {
- entries.forEach(entry => {
- if (entry.isIntersecting) {
- entry.target.style.opacity = '1';
- entry.target.style.transform = 'translateY(0)';
- }
- });
- }, { threshold: 0.1, rootMargin: '0px 0px -100px 0px' });
- document.querySelectorAll('section').forEach(s => {
- s.style.opacity = '0';
- s.style.transform = 'translateY(30px)';
- s.style.transition = 'opacity 0.8s ease-out, transform 0.8s ease-out';
- observer.observe(s);
- });
- // Pipeline step hover effect: dim non-hovered
- const steps = document.querySelectorAll('.pipeline-step');
- steps.forEach(step => {
- step.addEventListener('mouseenter', () => {
- steps.forEach(s => { if (s !== step) s.style.opacity = '0.45'; });
- });
- step.addEventListener('mouseleave', () => {
- steps.forEach(s => { s.style.opacity = '1'; });
- });
- });
- </script>
- </body>
- </html>
|