Spring Boot 3.4 接入 AI Agent 时的上下文状态丢失问题:Harness 工程底座的实践解法
上周排查一个线上故障,业务方反馈 AI 代码审查服务在连续处理 5 个文件后开始返回错误结果,日志里没有任何异常堆栈,只是大模型返回的上下文开始"遗忘"前面的审查结论。
排查过程走了弯路。先以为是 Token 超限,检查发现总 token 数只有模型的 1/5;又怀疑是并发竞争,加了 Redis 分布式锁,问题依然存在。直到把请求链路完整记录下来,才发现是 Agent 的多轮对话状态在 Harness 层被错误地重置了——每次循环迭代时,上一轮的审查结果没有正确追加到上下文,而是被新的 system prompt 覆盖。
这个故障暴露了一个被很多人忽视的问题:接入 AI Agent 时,我们过度关注模型本身的能力,却忽略了Harness 工程底座的设计质量。
从单点接入到体系化建设
2026 年 AI 编程工具链快速迭代,业界逐渐形成了一套被验证的三位一体架构理念:Harness 工程底座 + Loop 自治闭环 + SDD 标准化规范。
Harness Engineering 的核心主张是:大模型能力正逐渐趋同,技术壁垒从模型本身转向运行环境的可控性。曹辉在近期的技术分享中明确指出,Harness 设计的关键原则包括状态落盘而非驻留内存、边界清晰的状态机流转、可观测的循环终止条件。
这与传统的 SDK 调用方式有本质区别。传统方式下,开发者直接调用模型 API,上下文管理完全依赖应用层代码;而 Harness 工程将"护栏"内化为框架能力,提供状态持久化、循环控制、异常恢复等基础设施。
三种架构路径的对比
针对 AI Agent 的 Harness 层建设,目前业界存在三种主要路径:
| 维度 | SDK 直调模式 | Framework 封装模式 | Harness 工程模式 |
|------|-------------|-------------------|-----------------|
| 上下文管理 | 应用层自行处理 | 框架内置状态机 | 状态落盘 + 可恢复 |
| 循环控制 | 无内置支持 | 依赖外部调度 | 自治闭环 + 终止条件 |
| 异常恢复 | 需手动实现 | 部分框架支持 | 断点续跑 + 状态回滚 |
| 适用场景 | 简单问答 | 中等复杂度 Agent | 生产级多轮任务 |
| 维护成本 | 低 | 中 | 高(但长期收益大) |
| 代表方案 | 直接调 OpenAI/Claude API | LangChain 0.3.x、Spring AI 1.0 | 自研 Harness + Loop 框架 |
我团队在 2026 年 Q2 完成了从 Framework 模式向 Harness 模式的迁移,核心驱动力就是上述的"上下文遗忘"问题。
Loop 自治闭环的工程化实现
Loop Engineering 解决的核心问题是:Agent 如何自主决定下一轮动作,而不是被外部调度器驱动。
在 Spring Boot 3.4.5 项目中,我们实现了一个基于状态机的 Loop 控制器:
```java
@Component
public class AgentLoopController {
private final StatePersistenceService stateService;
private final ModelInvocationService modelService;
private final LoopTerminationChecker terminationChecker;
public AgentResult execute(AgentContext context) {
int maxIterations = context.getMaxIterations();
int iteration = 0;
while (iteration < maxIterations) {
// 1. 从持久化存储恢复状态,而非内存变量
AgentState state = stateService.restore(context.getStateId());
// 2. 调用模型获取下一步动作
AgentAction action = modelService.invoke(state);
// 3. 执行动作并更新状态
state = action.execute(state);
stateService.persist(state);
// 4. 检查是否满足终止条件
if (terminationChecker.isTerminated(state)) {
return state.toResult();
}
iteration++;
}
throw new LoopMaxIterationsExceededException(maxIterations);
}
}
```
关键设计点:状态必须落盘。内存中的状态在进程重启、OOM、网络抖动时全部丢失,而持久化状态支持断点续跑。我们使用 Redis 6.2.14 作为状态存储,TTL 设置为 24 小时,避免状态堆积。
SDD 标准化规范的作用
SDD(Specification-Driven Development)规范解决的是输入输出的确定性问题。
在 Harness 模式下,每个 Loop 迭代的输入输出都必须遵循统一规范:
```yaml
agent-sdd-spec.yaml
input_schema:
type: object
required: [state_id, task_description, available_tools]
properties:
state_id: { type: string, pattern: "^uuid-[0-9a-f-]+$" }
task_description: { type: string, minLength: 1, maxLength: 2000 }
available_tools:
type: array
items: { type: string, enum: [code_review, test_generate, refactor] }
output_schema:
type: object
required: [action_type, parameters, confidence]
properties:
action_type: { type: string, enum: [execute, observe, terminate, retry] }
parameters: { type: object }
confidence: { type: number, minimum: 0, maximum: 1 }
```
这套规范让 Harness 层可以在模型调用前做输入校验、调用后做输出解析,而不是把脏数据直接丢给模型。我们上线后,因输入格式错误导致的模型调用失败率从 12% 降到了 0.3%。
这个方案虽然官方推荐,但在我们场景下反而更糟
这里需要说一个反直觉的发现:我们最初尝试了 Spring AI 1.0.0 内置的 ChatMemory 功能,官方文档将其作为上下文管理的标准方案。但在我们的多文件代码审查场景下,ChatMemory 的滑动窗口策略导致早期审查结论被过早淘汰,反而加剧了"上下文遗忘"问题。
最终我们放弃了开箱即用的 Memory 方案,选择了自定义状态落盘 + 全量上下文拼接的策略。虽然内存占用增加了 3 倍,但审查准确率达到 94%,而 ChatMemory 方案只有 71%。
工程选型没有银弹,必须基于场景数据做决策。
未来 6-12 个月的趋势预判
根据近期行业实践和技术讨论,Harness Engineering 在 2026 年下半年将呈现三个方向:
第一,状态机标准化。目前各团队的 Harness 实现各自为战,未来会出现类似 OpenAPI 的 Agent 状态机描述规范,降低跨团队迁移成本。
第二,Loop 终止条件的可学习化。当前的终止条件多为规则硬编码,未来可能引入轻量级模型判断是否继续循环,减少无效迭代。
第三,SDD 规范与模型能力的解耦。目前 SDD 规范需要人工维护,未来 Harness 框架可能根据模型输出自动推断并更新 Schema,降低接入成本。
对于后端开发者而言,理解 Harness + Loop + SDD 的三位一体架构,已经从"加分项"变成"必选项"。AI Agent 的生产化落地,拼的不再是模型调用的技巧,而是工程底座的稳固程度。
#后端 #Java #SpringBoot #AI工程化 #Agent架构
你在实际项目中有遇到类似问题吗?欢迎在评论区分享你的经验和解决方案。