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

2024-04-25 17:12

本文主要是介绍LLM大语言模型(十二):关于ChatGLM3-6B不兼容Langchain 的Function Call,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 

背景

基于本地的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 = 8192do_sample: bool = Falsetemperature: float = 0.8top_p = 0.8tokenizer: object = Nonemodel: object = Nonehistory: List = []tool_names: List = []has_search: bool = Falsedef __init__(self):super().__init__()@propertydef _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 abcfrom typing import Type
from langchain.tools import BaseTool
from pydantic import BaseModel, Fieldclass 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] = CalculatorInputdef __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 = Truereturn f"""
Action: 
```
{json.dumps(action_json, ensure_ascii=False)}
```"""final_answer_json = {"action": "Final Answer","action_input": self.history[-1]["content"]}self.has_search = Falsereturn 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 historytools = [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博客

这篇关于LLM大语言模型(十二):关于ChatGLM3-6B不兼容Langchain 的Function Call的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/935297

相关文章

Golang的CSP模型简介(最新推荐)

《Golang的CSP模型简介(最新推荐)》Golang采用了CSP(CommunicatingSequentialProcesses,通信顺序进程)并发模型,通过goroutine和channe... 目录前言一、介绍1. 什么是 CSP 模型2. Goroutine3. Channel4. Channe

使用SQL语言查询多个Excel表格的操作方法

《使用SQL语言查询多个Excel表格的操作方法》本文介绍了如何使用SQL语言查询多个Excel表格,通过将所有Excel表格放入一个.xlsx文件中,并使用pandas和pandasql库进行读取和... 目录如何用SQL语言查询多个Excel表格如何使用sql查询excel内容1. 简介2. 实现思路3

Go语言实现将中文转化为拼音功能

《Go语言实现将中文转化为拼音功能》这篇文章主要为大家详细介绍了Go语言中如何实现将中文转化为拼音功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 有这么一个需求:新用户入职 创建一系列账号比较麻烦,打算通过接口传入姓名进行初始化。想把姓名转化成拼音。因为有些账号即需要中文也需要英

Go语言使用Buffer实现高性能处理字节和字符

《Go语言使用Buffer实现高性能处理字节和字符》在Go中,bytes.Buffer是一个非常高效的类型,用于处理字节数据的读写操作,本文将详细介绍一下如何使用Buffer实现高性能处理字节和... 目录1. bytes.Buffer 的基本用法1.1. 创建和初始化 Buffer1.2. 使用 Writ

深入理解C语言的void*

《深入理解C语言的void*》本文主要介绍了C语言的void*,包括它的任意性、编译器对void*的类型检查以及需要显式类型转换的规则,具有一定的参考价值,感兴趣的可以了解一下... 目录一、void* 的类型任意性二、编译器对 void* 的类型检查三、需要显式类型转换占用的字节四、总结一、void* 的

C语言线程池的常见实现方式详解

《C语言线程池的常见实现方式详解》本文介绍了如何使用C语言实现一个基本的线程池,线程池的实现包括工作线程、任务队列、任务调度、线程池的初始化、任务添加、销毁等步骤,感兴趣的朋友跟随小编一起看看吧... 目录1. 线程池的基本结构2. 线程池的实现步骤3. 线程池的核心数据结构4. 线程池的详细实现4.1 初

Python基于火山引擎豆包大模型搭建QQ机器人详细教程(2024年最新)

《Python基于火山引擎豆包大模型搭建QQ机器人详细教程(2024年最新)》:本文主要介绍Python基于火山引擎豆包大模型搭建QQ机器人详细的相关资料,包括开通模型、配置APIKEY鉴权和SD... 目录豆包大模型概述开通模型付费安装 SDK 环境配置 API KEY 鉴权Ark 模型接口Prompt

C++11的函数包装器std::function使用示例

《C++11的函数包装器std::function使用示例》C++11引入的std::function是最常用的函数包装器,它可以存储任何可调用对象并提供统一的调用接口,以下是关于函数包装器的详细讲解... 目录一、std::function 的基本用法1. 基本语法二、如何使用 std::function

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

Andrej Karpathy最新采访:认知核心模型10亿参数就够了,AI会打破教育不公的僵局

夕小瑶科技说 原创  作者 | 海野 AI圈子的红人,AI大神Andrej Karpathy,曾是OpenAI联合创始人之一,特斯拉AI总监。上一次的动态是官宣创办一家名为 Eureka Labs 的人工智能+教育公司 ,宣布将长期致力于AI原生教育。 近日,Andrej Karpathy接受了No Priors(投资博客)的采访,与硅谷知名投资人 Sara Guo 和 Elad G