找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

3102

积分

0

好友

416

主题
发表于 3 小时前 | 查看: 4| 回复: 0

在刚开始使用Claude Code进行项目开发的第三四天,我就接连遇到了几个让人头疼的问题。

一次,AI在实现功能时,顺手把 .env 文件里的数据库连接字符串写进了代码注释里。
另一次,AI执行了一段Bash命令后,把返回的API Key中间结果复制成了变量名,然后又把这个变量名写进了代码文件。
还有一次,AI觉得migrations目录下的文件需要“顺便优化一下”,结果把部分数据迁移记录给覆盖了。

这三件事,归根结底都指向同一个核心原因:AI拥有完整的文件系统访问权限,却缺乏系统层面的边界约束。

我曾尝试用更详细、更“聪明”的提示词来解决这个问题。但提示词终究是一种“软约束”——AI可以选择听从,也可能在上下文过长、任务变复杂时将其忽略。这并非Claude的“不听话”,而是提示词机制本身缺乏强制执行力。

真正有效的方案,是在系统层面把边界画死。不是告诉AI“你应该这样做”,而是让AI“必须这样做”,并在它试图越界的那一刻就将其拦住。这比事后发现问题再打补丁要有效得多。这就是Harness系统的核心思路——不是更好的提示,是系统强制执行的约束

想清楚这点后,我便着手设计自己的Harness系统。一切从遭遇的三个最核心问题开始:

  1. AI能访问哪些文件? 我的项目中,敏感文件主要有几类:.env(环境变量)、*.pem(密钥文件)、credentials.json(第三方凭证)。这几类必须被拦截。
  2. AI在什么时候最容易越界? 会话启动初期最危险,此时Claude对项目上下文不了解,容易“乱动手”。其次是在修改代码后,它倾向于“顺手”修复旁边看起来不顺眼的东西,但这部分根本不在本次任务范围内。
  3. AI的产出需要满足什么条件才能接受? 标准就三条:没有硬编码凭证、没有越界访问、日志输出规范。这三条必须通过自动化检查,不能依赖人工肉眼审查。

将这三个问题的答案梳理清晰,Harness系统的骨架也就明确了——不能靠AI的自觉,要靠系统来强制

那么,在Claude Code中搭建一套最小可用的Harness系统,至少需要实现以下四个层面:

  1. 约束层:通过两份上下文文件,定义AI的行为边界,明确什么该做、什么不该做。
  2. 工具层:权限配置,控制AI能调用什么工具、不能调用什么工具,遵循最小权限原则。
  3. 中间件层:三层拦截器,分别在工具调用前、工具调用后、会话结束时触发,处理不同的安全问题。
  4. 编排层:规范先行的开发流程,让AI在动手之前先确认理解是否正确。

不是说只有这四层,而是说这四层是必备的——缺少任何一层,系统都会存在明显的安全缺口。

Claude Code Harness 四层架构图

约束层:通过两份文件,定义行为边界

最底层是上下文文件。Claude Code每次启动时必然会读取它们,这是整个Harness系统的基石。

第一份是 CLAUDE.md,放在项目根目录,用于告知AI项目概况和团队角色:

# 项目概况

这是一个提供 RESTful API 的 Node.js 后端服务。
技术栈:Express + PostgreSQL + Redis。

## 团队协作方式

- 我(人类):产品决策,代码审查,最终上线
- 你(AI):主力开发,响应需求实现

## 当前阶段

MVP 开发中,预计 2 周后首版发布。

## 工作约定

1. 方案确认后再动手,不要边想边写
2. 改动超过 20 行必须主动告知我
3. 凭证相关操作必须停下来等我确认

第二份是 ARCHITECTURE.md,里面写的是AI绝对不允许违反的铁律:

# 架构铁律(不可违反)

## 凭证铁律

- 绝对不读取 `.env` 文件内容
- 绝对不将任何 Key、Token、密码写入代码或注释
- 所有外部凭证必须通过环境变量注入,代码中只引用 `process.env.XXX`

## 访问边界

- 禁止对 `src/migrations/` 目录执行 Write/Edit 操作
- 禁止修改 `.gitignore` 文件
- 禁止对 `node_modules/` 执行任何操作

## 代码质量

- 所有 API 路由必须有输入校验
- 错误必须返回结构化 JSON,不允许裸字符串
- console.log 只用于开发调试,提交前必须替换为日志库

这两份文件是刻在系统里的“宪法”,不是给AI看的建议。AI读不到是我的失职,读到了还违反,那就是它的责任。

工具层:按最小权限原则分配

Claude Code的权限由 settings.local.json 控制。我在这里定义了一套权限组合:

{
  "permissions": {
    "allow": ["Read", "Edit", "Write", "Bash", "Glob", "Grep"],
    "deny": ["NotebookEdit", "WebFetch"],
    "automaticToolApproval": false
  }
}

仅配置权限是不够的。像Bash这样的工具是双刃剑,AI可能用它执行危险命令。因此,我们还需要在接下来的拦截器里进一步细化命令拦截逻辑。

中间件层:三层拦截器,覆盖完整生命周期

这是Harness系统的核心。三层拦截器分别在工具调用前、工具调用后、会话结束时触发,各司其职。

1. 工具调用前拦截:阻断越界操作

AI每次调用工具前都会触发此拦截器。我用它来拦截对敏感文件和禁止目录的操作:

#!/usr/bin/env python3
# hooks/pre-tool-guard.py

import json
import re
import sys

SENSITIVE_PATTERNS = [
    r'\.env$',
    r'\.pem$',
    r'_key$',
    r'id_rsa',
    r'credentials\.json$',
    r'\.p12$',
]

BLOCKED_DIRS = [
    'src/migrations',
    '.git',
    'node_modules/',
]

def check_path(path: str) -> tuple[bool, str]:
    """检查路径是否命中敏感规则。返回 (blocked, reason)"""
    if not path:
        return False, ""

    for pattern in SENSITIVE_PATTERNS:
        if re.search(pattern, path, re.IGNORECASE):
            return True, f"敏感文件模式: {pattern}"

    for blocked in BLOCKED_DIRS:
        if blocked in path:
            return True, f"禁止目录: {blocked}"

    return False, ""

def main():
    try:
        raw = sys.stdin.read()
        if not raw.strip():
            sys.exit(0)

        payload = json.loads(raw)
        tool = payload.get("tool", "")
        path = payload.get("path", "") or payload.get("command", "")

        if tool in ("Read", "Write", "Edit", "Bash"):
            blocked, reason = check_path(path)
            if blocked:
                print(f"\n[Harness Guard] BLOCKED: {tool} on {path}")
                print(f"[Harness Guard] 原因: {reason}")
                print("[Harness Guard] 如需解除限制,请联系项目管理员。\n")
                sys.exit(1)

    except Exception as e:
        print(f"[Harness Guard] 检查异常: {e}", file=sys.stderr)

    sys.exit(0)

if __name__ == "__main__":
    main()

测试一下效果:

# 测试:Claude 试图读取 .env 文件
echo '{"tool": "Read", "path": "/project/.env"}' | python3 pre-tool-guard.py
# 输出:[Harness Guard] BLOCKED: Read on /project/.env
# 退出码:1 ✅

# 测试:Claude 试图编辑 migrations 目录
echo '{"tool": "Edit", "path": "/project/src/migrations/001_add_users.sql"}' \
  | python3 pre-tool-guard.py
# 输出:[Harness Guard] BLOCKED: Edit on ...src/migrations/...
# 退出码:1 ✅

# 测试:正常文件操作
echo '{"tool": "Read", "path": "/project/src/controllers/user.js"}' \
  | python3 pre-tool-guard.py
# 退出码:0 ✅

settings.local.json 中注册这个拦截器:

{
  "hooks": {
    "PreToolUse": {
      "Read": "python3 /path/to/hooks/pre-tool-guard.py",
      "Write": "python3 /path/to/hooks/pre-tool-guard.py",
      "Edit": "python3 /path/to/hooks/pre-tool-guard.py",
      "Bash": "python3 /path/to/hooks/pre-tool-guard.py"
    }
  }
}

2. 工具调用后审查:检测输出中的敏感信息

这道拦截器不阻断操作,但会扫描AI的Bash或Write输出,检测是否包含泄露的凭证:

#!/usr/bin/env python3
# hooks/post-output-guard.py

import json
import re
import sys

SECRET_PATTERNS = [
    (r'(?i)(api[_-]?key|secret[_-]?key)\s*[:=]\s*["\']?[\w\-]{16,}',
     "API/密钥泄露"),
    (r'-----BEGIN\s+(RSA\s+)?PRIVATE\s+KEY-----', "私钥泄露"),
    (r'password\s*[:=]\s*["\'][^"\']{6,}["\']', "密码硬编码"),
]

def scan_output(output: str) -> list[str]:
    violations = []
    for pattern, label in SECRET_PATTERNS:
        if re.search(pattern, output):
            violations.append(label)
    return violations

