代码智能体真正变得有用,并不只是因为模型更聪明,而是因为它开始拥有工具、能够读写同一份代码仓库、可以把任务拆给子智能体,并能将执行中积累的经验沉淀为可复用的技能。此时,问题已经从“如何向模型提问”变成了“如何安全、稳定地运行一个会操作真实工程资产的分布式系统”。
这正是 cloud native agent harness(云原生智能体运行框架)值得关注的原因。这里的 harness 不是另一个聊天界面,也不只是模型 SDK 的薄封装;它负责工作区、任务调度、工具权限、状态保存、隔离、日志和失败恢复,让智能体可以进入真实的软件交付流程。
四个变化重新定义了运行边界
1. 工具让输出变成了动作
只能生成文本的模型,最坏的结果通常是一段错误答案。能够执行 Shell、调用 Git、查询工单系统或提交 Pull Request 的智能体,最坏的结果可能是删除文件、泄露凭据,或者把未经验证的代码推入生产分支。
因此,工具不能只是一个函数列表。Harness 至少需要为每种工具定义:
- 哪些角色可以调用;
- 可以操作哪些路径、仓库和外部服务;
- 是否允许访问网络;
- 命令的超时、资源和输出上限;
- 哪些操作需要人工批准;
- 调用参数、结果和副作用如何审计。
一个实用原则是:默认拒绝,按任务授予最小能力。例如,代码审查智能体通常只需要只读仓库权限,不应该持有合并权限或生产环境凭据。
2. 共享仓库和文件系统成为协作协议
当规划、实现、测试和审查由不同智能体完成时,仓库不再只是输入材料,而是各参与者之间的共享状态。计划文件、补丁、测试报告和构建产物都可能被后续步骤消费。
共享目录虽然简单,却会立即引入并发问题:两个智能体可能同时修改同一个文件,一个智能体也可能读到另一个智能体尚未完成的中间状态。更稳妥的做法是把 Git 提升为协作协议:
- 每个子任务使用独立分支或
git worktree; - 通过提交而不是未保存的文件传递代码变更;
- 将测试报告和计划放入带运行 ID 的制品目录;
- 合并前统一执行测试和策略检查;
- 工作区可以销毁,但提交、日志和制品必须可恢复。
在云环境中,这通常意味着把计算与状态分开:Pod 或任务执行器可以是临时的,Git 远端、对象存储、事件数据库和技能仓库则应当持久化。
3. 子智能体把一次调用变成了工作流
子智能体适合把大型任务拆成边界清楚的角色,例如:
- 规划智能体分析代码和验收条件;
- 实现智能体在独立工作区修改代码;
- 测试智能体运行测试并归类失败;
- 审查智能体检查差异、风险和遗漏。
但“多开几个模型”并不等于可靠的多智能体系统。Harness 需要记录任务依赖、预算、截止时间、重试次数和产物位置。还要限制扇出规模,否则一个模糊任务可能递归地产生大量子任务,快速耗尽 token、CPU 和外部 API 配额。
适合编排的是明确的交付物,而不是含糊的角色扮演。与其要求“让三个专家讨论”,不如规定:规划者输出 plan.md,实现者提交一个 Git commit,测试者输出 JUnit 报告,审查者输出结构化的通过或阻塞结论。
4. 技能让系统形成工程记忆
技能可以保存某类任务的执行方法,例如仓库构建命令、迁移检查清单、发布规则或某个框架的常见故障处理流程。它们比一段不断膨胀的系统提示更容易维护,也更适合按仓库和任务动态加载。
不过,技能不应成为模型可以悄悄改写的“永久记忆”。建议把技能当成代码管理:
- 使用 Markdown、YAML 或代码文件保存;
- 标注版本、适用范围和维护者;
- 通过 Pull Request 审查更新;
- 在沙箱中测试后再发布;
- 记录一次运行加载了哪些技能版本。
自动总结执行经验可以生成技能候选稿,但不宜未经审查就影响后续生产任务,否则一次错误结论可能持续传播。
一个可以改造的 Kubernetes Harness
下面是一个最小化的 Kubernetes 示例。它假设你已经有一个智能体镜像,镜像中提供 /app/agent 命令,并支持 --repo、--task、--skills 和 --artifacts 参数。这些参数不是某个特定产品的标准 API,需要按照你的智能体实现调整。
运行前需要替换三处内容:智能体镜像、Git 仓库地址,以及 Secret 中的 API Key。示例使用临时工作区,并把技能作为只读 ConfigMap 挂载;生产环境应把运行制品上传到对象存储或其他持久化系统。
apiVersion: v1
kind: Namespace
metadata:
name: agent-harness
---
apiVersion: v1
kind: Secret
metadata:
name: model-credentials
namespace: agent-harness
type: Opaque
stringData:
MODEL_API_KEY: "replace-me"
---
apiVersion: v1
kind: ConfigMap
metadata:
name: repository-skills
namespace: agent-harness
data:
build-and-test.md: |
# Build and test skill
1. Inspect the repository before changing files.
2. Run the smallest relevant test set first.
3. Run the full test suite before producing the final result.
4. Write test output to /artifacts/test-output.txt.
---
apiVersion: batch/v1
kind: Job
metadata:
name: coding-agent-run
namespace: agent-harness
spec:
backoffLimit: 1
activeDeadlineSeconds: 1800
template:
metadata:
labels:
app: coding-agent
spec:
restartPolicy: Never
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
initContainers:
- name: checkout
image: alpine/git:2.45.2
command:
- sh
- -ec
- |
git clone --depth=1 "$REPOSITORY" /workspace/repo
env:
- name: REPOSITORY
value: "https://example.invalid/your-org/your-repo.git"
volumeMounts:
- name: workspace
mountPath: /workspace
containers:
- name: coordinator
image: ghcr.io/your-org/coding-agent:latest
imagePullPolicy: IfNotPresent
args:
- run
- --repo=/workspace/repo
- --task=Fix the failing tests and produce a reviewed patch
- --skills=/skills
- --artifacts=/artifacts
- --max-subagents=3
env:
- name: MODEL_API_KEY
valueFrom:
secretKeyRef:
name: model-credentials
key: MODEL_API_KEY
resources:
requests:
cpu: "500m"
memory: 1Gi
limits:
cpu: "2"
memory: 4Gi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
volumeMounts:
- name: workspace
mountPath: /workspace
- name: artifacts
mountPath: /artifacts
- name: skills
mountPath: /skills
readOnly: true
volumes:
- name: workspace
emptyDir:
sizeLimit: 4Gi
- name: artifacts
emptyDir:
sizeLimit: 1Gi
- name: skills
configMap:
name: repository-skills
保存为 agent-job.yaml 后,可以这样部署和查看日志:
kubectl apply -f agent-job.yaml
kubectl -n agent-harness wait --for=condition=complete job/coding-agent-run --timeout=30m
kubectl -n agent-harness logs job/coding-agent-run -c coordinator
这个例子有意保持简单,但它已经表达了几个关键边界:检出代码与执行任务分离;技能只读;凭据通过 Secret 注入;任务有截止时间、重试限制和资源上限;容器不以 root 身份运行,也不能提升权限。
如果智能体需要访问互联网或内部服务,还应补充 NetworkPolicy 或服务网格出站策略。若要保存 /artifacts,可以增加上传制品的 sidecar,或让协调器在退出前上传到对象存储。不要直接把永久云凭据放入环境变量;生产环境更适合使用工作负载身份和短期令牌。
云原生不等于把智能体塞进容器
容器化只解决了打包问题。一个完整的云原生 Harness 还需要把执行过程转化为可观测、可控制的状态机。每次运行至少应该关联这些信息:
- 任务 ID、父任务 ID 和子任务关系;
- 使用的模型、提示模板和技能版本;
- Git 基线提交、生成的提交和最终差异;
- 工具调用、退出码、耗时和截断后的输出;
- token、CPU、内存和外部 API 成本;
- 人工批准、重试、取消和失败原因。
日志也要避免走向另一个极端。完整记录 Shell 输出可能泄露密钥、源代码或用户数据,因此应在进入日志系统前进行脱敏,并为提示、工具输出和制品设置不同的保留策略。
调度层可以采用 Kubernetes Job、工作流引擎或队列消费者,关键不在具体产品,而在于每个步骤都具备幂等边界。任务重试时,系统必须知道是继续使用已有提交、重新创建工作区,还是撤销外部副作用。对于创建工单、推送分支和发表评论这类操作,应携带幂等键,避免重试产生重复结果。
从单任务开始,而不是立即构建“智能体组织”
落地时,建议先选择一个结果容易验证、权限较低的任务,例如修复格式问题、更新依赖或分析失败测试。先让单个智能体在隔离工作区中稳定完成闭环,再逐步增加子智能体和外部工具。
上线前可以使用这份检查清单:
- [ ] 每个工具是否都有明确的权限、超时和审计记录?
- [ ] 工作区被删除后,提交、日志和制品是否仍可恢复?
- [ ] 子智能体是否有最大数量、预算和递归深度?
- [ ] 技能是否经过版本管理和人工审查?
- [ ] 网络出口和敏感凭据是否按任务最小化?
- [ ] 重试是否会重复创建分支、评论或外部资源?
- [ ] 高风险变更是否要求人工批准?
- [ ] 是否能够复现一次失败运行使用的模型、代码和技能版本?
代码智能体走出聊天框之后,本质上成为了一个拥有工具、状态和权限的执行主体。模型决定它能想到什么,而 Harness 决定它可以做什么、在哪里做、失败后如何恢复,以及人类能否理解和控制整个过程。后者往往才是智能体能否安全进入生产工程体系的分水岭。