LangChain初探:为你的AI应用之旅导航

本文涉及的产品
阿里云百炼推荐规格 ADB PostgreSQL,4核16GB 100GB 1个月
简介: 这篇文章带来了 LangChain 较为全面的精彩初探,带领小白选手轻松揭开其神秘面纱,一窥其独特之处。不容错过!

先来个温馨的小提醒:

这篇文章虽然较为全面地介绍了 LangChain,但都是点到为止,只是让你了解一下它的皮毛而已,适合小白选手。

So,如果你是 LangChain 的小白,看完之后还是一头雾水,那就请毫不留情地,狠狠地 .................................... 给我点赞吧!有了你的鼓励,我会再接再厉的!(ง •_•)ง

What?

丹尼尔:蛋兄,刚刚听到别人在说 LangChain,你知道是啥玩意吗?

蛋先生:哦,LangChain 啊,一个开发框架

丹尼尔:开发啥的框架?

蛋先生:一个用于开发语言模型驱动的应用的框架

丹尼尔:哦,开发这种应用,不就是写写 Prompt 提示语,调调语言模型 API 的事么?

蛋先生:没错。但 LangChain 使得 Prompt 的编写,API 的调用更加标准化

丹尼尔:就这样吗?

蛋先生:当然不止,它还有很多很酷的功能

丹尼尔:比如?

蛋先生:它可以连接外部数据源,根据输入检索相关数据作为上下文给到语言模型,使得语言模型可以回答训练数据之外的问题。这是由 LangChain 的 Retrieval 来实现的

丹尼尔:太酷了,我想到了一个场景,比如通过它来连接客服的回答话术库,这样就可以让语言模型摇身一变,变成一个专业的客服了

蛋先生:恩,这是一个很好的场景

丹尼尔:还有其它更酷的功能吗?

蛋先生:它可以让语言模型来自行决定采取哪些行动

丹尼尔:这个就不是很明白了

蛋先生:接着你那个客服的例子继续说。如果用户问的问题是关于公司产品的,我们就想让语言模型使用客服的话术库来回答;如果是其它问题,就让语言模型用它自己的知识来直接回答。如果是你,你会怎么实现?

丹尼尔:我想我会先通过语言模型来判断用户的问题是否关于公司产品。如果是,就走连接话术库的逻辑;如果不是,就走让语言模型直接回答的逻辑

蛋先生:恩,你这种就是 hardcode 逻辑的方式。还有一种更加 amazing 的 方式,就是让语言模型自行决定采取哪种行为。这个由 LangChain 的 Agent 来实现。

丹尼尔:听上去太酷了,怎么用呢?

蛋先生:莫急,待我慢慢道来

Why?

丹尼尔:蛋兄,你刚刚说到 LangChain 使得 Prompt 的编写,API 的调用更加标准化,标准化了肯定是好的,但好处很大吗?我用语言模型的 SDK 不也用得好好的吗?

蛋先生:那你先给一个使用 SDK 与语言模型交互的例子呗

丹尼尔:这还不简单,我就用这个吧:fireworks.ai (注:这个平台提供免费的资源,访问也方便)

from fireworks.client import Fireworks

client = Fireworks(api_key="<FIREWORKS_API_KEY>")
response = client.chat.completions.create(
  model="accounts/fireworks/models/llama-v2-7b-chat",
  messages=[{
   
   
    "role": "user",
    "content": "Who are you?",
  }],
)
print(response.choices[0].message.content)
输出:
Hello! I'm just an AI assistant, here to help you in any way I can. My purpose is to provide helpful and respectful responses, always being safe and socially unbiased. I'm here to assist you in a positive and ethical manner, and I'm happy to help you with any questions or tasks you may have. Is there anything specific you would like me to help you with?

蛋先生:很好,再给另外一个语言模型的例子呗

丹尼尔:额,一样的操作啊,你这是在消遣我吗?好吧,那我就再给一个百度的文心一言的例子

import os
import qianfan

os.environ["QIANFAN_AK"] = "<QIANFAN_AK>"
os.environ["QIANFAN_SK"] = "<QIANFAN_SK>"

chat_comp = qianfan.ChatCompletion()

resp = chat_comp.do(messages=[{
   
   
    "role": "user",
    "content": "Who are you?"
}])

print(resp.body['result'])
输出:
您好,我是百度研发的知识增强大语言模型,中文名是文心一言,英文名是ERNIE Bot。我能够与人对话互动,回答问题,协助创作,高效便捷地帮助人们获取信息、知识和灵感。