def main():
    try:
        raw = sys.stdin.read()
        if not raw.strip():
            sys.exit(0)

        payload = json.loads(raw)
        tool_name = payload.get("tool", "")
        output = payload.get("output", {})

        if tool_name not in ("Bash", "Write"):
            sys.exit(0)

        output_text = ""
        if isinstance(output, dict):
            output_text = output.get("stdout", "") + str(output.get("stderr", ""))
        elif isinstance(output, str):
            output_text = output

        violations = scan_output(output_text)
        if violations:
            print(f"\n[Harness Output Guard] 检测到敏感信息: {', '.join(violations)}")
            print("[Harness Output Guard] 请审查输出内容,确保无误。\n")

    except Exception as e:
        print(f"[Harness Output Guard] 扫描异常: {e}", file=sys.stderr)

    sys.exit(0)

if __name__ == "__main__":
    main()

注册方式:

{
  "hooks": {
    "PostToolUse": {
      "Bash": "python3 /path/to/hooks/post-output-guard.py"
    }
  }
}

这里我选择只警告、不阻断,因为实际应用中误报率可能较高(例如Claude的Bash输出里可能恰好包含变量名 api_key)。直接阻断会影响正常的开发流程,而警告则能提醒开发者注意审查。

3. 会话结束时拦截:自动生成可追溯的工作摘要

这是最容易被忽略却极其重要的一环。我设计了一个会话结束拦截器,在AI完成工作后自动生成结构化的记录:

#!/bin/bash
# hooks/session-summary.sh

SESSION_DIR="$HOME/.claude/sessions/$(date +%Y-%m-%d)"
mkdir -p "$SESSION_DIR"

SESSION_FILE="$SESSION_DIR/summary-$(date +%H%M%S).md"

{
    echo "# 会话摘要 - $(date '+%Y-%m-%d %H:%M:%S')"
    echo ""
    echo "## 项目"
    echo "$(pwd)"
    echo ""
    echo "## 变更文件"
    git diff --name-only --diff-filter=ACMR 2>/dev/null \
      || echo "(非git仓库或无变更)"
    echo ""
    echo "## 新增文件"
    git ls-files --others --exclude-standard 2>/dev/null \
      || echo "(无新文件)"
    echo ""
    echo "## 拦截记录"
    grep -r "BLOCKED\|Harness" "$HOME/.claude/logs/" 2>/dev/null \
      | tail -10 || echo "无"
    echo ""
} > "$SESSION_FILE"

echo "[Harness] 会话摘要已生成: $SESSION_FILE"

至此,三层拦截器构建完毕:工具调用前拦截是“不让碰”,工具调用后审查是“防泄露”,会话结束拦截是“留痕迹”,共同构成了安全闭环。这种在关键时刻进行安全检查的思路,与运维/DevOps/SRE领域的门禁(Gate)和持续集成思想是相通的。

三层拦截器工作流程图

编排层:规范先行,理解对齐再动手

三层拦截器解决了“AI不越界”的问题,但这还不够。AI完全有可能在错误的理解上,做出一份“正确”但不符合需求的代码。

为此,我引入了一套规范先行的开发流程,强制AI在动手之前先确认理解是否正确:

需求进来 → /追问(追问澄清)→ /固化(固化规范)→ /实现(执行)→ /验证(逐条检查)

规范先行的开发流程示意图

追问的作用:在动手之前,先把需求里的所有隐含假设挖出来。
例如,当我说“给用户模块加上注册功能”时,AI会追问:

  • 密码强度规则是什么?最小几位?必须包含特殊字符吗?
  • 邮件验证是注册时发送验证链接,还是可选操作?
  • 注册后是直接登录,还是需要人工审核?
  • 一个邮箱是否允许重复注册?

我补充答案后,AI将其整理成一份不可变的规范文档:

# 规范:用户注册功能 v1.0

## 功能描述

支持邮箱注册,邮件验证后才能登录。

## 详细规则

1. 密码:最小8位,必须包含数字和字母
2. 邮件验证:注册后发送验证链接,24小时内有效
3. 登录:验证通过前禁止登录,返回 401 + {"error": "email_not_verified"}
4. 重复注册:已注册邮箱返回 409 + {"error": "email_already_registered"}

## API 设计

- POST /api/auth/register → {email, password} → {message, user_id}
- POST /api/auth/verify → {token} → {success, token}

## 验收标准

- [ ] 正常注册流程完整
- [ ] 密码强度校验生效
- [ ] 重复注册被拒绝
- [ ] 所有错误返回结构化 JSON

这份规范就是AI与人共同签署的合约。 在我确认之前,AI不会开始任何实现工作。实现完成后,AI会对照规范逐条自检是否满足所有条件。

最后防线:Git合并前门禁

