DeepSeek Harness: 服务隔离与作用域

最后更新:2026-08-31

在多 Agent、多会话的环境中,服务共享是福也是祸——全局服务方便但容易冲突,隔离服务安全但通信成本高。Cordis 的作用域系统在两者之间找到平衡:默认共享,按需隔离。

💡 提示:作用域的核心思想是"默认共享,按需隔离"——大多数服务全局共享即可,只有需要隔离的服务才配置 isolate。不隔离是常态,隔离是特例。

📋 前置知识:已完成 19-service.md,理解 Service 基类

1. 你将学到


2. 全局作用域(Global Scope)

服务隔离与作用域

(1) 默认行为

默认情况下,所有 Service 都是全局的——整个 DSH 实例只有一个实例:

TYPESCRIPT
export default class CacheService extends Service {
  constructor(ctx: Context) {
    super(ctx, 'cache')  // 全局唯一
  }
}

(2) 全局服务的特点

特点 说明
单例 整个进程只有一个实例
共享 所有会话和请求共享同一状态
无隔离 会话 A 修改的数据会话 B 能看到

(3) 适用场景

(4) ▶ 示例 4

TYPESCRIPT
// ❌ 全局缓存导致会话间数据泄漏
export default class CacheService extends Service {
  private data = new Map<string, any>()
  
  set(key: string, value: any) {
    this.data.set(key, value)
  }
}

// 会话 A: ctx.cache.set('temp', 'secret-data')
// 会话 B: ctx.cache.get('temp') → 'secret-data' (泄漏!)

3. 会话作用域(Session Scope)

(1) 概念

会话作用域为每个会话创建独立的服务实例:

TYPESCRIPT
export default class SessionCacheService extends Service {
  static scope = 'session'

  constructor(ctx: Context) {
    super(ctx, 'session-cache')
  }
}

(2) ▶ 示例 2

100%
graph LR
    S1[Session A 创建] --> C1[CacheService A 实例]
    S2[Session B 创建] --> C2[CacheService B 实例]
    S1 --> D1[Session A 销毁 → CacheService A 销毁]
    S2 --> D2[Session B 销毁 → CacheService B 销毁]

(3) 作用域声明

TYPESCRIPT
export default class SessionCacheService extends Service {
  static scope = 'session'
  // 或
  // static scope = Symbol('session')
}

(4) 适用场景

(5) 会话间的隔离效果

TEXT 📖 仅展示
Session A:
  ctx.sessionCache.set('key', 'value-A')

Session B:
  ctx.sessionCache.get('key') → undefined  (隔离)

Session A:
  ctx.sessionCache.get('key') → 'value-A'  (本会话可访问)

4. 请求作用域(Request Scope)

(1) 概念

请求作用域为每次工具调用或 LLM 请求创建独立实例:

TYPESCRIPT
export default class RequestContextService extends Service {
  static scope = 'request'

  constructor(ctx: Context) {
    super(ctx, 'request-context')
  }
}

(2) 请求作用域的生命周期

100%
graph LR
    R1[请求 1 开始] --> S1[Service 实例 1]
    R2[请求 2 开始] --> S2[Service 实例 2]
    R1 --> E1[请求 1 完成 → 实例 1 销毁]
    R2 --> E2[请求 2 完成 → 实例 2 销毁]

(3) 适用场景

(4) 三种作用域对比

维度 全局 会话 请求
实例数 1 每会话 1 每请求 1
生命周期 进程存活 会话存活 请求存活
状态共享 全局共享 会话内共享 请求内独享
内存占用
适用 配置/连接池 会话缓存/历史 权限/计时

5. isolate realm 配置

(1) realm 概念

realm 是 Cordis 的隔离域——在同一个 DSH 实例中创建独立的插件空间:

YAML
# cordis.yml
realms:
  agent-a:
    isolate: ['cache', 'tools']
    plugins:
      my-tool-a:
        $insert: ./plugins/tool-a
  
  agent-b:
    isolate: ['cache', 'tools']
    plugins:
      my-tool-b:
        $insert: ./plugins/tool-b

(2) isolate 字段

isolate 列表指定哪些服务在 realm 内独立实例化:

YAML
realms:
  my-realm:
    isolate:
      - cache       # cache 服务独立实例
      - tools       # tools 服务独立实例
      # 未列出的服务仍然全局共享

(3) realm 内的服务实例

TEXT 📖 仅展示
全局: llm (共享)
realm-a: cache (独立), tools (独立)
realm-b: cache (独立), tools (独立)

realm-a 中的插件 → ctx.cache = realm-a 的 cache
realm-b 中的插件 → ctx.cache = realm-b 的 cache
两者互不影响

(4) realm 的使用场景

场景 说明
多 Agent 不同 Agent 有不同的工具集和缓存
多租户 不同租户的服务互相隔离
测试 测试 realm 不影响生产 realm
A/B 测试 两个 realm 使用不同的服务实现

(5) realm 间通信

realm 之间默认隔离,但可以通过全局服务通信:

