LangChain: 大語言模型的新篇章

本文介紹了 LangChain 框架,它能夠將大型語言模型與其他計算或知識來源相結合,從而實現功能更加強大的應用。接着,對 LangChain 的關鍵概念進行了詳細說明,並基於該框架進行了一些案例嘗試,旨在幫助讀者更輕鬆地理解 LangChain 的工作原理。

引言

近期, 大型語言模型 (LLM) 如 GPT 系列模型引領了人工智能領域的一場技術革命。開發者們都在利用這些 LLM 進行各種嘗試, 雖然已經產生了許多有趣的應用, 但是單獨使用這些 LLM 往往難以構建功能強大的實用應用。

LangChain 通過將大型語言模型與其他知識庫、計算邏輯相結合,實現了功能更加強大的人工智能應用。簡單來說,個人理解 LangChain 可以被視爲開源版的 GPT 插件,它提供了豐富的大語言模型工具,可以在開源模型的基礎上快速增強模型的能力。

在此,我總結了最近對 LangChain 的學習內容,歡迎各位同學前來交流。LangChain 使得語言技術的運用更加活躍多元,它有望在人工智能領域發揮重要作用,推動我們工作效率的變革。我們正處在人工智能爆發的前夜,積極擁抱新技術將會帶來全新的體驗。

LangChain 主要概念與示例

LangChain 提供了一系列的工具幫助我們更好的使用大語言模型 (LLM)。可以認爲主要有 6 種不同類型的工具:

模型 (Models)

LangChain 的一個核心價值就是它提供了標準的模型接口;然後我們可以自由的切換不同的模型,當前主要有兩種類型的模型,但是考慮到使用場景,對我們一般用戶來說就是使用一種模型即文本生成模型。

說到模型,大家就理解模型就是 ChatGPT 就可以。單純的模型只能生成文本內容。

用於文本生成,文字作爲輸入,輸出也是文字。

  1. 普通 LLM:接收文本字符串作爲輸入,並返回文本字符串作爲輸出

  2. 聊天模型:將聊天消息列表作爲輸入,並返回一個聊天消息

代碼案例:

from langchain.schema import HumanMessage
from langchain.llms import OpenAI
from langchain.chat_models import ChatOpenAI
llm = OpenAI()
chat_model = ChatOpenAI()
print(llm("say hi!"))
print(chat_model.predict("say hi!"))

把文字轉換爲浮點數形式的描述:

這些模型接收文本作爲輸入並返回一組浮點數。這些浮點數通常用於表示文本的語義信息,以便進行文本相似性計算、聚類分析等任務。文本嵌入模型可以幫助開發者在文本之間建立更豐富的聯繫,提高基於大型語言模型的應用的性能。

from langchain.embeddings import OpenAIEmbeddings
embeddings = OpenAIEmbeddings()
text = "This is a test document."
query_result = embeddings.embed_query(text)
doc_result = embeddings.embed_documents([text])
print(doc_result)

提示詞 (Prompts)

提示詞是我們與模型交互的方式,或者是模型的輸入,通過提示詞可以讓模型返回我們期望的內容,比如讓模型按照一定的格式返回數據給我們。

LangChain 提供了一些工具,可以方便我們更容易的構建出我們想要的提示詞,主要工具如下:

瞭解這些工具都是更方便的讓我們構造提示詞就行了。

語言模型提示詞模板 PromptTemplates,提示模板可以讓我們重複的生成提示,複用我們的提示。它包含一個文本字符串(“模板”),從用戶那裏獲取一組參數並生成提示,包含:

  1. 對語言模型的說明,應該扮演什麼角色

  2. 一組少量示例,以幫助 LLM 生成更好的響應,

  3. 具體的問題

代碼案例:

from langchain import PromptTemplate
template = """
I want you to act as a naming consultant for new companies.
What is a good name for a company that makes {product}?
"""
prompt = PromptTemplate(
    input_variables=["product"],
    template=template,
)
prompt.format(product="colorful socks")
# -> I want you to act as a naming consultant for new companies.
# -> What is a good name for a company that makes colorful socks?

