如果你还在把 Codex 当成“高级版 Copilot”,只用它补几个函数、写两段单元测试,那这篇文章可能会颠覆你的认知。真实开发场景里,AI 编程 Agent 早已能独立撑起一个完整的数据分析工程:从数据探索、清洗、建模,到生成可交互报告,再到记录每一条数据血缘,全程不是“人写代码、AI 补全”,而是“人定目标、AI 执行、人做验收”。
这次要讲的是一场完整实战:用 DeepSeek(项目代号按标题写作 DeepSeek V4)作为推理引擎,接入 OpenAI 的 Codex CLI 命令行编程代理,通过 40 轮提示词迭代,完成一个面向 300 万行数据的分析 Agent 项目,并做到数据可追溯、报告可迭代、最终形成能写进简历的工程交付物。
先说结论:这个组合能跑通的关键,不在于“哪个模型更强”,而在于你有没有把任务拆解、上下文控制、数据血缘和交付验证做成一套工程机制。否则,别说 300 万行,3 万行数据就能让 Agent 在幻觉里打转。
读完后,你会得到一套可以直接照搬的接入配置、40 轮提示词的拆分思路、一个最小可运行的数据分析 Agent 示例,以及常见报错的排查方法。
1. 为什么是 DeepSeek + Codex,而不是继续手写脚本
先回应一个最直接的问题:数据分析项目,用 Pandas 手写不就行了?为什么要引入 Agent?
300 万行的数据集,放在真实业务里意味着什么?它意味着表结构不一致、字段命名混乱、缺失值和异常值分布复杂,还意味着分析结论必须能回溯到原始数据。这些工作如果全靠脚本手工堆,开发周期通常以“周”为单位,而且每一轮需求变化都可能让代码大面积返工。
引入 Codex CLI 之后,变化的不是“写代码”这个动作,而是整个交付流程:
- 模型负责把自然语言需求翻译成可执行的管道代码。
- Codex CLI 负责在真实文件系统里创建项目、修改文件、运行命令、读取错误并自修复。
- DeepSeek 负责在高密度推理场景下提供稳定的代码生成和中文理解能力。
- 人负责定义目标、拆解里程碑、审查输出和验收结果。
也就是说,传统开发中“需求—设计—编码—测试—交付”里的“编码与基础测试”环节,开始被 Agent 自动化。人从执行者变成验收者。
从模型选择上看,DeepSeek 系列模型在中文场景、代码生成、逻辑推理和 API 性价比上有明显优势。Codex CLI 官方默认绑定 OpenAI 模型,但它的 Provider 机制允许接入兼容 OpenAI 协议的第三方模型。DeepSeek 的 API 恰好是 OpenAI 兼容协议,这就让“DeepSeek 负责推理,Codex 负责干活”成为一套可行组合。
这个组合真正降低的开发成本,不是“少写了几行代码”,而是“减少了大规模重复性编码和低级错误排查”。对个人开发者来说,这意味着一个人可以完成过去一个小组才能交付的数据分析项目。
2. 基础概念:先把四个关键词讲透
在实操之前,需要先统一四个基础概念:DeepSeek、Codex CLI、数据分析 Agent、提示词工程。很多初学者把它们混为一谈,导致后面配置和排错时思路混乱。
2.1 DeepSeek 是什么
DeepSeek 是深度求索公司推出的开源大语言模型系列,以强推理能力、长上下文理解和友好的中文表现为重点。项目标题中的“DeepSeek V4”可以理解为该系列的新一代模型代号,具体型号名称以你实际使用的 API 文档为准。
在本文的架构中,DeepSeek 扮演的是“大脑”角色:它负责理解需求、生成代码、分析错误、推断下一步操作。它不直接操作文件系统,而是把决策交给 Codex CLI 去执行。
2.2 Codex CLI 是什么
Codex CLI 是 OpenAI 推出的命令行编程代理工具。和传统代码补全工具不同,Codex CLI 的工作方式是:
- 你通过终端给它下达任务。
- 它自主读取项目文件、生成或修改代码。
- 它执行命令,观察运行结果。
- 遇到报错时,它读取错误信息并尝试自主修复。
- 它会把整个操作记录在会话里。
用一个比喻理解:传统 AI 编程助手像一个“输入法”,你敲一句它补一句;Codex CLI 像一个“外包开发”,你给它一个任务列表,它在你的电脑上自己写代码、跑测试、修 bug。
2.3 数据分析 Agent 是什么
数据分析 Agent 不是单一的某个文件,而是一套自动化系统。它能接收原始数据,自动执行清洗、转换、统计分析、可视化,并生成报告。关键点在于“自动”和“可追踪”。
本文要做的数据分析 Agent,至少要满足三个条件:
- 输入是原始数据文件。
- 输出是分析报告和数据血缘记录。
- 中间每一步都由代码驱动,并且可重复运行。
这正是 Agent 和普通脚本的根本区别:脚本只能按既定路径执行,Agent 可以在目标指导下自我调整路径。
2.4 提示词工程是什么
提示词工程不是“写一句玄学咒语”,而是设计一套清晰、结构化的指令序列,让模型在正确的约束下完成复杂任务。
很多人误以为提示词工程就是学会几种 Prompt 模板。实际上,在 Agent 场景里,提示词工程的核心是:
- 目标描述:告诉 Agent 要交付什么。
- 约束条件:告诉 Agent 哪些不能做。
- 上下文管理:每轮对话中传递给模型的任务背景、文件内容、错误信息。
- 验收标准:告诉 Agent 做到什么程度算完成。
下面这张表可以帮你看清传统方式和 Agent 方式的差异:
| 维度 | 传统脚本开发 | DeepSeek + Codex 数据分析 Agent |
|---|---|---|
| 需求到代码 | 人手写 SQL/Python | 自然语言生成代码 |
| 文件操作 | 手动创建、编辑 | Agent 自动读写 |
| 错误处理 | 人看日志、打补丁 | Agent 读取报错并修复 |
| 数据追踪 | 常被忽略 | 内置 lineage 记录 |
| 报告迭代 | 每次手动改模板 | 提示词驱动改写模板 |
3. 环境准备与前置条件
动手之前,先把环境准备好。本文演示以 Linux/macOS 环境为主,Windows 用户建议使用 WSL2。
3.1 安装基础工具
需要准备以下环境:
- Node.js 16 或更高版本,用于安装 Codex CLI。
- Python 3.10 或更高版本,用于数据分析项目。
- Git,用于版本管理和提示词备份。
- DeepSeek API Key,用于模型推理调用。
Codex CLI 的安装方式以官方文档为准,常见方式是通过 npm 全局安装:
npm install -g @openai/codex安装结束后,运行以下命令确认安装成功:
codex --version如果你看到版本号输出,说明 Codex CLI 已经进入 PATH。如果提示command not found,通常是 npm 全局安装目录没有加入 PATH,需要把 npm 的 global bin 目录配置到环境变量中。
3.2 创建项目目录
在开始接入模型之前,先创建一个独立的项目目录,避免和已有项目混淆。
mkdir -p ~/projects/data-agent-demo cd ~/projects/data-agent-demo git init mkdir -p data/raw data/processed config pipeline output/reports output/lineage prompts这个目录结构会贯穿全文,后面所有代码和配置都基于它。
3.3 准备 Python 依赖
创建requirements.txt:
pandas numpy jinja2 matplotlib安装依赖:
pip install -r requirements.txt如果不在虚拟环境中,建议先创建虚拟环境:
python -m venv .venv source .venv/bin/activate4. 将 DeepSeek 接入 Codex CLI
Codex CLI 本身设计为 OpenAI 模型服务,但它提供了模型 Provider 的扩展机制。DeepSeek API 兼容 OpenAI 的接口协议,所以可以通过自定义 Provider 的方式接入。
本文的配置基于 Codex CLI 的 TOML 配置文件,默认路径是~/.codex/config.toml。实际配置项因 Codex CLI 版本而异,如果版本差别较大,请以官方文档和codex --help输出为准。
4.1 配置模型 Provider
修改~/.codex/config.toml:
model = "deepseek-chat" model_provider = "deepseek" [model_providers.deepseek] name = "DeepSeek" base_url = "https://api.deepseek.com/v1" env_key = "DEEPSEEK_API_KEY"这里的关键配置项有三个:
base_url:DeepSeek API 的兼容地址。env_key:指定 Codex CLI 从哪个环境变量读取 API Key。model:指定默认模型。不同版本期的 DeepSeek 模型名可能不同,请以 DeepSeek API 文档列举的模型名为准。如果 API 提供了 V4 对应的独立模型名,建议直接替换为具体名称。
4.2 配置环境变量
在~/.bashrc或~/.zshrc中增加:
export DEEPSEEK_API_KEY="你的DeepSeek_API_Key"然后让配置生效:
source ~/.bashrc4.3 验证连接
用一条最简单的指令验证模型是否接通:
codex exec "请输出一句话,说明当前你使用的模型是什么"如果返回结果里出现了 DeepSeek 相关模型的表述,说明接入成功。如果提示 401 或认证失败,优先检查环境变量是否已加载:
echo $DEEPSEEK_API_KEY这里容易踩的坑是:Codex CLI 启动时可能还会要求 OpenAI 账号登录或 API Key 配置,具体取决于版本。如果遇到强制认证,请先完成 Codex CLI 的基础登录,再切换到第三方 Provider。
另外,如果你的网络环境需要自定义代理才能访问外部 API,可以设置HTTP_PROXY和HTTPS_PROXY环境变量,但请注意使用合规的网络通道,并确保代理服务本身稳定。否则很容易出现类似cc switch local proxy failed while handling codex endpoint /responses的代理错误。
5. 40 轮提示词怎么拆:从需求到交付的完整路线
现在到了整篇文章的核心认知:40 轮提示词不是“40 次随机聊天”,而是一个有目的、有验证、有迭代的任务闭环。
下面是我推荐的拆分方式,你可以直接套用到自己的项目里。
| 阶段 | 对应轮次 | 目标 | 关键动作 |
|---|---|---|---|
| 需求澄清与数据探索 | 第 1-5 轮 | 摸清数据、定义验收标准 | 让 Agent 只读数据不写代码 |
| 管道骨架搭建 | 第 6-10 轮 | 建立 load/clean/transform/report 结构 | 定好接口和配置文件 |
| 核心分析逻辑 | 第 11-18 轮 | 实现统计口径和业务指标 | 逐项验证计算逻辑 |
| 报告与可视化 | 第 19-25 轮 | 生成 HTML 报告 | 用模板驱动,支持参数化 |
| 可追溯性 | 第 26-32 轮 | 记录数据血缘和运行日志 | 每次运行输出 lineage JSON |
| 测试与边界场景 | 第 33-38 轮 | 补单元测试,处理异常数据 | 覆盖空值、类型、重复数据 |
| 收尾与交付 | 第 39-40 轮 | 整理 README、运行说明、清理工程 | 让项目具备可交付性 |
5.1 第 1-5 轮:不让 Agent 写代码,先让它“看懂”数据
很多开发者犯的第一个错误,是让 Agent 一上来就写处理逻辑。但 300 万行数据里可能藏着各种脏数据,如果模型不了解数据分布,写出来的清洗规则就是空中楼阁。
第 1 轮提示词示例:
我们有一个订单数据文件 data/raw/orders.csv,大约 300 万行。 请先不要写任何代码,只读取文件前 1000 行做预分析。 输出以下内容: 1. 字段名和数据类型 2. 每列缺失值比例 3. 可能的异常值 4. 你希望向用户确认的最重要的 3 个业务口径问题这一轮的目的是让 Agent 进入“数据分析师”角色,而不是“代码生成器”角色。后续几轮围绕业务口径继续澄清,直到你确认 Agent 理解了字段含义。
5.2 第 6-10 轮:先搭骨架,再填肉
很多 Agent 项目做砸,是因为提示词第一轮就让模型生成完整项目。模型确实生成了 1000 行代码,但结构混乱、职责不清,后面一改需求就崩。
正确做法是让 Agent 先生成模块骨架:
请创建项目骨架,包含以下模块: - pipeline/load.py:读取数据并输出血缘信息 - pipeline/clean.py:加载清洗规则并执行清洗 - pipeline/transform.py:完成聚合统计 - pipeline/report.py:生成 HTML 报告 - main.py:主入口,串联全流程 每个模块先写清楚函数签名和 TODO 注释,不要实现细节。这一步的目的是约定接口。后续每一轮提示词只需要描述“改某个函数”,而不是让模型重新理解整个项目。
5.3 第 11-18 轮:聚焦核心分析逻辑
骨架搭好后,进入核心逻辑实现阶段。这里的关键是“一次只改一个模块”。
例如第 11 轮:
在 pipeline/transform.py 中实现 aggregate_sales 函数: - 按 order_date 的月份分组 - 计算订单金额 sum、订单数 count、客单价 mean - 结果保留三列:month、total_amount、order_count - 返回 DataFrame,并在函数内部打印每步耗时这一阶段的每一轮都要有明确的输入和输出,并且让 Agent 运行自己的代码,把结果贴回来。输出不符合预期时,直接基于结果继续追问,而不是重新写提示词。
5.4 第 19-25 轮:让报告可以迭代
数据分析项目最后总要出报告。如果报告是硬编码的 HTML,那么每改一次图表都要改代码。更好的方式是让报告模板支持参数化。
提示词示例:
请用 Jinja2 生成销售报告模板 output/reports/sales_report.html。 模板需要支持以下参数: - title:报告标题 - summary_stats:dict,包含总订单数、总金额、客单价 - monthly_table:DataFrame,转成 HTML 表格 - chart_path:图片保存路径 模板样式使用深色标题栏 + 简洁表格,不引用外网 CDN。5.5 第 26-32 轮:给项目装上“黑匣子”
“数据可追溯”是这个项目的重要交付特点。实现方式很直接:每一步数据处理都记录数据源、行数、列名、时间戳和规则版本,最后统一输出为 lineage JSON。
提示词示例:
在 pipeline 的每个模块中增加 lineage 记录: - load_csv 返回 (df, lineage_dict) - clean_data 返回 (df, clean_lineage) - aggregate_sales 返回 (result, transform_lineage) - main.py 把三个 lineage 合并后,保存到 output/lineage/run_lineage.json lineage JSON 必须包含: - source_file:原始文件绝对路径 - rows_before 和 rows_after - columns - executed_at - 每一步的代码版本(可以用 git commit hash)这样做的意义在于:任何一份分析报告都能回溯到原始数据和清洗过程,这在真实业务里是审计和数据团队协作的基础能力。
5.6 第 33-38 轮:补测试,处理边界
数据分析 Agent 最容易翻车的地方是异常数据,比如重复订单、空值、类型错乱。这阶段的提示词要引导 Agent 写测试:
请为 pipeline/clean.py 编写 pytest 测试: 1. 测试重复订单去重逻辑 2. 测试空值填充逻辑 3. 测试金额字段类型转换 4. 测试输入为空 DataFrame 时不抛异常 测试数据不要依赖外部文件,直接用构造的 DataFrame。5.7 第 39-40 轮:交付前清理
最后两轮做交付。让 Agent 写 README、检查依赖、确认目录结构。
提示词示例:
请生成 README.md,包含: - 项目简介和目标 - 环境依赖和安装方式 - 运行方式:python main.py - 输出说明:报告和 lineage 文件在哪个目录 - 常见问题:内存不足、API Key 未设置等 同时检查 requirements.txt 是否完整,不删除任何已实现功能。到这里,40 轮提示词全部完成。你会发现,真正有价值的不是“提示词的数量”,而是每一轮之间的验证和迭代。
6. 完整示例:一个最小可用的数据分析 Agent
为了让上面的方法论落地,这里给出一个最小可运行示例。示例不处理 300 万数据,但结构和真实项目完全一致。
6.1 项目结构
data-agent-demo/ ├── config/ │ └── cleaning_rules.yaml ├── data/ │ └── raw/ │ └── orders.csv ├── pipeline/ │ ├── __init__.py │ ├── load.py │ ├── clean.py │ ├── transform.py │ └── report.py ├── output/ │ ├── reports/ │ └── lineage/ ├── main.py └── requirements.txt6.2 加载模块:记录数据血缘
pipeline/load.py:
import pandas as pd from pathlib import Path from datetime import datetime, timezone def load_csv(path: str, sample: int = None): path = Path(path) df = pd.read_csv(path, nrows=sample) lineage = { "source_file": str(path.resolve()), "rows": len(df), "columns": df.columns.tolist(), "loaded_at": datetime.now(timezone.utc).isoformat(), } return df, lineage这个模块的核心是:读数据的同时,把来源、行数、列名、加载时间记录到 lineage 字典里。后续任何一步出问题,都可以通过 lineage 定位原始数据。
6.3 清洗规则配置
config/cleaning_rules.yaml:
rules: drop_duplicates: subset: ["order_id"] keep: first fill_missing: amount: 0 status: "unknown" type_cast: amount: float order_date: "datetime64[ns]"把清洗规则放到配置文件里,而不是写死在代码中,是让数据分析 Agent 具备可维护性的关键设计。以后业务口径变化,只需要改 YAML,不需要改 Python 代码。
6.4 清洗模块
pipeline/clean.py:
import pandas as pd import yaml def _apply_cleaning_rules(df: pd.DataFrame, rules: dict) -> pd.DataFrame: if "drop_duplicates" in rules: dup = rules["drop_duplicates"] df = df.drop_duplicates( subset=dup["subset"], keep=dup["keep"], ) if "fill_missing" in rules: fill_map = rules["fill_missing"] df = df.fillna(fill_map) if "type_cast" in rules: cast_map = rules["type_cast"] for col, dtype in cast_map.items(): if col in df.columns: df[col] = df[col].astype(dtype) return df def clean_data(df: pd.DataFrame, rules_path: str): with open(rules_path, "r", encoding="utf-8") as f: config = yaml.safe_load(f) rules = config.get("rules", {}) rows_before = len(df) df_clean = _apply_cleaning_rules(df, rules) lineage = { "rules_file": rules_path, "rows_before": rows_before, "rows_after": len(df_clean), "cleaned_at": pd.Timestamp.utcnow().isoformat(), } return df_clean, lineage注意fillna的用法:当列的类型是字符串时,用0填充可能会引发类型问题,实际项目中建议先统一转换类型再填充。这里保留了基本演示结构。
6.5 聚合统计模块
pipeline/transform.py:
import pandas as pd def aggregate_sales(df: pd.DataFrame) -> pd.DataFrame: df["month"] = df["order_date"].dt.to_period("M").astype(str) result = ( df.groupby("month") .agg( total_amount=("amount", "sum"), order_count=("order_id", "count"), avg_amount=("amount", "mean"), ) .reset_index() ) lineage = { "group_by": ["month"], "metrics": ["total_amount", "order_count", "avg_amount"], "transformed_at": pd.Timestamp.utcnow().isoformat(), } return result, lineage6.6 报告生成模块
pipeline/report.py:
from jinja2 import Environment, FileSystemLoader from pathlib import Path REPORT_TEMPLATE = """ <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>{{ title }}</title> <style> body { font-family: sans-serif; margin: 40px; } h1 { color: #1a1a2e; } table { border-collapse: collapse; width: 100%; margin-top: 20px; } th, td { border: 1px solid #ddd; padding: 8px; text-align: right; } th { background-color: #16213e; color: white; } </style> </head> <body> <h1>{{ title }}</h1> <h2>核心指标</h2> <p>总订单数:{{ summary_stats.order_count }}</p> <p>总金额:{{ summary_stats.total_amount }}</p> <p>客单价:{{ summary_stats.avg_amount }}</p> <h2>月度明细</h2> {{ monthly_table }} </body> </html> """ def generate_html_report(result: pd.DataFrame, output_path: str, title: str = "销售分析报告"): summary_stats = { "order_count": int(result["order_count"].sum()), "total_amount": float(result["total_amount"].sum()), "avg_amount": float(result["amount"].mean()) if "amount" in result.columns else 0, } env = Environment() template = env.from_string(REPORT_TEMPLATE) html = template.render( title=title, summary_stats=summary_stats, monthly_table=result.to_html(index=False), ) Path(output_path).parent.mkdir(parents=True, exist_ok=True) with open(output_path, "w", encoding="utf-8") as f: f.write(html)这个模块把数据渲染成独立的 HTML 报告,样式内嵌,不依赖外网资源,方便离线查看和分享。
6.7 主流程
main.py:
import json from pipeline.load import load_csv from pipeline.clean import clean_data from pipeline.transform import aggregate_sales from pipeline.report import generate_html_report def main(): df, load_lineage = load_csv("data/raw/orders.csv") df_clean, clean_lineage = clean_data(df, "config/cleaning_rules.yaml") result, transform_lineage = aggregate_sales(df_clean) generate_html_report(result, "output/reports/sales_report.html") full_lineage = { "load": load_lineage, "clean": clean_lineage, "transform": transform_lineage, } with open("output/lineage/run_lineage.json", "w", encoding="utf-8") as f: json.dump(full_lineage, f, ensure_ascii=False, indent=2) print("分析完成,报告已生成:output/reports/sales_report.html") print("血缘信息已保存:output/lineage/run_lineage.json") if __name__ == "__main__": main()主流程只做四件事:加载、清洗、聚合、报告。每一步都记录 lineage,最后统一输出。
6.8 使用 Codex 运行项目
现在你已经有了一个最小项目,可以用 Codex 来运行并让它调试:
codex exec "python main.py 报错了,请先看报错信息,修复后重新运行,并确认输出文件生成"如果一切正常,Codex 会读取错误、修改代码、重复运行,直到输出文件出现。
7. 运行结果与效果验证
在项目根目录运行:
python main.py预期输出:
分析完成,报告已生成:output/reports/sales_report.html 血缘信息已保存:output/lineage/run_lineage.json然后检查两个关键文件。
output/lineage/run_lineage.json内容类似:
{ "load": { "source_file": "/Users/you/data-agent-demo/data/raw/orders.csv", "rows": 3000000, "columns": ["order_id", "order_date", "amount", "status"], "loaded_at": "2025-01-01T12:00:00+00:00" }, "clean": { "rules_file": "config/cleaning_rules.yaml", "rows_before": 3000000, "rows_after": 2995000, "cleaned_at": "2025-01-01T12:00:01+00:00" }, "transform": { "group_by": ["month"], "metrics": ["total_amount", "order_count", "avg_amount"], "transformed_at": "2025-01-01T12:00:03+00:00" } }判断成功标准:
rows_after不等于rows_before时,说明清洗规则生效。report.html可以正常打开,且表格和数字显示正常。- lineage JSON 中每个阶段的时间戳是递增的。
如果rows_after和rows_before完全一致,大概率是清洗规则没有匹配到数据,需要检查cleaning_rules.yaml中的字段名是否和数据表一致。
8. 常见问题与排查思路
基于 Codex CLI 接入 DeepSeek、以及数据处理过程中最常见的报错,我整理了一份排查表。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
unable to locate the codex cli binary | Codex CLI 未安装或不在 PATH | 执行codex --version确认 | 重新安装 Codex CLI,并确保 npm 全局路径已加入 PATH |
| Codex 调用模型返回 401 | API Key 未设置或设置错误 | echo $DEEPSEEK_API_KEY确认变量是否存在 | 重新配置环境变量,并检查 API Key 是否有效 |
| Codex 提示当前模型不受支持 | model配置名与 API 实际模型名不匹配 | 查看 DeepSeek API 文档 | 将config.toml中的model改为实际支持的模型名 |
cc switch local proxy failed while handling codex endpoint /responses | 代理环境变量冲突或代理服务不稳定 | 检查HTTP_PROXY、HTTPS_PROXY环境变量 | 根据不同网络环境设置合规代理,或临时移除代理变量后重试 |
| Pandas 读取 300 万行时内存溢出 | 内存不足或 read_csv 一次性加载全量数据 | 查看系统内存;用top或htop监控 | 使用pd.read_csv(..., chunksize=100000)分块读取;或把中间结果存为 Parquet 格式 |
| 清洗后行数没变化 | 清洗规则字段名与数据不匹配 | 打印df.columns和rules对比 | 统一字段命名,确认 YAML 中字段大小写与数据一致 |
order_date类型转换失败 | 日期格式不统一或存在非法日期 | 打印异常值样本 | 先做日期解析标准化,再执行astype |
这里重点说下第一个问题。unable to locate the codex cli binary. set codex cli path or ensure the elec...是常见的 Codex 启动错误,通常出现在 Codex CLI 没有正确安装,或者 IDE/其他工具找不到可执行文件时。排查路径很简单:先确认codex命令在终端中可用,再把 Codex 可执行文件路径添加到调用方配置中。不需要卸载重装,通常是 PATH 问题。
9. 最佳实践与工程建议
到这里,项目已经跑通了。但“能跑”和“能写进简历”之间,还有一段距离。下面的工程建议能让项目真正具备交付质量。
9.1 提示词也是一种代码,要纳入版本管理
把 40 轮提示词按编号保存到prompts/目录,每个阶段一个 Markdown 文件。例如prompts/01-data-discovery.md、prompts/06-pipeline-skeleton.md。
这样做有两个好处:
- 提示词修改时可追溯,不会出现“上次那版能跑,改完就废了”的情况。
- 项目交付时,提示词本身就是技术文档,面试官能看到你是如何一步步构建 Agent 的。
推荐在 Git 提交信息里标注对应的提示词阶段:
git add prompts/ pipeline/ config/ git commit -m "feat: 完成第 6-10 轮,搭建数据管道骨架"9.2 用 lineage 审计数据流向
数据分析项目最怕“结果没法解释”。这个项目里,每一份 report 都对应一份run_lineage.json。建议每次运行后生成带时间戳的报告目录:
output/reports/20250101_1200/ output/lineage/20250101_1200.json这样一份报告对应一份血缘数据,审阅者可以追溯到原始文件、清洗规则和计算逻辑。
9.3 API Key 永远不写进仓库
.gitignore中必须包含.env和.venv:
.env .venv/ output/ __pycache__/同时,把 DeepSeek API Key 放在环境变量里,而不是写进config.toml或代码。即使config.toml是本地配置,也要防止误提交到 Git。
9.4 异常处理要覆盖“坏数据”,而不是只覆盖“坏代码”
数据分析 Agent 容易忽略数据层面的异常。实际项目中,建议在清洗阶段至少处理四类问题:
- 重复记录。
- 缺失值。
- 类型错乱。
- 超出业务边界的异常值。
每条规则都需要有测试覆盖。性能优化上,300 万行数据不要反复copy()和循环,优先使用 Pandas 的向量化操作。
9.5 简历描述推荐用“问题-动作-结果”结构
如果要把这个项目写进简历,不建议只写“使用 DeepSeek 和 Codex 做了一个数据分析 Agent”。更好的表述是:
基于 DeepSeek V4 与 Codex CLI 构建数据分析 Agent,覆盖 300 万行订单数据的清洗、聚合与报告生成;通过 40 轮提示词迭代完成需求澄清、管道搭建、血统记录与测试交付;输出 HTML 报告与 lineage 追踪文件,实现数据可审计、报告可迭代。
这里的关键是量化数据规模、明确工具链、点出工程能力(血统、追踪、测试、交付)。
9.6 善用 Codex 的多文件修改能力
Codex CLI 最大的价值在于“多文件协作”。用它重构模块时,提示词可以这样写:
在 pipeline/clean.py 中新增 fill_status 函数,并在 main.py 的 clean_data 调用链中接入;同时更新 config/cleaning_rules.yaml 增加 status 字段的默认值映射。这种提示词要求 Agent 同时修改多个文件,并保持调用链完整,比单文件补全更能体现 Agent 的生产力。
10. 总结与后续学习方向
这场实战真正的收获,不是“DeepSeek 接上了 Codex”,而是暴露了 Agent 工程化的一条关键路径:先用小样本探索数据,再约定接口,再分阶段填充实现,最后用血缘机制把整个流程串起来。没有这些约束,模型生成的代码越多,项目崩得越快。
接下来你可以继续往三个方向深入:
第一,把 Agent 接入调度系统,比如通过 cron 或 Airflow 定时运行分析任务,让报告每天自动更新。
第二,扩展数据源。把 CSV 换成数据库、Parquet 或 API 数据流,lineage 记录也要随之扩展。
第三,完善报告交互。在 HTML 报告里接入 ECharts 等图表库,让报告从静态表格升级为可探索的数据视图。
如果你手头正好有一个数据量较大、口径复杂、需要反复迭代的分析项目,不妨按照本文的 40 轮拆分思路重新做一遍。方式,不再只是“写代码”,而是“设计任务、验证结果、守住工程质量”——这才是我建议你把这个项目写进简历的真正原因。