一文探秘LLM应用开发(30)-编排与集成(langchain主要模块介绍)

技术

动手点关注

picture.image

干货不迷路

picture.image

本文旨在让无大模型开发背景的工程师或者技术爱好者无痛理解大语言模型应用开发的理论和主流工具,因此会先从与LLM应用开发相关的基础概念谈起,并不刻意追求极致的严谨和完备,而是从直觉和本质入手,结合笔者调研整理及消化理解,帮助大家能够更容易的理解LLM技术全貌,大家可以基于本文衍生展开,结合自己感兴趣的领域深入研究。若有不准确或者错误的地方也希望大家能够留言指正。

本文体系完整,内容丰富,由于内容比较多,分多次连载

第一部分 基础概念

1.机器学习场景类别

2.机器学习类型(LLM相关)

3.深度学习的兴起

4.基础模型

第二部分 应用挑战

1.问题定义与基本思路

2.基本流程与相关技术

1)Tokenization与Embbeding

2)向量数据库

3)finetune(微调)

4)模型部署与推理

5)prompt

6)编排与集成

7)其它(预训练等)

第三部分 场景案例

常用参考

第二部分 应用挑战

2.基本流程与相关技术

点此查看前面内容:

picture.image

4)编排与集成

经过前面的介绍,我们对大模型应用开发的通常涉及到的重要构成组件都有了介绍,然而这些零散的组件需要有一根”线“将它们串联起来,最终变成用户可以感受到的LLM应用。这里编排集成服务便起到了这样的“线“的作用,它作为粘合剂和应用骨架,在整个应用构成中起到了提纲挈领的作用。

在本章你将学习到:

1)相关理论和应用开发范式

2)Langchain框架介绍

3)LlamaIndex框架介绍

4)Semantic Kernel框架介绍

5) 技术展望

Langchain主要模块介绍

当前LangChain版本是由Langchain-core,Langchain-commuity,Langchain三部分组成,其中Langchain-core的核心是由LCEL构成的,专注于给开发者提供一个灵活、简单的声明式大模型链的构开发协议,而Langchain和Langchain-commuity是构建LLM应用的核心模式及生态实现,其重点是提供标准的,可扩展的接口实现和生态集成的基础模块,包含Models, Retriev al,Agents三类。

LCEL

picture.image

在langchain项目早期,这一模块是不存在的,但随着应用模式的复杂化,以及具体实现越来越多样,langchain越来越表现的复杂和僵化。为了解决这一问题,以及奠定langchain的标准地位,langchain core的概念逐渐形成,其核心是LCEL(Langchain Expression Language),它在langchain整体架构中定位为协议层。基于它可以有效的构造LLM应用链(Chains),在不用代码变更的情况下,完成从原型开发到生产应用。

官方列举的有关LCEL的一些特点:

1)流式支持:当您使用 LCEL 构建链时,您将获得最佳的 "time-to-first-token"(直到输出第一chunk内容所需的时间)。对于某些链来说,这意味着,例如,我们直接将 LLM 中的token流传输到流式输出解析器,您将以与 LLM 提供者输出原始token相同的速度获得已解析的增量输出chunk。

2)异步支持:使用 LCEL 构建的任何链都可以通过同步 API(例如在 Jupyter 笔记本中进行原型开发时)和异步 API(例如在 LangServe 服务器中)进行调用。这样就能在原型和生产中使用相同的代码,并获得极佳的性能,还能在同一服务器中处理多个并发请求。

3)优化并行执行:只要你的 LCEL 链中有可以并行执行的步骤(例如,从多个检索器中获取文档),我们就会在同步和异步接口中自动执行,以尽可能减少延迟。

4)重试和回退:为 LCEL 链的任何部分配置重试和回退。这是提高链可靠性的好方法。我们目前正在努力为重试/回退添加流支持,这样您就可以在不增加延迟成本的情况下获得更高的可靠性。

5)访问中间结果:对于更复杂的链来说,在生成最终输出之前访问中间步骤的结果往往非常有用。这可以用来让最终用户了解正在发生的事情,甚至只是用来调试链。你可以在每个 LangServe 服务器上对中间结果进行流式处理。

