Files
2026Technology-Competition/docs/superpowers/specs/implementation-steps/10-phase4.2-ai-engine.md
T
范智鹏 805737fcfc feat: 设置面板 + Provider 扩展 + 构建脚本
- 设置面板:三步引导 / AI 配置 / API Key / 规则管理 / 连接测试
- Provider 重构:统一 OpenAICompatibleProvider 基类,新增 Gemini/Claude/混元/智谱等
- 审查面板 Webview:三 Tab、统计卡片、问题列表、postMessage 通信
- esbuild 构建脚本 + 生产打包 + PMD 下载
- 保存文件自动静态分析(500ms debounce)
2026-07-16 22:20:30 +08:00

7.2 KiB

Step 10 — Phase 4.2: AI 引擎 + Schema

依赖: Step 09
参考设计: §5.3, §5.4, §5.5, §5.6

目标

实现 AI 审查引擎:两并行请求(自定义规则评估 + 翻译深度审查)、JSON 解析、错误降级。

新建文件

# 文件 说明
1 src/ai/schema.ts AI 响应结构类型定义
2 src/ai/engine.ts runAIReview() 主函数

1. src/ai/schema.ts

export interface TranslatedDiagnostic {
  originalRuleId: string;
  translatedMessage: string;
  translatedSuggestion: string;
  codeDiff?: string;
}

export interface CustomRuleResult {
  ruleId: string;
  line: number;
  severity: 'error' | 'warning' | 'info';
  message: string;
}

export interface AIFinding {
  ruleId: string;
  severity: 'error' | 'warning' | 'info';
  category: 'bug' | 'performance' | 'security' | 'style' | 'design';
  title: string;
  description: string;
  suggestion: string;
  codeDiff?: string;
  line: number;
}

export interface AIResponse {
  translatedDiagnostics: TranslatedDiagnostic[];
  customRuleResults: CustomRuleResult[];
  findings: AIFinding[];
}

export interface AIEngineResult {
  customRuleResults: CustomRuleResult[];
  translatedDiagnostics: TranslatedDiagnostic[];
  findings: AIFinding[];
  degraded: boolean;
  error?: string;
}

2. src/ai/engine.ts

import * as vscode from 'vscode';
import { AIProvider } from './providers/base';
import { createProvider } from './factory';
import { getAIConfig, getApiKey } from '../config';
import { LinterDiagnostic } from '../types';
import { CustomRule } from '../rules/yaml-parser';
import {
  AIEngineResult,
  CustomRuleResult,
  TranslatedDiagnostic,
  AIFinding,
} from './schema';

function buildCustomRulePrompt(rules: CustomRule[]): string {
  return rules.map(r =>
    `- [${r.id}] (${r.severity}) ${r.description}`
  ).join('\n');
}

function buildLinterDiagnosticsPrompt(diagnostics: LinterDiagnostic[]): string {
  return diagnostics.map(d =>
    `- [${d.ruleId}] L${d.range.start.line + 1}: ${d.message}`
  ).join('\n');
}

function addLineNumbers(code: string): string {
  return code.split('\n').map((line, i) => `${String(i + 1).padStart(4, ' ')}| ${line}`).join('\n');
}

function parseJsonResponse(raw: string): object {
  const trimmed = raw.trim();
  const start = trimmed.indexOf('{');
  const end = trimmed.lastIndexOf('}');
  if (start === -1 || end === -1) {
    throw new Error('响应中未找到 JSON');
  }
  return JSON.parse(trimmed.substring(start, end + 1));
}

const CUSTOM_RULE_SYSTEM_PROMPT = `你是代码规则审查员,只评估以下自定义规则是否被违反。
理解语义而非文本匹配。
仅输出 JSON,格式:
{ "customRuleResults": [{ "ruleId": "规则ID", "line": 行号, "severity": "error|warning|info", "message": "触发描述" }] }
如果没有违反任何规则,返回空数组。`;

