【学习LangChain】01. 模型(Models)

Andy Yang
33 min read3 days ago

--

随着 ChatGPT、Claude 和 Gemini 等聊天机器人的普及,生成式人工智能迅速融入了我们的日常生活。而作为这些技术的核心,LLM(大语言模型)也逐渐成为开发者的重要工具。LLM 能通过自然语言对话,实现摘要总结、扩写续写、信息提取、代码生成、逻辑推断等多种文本生成任务。

那么,如何在编程中方便地使用 LLM 呢?这就是本教程要介绍的 LangChain 框架的目标。通过 LangChain 框架,你可以轻松集成和使用 LLM,提高开发效率,让编程变得更简单。

与LLM对话

LLMs

在日常生活和工作中,我们使用ChatGPT、Claude、Grok等聊天机器人产品来与LLM对话。比如通过ChatGPT与GPT-4o模型对话:

通过Claude与Claude 3.5 Sonnet模型对话:

或者通过Grok与Llama3–8b-8192模型对话:

在代码中,应该如何与LLM对话呢?LangChain为我们封装好了不同的模块与类来实现,比如:

  • langchain_openai模块的ChatOpenAI类:OpenAI的ChatGPT系列LLM模型
  • langchain_anthropic模块的ChatAnthropic类:Anthropic的Claude系列LLM模型
  • langchain_groq模块的ChatGroq类:Grok的各种开源(Llama3、Mistral等)模型

完整支持的模型见链接🔗

ChatOpenAI

下面就以ChatOpenAI为例,看一个完整的、与LLM对话的例子:

# OpenAI Chat Model Documents: https://python.langchain.com/v0.2/docs/integrations/chat/openai/

from dotenv import load_dotenv
from langchain_openai import ChatOpenAI

# Load environment variables from .env
load_dotenv()

# Create a ChatOpenAI model
model = ChatOpenAI(model="gpt-4o")