6)输入和输出模式:输入和输出模式为每个 LCEL 链提供了根据链结构推断出的 Pydantic 和 JSONSchema 模式。这可用于验证输入和输出,是 LangServe 不可分割的一部分。

  7)无缝的 LangSmith 跟踪集成:随着链变得越来越复杂,了解每一步到底发生了什么变得越来越重要。有了 LCEL,所有步骤都会自动记录到 LangSmith 中,从而实现最大程度的可观察性和可调试性。

8)无缝的 LangServe 部署集成:使用 LCEL 创建的任何链都可以使用 LangServe 轻松部署。

LCEL相较于早期langchain实现方法,最大的优势是更加标准化,原子化,流程化,通过统一的对象接口(都实现Runnable接口)以及对象之间的自由组合,能够更容易应对需求的变化。

使用方法也比较简单,LCEL采用声明式的结构,通过类似linux管道的形式表达chain的逻辑。


          
from langchain.chat_models import ChatOpenAI
          
from langchain.prompts import ChatPromptTemplate
          
from langchain_core.output_parsers import StrOutputParser
          

          
prompt = ChatPromptTemplate.from_template("tell me a short joke about {topic}")
          
model = ChatOpenAI()
          
output_parser = StrOutputParser()
          

          
chain = prompt | model | output_parser
          

          
chain.invoke({"topic": "ice cream"})
      

通过LCEL将组件构造成一个链:


        
            

          chain = prompt | model | output\_parser
        
      

“|” 符号类似于 unix 管道操作符,它将不同的组件链在一起,将一个组件的输出作为下一个组件的输入。其pipeline结构如下:

picture.image

对于相对复杂的RAG来讲,LCEL表达式一样可以完成,如下:


          
# Requires:
          
# pip install langchain docarray tiktoken
          

          
from langchain.chat_models import ChatOpenAI
          
from langchain.embeddings import OpenAIEmbeddings
          
from langchain.prompts import ChatPromptTemplate
          
from langchain.vectorstores import DocArrayInMemorySearch
          
from langchain_core.output_parsers import StrOutputParser
          
from langchain_core.runnables import RunnableParallel, RunnablePassthrough
          

          
vectorstore = DocArrayInMemorySearch.from_texts(
          
    ["harrison worked at kensho", "bears like to eat honey"],
          
    embedding=OpenAIEmbeddings(),
          
)
          
retriever = vectorstore.as_retriever()
          

          
template = """Answer the question based only on the following context:
          
{context}
          

          
Question: {question}
          
"""
          
prompt = ChatPromptTemplate.from_template(template)
          
model = ChatOpenAI()
          
output_parser = StrOutputParser()
          

          
setup_and_retrieval = RunnableParallel(
          
    {"context": retriever, "question": RunnablePassthrough()}
          
)
          
chain = setup_and_retrieval | prompt | model | output_parser
          

          
chain.invoke("where did harrison work?")
      

其中,核心的RAG流程同样可以用下面表达式表达:


          
setup_and_retrieval = RunnableParallel(
          
    {"context": retriever, "question": RunnablePassthrough()}
          
)
          
chain = setup_and_retrieval | prompt | model | output_parser
      

最终形成的Pipeline结构如下:

picture.image

虽然,LCEL的初衷是为了简化LLM应用构建的复杂度,但它的一些框架概念和约定,比如接口实现和回调钩子会在用户不熟悉的情况下带来一些学习和排错成本。

picture.image

好处是,Langchain官方 给出了很多常见的LLM应用通过LCEL实现的例子,大家在实现过程中可以对照参考。地址: https://python.langchain.com/docs/expression\_language/cookbook。

基础模块

大模型技术栈和工具百花齐放,但上层的应用模式相对比较统一,为了更好的让开发者避免与底层差异性打交道,因此langchain提供了基础模块的协议实现,第三方可以根据该协议进行适配,这样对于开发者来讲就无须过度关注底层供应商,而只需专注应用本身即可。

1)Model I/O

picture.image

Model I/O是有关模型输入输出交互的相关模块,包含Prompts,Chat Models,LLMs,OutParsers。
  • Prompts

在前面介绍里,Prompt的好坏很大程度上决定了大模型输出结果的好坏,但又不是所有开发者都能熟练的掌握Prompt enginering的各种基础,并且,对于应用来讲,它和简单和大模型进行对话也是不同的,为了适配大模型的接口要求以及便于编程,因此langchain针对于LLM应用本身,对围绕Prompt的常见操作进行了一些增强和封装。比如PromptTemplate提供了prompt的模版,可以自动的进行变量的替换,应用开发者无需专门进行处理。


          
from langchain.prompts import PromptTemplate
          

          
prompt_template = PromptTemplate.from_template(
          
    "Tell me a {adjective} joke about {content}."
          
)
          
