docs(add):新增Arabica Sprint3系统架构图文件

Signed-off-by: gzkoala <guohao@gitconomy.org>
This commit is contained in:
gzkoala
2026-03-11 12:51:40 +08:00
parent a5cb36245e
commit c8ad7c1950

View File

@@ -1,13 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1320 1200" width="100%" height="100%">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="140 0 1100 1200" width="100%" height="100%">
<!--
================================================================================
图表名称Arabica Sprint 3 架构图 (Arabica Sprint 3 Architecture)
文件命名arabica-sprint3-architecture-design.svg
用途:聚焦外围学术检索与双轨制数据落盘模块的实现
用途:展示 Project Caffeine 在 Sprint 3 中的意图路由、学术检索接入与高容错防死循环落盘机制
版本v1.0.0 (Arabica) - Sprint 3
作者Gitconomy Research-郭晧
SPDX-License-Identifier: MIT & CC-BY-SA-4.0
创建日期2026-03-08
创建日期2026-03-11
================================================================================
-->
@@ -39,22 +39,27 @@ SPDX-License-Identifier: MIT & CC-BY-SA-4.0
.font-mono { font-family: 'JetBrains Mono', Consolas, 'Courier New', monospace; }
/* 文本层级 */
.card-title { font-size: 14px; font-weight: bold; fill: #FFFFFF; }
.card-text { font-size: 12px; fill: var(--c-neutral-gray); }
.card-title { font-size: 15px; font-weight: bold; fill: #FFFFFF; }
.card-text { font-size: 13px; fill: var(--c-neutral-gray); }
.text-code { font-size: 13px; font-weight: bold; fill: #0F172A; }
.label-text { font-size: 12px; font-weight: bold; fill: var(--c-neutral-gray); }
.step-text { font-size: 13px; font-weight: bold; fill: #FFFFFF; }
.alert-text { font-size: 12px; font-weight: bold; fill: #DC2626; } /* 红色警示文字 */
.amber-text { font-size: 12px; font-weight: bold; fill: #D97706; } /* 琥珀色强调文字 */
</style>
<!-- 箭头标记 -->
<marker id="arrow-gray" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto">
<path d="M 0 0 L 8 4 L 0 8 Z" fill="var(--c-neutral-gray)" />
<!-- 箭头标记:尺寸缩小三分之一以更精致呈现 -->
<marker id="arrow-gray" markerWidth="4" markerHeight="4" refX="3.5" refY="2" orient="auto">
<path d="M 0 0 L 4 2 L 0 4 Z" fill="var(--c-neutral-gray)" />
</marker>
<marker id="arrow-green" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto">
<path d="M 0 0 L 8 4 L 0 8 Z" fill="var(--c-local-green)" />
<marker id="arrow-green" markerWidth="4" markerHeight="4" refX="3.5" refY="2" orient="auto">
<path d="M 0 0 L 4 2 L 0 4 Z" fill="var(--c-local-green)" />
</marker>
<marker id="arrow-blue" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto">
<path d="M 0 0 L 8 4 L 0 8 Z" fill="var(--c-cloud-blue)" />
<marker id="arrow-blue" markerWidth="4" markerHeight="4" refX="3.5" refY="2" orient="auto">
<path d="M 0 0 L 4 2 L 0 4 Z" fill="var(--c-cloud-blue)" />
</marker>
<marker id="arrow-amber" markerWidth="4" markerHeight="4" refX="3.5" refY="2" orient="auto">
<path d="M 0 0 L 4 2 L 0 4 Z" fill="var(--c-risk-amber)" />
</marker>
</defs>
@@ -63,10 +68,10 @@ SPDX-License-Identifier: MIT & CC-BY-SA-4.0
顶层标题块 (Title Block)
===========================================================================
-->
<g id="title-block" transform="translate(660, 40)">
<g id="title-block" transform="translate(640, 40)">
<text y="0" text-anchor="middle" class="font-mono" font-size="12" fill="var(--c-neutral-gray)" letter-spacing="1">FIG-02</text>
<text y="30" text-anchor="middle" class="font-sans" font-weight="bold" font-size="24" fill="#000000">Arabica Sprint 3 系统开发组件架构图</text>
<text y="55" text-anchor="middle" class="font-mono" font-size="14" fill="var(--c-neutral-gray)">架构图 &gt; Arabica Sprint 3 &gt; 文献检索与标准化落盘工作流</text>
<text y="55" text-anchor="middle" class="font-mono" font-size="14" fill="var(--c-neutral-gray)">架构图 &gt; Arabica Sprint 3 &gt; 意图路由、学术检索与高容错落盘机制</text>
<!-- Context Indicator: Y=70 -->
<rect x="-30" y="70" width="60" height="3" fill="var(--c-cloud-blue)" />
</g>
@@ -74,28 +79,16 @@ SPDX-License-Identifier: MIT & CC-BY-SA-4.0
<!--
===========================================================================
架构图主体内容 (Diagram Content)
整体下移80单位保证距离标题拥有 50 单位以上的空间
===========================================================================
-->
<g id="diagram-content" transform="translate(0, 80)">
<!--
===========================================================================
物理边界与容器 (Boundaries)
===========================================================================
-->
<!-- 物理边界与容器 -->
<g id="boundaries" transform="translate(0, 240)">
<!-- Node.js MCP Server Runtime Boundary -->
<rect x="270" y="0" width="690" height="620" rx="12" fill="var(--c-local-green-light)" stroke="var(--c-local-green)" stroke-dasharray="4 4" stroke-width="2" />
<rect x="270" y="0" width="690" height="36" fill="var(--c-local-green)" opacity="0.1" rx="12"/>
<text x="290" y="23" class="font-mono" font-size="14" font-weight="bold" fill="var(--c-local-green)">📦 MCP Server RuntimeSprint 3)</text>
</g>
<!-- Public Internet Boundary (Cloud) - 距MCP服务器恰好保持30单位间距 -->
<g id="cloud-boundary" transform="translate(990, 80)">
<rect x="0" y="0" width="320" height="280" rx="12" fill="var(--c-cloud-blue-light)" stroke="var(--c-cloud-blue)" stroke-dasharray="4 4" stroke-width="2" />
<rect x="0" y="0" width="320" height="36" fill="var(--c-cloud-blue)" opacity="0.1" rx="12"/>
<text x="20" y="23" class="font-mono" font-size="14" font-weight="bold" fill="var(--c-cloud-blue)">☁️ Cloud</text>
<rect x="290" y="0" width="710" height="560" rx="12" fill="var(--c-local-green-light)" stroke="var(--c-local-green)" stroke-dasharray="4 4" stroke-width="2" />
<rect x="290" y="0" width="710" height="36" fill="var(--c-local-green)" opacity="0.1" rx="12"/>
<text x="310" y="23" class="font-mono" font-size="14" font-weight="bold" fill="var(--c-local-green)">📦 MCP Server RuntimeSprint3) </text>
</g>
<!--
@@ -104,48 +97,40 @@ SPDX-License-Identifier: MIT & CC-BY-SA-4.0
===========================================================================
-->
<g id="connections" fill="none" stroke-width="2">
<!-- User <-> Cherry Studio -->
<path d="M 380 110 L 462 110" stroke="var(--c-neutral-gray)" marker-end="url(#arrow-gray)" />
<path d="M 470 140 L 388 140" stroke="var(--c-neutral-gray)" marker-end="url(#arrow-gray)" />
<!-- User to Cherry Studio -->
<path d="M 400 110 L 482 110" stroke="var(--c-neutral-gray)" marker-end="url(#arrow-gray)" />
<path d="M 490 140 L 408 140" stroke="var(--c-neutral-gray)" marker-end="url(#arrow-gray)" />
<!-- Cherry Studio <-> Remote LLM -->
<path d="M 740 130 L 1112 130" stroke="var(--c-cloud-blue)" stroke-dasharray="4 2" marker-end="url(#arrow-blue)" />
<path d="M 1120 150 L 748 150" stroke="var(--c-cloud-blue)" stroke-dasharray="4 2" marker-end="url(#arrow-blue)" />
<!-- Cherry Studio to Remote LLM -->
<path d="M 760 110 L 892 110" stroke="var(--c-cloud-blue)" stroke-dasharray="4 2" marker-end="url(#arrow-blue)" />
<path d="M 900 140 L 768 140" stroke="var(--c-cloud-blue)" stroke-dasharray="4 2" marker-end="url(#arrow-blue)" />
<!-- Cherry Studio <-> app.ts (stdio) -->
<path d="M 600 170 L 600 272" stroke="var(--c-local-green)" marker-end="url(#arrow-green)" />
<path d="M 620 280 L 620 178" stroke="var(--c-local-green)" marker-end="url(#arrow-green)" />
<!-- stdio Transport -->
<path d="M 600 170 L 600 292" stroke="var(--c-local-green)" marker-end="url(#arrow-green)" />
<path d="M 640 300 L 640 178" stroke="var(--c-local-green)" marker-end="url(#arrow-green)" />
<!-- app.ts -> Controllers -->
<path d="M 580 350 L 580 370 L 365 370 L 365 395" stroke="var(--c-neutral-gray)" marker-end="url(#arrow-gray)" />
<path d="M 610 350 L 610 395" stroke="var(--c-neutral-gray)" marker-end="url(#arrow-gray)" />
<path d="M 640 350 L 640 370 L 820 370 L 820 395" stroke="var(--c-neutral-gray)" marker-end="url(#arrow-gray)" />
<!-- app.ts to Controllers -->
<!-- To toolsController (Router Brain) -->
<path d="M 560 370 L 560 395 L 420 395 L 420 422" stroke="var(--c-risk-amber)" stroke-width="2.5" marker-end="url(#arrow-amber)" />
<!-- toolsController -> Services -->
<!-- to literatureService -->
<path d="M 550 470 L 550 505" stroke="var(--c-local-green)" marker-end="url(#arrow-green)" />
<!-- to storageService -->
<path d="M 660 470 L 660 615" stroke="var(--c-local-green)" marker-end="url(#arrow-green)" />
<!-- To resourcesController -->
<path d="M 680 370 L 680 395 L 770 395 L 770 422" stroke="var(--c-neutral-gray)" marker-end="url(#arrow-gray)" />
<!-- resourcesController -> resourceService -->
<path d="M 820 470 L 820 505" stroke="var(--c-neutral-gray)" marker-end="url(#arrow-gray)" />
<!-- toolsController (Router) to Services -->
<path d="M 410 495 L 410 532" stroke="var(--c-local-green)" marker-end="url(#arrow-green)" />
<path d="M 580 495 L 580 515 L 770 515 L 770 532" stroke="var(--c-local-green)" marker-end="url(#arrow-green)" />
<!-- literatureService <-> Academic APIs (Cloud) -->
<path d="M 720 550 L 1150 550 L 1150 335" stroke="var(--c-cloud-blue)" stroke-dasharray="4 2" marker-end="url(#arrow-blue)" />
<path d="M 1130 330 L 1130 570 L 728 570" stroke="var(--c-cloud-blue)" stroke-dasharray="4 2" marker-end="url(#arrow-blue)" />
<!-- resourcesController to resourceService -->
<path d="M 770 495 L 770 532" stroke="var(--c-neutral-gray)" marker-end="url(#arrow-gray)" />
<!-- storageService -> yamlHelper -->
<path d="M 700 650 L 745 650" stroke="var(--c-neutral-gray)" marker-end="url(#arrow-gray)" />
<!-- arxivService to External arXiv API (Network) 穿越边界线 -->
<path d="M 320 580 L 220 580" stroke="var(--c-cloud-blue)" stroke-dasharray="4 4" marker-end="url(#arrow-blue)" />
<!-- storageService -> Local Vault (垂直向下落盘至正下方) -->
<path d="M 580 690 L 580 850 L 600 850 L 600 885" stroke="var(--c-neutral-gray)" marker-end="url(#arrow-gray)" />
<!-- resourceService to Local Vault (File I/O) -->
<path d="M 770 620 L 770 672" stroke="var(--c-local-green)" marker-end="url(#arrow-green)" />
<!-- resourceService -> Local Vault (绕开卡片落盘) -->
<path d="M 820 580 L 820 600 L 940 600 L 940 850 L 630 850 L 630 885" stroke="var(--c-neutral-gray)" marker-end="url(#arrow-gray)" />
<!-- API Clients & Schemas dotted dependencies -->
<path d="M 550 580 L 550 725" stroke="var(--c-neutral-gray)" stroke-dasharray="2 2" marker-end="url(#arrow-gray)" />
<path d="M 660 690 L 660 725" stroke="var(--c-neutral-gray)" stroke-dasharray="2 2" marker-end="url(#arrow-gray)" />
<!-- direct read Frameworks from toolsController (Bypass) -->
<path d="M 560 495 L 560 652" stroke="var(--c-risk-amber)" stroke-dasharray="2 2" marker-end="url(#arrow-amber)" opacity="0.6"/>
</g>
@@ -155,21 +140,24 @@ SPDX-License-Identifier: MIT & CC-BY-SA-4.0
===========================================================================
-->
<g id="path-labels" class="font-sans label-text">
<text x="425" y="95" text-anchor="middle">Query</text>
<text x="425" y="160" text-anchor="middle">Report</text>
<text x="920" y="120" text-anchor="middle" fill="var(--c-cloud-blue)">Reasoning / Tool Calls</text>
<text x="920" y="165" text-anchor="middle" fill="var(--c-cloud-blue)">LLM Result</text>
<!-- Top Level -->
<text x="445" y="95" text-anchor="middle">Query</text>
<text x="445" y="160" text-anchor="middle">Report / Confirm</text>
<text x="830" y="95" text-anchor="middle" fill="var(--c-cloud-blue)">Routing Intent</text>
<text x="830" y="160" text-anchor="middle" fill="var(--c-cloud-blue)">LLM Result / Ask</text>
<!-- stdio Link -->
<text x="590" y="220" text-anchor="end" fill="var(--c-local-green)">tools/call</text>
<text x="630" y="220" text-anchor="start" fill="var(--c-local-green)">Result JSON</text>
<rect x="580" y="230" width="60" height="20" rx="4" fill="#FFFFFF" stroke="var(--c-local-green)" />
<text x="610" y="245" text-anchor="middle" class="font-mono" font-size="11" fill="var(--c-local-green)">stdio</text>
<text x="585" y="210" text-anchor="end" fill="var(--c-local-green)">tools/call</text>
<text x="655" y="210" text-anchor="start" fill="var(--c-local-green)">Result / Brake</text>
<text x="700" y="415" text-anchor="start" fill="var(--c-neutral-gray)">resources/read</text>
<!-- Network / Vault Labels -->
<text x="1050" y="540" text-anchor="middle" fill="var(--c-cloud-blue)">HTTP GET (Search)</text>
<text x="1050" y="585" text-anchor="middle" fill="var(--c-cloud-blue)">Metadata JSON</text>
<text x="590" y="810" text-anchor="start" class="font-mono" font-size="11" fill="var(--c-neutral-gray)">fs.writeFileSync()</text>
<rect x="585" y="250" width="70" height="20" rx="4" fill="#FFFFFF" stroke="var(--c-local-green)" />
<text x="620" y="264" text-anchor="middle" class="font-mono" font-size="11" fill="var(--c-local-green)">stdio</text>
<!-- Internal Labels -->
<text x="420" y="515" text-anchor="start" fill="var(--c-local-green)" font-size="11">search_arxiv</text>
<text x="650" y="510" text-anchor="start" fill="var(--c-local-green)" font-size="11">save_note (z.any容错)</text>
<text x="570" y="590" text-anchor="start" fill="var(--c-risk-amber)" font-size="10">fetch_framework</text>
</g>
<!--
@@ -179,7 +167,7 @@ SPDX-License-Identifier: MIT & CC-BY-SA-4.0
-->
<g id="nodes">
<!-- 1. User Node -->
<g transform="translate(260, 95)">
<g transform="translate(280, 95)">
<rect x="0" y="0" width="110" height="60" rx="8" fill="#F8FAFC" stroke="var(--c-neutral-gray)" stroke-width="2" />
<circle cx="55" cy="22" r="10" fill="var(--c-neutral-gray)" />
<path d="M 35 50 C 35 35, 75 35, 75 50" fill="none" stroke="var(--c-neutral-gray)" stroke-width="3" stroke-linecap="round"/>
@@ -187,284 +175,261 @@ SPDX-License-Identifier: MIT & CC-BY-SA-4.0
</g>
<!-- 2. Cherry Studio -->
<g transform="translate(480, 80)">
<rect x="0" y="0" width="250" height="90" rx="8" fill="var(--c-gov-blue-light)" stroke="var(--c-gov-blue)" stroke-width="2" />
<rect x="0" y="0" width="250" height="30" fill="var(--c-gov-blue)" rx="8" />
<rect x="0" y="20" width="250" height="10" fill="var(--c-gov-blue)" />
<text x="125" y="20" text-anchor="middle" class="font-sans card-title">Cherry Studio (MCP Client)</text>
<text x="125" y="55" text-anchor="middle" class="font-sans card-text" font-weight="bold">大模型对话与调度宿主</text>
<text x="125" y="75" text-anchor="middle" class="font-mono card-text" font-size="11">Initiates stdio subprocess</text>
<g transform="translate(490, 80)">
<rect x="0" y="0" width="260" height="90" rx="8" fill="var(--c-gov-blue-light)" stroke="var(--c-gov-blue)" stroke-width="2" />
<rect x="0" y="0" width="260" height="30" fill="var(--c-gov-blue)" rx="8" />
<rect x="0" y="20" width="260" height="10" fill="var(--c-gov-blue)" />
<text x="130" y="20" text-anchor="middle" class="font-sans card-title">Cherry Studio (MCP Client)</text>
<text x="130" y="55" text-anchor="middle" class="font-sans card-text" font-weight="bold">大模型交互与意图传递中枢</text>
<text x="130" y="75" text-anchor="middle" class="font-mono card-text" font-size="11">Initiates stdio subprocess</text>
</g>
<!-- 3. Remote LLM Brain -->
<g transform="translate(1140, 145)">
<polygon points="0,-40 40,-20 40,20 0,40 -40,20 -40,-20" fill="#FFFFFF" stroke="var(--c-cloud-blue)" stroke-width="3" />
<text x="0" y="-5" text-anchor="middle" class="font-mono card-text" fill="var(--c-cloud-blue)" font-size="14" font-weight="bold">LLM</text>
<text x="0" y="15" text-anchor="middle" class="font-mono card-text" font-size="10" fill="var(--c-cloud-blue)">(Remote)</text>
<g transform="translate(970, 120)">
<polygon points="0,-45 40,-20 40,20 0,45 -40,20 -40,-20" fill="var(--c-cloud-blue-light)" stroke="var(--c-cloud-blue)" stroke-width="3" />
<text x="0" y="-5" text-anchor="middle" class="font-mono card-text" fill="var(--c-cloud-blue)" font-size="14">LLM</text>
<text x="0" y="15" text-anchor="middle" class="font-mono card-text" font-size="10" fill="var(--c-cloud-blue)">(Agent)</text>
</g>
<!-- 4. Academic APIs -->
<g transform="translate(1020, 260)">
<rect x="0" y="0" width="240" height="65" rx="8" fill="#FFFFFF" stroke="var(--c-cloud-blue)" stroke-width="3" />
<rect x="0" y="0" width="240" height="26" fill="var(--c-cloud-blue)" rx="8" />
<rect x="0" y="20" width="240" height="6" fill="var(--c-cloud-blue)" />
<text x="120" y="18" text-anchor="middle" class="font-sans card-title">Academic APIs</text>
<text x="120" y="42" text-anchor="middle" class="font-mono text-code" fill="var(--c-cloud-blue)" font-size="12">arXiv API</text>
<text x="120" y="56" text-anchor="middle" class="font-mono text-code" fill="var(--c-cloud-blue)" font-size="12">Semantic Scholar API</text>
</g>
<!-- 5. app.ts -->
<g transform="translate(530, 280)">
<rect x="0" y="0" width="160" height="70" rx="6" fill="#FFFFFF" stroke="var(--c-local-green)" stroke-width="2" />
<rect x="0" y="0" width="160" height="26" fill="var(--c-local-green)" rx="6" />
<rect x="0" y="20" width="160" height="6" fill="var(--c-local-green)" />
<text x="80" y="18" text-anchor="middle" class="font-mono card-title">app.ts</text>
<text x="80" y="45" text-anchor="middle" class="font-sans text-code" font-size="12">McpServer 注册原语</text>
<text x="80" y="62" text-anchor="middle" class="font-mono card-text" font-size="10">Stdio Transport</text>
</g>
<!-- 6. Controllers -->
<!-- promptsController -->
<g transform="translate(290, 400)">
<rect x="0" y="0" width="150" height="70" rx="6" fill="#FFFFFF" stroke="var(--c-risk-amber)" stroke-width="2"/>
<rect x="0" y="0" width="150" height="26" fill="var(--c-risk-amber)" rx="6"/>
<rect x="0" y="20" width="150" height="6" fill="var(--c-risk-amber)" />
<text x="75" y="18" text-anchor="middle" class="font-mono card-title">promptsController</text>
<text x="75" y="45" text-anchor="middle" class="font-sans card-text">处理 prompts/get</text>
</g>
<!-- toolsController (Sprint 3 Focus) -->
<g transform="translate(460, 400)">
<rect x="0" y="0" width="240" height="70" rx="6" fill="#FFFFFF" stroke="var(--c-risk-amber)" stroke-width="2" />
<rect x="0" y="0" width="240" height="26" fill="var(--c-risk-amber)" rx="6" />
<rect x="0" y="20" width="240" height="6" fill="var(--c-risk-amber)" />
<text x="120" y="18" text-anchor="middle" class="font-mono card-title">toolsController</text>
<text x="120" y="44" text-anchor="middle" class="font-sans card-text" font-size="11">search_academic_literature</text>
<text x="120" y="60" text-anchor="middle" class="font-sans card-text" font-size="11">save_literature_to_vault</text>
</g>
<!-- resourcesController -->
<g transform="translate(720, 400)">
<rect x="0" y="0" width="200" height="70" rx="6" fill="#FFFFFF" stroke="var(--c-risk-amber)" stroke-width="2" />
<rect x="0" y="0" width="200" height="26" fill="var(--c-risk-amber)" rx="6" />
<rect x="0" y="20" width="200" height="6" fill="var(--c-risk-amber)" />
<text x="100" y="18" text-anchor="middle" class="font-mono card-title">resourcesController</text>
<text x="100" y="44" text-anchor="middle" class="font-sans card-text">处理 resources/read 分发</text>
<text x="100" y="60" text-anchor="middle" class="font-sans card-text">含 literature:// 协议支持</text>
</g>
<!-- 7. Services Row 1 -->
<!-- promptService & intentService (S2 Stacked) -->
<g transform="translate(290, 510)">
<rect x="0" y="0" width="150" height="160" rx="6" fill="#FFFFFF" stroke="var(--c-local-green)" stroke-width="2" opacity="0.6"/>
<rect x="0" y="0" width="150" height="26" fill="var(--c-local-green)" rx="6" opacity="0.6"/>
<text x="75" y="18" text-anchor="middle" class="font-mono card-title">S2 Strategy Services</text>
<rect x="10" y="40" width="130" height="45" rx="4" fill="var(--c-local-green-light)" />
<text x="75" y="58" text-anchor="middle" class="font-mono text-code" font-size="11">promptService</text>
<text x="75" y="75" text-anchor="middle" class="font-sans card-text" font-size="10">多维思维框架管理</text>
<rect x="10" y="95" width="130" height="45" rx="4" fill="var(--c-local-green-light)" />
<text x="75" y="113" text-anchor="middle" class="font-mono text-code" font-size="11">intentService</text>
<text x="75" y="130" text-anchor="middle" class="font-sans card-text" font-size="10">意图拆解生成检索词</text>
</g>
<!-- literatureService -->
<g transform="translate(460, 510)">
<rect x="0" y="0" width="240" height="70" rx="6" fill="#FFFFFF" stroke="var(--c-local-green)" stroke-width="2" />
<rect x="0" y="0" width="240" height="26" fill="var(--c-local-green)" rx="6" />
<rect x="0" y="20" width="240" height="6" fill="var(--c-local-green)" />
<text x="120" y="18" text-anchor="middle" class="font-mono card-title">literatureService.ts (New)</text>
<text x="120" y="45" text-anchor="middle" class="font-sans text处理 prompts/ge-code" font-size="12" fill="var(--c-local-green)">并发调用学术API及去重</text>
<text x="120" y="62" text-anchor="middle" class="font-sans card-text" font-size="11">向大模型返回标准化 JSON 数组</text>
</g>
<!-- resourceService -->
<g transform="translate(720, 510)">
<!-- 4. app.ts -->
<g transform="translate(520, 300)">
<rect x="0" y="0" width="200" height="70" rx="6" fill="#FFFFFF" stroke="var(--c-local-green)" stroke-width="2" />
<rect x="0" y="0" width="200" height="26" fill="var(--c-local-green)" rx="6" />
<rect x="0" y="20" width="200" height="6" fill="var(--c-local-green)" />
<text x="100" y="18" text-anchor="middle" class="font-mono card-title">resourceService.ts</text>
<text x="100" y="45" text-anchor="middle" class="font-sans text-code" font-size="12">文件系统读取交互</text>
<text x="100" y="62" text-anchor="middle" class="font-sans card-text" font-size="11">读取 Vault 中的文献卡片</text>
<text x="100" y="18" text-anchor="middle" class="font-mono card-title">app.ts</text>
<text x="100" y="45" text-anchor="middle" class="font-sans text-code" font-size="12">McpServer 注册入口</text>
<text x="100" y="62" text-anchor="middle" class="font-mono card-text" font-size="10">Tools &amp; Resources (stdio)</text>
</g>
<!-- 8. Services Row 2 -->
<!-- storageService -->
<g transform="translate(460, 620)">
<rect x="0" y="0" width="240" height="70" rx="6" fill="#FFFFFF" stroke="var(--c-local-green)" stroke-width="2" />
<rect x="0" y="0" width="240" height="26" fill="var(--c-local-green)" rx="6" />
<rect x="0" y="20" width="240" height="6" fill="var(--c-local-green)" />
<text x="120" y="18" text-anchor="middle" class="font-mono card-title">storageService.ts (New)</text>
<text x="120" y="45" text-anchor="middle" class="font-sans text-code" font-size="12" fill="var(--c-local-green)">JSON 转 Markdown+YAML</text>
<text x="120" y="62" text-anchor="middle" class="font-sans card-text" font-size="11">路径安全校验与双轨数据落盘</text>
<!-- 5. toolsController.ts (Expanded Central Router) -->
<g transform="translate(320, 430)">
<rect x="0" y="0" width="280" height="65" rx="6" fill="var(--c-risk-amber-light)" stroke="var(--c-risk-amber)" stroke-width="2.5" />
<rect x="0" y="0" width="280" height="26" fill="var(--c-risk-amber)" rx="6" />
<rect x="0" y="20" width="280" height="6" fill="var(--c-risk-amber)" />
<text x="140" y="18" text-anchor="middle" class="font-mono card-title">toolsController</text>
<text x="140" y="45" text-anchor="middle" class="font-sans card-text" font-weight="bold">统一调度与防呆:截获意图请求并分发</text>
<text x="140" y="58" text-anchor="middle" class="font-sans alert-text" font-size="11">自动剥离框架 JSON 外壳,注入【🛑停止】指令</text>
</g>
<!-- yamlHelper.js -->
<g transform="translate(750, 625)">
<rect x="0" y="0" width="170" height="50" rx="6" fill="#F8FAFC" stroke="var(--c-neutral-gray)" stroke-width="1.5" />
<text x="85" y="20" text-anchor="middle" class="font-mono text-code" font-size="12">utils/yamlHelper.js</text>
<text x="85" y="40" text-anchor="middle" class="font-sans card-text" font-size="11">生成 Frontmatter 文本</text>
<!-- 6. resourcesController.ts -->
<g transform="translate(630, 430)">
<rect x="0" y="0" width="280" height="65" rx="6" fill="#FFFFFF" stroke="var(--c-neutral-gray-light)" stroke-width="2" />
<rect x="0" y="0" width="280" height="26" fill="var(--c-neutral-gray-light)" rx="6" />
<rect x="0" y="20" width="280" height="6" fill="var(--c-neutral-gray-light)" />
<text x="140" y="18" text-anchor="middle" class="font-mono card-title">resourcesController</text>
<text x="140" y="45" text-anchor="middle" class="font-sans card-text">解析 resource/read 请求</text>
<text x="140" y="58" text-anchor="middle" class="font-sans card-text" font-size="11">扩展 literature:// 协议</text>
</g>
<!-- 9. Utils & Models -->
<g transform="translate(460, 730)">
<rect x="0" y="0" width="115" height="55" rx="6" fill="#F8FAFC" stroke="var(--c-neutral-gray)" stroke-width="1.5" />
<text x="57" y="22" text-anchor="middle" class="font-mono text-code" font-size="11">apiClients.js</text>
<text x="57" y="42" text-anchor="middle" class="font-sans card-text" font-size="11">Axios / 重试</text>
<!-- 7. arxivService.ts -->
<g transform="translate(320, 540)">
<rect x="0" y="0" width="180" height="80" rx="6" fill="#FFFFFF" stroke="var(--c-local-green)" stroke-width="2" />
<rect x="0" y="0" width="180" height="26" fill="var(--c-local-green)" rx="6" />
<rect x="0" y="20" width="180" height="6" fill="var(--c-local-green)" />
<text x="90" y="18" text-anchor="middle" class="font-mono card-title">arxivService.ts</text>
<text x="90" y="45" text-anchor="middle" class="font-sans text-code" font-size="12">外部学术检索网关</text>
<text x="90" y="60" text-anchor="middle" class="font-sans card-text" font-size="11">解析底层复杂 XML 结构</text>
<text x="90" y="73" text-anchor="middle" class="font-sans card-text" font-size="11">转化为标准 Markdown 列表</text>
</g>
<g transform="translate(585, 730)">
<rect x="0" y="0" width="115" height="55" rx="6" fill="#F8FAFC" stroke="var(--c-neutral-gray)" stroke-width="1.5" />
<text x="57" y="18" text-anchor="middle" class="font-mono text-code" font-size="11">schemas.js</text>
<text x="57" y="34" text-anchor="middle" class="font-mono card-text" font-size="10">literatureSchema</text>
<text x="57" y="48" text-anchor="middle" class="font-sans card-text" font-size="10">Zod强校验标准</text>
<!-- 8. resourceService.ts -->
<g transform="translate(665, 540)">
<rect x="0" y="0" width="210" height="80" rx="6" fill="#FFFFFF" stroke="var(--c-local-green)" stroke-width="2" />
<rect x="0" y="0" width="210" height="26" fill="var(--c-local-green)" rx="6" />
<rect x="0" y="20" width="210" height="6" fill="var(--c-local-green)" />
<text x="105" y="18" text-anchor="middle" class="font-mono card-title">resourceService.ts</text>
<text x="105" y="45" text-anchor="middle" class="font-sans text-code" font-size="12">处理长文本落盘 (save_note)</text>
<rect x="25" y="52" width="160" height="20" rx="3" fill="var(--c-risk-amber-light)" />
<text x="105" y="66" text-anchor="middle" class="font-sans amber-text" font-size="11">拦截 z.any() 畸形入参并序列化</text>
</g>
<!-- 10. External Resources (Local Vault 位于MCP中心正下方) -->
<g transform="translate(565, 890)">
<path d="M 0 15 A 50 15 0 1 0 100 15 V 60 A 50 15 0 1 1 0 60 Z" fill="var(--c-local-green-light)" stroke="var(--c-neutral-gray)" stroke-width="2" stroke-dasharray="2 2" />
<ellipse cx="50" cy="15" rx="50" ry="15" fill="var(--c-local-green-light)" stroke="var(--c-neutral-gray)" stroke-width="2" stroke-dasharray="2 2" />
<text x="50" y="48" text-anchor="middle" class="font-sans card-text" fill="var(--c-neutral-gray)" font-size="13" font-weight="bold">Local Vault</text>
<text x="50" y="65" text-anchor="middle" class="font-mono card-text" fill="var(--c-neutral-gray)" font-size="10">.md 卡片落盘</text>
<!-- 9. External arXiv API -->
<g transform="translate(0, 580)">
<polygon points="30,-24 190,-24 220,0 190,24 30,24 0,0" fill="var(--c-cloud-blue-light)" stroke="var(--c-cloud-blue)" stroke-width="2" stroke-dasharray="4 2" />
<!-- arXiv 学术网站图标 (学士帽/文档云) -->
<g transform="translate(35, -10)">
<polygon points="12,0 2,5 12,10 22,5" fill="none" stroke="var(--c-cloud-blue)" stroke-width="1.5" stroke-linejoin="round"/>
<path d="M 5 6.5 L 5 12 Q 12 16 19 12 L 19 6.5" fill="none" stroke="var(--c-cloud-blue)" stroke-width="1.5"/>
<polyline points="12,5 22,5 22,11" fill="none" stroke="var(--c-cloud-blue)" stroke-width="1.5" stroke-linejoin="round"/>
<circle cx="22" cy="12" r="1.5" fill="var(--c-cloud-blue)"/>
</g>
<text x="130" y="4" text-anchor="middle" class="font-sans card-text" fill="var(--c-cloud-blue)" font-weight="bold">External arXiv API</text>
</g>
<!-- 10. models/frameworks -->
<g transform="translate(470, 660)">
<rect x="0" y="0" width="180" height="60" rx="6" fill="#F8FAFC" stroke="var(--c-neutral-gray)" stroke-width="1.5" stroke-dasharray="4 2" />
<path d="M 0 20 L 180 20" stroke="var(--c-neutral-gray)" stroke-width="1.5" stroke-dasharray="4 2" />
<text x="90" y="14" text-anchor="middle" class="font-mono text-code" font-size="11">models/frameworks/</text>
<text x="90" y="38" text-anchor="middle" class="font-mono card-text" font-size="11">静态分析框架模板</text>
<text x="90" y="52" text-anchor="middle" class="font-mono card-text" font-size="11">(swot.json, scqa.json)</text>
</g>
<!-- 11. Local Vault -->
<g transform="translate(695, 680)">
<path d="M 0 15 A 75 15 0 1 0 150 15 V 45 A 75 15 0 1 1 0 45 Z" fill="var(--c-local-green-light)" stroke="var(--c-neutral-gray)" stroke-width="2" />
<ellipse cx="75" cy="15" rx="75" ry="15" fill="var(--c-local-green-light)" stroke="var(--c-neutral-gray)" stroke-width="2" />
<text x="75" y="45" text-anchor="middle" class="font-sans card-text" fill="var(--c-neutral-gray)" font-size="12" font-weight="bold">Obsidian Vault</text>
</g>
<!-- 12. schemas.ts (Zod Validation) -->
<g transform="translate(695, 755)">
<rect x="0" y="0" width="150" height="24" rx="4" fill="#F8FAFC" stroke="var(--c-neutral-gray)" stroke-width="1" />
<text x="75" y="16" text-anchor="middle" class="font-mono text-code" font-size="11">schemas.ts: z.any()</text>
</g>
</g>
<!--
===========================================================================
步骤侧边栏与流程图注 (Execution Steps)
步骤侧边栏与流程图注 (Execution Steps) - 点落连线上
===========================================================================
-->
<g id="execution-steps">
<!-- 图内红圈标记 -->
<g transform="translate(420, 110)">
<!-- 1. User input -->
<g transform="translate(440, 110)">
<circle cx="0" cy="0" r="10" fill="var(--c-step-red)" />
<text x="0" y="4.5" text-anchor="middle" class="font-sans step-text">1</text>
</g>
<g transform="translate(820, 130)">
<!-- 2. LLM routes search -->
<g transform="translate(826, 110)">
<circle cx="0" cy="0" r="10" fill="var(--c-step-red)" />
<text x="0" y="4.5" text-anchor="middle" class="font-sans step-text">2</text>
</g>
<g transform="translate(610, 365)">
<!-- 3. arXiv fetch (下移至跨界线上) -->
<g transform="translate(270, 580)">
<circle cx="0" cy="0" r="10" fill="var(--c-step-red)" />
<text x="0" y="4.5" text-anchor="middle" class="font-sans step-text">3</text>
</g>
<g transform="translate(970, 550)">
<!-- 4. LLM routes framework -->
<g transform="translate(600, 210)">
<circle cx="0" cy="0" r="10" fill="var(--c-step-red)" />
<text x="0" y="4.5" text-anchor="middle" class="font-sans step-text">4</text>
</g>
<g transform="translate(1150, 420)">
<!-- 5. tools strips and brakes -->
<g transform="translate(560, 580)">
<circle cx="0" cy="0" r="10" fill="var(--c-step-red)" />
<text x="0" y="4.5" text-anchor="middle" class="font-sans step-text">5</text>
</g>
<g transform="translate(660, 490)">
<!-- 6. LLM stops tool, outputs & asks -->
<g transform="translate(826, 140)">
<circle cx="0" cy="0" r="10" fill="var(--c-step-red)" />
<text x="0" y="4.5" text-anchor="middle" class="font-sans step-text">6</text>
</g>
<g transform="translate(715, 650)">
<!-- 7. User confirms -->
<g transform="translate(440, 140)">
<circle cx="0" cy="0" r="10" fill="var(--c-step-red)" />
<text x="0" y="4.5" text-anchor="middle" class="font-sans step-text">7</text>
</g>
<g transform="translate(580, 820)">
<!-- 8. z.any fallback -->
<g transform="translate(675, 602)">
<circle cx="0" cy="0" r="10" fill="var(--c-step-red)" />
<text x="0" y="4.5" text-anchor="middle" class="font-sans step-text">8</text>
</g>
<g transform="translate(420, 140)">
<!-- 9. Write to vault -->
<g transform="translate(770, 646)">
<circle cx="0" cy="0" r="10" fill="var(--c-step-red)" />
<text x="0" y="4.5" text-anchor="middle" class="font-sans step-text">9</text>
</g>
<!-- 步骤流程侧边栏 -->
<g transform="translate(10, 320)">
<rect x="0" y="0" width="250" height="250" rx="8" fill="#FEF2F2" stroke="var(--c-step-red)" stroke-width="1.5" />
<text x="125" y="25" text-anchor="middle" class="font-sans" font-size="14" font-weight="bold" fill="var(--c-step-red)">Sprint 3 文献检索落盘工作流</text>
<line x1="15" y1="35" x2="235" y2="35" stroke="var(--c-step-red)" stroke-dasharray="2 2" />
<g transform="translate(15, 55)">
<circle cx="6" cy="-4" r="7" fill="var(--c-step-red)" />
<text x="6" y="0" text-anchor="middle" class="font-sans step-text" font-size="10">1</text>
<text x="20" y="0" class="font-sans card-text" fill="#000000">User: 输入研究主题进行查询</text>
</g>
<g transform="translate(15, 75)">
<circle cx="6" cy="-4" r="7" fill="var(--c-step-red)" />
<text x="6" y="0" text-anchor="middle" class="font-sans step-text" font-size="10">2</text>
<text x="20" y="0" class="font-sans card-text" fill="#000000">LLM: 判断并决定检索相关学术文献</text>
</g>
<g transform="translate(15, 95)">
<circle cx="6" cy="-4" r="7" fill="var(--c-step-red)" />
<text x="6" y="0" text-anchor="middle" class="font-sans step-text" font-size="10">3</text>
<text x="20" y="0" class="font-sans card-text" fill="#000000">Client: 调用 search_academic 工具</text>
</g>
<g transform="translate(15, 115)">
<circle cx="6" cy="-4" r="7" fill="var(--c-step-red)" />
<text x="6" y="0" text-anchor="middle" class="font-sans step-text" font-size="10">4</text>
<text x="20" y="0" class="font-sans card-text" fill="#000000">S1: 并发请求 arXiv / Sem. Scholar</text>
</g>
<g transform="translate(15, 135)">
<circle cx="6" cy="-4" r="7" fill="var(--c-step-red)" />
<text x="6" y="0" text-anchor="middle" class="font-sans step-text" font-size="10">5</text>
<text x="20" y="0" class="font-sans card-text" fill="#000000">API: 返回聚合的 JSON 文献元数据</text>
</g>
<g transform="translate(15, 155)">
<circle cx="6" cy="-4" r="7" fill="var(--c-step-red)" />
<text x="6" y="0" text-anchor="middle" class="font-sans step-text" font-size="10">6</text>
<text x="20" y="0" class="font-sans card-text" fill="#000000">LLM: 分析后调用 save_literature</text>
</g>
<g transform="translate(15, 175)">
<circle cx="6" cy="-4" r="7" fill="var(--c-step-red)" />
<text x="6" y="0" text-anchor="middle" class="font-sans step-text" font-size="10">7</text>
<text x="20" y="0" class="font-sans card-text" fill="#000000">S1: 将 JSON 转为 MD + YAML 前缀</text>
</g>
<g transform="translate(15, 195)">
<circle cx="6" cy="-4" r="7" fill="var(--c-step-red)" />
<text x="6" y="0" text-anchor="middle" class="font-sans step-text" font-size="10">8</text>
<text x="20" y="0" class="font-sans card-text" fill="#000000">S1: 安全写入指定的本地 Vault 目录</text>
</g>
<g transform="translate(15, 215)">
<circle cx="6" cy="-4" r="7" fill="var(--c-step-red)" />
<text x="6" y="0" text-anchor="middle" class="font-sans step-text" font-size="10">9</text>
<text x="20" y="0" class="font-sans card-text" fill="#000000">LLM: 生成带本地文献引用的最终报告</text>
</g>
</g>
</g>
</g>
<!--
===========================================================================
底部步骤流程说明面板 (Sprint 3 执行步骤流)
===========================================================================
-->
<g transform="translate(290, 910)">
<rect x="0" y="0" width="710" height="160" rx="8" fill="#FEF2F2" stroke="var(--c-step-red)" stroke-width="1.5" />
<text x="355" y="25" text-anchor="middle" class="font-sans" font-size="14" font-weight="bold" fill="var(--c-step-red)">Sprint 3 执行步骤流</text>
<line x1="15" y1="35" x2="695" y2="35" stroke="var(--c-step-red)" stroke-dasharray="2 2" />
<!-- Column 1 (Steps 1-5) -->
<g transform="translate(30, 55)">
<circle cx="6" cy="-4" r="7" fill="var(--c-step-red)" />
<text x="6" y="0" text-anchor="middle" class="font-sans step-text" font-size="10">1</text>
<text x="20" y="0" class="font-sans card-text" fill="#000000">用户输入包含检索与分析的复合查询</text>
</g>
<g transform="translate(30, 75)">
<circle cx="6" cy="-4" r="7" fill="var(--c-step-red)" />
<text x="6" y="0" text-anchor="middle" class="font-sans step-text" font-size="10">2</text>
<text x="20" y="0" class="font-sans card-text" fill="#000000">大模型识别意图1: 请求 search_arxiv</text>
</g>
<g transform="translate(30, 95)">
<circle cx="6" cy="-4" r="7" fill="var(--c-step-red)" />
<text x="6" y="0" text-anchor="middle" class="font-sans step-text" font-size="10">3</text>
<text x="20" y="0" class="font-sans card-text" fill="#000000">arxivService 请求外网并解析格式化</text>
</g>
<g transform="translate(30, 115)">
<circle cx="6" cy="-4" r="7" fill="var(--c-step-red)" />
<text x="6" y="0" text-anchor="middle" class="font-sans step-text" font-size="10">4</text>
<text x="20" y="0" class="font-sans card-text" fill="#000000">大模型识别意图2: 请求分析框架模板</text>
</g>
<g transform="translate(30, 135)">
<circle cx="6" cy="-4" r="7" fill="var(--c-step-red)" />
<text x="6" y="0" text-anchor="middle" class="font-sans step-text" font-size="10">5</text>
<text x="20" y="0" class="font-sans card-text" fill="#000000">Tools 剥离 JSON注入🛑【刹车指令】</text>
</g>
<!-- Column 2 (Steps 6-9) -->
<g transform="translate(380, 55)">
<circle cx="6" cy="-4" r="7" fill="var(--c-step-red)" />
<text x="6" y="0" text-anchor="middle" class="font-sans step-text" font-size="10">6</text>
<text x="20" y="0" class="font-sans card-text" fill="#000000">模型工具被截断,输出报告并询问保存</text>
</g>
<g transform="translate(380, 75)">
<circle cx="6" cy="-4" r="7" fill="var(--c-step-red)" />
<text x="6" y="0" text-anchor="middle" class="font-sans step-text" font-size="10">7</text>
<text x="20" y="0" class="font-sans card-text" fill="#000000">用户确认保存触发意图3: save_note</text>
</g>
<g transform="translate(380, 95)">
<circle cx="6" cy="-4" r="7" fill="var(--c-step-red)" />
<text x="6" y="0" text-anchor="middle" class="font-sans step-text" font-size="10">8</text>
<text x="20" y="0" class="font-sans card-text" fill="#000000">底层 z.any() 宽容拦截长文本并序列化</text>
</g>
<g transform="translate(380, 115)">
<circle cx="6" cy="-4" r="7" fill="var(--c-step-red)" />
<text x="6" y="0" text-anchor="middle" class="font-sans step-text" font-size="10">9</text>
<text x="20" y="0" class="font-sans card-text" fill="#000000">resourceService 安全写入知识库落盘</text>
</g>
</g>
<!--
===========================================================================
底部图例与注释块 (Legend & Key Block)
===========================================================================
-->
<g id="legend" transform="translate(660, 1090)">
<g id="legend" transform="translate(640, 1110)">
<!-- 统一的半透明背景容器 -->
<rect x="-480" y="-16" width="960" height="40" rx="4" fill="rgba(255, 255, 255, 0.9)" stroke="var(--c-neutral-gray)" stroke-width="0.5"/>
<rect x="-440" y="-16" width="880" height="40" rx="4" fill="rgba(255, 255, 255, 0.9)" stroke="var(--c-neutral-gray)" stroke-width="0.5"/>
<g transform="translate(-460, 0)">
<g transform="translate(-420, 0)">
<!-- 图例引导文本 -->
<text x="0" y="8" class="font-sans" font-size="13" font-weight="bold" fill="var(--c-neutral-gray)">组件与语义对照:</text>
<!-- 图例项 1 -->
<g transform="translate(130, 0)">
<rect x="-6" y="-4" width="12" height="12" rx="2" fill="var(--c-gov-blue)" />
<text x="12" y="8" class="font-sans" font-size="12" fill="var(--c-neutral-gray)">宿主客户端架构</text>
<text x="12" y="8" class="font-sans" font-size="12" fill="var(--c-neutral-gray)">宿主客户端</text>
</g>
<!-- 图例项 2 -->
<g transform="translate(280, 0)">
<g transform="translate(240, 0)">
<rect x="-6" y="-4" width="12" height="12" rx="2" fill="var(--c-risk-amber)" />
<text x="12" y="8" class="font-sans" font-size="12" fill="var(--c-neutral-gray)">路由分发控制器 (Controllers)</text>
<text x="12" y="8" class="font-sans" font-size="12" fill="var(--c-neutral-gray)">防火墙路由 (防死循环)</text>
</g>
<!-- 图例项 3 -->
<g transform="translate(520, 0)">
<g transform="translate(430, 0)">
<rect x="-6" y="-4" width="12" height="12" rx="2" fill="var(--c-local-green)" />
<text x="12" y="8" class="font-sans" font-size="12" fill="var(--c-neutral-gray)">核心引擎与本地执行层 (Sprint 3核心)</text>
<text x="12" y="8" class="font-sans" font-size="12" fill="var(--c-neutral-gray)">底层服务引擎与资源落盘</text>
</g>
<!-- 图例项 4 -->
<g transform="translate(790, 0)">
<g transform="translate(640, 0)">
<rect x="-6" y="-4" width="12" height="12" rx="2" fill="var(--c-cloud-blue)" />
<text x="12" y="8" class="font-sans" font-size="12" fill="var(--c-neutral-gray)">远程云端 API 依赖</text>
<text x="12" y="8" class="font-sans" font-size="12" fill="var(--c-neutral-gray)">外部云端/网络依赖</text>
</g>
</g>
</g>
@@ -474,7 +439,7 @@ SPDX-License-Identifier: MIT & CC-BY-SA-4.0
版权许可声明 (License)
===========================================================================
-->
<text x="660" y="1150" text-anchor="middle" class="font-sans" font-size="11" fill="var(--c-neutral-gray)">
<text x="640" y="1170" text-anchor="middle" class="font-sans" font-size="11" fill="var(--c-neutral-gray)">
本作品采用 CC-BY-SA 4.0 进行许可,© 2025-2026 Gitconomy Research社区
</text>
</svg>

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 25 KiB