即便有了Harness系统,为了防止有问题的代码绕过检查直接进入主干,我在Git层面又加了一道门禁,作为合并前的最后防线。

#!/bin/bash
# .git/hooks/pre-commit.d/harness-gate.sh

set -e

echo "[Harness Gate] 开始检查..."

# 1. 凭证扫描
if grep -rEn "(api[_-]?key|secret[_-]?key|password\s*=)" \
    --include="*.js" --include="*.ts" --include="*.py" \
    --include="*.md" --include="*.json" \
    -e "-----BEGIN.*PRIVATE KEY-----" \
    . 2>/dev/null | grep -v "node_modules" | grep -v ".git"; then
    echo "[Harness Gate] ❌ 凭证扫描未通过"
    echo "请使用环境变量或 .env.example 管理凭证"
    exit 1
fi

# 2. migrations 目录变更拦截
CHANGED_FILES=$(git diff --cached --name-only)
if echo "$CHANGED_FILES" | grep -q "src/migrations/"; then
    echo "[Harness Gate] ❌ 检测到 migrations 目录变更,需人工审查"
    exit 1
fi

echo "[Harness Gate] ✅ 门禁通过"
exit 0

实践中的两个经验与最终效果

第一个坑是关于误报。 初期,工具调用后审查器会检测所有包含 password 的输出。结果当AI执行 grep -r "password" ./src 进行代码审查时,每一行匹配都被误判为“密码泄露”。后来我将检测规则收紧,只检测真正的密钥格式(如16位以上字母数字组合前带 =:),误报率才得以降低。

第二个坑是关于流程重量。 /追问 → /固化 → /验证 这套流程对于小需求来说显得过于繁重。一个两句话能说清的需求,走完流程比直接实现还麻烦。现在的做法是:简单需求直接实现,只有遇到涉及多模块、有状态依赖、需要方案权衡的复杂需求时,才启用这套规范流程。流程是为复杂度服务的,不是必须遵守的教条。

使用两个月后的实际感受:最让我头疼的两类问题——凭证泄露到代码、越界修改migrations目录——几乎绝迹,因为AI在动手前就被系统拦住了。代码返工率明显下降,因为理解偏差在“确认规范”阶段就被纠正了。对话轮次减少,通常1-2轮就能敲定一个任务。这不是因为AI变聪明了,而是因为它先确认了理解,理解对了,实现自然就对了。

系统组件清单

以上构建的Claude Code Harness系统(约束层→工具层→中间件层→编排层)加上Git门禁,共同构成了一套最小可用的系统。以下是各层的具体组件清单:

Harness 最小可用系统组件清单

层级 组件 作用
约束层 CLAUDE.md 项目总规范,告知AI项目概况与工作约定
约束层 ARCHITECTURE.md 架构铁律,定义不可协商的禁止事项与质量标准
工具层 settings.local.json 权限配置,控制AI可用的工具
中间件层 pre-tool-guard.py 工具调用前拦截,阻断对敏感文件和禁止目录的操作
中间件层 post-output-guard.py 工具调用后审查,扫描输出中的凭证泄露
中间件层 session-summary.sh 会话结束记录,自动生成结构化工作摘要
编排层 /追问 追问需求,挖掘隐含假设
编排层 /固化 固化规范,形成AI与人的合约
编排层 /实现 按已确认的规范执行实现
编排层 /验证 对照规范逐条验证实现结果
CI/CD 层 harness-gate.sh Git合并前最后门禁,执行凭证扫描与禁止目录检查

结语

搭建这套系统,我花了大约10个小时进行一次性投入。之后每个新项目,只需Clone下来修改一下上下文文件的内容,5分钟就能完成基础配置。

真正的难点不在于编写代码,而在于想清楚你的边界在哪里:你允许AI做什么,不允许它做什么,什么情况下必须让它停下来等你确认。这些问题在写代码之前就必须有明确的答案。代码,仅仅是将这些决策翻译成系统可执行的规则。

Claude Code的Harness四层架构(约束→工具→中间件→编排)加上Git门禁,构成了一套完整、最小可用的AI开发约束系统。它不是一个一蹴而就的庞然大物,而是伴随你的项目共同成长的安全框架。如果你想深入了解如何构建可靠的技术文档体系来支撑此类复杂系统的设计与管理,欢迎来云栈社区交流探讨更多实战经验。




上一篇:从加班疲劳到复利式创造:关于开发者如何把握关键机会的几点杂谈
下一篇:QClaw V2发布:多Agent协同打破AI办公单兵局限,连接与安全并重
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-4-10 10:59 , Processed in 0.960196 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表