LLM大语言模型(十二):关于ChatGLM3-6B不兼容Langchain 的Function Call

news2025/3/14 0:56:13

 

背景

基于本地的ChatGLM3-6B直接开发LangChain Function Call应用,发现其输出的action和action_input非常不稳定。

表现为生成的JSON格式回答非常容易出现不规范的情况,导致LangChain的Agent执行报错,或者进入死循环。

ChatGLM3-6B不兼容Langchain 的Function Call

Langchain 作为最主流的大模型中间件开源框架,备受广大开发者的认可。

Langchain中具有一套完整的 Agent 思维,包括灵活,简单的Function Call开发框架。

ChatGLM3-6B 模型在同量级模型中有出色的Function Call能力。

但遗憾的是,其训练过程并没有与Langchain进行原生对齐。

这导致如果直接使用Langchian框架,将会遇到以下问题:

  • 无法载入ChatGLM3-6B模型,Langchain中的 LLM模型 目前仅支持在线的几个主流模型,例如ChatGPT,Bard,Claude等

  • 无法正常使用 Agent 的 Function Call 功能,ChatGLM3-6B的截断点与 Langchain 支持的并不同。

  • 提示词不同,使用 Langchain 封装的 Agent 提示词完全无法胜任ChatGLM3-6B 的 Function Call 任务。

将GLM模型接入Langchain

首先,要解决第一个痛点:ChatGLM3-6B 模型能够被 Langchain 读入并执行。

那么,我们就需要基于Langchain的LLM类完成ChatGLM3-6B的模型实现。

封装自定义LLM

class ChatGLM3(LLM):
    max_token: int = 8192
    do_sample: bool = False
    temperature: float = 0.8
    top_p = 0.8
    tokenizer: object = None
    model: object = None
    history: List = []
    tool_names: List = []
    has_search: bool = False

    def __init__(self):
        super().__init__()

    @property
    def _llm_type(self) -> str:
        return "ChatGLM3"

接着,我们要写入读入模型的方法,这与 Langchain 支持的在线模型不同,这里使用 Huggingface 的方式进行读入。

def load_model(self, model_name_or_path=None):
    model_config = AutoConfig.from_pretrained(
        model_name_or_path,
        trust_remote_code=True
    )
    self.tokenizer = AutoTokenizer.from_pretrained(
        model_name_or_path,
        trust_remote_code=True
    )
    self.model = AutoModel.from_pretrained(
        model_name_or_path, config=model_config, trust_remote_code=True
    ).half().cuda()

按LangChain的格式构建Tool

其中包括工具的name,description,params等信息,可以被LangChain自动识别出来,加入到prompt中

import abc

from typing import Type
from langchain.tools import BaseTool
from pydantic import BaseModel, Field


class CalculatorInput(BaseModel):
    calculation: str = Field(description="calculation to perform")


class Calculator(BaseTool, abc.ABC):
    name = "Calculator"
    description = "Useful for when you need to calculate math problems"
    args_schema: Type[BaseModel] = CalculatorInput

    def __init__(self):
        super().__init__()

    def _run(self, calculation: str) -> str:
        calculation = calculation.replace("^", "**")
        if "sqrt" in calculation:
            calculation = calculation.replace("sqrt", "math.sqrt")
        elif "log" in calculation:
            calculation = calculation.replace("log", "math.log")
        return eval(calculation)

从prompt中抽取tool信息并转换为ChatGLM能识别的结构 

然后,就是非常重要的一环。由于我们的工具调用和观察抓取与 Langchain 并不相同,我们需要对 Langchain 的提示词进行修改,并配上我们的提示词。

  • 我们先从AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION模板中截取到You have access to the following tools:\n\n")的关键词,并在合理插入已经注册的工具类型。

tool_prompts = prompt.split(
        "You have access to the following tools:\n\n")[1].split("\n\nUse a json blob")[0].split("\n")

    tool_names = [tool.split(":")[0] for tool in tool_prompts]
    self.tool_names = tool_name

增加Observation结构

由于ChatGLM3-6B拥有Observation角色,这与Langchain中原本设定的Observation截断并不相同,因此,在这里,我们需要做提取,在这段代码中,我们需要对原本Langchain中的Observation进行截断,并补

充上我们的工具观察的结果。

def _extract_observation(self, prompt: str):
    return_json = prompt.split("Observation: ")[-1].split("\nThought:")[0]
    self.history.append({
        "role": "observation",
        "content": return_json
    })
    return

