# Step 70: 统一内核 createCore

一句话导读:把工具、记忆、MCP、LSP、搜索、沙箱、hooks 的装配收成一个 createCore(),终端和 Web 只注入前端差异。


# 一、这一步做了什么(What)

step70 解决一个架构问题:终端 index.ts 装了完整能力,Web session.ts 只装了少量工具,导致 Web 不能联网搜索、功能不完整。于是新增 core/createCore.ts,把全套 agent 内核装配统一起来。

终端和 Web 都调用它,差异通过参数注入。

# 二、面试官视角:为什么要做?(Why)

面试题:终端和 Web 都能跑,为什么还要重构出 createCore?

因为两份装配必然漂移。工具系统最怕“新增能力忘了另一个入口”:终端有 WebSearch,Web 没有;终端接 MCP,Web 不接;权限、记忆、skills 都可能不一致。

两份装配 单一 createCore
加工具要改两处 只在一处注册
Web/终端功能漂移 多前端共享能力
bug 难定位 前端差异显式注入

# 三、原理:它是怎么工作的(How)

入口在 step70/core/createCore.ts:

export async function createCore(opts: CoreOptions): Promise<Core> {
  // registry / hooks / sandbox / memory / MCP / LSP / plugins / skills / engine
}
1
2
3

前端差异变成 getter 或回调:

createCore({
  canUseTool,
  getModel,
  getStyle,
  getWebSearch,
  approvePlan,
  connectMcp,
  connectLsp,
});
1
2
3
4
5
6
7
8
9

Web 的 server/session.ts 只负责传 Web 风格参数:

const core = await createCore({
  canUseTool: opts.canUseTool,
  getWebSearch: () => true,
  connectMcp: false,
  connectLsp: false,
});
1
2
3
4
5
6

架构图:

终端 readline 权限 ─┐
                   ├─ createCore ─ QueryEngine + 全套工具
WebSocket 权限  ───┘
1
2
3

# 四、深入追问(面试常见 follow-up)

Q:createCore 会不会变成上帝函数?
A:它确实是装配层,但不是业务逻辑层。它的职责是 wiring,把工具和依赖接起来;具体能力仍在各模块。

Q:为什么 Web 默认关 MCP/LSP?
A:启动慢、资源重。教学版先保证 Web parity 的核心能力,MCP/LSP 可按需打开。真实系统会做资源池和生命周期管理。

Q:canUseTool 为什么必须注入?
A:权限交互属于 surface:终端问 y/n,Web 弹窗,SDK 可能走 control message。内核只 await 一个布尔结果。

Q:这个抽象和真实 Claude Code 对得上吗?
A:真实源码不一定叫 createCore,但 QueryEngineConfig、bootstrap state、bridge/sdk surface 都体现了同一思想:内核无头,surface 注入差异。

# 五、踩坑 / 设计权衡

重构后要验证两个方向:Web 是否补齐搜索,终端是否没有回退。README 里实测了 Web 出现 web_search 事件,终端仍保留 44 工具。

# 六、与真实源码的对照

我们的实现 Claude Code 源码
createCore() 单一装配 bootstrap + QueryEngineConfig + surface 注入
canUseTool/getter 参数 终端/IDE/Bridge 各注入权限和状态
Web/终端共用工具 多入口共享 agent runtime
简化资源生命周期 会话隔离、资源池、feature flags

# 七、一句话总结

createCore() 把“一个内核,多张脸”真正落到代码上:能力只装一次,前端只负责注入交互方式。

# 下一节预告

下一篇是 step71:在统一内核上继续打磨 Web,加入 token/cost 状态栏和多会话管理。