LangChain于8月1日0.254版本更新,声称采用新的语法来创建带和组合功能的Chain,同时提供一个新的接口,支持批处理、异步和流处理,将这种语法成为LangChain Expression Language(LCEL)。体验了新版本LangChain的LCEL特性,确实是个重大有意义的更新,朝工程化应用方向发展了一大步。
LangChain的文档的Cookbook有丰富的例程,不想当简单的文档翻译和搬运工,尽可能从自己角度和理解试图解构LCEL。
from langchain.prompts import ChatPromptTemplate
from langchain.chat_models import ChatOpenAI
chain = prompt | ChatOpenAI() | StrOutputParser()
chain.invoke({"foo": "bears"})
LangChain的Prompt、LLM、OutputParser都是基本单元,通过“|”构成一个Pipeline。这与Linux的Shell Pipeline异曲同工,级联嵌套Shell调用可以串成一长串,将简单的程序连接在一起并修改彼此。
另外一种排版是不是更引入注目:
from langchain.output_parsers.openai_functions import JsonKeyOutputFunctionsParser
chain = (
prompt
| model.bind(function_call= {"name": "joke"}, functions= functions)
| JsonKeyOutputFunctionsParser(key_name="setup")
)
chain.invoke({"foo": "bears"})
# Stream
for s in chain.stream({"topic": "bears"}):
print(s.content, end="", flush=True)
# Invoke
chain.invoke({"topic": "bears"})
# Batch
chain.batch([{"topic": "bears"}, {"topic": "cats"}])
# Async Stream
async for s in chain.astream({"topic": "bears"}):
print(s.content, end="", flush=True)
# Async Invoke
await chain.ainvoke({"topic": "bears"})
# Async Batch
await chain.abatch([{"topic": "bears"}])
template = """Answer the question based only on the following context:
{context}
Question: {question}
"""
prompt = ChatPromptTemplate.from_template(template)
chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| model
| StrOutputParser()
)
chain.invoke("where did harrison work?")
这里可以看到
ChatGPT出现伴随着Prompt,“Prompt Engineer”开始是戏称后面慢慢成为现实;Prompt设计重要性不言而喻。但是LangChain以往版本,Prompt 被嵌套在最内部,隐蔽且难于修改。现在把Prompt放在前面或者中心的位置,更加突出也容易修改替换。
from langchain.schema.runnable import RunnableMap
from langchain.schema import format_document
from langchain.prompts.prompt import PromptTemplate
_template = """Given the following conversation and a follow up question, rephrase the follow up question to be a standalone question, in its original language.
Chat History:
{chat_history}
Follow Up Input: {question}
Standalone question:"""
CONDENSE_QUESTION_PROMPT = PromptTemplate.from_template(_template)
template = """Answer the question based only on the following context:
{context}
Question: {question}
"""
ANSWER_PROMPT = ChatPromptTemplate.from_template(template)
DEFAULT_DOCUMENT_PROMPT = PromptTemplate.from_template(template="{page_content}")
def _combine_documents(docs, document_prompt = DEFAULT_DOCUMENT_PROMPT, document_separator="\n\n"):
doc_strings = [format_document(doc, document_prompt) for doc in docs]
return document_separator.join(doc_strings)
from typing import Tuple, List
def _format_chat_history(chat_history: List[Tuple]) -> str:
buffer = ""
for dialogue_turn in chat_history:
human = "Human: " + dialogue_turn[0]
ai = "Assistant: " + dialogue_turn[1]
buffer += "\n" + "\n".join([human, ai])
return buffer
_inputs = RunnableMap(
{
"standalone_question": {
"question": lambda x: x["question"],
"chat_history": lambda x: _format_chat_history(x['chat_history'])
} | CONDENSE_QUESTION_PROMPT | ChatOpenAI(temperature=0) | StrOutputParser(),
}
)
_context = {
"context": itemgetter("standalone_question") | retriever | _combine_documents,
"question": lambda x: x["standalone_question"]
}
conversational_qa_chain = _inputs | _context | ANSWER_PROMPT | ChatOpenAI()
conversational_qa_chain.invoke({
"question": "where did harrison work?",
"chat_history": [],
})
这是一个复杂的例子例子,Prompt 相对于以前更加显目突出且易于修改;同时也展示组合的方式:级联和嵌套。
刚看到LangChain以“Expression Language”来命名这次版本变更,多少有点“飘了吧?”的感觉。这段时间学习体验以来,感觉多少有点匹配:以前版本缺乏统一设计的功能繁杂且散乱、各自为政、接口不互通,像极赶工的堆砌品;重构后,有了精巧的抽象的层级类设计,有了统一基类Runnable,各种模块可以方便的级联、嵌套起来。
标准化Block(通过基类定义标准Op),标准化部件间接口(输入输出);LangChain采用了Dict(key:Value)作为默认接口,并且重载了管道操作符“|”以及对应的有操作符。对于单独的string输入估计是通过对输入类型检测来支持,增加了灵活性。
TensorFlow定义计算图DAG,然后运行计算图进行推理或者训练;李沐大佬口头禅”神经网络是一门语言“。类比过来,LangChain是通过组合(级联、嵌套)各种功能部件Block构建一个任务的执行管道网络(Pipeline),这个管道网络(Pipeline)是以语言文本(Prompt/Text)驱动的。从这个视角上看,新的LangChain是一门语言。
”Text Is the Universal Interface",正如LangChain的发布Blog引用一样,文本Text是很好一种中介数据类型,Linxu Shell时代的Pipeline管道组合有限简单程序,完成众多近乎无限多样的复杂任务。与之类似,LangChain把Dict、Text/String作为默认基本接口数据类型。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。