Harness Engineering 项目实战

Harness Engineering 实战四:Java 项目的 Harness 层写在哪?附完整Demo 上周发布了Python版的Harness实战,对于后端使用Java的读者福利来了,企业级后端同样需要硬约束。Java/Spring Boot 项目怎么配?Maven 慢、Checkstyle 严、AI 还爱乱加注解。Java 生态重、规范多,AI 生成的代码更容易踩红线。咱们通过一个最小可运行 Demo,来一起聊聊,Java版本的Harness Engineering实战到底要怎么玩起来。 阅读详情

Harness Engineering 项目实战:把 AI Coding Agent 从“会写代码”变成“可靠交付”

Coding Agent = Model + Harness。模型决定能力上限,Harness 决定这份能力能否在真实代码库里稳定落地。本文不讨论“怎样写一个更玄学的 Prompt”,而是从控制论、上下文工程和软件质量反馈出发,为一个 Spring Boot 多模块能源平台搭建可审计、可约束、可自我纠错的 Agent 工程闭环。

一、为什么模型更强了,代码仍然不敢直接合并

今天的 Coding Agent 已经能跨文件修改、运行命令、补测试,甚至连续工作数小时。但“能生成代码”和“能可靠交付”之间仍隔着四类风险:

  1. 知识缺口:模型不知道团队的模块边界、历史约定和业务语义;
  2. 非确定性:相同任务多跑一次,方案、改动范围和遗漏点可能完全不同;
  3. 执行风险:Agent 不只输出文本,还能改文件、执行命令、访问网络;
  4. 验证幻觉:它很容易把“代码看起来合理”误判为“任务已经完成”。

传统 Prompt Engineering 主要优化单次输入,Context Engineering 关心在正确时间提供正确上下文,而 **Harness Engineering(Agent 驾驭工程)**进一步把问题变成一个工程系统:

Agent = Model + Harness

Harness = 指令 + 上下文策略 + 工具 + 权限 + 状态
        + 编排 + 验证 + 反馈 + 可观测性 + 恢复机制

它的目标不是保证 Agent 永不犯错——对非确定性系统,这几乎不现实;真正目标是:

  • 提高第一次做对的概率;
  • 让错误尽量被机器发现,而不是流到人工 Review;
  • 把失败转化为规则、测试或工具,使同类错误不再重复;
  • 把人类注意力留给需求取舍、业务语义和高风险决策。

这里的 Harness Engineering 不是名为 Harness 的 CI/CD 产品,也不只是某个 Agent 框架。它是一种围绕 Agent 运行时设计控制系统的工程方法。

二、理论骨架:Guide、Sensor 与自校正回路

2.1 从“提示词”升级为闭环控制

把代码库当前状态记为 xtx_txt​,目标状态记为 x∗x^*x∗,Agent 在第 ttt 轮执行动作 utu_tut​:

xt+1=F(xt,ut)x_{t+1}=F(x_t,u_t)xt+1​=F(xt​,ut​)

如果只有 Prompt,系统相当于开环控制:给出一次指令,然后期待结果正确。Harness 则引入 Sensor 观测误差:

et=S(xt+1,x∗)e_t = S(x_{t+1}, x^*)et​=S(xt+1​,x∗)

再将结构化错误反馈给 Agent,产生修正动作:

ut+1=C(et,contextt)u_{t+1}=C(e_t, context_t)ut+1​=C(et​,contextt​)

于是工作流从“一次生成”变成:

任务规格
   │
   ▼
Guide(前馈约束)──────→ Agent 规划与修改
                              │
                              ▼
                         Tool 执行动作
                              │
                              ▼
Sensor(测试/检查/评审)←── 代码库新状态
   │                          │
   └──── 失败证据 ────────────┘
                 自我修正,直到通过或升级给人

2.2 两个维度,四类控制手段

一个成熟 Harness 可以用两条轴分类。

第一条轴是控制方向:

  • Guide(前馈):在动作前告诉 Agent 应该怎么做,例如 AGENTS.md、架构说明、Skill;
  • Sensor(反馈):动作后给出可验证信号,例如编译器、测试、静态分析、浏览器截图。

第二条轴是执行性质:

  • Computational(计算型):确定、快速、可复现,例如类型检查、ArchUnit、单元测试;
  • Inferential(推理型):依赖语义判断,例如独立 Review Agent、LLM-as-Judge。
控制类型前馈 Guide反馈 Sensor
计算型代码模板、OpenRewrite、Schema、脚手架编译、测试、Lint、ArchUnit、覆盖率
推理型AGENTS.md、Skill、业务说明、示例Review Agent、需求一致性检查、UI 评审

关键原则是:能用计算型 Sensor 解决的问题,不要只靠推理型 Sensor。

“禁止 Controller 直接依赖 Mapper”写进 Markdown,只是希望模型记住;将它写成 ArchUnit 测试,才是可执行约束。前者提高首次正确率,后者防止错误漏网,两者结合才是 Harness。

2.3 Harness 与 Context Engineering 的边界

两者高度重叠,但关注点不同:

Prompt Engineering:这句话怎样写,模型更容易理解?
Context Engineering:此时应向模型提供哪些信息?
Harness Engineering:谁提供、何时提供、允许做什么、怎样验证、失败后如何继续?

因此,“把全仓库文档塞进上下文”不是成熟的 Context Engineering,更不是成熟的 Harness。上下文越长并不等于推理越好;无关信息、重复日志和过多工具描述会稀释真正重要的约束。

三、实战目标:为 Spring Boot 多模块项目加一层 Agent Harness

假设项目是一个能源管理平台:

platform-energy-parent/
├── core/
│   ├── energy-base/          # 基础能力
│   └── energy-domain/        # 领域对象与共享契约
├── platform-energy-auth/     # 认证服务
├── platform-energy-manage/   # 管理服务
├── platform-energy-task/     # 调度任务
├── platform-energy-open/     # 开放接口
├── platform-energy-data-stream/
├── platform-energy-user-sync/
└── pom.xml

我们希望 Agent 能完成这样的任务:

给管理服务新增“设备离线原因”字段,修改领域对象、Mapper、接口与测试;不得破坏模块依赖;只运行受影响模块测试;所有写操作可审计;遇到失败自动修复,连续失败则停止并请求人工判断。

Harness 不侵入业务运行时。建议把控制面独立放在仓库中:

platform-energy-parent/
├── AGENTS.md
├── docs/
│   ├── architecture.md
│   └── domain-glossary.md
├── harness/
│   ├── __init__.py
│   ├── policy.json
│   ├── contracts.py
│   ├── tools.py
│   ├── verify.py
│   ├── agent_loop.py
│   └── tests/
│       └── test_harness.py
└── ...业务模块

这套最小实现采用 Python 3.11 编写 Harness,Agent 修改的仍然是 Java 工程。Python 只负责控制循环,不参与生产服务部署。

四、第一层:把仓库规则写成高信号 Guide

4.1 AGENTS.md 不是百科全书

根目录规则会频繁进入 Agent 上下文,应该像飞行员检查单,而不是 200 页团队手册。一个适合当前案例的版本如下:

# Repository Guide

## Build
- JDK 17;从父工程执行 Maven。
- 全量验证:`mvn test`。
- 单模块验证:`mvn -pl <module> -am test`。

## Architecture
- `energy-domain` 不依赖任何业务服务模块。
- Controller 只能调用应用层 Service,不得直接调用 Mapper。
- 跨模块共享 DTO、枚举和接口契约放入 `energy-domain`。
- 禁止业务模块循环依赖。

## Change Rules
- 修改数据库字段时,同步检查实体、DTO、Mapper SQL、接口文档和测试。
- 不修改 `target/`、日志、IDE 元数据和生产环境配置。
- 不擅自执行数据库迁移、推送远程分支或创建发布。
- 修复缺陷时先添加可复现测试,再修改实现。

## Verification
- 优先运行受影响模块测试,成功时不输出完整日志。
- 变更跨越两个以上业务模块时,再执行父工程验证。
- 最终报告必须列出改动文件、验证命令和未验证风险。

它有三个特点:

  1. 只保留全局且高频的规则;
  2. 命令可复制执行,不写“请充分测试”这类空话;
  3. 每条限制都能追溯到真实风险,而非提前想象全部失败。

不建议把完整目录树、所有 API 或冗长代码规范塞进文件。Agent 可以搜索目录;真正稀缺的是它无法自行推断的组织约束。

4.2 渐进式披露

全局 Guide 只提供导航,细节按需加载:

AGENTS.md(始终加载,约 50 行)
   ├── 修改任务模块?读取 docs/task-module.md
   ├── 修改数据库?加载 /database-change Skill
   ├── 修改开放接口?读取 docs/open-api-contract.md
   └── 排查线上异常?加载 /log-diagnosis Skill

可以把信息价值近似理解为:

ContextEfficiency=RelevantTokensTotalTokensContextEfficiency = \frac{RelevantTokens}{TotalTokens}ContextEfficiency=TotalTokensRelevantTokens​

Harness 优化的不是上下文绝对长度,而是相关信息密度。工具返回也应遵循同样原则:成功静默,失败只返回关键错误和定位信息。

五、第二层:安全工具不是“给 Agent 一个 Shell”

5.1 工具设计原则

工具是模型与现实世界之间的执行边界。一个工具至少应该具备:

  • 参数化接口,而非让模型拼任意字符串;
  • 工作区边界检查,阻止路径逃逸;
  • 命令 Allowlist 或明确的风险分级;
  • 超时、输出截断和退出码;
  • 每次调用写入审计轨迹;
  • 危险动作需要人工批准,默认拒绝。

先定义统一的数据结构:

# harness/contracts.py
from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, Literal


@dataclass(frozen=True)
class ToolCall:
    id: str
    name: str
    arguments: dict[str, Any]


@dataclass(frozen=True)
class ToolResult:
    call_id: str
    ok: bool
    summary: str
    details: str = ""


@dataclass
class AgentState:
    task: str
    iteration: int = 0
    changed_files: set[str] = field(default_factory=set)
    history: list[dict[str, Any]] = field(default_factory=list)
    status: Literal["running", "passed", "blocked", "failed"] = "running"

5.2 路径沙箱与命令策略

下面的 Tool Runtime 不使用 shell=True,并把命令限制在 Maven、Git 只读查询和 Python Harness 测试范围内:

# harness/tools.py
from __future__ import annotations

import json
import re
import subprocess
import time
from pathlib import Path
from typing import Sequence

from harness.contracts import ToolResult


class PolicyViolation(RuntimeError):
    pass


class ToolRuntime:
    ALLOWED_GIT_SUBCOMMANDS = {
        "status", "diff", "log", "show", "grep", "rev-parse", "ls-files"
    }
    ALLOWED_MAVEN_GOALS = {"compile", "test", "verify"}
    ALLOWED_MAVEN_OPTIONS = {"-q", "-am", "--also-make"}

    def __init__(self, workspace: Path, trace_file: Path) -> None:
        self.workspace = workspace.resolve()
        self.trace_file = trace_file
        self.trace_file.parent.mkdir(parents=True, exist_ok=True)

    def _safe_path(self, relative: str) -> Path:
        candidate = (self.workspace / relative).resolve()
        if candidate != self.workspace and self.workspace not in candidate.parents:
            raise PolicyViolation(f"路径越界:{relative}")
        return candidate

    def read_file(self, relative: str, max_chars: int = 20_000) -> ToolResult:
        path = self._safe_path(relative)
        text = path.read_text(encoding="utf-8")
        clipped = text[:max_chars]
        suffix = "\n...<truncated>" if len(text) > max_chars else ""
        result = ToolResult(relative, True, f"已读取 {relative}", clipped + suffix)
        self._audit("read_file", {"path": relative}, result)
        return result

    def write_file(self, relative: str, content: str) -> ToolResult:
        path = self._safe_path(relative)
        parts = set(Path(relative.replace("\\", "/")).parts)
        if parts.intersection({"target", ".git", ".idea", "logs"}):
            raise PolicyViolation(f"禁止写入:{relative}")
        path.parent.mkdir(parents=True, exist_ok=True)
        path.write_text(content, encoding="utf-8")
        result = ToolResult(relative, True, f"已写入 {relative}")
        self._audit("write_file", {"path": relative}, result)
        return result

    def _validate_command(self, argv: Sequence[str]) -> None:
        if not argv:
            raise PolicyViolation("命令不能为空")
        program = Path(argv[0]).name.lower()
        if program == "git":
            if len(argv) < 2 or argv[1] not in self.ALLOWED_GIT_SUBCOMMANDS:
                raise PolicyViolation(f"Git 子命令不在白名单:{list(argv)}")
            return
        if program in {"mvn", "mvn.cmd"}:
            index = 1
            while index < len(argv):
                token = argv[index]
                if token == "-pl":
                    index += 1
                    if index >= len(argv) or not re.fullmatch(r"[\w./,-]+", argv[index]):
                        raise PolicyViolation("非法 Maven 模块参数")
                elif token not in self.ALLOWED_MAVEN_OPTIONS | self.ALLOWED_MAVEN_GOALS:
                    raise PolicyViolation(f"Maven 参数不在白名单:{token}")
                index += 1
            return
        if program in {"python", "python.exe"} and list(argv[1:3]) == ["-m", "pytest"]:
            return
        raise PolicyViolation(f"命令不在白名单:{list(argv)}")

    def run(self, argv: Sequence[str], timeout: int = 120) -> ToolResult:
        self._validate_command(argv)
        started = time.monotonic()
        try:
            completed = subprocess.run(
                list(argv), cwd=self.workspace, capture_output=True,
                text=True, encoding="utf-8", errors="replace", timeout=timeout,
                shell=False,
            )
            elapsed_ms = int((time.monotonic() - started) * 1000)
            output = (completed.stdout + "\n" + completed.stderr).strip()
            # 成功只返回摘要;失败保留尾部错误,避免日志污染上下文。
            details = "" if completed.returncode == 0 else output[-12_000:]
            result = ToolResult(
                "command", completed.returncode == 0,
                f"exit={completed.returncode}, elapsed={elapsed_ms}ms", details,
            )
        except subprocess.TimeoutExpired as error:
            result = ToolResult(
                "command", False, f"timeout>{timeout}s", str(error)[-2_000:]
            )
        self._audit("run", {"argv": list(argv)}, result)
        return result

    def _audit(self, tool: str, args: dict, result: ToolResult) -> None:
        event = {
            "timestamp": time.time(), "tool": tool, "args": args,
            "ok": result.ok, "summary": result.summary,
        }
        with self.trace_file.open("a", encoding="utf-8") as file:
            file.write(json.dumps(event, ensure_ascii=False) + "\n")

