上下文管理
LLM 的上下文窗口是有限的——即使是 200K token 的模型,面对一个 40 万行的代码库也装不下。上下文管理决定了哪些信息进入模型视野,直接影响 AI 回答的质量。
原则:注入用户消息,不改系统提示词
wescode 的所有代码上下文(CKG 调用图、CSE 约束、文件内容)都注入到用户消息中,而不是系统提示词。
原因是 prompt cache:系统提示词在整个会话期间保持字节稳定,任何修改都会使 cache 失效,下一轮 API 调用就要从头处理全部 token。用户消息位于序列末尾,只影响增量部分。
System Prompt: [固定,缓存命中]
History: [之前的对话]
User Message: [用户输入] + [CKG overlay] + [CSE overlay] + [文件卡片]
四层 Overlay 管线
wescode 在 wesgine 的 ContextAssembler 基础上叠加了四层 overlay,按优先级注入:
1. CKG Overlay
当用户的问题涉及代码结构时,自动注入相关的调用图:
用户: "这个函数改了会影响什么?"
CKG Overlay 注入:
- 该函数的调用者列表(3 个)
- 每个调用者的签名和文件位置
- 关键调用路径摘要
不是把整个调用图灌进去——只注入与当前问题相关的子图,控制 token 消耗。
2. Type Overlay
语言服务器(LSP)提供的类型信息:
- 变量的推断类型
- 函数的完整签名(含泛型参数)
- 接口的实现列表
这些信息帮助模型理解代码的类型约束,避免生成类型不匹配的代码。
3. CSE Overlay
当前修改可能违反的约束列表:
CSE Overlay 注入:
⚠️ architecture: internal/ 包不可被 cmd/ 之外的代码引用
⚠️ data: schema 变更必须配套迁移文件
约束以警告的形式出现在模型视野中,让它在生成代码时主动规避违反。
4. MindMap Overlay
对话历史的结构化摘要——当对话变长时,早期消息会被压缩,MindMap 保留关键的决策点和上下文。
文件卡片
除了 overlay,wescode 还使用**文件卡片(file_card)**机制管理文件内容:
[file_card: src/service/user.go]
← 可重生资源:如果被压缩丢弃,需要时重新读取
文件卡片的关键特性:
- 按需重读:被压缩删除的文件,在模型需要时通过
read工具重新加载 - 增量更新:文件被修改后,卡片自动更新为最新内容
- 优先级排序:最近被引用的文件优先保留
Token 预算管理
上下文注入不是无限的。wescode 管理一个 token 预算:
| 项目 | 预算比例 |
|---|---|
| 系统提示词 | 固定(~2K token) |
| 对话历史 | 动态(根据窗口大小调整) |
| Overlay 注入 | 上限约 30% 可用空间 |
| 用户消息 + 附件 | 剩余空间 |
当预算紧张时,优先保留:
- 最近一轮的 overlay(最可能与当前问题相关)
- 用户明确
@引用的文件 - CKG 发现的直接调用者/被调用者
- CSE 约束(通常很短,token 消耗小)
上下文压缩
当对话历史超过窗口容量时,触发 CognitiveSettlement(认知结算):
- 模型生成 SessionState——一份对话到目前为止的结构化摘要
- 旧消息被压缩,SessionState 注入为下一轮的历史上下文
- 被压缩的工具调用证据通过
ExtractToolEvidence保留关键信息
压缩是透明的——你不会感知到对话"被截断了",因为关键信息已经被结算到摘要中。
与竞品的区别
| Cursor | Claude Code | wescode | |
|---|---|---|---|
| 代码检索 | Embedding RAG | grep + read | CKG 结构化查询 |
| 约束感知 | 静态 .cursorrules | 无 | CSE 动态约束 |
| 注入方式 | 系统提示词 | 用户消息 | 用户消息(缓存安全) |
| 压缩策略 | 截断 | 截断 | 认知结算(保留关键信息) |
下一步
- 代码知识图谱(CKG) — CKG Overlay 的数据来源
- 约束满足引擎 — CSE Overlay 的约束来源
- Chat 与 Agent 模式 — 对话中的上下文体验