使用大型语言模型微调命名实体识别

目标

这里探索了借助大型语言模型微调进行命名实体识别的标注。

定义了一套电力领域的命名实体类型:

  • Province: 省份。例如:山东省。
  • City: 城市。例如:济南市、济南。
  • Company: 供电公司。例如:长清区供电公司、市中供电中心。
  • Substation: 供电所。例如:崮山供电所。
  • Indicator: 指标。例如:投诉、意见。
  • Date: 日期。例如:今天、昨天、今年、去年、本周、上周、本月、上月、3月、本季度、上季度、一季度、今年第一季度、2022年、2024年5月。

对用户的输入进行命名实体识别标注,输出的结果应该包含所有的电力领域实体类型的实例。

  • 山东省菏泽巨野县供电公司麒麟供电所投诉数量

<Province>山东省</Province><City>菏泽</City><Company>巨野县供电公司</Company><Substation>麒麟供电所</Substation><Indicator>投诉</Indicator>数量

  • 菏泽巨野县供电公司麒麟供电所投诉数量

<City>菏泽</City><Company>巨野县供电公司</Company><Substation>麒麟供电所</

使用大型语言模型微调命名实体识别生成

目标

这里探索了借助大型语言模型进行命名实体识别的标注,并在缺少相关类型实体的时候可以自动生成。

定义了一套电力领域的命名实体类型:

  • Province: 省份。例如:山东省。
  • City: 城市。例如:济南市、济南。
  • Company: 供电公司。例如:长清区供电公司、市中供电中心。
  • Substation: 供电所。例如:崮山供电所。
  • Indicator: 指标。例如:投诉、意见。
  • Date: 日期。例如:今天、昨天、今年、去年、本周、上周、本月、上月、3月、本季度、上季度、一季度、今年第一季度、2022年、2024年5月。

理想的情况下的输入可能是这样的:{DATE}山东省菏泽巨野县供电公司麒麟供电所投诉数量

但是用户的输入是多种多样的:

  • 山东省菏泽巨野县供电公司麒麟供电所投诉数量
  • 菏泽巨野县供电公司麒麟供电所投诉数量
  • 菏泽巨野投诉数量
  • 菏泽麒麟投诉数量
  • 巨野县供电公司麒麟供电所投诉数量
  • 巨野麒麟投诉数量
  • 巨野投诉数量
  • 麒麟供电所投诉数量
  • 麒麟投诉数量

通过微调后的模型可以生成如下实体标注: <Date>本月</Date><Province>山东省</Province><City>菏泽</City><Company>巨野县供电公司</Company><Substation>麒麟供电所

使用大型语言模型进行命名实体识别

总结

  • Qwen 模型的指令遵循还是差强人意,这里使用的参数应该是 72B
  • 大型语言模型发挥了它的生成能力,会在原文的基础上给你增加内容,如:济南
  • 问题变化多样,示例也不可能覆盖所有的情况,写的越多占用的上下文长度越大。
  • 在实验二中
    • 明确说明Date实体类型的值,并没有很好的识别出来,如:3月识别为Month一季度识别为Quarter今年识别为Year。这个跟模型有关,ChatGPT就识别的不错。
  • 在实验三中
    • 明确说明不要增加实体类型,但还是增加了,如:County实体类型。
    • 识别的实体有重叠文字,如:曹县曹县供电公司
    • 位置很容易出错,一旦出错后面的实体位置都是错误的了。
  • 使用XML标记方式比输出json结果方式效果更好。

代码 from langchain_core.output_parsers import StrOutputParser from langchain_core.prompts import PromptTemplate from langchain_core.runnables import RunnablePassthrough from langchain_community.chat_models.

LLaMA-Factory 微调 Text2SQL

安装 LLaMA-Factory

git clone https://github.com/hiyouga/LLaMA-Factory.git
cd LLaMA-Factory

python -m venv env
source env/bin/activate

pip install -e .[metrics]

下载模型

git clone https://www.modelscope.cn/qwen/Qwen1.5-4B-Chat.git

自定义数据集