将ChatGLM生成的结果转换为LangChain能识别的结构

在这,我们还需要对执行工具进行截断和填充,使得其能满足ChatGLM3-6B的思维模式

def _extract_tool(self):
        if len(self.history[-1]["metadata"]) > 0:
            metadata = self.history[-1]["metadata"]
            content = self.history[-1]["content"]
            if "tool_call" in content:
                for tool in self.tool_names:
                    if tool in metadata:
                        input_para = content.split("='")[-1].split("'")[0]
                        action_json = {
                            "action": tool,
                            "action_input": input_para
                        }
                        self.has_search = True
                        return f"""
Action: 
```
{json.dumps(action_json, ensure_ascii=False)}
```"""
        final_answer_json = {
            "action": "Final Answer",
            "action_input": self.history[-1]["content"]
        }
        self.has_search = False
        return f"""
Action: 
```
{json.dumps(final_answer_json, ensure_ascii=False)}
```"""

由于ChatgGLM3-6B的思维方式并没有Action: 字段,而这是langchain的截断点,因此,我们需要对其进行补充,使得Langchain能知道,此时模型进入调用工具阶段。

最后,我们要基于Langchain的构造,重写_call函数,包括历史记录,提示词等拼接内容。

def _call(self, prompt: str, history: List = [], stop: Optional[List[str]] = ["<|user|>"]):
    if not self.has_search:
        self.history, query = self._tool_history(prompt)
    else:
        self._extract_observation(prompt)
        query = ""
    _, self.history = self.model.chat(
        self.tokenizer,
        query,
        history=self.history,
        do_sample=self.do_sample,
        max_length=self.max_token,
        temperature=self.temperature,
    )
    response = self._extract_tool()
    history.append((prompt, response))
    return response

使用接入了Langchain的ChatGLM3-6B模型

在完成了上述工作之后,我们就已经拥有了支持Langchain的ChatGLM3-6B模型,我们在main.py中对其进行了简单调用

if __name__ == "__main__":
    llm = ChatGLM3()
    llm.load_model(MODEL_PATH)
    prompt = hub.pull("hwchase17/structured-chat-agent")

    # for single parameter without history

    tools = [Calculator()]
    agent = create_structured_chat_agent(llm=llm, tools=tools, prompt=prompt)
    agent_executor = AgentExecutor(agent=agent, tools=tools)
    ans = agent_executor.invoke({"input": "34 * 34"})
    print(ans)

注意事项

到此为止,你已经简单实现了使用LangChain调用ChatGLM3-6B模型来实现工具调用和其他基本用法。但是,在更多探索之前,请一定要看这部分的内容。这将能为你之后的开发减少不必要的麻烦。

使用LLMChain的工具

在官方的实现方案中,暂时不能解决在工具中仍然需要调用正常的LLMChain的操作,这意味着你在工具的设计中不能再次调用大模型进行更多操作,例如参数解析等,典型的错误例子为

LLMMathChain

如果使用官方Demo调用这个工具,则必然遇到以下错误:

line 120, in _process_llm_result

raise ValueError(f"unknown format from LLM: {llm_output}")

ValueError: unknown format from LLM: Action:

{"action": "Calculator", "action_input": "23*23"}

这是因为在模型构建的过程中,模型会解析到tools,而在tools中的常规调用模型并没有修改模型的系统提示词,模型还会尝试调用工具,这在常规的Chain中是错误的。

无效的参数和固定的参数

  • ChatGLM3-6B必须使用结构化的Agent,在Langchain中,我们只适配了AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION

  • 如果使用LLMSingleActionAgent来构建,stop参数无效。

  • 使用Tool.from_function时,args_schema无效。

  • 每次创建一个新的Tools,都必须有同名的yaml,或者自己实现传入格式化的工具说明。

兼容OpenAI API

官方的OpenAI API格式的demo,目前无法适配Langchain的工具。

 参考

  1. GitHub - THUDM/ChatGLM-6B: ChatGLM-6B: An Open Bilingual Dialogue Language Model | 开源双语对话语言模型
  2.  LLM大语言模型(十一):基于自定义的ChatGLM3-6B构建LangChain的chain-CSDN博客
  3. LLM大语言模型(十):LangChain自定义Agent使用自定义的LLM-CSDN博客
  4. LLM大语言模型(九):LangChain封装自定义的LLM-CSDN博客
  5. LLM大语言模型(八):ChatGLM3-6B使用的tokenizer模型BAAI/bge-large-zh-v1.5-CSDN博客
  6. LLM大语言模型(七):部署ChatGLM3-6B并提供HTTP server能力
  7. LLM大语言模型(四):在ChatGLM3-6B中使用langchain_chatglm3-6b langchain-CSDN博客
  8. LLM大语言模型(一):ChatGLM3-6B本地部署-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1622918.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

