DeepSeek V4 Agent 开发实战:用 deepseek-v4-pro 搭建多步骤工作流(2026 完整代码)

上周 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 工作流长什么样

写代码之前先理清楚要搭的东西:

graph TD A[用户输入] --> B[Agent 主循环] B --> C{模型决策} C -->|需要调用工具| D[执行 Function Call] D --> E[工具返回结果] E --> B C -->|直接回答| F[输出最终结果] B --> G{超过最大步数?} G -->|是| H[强制终止并总结] G -->|否| C

核心就是一个循环:把用户消息丢给模型 → 模型决定要不要调工具 → 调了就把结果塞回消息列表 → 再丢给模型 → 直到模型觉得可以直接回答了。

不是什么新概念,但魔鬼在细节里。下面一步步来。

第一步:定义工具集

我搭的是一个「市场调研 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 了,有问题评论区聊。

相关推荐
斯维赤1 小时前
Python学习超简单第八弹:连接Mysql数据库
数据库·python·学习
qq_654366982 小时前
如何排查Oracle客户端连接慢_DNS解析超时与sqlnet配置优化
jvm·数据库·python
迷途酱2 小时前
手写一个 AI Agent:从 Function Calling 到自动化任务链
python
Gerardisite2 小时前
企微机器人开发指南
java·python·机器人·自动化·企业微信
城管不管3 小时前
嵌入模型Embedding Model
java·开发语言·python·embedding·嵌入模型
Architect_Lee3 小时前
python3.14.4环境搭建
python
适应规律3 小时前
pointnet 实战
python
慕涯AI3 小时前
Agent 30 课程开发指南 - 第28课
人工智能·python
迷途酱3 小时前
RAG 从零到一:用 Python 给大模型接上你的私有知识库
python