不支持函数调用的大语言模型解决技巧

不支持函数调用的大语言模型解决技巧

一、这是什么?(概念解释)

当使用不支持原生函数调用 的大语言模型时(如 Moonshot、某些开源模型),无法像 GPT-4 那样使用 bind_tools()tool_calls

解决方案 :通过精心设计的 Prompt,让模型以 JSON 格式 输出工具调用指令,然后手动解析并执行工具。

核心思想:

  • 不依赖模型的原生函数调用能力
  • 让模型输出结构化的 JSON:{"name": "工具名", "arguments": {参数}}
  • 手动解析 JSON 并执行对应的工具

二、有什么用?(应用场景)

场景 说明
使用国产模型 Moonshot、智谱、通义千问等早期版本不支持原生函数调用
使用开源模型 Llama、Qwen 等开源模型部署时
降低成本 某些支持函数调用的模型价格较高,用便宜模型替代
统一接口 让不同能力的模型都能使用工具调用功能
灵活控制 完全控制工具调用的解析和执行流程

三、完整示例代码

python 复制代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import json
import os
from typing import Type, Any, TypedDict, Dict, Optional
import requests
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableConfig, RunnablePassthrough
from langchain_core.tools import BaseTool, render_text_description_and_args
from langchain_openai import ChatOpenAI
from pydantic import Field, BaseModel
import dotenv

dotenv.load_dotenv()

# ============ 第一步:定义工具(与原生方式相同)============

class WeatherArgsSchema(BaseModel):
    city: str = Field(description="需要查询天气的城市,例如:北京")

class WeatherTool(BaseTool):
    """查询指定城市的天气预报"""
    name: str = "weather_query"
    description: str = "当你需要查询天气信息时使用此工具"
    args_schema: Type[BaseModel] = WeatherArgsSchema

    def _run(self, city: str) -> str:
        # 实际调用天气 API
        return f"{city}今天晴天,温度 25°C"

# ============ 第二步:创建工具字典和执行函数 ============

weather_tool = WeatherTool()
tool_dict = {weather_tool.name: weather_tool}
tools = [weather_tool]

# 定义工具调用请求的类型
class ToolCallRequest(TypedDict):
    name: str
    arguments: Dict[str, Any]

# 定义工具执行函数
def invoke_tool(
    tool_call_request: ToolCallRequest,
    config: Optional[RunnableConfig] = None,
) -> str:
    """执行工具调用"""
    name = tool_call_request["name"]
    requested_tool = tool_dict.get(name)
    return requested_tool.invoke(tool_call_request.get("arguments"), config=config)

# ============ 第三步:构建 Prompt(关键!)============

# 将工具列表渲染成文本描述
rendered_tools = render_text_description_and_args(tools)

system_prompt = f"""你是一个聊天机器人,可以访问以下工具。
以下是每个工具的名称和描述:

{rendered_tools}

根据用户输入,返回要使用的工具的名称和输入。
将您的响应作为具有`name`和`arguments`键的JSON块返回。
`arguments`应该是一个字典,其中键对应于参数名称,值对应于请求的值。"""

prompt = ChatPromptTemplate.from_messages([
    ("system", system_prompt),
    ("human", "{query}")
])

# ============ 第四步:创建执行链 ============

# 使用不支持函数调用的模型
llm = ChatOpenAI(model="moonshot-v1-8k", temperature=0)

# 链路:Prompt -> LLM -> 解析JSON -> 执行工具
chain = (
    prompt
    | llm
    | JsonOutputParser()          # 关键:解析模型输出的 JSON
    | RunnablePassthrough.assign(output=invoke_tool)  # 执行工具并将结果赋值给 output
)

# ============ 第五步:调用 ============

result = chain.invoke({"query": "北京今天天气怎么样?"})
print(result)
# 输出类似:
# {
#   "name": "weather_query",
#   "arguments": {"city": "北京"},
#   "output": "北京今天晴天,温度 25°C"
# }

四、流程对比图

scss 复制代码
┌─────────────────────────────────────────────────────────────────────────┐
│              原生函数调用 VS Prompt Engineering 方式对比                    │
└─────────────────────────────────────────────────────────────────────────┘


  ================== 原生支持函数调用 (GPT-4) ==================

  用户提问               LLM                  应用层
     │                   │                      │
     ▼                   ▼                      │
  "北京天气?" ──────────▶│ 返回 tool_calls      │
     │                   │ (结构化对象)         │
     │                   │ [{name: "weather",  │     │                   │   args: {...}}]      │
     │◀──────────────────│                      │
     │                   │                      │
     │ 解析 tool_calls    │                      │
     │                   │                      │
     ▼                   │                      │
  调用工具 ──────────────────────────────────────▶│
     │                                          │
     │◀─────────────────────────────────────────│ 工具返回
     │                                          │
     ▼                   │                      │
  构造 ToolMessage ──────▶│ 生成最终回答         │
     │                   │                      │
     │◀──────────────────│                      │
  最终回答                                         │


  ================== 不支持函数调用 (Moonshot) ==================

  用户提问               LLM                  应用层
     │                   │                      │
     ▼                   ▼                      │
  "北京天气?" ──────────▶│ 返回文本            │
     │                   │ (JSON字符串)        │
     │                   │ '{"name": "weather"│
     │                   │   "arguments": {...│
     │                   │  }}'               │
     │◀──────────────────│                      │
     │                   │                      │
     ▼                   │                      │
  JsonOutputParser      │                      │
  (解析 JSON)           │                      │
     │                   │                      │
     ▼                   │                      │
  invoke_tool() ────────────────────────────────▶│
  (手动执行工具)                               │
     │                                          │
     │◀─────────────────────────────────────────│ 工具返回
     │                   │                      │
     ▼                   ▼                      ▼
  返回完整结果                                   │
  {name, arguments, output}                     │


  ┌─────────────────────────────────────────────────────────────────────────┐
  │                         核心差异                                         │
  └─────────────────────────────────────────────────────────────────────────┘

  原生方式:                     Prompt Engineering 方式:
  - LLM 返回结构化对象            - LLM 返回 JSON 文本
  - 自动解析 tool_calls           - 手动用 JsonOutputParser 解析
  - 使用 ToolMessage 反馈         - 直接将结果附加到输出
  - 模型内置支持                   - 完全靠 Prompt 设计
相关推荐
H5css�海秀1 天前
今天是自学大模型的第一天(sanjose)
后端·python·node.js·php
Z兽兽1 天前
React@18+Vite项目配置env文件
前端·react.js·前端框架
SuniaWang1 天前
《Spring AI + 大模型全栈实战》学习手册系列 · 专题六:《Vue3 前端开发实战:打造企业级 RAG 问答界面》
java·前端·人工智能·spring boot·后端·spring·架构
韩立学长1 天前
Springboot校园跑腿业务系统0b7amk02(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
数据库·spring boot·后端
sheji34161 天前
【开题答辩全过程】以 基于springboot的扶贫系统为例,包含答辩的问题和答案
java·spring boot·后端
A_nanda1 天前
根据AI提示排查vue前端项目
前端·javascript·vue.js
happymaker06261 天前
web前端学习日记——DAY05(定位、浮动、视频音频播放)
前端·学习·音视频
代码栈上的思考1 天前
消息队列:内存与磁盘数据中心设计与实现
后端·spring
~无忧花开~1 天前
React状态管理完全指南
开发语言·前端·javascript·react.js·前端框架
LegendNoTitle1 天前
计算机三级等级考试 网络技术 选择题考点详细梳理
服务器·前端·经验分享·笔记·php