DeepSeek API 本地 Agent 搭建 — V4 Pro + 工具调用实战
为什么选择 DeepSeek
模型 上下文 价格(输入/输出) 工具调用
deepseek-chat(V3) 128K ¥1/¥4 每百万 token ✅
deepseek-reasoner(R1) 128K ¥4/¥16 ❌ 不支持 Function Calling
deepseek-v4-pro 128K ¥2/¥8 ✅ 支持 + 推理链
Agent 场景核心需求:工具调用(Function Calling) + 长上下文 + 推理能力。deepseek-v4-pro 三项都满足。
第一步:获取 API Key
- 打开 platform.deepseek.com
- 注册 → API Keys → 创建
- 复制
sk-xxxxxxxx保存好
第二步:最小调用验证
curl https://api.deepseek.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-your-key-here" \
-d '{
"model": "deepseek-v4-pro",
"messages": [{"role": "user", "content": "Hello"}],
"temperature": 0.7
}'
第三步:Function Calling — Agent 的灵魂
Agent 区别于普通聊天机器人的核心:模型决定”该调哪个工具”,代码执行工具 + 把结果塞回对话。
import json
import requests
API_KEY = "sk-your-key-here"
API_URL = "https://api.deepseek.com/v1/chat/completions"
# ── 定义工具 ──
TOOLS = [
{
"type": "function",
"function": {
"name": "read_file",
"description": "读取本地文件内容",
"parameters": {
"type": "object",
"properties": {
"path": {"type": "string", "description": "文件路径"}
},
"required": ["path"]
}
}
},
{
"type": "function",
"function": {
"name": "write_file",
"description": "写入内容到本地文件",
"parameters": {
"type": "object",
"properties": {
"path": {"type": "string"},
"content": {"type": "string"}
},
"required": ["path", "content"]
}
}
},
{
"type": "function",
"function": {
"name": "run_command",
"description": "执行 shell 命令并返回输出",
"parameters": {
"type": "object",
"properties": {
"command": {"type": "string"}
},
"required": ["command"]
}
}
}
]
# ── 工具执行器 ──
def execute_tool(name: str, args: dict) -> str:
if name == "read_file":
with open(args["path"], "r") as f:
return f.read()
elif name == "write_file":
with open(args["path"], "w") as f:
f.write(args["content"])
return f"已写入 {args['path']}"
elif name == "run_command":
import subprocess
result = subprocess.run(
args["command"], shell=True,
capture_output=True, text=True, timeout=30
)
return result.stdout or result.stderr
return f"未知工具: {name}"
# ── Agent 循环 ──
SYSTEM_PROMPT = """你是一个本地编程助手,可以读写文件和执行命令。
需要操作文件或执行命令时,调用对应工具。完成用户任务后直接总结结果。"""
def agent_loop(user_input: str, max_turns: int = 10):
messages = [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_input}
]
for turn in range(max_turns):
resp = requests.post(API_URL, headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}, json={
"model": "deepseek-v4-pro",
"messages": messages,
"tools": TOOLS,
"temperature": 0.3
}).json()
msg = resp["choices"][0]["message"]
# 模型决定回复文本 → 结束
if msg.get("content") and not msg.get("tool_calls"):
return msg["content"]
# 模型决定调工具 → 执行 + 塞回结果
if msg.get("tool_calls"):
messages.append(msg) # 助手消息(含工具调用)
for tc in msg["tool_calls"]:
fn_name = tc["function"]["name"]
fn_args = json.loads(tc["function"]["arguments"])
print(f" 🔧 调用工具: {fn_name}({fn_args})")
result = execute_tool(fn_name, fn_args)
messages.append({
"role": "tool",
"tool_call_id": tc["id"],
"content": result[:2000] # 截断过长结果
})
return "达到最大轮次"
第四步:实战 — 让 Agent 分析项目
result = agent_loop("""
请分析 /home/user/myproject 目录:
1. 列出所有 .cpp 和 .h 文件
2. 统计代码总行数
3. 把结果写入 project_stats.txt
""")
print(result)
执行过程:
🔧 调用工具: run_command({"command": "find /home/user/myproject -name '*.cpp' -o -name '*.h'"})
🔧 调用工具: run_command({"command": "find /home/user/myproject ... | xargs wc -l"})
🔧 调用工具: write_file({"path": "project_stats.txt", "content": "..."})
Agent 回复:
项目分析完成:
- C++ 源文件: 15 个
- 头文件: 8 个
- 总行数: 4,230 行
- 结果已写入 project_stats.txt
第五步:扩展更多工具
# 网页搜索
{
"name": "web_search",
"description": "搜索网页",
"parameters": {
"properties": {
"query": {"type": "string"}
}
}
}
# 执行 Python 代码
{
"name": "run_python",
"description": "执行 Python 代码并返回结果",
"parameters": {
"properties": {
"code": {"type": "string"}
}
}
}
# Git 操作
{
"name": "git_commit",
"description": "提交当前变更",
"parameters": {
"properties": {
"message": {"type": "string"}
}
}
}
第六步:安全边界 — 白名单 + 确认机制
DANGEROUS_COMMANDS = ["rm -rf", "sudo", "chmod 777", "> /dev/sda"]
def execute_tool_safe(name: str, args: dict) -> str:
if name == "run_command":
cmd = args["command"]
for dangerous in DANGEROUS_COMMANDS:
if dangerous in cmd:
return f"❌ 拒绝执行危险命令: '{dangerous}'"
return execute_tool(name, args)
# 高风险操作要求确认
HIGH_RISK_TOOLS = {"write_file", "run_command"}
# 在 agent_loop 中:
if fn_name in HIGH_RISK_TOOLS:
print(f" ⚠️ 高风险操作: {fn_name}({fn_args})")
confirm = input(" 执行? (y/n): ")
if confirm.lower() != 'y':
messages.append({
"role": "tool",
"tool_call_id": tc["id"],
"content": "用户拒绝了此操作"
})
continue
关键参数调优
| 参数 | 推荐值 | 原因 |
|---|---|---|
temperature | 0.3 | Agent 场景需要确定性,不要创意 |
top_p | 0.9 | 配合低 temperature |
max_tokens | 4096 | 足够返回工具参数 + 总结 |
| System Prompt | 精简 | 省 token,把空间留给工具结果 |
常见问题
“为何不用 deepseek-reasoner?” → R1 不支持 Function Calling,无法调工具。
“工具结果太长怎么办?”
→ content[:2000] 截断。或让工具返回摘要而非全文。
“如何让 Agent 记住之前的操作?” → messages 数组天然是对话历史,工具结果塞回去模型就能引用。
“如何对接到 Webhook / Discord Bot?”
→ 把 agent_loop(input) 包装成 HTTP 端点即可:
from flask import Flask, request
app = Flask(__name__)
@app.post("/chat")
def chat():
user_input = request.json["message"]
reply = agent_loop(user_input)
return {"reply": reply}
完整文件结构
my-agent/
├── agent.py # 核心循环 + 工具定义
├── config.py # API_KEY + 模型参数
├── tools/
│ ├── files.py # 文件读写工具
│ ├── shell.py # 命令执行工具
│ └── web.py # 搜索工具
└── requirements.txt # requests, flask