员工让 Agent 制作一个网页,往往还需要检查效果、修复问题,并在后续对话中继续修改。如果每个 Agent 都使用临时目录,切换任务或重建环境后就需要重新准备文件。
本实践使用 DeepSeek Harness 编排任务,让 Code Agent 生成网页、Review Agent 用浏览器检查页面,评审通过后启动展示服务。各阶段顺序挂载同一个 AgentWorkspaces 工作区,后续任务直接使用上一阶段留下的文件。
您将完成两轮任务:先制作一个动画网页,再增加新功能;最后重建展示 Pod,检查第二轮修改是否仍然保留。
工作方式
阶段 | 做什么 | 如何使用工作区 |
Code Agent | 生成或修改 HTML、CSS 和 JavaScript | 将页面写入工作区 |
Review Agent | 启动 Chrome,检查 DOM、布局、交互和控制台错误 | 新建 Job,只读挂载同一工作区 |
修复与复审 | 根据阻塞项修改页面,再进行一次评审 | Code Agent 写入,Review Agent 再读取 |
展示服务 | 使用 Nginx 提供页面访问地址 | 挂载已通过评审的文件 |
编排由 Harness 中的 Kubernetes 插件完成。工作区使用同一个 PVC,并通过 Lease 顺序使用,不依赖多个节点同时写入。Code 和 Review 是不同的执行进程,不要求任务始终留在同一个节点。
这里保留的是文件。AgentWorkspaces 不恢复 Agent 进程、浏览器状态、内存或模型对话。页面存在工作区中,任务版本和评审状态存在 ConfigMap 中;Harness Web 历史会话也不等同于工作区数据。
开始前准备
1. 已通过控制台 创建 Agent 集群和节点池。AgentWorkspaces 随集群默认安装,无需再次安装;确认
awv-btrfs StorageClass 存在,且工作区 Controller、节点组件及其依赖的存储服务均就绪,请参见 AgentWorkspaces 使用说明。2. 准备 Agent 集群节点。单个 Code 或 Review 任务请求 1 核 CPU、2 GiB 内存,限制为 2 核、4 GiB;同时预留 Harness 和组件所需容量。若要验证跨节点交接,至少准备三个可调度的目标节点。
3. 在本地或构建机准备 Bash 4 及以上、Make、Docker、kubectl、Helm 3、Node.js、npm、curl 7.71 及以上、jq,以及提供
sha256sum 的 GNU coreutils。Docker 构建目标需要为 Linux amd64;使用 ARM 电脑时,配置 DOCKER_DEFAULT_PLATFORM=linux/amd64 并确保构建环境支持该目标。4. 准备自己可推送的镜像仓库及拉取凭证,确保所有目标节点能拉取 Controller、Worker 和 Nginx 镜像。构建过程还需要访问基础镜像、软件包及浏览器下载源。
5. 准备有权限调用模型的 Token Hub API Key。本例默认使用
deepseek/deepseek-flash 和 OpenAI Chat Completions 兼容接口。模型调用、镜像存储、集群资源及展示用负载均衡器可能产生费用。6. 使用专用测试命名空间。示例 Controller 需要在该命名空间创建任务和服务,Worker 需要访问模型接口;不要直接放进已启用默认拒绝网络、但尚未适配代理注入和白名单的命名空间。
本例使用 Harness
0.1.5-rc.2,用于验证 Agent 工作文件交接。当前提供的 Job 模板没有显式设置 runtimeClassName: cube,不能把此示例的运行结果当作 Cube 安全隔离验收。在控制台检查工作区组件,也可通过以下只读命令核对。若 Controller 未就绪、就绪探针返回错误,或存储服务因调度问题长期 Pending,应先处理组件问题,不继续创建本实践的工作区。
kubectl --kubeconfig "$KUBECONFIG" get storageclass awv-btrfskubectl --kubeconfig "$KUBECONFIG" -n awv-system get podskubectl --kubeconfig "$KUBECONFIG" -n awv-system get events --sort-by=.metadata.creationTimestamp
执行上述命令前,将
KUBECONFIG 设置为目标集群访问配置文件的路径。第一步:获取示例并填写配置
下载配套示例包(
dsh-awv-example.zip),解压后进入目录:unzip dsh-awv-example.zipcd dsh-awvcp .env.example .env
包内包含部署模板、镜像构建文件、Harness 插件、任务提示词和验证脚本。编辑
.env,至少修改下列配置:配置 | 如何填写 |
KUBECONFIG | 目标 Agent 集群访问配置文件的绝对路径。 |
NAMESPACE | 独立测试命名空间,例如 dsh-awv-demo。 |
REGISTRY | 自己的镜像仓库前缀,构建脚本将在其下推送两个镜像。 |
IMAGE_TAG | 本次构建使用的标签,例如 demo-01。 |
STORAGE_CLASS | 可用的工作区 StorageClass,默认 awv-btrfs。 |
IMAGE_PULL_SECRET | 在命名空间内创建的拉取凭证名称;无需认证时设为空。 |
DOCKER_CONFIG_FILE | 已登录目标仓库的 Docker 配置文件路径;配置拉取 Secret 时必填。 |
OPENAI_BASE_URL | 默认 https://tokenhub.tencentmaas.com/v1。 |
OPENAI_API_TYPE | 保持 openai-completions,除非所接模型服务另有要求。 |
DSH_MODEL、DSH_CODE_MODEL、DSH_REVIEW_MODEL | 账号实际可用的模型;Code/Review 留空时使用 DSH_MODEL。 |
默认由调度器选择节点。若要验证跨节点交接,将
CODE_NODE、REVIEW_NODE、SITE_NODE 填为三个不同目标节点的 kubernetes.io/hostname 标签值,确认与节点名称一致;CONTROLLER_NODE 可留空。不要照抄他人的节点地址。模型 Key 不写入
.env、镜像或工作区。在 Bash 终端中加载配置,并通过隐藏输入提供 Key:set -asource .envset +aread -r -s -p '模型 API Key: ' OPENAI_API_KEYprintf '\\n'export OPENAI_API_KEYmake preflight
预检查应确认集群可访问、工作区 StorageClass 存在、至少一个节点就绪。它不会验证模型额度、镜像拉取或工作区实际读写,后续步骤仍需检查。
第二步:构建并部署任务入口
先登录自己的镜像仓库,再执行:
make buildmake installmake verifyunset OPENAI_API_KEY
构建脚本生成 Controller 和 Worker 镜像,推送后将镜像 digest 保存到
_output/images.env,部署时使用这些 digest。安装脚本在测试命名空间创建模型 Secret、镜像拉取 Secret、10 GiB 工作区 PVC、Harness 服务及命名空间权限。make verify 检查部署对象和权限配置,PVC 为 Pending 或 Bound 都可能通过,因此该输出不是文件持久化验证结果。若 StorageClass 使用延迟绑定,PVC 会在首个任务调度时绑定;任务开始后仍持续 Pending,则查看 PVC 和 Pod 事件。确认 Controller 就绪后,在一个独立终端保持端口转发:
kubectl --kubeconfig "$KUBECONFIG" -n "$NAMESPACE" \\port-forward service/dsh-harness 3080:80
在另一终端查看 Harness 日志中的登录链接,在本机浏览器打开包含登录 token 的完整链接:
kubectl --kubeconfig "$KUBECONFIG" -n "$NAMESPACE" logs deployment/dsh-harness
默认地址为
127.0.0.1:3080。登录链接包含访问凭证。本例保持 Harness 为 ClusterIP,通过本机端口转发访问;不需要把任务管理入口暴露到公网。Controller 的 /opt/dsh/sessions 未持久化,重建 Controller 前先保存需要保留的会话记录。第三步:让 Agent 生成并评审网页
在 Harness 页面发送以下任务,也可直接复制
examples/prompts/create-pelican.md:请制作一个“鹈鹕骑自行车”的轻松动画网页,完成浏览器评审后发布访问地址。交付为单文件 index.html,CSS 和 JavaScript 内联,不使用外部资源。主场景带 data-testid="pelican-scene";鹈鹕、两个车轮、道路和云朵均用 CSS/HTML 绘制并有动画。支持手机和桌面,不出现横向滚动条。页面有“AWV 接力完成”说明和动画开关。文件写入 /workspace/site/index.html。
任务执行过程中,应依次看到
code_agent、review_agent 和 publish_site 工具调用。Review 不通过时,主 Agent 将阻塞项交给 Code Agent 修复,并再次评审。评审通过后,展示服务才启动。本例默认通过 LoadBalancer 提供展示页面,可能分配可被外部访问的地址。只生成演示内容,不放置敏感文件。查看任务返回链接或在控制台查看
pelican-site Service 地址,打开后检查页面和动画开关。如果 Review 失败,先查看具体阻塞项。不要手动把评审状态改成 PASS;发布要求
reviewStatus=PASS,并且评审版本 reviewedGeneration 与当前 generation 一致。当前 Harness 版本可以调用真实 Chrome、截图及 DOM 检查,但截图在模型上下文中显示为文件链接。本实践不将其描述为模型已完成截图内容识别,也不保证生成页面达到人工设计质量。
第四步:让新的 Agent 任务继续修改
在 Harness 页面继续发送
examples/prompts/update-pelican.md 中的任务:请先用 Review Agent 打开上一次生成的鹈鹕骑车网页,检查桌面端和移动端的实际效果。发现问题后交给 Code Agent 修复,复审通过后发布。页面显著位置增加文本 AWV-ROUND-2,元素 id 为 version-badge;增加一个切换黄昏配色的按钮;保留原有场景、动画和移动端适配。
确认新创建的 Job 使用原有工作区,并在已有页面上继续修改。打开更新后的展示页面,核对
AWV-ROUND-2、配色按钮和原有场景均存在。make statuskubectl --kubeconfig "$KUBECONFIG" -n "$NAMESPACE" \\get configmap pelican-workspace-state -o jsonpath='{.data.state}'
本轮结束时应为
reviewStatus=PASS、generation=reviewedGeneration。任务版本号随实际执行变化,不需要与其他人的记录相同。后续任务成功复用文件,才能说明完成了工作文件交接;仅看到 PVC Bound 不足以证明这一点。第五步:重建展示 Pod,检查文件是否保留
先保存页面,记录文件校验值。在 Bash 中输入当前展示地址:
read -r -p '展示页面 URL: ' SITE_URLcurl --fail --show-error "$SITE_URL" -o page-before.htmlsha256sum page-before.html
在控制台进入
pelican-site Deployment,找到它创建的展示 Pod,仅删除该 Pod,保留 Deployment 和 pelican-workspace PVC。等待 Deployment 创建的新 Pod 就绪后重新读取:kubectl --kubeconfig "$KUBECONFIG" -n "$NAMESPACE" \\rollout status deployment/pelican-site --timeout=5mcurl --fail --show-error "$SITE_URL" -o page-after.htmlsha256sum page-after.htmlcmp page-before.html page-after.html
操作期间不要提交其他页面修改任务。预期重建前后校验值一致,
cmp 返回 0,页面仍有第二轮内容。还应在控制台确认 Pod 名称或 UID 已变化,避免把未发生重建的情况记作通过。验证结果如何记录
检查项 | 通过条件 |
首轮生成和评审 | Code/Review Job 完成,评审 PASS,页面可访问。 |
第二轮继续任务 | 在原页面上增加 AWV-ROUND-2 和按钮,旧内容保留。 |
评审约束 | 当前文件版本已被评审,generation 与 reviewedGeneration 一致。 |
Pod 重建 | 新 Pod 身份发生变化,页面文件校验值保持一致。 |
跨节点交接 | 仅在配置不同节点并核对实际落点后记录通过。 |
问题排查
现象 | 检查和处理 |
构建失败 | 检查构建架构、外部下载连接和镜像仓库权限。 |
镜像拉取失败 | 检查推送后的 digest、拉取 Secret 与目标节点网络。 |
PVC 或任务长时间 Pending | 检查 StorageClass、节点容量、hostname 标签和挂载事件。 |
模型调用失败 | 检查 Secret、模型访问权限、额度及 API 地址。 |
Review FAIL | 查看 Review Job 的 blocking_issues 和浏览器检查记录,按阻塞项修复。 |
工作区正在使用 | 核对是否有任务或展示 Pod 尚未退出;确认无人使用后才处理残留 Lease,不强制解绑活动卷。 |
页面没有更新 | 核对任务版本、评审版本、展示服务状态,重新获取页面避免浏览器缓存干扰。 |
LoadBalancer 没有地址 | 查看 Service 事件、配额与相关网络配置。 |