# Invoke the model with a message
result = model.invoke("简要告知:应该如何开始学习LangChain?")
print("Full result:")
print(result)
print("Content only:")
print(result.content)
Full result:
content='开始学习LangChain可以按照以下几个步骤进行:\n\n1. **基本了解**:\n - **阅读文档**:首先,访问LangChain的官方网站或GitHub页面,阅读其文档和介绍,了解LangChain的基本概念和功能。\n - **示例项目**:查看一些示例项目,了解LangChain的应用场景和使用方法。\n\n2. **安装环境**:\n - **Python环境**:确保你的计算机上安装了Python环境(通常是Python 3.6以上)。\n - **安装LangChain**:使用pip来安装LangChain,可以在命令行中输入以下命令:\n ```bash\n pip install langchain\n ```\n\n3. **学习基础概念**:\n - **核心概念**:熟悉LangChain的核心概念和组件,如链(Chain)、节点(Node)、数据流(Data Flow)等。\n - **API使用**:了解并学习LangChain的API,学会如何调用和使用这些API来构建自己的数据处理链。\n\n4. **实践操作**:\n - **动手实验**:创建一些简单的项目或实验,尝试使用LangChain来解决实际问题。\n - **调试和优化**:在实践中调试和优化你的代码,理解LangChain的运行机制和性能优化方法。\n\n5. **社区和资源**:\n - **社区支持**:加入LangChain的社区(如论坛、Slack群组等),与其他用户交流心得,解决问题。\n - **学习资源**:查找并利用各种学习资源,如教程、博客、视频课程等,不断深入学习。\n\n6. **高级应用**:\n - **扩展功能**:学习如何扩展LangChain的功能,根据自己的需求编写自定义节点和链。\n - **项目开发**:尝试使用LangChain进行更复杂的项目开发,解决更具挑战性的问题。\n\n通过以上步骤,你可以逐步掌握LangChain的使用方法,并应用到实际项目中。' response_metadata={'token_usage': {'completion_tokens': 435, 'prompt_tokens': 19, 'total_tokens': 454}, 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_d33f7b429e', 'finish_reason': 'stop', 'logprobs': None} id='run-26dd0672-2e64-4f3b-9ffb-235a4a00358a-0' usage_metadata={'input_tokens': 19, 'output_tokens': 435, 'total_tokens': 454}
Content only:
开始学习LangChain可以按照以下几个步骤进行:

1. **基本了解**:
- **阅读文档**:首先,访问LangChain的官方网站或GitHub页面,阅读其文档和介绍,了解LangChain的基本概念和功能。
- **示例项目**:查看一些示例项目,了解LangChain的应用场景和使用方法。

2. **安装环境**:
- **Python环境**:确保你的计算机上安装了Python环境(通常是Python 3.6以上)。
- **安装LangChain**:使用pip来安装LangChain,可以在命令行中输入以下命令:
```bash
pip install langchain
```

3. **学习基础概念**:
- **核心概念**:熟悉LangChain的核心概念和组件,如链(Chain)、节点(Node)、数据流(Data Flow)等。
- **API使用**:了解并学习LangChain的API,学会如何调用和使用这些API来构建自己的数据处理链。

4. **实践操作**:
- **动手实验**:创建一些简单的项目或实验,尝试使用LangChain来解决实际问题。
- **调试和优化**:在实践中调试和优化你的代码,理解LangChain的运行机制和性能优化方法。

5. **社区和资源**:
- **社区支持**:加入LangChain的社区(如论坛、Slack群组等),与其他用户交流心得,解决问题。
- **学习资源**:查找并利用各种学习资源,如教程、博客、视频课程等,不断深入学习。

6. **高级应用**:
- **扩展功能**:学习如何扩展LangChain的功能,根据自己的需求编写自定义节点和链。
- **项目开发**:尝试使用LangChain进行更复杂的项目开发,解决更具挑战性的问题。

通过以上步骤,你可以逐步掌握LangChain的使用方法,并应用到实际项目中。

================

上面代码的核心在于:

  • 设定模型:model = ChatOpenAI(model="gpt-4o")
  • 发起对话:result = model.invoke("应该如何开始学习LangChain?")
  • 输出结果:result.content

设定模型

通过初始化一个ChatOpenAI类的实例来设定用户想要对话的LLM模型,上面的例子是选择gpt-4o模型,其他的选择还有gpt-3.5-turbogpt-4,对应着ChatGPT模型的不同版本:

同样的问题,不同的模型,其回答会有差异:

def ask_model(model, question):
model = ChatOpenAI(model=model)
result = model.invoke(question)
return result.content

q = "三句话告诉我:应该如何开始学习LangChain?"
model = 'gpt-3.5-turbo'
a = ask_model(model, q)
print(f"\n--------\nUser: {q}\nChatGPT(model={model}): {a}")

model = 'gpt-4o'
a = ask_model(model, q)
print(f"\n--------\nUser: {q}\n\nChatGPT(model={model}): {a}")

model = 'gpt-4'
a = ask_model(model, q)
print(f"\n--------\nUser: {q}\n\nChatGPT(model={model}): {a}")
--------
User: 三句话告诉我:应该如何开始学习LangChain?
ChatGPT(model=gpt-3.5-turbo): 1. 首先,注册一个LangChain账户并下载LangChain应用程序。
2. 探索应用程序中的不同功能和工具,例如单词卡片、语法练习和在线课程。
3. 制定一个学习计划,每天花一些时间在LangChain上学习并不断提升自己的语言技能。

--------
User: 三句话告诉我:应该如何开始学习LangChain?

ChatGPT(model=gpt-4o): 1. 从官方文档开始阅读,了解LangChain的基本概念、架构和核心组件,这将帮助你建立一个全面的知识框架。
2. 观看一些相关的教程视频或参加在线课程,实际操作中学习如何使用LangChain进行项目开发。
3. 通过实践项目和示例代码,不断练习和探索LangChain的各种功能和应用场景,以加深理解和掌握。

--------
User: 三句话告诉我:应该如何开始学习LangChain?

ChatGPT(model=gpt-4): 1. 首先,你需要下载并安装LangChain应用,这是你学习的主要平台。
2. 接着,根据你的语言需求选择相应课程,比如如果你想学习英语,就选择英语课程。
3. 最后,制定一个合理的学习计划,每天坚持练习和复习,这是保证学习效果的关键。

更多参数

除了上面的model变量,ChatOpenAI还支持更多参数的设定,详见API文档.

一个典型的调用如下:

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
model="gpt-4o",
temperature=0,
max_tokens=None,
timeout=None,
max_retries=2,
# api_key="...",
# base_url="...",
# organization="...",
# other params...
)