聊天模型提示詞模板 ChatPrompt Templates, ChatModels 接受聊天消息列表作爲輸入。列表一般是不同的提示,並且每個列表消息一般都會有一個角色。

from langchain.prompts import (
    ChatPromptTemplate,
    PromptTemplate,
    SystemMessagePromptTemplate,
    AIMessagePromptTemplate,
    HumanMessagePromptTemplate,
)
from langchain.schema import (
    AIMessage,
    HumanMessage,
    SystemMessage
)
template="You are a helpful assistant that translates {input_language} to {output_language}."
system_message_prompt = SystemMessagePromptTemplate.from_template(template)
human_template="{text}"
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])
# get a chat completion from the formatted messages
print(chat_prompt.format_prompt(input_language="English", output_language="French", text="I love programming.").to_messages())

示例選擇器 Example Selectors,如果有多個案例的時候,使用 ExampleSelectors 選擇一個案例讓提示詞使用:

  1. 自定義的案例選擇器

  2. 基於長度的案例選擇器,輸入長的時候按理會少一點,輸入多的時候,案例會多一些。

  3. 相關性選擇器,選擇一個和輸入最相關的案例

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
print(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"})
print(example_selector.examples)
# -> [{'foo': '1'}, {'foo': '2'}, {'foo': '3'}, {'foo': '4'}]
# Select examples
print(example_selector.select_examples({"foo": "foo"}))
# -> array([{'foo': '1'}, {'foo': '4'}], dtype=object)

輸出解析器 OutputParsers,可以讓 LLM 輸出更加結構化的信息:

  1. 指示模型如何格式化輸出:get_format_instructions

  2. 輸出解析爲所需的格式:parse(str)

主要的 Parsers:

  1. CommaSeparatedListOutputParser,讓 LLM 按照逗號分隔的形式返回。['Vanilla',  'Chocolate',  'Strawberry',  'Mint Chocolate Chip',  'Cookies and Cream']

  2. StructuredOutputParser 無需定義對象,直接生成結構化的內容。 和 PydanticOutputParser 比較像,但是不用定義對象。

  3. PydanticOutputParser 定義一個對象模型,讓 LLM 按照這個模型返回數據

可以看到我們定義了 Joke 類,然後 PydanticOutputParser 可以讓 LLM 按照我們定義對象的格式返回數據給我們。

from langchain.prompts import PromptTemplate, ChatPromptTemplate, HumanMessagePromptTemplate
from langchain.llms import OpenAI
from langchain.chat_models import ChatOpenAI
from langchain.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field, validator
from typing import List
model_name = 'text-davinci-003'
temperature = 0.0
model = OpenAI(model_name=model_name, temperature=temperature)
# Define your desired data structure.
class Joke(BaseModel):
    setup: str = Field(description="question to set up a joke")
    punchline: str = Field(description="answer to resolve the joke")
    # You can add custom validation logic easily with Pydantic.
    @validator('setup')
    def question_ends_with_question_mark(cls, field):
        if field[-1] != '?':
            raise ValueError("Badly formed question!")
        return field
parser = PydanticOutputParser(pydantic_object=Joke)
prompt = PromptTemplate(
    template="Answer the user query.\n{format_instructions}\n{query}\n",
    input_variables=["query"],
    partial_variables={"format_instructions": parser.get_format_instructions()}
)
joke_query = "Tell me a joke."
_input = prompt.format_prompt(query=joke_query)
output = model(_input.to_string())
print(parser.get_format_instructions())
print(output)
print(parser.parse(output))

索引(Indexs)

索引可以讓文檔結構化,從而 LLM 可以直接更好的和文檔交互;比如用於答疑,知識庫等,LLM 先從文檔中獲取答案。

LangChain 在索引這塊也提供了許多有用的函數和工具,方便我們從外部加載與檢索不同的文檔數據;

在數據索引這塊,LangChain 提供的主要工具:

  1. Document Loaders:從不同的數據源加載文檔,當使用 loader 加載器讀取到數據源後,數據源需要轉換成 Document 對象後,後續才能進行使用。

  2. Text Splitters:實現文本分割, 我們每次不管是做把文本當作 prompt 發給 openai api ,還是還是使用 openai api embedding 功能都是有字符限制的。比如我們將一份 300 頁的 pdf 發給 openai api,讓他進行總結,他肯定會報超過最大 Token 錯。所以這裏就需要使用文本分割器去分割我們 loader 進來的 Document。

  3. VectorStores:把文檔存儲爲向量結構, 因爲數據相關性搜索其實是向量運算。所以,不管我們是使用 openai api embedding 功能還是直接通過向量數據庫直接查詢,都需要將我們的加載進來的數據 Document 進行向量化,才能進行向量運算搜索。轉換成向量也很簡單,只需要我們把數據存儲到對應的向量數據庫中即可完成向量的轉換。

  4. Retrievers:用於檢索文檔的數據

圖中的 FAISS 是一種向量存儲的服務;

給一個案例,瞭解下不同工具的用法:

  1. 首先加載文檔

  2. 然後分隔文檔爲不同區塊:

  3. 然後轉換爲向量存儲

  4. 將向量存儲轉換爲檢索器,交給 LangChain,用於問答

import os
from langchain.chains import RetrievalQA
from langchain.document_loaders import TextLoader
from langchain.embeddings import OpenAIEmbeddings
from langchain.indexes import VectorstoreIndexCreator
from langchain.text_splitter import CharacterTextSplitter
from langchain.vectorstores import Chroma
from langchain.llms import OpenAI
# 設置代理
os.environ['HTTP_PROXY'] = 'socks5h://127.0.0.1:13659'
os.environ['HTTPS_PROXY'] = 'socks5h://127.0.0.1:13659'
# 創建文本加載器
loader = TextLoader('/Users/aihe/Downloads/demo.txt', encoding='utf8')
# 加載文檔
documents = loader.load()
# 文本分塊
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = text_splitter.split_documents(documents)
# 計算嵌入向量
embeddings = OpenAIEmbeddings()
# 創建向量庫
db = Chroma.from_documents(texts, embeddings)
# 將向量庫轉換爲檢索器
retriever = db.as_retriever()
# 創建檢索問答系統
qa = RetrievalQA.from_chain_type(llm=OpenAI(), chain_type="stuff", retriever=retriever)
# 運行問題答案檢索
query = "如何申請租戶?"
print(qa.run(query))
print(qa.run("能否說明下你可以提供的功能?"))

存儲(Memory)

默認情況下 Agent 和 Chain 都是無狀態的,也就是用完之後不知道上次的對話內容是什麼。每次的 query 都是獨立的。

但是在有些應用中,記住上一次的會話內容是比較重要的,比如聊天,LangChain 對於也提供了一些相關的工具類。

from langchain import ConversationChain, OpenAI
from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory()
memory.chat_memory.add_user_message("你好!")
memory.chat_memory.add_ai_message("你好嗎?")
llm = OpenAI(temperature=0)
chain = ConversationChain(llm=llm,
                          verbose=True,
                          memory=memory)
chain.predict(input="最近怎麼樣!")
print(chain.predict(input="感覺很不錯,剛和AI做了場對話."))

鏈(Chains)

鏈可以讓我們把多個組件組合成一個應用,比如我們創建一個鏈,這個鏈可以接受用戶的輸入,然後通過 PromptTemplate 格式化用戶的輸入爲提示詞,然後把這個提示詞輸入給 LLM。

我們也可以把一些鏈組合在一起,構建更復雜的鏈。

一個簡單的案例:

# 引入所需模塊和類
from langchain.chains import LLMChain
from langchain.chat_models import ChatOpenAI
from langchain import PromptTemplate
from langchain.prompts.chat import (
    ChatPromptTemplate,  # 引入對話模板類
    HumanMessagePromptTemplate,  # 引入人類消息模板類
)
# 創建人類消息模板類
human_message_prompt = HumanMessagePromptTemplate(
        prompt=PromptTemplate(
            template="給我一個製作{product}的好公司名字?",  # 輸入模板,其中product爲佔位符
            input_variables=["product"],  # 指定輸入變量爲product
        )
    )
# 創建對話模板類
chat_prompt_template = ChatPromptTemplate.from_messages([human_message_prompt])
# 創建OpenAI聊天模型對象
chat = ChatOpenAI(temperature=0.9)
# 創建LLMChain對象,將聊天模型和對話模板傳入
chain = LLMChain(llm=chat, prompt=chat_prompt_template)
# 運行LLMChain對象,並輸出結果
print(chain.run("襪子"))

代理(Agents)

代理是使用 LLM 作爲思考工具,決定當前要做什麼。我們會給代理一系列的工具,代理根據我們的輸入判斷用哪些工具可以完成這個目標,然後不斷的運行工具,來完成目標。

代理可以看做是增強版的 Chain,不僅綁定模板、LLM,還可以給代理添加一些工具。

Agent 是一個智能代理,它負責根據用戶輸入和應用場景,在一系列可用工具中選擇合適的工具進行操作。Agent 可以根據任務的複雜性,採用不同的策略來決定如何執行操作。

有兩種類型的 Agent:

  1. 動作代理(Action Agents):這種代理一次執行一個動作,然後根據結果決定下一步的操作。

  2. 計劃 - 執行代理(Plan-and-Execute Agents):這種代理首先決定一系列要執行的操作,然後根據上面判斷的列表逐個執行這些操作。

對於簡單的任務,動作代理更爲常見且易於實現。對於更復雜或長期運行的任務,計劃 - 執行代理的初始規劃步驟有助於維持長期目標並保持關注。但這會以更多調用和較高延遲爲代價。這兩種代理並非互斥,可以讓動作代理負責執行計劃 - 執行代理的計劃。

Agent 內部涉及的核心概念如下:

  1. 代理(Agent):這是應用程序主要邏輯。代理暴露一個接口,接受用戶輸入和代理已執行的操作列表,並返回 AgentAction 或 AgentFinish。

  2. 工具(Tools):這是代理可以採取的動作。比如發起 HTTP 請求,發郵件,執行命令。

  3. 工具包(Toolkits):這些是爲特定用例設計的一組工具。例如,爲了讓代理以最佳方式與 SQL 數據庫交互,它可能需要一個執行查詢的工具和另一個查看錶格的工具。可以看做是工具的集合。

  4. 代理執行器(Agent Executor):這將代理與一系列工具包裝在一起。它負責迭代運行代理,直到滿足停止條件。

代理的執行流程:

一個案例:

# 引入所需模塊和類
from langchain.agents import load_tools  # 引入加載工具函數
from langchain.agents import initialize_agent  # 引入初始化代理函數
from langchain.agents import AgentType  # 引入代理類型類
from langchain.llms import OpenAI  # 引入OpenAI語言模型類
import os  # 引入os模塊
# 創建OpenAI語言模型對象,設定temperature爲0,即關閉隨機性
llm = OpenAI(temperature=0)
# 加載所需工具,包括serpapi和llm-math
tools = load_tools(["serpapi", "llm-math"], llm=llm)
# 初始化代理對象,設定代理類型爲ZERO_SHOT_REACT_DESCRIPTION,輸出詳細信息
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
# 運行代理對象,向其提問特朗普的年齡和年齡除以2的結果
agent.run("特朗普今年多少歲? 他的年齡除以2是多少?")

上述代碼中關於 Agent 有個初始化的階段,agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,代理類型決定了代理如何使用工具、處理輸入以及與用戶進行交互。從而爲用戶提供有針對性的服務。其中可以選擇的類型如下:

initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
  1. zero-shot-react-description:該代理使用 ReAct 框架僅根據工具的描述來確定要使用哪個工具,可以提供任意數量的工具。要求爲每個工具提供一個描述。

  2. react-docstore:該代理使用 ReAct 框架與文檔存儲(docstore)進行交互。必須提供兩個工具:一個搜索工具和一個查找工具(它們必須確切地命名爲 Search 和 Lookup)。搜索工具應該用於搜索文檔,而查找工具應該在最近找到的文檔中查找術語。該代理等同於原始的 ReAct 論文,特別是維基百科的示例。

  3. self-ask-with-search:該代理使用一個名爲 Intermediate Answer 的單一工具。這個工具應該能夠查找問題的事實性答案。這個代理等同於原始的自問自答(self-ask)與搜索論文,其中提供了作爲工具的谷歌搜索 API。

  4. conversational-react-description該代理旨在用於對話設置中。提示讓代理在對話中變得有幫助。它使用 ReAct 框架來決定使用哪個工具,並使用內存來記住之前的對話互動。

  5. **structured-chat-zero-shot-react-description:  **在對話中可以使用任意的工具,並且能夠記住對話的上下文。

官方已經默認提供了一系列的工具箱,發 Gmail 郵件,數據庫查詢,JSON 處理等;還有一些單個的工具列表,都可以在文檔中看到:https://python.langchain.com/en/latest/modules/agents/tools/getting_started.html

我們通過一個自定義的工具,瞭解下工具怎麼用,因爲後面再使用 LangChain 的時候我們做的也就是不斷的自定義工具。

編寫工具的時候,要準備:

  1. 名稱

  2. 工具描述:說明你的工具是做什麼的

  3. 參數結構:當前工具需要的入參是什麼結構

LangChain 應用案例

假設我們需要構建一個基於 LLM 的問答系統,該系統需要從指定的數據源中提取信息以回答用戶的問題。我們可以使用 LangChain 中的數據增強生成功能與外部數據源進行交互,獲取所需的數據。然後,將數據輸入到 LLM 中,生成回答。記憶功能可以幫助我們在多次調用之間保持相關狀態,從而提高問答系統的性能。此外,我們還可以使用智能代理功能實現系統的自動優化。最後,通過 LangChain 提供的評估提示和鏈實現,我們可以對問答系統的性能進行評估和優化。

LangChain 生成圖片

實現了一個基於語言模型的文本生成圖片工具,調用不同的工具函數來最終生成圖片。主要提供了以下幾個工具:

  1. random_poem:隨機返回中文的詩詞。

  2. prompt_generate:根據中文提示詞生成對應的英文提示詞。

  3. generate_image:根據英文提示詞生成對應的圖片。

import base64
import json
import os
from io import BytesIO
import requests
from PIL import Image
from pydantic import BaseModel, Field
from langchain.agents import AgentType, initialize_agent, load_tools
from langchain.chat_models import ChatOpenAI
from langchain.llms import OpenAI
from langchain.tools import BaseTool, StructuredTool, Tool, tool
from langchain import LLMMathChain, SerpAPIWrapper
def generate_image(prompt: str) -> str:
    """
    根據提示詞生成對應的圖片
    Args:
        prompt (str): 英文提示詞
    Returns:
        str: 圖片的路徑
    """
    url = "http://127.0.0.1:7860/sdapi/v1/txt2img"
    headers = {
        "accept": "application/json",
        "Content-Type": "application/json"
    }
    data = {
        "prompt": prompt,
        "negative_prompt": "(worst quality:2), (low quality:2),disfigured, ugly, old, wrong finger",
        "steps": 20,
        "sampler_index": "Euler a",
        "sd_model_checkpoint": "cheeseDaddys_35.safetensors [98084dd1db]",
        # "sd_model_checkpoint": "anything-v3-fp16-pruned.safetensors [d1facd9a2b]",
        "batch_size": 1,
        "restore_faces": True
    }
    response = requests.post(url, headers=headers, data=json.dumps(data))
    if response.status_code == 200:
        response_data = response.json()
        images = response_data['images']
        for index, image_data in enumerate(images):
            img_data = base64.b64decode(image_data)
            img = Image.open(BytesIO(img_data))
            file_name = f"image_{index}.png"
            file_path = os.path.join(os.getcwd(), file_name)
            img.save(file_path)
            print(f"Generated image saved at {file_path}")
            return file_path
    else:
        print(f"Request failed with status code {response.status_code}")
def random_poem(arg: str) -> str:
    """
    隨機返回中文的詩詞
    Returns:
        str: 隨機的中文詩詞
    """
    llm = OpenAI(temperature=0.9)
    text = """
        能否幫我從中國的詩詞數據庫中隨機挑選一首詩給我,希望是有風景,有畫面的詩:
        比如:山重水複疑無路,柳暗花明又一村。
    """
    return llm(text)
def prompt_generate(idea: str) -> str:
    """
    生成圖片需要對應的英文提示詞
    Args:
        idea (str): 中文提示詞
    Returns:
        str: 英文提示詞
    """
    llm = OpenAI(temperature=0, max_tokens=2048)
    res = llm(f"""
    Stable Diffusion is an AI art generation model similar to DALLE-2.
    Below is a list of prompts that can be used to generate images with Stable Diffusion:
    - portait of a homer simpson archer shooting arrow at forest monster, front game card, drark, marvel comics, dark, intricate, highly detailed, smooth, artstation, digital illustration by ruan jia and mandy jurgens and artgerm and wayne barlowe and greg rutkowski and zdislav beksinski
    - pirate, concept art, deep focus, fantasy, intricate, highly detailed, digital painting, artstation, matte, sharp focus, illustration, art by magali villeneuve, chippy, ryan yee, rk post, clint cearley, daniel ljunggren, zoltan boros, gabor szikszai, howard lyon, steve argyle, winona nelson
    - ghost inside a hunted room, art by lois van baarle and loish and ross tran and rossdraws and sam yang and samdoesarts and artgerm, digital art, highly detailed, intricate, sharp focus, Trending on Artstation HQ, deviantart, unreal engine 5, 4K UHD image
    - red dead redemption 2, cinematic view, epic sky, detailed, concept art, low angle, high detail, warm lighting, volumetric, godrays, vivid, beautiful, trending on artstation, by jordan grimmer, huge scene, grass, art greg rutkowski
    - a fantasy style portrait painting of rachel lane / alison brie hybrid in the style of francois boucher oil painting unreal 5 daz. rpg portrait, extremely detailed artgerm greg rutkowski alphonse mucha greg hildebrandt tim hildebrandt
    - athena, greek goddess, claudia black, art by artgerm and greg rutkowski and magali villeneuve, bronze greek armor, owl crown, d & d, fantasy, intricate, portrait, highly detailed, headshot, digital painting, trending on artstation, concept art, sharp focus, illustration
    - closeup portrait shot of a large strong female biomechanic woman in a scenic scifi environment, intricate, elegant, highly detailed, centered, digital painting, artstation, concept art, smooth, sharp focus, warframe, illustration, thomas kinkade, tomasz alen kopera, peter mohrbacher, donato giancola, leyendecker, boris vallejo
    - ultra realistic illustration of steve urkle as the hulk, intricate, elegant, highly detailed, digital painting, artstation, concept art, smooth, sharp focus, illustration, art by artgerm and greg rutkowski and alphonse mucha
    I want you to write me a list of detailed prompts exactly about the idea written after IDEA. Follow the structure of the example prompts. This means a very short description of the scene, followed by modifiers divided by commas to alter the mood, style, lighting, and more.
    IDEA: {idea}""")
    return res
class PromptGenerateInput(BaseModel):
    """
    生成英文提示詞所需的輸入模型類
    """
    idea: str = Field()
class GenerateImageInput(BaseModel):
    """
    生成圖片所需的輸入模型類
    """
    prompt: str = Field(description="英文提示詞")
tools = [
    Tool.from_function(
        func=random_poem,
        ,
        description="隨機返回中文的詩詞"
    ),
    Tool.from_function(
        func=prompt_generate,
        ,
        description="生成圖片需要對應的英文提示詞,當前工具可以將輸入轉換爲英文提示詞,以便方便生成",
        args_schema=PromptGenerateInput
    ),
    Tool.from_function(
        func=generate_image,
        ,
        description="根據提示詞生成對應的圖片,提示詞需要是英文的,返回是圖片的路徑",
        args_schema=GenerateImageInput
    ),
]
def main():
    """
    主函數,初始化代理並執行對話
    """
    llm = OpenAI(temperature=0)
    agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
    agent.run("幫我生成一張詩詞的圖片?")
if __name__ == '__main__':
    main()

LangChain 做答疑

參考上面的索引部分:

import os
from langchain.chains import RetrievalQA
from langchain.document_loaders import TextLoader
from langchain.embeddings import OpenAIEmbeddings
from langchain.indexes import VectorstoreIndexCreator
from langchain.text_splitter import CharacterTextSplitter
from langchain.vectorstores import Chroma
from langchain.llms import OpenAI
# 設置代理
os.environ['HTTP_PROXY'] = 'socks5h://127.0.0.1:13659'
os.environ['HTTPS_PROXY'] = 'socks5h://127.0.0.1:13659'
# 創建文本加載器
loader = TextLoader('/Users/aihe/Downloads/demo.txt', encoding='utf8')
# 加載文檔
documents = loader.load()
# 文本分塊
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = text_splitter.split_documents(documents)
# 計算嵌入向量
embeddings = OpenAIEmbeddings()
# 創建向量庫
db = Chroma.from_documents(texts, embeddings)
# 將向量庫轉換爲檢索器
retriever = db.as_retriever()
# 創建檢索問答系統
qa = RetrievalQA.from_chain_type(llm=OpenAI(), chain_type="stuff", retriever=retriever)
# 運行問題答案檢索
query = "如何申請租戶?"
print(qa.run(query))
print(qa.run("能否說明下你可以提供的功能?"))

Langchain 輸出結構化 JSON 數據

參考上述概念,提示詞工具中提供了 OutputParser 可以把我們的對象轉換爲提示詞,告訴 LLM 要返回什麼結構的內容。

import requests
from langchain.agents import AgentType, initialize_agent
from langchain.chat_models import ChatOpenAI
from langchain.tools import StructuredTool
from pydantic import BaseModel, Field
def post_message(type: str, param: dict) -> str:
    """
     當需要生成人羣、分析畫像、諮詢問題時,使用如下的指示:url 固定爲:http://localhost:3001/
     如果請求是生成人羣,請求的type爲crowd; 如果請求是分析畫像,請求的type爲analyze; 如果是其他或者答疑,請求的type爲question;
     請求body的param把用戶指定的條件傳進來即可
     """
    result = requests.post("http://localhost:3001/", json={"type": type, "param": param})
    return f"Status: {result.status_code} - {result.text}"
class PostInput(BaseModel):
    # body: dict = Field(description="""格式:{"type":"","param":{}}""")
    type: str = Field(description="請求的類型,人羣爲crowd,畫像爲analyze")
    param: dict = Field(description="請求的具體描述")
llm = ChatOpenAI(temperature=0)
tools = [
    StructuredTool.from_function(post_message)
]
agent = initialize_agent(tools, llm, agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
agent.run("我想生成一個性別爲男並且在180天訪問過淘特的人羣?")

LangChain 做一款自己的聊天機器人

原本做聊天機器人,需要一些前端代碼,但是已經有相應的開源工具,幫我們把 LangChian 的各種組件做了可視化,直接拖拽即可,我們直接使用 LangFlow;

pip install langflow

然後運行命令:

langfow

如果和本地的 LangChain 有衝突,可以使用 Docker 運行 langfow:

FROM python:3.10-slim
RUN apt-get update && apt-get install gcc g++ git make -y
RUN useradd -m -u 1000 user
USER user
ENV HOME=/home/user \
    PATH=/home/user/.local/bin:$PATH
WORKDIR $HOME/app
COPY --chown=user . $HOME/app
RUN pip install langflow>==0.0.71 -U --user
CMD ["langflow", "--host", "0.0.0.0", "--port", "7860"]

在界面上配置 LangChain 的三個組件:在最右下角是對應的聊天窗口,輸入下 openai 的 key

開始聊天驗證下我們的配置:

全程基本上不用怎麼寫代碼,只需要瞭解 LangChain 的組件是做什麼的,基本上就可以搭出一款簡單的聊天機器人。

其它的 LangChain 組件代理,內存,數據索引也是都可以使用的。

LangChain 的未來展望

LangChain 爲構建基於大型語言模型的應用提供了一個強大的框架,將逐步的運用到各個領域中,如,智能客服、文本生成、知識圖譜構建等。隨着更多的工具和資源與 LangChain 進行集成,大語言模型對人的生產力將會有更大的提升。

應用場景構思:

  1. 智能客服:結合聊天模型、自主智能代理和問答功能,開發智能客服系統,幫助用戶解決問題,提高客戶滿意度。

  2. 個性化推薦:利用智能代理與文本嵌入模型,分析用戶的興趣和行爲,爲用戶提供個性化的內容推薦。

  3. 知識圖譜構建:通過結合問答、文本摘要和實體抽取等功能,自動從文檔中提取知識,構建知識圖譜。

  4. 自動文摘和關鍵信息提取:利用 LangChain 的文本摘要和抽取功能,從大量文本中提取關鍵信息,生成簡潔易懂的摘要。

  5. 代碼審查助手:通過代碼理解和智能代理功能,分析代碼質量,爲開發者提供自動化代碼審查建議。

  6. 搜索引擎優化:結合文本嵌入模型和智能代理,分析網頁內容與用戶查詢的相關性,提高搜索引擎排名。

  7. 數據分析與可視化:通過與 API 交互和查詢表格數據功能,自動分析數據,生成可視化報告,幫助用戶瞭解數據中的洞察信息。

  8. 智能編程助手:結合代碼理解和智能代理功能,根據用戶輸入的需求自動生成代碼片段,提高開發者的工作效率。

  9. 在線教育平臺:利用問答和聊天模型功能,爲學生提供實時的學術支持,幫助他們解決學習中遇到的問題。

  10. 自動化測試:結合智能代理和代理模擬功能,開發自動化測試場景,提高軟件測試的效率和覆蓋率。

現在有個平臺已經實現了大部分:https://zapier.com/l/natural-language-actions。底層爲 OpenAI 模型,使用 zapier 來實現將萬種工具連接起來。可以在這個平臺上配置各種工具,模型會根據你的目標選擇相應的動作。工作內容自動化在不遠處很快就會實現

總結

本文介紹了 LangChain 框架,它能夠將大型語言模型與其他計算或知識來源相結合,從而實現功能更加強大的應用。接着,對 LangChain 的關鍵概念進行了詳細說明,並基於該框架進行了一些案例嘗試,旨在幫助讀者更輕鬆地理解 LangChain 的工作原理。

展望未來,LangChain 有望在各個領域發揮巨大作用,促進我們工作效率的變革。我們正處於 AI 爆發的前夜,積極擁抱新技術將會帶來完全不同的感覺。

參考資料:

  1. Langchain 中文入門:https://github.com/liaokongVFX/LangChain-Chinese-Getting-Started-Guide

  2. LangChain 官方文檔:https://python.langchain.com/en/latest/modules/indexes/getting_started.html

  3. LangFlow,LangChain 的可視化編排工具:https://github.com/logspace-ai/langflow

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/gPfYTxwiCkFa4fck0weBRA