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))