返回

DeepSeek Harness 接入 CI:headless、结构化输出与独立验收

用 dsh 0.2.0-rc.2 的 headless、--json 和 --session-id 接入脚本,区分 Agent 执行结果与测试结果,给出独立测试门禁、超时和会话数据管理方法。

让 Agent 在流水线里修复代码,并不意味着让它决定流水线是否通过。一个更容易审计的分工是:Agent 提出修改,测试工具独立检查,CI 根据测试工具的真实结果决定状态。

本文使用 CLI 0.2.0-rc.2。先完成安装篇,在安装了 CLI 的练习项目目录执行命令,并使用同一个 DSH_HOME。参数依据同版本headless 声明。下面的 CI 脚本是接入模板,需在自己的项目中执行真实模型任务和测试后验收。

先选择输出契约

普通模式适合只需要最终文字的脚本:

npx --no-install dsh --profile headless \
  "Read tutorial-input.txt and report its port field." \
  > agent.stdout 2> agent.stderr

agent.stdout 保存最终回答,诊断信息另存到 agent.stderr。发生失败时保留诊断,不在示例中用 2>/dev/null 抹掉排错依据。

0.2.0-rc.2 还支持结构化输出:

npx --no-install dsh --profile headless --json \
  "Read tutorial-input.txt and report its port field." \
  > agent-events.jsonl 2> agent.stderr

这里的 stdout 是逐行 JSON 事件,不是一个完整 JSON 文档,也不再只是最终回答。解析时按行读取,保留事件顺序,并依据同版本的事件投影实现识别记录,别直接对整个文件调用一次 JSON.parse。

“headless 没有 --json”这个旧结论对应的是 0.1.5-rc.1 的参数面,不能套用到本版本。是否支持某个选项,以你安装的版本运行 --help 为准。

让测试程序决定是否通过

下面的 Bash 模板用于已有 npm test 脚本、已在本地依赖中固定安装 dsh 的 Node 项目。凭据由 CI 的 secret 环境注入 DEEPSEEK_API_KEY,不回显到日志。

#!/usr/bin/env bash
set -euo pipefail

: "${DEEPSEEK_API_KEY:?CI secret DEEPSEEK_API_KEY is required}"
export DSH_HOME="$(mktemp -d)"

# Agent 步骤也有独立的执行时限;GNU timeout 超时会返回非零。
timeout 300s npx --no-install dsh --profile headless \
  "Run the project tests and make the smallest change needed to fix failures." \
  > agent.stdout 2> agent.stderr

# 重新运行真实测试,直接使用测试进程退出码作为门禁。
npm test > test.log 2>&1

它有两道独立检查:Agent 进程没正常完成时,脚本直接失败;Agent 进程正常结束后,测试程序仍要再跑一次。npm test 失败时,set -e 会让脚本返回非零。非 Node 项目把这一行换成仓库自己的测试命令。

不要用模型回答的 OK 替代第二道检查。 模型可能判断错误、跳过测试,或者只完成部分任务。--json 也只是更容易观察过程,不会自动把一个错误判断变成可靠的验收。

另外,测试通过只说明测试覆盖的条件通过。对真实仓库还要核对差异是否符合任务范围,测试和 CI 配置本身是否被修改,需不需要构建、lint 或人工验收。把这些检查作为流水线的明确步骤,不交给一段“全部完成”的自然语言回答。

会话可以继续,但要保存正确的状态

本版本提供:

npx --no-install dsh --profile headless --session-id "$SESSION_ID" \
  "Continue the previous investigation without modifying files."

SESSION_ID 应来自已有会话,并使用原来的 DSH_HOME 和工作区。它不是一个随便指定的任务标签;未知会话 ID 会报错。跨 runner 继续任务时,只有 ID 而没有会话数据,并不能恢复对话。

可复现的 CI 任务通常从干净工作副本和独立 DSH_HOME 开始。确实需要续接时,再明确哪些会话和工作区状态要带到下一步。

权限和执行时限分开处理

headless 只是没有交互界面的运行入口,不等于已经为任意输入建立完整的安全隔离。实际权限来自 profile、Agent 配置、操作系统和 runner 环境。

旧版在 Linux workspace-write 策略下的验证中,工作区外写入受到限制,但 /tmp 和系统临时目录仍可能可写。可写根目录声明给出了判断依据。不要只凭一个模式名称推断进程能接触的全部资源。

同样,模型请求超时和整个 CI 步骤超时是两个范围。上面的 timeout 约束整条命令;runner 是否彻底回收子进程,应结合自己的执行环境检查。别让“等待模型”占满一个长期运行的 worker。

会话和日志需要明确的保留策略

Agent 运行会产生会话数据,其中可能包含 prompt、代码片段、工具参数和回复。agent.stdout、agent.stderr、事件流和 DSH_HOME 也有不同用途。

本例用 mktemp 创建独立 home,但没有在脚本里自动删除它,方便失败时取证。为 CI 配置退出后的清理步骤:先按需要保存受控的测试报告与诊断,再删除该次运行的数据目录。诊断需要上传 artifact 时,检查访问范围并脱敏,不把模型凭据或完整会话无条件公开。

到这里,CI 的职责就明确了:启动 Agent、限制执行范围与时间、保留证据,然后独立验证产物。需要在程序里持续接收事件、管理多轮会话时,接着读TypeScript SDK;需要调整 profile 行为时,读配置覆盖层。

最后更新于 2026年10月15日 00点00分00秒