蛋先生:Good,现在假设我一开始使用 fireworks 来开发应用,过程中发现效果不太理想,想换成文心一言呢?

丹尼尔:Oh~,各个语言模型的 SDK 的接口定义是不一样的,替换起来确实麻烦。来吧,是时候开始你的表演了

蛋先生:我们直接来看下通过 LangChain 使用 fireworks 和 文心一言 的代码示例吧,毕竟 No Code No BB 嘛

  • fireworks LangChain 示例
import os
from langchain_community.chat_models.fireworks import ChatFireworks

os.environ["FIREWORKS_API_KEY"] = '<FIREWORKS_API_KEY>'
model = ChatFireworks(model="accounts/fireworks/models/llama-v2-13b-chat")

res = model.invoke("Who are you?")
print(res.content)
  • 文心一言 LangChain 示例
import os
from langchain_community.chat_models import QianfanChatEndpoint

os.environ["QIANFAN_AK"] = "<QIANFAN_AK>"
os.environ["QIANFAN_SK"] = "<QIANFAN_SK>"
model = QianfanChatEndpoint(model="ERNIE-Bot-turbo")

res = model.invoke("Who are you?")
print(res.content)

丹尼尔:好像看出来了,标准化之后,要更换语言模型变得非常方便了,只需要更换下 model 的实例化就行了

蛋先生:是的,这只是个最简单的例子,LangChain 还有很多种优雅的方式来切换不同的模型。从此以后我们就可以专注于 Prompt 的开发了。语言模型嘛,哪个合适换哪个

How?

丹尼尔:好了,我决定入坑 LangChain 了,那咱们进一步聊聊?

蛋先生:当然可以!我们从简单到复杂,结合代码和流程图来展示 LangChain 的一些用法。先来最简单的代替 SDK 的用法,这个上边已经有提到了

res = model.invoke("tell me a short joke about a cat")
print(res.content)

image

丹尼尔:恩,这个 so easy,一瞄就懂

蛋先生:OK,那接下来我们来使用 PromptTemplate,通过变量的方式来控制模板里的部分内容

from langchain_core.prompts import ChatPromptTemplate

...

prompt = ChatPromptTemplate.from_template("tell me a short joke about {topic}")
chain = prompt | model
res = chain.invoke({
   
   "topic": "a cat"})
print(res.content)

image

丹尼尔:使用 PromptTemplate 的方式来写 prompt,确实比字符串的拼接要优雅不少

蛋先生:再加个简单的输出转换吧

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

...

prompt = ChatPromptTemplate.from_template("tell me a short joke about {topic}")
output_parser = StrOutputParser()
chain = prompt | model | output_parser
res = chain.invoke({
   
   "topic": "a cat"})
print(res)

image

丹尼尔:终于知道为啥叫 chain

蛋先生:继续?

丹尼尔:继续...

蛋先生:接下来这段代码可能有点长哦

from langchain_community.embeddings import QianfanEmbeddingsEndpoint
from langchain_community.document_loaders import WebBaseLoader
from langchain_community.vectorstores import faiss
from langchain_community.chat_models import QianfanChatEndpoint

from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.chains.combine_documents import create_stuff_documents_chain

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableParallel, RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser

# 1
docs = WebBaseLoader("https://docs.smith.langchain.com").load()
embeddings = QianfanEmbeddingsEndpoint()
documents = RecursiveCharacterTextSplitter(chunk_size=900).split_documents(docs)
vector = faiss.FAISS.from_documents(documents, embeddings)
retriever = vector.as_retriever(search_kwargs={
   
   'k': 4})

# 2
setup_and_retrieval = RunnableParallel(
    {
   
   "context": retriever, "input": RunnablePassthrough()}
)
prompt = ChatPromptTemplate.from_template("""Answer the following question based only on the provided context:
<context>
{context}
</context>
Question: {input}""")
model = QianfanChatEndpoint(streaming=False, model="ERNIE-Bot-turbo")
output_parser = StrOutputParser()

# 3
retrieval_chain = setup_and_retrieval | prompt | model | output_parser

res = retrieval_chain.invoke("how can langsmith help with testing?")
print(res)

丹尼尔:请把“可能”去掉,谢谢

蛋先生:但逻辑其实并不复杂,主要分为三块

1)加载网页文档,通过 Embeddings 将文档内容转成向量并存储在向量数据库 FAISS 中,retriever 就是一个可以根据输入从向量数据库获取相关文档的检索工具