prompt_template.format(adjective="funny", content="chickens")
      

在针对于COT few-shot场景,为了提高例子选择的有效性,还提供了 Example selectors可以方便的自定义示例的添加。

  • Chat Models/LLMs ==================

langchain提供了大量的基座模型的适配,基本上涵盖当下主流的所有模型,可以采用一致的方法添加使用。以OpenAI的LLM为例:


          
from langchain.llms import OpenAI
          

          
llm = OpenAI()
      

即langchain.llms中选择要导入的模型提供商,初始化使用即可。

除此之外,langchain还提供了请求cache,监控token使用量等常见功能支持,避免开发者从零开始。

  • Output parsers ===============

由于大模型的默认输出是非结构化的文本内容。然而,对于程序来讲,更倾向于处理结构化的数据,从而提升应用程序的鲁棒性。而Output Parser便是针对这一需求产生的,它可以将大模型的输出变得结构化。可以说,它是function calling的一个早期兼容实现。官方实现了很多种Parser,常见的有List Parser、Datetime Parser、Enum Parser、Pydantic Parser等等。

下面是一个使用Pydantic Parser解析json对象输出的例子:


          
from langchain.llms import OpenAI
          
from langchain.output_parsers import PydanticOutputParser
          
from langchain.prompts import PromptTemplate
          
from langchain_core.pydantic_v1 import BaseModel, Field, validator
          

          
model = OpenAI(model_name="gpt-3.5-turbo-instruct", temperature=0.0)
          

          

          
# 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
          

          

          
# Set up a parser + inject instructions into the prompt template.
          
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()},
          
)
          

          
# And a query intended to prompt a language model to populate the data structure.
          
prompt_and_model = prompt | model
          
output = prompt_and_model.invoke({"query": "Tell me a joke."})
          
parser.invoke(output)
      
2)Retrieval

picture.image

Retrieval类的模块专注于检索增强应用(RAG)的构建,包含了建库和检索两部分。具体包含Document loaders、 Document transformers 、 Text embedding models 、 Vector stores 、 Indexing 、 Retrievers 模块构成。
  • Document loaders =================
Document loaders,即文档加载器,负责从不同的类别的外部介质中将文档读取到内存中。LangChain提供了100多种不同的文档加载程序,并与该领域的其他主要提供商(如AirByte和Unstructured)集成。LangChain提供集成,可从所有类型的位置(私有S3存储桶、公共网站)加载所有类型的文档(HTML、PDF、代码)。比如,加载本地json格式文件:

          
from langchain.document_loaders import JSONLoader
          

          
import json
          
from pathlib import Path
          
from pprint import pprint
          

          

          
file_path='./example_data/facebook_chat.json'
          
data = json.loads(Path(file_path).read_text())
      
  • Document transformers ======================
Document transformers,即文档转换器。langchain内置的或者集成的文档转换器,可以轻松地拆分、组合、过滤和以其他方式操作文档。其核心目标是负责将读取的文档根据一定的策略切分成chunk,添加metadata等信息。langchain提供了很多算法策略来优化chunking的效果,并且还针对于不同的文档类型,比如code,markdown等做了优化。

          
# This is a long document we can split up.
          
with open('../../state_of_the_union.txt') as f:
          
    state_of_the_union = f.read()
          

          
from langchain.text_splitter import RecursiveCharacterTextSplitter
          

          
text_splitter = RecursiveCharacterTextSplitter(
          
    # Set a really small chunk size, just to show.
          
    chunk_size = 100,
          
    chunk_overlap  = 20,
          
    length_function = len,
          
    add_start_index = True,
          
)
          

          
texts = text_splitter.create_documents([state_of_the_union])
          
print(texts[0])
          
print(texts[1])
          

      

          
    page_content='Madam Speaker, Madam Vice President, our First Lady and Second Gentleman. Members of Congress and' metadata={'start_index': 0}
          
    page_content='of Congress and the Cabinet. Justices of the Supreme Court. My fellow Americans.' metadata={'start_index': 82}
      
  • Text embedding models ======================
