@nifinet: https://x.com/nifinet/status/2078851409068654639
摘要
一份关于使用Codex构建自我改进外呼系统的指南:AI代理会读取历史结果、编辑评分和策略文件、运行测试,并生成拉取请求供人工审核。其核心理念是将上市策略逻辑视为版本化代码,通过市场反馈持续优化。
查看缓存全文
缓存时间: 2026/07/20 21:32
如何基于 Codex 构建一个自我优化的外呼系统
今年早些时候,Andrej Karpathy(@karpathy)将一个智能体指向了自己的训练代码,并让它运行了两天。它执行了 700 个实验,保留了其中 20 个超过基准的,使模型训练速度提升了 11%。然后他说了一句很有意思的话:任何能够廉价评估的指标,都可以交给智能体集群来处理。回复率就是一个能够廉价评估的指标。
我花了一些时间,琢磨如何将这个循环瞄准外呼场景。我的构建方案是:Codex 读取上周的结果,编辑外呼系统运行时所用的评分和策略文件,运行一次测试,然后发起一个 Pull Request。它会附上证据和得分,提出对规则手册的修改,然后等待人工审批。发送和合并不在循环之内。
我曾经多次搭建过第一个循环:感知市场、对客户评分、根据信号撰写内容、检查消息、记录结果、从回复中学习。本文介绍的是第二个循环,即编辑第一个循环的那个循环。这个构建思路就是:将 GTM(市场推广)视为可版本化的代码,并且它会根据市场反馈不断改进。
Repo(代码仓库)
从文件夹开始。结构很重要,因为 Codex 只能改进它能读取和编辑的内容。
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
这个仓库特意保持简洁。config/scoring.yaml 保存决定哪些信号重要的规则。prompts/ 保存用于撰写消息的策略。memory/outcomes.jsonl 保存市场的反馈。evals/score.py 是一个门控机制,用来判断一个提议的修改是否有效。AGENTS.md 是 Codex 在触碰任何东西之前必须读取的法则。
先在本地离线运行第一个版本。不接入 CRM、不接入数据补充工具、不接入发送系统。改进循环应该先在本地文件上证明自己,然后才能接近真正的外呼机器。
第一步:先写好法则
在编写评分文件、提示文件之前,先写好 AGENTS.md。这个文件能让智能体既有用又受约束。
# 自优化外呼规则
你根据结果来优化外呼系统。
硬性规则:
- 绝不要发送消息。
- 绝不要爬取或补充真实用户数据。
- 绝不要自我合并。
- 只编辑此仓库内的文件。
- 一次只更改一个概念。
- 每个提议的更改都必须引用 memory/outcomes.jsonl 中的结果。
- 在更改成为 PR 之前,必须先改进 evals/score.py。
- 如果评估结果没有提升,撤销你的编辑并停止。
允许的编辑:
- config/scoring.yaml
- config/plays.yaml
- prompts/*.md
必需输出:
- 更改的文件
- 每个更改的理由
- 更改前的得分
- 更改后的得分
- Pull Request 摘要
这条法则只有一个任务:缩小工作范围。没有它,Codex 会试图通过扩大范围来帮忙。它会增加更多数据、触碰更多文件、调用更多工具,或者自动化一个应该由人工把控的步骤。在这里,工作范围更小:读取结果、提出一个文件改动、证明它有效,然后等待。
理想状态: 你在审批 PR 之前可以阅读这条法则,并清楚知道 Codex 被允许做什么。
出错的情况: 法则变成了一纸合规文件。如果 AGENTS.md 需要目录,那就已经太长了。保持它的可操作性。
第二步:将判断逻辑移到配置中
大多数外呼判断逻辑存在于某人的头脑中。然后团队购买软件,却期望软件能改进一个它无法看到的决策。把判断逻辑移到文件中。
signals:
competitor_comparison:
weight: 8
reason: "买家正在比较替代方案"
implementation_page_visit:
weight: 6
reason: "买家正在检查这个方案是否可以安装"
job_repost:
weight: 5
reason: "职位仍然开放且紧急"
funding_event:
weight: 5
reason: "预算或授权可能已发生变化"
generic_download:
weight: 1
reason: "对内容感兴趣,购买意图较弱"
thresholds:
draft: 6
human_review: 10
negative_signals:
student_research: -8
vendor_pitch: -6
competitor: -10
这个文件一开始是一个可见的假设。如果某个通用下载应该计为零分,团队可以指着具体那一行进行修改。如果某个实现页面访问的信号强度超过了你的预期,Codex 可以提出差异并展示支持该观点的结果行。
不要把这套逻辑埋在一个 Python 函数里。如果规则是可见的,团队就可以审阅它、对它提出异议、并在不需要把销售判断变成工程重构的情况下加以改进。
理想状态: 文件足够小,可以进行讨论。五个信号是一个不错的初始版本。
出错的情况: 评分文件变成了一个万能抽屉。二十个信号、六个阈值、以及针对每种边缘情况的例外规则,会让优化器过拟合。从窄处开始,让结果告诉你下一个调节旋钮应该放在哪里。
第三步:将结果作为记忆写入
最重要的文件是 memory/outcomes.jsonl。每次接触对应一行,在结果已知时写入:
{"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 这种细节是可以改变权重的信息。
在构建优化器之前先构建验证器:
构建 scripts/append_outcome.py。它接受:
- date
- account
- signal
- play
- score
- outcome: reply | meeting | no_reply | bad_fit | bounced
- reason
它拒绝:
- 缺失字段
- 未知的 outcome
- 空的 reason
- 未来的日期
将有效的行追加到 memory/outcomes.jsonl。打印追加的行。
这就是复利开始的地方。一个仪表盘可以告诉你一次活动表现不佳。一份干净的结果日志可以告诉 Codex,在下一次运行之前应该更改哪个信号、策略或措辞。
理想状态: 一周后,一个陌生人可以读取这个文件,分辨出哪些信号产生了回复,哪些策略导致了对不匹配客户的对话,以及哪些内部偏爱被市场忽视了。
出错的情况: 团队在周五靠记忆补充结果。成功的案例留存下来,不匹配的原因变得模糊,系统从虚构中学习。在结果确定时立即写入该行。
第四步:构建评估门控
在 Codex 编辑任何东西之前,它需要一个它无法解释过去的测试。
创建 evals/fixtures.yaml:
cases:
- account: Northwind Finance
signals: [competitor_comparison, implementation_page_visit]
expected: human_review
note: "两个强信号出现在同一个客户"
- account: Bluepeak Studio
signals: [generic_download]
expected: ignore
note: "仅内容意图"
- account: KiteOps
signals: [implementation_page_visit]
expected: draft
note: "实施意图应达到草稿阈值"
- account: Atlas Recruiting
signals: [job_repost, student_research]
expected: ignore
note: "不匹配标记抵消了信号"
然后创建 evals/score.py:
构建 evals/score.py。读取 config/scoring.yaml 和 evals/fixtures.yaml。
对于每个案例:
1. 对每个信号求和权重。
2. 加上负面信号惩罚。
3. 路由该客户:
- score >= thresholds.human_review => human_review
- score >= thresholds.draft => draft
- 否则 => ignore
4. 比较路由结果与预期。
打印每个预测。
以 score=0.00 到 score=1.00 的格式打印最终准确率。
只有当准确率为 1.00 时才以 0 退出。
第一个门控应该足够小以便理解,足够敏锐以便捕捉真正的失误。在我的第一次运行中,基线有一个案例失败了:
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
这很好。系统的实现意图低于草稿阈值,因此它忽略了一个测试用例认为应该收到消息的客户。最好在测试中捕获这一点,而不是在一个月后错失客户时才意识到。
理想状态: 一个命令返回一个数字,每个失败的案例都能轻松审查。
出错的情况: 测试用例只包含明显的成功案例。然后任何鲁莽的更改都能通过。把难处理的案例也纳入门控:弱意图、不匹配、无回复、过时信号,以及你希望系统跳过的那些客户。
第五步:让 Codex 提出一个评分修改
现在 Codex 可以编辑了。创建 prompts/improve_scoring.md:
你改进外呼评分系统。
读取:
- AGENTS.md
- config/scoring.yaml
- memory/outcomes.jsonl
- evals/fixtures.yaml
你的工作:
1. 找到一个应该更改的评分规则。
2. 理由必须引用 memory/outcomes.jsonl。
3. 只更改 config/scoring.yaml。
4. 运行 python3 evals/score.py。
5. 如果评分提高,保留更改。
6. 如果评分持平或下降,撤销你的更改并停止。
输出:
- 更改的具体行
- 导致更改的结果行
- 更改前的评分
- 更改后的评分
- 该更改是否应该成为 PR
不要编辑 prompts。不要添加新信号。不要触碰发送流程。
通过仓库包装器运行它:
scripts/run_codex_step.sh improve_scoring
我的第一个优化器版本犯了一个有用的错误。它追逐了看起来最干净的回复信号。在小小的结果日志中,competitor_comparison 的回复率最高,所以优化器想增加它的权重。评估结果仍然是 0.75,因此更改被拒绝。这正是门控存在的原因。一个较弱系统会接受这个说法,因为它听起来合理。但这个系统提出了一个更好的问题:这个更改是否修复了已知的失误?
第二次尝试找到了最小且有效的编辑:
- implementation_page_visit: 4
+ implementation_page_visit: 6
评估通过了:
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
这就是循环变得有用的时刻。它更改了一条规则,一个理由,并针对测试用例证明了更改的有效性。
理想状态: 提出的差异是无聊且可追溯的:一行更改,一个基于结果的理由,一个评估的改进。
出错的情况: Codex 同时更改了三个权重和两个提示。现在没人能分辨哪个更改起了作用。保持法则严格:每个提议只改一个概念。
第六步:单独改进提示文件
评分只是系统的一半。消息模板也会衰退。上个月有效的措辞,这个月开始听起来千篇一律。在一个细分市场获得回复的问题,在另一个细分市场却被忽视。内部觉得尖锐的短语,在市场上却受到惩罚。
将提示改进视为一个独立通道,这样 Codex 就不会在同一 PR 中混合评分和文案。
创建 config/plays.yaml:
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"
然后创建 prompts/improve_prompt.md:
你改进一个外呼策略。
读取:
- AGENTS.md
- config/plays.yaml
- memory/outcomes.jsonl
- 所选策略的提示文件
选择一个至少有 10 个结果的策略。找出:
- 在积极结果中出现的行或结构
- 在 no_reply 或 bad_fit 结果中出现的行或结构
- 任何应该被禁止的短语
对该策略的提示做一次小编辑。
规则:
- 不要更改评分。
- 不要创建新策略。
- 不要添加新渠道。
- 引用结果行。
- 写出修改前后的指令。
然后如果有文案评估,则运行它。如果不存在文案评估,则打开一个标记为 review_required 的 PR。
有些改进可以自动评分。其他改进仍然需要品味。如果没有文案评估,Codex 可以提出提示编辑,但它应该将 PR 标记为待审查,而不是假装该编辑已被证实。
理想状态: Codex 说:“这个短语出现在七个无回复结果中,所以我把它加到了 banned_lines”,或者“积极回复引用了第一句中的实现细节,所以我加强了这个策略,要求必须包含那个细节。”
出错的情况: 因为一次消息获得回复,优化器就重写了整个语气。提示的编辑应该比你直觉认为的更小。
第七步:通过 Pull Request 交付更改
这是控制层。Codex 编辑文件,运行评估,编写 PR 摘要。由人工审查并合并。
创建 prompts/pr_summary.md:
为这个外呼改进编写一个 Pull Request 摘要。包括:
1. 什么更改了。
2. 为什么更改,引用结果行。
3. 更改前的评分。
4. 更改后的评分。
5. 更改的文件。
6. 风险。
7. 审查者应该检查什么。
保持简短。不要说该更改已经上线。
创建 scripts/open_pr.sh:
#!/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"
PR 应该读起来像是一个队友写的:
更改:
- 将 implementation_page_visit 从 4 提高到 6。
原因:
- KiteOps 有实现页面的意图,并回复了实现时间线。
- 之前的评分将该客户路由到了“忽略”。
更改前:
- 评估评分 0.75
更改后:
- 评估评分 1.00
审查者检查:
- 确保实现意图足够具体。
- 保持通用下载的权重较低。
- 仅当与实际的销售判断一致时才合并。
这就是安全系统。Codex 完成繁琐的工作。操作者保持标准。
理想状态: 每周一个 PR,差异小,理由清楚,评估通过。
出错的情况: 有人因为审查感觉像阻力而给了 Codex 合并权限。那一分钟就区分了改进系统和漂移系统。
第八步:设定周期
不要每次回复后都运行。那样会导致系统对某个大嗓门客户过度拟合。让一周过去,让结果累积,然后进行调优。
创建 scripts/weekly_tune.sh:
#!/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
然后 cron:
0 8 * * MON cd ~/codex-self-improving-outbound && scripts/weekly_tune.sh
如果使用 GitHub Actions,保持同样的结构:
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 在样本量较少时试图更改什么。一旦提议变得无聊,就将其放在计划任务上。
理想状态: 每周出现一个 PR,附有证据、差异和评估结果。你合并、编辑或关闭它。
出错的情况: 任务运行,无人审查,PR 堆积。一个自我优化的系统仍然只有一个人类把关。
相似文章
@nifinet: https://x.com/nifinet/status/2066933179169329303
一份关于在2026年构建基于信号的销售分发外呼引擎的详细指南,包含六个阶段和可复制提示,用于利用AI自动化潜在客户开发。
@nifinet: https://x.com/nifinet/status/2064397495036440907
一份关于使用Claude Code构建AI驱动的GTM(上市策略)大脑的详细指南,涵盖五个核心组成部分——Sense、Remember、Judge、Act、Learn——以实现有判断力的基于客户的主动 outreach,而不仅仅是数量。
@jxnlco: https://x.com/jxnlco/status/2057153744630890620
这个推文串讨论了使用Codex编码代理的最佳实践,重点包括持久线程、语音输入、引导、队列,以及其从代码生成扩展到完整计算机工作流程自动化的能力。
@ChrisHayduk: https://x.com/ChrisHayduk/status/2053807198870880743
本文提供了有效使用 OpenAI Codex Goals 功能的建议,强调了制定清晰、可量化的目标以及建立紧密反馈循环的重要性,以防止智能体出现失效模式。
@PaulSolt: https://x.com/PaulSolt/status/2073470146115490230
Paul Solt 分享了一个详细的工作流程,利用 Codex 智能体循环实现夜间自主构建功能,包括管理线程、心跳检测和自动 PR 审查。该技术从单次提示转向设计好的智能体循环,使得只需极少的人工干预即可实现持续开发。