其中:

  • model: 模型名称。
  • temperature: 采样温度。
  • max_tokens: 输出的最长token数。
  • time_out: 超时时长。
  • max_retries: 最大重试次数。
  • api_key: 访问OpenAI必需的api_key。到OpenAI后台生成,自己保管好。谨防泄露,避免他人使用你的api_key,最终却计费到你的账户上。一般以环境变量的方式(OPENAI_API_KEY=YOUR_OPENAI_API_KEY),写入到.env文件中,然后通过load_dotenv()函数加载,供ChatOpenAI使用,应避免直接赋值。
  • base_url: 模型服务的网络访问点或地址, 如果使用自己搭建的方向代理或者其他复用OpenAI接口的大模型服务,就必须提供base_url。比如国内的Kimi,使用和OpenAI相同的API接口,其base_url为:https://api.moonshot.cn/v1.

下面来展开说说这些参数。

model: 模型名称

在ChatOpenAI中,可选的模型包括gpt-4o, gpt-4-turbogpt-3.5-turbo 等等。

不同的模型智能水平不同。现在OpenAI主推gpt-4o,它与gpt-4-turbo(LLM界的智能天花板)有着相近的智能水平,但响应更快,价格更便宜;gpt-3.5-turbo是更便宜的上一代模型。同时,gpt-4ogpt-4-turbo的上下文长度是128000(128K)个token,而 gpt-3.5-turbo 只有4096(4K)。这意味着gpt-4ogpt-4-turbo能在一次对话中接受比gpt-3.5-turbo长得多的信息,你可以喂给它更多的上下文。

可以到链接🔗查看OpenAI支持的模型及其性能与价格,下图是20240711当天的情况:

Token

上面提到的token(标记词),是LLM处理信息的基本单位,也是调用OpenAI API计费的基础。在四川吃串串,计费是数签签;在LLM调用时,计费是数token。Token是比英语中单词(word)更基本的语言元素,LLM可以看做是predict next token(预测下一个token)的机器。为了获得关于token的直观印象,可以到OpenAI的标记词页面体验。下图是其例子🌰:

从上面可知:

  • token可以是一个完整的单词,比如Manywords等。
  • token可以是单词的一部分,比如don’t, indivisible,像是词根和词缀的拆分。
  • token往往包含单词开头的空白间隔,比如map, may, be等等。
  • 像emoji这样的Unicode字符,会被拆分成若干个token,每个一字节。
  • 1234567890这样的字符序列,会被拆成多个连续数字的组合token,123, 456, 7890
  • 在LLM内部,也不是直接处理token,而是将token映射成token id

根据统计,对英文文本:

1 token ~= 4 chars in English

1 token ~= ¾ words

100 tokens ~= 75 words

而中文文本与此不同:

中文token有自己的特点:

  • 大部分汉字对应一个token,比如
  • 有些字会被映射称两个或者多个token,应该跟英文中的emoji一样,其Unicode编码中的每一个字节就是一个token
  • 有一小部分词语会被映射成一个token,比如上文中的方式时间。这个比例非常小,远小于汉语中组词的频率。

Tokeniser是LLM的一个重要课题,值得深入学习,在此不再赘述。

Temperature:采样温度

Temperature用来控制LLM输出的前后一致性。其取值范围是0~2。对相同输入,温度越低,模型在不同时候调用结果的一致性越高(比如0.3);反之,温度越高,模型在不同时候调用结果的一致性就越差(比如0.7)。不过一体两面,一致性差意味着多样性和创新性越高。因此要根据使用场景,做适配调整。可以将LLM的采样温度和现实的温度做类比:温度越高,分子活动越活跃,越不稳定。当温度低到0度,水会结冰,分子被冻住,位置固定,非常老实;当温度高到100度,水会沸腾,分子满天乱串,不守规矩。

下面是一个直观的示例:

model = ChatOpenAI(model="gpt-4o")
model.temperature
0.7

LangChain对OpenAI模型的温度是0.7, 这是一个稍微有点多样性和创新性的设置。我们试试不同的温度:

def chat_with_model(q, model='gpt-4o', **params):
model = ChatOpenAI(model=model, **params)
result = model.invoke(q)
return result.content

q = 'Hi, this a good day!'
t = 0
print(chat_with_model(q, temperature=t))
print(chat_with_model(q, temperature=t))
print(chat_with_model(q, temperature=t))
I'm glad to hear that! What's making your day so good?
I'm glad to hear that! What's making your day so good?
I'm glad to hear that! What's making your day so good?
t = 0.3
print(chat_with_model(q, temperature=t))
print(chat_with_model(q, temperature=t))
print(chat_with_model(q, temperature=t))
I'm glad to hear that! What's making your day so good?
I'm glad to hear that! What's making your day so good?
I'm glad to hear that! What's making your day so good?
t = 0.7
print(chat_with_model(q, temperature=t))
print(chat_with_model(q, temperature=t))
print(chat_with_model(q, temperature=t))
Hello! I'm glad to hear you're having a good day. How can I assist you today?
Hello! I'm glad to hear you're having a good day. How can I assist you today?
I'm glad to hear that you're having a good day! How can I assist you today?
t = 1.0
print(chat_with_model(q, temperature=t))
print(chat_with_model(q, temperature=t))
print(chat_with_model(q, temperature=t))
Hello! I'm glad to hear that you're having a good day! How can I assist you today?
Hello! I'm glad to hear that you're having a good day! Is there something specific you're excited about or that made your day special?
I'm glad to hear that! What's making your day good so far?
t = 1.3
print(chat_with_model(q, temperature=t))
print(chat_with_model(q, temperature=t))
print(chat_with_model(q, temperature=t))
I'm glad to hear that! What's made your day so good?
Hello! I'm glad to hear you're having a good day. Is there anything specific you'd like to talk about or need help with?
Hi there! I'm glad to hear it's a good day for you! Is there something specific you'd like to talk about or need assistance with?
t = 1.7
print(chat_with_model(q, temperature=t))
print(chat_with_model(q, temperature=t))
print(chat_with_model(q, temperature=t))
I'm glad to hear you're having a good day! Is there something specific that's making today great for you, or do you just want to chat about something interesting?
I'm glad to hear that you're having a good day! What's making your day so enjoyable?
Hello! I'm glad to hear you're having a good day. Is there anything special making it good, or something in particular you want to talk or ask about?

从上面可以看出:

  • t=0和0.3时,三次输出的答案是一样的,一致性拉满;
  • t=0.7时,多样性增加,但一致性还是比较强;
  • t=1.0时,非常多样,一致性较弱;
  • t=1.3和1.7时,多样性拉满
  • t=2.0时,我测试了,但没有展示在这里,是因为它会输出满屏的类似乱码的东西,简直是一个毫无意识的酒鬼。

max_tokens

下面简单看一下max_tokens的影响:

def chat_raw_result(q, model='gpt-4o', **params):
model = ChatOpenAI(model=model, **params)
result = model.invoke(q)
return result