为了完成向量检索,需要将拆分好的chunk写入到向量数据库中以以及检索阶段召回有用的chunk,这时候就需要embeding model。langchain提供了大量的embedding model实现。优秀的embeding模型对于RAG整体效果有非常重要的作用,甚至在某些场合下我们还需要和大模型一样对embedding模型进行微调以便提升效果。

          
from langchain.embeddings import OpenAIEmbeddings
          

          
embeddings_model = OpenAIEmbeddings()
          

          
embeddings = embeddings_model.embed_documents(
          
    [
          
        "Hi there!",
          
        "Oh, hello!",
          
        "What's your name?",
          
        "My friends call me World",
          
        "Hello World!"
          
    ]
          
)
          

          
len(embeddings), len(embeddings[0])
      

为了避免重复的进行embedding计算,提高性能降低成本,还提供了CacheBackedEmbeddings的实现。

  • Vector stores ==============

作为RAG应用的关键构成,向量数据库对于提升检索召回效果尤为重要。langchain提供了众多向量数据库的集成,开发者可以采用相对统一的方式,结合实际的场景选择不同的实现,比如本地、云等。


          
import os
          
import getpass
          

          
os.environ['OPENAI_API_KEY'] = getpass.getpass('OpenAI API Key:')
          

          
from langchain.document_loaders import TextLoader
          
from langchain.embeddings.openai import OpenAIEmbeddings
          
from langchain.text_splitter import CharacterTextSplitter
          
from langchain.vectorstores import Chroma
          

          
# Load the document, split it into chunks, embed each chunk and load it into the vector store.
          
raw_documents = TextLoader('../../../state_of_the_union.txt').load()
          
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
          
documents = text_splitter.split_documents(raw_documents)
          
db = Chroma.from_documents(documents, OpenAIEmbeddings())
      
  • Indexing =========

为了方便将文档写入到向量数据库中,langchain提供了标准的建库的API,可以帮助源文档与向量数据库内容保持同步。关键的是,就算前面经过了文档转换,建库的API仍然能够正常工作。这得益于,LangChain建库使用记录管理器(RecordManager)来跟踪写入向量存储的文档。索引内容时,会对每个文档计算哈希值,并在记录管理器中存储以下信息:

  • 文档哈希值(页面内容和元数据的哈希值)
  • 写入时间
  • 源 id - 每份文档都应在元数据中包含信息,以便确定该文档的最终来源

          
from langchain.embeddings import OpenAIEmbeddings
          
from langchain.indexes import SQLRecordManager, index
          
from langchain.schema import Document
          
from langchain.vectorstores import ElasticsearchStore
          

          
Initialize a vector store and set up the embeddings:
          

          
collection_name = "test_index"
          

          
embedding = OpenAIEmbeddings()
          

          
vectorstore = ElasticsearchStore(
          
    es_url="http://localhost:9200", index_name="test_index", embedding=embedding
          
)
          

          

          
namespace = f"elasticsearch/{collection_name}"
          
record_manager = SQLRecordManager(
          
    namespace, db_url="sqlite:///record_manager_cache.sql"
          
)
          

          

          
record_manager.create_schema()
          

          
doc1 = Document(page_content="kitty", metadata={"source": "kitty.txt"})
          
doc2 = Document(page_content="doggy", metadata={"source": "doggy.txt"})
      
  • retriever

retriever,检索器,它作为RAG应用的核心模块,是整个检索过程的载体,是langchain实现的重点,同时,检索器实现了 Runnable 接口,这是 LangChain 表达式语言(LCEL)的基本构件。这意味着它们支持 invoke、ainvoke、stream、astream、batch、abatch、astream_log 调用,其中一个典型应用就是可以更好的观察调试。retriever有大量的实现,比如MultiQueryRetriever、MultiVectorRetriever、self-query retriever等等,它们都是langchain结合生产实际需求不断沉淀的精华所在。


          
from langchain.chat_models import ChatOpenAI
          
from langchain.retrievers.multi_query import MultiQueryRetriever
          

          
question = "What are the approaches to Task Decomposition?"
          
llm = ChatOpenAI(temperature=0)
          
retriever_from_llm = MultiQueryRetriever.from_llm(
          
    retriever=vectordb.as_retriever(), llm=llm
          
)
      
3)Agents

Agents应用作为langchain区别于其它框架的一大亮点,是langchain重点关注的领域。Langchain提供了主流的自主agent构建的模式和方法,包括Re-Act、Plan-and-execute 、Self-ask with search、OpenAI assistants等等。

