目标

模型入门

Langchain 2.0 都找不到下面这个图了,藏到了1.0 里面…

语言模型是核心,我们需要熟悉跟语言模型相关的消息:系统消息、AI消息、Human消息、工具消息…

image-20240627100437691

llm vs chatModel

百度千帆

对话

1
2
3
4
5
6
7
chat_comp = qianfan.ChatCompletion(access_key="...", secret_key="...")

# 调用默认模型,即 ERNIE-Bot-turbo
resp = chat_comp.do(messages=[{
"role": "user",
"content": "你好"
}])

完成

1
2
3
4
5
6
7
8
9
comp = qianfan.Completion()

resp = comp.do(model="ERNIE-Bot", prompt="你好")
# 输出:你好!有什么我可以帮助你的吗?

# 续写功能同样支持流式调用
resp = comp.do(model="ERNIE-Bot", prompt="你好", stream=True)
for r in resp:
print(r['result'])

Azure Openai

完成

1
2
3
4
start_phrase = 'Write a tagline for an ice cream shop. '
response = openai.Completion.create(engine=deployment_name, prompt=start_phrase, max_tokens=10)
text = response['choices'][0]['text'].replace('\n', '').replace(' .', '.').strip()
print(start_phrase+text)

对话

1
2
3
4
5
6
7
8
9
response = openai.ChatCompletion.create(
engine="gpt-35-turbo", # engine = "deployment_name".
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Does Azure OpenAI support customer managed keys?"},
{"role": "assistant", "content": "Yes, customer managed keys are supported by Azure OpenAI."},
{"role": "user", "content": "Do other Azure AI services support this too?"}
]
)

消息 ChatModels 接收一个消息列表作为输入,并返回一个消息。消息有几种不同的类型。所有消息都有一个角色(role)和一个内容(content)属性。角色描述了是谁在说话。LangChain 为不同的角色提供了不同的消息类。内容属性描述了消息的内容。这可以是以下几种不同的东西:

  • 一个字符串(大多数模型都是这种方式)
  • 一个字典列表(这用于多模态输入,其中字典包含有关该输入类型和位置的信息) 此外,消息还有一个 additional_kwargs 属性。这是传递关于消息的额外信息的地方。这主要用于特定于提供商的输入参数,而不是通用的。最著名的例子是 OpenAI 的 function_call。

人类消息(HumanMessage) 这代表用户的消息。通常只包含内容。

AI消息(AIMessage) 这代表模型的消息。这可能有 additional_kwargs ——例如,如果使用 OpenAI 函数调用,则可能有 functional_call。

系统消息(SystemMessage) 这代表系统消息。只有一些模型支持这个。这告诉模型如何表现。这通常只包含内容。

函数消息(FunctionMessage) 这代表函数调用的结果。除了角色和内容之外,这个消息还有一个 name 参数,它传达了产生这个结果的函数的名称。

工具消息(ToolMessage) 这代表工具调用的结果。这与 FunctionMessage 是不同的,以匹配 OpenAI 的函数和工具消息类型。除了角色和内容之外,这个消息还有一个 tool_call_id 参数,它传达了产生这个结果的工具调用的 id。


函数调用 function call

定义函数: 将2个数相加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function = {
"name": "add_two_int",
"description": "将输入的2个整数相加",
"parameters": {
"type": "object",
"properties": {
"int_a": {
"description": "一个整数",
"type": "string"
},
"int_b": {
"description": "一个整数",
"type": "string"
},
},
"required": ["int_a", "int_b"]
},
}

绑定模型

1
2
3
4
chat_with_tools = azure_chat.bind(
function_call={"name": "add_two_int"}, functions=[function]
)
res = chat_with_tools.invoke("3加18等于多少")

结果

1
2
{'function_call': 
{'arguments': '{\n "int_a": "3",\n "int_b": "18"\n}', 'name': 'add_two_int'}}

绑定运行时参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 运行时配置参数
res = azure_chat.with_config(configurable={"llm_temperature": 0.9}).invoke("给出一个随机数")


# 配置多个模型,运行时根据需求调用
llm = QianfanChatEndpoint(temperature=0.7).configurable_alternatives(

# 设置可以配置的项目
ConfigurableField(id="llm"),
# 设置缺省值,默认用百度
default_key="baidu4",
# 可以选择 Azure OpenAI
azure_openai=azure_chat,
)
chain = prompt | llm
# 调用百度
res_ = chain.with_config(configurable={"llm": "baidu4"}).invoke({"product": "铅笔"})

