# Prompt / Context / MCP 入口收敛设计

**Date:** 2026-05-06
**Status:** Proposed design
**Scope:** Main ACP agent prompts, workspace context delivery, MCP activation, backend-only LLM prompts

---

## 1. 目标

把 Investibook 里所有“会影响 AI 行为的文本入口”统一成可解释、可治理的分层模型，避免系统继续演化成：

- `acp.py` 的 prompt builder 里有一部分规则；
- OpenCode config / 旧 `system_static.md` 里也曾有一部分规则；
- skill 里又重复一部分规则；
- backend post-pass / Lark / evaluation 各自私有 prompt；
- MCP 是否 active 由 frontend、backend fallback、opencode config 多处共同决定。

本设计优先把**逻辑框架**定清楚，不要求第一步完全重构到目标实现。

---

## 2. 设计结论

1. **Prompt 入口必须分层，不再混写。**
   - 静态规则放 `Static Session Instructions`。
   - 每轮动态权限 / 身份 / mode 放 `Turn Policy`。
   - workspace 事实和 evidence 不主动展开注入，改为 `Workspace Manifest` 指向文件，让 agent 按需读。
   - 诊断 SOP 只存在于 skills / workflow stage。
   - backend-only LLM prompt 与主 agent prompt 分开治理。

2. **MCP activation 必须显式化。**
   - `opencode.json` 里的 `mcp.enabled=true` 只表示“这个 server 可被启动”，不等于“本次对话应 active”。
   - 每次 session / turn 必须有明确 active MCP allowlist。
   - allowlist 为空时，应加载 0 个 MCP server，而不是 fallback 到“加载所有 configured MCP”。

3. **Workspace meta 不应该作为默认上下文正文。**
   - 如果只是第一轮注入一次，短期优先级不高。
   - 目标模型仍然应该是：只注入 manifest 路径和可读文件索引；具体 `cluster_meta.json`、`issue_meta.json`、`evidence_summary_for_agent.txt` 由 agent 在需要时读取。

4. **Prompt 需要 registry。**
   - 每一个 prompt builder 要有 owner、生命周期、输入、输出、预算、是否进入主 agent context。
   - 没登记的新 prompt 不应该随意新增。

---

## 3. 当前 MCP 状态梳理

### 3.1 配置层

当前 `agentkit/config/opencode.json.template` 里配置了两个 MCP server：

```text
resource-worker-mcp
devops
```

两者在模板里都是 `enabled: true`。这表示 OpenCode 配置中“可用”，但业务上不应该直接等价为“每个会话都 active”。

### 3.2 Web 入口

当前 frontend workspace 默认 source 里只有 `mcp-devops` 这个 MCP connector。`WorkspaceProvider` 又有一个临时逻辑：把所有 MCP connector source 强制置为 active。

因此 Web chat 通常会传：

```text
active_mcp_servers=devops
```

backend 收到非空 allowlist 后，只加载 `devops`。

### 3.3 Lark 入口

Lark 当前调用 `run_chat_and_wait(..., active_mcp_servers="devops")`，所以也是显式加载 `devops`。

### 3.4 风险入口

backend 的 `_load_mcp_servers_config(workspace_dir, active_server_ids=None)` 当前语义是：

```text
active_server_ids is None -> 加载 opencode.json 中所有 enabled MCP
```

这意味着任何没有传 `active_mcp_servers` 的入口，都可能意外加载：

```text
devops
resource-worker-mcp
```

这是需要收敛的主要问题。目标语义应该改为：

```text
active_server_ids is None -> []
active_server_ids == [] -> []
active_server_ids == ["devops"] -> only devops
```

如确实需要“加载所有 configured MCP”，必须显式传特殊值，例如 `active_mcp_servers="*"`，并且只允许 admin / debug 场景使用。

---

## 4. Prompt / Context 入口分类

### 4.1 主 Agent Context 入口

