Doramagic 项目包 · 项目说明书
contextful 项目
生成时间:2026-05-16 04:01:04 UTC
项目概述
Contextful(也称 cxf 或 contextful)是一个本地代码索引与上下文检索系统,专为 AI 编程助手设计。该项目由 Inferensys 团队开发,旨在解决大型代码库中上下文信息过载的问题,帮助 AI Agent 在代码审查、重构、依赖分析等场景中高效获取精确的证据支撑[资料来源:README.md:1]()
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
项目简介
Contextful(也称 cxf 或 contextful)是一个本地代码索引与上下文检索系统,专为 AI 编程助手设计。该项目由 Inferensys 团队开发,旨在解决大型代码库中上下文信息过载的问题,帮助 AI Agent 在代码审查、重构、依赖分析等场景中高效获取精确的证据支撑资料来源:README.md:1
Contextful 的核心价值在于将传统的"暴力读取文件"模式转变为"证据驱动的紧凑上下文打包"模式。传统方式下,AI Agent 可能需要读取数十个文件才能理解一个问题,而 Contextful 能够根据查询意图返回一个经过排序、标注来源、符合 token 预算的紧凑证据包资料来源:README.md:1-5。
核心设计理念
Contextful 遵循以下设计原则:
- 证据优先:每个返回的上下文都附带文件引用和行号,AI 可以直接溯源
- 意图感知:系统能够分类用户查询(如精确搜索、影响分析、架构追踪等)
- 预算可控:返回结果严格遵守 token 预算限制,避免信息过载
- 记忆持久化:支持将 AI 学习到的经验持久化存储,供后续会话复用
技术架构
整体架构图
graph TD
subgraph 输入层
Q[用户查询]
W[工作区文件]
M[记忆数据]
end
subgraph 处理层
C[CLI命令解析]
S[搜索引擎]
G[图数据库]
I[索引引擎]
end
subgraph MCP层
MCP[MCP Server]
TOOLS[7大工具集]
end
subgraph 输出层
P[Evidence Pack]
R[Context Report]
end
Q --> C
W --> I
I --> G
C --> S
S --> G
M --> S
C --> MCP
MCP --> TOOLS
TOOLS --> P
TOOLS --> R
S --> P
G --> P核心模块
| 模块名称 | 文件路径 | 职责说明 |
|---|---|---|
| CLI 解析器 | src/cli.ts | 命令行参数解析与路由 |
| 搜索引擎 | src/search.ts | 全文检索、意图分类、结果排序 |
| 索引引擎 | src/extract.ts | 符号提取、依赖关系图构建 |
| MCP 服务 | src/mcp-server.ts | MCP 协议实现与工具暴露 |
| 报告生成 | src/report.ts | 上下文报告与证据包渲染 |
功能特性
CLI 命令行工具
Contextful 提供完整的命令行界面,支持以下操作资料来源:src/cli.ts:1-100:
| 命令 | 功能描述 | 核心参数 |
|---|---|---|
cxf index | 建立或更新工作区索引 | --workspace, --watch |
cxf daemon | 启动本地索引守护进程 | --workspace |
cxf query | 创建证据包 | --workspace, --budget, --json |
cxf search | 搜索上下文 | --workspace, --limit, --kind |
cxf report | 生成上下文报告 | --workspace, --format |
cxf memory add | 存储经验教训 | --claim, --evidence, --scope |
cxf server | 启动 MCP 服务 | 无 |
MCP 工具集
Contextful 作为 MCP(Model Context Protocol)服务器,暴露了 7 个核心工具资料来源:src/mcp-server.ts:1-50:
| 工具名称 | 功能说明 |
|---|---|
context_pack | 返回排序、标注来源、符合预算的证据包 |
search_code | 强大的代码、文档、符号和记忆搜索 |
trace_path | 跨文件、符号、模块、配置的图遍历 |
impact_analysis | 逆向依赖分析与影响范围识别 |
why_changed | 结合 Git 历史的变更原因分析 |
recall_memory | 搜索持久化的经验教训 |
write_lesson | 写入带证据的经验教训 |
搜索意图分类
系统能够将用户查询自动分类为以下意图类型资料来源:src/search.ts:1-30:
| 意图类型 | 触发关键词 | 典型使用场景 |
|---|---|---|
exact | 文件路径、符号名、正则表达式 | 精确查找定义或文件 |
code | 函数、变量、参数、实现 | 代码实现分析 |
memory | 记忆、经验、教训、会话 | 经验检索 |
impact | 影响、依赖、影响范围 | 变更影响分析 |
historical | 为什么、变更、历史、提交 | 变更原因追溯 |
architectural | 架构、流程、路径、依赖 | 系统架构分析 |
docs | 文档、指南、README、配置 | 文档查找 |
vague | 通用查询 | 模糊匹配 |
索引能力
系统支持多种编程语言的代码索引资料来源:src/extract.ts:1-80:
| 语言 | 支持类型 | 提取内容 |
|---|---|---|
| TypeScript/JavaScript | 函数、类、接口、类型 | 函数声明、导出状态、签名 |
| Python | 函数、类 | 函数定义、类定义 |
| Go | 函数、结构体、接口 | 函数声明、包级导出 |
| Rust | 函数、结构体、枚举、特征、impl | 函数、结构体、特征实现 |
| Markdown | 标题 | 层级标题结构 |
| JSON | 配置键 | 顶层键名 |
| Go | import 路径 | 包引用 |
| Rust | use/mod 语句 | 模块引用 |
工作流程
索引构建流程
graph LR
A[文件扫描] --> B[语言检测]
B --> C[符号提取]
C --> D[依赖关系提取]
D --> E[全文分块]
E --> F[SQLite存储]
F --> G[FTS全文索引]
G --> H[图数据库索引]证据包生成流程
graph TD
Q[query查询] --> C{意图分类}
C -->|code| F1[FTS全文搜索]
C -->|impact| F2[图遍历分析]
C -->|memory| F3[记忆库搜索]
C -->|historical| F4[Git历史查询]
F1 --> R[结果合并]
F2 --> R
F3 --> R
F4 --> R
R --> D[相关性评分]
D --> S[Token预算分配]
S --> P[Evidence Pack]
P --> CITE[引用标注]
P --> GRAPH[图路径连接]
P --> CONF[置信度计算]
CITE --> OUTPUT[最终输出]
GRAPH --> OUTPUT
CONF --> OUTPUT依赖关系
核心依赖
| 依赖包 | 版本 | 用途 |
|---|---|---|
@modelcontextprotocol/sdk | ^1.29.0 | MCP 协议实现 |
better-sqlite3 | ^12.10.0 | SQLite 数据库引擎 |
commander | ^14.0.3 | CLI 命令解析 |
fast-glob | ^3.3.3 | 文件模式匹配 |
web-tree-sitter | ^0.20.8 | 语法树解析 |
zod | ^4.4.3 | 数据验证 |
开发依赖
| 依赖包 | 版本 | 用途 |
|---|---|---|
typescript | ^6.0.3 | 类型检查与编译 |
vitest | ^4.1.6 | 单元测试框架 |
环境要求
- Node.js 版本: >= 20资料来源:package.json:45
支持的 IDE
项目已针对以下 IDE 和编辑器进行测试资料来源:package.json:10-18:
- Windsurf
- GitHub Copilot
- VS Code
- Cline
- Roo Code
- Continue
- Zed
项目元数据
| 属性 | 值 |
|---|---|
| 项目名称 | contextful |
| CLI 别名 | cxf |
| MCP 名称 | io.github.Inferensys/contextful |
| 许可证 | MIT |
| 仓库地址 | git+https://github.com/Inferensys/contextful.git |
| 官网 | https://inferensys.github.io/contextful/ |
| 问题追踪 | https://github.com/Inferensys/contextful/issues |
使用示例
安装与索引
# 全局安装
npx @inferensys/contextful index --workspace .
# 持续监听文件变化
npx @inferensys/contextful index --workspace . --watch
查询上下文
# 基本查询
cxf query "where is user auth handled" --workspace . --budget 2000
# 输出 JSON 格式
cxf query "memory ledger implementation" --workspace . --json
MCP 服务模式
# 启动 MCP 服务器
npx @inferensys/contextful server
数据模型
证据包结构
classDiagram
class EvidencePack {
+string id
+string query
+string scope
+SearchIntent intent
+string summary
+SearchHit[] citations
+FileContext[] files
+SymbolRecord[] symbols
+GraphPath[] graphPaths
+SearchHit[] memoryHits
+number confidence
+number tokenEstimate
+number budget
+string createdAt
}
class SearchHit {
+string ref
+string path
+string title
+string kind
+string excerpt
+number rank
}
class GraphPath {
+string from
+string to
+string edgeType
+string filePath
+number line
}
EvidencePack --> SearchHit
EvidencePack --> GraphPath记忆条目结构
| 字段 | 类型 | 说明 |
|---|---|---|
id | string | 唯一标识符 |
claim | string | 经验主张 |
evidenceRefs | string[] | 证据引用列表 |
scope | string | 作用范围(repo/global) |
confidence | number | 置信度(0-1) |
createdAt | string | 创建时间 |
报告功能
系统支持生成多格式的上下文报告资料来源:src/report.ts:1-60:
| 格式 | 说明 |
|---|---|
markdown | 默认格式,Markdown 渲染 |
json | 结构化 JSON 输出 |
html | 独立 HTML 页面,可直接在浏览器打开 |
报告包含内容
- 索引状态:已索引文件数、符号数、块数
- 统计摘要:Token 使用情况、节省比例估算
- 警告信息:潜在问题提示(如未索引文件、依赖缺失)
- Token 节省估算:相对于未使用系统的平均节省比例
来源:https://github.com/Inferensys/contextful / 项目说明书
系统架构
Contextful 是一个基于语义索引的上下文检索系统,旨在为 AI 代理提供精准、紧凑且有据可查的证据包。系统通过解析、索引代码仓库中的符号、导入关系和文档片段,使代理能够在执行任务时快速获取相关上下文,避免随机文件读取带来的效率低下问题。资料来源:[README.md]()
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
1. 概述
Contextful 是一个基于语义索引的上下文检索系统,旨在为 AI 代理提供精准、紧凑且有据可查的证据包。系统通过解析、索引代码仓库中的符号、导入关系和文档片段,使代理能够在执行任务时快速获取相关上下文,避免随机文件读取带来的效率低下问题。资料来源:README.md
2. 整体架构
Contextful 采用分层架构设计,主要包含以下层次:
| 层次 | 职责 | 核心模块 |
|---|---|---|
| CLI 层 | 用户交互接口 | src/cli.ts |
| MCP 服务层 | 与 AI 代理的标准通信协议 | src/mcp-server.ts |
| 搜索/查询层 | 语义检索和证据包生成 | src/search.ts |
| 索引层 | 代码解析和数据库写入 | src/indexer.ts |
| 提取层 | 符号和依赖关系解析 | src/extract.ts |
| 工具层 | 通用工具函数 | src/util.ts |
graph TD
A[CLI 客户端] --> B[MCP Server]
C[AI 代理] --> B
B --> D[Search Module]
D --> E[Index Layer]
E --> F[SQLite Kernel DB]
G[File System] --> E
D --> G资料来源:src/cli.ts:40-65,src/search.ts:1-50
3. 核心组件详解
3.1 索引子系统 (Indexer)
索引子系统负责扫描工作区文件并将其内容转换为可检索的数据库记录。索引过程包括文件发现、语言检测、符号提取和依赖关系分析四个阶段。
graph LR
A[文件扫描] --> B[语言检测]
B --> C[符号提取]
C --> D[依赖分析]
D --> E[分块存储]#### 索引流程
| 阶段 | 功能 | 关键函数 |
|---|---|---|
| 文件发现 | 递归扫描目录,忽略隐藏文件和测试文件 | scanWorkspace() |
| 语言检测 | 根据扩展名识别 TypeScript/JavaScript、Python、Go、Rust 等语言 | detectLanguage() |
| 符号提取 | 解析函数、类、接口、类型定义 | extractSymbols() |
| 依赖分析 | 提取 import/require/use 语句 | extractEdges() |
| 内容分块 | 将文件内容切分为可管理的片段 | textChunks() |
资料来源:src/extract.ts:1-50,src/indexer.ts
#### 支持的编程语言
系统支持多种编程语言的符号提取和依赖分析:
| 语言 | 符号类型 | 依赖检测 |
|---|---|---|
| TypeScript/JavaScript | function, class, interface, type, const | import from、require() |
| Python | function, class | from ... import、import |
| Go | function, struct, interface | 字符串字面量导入 |
| Rust | function, struct, enum, trait, impl | use、mod |
| Markdown | heading | 无依赖 |
| JSON | config-key | 键值对配置 |
资料来源:src/extract.ts:10-45
3.2 搜索与查询子系统 (Search)
搜索子系统是系统的核心大脑,负责理解用户查询意图并返回最相关的上下文片段。
graph TD
A[用户查询] --> B{意图分类}
B -->|code| C[代码搜索]
B -->|symbol| D[符号搜索]
B -->|impact| E[影响分析]
B -->|historical| F[历史追溯]
B -->|architectural| G[架构路径]
B -->|docs| H[文档检索]
C --> I[全文索引查询]
D --> J[符号表查询]
E --> K[依赖图遍历]
F --> L[Git 历史读取]
I --> M[BM25 排序]
J --> M
K --> M
M --> N[证据包组装]#### 意图分类器
查询意图自动分类为以下类型:
| 意图 | 检测关键词 | 搜索模式 |
|---|---|---|
code | how, implement, code, function | 全文搜索 |
symbol | class, interface, function name | 精确符号匹配 |
impact | impact, affected, depends, blast radius | 逆向依赖分析 |
historical | why, changed, commit, history | Git 历史 + 当前代码 |
architectural | architecture, flow, path, trace | 图遍历 |
docs | resource, docs, documentation, guide | 文档优先 |
vague | 通用模糊查询 | 扩展术语 + 全文搜索 |
资料来源:src/search.ts:1-20
3.3 证据包系统 (Evidence Pack)
证据包是系统返回给 AI 代理的核心数据结构,包含查询答案的所有支持证据。
graph TD
A[createContextPack] --> B[searchContext]
B --> C{选择命中}
C -->|hits| D[topKByScore]
C -->|graphPaths| E[loadGraphPaths]
C -->|memoryHits| F[内存记忆]
D --> G[组装证据包]
E --> G
F --> G
G --> H[EvidencePack]
H --> I[summary 摘要]
H --> J[citations 引用]
H --> K[symbols 符号]
H --> L[graphPaths 路径]#### 证据包数据结构
interface EvidencePack {
id: string; // 唯一标识符
query: string; // 原始查询
scope: string; // 作用域 (repo|file|session)
intent: SearchIntent; // 识别的查询意图
summary: string; // 自然语言摘要
citations: SearchHit[]; // 命中的上下文片段
files: FileReference[]; // 相关文件列表
symbols: SymbolRecord[]; // 匹配的符号
graphPaths: GraphPath[]; // 图路径连接
memoryHits: SearchHit[]; // 记忆系统命中
confidence: number; // 置信度 (0.1-0.92)
tokenEstimate: number; // 估算的 token 数量
budget: number; // token 预算上限
createdAt: string; // 创建时间戳
}
资料来源:src/search.ts:150-200,src/types.ts
3.4 MCP 服务层
MCP (Model Context Protocol) 服务层提供了与 AI 代理通信的标准接口,使 Contextful 可作为工具被集成到任何兼容 MCP 的代理中。
graph LR
A[AI Agent] -->|stdio| B[MCP Server]
B -->|context_pack| C[createContextPack]
B -->|search_code| D[searchContext]
B -->|trace_path| E[traceGraph]
B -->|impact_analysis| F[impactAnalysis]
B -->|why_changed| G[whyChanged]
B -->|recall_memory| H[recallMemory]
B -->|write_lesson| I[writeLesson]#### MCP 工具列表
| 工具名 | 功能 | 参数 |
|---|---|---|
context_pack | 生成带证据的上下文包 | query, budget, scope |
search_code | 搜索代码、文档、符号、记忆 | query, mode, filters |
trace_path | 图遍历追踪符号/模块依赖 | from, to, edge_types |
impact_analysis | 分析符号/文件的逆向依赖 | symbol_or_file |
why_changed | 追溯变更历史 | symbol_or_file |
recall_memory | 搜索记忆系统 | query, scope |
write_lesson | 写入学习记忆 | claim, evidence_refs |
资料来源:src/mcp-server.ts,README.md
3.5 CLI 命令行接口
CLI 模块提供了独立的命令行工具 cxf (contextful) 供开发者直接使用。
#### 命令概览
| 命令 | 描述 | 核心选项 |
|---|---|---|
index | 索引工作区文件 | --workspace, --watch |
daemon | 启动本地索引守护进程 | --workspace |
query | 创建证据包 | --workspace, --budget, --json |
search | 搜索索引内容 | --workspace, --limit, --kind |
report | 生成上下文报告 | --workspace, --format |
memory add | 添加学习记忆 | --claim, --evidence, --confidence |
server | 启动 MCP 服务 | 无 |
资料来源:src/cli.ts:1-80
#### 使用示例
# 索引当前目录
cxf index --workspace .
# 启动守护进程监听变更
cxf daemon --workspace .
# 查询上下文
cxf query "用户认证在哪里处理" --workspace . --budget 2000
# 生成报告
cxf report --workspace . --format markdown
4. 数据模型
4.1 内核数据库 (SQLite)
系统使用 SQLite 作为内核数据库,存储以下核心表结构:
| 表名 | 用途 | 核心字段 |
|---|---|---|
files | 已索引文件元数据 | path, language, hash, indexed_at |
chunks | 文件分块内容 | file_id, path, title, text, kind |
chunks_fts | 全文搜索索引 | BM25 排序的 FTS5 表 |
symbols | 代码符号表 | name, kind, file_path, line, signature |
edges | 依赖关系图 | source_path, target_name, edge_type |
memory | 学习记忆存储 | id, claim, evidence, confidence, scope |
queries | 查询历史 | query, intent, timestamp |
资料来源:src/indexer.ts,src/search.ts:50-100
4.2 符号提取数据模型
interface SymbolRecord {
ref: string; // 文件引用,如 "file:src/auth.ts:1-20"
name: string; // 符号名称
kind: string; // 类型:function, class, interface, struct, enum
filePath: string; // 文件路径
line: number; // 定义行号
signature?: string; // 函数签名摘要
exported?: boolean; // 是否导出
}
interface RawEdge {
targetName: string; // 目标名称
targetType: string; // 目标类型:module, config
edgeType: string; // 边类型:IMPORTS, CONFIGURES
filePath: string; // 源文件路径
line: number; // 行号
}
资料来源:src/extract.ts:1-30
5. 工作流程
5.1 索引完整流程
sequenceDiagram
participant User
participant CLI as CLI/Server
participant Indexer
participant Extractor
participant DB as Kernel DB
User->>CLI: cxf index --workspace .
CLI->>Indexer: scanWorkspace(workspace)
Indexer->>Indexer: 遍历所有文件
loop 每个文件
Indexer->>Extractor: extractSymbols(content, language)
Extractor-->>Indexer: symbols[]
Indexer->>Extractor: extractEdges(content, language)
Extractor-->>Indexer: edges[]
Indexer->>Extractor: textChunks(content)
Extractor-->>Indexer: chunks[]
Indexer->>DB: insert records
end
DB-->>CLI: indexing complete
CLI-->>User: status report5.2 查询证据包生成流程
sequenceDiagram
participant Agent
participant MCP as MCP Server
participant Search
participant DB as Kernel DB
Agent->>MCP: context_pack("用户认证", budget=2000)
MCP->>Search: createContextPack({query, budget})
Search->>Search: classifyQuery(query) -> intent
Search->>Search: searchContext({query, intent})
Search->>DB: FTS query + BM25
DB-->>Search: ranked hits
Search->>Search: selectTopK(hits, budget)
Search->>DB: loadSymbolsForPaths()
Search->>DB: loadGraphPaths()
Search-->>MCP: EvidencePack
MCP-->>Agent: EvidencePack (JSON/Markdown)6. 记忆系统
Contextful 内置了一个证据支持的学习记忆系统,允许 AI 代理保存从查询中获得的经验教训。
6.1 记忆数据结构
| 字段 | 类型 | 说明 |
|---|---|---|
id | string | 唯一标识符 |
claim | string | 经验断言/教训 |
evidence | SearchHit[] | 支持证据引用 |
confidence | number | 置信度 (0-1) |
scope | string | 作用域 (repo/file/session) |
createdAt | string | 创建时间 |
6.2 记忆查询
记忆系统支持通过自然语言查询检索相关经验,与常规代码搜索并行执行,结果合并到证据包中。
7. 报告系统
报告模块提供工作区的整体上下文分析视图。
graph TD
A[generateReport] --> B[getIndexStatus]
A --> C[getQueryStats]
A --> D[getStaleMemories]
B --> E[renderReport]
C --> E
D --> E
E -->|markdown| F[Markdown 格式]
E -->|json| G[JSON 格式]
E -->|html| H[HTML 格式]7.1 报告内容
| 部分 | 内容 |
|---|---|
| 状态概览 | 文件数、符号数、索引状态 |
| 语言覆盖 | 各编程语言的文件数量统计 |
| 热门查询 | 最常使用的查询及意图分布 |
| 陈旧记忆 | 需要更新的学习记忆 |
| 代理指导 | 最佳实践建议 |
| 警告 | 索引过程中的潜在问题 |
资料来源:src/report.ts:1-100
8. 扩展机制
8.1 自定义文件类型支持
系统通过 extract.ts 中的语言检测器支持扩展新的编程语言。需要实现:
- 符号提取:匹配函数/类/类型定义的正则表达式
- 依赖分析:匹配导入语句的模式
- 分块策略:适用于该语言内容的分块算法
8.2 MCP 工具扩展
MCP 服务层支持注册新的工具函数,遵循以下签名:
interface MCPTool {
name: string;
description: string;
inputSchema: object;
handler: (params: object) => Promise<object>;
}
9. 总结
Contextful 的系统架构围绕"精准上下文检索"这一核心目标设计,通过分层解耦实现了以下能力:
- 多语言支持:支持 TypeScript/JavaScript、Python、Go、Rust 等主流语言的符号提取
- 智能意图分类:自动识别查询意图并选择最优搜索策略
- 图遍历能力:通过依赖图支持影响分析和架构追踪
- 记忆持久化:证据支持的学习记忆系统
- MCP 集成:标准化的 AI 代理通信协议
整个系统以 SQLite 为核心存储,通过 FTS5 全文索引和 BM25 排序算法实现高效检索,最终输出紧凑且有据可查的证据包。
资料来源:[src/cli.ts:40-65](),[src/search.ts:1-50]()
搜索系统
搜索系统是 Contextful 的核心功能模块,负责在已索引的工作区中执行多维度上下文检索。该系统通过整合全文搜索(FTS)、符号搜索、图关系遍历和记忆搜索等多种检索策略,为 AI 代理提供精确、相关且有据可查的代码上下文。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
搜索系统是 Contextful 的核心功能模块,负责在已索引的工作区中执行多维度上下文检索。该系统通过整合全文搜索(FTS)、符号搜索、图关系遍历和记忆搜索等多种检索策略,为 AI 代理提供精确、相关且有据可查的代码上下文。
搜索系统的主要设计目标是解决传统 RAG(检索增强生成)方法中常见的"随机文件读取"问题,通过意图分类、相关性排序和证据打包等机制,返回紧凑且经过验证的证据集,而非大量无关文件。资料来源:README.md
架构概览
graph TD
A[用户查询] --> B[意图分类 classifyQuery]
B --> C{查询类型}
C -->|exact| D[精确搜索]
C -->|symbol| E[符号搜索]
C -->|memory| F[记忆搜索]
C -->|impact| G[影响分析]
C -->|historical| H[历史分析]
C -->|architectural| I[架构分析]
C -->|docs| J[文档搜索]
C -->|vague| K[模糊搜索]
D --> L[全文搜索引擎]
E --> L
F --> M[记忆数据库]
G --> N[依赖图遍历]
H --> O[Git历史]
I --> N
J --> L
L --> P[结果合并去重]
M --> P
N --> P
O --> P
P --> Q[证据打包 createContextPack]
Q --> R[EvidencePack]核心组件
搜索上下文管理器
searchContext 是搜索系统的入口函数,负责协调整个搜索流程:
export async function searchContext(options: SearchOptions): Promise<{ intent: SearchIntent; hits: SearchHit[] }>
主要职责:
- 解析并验证工作区路径
- 确保索引已完成(调用
ensureIndexed) - 对查询进行意图分类
- 执行对应的搜索策略
- 合并和去重搜索结果
资料来源:src/search.ts:核心函数
意图分类器
意图分类器 classifyQuery 是搜索系统的智能路由层,根据查询内容将其映射到最适合的搜索策略。
function classifyQuery(q: string): SearchIntent
支持的意图类型:
| 意图类型 | 触发关键词 | 搜索策略 |
|---|---|---|
exact | 符号名(驼峰命名)、路径分隔符、井号 | 精确匹配文件路径或符号 |
symbol | function、method、class、interface、变量名 | 符号定义检索 |
memory | memory、lesson、remember、learned、session | 记忆库检索 |
impact | impact、affected、depends、blast radius、uses | 影响分析和依赖追踪 |
historical | why、changed、commit、history、regression | Git 历史分析 |
architectural | architecture、flow、trace、connects、imports | 架构图遍历 |
docs | docs、documentation、guide、readme、how to | 文档检索 |
vague | 其他情况 | 模糊全文搜索 |
资料来源:src/search.ts:意图分类逻辑
意图分类的实现细节:
function classifyQuery(q: string): SearchIntent {
const lower = q.toLowerCase();
if (/[`"'#.:/]/.test(q) || /\b[A-Z][A-Za-z0-9_]{2,}\b/.test(query)) return "exact";
if (/\b(function|method|class|interface|enum|struct|impl)\b/.test(q)) return "symbol";
if (/\b(memory|memories|remember|remembers|lesson|lessons|learned|session|sessions)\b/.test(q)) return "memory";
if (/\b(impact|affected|depends on|dependents|blast radius|what uses|who calls)\b/.test(q)) return "impact";
// ... 更多分类规则
}
搜索策略
全文搜索(FTS)
全文搜索引擎基于 SQLite 的 FTS5 扩展实现,支持 BM25 排序算法:
const rows = kernel.db
.prepare("SELECT ref, path, title, text, bm25(chunks_fts) AS rank FROM chunks_fts WHERE chunks_fts MATCH ? LIMIT ?")
.all(fts, limit * 10)
查询构建器 ftsQuery:
负责将用户查询转换为 FTS5 兼容的查询语法:
- 移除停用词(stopwords)
- 展开相关术语(同义词扩展)
- 处理特殊字符和符号
停用词列表:
const STOPWORDS = new Set(["where", "what", "which", "when", "how", "are", "the", "for", "with", "and", "or", "to"]);
术语扩展 expandedTerms:
根据查询语义自动添加相关术语:
| 语义主题 | 扩展术语 |
|---|---|
| tool/tools 相关 | server, tool, tools, callTool |
| MCP 相关 | mcp, server, stdio |
| memory 相关 | memory, memories, lesson, lessons, claim, ledger, evidence |
| impact 相关 | imports, tests, edges |
资料来源:src/search.ts:FTS实现
符号搜索
符号搜索专门用于定位代码中的定义和声明,支持多种编程语言:
支持的符号类型:
| 语言 | 符号类型 |
|---|---|
| TypeScript/JavaScript | function, class, interface, type, const |
| Python | function, class |
| Go | function (大写导出), struct, interface |
| Rust | function, struct, enum, trait, impl |
| Markdown | heading |
符号提取器 extractSymbols:
function extractSymbols(relativePath: string, content: string, language: string): SymbolRecord[]
示例 - TypeScript 函数提取:
matchPush(line, /^\s*(export\s+)?(?:async\s+)?function\s+([A-Za-z_$][\w$]*)/, push, "function");
资料来源:src/extract.ts:符号提取
图关系搜索
图搜索基于提取的导入和依赖关系构建有向图,支持:
- 依赖追踪:查找某个模块的导入关系
- 影响分析:反向查找依赖当前目标的所有模块
- 路径追踪:在两个符号/文件之间寻找连接路径
图数据结构:
interface RawEdge {
targetName: string;
targetType: "module" | "symbol" | "config";
edgeType: "IMPORTS" | "TESTS" | "CONFIGURES";
line: number;
}
导入关系提取:
| 语言 | 导入语法 |
|---|---|
| TypeScript/JavaScript | from "..." / require("...") |
| Python | from ... import ... / import ... |
| Go | "..." |
| Rust | use ...; / mod ...; |
| JSON | "key": value |
资料来源:src/extract.ts:边提取
记忆搜索
记忆系统允许 AI 代理存储和检索基于证据的经验教训:
memory
.command("add")
.requiredOption("--claim <text>", "Lesson claim.")
.requiredOption("--evidence <ref...>", "Evidence ref(s)")
.option("--scope <scope>", "Memory scope.", "repo")
.option("--confidence <number>", "Confidence from 0 to 1.", parseFloat, 0.7)
记忆搜索触发条件:
当查询包含以下关键词时,系统自动启用记忆搜索:
- memory, memories
- remember, remembers
- lesson, lessons
- learned
- session, sessions
- ledger, evidence
资料来源:src/search.ts:记忆搜索触发
证据打包系统
createContextPack 函数将搜索结果整合为结构化的证据包:
export async function createContextPack(options: CreatePackOptions): Promise<EvidencePack>
证据包结构
interface EvidencePack {
id: string; // 唯一标识符
query: string; // 原始查询
scope: string; // 搜索范围
intent: SearchIntent; // 识别的意图类型
summary: string; // 结果摘要
citations: SearchHit[]; // 引用列表
files: FileContext[]; // 文件级上下文
symbols: SymbolRecord[]; // 相关符号
graphPaths: GraphPath[];// 图路径连接
memoryHits: SearchHit[]; // 记忆命中
confidence: number; // 置信度 0.1-0.92
tokenEstimate: number; // 估算 token 数
budget: number; // 预算上限
createdAt: string; // 创建时间 (ISO)
}
置信度计算
function confidenceFor(hits: SearchHit[], graphPaths: GraphPath[], memoryHits: SearchHit[]): number {
return clamp(0.25 + hits.length * 0.05 + graphPaths.length * 0.02 + memoryHits.length * 0.05, 0.1, 0.92);
}
置信度计算公式:
| 贡献来源 | 权重 |
|---|---|
| 基础分 | 0.25 |
| 每条命中 | +0.05 |
| 每条图路径 | +0.02 |
| 每条记忆命中 | +0.05 |
| 最小值 | 0.1 |
| 最大值 | 0.92 |
资料来源:src/search.ts:置信度计算
CLI 集成
搜索系统通过命令行提供完整的交互接口:
可用命令
# 搜索上下文
cxf search "<query>" --workspace <path> --limit 10 --kind all|code|docs|symbols|memory
# 创建证据包
cxf query "<query>" --workspace <path> --budget 2000 --json
# 追踪图路径
cxf trace --from <symbol> --to <target> --edge-types imports|tests
# 影响分析
cxf impact <symbol_or_file>
# 历史分析
cxf why --target <symbol_or_file>
查询选项
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
--workspace | path | process.cwd() | 工作区路径 |
--limit | number | 10 | 最大命中数 |
--kind | enum | all | 搜索类型 |
--budget | number | 2000 | token 预算 |
--json | boolean | false | JSON 输出格式 |
资料来源:src/cli.ts:CLI命令定义
MCP 工具集成
Contextful 作为 MCP(Model Context Protocol)服务器运行,提供标准化的工具接口:
核心工具
| 工具名 | 功能 | 参数 |
|---|---|---|
context_pack | 创建证据包 | query, budget, scope |
search_code | 多模式搜索 | query, mode, filters |
trace_path | 图路径追踪 | from, to, edge_types |
impact_analysis | 影响分析 | symbol_or_file |
why_changed | 变更历史 | symbol_or_file |
recall_memory | 记忆检索 | query, scope |
write_lesson | 写入记忆 | claim, evidence_refs |
MCP 服务器启动
npx @inferensys/contextful server
资料来源:README.md:MCP工具
搜索流程图
sequenceDiagram
participant User as 用户
participant CLI as CLI/MCP
participant Search as 搜索系统
participant FTS as FTS引擎
participant Graph as 图数据库
participant Memory as 记忆库
participant Pack as 证据打包
User->>CLI: query "where is auth handled"
CLI->>Search: searchContext({query})
Search->>Search: classifyQuery()
Note over Search: intent = "architectural"
Search->>FTS: executeQuery()
Search->>Graph: loadGraphPaths()
Search->>Memory: memoryHits()
FTS-->>Search: hits[]
Graph-->>Search: graphPaths[]
Memory-->>Search: memoryHits[]
Search->>Pack: createContextPack()
Pack->>Pack: calculateConfidence()
Pack->>Pack: estimateTokens()
Pack-->>CLI: EvidencePack
CLI-->>User: 格式化输出数据模型
SearchHit
interface SearchHit {
ref: string; // 引用标识 (file:path:start-end)
path: string; // 文件路径
title: string; // 标题
text: string; // 匹配文本
kind: "code" | "doc" | "symbol" | "memory";
score: number; // 相关性得分
rank: number; // BM25 排名
line?: number; // 行号
}
SymbolRecord
interface SymbolRecord {
ref: string;
name: string;
kind: string; // function, class, etc.
filePath: string;
line: number;
signature: string; // 函数签名/类型签名
exported?: boolean;
}
GraphPath
interface GraphPath {
from: string;
to: string;
edgeType: string;
filePath: string;
line: number;
}
资料来源:src/search.ts:数据结构定义
高级功能
影响分析
impactAnalysis 函数执行反向依赖分析:
export async function impactAnalysis(options: {
workspace?: string;
target: string;
limit?: number;
}): Promise<{
target: string;
dependencies: GraphPath[];
dependents: GraphPath[];
likelyTests: GraphPath[];
}>
返回数据说明:
| 字段 | 说明 |
|---|---|
dependencies | 目标直接依赖的模块 |
dependents | 依赖该目标的模块 |
likelyTests | 相关的测试文件 |
变更历史分析
whyChanged 函数结合搜索结果和 Git 历史:
export async function whyChanged(options: {
workspace?: string;
target: string;
limit?: number
}): Promise<{
target: string;
currentEvidence: SearchHit[];
commits: Array<{
hash: string;
subject: string;
date?: string;
files: string[];
}>;
}>
资料来源:src/search.ts:高级搜索功能
索引状态查询
export async function getIndexStatus(options: { workspace?: string }): Promise<IndexStatus>
返回的索引状态信息:
| 字段 | 类型 | 说明 |
|---|---|---|
workspace | string | 工作区路径 |
status | string | 索引状态 |
fileCount | number | 文件总数 |
languageCounts | Record<string, number> | 各语言文件统计 |
warnings | string[] | 索引警告列表 |
搜索结果后处理
去重机制
function dedupeHits(hits: SearchHit[]): SearchHit[] {
const seen = new Set<string>();
return hits.filter((hit) => {
if (seen.has(hit.ref)) return false;
seen.add(hit.ref);
return true;
});
}
得分计算
搜索结果通过多层评分机制排序:
- BM25 基础分:FTS5 内置的 BM25 算法
- 意图匹配奖励:根据意图类型调整权重
- 语义扩展奖励:术语扩展匹配额外加分
function scoreFromRank(rank: number, intent: SearchIntent, query: string): number {
const lower = query.toLowerCase();
let bonus = 0;
// 意图特定奖励
if (intent === "symbol" && lower.includes("function")) bonus += 10;
if (intent === "memory" && lower.includes("memory ledger")) bonus += 7;
return 10 / (1 + Math.abs(rank)) + bonus;
}
资料来源:src/search.ts:得分计算
总结
搜索系统是 Contextful 实现智能上下文检索的核心引擎,通过以下机制为 AI 代理提供精确的代码上下文:
- 意图驱动的路由:自动识别查询意图并选择最优搜索策略
- 多模态检索:整合全文搜索、符号搜索、图搜索和记忆搜索
- 证据打包:将零散的搜索结果整合为结构化的证据包
- 智能排序:基于 BM25 和语义理解的结果排序
- 置信度评估:量化的结果可信度指标
该系统特别适用于大型代码库的场景,能够帮助 AI 代理快速定位相关代码片段,避免盲目探索,同时保留完整的引用溯源能力。
资料来源:[src/search.ts:核心函数](https://github.com/Inferensys/contextful/blob/main/src/search.ts)
上下文包系统
上下文包(Context Pack)是 Contextful 的核心功能模块,它将索引后的代码上下文、符号信息、图关系和记忆数据打包成紧凑的、带引用的、符合 token 预算的证据束,供 AI Agent 在执行任务时使用。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
系统概述
设计目标
上下文包系统旨在解决 AI Agent 在大型代码库中检索上下文时的核心痛点:
| 问题 | 上下文包解决方案 |
|---|---|
| 随机文件读取导致 token 浪费 | 基于查询意图的精确检索 |
| 缺乏可信引用 | 每个证据块都附带文件路径和行号 |
| 无法追踪代码关系 | 集成图路径遍历结果 |
| 遗忘跨会话经验 | 整合证据-backed 记忆数据 |
核心数据类型
上下文包的数据结构定义在 src/types.ts 中,主要包含以下组件:
interface EvidencePack {
id: string; // 唯一标识符,格式: ctx_<hash>
query: string; // 原始查询文本
scope: string; // 作用域(如 "repo")
intent: SearchIntent; // 查询意图分类
summary: string; // 包内容的自然语言摘要
citations: SearchHit[]; // 命中的证据列表
files: FileContext[]; // 按文件分组的引用
symbols: SymbolRecord[]; // 相关符号记录
graphPaths: GraphPath[]; // 图关系路径
memoryHits: SearchHit[]; // 记忆命中结果
confidence: number; // 置信度(0.1-0.92)
tokenEstimate: number; // 实际 token 估算值
budget: number; // 分配的 token 预算
createdAt: string; // 创建时间(ISO 格式)
}
工作流程
上下文包创建流程
graph TD
A[接收查询请求] --> B[分类查询意图]
B --> C{意图类型}
C -->|code| D[执行代码搜索]
C -->|docs| E[执行文档搜索]
C -->|symbol| F[执行符号搜索]
C -->|memory| G[搜索记忆数据]
C -->|impact| H[执行影响分析]
D --> I[检索图路径]
E --> I
F --> I
G --> I
H --> I
I --> J[根据 token 预算排序选择证据]
J --> K[生成置信度评分]
K --> L[构建上下文包]
L --> M[保存到数据库]
M --> N[返回 EvidencePack]证据选择与排序
上下文包使用分层策略选择证据:
- 意图匹配:根据查询意图优先返回相关类型的命中结果
- 相关性评分:使用 BM25 算法结合自定义调整因子
- Token 预算约束:按优先级遍历,直到达到预算上限
// token 预算选择逻辑
let tokenEstimate = 0;
const selected: SearchHit[] = [];
for (const hit of scored) {
if (selected.some(s => s.ref === hit.ref)) continue;
if (tokenEstimate + hit.tokenEstimate >= budget) break;
selected.push(hit);
tokenEstimate += hit.tokenEstimate;
}
意图分类系统
意图类型定义
| 意图类型 | 触发关键词 | 说明 |
|---|---|---|
symbol | 函数名、类名、常量 | 符号定义和引用查找 |
code | 实现、逻辑、算法 | 代码片段搜索 |
docs | 文档、README、如何 | 文档内容检索 |
memory | 记忆、经验、教训 | 证据-backed 记忆查询 |
impact | 影响、依赖、影响范围 | 影响分析 |
historical | 为什么、变更、历史 | Git 历史追溯 |
architectural | 架构、流程、调用链 | 架构分析 |
exact | 文件路径、行号、符号 | 精确匹配 |
vague | 无明确意图 | 模糊查询 |
意图分类实现
function classifyQuery(q: string): SearchIntent {
if (/\b(function|class|method|const|interface|type|struct)\s+[A-Z]/.test(q)) return "symbol";
if (/\b(where|find|search|locate|get|retrieve)\b/.test(q)) return "code";
if (/\b(memory|remember|learned|lessons?|sessions?)\b/.test(q)) return "memory";
if (/\b(impact|affected|depends on|dependents|blast radius|what uses|who calls)\b/.test(q)) return "impact";
if (/\b(why|changed|commit|history|regression|introduced)\b/.test(q)) return "historical";
if (/\b(architecture|flow|path|trace|connects|calls|imports|dependency)\b/.test(q)) return "architectural";
if (/\b(resource|docs|documentation|guide|readme|how to|setup)\b/.test(q)) return "docs";
if (/[`"'#.:/]/.test(q) || /\b[A-Z][A-Za-z0-9_]{2,}\b/.test(query)) return "exact";
return "vague";
}
资料来源:src/search.ts:1-14
置信度评估
置信度计算公式
上下文包的置信度通过以下公式计算:
confidence = clamp(0.25 + hits.length × 0.05 + graphPaths.length × 0.02 + memoryHits.length × 0.05, 0.1, 0.92)
| 组成部分 | 权重 | 说明 |
|---|---|---|
| 基础分 | 0.25 | 最低置信度保证 |
| 命中数 | +0.05/个 | 每个搜索命中增加置信度 |
| 图路径数 | +0.02/个 | 每条图关系路径增加置信度 |
| 记忆命中数 | +0.05/个 | 每个记忆命中增加置信度 |
置信度边界
置信度始终被限制在 [0.1, 0.92] 范围内,确保:
- 最低 10% 置信度(无任何证据时)
- 最高 92% 置信度(避免过度自信)
function confidenceFor(hits: SearchHit[], graphPaths: GraphPath[], memoryHits: SearchHit[]): number {
return clamp(0.25 + hits.length * 0.05 + graphPaths.length * 0.02 + memoryHits.length * 0.05, 0.1, 0.92);
}
资料来源:src/search.ts:89-91
图关系集成
图路径类型
上下文包包含代码库中实体之间的图关系:
interface GraphPath {
from: string; // 源实体名称
to: string; // 目标实体名称
edgeType: string; // 边类型(IMPORTS、DEFINES、CONFIGURES 等)
filePath: string; // 关系所在文件
line: number; // 关系所在行号
}
边类型定义
| 边类型 | 说明 | 提取来源 |
|---|---|---|
IMPORTS | 模块导入关系 | TypeScript/Python/Go import 语句 |
DEFINES | 符号定义关系 | 函数、类、接口声明 |
CONFIGURES | 配置关系 | package.json 依赖、配置文件键 |
TESTS | 测试关系 | 测试文件与被测文件关联 |
图路径加载
function loadGraphPaths(db: Database, paths: string[], limit: number): GraphPath[] {
const rows = db.prepare(`
SELECT from_name, target_name, edge_type, file_path, line
FROM edges
WHERE file_path IN (${paths.map(() => "?").join(",")})
LIMIT ?
`).all(...paths, limit) as EdgeRow[];
return rows.map(row => ({
from: row.from_name,
to: row.target_name,
edgeType: row.edge_type,
filePath: row.file_path,
line: row.line
}));
}
CLI 接口
查询命令
cxf query "<query>" --workspace <path> --budget <tokens> --json
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
query | 字符串 | 必需 | 要回答的查询文本 |
--workspace | 路径 | 当前目录 | 工作区路径 |
--budget | 整数 | 2000 | 近似的 token 预算 |
--json | 标志 | false | 输出 JSON 格式而非 Markdown |
实现逻辑
program
.command("query")
.description("Create an evidence pack for a query.")
.argument("<query>", "Query to answer from indexed context.")
.option("--workspace <path>", "Workspace path.", process.cwd())
.option("--budget <tokens>", "Approximate token budget.", parseInteger, 2000)
.option("--json", "Print JSON instead of Markdown.")
.action(async (query: string, options) => {
const pack = await createContextPack({
workspace: options.workspace,
query,
budget: options.budget
});
process.stdout.write(
options.json
? `${JSON.stringify(pack, null, 2)}\n`
: renderEvidencePackMarkdown(pack)
);
});
资料来源:src/cli.ts:20-36
Markdown 渲染
渲染格式
Evidence Pack 的 Markdown 渲染输出格式:
# Context Pack ctx_xxx
Query: <原始查询>
Intent: <意图类型>
Confidence: <置信度百分比>
Token estimate: <实际token数>/<预算token数>
<摘要文本>
## Citations
- file:src/auth.ts:10-25 (User authentication handler)
<证据摘要>
## Graph Paths
- auth.ts --IMPORTS--> utils.ts (src/auth.ts:3)
## Memory Hits
- <记忆引用>: <记忆内容>
渲染实现
export function renderEvidencePackMarkdown(pack: EvidencePack): string {
const lines = [
`# Context Pack ${pack.id}`,
"",
`Query: ${pack.query}`,
`Intent: ${pack.intent}`,
`Confidence: ${Math.round(pack.confidence * 100)}%`,
`Token estimate: ${pack.tokenEstimate}/${pack.budget}`,
"",
pack.summary,
"",
"## Citations"
];
for (const hit of pack.citations) {
lines.push(`- ${hit.ref} (${hit.title})`);
lines.push(` ${hit.excerpt}`);
}
// ... 图路径和记忆命中渲染
return lines.join("\n");
}
资料来源:src/report.ts:90-115
数据持久化
保存上下文包
创建后的上下文包会被保存到内核数据库:
function saveEvidencePack(
db: Database,
pack: { id: string; query: string; tokenEstimate: number; json: string }
): void {
db.prepare(`
INSERT INTO evidence_packs (id, query, token_estimate, created_at, json)
VALUES (?, ?, ?, ?, ?)
`).run(pack.id, pack.query, pack.tokenEstimate, nowIso(), pack.json);
}
数据库表结构
| 表名 | 用途 |
|---|---|
chunks_fts | 全文搜索索引 |
symbols | 符号索引 |
edges | 图关系边 |
memory | 证据-backed 记忆 |
evidence_packs | 已创建的上下文包历史 |
与 MCP 工具集成
核心 MCP 工具
上下文包系统通过以下 MCP 工具暴露给 AI Agent:
| 工具名称 | 功能 |
|---|---|
context_pack | 创建上下文包(核心功能) |
search_code | 代码、文档、符号、记忆搜索 |
trace_path | 图路径追踪 |
impact_analysis | 影响分析 |
why_changed | 变更历史追溯 |
recall_memory | 记忆召回 |
资料来源:README.md
工具调用示例
{
"tool": "context_pack",
"arguments": {
"query": "用户认证逻辑在哪里",
"budget": 2000,
"scope": "repo"
}
}
扩展词项机制
为提高搜索召回率,系统包含智能词项扩展:
function expandedTerms(query: string): string[] {
const additions: string[] = [];
const lower = query.toLowerCase();
if (/\b(tool|tools|registered|register)\b/.test(lower))
additions.push("server", "tool", "tools", "callTool");
if (/\bmcp\b/.test(lower))
additions.push("mcp", "server", "stdio");
if (/\bmemory|memories|remember|remembers|lesson|lessons|learned\b/.test(lower))
additions.push("memory", "memories", "lesson", "lessons", "claim", "ledger", "evidence");
if (/\bimpact|depends|dependents|uses\b/.test(lower))
additions.push("imports", "tests", "edges");
return [...terms, ...additions];
}
资料来源:src/search.ts:50-68
总结
上下文包系统是 Contextful 的核心模块,它通过以下机制为 AI Agent 提供精准、可信的代码上下文:
- 智能意图分类 — 自动识别查询类型并选择最佳搜索策略
- Token 预算管理 — 确保返回内容在预算范围内
- 多源证据整合 — 合并代码片段、符号信息、图关系和记忆数据
- 置信度评估 — 提供可量化的结果可信度指标
- 持久化存储 — 记录查询历史以供分析和回溯
通过 MCP 工具接口,AI Agent 可以方便地调用 context_pack 获取高质量的代码上下文,显著提升代码理解和任务完成效率。
资料来源:[src/search.ts:180-195]()
内存分类账
内存分类账(Memory Ledger)是 Contextful 项目中的核心模块,用于存储和管理基于证据的经验教训。它允许 AI 代理在执行任务过程中积累可复用的知识,并通过引用具体的代码片段作为证据,确保记忆的可靠性和可追溯性。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
设计目标
内存分类账解决了 AI 代码代理在长时间任务执行中面临的两个核心问题:
- 知识遗忘 - 代理无法记住跨会话的重要决策和经验
- 无据可查 - 记忆缺乏具体的代码引用,导致引用不准确
通过建立证据分类账,代理能够:
- 持久化存储项目特定的学习成果
- 通过引用索引快速检索相关记忆
- 在执行任务前调用已有记忆,避免重复踩坑
- 为每条记忆维护置信度,支持动态更新
资料来源:src/memory.ts:1-30
核心数据模型
Lesson(经验教训)
内存分类账中的基本存储单元是 Lesson 对象,其结构如下:
| 字段 | 类型 | 说明 |
|---|---|---|
id | string | 唯一标识符,格式为 les_{shortHash} |
claim | string | 核心主张/结论,描述学到的经验 |
evidence_refs | string[] | 证据引用数组,每项格式为 file:{path}:{startLine}-{endLine} |
scope | string | 作用范围,如 "repo" |
confidence | number | 置信度,范围 0.0-1.0 |
created_at | string | ISO 时间戳 |
supersedes | string[] | 被替代的记忆 ID 列表 |
资料来源:src/types.ts
证据引用格式
证据引用采用标准化格式,确保与代码索引系统无缝集成:
file:src/auth.ts:1-20
| 组成部分 | 说明 |
|---|---|
file | 固定前缀,表示文件引用 |
src/auth.ts | 相对于工作区的文件路径 |
1-20 | 代码行号范围 |
资料来源:src/memory.ts
架构设计
系统组件
graph TD
subgraph "内存分类账核心"
A[writeLesson] --> B[Lesson Store]
C[recallMemory] --> B
D[readEvidenceRefs] --> E[Chunk Loader]
E --> F[代码片段内容]
end
subgraph "持久化层"
B --> G[SQLite Database]
end
subgraph "接入层"
H[CLI memory 命令]
I[MCP Server Tools]
J[Query Search]
end
H --> A
I --> A
I --> C
J -.-> C工作流程
sequenceDiagram
participant Agent as AI 代理
participant MCP as MCP Server
participant Memory as 内存分类账
participant DB as SQLite
Agent->>MCP: write_lesson(claim, evidence_refs)
MCP->>Memory: writeLesson(claim, evidenceRefs)
Memory->>DB: 存储 Lesson 记录
Memory-->>Agent: 返回 Lesson ID
Agent->>MCP: recall_memory(query, scope)
MCP->>Memory: recallMemory(query, scope)
Memory->>DB: 全文检索匹配
Memory->>DB: 加载证据引用
Memory-->>Agent: 返回匹配的 Lesson 列表MCP 工具接口
内存分类账通过 MCP(Model Context Protocol)提供服务端工具:
write_lesson
写入一条基于证据的经验教训。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
claim | string | 是 | 经验主张文本 |
evidence_refs | string[] | 是 | 证据引用数组 |
scope | string | 否 | 作用域,默认 "repo" |
confidence | number | 否 | 置信度,默认 0.7 |
supersedes | string | 否 | 被替代的记忆 ID |
server.tool(
"write_lesson",
"Write an evidence-backed lesson to the memory ledger. Loose remember-this notes are rejected.",
{
claim: z.string(),
evidence_refs: z.array(z.string()),
scope: z.string().optional(),
confidence: z.number().optional(),
supersedes: z.string().optional()
},
async (params) =>
jsonContent(
await writeLesson({
workspace: params.workspace,
claim: params.claim,
evidenceRefs: params.evidence_refs,
scope: params.scope,
confidence: params.confidence,
supersedes: params.supersedes
})
)
);
recall_memory
检索匹配的经验教训。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
query | string | 是 | 检索查询字符串 |
scope | string | 否 | 作用域过滤 |
limit | number | 否 | 返回结果上限 |
server.tool(
"recall_memory",
"Search the evidence-backed memory ledger for lessons that survived previous agent sessions.",
{
query: z.string(),
scope: z.string().optional(),
limit: z.number().optional()
},
async (params) => jsonContent(await recallMemory(params))
);
CLI 命令
通过命令行界面管理内存分类账:
cxf memory add --claim <text> --evidence <ref...> [--workspace <path>] [--scope <scope>] [--confidence <number>]
命令参数
| 参数 | 说明 |
|---|---|
--claim <text> | 必填 经验主张内容 |
--evidence <ref...> | 必填 证据引用,至少一个 |
--workspace <path> | 工作区路径,默认为当前目录 |
--scope <scope> | 作用域,默认 "repo" |
--confidence <number> | 置信度 0-1,默认 0.7 |
资料来源:src/cli.ts:70-90
使用示例
# 基础用法
cxf memory add --claim "用户认证在 src/auth.ts 中处理" --evidence "file:src/auth.ts:1-50"
# 指定作用域和置信度
cxf memory add \
--claim "数据库连接池大小应设为 CPU 核心数的 2 倍" \
--evidence "file:src/db.ts:10-30" \
--evidence "file:config/default.json:5-10" \
--scope "repo" \
--confidence 0.85
# 替代旧记忆
cxf memory add \
--claim "新的配置管理方式已迁移到 config/v2" \
--evidence "file:config/v2/index.ts:1-100" \
--supersedes "les_abc123"
存储实现
数据库架构
内存分类账使用 SQLite 存储,通过 better-sqlite3 实现同步操作:
erDiagram
LESSONS {
string id PK
string claim
string evidence_refs
string scope
float confidence
string created_at
string supersedes
}
LESSONS_FTS {
string id PK
string claim
}证据引用处理
证据引用通过专门的解析器处理,将字符串引用转换为具体的代码内容:
// 引用格式解析
const ref = "file:src/auth.ts:1-20";
const parsed = parseFileRef(ref);
// 返回 { path: "src/auth.ts", startLine: 1, endLine: 20 }
资料来源:src/search.ts:80-85
与搜索系统的集成
查询分类增强
内存分类账与搜索系统深度集成,当用户查询命中内存相关关键词时,系统会给予搜索加权:
if (/\bmemory|memories|remember|remembers|lesson|lessons|learned|session|sessions\b/.test(lower)) {
additions.push("memory", "memories", "lesson", "lessons", "claim", "ledger", "evidence");
}
资料来源:src/search.ts:45-50
记忆匹配优先级
| 匹配条件 | 优先级调整 |
|---|---|
| 命中 "memory ledger" 或 "evidence-backed memory" | +7 |
包含 src/memory.ts 引用 | +5 |
包含 readme.md 引用 | +4 |
| 包含搜索模块内部函数 | -8 至 -16 |
置信度机制
置信度计算
每条记忆关联一个置信度分数,影响其在搜索结果中的排名:
| 置信度范围 | 语义含义 |
|---|---|
| 0.8 - 1.0 | 高可信,经过充分验证 |
| 0.5 - 0.8 | 中可信,基于合理推断 |
| 0.2 - 0.5 | 低可信,需要进一步验证 |
| 0.0 - 0.2 | 实验性,仅供参考 |
置信度衰减
长时间未使用的记忆会逐渐降低置信度,系统通过 staleMemories 机制跟踪这类记忆:
// 在报告生成中检测陈旧记忆
lines.push("", "## Stale Memories");
if (report.staleMemories.length === 0) lines.push("- No stale memories.");
for (const memory of report.staleMemories) {
lines.push(`- ${memory.id}: ${memory.claim}`);
}
资料来源:src/report.ts
使用场景
场景一:跨会话知识传递
graph LR
A[Session 1: 发现问题] --> B[write_lesson]
B --> C[存储到 Ledger]
C --> D[Session 2: 遇到类似问题]
D --> E[recall_memory]
E --> F[获取历史经验]场景二:代码变更影响评估
代理在修改共享模块前,通过内存分类账查找相关历史决策:
# 查询某模块的历史记忆
cxf query "为什么这里使用缓存" --workspace .
# 或通过 MCP
recall_memory(query="缓存策略决策", scope="repo")
场景三:证据驱动的决策
每条记忆必须包含证据引用,避免无依据的主观判断:
| 有效记忆 | 无效记忆 |
|---|---|
| "配置迁移到 config/v2,因为原有配置结构存在循环依赖问题" | "配置管理很重要" |
证据:file:config/v1/base.ts:20-30 | 无证据引用 |
最佳实践
撰写有效的经验主张
- 明确具体 - 包含具体的文件路径、函数名或配置项
- 包含证据 - 每条主张至少引用一个代码片段
- 合理置信度 - 根据验证程度设置合适的置信度
- 及时更新 - 发现新信息时替代旧记忆
证据引用规范
- 使用精确的行号范围,避免整文件引用
- 优先引用关键决策点而非辅助代码
- 定期验证证据引用仍然有效
作用域策略
| 作用域 | 适用场景 |
|---|---|
repo | 项目级通用经验 |
module:auth | 模块特定知识 |
feature:checkout | 功能特定决策 |
相关文档
资料来源:[src/memory.ts:1-30](https://github.com/Inferensys/contextful/blob/main/src/memory.ts)
数据存储与索引
Contextful 的数据存储与索引系统是整个工具的核心基础设施,负责将代码仓库转换为可高效查询的索引数据库。该系统基于 SQLite 构建,使用全文搜索(FTS)技术实现快速准确的语义检索,并为代码图谱、符号索引和证据包提供持久化存储。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
Contextful 的数据存储与索引系统是整个工具的核心基础设施,负责将代码仓库转换为可高效查询的索引数据库。该系统基于 SQLite 构建,使用全文搜索(FTS)技术实现快速准确的语义检索,并为代码图谱、符号索引和证据包提供持久化存储。
索引系统的主要职责包括:
- 解析多种编程语言的代码结构,提取符号(函数、类、接口等)
- 分析代码依赖关系,构建模块间的导入/导出图谱
- 将文件内容分块并建立全文索引
- 管理证据包(Evidence Pack)和记忆(Memory)数据
- 提供 CLI 命令和 MCP 接口供外部调用
资料来源:README.md:1-10
核心架构
技术选型
| 技术组件 | 用途 | 资料来源 |
|---|---|---|
| SQLite + better-sqlite3 | 关系型数据存储 | package.json |
| FTS5 全文索引 | 文本搜索 | src/search.ts |
| Tree-sitter | 代码解析与 AST 提取 | package.json |
| Fast-glob | 文件模式匹配 | package.json |
Contextful 选择 SQLite 作为存储引擎,主要考虑其轻量级、无需独立服务器进程的特性,非常适合本地开发环境和 CLI 工具场景。全文章索引使用 SQLite 的 FTS5 扩展实现,支持 BM25 排序算法和复杂的 MATCH 查询语法。
资料来源:package.json:20-35
数据库结构概览
graph TD
A[文件系统] --> B[文件解析]
B --> C[符号提取 extractSymbols]
B --> D[边提取 extractEdges]
B --> E[内容分块]
C --> F[symbols 表]
D --> G[edges 表]
E --> H[chunks 表]
H --> I[chunks_fts 全文索引]
F --> J[MCP 查询接口]
G --> J
H --> J数据提取模块
符号提取(extractSymbols)
extractSymbols 函数负责从源代码中提取各种编程结构,返回包含名称、种类、所在行号和签名的符号记录数组。该函数支持的语言及对应的提取模式如下:
资料来源:src/extract.ts:1-50
#### TypeScript / JavaScript 提取规则
| 语言元素 | 正则模式 | 符号种类 |
|---|---|---|
| 函数 | export async function 或 function | function |
| 类 | export class | class |
| 接口 | export interface | interface |
| 类型别名 | export type | type |
| 常量箭头函数 | export const ... => | function |
// 提取逻辑示例
matchPush(line, /^\s*(export\s+)?(?:async\s+)?function\s+([A-Za-z_$][\w$]*)/, push, "function");
matchPush(line, /^\s*(export\s+)?class\s+([A-Za-z_$][\w$]*)/, push, "class");
资料来源:src/extract.ts:10-18
#### Python 提取规则
Python 支持函数和类的提取,使用缩进敏感的解析方式:
const def = line.match(/^\s*(?:async\s+)?def\s+([A-Za-z_][\w]*)/);
if (def) push(def[1], "function");
const cls = line.match(/^\s*class\s+([A-Za-z_][\w]*)/);
if (cls) push(cls[1], "class");
#### Rust 提取规则
Rust 支持函数、结构体、枚举、Trait 和 impl 块的提取:
matchPush(line, /^\s*(pub\s+)?fn\s+([A-Za-z_][\w]*)/, push, "function");
matchPush(line, /^\s*(pub\s+)?struct\s+([A-Za-z_][\w]*)/, push, "struct");
matchPush(line, /^\s*(pub\s+)?enum\s+([A-Za-z_][\w]*)/, push, "enum");
资料来源:src/extract.ts:45-55
#### Markdown 标题提取
Markdown 文件会被提取为标题层级结构:
const heading = line.match(/^(#{1,6})\s+(.+)$/);
if (heading) push(heading[2].trim(), "heading");
边提取(extractEdges)
extractEdges 函数分析代码中的导入语句,构建模块间的依赖图谱。返回的边记录包含源文件名、行号和目标模块信息。
资料来源:src/extract.ts:60-90
#### 各语言导入解析规则
| 语言 | 导入语法 | 正则匹配 |
|---|---|---|
| TypeScript/JS (ES Module) | import ... from "..." | from\s+"'["'] |
| TypeScript/JS (CommonJS) | require("...") | require\("'["'] |
| Python | from ... import 或 import ... | ^\s*from\s+([\w.]+)\s+import |
| Go | import "..." | "([^"]+)" |
| Rust | use ...; 或 mod ...; | ^\s*use\s+([^;]+); |
#### package.json 依赖提取
当处理 package.json 文件时,系统会额外解析依赖配置:
for (const section of ["dependencies", "devDependencies", "peerDependencies", "scripts"]) {
const values = parsed[section];
if (!values || typeof values !== "object") continue;
for (const key of Object.keys(values)) {
edges.push({ targetName: `${section}:${key}`, targetType: "config", edgeType: "CONFIGURES", line: 1 });
}
}
内容分块策略
分块模式
Contextful 使用多层次的分块策略将文件内容转换为可管理的检索单元:
| 分块类型 | 生成方式 | 适用场景 |
|---|---|---|
| 符号块 (symbol) | 以符号定义为边界,最多延伸60行 | 精确查找函数/类定义 |
| 文件块 (file) | 80行窗口滑动分块 | 文档和较大代码段 |
| 文档块 (doc) | 以 Markdown 标题分割 | 文档检索 |
分块记录结构
interface ChunkRecord {
ref: string; // 引用标识符,格式: file:path:start-end
filePath: string; // 文件路径
startLine: number; // 起始行号
endLine: number; // 结束行号
kind: "symbol" | "file" | "doc"; // 分块类型
title: string; // 显示标题
text: string; // 原始文本内容
tokenEstimate: number; // token 数量估算
}
Markdown 特殊处理
Markdown 文件的分块逻辑与代码文件不同,会首先提取所有标题层级:
const headings: Array<{ title: string; line: number }> = [];
lines.forEach((line, index) => {
const match = line.match(/^(#{1,6})\s+(.+)$/);
if (match) headings.push({ title: match[2].trim(), line: index + 1 });
});
每个标题到下一个标题之间的内容构成一个独立的文档块,便于精确定位文档内容。
全文搜索实现
FTS 查询构建
Contextful 使用增强的 FTS 查询语法提升搜索效果:
资料来源:src/search.ts:20-60
function ftsQuery(query: string): string {
// 1. 展开查询术语,添加同义词和关联词
const expanded = expandedTerms(query);
// 2. 组合为 FTS5 MATCH 表达式
return expanded.map(t => `"${t}"*`).join(" OR ");
}
搜索意图分类
系统通过正则表达式匹配查询特征,自动识别用户意图:
| 意图类型 | 检测关键词 | 搜索策略 |
|---|---|---|
| memory | memory, remember, lesson | 记忆库检索 |
| impact | impact, affected, depends | 影响分析 |
| historical | why, changed, commit | 历史追溯 |
| architectural | architecture, flow, trace | 架构追踪 |
| docs | docs, documentation, how to | 文档检索 |
| exact | 代码符号、路径引用 | 精确匹配 |
| vague | 其他模糊查询 | 宽松匹配 |
资料来源:src/search.ts:1-20
搜索结果排序
搜索结果使用 BM25 算法结合自定义权重进行排序:
function scoreFromRank(rank: number, query: string, path?: string): number {
const lower = query.toLowerCase();
const pathLower = path?.toLowerCase() || "";
let bonus = 0;
// 路径匹配奖励
if (terms.some(t => pathLower.includes(t))) bonus += 5;
// 特定文件奖励/惩罚
if (pathLower.includes("memory")) bonus += 5;
if (pathLower.includes("readme")) bonus += 4;
return 10 / (1 + Math.abs(rank)) + bonus;
}
证据包(Evidence Pack)
创建流程
证据包是 Contextful 查询的最终输出,聚合了搜索结果、图谱路径和记忆数据:
graph TD
A[用户查询] --> B[searchContext]
B --> C{意图分类}
C --> D[FTS 搜索]
C --> E[记忆检索]
D --> F[结果去重]
E --> F
F --> G[Token 预算分配]
G --> H[图谱路径扩展]
H --> I[生成 Evidence Pack]证据包数据结构
interface EvidencePack {
id: string; // 唯一标识符
query: string; // 原始查询
scope: string; // 查询范围
intent: SearchIntent; // 识别的意图类型
summary: string; // 结果摘要
citations: SearchHit[]; // 搜索命中结果
files: Array<{ // 相关文件
path: string;
reason: string;
refs: string[];
}>;
symbols: SymbolRecord[]; // 符号信息
graphPaths: GraphPath[]; // 图谱路径
memoryHits: SearchHit[]; // 记忆命中
confidence: number; // 置信度 (0.1-0.92)
tokenEstimate: number; // Token 估算
budget: number; // 预算上限
createdAt: string; // 创建时间
}
置信度计算
function confidenceFor(hits: SearchHit[], graphPaths: GraphPath[], memoryHits: SearchHit[]): number {
return clamp(0.25 + hits.length * 0.05 + graphPaths.length * 0.02 + memoryHits.length * 0.05, 0.1, 0.92);
}
置信度基于命中数量、图谱连接数和记忆命中数计算,最低 0.1,最高 0.92。
CLI 命令接口
索引命令
cxf index --workspace <path> [--watch]
索引命令扫描工作区文件,调用符号提取和边提取模块,将结果存储到 SQLite 数据库。
查询命令
cxf query "<query>" --workspace <path> --budget 2000 --json
执行查询并返回格式化的证据包,支持 JSON 输出模式。
搜索命令
cxf search "<query>" --workspace <path> --limit 10 --kind all
支持按类型过滤:all|code|docs|symbols|memory。
报告命令
cxf report --workspace <path> --format markdown|json|html
生成工作区的上下文报告,包含文件统计、符号分布和警告信息。
资料来源:src/cli.ts:1-50
工具函数库
文本处理
src/util.ts 提供了索引过程中常用的文本处理函数:
export function lineRange(text: string, startLine: number, endLine: number): string {
const lines = text.split(/\r?\n/);
return lines.slice(Math.max(0, startLine - 1), Math.min(lines.length, endLine)).join("\n");
}
export function clamp(value: number, min: number, max: number): number {
return Math.max(min, Math.min(max, value));
}
lineRange 函数用于按行号范围提取文本片段,是分块策略的基础工具。clamp 函数确保数值在指定范围内,用于置信度计算。
二进制文件检测
export function isLikelyBinary(buffer: Buffer): boolean {
const sample = buffer.subarray(0, Math.min(buffer.length, 4096));
return sample.includes(0);
}
索引过程会跳过二进制文件以节省存储空间和提升检索效率。
资料来源:src/util.ts:1-30
MCP 服务器集成
Contextful 支持以 MCP(Model Context Protocol)服务器模式运行,提供标准化工具接口:
npx @inferensys/contextful server
核心工具列表
| 工具名称 | 功能描述 |
|---|---|
| context_pack | 生成带证据包的上下文响应 |
| search_code | 代码、文档、符号和记忆搜索 |
| trace_path | 图谱遍历追踪依赖路径 |
| impact_analysis | 影响分析和反向依赖查找 |
| why_changed | 变更历史追溯 |
| recall_memory | 检索持久化的项目记忆 |
资料来源:README.md:25-40
性能优化策略
Token 估算与预算控制
系统使用简单的 token 估算方法控制输出大小:
function estimateTokens(text: string): number {
return Math.ceil(text.length / 4); // 粗略估算:每4字符约1个token
}
证据包生成时会根据用户指定的 budget 参数筛选内容,确保返回的上下文在 token 预算范围内。
结果去重
搜索结果通过引用标识符进行去重:
function dedupeHits(hits: SearchHit[]): SearchHit[] {
const seen = new Set<string>();
return hits.filter((hit) => {
if (seen.has(hit.ref)) return false;
seen.add(hit.ref);
return true;
});
}
图谱剪枝
图谱查询支持深度限制,防止返回过大的依赖路径:
const graphPaths = loadGraphPaths(kernel.db, paths, 20); // 限制最多20条路径
总结
Contextful 的数据存储与索引系统通过模块化的设计实现了高效的代码检索能力。符号提取与边分析模块支持多种主流编程语言,SQLite+FTS5 的组合提供了可靠且快速的全文搜索能力。证据包机制将搜索结果包装为结构化的上下文响应,便于 AI 代理直接使用。整个系统的设计强调实用性和可扩展性,是构建代码智能助手的重要基础设施。
资料来源:[README.md:1-10]()
MCP 服务器集成
Contextful 项目通过 MCP(Model Context Protocol)协议提供服务器集成能力,使其能够作为标准的 MCP 服务器运行,为 AI 代理提供代码上下文理解服务。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
Contextful 项目通过 MCP(Model Context Protocol)协议提供服务器集成能力,使其能够作为标准的 MCP 服务器运行,为 AI 代理提供代码上下文理解服务。
MCP 服务器集成的核心设计理念是:代理请求上下文,Contextful 返回紧凑的证据包。这种设计避免了强制 AI 代理读取大量随机文件,通过结构化的证据打包机制提供精准、相关的上下文信息。
核心功能
Contextful MCP 服务器暴露以下核心工具:
| 工具名称 | 功能描述 |
|---|---|
context_pack | 返回排名、引用、令牌预算内的证据包 |
search_code | 强大的代码、文档、符号和内存搜索 |
trace_path | 在文件、符号、模块和配置之间进行图遍历 |
impact_analysis | 逆向依赖和可能的测试 |
why_changed | 当前证据加 Git 历史 |
recall_memory | 搜索会话学习记录和持久化的项目经验 |
write_lesson | 写入带证据支撑的经验教训 |
架构设计
graph TD
A[AI 代理] -->|MCP 协议| B[Contextful MCP 服务器]
B --> C{功能路由}
C -->|上下文打包| D[createContextPack]
C -->|代码搜索| E[searchContext]
C -->|图路径追踪| F[traceGraph]
C -->|影响分析| G[impactAnalysis]
C -->|历史分析| H[whyChanged]
C -->|记忆检索| I[recallMemory]
D --> J[SQLite Kernel DB]
E --> J
F --> J
G --> J
H --> J
I --> J工具参数规范
context_pack
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| query | string | 是 | 要回答的查询 |
| budget | number | 否 | 令牌预算,默认 2000 |
| scope | string | 否 | 搜索范围,默认 "repo" |
search_code
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| query | string | 是 | 搜索查询 |
| mode | string | 否 | 搜索模式 |
| filters | object | 否 | 过滤条件 |
trace_path
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| from | string | 是 | 起始节点 |
| to | string | 否 | 目标节点 |
| edge_types | string[] | 否 | 边类型过滤 |
搜索意图分类
系统会根据查询内容自动分类搜索意图:
| 意图类型 | 触发关键词 | 说明 |
|---|---|---|
| code | function, class, variable | 代码实体搜索 |
| memory | memory, lesson, learned | 记忆和经验检索 |
| impact | impact, depends, affected | 影响范围分析 |
| historical | why, history, commit | 历史变更追溯 |
| architectural | architecture, flow, dependency | 架构依赖分析 |
| docs | documentation, readme, how to | 文档搜索 |
资料来源:src/search.ts:1-15
查询扩展机制
系统包含智能查询扩展功能,根据用户查询自动添加相关术语:
// 相关术语扩展示例
if (/\b(tool|tools|registered|register)\b/.test(lower)) {
additions.push("server", "tool", "tools", "callTool");
}
if (/\bmcp\b/.test(lower)) {
additions.push("mcp", "server", "stdio");
}
if (/\bmemory|memories|remember\b/.test(lower)) {
additions.push("memory", "memories", "lesson", "lessons", "claim", "ledger", "evidence");
}
资料来源:src/search.ts:45-60
证据包结构
context_pack 返回的结构化证据包包含以下字段:
| 字段 | 类型 | 说明 |
|---|---|---|
| id | string | 唯一标识符 |
| query | string | 原始查询 |
| intent | SearchIntent | 检测到的搜索意图 |
| summary | string | 证据摘要 |
| citations | SearchHit[] | 引用列表 |
| files | FileInfo[] | 相关文件信息 |
| symbols | SymbolRecord[] | 相关符号 |
| graphPaths | GraphPath[] | 图路径连接 |
| memoryHits | SearchHit[] | 记忆命中 |
| confidence | number | 置信度 0-1 |
| tokenEstimate | number | 令牌估算 |
| budget | number | 令牌预算 |
| createdAt | string | 创建时间 |
启动方式
CLI 命令行启动
npx @inferensys/contextful server
MCP 服务器配置
服务器注册名称为 io.github.Inferensys/contextful,可通过 server.json 进行配置:
{
"mcpServers": {
"contextful": {
"command": "npx",
"args": ["@inferensys/contextful", "server"]
}
}
}
资料来源:package.json:40
依赖关系
MCP 服务器集成依赖以下核心包:
| 依赖包 | 版本 | 用途 |
|---|---|---|
| @modelcontextprotocol/sdk | ^1.29.0 | MCP 协议实现 |
| better-sqlite3 | ^12.10.0 | 本地索引数据库 |
| zod | ^4.4.3 | 类型验证 |
资料来源:package.json:19-32
内存管理功能
MCP 服务器提供持久化的记忆功能,支持通过 CLI 添加经验教训:
cxf memory add \
--claim "使用 JWT 时必须验证签名" \
--evidence "file:src/auth.ts:1-50" \
--scope "repo" \
--confidence 0.9
记忆数据与搜索系统集成,在相关查询时可以自动召回。
与 AI IDE 的集成
Contextful 支持多种 AI 编程辅助工具的 MCP 集成:
- Windsurf
- GitHub Copilot
- VS Code
- Cline
- Roo Code
- Continue
- Zed
资料来源:package.json:8-15
工作流程示例
sequenceDiagram
participant Agent as AI 代理
participant MCP as Contextful MCP
participant Kernel as Kernel DB
participant FS as 文件系统
Agent->>MCP: context_pack("用户认证逻辑在哪")
MCP->>Kernel: 搜索相关索引
Kernel-->>MCP: 命中结果 + 图路径
MCP->>MCP: 构建证据包
MCP->>Agent: 返回紧凑证据包
Agent->>Agent: 基于证据回答总结
MCP 服务器集成是 Contextful 的核心交互接口,它将复杂的代码索引和搜索能力通过标准化的 MCP 协议暴露给 AI 代理。通过结构化的证据包、图路径追踪和记忆系统,代理能够获得精准、可靠且可追溯的代码上下文,显著提升代码理解任务的准确性。
资料来源:[src/search.ts:1-15]()
解析与代码提取
解析与代码提取是 Contextful 项目中负责将源代码文件转换为可索引、可搜索的结构化数据的关键模块。该模块位于 src/extract.ts,是整个上下文检索系统的核心基础设施。其主要职责包括:
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
解析与代码提取是 Contextful 项目中负责将源代码文件转换为可索引、可搜索的结构化数据的关键模块。该模块位于 src/extract.ts,是整个上下文检索系统的核心基础设施。其主要职责包括:
- 符号提取:从源代码中识别函数、类、接口、类型等定义
- 边关系提取:解析文件间的导入依赖关系
- 代码分块:将大型文件语义化拆分为可管理的片段
- Markdown 处理:提取标题结构并按章节分块
资料来源:src/extract.ts:1-50
核心功能架构
A[源代码文件] --> B{文件类型判断}
B -->|TypeScript/JavaScript| C[TypeScript/JS 解析器]
B -->|Python| D[Python 解析器]
B -->|Go| E[Go 解析器]
B -->|Rust| F[Rust 解析器]
B -->|Markdown| G[Markdown 处理器]
B -->|JSON| H[JSON 处理器]
C --> I[extractSymbols]
D --> I
E --> I
F --> I
I --> J[符号列表]
C --> K[extractEdges]
D --> K
E --> K
F --> K
H --> K
K --> L[边关系列表]
J --> M[codeChunks]
L --> M
G --> N[markdownChunks]
N --> O[文档分块]
M --> P[索引数据库]
O --> P
符号提取详解
extractSymbols 函数
extractSymbols 是符号提取的主入口函数,通过正则表达式匹配源代码中的各种声明语句。
#### 支持的语言与符号类型
| 语言 | 符号类型 | 正则模式 | |
|---|---|---|---|
| TypeScript/JavaScript | 函数 | /^\s*(export\s+)?(?:async\s+)?function\s+([A-Za-z_$][\w$]*)/ | |
| TypeScript/JavaScript | 类 | /^\s*(export\s+)?class\s+([A-Za-z_$][\w$]*)/ | |
| TypeScript/JavaScript | 接口 | /^\s*(export\s+)?interface\s+([A-Za-z_$][\w$]*)/ | |
| TypeScript/JavaScript | 类型 | /^\s*(export\s+)?type\s+([A-Za-z_$][\w$]*)/ | |
| Python | 函数 | /^\s*(?:async\s+)?def\s+([A-Za-z_][\w]*)/ | |
| Python | 类 | /^\s*class\s+([A-Za-z_][\w]*)/ | |
| Go | 函数 | /^\s*func\s+(?:\([^)]*\)\s*)?([A-Za-z_][\w]*)/ | |
| Go | 结构体/接口 | `/^\s*type\s+([A-Za-z_][\w]*)\s+(struct\ | interface)/` |
| Rust | 函数 | /^\s*(pub\s+)?fn\s+([A-Za-z_][\w]*)/ | |
| Rust | 结构体 | /^\s*(pub\s+)?struct\s+([A-Za-z_][\w]*)/ | |
| Rust | 枚举 | /^\s*(pub\s+)?enum\s+([A-Za-z_][\w]*)/ | |
| Rust | Trait | /^\s*(pub\s+)?trait\s+([A-Za-z_][\w]*)/ |
#### matchPush 辅助函数
matchPush 是一个通用的高阶函数,用于将正则匹配结果转换为符号记录:
function matchPush(
line: string,
pattern: RegExp,
push: (name: string, kind: string, exported?: boolean) => void,
kind: string
): void {
const match = line.match(pattern);
if (!match) return;
push(match[2], kind, Boolean(match[1]));
}
该函数的设计允许:
- 捕获符号名称(match[2])
- 标记导出状态(match[1] 匹配
export关键字) - 统一处理不同类型的符号
边关系提取详解
extractEdges 函数
extractEdges 函数负责解析代码中的导入语句,构建模块间的依赖图。
#### 各语言的导入语句识别
| 语言 | 导入类型 | 正则/匹配模式 | |
|---|---|---|---|
| TypeScript/JavaScript | ES Module | `/(?:from\s+\ | import\s*)"'["']/g` |
| TypeScript/JavaScript | CommonJS | /require\("'["']\)/g | |
| Python | from import | /^\s*from\s+([\w.]+)\s+import\s+/ | |
| Python | import | /^\s*import\s+([\w.]+)/ | |
| Go | 导入路径 | /"([^"]+)"/g | |
| Rust | use 语句 | /^\s*use\s+([^;]+);/ | |
| Rust | mod 声明 | /^\s*mod\s+([A-Za-z_][\w]*);/ |
#### 特殊的 package.json 处理
当文件路径以 package.json 结尾时,函数会解析 JSON 内容并生成配置依赖边:
if (relativePath.endsWith("package.json")) {
try {
const parsed = JSON.parse(content) as Record<string, unknown>;
for (const section of ["dependencies", "devDependencies", "peerDependencies", "scripts"]) {
const values = parsed[section];
if (!values || typeof values !== "object") continue;
for (const key of Object.keys(values)) {
edges.push({ targetName: `${section}:${key}`, targetType: "config", edgeType: "CONFIGURES", line: 1 });
}
}
} catch {
// Broken JSON 处理
}
}
代码分块机制
分块策略概览
Contextful 实现了多种分块策略以适应不同的文件类型和搜索需求:
A[输入文件] --> B{文件类型}
B -->|代码文件| C[codeChunks]
B -->|Markdown| D[markdownChunks]
B -->|纯文本| E[textChunks]
C --> F[符号边界分块]
C --> G[空行分块]
G --> H[合并小片段]
F --> H
H --> I[生成 ChunkRecord]
D --> J[提取标题]
J --> K[按标题切分]
K --> I
E --> L[固定行数分块]
L --> I
codeChunks 函数
codeChunks 是代码文件的主要分块实现,采用以下策略:
- 空行分割:在空行处将文件分割为候选块
- 符号保护:确保函数/类定义的完整性不被分割
- 小片段合并:将行数过少的片段合并到前一个块
- 测试文件优先:测试文件中的相关代码会被优先选中
function codeChunks(relativePath: string, content: string, language: string): ChunkRecord[] {
const symbols = extractSymbols(relativePath, content, language);
const symbolLines = new Set(symbols.map((s) => s.line));
// 空行分割逻辑...
// 符号边界保护...
// 小片段合并...
return chunks;
}
测试文件识别
isTestFile 函数使用以下模式识别测试文件:
function isTestFile(relativePath: string): boolean {
return /(^|\/)(tests?|__tests__)\/|(\.|-)(test|spec)\.[A-Za-z]+$/.test(relativePath);
}
符合以下任一条件的文件将被识别为测试文件:
Markdown 处理
markdownChunks 函数
Markdown 文件的分块基于标题结构:
function markdownChunks(relativePath: string, content: string): ChunkRecord[] {
const lines = content.split(/\r?\n/);
const headings: Array<{ title: string; line: number }> = [];
// 提取所有标题 (# 到 ######)
lines.forEach((line, index) => {
const match = line.match(/^(#{1,6})\s+(.+)$/);
if (match) headings.push({ title: match[2].trim(), line: index + 1 });
});
// 无标题时返回整个文件
// 有标题时按标题切分
}
CLI 命令集成
解析与代码提取功能通过 CLI 模块对外提供服务:
A[CLI 入口] --> B[index 命令]
A --> C[daemon 命令]
A --> D[query 命令]
A --> E[search 命令]
A --> F[report 命令]
B --> G[ensureIndexed]
G --> H[索引工作区]
H --> I[调用 extract.ts]
D --> J[createContextPack]
J --> K[搜索索引]
K --> I
主要 CLI 命令
| 命令 | 功能 | 相关源码 |
|---|---|---|
index | 索引工作区中的所有代码文件 | src/cli.ts:30-50 |
daemon | 启动本地索引守护进程 | src/cli.ts:55-65 |
query | 根据查询创建证据包 | src/cli.ts:70-85 |
search | 在索引中搜索上下文 | src/cli.ts:90-105 |
report | 生成上下文报告 | src/cli.ts:110-120 |
资料来源:src/cli.ts:1-100
搜索与索引集成
搜索上下文流程
解析提取的数据最终服务于搜索功能:
A[searchContext] --> B[classifyQuery]
B --> C{意图类型}
C -->|exact| D[精确匹配]
C -->|code| E[FTS 代码搜索]
C -->|docs| F[FTS 文档搜索]
C -->|symbol| G[符号搜索]
C -->|memory| H[记忆搜索]
D --> I[rankResults]
E --> I
F --> I
G --> I
H --> I
I --> J[dedupeHits]
J --> K[返回搜索结果]
查询意图分类
classifyQuery 函数根据查询特征判断用户意图:
| 意图 | 触发关键词 | 资料来源 |
|---|---|---|
| symbol | function, class, interface | src/search.ts:20-30 |
| memory | memory, lesson, remember | src/search.ts:35-40 |
| impact | impact, affected, depends | src/search.ts:42-44 |
| historical | why, changed, history | src/search.ts:46-48 |
| architectural | architecture, flow, imports | src/search.ts:50-52 |
| docs | docs, documentation, readme | src/search.ts:54-56 |
资料来源:src/search.ts:15-60
证据包生成
createContextPack 函数
createContextPack 将搜索结果整合为结构化的证据包:
export async function createContextPack(options: CreatePackOptions): Promise<EvidencePack> {
const search = await searchContext({ workspace, query, limit: budget });
// 选择性合并...
const selected = search.hits.slice(0, maxChunks);
const tokenEstimate = estimateTokens(selected.map((h) => h.text).join("\n"));
const kernel = openKernelDb(workspace);
const graphPaths = loadGraphPaths(kernel.db, paths, 20);
const pack: EvidencePack = {
id: `ctx_${shortHash(`${query}:${nowIso()}`)}`,
query,
scope,
intent: search.intent,
summary: summarizePack(query, search.intent, selected, graphPaths, memoryHits),
citations: selected,
confidence: confidenceFor(selected, graphPaths, memoryHits),
// ...
};
return pack;
}
工具函数
行范围提取
lineRange 函数从文本中提取指定行范围:
export function lineRange(text: string, startLine: number, endLine: number): string {
const lines = text.split(/\r?\n/);
return lines.slice(Math.max(0, startLine - 1), Math.min(lines.length, endLine)).join("\n");
}
资料来源:src/util.ts:30-35
二进制文件检测
isLikelyBinary 函数通过检测空字节判断文件类型:
export function isLikelyBinary(buffer: Buffer): boolean {
const sample = buffer.subarray(0, Math.min(buffer.length, 4096));
return sample.includes(0);
}
资料来源:src/util.ts:20-25
数据模型
ChunkRecord 结构
interface ChunkRecord {
ref: string; // 文件引用,如 "file:src/auth.ts:1-20"
filePath: string; // 相对文件路径
startLine: number; // 起始行号
endLine: number; // 结束行号
kind: "code" | "doc" | "file"; // 块类型
title: string; // 标题/符号名
text: string; // 块内容
tokenEstimate: number; // token 估算值
}
RawEdge 结构
interface RawEdge {
targetName: string; // 目标名称
targetType: "module" | "config" | "symbol"; // 目标类型
edgeType: "IMPORTS" | "CONFIGURES"; // 边类型
line: number; // 所在行号
filePath?: string; // 文件路径
}
资料来源:src/extract.ts:40-48
报告生成
generateReport 函数
generateReport 汇总索引状态并生成统计报告:
export async function generateReport(options: { workspace?: string }): Promise<ContextReport> {
const workspace = resolveWorkspace(options.workspace);
await ensureIndexed(workspace);
const kernel = openKernelDb(workspace);
const languageRows = kernel.db
.prepare("SELECT language, COUNT(*) AS count FROM files GROUP BY language ORDER BY count DESC")
.all();
// 收集统计信息...
// 生成报告...
}
资料来源:src/report.ts:50-80
总结
解析与代码提取模块是 Contextful 的核心基础设施,通过模块化的设计实现了对多种编程语言的支持。其关键设计特点包括:
- 正则驱动:使用正则表达式实现轻量级代码解析
- 语义分块:保持函数/类边界的完整性
- 多语言支持:覆盖 TypeScript、JavaScript、Python、Go、Rust 等主流语言
- 测试优先:自动识别并优先处理测试文件
- 可扩展架构:通过
matchPush等高阶函数便于添加新语言支持
该模块与搜索模块紧密集成,共同构成了上下文检索的能力基础。
资料来源:[src/extract.ts:1-50]()
CLI 命令行工具
Contextful 的 CLI(命令行界面)是用户与上下文索引系统交互的主要入口点。该工具提供了索引工作区、查询证据包、搜索上下文、生成报告以及管理 MCP 服务器等功能。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
Contextful 的 CLI(命令行界面)是用户与上下文索引系统交互的主要入口点。该工具提供了索引工作区、查询证据包、搜索上下文、生成报告以及管理 MCP 服务器等功能。
CLI 采用 Commander.js 框架构建,支持多种子命令,覆盖了从代码索引到证据管理的完整工作流程。cxf 是主二进制文件名称,同时提供 contextful 作为可读别名。
资料来源:src/cli.ts:1-20
核心命令架构
命令层次结构
graph TD
A[cxf / contextful] --> B[index]
A --> C[daemon]
A --> D[query]
A --> E[search]
A --> F[report]
A --> G[memory]
A --> H[server]
G --> G1[memory add]命令总览
| 命令 | 功能描述 | 输出格式 |
|---|---|---|
index | 索引工作区文件 | JSON |
daemon | 启动本地索引守护进程 | JSON(流式) |
query | 创建证据包 | Markdown / JSON |
search | 搜索索引上下文 | JSON |
report | 生成上下文报告 | Markdown / JSON / HTML |
memory add | 存储证据-backed 经验 | JSON |
server | 运行 MCP stdio 服务器 | - |
资料来源:src/cli.ts:20-80
索引命令
index
索引命令用于扫描工作区中的代码文件,建立搜索索引。
cxf index --workspace <path> [--watch]
#### 参数与选项
| 参数 | 类型 | 必需 | 默认值 | 说明 |
|---|---|---|---|---|
--workspace <path> | string | 否 | process.cwd() | 工作区路径 |
--watch | flag | 否 | false | 监听文件变化 |
#### 功能说明
- 扫描指定工作区路径下的所有代码文件
- 支持 TypeScript、JavaScript、Python、Go、Rust 等多种语言
- 提取文件中的符号(symbols)、边(edges)和代码块(chunks)
- 将索引数据存储到 SQLite 数据库中
资料来源:src/cli.ts:20-35
daemon
守护进程命令启动一个持续运行的索引服务,监听文件系统变化并实时更新索引。
cxf daemon --workspace <path>
#### 特性
- 实时监听工作区文件变化
- 增量更新索引,而非完全重建
- 通过 stdout 流式输出 JSON 格式的索引结果
资料来源:src/cli.ts:36-45
查询命令
query
query 命令是 Contextful 的核心功能,用于创建紧凑的证据包回答用户查询。
cxf query "<query>" --workspace <path> --budget <tokens> [--json]
#### 参数与选项
| 参数 | 类型 | 必需 | 默认值 | 说明 |
|---|---|---|---|---|
<query> | string | 是 | - | 要回答的查询语句 |
--workspace <path> | string | 否 | process.cwd() | 工作区路径 |
--budget <tokens> | integer | 否 | 2000 | 近似 token 预算 |
--json | flag | 否 | false | 输出 JSON 而非 Markdown |
#### 工作流程
graph LR
A[用户查询] --> B[搜索索引]
B --> C[意图分类]
C --> D[BM25 排序]
D --> E[图路径分析]
E --> F[选择证据]
F --> G[生成证据包]
G --> H[返回结果]#### 输出内容
证据包包含以下结构化信息:
id: 证据包唯一标识符query: 原始查询intent: 搜索意图分类summary: 结果摘要citations: 选中的证据引用列表files: 相关文件及原因symbols: 匹配的符号记录graphPaths: 图连接路径memoryHits: 记忆命中confidence: 置信度分数tokenEstimate: 估算的 token 数量budget: 分配的 token 预算createdAt: 创建时间戳
资料来源:src/cli.ts:46-60, src/search.ts:80-150
搜索命令
search
search 命令提供轻量级的上下文搜索功能,不生成完整证据包。
cxf search "<query>" --workspace <path> --limit <count> --kind <kind>
#### 参数与选项
| 参数 | 类型 | 必需 | 默认值 | 说明 |
|---|---|---|---|---|
<query> | string | 是 | - | 搜索查询 |
--workspace <path> | string | 否 | process.cwd() | 工作区路径 |
--limit <count> | integer | 否 | 10 | 最大命中数 |
--kind <kind> | enum | 否 | all | 搜索类型 |
#### kind 参数选项
| 值 | 说明 |
|---|---|
all | 所有类型 |
code | 仅代码 |
docs | 仅文档 |
symbols | 仅符号 |
memory | 仅记忆 |
资料来源:src/cli.ts:70-80
报告命令
report
生成工作区的上下文索引报告。
cxf report --workspace <path> --format <format>
#### 参数与选项
| 参数 | 类型 | 必需 | 默认值 | 说明 |
|---|---|---|---|---|
--workspace <path> | string | 否 | process.cwd() | 工作区路径 |
--format <format> | enum | 否 | markdown | 输出格式 |
#### format 参数选项
| 值 | 说明 |
|---|---|
markdown | Markdown 格式(默认) |
json | JSON 格式 |
html | HTML 格式 |
#### 报告内容
报告包含以下部分:
- 索引状态概览
- 语言覆盖率统计
- 热门查询记录
- 陈旧记忆列表
- Agent 使用建议
- 警告信息(如有)
资料来源:src/cli.ts:81-90, src/report.ts:1-100
记忆管理命令
memory add
存储证据-backed 的经验教训到记忆账本中。
cxf memory add \
--claim <text> \
--evidence <ref...> \
--workspace <path> \
--scope <scope> \
--confidence <number>
#### 参数与选项
| 参数 | 类型 | 必需 | 默认值 | 说明 |
|---|---|---|---|---|
--claim <text> | string | 是 | - | 经验声明 |
--evidence <ref...> | string[] | 是 | - | 证据引用列表 |
--workspace <path> | string | 否 | process.cwd() | 工作区路径 |
--scope <scope> | string | 否 | repo | 记忆作用域 |
--confidence <number> | float | 否 | 0.7 | 置信度(0-1) |
#### 证据引用格式
证据引用格式为:file:src/auth.ts:1-20,表示从 src/auth.ts 文件的第 1-20 行提取证据。
#### 功能说明
- 验证证据引用的有效性
- 将经验存储到 SQLite 数据库
- 支持覆盖(supersedes)旧记忆
资料来源:src/cli.ts:92-125
MCP 服务器命令
server
启动 MCP(Model Context Protocol)stdio 服务器。
cxf server
#### 功能说明
- 提供 MCP 标准工具接口
- 支持
context_pack、search_code、trace_path等工具 - 通过 stdio 与 AI 代理通信
资料来源:src/cli.ts:126-135
工具函数
参数解析辅助函数
function parseInteger(value: string): number
function parseReportFormat(value: string): ReportFormat
| 函数 | 输入 | 输出 | 错误处理 |
|---|---|---|---|
parseInteger | 字符串 | 整数 | 无效整数抛出错误 |
parseReportFormat | 字符串 | markdown/json/html | 无效格式抛出错误 |
资料来源:src/cli.ts:148-165
错误处理
CLI 采用统一的错误处理机制:
program.parseAsync(process.argv).catch((error) => {
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
process.exitCode = 1;
});
错误处理特点:
- 错误信息输出到 stderr
- 非零退出码表示失败
- 区分 Error 实例与普通字符串
资料来源:src/cli.ts:136-145
安装与使用
安装方式
npx @inferensys/contextful index --workspace .
npx @inferensys/contextful query "where is user auth handled" --workspace . --budget 2000
MCP 服务器启动
npx @inferensys/contextful server
环境要求
- Node.js >= 20
- 支持 Unix-like 系统及 Windows
资料来源:package.json:1-30, README.md:1-30
快速参考
| 命令 | 用途 |
|---|---|
cxf index --workspace . --watch | 索引并监听变化 |
cxf query "认证逻辑在哪里" | 查询证据包 |
cxf search "auth" --kind code | 搜索代码 |
cxf report --format html | 生成 HTML 报告 |
cxf memory add --claim "..." --evidence file:src/x.ts:1-10 | 添加记忆 |
cxf server | 启动 MCP 服务器 |
资料来源:[src/cli.ts:1-20]()
部署与配置
部署与配置 是 Contextful 项目的安装、环境设置及运行时参数管理模块。该模块涵盖了从 NPM 包安装到 MCP 服务器运行的完整部署链路,为开发者提供命令行界面(CLI)和 MCP(Model Context Protocol)服务器两种使用方式。Contextful 是一个上下文管理工具,帮助智能体(Agent)在处理复杂任务时获取精确的代码证据和上下文信息。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
部署与配置 是 Contextful 项目的安装、环境设置及运行时参数管理模块。该模块涵盖了从 NPM 包安装到 MCP 服务器运行的完整部署链路,为开发者提供命令行界面(CLI)和 MCP(Model Context Protocol)服务器两种使用方式。Contextful 是一个上下文管理工具,帮助智能体(Agent)在处理复杂任务时获取精确的代码证据和上下文信息。
核心部署模式
Contextful 支持两种主要的部署模式,适用于不同的使用场景。
本地 CLI 部署
本地 CLI 部署适合开发者直接在终端环境中使用,适用于代码浏览、上下文搜索和报告生成等场景。CLI 模式通过 cxf 或 contextful 命令行工具提供完整功能集。
# 基本索引操作
npx @inferensys/contextful index --workspace .
# 创建证据包
npx @inferensys/contextful query "where is user auth handled" --workspace . --budget 2000
资料来源:README.md
MCP 服务器部署
MCP 服务器部署适用于将 Contextful 作为智能体工具集成的场景。服务器通过标准输入/输出(stdio)接口与 MCP 客户端通信,提供标准化的工具调用接口。
npx @inferensys/contextful server
MCP 服务器模式下,Contextful 提供以下核心工具接口供智能体调用:
| 工具名称 | 功能描述 | 主要参数 |
|---|---|---|
context_pack | 返回排序的、带引用的、符合token预算的证据包 | query, budget, scope |
search_code | 强大的代码、文档、符号和内存搜索 | query, mode, filters |
trace_path | 跨文件、符号、模块和配置的图遍历 | from, to, edge_types |
impact_analysis | 反向依赖分析和可能的测试识别 | symbol_or_file |
why_changed | 结合当前证据和Git历史解释变更原因 | symbol_or_file, limit |
recall_memory | 搜索跨会话持久化的项目经验 | query, scope, limit |
write_lesson | 将带证据的经验写入内存账本 | claim, evidence_refs, scope, confidence |
资料来源:README.md, src/mcp-server.ts
CLI 命令详解
CLI 是 Contextful 的主要交互接口,命令结构遵循 cxf <command> [options] 的格式。
索引命令 (index)
索引命令用于扫描和索引工作区内的代码文件,建立搜索和图遍历的基础数据。
cxf index --workspace <path> [--watch]
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
--workspace | path | process.cwd() | 工作区路径 |
--watch | flag | false | 监视模式,持续监听文件变化 |
资料来源:src/cli.ts
守护进程命令 (daemon)
守护进程命令启动本地索引服务,持续监视工作区文件变化并更新索引。
cxf daemon --workspace <path>
当工作区文件发生变更时,守护进程会主动推送更新结果到标准输出:
await watchWorkspace(options.workspace, (result) => {
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
});
资料来源:src/cli.ts
查询命令 (query)
查询命令是 Contextful 的核心功能,根据自然语言查询创建包含证据的上下文包。
cxf query "<query>" --workspace <path> --budget <tokens> [--json]
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
--workspace | path | process.cwd() | 工作区路径 |
--budget | number | 2000 | 近似token预算 |
--json | flag | false | 输出JSON格式而非Markdown |
查询命令内部调用 createContextPack 函数,生成包含以下信息的证据包:
- 查询意图分类(intent)
- 置信度评分(confidence)
- 相关代码引用(citations)
- 依赖图路径(graphPaths)
- 内存命中(memoryHits)
资料来源:src/cli.ts, src/search.ts
搜索命令 (search)
搜索命令在不编译完整证据包的情况下搜索索引上下文,适用于快速定位信息。
cxf search "<query>" --workspace <path> --limit <count> --kind <kind>
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
--workspace | path | process.cwd() | 工作区路径 |
--limit | number | 10 | 最大命中数 |
--kind | enum | "all" | 搜索类型:all/code/docs/symbols/memory |
搜索类型参数决定搜索结果的过滤范围:
all:搜索所有类型的索引块code:仅搜索代码文件块docs:仅搜索文档块symbols:仅搜索符号定义块memory:仅搜索内存记录块
资料来源:src/cli.ts, src/search.ts
报告命令 (report)
报告命令生成工作区的上下文索引报告。
cxf report --workspace <path> --format <format>
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
--workspace | path | process.cwd() | 工作区路径 |
--format | enum | "markdown" | 输出格式:markdown/json/html |
报告生成器调用 generateReport 函数,收集工作区的索引统计信息并渲染为指定格式。
资料来源:src/cli.ts, src/report.ts
内存管理命令 (memory)
内存命令用于管理证据支持的智能体内存,允许存储和检索跨会话的项目经验。
#### 添加经验 (add)
cxf memory add --claim <text> --evidence <ref...> --workspace <path> --scope <scope> --confidence <number>
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
--claim | text | 必需 | 经验声明/教训 |
--evidence | ref[] | 必需 | 证据引用,如 file:src/auth.ts:1-20 |
--workspace | path | process.cwd() | 工作区路径 |
--scope | string | "repo" | 内存范围 |
--confidence | number | 0.7 | 置信度(0-1) |
经验引用格式:file:<relativePath>:<startLine>-<endLine>
cxf memory add \
--claim "用户认证模块位于 src/auth.ts" \
--evidence "file:src/auth.ts:1-50" \
--workspace . \
--confidence 0.9
资料来源:src/cli.ts
MCP 服务器命令 (server)
服务器命令启动 MCP stdio 服务器,供 MCP 客户端连接使用。
cxf server
服务器接收来自客户端的工具调用请求,执行相应操作并返回 JSON 格式的结果。工具参数使用 Zod 模式进行验证。
资料来源:src/cli.ts, src/mcp-server.ts
工作区配置
工作区路径解析
工作区路径的解析遵循以下优先级:
- CLI 选项
--workspace显式指定 - 环境变量
WORKSPACE(如果实现) - 当前工作目录
process.cwd()作为默认值
.option("--workspace <path>", "Workspace path.", process.cwd())
资料来源:src/cli.ts
索引结构
工作区索引数据库(kernel.db)包含以下核心表结构:
| 表名 | 用途 | 关键字段 |
|---|---|---|
files | 已索引文件元数据 | path, language, indexed_at |
chunks_fts | 全文搜索索引 | ref, path, title, text, bm25 |
symbols | 代码符号索引 | name, kind, file_path, line |
edges | 导入/依赖关系图 | from, to, edge_type, file_path, line |
lessons | 经验记忆存储 | id, claim, scope, confidence, evidence |
query_log | 查询历史记录 | query, intent, timestamp |
文件类型支持
索引器支持多种编程语言的符号提取和边关系提取:
| 语言 | 符号类型 | 边关系类型 |
|---|---|---|
| TypeScript/JavaScript | function, class, interface, type, const | ES imports, require() |
| Python | def, class | from...import, import |
| Go | func, struct, interface | import |
| Rust | fn, struct, enum, trait, impl | use, mod |
| Markdown | heading | - |
| JSON | config-key | - |
资料来源:src/extract.ts
报告生成配置
报告格式选项
报告支持三种输出格式,通过 --format 选项指定:
#### Markdown 格式
默认格式,生成人类可读的 Markdown 文档,包含以下章节:
- 工作区概览
- 文件语言分布
- 索引警告
- Token 使用统计
#### JSON 格式
机器可读的 JSON 输出,适合程序化处理:
{
"status": { "workspace": "...", "indexedAt": "...", "languageDistribution": [...] },
"summary": { "totalChunks": 123, "totalSymbols": 456, "totalEdges": 789 },
"tokenSavingsEstimate": { "indexedTokens": ..., "averagePackTokens": ... }
}
#### HTML 格式
自包含的 HTML 文档,内嵌样式,适合浏览器查看:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Contextful Report</title>
<style>
body { font: 15px/1.55 system-ui, sans-serif; margin: 0; ... }
</style>
</head>
<body><main><pre>[Markdown content]</pre></main></body>
</html>
资料来源:src/report.ts
运行时参数配置
查询预算配置
--budget 参数控制返回证据包的 token 上限,影响搜索结果的精选程度:
| 预算值 | 适用场景 | 示例 |
|---|---|---|
| 1000-2000 | 简短查询、精确查找 | cxf query "auth middleware" --budget 1500 |
| 2000-5000 | 标准查询、代码理解 | cxf query "how does cache work" --budget 3000 |
| 5000+ | 复杂查询、架构分析 | cxf query "dependency injection flow" --budget 8000 |
搜索类型过滤
--kind 参数过滤搜索结果的类型范围:
# 仅搜索代码符号
cxf search "UserService" --kind symbols
# 仅搜索文档
cxf search "installation guide" --kind docs
# 仅搜索记忆
cxf search "previous lessons" --kind memory
置信度阈值
经验记忆的置信度参数(--confidence)影响信息优先级排序:
- 0.9-1.0:高置信度,直接可用于决策
- 0.7-0.9:中高置信度,建议交叉验证
- 0.5-0.7:中等置信度,需要更多证据支持
- 0.0-0.5:低置信度,仅作参考
部署架构图
graph TD
A[开发者终端] --> B[CLI 界面]
A --> C[MCP 客户端]
B --> D[index 命令]
B --> E[query 命令]
B --> F[search 命令]
B --> G[report 命令]
B --> H[memory 命令]
C --> I[MCP Server]
I --> J[context_pack 工具]
I --> K[search_code 工具]
I --> L[trace_path 工具]
I --> M[impact_analysis 工具]
I --> N[why_changed 工具]
I --> O[recall_memory 工具]
I --> P[write_lesson 工具]
D --> Q[文件系统扫描]
Q --> R[SQLite 数据库]
E --> S[证据包生成]
S --> R
S --> T[Token 预算控制]
F --> U[全文搜索]
U --> R
G --> V[报告渲染]
V --> W[Markdown/JSON/HTML]
H --> X[记忆存储]
X --> R环境变量参考
| 变量名 | 类型 | 说明 | 默认值 |
|---|---|---|---|
WORKSPACE | string | 工作区根目录路径 | 当前工作目录 |
CONTEXTFUL_BUDGET | number | 默认 token 预算 | 2000 |
常见部署场景
场景一:本地开发环境
适用于开发者在本地机器上浏览和分析代码库:
# 首次索引
cxf index --workspace /path/to/project
# 启动守护进程监视变化
cxf daemon --workspace /path/to/project &
# 执行查询
cxf query "用户认证流程" --workspace /path/to/project --budget 3000
场景二:智能体集成
将 Contextful 作为智能体工具集成的标准模式:
- 启动 MCP 服务器
- 配置 MCP 客户端连接
- 通过
context_pack工具获取上下文
# 服务器端
cxf server
# 客户端调用示例(伪代码)
result = mcp_client.call_tool("context_pack", {
query: "where is user auth handled",
budget: 2000,
scope: "repo"
})
场景三:CI/CD 集成
在持续集成流程中生成索引报告:
# .github/workflows/context-report.yml
- name: Generate Context Report
run: |
npx @inferensys/contextful index --workspace .
npx @inferensys/contextful report --workspace . --format html > report.html
安全考虑
敏感信息处理
Contextful 在日志输出和报告生成中自动过滤敏感信息:
// 邮箱地址脱敏
if (match.includes("@") && !match.toLowerCase().includes("token")) return "<email>";
// 密钥脱敏
const key = match.split(/[:=]/)[0]?.trim();
return key && key.length < match.length ? `${key}=<redacted>` : "<secret>";
资料来源:src/util.ts
二进制文件检测
索引器自动跳过二进制文件以避免处理错误:
export function isLikelyBinary(buffer: Buffer): boolean {
const sample = buffer.subarray(0, Math.min(buffer.length, 4096));
return sample.includes(0);
}
故障排除
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 索引失败 | 工作区路径不存在或无权限 | 检查 --workspace 参数,确保路径可访问 |
| 查询无结果 | 文件未被索引 | 确认已运行 cxf index,检查文件类型是否支持 |
| 服务器连接失败 | 端口占用或权限问题 | 使用 stdio 模式,确认客户端配置正确 |
| 报告生成错误 | 数据库损坏 | 删除 .contextful 目录后重新索引 |
扩展阅读
资料来源:[README.md]()
失败模式与踩坑日记
保留 Doramagic 在发现、验证和编译中沉淀的项目专属风险,不把社区讨论只当作装饰信息。
安装可能改变本机 AI 工具行为,用户需要知道写入位置和回滚方法。
假设不成立时,用户拿不到承诺的能力。
新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
下游已经要求复核,不能在页面中弱化。
Pitfall Log / 踩坑日志
项目:Inferensys/contextful
摘要:发现 7 个潜在踩坑项,其中 0 个为 high/blocking;最高优先级:配置坑 - 可能修改宿主 AI 配置。
1. 配置坑 · 可能修改宿主 AI 配置
- 严重度:medium
- 证据强度:source_linked
- 发现:项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主,或安装命令涉及用户配置目录。
- 对用户的影响:安装可能改变本机 AI 工具行为,用户需要知道写入位置和回滚方法。
- 建议检查:列出会写入的配置文件、目录和卸载/回滚步骤。
- 防护动作:涉及宿主配置目录时必须给回滚路径,不能只给安装命令。
- 证据:capability.host_targets | github_repo:1240001007 | https://github.com/Inferensys/contextful | host_targets=claude, claude_code
2. 能力坑 · 能力判断依赖假设
- 严重度:medium
- 证据强度:source_linked
- 发现:README/documentation is current enough for a first validation pass.
- 对用户的影响:假设不成立时,用户拿不到承诺的能力。
- 建议检查:将假设转成下游验证清单。
- 防护动作:假设必须转成验证项;没有验证结果前不能写成事实。
- 证据:capability.assumptions | github_repo:1240001007 | https://github.com/Inferensys/contextful | README/documentation is current enough for a first validation pass.
3. 维护坑 · 维护活跃度未知
- 严重度:medium
- 证据强度:source_linked
- 发现:未记录 last_activity_observed。
- 对用户的影响:新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
- 建议检查:补 GitHub 最近 commit、release、issue/PR 响应信号。
- 防护动作:维护活跃度未知时,推荐强度不能标为高信任。
- 证据:evidence.maintainer_signals | github_repo:1240001007 | https://github.com/Inferensys/contextful | last_activity_observed missing
4. 安全/权限坑 · 下游验证发现风险项
- 严重度:medium
- 证据强度:source_linked
- 发现:no_demo
- 对用户的影响:下游已经要求复核,不能在页面中弱化。
- 建议检查:进入安全/权限治理复核队列。
- 防护动作:下游风险存在时必须保持 review/recommendation 降级。
- 证据:downstream_validation.risk_items | github_repo:1240001007 | https://github.com/Inferensys/contextful | no_demo; severity=medium
5. 安全/权限坑 · 存在评分风险
- 严重度:medium
- 证据强度:source_linked
- 发现:no_demo
- 对用户的影响:风险会影响是否适合普通用户安装。
- 建议检查:把风险写入边界卡,并确认是否需要人工复核。
- 防护动作:评分风险必须进入边界卡,不能只作为内部分数。
- 证据:risks.scoring_risks | github_repo:1240001007 | https://github.com/Inferensys/contextful | no_demo; severity=medium
6. 维护坑 · issue/PR 响应质量未知
- 严重度:low
- 证据强度:source_linked
- 发现:issue_or_pr_quality=unknown。
- 对用户的影响:用户无法判断遇到问题后是否有人维护。
- 建议检查:抽样最近 issue/PR,判断是否长期无人处理。
- 防护动作:issue/PR 响应未知时,必须提示维护风险。
- 证据:evidence.maintainer_signals | github_repo:1240001007 | https://github.com/Inferensys/contextful | issue_or_pr_quality=unknown
7. 维护坑 · 发布节奏不明确
- 严重度:low
- 证据强度:source_linked
- 发现:release_recency=unknown。
- 对用户的影响:安装命令和文档可能落后于代码,用户踩坑概率升高。
- 建议检查:确认最近 release/tag 和 README 安装命令是否一致。
- 防护动作:发布节奏未知或过期时,安装说明必须标注可能漂移。
- 证据:evidence.maintainer_signals | github_repo:1240001007 | https://github.com/Inferensys/contextful | release_recency=unknown
来源:Doramagic 发现、验证与编译记录