生产实现还要补三项:

  • 在容器或临时 Worktree 中运行,避免并行 Agent 互相覆盖;
  • 网络默认关闭,依赖下载通过代理与域名白名单;
  • 密钥不进入 Prompt、日志和子进程环境,只给特定工具短期凭证。

注意:正则拦截危险命令只能兜底,不能作为唯一沙箱。安全边界应建立在 OS 权限、容器、网络策略和人工批准之上。

六、第三层:选择性验证,把反馈左移

6.1 为什么不能每次都跑全量测试

全量测试五分钟,不代表它适合每轮 Agent 修改。反馈太慢会降低迭代次数;输出四千行成功日志,还会造成 Context Rot。合理做法是分层:

文件写入后:格式化、语法检查                  秒级
一轮修改后:受影响模块编译 + 单元测试          十秒级
任务完成前:架构测试 + 集成测试               分钟级
合并流水线:全量回归、依赖扫描、变异测试       更高成本
线上持续:SLO、错误率、日志异常、业务指标       持续运行

6.2 从变更文件推导 Maven 模块

# harness/verify.py
from __future__ import annotations

import os
from dataclasses import dataclass

from harness.tools import ToolRuntime
from harness.contracts import ToolResult


MODULES = {
    "core/energy-base": "core/energy-base",
    "core/energy-domain": "core/energy-domain",
    "platform-energy-auth": "platform-energy-auth",
    "platform-energy-manage": "platform-energy-manage",
    "platform-energy-open": "platform-energy-open",
    "platform-energy-task": "platform-energy-task",
    "platform-energy-data-stream": "platform-energy-data-stream",
    "platform-energy-user-sync": "platform-energy-user-sync",
}


@dataclass(frozen=True)
class VerificationReport:
    passed: bool
    checks: list[ToolResult]

    def feedback(self) -> str:
        failures = [item for item in self.checks if not item.ok]
        if not failures:
            return "VERIFICATION_PASSED"
        return "\n\n".join(
            f"[{item.summary}]\n{item.details}" for item in failures
        )


class MavenVerifier:
    def __init__(self, runtime: ToolRuntime) -> None:
        self.runtime = runtime

    def affected_modules(self, changed_files: set[str]) -> list[str]:
        normalized = {path.replace("\\", "/") for path in changed_files}
        modules = {
            module
            for prefix, module in MODULES.items()
            if any(path == prefix or path.startswith(prefix + "/") for path in normalized)
        }
        # 父 POM 或共享基础层变化,影响面难以局部证明,升级为全量验证。
        if "pom.xml" in normalized or "core/energy-base" in modules:
            return []
        return sorted(modules)

    def verify(self, changed_files: set[str]) -> VerificationReport:
        modules = self.affected_modules(changed_files)
        maven = "mvn.cmd" if os.name == "nt" else "mvn"
        if modules:
            command = [maven, "-q", "-pl", ",".join(modules), "-am", "test"]
        else:
            command = [maven, "-q", "test"]
        result = self.runtime.run(command, timeout=600)
        return VerificationReport(result.ok, [result])

这里的 -am 很关键:只测 platform-energy-manage 可能漏掉它依赖的共享模块,--also-make 会同时构建依赖链。反过来,如果父 POM 或基础模块变化,局部验证无法证明安全,应自动升级为全量验证。

6.3 用 ArchUnit 固化模块边界

架构说明是 Guide,ArchUnit 则把它升级为 Sensor:

package com.smalleel.architecture;

import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import com.tngtech.archunit.lang.ArchRule;
import org.junit.jupiter.api.Test;

import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;

class LayerDependencyTest {

    private final JavaClasses classes = new ClassFileImporter()
            .importPackages("com.smalleel");

    @Test
    void controllerMustNotAccessMapperDirectly() {
        ArchRule rule = noClasses()
                .that().resideInAPackage("..controller..")
                .should().dependOnClassesThat()
                .resideInAnyPackage("..mapper..", "..repository.impl..");

        rule.check(classes);
    }

    @Test
    void domainMustNotDependOnBusinessApplications() {
        ArchRule rule = noClasses()
                .that().resideInAPackage("com.smalleel.domain..")
                .should().dependOnClassesThat()
                .resideInAnyPackage(
                        "com.smalleel.manage..",
                        "com.smalleel.task..",
                        "com.smalleel.auth.."
                );

        rule.check(classes);
    }
}

