DeepSeek大模型实现Tools/Functions调用的完整Go代码实现

一、Tools与Functions的核心概念

在AI大模型应用中,ToolsFunctions是扩展模型能力的关键机制:

  1. Tools(工具)
  • 外部API或服务的抽象封装
  • 示例:天气API、IP查询服务、日历服务
  • 特点:独立于模型存在,通过API调用实现特定功能
  1. Functions(函数)
  • 预定义的逻辑处理单元
  • 示例:日期处理、参数解析、数据格式化
  • 特点:直接与模型集成,决定何时调用特定工具
  1. 协同工作机制
javascript 复制代码
用户输入 → 模型识别意图 → 选择Function → 调用对应Tool → 返回结果

二、系统架构设计

整体流程图

graph TD A[用户请求] --> B(HTTP Server) B --> C[AI 模型] C --> D{识别Function} D -->|get_date| E[系统时间] D -->|get_ip| F[IP API] D -->|get_weather| G[天气API] E/F/G --> H[格式化响应] H --> I[返回用户]

三、Go语言完整实现

1. 核心代码实现

go 复制代码
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

// 环境变量配置(实际部署时应通过环境变量设置)
const (
	DeepSeekAPIKey  = "YOUR_DEEPSEEK_API_KEY"  // 替换为实际API密钥
	WeatherAPIKey   = "YOUR_WEATHER_API_KEY"   // 替换为OpenWeather API密钥
	DeepSeekAPIURL  = "https://api.deepseek.com/v1/chat/completions"
	WeatherAPIURL   = "https://api.openweathermap.org/data/2.5/weather"
)

// 定义支持的Functions
const (
	FuncGetDate    = "get_current_date"
	FuncGetIP      = "get_client_ip"
	FuncGetWeather = "get_weather_info"
)

// DeepSeek API请求结构
type DeepSeekRequest struct {
	Model    string         `json:"model"`
	Messages []Message      `json:"messages"`
	Tools    []Tool         `json:"tools,omitempty"`
}

// DeepSeek API响应结构
type DeepSeekResponse struct {
	Choices []struct {
		Message struct {
			ToolCalls []ToolCall `json:"tool_calls"`
		} `json:"message"`
	} `json:"choices"`
}

// 工具定义结构
type Tool struct {
	Type     string   `json:"type"`
	Function Function `json:"function"`
}

type Function struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	Parameters any    `json:"parameters"`
}

type ToolCall struct {
	ID       string `json:"id"`
	Type     string `json:"type"`
	Function struct {
		Name      string `json:"name"`
		Arguments string `json:"arguments"`
	} `json:"function"`
}

// 定义工具参数结构
type WeatherParams struct {
	City string `json:"city"`
}

// HTTP请求处理结构
type APIRequest struct {
	Prompt string `json:"prompt"`
}

type APIResponse struct {
	Function string `json:"function"`
	Result   any    `json:"result"`
}

// 初始化工具定义
var availableTools = []Tool{
	{
		Type: "function",
		Function: Function{
			Name:        FuncGetWeather,
			Description: "获取指定城市的天气信息",
			Parameters: WeatherParams{},
		},
	},
	{
		Type: "function",
		Function: Function{
			Name:        FuncGetDate,
			Description: "获取当前系统日期和时间",
		},
	},
	{
		Type: "function",
		Function: Function{
			Name:        FuncGetIP,
			Description: "获取客户端IP地址",
		},
	},
}

// 调用DeepSeek模型
func callDeepSeek(prompt string) (*DeepSeekResponse, error) {
	requestBody := DeepSeekRequest{
		Model: "deepseek-chat",
		Messages: []Message{
			{
				Role:    "user",
				Content: prompt,
			},
		},
		Tools: availableTools,
	}

	jsonBody, _ := json.Marshal(requestBody)
	req, _ := http.NewRequest("POST", DeepSeekAPIURL, bytes.NewBuffer(jsonBody))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer "+DeepSeekAPIKey)

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("API请求失败: %v", err)
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	var response DeepSeekResponse
	if err := json.Unmarshal(body, &response); err != nil {
		return nil, fmt.Errorf("响应解析失败: %v", err)
	}

	return &response, nil
}

// 工具函数实现
func getCurrentDate() string {
	return time.Now().Format("2006-01-02 15:04:05 MST")
}

func getClientIP(r *http.Request) string {
	forwarded := r.Header.Get("X-Forwarded-For")
	if forwarded != "" {
		return strings.Split(forwarded, ",")[0]
	}
	return r.RemoteAddr
}

func getWeather(city string) (map[string]any, error) {
	url := fmt.Sprintf("%s?q=%s&appid=%s&units=metric&lang=zh_cn", 
		WeatherAPIURL, city, WeatherAPIKey)
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var result map[string]any
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, err
	}

	return map[string]any{
		"city":    city,
		"temp":    result["main"].(map[string]any)["temp"],
		"weather": result["weather"].([]any)[0].(map[string]any)["description"],
	}, nil
}

