diff --git a/README.md b/README.md
index 5d5f0f4..bedbaed 100644
--- a/README.md
+++ b/README.md
@@ -132,6 +132,9 @@
| [**Colab Demo**](https://colab.research.google.com/drive/1yu0eZ3a66by8Zqm883LLtRQrguBAb9MR?usp=sharing) | 在Colab中启动交互界面 | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | [link](https://colab.research.google.com/drive/1yu0eZ3a66by8Zqm883LLtRQrguBAb9MR?usp=sharing) |
| [**仿OpenAI API调用**](https://platform.openai.com/docs/api-reference) | 仿OpenAI API接口的服务器Demo | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | [link](https://github.com/ymcui/Chinese-LLaMA-Alpaca-2/wiki/api_calls_zh) |
| [**text-generation-webui**](https://github.com/oobabooga/text-generation-webui) | 前端Web UI界面的部署方式 | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | [link](https://github.com/ymcui/Chinese-LLaMA-Alpaca-2/wiki/text-generation-webui_zh) |
+| [**LangChain**](https://github.com/hwchase17/langchain) | 适合二次开发的大模型应用开源框架 | ✅† | ✅ | ✅† | ❌ | ❌ | ❌ | [link](https://github.com/ymcui/Chinese-LLaMA-Alpaca-2/wiki/langchain_zh) |
+
+†: LangChain框架支持,但教程中未实现;详细说明请参考LangChain官方文档。
⚠️ 一代模型相关推理与部署支持将陆续迁移到本项目,届时将同步更新相关教程。
diff --git a/README_EN.md b/README_EN.md
index b36cd71..c894335 100644
--- a/README_EN.md
+++ b/README_EN.md
@@ -126,6 +126,9 @@ The models in this project mainly support the following quantization, inference,
| [**Colab Demo**](https://colab.research.google.com/drive/1yu0eZ3a66by8Zqm883LLtRQrguBAb9MR?usp=sharing) | Running a Gradio web demo in Colab | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | [link](https://colab.research.google.com/drive/1yu0eZ3a66by8Zqm883LLtRQrguBAb9MR?usp=sharing) |
| [**OpenAI API Calls**](https://platform.openai.com/docs/api-reference) | A server that implements OpenAI API | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | [link](https://github.com/ymcui/Chinese-LLaMA-Alpaca-2/wiki/api_calls_en) |
| [**text-generation-webui**](https://github.com/oobabooga/text-generation-webui) | A tool for deploying model as a web UI | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | [link](https://github.com/ymcui/Chinese-LLaMA-Alpaca-2/wiki/text-generation-webui_en) |
+| [**LangChain**](https://github.com/hwchase17/langchain) | LLM application development framework, suitable for secondary development | ✅† | ✅ | ✅† | ❌ | ❌ | ❌ | [link](https://github.com/ymcui/Chinese-LLaMA-Alpaca-2/wiki/langchain_en) |
+
+†: Supported by LangChain, but not implemented in the tutorial. Please refer to the official LangChain Documentation for details.
⚠️ Inference and deployment support related to the first-generation model will be gradually migrated to this project, and relevant tutorials will be updated later.
diff --git a/scripts/langchain/doc.txt b/scripts/langchain/doc.txt
new file mode 100644
index 0000000..55420f7
--- /dev/null
+++ b/scripts/langchain/doc.txt
@@ -0,0 +1,20 @@
+李白[注 1](701年5月19日—762年11月30日),字太白,号青莲居士,中国唐朝诗人。李白自言祖籍陇西成纪(今甘肃静宁西南),汉飞将军李广后裔,西凉武昭王李暠之后,与李唐皇室同宗。
+一说其幼时内迁,寄籍剑南道绵州昌隆(今四川省江油市青莲镇)。一说先人隋末被窜于碎叶,出生于碎叶,属唐安西都护府(今吉尔吉斯斯坦共和国楚河州托克马克市)。有“诗仙”、“诗侠”、“酒仙”、“谪仙人”等称呼,活跃于盛唐[1],为杰出的浪漫主义诗人。与杜甫合称“李杜”[注 2]。被贺知章呼为“天上谪仙”、“李谪仙”。
+李白的诗歌在唐朝已被选进殷璠编选的《河岳英灵集》、于敦煌石室发现的《唐写本唐人选唐诗》、韦庄编选的《又玄集》和韦縠编选的《才调集》。唐文宗御封李白的诗歌、裴旻的剑舞、张旭的草书称为“三绝”[2]。其作品想像奇特丰富,风格雄奇浪漫,意境独特,清新俊逸;善于利用夸饰与譬喻等手法、自然优美的词句,表现出奔放的情感。诗句行云流水,浑然天成。李白诗篇传诵千年,众多诗句已成经典,清赵翼称:“李杜诗篇万口传”(例如“抽刀断水水更流,举杯消愁愁更愁”等,更被谱入曲)。李白在诗歌的艺术成就被认为是中国浪漫主义诗歌的巅峰。诗作在全唐诗收录于卷161至卷185。有《李太白集》传世。杜甫曾经这样评价过李白的文章:“笔落惊风雨,诗成泣鬼神”、“白也诗无敌,飘然思不群”。
+生平
+早年
+据《新唐书》记载李白为兴圣皇帝(凉武昭王李暠)九世孙[3],如果按照这个说法李白与李唐诸王实际上同宗,应是唐太宗李世民的同辈族弟。亦有野史说其祖是李建成或李元吉,因为被李世民族灭而逃往西域;但此说缺乏佐证,且李建成、李元吉诸子尚在幼年即在玄武门之变后全数被害,留有亲生后嗣的可能性很小。据《旧唐书》记载,李白之父李客为任城尉。更为了学习而隐居。
+李白于武则天大足元年(701年)[4]出生,关于其出生地有多种说法,现在主要有剑南道绵州昌隆县(今四川省江油市)[5]青莲乡(今青莲镇)和西域的碎叶(Suyab,位于今吉尔吉斯托克马克附近)[6]这两种说法,其中后一种说法认为李白直到四岁时(705年)才跟随他的父亲李客迁居蜀地,入籍绵州。李白自四岁(705年)接受启蒙教育,从景云元年(710年)开始,李白开始读诸子史籍[7],开元三年时十四岁(715年)——喜好作赋、剑术、奇书、神仙:“十五观奇书,做赋凌相如”。在青年时期开始在中国各地游历。开元五年左右,李白曾拜撰写《长短经》的赵蕤为师,学习一年有余,这段时期的学习对李白产生了深远的影响。开元六年,在戴天山(约在四川省昌隆县北五十里处)大明寺读书。二十五岁时只身出四川,开始了广泛漫游,南到洞庭湘江,东至吴、越,寓居在安陆(今湖北省安陆市)、应山(今湖北省广水市)。
+中年
+李白曾经在唐玄宗天宝元年(742年)供奉翰林。有一次皇帝因酒酣问李白说:“我朝与天后(武后)之朝何如?”白曰:“天后朝政出多门,国由奸幸,任人之道,如小儿市瓜,不择香味,惟拣肥大者;我朝任人如淘沙取金,剖石采用,皆得其精粹者。”玄宗听后大笑不止[8][9]。但是由于他桀骜不驯的性格,所以仅仅不到两年他就离开了长安。据说是因为他作的《清平调》得罪了当时宠冠后宫的杨贵妃(因李白命“力士脱靴”,高力士引以为大耻,因而以言语诱使杨贵妃认为“可怜飞燕倚新妆”几句是讽刺她)而不容于宫中[注 3]。天宝三年(745年)“恳求还山,帝赐金放还”,离开长安。
+后在洛阳与另两位著名诗人杜甫、高适相识,并结为好友。
+晚年
+天宝十一年(752年)李白年届五十二岁,北上途中游广平郡邯郸、临洺、清漳等地。十月,抵幽州。初有立功边疆思想,在边地习骑射。后发现安禄山野心,登黄金台痛哭。不久即离幽州南下。
+安史之乱爆发时,李白游华山,南下回宣城,后上庐山。756年12月,李白被三次邀请,下山赴寻阳入永王李璘幕僚[10]。永王触怒唐肃宗被杀后,李白也获罪入狱。幸得郭子仪力保,方得免死,改为流徙夜郎(今贵州关岭县一带),在途经巫山时遇赦,此时他已经59岁。(参见李璘之乱)
+李白晚年在江南一带漂泊。在他61岁时,听到太尉李光弼率领大军讨伐安史叛军,于是他北上准备追随李光弼从军杀敌,但是中途因病折回。第二年,李白投奔他的族叔、当时在当涂(今属安徽省马鞍山)当县令的李阳冰。同年11月,李白病逝于寓所,终年61岁,葬当涂龙山。唐宪宗元和十二年(817年),宣歙观察使范传正根据李白生前“志在青山”的遗愿,将其墓迁至当涂青山。
+去世
+《新唐书》记载,唐代宗继位后以左拾遗召李白,但李白当时已去世。
+李阳冰在《草堂集序》中说李白是病死的[11];皮日休在诗作中记载,李白是患“腐胁疾”而死的[12]。
+《旧唐书》则记载,李白流放虽然遇赦,但因途中饮酒过度,醉死于宣城。中国民间有“太白捞月”的传说:李白在舟中赏月,饮酒大醉,想要跳下船至水里捞月而溺死[13][14][15];在民间的求签活动中亦有“太白捞月”一签文,乃是下下签[16]。
+作品
+李白一生创作大量的诗歌,绝大多数已散佚[17],流传至今的只有九百多首。他的诗歌创作涉及的中国古典诗歌的题材非常广泛,而且在许多题材都有名作出现,而且因为际遇的不同,每个时期的诗风都有所不同。
\ No newline at end of file
diff --git a/scripts/langchain/langchain_qa.py b/scripts/langchain/langchain_qa.py
new file mode 100644
index 0000000..7705ea0
--- /dev/null
+++ b/scripts/langchain/langchain_qa.py
@@ -0,0 +1,114 @@
+import argparse
+import os
+parser = argparse.ArgumentParser()
+parser.add_argument('--file_path', required=True, type=str)
+parser.add_argument('--embedding_path', required=True, type=str)
+parser.add_argument('--model_path', required=True, type=str)
+parser.add_argument('--gpu_id', default="0", type=str)
+parser.add_argument('--chain_type', default="refine", type=str)
+args = parser.parse_args()
+os.environ["CUDA_VISIBLE_DEVICES"] = args.gpu_id
+file_path = args.file_path
+embedding_path = args.embedding_path
+model_path = args.model_path
+
+import torch
+from langchain import HuggingFacePipeline
+from langchain.text_splitter import RecursiveCharacterTextSplitter
+from langchain.vectorstores import FAISS
+from langchain.document_loaders import TextLoader
+from langchain.prompts import PromptTemplate
+from langchain.chains import RetrievalQA
+from langchain.embeddings.huggingface import HuggingFaceEmbeddings
+
+prompt_template = (
+ "[INST] <>\n"
+ "You are a helpful assistant. 你是一个乐于助人的助手。\n"
+ "<>\n\n"
+ "{context}\n{question} [/INST]"
+)
+
+refine_prompt_template = (
+ "[INST] <>\n"
+ "You are a helpful assistant. 你是一个乐于助人的助手。\n"
+ "<>\n\n"
+ "这是原始问题: {question}\n"
+ "已有的回答: {existing_answer}\n"
+ "现在还有一些文字,(如果有需要)你可以根据它们完善现有的回答。"
+ "\n\n"
+ "{context_str}\n"
+ "\\nn"
+ "请根据新的文段,进一步完善你的回答。"
+ " [/INST]"
+)
+
+initial_qa_template = (
+ "[INST] <>\n"
+ "You are a helpful assistant. 你是一个乐于助人的助手。\n"
+ "<>\n\n"
+ "以下为背景知识:\n"
+ "{context_str}"
+ "\n"
+ "请根据以上背景知识, 回答这个问题:{question}。"
+ " [/INST]"
+)
+
+
+if __name__ == '__main__':
+ load_type = torch.float16
+ if not torch.cuda.is_available():
+ raise RuntimeError("No CUDA GPUs are available.")
+
+ loader = TextLoader(file_path)
+ documents = loader.load()
+ text_splitter = RecursiveCharacterTextSplitter(
+ chunk_size=600, chunk_overlap=100)
+ texts = text_splitter.split_documents(documents)
+
+ print("Loading the embedding model...")
+ embeddings = HuggingFaceEmbeddings(model_name=embedding_path)
+ docsearch = FAISS.from_documents(texts, embeddings)
+
+ print("loading LLM...")
+ model = HuggingFacePipeline.from_model_id(model_id=model_path,
+ task="text-generation",
+ device=0,
+ model_kwargs={
+ "torch_dtype" : load_type,
+ "low_cpu_mem_usage" : True,
+ "temperature": 0.2,
+ "max_length": 1000,
+ "repetition_penalty":1.1}
+ )
+
+ if args.chain_type == "stuff":
+ PROMPT = PromptTemplate(
+ template=prompt_template, input_variables=["context", "question"]
+ )
+ chain_type_kwargs = {"prompt": PROMPT}
+ qa = RetrievalQA.from_chain_type(
+ llm=model,
+ chain_type="stuff",
+ retriever=docsearch.as_retriever(search_kwargs={"k": 1}),
+ chain_type_kwargs=chain_type_kwargs)
+
+ elif args.chain_type == "refine":
+ refine_prompt = PromptTemplate(
+ input_variables=["question", "existing_answer", "context_str"],
+ template=refine_prompt_template,
+ )
+ initial_qa_prompt = PromptTemplate(
+ input_variables=["context_str", "question"],
+ template=initial_qa_template,
+ )
+ chain_type_kwargs = {"question_prompt": initial_qa_prompt, "refine_prompt": refine_prompt}
+ qa = RetrievalQA.from_chain_type(
+ llm=model, chain_type="refine",
+ retriever=docsearch.as_retriever(search_kwargs={"k": 1}),
+ chain_type_kwargs=chain_type_kwargs)
+
+ while True:
+ query = input("请输入问题:")
+ if len(query.strip())==0:
+ break
+ print(qa.run(query))
diff --git a/scripts/langchain/langchain_sum.py b/scripts/langchain/langchain_sum.py
new file mode 100644
index 0000000..0816041
--- /dev/null
+++ b/scripts/langchain/langchain_sum.py
@@ -0,0 +1,70 @@
+import argparse
+import os
+parser = argparse.ArgumentParser()
+parser.add_argument('--file_path', required=True, type=str)
+parser.add_argument('--model_path', required=True, type=str)
+parser.add_argument('--gpu_id', default="0", type=str)
+parser.add_argument('--chain_type', default="refine", type=str)
+args = parser.parse_args()
+os.environ["CUDA_VISIBLE_DEVICES"] = args.gpu_id
+file_path = args.file_path
+model_path = args.model_path
+
+import torch
+from langchain import HuggingFacePipeline
+from langchain.text_splitter import RecursiveCharacterTextSplitter
+from langchain.prompts import PromptTemplate
+from langchain.chains.summarize import load_summarize_chain
+
+prompt_template = (
+ "[INST] <>\n"
+ "You are a helpful assistant. 你是一个乐于助人的助手。\n"
+ "<>\n\n"
+ "请为以下文字写一段摘要:\n{text} [/INST]"
+)
+refine_template = (
+ "[INST] <>\n"
+ "You are a helpful assistant. 你是一个乐于助人的助手。\n"
+ "<>\n\n"
+ "已有一段摘要:{existing_answer}\n"
+ "现在还有一些文字,(如果有需要)你可以根据它们完善现有的摘要。"
+ "\n"
+ "{text}\n"
+ "\n"
+ "如果这段文字没有用,返回原来的摘要即可。请你生成一个最终的摘要。"
+ " [/INST]"
+)
+
+
+if __name__ == '__main__':
+ load_type = torch.float16
+ if not torch.cuda.is_available():
+ raise RuntimeError("No CUDA GPUs are available.")
+
+ text_splitter = RecursiveCharacterTextSplitter(chunk_size=600, chunk_overlap=100, length_function=len)
+ with open(file_path) as f:
+ text = f.read()
+ docs = text_splitter.create_documents([text])
+
+ print("loading LLM...")
+ model = HuggingFacePipeline.from_model_id(model_id=model_path,
+ task="text-generation",
+ device=0,
+ model_kwargs={
+ "torch_dtype" : load_type,
+ "low_cpu_mem_usage" : True,
+ "temperature": 0.2,
+ "max_length": 1000,
+ "repetition_penalty":1.1}
+ )
+
+ PROMPT = PromptTemplate(template=prompt_template, input_variables=["text"])
+ REFINE_PROMPT = PromptTemplate(
+ template=refine_template,input_variables=["existing_answer", "text"],
+ )
+
+ if args.chain_type == "stuff":
+ chain = load_summarize_chain(model, chain_type="stuff", prompt=PROMPT)
+ elif args.chain_type == "refine":
+ chain = load_summarize_chain(model, chain_type="refine", question_prompt=PROMPT, refine_prompt=REFINE_PROMPT)
+ print(chain.run(docs))