很多 Agent 工具默认以交互会话的方式运行——使用者需要等它一步步提问、确认、输出,像实时对话。但真实场景里,往往只想发一条命令,让它自己后台跑完、把结果落到文件里,甚至配合定时任务每天自动跑一套工作流。本教程讲解如何在 不进入交互会话 的前提下,让 DeepSeek Harness(DSH)、Codex、Claude Code 后台自主执行任务,核心机制是 no-tty(无终端)与 headless(无头)模式。全文配套可运行的示例项目 agent-dispatcher,把三种方式串成一条完整的下发与编排链路。
前置教程
如想快速开始学习本教程,你可能需要先完成以下前置教程:
- DeepSeek Harness 安装与使用教程,了解 DSH 作为 Agent 宿主的调度机制,本教程的后台任务以其 background job 能力为基础。
- Python+FastAPI在Windows环境下创建一个基础后端服务教程,本教程示例项目基于 FastAPI 构建后台服务与接口。
- Codex 安装与 DeepSeek v4 Flash 接入教程,了解 Codex CLI 的调用方式,本教程的 no-tty 命令以其为基础。
- Claude Code 安装及配置国内大模型完整教程,了解 Claude Code 的命令行入口,用于对比 headless 模式。
- Workflow 概念详解,理解 Workflow 的多步骤编排机制,后台定时循环工作流正是 Workflow 的典型应用;Skill 概念详解 说明 Skill 定义行为规范、Workflow 定义执行路径,二者互补。
资源下载
- agent-dispatcher 示例项目源码下载 — 包含 FastAPI 后端、工作流引擎、引擎适配层与前端页面的完整源码,解压后进入项目目录即可运行。
1. 为什么需要"后台自主执行"
交互式会话适合学习和调试,但它有两个天然限制:
- 必须有人守着:每一步都需要人工确认,无法无人值守。
- 无法编排:难以塞进定时任务、CI/CD 或自动化流水线。
而很多真实需求恰恰相反——只想"甩一条指令,让它自己干完"。例如:
- 每天定时让 Agent 审查项目代码并提交修复
- 后台批量处理一批文件或生成报告
- 在服务器、容器、脚本里触发一次性的编码任务
这类需求的共同点:只管下发任务,不关心也不想要交互过程。实现它们的关键,是让 Agent 工具进入 no-tty(无终端输入)或 headless(无界面)模式——一旦检测到没有交互式终端,它们会自动从"对话模式"切换到"任务模式":跑完即止、结果存留、可被后台调度。
1.1 延伸概念:CI/CD 与自动化流水线
前面限制里提到的 CI/CD 是软件工程里的一对标准概念,这里在首次出现处把它解释清楚。
CI(Continuous Integration,持续集成):开发者频繁把代码合并到主干,每次合并自动触发一套检查流程——自动构建、自动跑测试,尽早发现冲突和 bug。CI 只负责到"测试通过"为止,不会自动上线。
CD(Continuous Deployment / Continuous Delivery,持续部署 / 持续交付):把"发布上线"也自动化。两者名字相近,区别在最后一步是否需要人工确认:
| 类型 | 是否自动上线 | 人的角色 |
|---|---|---|
| 持续交付(Delivery) | 不自动,准备好发布包,人工点确认 | 人工把关最后一步 |
| 持续部署(Deployment) | 全自动,测试通过就自动发 | 人只管维护规则 |
与本教程的关系:后文介绍的 no-tty 命令正是 CI/CD 流水线的执行单元——CI 在每次代码提交后触发一次 codex -p 审查,或在发布前自动跑一遍检查;而 7.2 节讲的"无人值守与人工确认的平衡",对应的就是持续交付(自动化到最后一步、人工放行发布)与持续部署(全自动)的分界。
2. 核心概念:no-tty 与 headless
no-tty 和 headless 是两回事,但目标一致——都为了让任务脱离交互。
| 概念 | 含义 | 触发条件 | 典型场景 |
|---|---|---|---|
| no-tty(无终端) | 程序检测不到交互式终端输入 | 被重定向、管道、后台进程调用时 | 脚本、cron、CI 流水线 |
| headless(无头) | 程序在无人值守、无图形界面的模式下运行 | 显式参数开启或环境无界面时 | 服务器、容器、自动化测试 |
no-tty 强调的是"没有交互输入设备",headless 强调的是"没有图形界面"。对编码 Agent 而言,前者决定它"进不进对话循环",后者决定它"看不看得见页面"。
2.1 任务模式与交互模式的区别
Agent 工具通常区分两种运行状态:
当命令被放入后台、重定向到文件、或没有终端时,工具检测到"无交互终端",就会走下面的任务模式——这是无人值守调度的前提。
3. Codex:最纯粹的"命令即任务"
Codex 的 CLI 从设计上就支持脚本化、非交互运行,是三者中最适合"一条命令后台执行"的。
3.1 --print 模式:不进会话直接出结果
-p(或 --print)是 Codex 的招牌非交互模式:给一条指令,直接打印结果,完全不进入交互会话,非常适合管道和脚本。
# 直接输出结果,不进交互界面
codex -p "用 try/except 包裹 src/main.py 里所有文件读取调用"
# 配合重定向,把结果存留
codex -p "给本项目加一份 README,说明安装步骤" > README.md 2>&1
3.2 后台执行:命令立刻返回
用操作系统的后台能力,让 Codex 在后台跑,命令本身立刻返回:
# Windows PowerShell
Start-Process codex -ArgumentList "-p","重构 src/ 的异常处理" -WindowStyle Hidden
# Linux / macOS(bash)
codex -p "重构 src/ 的异常处理" > result.md 2>&1 &
3.3 无 TTY 自动适配
没有交互式终端时,Codex 自动走非交互逻辑:
# 强制无 stdin,确保非交互
codex "给 config.py 补全注释" < /dev/null > out.md 2>&1
4. Claude Code:headless + 结构化输出
Claude Code 的 CLI 同样区分交互会话与一次性任务。当它检测到没有交互式 TTY 时,会自动走任务模式——跑完即止。
4.1 任务模式:跑完即止
在脚本或非交互环境下直接给指令:
# 没有交互式 TTY 时,跑完任务即退出
claude "审查 src/ 的代码质量并给出修复建议"
4.2 headless 模式:无人值守
配合后台重定向,让 Claude Code 在无界面下运行并把日志存留:
# 后台运行,日志存留,命令立即返回
claude "批量重构 utils/ 目录" > log.txt 2>&1 &
4.3 结构化输出:便于脚本解析
用 --output-format 指定输出为 JSON,方便后续脚本处理:
# 以 JSON 输出结果
claude "检查 src/ 是否有未捕获的异常" --output-format json > report.json
5. DeepSeek Harness:调度层 + 后台代理
DSH 的机制与前面两个工具不同:它是 Agent 宿主 / 调度层,本身不直接跑代码任务,而是通过调用底层引擎(Codex、Claude Code 等)来完成。因此"后台执行"在 DSH 里分两层理解。
5.1 DSH 的后台代理(background job)
DSH 可以直接创建后台子代理执行任务,无需在会话中守候,这是调度 node main.js 等脚本类任务时的常见用法。后台任务完成后,DSH 会主动通知结果。
# 在 DSH 会话中触发一个后台任务
(由 DSH 的 subagent / background job 机制承接,跑完即止)
5.2 DSH 调度底层引擎
DSH 作为调度层,可以把"一条命令后台执行"的活儿交给底层引擎。结合第 3、4 节的 --print / headless 模式,就能实现"DSH 发令、底层引擎后台跑"的组合。
关键理解:Codex 和 Claude Code 是"引擎",负责真正执行任务;DSH 是"调度层",负责编排和承接。"后台默认执行"这一需求,在 DSH 里由它的后台代理能力 + 底层引擎的 no-tty / headless 模式协同实现。
6. 实战示例:agent-dispatcher 任务下发与工作流编排
前面讲了三种工具各自的后台执行方式,本节把它们串成一个可运行的示例项目 agent-dispatcher:前端页面提交任务后,后端立即返回任务编号并在后台线程自主执行;执行过程按 Workflow 方式编排为四个节点(解析任务、引擎执行、质量校验、生成报告);引擎层以 no-tty 方式调用 Codex / Claude Code CLI,未安装时回退到模拟引擎。整体链路如下:
6.1 项目结构
示例项目 agent-dispatcher 直接放在本教程目录下,通过资源下载区获取后解压即可使用:
agent-dispatcher/
├── main.py # FastAPI 入口:提交任务、查询状态、托管页面
├── workflow.py # 工作流引擎:四节点线性流水线
├── engines.py # 引擎适配层:no-tty 调用 codex -p 与 claude
├── config.py # 配置:引擎顺序、超时、端口
├── requirements.txt # 依赖清单
└── index.html # 前端界面
6.2 工作流引擎:四节点线性流水线
workflow.py 定义了四个节点的执行顺序——这是整个编排的"剧本":
# 工作流定义:节点按列表顺序执行,构成一条线性流水线
WORKFLOW_STEPS = [
{"id": "parse", "name": "解析任务", "desc": "确认引擎与输入,生成执行计划"},
{"id": "execute", "name": "引擎执行", "desc": "以 no-tty 方式调用底层 CLI 处理任务"},
{"id": "validate", "name": "质量校验", "desc": "检查产出是否有效"},
{"id": "report", "name": "生成报告", "desc": "汇总各节点结果与耗时"},
]
每个节点执行时记录状态(running / success / failed)与耗时。流水线的推进逻辑包含一个关键控制流——失败即截断,任一节点失败后剩余节点标记为 skipped:
pipeline = [parse, execute, validate, report]
for index, fn in enumerate(pipeline):
self._run_step(index, fn)
if self.status == "failed":
# 失败截断:剩余节点全部标记 skipped
for rest in self.steps[index + 1:]:
rest["status"] = "skipped"
return
self.status = "success"
self.result = self.steps[-1]["output"]
这正是 Workflow 的典型形态:步骤固定、顺序明确、有分支控制流。完整代码请查看 agent-dispatcher/workflow.py。
6.3 引擎适配层:以 no-tty 方式调用底层 CLI
engines.py 负责把任务真正交给底层引擎,核心是 subprocess.run 的单次调用——被调进程没有交互终端,CLI 自动进入任务模式,stdout 即产出:
def run_engine(engine: str, prompt: str) -> str:
argv = ENGINE_COMMANDS[engine] + [prompt] # codex -> ["codex", "-p", prompt]
result = subprocess.run(
argv,
capture_output=True,
text=True,
timeout=ENGINE_TIMEOUT,
)
if result.returncode != 0 or not result.stdout.strip():
raise RuntimeError(f"{engine} 调用失败或无输出")
return result.stdout.strip()
ENGINE_COMMANDS 来自 config.py,对应第 3、4 节的非交互命令前缀:codex 为 codex -p,claude 为 claude。本机两者都未安装时自动回退到 mock 引擎,保证示例在任何环境都能跑通完整工作流。完整代码请查看 agent-dispatcher/engines.py。
6.4 后端接口:下发即返回,后台自主执行
main.py 提供提交、列表、详情三个接口,并托管前端页面。关键在 create_task:任务对象创建后交给后台线程,接口立即返回 task_id,不阻塞等待结果——这就是"下发"与"执行"的分离:
@app.post("/api/tasks")
def create_task(req: TaskRequest):
wf = TaskWorkflow(req.prompt, req.engine)
TASKS[wf.task_id] = wf
# 下发到后台线程后立即返回,接口不阻塞(自主执行的关键)
threading.Thread(target=wf.run, daemon=True).start()
return {"task_id": wf.task_id, "engine": wf.engine}
前端随后轮询详情接口,即可看到四个节点从 pending 到 success 的实时推进。完整代码请查看 agent-dispatcher/main.py。
6.5 前端界面
index.html 是单文件页面,功能分两块:顶部表单提交任务(任务描述 + 目标引擎选择),下方任务队列每 2 秒轮询刷新,展示每个任务的总体状态徽标、四节点进度条(含各节点耗时)以及最终产出或错误信息。
样式遵循 frontend-style 规范:主题色 #16baaa 及衍生色全部收敛为 CSS 变量;组件采用 BEM 命名(.card__title、.badge--success、.step--running 等);间距遵循 8px 网格系统;按钮与输入框均带 hover / focus / active 交互态和过渡动画;卡片标题使用主题色装饰线;表单校验色采用成功绿、警告黄、错误红三态;并针对移动端做了响应式断点。完整代码请查看 agent-dispatcher/index.html。
6.6 运行与验证
conda create -n agent-dispatcher python=3.10
conda activate agent-dispatcher
uv pip install -r requirements.txt
uvicorn main:app --host 127.0.0.1 --port 8888
浏览器打开 http://127.0.0.1:8888,输入任意任务描述并下发:
- 选择「模拟引擎」:无需安装任何 CLI,几秒内可见四节点依次点亮,产出为模拟输出;
- 本机已安装 Codex 或 Claude Code:选择对应引擎(或保持自动探测),「引擎执行」节点会真实调用 CLI 的非交互模式完成处理。
观察两个要点:其一,提交后接口立刻返回,页面不卡顿(下发不阻塞);其二,「解析任务」节点先行点亮、其余节点依次推进直至报告产出——这正是"后台自主执行 + 工作流编排"的直观呈现。
7. 进阶:定时循环工作流
把上面的"一条命令后台执行"放进定时任务,就能实现无人值守的每日循环工作流——这也正是"个人 AI 工作流"的核心形态。
7.1 定时触发:让 Agent 每天自动干活
Linux / macOS 用 crontab,Windows 用"任务计划程序",都能做到定时触发一个后台 Agent 任务:
# crontab 示例:每天凌晨 2 点让 Codex 审查代码
0 2 * * * codex -p "审查 src/ 本周改动,报告潜在问题" >> /path/to/log.txt 2>&1
7.2 无人值守与人工确认的平衡
完全无人值守适合低风险任务(审查、整理、生成草稿);涉及写入或发布的高风险操作,建议停在确认页,人工过一遍再放行。
| 任务类型 | 推荐模式 | 说明 |
|---|---|---|
| 代码审查、日志分析 | 全自动后台跑 | 只读操作,结果存留即可 |
| 生成文档、报告草稿 | 后台生成 + 通知 | 产出文件,人工审阅 |
| 提交代码、发布内容 | 后台执行 + 人工确认 | 停在确认页,人工放行 |
8. 总结
8.1 核心内容回顾
- no-tty 与 headless:是让 Agent 脱离交互、后台执行的两个关键机制。
no-tty决定"进不进对话循环",headless决定"看不看得见界面"。 - 任务模式 vs 交互模式:Agent 工具检测到无交互终端时,会自动从"逐步确认"切到"跑完即止"的任务模式,这是无人值守调度的前提。
- 三者对比:DSH 是调度层,通过后台代理 + 调度底层引擎实现后台执行;Codex 的
--print模式最纯粹,适合单条命令直出结果;Claude Code 支持 headless + 结构化 JSON 输出。 - 定时循环:配合 crontab / 任务计划程序,一行命令即可实现每日自动工作的无人值守流程。
- 实战示例:agent-dispatcher 项目演示了任务下发、后台线程自主执行、四节点工作流编排的完整闭环,前端可视化查看各节点进度。
8.2 常见问题与解答
问:后台执行时任务出错了怎么办?
答:把标准错误重定向到日志文件(2>&1 >> log.txt),方便事后排查;高风险任务建议停在确认页而非全自动。
问:no-tty 和 headless 必须同时用吗?
答:不必。编码 Agent 主要看 no-tty(决定是否进对话循环);只有涉及图形界面时才需要 headless。对 Codex、Claude Code 这类命令行工具,no-tty 通常就够了。
问:DSH 本身能像 Codex 那样用 --print 吗?
答:DSH 是调度层,不是直接执行引擎。它通过后台代理和调用底层引擎(Codex、Claude Code)来实现后台执行,因此"一条命令后台跑"最终由底层引擎的 no-tty / headless 模式承接。
举手提问