2)声明 chain 的各个步骤

3)将各个步骤按顺序 chain 起来

丹尼尔:等等,看着有点脑壳疼。Embeddings?向量?向量数据库?

蛋先生:咱们今天是“初探”,所以也只能简单讲讲,不然很多同学就要昏昏欲睡了

丹尼尔:没问题,有个大概印象也好

蛋先生:首先,为什么要将文本转成向量呢?因为通过计算两个向量的距离,我们就可以量化地评估它们的相关性。距离越小,通常意味着文本之间的相关性越高。我们这里是需要检索与输入相关的文档内容,将其作为会话上下文提供给语言模型。如果是整个文档都传过去,是不是就太大了呢?

丹尼尔:哦,原来向量有这么高级的功能啊

蛋先生:没错。然后要将文本转成向量,就需要用到 Embeddings(词嵌入)技术。Embeddings 在历史上有过多种方法,如基于统计的计数方法,基于神经网络的推理方法等。 QianfanEmbeddingsEndpoint 正是一个利用深度学习训练得到的 Embeddings 模型服务,输入为文本,输出为向量

丹尼尔:大概有点明白了

蛋先生:那我们接着看下流程图

image

丹尼尔:能否为小弟我解释一下上面这个流程图的前半部分

蛋先生:当然!首先输入是 "how can langsmith help with testing?";接着有个并行的逻辑,一个是通过 Retriever 根据输入检索相关的文档内容作为 context 的值,另一个则是直接 pass 将输入作为 input 的值;然后就是将数据传给 Prompt 模板,最终就可以得到传给语言模型的 PromptValue 了

丹尼尔:Soga

蛋先生:注意,压轴要登场了哦,现在让我们来请出大名鼎鼎的 Agent 吧

from langchain import hub
from langchain.agents import AgentExecutor, create_json_chat_agent
from langchain.tools import tool
from langchain_community.chat_models.fireworks import ChatFireworks

@tool
def leng(word: str) -> str:
    """Please use this tool if you want to find the length of the word."""
    return len(word)
@tool
def lower(word: str) -> str:
    """Please use this tool if you need to change the word to lowercase."""
    return f'dx_{word.lower()}'


tools = [leng, lower]
model = ChatFireworks(model="accounts/fireworks/models/llama-v2-70b-chat")
prompt = hub.pull("hwchase17/react-chat-json")

agent = create_json_chat_agent(model, tools, prompt, stop_sequence=False)
agent_executor = AgentExecutor(
    agent=agent, tools=tools, verbose=True, handle_parsing_errors=True, max_iterations=5)

res = agent_executor.invoke({
   
   "input": "Make this word lowercase: 'Daniel'"})
print(res)
{
   
   'input': "Make this word lowercase: 'Daniel'", 'output': "The lowercase version of 'Daniel' is 'dx_daniel'"}

丹尼尔:好耶,快点讲解一下吧

蛋先生:首先我们声明了两个工具:一个是 leng(用于求字符串长度),一个是 lower(用于将字符串变成小写)。这里为了证明结果是通过我们的工具来得到结果的,所以特意在 lower 的实现中加了个 dx_ 前缀

丹尼尔:等等,hub.pull("hwchase17/react-chat-json") 是什么神秘代码?

蛋先生:这是 LangChain hub 社区上共享的用于实现 Agent 的众多 Prompt 中的一个,你可以在这里找到很多有用的 Prompt。毕竟,语言工程也是一种艺术,也是需要实践积累的。

丹尼尔:明白,请继续

蛋先生:通过 Agent,语言模型就可以根据输入自行判断应该使用哪个工具了

丹尼尔:哇,这太神奇了!我对它是怎么自行判断很感兴趣

蛋先生:简单来说,语言模型可以根据输入,再根据各个工具的描述,来判断哪个工具更适合,然后将结果输出为可以让 LangChain 理解的执行指令(比如 JSON)

丹尼尔:太棒了!现在我对 LangChain 有了一个大致的了解,希望以后还能跟你继续深入探讨

蛋先生:机会有滴是,咱们后会有期!ヾ( ̄▽ ̄)Bye~Bye~