这些会进入主 ACP/OpenCode agent context，直接影响用户对话行为。

| 入口 | 生命周期 | 当前例子 | 目标职责 |
| --- | --- | --- | --- |
| Static Session Instructions | ACP 首次 prompt 注入 | `build_static_protocol()` | 永远成立的行为规则和路由原则 |
| Skill Descriptions | session / skill discovery | `.opencode/skills/**/SKILL.md` frontmatter | skill 匹配，不承载长 SOP |
| Skill Body / Stage Files | agent 按需 read | `tidb-clinic-diagnosis/SKILL.md`, `workflow/stages/*.md` | 诊断流程、工具说明、知识正文 |
| Turn Policy | 每轮 user prompt 前 | `build_mcp_guidance_prompt()`、user identity | 本轮权限、active MCP allowlist、最小身份信息 |
| Workspace Context | 当前第一轮注入 | `build_dynamic_context()` | 目标改为 manifest hint，不展开 meta 正文 |
| Diagnosis Stage Guidance | Phase 2，每轮按需 | 未来 `diagnosis_orchestration.py` | 只在诊断已开始时提示当前 stage |

### 4.2 Backend-only LLM Prompt

这些不进入主 agent context，应单独治理，不能混进 system prompt 设计。

| 入口 | 位置 | 用途 | 是否影响主 agent context |
| --- | --- | --- | --- |
| Jira comments summary | `backend/services/source_preparer.py` | 将 Jira comments 摘要成状态说明 | 否 |
| Workspace evidence post-pass | `workspace_evidence_postpass.py` | hidden authored evidence patch | 否 |
| Evaluation prompt | `core/evaluation.py` | 评估诊断质量 | 否 |
| AutoChat intervention judge | `core/auto_chat.py` | 判断是否需要人工介入 | 否 |
| Lark wrapper prompt | `api/lark.py` | 把群聊消息包装成 agent 请求 | 是，作为用户消息内容进入 agent |

Lark wrapper 比较特殊：它本身不是 system prompt，但会作为用户消息传给主 agent，所以也必须纳入 registry。

---

## 5. 目标 Prompt Surface 模型

### 5.1 Static Session Instructions

来源：

```text
backend/investibook/core/system_prompt.py::build_static_protocol()
```

允许包含：

- 初始化不主动行动。
- 语言规则。
- ticket-only 不触发诊断。
- 诊断触发 gate。
- 时间处理原则。
- 不输出监控链接。
- “诊断触发后读取 `tidb-clinic-diagnosis` pipeline”。

禁止包含：

- workspace 具体 ID / cluster meta / issue meta。
- 完整 metric routing 详表。
- 完整 Step A/B/C/D/E SOP。
- 大段工具使用手册。
- MCP server 详细工具列表。

### 5.2 Turn Policy

来源：

```text
backend/investibook/core/system_prompt.py
```

建议重命名为：

```text
backend/investibook/core/prompting/turn_policy.py
```

允许包含：

- 当前 active MCP allowlist。
- “未在 allowlist 的 MCP 不可用”。
- 当前登录用户 email，前提是确实需要用于审计 / 查询上下文。
- 当前 turn 的 mode，例如 Lark read-only wrapper、admin debug、normal chat。

禁止包含：

- workspace cluster meta 正文。
- evidence 摘要正文。
- 诊断 SOP。
- 任何可以通过读文件获得的大块上下文。

### 5.3 Workspace Manifest

目标新增一个 workspace 内的 manifest，作为 agent 需要时读取 workspace meta 的入口。

建议路径：

```text
<workspace>/context/workspace_manifest.json
```

或者如果希望更贴近 agent 阅读：

```text
<workspace>/context/workspace_manifest.md
```

内容只放索引和路径，不放大块正文：