在前面的文章里,我们提到过Agents相较于RAG等LLM Chains应用最大的不同是在Agents中,原本人来规划任务流程和操作变成了由大模型来完成。

有关langchain构建agents的相关细节内容在《 一文探秘LLM应用开发(26)-Prompt(架构模式之Agent框架AutoGPT、AutoGen等) 》,这里就不再赘述。在其官方文档中还有更多的使用案例,这里不再一一介绍。

4)其它

除了前面提到的Model I/O、Retrieval、Agents外,langchain还提供了一些公共的组件支持,比如

Chains、memory和callbacks。

Chains是在LCEL出现之前的应用编排的方法,在更标准、更简单LCEL出现后,官方更推荐使用LCEL,然而,chains中遗留了很多历史实现的一些模式还很有价值,因此开发者也可以直接使用它们。

picture.image

大模型本身是无记忆的,为了让应用有状态,形成多轮的交互,即支持记忆。langchain提供了Memory模块,它能够帮助应用维持会话信息,自动的将对话历史追加到Prompt中,继而透明的完成大模型记忆的构建,在langchain中还提供了很多优化的手段,如对与历史进行摘要减少历史会话内容过多,导致token消耗或者context window超限的问题。

最后,callbacks是为了提高LLM应用的灵活性,langchain在LLM应用生命周期的各个阶段增设了一些钩子,利用它们用来自定义实现一些逻辑,这对于日志记录、监控、流式传输和其他任务非常有用。


          
class BaseCallbackHandler:
          
    """Base callback handler that can be used to handle callbacks from langchain."""
          

          
    def on_llm_start(
          
        self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any
          
    ) -> Any:
          
        """Run when LLM starts running."""
          

          
    def on_chat_model_start(
          
        self, serialized: Dict[str, Any], messages: List[List[BaseMessage]], **kwargs: Any
          
    ) -> Any:
          
        """Run when Chat Model starts running."""
          

          
    def on_llm_new_token(self, token: str, **kwargs: Any) -> Any:
          
        """Run on new LLM token. Only available when streaming is enabled."""
          

          
    def on_llm_end(self, response: LLMResult, **kwargs: Any) -> Any:
          
        """Run when LLM ends running."""
          

          
    def on_llm_error(
          
        self, error: Union[Exception, KeyboardInterrupt], **kwargs: Any
          
    ) -> Any:
          
        """Run when LLM errors."""
          

          
    def on_chain_start(
          
        self, serialized: Dict[str, Any], inputs: Dict[str, Any], **kwargs: Any
          
    ) -> Any:
          
        """Run when chain starts running."""
          

          
    def on_chain_end(self, outputs: Dict[str, Any], **kwargs: Any) -> Any:
          
        """Run when chain ends running."""
          

          
    def on_chain_error(
          
        self, error: Union[Exception, KeyboardInterrupt], **kwargs: Any
          
    ) -> Any:
          
        """Run when chain errors."""
          

          
    def on_tool_start(
          
        self, serialized: Dict[str, Any], input_str: str, **kwargs: Any
          
    ) -> Any:
          
        """Run when tool starts running."""
          

          
    def on_tool_end(self, output: str, **kwargs: Any) -> Any:
          
        """Run when tool ends running."""
          

          
    def on_tool_error(
          
        self, error: Union[Exception, KeyboardInterrupt], **kwargs: Any
          
    ) -> Any:
          
        """Run when tool errors."""
          

          
    def on_text(self, text: str, **kwargs: Any) -> Any:
          
        """Run on arbitrary text."""
          

          
    def on_agent_action(self, action: AgentAction, **kwargs: Any) -> Any:
          
        """Run on agent action."""
          

          
    def on_agent_finish(self, finish: AgentFinish, **kwargs: Any) -> Any:
          
        """Run on agent end."""
      

