核心摘要

本文提出的四层模型是一种工程拆分,而不是厂商标准:指令层定义稳定策略,知识层提供任务证据,记忆层携带跨轮状态,编排层选择并校验其他层。只有当每层都有负责人、接口、信任模型和可测量的失败路径时,分层才真正有价值。

不要把某层理解为上下文窗口的固定百分比。Token 限制、价格、缓存行为和模型注意力会随供应商与版本变化。应在实际部署的模型和工作负载上测量最终请求。

为什么需要分层

把所有内容拼成一个 Prompt 会隐藏关键差异:

失败现象 常见原因 分层控制
重要规则消失 历史或检索噪声过长 预留并校验指令预算
引用过期事实 没有新鲜度和权威性元数据 知识路由与来源检查
用户状态丢失 无界截断 显式记忆策略与压缩测试
成本和延迟上升 每次请求携带全部信息 编排、预算和遥测

模型在推理时仍只接收一个请求。分层改善的是构建和验证流程,并不会创造新的注意力机制。

graph TD O["编排:选择、预算、校验"] --> I["指令:策略与输出契约"] O --> K["知识:检索证据与 Schema"] O --> M["记忆:会话状态与获准偏好"] I --> C["最终请求上下文"] K --> C M --> C C --> L["模型或兼容运行时"]

第一层:指令层

指令层是相对稳定的契约,包括安全边界、能力范围、输出 Schema 和项目约定。它应版本控制并保持短小。好的规则需要说明可观察行为和验证方法:

go
type InstructionSet struct {
	Version          string
	GlobalRules      []string
	DomainRules      map[string][]string
	ForbiddenActions []string
	OutputSchema     string
}

func buildInstructions(set InstructionSet, domain string) string {
	rules := append([]string{}, set.GlobalRules...)
	rules = append(rules, set.DomainRules[domain]...)

	parts := []string{"## Contract " + set.Version, "### Rules"}
	for _, rule := range rules {
		parts = append(parts, "- "+rule)
	}
	parts = append(parts, "### Do not do")
	for _, rule := range set.ForbiddenActions {
		parts = append(parts, "- "+rule)
	}
	if set.OutputSchema != "" {
		parts = append(parts, "### Output schema\n"+set.OutputSchema)
	}
	return strings.Join(parts, "\n")
}

任务请求不能静默覆盖授权、密钥处理或合规策略。两个受信规则冲突时,应返回冲突并交给人工处理。厂商规则文件只是适配器,其路径和优先级必须结合客户端版本核验。

text.length / 4 这类 Token 估算只能用于粗略诊断,不能代表计费或模型真实 Token 数。预算应使用目标供应商的 Tokenizer,并记录模型版本。

第二层:知识层

知识层是动态证据,包括文档、API Schema、数据库元数据和批准的工具说明。检索结果不会自动变成事实;应同时保存来源、版本日期、权威性、租户和访问决策。

go
type KnowledgeChunk struct {
	ID         string
	Text       string
	Source     string
	UpdatedAt  time.Time
	Authority  string
	TokenCount int
	Relevance  float64
}

func selectKnowledge(chunks []KnowledgeChunk, budget int) []KnowledgeChunk {
	eligible := slices.DeleteFunc(slices.Clone(chunks), func(chunk KnowledgeChunk) bool {
		return chunk.Authority == "unknown"
	})
	slices.SortFunc(eligible, func(a, b KnowledgeChunk) int {
		return cmp.Compare(b.Relevance, a.Relevance)
	})

	selected := make([]KnowledgeChunk, 0, len(eligible))
	used := 0
	for _, chunk := range eligible {
		if used+chunk.TokenCount > budget {
			continue
		}
		selected = append(selected, chunk)
		used += chunk.TokenCount
	}
	return selected
}

生产检索需要定义查询路由、租户过滤、ACL、新鲜度、去重、重排、引用格式和“没有证据”时的响应。相关性分数不是安全决策,也不能证明事实正确。应评测检索精度、过时来源比例、引用覆盖率和未授权数据泄露。

