报告日期: 2026-06-01


一、变更总览

序号能力修改前修改后
1「网上资源」解释曾接入 Tavily/Serper 搜索 API(后移除)仅 LLM(OpenAI 兼容,默认 DeepSeek)
2JS 选中分析 + 无漏洞无文件内补全提示与 Python 对齐:短选区前置提示 + 无漏洞后置提示
3跨文件补全展示独立 Webview + 另一套输出格式与主分析共用 Problems / 高亮 / 解释面板 / 输出日志

二、后端:解释层改为 LLM(DeepSeek 兼容)

2.1 设计目标

  • 用户选择 web_only 或 materials_and_web 时,用大模型生成中文「漏洞说明 / 如何解决」,不再依赖外网搜索 API。
  • 未配置 API Key 或调用失败时,回退内置 WEB_KNOWLEDGE(OWASP/CWE 风格摘要),保证教学场景可用。
  • 接口契约不变:仍为 POST /enrich-explanations,explanation_source 枚举保持 materials_only | materials_and_web | web_only。

2.2 新增 llm_service.py

职责: 读取环境变量 → 调用 Chat Completions → 解析 JSON → 返回 web_block 结构(与旧逻辑字段一致:title / explanation / fix / refs)。

默认对接 DeepSeek:

_DEFAULT_BASE_URL = "https://api.deepseek.com"
_DEFAULT_MODEL = "deepseek-chat"

环境变量(优先级从高到低):

变量说明
CODEGUARD_LLM_API_KEY通用密钥
DEEPSEEK_API_KEY / OPENAI_API_KEY简写别名
CODEGUARD_LLM_BASE_URL / DEEPSEEK_BASE_URLAPI 根地址
CODEGUARD_LLM_MODEL / DEEPSEEK_MODEL模型名

核心调用逻辑:

def generate_knowledge_for_risk(
    risk: RiskItem,
    *,
    source_code: str = "",
    material_excerpt: str = "",
    timeout_sec: float = _DEFAULT_TIMEOUT_SEC,
) -> dict[str, str | list[str]] | None:
    """调用 OpenAI 兼容 Chat Completions API 生成教学向说明;失败返回 None。"""
    api_key = _api_key()
    if not api_key:
        return None

    user_prompt = _build_user_prompt(risk, source_code=source_code, material_excerpt=material_excerpt)
    try:
        content = _chat_completion(
            api_key=api_key,
            model=_model(),
            base_url=_base_url(),
            messages=[
                {"role": "system", "content": _SYSTEM_PROMPT},
                {"role": "user", "content": user_prompt},
            ],
            timeout_sec=timeout_sec,
        )
        parsed = parse_knowledge_json(content)
        ...

Prompt 约定:

  • System:要求输出单行 JSON:{“explanation”,“fix”,“refs”},中文、可提 OWASP/CWE,不编造 URL。
  • User:拼装漏洞类型、行号、reason、attack_path、引擎 fix 建议、带行号的代码片段(选区上下各约 6 行)、可选「上传资料摘录」。

parse_knowledge_json: 支持纯 JSON、markdown 代码块包裹、或文本中提取首个 {…},提高模型格式漂移时的容错。

2.3 修改 explanation_service.py

删除: 对 **web_search_service **的依赖(该文件已移除)。

主流程 enrich_explanations

    mode = req.explanation_source
    use_materials = mode in ("materials_only", "materials_and_web")
    use_llm = mode in ("web_only", "materials_and_web")

    if mode == "materials_only" and not req.reference_materials:
        use_llm = True  # 无资料时降级,避免空解释

    ...
    llm_cache: dict[str, dict[str, str | list[str]] | None] = {}

    for risk in req.risks:
        ...
        if use_llm:
            cache_key = _llm_cache_key(
                risk, material_excerpt if mode == "materials_and_web" else ""
            )
            if cache_key not in llm_cache:
                llm_cache[cache_key] = _knowledge_block_for(
                    risk,
                    source_code=req.source_code,
                    material_excerpt=material_excerpt if mode == "materials_and_web" else "",
                )
            web_block = llm_cache[cache_key]

缓存键: 类型:起始行:结束行:reason前60字:资料摘录前80字,避免同请求内重复调 LLM。

_knowledge_block_for

  1. is_llm_configured()generate_knowledge_for_risk(…)
  2. 失败 → WEB_KNOWLEDGE[risk.type] 或 _DEFAULT_WEB

文案调整(面向用户):

  • web_only:大模型生成的安全说明
  • materials_and_web:大模型补充的公开安全实践说明

2.4 测试

文件内容
backend/tests/test_llm_service.pyJSON 解析(纯文本 / markdown fence)
backend/tests/test_explanation_service.py离线 OWASP 兜底;mock LLM 时断言 enrich 结果