依赖示例:

<dependency>
    <groupId>com.tngtech.archunit</groupId>
    <artifactId>archunit-junit5</artifactId>
    <version>1.3.0</version>
    <scope>test</scope>
</dependency>

版本应按项目 JDK 与依赖治理策略统一管理。重点不是某个库,而是把“架构意图”变成每次修改都能执行的 Fitness Function。

七、第四层:实现一个最小但完整的 Agent Loop

7.1 模型适配层

Harness 不应和某一家模型 API 强耦合。先定义协议:

# harness/agent_loop.py
from __future__ import annotations

from dataclasses import dataclass
from typing import Protocol

from harness.contracts import AgentState, ToolCall, ToolResult
from harness.tools import PolicyViolation, ToolRuntime
from harness.verify import MavenVerifier


@dataclass(frozen=True)
class ModelTurn:
    text: str
    tool_calls: list[ToolCall]
    wants_to_finish: bool = False


class ModelClient(Protocol):
    def complete(self, messages: list[dict]) -> ModelTurn:
        """适配具体模型,将原生响应统一转换为 ModelTurn。"""
        ...

将模型 SDK 隔离后,可以替换模型、做 A/B Test,也可以用脚本模型稳定测试 Harness 自身。

7.2 状态机、预算和停止条件

class AgentLoop:
    def __init__(
        self,
        model: ModelClient,
        runtime: ToolRuntime,
        verifier: MavenVerifier,
        max_iterations: int = 12,
        max_consecutive_failures: int = 3,
    ) -> None:
        self.model = model
        self.runtime = runtime
        self.verifier = verifier
        self.max_iterations = max_iterations
        self.max_consecutive_failures = max_consecutive_failures

    def run(self, task: str) -> AgentState:
        state = AgentState(task=task)
        messages = [{
            "role": "system",
            "content": (
                "按仓库 AGENTS.md 工作。先调查再修改;最小化改动;"
                "不得绕过权限;完成前必须通过 verify。"
            ),
        }, {"role": "user", "content": task}]
        consecutive_failures = 0

        while state.iteration < self.max_iterations:
            state.iteration += 1
            turn = self.model.complete(messages)
            messages.append({"role": "assistant", "content": turn.text})

            for call in turn.tool_calls:
                result = self._execute(call, state)
                messages.append({
                    "role": "tool",
                    "tool_call_id": call.id,
                    "content": self._compact_result(result),
                })
                consecutive_failures = 0 if result.ok else consecutive_failures + 1

            if consecutive_failures >= self.max_consecutive_failures:
                state.status = "blocked"
                state.history.append({
                    "reason": "连续失败达到上限,需要人工判断根因"
                })
                return state

            if turn.wants_to_finish:
                report = self.verifier.verify(state.changed_files)
                if report.passed:
                    state.status = "passed"
                    return state

                # 拒绝“带病完成”,把可执行证据送回下一轮。
                messages.append({
                    "role": "user",
                    "content": (
                        "验证未通过,任务尚未完成。仅根据以下错误修复,"
                        "不要通过删除测试或降低断言绕过:\n"
                        + report.feedback()
                    ),
                })
                consecutive_failures += 1

        state.status = "blocked"
        state.history.append({"reason": "迭代预算耗尽"})
        return state

    def _execute(self, call: ToolCall, state: AgentState) -> ToolResult:
        try:
            if call.name == "read_file":
                return self.runtime.read_file(call.arguments["path"])
            if call.name == "write_file":
                path = call.arguments["path"]
                result = self.runtime.write_file(path, call.arguments["content"])
                if result.ok:
                    state.changed_files.add(path)
                return result
            if call.name == "run_command":
                return self.runtime.run(call.arguments["argv"])
            return ToolResult(call.id, False, f"未知工具:{call.name}")
        except (PolicyViolation, TimeoutError, OSError) as error:
            return ToolResult(call.id, False, type(error).__name__, str(error))

    @staticmethod
    def _compact_result(result: ToolResult) -> str:
        if result.ok and not result.details:
            return result.summary
        return f"{result.summary}\n{result.details[-12_000:]}"

这个循环中有几个比 Prompt 更“硬”的设计:

  • max_iterations 控制成本和失控循环;
  • 连续失败熔断,避免 Agent 对同一错误盲目重试;
  • 模型宣布完成不等于完成,必须通过 verifier;
  • 验证失败自动回灌,但禁止删测试、降断言;
  • 工具异常被转换成结构化反馈,不让整个运行时崩溃。

7.3 “Done”必须是机器可判断的

差的完成条件:

功能写好,代码优雅,测试充分。

可执行的完成契约:

acceptance:
  - response_field: offlineReason
    endpoint: GET /devices/{id}
  - database_nullable: true
  - backward_compatible: true
verification:
  - mvn -pl platform-energy-manage -am test
  - architecture tests pass
forbidden:
  - no production config changes
  - no disabled tests
  - no direct controller-to-mapper dependency

Behavior Harness 最难的地方,不是让 Agent 写测试,而是避免“实现和测试一起误解需求”。高风险需求可使用 Approved Fixtures:由人先给出输入输出样例,Agent 只能实现让固定样例通过的代码,不能自己重写真相。

八、第五层:独立 Evaluator,避免“自己给自己打满分”

生成 Agent 容易对自己的方案产生确认偏差。更稳妥的结构是角色分离:

Planner:澄清范围,输出完成契约
   ↓
Implementer:只负责修改与本地自检
   ↓
Computational Sensors:编译、测试、架构、覆盖率
   ↓
Evaluator:独立读取任务和 diff,寻找遗漏与投机通过
   ↓
Human:只处理语义歧义、高风险授权和最终责任

Evaluator 的输入应尽量“去污染”:给它原始需求、验收标准、diff、验证摘要,不给 Implementer 的冗长思考过程。

一个实用的评审输出 Schema:

{
  "decision": "reject",
  "findings": [
    {
      "severity": "high",
      "category": "behavior",
      "file": "platform-energy-manage/.../DeviceController.java",
      "evidence": "新增字段未出现在详情接口 DTO 中",
      "required_fix": "补充 DeviceDetailVO 映射并增加接口测试"
    }
  ],
  "residual_risks": ["未连接达梦测试库验证旧数据兼容性"]
}

不要让 Evaluator 输出“整体不错,建议优化”式散文。没有文件、证据和修复条件的意见,无法进入自动闭环。