const DEEP_REVIEW_SYSTEM_PROMPT = `你是资深代码审查专家,完成两个任务:
1. 将英文静态分析结果翻译为输出语言,并补充修复建议
2. 深度审查代码,发现静态分析未覆盖的问题
重点:安全漏洞、逻辑错误、性能问题、设计缺陷
不要重复静态分析已报告的问题。

仅输出 JSON,格式:
{
  "translatedDiagnostics": [{ "originalRuleId": "原始ID", "translatedMessage": "翻译", "translatedSuggestion": "建议", "codeDiff": "可选" }],
  "findings": [{ "ruleId": "kebab-case", "severity": "error|warning|info", "category": "bug|performance|security|style|design", "title": "标题", "description": "描述", "suggestion": "建议", "codeDiff": "可选", "line": 行号 }]
}`;

export async function runAIReview(
  context: vscode.ExtensionContext,
  code: string,
  staticDiagnostics: LinterDiagnostic[],
  customRules: CustomRule[]
): Promise<AIEngineResult> {
  const config = getAIConfig();
  const apiKey = await getApiKey(context);

  if (!apiKey) {
    return {
      customRuleResults: [],
      translatedDiagnostics: [],
      findings: [],
      degraded: true,
      error: '未配置 API Key',
    };
  }

  let provider: AIProvider;
  try {
    provider = createProvider(config.provider, apiKey, config.baseUrl);
  } catch (err) {
    return {
      customRuleResults: [],
      translatedDiagnostics: [],
      findings: [],
      degraded: true,
      error: `创建 Provider 失败: ${err instanceof Error ? err.message : String(err)}`,
    };
  }

  const options = {
    model: config.model,
    temperature: config.temperature,
    timeoutMs: config.timeout * 1000,
  };

  const numberedCode = addLineNumbers(code);

  const requestA =
    customRules.length > 0
      ? provider.chat(
          CUSTOM_RULE_SYSTEM_PROMPT,
          `## 自定义规则\n${buildCustomRulePrompt(customRules)}\n\n## 代码(带行号)\n${numberedCode}`,
          options
        )
      : Promise.resolve('{}');

  const requestB = provider.chat(
    `${DEEP_REVIEW_SYSTEM_PROMPT}\n输出语言:${config.outputLanguage}`,
    `## 代码(带行号)\n${numberedCode}\n\n## 静态分析结果(英文)\n${buildLinterDiagnosticsPrompt(staticDiagnostics)}`,
    options
  );

  const [resultA, resultB] = await Promise.allSettled([requestA, requestB]);

  const errors: string[] = [];

  let customRuleResults: CustomRuleResult[] = [];
  if (resultA.status === 'fulfilled') {
    try {
      const parsed = parseJsonResponse(resultA.value) as { customRuleResults?: CustomRuleResult[] };
      customRuleResults = (parsed.customRuleResults ?? []).map(r => ({
        ...r,
        ruleId: `custom:${r.ruleId}`,
      }));
    } catch {
      errors.push('自定义规则响应解析失败');
    }
  } else {
    errors.push(`自定义规则请求失败: ${resultA.reason}`);
  }

  let translatedDiagnostics: TranslatedDiagnostic[] = [];
  let findings: AIFinding[] = [];
  if (resultB.status === 'fulfilled') {
    try {
      const parsed = parseJsonResponse(resultB.value) as {
        translatedDiagnostics?: TranslatedDiagnostic[];
        findings?: AIFinding[];
      };
      translatedDiagnostics = parsed.translatedDiagnostics ?? [];
      findings = parsed.findings ?? [];
    } catch {
      errors.push('AI 审查响应解析失败');
    }
  } else {
    errors.push(`AI 审查请求失败: ${resultB.reason}`);
  }

  const degraded = errors.length > 0;
  return {
    customRuleResults,
    translatedDiagnostics,
    findings,
    degraded,
    error: errors.join('; '),
  };
}

关键逻辑

两并行请求:

请求 内容 System Prompt
A 自定义规则评估(需完整代码) 只评估规则、语义理解、输出 JSON
B 翻译 + 深度审查(需静态分析结果) 翻译诊断 + 深度审查、不重复静态分析、输出 JSON

降级策略:

  1. Promise.allSettled 确保单请求失败不影响另一个
  2. API Key 未配置 → 所有 AI 功能降级
  3. JSON 解析失败 → 该请求降级,记录错误
  4. Provider 创建失败 → 全部降级

Prompt 设计:

  • 请求 A: 注入自定义规则的 description 列表
  • 请求 B: 注入静态分析英文诊断列表 + 输出语言配置

验收

  • 2 个文件创建完成
  • npm run compile 通过
  • npm run lint 通过