TYPESCRIPT
// 全局服务(不受 isolate 影响)
export default class EventBusService extends Service {
  constructor(ctx: Context) {
    super(ctx, 'event-bus')  // 未列入 isolate → 全局共享
  }

  emit(event: string, data: any) { /* ... */ }
  on(event: string, handler: Function) { /* ... */ }
}

// realm-a 中的插件
ctx.eventBus.emit('data-updated', { source: 'realm-a' })

// realm-b 中的插件
ctx.eventBus.on('data-updated', (data) => {
  ctx.logger.info(`received from ${data.source}`)
})

6. 作用域与 Agent preset

(1) Agent preset 概念

Agent preset 是预定义的 Agent 配置,包含工具集、模型参数和作用域设置:

YAML
presets:
  coder:
    model: deepseek-coder
    tools: [file_edit, shell, search]
    mode: standard
    
  reviewer:
    model: deepseek-chat
    tools: [file_edit, search]
    mode: minimal
    isolate: [cache]

(2) preset 与作用域的关系

每个 preset 可以指定 isolate 列表,为该 Agent 创建隔离的服务实例:

TEXT 📖 仅展示
coder Agent:  共享 cache, 独立 tools
reviewer Agent: 独立 cache, 共享 tools

(3) 多 Agent 场景

YAML
# cordis.yml
agents:
  coder:
    preset: coder
    isolate: [tools]
    
  reviewer:
    preset: reviewer
    isolate: [tools, cache]

(4) Agent 间协作

100%
graph TB
    subgraph Global
        LLM[llm Service]
        EVENT[event-bus Service]
    end
    subgraph Agent-Coder
        CT[tools Service]
        CC[cache Service]
    end
    subgraph Agent-Reviewer
        RT[tools Service]
        RC[cache Service]
    end
    CT --> LLM
    RT --> LLM
    CT --> EVENT
    RT --> EVENT

7. 多 Agent 环境下的服务隔离

(1) 隔离策略选择

TEXT 📖 仅展示
完全共享:     所有服务全局 → 简单但可能冲突
完全隔离:     所有服务独立 → 安全但资源浪费
混合隔离:     核心服务共享 + 业务服务隔离 → 平衡方案

推荐混合隔离:

服务类型 隔离策略 原因
llm 共享 API 调用可复用
sessions 共享 会话管理统一
tools 隔离 各 Agent 工具集不同
cache 隔离 各 Agent 缓存独立
fs 共享 文件系统只有一个

(2) ▶ 示例 2

YAML
agents:
  frontend-dev:
    preset: coder
    isolate: [tools, cache]
    tools:
      - file_edit
      - shell
      - search
    config:
      cache:
        maxSize: 100
  
  backend-dev:
    preset: coder
    isolate: [tools, cache]
    tools:
      - file_edit
      - shell
      - search
      - database
    config:
      cache:
        maxSize: 200

(3) 资源消耗评估

隔离级别 内存 CPU 连接数
全局共享 1x 1x 1x
2 Agent 隔离 ~2x ~1.5x ~2x
5 Agent 隔离 ~5x ~3x ~5x

(4) 隔离泄漏检测

TYPESCRIPT
// 监控服务实例数量
ctx.on('service/created', (name, instance) => {
  ctx.logger.info(`service created: ${name}, total instances: ${countInstances(name)}`)
})

// 如果某个服务的实例数远超 Agent 数,可能有泄漏

❓ 常见问题

Q 默认不声明 scope,服务是全局的吗?
A 是的。不声明 static scope 的 Service 默认全局单例。
Q 会话作用域的 Service 在会话结束后会被回收吗?
A 会。会话销毁时,该会话的 Service 实例自动清理,包括 ctx.effect 注册的资源。
Q realm 的 isolate 列表可以动态修改吗?
A 不可以。realm 配置在启动时确定,修改需要重启。
Q 一个 Service 能同时存在于多个作用域吗?
A 不能。一个 Service 要么全局,要么会话级,要么请求级。如果需要跨作用域共享数据,用全局事件总线。
Q 请求作用域的性能开销大吗?
A 每次请求创建和销毁 Service 有开销。只在确实需要请求级隔离时使用,否则用全局或会话作用域。
Q 如何调试作用域问题?
A 在 Service 构造函数中打印实例 ID: typescript constructor(ctx: Context) { super(ctx, 'cache') console.log(`cache instance created: ${this.id}, scope: ${this.scope}`) } ---

📖 小节


📝 作业

1. ⭐ 基础题:编写一个会话作用域的 SessionStateService,为每个会话维护独立的键值存储。启动两个会话,验证数据互不干扰。

2. ⭐⭐ 进阶题:配置一个 realm,将 cache 和 tools 服务隔离。在 realm 内外分别访问 cache,验证得到不同的实例。

3. ⭐⭐⭐ 挑战题:设计一个双 Agent 系统:coder 和 reviewer。coder 有 file_edit/shell 工具,reviewer 只有 file_edit/search 工具。两者共享 llm 和 sessions,但缓存和工具集各自隔离。验证:coder 的 shell 工具 reviewer 不可见,两者缓存互不影响。

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