九、第六层:用测试验证 Harness,而不只验证业务代码

Harness 本身也是软件,也会出现安全策略误判、状态机提前结束、日志泄漏等缺陷。至少要测试以下不变量:

# harness/tests/test_harness.py
from pathlib import Path

import pytest

from harness.tools import PolicyViolation, ToolRuntime
from harness.verify import MavenVerifier


def runtime(tmp_path: Path) -> ToolRuntime:
    return ToolRuntime(tmp_path, tmp_path / ".harness" / "trace.jsonl")


def test_path_cannot_escape_workspace(tmp_path: Path) -> None:
    with pytest.raises(PolicyViolation):
        runtime(tmp_path).read_file("../secret.txt")


def test_agent_cannot_push_repository(tmp_path: Path) -> None:
    with pytest.raises(PolicyViolation):
        runtime(tmp_path).run(["git", "push", "origin", "main"])


def test_domain_change_selects_domain_module(tmp_path: Path) -> None:
    verifier = MavenVerifier(runtime(tmp_path))
    modules = verifier.affected_modules({
        "core/energy-domain/src/main/java/com/smalleel/domain/Device.java"
    })
    assert modules == ["core/energy-domain"]


def test_parent_pom_change_escalates_to_full_build(tmp_path: Path) -> None:
    verifier = MavenVerifier(runtime(tmp_path))
    assert verifier.affected_modules({"pom.xml"}) == []

进一步可做 Harness Evals:准备 20~50 个历史任务和失败样本,对不同规则、工具或模型组合重复运行,统计:

  • Task Success Rate:满足外部验收的任务比例;
  • First-pass Yield:第一次验证即通过的比例;
  • Human Intervention Rate:需要人工接管的任务比例;
  • Escaped Defect Rate:Harness 通过但 Review/线上发现缺陷的比例;
  • Median Iterations:完成任务的中位迭代轮次;
  • Token / Cost per Success:每个成功任务的真实成本;
  • Time to Reliable Result:不是首次输出,而是首次可信结果的时间。

只看 Token 数会鼓励少验证,只看一次通过率会鼓励过度提示。更合理的核心指标是:

CostPerReliableChange=模型成本+计算成本+人工复核成本通过独立验收的变更数CostPerReliableChange = \frac{模型成本 + 计算成本 + 人工复核成本}{通过独立验收的变更数}CostPerReliableChange=通过独立验收的变更数模型成本+计算成本+人工复核成本​

9.1 Eval 必须抵抗偶然性

Agent 是非确定性的,同一任务至少运行多次。若一次成功概率为 ppp,运行 nnn 次得到的成功数 KKK 服从二项分布:

K∼Binomial(n,p)K \sim Binomial(n,p)K∼Binomial(n,p)

样本太少时,“从 70% 提升到 80%”可能只是随机波动。工程上至少报告:

  • 任务集版本与难度分层;
  • 每个任务重复次数;
  • 模型、温度、Harness 版本;
  • 成功判定器及人工复核规则;
  • 均值之外的失败类型分布。

Harness 优化不是凭体感叠规则,而是像优化编译器或测试平台一样做回归实验。

十、可观测性:看见 Agent 为什么成功或失败

建议每轮记录以下事件,但不要记录密钥和完整敏感数据:

{
  "runId": "run-20260902-001",
  "taskId": "ENERGY-1842",
  "iteration": 4,
  "model": "coding-model-a",
  "event": "verification_failed",
  "tool": "maven",
  "durationMs": 18420,
  "changedFiles": 6,
  "inputTokens": 12840,
  "outputTokens": 2130,
  "errorFingerprint": "DeviceServiceTest:expected-offlineReason",
  "policyVersion": "harness-0.3.0"
}

单次 Trace 用来复盘,聚合指标用来治理:

同类失败重复出现?  → Guide 不清楚,或缺少确定性 Sensor
工具调用频繁选错?  → 工具太多、描述重叠,或参数设计不合理
总在最后一步失败?  → 反馈太靠右,应前移到文件写入后
测试都绿但线上出错?→ Behavior Harness 不足,验收样例不代表真实需求
上下文快速膨胀?    → 日志未压缩、工具未渐进披露、子任务未隔离

成熟团队会形成“棘轮效应”:

线上/Review 发现缺陷
        ↓
归类为可重复失败模式
        ↓
优先补 Sensor(测试、Lint、策略)
        ↓
必要时补 Guide(规则、示例、Skill)
        ↓
加入 Harness Eval 防止回归

不是每次失败都加一条自然语言规则。最优先顺序通常是:可执行测试 > 静态规则 > 工具约束 > 简短说明 > 再次提醒模型。

十一、长任务与多 Agent:子 Agent 是 Context Firewall

把子 Agent 命名为“前端专家”“后端专家”,并不会自动产生专业性。它最稳定的价值是 上下文隔离:

  • Search Agent 阅读几十个文件,只把调用链和证据返回主线程;
  • Implementer 在独立 Worktree 修改,避免与其他任务冲突;
  • Evaluator 只看需求、diff 和测试结果,减少自我确认偏差;
  • 主 Agent 保留目标、决策和状态,不承载海量中间输出。

一个任务拆分协议可以这样定义:

from dataclasses import dataclass


@dataclass(frozen=True)
class DelegationContract:
    goal: str                 # 唯一、可验证的子目标
    allowed_paths: tuple[str, ...]
    forbidden_actions: tuple[str, ...]
    required_evidence: tuple[str, ...]
    return_schema: str        # 只返回结论、证据和残余风险

并行的前提是文件所有权可分离。两个 Agent 同时编辑同一个 Mapper XML,不叫并行开发,叫非确定性冲突制造器。推荐隔离方式:

主任务
├── Agent A:只读调查调用链
├── Agent B:在 worktree-B 修改领域模型
├── Agent C:在 worktree-C 编写黑盒验收测试
└── 主 Agent:按依赖顺序集成,运行统一 Sensor

长任务发生上下文压缩时,应把状态落盘为结构化 Hand-off:

# Handoff
- Goal:新增设备离线原因并保持接口兼容
- Done:领域字段、Mapper、Service 已完成
- Pending:Controller DTO、接口测试
- Decisions:字段 nullable;旧客户端不受影响
- Verification:domain tests passed;manage tests failing
- Current failure:DeviceControllerTest 缺少 JSON 字段
- Do not touch:生产配置、数据库迁移脚本

