LangChain入门学习笔记(五)—— Model I/O之Chat Models

在LangChain的组件当中,Chat Models可以说跟LLMs占据着相同的“生态位”,它也是根据用户输入的提示内容,调用底层的大模型产生内容。与LLMs不同的是,LangChain的Chat Models主要有如下一些不同:

  • 输入输出格式不同:LLMs通常接受单一的文本提示语,而Chat Models则接受一系列的Messages作为提示输入上下文,里面除了内容外还区分输入的不同角色。
  • 应用的场景不同:LLMs通常用于文本处理,比如问答、总结和创作;而Chat Models更强调的是上下文的理解和跟踪对话,引入了更多的对话逻辑。
  • 使用成本不同:针对Chat Models的使用,大模型提供商在内部结构上做了优化,这使得它的推理成本会比通用的LLMs更高。

Message类型

如前所述,Messages是Chat Models的主要输入类型,通过Messages我们可以给后端的大模型提供必要的角色和信息内容。在介绍Chat Models的使用前,先学习一下Messages的类型,便于后面的使用理解。

所有的Message都有两个属性:

  • Role:role表示这条message是谁“说”的,不同类型的Message具有不同的role。
  • Content:表示这条message的内容,即消息的文本。

根据这2个属性可以构造不同类型的Message。

Messages的主要类型见下表:

Message类型作用说明
HumanMessage表示“人”的消息,可以认为是使用者输入的信息,是对话的起点。
AIMessage表示模型的消息,是语言模型生成的响应消息,可以认为是对HumanMessage的回复。
SystemMessage

表示给予语言模型的系统指令,告知大模型该以怎样的行为响应。一般用来设置语言模型的身份、任务和语气等。

并不是每个LangChain支持的大模型都支持这个类型。

FunctionMessage表示一个可执行函数或工具的调用结果。除了role和content,本类型消息还有一个name参数,用来传达用于生成此结果的函数名称。
ToolMessage与FunctionMessage类似,表示工具调用的结果。此类型的message携带tool_call_id参数表示生成该结果的工具id。

Chat Models基本使用

作为Runnable的子类,Chat Models的使用和LLMs大同小异,主要的不同就是构造Messages对象,如下面代码所示:

from langchain_community.chat_models import ChatOllama
from langchain_core.messages import SystemMessage, HumanMessage

# 构造Messages对象,提供系统信息(SystemMessage)和用户信息(HumanMessage)。
messages = [
    SystemMessage(content="You're a helpful assistant"),
    HumanMessage(content="What is the purpose of model regularization?"),
]

# 使用的是ChatOllama类,而非Ollama
chat = ChatOllama(model="llama3")

# 返回的是AIMessage对象
response = chat.invoke(messages)

# 打印AIMessage对象的content内容
print(response.content)

当传入messages给到Chat Model的invoke方法后,返回结果在AIMessage的response对象里。打印content的内容结果如下:

与前面介绍的LLMs直接返回str类型的结果不同,Chat Models输出的结果是Chat Message,因此,如果只想要大模型回答的结果内容,需要访问content字段。

流式传输

所有实现了Runnable接口的Chat Models都默认支持ainvoke/batch/abatch/stream/astream方法。流式传输支持返回结果的iterator,这样可以用迭代的方式输出结果:

比如上面的代码调用invoke部分改成:

for trunk in chat.stream(messages):
    print(trunk.content, end="", flush=True)

最终结果一致,只是输出是迭代的流式输出。

自定义Chat Model

与自定义LLM类似,自定义Chat Model需要继承BaseChatModel,并实现方法:

  • _generate:用于根据输入的提示语生成结果。
  • _llm_type:返回属性字符串,用来唯一标志模型类型名称。

还有一些可选接口方法:

  • _agenerate:_generate的异步版本。
  • _stream / _astream:流式传输的同步/异步版本。
  • _identifying_params:用于追踪目的的模型参数属性值。

下面定义一个自定义的Chat Model叫做MyCustomChatModel,为了简单示例,这里对任何输入都返回固定的字符串:

from typing import Any, List, Optional

from langchain_core.callbacks import (
    CallbackManagerForLLMRun,
)
from langchain_core.language_models import BaseChatModel
from langchain_core.messages import BaseMessage, AIMessage
from langchain_core.outputs import ChatGeneration, ChatResult


class MyCustomChatModel(BaseChatModel):
    def _generate(
        self,
        messages: List[BaseMessage],
        stop: Optional[List[str]] = None,
        run_manager: Optional[CallbackManagerForLLMRun] = None,
        **kwargs: Any,
    ) -> ChatResult:
        # 这里实现自己的生成逻辑,此处仅作举例所以输出固定字符串
        tokens = "I don't want to answer any question from you"
        message = AIMessage(
            content=tokens,
            additional_kwargs={},  # Used to add additional payload (e.g., function calling request)
            response_metadata={  # Use for response metadata
                "time_in_seconds": 3,
            },
        )

        generation = ChatGeneration(message=message)
        return ChatResult(generations=[generation])

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


# 使用自定义的Chat Model
chat = MyCustomChatModel()

response = chat.invoke("tell me a joke about bear")
print(response.content)

结果打印如下: 

响应元数据(Response metadata)

在模型返回AIMessage中,还有一些额外的信息,模型提供商会将它们记录在AIMessage的response_metadata属性中。

使用很简单,如下直接调用ChatModel返回的AIMessage对象的response_metadata属性:

print(response.response_metadata)

在ChatOllama中返回如下(json格式化处理过):

{
  "model": "llama3",
  "created_at": "2024-06-19T13:02:40.297019706Z",
  "message": {
    "role": "assistant",
    "content": ""
  },
  "done_reason": "stop",
  "done": true,
  "total_duration": 13890899022,
  "load_duration": 7291480563,
  "prompt_eval_count": 27,
  "prompt_eval_duration": 124457000,
  "eval_count": 355,
  "eval_duration": 6327830000
}

不同提供商具体提供了哪些内容,需要查阅对应厂家的文档。通过response_metadata,有些厂家提供了Token使用的统计数据,有些提供了日志相关信息。

缓存(Caching)

具体使用和LLMs类似,具体使用方法可以参看《LangChain入门学习笔记(四)—— Model I/O之LLMs》的缓存部分。

  • 23
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你好!感谢提问。下面是有关 K210 学习笔记五中串口通信的一些内容: 在 K210 开发板上,串口是一种常见的通信接口,用于将数据从一个设备传输到另一个设备。串口通信通常使用 UART (Universal Asynchronous Receiver/Transmitter) 协议。 要在 K210 上进行串口通信,首先需要使用两个引脚:一个用于接收数据(RX),一个用于发送数据(TX)。这些引脚可以通过 GPIO 端口与外部设备连接。 在 K210 的开发环境中,可以使用 MaixPy 或者 Kendryte Standalone SDK 进行串口编程。 在 MaixPy 中,可以使用 `uart` 模块来进行串口通信。例如,要初始化一个串口对象并设置波特率为 115200,可以使用以下代码: ```python from machine import UART uart = UART(UART.UART1, 115200) ``` 然后,可以使用 `uart.write()` 函数发送数据,使用 `uart.read()` 函数接收数据。例如: ```python uart.write("Hello, world!\n") data = uart.read(10) ``` 在 Kendryte Standalone SDK 中,可以使用 `uart.h` 头文件中的函数来进行串口通信。例如,要初始化一个串口对象并设置波特率为 115200,可以使用以下代码: ```c #include "uart.h" uart_init(UART_DEVICE_1, 115200); ``` 然后,可以使用 `uart_send_data()` 函数发送数据,使用 `uart_receive_data()` 函数接收数据。例如: ```c uart_send_data(UART_DEVICE_1, "Hello, world!\n", 14); char buffer[10]; uart_receive_data(UART_DEVICE_1, buffer, 10); ``` 以上是关于 K210 学习笔记五中串口通信的简要介绍。如果你有更具体的问题,请随时提问!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值