# 调用 Azure Opena
res_ = chain.with_config(configurable={"llm": "azure_openai"}).invoke({"product": "铅笔"})

聊天模型接受消息作为输入,并返回一个消息作为输出。 LangChain 有一些内置的消息类型: 系统消息(SystemMessage):用于引导 AI 行为,通常作为输入消息序列中的第一个消息传递。 人类消息(HumanMessage):代表与聊天模型互动的人的消息。 AI消息(AIMessage):代表聊天模型的消息。这可以是文本或调用工具的请求。 函数消息/工具消息(FunctionMessage / ToolMessage):用于将工具调用的结果传递回模型的消息。

让chat 有记忆:维护一个消息列表

1
2
3
4
5
6
7
8
9
response = openai.ChatCompletion.create(
engine="gpt-35-turbo", # engine = "deployment_name".
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Does Azure OpenAI support customer managed keys?"},
{"role": "assistant", "content": "Yes, customer managed keys are supported by Azure OpenAI."},
{"role": "user", "content": "Do other Azure AI services support this too?"}
]
)

在提示词中保存对话内容

1
2
3
4
5
6
7
8
9
10
11
12
13
prompt = ChatPromptTemplate.from_messages(
[
("system", "你是AI助手"),
MessagesPlaceholder(variable_name="history"), <---虚位以待
("human", "{input}"),
]
)

memory = ConversationBufferMemory(return_messages=True) <-- 想象成一个list
res = memory.load_memory_variables({})

------
# 内容 {'history': []}

保存对话记录

1
2
3
4
5
6
inputs = {"input": "你好!我是茉卷"}
response = chain.invoke(inputs)

memory.save_context(inputs, {"output": response.content})
res = memory.load_memory_variables({})

1
2
3
    inputs = {"input": "我叫什么名字"}
response = chain.invoke(inputs)
content='你叫茉卷。如果你有其他疑问或者需要帮助,请随时告诉我,我会尽力为你服务。' additional_kwargs={'finish_reason': 'normal', 'request_id': 'as-jjdgubp1k9', 'object': 'chat.completion', 'search_info': []} response_metadata={'finish_reason': 'normal', 'id': 'as-jjdgubp1k9', 'object': 'chat.completion', 'created': 1711101413, 'result': '你叫茉卷。如果你有其他疑问或者需要帮助,请随时告诉我,我会尽力为你服务。', 'is_truncated': False, 'need_clear_history': False, 'usage': {'prompt_tokens': 37, 'completion_tokens': 19, 'total_tokens': 56}}

本质是一个list [], 不断往里面增加

{‘role’:’user’, ‘content’:’…’}

{‘role’:’assistent’, ‘content’:’…’}

![image.png]([Vol][6]+语言模型+f5d8e690-b777-4214-8b28-491bf3ce268c/image 2.png)


计算token 数量

1
2
3
4
5
6
# callback : token 计算
from langchain.callbacks import get_openai_callback
with get_openai_callback() as cb:
result = azure_chat.invoke("Tell me a joke")
print(cb)
pass

结果

1
2
3
4
5
Tokens Used: 34
Prompt Tokens: 11
Completion Tokens: 23
Successful Requests: 1
Total Cost (USD): $6.25e-05 ($0.0000625)

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
import os
import uuid
from langchain.memory import ConversationBufferMemory
from langchain_community.chat_models.azure_openai import AzureChatOpenAI
from langchain_community.chat_models.baidu_qianfan_endpoint import QianfanChatEndpoint
from langchain_community.embeddings import QianfanEmbeddingsEndpoint
from langchain_community.llms.baidu_qianfan_endpoint import QianfanLLMEndpoint
from langchain_community.vectorstores.chroma import Chroma
from langchain_core.messages import HumanMessage, SystemMessage
from langchain_core.output_parsers import StrOutputParser, CommaSeparatedListOutputParser
from langchain_core.prompt_values import ChatPromptValue
from langchain_core.prompts import ChatPromptTemplate, PromptTemplate, MessagesPlaceholder
from langchain_core.runnables import RunnablePassthrough, RunnableParallel, RunnableLambda, ConfigurableField

from operator import itemgetter
from langchain_core.pydantic_v1 import BaseModel, Field


if __name__ == '__main__':

os.environ["QIANFAN_ACCESS_KEY"] = os.getenv('MY_QIANFAN_ACCESS_KEY')
os.environ["QIANFAN_SECRET_KEY"] = os.getenv('MY_QIANFAN_SECRET_KEY')

