arch-mapping.html
11.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" />
<title>对 LemonBoss 的映射 · LemonBoss PRD</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@9..144,300;9..144,500;9..144,700&family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="assets/shell.css" />
</head>
<body data-page="arch-mapping.html">
<div class="shell">
<aside id="sidebar"></aside>
<main class="page">
<header class="page-head">
<div class="crumb"><span class="pill">04 · ARCHITECTURE</span><span class="sep">/</span><span>对 LemonBoss 的映射</span></div>
<h1>对 LemonBoss 现有架构的映射</h1>
<p class="deck">99% 是在现有抽象上加薄薄一层。本页列出每一项能力的对照:REUSE(沿用)/ NEW(新增)/ PATCH(小改)。</p>
</header>
<article class="body">
<section>
<h2>能力映射总表</h2>
<table class="dense">
<thead><tr><th>能力</th><th>新组件</th><th>对应现有模块</th><th>改动</th></tr></thead>
<tbody>
<tr><td>Agent 启动与会话复用</td><td>—</td><td><code>packages/acp-core/protocol/ClaudeCliProtocol.js</code> + <code>server/src/core/session-pool.js</code></td><td><span class="tag REUSE">REUSE</span></td></tr>
<tr><td>多 Agent 调用 facade</td><td>—</td><td><code>server/src/core/agent-manager.js</code> · <code>master-session.js</code></td><td><span class="tag REUSE">REUSE</span></td></tr>
<tr><td>任务 → 步骤拆分</td><td>—</td><td><code>server/src/tools/orchestrate-tool.js</code></td><td><span class="tag REUSE">REUSE</span></td></tr>
<tr><td>DAG 依赖解析</td><td>—</td><td><code>server/src/core/scheduler.js</code> (<code>getExecutionGroups</code>)</td><td><span class="tag REUSE">REUSE</span></td></tr>
<tr><td>Pipeline 描述结构</td><td>—</td><td><code>server/services/pipeline-service.js</code></td><td><span class="tag REUSE">REUSE</span> · units.json 复用 step 结构</td></tr>
<tr><td>重试 + 反思</td><td><code>retryWithReflection()</code> 写在 loop-controller.js 内</td><td>参考 <code>server/services/evolution-loop.js</code> (PRAE) 思路,但<b>不抽公共</b></td><td><span class="tag NEW">NEW</span> · P5 再考虑合并</td></tr>
<tr><td>ACP / Claude CLI 协议层</td><td>—</td><td><code>packages/acp-core/</code></td><td><span class="tag REUSE">REUSE</span></td></tr>
<tr><td>Agent 模板注册</td><td>6 个新模板</td><td><code>system/templates/_registry.json</code></td><td><span class="tag NEW">NEW</span></td></tr>
<tr><td>三层 Loop 编排</td><td><code>LoopController</code></td><td><code>server/src/core/loop-controller.js</code></td><td><span class="tag NEW">NEW</span></td></tr>
<tr><td>PRD/SDD 文档存储</td><td><code>DocStore</code></td><td><code>server/services/doc-store.js</code></td><td><span class="tag NEW">NEW</span></td></tr>
<tr><td>Unit 状态机</td><td><code>UnitRegistry</code></td><td><code>server/services/unit-registry.js</code></td><td><span class="tag NEW">NEW</span></td></tr>
<tr><td>HTTP / SSE 入口</td><td><code>/api/devloop/*</code></td><td><code>server/routes/devloop.js</code> → 挂在 <code>server/index.js</code></td><td><span class="tag NEW">NEW</span></td></tr>
<tr><td>Web 看板</td><td><code>DevLoopDashboard.vue</code></td><td>放在 <code>web/src/views/</code>,复用 <code>PipelineEditor</code> DAG 渲染</td><td><span class="tag NEW">NEW</span></td></tr>
<tr><td>结果持久化根</td><td>—</td><td><code>data/companies/{cid}/projects/{pid}/</code></td><td><span class="tag REUSE">REUSE</span> · 沿用 company-scoped 文件根</td></tr>
<tr><td>进程沙箱 / 端口管理</td><td>—</td><td><code>server/src/engine/process-guard.js</code></td><td><span class="tag REUSE">REUSE</span></td></tr>
<tr><td>WS 流式</td><td>—</td><td><code>server/routes/claude-chat-ws.js</code></td><td><span class="tag REUSE">REUSE</span> · DevLoop SSE 走 HTTP 复用同套帧</td></tr>
</tbody>
</table>
</section>
<section>
<h2>分层视图</h2>
<p>三色块代表三种改动类型;越靠下越基础,越靠上越业务。</p>
<svg viewBox="0 0 1100 360" width="100%" role="img" aria-label="分层视图">
<defs><marker id="arrM" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M0,0 L10,5 L0,10 Z" fill="#0E0E10"/></marker></defs>
<g font-family="JetBrains Mono" font-size="12">
<rect x="40" y="30" width="240" height="50" rx="4" fill="#FCE7E2" stroke="#C7341A"/><text x="160" y="60" text-anchor="middle">routes/devloop.js · NEW</text>
<rect x="40" y="110" width="240" height="50" rx="4" fill="#FCE7E2" stroke="#C7341A"/><text x="160" y="140" text-anchor="middle">core/loop-controller.js · NEW</text>
<rect x="40" y="190" width="110" height="50" rx="4" fill="#FCE7E2" stroke="#C7341A"/><text x="95" y="220" text-anchor="middle">DocStore</text>
<rect x="170" y="190" width="110" height="50" rx="4" fill="#FCE7E2" stroke="#C7341A"/><text x="225" y="220" text-anchor="middle">UnitRegistry</text>
<rect x="360" y="30" width="260" height="50" rx="4" fill="#EAEAEA" stroke="#666"/><text x="490" y="60" text-anchor="middle">core/master-session.js</text>
<rect x="360" y="110" width="260" height="50" rx="4" fill="#EAEAEA" stroke="#666"/><text x="490" y="140" text-anchor="middle">core/agent-manager.js</text>
<rect x="360" y="190" width="260" height="50" rx="4" fill="#EAEAEA" stroke="#666"/><text x="490" y="220" text-anchor="middle">core/scheduler.js · core/session-pool.js</text>
<rect x="360" y="270" width="260" height="50" rx="4" fill="#EAEAEA" stroke="#666"/><text x="490" y="300" text-anchor="middle">tools/orchestrate · call-agent</text>
<rect x="700" y="30" width="320" height="50" rx="4" fill="#fff" stroke="#0E0E10"/><text x="860" y="60" text-anchor="middle">packages/acp-core (Protocol)</text>
<rect x="700" y="110" width="320" height="50" rx="4" fill="#fff" stroke="#0E0E10"/><text x="860" y="140" text-anchor="middle">ClaudeCliProtocol (subprocess)</text>
<rect x="700" y="190" width="320" height="50" rx="4" fill="#fff" stroke="#0E0E10"/><text x="860" y="220" text-anchor="middle">Claude CLI · local process</text>
<rect x="700" y="270" width="320" height="50" rx="4" fill="#EAEAEA" stroke="#666"/><text x="860" y="300" text-anchor="middle">services/evolution-loop.js · 不动</text>
<g stroke="#0E0E10" fill="none" marker-end="url(#arrM)">
<line x1="280" y1="55" x2="355" y2="55"/>
<line x1="280" y1="135" x2="355" y2="135"/>
<line x1="280" y1="215" x2="355" y2="215"/>
<line x1="620" y1="55" x2="695" y2="55"/>
<line x1="620" y1="135" x2="695" y2="135"/>
<line x1="620" y1="215" x2="695" y2="215"/>
<line x1="620" y1="295" x2="695" y2="295"/>
<line x1="160" y1="160" x2="160" y2="185"/>
<line x1="225" y1="160" x2="225" y2="185"/>
</g>
</g>
</svg>
<p class="sig"><span style="color:#C7341A;font-weight:700">红</span> 新增 · <span style="color:#666">灰</span> 复用 · <span style="color:#8a6b00">黄</span> 补丁 · <span style="color:#0E0E10">黑</span> 底层依赖</p>
</section>
<section>
<h2>为什么 P1~P4 不抽公共 retry 函数</h2>
<p>EvolutionLoop 当前实现 PRAE (Perceive → Reason & Plan → Execute → Evaluate → Reflect),里面有「失败 → 反思 → 重试」逻辑。直觉上 L1 可以共用,但<b>初版决定不抽</b>:</p>
<ul>
<li><b>避免回归风险:</b>EvolutionLoop 跑的是 Skill 进化,目前在生产里运行。动它意味着要把 Skill 进化的回归一起做。</li>
<li><b>反思 prompt 差异大:</b>Skill 进化的反思是「Skill 评分低,怎么改 prompt」;L1 的反思是「单测失败,代码哪里错」。共用会让 prompt 模板变成「上帝模板」,反而难维护。</li>
<li><b>80 行不算多:</b>P2 在 loop-controller.js 内重写一份 retryWithReflection 也就 80 行,DRY 不必这么早追。</li>
</ul>
<pre class="code"><span class="c">// P2 直接在 server/src/core/loop-controller.js 写一份新的</span>
<span class="k">async function</span> <span class="n">retryWithReflection</span>(<span class="v">unit</span>, <span class="v">budget</span>) <span class="p">{</span>
<span class="k">let</span> failures = <span class="p">[]</span>;
<span class="k">for</span> (<span class="k">let</span> i = <span class="v">0</span>; i < budget; i++) <span class="p">{</span>
<span class="k">await</span> <span class="n">agentManager</span>.<span class="n">callAgent</span>(<span class="s">'coder'</span>, <span class="p">{</span> spec: unit.spec, history: failures <span class="p">}</span>);
<span class="k">const</span> r = <span class="k">await</span> <span class="n">agentManager</span>.<span class="n">callAgent</span>(<span class="s">'tester'</span>, <span class="p">{</span> unit <span class="p">}</span>);
<span class="k">if</span> (r.<span class="n">ok</span>) <span class="k">return</span> <span class="p">{</span> ok: <span class="v">true</span>, retries: i <span class="p">}</span>;
failures.<span class="n">push</span>(r.<span class="n">failures</span>);
<span class="p">}</span>
<span class="k">return</span> <span class="p">{</span> ok: <span class="v">false</span>, reason: <span class="s">"budget_exceeded"</span> <span class="p">}</span>;
<span class="p">}</span>
<span class="c">// P5 视实测情况再决定是否与 evolution-loop 合并到 packages/ 公共目录</span></pre>
<p class="sig">这条改动同步影响 plan-migration.html 的 P2 阶段:retry 函数从「抽公共」改为「直接新写」。</p>
</section>
<section>
<h2>不动的边界</h2>
<div class="callout">
<b>本次改造绝不触碰:</b>
<ul>
<li>ACP 协议本身(<code>packages/acp-core/</code>)</li>
<li>Master / Orchestrator 已有行为(仅注册新的 6 个 Agent 模板)</li>
<li>WebSocket 路由(<code>/ws/claude</code>)</li>
<li>SkillsMarket / Arena 路径下任何文件</li>
<li>认证 / 用户系统(<code>routes/auth.js</code>, <code>routes/users.js</code>)</li>
</ul>
</div>
</section>
</article>
<nav class="prev-next"></nav>
<footer class="site"><div><b>Section</b>04 · Architecture</div><div><b>Page</b>arch-mapping.html</div></footer>
</main>
</div>
<script src="assets/shell.js"></script>
</body>
</html>