data/text2sql.json [ { "instruction": "You are an SQLite database expert. Help users write SQL statements based on the following table schema.

Gradio DataFrame

Gradio DataFrame

import pandas as pd
import gradio as gr

def read_csv_from_text2sql(file_path="data/text2sql.csv"):
    try:
        df = pd.read_csv(file_path)
        return df
    except Exception as e:
        return pd.DataFrame([{"error": f"❌ {e}"}])

def selected_text2sql_dataframe(selected_index: gr.SelectData, df: gr.DataFrame):
    selected_row = df.iloc[selected_index.index[0]]
    text = selected_row.get('Text', '')
    sql = selected_row.get('SQL', '')
    return text, sql

with gr.Blocks() as demo:
    # UI
    upload_button = gr.UploadButton(label="上传 Text2SQL CSV 文件", 
                                    file_types = ['.csv'], 
                                    file_count = "single")
    df_text2sql = gr.Dataframe(headers=["Text", "SQL"], 
                                type="pandas", 
                                col_count=2, 
                                value=read_csv_from_text2sql,
                                interactive=False)
    with gr.Row():
        textbox_text = gr.Textbox(label="Text", lines=4)
        textbox_sql = gr.Textbox(label="SQL", lines=4)

    # Event
    upload_button.upload(fn=read_csv_from_text2sql, 
                            inputs=upload_button, 
                            outputs=df_text2sql)
    df_text2sql.select(fn=selected_text2sql_dataframe,
                        inputs=df_text2sql,
                        outputs=[textbox_text, textbox_sql])

demo.queue(api_open=False)
demo.launch(max_threads=30)

Gradio Chatbot

Gradio Chatbot

DashScope

import os
import pandas as pd
import gradio as gr
from http import HTTPStatus
from dashscope import Generation
from dashscope.api_entities.dashscope_response import Role
from typing import List, Optional, Tuple, Dict, Generator
from urllib.error import HTTPError


DEFAULT_SYSTEM = '您是一个有用的助手。'

History = List[Tuple[str, str]]
Messages = List[Dict[str, str]]

// ...

LangChain ChatTongyi

Meta Llama 3

Llama3

模型

下载

数据集

HuggingFaceH4/no_robots

No Robots 是由熟练的人类注释者创建的包含 10,000 条指令和演示的高质量数据集。该数据可用于监督微调(SFT),使语言模型更好地遵循指令。 No Robots 是根据 OpenAI 的 InstructGPT 论文中描述的指令数据集进行建模的。

介绍 Llama 3 最大的变化是采用了新的 Tokenizer,将词汇表大

Anthropic Claude

Claude 3 模型

模型 模型名称 价格(MTok) 能力
Opus claude-3-opus-20240229 Input: 15<br>Output:15<br>Output:75 处理复杂的分析、多步骤的长期任务,以及更高阶的数学和编码任务
Sonnet claude-3-sonnet-20240229 Input: 3<br>Output:3<br>Output:15 适用于高效、高吞吐量的任务
Haiku claude-3-haiku-20240307 Input: 0.25<br>Output:0.25<br>Output:1.25 执行轻量级操作,速度领先行业
  • MTok = million tokens.(百万 Token)
  • 所有 Claude 3 模型都支持视觉和 200,000 个 Token 上下文窗口。

例子

LangChain : SQL Chain & SQL Agent

SQL Chain

from datetime import datetime
from operator import itemgetter

from langchain.chains import create_sql_query_chain

from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.runnables import RunnableLambda

from langchain_community.chat_models.tongyi import ChatTongyi
from langchain_community.utilities import SQLDatabase
from langchain_community.tools.sql_database.tool import QuerySQLDataBaseTool


// ...

LangChain : Tagging and Extraction Using OpenAI functions

Extraction

from enum import Enum
from typing import Optional, Type
from langchain.pydantic_v1 import BaseModel, Field


class ProvinceEnum(str, Enum):
    """省、直辖市、自治区"""
    山东省 = "山东省"

class CityEnum(str, Enum):
    """山东省地级市"""
    济南 = "济南"
    青岛 = "青岛"
    淄博 = "淄博"
    枣庄 = "枣庄"
// ...

OpenAI

from langchain_openai import ChatOpenAI

model = ChatOpenAI(temperature=0).bind(
    functions=functions,
    function_call={"name": PowerSupplyStationLocation.__name__}
)

response = model.invoke(prompt)
print(response)

LangChain Chat Models Function & Tool Calling

Chat Models Functions & Tools

Model Function Calling Tool Calling Python Package
ChatOpenAI langchain-openai
ChatTongyi langchain-community
ChatOllama langchain-community
OllamaFunctions langchain-experimental

自定义工具

在构建自己的代理时,您需要为其提供一个工具列表,供其使用。除了实际调用的函数之外,工具还包括几个组件:

  • name (str):是必需的,并且在提供给代理的一组工具中必须是唯一的。
  • description (str):可选,但建议提供,因为代理使用它来确定工具的使用。
  • args_schema (Pydantic BaseModel):可选,但建议提供,可用于提供更多信息(例如,少量示例)或对预期参数进行验证。

定义 Function

DashScope 模型服务灵积

DashScope 模型服务灵积

让大模型能力触达每位开发者

灵积模型服务建立在“模型即服务”(Model-as-a-Service,MaaS)的理念基础之上。

灵积通过灵活、易用的模型API服务,让各种模态模型的能力,都能方便的为AI开发者所用。通过灵积API,开发者不仅可以直接集成大模型的强大能力,也可以对模型进行训练微调,实现模型定制化。

通义千问大型语言模型

模型 描述 上下文长度 计量单价
qwen-turbo 通义千问超大型语言模型,支持中文、英文等不同语言输入。 8k 0.008元/1000 tokens
qwen-plus 通义千问超大型语言模型增强版,支持中文、英文等不同语言输入。 32k 0.02元/1000 tokens
qwen-max 通义千问千亿级别超大型语言模型,支持中文、英文等不同语言输入。 8k 0.12元/1000 tokens
qwen-max-longcontext 通义千问千亿级别超大型语言模型,支持中文、英文等不同语言输入。 30k 0.12元/1000 tokens
qwen-72b-chat 通义千问开源 720 亿参数大型语言模型 8k 0.02元/1000 tokens
qwen1.5-72b-chat 通义千问开源 720 亿参数大型语言模型 32k

LangChain 调用

LangChain Text2SQL Agent

OpenAI Function Call (Extraction)

这个方法只有 OpenAI 的模型支持。

from langchain.agents import tool
from langchain.chat_models import ChatOpenAI
from langchain.tools.render import format_tool_to_openai_function

from langchain.pydantic_v1 import BaseModel, Field
from enum import Enum


# 省份、直辖市
class ProvinceEnum(str, Enum):
    山东省 = "山东省"
    # 其它省份


# 山东省地级市
// ...

OpenAI gpt-3.

LangChain

介绍

LangChain 是一个用于开发由大型语言模型(LLM)支持的应用程序的框架。

LangChain 简化了 LLM 应用程序生命周期的每个阶段:

  • 开发(Development):使用 LangChain 的开源构建块和组件构建您的应用程序。使用第三方集成和模板快速启动。
  • 生产化(Productionization):使用 LangSmith 检查、监控和评估您的链,以便您可以持续优化并放心部署。
  • 部署(Deployment):使用 LangServe 将任何链转换为 API。

具体来说,该框架由以下开源库组成:

  • langchain-core: 基本抽象和 LangChain 表达语言(LangChain Expression Language)。
  • langchain-community: 第三方集成。
    • 合作伙伴包(例如 langchain-openai、langchain-anthropic 等):一些集成已进一步拆分为自己的轻量级包,这些包仅依赖于 langchain-core。
  • langchain: 构成应用程序认知架构(Cognitive Architecture)的链(Chains)、代理(Agents)和检索策略(Retrieval Strategies)。
  • langgraph: 通过将步骤建模为图中的边和节点,使用 LLM 构建强大且有状态的多参与者应用程序。
  • langserve: 将 LangChain 链部署为 REST API。

Functions, Tools and Agents with LangChain

OpenAI Function Calling (OpenAI 函数调用)

import os
import openai
import json

from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file
openai.api_key = os.environ['OPENAI_API_KEY']


# Example dummy function hard coded to return the same weather
# In production, this could be your backend API or an external API
def get_current_weather(location, unit="fahrenheit"):
    """Get the current weather in a given location"""
    weather_info = {
        "location": location,
        "temperature": "72",
        "unit": unit,
        "forecast": ["sunny", "windy"],
    }
    return json.dumps(weather_info)

# define a function
functions = [
    {
        "name": "get_current_weather",
        "description": "Get the current weather in a given location",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "The city and state, e.g. San Francisco, CA",
                },
                "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
            },
            "required": ["location"],
        },
    }
]

messages = [
    {
        "role": "user",
        "content": "What's the weather like in Boston?"
    }
]

response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=messages,
    functions=functions
)
print(response)
{
  "id": "chatcmpl-9CK2or9rtxzcsVgbfwWmIvqi36wF0",
  "object": "chat.completion",
  "created": 1712724014,
  "model": "gpt-3.5-turbo-0125",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": null,
        "function_call": {
          "name": "get_current_weather",
          "arguments": "{\"location\":\"Boston\",\"unit\":\"celsius\"}"
        }
      },
      "logprobs": null,
      "finish_reason": "function_call"
    }
  ],
  "usage": {
    "prompt_tokens": 82,
    "completion_tokens": 20,
    "total_tokens": 102
  },
  "system_fingerprint": "fp_b28b39ffa8"
}