unique_id = uuid.uuid4().hex[0:8]
os.environ["LANGCHAIN_PROJECT"] = f" [返回docs]轨迹 - {unique_id}"
os.environ["LANGCHAIN_TRACING_V2"] = 'true'
os.environ["LANGCHAIN_API_KEY"] = os.getenv('MY_LANGCHAIN_API_KEY')

# chat
chat_model = QianfanChatEndpoint(
model="ERNIE-Bot-4"
)

# llm
llm = QianfanLLMEndpoint(model="ERNIE-Bot-4")

text = "讲一个狗熊的笑话"
messages = [HumanMessage(content=text)]

llm_res = llm.invoke(text)

# chat_res = chat_model.invoke(messages)


# 提示词 PromptTemplate
prompt = PromptTemplate.from_template("生产 {product} 的公司在哪里?")
prompt.format(product="袜子")

# ChatPromptTemplate
template = "你是个专业的翻译,你把 {input_language} 翻译到 {output_language}."
human_template = "{text}"

chat_prompt = ChatPromptTemplate.from_messages([
("system", template),
("human", human_template),
])

chat_prompt.format_messages(input_language="English", output_language="Chinese", text="I love programming.")

# 消息
messages = [
SystemMessage(content="你是一个AI助手"),
HumanMessage(content="今天有什么新闻?"),
]

# invoke
res = chat_model.invoke(messages)

# stream
for chunk in chat_model.stream(messages):
print(chunk.content, end="", flush=True)

# function call
class Multiply(BaseModel):
""" 将2个数相加"""

a: int = Field(..., description="第一个整数")
b: int = Field(..., description="第二个整数")

# langchain的百度接口不支持
os.environ["AZURE_OPENAI_API_KEY"] = os.getenv('MY_AZURE_OPENAI_API_KEY')
os.environ["AZURE_OPENAI_ENDPOINT"] = os.getenv('MY_AZURE_OPENAI_ENDPOINT')
DEPLOYMENT_NAME_GPT3P5 = os.getenv('MY_DEPLOYMENT_NAME_GPT3P5')
azure_chat = AzureChatOpenAI(
openai_api_version="2024-02-15-preview",
azure_deployment=DEPLOYMENT_NAME_GPT3P5,
)

function = {
"name": "add_two_int",
"description": "将输入的2个整数相加",
"parameters": {
"type": "object",
"properties": {
"int_a": {
"description": "一个整数",
"type": "string"
},
"int_b": {
"description": "一个整数",
"type": "string"
},
},
"required": ["int_a", "int_b"]
},
}

# 绑定运行时参数
chat_with_tools = azure_chat.bind(
function_call={"name": "add_two_int"}, functions=[function]
)
# res = chat_with_tools.invoke("3加18等于多少")
pass

res = azure_chat.with_config(configurable={"llm_temperature": 0.9}).invoke("给出一个随机数")

llm = QianfanChatEndpoint(temperature=0.7).configurable_alternatives(

# 设置可以配置的项目
ConfigurableField(id="llm"),
# 设置缺省值,默认用百度
default_key="baidu4",
# 可以选择 Azure OpenAI
azure_openai=azure_chat,
)
chain = prompt | llm
# res_ = chain.with_config(configurable={"llm": "baidu4"}).invoke({"product": "铅笔"})
# res_ = chain.with_config(configurable={"llm": "azure_openai"}).invoke({"product": "铅笔"})
pass

#
prompt = ChatPromptTemplate.from_messages(
[
("system", "你是AI助手"),
MessagesPlaceholder(variable_name="history"),
("human", "{input}"),
]
)

memory = ConversationBufferMemory(return_messages=True)
res = memory.load_memory_variables({})
chain = (
RunnablePassthrough.assign(
history=RunnableLambda(memory.load_memory_variables) | itemgetter("history")
)
| prompt
| chat_model
)

inputs = {"input": "你好!我是茉卷"}
response = chain.invoke(inputs)

memory.save_context(inputs, {"output": response.content})
res = memory.load_memory_variables({})

# 测试记忆
inputs = {"input": "我叫什么名字"}
response = chain.invoke(inputs)
pass
memory.save_context(inputs, {"output": response.content})
res = memory.load_memory_variables({})
pass

# callback : token 计算
from langchain.callbacks import get_openai_callback
with get_openai_callback() as cb:
result = azure_chat.invoke("Tell me a joke")
print(cb)
pass