```json
{
  "workspace_id": "ws-xxx",
  "issues": [
    {
      "issue_id": "O11Y-123",
      "issue_meta_path": "issues/O11Y-123/issue_meta.json",
      "cluster_meta_path": "issues/O11Y-123/cluster_meta.json",
      "comments_summary_path": "issues/O11Y-123/comments_summary_ai.md"
    }
  ],
  "evidence": {
    "summary_text_path": "evidences/evidence_summary_for_agent.txt",
    "summary_json_path": "evidences/evidence_summary_for_agent.json",
    "workspace_report_path": "evidences/workspace_evidence_report.json"
  },
  "skills": {
    "diagnosis_pipeline": ".opencode/skills/builtin/tidb-clinic-diagnosis/workflow/pipeline.yaml"
  }
}
```

主 agent prompt 里最多只注入：

```text
Workspace metadata is available through context/workspace_manifest.md.
Read it only when the user request requires workspace-specific facts.
```

### 5.4 Skill / Workflow Context

诊断流程正文属于 skill，不属于 system prompt：

```text
.opencode/skills/builtin/tidb-clinic-diagnosis/SKILL.md
.opencode/skills/builtin/tidb-clinic-diagnosis/workflow/stages/*.md
```

原则：

- `SKILL.md` 是目录页。
- Stage 文件是诊断正文。
- Knowledge JSON 是引用文件。
- Agent 在需要时 read。

### 5.5 Diagnosis Stage Guidance

Phase 2 才引入。它不是 SOP，也不是完整上下文，只是一条短提醒：

```text
Diagnosis is in stage node-d-tikv. If continuing diagnosis, read
.opencode/skills/builtin/tidb-clinic-diagnosis/generated/stages/04-node-d-tikv.md.
```

只有满足以下条件才注入：

- 用户请求是诊断继续 / root cause / evidence analysis；
- 或 workspace 已有 active diagnosis state；
- 且不是 ticket-only 请求。

---

## 6. MCP 收敛设计

### 6.1 三层语义

| 层 | 含义 | 例子 |
| --- | --- | --- |
| Installed MCP | repo / image 中存在 server | `agentkit/mcp/...` |
| Configured MCP | workspace `opencode.json` 里有配置 | `devops`, `resource-worker-mcp` |
| Active MCP | 本次 session/turn 明确 allowlist | `["devops"]` |

只有 Active MCP 可以传给 OpenCode session。

### 6.2 目标规则

- 默认 normal chat：`active_mcp_servers=[]`。
- Web UI 如果用户没有显式启用 MCP connector，不传任何 active MCP。
- Lark 如需 DevOps，显式传 `["devops"]`。
- Backend 不允许 `None` 语义变成“加载所有 configured MCP”。
- `opencode.json` 的 `enabled` 只表示 configured server 是否可用，不表示 active。

### 6.3 为什么要这样

MCP 是可执行工具入口，不应该因为配置存在就进入 agent runtime。否则：

- agent 可见工具面过宽；
- prompt 中需要反复解释“不要用某些 MCP”；
- session cold start 更重；
- 非 Web 入口容易出现和 UI 不一致的工具集。

---

## 7. Prompt Registry 设计

新增 registry 文档或代码表，统一登记所有 prompt surface。

建议文件：

```text
backend/investibook/core/prompting/registry.py
docs/specs/prompt-context-registry.md
```

首版可以只做文档表，后续再代码化。

字段：

| 字段 | 含义 |
| --- | --- |
| `id` | 稳定 ID，例如 `main.static.system` |
| `owner` | 代码 owner / 模块 |
| `file` | prompt 来源文件 |
| `lifecycle` | session / turn / on-demand / backend-job |
| `enters_main_agent_context` | 是否进入主 agent |
| `max_budget_chars` | 预算 |
| `allowed_content` | 允许内容 |
| `forbidden_content` | 禁止内容 |
| `tests` | 覆盖测试 |

示例：