2.5 DeepSeek 产品建议(运维)

产品场景
deepseek-chat默认,漏洞说明 + 修复步骤,性价比高
deepseek-reasoner复杂攻击链,可选,更慢更贵
硅基流动等兼容中转BASE_URL + MODEL 即可

配置说明已写入 插件启动方式.txt 第 15–31 行。


三、插件:JavaScript 文件内上下文补全

3.1 问题

原先仅 language === "python" 时,选中过短片段会提示「补全上下文」;JavaScript 选中分析无漏洞时,也不会询问是否在同一文件内扩窗重分析。

3.2 语言判定扩展

/** 支持选中分析时的文件内上下文逐步扩窗(与后端已接入的语言一致) */
export function supportsInFileContextExpansion(language: string): boolean {
  return language === "python" || language === "javascript";
}

normalizeLanguage 已将 javascript / typescript 归为 javascript 送审后端。

3.3 两条触发路径(extension.ts

路径 A — 分析前(选区过短,与 Python 相同):

  if (
    mode === "selection" &&
    supportsInFileContextExpansion(language) &&
    expansionSettings.enabled &&
    document.lineCount > 0
  ) {
    ...
    if (isWindowTooShort(...)) {
      const choice = await vscode.window.showWarningMessage(
        `...是否自动扩大选区并补全上下文后再分析?`,
        confirmExpand, cancel
      );
      if (choice !== confirmExpand) { return; }
      useExpandingContext = true;
    }
  }

路径 B — 分析后(仅 JavaScript,首次分析无漏洞):

    if (
      mode === "selection" &&
      language === "javascript" &&
      expansionSettings.enabled &&
      !useExpandingContext &&
      !responseHasRisks(responseJson) &&
      document.lineCount > 0
    ) {
      const choice = await vscode.window.showInformationMessage(
        `当前选中范围内未发现漏洞。...是否在文件内自动扩大分析窗口后再分析?`,
        { modal: true },
        confirmExpand, keep
      );
      if (choice === confirmExpand) {
        useExpandingContext = true;
        responseJson = await analyzeSelectionWithExpandingContext({...});
      }
    }

扩窗算法(共用 analyzeSelectionWithExpandingContext):

  • 以选区行为 [winStart, winEnd],每轮 expandWindow 向上下各扩 stepLines 行;
  • 每轮 POST /analyzemode: "selection",带range;
  • 停止条件:risks_found | 覆盖全文 | 窗口不再增长 | 达到 maxIterations;
  • 结束时写入 _codeguard_context_expansion、_codeguard_completion_kind: “in_file”。

配置项:codeGuardTutor.expandContextForShortSelections 等(package.json 描述已改为「Python / JavaScript」)。


四、插件:文件内 / 跨文件补全 — 展示统一

4.1 问题

路径修改前
主分析 / 文件内补全ResultPresenter + ExplanationPanel + 统一 logResponse
跨文件补全多个 codeguardCrossFileRisk Webview + 手写 appendLine 分段

用户体验割裂:跨文件无 Problems 高亮、解释面板不联动。

4.2 新增 analysisPresentation.ts

类型:

export type CompletionKind = "standard" | "in_file" | "cross_file";

跨文件合并响应 buildCrossFileMergedResponse

  • 遍历 riskHits[],将各文件 risks 合并为单一 risks[];
  • 强制 file_path 为命中文件路径,id 缺省为 risk-cross-{n};
  • 附加元数据:
_codeguard_completion_kind: "cross_file",
_codeguard_cross_file_meta: {
  files_checked, files_with_risks, risk_count
}

统一出口 presentUnifiedAnalysisOutcome

  1. logAnalysisResponse — 输出通道([补全类型][跨文件] 统计、风险条目含文件名)
  2. presentAnalysisResultResultPresenter(Diagnostics、行高亮)
  3. ExplanationPanel(右侧 Webview)
  4. 中文 Toast(摘要、风险等级、解释来源、条数提示)

主分析与跨文件均调用:

// 主流程(extension.ts)
presentUnifiedAnalysisOutcome({
  completionKind: useExpandingContext ? "in_file" : "standard",
  ...
});

// 跨文件(runCrossFileAnalysis)
const merged = buildCrossFileMergedResponse(riskHits, args.relatedFiles.length);
presentUnifiedAnalysisOutcome({
  completionKind: "cross_file",
  responseJson: merged,
  ...
});

删除: showCrossFileRiskWebviewPanelsbuildCrossFileRiskWebviewHtmlflattenCrossFileRisks 的独立展示分支。

4.3 解释面板 explanationPanel.ts 统一

  • 标题:CodeGuard 导师 · 漏洞说明(中文)
  • 风险列表:显示 文件名 · Lx–Ly、严重程度中文
  • 详情:文件 / 漏洞说明 / 攻击路径 / 如何解决(优先 how_to_fix)/ 最小改动 / 推荐做法 / 修改前后代码

与输出面板 formatRiskLineForOutput / formatRiskDetailForOutput 字段对齐。

4.4 端到端展示流程(示意)

跨文件

主流程/文件内

分析或补全完成

有 risks?

buildCrossFileMergedResponse

responseJson 原样或带 in_file 元数据

presentUnifiedAnalysisOutcome

logAnalysisResponse 输出通道

presentAnalysisResult

Problems + 行高亮

ExplanationPanel Webview

Toast 通知


五、插件:解释来源文案(LLM)

先解释一下为什么没有连接到搜索引擎的API:
首先搜索引擎功能比较局限,返回结果后需要用户自己查看网页内容。
其次功能中包含同时使用用户自身上传文档与线上资源,搜索引擎没有合并功能,比较局限
再次我们使用的平台没有提供主流搜索引擎API
最后综合考虑后,我认为将功能变更为大模型回答更符合当下的发展趋势,也更适合我们这个项目。

userMaterials.ts 模态框按钮更新:

原文案(概念)现文案
资料 + 网上资源② 参考我的资料与大模型
仅网上资源③ 仅参考大模型(LLM)

extension.ts 中 explanationSourceLabelZh 同步为「上传资料与大模型」「仅大模型」。


六、涉及文件清单

6.1 后端

文件操作
backend/core/context/llm_service.py新增
backend/core/context/explanation_service.py修改(LLM + 缓存 + 文案)
backend/core/context/web_search_service.py删除
backend/tests/test_llm_service.py新增
backend/tests/test_explanation_service.py修改(mock LLM)
backend/tests/test_web_search_service.py删除

6.2 插件

文件操作
vscode-extension/src/analysisPresentation.ts新增
vscode-extension/src/extension.ts修改(JS 补全、统一展示、传 resultPresenter)
vscode-extension/src/contextExpansion.ts修改(supportsInFileContextExpansion
vscode-extension/src/explanationPanel.ts修改(中文 UI、文件路径、如何解决)
vscode-extension/src/userMaterials.ts修改(LLM 文案)
vscode-extension/package.json配置项描述更新

6.3 文档与启动说明

文件操作
插件启动方式.txtDeepSeek / LLM 环境变量说明
docs/项目开发报告-2026-05-31.md本报告

七、配置与验证

7.1 后端 LLM

在这里加了配置大模型的方法,具体模型和密钥使用自己账号上的就行
注:大家跑测试之前记得找我要APIKey这些参数

cd backend
#在这里加了配置大模型的方法,具体模型和密钥使用自己账号上的就行,
#依旧只需要配置一次
$env:CODEGUARD_LLM_API_KEY = "sk-...(APIkey)"
$env:CODEGUARD_LLM_BASE_URL = "https://api...(URL)"
$env:CODEGUARD_LLM_MODEL = "...(模型名称)"
python -m uvicorn app:app --host 127.0.0.1 --port 8000 --reload

7.2 插件

cd vscode-extension
npm run compile
# F5 启动扩展开发窗口

7.3 测试用例

在test文件夹里面我更新了相关被测文件,选择相应语言的文件夹的子文件夹打开就可以进行测试。

code-guard-tutor\tests> tree
└─cases
    ├─javascript
    │  └─javascript
    └─python
        └─vulnerability_samples


八、已知限制与后续

项目说明
LLM 非实时联网说明来自模型知识 + 引擎上下文,非爬取网页
跨文件语言仍仅 Python import 推断关联 .py
JS 后置扩窗javascripttypescript 归并后同等对待
多文件高亮需打开对应文件编辑器才显示行装饰;Diagnostics 已按路径分组
接口字段名仍为 web_only / web_references_used,与历史插件兼容

后续可能会扩展:

  • 将 risk_level / summary 在解释面板改为中文映射(与输出通道一致)
  • 跨文件支持 JavaScript import / require
  • LLM 流式输出或按文件批量合并 prompt 以降低调用次数

九、小结

本次完成三件事:(1) C 层解释由搜索 API 转为可配置的 LLM(默认 DeepSeek),保留离线兜底;(2) JavaScript 与 Python 在选中分析上对齐文件内上下文补全交互;(3) 通过 analysisPresentation.ts 将标准分析、文件内补全、跨文件补全的结果收束到同一套输出日志、Problems、解释面板与 Toast,降低学习与演示成本。

到这里这个项目的主要开发工作就结束了,后面是测试优化与材料整理。


Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