30 KiB
30 KiB
10 - 实施计划详解 (Implementation Plan)
1. 总体时间线
Week 1 Week 2 Week 2-3 Week 3 Week 4 Week 5
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Phase 1 │ │ Phase 2 │ │ Phase 3 │ │ Phase 4 │ │ Phase 5+6│ │ Phase 7 │
│ │ │ │ │ │ │ │ │ │ │ │
│ 架构文档 │──→│ 基础设施 │──→│ 专家Agent│──→│ Coordinator│──→│ 集成+前端│──→│ 测试+优化│
│ + 类型 │ │ │ │ │ │ │ │ │ │ │
│ 定义 │ │ Queue │ │ 6个Agent │ │ 核心Loop │ │ Module │ │ 场景测试 │
│ │ │ Context │ │ 6份Prompt│ │ 主Prompt │ │ Gateway │ │ 性能优化 │
│ │ │ Base │ │ │ │ │ │ Frontend │ │ 旧代码清理│
└──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘
2. Phase 1: 架构文档 + 类型定义 (Week 1)
2.1 架构文档(12份)
| 序号 | 文件 | 内容 | 状态 |
|---|---|---|---|
| 00 | 00-overview.md |
总览 + 架构图 | ✅ 已完成 |
| 01 | 01-coordinator-agent.md |
Coordinator 设计 | ✅ 已完成 |
| 02 | 02-specialist-agents.md |
6 个专家 Agent 设计 | 待完成 |
| 03 | 03-agent-communication.md |
Agent 间通信协议 | 待完成 |
| 04 | 04-streaming-protocol.md |
流式传输协议 | 待完成 |
| 05 | 05-frontend-integration.md |
前端集成方案 | 待完成 |
| 06 | 06-token-cost-management.md |
Token 与成本管理 | 待完成 |
| 07 | 07-testing-strategy.md |
测试策略 | 待完成 |
| 08 | 08-context-injection.md |
动态上下文注入 | ✅ 已完成 |
| 09 | 09-tool-execution.md |
工具并发执行 | ✅ 已完成 |
| 10 | 10-implementation-plan.md |
实施计划(本文档) | ✅ 已完成 |
| 11 | 11-prompt-templates.md |
所有 Prompt 模板 | ✅ 已完成 |
2.2 类型定义文件
需要创建以下类型定义文件:
packages/services/conversation-service/src/infrastructure/agents/
├── types/
│ ├── agent.types.ts # Agent 相关类型
│ ├── stream.types.ts # 流式事件类型
│ └── context.types.ts # 上下文注入类型
agent.types.ts:
// 核心 Agent 类型定义
/** Agent 名称枚举 */
export enum AgentName {
COORDINATOR = 'coordinator',
POLICY_EXPERT = 'policy_expert',
ASSESSMENT_EXPERT = 'assessment_expert',
STRATEGIST = 'strategist',
OBJECTION_HANDLER = 'objection_handler',
CASE_ANALYST = 'case_analyst',
MEMORY_MANAGER = 'memory_manager',
}
/** Agent 使用的模型 */
export enum AgentModel {
SONNET = 'claude-sonnet-4-20250514',
HAIKU = 'claude-haiku-4-20250514',
}
/** Agent 配置 */
export interface AgentConfig {
name: AgentName;
model: AgentModel;
maxTokens: number;
maxTurns: number; // Agent mini-loop 最大轮次
timeoutMs: number; // 超时时间
tools: string[]; // 可用工具名列表
systemPromptFile: string; // Prompt 文件路径
}
/** Agent 执行上下文 */
export interface AgentExecutionContext {
userId: string;
conversationId: string;
coordinatorTurn: number; // Coordinator 当前轮次
parentToolUseId: string; // 触发此 Agent 的 tool_use ID
}
/** Agent Loop 参数 */
export interface AgentLoopParams {
messages: Anthropic.MessageParam[];
systemPrompt: string[] | Anthropic.TextBlockParam[];
tools: Anthropic.Tool[];
maxTurns: number;
maxBudgetUsd: number;
conversationId: string;
userId: string;
abortSignal?: AbortSignal;
}
/** 咨询状态(从 consulting_state XML tag 提取) */
export interface ConsultingStateReport {
currentStage: string;
collectedFields: string[];
nextAction: string;
confidenceLevel: 'low' | 'medium' | 'high';
recommendedPrograms?: string[];
}
stream.types.ts:
// 流式事件类型
/** 所有可能的 Stream 事件 */
export type StreamEvent =
| TextStreamEvent
| AgentStartEvent
| AgentProgressEvent
| AgentCompleteEvent
| ToolStartEvent
| ToolCompleteEvent
| ToolErrorEvent
| StateUpdateEvent
| UsageEvent
| ErrorEvent
| EndEvent;
export interface TextStreamEvent {
type: 'text';
content: string;
}
export interface AgentStartEvent {
type: 'agent_start';
agentName: string;
toolUseId: string;
}
export interface AgentProgressEvent {
type: 'agent_progress';
agentName: string;
turn: number;
maxTurns: number;
}
export interface AgentCompleteEvent {
type: 'agent_complete';
agentName: string;
durationMs: number;
tokensUsed?: { input: number; output: number };
}
export interface StateUpdateEvent {
type: 'state_update';
state: ConsultingStateReport;
}
export interface UsageEvent {
type: 'usage';
usage: { inputTokens: number; outputTokens: number };
totalCostUsd: number;
}
export interface ErrorEvent {
type: 'error';
code: string;
message: string;
}
export interface EndEvent {
type: 'end';
totalTokens: { input: number; output: number };
totalCostUsd: number;
turnsUsed: number;
agentsCalled: string[];
}
context.types.ts:
- 详见 08-context-injection.md 第 3 节
交付标准:
- 所有类型文件通过
tsc --noEmit类型检查 - 每个 interface 有 JSDoc 注释
- 导出为 barrel file (
types/index.ts)
3. Phase 2: 基础设施 (Week 2)
3.1 文件结构
packages/services/conversation-service/src/infrastructure/agents/
├── types/ # Phase 1 产物
│ ├── agent.types.ts
│ ├── stream.types.ts
│ ├── context.types.ts
│ └── index.ts
├── core/ # Phase 2 产物
│ ├── tool-execution-queue.ts # 工具并发执行队列
│ ├── context-injector.service.ts # 上下文注入器
│ ├── base-specialist.service.ts # 专家 Agent 基类
│ ├── agent-executor.ts # Agent 执行器工厂
│ └── token-tracker.ts # Token 追踪器
3.2 tool-execution-queue.ts
- 完整实现详见 09-tool-execution.md 第 4 节
- 关键依赖:
tool-execution.types.ts - 单测覆盖:
- 纯并发批次(所有 safe 工具)
- 纯串行批次(所有 unsafe 工具)
- 混合批次(safe + unsafe 交替)
- 单个工具超时
- 批次中一个工具失败
- 空请求
- 结果排序正确性
// 单测示例
describe('ToolExecutionQueue', () => {
it('should execute concurrent-safe tools in parallel', async () => {
const queue = new ToolExecutionQueue();
const executionOrder: string[] = [];
queue.registerTool('tool_a', {
isConcurrencySafe: true,
executor: async () => {
executionOrder.push('a_start');
await sleep(100);
executionOrder.push('a_end');
return { content: 'a', success: true };
},
// ...
});
queue.registerTool('tool_b', {
isConcurrencySafe: true,
executor: async () => {
executionOrder.push('b_start');
await sleep(50);
executionOrder.push('b_end');
return { content: 'b', success: true };
},
// ...
});
const results = await queue.executeAll([
{ toolUseId: '1', toolName: 'tool_a', input: {}, originalIndex: 0 },
{ toolUseId: '2', toolName: 'tool_b', input: {}, originalIndex: 1 },
]);
// 两个工具应该几乎同时开始
expect(executionOrder[0]).toBe('a_start');
expect(executionOrder[1]).toBe('b_start');
// b 先完成(50ms vs 100ms)
expect(executionOrder[2]).toBe('b_end');
expect(executionOrder[3]).toBe('a_end');
// 结果按 originalIndex 排序
expect(results[0].toolName).toBe('tool_a');
expect(results[1].toolName).toBe('tool_b');
});
});
3.3 context-injector.service.ts
- 完整实现详见 08-context-injection.md 第 5 节
- 关键依赖:
KnowledgeClientService,context.types.ts - 单测覆盖:
- 所有 8 种上下文的独立构建
- 缓存命中/未命中
- Token 预算裁剪
- P0 上下文不被裁剪
- 缓存失效
- auto-compaction 触发条件
3.4 base-specialist.service.ts
- 完整实现详见 09-tool-execution.md 第 6 节
- 关键依赖:
@anthropic-ai/sdk - 单测覆盖:
- Mini-loop 正常完成(1轮无工具调用)
- Mini-loop 有工具调用(2轮)
- 达到 maxTurns 强制终止
- API 错误处理
- Token 追踪回调
3.5 交付标准
- 所有基础设施组件可以独立运行单测
- 不依赖具体的 Specialist Agent 实现
- 使用 mock 的 Claude API 进行测试
4. Phase 3: 专家 Agent (Week 2-3)
4.1 文件结构
packages/services/conversation-service/src/infrastructure/agents/
├── specialists/
│ ├── policy-expert.service.ts # 政策专家
│ ├── assessment-expert.service.ts # 评估专家
│ ├── strategist.service.ts # 策略顾问
│ ├── objection-handler.service.ts # 异议处理
│ ├── case-analyst.service.ts # 案例分析
│ └── memory-manager.service.ts # 记忆管理
├── prompts/
│ ├── coordinator-system-prompt.ts # Phase 4
│ ├── policy-expert-prompt.ts
│ ├── assessment-expert-prompt.ts
│ ├── strategist-prompt.ts
│ ├── objection-handler-prompt.ts
│ ├── case-analyst-prompt.ts
│ └── memory-manager-prompt.ts
4.2 各 Agent 实现计划
| Agent | 继承 | Model | 工具 | 预估代码量 | 优先级 |
|---|---|---|---|---|---|
PolicyExpertService |
BaseSpecialistService |
Sonnet | search_knowledge |
~120 行 | P0 |
AssessmentExpertService |
BaseSpecialistService |
Sonnet | search_knowledge, get_user_context |
~200 行 | P0 |
MemoryManagerService |
BaseSpecialistService |
Haiku | save_user_memory, get_user_context |
~150 行 | P0 |
StrategistService |
BaseSpecialistService |
Sonnet | get_user_context |
~100 行 | P1 |
ObjectionHandlerService |
BaseSpecialistService |
Sonnet | search_knowledge, get_user_context |
~120 行 | P1 |
CaseAnalystService |
BaseSpecialistService |
Haiku | search_knowledge, get_user_context |
~100 行 | P2 |
4.3 开发顺序
建议按以下顺序开发(优先级 + 依赖关系):
1. MemoryManagerService → 最简单,验证 BaseSpecialist + 工具执行
↓
2. PolicyExpertService → 最常用,验证 knowledge-service 集成
↓
3. AssessmentExpertService → 核心业务,需要 knowledge + 用户上下文
↓
4. StrategistService → 辅助 Coordinator 决策
↓
5. ObjectionHandlerService → 异议处理,依赖 knowledge
↓
6. CaseAnalystService → 最后实现,依赖度最低
4.4 每个 Agent 的独立测试策略
// 以 PolicyExpertService 为例的独立测试
describe('PolicyExpertService', () => {
let service: PolicyExpertService;
let mockAnthropicClient: jest.Mocked<Anthropic>;
let mockKnowledgeClient: jest.Mocked<KnowledgeClientService>;
beforeEach(() => {
mockAnthropicClient = createMockAnthropicClient();
mockKnowledgeClient = createMockKnowledgeClient();
service = new PolicyExpertService(mockAnthropicClient, mockKnowledgeClient);
});
it('should answer policy questions without tool calls', async () => {
// Mock: Claude 直接回答,不调用工具
mockAnthropicClient.messages.create.mockResolvedValue({
content: [{ type: 'text', text: '高才通B类要求...' }],
usage: { input_tokens: 500, output_tokens: 200 },
stop_reason: 'end_turn',
});
const result = await service.execute({
input: { query: '高才通B类条件是什么' },
maxTurns: 3,
});
expect(result.output).toContain('高才通');
expect(result.turnsUsed).toBe(1);
});
it('should use search_knowledge tool when needed', async () => {
// Mock: Claude 调用 search_knowledge,再用结果生成回答
mockAnthropicClient.messages.create
.mockResolvedValueOnce({
content: [
{ type: 'tool_use', id: 't1', name: 'search_knowledge', input: { query: 'TTPS B类 条件' } },
],
usage: { input_tokens: 500, output_tokens: 100 },
stop_reason: 'tool_use',
})
.mockResolvedValueOnce({
content: [{ type: 'text', text: '根据查询结果,高才通B类...' }],
usage: { input_tokens: 800, output_tokens: 300 },
stop_reason: 'end_turn',
});
mockKnowledgeClient.retrieveKnowledge.mockResolvedValue({
content: '高才通B类要求全球百强大学学士学位...',
sources: [{ articleId: '1', title: '高才通指南', similarity: 0.92 }],
});
const result = await service.execute({
input: { query: '高才通B类条件' },
maxTurns: 3,
onToolCall: jest.fn(),
});
expect(result.output).toContain('根据查询结果');
expect(result.turnsUsed).toBe(2);
expect(mockKnowledgeClient.retrieveKnowledge).toHaveBeenCalled();
});
});
4.5 交付标准
- 每个 Agent 有独立的单元测试(mock Claude API + mock 外部服务)
- 每个 Agent 的 Prompt 是独立文件,可以独立调整
- 所有 Agent 通过
BaseSpecialistService.execute()统一调用
5. Phase 4: Coordinator (Week 3)
5.1 文件结构
packages/services/conversation-service/src/infrastructure/agents/
├── coordinator/
│ ├── coordinator-agent.service.ts # 主服务
│ ├── agent-loop.ts # 核心递归循环
│ └── state-extractor.ts # 从回复中提取 consulting_state
├── prompts/
│ └── coordinator-system-prompt.ts # 500+ 行 Prompt
5.2 coordinator-system-prompt.ts
这是整个系统最重要的文件,详见 11-prompt-templates.md。
关键结构:
export function buildCoordinatorSystemPrompt(config: {
expertContact: { wechat: string; phone: string; workingHours: string };
paidServices: { assessmentPrice: number; description: string };
currentDate: string;
}): string {
return `
# 身份定义
...(约 30 行)
# 你的专家团队
...(约 80 行)
# 六大移民类别
...(约 200 行)
# 对话策略
...(约 100 行)
# 回复规范
...(约 40 行)
# 状态报告格式
...(约 30 行)
# 业务规则
...(约 20 行)
`;
}
5.3 agent-loop.ts
核心递归循环,详见 01-coordinator-agent.md 第 4 节。
关键特性:
async function* agentLoop(): AsyncGenerator 模式- 递归调用自身(tool_results → 再次调用 Claude)
- 集成 ContextInjector
- 集成 ToolExecutionQueue
- 集成 state extractor
- abort 信号支持
5.4 coordinator-agent.service.ts
NestJS 服务,封装 agent-loop,对外暴露与旧 ClaudeAgentServiceV2 相同的接口:
@Injectable()
export class CoordinatorAgentService {
constructor(
private contextInjector: ContextInjectorService,
private toolExecutionQueue: ToolExecutionQueue,
// ... 各 Specialist Agent
) {}
async *sendMessage(params: {
conversationContext: ConversationContext;
userMessage: string;
attachments?: FileAttachment[];
userId: string;
conversationId: string;
deviceInfo?: DeviceInfo;
}): AsyncGenerator<StreamEvent> {
// 委托给 agentLoop
yield* agentLoop({
messages: this.buildMessages(params),
systemPrompt: this.buildSystemPrompt(),
tools: this.toolExecutionQueue.getClaudeTools(),
maxTurns: 15,
maxBudgetUsd: 0.50,
conversationId: params.conversationId,
userId: params.userId,
});
}
}
5.5 交付标准
- Coordinator 可以独立运行集成测试(使用真实 Claude API)
- agent-loop 有完整的单元测试(mock API)
- System Prompt 经过人工审查
- 通过 5 个核心对话场景的 E2E 测试
6. Phase 5: 集成 (Week 4 前半)
6.1 NestJS Module 集成
新增 agents.module.ts:
// packages/services/conversation-service/src/infrastructure/agents/agents.module.ts
@Module({
imports: [KnowledgeModule], // 依赖 KnowledgeClientService
providers: [
// Core
ToolExecutionQueue,
ContextInjectorService,
// Specialists
PolicyExpertService,
AssessmentExpertService,
StrategistService,
ObjectionHandlerService,
CaseAnalystService,
MemoryManagerService,
// Coordinator
CoordinatorAgentService,
],
exports: [CoordinatorAgentService],
})
export class AgentsModule {}
修改 claude.module.ts:
// 在 claude.module.ts 中导入 AgentsModule
@Module({
imports: [AgentsModule], // 新增
providers: [
ClaudeAgentServiceV2, // 保留旧服务(过渡期)
// ...
],
exports: [
ClaudeAgentServiceV2, // 保留旧导出
CoordinatorAgentService, // 新增导出
],
})
export class ClaudeModule {}
修改 conversation.service.ts:
// 切换注入(使用 feature flag)
@Injectable()
export class ConversationService {
constructor(
@Inject(CONVERSATION_REPOSITORY)
private readonly conversationRepo: IConversationRepository,
@Inject(MESSAGE_REPOSITORY)
private readonly messageRepo: IMessageRepository,
// 旧服务(过渡期保留)
private readonly claudeAgentService: ClaudeAgentServiceV2,
// 新服务
private readonly coordinatorAgentService: CoordinatorAgentService,
private readonly configService: ConfigService,
) {}
private get useNewArchitecture(): boolean {
return this.configService.get<boolean>('USE_MULTI_AGENT', false);
}
async *sendMessage(params: SendMessageParams): AsyncGenerator<StreamChunk> {
if (this.useNewArchitecture) {
yield* this.sendMessageV3(params); // 新架构
} else {
yield* this.sendMessageV2(params); // 旧架构
}
}
}
更新 conversation.gateway.ts:
// 新增 Agent 相关的 WebSocket 事件
// stream_chunk 保持不变
// 新增:
// agent_start { agentName, conversationId }
// agent_progress { agentName, turn, maxTurns, conversationId }
// agent_complete { agentName, durationMs, conversationId }
6.2 Feature Flag 策略
环境变量: USE_MULTI_AGENT=true/false
开发环境: true (直接使用新架构)
测试环境: true (测试新架构)
生产环境: false (等全部测试通过后切换)
6.3 共享类型更新
// packages/shared/types/src/conversation.ts
// 新增 StreamEvent 类型供前端使用
export interface AgentStatusEvent {
type: 'agent_start' | 'agent_progress' | 'agent_complete';
agentName: string;
conversationId: string;
// agent_progress only
turn?: number;
maxTurns?: number;
// agent_complete only
durationMs?: number;
}
6.4 交付标准
- Feature flag 可以在不重启服务的情况下切换
- 旧架构在
USE_MULTI_AGENT=false时完全不受影响 - WebSocket 事件向后兼容(新事件是追加的,不修改已有事件)
7. Phase 6: 前端 (Week 4 后半)
7.1 前端文件修改
packages/clients/web-client/src/
├── stores/
│ └── chatStore.ts # 新增 agentStatus 状态
├── components/
│ ├── chat/
│ │ ├── ChatWindow.tsx # 处理新的 WebSocket 事件
│ │ ├── MessageBubble.tsx # 可能需要微调
│ │ └── AgentStatus.tsx # 新增:Agent 工作状态组件
│ └── shared/
│ └── AgentBadge.tsx # 新增:Agent 名称+状态徽章
7.2 chatStore 更新
// chatStore.ts (Zustand)
interface AgentStatus {
name: string;
displayName: string; // 中文显示名
status: 'idle' | 'working' | 'completed';
startedAt?: number;
completedAt?: number;
durationMs?: number;
}
interface ChatState {
// 已有状态...
messages: Message[];
isStreaming: boolean;
// 新增:Agent 状态
activeAgents: AgentStatus[];
agentHistory: AgentStatus[]; // 本次对话中所有 Agent 调用记录
}
// Agent 名称映射
const AGENT_DISPLAY_NAMES: Record<string, string> = {
policy_expert: '政策专家',
assessment_expert: '评估专家',
strategist: '策略顾问',
objection_handler: '异议处理',
case_analyst: '案例分析',
memory_manager: '记忆管理',
};
7.3 AgentStatus 组件
// AgentStatus.tsx
// 显示在聊天窗口中,消息气泡和输入框之间
function AgentStatus({ agents }: { agents: AgentStatus[] }) {
const workingAgents = agents.filter(a => a.status === 'working');
if (workingAgents.length === 0) return null;
return (
<div className="agent-status-bar">
{workingAgents.map(agent => (
<div key={agent.name} className="agent-badge working">
<span className="agent-icon">🔄</span>
<span className="agent-name">{agent.displayName}</span>
<span className="agent-time">
{formatElapsedTime(Date.now() - (agent.startedAt || 0))}
</span>
</div>
))}
<span className="agent-hint">正在分析中...</span>
</div>
);
}
7.4 ChatWindow 事件处理
// ChatWindow.tsx - WebSocket 事件处理更新
socket.on('agent_start', (data: { agentName: string; conversationId: string }) => {
chatStore.addActiveAgent({
name: data.agentName,
displayName: AGENT_DISPLAY_NAMES[data.agentName] || data.agentName,
status: 'working',
startedAt: Date.now(),
});
});
socket.on('agent_complete', (data: { agentName: string; durationMs: number }) => {
chatStore.completeAgent(data.agentName, data.durationMs);
});
socket.on('stream_end', () => {
chatStore.clearActiveAgents(); // 清除所有工作中的 Agent 状态
});
7.5 交付标准
- Agent 状态在 UI 中实时显示
- Agent 完成后自动消失(带淡出动画)
- 在弱网环境下不会出现 Agent 状态 "卡住" 的问题(超时自动清除)
- 旧架构模式下不显示 Agent 状态
8. Phase 7: 测试 + 优化 + 清理 (Week 5)
8.1 测试场景矩阵
| 场景编号 | 场景描述 | 涉及 Agent | 预期行为 |
|---|---|---|---|
| S01 | 新用户首次咨询 | Coordinator + Memory | 破冰 → 收集信息 → 保存记忆 |
| S02 | 询问高才通条件 | Coordinator + Policy | 检索知识库 → 准确回答 |
| S03 | 信息收集后评估 | Coordinator + Assessment + Memory | 评估资格 → 推荐方案 |
| S04 | 用户表示犹豫 | Coordinator + Objection + Strategist | 识别异议 → 策略回应 |
| S05 | 用户要求付费评估 | Coordinator + (Payment tool) | 生成支付链接 |
| S06 | 老用户回访 | Coordinator + Memory | 加载历史记忆 → 个性化问候 |
| S07 | 并发工具调用 | Coordinator + Policy + Case | 并行执行两个 Agent |
| S08 | 超长对话 (30+ 轮) | All | Auto-compaction 触发 |
| S09 | API 错误恢复 | Coordinator | 降级到 Haiku / 友好错误 |
| S10 | 用户中途取消 | Coordinator | AbortSignal 生效 |
8.2 性能优化清单
| 优化项 | 目标 | 方法 |
|---|---|---|
| 首次回复延迟 | < 3s | Prompt Caching + 预热 |
| 并发 Agent 延迟 | < 5s (3 个 Agent 并行) | ToolExecutionQueue 并行 |
| Context Injection 延迟 | < 200ms | 缓存 + 并行获取 |
| Auto-compaction 延迟 | < 2s | Haiku 摘要 |
| Token 成本 (每对话) | < $0.30 | Haiku for 辅助 Agent + Caching |
| 内存使用 | < 100MB per 1000 并发对话 | 对话结束清理缓存 |
8.3 旧代码清理计划
阶段 A: 标记废弃 (Week 5)
// 不删除代码,只标记 @deprecated
/** @deprecated Use CoordinatorAgentService instead. Will be removed in v4. */
export class ClaudeAgentServiceV2 { ... }
/** @deprecated Replaced by Coordinator Prompt. */
export class StrategyEngineService { ... }
/** @deprecated Intent classification now handled by LLM. */
export const intentClassifier = { ... };
/** @deprecated Response quality now handled by Prompt. */
export const responseGate = { ... };
阶段 B: 删除代码 (Week 6+, after 1 week in production)
- 删除
strategy-engine.service.ts - 删除
intent-classifier.ts - 删除
response-gate.ts - 删除
default-strategy.ts - 删除
claude-agent-v2.service.ts - 移除 feature flag
8.4 Rollback 计划
如果新架构在生产中出现严重问题:
1. 即时回滚 (< 1 分钟):
设置环境变量 USE_MULTI_AGENT=false
→ 自动切回 ClaudeAgentServiceV2
→ 不需要重新部署
2. 部署回滚 (< 5 分钟):
git revert 到 Phase 5 之前的 commit
→ 重新部署 conversation-service
3. 数据恢复:
新架构不修改数据库 schema
ConsultingState 格式向后兼容
→ 无需数据迁移
9. 组件依赖图
┌─────────────────┐
│ agents.module │
└────────┬────────┘
│ exports
┌────────────▼────────────┐
│ CoordinatorAgentService │
└────────────┬────────────┘
│ depends on
┌──────────────────┼──────────────────┐
│ │ │
┌────────▼───────┐ ┌────────▼────────┐ ┌───────▼────────┐
│ ContextInjector │ │ ToolExecution │ │ agentLoop() │
│ Service │ │ Queue │ │ (function) │
└────────┬───────┘ └────────┬────────┘ └───────┬────────┘
│ │ │
┌────────▼───────┐ ┌────────▼────────┐ │
│ Knowledge │ │ Agent Executors │ │
│ ClientService │ │ (factory) │ │
└────────────────┘ └────────┬────────┘ │
│ │
┌───────▼───────────────────┘
│
┌─────────▼─────────┐
│ BaseSpecialist │
│ Service (abstract) │
└─────────┬─────────┘
│ extends
┌───────┬───────┬───┴───┬───────┬───────┐
│ │ │ │ │ │
Policy Assess Strat Object Case Memory
Expert Expert gist Handler Analyst Manager
10. 风险与缓解
| 风险 | 概率 | 影响 | 缓解措施 |
|---|---|---|---|
| Coordinator Prompt 效果不佳 | 高 | 高 | Phase 4 投入大量时间测试 Prompt,准备多个版本 A/B 测试 |
| Token 成本超预期 | 中 | 中 | 监控每次对话成本,设置 maxBudgetUsd 硬上限 |
| 并发 Agent 导致 Rate Limit | 中 | 中 | 实现指数退避重试,降级到 Haiku |
| Context Window 不够用 | 低 | 高 | Auto-compaction + 严格的 token 预算 |
| 前端 Agent 状态同步问题 | 中 | 低 | WebSocket 事件超时自动清理 |
| 旧代码删除导致回归 | 低 | 高 | Feature flag 过渡期,完善的回滚计划 |
11. 交付 Checklist
Phase 1 Checklist
- 12 份架构文档全部完成
agent.types.ts通过类型检查stream.types.ts通过类型检查context.types.ts通过类型检查- 所有类型有 JSDoc 注释
Phase 2 Checklist
ToolExecutionQueue通过所有单元测试ContextInjectorService通过所有单元测试BaseSpecialistService通过所有单元测试- 所有组件可以独立测试(不依赖 Claude API)
Phase 3 Checklist
- 6 个 Specialist Agent 全部实现
- 6 份 Prompt 文件全部编写
- 每个 Agent 有独立的单元测试
- 每个 Agent 使用真实 API 的集成测试(可选,按需运行)
Phase 4 Checklist
- Coordinator System Prompt 完成(500+ 行)
- agent-loop 通过所有单元测试
- CoordinatorAgentService 通过集成测试
- 5 个核心场景 E2E 测试通过
Phase 5 Checklist
agents.module.ts编写完成- Feature flag 切换工作正常
- 旧架构在 flag=false 时不受影响
- WebSocket 事件向后兼容
Phase 6 Checklist
- chatStore 更新完成
- AgentStatus 组件实现
- ChatWindow 处理新事件
- 前端无 regression
Phase 7 Checklist
- 10 个测试场景全部通过
- 性能指标达标
- 旧代码标记 @deprecated
- 回滚计划验证通过
- 文档更新完成