这比让新会话阅读全部聊天历史更可靠。

十二、常见反模式:为什么 Harness 越做越差

12.1 规则文件无限膨胀

每次失败都向 AGENTS.md 追加五行,最终关键规则被淹没。应定期删除已被测试、类型系统或工具强制保证的重复说明。

12.2 一次挂载几十个 MCP Server

每个工具的名称、描述和参数都占用指令预算。能力重复还会导致 Tool Thrashing。按任务启用工具,并优先提供窄接口、短响应。

12.3 让 Agent 自己写实现、测试,再自己宣布正确

三者共享同一误解。至少把外部验收样例、架构规则或独立 Evaluator 放在生成链之外。

12.4 成功也打印完整日志

成功日志的边际信息接近零,却会挤占上下文。正确策略是 Success is silent, failure is actionable。

12.5 为追求自治取消全部人工批准

自治不是无限权限。数据库迁移、生产发布、外部消息、资金与权限变更应始终设置明确的人类闸门。

12.6 一开始就设计“终极 Harness”

没有失败数据就无法知道哪些约束有价值。先让最小版本跑起来,再从真实失败中演化;Harness 是累积出来的组织经验,不是一次性采购的模板。

12.7 只统计生成速度

“10 分钟生成 3000 行代码”不是交付指标。若人工花两天查错,系统吞吐反而下降。应统计可靠结果的端到端时间与漏检缺陷。

十三、落地路线:从 Level 0 到 Level 4

等级能力进入下一阶段的条件
L0 对话助手生成片段,人工复制开始允许读写仓库
L1 工具化文件、搜索、命令,人工全程盯守有权限边界和审计日志
L2 可验证编译、测试、Lint 自动回灌失败可稳定复现和分类
L3 可委派计划、子 Agent、Worktree、独立评审中等任务低干预完成
L4 可治理Eval、指标、策略版本、持续漂移检测Harness 有明确 ROI

针对现有 Java 多模块项目,可以按四周推进:

第一周:建立基线

  • 精简根级 Guide;
  • 统一单模块和全量 Maven 命令;
  • 禁止写入日志、target 和生产配置;
  • 收集 20 个历史任务作为 Eval Set。

第二周:补确定性 Sensor

  • 增加 ArchUnit 模块边界测试;
  • 对高频缺陷补单元/集成测试;
  • 实现变更文件到 Maven 模块的选择性验证;
  • 压缩成功输出,只回传失败证据。

第三周:形成闭环

  • 验证失败自动重入 Agent Loop;
  • 增加迭代、时间、Token 和连续失败预算;
  • 对数据库、Git、网络和发布动作配置人工批准;
  • 接入独立 Review Agent。

第四周:测量与演化

  • 每个 Eval 任务重复运行;
  • 统计成功率、人工介入率和单位成功成本;
  • 对 Top 3 失败模式增加规则或 Sensor;
  • 删除没有提升指标的 Hook、Skill 和工具。

十四、进一步思考:Harnessability 是架构质量的新维度

一个代码库是否适合 Agent,不只取决于代码量,还取决于它是否“可被约束和观测”:

  • 强类型语言天然提供类型 Sensor;
  • 清晰模块边界可被 ArchUnit 等工具验证;
  • 确定性的本地构建让 Agent 快速获得反馈;
  • 稳定测试数据让行为验证不依赖外部环境;
  • 统一日志与错误码让运行时问题可以机器定位;
  • 小而清晰的接口让任务容易拆分给多个 Agent。

这可以称为 Harnessability(可驾驭性)。过去我们为人类维护性设计模块、测试和文档;现在同一批工程实践又成为 Agent 的感知器和护栏。好架构不仅更容易被人理解,也更容易被机器可靠修改。

模型升级不会让 Harness 消失,只会让 Harness 的职责迁移。模型学会了基本重构,我们就不再需要细碎的重构提示;但当它开始承担跨服务、多天任务时,又需要更强的状态管理、并发隔离、Evaluator 和恢复协议。每一个 Harness 组件,本质上都编码了一个假设:模型当前还不能独立可靠地完成什么。 当假设失效,组件就应被删除。

十五、结语

Harness Engineering 的核心不是“多装几个 Agent 插件”,而是把软件工程中已经验证过的思想重新组合:

Harness 组件软件工程中的对应物
Guide规范、架构决策、Runbook
Tool类型化 API、最小权限接口
Sensor编译器、测试、静态分析、监控
Agent Loop控制循环、故障恢复状态机
Evaluator独立 Review、质量门禁
Trace / Eval可观测性、基准测试、回归体系
Human Gate变更审批与责任边界

真正高杠杆的习惯只有一句话:

当 Agent 犯下一个可重复的错误,不要只在下一次 Prompt 里提醒它;把这个错误沉淀为可复用 Guide、可执行 Sensor 或不可绕过的权限边界。

Prompt 让模型“听说过”规则,Harness 才让系统“执行”规则。最终竞争力也不只是用了哪个模型,而是谁能更快地把失败变成反馈,把反馈变成约束,再把约束变成团队可复用的工程资产。

Harness Engineering实战:让AI Coding Agent高效驱动你的代码库 随着大语言模型与代码生成技术的成熟,AI Coding Agent正从辅助工具演变为研发流程的核心参与者。然而,实际落地中真正的瓶颈并非模型能力,而是代码库结构与研发流程是否具备“机读性”。Harness Engineering——即为AI套上缰绳的工程化实践,主张通过代码库结构化、流程协议化与任务拆解工程化,让仓库从“人读”变为“机读”,使Agent能精准理解、高效执行。这一理念不仅适用于正在引入AI Coding Agent的团队,也适合从AI辅助编程进阶到AI原生开发的个人工程师。通过调整工程基础设施 阅读详情

相关推荐

Harness Engineering实战:从最小实现到openclaw企业级智能体项目

大模型驱动的智能体在真实业务中常因工具调用不可控而引发越权、成本失控等问题。Harness Engineering(缰绳工程)正是为解决这一痛点而生的工程方法论,它在模型与工具之间构建一道管理边界,通过生命周期管理、工具路由、权限校验、上下文分层记忆、错误恢复与熔断机制,将模型自主行为约束在安全规则内。这一思路类似传统服务治理中的熔断与审批机制,但被重新应用于智能体系统,使其具备企业级可靠性和可审计性。在实际工程中,无论是使用DeepAgents框架还是开源企业级框架openclaw,Harness层都能让