// HTTP处理函数
func handler(w http.ResponseWriter, r *http.Request) {
	var req APIRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		sendError(w, "无效的请求格式", http.StatusBadRequest)
		return
	}

	// 调用DeepSeek模型
	resp, err := callDeepSeek(req.Prompt)
	if err != nil {
		sendError(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// 处理工具调用
	if len(resp.Choices) == 0 || len(resp.Choices[0].Message.ToolCalls) == 0 {
		sendError(w, "未识别到有效操作", http.StatusBadRequest)
		return
	}

	toolCall := resp.Choices[0].Message.ToolCalls[0]
	var result any
	var errMsg string

	switch toolCall.Function.Name {
	case FuncGetDate:
		result = getCurrentDate()
	case FuncGetIP:
		result = getClientIP(r)
	case FuncGetWeather:
		var params WeatherParams
		if err := json.Unmarshal([]byte(toolCall.Function.Arguments), &params); err != nil {
			errMsg = "天气参数解析失败"
			break
		}
		if weather, err := getWeather(params.City); err == nil {
			result = weather
		} else {
			errMsg = "获取天气信息失败"
		}
	default:
		errMsg = "不支持的功能调用"
	}

	if errMsg != "" {
		sendError(w, errMsg, http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(APIResponse{
		Function: toolCall.Function.Name,
		Result:   result,
	})
}

func sendError(w http.ResponseWriter, message string, code int) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(code)
	json.NewEncoder(w).Encode(map[string]string{"error": message})
}

func main() {
	http.HandleFunc("/query", handler)
	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}
	fmt.Printf("Server running on :%s\n", port)
	http.ListenAndServe(":"+port, nil)
}

代码解析与使用说明

  1. 环境准备
bash 复制代码
# 设置环境变量(实际部署时推荐使用.env文件)
export DEEPSEEK_API_KEY="your_api_key_here"
export WEATHER_API_KEY="your_weather_key"
  1. 核心实现逻辑
  • 工具定义 :通过availableTools声明系统支持的三个功能
  • 模型交互callDeepSeek方法实现与DeepSeek API的交互
  • 函数路由:根据返回的tool_call名称执行对应操作
  • 天气查询:集成OpenWeatherMap API实现真实数据获取
  1. 请求示例
bash 复制代码
curl -X POST http://localhost:8080/query \
  -H "Content-Type: application/json" \
  -d '{"prompt":"上海现在的气温是多少?"}'
  1. 响应结构
json 复制代码
{
  "function": "get_weather_info",
  "result": {
    "city": "Shanghai",
    "temp": 28.5,
    "weather": "多云"
  }
}

关键点说明

  1. 深度集成DeepSeek
  • 使用官方API端点api.deepseek.com
  • 支持最新的deepseek-chat模型
  • 实现完整的工具调用(Tool Calls)流程
  1. 结构化参数处理
go 复制代码
// 参数自动解析示例
var params WeatherParams
json.Unmarshal([]byte(toolCall.Function.Arguments), &params)
  1. 生产级特性
  • 环境变量配置管理
  • 完善的错误处理机制
  • 符合RESTful规范的API设计
  • 支持代理头部识别(X-Forwarded-For)
  1. 天气服务增强
  • 使用OpenWeatherMap官方API
  • 返回结构化天气数据
  • 支持多语言(中文)显示

本文由 www.dblens.com 知识分享,🚀 dblens for MySQL- 免费的AI大模型深度融合的一款MySQL可视化GUI数据库管理工具。

相关推荐
鬼火儿4 小时前
SpringBoot】Spring Boot 项目的打包配置
java·后端
cr7xin4 小时前
缓存三大问题及解决方案
redis·后端·缓存
间彧5 小时前
Kubernetes的Pod与Docker Compose中的服务在概念上有何异同?
后端
间彧5 小时前
从开发到生产,如何将Docker Compose项目平滑迁移到Kubernetes?
后端
间彧5 小时前
如何结合CI/CD流水线自动选择正确的Docker Compose配置?
后端
间彧5 小时前
在多环境(开发、测试、生产)下,如何管理不同的Docker Compose配置?
后端
间彧5 小时前
如何为Docker Compose中的服务配置健康检查,确保服务真正可用?
后端
间彧5 小时前
Docker Compose和Kubernetes在编排服务时有哪些核心区别?
后端
间彧5 小时前
如何在实际项目中集成Arthas Tunnel Server实现Kubernetes集群的远程诊断?
后端
brzhang6 小时前
读懂 MiniMax Agent 的设计逻辑,然后我复刻了一个MiniMax Agent
前端·后端·架构