为 AI Agent 时代构建的 Java 驾驭工程框架
核心公式:Agent = Model + Harness
模型提供原始智能,Harness 让这个智能能够真正投入生产。
- 背景与动机
- 核心概念
- 技术选型
- 整体架构
- 六层 Harness 设计
- 三大工程支柱
- 核心组件详解
- 项目结构
- AgentScope-Java 集成
- Langfuse 监控对接
- 快速开始
- 配置说明
- 扩展指南
- 最佳实践
- 路线图
2026 年初,AI 工程领域迎来范式转变。HashiCorp 联合创始人 Mitchell Hashimoto 正式提出 Harness Engineering(驾驭工程),随后 OpenAI 与 Anthropic 几乎同步发布了各自的 Harness 实践文章。
核心公式来自 LangChain 工程师 Vivek Trivedy:
Agent = Model + Harness
更进一步的推导:
Harness = (功能侧架构 + 治理侧架构) - 模型层
这意味着:除了模型本身,所有让 AI 在企业级场景中稳定运行的工程设施,都属于 Harness 的范畴。
| 阶段 | 关注点 | 核心问题 |
|---|---|---|
| Prompt Engineering | 说什么 | 如何让模型输出更准确 |
| Context Engineering | 给什么上下文 | 如何管理模型的信息输入 |
| Harness Engineering | 在什么条件下运行 | 如何让模型可靠地长期工作 |
迷失问题(Doom Loop):Agent 在复杂任务中失去方向,反复犯同样的错误,耗费大量 token 却无进展。
熵增问题(Entropy):随着 AI 持续生成代码,架构腐化、文档过时、命名混乱,系统质量持续下滑。
信任问题(Trust):AI 生成代码的质量、安全性、合规性无法被系统化保证,只能靠人工逐行审查。
Anthropic 在 Claude Managed Agents 中总结了三个关键设计模式,本框架也遵循这些原则:
模式一:使用模型已知的工具 提供 Claude 已经精通的通用工具(如 bash、文件读写),让模型自己组合出解决方案,而非为每个任务设计专用工具。Claude 会随着模型迭代不断提升这些工具的使用能力。
模式二:让模型自主决策编排 通过代码执行工具,让 Agent 自己决定哪些工具结果需要处理、哪些可以过滤、哪些可以管道传输。编排决策从 Harness 转移到模型本身,只有最终输出进入上下文窗口,大幅降低 token 消耗。
模式三:谨慎设置边界 需要安全边界的操作才提升为专用工具——可逆性是好标准,难以逆转的操作(外部 API 调用、文件写入)通过专用工具加拦截钩子控制。边界设置应持续重新评估。
| 旧架构("宠物") | 新架构("牲畜") |
|---|---|
| 大脑/双手/记忆全部打包在黑盒里 | 无状态化设计,组件解耦 |
| 故障黑箱化,难以调试 | 反脆弱,单点故障不影响整体 |
| 难以规模化 | 从 1 个 Agent 到 1000 个,只是数字变化 |
Java 的"Ambient Affordances"(环境自生能力)天然适合构建生产级 Harness:
- 强类型系统:编译期约束,架构违规即时暴露
- ArchUnit:Java 架构约束测试的事实标准
- Spring 生态:依赖注入、AOP、事件驱动,天然支持横切关注点
- Project Reactor:响应式编程,非阻塞执行,天然匹配 Agent 的异步特性
- OpenTelemetry Java:成熟的自动插桩方案
一个完整的 Harness 必须包含以下六大工程化组件:
| 组件 | 职责 | 类比 |
|---|---|---|
| Tool Integration | MCP 网关、Skills 编排、工具统一抽象 | 给模型"双手" |
| Memory & State | 短期上下文、长期记忆、断点续传 | 给模型"记忆" |
| Context Engineering | 动态 Prompt 策展、技能渐进披露 | 给模型"领域经验" |
| Planning & Decompose | 任务拆解、ReAct 循环、自我验证 | 给模型"规划能力" |
| AI Safety | 沙箱隔离、验证钩子、自我纠正循环 | 给模型"安全边界" |
| Extensions | 微内核 + 插件化,MCP/Skills/记忆扩展 | 给模型"可扩展能力" |
while (!taskComplete) {
context = gather(); // 收集上下文(渐进式披露)
action = decide(); // ReAct 推理决策
result = execute(); // 工具执行(沙箱化)
verified = verify(); // 多维度验证
update(result, verified); // 更新状态 + 记忆
}
随着模型能力增强,传统 AI 框架正在发生重构:
- 80% 的能力迁移到模型层:定义 Agent、消息路由、生命周期管理,大模型已原生支持
- 20% 的能力沉淀为 Harness:持久化、确定性重放、成本控制、可观测性、错误恢复
结论:未来 AI 应用开发,可能不再需要重型编排框架,但一定需要 Harness 层来治理运行时。
| 层级 | 技术选型 | 版本 | 选型理由 |
|---|---|---|---|
| Agent 核心 | agentscope-java | 1.0.11+ | 生产级 Java Agent 框架,原生 ReAct、工具调用、响应式架构 |
| 可观测性 | Langfuse via OTLP | v3.22+ | 专为 LLM 设计的可观测平台,支持 Trace/Generation/Evaluation |
| 链路追踪 | OpenTelemetry Java | 1.x | agentscope-java 已内置,直接对接 Langfuse OTLP 端点 |
| 响应式 | Project Reactor | 3.x | agentscope-java 底层,非阻塞执行 |
| 架构约束 | ArchUnit | 1.x | Java 架构测试事实标准 |
| 应用框架 | Spring Boot 3.x | 3.x | 可选,agentscope 提供 Spring Boot Starter |
| 工具协议 | MCP (Model Context Protocol) | - | agentscope-java 原生支持 |
agentscope-java 提供了 Harness 所需的全部 Agent 核心能力,无需重复造轮子:
- ReAct 推理引擎:动态决策工具调用,比 rigid workflow 更灵活
- 运行时介入机制:安全中断、优雅取消、人机协同(Hook 系统)
- PlanNotebook:结构化任务管理,将复杂目标分解为可追踪步骤
- 结构化输出:自纠错解析器,LLM 输出直接映射到 Java POJO
- 长期记忆:跨会话持久化,支持语义搜索,多租户隔离
- 原生 OTel 支持:内置 OpenTelemetry 链路追踪,直接对接 Langfuse
- 响应式架构:基于 Project Reactor,GraalVM 原生编译支持 200ms 冷启动
- 专为 LLM 设计:Trace → Span → Generation 三层模型,完美匹配 Agent 执行结构
- OTLP 原生支持:agentscope-java 的 OTel traces 可直接打到 Langfuse OTLP 端点,零额外代码
- Evaluation 体系:内置 LLM-as-Judge、人工标注、自动化评估流水线
- Prompt Management:版本化 Prompt 管理,生产环境动态更新
- 开源可自托管:数据不出境,满足企业合规要求
┌──────────────────────────────────────────────────────────────────┐
│ Java Harness Framework │
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ HarnessOrchestrator │ │
│ │ (任务规划 · Sprint 管理 · 并行控制) │ │
│ └────────────────────────────┬──────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────┼────────────────────────────┐ │
│ │ agentscope-java (Agent 核心) │ │
│ │ │ │ │
│ │ ReActAgent ─── Toolkit ─── Memory ─── PlanNotebook │ │
│ │ │ │ │ │ │
│ │ Hook System MCP Bridge LongTermMemory │ │
│ └─────────────────────────────┬────────────────────────────┘ │
│ │ OTel Traces │
│ Harness 治理层 │ │
│ ┌──────────────┐ ┌───────────▼──────┐ ┌───────────────────┐ │
│ │ContextEngine │ │ VerifyPipeline │ │ EntropyAgent │ │
│ └──────────────┘ └──────────────────┘ └───────────────────┘ │
│ ┌──────────────┐ ┌──────────────────┐ ┌───────────────────┐ │
│ │ConstraintGuard │ SafetyBoundary │ │ StateStore │ │
│ └──────────────┘ └──────────────────┘ └───────────────────┘ │
│ │ OTLP/HTTP │
│ ┌──────────────────────────────▼───────────────────────────┐ │
│ │ Langfuse (可观测层) │ │
│ │ Traces · Generations · Evaluations · Prompt Management │ │
│ └───────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────┐
│ L6 安全边界层 (Safety Boundary) │
│ 红线规则 · 权限白名单 · 熔断降级 · 一键回滚 │
├──────────────────────────────────────────────────────┤
│ L5 验证反馈层 (Verification & Feedback) │
│ ArchUnit · 单元测试 · E2E 验证 · LLM 评分 │
├──────────────────────────────────────────────────────┤
│ L4 状态记忆层 (State & Memory) │
│ Session 管理 · LongTermMemory · 断点续传 │
├──────────────────────────────────────────────────────┤
│ L3 执行流程层 (Execution & Workflow) │
│ PlanNotebook · Sprint 调度 · 并行 Agent 控制 │
├──────────────────────────────────────────────────────┤
│ L2 工具能力层 (Tools & Skills) │
│ Toolkit · MCP Bridge · Skills · 沙箱执行 │
├──────────────────────────────────────────────────────┤
│ L1 上下文信息层 (Context & Knowledge) │
│ AGENTS.md · 架构文档 · Skills YAML · 动态上下文 │
└──────────────────────────────────────────────────────┘
↕ agentscope-java ReActAgent
| 层级 | 类比 | 核心职责 | 主要实现 |
|---|---|---|---|
| L1 上下文信息层 | 岗位说明书 | 知识供给、渐进式披露 | ContextEngine + AGENTS.md |
| L2 工具能力层 | 工具箱 | 原子化工具、MCP 集成 | agentscope Toolkit + MCP |
| L3 执行流程层 | 标准流程 | 任务拆解、Sprint 执行 | PlanNotebook + Orchestrator |
| L4 状态记忆层 | 项目笔记本 | 跨窗口记忆、会话持久化 | agentscope Session + LongTermMemory |
| L5 验证反馈层 | 质检流程 | 约束验证、自动测试 | VerifyPipeline + ArchUnit |
| L6 安全边界层 | 红线规则 | 权限控制、应急兜底 | SafetyBoundary + Hook |
地图模式 vs 说明书模式
❌ 说明书模式:一个 1000 行 AGENTS.md,塞入所有规则 → 挤占上下文,成为"陈旧规则的坟场"
✅ 地图模式:100 行 AGENTS.md 作为目录 + docs/ 深层文档按需加载(渐进式披露)
agentscope-java 的 Skills 机制天然支持渐进式披露:每个 Skill 的 YAML 前言预加载到上下文(简短描述),需要时通过文件读取工具展开完整内容。
// ContextEngine:按 token 预算动态装配上下文
@Service
public class ContextEngine {
// Skills 渐进式披露:只预加载摘要,按需展开详情
public String buildSystemPrompt(Task task) {
StringBuilder sb = new StringBuilder();
sb.append(loadAgentsMd()); // 核心地图,~100 tokens
sb.append(loadSkillSummaries(task.getCategory())); // Skills 摘要,供 Agent 判断是否需要展开
return sb.toString();
}
}原则:将「代码品味」硬编码为机械规则,错误消息必须包含修复指令
// ArchUnit 强制分层依赖
@AnalyzeClasses(packages = "com.example")
public class ArchitectureConstraintTest {
@ArchTest
static final ArchRule LAYER_DEPENDENCY =
layeredArchitecture()
.layer("Types").definedBy("..types..")
.layer("Config").definedBy("..config..")
.layer("Repository").definedBy("..repository..")
.layer("Service").definedBy("..service..")
.layer("Runtime").definedBy("..runtime..")
.layer("Controller").definedBy("..controller..")
.whereLayer("Service").mayNotAccessLayers("Controller")
.whereLayer("Repository").mayNotAccessLayers("Service", "Controller");
// 违规时报错:
// [ARCH-001] Service 层不能直接依赖 Controller 层
// ❌ 问题:UserService 引用了 UserController
// ✅ 修复:将共享逻辑提取到 Types 层或独立的 DTO 类
// 📖 文档:docs/architecture/boundaries.md#layer-rules
}原则:定期运行「垃圾回收」Agent,对抗架构腐化,生成重构 PR 而非直接修改
@Scheduled(cron = "0 0 2 * * MON")
@Component
public class EntropyAgent {
@Autowired
private ReActAgent refactorAgent; // agentscope-java ReActAgent
public void collect() {
EntropyReport report = scanner.scan();
// 用 Agent 生成重构建议,生成 PR 而非直接修改
// 保持人类对架构决策的最终控制权
if (report.getDriftScore() > threshold) {
refactorAgent.call(buildRefactorPrompt(report))
.flatMap(result -> gitService.createPR(result))
.subscribe();
}
}
}基于 agentscope-java 的 PlanNotebook,实现 Anthropic 2026 年实践中的三智能体架构:
@Service
public class HarnessOrchestrator {
@Autowired private ReActAgent plannerAgent; // 规划者
@Autowired private ReActAgent generatorAgent; // 执行者
@Autowired private ReActAgent evaluatorAgent; // 评估者
public Mono<ExecutionReport> execute(String taskDescription) {
return plannerAgent
.call(buildPlannerPrompt(taskDescription))
.flatMap(plan -> {
List<Feature> features = parseFeatures(plan);
// 所有功能初始标记 FAILING(TDD 思想)
features.forEach(f -> f.setStatus(FeatureStatus.FAILING));
stateStore.save(features);
return Flux.fromIterable(features)
.concatMap(this::executeFeatureSprint)
.collectList()
.map(ExecutionReport::new);
});
}
private Mono<SprintResult> executeFeatureSprint(Feature feature) {
return Mono.defer(() -> {
if (loopDetector.isLoop(feature)) {
return Mono.just(SprintResult.escalate(feature));
}
Context ctx = contextEngine.buildContext(feature.toTask());
return generatorAgent.call(ctx.toMsg())
.flatMap(action -> verifyPipeline.verify(action)
.flatMap(verify -> {
if (verify.isPassing()) {
feature.setStatus(FeatureStatus.PASSING);
// 每个 Sprint 后立即 commit,保留可接班产物
return gitService.commit("feat: " + feature.getName())
.thenReturn(SprintResult.success(feature));
}
feature.addFeedback(verify.getReport());
return executeFeatureSprint(feature); // 带反馈重试
}));
});
}
}@Component
public class VerifyPipeline {
public Mono<VerifyResult> verify(Msg agentOutput) {
return Mono.zip(
Mono.fromCallable(() -> compiler.check(agentOutput)), // 编译检查
Mono.fromCallable(() -> constraintGuard.validate(agentOutput)), // ArchUnit
testRunner.runTests(agentOutput.getTargetModule()), // 单元测试
evaluatorAgent.call(buildEvalPrompt(agentOutput)) // LLM 评分
).map(tuple -> VerifyResult.aggregate(
tuple.getT1(), tuple.getT2(), tuple.getT3(), tuple.getT4()
));
}
}@Component
public class LoopDetector {
public boolean isLoop(Feature feature) {
List<String> recentErrors = feature.getRecentErrors(5);
if (recentErrors.size() < 5) return false;
long uniqueTypes = recentErrors.stream().distinct().count();
if (uniqueTypes <= 1) {
// 5 次内错误类型少于 2 种,判定为 Doom Loop,触发人工介入
notificationService.escalate(
"Doom Loop 检测:[" + feature.getName() + "] 需要人工介入"
);
return true;
}
return false;
}
}java-harness-framework/
├── harness-core/ # Harness 核心调度层
│ └── src/main/java/com/harness/
│ ├── orchestrator/
│ │ ├── HarnessOrchestrator.java # Planner-Generator-Evaluator 调度
│ │ ├── SprintManager.java
│ │ └── LoopDetector.java
│ ├── context/
│ │ ├── ContextEngine.java # 上下文装配(地图模式)
│ │ └── DocumentLoader.java
│ └── model/
│ ├── Feature.java
│ ├── SprintResult.java
│ └── ExecutionReport.java
│
├── harness-agent/ # Agent 核心层(agentscope-java 集成)
│ ├── pom.xml # 依赖 io.agentscope:agentscope:1.0.11
│ └── src/main/java/com/harness/agent/
│ ├── config/
│ │ └── AgentScopeConfig.java # Planner/Generator/Evaluator Bean 配置
│ ├── tools/
│ │ ├── HarnessToolkit.java # 工具集注册(含 MCP Bridge)
│ │ ├── FileReadTool.java
│ │ ├── FileWriteTool.java
│ │ └── ShellExecuteTool.java # 沙箱化 Shell
│ ├── hooks/
│ │ ├── SafetyHook.java # 安全边界钩子(L6)
│ │ ├── ConstraintHook.java # 架构约束钩子(L5)
│ │ └── AuditHook.java # 审计日志
│ └── memory/
│ └── HarnessMemoryConfig.java
│
├── harness-observability/ # 可观测性层(Langfuse via OTLP)
│ ├── pom.xml
│ └── src/main/java/com/harness/observability/
│ ├── config/
│ │ └── LangfuseOtelConfig.java # OTLP → Langfuse 端点配置
│ ├── instrument/
│ │ ├── HarnessSpanDecorator.java # gen_ai.* 语义属性注入
│ │ └── GenAiAttributes.java # OTel 属性常量定义
│ └── evaluation/
│ └── LangfuseEvalClient.java # 评分回写 Langfuse API
│
├── harness-constraints/ # 架构约束层(ArchUnit)
│ ├── src/test/java/com/harness/
│ │ └── ArchitectureConstraintTest.java
│ └── config/checkstyle.xml
│
├── harness-verify/ # 验证反馈层
│ └── src/main/java/com/harness/verify/
│ ├── VerifyPipeline.java
│ └── TestRunner.java
│
├── harness-entropy/ # 熵管理层
│ └── src/main/java/com/harness/entropy/
│ ├── EntropyAgent.java
│ ├── EntropyScanner.java
│ └── RefactorPRGenerator.java
│
├── harness-spring-boot-starter/ # Spring Boot 自动配置
│ └── src/main/java/com/harness/autoconfigure/
│ ├── HarnessAutoConfiguration.java
│ └── HarnessProperties.java
│
├── harness-examples/
│ ├── coding-agent-demo/
│ ├── multi-agent-pipeline/
│ └── enterprise-integration/
│
├── docs/
│ ├── architecture/
│ │ ├── overview.md
│ │ ├── boundaries.md # 模块边界 + 约束错误消息模板
│ │ └── adr/
│ ├── conventions/
│ │ ├── coding-style.md
│ │ └── testing.md
│ └── plans/current-sprint.md
│
├── AGENTS.md # Agent 导航地图(≤100 行)
└── pom.xml
<!-- harness-agent/pom.xml -->
<dependencies>
<!-- AgentScope Java 全量包(含 MCP SDK、OTel 依赖) -->
<dependency>
<groupId>io.agentscope</groupId>
<artifactId>agentscope</artifactId>
<version>1.0.11</version>
</dependency>
<!-- Spring Boot Starter(可选) -->
<dependency>
<groupId>io.agentscope</groupId>
<artifactId>agentscope-spring-boot-starter</artifactId>
<version>1.0.11</version>
</dependency>
<!-- OTel OTLP Exporter(agentscope 依赖中已包含 OTel API,这里补充 Exporter) -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>
<!-- Reactor 异步链路上下文传播 -->
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-reactor-3.1</artifactId>
<version>${otel.instrumentation.version}</version>
</dependency>
</dependencies>@Configuration
public class AgentScopeConfig {
@Bean
public ReActAgent plannerAgent(ChatModel model) {
return ReActAgent.builder()
.name("Planner")
.sysPrompt("""
你是一个任务规划专家。将用户需求扩展为详细的功能列表。
每个功能必须包含:名称、描述、验收标准。
在范围上要大胆,确保功能完整覆盖需求。
""")
.model(model)
.toolkit(minimalReadToolkit()) // Planner 只需读取文档
.build();
}
@Bean
public ReActAgent generatorAgent(ChatModel model, Toolkit harnessToolkit) {
return ReActAgent.builder()
.name("Generator")
.sysPrompt(loadFromFile("docs/conventions/coding-style.md"))
.model(model)
.toolkit(harnessToolkit) // 完整工具集:文件读写、Shell、MCP
.memory(new InMemoryMemory())
.build();
}
@Bean
public ReActAgent evaluatorAgent(ChatModel model) {
return ReActAgent.builder()
.name("Evaluator")
.sysPrompt("""
你是代码质量评估专家。按以下维度评分(0-10):
- 功能完整性:是否满足验收标准
- 代码质量:可读性、命名、结构
- 测试覆盖:是否有对应测试
- 架构合规:是否符合分层规则
返回 JSON 格式评分,并给出具体改进建议。
""")
.model(model)
.toolkit(readOnlyToolkit()) // Evaluator 只需读代码
.build();
}
@Bean
public Toolkit harnessToolkit(SandboxService sandboxService) {
Toolkit toolkit = new Toolkit();
toolkit.registerTool(new FileReadTool());
toolkit.registerTool(new FileWriteTool(sandboxService));
toolkit.registerTool(new ShellExecuteTool(sandboxService));
// MCP 工具注册(按需启用)
// toolkit.registerMcp("github", "https://mcp.github.com/sse");
return toolkit;
}
}agentscope-java 的 Hook 系统是实现 L5/L6 层的关键,在任意推理步骤注入控制逻辑:
// L6 安全边界钩子
@Component
public class SafetyHook implements AgentHook {
private static final List<String> FORBIDDEN_PATHS = List.of(
"/etc", "/sys", "~/.ssh", ".env", ".git/config"
);
@Override
public HookPoint getHookPoint() {
return HookPoint.BEFORE_TOOL_EXECUTION;
}
@Override
public Mono<HookResult> execute(HookContext context) {
if (containsForbiddenPath(context.getAction())) {
auditLogger.warn("安全拦截 - {}", context.getAction());
return Mono.just(HookResult.block("禁止访问受保护系统路径"));
}
return Mono.just(HookResult.proceed());
}
}
// L5 架构约束钩子(文件写入后立即校验)
@Component
public class ConstraintHook implements AgentHook {
@Override
public HookPoint getHookPoint() {
return HookPoint.AFTER_FILE_WRITE;
}
@Override
public Mono<HookResult> execute(HookContext context) {
return constraintGuard.validate(context.getWrittenFile())
.map(result -> result.hasViolations()
// 教学式反馈:包含修复指令,Agent 被纠错的同时被教会
? HookResult.feedback(result.toTeachingMessage())
: HookResult.proceed());
}
}@Service
public class HarnessSessionManager {
// agentscope-java Session:任务中断后可完整恢复上下文和工具状态
public ReActAgent restoreOrCreate(String sessionId, ReActAgent agentTemplate) {
Path sessionPath = Path.of(sessionStorePath, sessionId);
Session session = new JsonSession(sessionPath);
boolean loaded = agentTemplate.loadIfExists(session, sessionId);
log.info(loaded ? "恢复会话:{}" : "新建会话:{}", sessionId);
return agentTemplate;
}
// Sprint 结束后立即保存检查点
public void checkpoint(ReActAgent agent, String sessionId) {
Session session = new JsonSession(Path.of(sessionStorePath, sessionId));
agent.saveTo(session, sessionId);
}
}agentscope-java 已内置 OpenTelemetry,只需将 OTLP Exporter 的端点指向 Langfuse,即可实现零侵入的全链路追踪:
agentscope-java 内部执行
→ OTel SDK(agentscope 内置)
→ BatchSpanProcessor
→ OtlpHttpSpanExporter
→ Langfuse /api/public/otel/v1/traces (OTLP/HTTP,支持 JSON 和 Protobuf)
→ Langfuse UI(Traces / Generations / Evaluations)
注意:Langfuse 目前支持 OTLP over HTTP,不支持 gRPC,需确认 Exporter 使用 HTTP 协议。
@Configuration
public class LangfuseOtelConfig {
@Value("${langfuse.base-url}")
private String langfuseBaseUrl;
@Value("${langfuse.public-key}")
private String publicKey;
@Value("${langfuse.secret-key}")
private String secretKey;
@Bean
@Primary
public OpenTelemetry openTelemetry() {
// Langfuse Basic Auth:Base64(publicKey:secretKey)
String credentials = Base64.getEncoder().encodeToString(
(publicKey + ":" + secretKey).getBytes(StandardCharsets.UTF_8)
);
OtlpHttpSpanExporter exporter = OtlpHttpSpanExporter.builder()
.setEndpoint(langfuseBaseUrl + "/api/public/otel/v1/traces")
.addHeader("Authorization", "Basic " + credentials)
.addHeader("x-langfuse-ingestion-version", "4")
.build();
SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
.addSpanProcessor(BatchSpanProcessor.builder(exporter)
.setScheduleDelay(Duration.ofSeconds(5))
.build())
.setResource(Resource.getDefault().merge(
Resource.create(Attributes.of(
ResourceAttributes.SERVICE_NAME, "java-harness-framework",
ResourceAttributes.SERVICE_VERSION, "1.0.0"
))
))
.build();
return OpenTelemetrySdk.builder()
.setTracerProvider(tracerProvider)
// W3C Trace Context 传播,确保 Reactor 异步链路不断链
.setPropagators(ContextPropagators.create(
W3CTraceContextPropagator.getInstance()
))
.buildAndRegisterGlobal();
}
}为让 Langfuse 正确解析 LLM 调用(显示 token 用量、成本、评分等),按 gen_ai.* 规范注入属性:
@Component
public class HarnessSpanDecorator {
// gen_ai.* 标准语义(Langfuse 用于识别 LLM Generations)
public static final AttributeKey<String> GEN_AI_SYSTEM =
stringKey("gen_ai.system");
public static final AttributeKey<String> GEN_AI_MODEL =
stringKey("gen_ai.request.model");
public static final AttributeKey<Long> GEN_AI_PROMPT_TOKENS =
longKey("gen_ai.usage.prompt_tokens");
public static final AttributeKey<Long> GEN_AI_COMPLETION_TOKENS =
longKey("gen_ai.usage.completion_tokens");
// Langfuse 业务追踪属性
public static final AttributeKey<String> LANGFUSE_SESSION_ID =
stringKey("langfuse.trace.session_id");
public static final AttributeKey<String> LANGFUSE_USER_ID =
stringKey("langfuse.trace.user_id");
public static final AttributeKey<String> LANGFUSE_GEN_NAME =
stringKey("langfuse.generation.name");
// Harness 自定义属性
public static final AttributeKey<String> HARNESS_SPRINT_ID =
stringKey("harness.sprint.id");
public static final AttributeKey<String> HARNESS_FEATURE_STATUS =
stringKey("harness.feature.status");
public Span startSprintSpan(Feature feature, String sessionId) {
Tracer tracer = GlobalOpenTelemetry.getTracer("java-harness-framework");
return tracer.spanBuilder("harness.sprint." + feature.getName())
.setAttribute(LANGFUSE_SESSION_ID, sessionId)
.setAttribute(LANGFUSE_GEN_NAME, feature.getName())
.setAttribute(HARNESS_SPRINT_ID, feature.getId())
.setAttribute(HARNESS_FEATURE_STATUS, "RUNNING")
.startSpan();
}
}| 数据维度 | 来源 | 说明 |
|---|---|---|
| Traces | agentscope OTel Spans | 完整的 Agent 执行链路(Sprint → Tool Call → LLM Call) |
| Generations | gen_ai.* 属性自动解析 | 每次 LLM 调用的 input/output/token 用量/成本估算 |
| Sessions | langfuse.trace.session_id | 按会话聚合的多轮 Agent 交互 |
| Scores | Evaluator Agent 评分回写 | 功能完整性/代码质量/架构合规评分 |
| Latency | Span duration | 每个工具调用、LLM 调用的耗时分布 |
@Component
public class LangfuseEvalClient {
// Evaluator Agent 完成评分后,通过 Langfuse API 将评分关联到对应 Trace
public void submitScore(String traceId, String featureName,
double score, String comment) {
// 使用 Langfuse Java SDK(通过 OTLP 写入或 REST API)
// 推荐:读取当前 Span 的 traceId,与 Langfuse Trace 对应
client.scores().create(CreateScoreRequest.builder()
.traceId(traceId)
.name("harness_feature_quality")
.value(score)
.comment(comment)
.build());
}
}- Java 17+(agentscope-java 要求;推荐 Java 21)
- Maven 3.9+ 或 Gradle 8+
- Langfuse Cloud 或自托管(版本 ≥ v3.22.0)
- LLM API Key(支持 Anthropic / OpenAI / DashScope 等)
Step 1:配置 pom.xml
<dependency>
<groupId>io.agentscope</groupId>
<artifactId>agentscope</artifactId>
<version>1.0.11</version>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>Step 2:配置环境变量
export ANTHROPIC_API_KEY=sk-ant-...
# 从 Langfuse 项目设置页面获取
export LANGFUSE_PUBLIC_KEY=pk-lf-...
export LANGFUSE_SECRET_KEY=sk-lf-...
export LANGFUSE_BASE_URL=https://cloud.langfuse.com # 或自托管地址Step 3:运行
@SpringBootApplication
public class HarnessApp {
@Bean
CommandLineRunner run(HarnessOrchestrator orchestrator) {
return args -> {
orchestrator.execute("实现用户注册登录模块,包含 JWT 认证和邮箱验证")
.subscribe(report -> {
System.out.println("通过率:" + report.getPassRate() + "%");
System.out.println("Langfuse 追踪:" + report.getTraceUrl());
});
};
}
}# AGENTS.md — Agent 快速导航地图
## 项目简介
面向企业的任务管理平台,基于 Spring Boot 3 + PostgreSQL。
## 快速导航
| 你想做什么 | 去哪里看 |
|-----------|---------|
| 了解系统架构 | docs/architecture/overview.md |
| 了解模块边界规则 | docs/architecture/boundaries.md |
| 了解编码规范 | docs/conventions/coding-style.md |
| 了解测试规范 | docs/conventions/testing.md |
| 了解当前任务 | docs/plans/current-sprint.md |
## 硬性规则(CI 自动验证,违反即报错含修复指令)
1. 依赖方向:Types → Config → Repository → Service → Runtime → Controller
2. 横切关注点(日志/认证/追踪)只能通过 Provider/Hook 注入
3. 单文件不超过 300 行
4. 新增代码必须有对应测试,覆盖率 ≥ 80%
5. 禁止 System.out.println,统一使用 SLF4J
6. 禁止在 Service 层直接使用 JDBC,统一走 Repository
## 构建与测试
- 全量测试(含架构约束): mvn test
- 构建: mvn package -DskipTestsharness:
llm:
provider: anthropic
model: claude-sonnet-4-6
api-key: ${ANTHROPIC_API_KEY}
context:
token-budget: 8000
agents-md-path: AGENTS.md
docs-path: docs/
orchestrator:
max-sprint-retries: 3
loop-detection-window: 5
parallel-features: false # 建议先用串行,稳定后再开并行
tools:
shell:
sandbox-enabled: true
allowed-commands: ["git", "mvn", "ls", "cat", "find", "grep"]
mcp:
servers: [] # 按需添加 MCP Server
safety:
forbidden-paths: ["/etc", "/sys", "~/.ssh", ".env"]
max-consecutive-failures: 3
entropy:
scan-enabled: true
cron: "0 0 2 * * MON"
auto-pr: true
langfuse:
base-url: ${LANGFUSE_BASE_URL:https://cloud.langfuse.com}
public-key: ${LANGFUSE_PUBLIC_KEY}
secret-key: ${LANGFUSE_SECRET_KEY}
enabled: true@Component
public class CodeReviewTool implements AgentTool {
@Override
public String getName() { return "code_review"; }
@Override
public String getDescription() {
return "对指定文件或目录进行代码审查,返回问题列表和改进建议";
}
@Override
public ToolSchema getSchema() {
return ToolSchema.builder()
.param("path", "string", "要审查的文件路径", true)
.param("focus", "enum", "审查重点", false, "security", "performance", "style")
.build();
}
@Override
public Mono<String> execute(Map<String, Object> params) {
return Mono.fromCallable(() -> performReview((String) params.get("path")));
}
}// 代码生成 → 测试生成 → 代码审查 三阶段 Pipeline
SequentialPipeline codingPipeline = SequentialPipeline.builder()
.addAgent(generatorAgent)
.addAgent(testWriterAgent)
.addAgent(reviewerAgent)
.build();
// 带结构化输出(最后一个 Agent 返回 POJO)
Msg result = codingPipeline.execute(featureMsg, CodeDeliverable.class).block();
CodeDeliverable deliverable = result.getStructuredData(CodeDeliverable.class);Phase 1(1-2 天):信息层
└── 创建 AGENTS.md(地图模式,≤100 行)
└── 建立 docs/ 结构化目录
└── 对接 Langfuse(仅配置环境变量,零代码侵入)
Phase 2(3-5 天):约束层
└── 配置 ArchUnit 分层依赖规则
└── 错误消息包含 ❌问题 + ✅修复 + 📖文档
└── CI 流水线集成约束检查
Phase 3(1-2 周):自动化闭环
└── 接入 agentscope-java(ReActAgent + Hook)
└── 实现 VerifyPipeline(编译 + ArchUnit + 测试)
└── 启用 EntropyAgent 定时扫描
// ❌ 无效报错(Agent 不知道怎么改)
throw new ConstraintViolationException("架构违规");
// ✅ 教学式报错(被纠错的同时被教会正确做法)
return HookResult.feedback("""
[ARCH-001] 架构依赖违规
❌ 问题:UserService 直接调用了 UserController(反向依赖)
✅ 修复:将共享逻辑提取到 UserDto(Types 层)
📖 规则:docs/architecture/boundaries.md#layer-rules
💡 参考:OrderService 是正确的实现示例
""");验证链路中必须包含不依赖 Agent 的客观标准:
- ArchUnit 架构约束(机械规则)
- 已有的人工编写回归测试
- 编译检查(Java 强类型天然优势)
- Langfuse 中的人工标注(修正 Evaluator Agent 的评分偏差)
AGENTS.md 不是一次性文档。每当 Agent 犯一个错误,就工程化一个解决方案让它不再重犯,然后更新 AGENTS.md。这是 Harness Engineering 的核心循环。
// ❌ 严禁在非 main/test 代码中使用 .block()
agent.call(msg).block(); // 阻塞,破坏响应式链!
// ✅ 保持响应式链
agent.call(msg)
.flatMap(result -> verifyPipeline.verify(result))
.subscribe(verified -> handleResult(verified));
// ❌ 严禁 Thread.sleep(),使用 Mono.delay() 替代- 用
langfuse.trace.session_id将同一任务的所有 Agent 调用关联到同一 Session - 用
langfuse.generation.name标注 Feature 名称,便于按业务维度过滤 - 自托管 Langfuse 需确保版本 ≥ v3.22.0(OTLP 端点最低版本要求)
- 定期在 Langfuse UI 审查低分 Generation,根据规律更新 AGENTS.md 规则
- agentscope-java 核心集成(ReActAgent + Hook + Session + PlanNotebook)
- Langfuse OTLP 对接(零侵入)
- HarnessOrchestrator(Planner-Generator-Evaluator 三角架构)
- VerifyPipeline(编译 + ArchUnit + 单元测试 + LLM 评分)
- LoopDetector + 人工升级通知
- Spring Boot Starter
- MCP Server 管理(多 MCP 路由、权限控制)
- Langfuse Evaluation 自动回写(Evaluator 评分 → Langfuse Score API)
- Langfuse Prompt Management 集成(版本化 Prompt,生产环境动态更新)
- EntropyAgent(定时扫描 + 重构 PR 生成)
- 并行 Agent 调度(agentscope Pipeline 并行模式)
- Long-term Memory 向量检索(agentscope 扩展 + Qdrant)
- GraalVM 原生镜像支持(适配 Serverless 场景)
- A2A(Agent-to-Agent)协议支持
- 预制 Harness 模板(Java/Spring 黄金路径)
- 基于 Langfuse 历史 Trace 数据的智能熵预测
- 多模型动态路由(按任务类型自动选择最优模型)
- Anthropic: Claude Managed Agents
- OpenAI: Harness Engineering
- agentscope-java GitHub
- agentscope-runtime-java GitHub
- Langfuse OpenTelemetry Integration
- Langfuse Spring AI Integration
- ArchUnit
- Mitchell Hashimoto: My AI Adoption Journey
本文档由 Java Harness Framework 项目组维护。每当 Agent 犯错,工程化解决方案并更新本文档。