weixin_29056101的博客 256

Learn Harness Engineering 实战项目路线图:从最小 Harness 到完整 Agent 工作环境

本指南以 [docs/de/projects/index.md](https://link.gitcode.com/i/b2195f6231fa2b55fe0a357dc270d58b)(课程德语版的"项目"导航页)为骨架,系统讲解 Learn Harness Engineering 课程中"动手实践"部分的完整路线:从只用一个 Prompt 的弱 harness 对照实验,到最终组装一套可观测、

gitblog_00736的博客 172

【AI智能体】Harness Engineering 驾驭工程从使用到项目实战详解

Harness Engineering 驾驭工程从使用到项目实战详解

congge 2587

Learn Harness Engineering 实战项目 01:仅 Prompt 与规则先行(Minimal Harness)到底差多少

本篇技术指南围绕 learn-harness-engineering 仓库中的实战项目 01「仅 Prompt 与规则先行」展开:用同一个"最小 Electron 知识库应用"任务跑两次 Agent —— 第一次只丢一句 Prompt,第二次预置 `AGENTS.md`、`init.sh`、`feature_list.json` 等最小 harness 文件 —— 然后对比两次运行的完成度与证据。

gitblog_00625的博客 226

DANN实战:用Python手把手教你实现对抗迁移学习(附完整代码)

本文通过Python实战教程,手把手教你实现DANN对抗迁移学习模型,以解决领域偏移问题。文章详细解析了领域对抗神经网络的核心机制,包括梯度反转层和领域判别器的构建,并提供了从数据准备、模型搭建到训练评估的完整代码,帮助开发者快速掌握这一强大的无监督领域自适应技术。

net55的博客 317

对称加密和非对称加密、公钥和私钥、单向认证和双向认证、数字签名、数字证书、根证书

文章目录1. 什么是公钥和私钥?2. 加密算法2.1 对称加密2.2 非对称加密2.2.1 非对称加密的重要性质2.2.2 非对称加密算法应用2.2.2.1 应用1 加密通信2.2.2.1.1 单向认证和双向认证2.2.2.1 应用2 数字签名3. 数字签名3.1 数字签名用法演示3.2 数字签名存在问题4. 数字证书(Digital Certificate)4.1 创建数字证书4.1.1 举例,CA如何给我们签发一个有效证书: 1. 什么是公钥和私钥? 摘自《什么是公钥和私钥?》 公钥(Public Ke

m0_45406092的博客 1万+

Learn Harness Engineering 实战项目路线图:从 0 到 1 构建可靠的 Agent 工作环境

本篇技术指南以 Learn Harness Engineering 课程的项目实战板块为核心,系统梳理从“纯提示词驱动”到“完整 Agent Harness”的六条渐进式训练线,并给出每个项目的目录结构、对比实验方法与可度量指标。读完本文,你将掌握如何利用 `starter/` 与 `solution/` 双轨目录开展对照实验,理解 `AGENTS.md`、`feature_list.json`、

gitblog_00533的博客 475

基于ROS2 Humble与Livox Mid-360的双雷达点云融合实战解析

本文详细解析了基于ROS2 Humble与Livox Mid-360的双雷达点云融合实战方案。从环境搭建、驱动安装、双雷达配置、外参标定、时间同步到点云融合核心实现,全面介绍了技术要点与避坑指南,并提供了工程化部署与性能优化建议,助力开发者高效实现高精度点云合成应用。

ss78901的博客 1093

Learn Harness Engineering 实战项目 05:让 Agent 验证自己的工作——生成者、评估者与规划者的角色分离实验

> 本篇对应 [德语项目文档](https://link.gitcode.com/i/21d24e8d0a4d7d758cafd6b0359df796)([中文版](https://link.gitcode.com/i/e45d6cd26dffe9dd9cfa152ef3b54355)),配套讲义为 [Lecture 09 为什么 Agent 会提前宣告完成](https://link.gitco

gitblog_00616的博客 1016

GEE开发之Landsat8计算MNDWI和数据分析

上一篇博客介绍了landsat8计算NDWI以及数据的获取,这次介绍MNDWI(改进的归一化差异水体指数)。

等待着冬天的风的博客 8439

代谢组数据分析(十九):随机森林构建代谢组预后模型

建立胃癌(GC)预后模型时,从队列3中的181名患者中,使用右删失结果数据进行了随机分层抽样,分为训练数据集(n = 121)和测试数据集(n = 60)。训练了一个包含1000棵树的随机生存森林(RSF)模型,根据它们基于排列的特征重要性来选择突出的特征。通过再次训练随机生存模型,并选取28种代谢物,建立了显示出色预测能力(AUROC = 0.832,95% CI:0.697-0.951)的最佳模型,用于预测测试数据集中GC患者的生存结果。

专注生信领域 1713

Learn Harness Engineering 实战项目 05:用「生成—评估」角色分离让 Agent 自证其成,打造 grounded Q&A 验证工作流

本篇指南讲解 learn-harness-engineering 仓库中 Project 05 的核心实验:通过将「实现(Generator)」「评审(Evaluator)」「规划(Planner)」拆分为独立角色,让 Agent 对自己的产出进行自我验证、基于证据的收尾(grounded Q&A),而不是在功能未达标时过早宣布胜利。读者将掌握一套可复现的三变体对照实验方法(single-role

gitblog_00692的博客 644

Trae IDE项目开发全流程深度技巧与最佳实践

2026年AI开发新范式:Trae AI IDE深度解析 摘要 2026年,AI已成为软件开发的核心驱动力。字节跳动推出的AI原生IDE——Trae,从根本上重塑了开发体验,将AI作为第一公民而非附加功能。Trae通过深度集成大型语言模型和创新交互模式,解决了现代开发中的重复劳动、信息过载等核心痛点。 报告全面剖析了Trae的核心功能: 智能代码生成:支持上下文感知续写、自然语言驱动生成和多模态输入转换 对话式AI助手:提供侧边栏和行内对话模式,支持代码解释、Bug修复、重构建议等 Builder/SOLO

公众号:AI前沿侦探 159

Learn Harness Engineering 实战项目 03:让 Agent 在会话重启后继续工作——多会话连续性、范围控制与验证门禁

本文是 Learn Harness Engineering 系列实战教程的第三课,围绕仓库中 [docs/en/projects/project-03-multi-session-continuity/index.md](https://link.gitcode.com/i/ca3a347fc36480a53bdb27cc4778b634) 展开。你将学习如何为 AI 编码 Agent(Claud

gitblog_00544的博客 649

【Pix4d精品教程】Pix4d空三后处理:点云分类与过滤、DSM精编生成DEM、生成等高线案例详解

本文详细介绍了利用Pix4D软件进行无人机摄影测量后处理的关键步骤,主要包括点云分类与分配、DEM精编生成和等高线绘制三个核心环节。首先通过点云分类区分地面、植被等7种地物类型,然后通过点云分配将地面点云归并到Ground类别,剔除植被等干扰要素。随后重新运行DSM生成步骤获取精确DEM,最后在附加输出中设置参数生成标准等高线。文中配有详细的操作截图和注意事项,如处理前需备份原始DSM/DOM数据,并解释了DEM与DSM的本质区别。该教程为无人机摄影测量内业处理提供了完整的解决方案。

智慧空间实验室 1万+

学Simulink--基础微电网场景实例:基于Simulink的微电网经济调度优化策略仿真

指标传统调度PSO经济调度(本文)目标值总运行成本(元/h)45.232.5(工况1)降低≥20%调度响应时间(s)25<30储能SOC范围(%)50~50(不变)28~56(动态优化)20~80弃风弃光率(%)0(强制满发)0(优化消纳)0原理:微电网经济调度通过PSO算法优化各单元出力,以总成本最小化为目标,平衡功率平衡与设备约束;建模:Simulink中用实现PSO控制器,结合PV/WT/DG/ESS模型,完成闭环优化;验证。

amy_mhd的博客 67

Harness Engineering 驾驭工程:从使用到项目实战

Harness 的核心竞争力在于“结构化”:Pipeline、Stage、Step 层次清晰,Service 与 Environment 分离,变量与模板消除重复,内置策略与回滚降低操作风险。对工程团队来说,它更像一套交付操作系统,而不是又一个需要自己维护插件的脚本执行器。理解核心概念;部署 Delegate 与连接外部资源;编写 CI 流水线完成测试和镜像构建;借助 K8s Deployment 实现滚动部署;引入模板、审批、回滚等企业级能力;

2601_96493715的博客 195

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Learn Harness Engineering项目实战:从零构建可靠的多会话AI代理环境

Learn Harness Engineering是一个专注于AI编程智能体工程化落地的开源项目,通过系统化的环境设计、状态管理、验证与控制机制,帮助开发者构建可靠的多会话AI代理环境。本项目提供了从理论到实践的完整教程,让你能够从零开始掌握Harness Engineering技术,解决AI代理在实际开发中面临的连续性、可靠性和可观测性挑战。 ## 为什么需要Harness Engineeri

gitblog_00566的博客 454

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Quality Document(质量文档)实战指南:用 A–D 等级快照追踪 learn-harness-engineering 项目的代码健康度

质量文档(Quality Document)是 learn-harness-engineering 仓库中一套面向"代码库本身"的健康度快照机制:它按产品域与架构层给代码库打分(A–D),供 Agent 与人类在每次会话前后快速定位"哪里强、哪里需要返工"。读完本文,你将掌握该模板的完整字段语义、评分等级定义、更新节奏,并能结合仓库内 project-06 的真实高分/低分示例,把质量文档接入自己

gitblog_00064的博客 189

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Learn Harness Engineering 实战项目指南:从零到一构建可靠的 Agent 工作环境

> 本篇指南以 [docs/ru/projects/index.md](https://link.gitcode.com/i/a81b165110e07afbc4eeffe214242590)(项目实战索引)为核心骨架,逐一展开该课程全部实战项目的目标、实验设计、harness 机制与仓库内可对照的产物文件,并补充 [projects/](https://link.gitcode.com/i/0c

gitblog_01033的博客 275

构建你的第一个自动化循环:learn-harness-engineering 项目 07 的 Loop Engineering 实战

本文是 Learn Harness Engineering 课程项目 07「初めての自動ループを構築する」(构建你的第一个自动循环)的完整实战指南。该项目标志着课程从「harness(挽具/工作环境)」阶段向「loop(循环)」阶段的迁移:你已学会搭建具备环境、指令与反馈的 Agent 工作区,现在要把它变成一个能自行运转的自动化循环。读完本文,你将掌握三种可复用的循环设计模式——Goal Loo

gitblog_00955的博客 191

多Agent项目实战:Harness Engineering从原理到企业级落地

随着大模型能力的持续演进,基于LLM的智能体(Agent)系统正从单轮对话走向复杂任务协作。然而在实际工程中,模型推理能力只是起点,真正决定系统稳定性和业务价值的是其支撑框架——即Harness Engineering。它负责管理工具调用、上下文窗口、状态记忆与异常恢复,构成Agent能够安全、可控运行的“底板”。从底层看,Harness通过“感知-决策-执行-反馈”的控制回路,将模型输出规范为可验证的行动序列;从技术价值看,优秀的Harness能显著提升多Agent协作效率,降低token消耗与故障率,使

weixin_29053577的博客 76

基于Harness Engineering架构的企业实战项目:用TaoToken统一Key打通Agent与LLM的SSE流式链路

在Harness Engineering架构的LLM接入层,用TaoToken统一Key与Base URL,让多个Agent共用同一出口调用LLM。本文给出可复制的环境变量、客户端初始化与SSE流式验证脚本,并对照401、choices判空、超时等报错排查,帮助团队在沙箱中端到端跑通流式链路。官网:https://taotoken.net/?utm_source=taotoken_aicg_blog_end

weixin_42602368的博客 4

Harness Engineering 实战四:Java 项目的 Harness 层写在哪?附完整Demo与TaoToken配置

Spring Boot 3.2 + Maven 工程实战 Harness Engineering:把 AGENTS.md 红线、pre-commit 正则校验、harness.yaml 沙箱与 CI 覆盖率四层落到 controller/service 边界,附完整 Demo 与 TaoToken 统一通道配置,一次 curl 验证拦截是否生效。官网:https://taotoken.net/?utm_source=taotoken_aicg_blog_end

weixin_35751194的博客 7
上一篇: 从像素到汉字:基于深度学习的中文OCR系统六步全链路剖析
下一篇: Harness Engineering 延续篇:用 Evals、Trace 与 Failure Mining 构建自进化质量闭环
yychen_java
博客等级 码龄8年 1451粉丝 77原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值