工具 Schema 只能表示客户端可以提出的能力;服务端必须独立校验参数并执行授权,模型不能通过生成工具调用自行获得权限。

第三层:记忆层

记忆是状态,不是无限增长的对话转录。至少分开:

  • 工作记忆:当前请求和即时工具结果;
  • 会话记忆:经过批准的摘要和未决决定;
  • 长期记忆:带同意、留存、删除和租户范围的用户或组织事实。

结构化状态可以使用确定性压缩,散文摘要可以调用模型辅助,但摘要有损且在校验前不可信:

go
type Turn struct {
	Role       string
	Content    string
	CreatedAt  time.Time
	TokenCount int
}

func compactHistory(turns []Turn, keepRecent, maxTokens int) (recent, older []Turn) {
	start := max(0, len(turns)-keepRecent)
	recent = slices.Clone(turns[start:])
	used := 0
	for _, turn := range recent {
		used += turn.TokenCount
	}
	for index := start - 1; index >= 0; index-- {
		turn := turns[index]
		if used+turn.TokenCount > maxTokens {
			break
		}
		older = append([]Turn{turn}, older...)
		used += turn.TokenCount
	}
	return recent, older
}

未经来源和策略检查,不要把用户说法或工具结果提升为长期记忆。应支持删除、纠正、过期和租户隔离,并用召回率、错误记忆率、过期记忆率和删除测试评估记忆系统。

第四层:编排层

编排层组装最终上下文并负责预算。它应是可审计的策略,而不是不透明的字符串拼接:

go
type ContextParts struct {
	Instructions string
	Knowledge    string
	Memory       string
	Task         string
}

type Budget struct {
	TotalTokens       int
	InstructionTokens int
	KnowledgeTokens   int
	MemoryTokens      int
}

func assemble(parts ContextParts, budget Budget, countTokens func(string) int) (string, error) {
	required := countTokens(parts.Instructions) + countTokens(parts.Task)
	if required > budget.TotalTokens {
		return "", errors.New("required context exceeds configured budget")
	}
	sections := []string{
		"## Instructions\n" + parts.Instructions,
		"## Evidence\n" + parts.Knowledge,
		"## Memory\n" + parts.Memory,
		"## Task\n" + parts.Task,
	}
	return strings.Join(sections, "\n\n"), nil
}

生产实现应为每层计数、为响应预留空间、只截断可选证据,并在必要策略无法装入时安全失败。记录输入/输出 Token、延迟、缓存、检索结果、工具调用、重试和人工修正。不要声称固定配额适用于所有模型。

评测与失败路径

上下文变化应像代码一样评估:

yaml
case: "answer-with-current-policy"
fixture:
  tenant: "synthetic-tenant"
  policy_revision: "2026-01"
assertions:
  - "只查询 fixture 租户"
  - "过期策略不能被引用为当前策略"
  - "缺少证据时明确表达不确定性"
  - "工具参数通过服务端授权"
record:
  model: "确切模型和版本"
  tokenizer: "确切 Tokenizer"
  context_revision: "git commit"

加入负向和对抗用例:检索文档中的 Prompt Injection、畸形工具结果、缺失记忆、冲突指令、过期凭证、超大文档和供应商超时。把质量、安全、成本、延迟和恢复能力分开测量。

安全与运维

检索和工具使用最小权限。日志脱敏密钥和个人数据,默认不要持久化完整 Prompt。需要可复现时固定 Schema 与供应商版本。每条记忆都应有租户、来源、创建时间、过期/复核策略和删除路径。

四层模型不能替代普通应用控制:授权仍在服务端执行,输出仍需校验,模型响应在应用代码和测试接受前只是提案。

延伸阅读

参考资料

总结

四层模型的价值在于分离职责,而不是成为通用规范。让指令受治理、知识有来源、记忆有同意和删除机制、编排可测量;当每层都有明确的信任与失败边界时,系统就能演进,而不会把更长的 Prompt 当作工程能力的替代品。