上下文提供者插件模式
上下文提供者插件模式
学习目标
读完本章后,你将能够:
- 理解上下文提供者在 AI 编程助手中的角色和设计目标
- 设计双方法模式的 ContextProvider 接口(加载 + 获取)
- 实现按需加载和懒执行的上下文提供者
- 构建覆盖代码、文档、外部系统等多种数据源的上下文注入管线
前置知识
- 工具调用协议与执行模型 — 上下文提供者与工具系统的区别
- RAG 策略 — 检索增强生成的基本原理
核心概念
什么是上下文提供者
上下文提供者(Context Provider)是 AI 编程助手中的一种插件模式,负责将外部数据源的内容注入到 LLM 的对话上下文中。与工具系统(Tool System)不同,上下文提供者是拉取式(pull-based)的:用户主动触发或选择后,提供者返回相关上下文片段,而不是由 LLM 自主调用执行。
与工具系统的区别
| 维度 | 上下文提供者 | 工具系统 |
|---|---|---|
| 触发方式 | 用户通过 @mention 或子菜单选择 | LLM 自主决定调用 |
| 执行时机 | 在发送给 LLM 之前注入 | 在 LLM 响应过程中调用 |
| 输出形式 | 文本片段(ContextItem) | 结构化结果 + 可能的文本 |
| 典型用例 | 打开的文件、代码库、文档、Issues | 文件编辑、终端命令、搜索 |
| 协议 | getContextItems(query) | Function Calling / MCP Tool |
接口设计
双方法模式
上下文提供者通常实现两个核心方法:
interface ContextProvider { // 方法 1:加载子菜单项(用于 @mention 下拉列表) loadSubmenuItems(config: Config): Promise<SubmenuItem[]>;
// 方法 2:根据查询返回上下文片段 getContextItems( query: string, extras: ContextExtras ): Promise<ContextItem[]>;}loadSubmenuItems 的职责:
- 返回该提供者可以提供的上下文列表
- 用于 GUI 的 @mention 自动补全
- 通常是轻量级操作(列举文件、列出文档等)
getContextItems 的职责:
- 根据用户的查询返回相关的上下文片段
- 可能涉及检索、搜索、嵌入向量匹配等操作
- 返回的结果会被注入到 LLM 的系统提示或用户消息中
上下文片段结构
interface ContextItem { content: string; // 实际文本内容,发送给 LLM name: string; // 片段名称(如文件名、类名) description: string; // 人类可读的描述 uri?: { filepath: string }; // 可选的来源位置}典型提供者分类
代码级提供者
| 提供者 | 数据源 | 检索方式 |
|---|---|---|
| 当前文件 | 编辑器中当前打开的文件 | 直接读取 |
| 选中代码 | 用户选中的代码范围 | IDE API 获取 |
| 代码库 | 整个项目的索引 | FTS / 向量检索 / Tree-sitter |
| 文件树 | 项目目录结构 | 文件系统遍历 |
| Diff | Git 工作区变更 | git diff 或 IDE API |
| 问题诊断 | IDE 的诊断信息(错误、警告) | IDE diagnostics API |
| Git 提交 | Git 提交历史 | Git CLI 或 libgit2 |
文档级提供者
| 提供者 | 数据源 | 检索方式 |
|---|---|---|
| 文档 | 外部文档 URL 集合 | 文档索引 + 向量检索 |
| 网页搜索 | 搜索引擎 API | HTTP 请求 |
| URL | 指定的单个 URL | 网页抓取 + 提取 |
外部系统集成提供者
| 提供者 | 数据源 | 检索方式 |
|---|---|---|
| GitHub Issues | GitHub API | REST API 查询 |
| GitLab MR | GitLab API | REST API 查询 |
| Jira Issues | Jira API | REST API 查询 |
| 数据库 | PostgreSQL 等 | SQL 查询 + 结果格式化 |
| Discord | Discord API | API 查询频道和消息 |
| 终端输出 | 最近的终端命令输出 | 终端缓冲读取 |
生命周期管理
加载阶段
用户打开 IDE ↓配置加载 → 注册上下文提供者 ↓提供者按需初始化(可能建立连接、加载索引) ↓GUI 请求 loadSubmenuItems → 构建 @mention 列表执行阶段
用户输入 @provider_name query ↓GUI 发送请求到 Core ↓Core 查找对应的提供者实例 ↓调用 getContextItems(query, extras) ↓过滤和 Token 预算检查 ↓注入到 LLM 消息中按需加载模式
对于大型数据源(如代码库索引、文档索引),提供者使用懒执行:
loadSubmenuItems只返回轻量级元数据getContextItems时才触发实际的检索操作- 可能涉及异步索引构建(如文档首次访问时的索引建立)
设计权衡
优势
- 可扩展性:新数据源只需实现一个接口,无需修改核心代码
- 用户控制:用户明确选择注入什么上下文,减少不必要的 Token 消耗
- 按需加载:懒执行避免启动时加载所有数据源
- 组合性:多个提供者可以同时激活,组合提供丰富的上下文
代价与挑战
- Token 预算:每个提供者的输出需要被截断或压缩以适配上下文窗口
- 检索相关性:提供者的检索质量直接影响 LLM 的回答质量
- 延迟:远程提供者(如 GitHub Issues API)可能引入网络延迟
- 一致性:不同提供者返回的格式和质量可能不一致,需要统一处理
替代方案
- 自动上下文注入:不通过 @mention,而是由系统自动选择相关上下文(如 Autocomplete 中的隐式上下文检索)
- 工具式获取:让 LLM 通过工具调用主动获取上下文,而非用户选择(Agent 模式)
安全考量
- 敏感数据过滤:上下文提供者可能暴露代码中的密钥、配置等敏感信息,需要过滤机制
- 外部 API 认证:GitHub、Jira 等提供者需要安全存储和传递认证凭据
- 内容大小限制:防止恶意的大响应占用 LLM 上下文
参考来源
- Continue Context Providers 文档
- Lewis, P. et al. “Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks.” arXiv:2005.11401, 2020
- Model Context Protocol (MCP) — Context Resources: https://modelcontextprotocol.io/specification