
今年早些时候,Andrej Karpathy (@karpathy) 将一个智能体(agent)指向他自己的训练代码,并让它运行了两天。它运行了 700 次实验,保留了 20 个击败基准(benchmark)的实验,并使模型训练速度提高了 11%。然后他说了一句非常有趣的话:任何你可以低成本评估的指标(metric),都可以交给智能体群(agent swarm)来处理。
回复率(Reply rate)就是一个可以低成本评估的指标。从那以后,我花了一些时间来弄清楚,如果将这个循环指向对外拓展(outbound),它会是什么样子。
我的构建:
Codex 读取上周的结果(outcomes),编辑对外拓展系统运行所依赖的评分(scoring)和策略(play)文件,运行测试,并开启一个拉取请求(pull request)。它提出对策略手册(playbook)的更改,并附上证据和分数,然后等待人类批准。发送和合并操作保持在循环之外。
我已经多次构建了第一个循环:感知市场,对账户进行评分,根据信号(signal)进行撰写,检查消息,记录结果,从回复中学习。本文讨论的是第二个循环,即编辑第一个循环的那个循环。
这就是该构建的核心:将进入市场策略(GTM)作为版本化代码(versioned code),并根据市场反馈不断改进。
Northwind Finance: predicted=human_review expected=human_review
Bluepeak Studio: predicted=ignore expected=ignore
KiteOps: predicted=draft expected=draft
Atlas Recruiting: predicted=ignore expected=ignore
score=1.00
仓库(repo)
从文件夹开始。结构很重要,因为 Codex 只能改进它能读取和编辑的内容。
Northwind Finance: predicted=human_review expected=human_review
Bluepeak Studio: predicted=ignore expected=ignore
KiteOps: predicted=ignore expected=draft
Atlas Recruiting: predicted=ignore expected=ignore
score=0.75
仓库故意保持简单。config/scoring.yaml 包含决定哪些信号重要的规则。prompts/ 包含编写消息的策略。memory/outcomes.jsonl 记录了市场的反应。evals/score.py 是一个关卡(gate),用于判断提议的更改是否有帮助。AGENTS.md 是 Codex 在触碰任何东西之前必须阅读的法则。
离线运行第一个版本。没有 CRM,没有数据丰富(enrichment),没有交付系统。改进循环在接近真正的对外拓展机器之前,应该先在本地文件上证明自己。
第 1 步:先编写法则
在编写评分文件之前,在编写提示词(prompt)文件之前,先编写 AGENTS.md。这个文件能让智能体保持实用并受到约束。
Changed:
- Raised implementation_page_visit from 4 to 6.
Why:
- KiteOps had implementation-page intent and replied with implementation timing.
- The previous score routed this account to ignore.
Before:
- eval score 0.75
After:
- eval score 1.00
Reviewer check:
- Make sure implementation intent is specific enough.
- Keep generic downloads low.
- Merge only if this matches actual sales judgment.
法则只有一个任务:缩小工作范围。如果没有它,Codex 会试图通过扩大范围来提供帮助。它会添加更多数据,触碰更多文件,调用更多工具,或者自动化一个本应由人类控制的步骤。在这里,任务要小得多:读取结果,提出一个文件更改,证明它有帮助,然后等待。
好的表现是什么样的。 你可以在批准 PR 之前阅读法则,并确切知道 Codex 被允许做什么。
哪里会出问题。 法则变成了一份合规文档。如果 AGENTS.md 需要一个目录,那它就已经太大了。保持它的可操作性。
第 2 步:将判断移入配置(config)
大多数对外拓展的判断都存在于某人的脑海中。然后团队购买了软件,并期望软件能改进一个它看不见的决策。
将判断移入文件中。
name: weekly-outbound-tune
on:
schedule:
- cron: "0 8 * * 1"
workflow_dispatch:
jobs:
tune:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- run: pip install -r requirements.txt
- run: python3 evals/score.py || true
- run: scripts/weekly_tune.sh
这个文件最初是一个可见的假设。如果一个通用的下载应该计为零分,团队可以指向确切的代码行并更改它。如果访问实施页面是一个比你想象中更强烈的信号,Codex 可以提出差异(diff),并展示证明其合理性的结果行。
不要将这种逻辑埋藏在 Python 函数中。如果规则是可见的,团队就可以审查它、讨论它并改进它,而无需将销售判断变成工程重构(engineering refactor)。
好的表现是什么样的。 文件小到足以进行讨论。五个信号是一个很好的初始版本。
哪里会出问题。 评分文件变成了一个杂物屉。二十个信号、六个阈值以及针对每个边缘情况(edge case)的例外规则,会使改进器过拟合(overfit)。从狭窄的范围开始,让结果告诉你下一个旋钮应该放在哪里。
第 3 步:将结果写为记忆(memory)
最重要的文件是 memory/outcomes.jsonl。
每次接触(touch)占一行,在结果已知时写入:
{"date":"2026-07-01","account":"Northwind Finance","signal":"competitor_comparison","play":"migration_note","score":8,"outcome":"reply","reason":"asked for migration notes"}
{"date":"2026-07-01","account":"Bluepeak Studio","signal":"generic_download","play":"resource_followup","score":1,"outcome":"no_reply","reason":"content-only intent"}
{"date":"2026-07-02","account":"KiteOps","signal":"implementation_page_visit","play":"implementation_angle","score":6,"outcome":"reply","reason":"asked about implementation timeline"}
{"date":"2026-07-02","account":"Atlas Recruiting","signal":"job_repost","play":"hiring_angle","score":5,"outcome":"bad_fit","reason":"student research request"}
reason 字段是整个重点。no_reply 几乎什么也没告诉你。content-only intent 告诉下一次运行,这个信号可能不值得起草消息。bad_fit 只有在原因解释了为什么不合适时才有用。asked about implementation timeline 则是那种可以改变权重(weight)的细节。
在构建改进器之前,先构建验证器(validator):
You improve one outbound play.
Read:
- AGENTS.md
- config/plays.yaml
- memory/outcomes.jsonl
- the prompt file for the chosen play
Pick one play with at least 10 outcomes.
Find:
- lines or structures that appear in positive outcomes
- lines or structures that appear in no_reply or bad_fit outcomes
- any phrase that should be banned
Make one small edit to that play's prompt.
Rules:
- Do not change scoring.
- Do not create a new play.
- Do not add a new channel.
- Cite outcome rows.
- Write the before and after instruction.
Then run the copy eval if present.
If no copy eval exists, open the PR as review_required.
这就是复利(compounding)开始的地方。仪表板(dashboard)可以告诉你一个活动(campaign)表现不佳。而一个干净的结果日志可以告诉 Codex,在下一次运行之前,哪个信号、策略或短语应该被更改。
好的表现是什么样的。 一周后,一个陌生人可以阅读该文件,并分辨出哪些信号带来了回复,哪些策略导致了不匹配的对话,以及哪些内部偏好被市场忽视了。
哪里会出问题。 团队在周五凭记忆回填结果。成功的案例被保留下来,不匹配的原因变得模糊,系统从虚构中学习。在结果落地时就写入该行。
第 4 步:构建评估关卡(eval gate)
在 Codex 编辑任何东西之前,它需要一个它无法敷衍过去的测试。
创建 evals/fixtures.yaml:
- implementation_page_visit: 4
+ implementation_page_visit: 6
然后创建 evals/score.py:
You improve the outbound scoring system.
Read:
- AGENTS.md
- config/scoring.yaml
- memory/outcomes.jsonl
- evals/fixtures.yaml
Your job:
1. Find one scoring rule that should change.
2. The reason must cite memory/outcomes.jsonl.
3. Change only config/scoring.yaml.
4. Run python3 evals/score.py.
5. If the score improves, keep the change.
6. If the score stays flat or drops, revert your change and stop.
Output:
- the exact line changed
- the outcome rows that caused it
- before score
- after score
- whether the change should become a PR
Do not edit prompts.
Do not add new signals.
Do not touch delivery.
第一个关卡应该小到易于理解,并且敏锐到足以捕捉到真正的失误。在我的第一次运行中,基线(baseline)在一个案例上失败了:
0 8 * * MON cd ~/codex-self-improving-outbound && scripts/weekly_tune.sh
这很好。系统将实施意图(implementation intent)设定在起草阈值之下,因此它忽略了一个测试夹具(fixture)认为值得发送消息的账户。在测试中发现这一点,总比错过账户一个月后才发现要好。
好的表现是什么样的。 一个命令给出一个数字,每一个失败的案例都很容易检查。
哪里会出问题。 测试夹具只包含明显的成功案例。这样一来,每一个鲁莽的更改都会通过。把丑陋的案例放进关卡中:微弱的意图、不匹配、无回复、过时的信号,以及你希望系统跳过的账户。
第 5 步:让 Codex 提出一个评分更改
现在 Codex 可以进行编辑了。
创建 prompts/improve_scoring.md:
通过仓库包装器(repo wrapper)运行它:

我的改进器的第一个版本犯了一个有用的错误。它追逐了看起来最干净的回复信号。在微小的结果日志中,competitor_comparison 拥有最强的回复率,所以改进器想要增加那个权重。评估(eval)停留在 0.75,因此该更改被拒绝了。
这正是关卡存在的原因。一个较弱的系统会接受这个说法,因为它听起来很合理。而这个系统提出了一个更好的问题:这个更改修复了已知的失误吗?
第二次运行找到了有帮助的最小编辑:
git clone <repo>
cd codex-self-improving-outbound
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python3 evals/score.py
python3 scripts/propose_improvement.py
评估通过了:

这就是循环变得有用的时刻。它因为一个原因更改了一条规则,并针对测试夹具证明了该更改。
Build scripts/append_outcome.py.
It accepts:
- date
- account
- signal
- play
- score
- outcome: reply | meeting | no_reply | bad_fit | bounced
- reason
It rejects:
- missing fields
- unknown outcomes
- empty reason
- dates in the future
Append valid rows to memory/outcomes.jsonl.
Print the appended row.
好的表现是什么样的。 提议的差异是枯燥且可追踪的:更改了一行,附带了一个基于结果的原因,改进了一个评估。
哪里会出问题。 Codex 一次更改了三个权重和两个提示词。现在没人能说清哪个更改起了作用。保持法则的严格性:每个提案只涉及一个概念。
第 6 步:单独改进提示词文件
评分只是系统的一半。消息模板也会衰退。
上个月有效的句子开始让人觉得耳熟。在一个细分市场(segment)中获得回复的问题在另一个细分市场中被忽略。一个在内部感觉很犀利的短语受到了市场的惩罚。将提示词改进作为一个单独的通道,这样 Codex 就不会在同一个 PR 中混合评分和文案(copy)。
创建 config/plays.yaml:
scripts/run_codex_step.sh improve_scoring
然后创建 prompts/improve_prompt.md:
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")/.."
python3 evals/score.py || true
scripts/run_codex_step.sh improve_scoring
python3 evals/score.py
scripts/run_codex_step.sh pr_summary > outputs/pr-summary.md
scripts/open_pr.sh
有些改进可以自动评分。其他改进仍然需要品味。如果没有文案评估,Codex 可以提出提示词编辑,但它应该将 PR 标记为需要审查,而不是假装该编辑已被证明有效。
好的表现是什么样的。 Codex 说:“这个短语出现在七个无回复的结果中,所以我把它添加到了 banned_lines 中”,或者“积极的回复在第一句中引用了实施细节,所以我收紧了策略以要求这样做。”
哪里会出问题。 改进器因为一条消息得到了回复就重写了整个语气(voice)。提示词的编辑应该比你的直觉更小。
第 7 步:将更改作为拉取请求(pull requests)发布
这是控制层。Codex 编辑文件,运行评估,并编写 PR 摘要。人类进行审查和合并。
cases:
- account: Northwind Finance
signals: [competitor_comparison, implementation_page_visit]
expected: human_review
note: "two strong signals on one account"
- account: Bluepeak Studio
signals: [generic_download]
expected: ignore
note: "content-only intent"
- account: KiteOps
signals: [implementation_page_visit]
expected: draft
note: "implementation intent should clear draft threshold"
- account: Atlas Recruiting
signals: [job_repost, student_research]
expected: ignore
note: "bad-fit marker cancels the signal"
创建 prompts/pr_summary.md:
codex-self-improving-outbound/
AGENTS.md
README.md
config/
scoring.yaml
plays.yaml
prompts/
improve_scoring.md
improve_prompt.md
pr_summary.md
memory/
outcomes.jsonl
evals/
fixtures.yaml
score.py
scripts/
append_outcome.py
run_codex_step.sh
propose_improvement.py
open_pr.sh
weekly_tune.sh
examples/
outcomes.sample.jsonl
weekly-pr.md
创建 scripts/open_pr.sh:
Write a pull request summary for this outbound improvement.
Include:
1. What changed.
2. Why it changed, citing outcome rows.
3. Before score.
4. After score.
5. Files changed.
6. Risk.
7. What the human reviewer should check.
Keep it short.
Do not claim the change is live.
PR 读起来应该像是一个队友写的:
score=0.75
changed config/scoring.yaml
implementation_page_visit: 4 -> 6
score=1.00
open PR for human review
这就是安全系统。Codex 完成繁琐的工作。操作员(operator)保持标准。
好的表现是什么样的。 每周一个 PR,差异很小,原因清晰,评估通过。
哪里会出问题。 有人赋予 Codex 合并的权限,因为审查感觉像是一种摩擦。那一分钟区分了一个不断改进的系统和一个随波逐流的系统。
第 8 步:将其置于节奏(cadence)中
不要每次回复后都运行它。那样系统会对一个吵闹的账户产生过拟合。
让这一周过去,让结果积累,然后进行调整(tune)。
plays:
migration_note:
prompt_file: prompts/plays/migration_note.md
use_when:
- competitor_comparison
banned_lines:
- "thought this might be relevant"
- "quick question"
implementation_angle:
prompt_file: prompts/plays/implementation_angle.md
use_when:
- implementation_page_visit
banned_lines:
- "checking out our solution"
- "would love to chat"
创建 scripts/weekly_tune.sh:

然后设置定时任务(cron):

如果你使用 GitHub Actions,保持相同的结构:
# Self-Improving Outbound Rules
You improve an outbound system from outcomes.
Hard rules:
- Never send messages.
- Never scrape or enrich real people.
- Never self-merge.
- Edit only files in this repo.
- Change one concept at a time.
- Cite outcomes from memory/outcomes.jsonl for every proposed change.
- Improve evals/score.py before a change can become a PR.
- If the eval does not improve, revert your edit and stop.
Allowed edits:
- config/scoring.yaml
- config/plays.yaml
- prompts/*.md
Required output:
- changed files
- reason for each change
- before score
- after score
- pull request summary
手动运行前两次调整。阅读每一个差异。观察当样本稀少时 Codex 试图更改什么。一旦提案变得枯燥,就把它放到日程表中。
好的表现是什么样的。 每周出现一个 PR,附带证据、差异和评估结果。你可以合并、编辑或关闭它。
哪里会出问题。 任务运行了,没人审查,PR 堆积如山。一个自我改进的系统仍然需要一个人类习惯:阅读差异。
克隆并运行(clone-and-run)版本
仓库应该附带四个命令:
#!/usr/bin/env bash
set -euo pipefail
branch="codex/weekly-tune-$(date +%Y-%m-%d)"
git checkout -b "$branch"
git add config prompts evals memory
git commit -m "Codex weekly outbound tune"
body="$(cat outputs/pr-summary.md)"
python3 scripts/create_pr.py \
"$branch" \
"Codex weekly outbound tune" \
"$body"
预期的首次运行:
Build evals/score.py.
Read config/scoring.yaml and evals/fixtures.yaml.
For each case:
1. Sum weights for every signal.
2. Add negative signal penalties.
3. Route the account:
- score >= thresholds.human_review => human_review
- score >= thresholds.draft => draft
- otherwise => ignore
4. Compare route to expected.
Print each prediction.
Print final accuracy as score=0.00 to score=1.00.
Exit 0 only when accuracy is 1.00.
离线演示证明了文件契约(file contracts)。Codex 运行证明了编辑循环。之后,用你自己的结果替换样本结果,重命名信号,添加你的策略,并构建一个测试夹具,以反映你希望系统以不同方式路由的账户。
不要从连接交付(delivery)开始。从证明改进循环开始。
完整版本:max
这个仓库是手动层。它从文件、公共信号和你的 Codex 计划中运行。它教授了结构,因为每条规则都是暴露的。
yourmax.ai 是同一个系统,只是隐藏了接缝。
max 不是一个你自己组装的仓库,而是你直接使用的智能体。它检测市场的动向,决定谁值得联系以及为什么是现在,起草跨越电子邮件和 LinkedIn 的拓展信息供你批准,并根据结果不断改进。
该仓库展示了大多数团队从未构建的自我调整层:结果变成提议的规则更改,提议的规则更改通过一个关卡,人类的合并决定了什么会生效。max 采用了相同的操作逻辑,并将其作为一个托管系统(managed system)运行。
如果你想要完整的仓库,可以告诉我,我会发给你。