具体实现也比较简单,开发者只需要覆盖实现相应的方法即可,例如 StdOutCallbackHandler,它 将所有事件记录到stdout :


          
class StdOutCallbackHandler(BaseCallbackHandler):
          
    """Callback Handler that prints to std out."""
          

          
    def __init__(self, color: Optional[str] = None) -> None:
          
        """Initialize callback handler."""
          
        self.color = color
          

          
    def on_chain_start(
          
        self, serialized: Dict[str, Any], inputs: Dict[str, Any], **kwargs: Any
          
    ) -> None:
          
        """Print out that we are entering a chain."""
          
        class_name = serialized.get("name", serialized.get("id", ["<unknown>"])[-1])
          
        print(f"\n\n\033[1m> Entering new {class_name} chain...\033[0m")
          

          
    def on_chain_end(self, outputs: Dict[str, Any], **kwargs: Any) -> None:
          
        """Print out that we finished a chain."""
          
        print("\n\033[1m> Finished chain.\033[0m")
          

          
    def on_agent_action(
          
        self, action: AgentAction, color: Optional[str] = None, **kwargs: Any
          
    ) -> Any:
          
        """Run on agent action."""
          
        print_text(action.log, color=color or self.color)
          

          
    def on_tool_end(
          
        self,
          
        output: str,
          
        color: Optional[str] = None,
          
        observation_prefix: Optional[str] = None,
          
        llm_prefix: Optional[str] = None,
          
        **kwargs: Any,
          
    ) -> None:
          
        """If not the final action, print out observation."""
          
        if observation_prefix is not None:
          
            print_text(f"\n{observation_prefix}")
          
        print_text(output, color=color or self.color)
          
        if llm_prefix is not None:
          
            print_text(f"\n{llm_prefix}")
          

          
    def on_text(
          
        self,
          
        text: str,
          
        color: Optional[str] = None,
          
        end: str = "",
          
        **kwargs: Any,
          
    ) -> None:
          
        """Run when agent ends."""
          
        print_text(text, color=color or self.color, end=end)
          

          
    def on_agent_finish(
          
        self, finish: AgentFinish, color: Optional[str] = None, **kwargs: Any
          
    ) -> None:
          
        """Run on agent end."""
          
        print_text(finish.log, color=color or self.color, end="\n")
      

调用:


          
from langchain.callbacks import StdOutCallbackHandler
          
from langchain.chains import LLMChain
          
from langchain.llms import OpenAI
          
from langchain.prompts import PromptTemplate
          

          
handler = StdOutCallbackHandler()
          
llm = OpenAI()
          
prompt = PromptTemplate.from_template("1 + {number} = ")
          

          
# Constructor callback: First, let's explicitly set the StdOutCallbackHandler when initializing our chain
          
chain = LLMChain(llm=llm, prompt=prompt, callbacks=[handler])
          
chain.run(number=2)
          

          
# Use verbose flag: Then, let's use the `verbose` flag to achieve the same result
          
chain = LLMChain(llm=llm, prompt=prompt, verbose=True)
          
chain.run(number=2)
          

          
# Request callbacks: Finally, let's use the request `callbacks` to achieve the same result
          
chain = LLMChain(llm=llm, prompt=prompt)
          
chain.run(number=2, callbacks=[handler])
      

输出:


          
    > Entering new LLMChain chain...
          
    Prompt after formatting:
          
    1 + 2 =
          

          
    > Finished chain.
          

          

          
    > Entering new LLMChain chain...
          
    Prompt after formatting:
          
    1 + 2 =
          

          
    > Finished chain.
          

          

          
    > Entering new LLMChain chain...
          
    Prompt after formatting:
          
    1 + 2 =
          

          
    > Finished chain.
          

          

          
    '\n\n3'
      

小结

Langchain作为当前最热的LLM 应用编排框架,虽然受到了大模型能力增强对其空间的压缩,但它仍然是LLM应用不可或缺的重要支撑。它不断的在扩展着LLM应用的边界,给很多后来的框架和应用开发者以启发,其生态也最为完善,对于想要入门大模型应用开发的朋友来讲,langchain不管未来会不会实际在生产环境使用,但都是值得学习参考的重要案例。

点此查看合集:

picture.image

0
0
0
0
关于作者
关于作者

文章

0

获赞

0

收藏

0

相关资源
字节跳动 EB 级湖仓一体分析服务 LAS 的实践与展望
火山引擎湖仓一体分析服务 LAS 是面向湖仓一体架构的 Serverless 数据处理分析服务,提供一站式的海量数据存储计算和交互分析能力,完全兼容 Spark、Presto、Flink 生态,在字节跳动内部有着广泛的应用。本次演讲将介绍 LAS 在字节跳动内部的发展历程和大规模应用实践,同时介绍 LAS 在火山引擎上的发展规划。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论