不依赖任何框架,手写原生 DeepSeek Agent 工具调用(Function Calling)详解
在使用 DeepSeek 大模型进行应用开发时,很多同学会优先选择现成的 Agent 框架,例如 LangChain、LlamaIndex 等。然而在一些对性能敏感、或需要完全掌控逻辑的场景中,我们更希望 以最原生、最轻量的方式 直接实现工具调用(function calling)。
本文将结合一段可直接运行的 Python 代码,完整讲解如何使用 DeepSeek API 实现 原生的 Agent 工具调用,且完全不依赖任何框架。
🌟 最终效果预览
用户输入:
帮我查一下北京的天气
DeepSeek 根据 prompt 自动决定是否调用工具 → 发起工具调用 → 本地执行天气接口 → 将结果回传给模型 → 模型基于结果生成最终输出。这一全链路完全由我们手写实现。
最终你将获得一个真正意义上“原生、可控、可扩展”的 Agent 调用框架。
🧠 核心思路
原生实现工具调用的过程可以拆分为 4 步:
-
定义工具(functions 参数):告诉模型可用哪些函数。
-
让模型决定是否调用工具:设置
tool_choice="auto"。 -
接收模型生成的 tool_call:解析调用的函数名和参数。
-
本地执行工具 → 将执行结果回传模型:实现类似 OpenAI function calling 的闭环。
这一模式适用于:
-
自定义 Agent 系统
-
需要对调用链路完全掌控的场景
-
想做本地函数、数据库、互联网 API 调用的开发者
📌 完整示例代码讲解
下面是完整可运行的代码,包含天气查询函数、工具声明、模型调用、二次回传等完整链路。
import json
from openai import OpenAI
import os
import requests
client = OpenAI(api_key=os.getenv("DEEPSEEK_API_KEY"), base_url="https://api.deepseek.com")
def get_weather(city: str, units: str = "metric") -> str:
"""
查询指定城市的天气信息。
"""
params = {
"q": city,
"appid": os.getenv("OPENWEATHER_API_KEY"),
"units": units,
"lang": "zh_cn"
}
try:
response = requests.get("https://api.openweathermap.org/data/2.5/weather", params=params)
response.raise_for_status()
data = response.json()
weather_info = {
"城市": data.get("name"),
"温度": data["main"].get("temp"),
"体感温度": data["main"].get("feels_like"),
"湿度": data["main"].get("humidity"),
"气压": data["main"].get("pressure"),
"天气": data["weather"][0].get("description"),
"风速": data["wind"].get("speed"),
}
return str(weather_info)
except requests.exceptions.RequestException as e:
return f"查询失败:{str(e)}"
# 工具定义(function calling)
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询指定城市的天气信息,使用英文城市名称。",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"},
"units": {
"type": "string",
"enum": ["metric", "imperial"],
"default": "metric",
},
},
"required": ["city"],
},
},
}
]
messages = [
{"role": "system", "content": "You are a helpful assistant"},
{"role": "user", "content": "帮我查一下北京的天气"},
]
# 第一次请求,由模型决定是否调用工具
resp = client.chat.completions.create(
model="deepseek-chat",
messages=messages,
tools=tools,
tool_choice="auto",
)
msg = resp.choices[0].message
# 模型触发工具调用
if msg.tool_calls:
for tool_call in msg.tool_calls:
if tool_call.function.name == "get_weather":
args = json.loads(tool_call.function.arguments)
result = get_weather(**args)
messages.append(msg)
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"name": "get_weather",
"content": result,
})
# 第二次请求:将工具执行结果喂给模型
final_resp = client.chat.completions.create(
model="deepseek-chat",
messages=messages,
)
print(final_resp.choices[0].message.content)
else:
print(msg.content)
🔍 关键逻辑逐段解析
1. 定义工具
工具的功能、参数、类型严格遵循 JSON Schema。DeepSeek 会自动理解其结构。
"type": "function",
"function": { ... }
2. 发起第一次对话:让模型自行判断是否需要调用工具
tool_choice="auto"
模型会根据用户需求决定是否调用 get_weather。
3. 处理模型返回的 tool_calls
如果模型决定调用:
if msg.tool_calls:
...
解析参数,真正执行 Python 函数。
4. 将工具执行结果回传模型
这是 function calling 的关键步骤:
messages.append({"role": "tool", "content": result})
模型收到后,会基于工具结果生成最终自然语言输出。
🛠️ 如何拓展更多工具?
你可以轻松扩展更多工具:
-
数据库查询
-
文件系统操作
-
第三方 API
-
本地知识库检索
-
操控浏览器(Playwright)
只需要:
-
按 JSON Schema 描述参数
-
写一个 Python 函数
-
在 tools 数组里注册
就能被模型自动识别和调用。
🚀 实际生产可用吗?
答案是:完全可以。
你可以基于文中逻辑搭建:
-
企业内部 Agent 系统
-
任务分解型助理
-
数据分析问答系统
-
智能客服
-
工作流调度系统
优点:
-
无额外框架依赖
-
更高透明度与可控性
-
可严格限制模型权限
-
可监控所有函数调用
📦 示例项目建议结构
project/
├── tools/
│ ├── weather.py
│ └── database.py
├── core/
│ ├── agent.py
│ └── schema.py
├── main.py
└── README.md
这样你就能进一步搭建更复杂的 Agent 系统。
🎉 总结
本文手把手演示了一个完全原生、无任何框架依赖的 DeepSeek 工具调用实现示例。通过手写 JSON Schema + Tool Call 解析 + 二次对话,你可以构建一个高度可控的 Agent 框架。
如果你正准备做自己的 AI 应用、ChatOps、智能助手,这种方式会给你最自由的开发体验。
更多推荐

所有评论(0)