LangChain组件(一) - 基础篇

LangChain内部提供了很多标准的、可以扩展的接口,以及集成了不少第三方工具,了解这些组件也是非常重要的,后面我们开发LangChain都需要使用到这些Component,下面我们介绍它们,后面会针对场景来介绍如何使用LangChain进行开发:

Chat models

第一次看到Chat models和LLMs有点搞不懂这两个有什么区别,我理解Chat models是用来逐步替代LLMs的。
它的输入是 messages,返回也是 messages(不是string)。支持为对话的消息赋予不同的roles,用来区分AI、users、system messages等。

不过为了能很好的替代LLMs,也支持接受strings作为输入,内部会将其转化为HumanMessage。

from langchain_openai import ChatOpenAI

model = ChatOpenAI(model="gpt-4")

from langchain_core.messages import HumanMessage, SystemMessage

messages = [
    SystemMessage(content="Translate the following from English into Italian"),
    HumanMessage(content="hi!"),
]

model.invoke(messages)

LLMs

LLMs 接受string作为输入,返回也是string。
其实目前通过LangChain的wrappers,也支持了接受message作为输入。

from langchain_openai import OpenAI

llm = OpenAI()

question = "What NFL team won the Super Bowl in the year Justin Beiber was born?"

llm.invoke(question)

看的出来,和ChatModels的输入类型,还是有区别的。

Messages

messages这个类型,无疑是非常的重要了,所有的messages都有几个属性需要注意:

  • role:描述WHO,saying了这个消息
  • content:消息的内容
    • string:大部分的消息类型都是如此
    • diction 列表:用于多模态输入,比如包括了input type,input location等
  • response_metadata:帮助我们更好的理解返回数据类型

HumanMessage

表示用户的输入message。

AIMessage

表示model的消息,除了content属性,这个消息也包括了response_metadata
tool_calls:这个字段也是可能由AIMessage生成的,表示的是需要调用工具了。

  • name:tool的名称
  • args:tool的参数
  • id:tool call的id

SystemMessage

其实是告诉model的角色,并非所有model支持。

FunctionMessage

function call的结果。除了rolecontent字段,还提供了name字段,告诉function的名字。

ToolMessage

表示的是tool call的结果。调用工具的时候,除了rolecontent,还会产生tool_call_id参数。

Prompt templates

用于将用户的input、parameters,翻译为instructions。
接受一个dictionary类型的input,每个key表示的是变量;输出的是PromptValue,这个PromptValue可以传给LLM、ChatModel,也可以转为string、message。

我们来看几种prompt templates

  • String PromptTemplates
    用于format一个string,通常用于简单的inputs。
from langchain_core.prompts import PromptTemplate

prompt_template = PromptTemplate.from_template("Tell me a joke about {topic}")

prompt_template.invoke({"topic": "cats"})
  • Chat PromptTemplates
    用于format一个messages列表,示例如下:
from langchain_core.prompts import ChatPromptTemplate

prompt_template = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant"),
    ("user", "Tell me a joke about {topic}")
])

prompt_template.invoke({"topic": "cats"})
  • MessagesPlaceholder
    这个也挺有用,主要用于将messages列表,添加到某个特别的地方。
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import HumanMessage, AIMessage

prompt_template = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant"),
    MessagesPlaceholder("msgs")
])

prompt_template.invoke({"msgs": [HumanMessage(content="hi!"), AIMessage(content="ciao!")]})

有意思的是,也可以用ChatPromptTemplate来实现。

prompt_template = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant"),
    ("placeholder", "{msgs}") # <-- This is the changed part
])

Example selectors

有时候希望提供一些样例,可以这么做:

from langchain.prompts.example_selector.base import BaseExampleSelector
from typing import Dict, List
import numpy as np

class CustomExampleSelector(BaseExampleSelector):    
    def __init__(self, examples: List[Dict[str, str]]):
        self.examples = examples
    
    def add_example(self, example: Dict[str, str]) -> None:
        """Add new example to store for a key."""
        self.examples.append(example)

    def select_examples(self, input_variables: Dict[str, str]) -> List[dict]:
        """Select which examples to use based on the inputs."""
        return np.random.choice(self.examples, size=2, replace=False)

examples = [
    {"foo": "1"},
    {"foo": "2"},
    {"foo": "3"}
]

# Initialize example selector.
example_selector = CustomExampleSelector(examples)

# Select examples
example_selector.select_examples({"foo": "foo"})
# -> array([{'foo': '2'}, {'foo': '3'}], dtype=object)

# Add new example to the set of examples
example_selector.add_example({"foo": "4"})
example_selector.examples
# -> [{'foo': '1'}, {'foo': '2'}, {'foo': '3'}, {'foo': '4'}]

# Select examples
example_selector.select_examples({"foo": "foo"})

Output parsers

指的是parsers,接收model的output,解析为更加结构化的内容。
越来越多的models,支持function/tool调用,建议优先使用function/tool调用,而非output parser

LangChain有很多的output parser,不过这里要解释一些概念,再来说明一下有哪些output parser

  • name:output parser 的名称
  • streaming的支持:output parser是否支持streaming
  • 是否有format指令:output parser是否有format指令
  • 是否调用LLM:output parser是否调用了LLM,一般用于纠正一些错误的格式
  • 输入类型:期望的输入类型。有一些functions需要message有具体的kwargs(关键字参数)
  • 输出类型:parser的输出类型
  • 描述:对outputparser的补充性描述
Name Supports Streaming Has Format Instructions Call's LLM Input Type Output Type Desc
Json Y Y Str/Message JSON Object
XML Y Y Str/Message dict
CSV Y Y Str/Message List[str]
OutputFixing Y Str/Message
RetryWithError Y Str/Message
Pydantic Y Str/Message pydantic.BaseModel
YAML Y Str/Message pydantic.BaseModel
PandasDataFrame Y Str/Message dict
Enum Y Str/Message Enum
Datatime Y Str/Message datetime.datetime
Structured Y Str/Message Dict[str, str]

Chat history

我们知道LLM有时候是需要了解对话历史的,这样方便上下文对话。
对话系统需要能够访问到past messages

ChatHistory可以用来包裹chain,会跟进inputs、outputs,将消息加入到一个message database,后面作为模型的输入。

from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.chat_history import BaseChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory

store = {}

def get_session_history(session_id: str) -> BaseChatMessageHistory:
    if session_id not in store:
        store[session_id] = ChatMessageHistory()
    return store[session_id]

conversational_rag_chain = RunnableWithMessageHistory(
    rag_chain,
    get_session_history,
    input_messages_key="input",
    history_messages_key="chat_history",
    output_messages_key="answer",
)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容