相关实践学习
阿里云百炼xAnalyticDB PostgreSQL构建AIGC应用
通过该实验体验在阿里云百炼中构建企业专属知识库构建及应用全流程。同时体验使用ADB-PG向量检索引擎提供专属安全存储,保障企业数据隐私安全。
AnalyticDB PostgreSQL 企业智能数据中台:一站式管理数据服务资产
企业在数据仓库之上可构建丰富的数据服务用以支持数据应用及业务场景;ADB PG推出全新企业智能数据平台,用以帮助用户一站式的管理企业数据服务资产,包括创建, 管理,探索, 监控等; 助力企业在现有平台之上快速构建起数据服务资产体系
目录
相关文章
|
4天前
|
存储 人工智能 搜索推荐
解锁AI新境界:LangChain+RAG实战秘籍,让你的企业决策更智能,引领商业未来新潮流!
【10月更文挑战第4天】本文通过详细的实战演练,指导读者如何在LangChain框架中集成检索增强生成(RAG)技术,以提升大型语言模型的准确性与可靠性。RAG通过整合外部知识源,已在生成式AI领域展现出巨大潜力。文中提供了从数据加载到创建检索器的完整步骤,并探讨了RAG在企业问答系统、决策支持及客户服务中的应用。通过构建知识库、选择合适的嵌入模型及持续优化系统,企业可以充分利用现有数据,实现高效的商业落地。
26 6
|
4天前
|
机器学习/深度学习 人工智能 算法
AI技术在医疗领域的应用及挑战
【10月更文挑战第4天】本文将探讨AI技术在医疗领域的应用及其面临的挑战。我们将从AI技术的定义和发展历程入手,分析其在医疗领域的应用场景,包括辅助诊断、个性化治疗、药物研发等方面。同时,我们也将讨论AI技术在医疗领域面临的挑战,如数据隐私、算法偏见等问题。最后,我们将以一个简单的代码示例来展示AI技术在医疗领域的应用。
22 0
|
4天前
|
机器学习/深度学习 人工智能 开发框架
解锁AI新纪元:LangChain保姆级RAG实战,助你抢占大模型发展趋势红利,共赴智能未来之旅!
【10月更文挑战第4天】本文详细介绍检索增强生成(RAG)技术的发展趋势及其在大型语言模型(LLM)中的应用优势,如知识丰富性、上下文理解和可解释性。通过LangChain框架进行实战演练,演示从知识库加载、文档分割、向量化到构建检索器的全过程,并提供示例代码。掌握RAG技术有助于企业在问答系统、文本生成等领域把握大模型的红利期,应对检索效率和模型融合等挑战。
35 14
|
1天前
|
机器学习/深度学习 人工智能 自然语言处理
探索AI在自然语言处理中的创新应用
【10月更文挑战第7天】本文将深入探讨人工智能在自然语言处理领域的最新进展,揭示AI技术如何改变我们与机器的互动方式,并展示通过实际代码示例实现的具体应用。
|
1天前
|
人工智能 搜索推荐 算法
AI Agent应用出路到底在哪?
【10月更文挑战第6天】
8 0
AI Agent应用出路到底在哪?
|
4天前
|
机器学习/深度学习 人工智能 自然语言处理
AI技术在自然语言处理中的应用
【10月更文挑战第4天】本文将介绍人工智能(AI)在自然语言处理(NLP)领域的应用,包括语音识别、机器翻译、情感分析等方面。我们将通过一些实际案例展示AI如何帮助人们更好地理解和使用自然语言。同时,我们也会探讨AI在NLP领域面临的挑战和未来发展方向。
|
23小时前
|
传感器 人工智能 语音技术
探索AI技术在智能家居中的应用
【8月更文挑战第78天】本文将探讨人工智能(AI)技术在智能家居领域的应用。我们将从AI技术的基本概念入手,介绍其在智能家居中的作用,并通过代码示例展示如何实现一个简单的智能照明系统。最后,我们将总结AI技术在智能家居领域的优势和挑战。
|
1天前
|
人工智能 搜索推荐 算法
探索AI技术在医疗诊断中的应用与挑战
【10月更文挑战第7天】 人工智能(AI)在医疗领域的应用日益广泛,尤其在医疗诊断中表现出巨大的潜力和价值。本文将探讨AI在医疗诊断中的具体应用、所面临的伦理和隐私问题以及未来的发展方向,旨在为读者提供一个全面而深入的理解。
6 0
|
5月前
|
Shell Android开发
Android系统 adb shell push/pull 禁止特定文件
Android系统 adb shell push/pull 禁止特定文件
464 1
|
5月前
|
Android开发 Python
Python封装ADB获取Android设备wifi地址的方法
Python封装ADB获取Android设备wifi地址的方法
141 0

热门文章

最新文章