<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>无人值守 on Codexer</title><link>https://codexer.com/tags/%E6%97%A0%E4%BA%BA%E5%80%BC%E5%AE%88/</link><description>Recent content in 无人值守 on Codexer</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Wed, 19 Aug 2026 09:00:00 +0800</lastBuildDate><atom:link href="https://codexer.com/tags/%E6%97%A0%E4%BA%BA%E5%80%BC%E5%AE%88/index.xml" rel="self" type="application/rss+xml"/><item><title>关掉审批、不再盯屏：我是怎么放心让 Codex 独自写后端的</title><link>https://codexer.com/posts/2026-08-19-codex-unattended-backend-guardrails/</link><pubDate>Wed, 19 Aug 2026 09:00:00 +0800</pubDate><guid>https://codexer.com/posts/2026-08-19-codex-unattended-backend-guardrails/</guid><description>&lt;p&gt;想象一个场景：你下班前给 Codex 丢下一句「给订单服务加一个下单事件，再让通知服务发确认邮件」，然后关掉电脑回家。第二天早上，功能已经写好、测试通过、甚至已经在 preview 环境里跑起来了，你只需要扫一眼 diff、点一下合并。这个画面，就是很多人对「AI 无人值守编程」的终极想象。&lt;/p&gt;
&lt;p&gt;但真正试过的人会告诉你，事情远没有这么美好。作者 Ivan 在过去几个月里一直在搭这样一个环境，让 Codex 在没人盯着的情况下自己写后端代码，审批关闭、输出也不看。他给出的结论有点反直觉：这件事里，提示词几乎不是重点。真正会出问题的，是 agent 在补全那些代码库里根本没告诉它的运维细节，而这些错误往往要等几周后流量涨上来才爆发，而不是在 diff 里就现形。&lt;/p&gt;
&lt;p&gt;于是他不再纠结怎么把提示词写得更漂亮，而是把精力全部放到了「护栏」上。所谓护栏，就是让 agent 就算跑偏了，也翻不出什么大浪。这套护栏一共六层：一份每次运行都会读的 AGENTS.md、一个限制 shell 权限的沙箱、用 codex exec 做无人值守运行、一套让基础设施无需被 agent 猜测的技术栈、一个能用 trace 自查的本地环境，以及一个在代码真正进入生产账户之前先落地的 preview 环境。下面一层一层拆开讲。&lt;/p&gt;
&lt;h2 id="真正的坑agent-会替你把运维细节补全"&gt;真正的坑：agent 会替你把运维细节补全&lt;/h2&gt;
&lt;p&gt;先讲一个贯穿全文的核心判断：无人值守编程里，大部分致命错误不是模型写错了业务逻辑，而是它「发明」了一些代码库里根本没有依据的运维参数。&lt;/p&gt;
&lt;p&gt;Ivan 举了一个很形象的例子。如果你让 Codex 在一个 Express + Terraform 的项目里加一个事件队列，它可能会生成这样一段 Terraform：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-hcl" data-lang="hcl"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;resource&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;aws_sqs_queue&amp;#34; &amp;#34;order_created&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;order-created&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; visibility_timeout_seconds &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; message_retention_seconds &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1209600&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; redrive_policy &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;jsonencode&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; deadLetterTargetArn &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;aws_sqs_queue&lt;/span&gt;.&lt;span style="color:#66d9ef"&gt;order_created_dlq&lt;/span&gt;.&lt;span style="color:#66d9ef"&gt;arn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; maxReceiveCount &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;看起来挺像那么回事。但仔细看这几个数字：visibility_timeout 必须大于 handler 的实际运行时长，而这个时长应用代码里根本没有写；maxReceiveCount 等于 5 只有在 handler 幂等的时候才正确，否则就是一次线上事故。更麻烦的是，terraform validate 会接受这一切，沙箱也不会拦它，因为在工作目录里写文件本来就是 workspace-write 模式的职责。换句话说，这段「看起来完全合法」的代码里，藏着三个纯靠猜的参数，而它们要到生产环境流量上来之后才会引爆。&lt;/p&gt;</description></item></channel></rss>