langChain大模型开发

  1. 如何使用 LangChain:一套在大模型能力上封装的工具框架
  2. 如何用几行代码实现一个复杂的 AI 应用
  3. 面向大模型的流程开发的过程抽象

写在前面

  • LangChain 是一套面向大模型的开发框架
  • LangChain 是 AGI 时代软件工程的一个探索和原型
  • LangChain 并不完美,还在不断迭代中:我写这个课件的时候是 V0.0.200,现在是 V0.0.241
  • 学习 LangChain 更重要的是借鉴其思想,具体的接口可能很快就会改变

LangChain是一个基于语言模型开发应用程序的框架,旨在帮助开发人员使用大型语言模型(LLM)构建端到端的应用程序。它提供了一套工具、组件和接口,可简化创建由LLM和聊天模型提供支持的应用程序的过程。LangChain可以轻松管理与语言模型的交互,将多个组件链接在一起,并集成额外的资源,如API和数据库。

LangChain的核心价值在于其组件化特性,为使用语言模型提供抽象层,以及每个抽象层的一组实现。这些组件是模块化且易于使用的,无论是否使用LangChain框架的其余部分。

此外,LangChain的优势在于可以重新利用语言模型。借助LangChain,组织可以将LLMs重新用于特定领域的应用程序,而无需重新训练或微调。这为AI开发者提供了连接语言模型和外部数据源的工具,从而解决语言处理领域中的一系列挑战。

总的来说,LangChain是一个功能强大且灵活的框架,为开发人员提供了一个创新的工具集,用于构建基于LLM的应用程序,并扩展LLM的使用场景。它得到了开源社区的支持,并且是免费的,为开发者提供了与其他精通该框架的开发人员交流和支持的机会。

LangChain 的核心组件

  1. 模型 I/O 封装
    • LLMs:大语言模型
    • Chat Models:一般基于 LLMs,但按对话结构重新封装
    • PromptTemple:提示词模板
    • OutputParser:解析输出
  2. 数据连接封装
    • Document Loaders:各种格式文件的加载器
    • Document transformers:对文档的常用操作,如:split, filter, translate, extract metadata, etc
    • Text Embedding Models:文本向量化表示,用于检索等操作(啥意思?别急,后面详细讲)
    • Verctor stores: (面向检索的)向量的存储
    • Retrievers: 向量的检索
  3. 记忆封装
    • Memory:这里不是物理内存,从文本的角度,可以理解为“上文”、“历史记录”或者说“记忆力”的管理
  4. 架构封装
    • Chain:实现一个功能或者一系列顺序功能组合
    • Agent:根据用户输入,自动规划执行步骤,自动选择每步需要的工具,最终完成用户指定的功能
      • Tools:调用外部功能的函数,例如:调 google 搜索、文件 I/O、Linux Shell 等等
      • Toolkits:操作某软件的一组工具集,例如:操作 DB、操作 Gmail 等等
  5. Callbacks
1
!pip install langchain == 0.0.240rc4
 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

from langchain.llms import OpenAI
from langchain.chat_models import ChatOpenAI

llm = OpenAI()  # 默认是text-davinci-003模型
llm.predict("你好,欢迎")

# '你好!感谢您的欢迎。有什么我可以帮助您的吗?


from langchain.schema import (
    AIMessage,
    HumanMessage,
    SystemMessage
)



chat_model = ChatOpenAI() #默认是gpt-3.5-turbo
chat_model.predict("你好,欢迎")

messages = [
    SystemMessage(content="你是AGIClass的课程助理。"),
    HumanMessage(content="我来上课了")
]
chat_model(messages)

1.2 模型的输入与输出

模型的输入与输出

PromptTemplate

1
2
3
4
5
from langchain.prompts import PromptTemplate

template = PromptTemplate.from_template("给我讲个关于{subject}的笑话")
print(template.input_variables)
print(template.format(subject='小明'))
 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
from langchain.prompts import PromptTemplate, ChatPromptTemplate, HumanMessagePromptTemplate
from langchain.llms import OpenAI

from langchain.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field, validator
from typing import List, Dict
import json


def chinese_friendly(string):
    lines = string.split('\n')
    for i, line in enumerate(lines):
        if line.startswith('{') and line.endswith('}'):
            try:
                lines[i] = json.dumps(json.loads(line), ensure_ascii=False)
            except:
                pass
    return '\n'.join(lines)


model_name = 'gpt-4'
temperature = 0.0
model = OpenAI(model_name=model_name, temperature=temperature)

# 定义你的输出格式


class Command(BaseModel):
    command: str = Field(description="linux shell命令名")
    arguments: Dict[str, str] = Field(description="命令的参数 (name:value)")

    # 你可以添加自定义的校验机制
    @validator('command')
    def no_space(cls, field):
        if " " in field or "\t" in field or "\n" in field:
            raise ValueError("命令名中不能包含空格或回车!")
        return field


parser = PydanticOutputParser(pydantic_object=Command)

prompt = PromptTemplate(
    template="将用户的指令转换成linux命令.\n{format_instructions}\n{query}",
    input_variables=["query"],
    partial_variables={"format_instructions": parser.get_format_instructions()}
)

print(chinese_friendly(parser.get_format_instructions()))


query = "将系统日期设为2023-04-01"
model_input = prompt.format_prompt(query=query)

#print(parser.get_format_instructions())

print("====Prompt=====")
print(chinese_friendly(model_input.to_string()))

output = model(model_input.to_string())
print("====Output=====")
print(output)
print("====Parsed=====")
cmd = parser.parse(output)
print(cmd)

文档向量化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from langchain.embeddings import OpenAIEmbeddings

embeddings = OpenAIEmbeddings()
text = "这是一个测试"
document = "测试文档"
query_vec = embeddings.embed_query(text)
doc_vec = embeddings.embed_documents([document])

print(len(query_vec))
print(query_vec[:10])  # 为了展示方便,只打印前10维
print(len(doc_vec[0]))
print(doc_vec[0][:10])  # 为了展示方便,只打印前10维

2.4 向量的存储(与索引):Vectorstores

向量存储

1
2
3
4
5
6
7
8
9
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import FAISS

embeddings = OpenAIEmbeddings()
db = FAISS.from_documents(paragraphs, embeddings)

query = "What can ChatGPT do?"
docs = db.similarity_search(query)
print(docs[0].page_content)
VectorDB建议:
  • 没有极端高性能要求的,FAISS比较常用
  • Pinecone(付费-云服务)易用性比较好
  • 有极端性能要求的,可以找专人优化ElasticSearch(或APU加速)
  • 一些对比分析可参考:https://www.modb.pro/db/516016
  • 2.5 向量检索:Retrievers

    1
    2
    3
    4
    
    retriever = db.as_retriever()
    docs = retriever.get_relevant_documents("What can ChatGPT do?")
    
    print(docs[0].page_content)
    

    如果不用向量检索会怎样?

    1
    2
    3
    4
    5
    6
    
    from langchain.retrievers import TFIDFRetriever  # 最传统的关键字加权检索
    
    retriever = TFIDFRetriever.from_documents(paragraphs)
    docs = retriever.get_relevant_documents("What can ChatGPT do?")
    
    print(docs[0].page_content)
    
    思考:为什么向量检索效果更好?