关于DevOps理解和总结

DevOps是研发领域最近几年最热的一个概念。参加过一些讲座&#xff0c;也看过不少的书籍&#xff0c;经常听到以下说法&#xff1a; DevOps是没有明确定义的&#xff0c;一千个研发心中就有一千个Devops&#xff1b;DevOps是一种文化&#xff0c;每个团队的DevOps实践都不一样…

spring基本使用

文章目录 1. ioc(Inversion of Control) | DI(Dependency Injection)(1) maven坐标导包(2) 编写配置文件bean.xml(3) 配置bean(4) 配置文件注入属性 2. DI(dependency injection) 依赖注入(setter)其他属性(1) 对象属性注入(2) 数组属性输入(3) 集合属性注入(4) map集合注入(5)…

JAVASE8中基本数据类型

本篇文章基于有过一部分的C语言基础的&#xff0c;还望大家理解 在进入到学习之前我们必须要清楚的是在JAVASE中数据类型与C语言中的数据类型基本上是相同的,接下来我们先来对8中数据类型进行简要介绍&#xff0c;他们分别是&#xff1a; 如果大家之前了解过C语言那么对于基本数…

【FP7208-RGBWY五路调光方案】 单节锂电池LED升压恒流驱动调光芯片FP7208,PWM内部转模拟调光,无频闪顾虑低亮无抖动

文章目录 方案背景 二、RGBWY五路调光调色芯片FP7208 1.芯片参数 2.单颗芯片五路调光应用原理 调光调色信号注意事项&#xff1a; 3.五路调光应用电路图DEMO实物图 4.RGBWY调光调色详解 总结 方案背景 近年来随着技术的不断进步&#xff0c;越来越多的产品需要适应小型化和便携…

系统试运行报告(上线运行报告Word原件2024)

一、试运行目的 软件项目试运行的主要目的是在实际应用环境中对软件系统进行全面检验&#xff0c;确保其满足设计要求和用户需求&#xff0c;同时发现和解决潜在的问题&#xff0c;为正式投入使用做好准备。通过试运行&#xff0c;我们可以&#xff1a; 验证软件系统的稳定性…

ONES 功能上新|ONES Wiki 新功能一览

支持在 ONES Wiki 页面中使用分栏进行横向排版&#xff0c;丰富排版方式&#xff0c;帮助用户以更丰富的版式展示内容。 应用场景&#xff1a; 页面的布局对内容的阅读有很大的影响。当页面中有图文混排的需求时&#xff0c;可以通过分栏来组织页面结构&#xff0c;以更清晰、更…

LabVIEW学习记录 - 实时显示时间

LabVIEW操作 - 实时显示时间 在程序框图&#xff0c;选择函数->定时->格式化日期/时间字符串 该函数的使用手册说明&#xff1a; 鼠标选择“格式化日期/时间字符串”->创建->输入控件->输入格式 查看时间代码格式&#xff1a; 编程->定时->获取时间日…

cad中快速计算多个矩形面积的方法

1、输入命令reg&#xff0c;选中矩形创建面域 2、输入命令uni,选中刚刚创建的面域&#xff0c;组合成一个面域 3、输入命令&#xff1a;LI &#xff0c;选中面域&#xff0c;即可查看面积和周长 需注意的一点&#xff0c;开始创建的矩形或者多段线要在一个面内&#xff0c;就是…

word常用的文件格式有哪些?word格式文件删除了怎么恢复

在数字文档处理的世界中&#xff0c;Microsoft Word以其丰富的格式选项和强大的编辑功能赢得了广大用户的青睐。但与此同时&#xff0c;误删或丢失Word格式文件的情况也时有发生。本文将深入探讨Word常用的文件格式有哪些&#xff0c;同时分享如何恢复误删的Word文件&#xff0…

浏览器的工作原理

参考&#xff1a;渲染页面&#xff1a;浏览器的工作原理 - Web 性能 | MDN (mozilla.org) Web 性能 | MDN (mozilla.org) Web性能影响因素 首先有两个&#xff0c;一个是网络延迟&#xff0c;一个是大部分情况下浏览器都是单线程执行的 保障页面快速加载的最大威胁是网络延迟…

