上周把一批客户资料从散乱的 Excel 和邮件附件里整理成结构化表格,本来想手动做,后来想起 DeepSeek 官方博客说 V4-Flash 刚出的正式版在 Agent 基准上把自家 Pro 都比下去了,就干脆用它写了个小脚本,让模型自己调工具把这活干了。跑下来的结论是:接口没变复杂,但有几个参数不摸清楚很容易多花钱。
DeepSeek-V4-Flash-0731 是 2026 年 7 月 31 日转正的版本,之前一直是 preview 状态。这篇教程按我实际跑通的那个任务,把 Agent 模式该怎么配讲一遍。
V4-Flash-0731 到底改了什么
先说清楚这次更新的性质,免得抱错预期。DeepSeek 官方在发布说明里写得很直接:这次只重跑了后训练,没有换新的基座模型,改动集中在"对齐和 Agent 行为",直接影响的是工具调用的风格和拒答倾向。
九个官方公布的 Agent 基准里,V4-Flash-0731 全面超过了同门更贵的 V4-Pro-Preview:
| 基准 | V4-Flash-0731 得分 |
|---|---|
| Terminal Bench 2.1 | 82.7 |
| Cybergym | 76.7 |
| Toolathlon (verified) | 70.3 |
| DSBench-FullStack | 68.7 |
| DSBench-Hard | 59.6 |
| DeepSWE | 54.4 |
| NL2Repo | 54.2 |
| Agent Last Exam | 25.2 |
| Automation Bench (Public) | 25.1 |
另一个变化是原生支持 Responses API 格式,并且专门针对 Codex 场景做了适配。这两点对大多数用普通 chat completions 接口的场景影响不大,但如果你在用 OpenAI 风格的 Responses API 或者接 Codex 类工具,直接能用上,不用再套一层格式转换。
模型名没变,API 里还是写 deepseek-v4-flash。
实战:让它自动整理一批本地文件
任务很具体:一个文件夹里有几十个杂乱的 txt/csv,每个里面记着一条客户信息,字段名不统一(有的叫"电话"有的叫"联系方式"),要让模型读文件、抽字段、汇总成一张表。这类"读文件、判断、再决定下一步读哪个文件"的任务,正是 Agent 模式的典型场景,单轮问答做不了。
第一步:定义工具
工具调用走标准的 tools 字段,写法和 OpenAI 的 function calling 规范一致:
tools = [
{
"type": "function",
"function": {
"name": "list_files",
"description": "列出指定目录下的所有文件名",
"parameters": {
"type": "object",
"properties": {
"dir_path": {"type": "string", "description": "目录路径"}
},
"required": ["dir_path"]
}
}
},
{
"type": "function",
"function": {
"name": "read_file",
"description": "读取指定文件的文本内容",
"parameters": {
"type": "object",
"properties": {
"file_path": {"type": "string", "description": "文件路径"}
},
"required": ["file_path"]
}
}
}
]
第二步:多轮循环处理 tool_calls
Agent 模式的核心不是一次请求,是"模型返回工具调用 → 你执行 → 把结果喂回去 → 模型决定下一步"这个循环。跳过这一步、以为传了 tools 就自动跑完全程,是最常见的误解:
from openai import OpenAI
client = OpenAI(api_key="你的key", base_url="https://api.deepseek.com")
messages = [{"role": "user", "content": "整理 ./客户资料 目录下所有文件的联系人信息,汇总成表格"}]
MAX_ROUNDS = 8 # 硬上限,防止模型在工具间反复试探
for round_i in range(MAX_ROUNDS):
resp = client.chat.completions.create(
model="deepseek-v4-flash",
messages=messages,
tools=tools,
tool_choice="auto"
)
msg = resp.choices[0].message
messages.append(msg)
if not msg.tool_calls:
print(msg.content) # 模型认为任务完成,输出最终结果
break
for call in msg.tool_calls:
result = execute_tool(call.function.name, call.function.arguments)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": result[:4000] # 裁剪长度,防止撑爆上下文
})
这段代码里有两个我踩过坑之后才加上的细节,下面单独说。
三个容易踩的坑
没设置最大循环轮数。 第一次跑的时候没写 MAX_ROUNDS,模型对着一个格式怪异的 csv 反复调用 read_file 又反复判断"信息不够",跑了二十多轮才停,输出费用比预期高了不少。工具调用类任务务必给一个硬上限,超过就强制截断并让模型基于已有信息收尾。
tool_choice 留空。 默认值是 auto,意思是模型自己判断要不要调用工具。如果你的任务必须走工具(比如这次的文件读取),什么都不传等于把主动权交给模型,它可能会跳过读文件直接凭猜测编一份"看起来对"的汇总表。需要强制调用时把 tool_choice 设成具体的函数名,或者至少设成 "required"。
role: tool 返回内容不裁剪。 客户资料里有几个文件是导出的完整邮件记录,几千字一个文件,原样塞回 messages 直接把后续几轮的上下文占满,导致模型"忘了"前面读过的文件又重新读一遍。上面代码里 content[:4000] 这行看着简单,是省下最多重复调用的一处。
价格:谷时段能省一半
V4-Flash 走的是峰谷双价,峰值时段是 UTC 01:00-04:00 和 06:00-10:00(周一到周五),价格是谷值的两倍:
| 项目 | 谷值 (USD/1M tokens) | 峰值 (USD/1M tokens) |
|---|---|---|
| 输入(缓存命中) | 0.007 | 0.014 |
| 输入(缓存未命中) | 0.22 | 0.44 |
| 输出 | 0.66 | 1.32 |
按北京时间算,峰值窗口大致落在 09:00-12:00 和 14:00-18:00 这两段,如果是定时批处理任务(比如夜里跑的数据整理),把触发时间挪到谷时段,输出费用直接减半,不需要改任何代码。
我的判断
V4-Flash-0731 这次升级的价值不在"更聪明",官方自己都说基座没换,纯粹是靠重跑后训练把工具调用行为调顺了。对已经在用 V4-Flash 做 Agent 任务的人,直接受益,不用改代码,接口和模型名都没变。对还在犹豫要不要上 Agent 模式的人,这次的九项基准提供了一个具体理由:同样价位(甚至更低)能拿到比 Pro-Preview 更好的工具调用表现,没必要为了"Pro"这个名字多付钱。真正决定任务跑不跑得顺的,还是循环轮数、tool_choice、上下文裁剪这几个工程细节,模型再强,这几处没配对照样费用失控。
参考
- DeepSeek-V4-Flash Goes Official: Agent Benchmarks Beat V4-Pro-Preview
- Change Log | DeepSeek API Docs
- DeepSeek API Pricing | DeepSeek API Docs
- DeepSeek V4 Flash 0731 - API Pricing & Benchmarks | OpenRouter