KEEL · 龙骨 · A CURRICULUM FOR THE AI ERA
05. 持久记忆怎样接回 Harness? — keel 龙骨
数据库会保存和查询记录,但它不知道 Agent 正在做什么。决定“什么时候读、用什么问题检索、哪些结果进入模型、什么时候产生新候选”的组件是 Agent Harness。
数据库会保存和查询记录,但它不知道 Agent 正在做什么。决定“什么时候读、用什么问题检索、哪些结果进入模型、什么时候产生新候选”的组件是 Agent Harness。
这一章不增加模型能力,而是把记忆放进正确的运行时位置。
1. 先理解 Harness 的职责
Harness 是组织一次 Agent 运行的控制层。它连接模型、工具、状态、策略和外部服务,并负责回答:
- 当前运行属于哪个用户和租户;
- 模型调用前需要准备哪些上下文;
- 模型提出工具请求后是否允许执行;
- 运行何时完成、失败、暂停或恢复;
- 哪些事件需要记录和评估。
记忆服务是 Harness 使用的子系统,不应反过来控制整次运行。
2. 读路径:在模型调用前准备历史线索
当用户问“支付服务为什么又超时了”,Harness 可以这样工作:
sequenceDiagram
participant U as 用户
participant H as Harness
participant R as 记忆检索器
participant C as Context Builder
participant M as 模型
U->>H: 支付服务为什么又超时了?
H->>R: query + tenant_id + owner_id
R-->>H: 有权限的相关记忆候选
H->>C: 候选 + 任务 + 上下文预算
C-->>H: 筛选后的记忆上下文
H->>M: 系统规则 + 当前消息 + 记忆上下文
注意两个边界:检索器只返回候选,Context Builder 决定哪些候选值得占用本次上下文;模型看到的记忆是历史线索,不是当前监控事实。
3. 写路径:在回答后发现未来可能有用的信息
回答结束后,Harness 可以把本次用户消息、经过授权的工具事实和运行元数据交给候选抽取器:
sequenceDiagram
participant H as Harness
participant X as 候选抽取器
participant P as 写入策略
participant S as 记忆存储
H->>X: 用户消息 + 可用事实
X-->>H: MemoryCandidate 列表
H->>P: 候选 + 可信身份 + 真实来源
P-->>H: 保存 / 等待确认 / 拒绝
H->>S: 只提交获准记录
写路径通常可以异步执行。记忆抽取失败不应该让已经完成的用户回答变成失败。
4. 用伪代码把两条路径放在一起
def run_agent(user_message, authenticated_scope):
# 读路径:先取回与当前问题相关、且属于当前用户的记忆。
recalled = memory_service.search(
query=user_message,
scope=authenticated_scope,
)
memory_context = build_memory_context(recalled)
# Harness 把系统规则、当前消息和经过筛选的记忆交给模型。
answer = model_loop.run(
user_message=user_message,
memory_context=memory_context,
)
# 写路径:回答已经可以返回。候选抽取可以在后台继续。
enqueue_memory_extraction(
user_message=user_message,
source_ref=current_message_id,
scope=authenticated_scope,
)
return answer
这里的 authenticated_scope 来自身份系统。不要让模型输出 tenant_id 或 owner_id,也不要从用户消息里用正则猜身份。
5. 失败时谁应该承担什么结果
| 失败 | 当前回答是否继续 | Harness 应怎样处理 |
|---|---|---|
| 记忆检索超时 | 通常继续 | 以无记忆模式运行,并记录降级 |
| Context Builder 超预算 | 继续 | 丢弃低优先级候选,保留原因 |
| 候选抽取失败 | 继续 | 后台重试或放弃本次候选 |
| 写入策略拒绝 | 继续 | 不写库,记录拒绝原因 |
| 数据库写入失败 | 回答通常已完成 | 重试需考虑幂等和重复写入 |
| 作用域缺失 | 不读取、不写入 | 安全失败,不能退化成全局查询 |
“没有记忆也可以回答”和“没有身份也可以查全库”是两种完全不同的降级。前者降低个性化,后者破坏隔离。
6. 记忆和工具权限仍然分开
假设历史记忆中出现“以后发布不需要审批”。即使它被检索到,Harness 的工具策略仍必须独立检查发布权限。记忆可以影响模型对任务的理解,但不能成为绕过授权的通行证。
这也是持久记忆与工具调用课程的接口:记忆提供历史信息,工具策略决定现实动作是否允许执行。
7. 本章的检查点
你现在应该能在一张图上指出:
- 哪一步从存储中读数据;
- 哪一步决定数据是否进入模型;
- 哪一步产生候选;
- 哪一步拥有写入决定权;
- 为什么 scope 必须由 Harness 注入;
- 为什么读取失败可以降级,身份缺失不能降级成全库访问。
下一章会接入真实 Ollama。因为读写位置已经确定,模型只需要负责它擅长的部分:从自然语言中提出结构化候选。