上周 DeepSeek 放出了 V4 预览版,我第一时间拿到了 deepseek-v4-pro 的 API 访问权限,花了三天时间用它搭了一个多步骤 Agent 工作流。直接说结论:deepseek-v4-pro 的 Function Calling 能力比 V3 有质的飞跃,原生支持并行工具调用,配合循环编排可以做出相当靠谱的自动化 Agent。本文会给出完整可运行的 Python 代码,从单步调用到多步骤工作流,一步步搭起来。
说实话一开始我是拒绝用 DeepSeek 做 Agent 的------V3 时代它的 Function Calling 经常漏参数、幻觉工具名,被 GPT-5 和 Claude Opus 4.6 按在地上摩擦。但 V4 这次确实让我改观了,尤其是中文场景下的工具调用准确率,实测下来已经能打。
先说结论
| 维度 | DeepSeek V3 | DeepSeek V4-pro | GPT-5 |
|---|---|---|---|
| Function Calling 准确率 | ~78% | ~94% | ~96% |
| 并行工具调用 | 不支持 | 原生支持 | 原生支持 |
| 中文指令理解 | 良好 | 优秀 | 良好 |
| 多步推理(5步+) | 容易跑偏 | 基本稳定 | 稳定 |
| 价格(输入/百万token) | ¥1 | ¥2 | ¥50+ |
| 响应延迟(首token) | ~800ms | ~500ms | ~300ms |
V4-pro 性价比依然碾压,Agent 场景下多步调用累积的 token 费用差距会非常大。
环境准备
Python 3.10+,装好 openai SDK 就行:
bash
pip install openai>=1.40.0
我用的是 ofox.ai 的聚合接口来调 DeepSeek V4,原因很简单------ofox.ai 是一个 AI 模型聚合平台,一个 API Key 可以调用 GPT-5.5、Claude Opus 4.6、DeepSeek V4 等 50+ 模型,兼容 OpenAI 协议,改个 base_url 就行,不用分别管理各家的 Key 和鉴权。
基础连接测试:
python
from openai import OpenAI
client = OpenAI(
api_key="your-ofox-key",
base_url="https://api.ofox.ai/v1"
)
# 先测一下模型能不能通
resp = client.chat.completions.create(
model="deepseek-v4-pro",
messages=[{"role": "user", "content": "你好,报一下你的模型版本"}],
max_tokens=100
)
print(resp.choices[0].message.content)
返回正常就说明链路通了,继续往下。
Agent 工作流长什么样
写代码之前先理清楚要搭的东西:
核心就是一个循环:把用户消息丢给模型 → 模型决定要不要调工具 → 调了就把结果塞回消息列表 → 再丢给模型 → 直到模型觉得可以直接回答了。
不是什么新概念,但魔鬼在细节里。下面一步步来。
第一步:定义工具集
我搭的是一个「市场调研 Agent」,能搜索信息、分析数据、生成报告。先定义三个工具:
python
import json
import random
from datetime import datetime
# 模拟工具函数(实际项目替换成真实 API)
def search_web(query: str, max_results: int = 5) -> str:
"""模拟搜索引擎"""
# 实际项目这里接 SerpAPI / Tavily 等
fake_results = [
{"title": f"关于「{query}」的分析报告 - 2026", "snippet": f"最新数据显示{query}市场规模持续增长..."},
{"title": f"{query}行业趋势", "snippet": f"2026年{query}领域出现了几个关键变化..."},
{"title": f"{query}竞品分析", "snippet": f"主要玩家包括A、B、C三家,市场份额分别为..."},
]
return json.dumps(fake_results[:max_results], ensure_ascii=False)
def analyze_data(data: str, analysis_type: str) -> str:
"""模拟数据分析"""
return json.dumps({
"analysis_type": analysis_type,
"input_summary": data[:100] + "...",
"key_findings": [
"市场年增长率约 23%",
"头部三家占据 67% 市场份额",
"用户付费意愿同比提升 15%"
],
"confidence": 0.85
}, ensure_ascii=False)
def generate_report(title: str, sections: list, format: str = "markdown") -> str:
"""生成结构化报告"""
report = f"# {title}\n\n生成时间:{datetime.now().strftime('%Y-%m-%d %H:%M')}\n\n"
for i, section in enumerate(sections, 1):
report += f"## {i}. {section}\n\n[此处为详细内容]\n\n"
return report
# 工具注册表:函数名 -> 函数对象
TOOL_REGISTRY = {
"search_web": search_web,
"analyze_data": analyze_data,
"generate_report": generate_report,
}
然后是 OpenAI 格式的工具定义(这部分写起来最烦,但不能偷懒):
python
TOOLS = [
{
"type": "function",
"function": {
"name": "search_web",
"description": "搜索互联网获取最新信息。用于获取市场数据、竞品信息、行业报告等。",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "搜索关键词"
},
"max_results": {
"type": "integer",
"description": "最大返回结果数",
"default": 5
}
},
"required": ["query"]
}
}
},
{
"type": "function",
"function": {
"name": "analyze_data",
"description": "对收集到的数据进行分析。支持趋势分析、竞品分析、用户画像分析等。",
"parameters": {
"type": "object",
"properties": {
"data": {
"type": "string",
"description": "待分析的原始数据(JSON 字符串或文本)"
},
"analysis_type": {
"type": "string",
"enum": ["trend", "competitor", "user_profile", "market_size"],
"description": "分析类型"
}
},
"required": ["data", "analysis_type"]
}
}
},
{
"type": "function",
"function": {
"name": "generate_report",
"description": "根据分析结果生成结构化报告。在所有搜索和分析完成后调用。",
"parameters": {
"type": "object",
"properties": {
"title": {
"type": "string",
"description": "报告标题"
},
"sections": {
"type": "array",
"items": {"type": "string"},
"description": "报告章节标题列表"
},
"format": {
"type": "string",
"enum": ["markdown", "plain"],
"default": "markdown"
}
},
"required": ["title", "sections"]
}
}
}
]
第二步:Agent 主循环(核心代码)
整个 Agent 的心脏,重点看错误处理和并行调用的处理:
python
def run_agent(user_query: str, max_steps: int = 10, verbose: bool = True) -> str:
"""
Agent 主循环
- user_query: 用户的任务描述
- max_steps: 最大工具调用步数,防止死循环
- verbose: 是否打印中间过程
"""
system_prompt = """你是一个专业的市场调研 Agent。你可以使用工具来搜索信息、分析数据、生成报告。
工作流程:
1. 先用 search_web 搜索相关信息(可以搜多次,覆盖不同维度)
2. 用 analyze_data 对搜索结果进行分析
3. 最后用 generate_report 生成完整报告
4. 报告生成后,用自然语言总结关键发现
注意:
- 每次搜索要有明确的目的,不要重复搜索
- 分析时要指定正确的 analysis_type
- 如果某个工具调用失败,尝试换个方式重试一次"""
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_query}
]
step = 0
while step < max_steps:
if verbose:
print(f"\n--- Step {step + 1} ---")
# 调用模型
try:
response = client.chat.completions.create(
model="deepseek-v4-pro",
messages=messages,
tools=TOOLS,
tool_choice="auto", # 让模型自己决定
temperature=0.1, # Agent 场景低温度更稳定
max_tokens=2000
)
except Exception as e:
print(f"API 调用失败: {e}")
# 重试一次
import time
time.sleep(2)
try:
response = client.chat.completions.create(
model="deepseek-v4-pro",
messages=messages,
tools=TOOLS,
tool_choice="auto",
temperature=0.1,
max_tokens=2000
)
except Exception as e2:
return f"Agent 执行失败,API 连续报错: {e2}"
msg = response.choices[0].message
# 没有工具调用 = 模型认为任务完成了
if not msg.tool_calls:
if verbose:
print("模型直接回答,Agent 结束")
return msg.content
# 把模型的回复(含 tool_calls)加入消息列表
messages.append(msg)
# 处理所有工具调用(V4 支持并行,可能一次返回多个)
for tool_call in msg.tool_calls:
func_name = tool_call.function.name
# 解析参数
try:
func_args = json.loads(tool_call.function.arguments)
except json.JSONDecodeError:
# V4 偶尔会输出不完整的 JSON,这里兜底
if verbose:
print(f" ⚠️ 参数解析失败: {tool_call.function.arguments}")
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": "参数格式错误,请重试并确保输出合法 JSON"
})
continue
if verbose:
print(f" 🔧 调用工具: {func_name}({json.dumps(func_args, ensure_ascii=False)[:80]}...)")
# 执行工具
if func_name in TOOL_REGISTRY:
try:
result = TOOL_REGISTRY[func_name](**func_args)
except TypeError as e:
result = f"工具调用参数错误: {e}"
except Exception as e:
result = f"工具执行异常: {e}"
else:
result = f"未知工具: {func_name}"
if verbose:
print(f" ✅ 返回: {str(result)[:100]}...")
# 工具结果塞回消息列表
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": str(result)
})
step += 1
# 超过最大步数,强制让模型总结
messages.append({
"role": "user",
"content": "你已经执行了足够多的步骤,请基于已有信息直接给出最终回答。"
})
final = client.chat.completions.create(
model="deepseek-v4-pro",
messages=messages,
max_tokens=2000
)
return final.choices[0].message.content
第三步:跑起来看效果
python
if __name__ == "__main__":
result = run_agent(
"帮我调研一下 2026 年 AI 编程工具市场的现状,"
"包括主要玩家、市场规模、用户增长趋势,"
"最后生成一份简要报告。",
max_steps=8,
verbose=True
)
print("\n" + "=" * 50)
print("最终输出:")
print(result)
实测跑下来,V4-pro 通常走 4-5 步:
erlang
--- Step 1 ---
🔧 调用工具: search_web({"query": "2026 AI编程工具市场规模"})
✅ 返回: [{"title": "关于「2026 AI编程工具市场规模」的分析报告...
--- Step 2 ---
🔧 调用工具: search_web({"query": "AI编程工具主要玩家 Cursor Copilot Claude Code"})
🔧 调用工具: search_web({"query": "AI编程工具用户增长 2026"})
✅ 返回: ...(并行调用,两个同时返回)
--- Step 3 ---
🔧 调用工具: analyze_data({"data": "...", "analysis_type": "market_size"})
✅ 返回: ...
--- Step 4 ---
🔧 调用工具: generate_report({"title": "2026 AI编程工具市场调研报告", ...})
✅ 返回: ...
--- Step 5 ---
模型直接回答,Agent 结束
注意 Step 2 里它一次发了两个并行的 search_web 调用,这是 V4 的新能力,V3 做不到。
踩坑记录
踩了不少坑,挑几个有代表性的:
坑 1:tool_choice 不要用 "required"
一开始我把 tool_choice 设成 "required",想强制模型每轮都调工具。结果模型在该结束的时候也硬凑一个工具调用出来,参数完全是幻觉。改成 "auto" 就好了,让模型自己判断什么时候该停。
坑 2:temperature 必须压低
Agent 场景下 temperature 设 0.7 以上就是灾难。模型会"创造性"地发明工具参数,比如给 analysis_type 传一个 "comprehensive"------根本不在 enum 里。我现在统一用 0.1。
坑 3:JSON 解析要兜底
V4-pro 大约有 3-5% 的概率输出不完整的 JSON 参数,尤其是参数比较长的时候。必须加 try-except,而且错误信息要告诉模型"请重试",它通常第二次就能输出正确的。
坑 4:消息列表别忘了加 assistant message
新手最容易犯的错:模型返回了带 tool_calls 的 message,你必须先把这个 message 原封不动 append 到 messages 里,然后再 append tool 的返回结果。少了 assistant message 那一步,API 会直接报 400。
进阶:加个简单的记忆机制
如果你想让 Agent 跨多轮对话保持上下文,最简单的方案是把历史摘要塞进 system prompt:
python
def summarize_history(messages: list, client: OpenAI) -> str:
"""用模型自己总结历史对话"""
summary_resp = client.chat.completions.create(
model="deepseek-v4-pro",
messages=[
{"role": "system", "content": "用 3-5 句话总结以下对话的关键信息和结论。"},
{"role": "user", "content": json.dumps(
[m for m in messages if m.get("role") in ("user", "assistant") and isinstance(m, dict)],
ensure_ascii=False
)[:3000]}
],
max_tokens=300
)
return summary_resp.choices[0].message.content
在 messages 长度超过一定阈值时调用这个函数,把摘要塞进 system prompt,然后清空旧消息。粗暴但有效。
小结
deepseek-v4-pro 做 Agent 的体验比 V3 好了一个档次,并行工具调用和 JSON 输出稳定性提升最明显。跟 GPT-5.5 比还是有差距,主要体现在超长链路(8步以上)的推理连贯性上。但价格差了 25 倍,很多场景下 V4-pro 完全够用。
我现在的做法是:简单任务用 deepseek-v4-pro 跑,复杂的多 Agent 协作场景切 GPT-5.5 或 Claude Opus 4.6------反正都是同一个 API Key,改个 model 参数就行。
完整代码我放 gist 了,有问题评论区聊。