MyBatisPlus详解(二)条件构造器Wrapper、自定义SQL、Service接口

文章目录 前言2 核心功能2.1 条件构造器2.1.1 Wrapper2.1.2 QueryWrapper2.1.3 UpdateWrapper2.1.4 LambdaQueryWrapper 2.2 自定义SQL2.2.1 基本用法2.2.2 多表关联 2.3 Service接口2.3.1 IService2.3.1.1 save2.3.1.2 remove2.3.1.3 update2.3.1.4 get2.3.1.5 list2.3.1.6 co…

主成分分析PCA原理以及特征

一、PCA原理 原始数据 x ∈ R N x\in R^N x∈RN&#xff0c;经过PCA投影后的数据 y A x &#xff0c; y ∈ R P yAx&#xff0c;y\in R^P yAx&#xff0c;y∈RP 其中&#xff0c; A ∈ R P N A\in R^{P\times N} A∈RPN 二、PCA特征 1、降低数据的维度 2、提取数据的特征…

imx6ull----IIC--AP3216C

概念 IIC总共有两条线&#xff0c;一条是 SCL(串行时钟线)&#xff0c;另外一条是 SDA(串行数据线)&#xff0c;这两条数据线需要接上拉电阻&#xff0c;总线空闲的时候 SCL 和 SDA 处于高电平。 I2C 总线标准模式下速度可以达到 100Kb/S&#xff0c;快速模式下可以达到 400Kb…

嵌入式Linux driver开发实操(十七):Linux Media Infrastructure userspace API

视频和无线电流媒体设备使用的Linux内核到用户空间API,包括摄像机、模拟和数字电视接收卡、AM/FM接收卡、软件定义无线电(SDR)、流捕获和输出设备、编解码器设备和遥控器。典型的媒体设备硬件如下: 媒体基础设施API就是用于控制此类设备的,分五个部分。 第一部分V4L2 API…

Postman 工具发送请求的技巧与实践

在开发和测试 API 时&#xff0c;发送 JSON 格式的请求是一个常见需求。 在 Postman 中构建和发送 JSON 请求 创建一个新的请求 首先&#xff0c;在 Postman 启动界面上找到并点击 “New” 按钮&#xff0c;选择 “HTTP Request” 来开始新建一个请求。这一步骤允许你定义请…

解决office2016专业增强版 “你的许可证并非正版,你可能是盗版软件的受害者“

问题描述&#xff1a;安装完office后,用kms已经激活成功&#xff0c;但是一直在上面显示“你的许可证不是正版&#xff0c;并且你可能是盗版软件的受害者&#xff0c;使用正版Office,避免干扰并保护你的文件安全。” 尝试过网上的各种方法都没用&#xff0c;后面发现是用的HEU …

低代码开发之腾讯云微搭工具

低代码开发之腾讯云微搭工具 微搭简介诞生缘由开发模式如何创建组件模块介绍实例讲解url传参级联联动使用事件其他方法调用数据源方法 callDataSource触发流程 callProcess 引入外部css/js代码编辑器的使用Handler 方法使用介绍Style 用法示例LifeCycle 生命周期介绍 数据模型方…

2024年航空航天与工业技术国际学术会议(IACAIT 2024)

2024年航空航天与工业技术国际学术会议(IACAIT 2024) 2024 International Conference on Aerospace and Industrial Technology 一、【会议简介】 2024年航空航天与工业技术国际学术会议&#xff0c;将汇集全球顶尖专家&#xff0c;探讨前沿技术。 这次会议主题为“航空航天与…

idea - 配置模板消息

这是要用到的模板代码 " $DATE$ 自定义表示参数&#xff0c;后续会定义参数的值" " $END$ 表示应用该模板后&#xff0c;光标的位置"/**** author lyj* date $DATE$*/Testpublic void test$END$(){}这是配置完之后&#xff0c;输入test然后回车&#xff0c…

如何使用 Dolphin Anty 设置代理

文章目录 Dolphin Anty是什么? 为什么要使用代理? 使用 Dolphin Anty 浏览器设置 Smartdaili 代理 与动态住宅代理集成 与数据中心代理集成 Dolphin Anty 中的配置 Smartdaili 代理与 Dolphin Anty 反检测浏览器 Dolphin Anty 和 Smartdaili 代理服务可帮助你增强数字身份保护…