t = 1.0
q = 'Hi, this a good day!'
print(chat_raw_result(q, temperature=t, max_tokens=10))
content="Hello! I'm glad to hear that you're having a" response_metadata={'token_usage': {'completion_tokens': 10, 'prompt_tokens': 14, 'total_tokens': 24}, 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_d33f7b429e', 'finish_reason': 'length', 'logprobs': None} id='run-6861e159-ea3a-4351-b653-0d3c0425cd1e-0' usage_metadata={'input_tokens': 14, 'output_tokens': 10, 'total_tokens': 24}
print(chat_raw_result(q, temperature=t, max_tokens=10))
content="I'm glad to hear you're having a good day!" response_metadata={'token_usage': {'completion_tokens': 10, 'prompt_tokens': 14, 'total_tokens': 24}, 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_d33f7b429e', 'finish_reason': 'length', 'logprobs': None} id='run-e81a9201-76cf-43d3-a184-090c0a92f2bc-0' usage_metadata={'input_tokens': 14, 'output_tokens': 10, 'total_tokens': 24}

从结果可见,max_tokens完全限制住了输出的token数量,第一个回答甚至被截断了(”Hello! I’m glad to hear that you’re having a” ).

疑问🤔:’input_tokens’: 14,而输入”Hi, this a good day!”的token只有7个,这是为什么?是系统prompt的影响吗? https://community.openai.com/t/overheads-tokens-usage-does-not-add-up/384087/3

debug: 调试

为进一步了解LangChain运行的细节,可将LangChain设为debug模式。方法一是设置langchain.debug = True

import langchain
langchain.debug = True

chat_raw_result(q, temperature=t, max_tokens=10)
•[32;1m•[1;3m[llm/start]•[0m •[1m[llm:ChatOpenAI] Entering LLM run with input:
•[0m{
"prompts": [
"Human: Hi, this a good day!"
]
}
•[36;1m•[1;3m[llm/end]•[0m •[1m[llm:ChatOpenAI] [1.68s] Exiting LLM run with output:
•[0m{
"generations": [
[
{
"text": "I'm glad to hear that! What's making your day",
"generation_info": {
"finish_reason": "length",
"logprobs": null
},
"type": "ChatGeneration",
"message": {
"lc": 1,
"type": "constructor",
"id": [
"langchain",
"schema",
"messages",
"AIMessage"
],
"kwargs": {
"content": "I'm glad to hear that! What's making your day",
"response_metadata": {
"token_usage": {
"completion_tokens": 10,
"prompt_tokens": 14,
"total_tokens": 24
},
"model_name": "gpt-4o-2024-05-13",
"system_fingerprint": "fp_dd932ca5d1",
"finish_reason": "length",
"logprobs": null
},
"type": "ai",
"id": "run-4f67413b-50d0-419c-9731-9868f52991d1-0",
"usage_metadata": {
"input_tokens": 14,
"output_tokens": 10,
"total_tokens": 24
},
"tool_calls": [],
"invalid_tool_calls": []
}
}
}
]
],
"llm_output": {
"token_usage": {
"completion_tokens": 10,
"prompt_tokens": 14,
"total_tokens": 24
},
"model_name": "gpt-4o-2024-05-13",
"system_fingerprint": "fp_dd932ca5d1"
},
"run": null
}
AIMessage(content="I'm glad to hear that! What's making your day", response_metadata={'token_usage': {'completion_tokens': 10, 'prompt_tokens': 14, 'total_tokens': 24}, 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_dd932ca5d1', 'finish_reason': 'length', 'logprobs': None}, id='run-4f67413b-50d0-419c-9731-9868f52991d1-0', usage_metadata={'input_tokens': 14, 'output_tokens': 10, 'total_tokens': 24})

也可随时关掉:

langchain.debug = False
chat_raw_result(q, temperature=t, max_tokens=10)
AIMessage(content="Hi! I'm glad to hear you're having a good", response_metadata={'token_usage': {'completion_tokens': 10, 'prompt_tokens': 14, 'total_tokens': 24}, 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_d33f7b429e', 'finish_reason': 'length', 'logprobs': None}, id='run-5f27c6ea-5f04-44d1-ac85-8239b0eb9f18-0', usage_metadata={'input_tokens': 14, 'output_tokens': 10, 'total_tokens': 24})

方法二set_debug(True),效果相同:

from langchain.globals import set_debug
set_debug(True)

# chat_raw_result(q, temperature=t, max_tokens=10)

set_debug(False)

从源码看,langchain.debug是通过调用set_debug来实现的:

elif name == "debug":
from langchain.globals import _debug

_warn_on_import(
name,
replacement=(
"langchain.globals.set_debug() / langchain.globals.get_debug()"
),
)

return _debug

从运行告警看:

UserWarning: Importing debug from langchain root module is no longer supported. Please use langchain.globals.set_debug() / langchain.globals.get_debug() instead.

官方推荐使用set_debug取代langchain.debug.

另外,相关文档中提到可以set_verbose来打印可读性更强的运行信息,不过实际运行发现,当前版本(v0.2.7)并不能打印(找到一个相关bug):

from langchain.globals import set_verbose
set_verbose(True)

print(chat_raw_result(q, temperature=t, max_tokens=10))

set_verbose(False)
content="I'm glad to hear that! What's making your day" response_metadata={'token_usage': {'completion_tokens': 10, 'prompt_tokens': 14, 'total_tokens': 24}, 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_d33f7b429e', 'finish_reason': 'length', 'logprobs': None} id='run-e4bf71ff-74fc-4e6a-8914-e30c40695fc2-0' usage_metadata={'input_tokens': 14, 'output_tokens': 10, 'total_tokens': 24}

其他查看token用量或者debug信息的方法(How to track token usage for LLMs):

  • ConsoleCallbackHandler:model = ChatOpenAI(model="gpt-4o").with_config({"callbacks": [ConsoleCallbackHandler()]})
  • get_openai_callback: with get_openai_callback() as cb
  • LangSmith: LangChain团队开发的用做监控和评估LLM应用的平台。

其他模型

Claude

除了OpenAI,我们还试一下LangChain提供的其他模型。比如Anthropic的Claude系列LLM模型:

from langchain_anthropic import ChatAnthropic

llm = ChatAnthropic(
model="claude-3-5-sonnet-20240620",
api_key=os.environ['ANTHROPIC_API_KEY']
)

result = llm.invoke('你是谁?')
print(result)
... 由于网络原因
AuthenticationError: Error code: 401 - {'type': 'error', 'error': {'type': 'authentication_error', 'message': 'invalid x-api-key'}}

Groq的Llama3

Groq专注于提供快速的LLM推理服务,它支持Llama3(8b和70b)、Mixtral 8x7b、Gemma 7b和Gemma2 9b等模型。可以像下面这样访问:

from langchain_groq import ChatGroq

llm = ChatGroq(
temperature=0,
model="llama3-70b-8192",
)

result = llm.invoke('你是谁?')
print(result)
content="😊 I am LLaMA, an AI assistant developed by Meta AI that can understand and respond to human input in a conversational manner. I'm not a human, but a computer program designed to simulate conversation, answer questions, and even generate text based on the input I receive.\n\nI don't have a personal identity or emotions, but I'm designed to be helpful and assist with a wide range of topics and tasks. I can provide information, answer questions, offer suggestions, and even engage in creative activities like storytelling or dialogue.\n\nSo, how can I assist you today? 🤔" response_metadata={'token_usage': {'completion_tokens': 121, 'prompt_tokens': 14, 'total_tokens': 135, 'completion_time': 0.373936891, 'prompt_time': 0.006842588, 'queue_time': None, 'total_time': 0.380779479}, 'model_name': 'llama3-70b-8192', 'system_fingerprint': 'fp_87cbfbbc4d', 'finish_reason': 'stop', 'logprobs': None} id='run-a750c4da-9154-4bd0-b950-07227f231772-0' usage_metadata={'input_tokens': 14, 'output_tokens': 121, 'total_tokens': 135}

Kimi

Kimi是月之暗面公司推出的、在国内非常流行的大模型,其特点是超长的上下文窗口,能处理长达128K的对话内容。Kimi采用的是与OpenAI兼容的编程接口,因此可以复用ChatOpenAI,替换掉model(moonshot-v1-8k/32k/128k)、base_url(https://api.moonshot.cn/v1)和api_key(去这里申请)即可

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
model = 'moonshot-v1-8k',
base_url='https://api.moonshot.cn/v1',
api_key=os.environ['KIMI_API_KEY']
)

result = llm.invoke('你是谁?')
print(result)
content='我是一个AI助手,我的目标是帮助用户解决问题和完成任务。请随时向我提问或请求帮助,我会尽我所能提供帮助。' response_metadata={'token_usage': {'completion_tokens': 30, 'prompt_tokens': 11, 'total_tokens': 41}, 'model_name': 'moonshot-v1-8k', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None} id='run-a621bfd9-7739-4d3b-83aa-0e281d2d6cb4-0' usage_metadata={'input_tokens': 11, 'output_tokens': 30, 'total_tokens': 41}

【未完待续】

--

--