| id | lifecycle | file | main context | budget |
| --- | --- | --- | --- | ---: |
| `main.static.system` | first ACP prompt | `core/system_prompt.py::build_static_protocol()` | yes | 4000 chars |
| `main.turn.policy` | turn | `core/prompting/turn_policy.py` | yes | 1200 chars |
| `main.workspace.manifest_hint` | first turn / on demand | `core/prompting/workspace_manifest.py` | yes | 500 chars |
| `main.diagnosis.stage_guidance` | turn when active | `core/diagnosis_orchestration.py` | yes | 500 chars |
| `backend.evidence.postpass` | backend job | `workspace_evidence_postpass.py` | no | 12000 chars |
| `backend.evaluation` | backend job | `evaluation.py` | no | 20000 chars |
| `lark.agent.wrapper` | user-message wrapper | `api/lark.py` | yes | 6000 chars |

---

## 8. 推荐落地顺序

### Step 0：只做文档和 inventory

- 保留当前行为。
- 建立本设计文档。
- 在主设计中引用 prompt/context 收敛原则。

### Step 1：MCP active 语义收敛

目标：

- backend 显式区分 `configured` 和 `active`。
- `active_mcp_servers=None` 不再加载所有 configured MCP。
- frontend 去掉“强制所有 MCP connectors active”的临时逻辑。

验收：

- Web normal chat 默认只加载显式 active MCP。
- Lark 仍可显式加载 devops。
- 没有入口因为漏传参数而加载 `resource-worker-mcp`。

### Step 2：Prompt registry 文档化

目标：

- 列出所有 prompt builder。
- 给每个 prompt surface 加预算和边界。
- 单测只断言关键语义，不断言长文案。

### Step 3：Workspace Manifest

目标：

- backend 生成 `context/workspace_manifest.md/json`。
- `build_dynamic_context()` 从“展开 cluster meta”改为“注入 manifest hint”。
- agent 需要 workspace 事实时读 manifest，再读具体 meta 文件。

这个步骤可以后置，因为当前 workspace meta 只在第一轮注入一次，不是每轮重复注入。

### Step 4：Prompt builders 代码归拢

目标结构：

```text
backend/investibook/core/prompting/
  __init__.py
  registry.py
  turn_policy.py
  workspace_manifest.py
```

迁移：

- `build_mcp_guidance_prompt()` -> `turn_policy.py`
- `build_dynamic_context()` -> `workspace_manifest.py`
- `system_prompt.py` 保留兼容 re-export 或删除。

### Step 5：预算和 CI 检查

增加测试：

- `build_static_protocol()` 不超过预算。
- `turn_policy` 不超过预算。
- `build_static_protocol()` 不包含具体 cluster id / parent_id 示例大表。
- `turn_policy` 不包含 workspace evidence 正文。
- `active_mcp_servers=None` 不加载所有 configured MCP。

---

## 9. 和诊断知识编排的关系

本设计是 `Diagnosis Knowledge Orchestration` 的横向基础设施。

对应关系：

| 诊断编排设计 | Prompt/Context 收敛设计 |
| --- | --- |
| Phase 0 拆 `tidb-clinic-diagnosis/SKILL.md` | system prompt 只保留诊断 gate |
| Phase 1 Knowledge Units | generated stage 通过 skill 按需 read |
| Phase 2 diagnosis stage state | 注入短 stage guidance，不注入 SOP 正文 |
| Guard validation | backend-only prompt / deterministic validation，不污染主 agent |
| Evidence summary | 通过 manifest 指向文件，agent 按需读取 |

---

## 10. 完成定义

最终目标状态：

- 能列出所有 prompt 入口，没有隐藏 prompt。
- 每个 prompt 入口有 owner、生命周期、预算和边界。
- 主 agent context 只主动接收：
  - 静态行为规则；
  - 当前 turn 权限；
  - 极短 workspace manifest hint；
  - 必要的 stage guidance。
- workspace meta / evidence / SOP 正文都通过文件按需读取。
- MCP server 必须显式 active 才会加载。
- backend-only LLM prompt 不与主 agent prompt 混用。
