2024工作周期安排
2024项目整体规划
沐曦测试(已完成)
沐曦性能测试研究
沐曦Benchmark相关测试
沐曦模型适配表
2024-02-26沐曦沟通报告
智能打标
数据打标服务Json样例
智能打标寒武纪大模型思路
业务层优先级排序
智能打标流程图
打标API接口文档
图像内容识别
其他
申报项目文本段落
研发链相关资料文档
国产GPU虚拟化培训介绍
RAG垂直落地
DB-GPT与TeleChat-7B搭建相关RAG知识库
ChatWithRTX
ChatRTX安装教程
ChatWithRTX 踩坑记录
ChatWithRTX 使用其他量化模型
ChatWithRTX介绍
RAG 相关资料
英伟达—大模型结合 RAG 构建客服场景自动问答
又一大模型技术开源!有道自研RAG引擎QAnything正式开放下载
收藏!RAG入门参考资料开源大总结:RAG综述、介绍、比较、预处理、RAG Embedding等
RAG调研
解决现代RAG实际生产问题
解决现代 RAG 系统中的生产问题-II
先进的Retriever技术来增强你的RAGs
高级RAG — 使用假设文档嵌入 (HyDE) 改进检索
提升 RAG:选择最佳嵌入和 Reranker 模型
LangGraph
增强型RAG:re-rank
大模型比赛
相关资料
智能填单_填单 启动命令
2024私人规划
ChatGPT API账号记录
公众号相关资料
基于 Docker 的深度学习环境:入门篇
ollama
-
+
首页
LangGraph
![img](https://yg9538.kmgy.top/202405051406845.png) 来源:作者使用 MidJourney 创建的图像 ## **介绍** LangChain的LangGraph Agents为制定智能工作流程提供了一个强大的平台,集成Retriever-Augmented Generator(RAG)模型将电子邮件通信的效率提升到一个新的水平。本文探讨了 RAG 如何专门用于回复客户电子邮件的 LangChain 代理。 **座席目标在行动:** 1. **检索电子邮件:**LangChain代理通过获取传入的客户电子邮件来启动。 2. **电子邮件分类:**利用预先训练的模型或基于规则的系统,代理将电子邮件分为“销售查询”、“自定义查询”、“偏离主题”或“客户投诉”等类别。这种分类是制定相关对策的基础。 3. **RAG搜索的问题表述:**根据电子邮件类别和初始内容,代理为 RAG 模型生成特定问题。以下是每个类别的展开方式: **i) 销售咨询:** - 问题可能针对产品详细信息、定价信息或在知识库中发现的类似过去查询中提出的常见销售异议。 - 示例问题:“客户最常询问的产品 X 的功能是什么?”或“产品 Y 最有效的推销是什么?” **ii) 海关查询:** - 在这里,问题更深入地了解客户的具体需求。 - 示例包括:“对于与客户描述的问题类似的挑战,提供了哪些常见的解决方案?”或“是否有任何案例研究展示了此类场景的成功实施? **iii) 题外话:** - 座席可能会提出问题,礼貌地将客户重定向到适当的渠道或资源。 - 示例:“客户询问的最常见的支持主题是什么? **iv) 客户投诉:** - 问题旨在确定潜在的解决方案或故障排除步骤。 - 例如:“对于此类投诉,最常见的解决方案是什么?”或“是否有任何知识库文章可以解决与客户类似的问题? **4. 回复草稿生成:** - LangChain 代理中的 LLM 利用从 RAG 中检索到的信息(产品详细信息、解决方案、故障排除步骤等)来创建初始草稿响应。 - 此草案考虑了电子邮件类别、客户的特定查询以及检索到的知识库信息。 **5. RAG验证和回复细化:** - 将答复草稿与原始 RAG 答复进行比较,以确保准确纳入检索到的信息。 - 如果出现不一致,代理会优化草稿以与检索到的知识保持一致。 **6. 最终回复输出:** - LangChain代理向客户提供最终的、精炼的电子邮件回复。这种回答是针对他们的具体询问量身定制的,利用知识库中的相关知识,并保持专业和信息丰富的语气。 ![img](https://yg9538.kmgy.top/202405051406846.png) 资料来源:[Sam-Witteveen-course](https://www.youtube.com/watch?v=WyIWaopiUEo) ## **什么是RAG?** RAG 是一种基于神经检索的抽象摘要方法。它由两个组件组成:猎犬和发电机。检索器从知识库中检索相关段落以响应查询。然后,生成器使用检索到的段落来生成一个既有信息又有抽象性的摘要,这意味着它不仅仅是简单地从源文本中复制句子。 ## **将RAG与LangChain的LangGraph代理集成的好处** 将RAG与LangChain的LangGraph Agents集成,为电子邮件起草提供了几个优势: - **改进了上下文理解:**RAG 可以利用外部知识库来了解初始电子邮件的上下文。这允许LangChain代理生成更相关和信息量更大的草稿响应。 - **增强的问答:**RAG检索相关信息的能力可用于识别电子邮件草稿中需要解决的关键问题。这可以简化电子邮件写作过程,并确保涵盖所有要点。 - **更自然的语言生成:**通过整合从知识库中检索到的信息,RAG 可以帮助 LLM 生成更自然、更连贯的电子邮件草稿。 ![img](https://yg9538.kmgy.top/202405051406847.png) 资料来源: [LangGraph-Llama3](https://twitter.com/LangChainAI/status/1781349425337729176/photo/1) ## **代码实现** 以下是将 RAG 添加到 LangChain 的 LangGraph Agents 以进行电子邮件起草的代码实现的高级概述: 1. **定义 LangGraph 代理:**第一步涉及定义负责电子邮件起草的 LangGraph 代理。此代理将收到初始电子邮件作为输入。 2. **RAG 集成:**在 LangGraph 代理中,集成 RAG 模型。RAG 模型将初始电子邮件作为查询,并从知识库中检索相关段落。 3. **问答:**使用检索到的段落来确定电子邮件草稿中需要解决的关键问题。这可以通过信息提取或问题生成等技术来实现。 4. **电子邮件生成草稿:**利用 LLM 生成草稿电子邮件内容。LLM应该考虑最初的电子邮件,从RAG中检索到的段落,以及确定的关键问题。 5. **精炼和输出:**生成的电子邮件草稿可以进行进一步的优化步骤,例如语法检查和情感分析。最后,LangGraph 代理输出最终的电子邮件草稿。 **步骤一:安装库并下载数据** ``` # Download Data !wget -q -O westworld_resort_facts.csv https://www.dropbox.com/scl/fi/qhzosgi21sqsymv5j4o1b/westworld_resort_facts.csv?rlkey=d81cez1bxck2y3lw53phar8nk&st=70bbkq9n&dl=1 # Install Libraries !pip -q install langchain-groq !pip -q install -U langchain_community tiktoken langchainhub !pip -q install -U langchain langgraph # for RAG Only !pip -q install -U langchain langchain-community langchainhub !pip -q install langchain-chroma bs4 !pip -q install huggingface_hub unstructured sentence_transformers ``` **第二步:初始 HF 和 Groq API** ``` import os from pprint import pprint from google.colab import userdata os.environ["GROQ_API_KEY"] = userdata.get('GROQ_API_KEY') os.environ["HF_TOKEN"] = userdata.get('HF_TOKEN') ``` **第三步:构建 RAG** ``` # Load Sheet base from langchain_community.document_loaders.csv_loader import CSVLoader from langchain_community.document_loaders.merge import MergedDataLoader from langchain.embeddings import HuggingFaceBgeEmbeddings from langchain_groq import ChatGroq from langchain_core.prompts import ChatPromptTemplate from langchain.prompts import PromptTemplate from langchain_core.runnables import RunnablePassthrough from langchain_core.output_parsers import StrOutputParser from langchain_core.output_parsers import JsonOutputParser from langchain_chroma import Chroma loader_csv = CSVLoader(file_path="/content/westworld_resort_facts.csv") # Merge All Loader loader_all = MergedDataLoader(loaders=[loader_csv]) docs_all = loader_all.load() len(docs_all) # Output 148 # Text splitting if you have long documents from langchain.text_splitter import RecursiveCharacterTextSplitter #splitting the text into text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200) texts = text_splitter.split_documents(docs_all) # Embeddings model_name = "BAAI/bge-base-en" encode_kwargs = {'normalize_embeddings': True} # set True to compute cosine similarity bge_embeddings = HuggingFaceBgeEmbeddings( model_name=model_name, model_kwargs={'device': 'cuda'}, encode_kwargs=encode_kwargs ) #Vector Store persist_directory = 'db' ## Here you can change the embeddings etc embedding = bge_embeddings vectordb = Chroma.from_documents(documents=texts, embedding=embedding, persist_directory=persist_directory) # Retreiever retriever = vectordb.as_retriever(search_kwargs={"k": 5}) #RAG Chain GROQ_LLM = ChatGroq( model="llama3-70b-8192", ) rag_prompt = PromptTemplate( template="""<|begin_of_text|><|start_header_id|>system<|end_header_id|> You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don't know the answer, just say that you don't know. Use three sentences maximum and keep the answer concise.\n <|eot_id|><|start_header_id|>user<|end_header_id|> QUESTION: {question} \n CONTEXT: {context} \n Answer: <|eot_id|> <|start_header_id|>assistant<|end_header_id|> """, input_variables=["question","context"], ) rag_prompt_chain = rag_prompt | GROQ_LLM | StrOutputParser() QUESTION = """What can I do in the Westworld Park?""" CONTEXT = retriever.invoke(QUESTION) rag_chain = ( {"context": retriever , "question": RunnablePassthrough()} | rag_prompt | GROQ_LLM | StrOutputParser() ) rag_chain.invoke("What is the westworld park all about?") # Output Westworld is an immersive, high-tech theme park that allows guests to experience the Wild West in a realistic and interactive way, populated by advanced androids called "hosts." The park offers a level of raw, unscripted excitement that cannot be replicated by traditional amusement park rides. It immerses guests in a living, breathing world where they become active participants in their own stories. ``` **第四步:基本链** 1. 对电子邮件进行分类 2. 研究路由器 3. RAG 问题 4. 撰写草稿电子邮件 5. 重写路由器 6. 电子邮件草稿分析 7. 重写电子邮件 8. RAG Chain — 在上面的 RAG 部分创建 ``` #Categorize EMAIL prompt = PromptTemplate( template="""<|begin_of_text|><|start_header_id|>system<|end_header_id|> You are the Email Categorizer Agent for the theme park Westworld,You are a master at \ understanding what a customer wants when they write an email and are able to categorize \ it in a useful way. Remember people maybe asking about experiences they can have in westworld. \ <|eot_id|><|start_header_id|>user<|end_header_id|> Conduct a comprehensive analysis of the email provided and categorize into one of the following categories: price_equiry - used when someone is asking for information about pricing \ customer_complaint - used when someone is complaining about something \ product_enquiry - used when someone is asking for information about a product feature, benefit or service but not about pricing \\ customer_feedback - used when someone is giving feedback about a product \ off_topic when it doesnt relate to any other category \ Output a single cetgory only from the types ('price_equiry', 'customer_complaint', 'product_enquiry', 'customer_feedback', 'off_topic') \ eg: 'price_enquiry' \ EMAIL CONTENT:\n\n {initial_email} \n\n <|eot_id|> <|start_header_id|>assistant<|end_header_id|> """, input_variables=["initial_email"], ) email_category_generator = prompt | GROQ_LLM | StrOutputParser() EMAIL = """HI there, \n I am emailing to find out info about your them park and what I can do there. \n I am looking for new experiences. Thanks, Paul """ result = email_category_generator.invoke({"initial_email": EMAIL}) print(result) #Output 'product_enquiry' ## Research Router research_router_prompt = PromptTemplate( template="""<|begin_of_text|><|start_header_id|>system<|end_header_id|> You are an expert at reading the initial email and routing to our internal knowledge system\ or directly to a draft email. \n Use the following criteria to decide how to route the email: \n\n If the initial email only requires a simple response Just choose 'draft_email' for questions you can easily answer, prompt engineering, and adversarial attacks. If the email is just saying thank you etc then choose 'draft_email' If you are unsure or the person is asking a question you don't understand then choose 'research_info' You do not need to be stringent with the keywords in the question related to these topics. Otherwise, use research-info. Give a binary choice 'research_info' or 'draft_email' based on the question. Return the a JSON with a single key 'router_decision' and no premable or explaination. use both the initial email and the email category to make your decision <|eot_id|><|start_header_id|>user<|end_header_id|> Email to route INITIAL_EMAIL : {initial_email} \n EMAIL_CATEGORY: {email_category} \n <|eot_id|><|start_header_id|>assistant<|end_header_id|>""", input_variables=["initial_email","email_category"], ) research_router = research_router_prompt | GROQ_LLM | JsonOutputParser() email_category = 'product_enquiry' print(research_router.invoke({"initial_email": EMAIL, "email_category":email_category})) # Output {'router_decision': 'research_info'} ## RAG QUESTIONS search_rag_prompt = PromptTemplate( template="""<|begin_of_text|><|start_header_id|>system<|end_header_id|> You are a master at working out the best questions to ask our knowledge agent to get the best info for the customer. given the INITIAL_EMAIL and EMAIL_CATEGORY. Work out the best questions that will find the best \ info for helping to write the final email. Remember when people ask about a generic park they are \ probably reffering to the park WestWorld. Write the questions to our knowledge system not to the customer. Return a JSON with a single key 'questions' with no more than 3 strings of and no premable or explaination. <|eot_id|><|start_header_id|>user<|end_header_id|> INITIAL_EMAIL: {initial_email} \n EMAIL_CATEGORY: {email_category} \n <|eot_id|><|start_header_id|>assistant<|end_header_id|>""", input_variables=["initial_email","email_category"], ) question_rag_chain = search_rag_prompt | GROQ_LLM | JsonOutputParser() email_category = 'product_enquiry' research_info = None print(question_rag_chain.invoke({"initial_email": EMAIL, "email_category":email_category})) #Output {'questions': ['What are the main attractions and experiences offered at WestWorld theme park?', 'What are some new or unique experiences that WestWorld theme park has to offer?', 'What are the most popular activities or rides at WestWorld theme park?']} ## Write Draft Email draft_writer_prompt = PromptTemplate( template="""<|begin_of_text|><|start_header_id|>system<|end_header_id|> You are the Email Writer Agent for the theme park Westworld, take the INITIAL_EMAIL below \ from a human that has emailed our company email address, the email_category \ that the categorizer agent gave it and the research from the research agent and \ write a helpful email in a thoughtful and friendly way. Remember people maybe asking \ about experiences they can have in westworld. If the customer email is 'off_topic' then ask them questions to get more information. If the customer email is 'customer_complaint' then try to assure we value them and that we are addressing their issues. If the customer email is 'customer_feedback' then try to assure we value them and that we are addressing their issues. If the customer email is 'product_enquiry' then try to give them the info the researcher provided in a succinct and friendly way. If the customer email is 'price_equiry' then try to give the pricing info they requested. You never make up information that hasn't been provided by the research_info or in the initial_email. Always sign off the emails in appropriate manner and from Sarah the Resident Manager. Return the email a JSON with a single key 'email_draft' and no premable or explaination. <|eot_id|><|start_header_id|>user<|end_header_id|> INITIAL_EMAIL: {initial_email} \n EMAIL_CATEGORY: {email_category} \n RESEARCH_INFO: {research_info} \n <|eot_id|><|start_header_id|>assistant<|end_header_id|>""", input_variables=["initial_email","email_category","research_info"], ) draft_writer_chain = draft_writer_prompt | GROQ_LLM | JsonOutputParser() email_category = 'customer_feedback' research_info = None print(draft_writer_chain.invoke({"initial_email": EMAIL, "email_category":email_category,"research_info":research_info})) ## Rewrite Router rewrite_router_prompt = PromptTemplate( template="""<|begin_of_text|><|start_header_id|>system<|end_header_id|> You are an expert at evaluating the emails that are draft emails for the customer and deciding if they need to be rewritten to be better. \n Use the following criteria to decide if the DRAFT_EMAIL needs to be rewritten: \n\n If the INITIAL_EMAIL only requires a simple response which the DRAFT_EMAIL contains then it doesn't need to be rewritten. If the DRAFT_EMAIL addresses all the concerns of the INITIAL_EMAIL then it doesn't need to be rewritten. If the DRAFT_EMAIL is missing information that the INITIAL_EMAIL requires then it needs to be rewritten. Give a binary choice 'rewrite' (for needs to be rewritten) or 'no_rewrite' (for doesn't need to be rewritten) based on the DRAFT_EMAIL and the criteria. Return the a JSON with a single key 'router_decision' and no premable or explaination. \ <|eot_id|><|start_header_id|>user<|end_header_id|> INITIAL_EMAIL: {initial_email} \n EMAIL_CATEGORY: {email_category} \n DRAFT_EMAIL: {draft_email} \n <|eot_id|><|start_header_id|>assistant<|end_header_id|>""", input_variables=["initial_email","email_category","draft_email"], ) rewrite_router = rewrite_router_prompt | GROQ_LLM | JsonOutputParser() email_category = 'customer_feedback' draft_email = "Yo we can't help you, best regards Sarah" print(rewrite_router.invoke({"initial_email": EMAIL, "email_category":email_category, "draft_email":draft_email})) ## Draft Email Analysis draft_analysis_prompt = PromptTemplate( template="""<|begin_of_text|><|start_header_id|>system<|end_header_id|> You are the Quality Control Agent read the INITIAL_EMAIL below from a human that has emailed \ our company email address, the email_category that the categorizer agent gave it and the \ research from the research agent and write an analysis of how the email. Check if the DRAFT_EMAIL addresses the customer's issued based on the email category and the \ content of the initial email.\n Give feedback of how the email can be improved and what specific things can be added or change\ to make the email more effective at addressing the customer's issues. You never make up or add information that hasn't been provided by the research_info or in the initial_email. Return the analysis a JSON with a single key 'draft_analysis' and no premable or explaination. <|eot_id|><|start_header_id|>user<|end_header_id|> INITIAL_EMAIL: {initial_email} \n\n EMAIL_CATEGORY: {email_category} \n\n RESEARCH_INFO: {research_info} \n\n DRAFT_EMAIL: {draft_email} \n\n <|eot_id|><|start_header_id|>assistant<|end_header_id|>""", input_variables=["initial_email","email_category","research_info"], ) draft_analysis_chain = draft_analysis_prompt | GROQ_LLM | JsonOutputParser() email_category = 'customer_feedback' research_info = None draft_email = "Yo we can't help you, best regards Sarah" email_analysis = draft_analysis_chain.invoke({"initial_email": EMAIL, "email_category":email_category, "research_info":research_info, "draft_email": draft_email}) pprint(email_analysis) # Rewrite Email with Analysis rewrite_email_prompt = PromptTemplate( template="""<|begin_of_text|><|start_header_id|>system<|end_header_id|> You are the Final Email Agent read the email analysis below from the QC Agent \ and use it to rewrite and improve the draft_email to create a final email. You never make up or add information that hasn't been provided by the research_info or in the initial_email. Return the final email as JSON with a single key 'final_email' which is a string and no premable or explaination. <|eot_id|><|start_header_id|>user<|end_header_id|> EMAIL_CATEGORY: {email_category} \n\n RESEARCH_INFO: {research_info} \n\n DRAFT_EMAIL: {draft_email} \n\n DRAFT_EMAIL_FEEDBACK: {email_analysis} \n\n <|eot_id|><|start_header_id|>assistant<|end_header_id|>""", input_variables=["initial_email", "email_category", "research_info", "email_analysis", "draft_email", ], ) rewrite_chain = rewrite_email_prompt | GROQ_LLM | JsonOutputParser() email_category = 'customer_feedback' research_info = None draft_email = "Yo we can't help you, best regards Sarah" final_email = rewrite_chain.invoke({"initial_email": EMAIL, "email_category":email_category, "research_info":research_info, "draft_email": draft_email, "email_analysis":email_analysis}) final_email['final_email'] ``` **步骤 V:LangGraph 状态** ``` from langchain.schema import Document from langgraph.graph import END, StateGraph from typing_extensions import TypedDict from typing import List ### State class GraphState(TypedDict): """ Represents the state of our graph. Attributes: initial_email: email email_category: email category draft_email: LLM generation final_email: LLM generation research_info: list of documents info_needed: whether to add search info num_steps: number of steps """ initial_email : str email_category : str draft_email : str final_email : str research_info : List[str] # this will now be the RAG results info_needed : bool num_steps : int draft_email_feedback : dict rag_questions : List[str] ``` **第六步:节点** 1. categorize_email 2. research_info_search # 现在使用 RAG 完成 3. draft_email_writer 4. analyze_draft_email 5. rewrite_email 6. no_rewrite 7. state_printer ``` def categorize_email(state): """take the initial email and categorize it""" print("---CATEGORIZING INITIAL EMAIL---") initial_email = state['initial_email'] num_steps = int(state['num_steps']) num_steps += 1 email_category = email_category_generator.invoke({"initial_email": initial_email}) print(email_category) # save to local disk write_markdown_file(email_category, "email_category") return {"email_category": email_category, "num_steps":num_steps} def research_info_search(state): print("---RESEARCH INFO RAG---") initial_email = state["initial_email"] email_category = state["email_category"] num_steps = state['num_steps'] num_steps += 1 # Web search questions = question_rag_chain.invoke({"initial_email": initial_email, "email_category": email_category }) questions = questions['questions'] # print(questions) rag_results = [] for question in questions: print(question) temp_docs = rag_chain.invoke(question) print(temp_docs) question_results = question + '\n\n' + temp_docs + "\n\n\n" if rag_results is not None: rag_results.append(question_results) else: rag_results = [question_results] print(rag_results) print(type(rag_results)) write_markdown_file(rag_results, "research_info") write_markdown_file(questions, "rag_questions") return {"research_info": rag_results,"rag_questions":questions, "num_steps":num_steps} def draft_email_writer(state): print("---DRAFT EMAIL WRITER---") ## Get the state initial_email = state["initial_email"] email_category = state["email_category"] research_info = state["research_info"] num_steps = state['num_steps'] num_steps += 1 # Generate draft email draft_email = draft_writer_chain.invoke({"initial_email": initial_email, "email_category": email_category, "research_info":research_info}) print(draft_email) # print(type(draft_email)) email_draft = draft_email['email_draft'] write_markdown_file(email_draft, "draft_email") return {"draft_email": email_draft, "num_steps":num_steps} def analyze_draft_email(state): print("---DRAFT EMAIL ANALYZER---") ## Get the state initial_email = state["initial_email"] email_category = state["email_category"] draft_email = state["draft_email"] research_info = state["research_info"] num_steps = state['num_steps'] num_steps += 1 # Generate draft email draft_email_feedback = draft_analysis_chain.invoke({"initial_email": initial_email, "email_category": email_category, "research_info":research_info, "draft_email":draft_email} ) # print(draft_email) # print(type(draft_email)) write_markdown_file(str(draft_email_feedback), "draft_email_feedback") return {"draft_email_feedback": draft_email_feedback, "num_steps":num_steps} def rewrite_email(state): print("---ReWRITE EMAIL ---") ## Get the state initial_email = state["initial_email"] email_category = state["email_category"] draft_email = state["draft_email"] research_info = state["research_info"] draft_email_feedback = state["draft_email_feedback"] num_steps = state['num_steps'] num_steps += 1 # Generate draft email final_email = rewrite_chain.invoke({"initial_email": initial_email, "email_category": email_category, "research_info":research_info, "draft_email":draft_email, "email_analysis": draft_email_feedback} ) write_markdown_file(str(final_email), "final_email") return {"final_email": final_email['final_email'], "num_steps":num_steps} def no_rewrite(state): print("---NO REWRITE EMAIL ---") ## Get the state draft_email = state["draft_email"] num_steps = state['num_steps'] num_steps += 1 write_markdown_file(str(draft_email), "final_email") return {"final_email": draft_email, "num_steps":num_steps} def state_printer(state): """print the state""" print("---STATE PRINTER---") print(f"Initial Email: {state['initial_email']} \n" ) print(f"Email Category: {state['email_category']} \n") print(f"Draft Email: {state['draft_email']} \n" ) print(f"Final Email: {state['final_email']} \n" ) print(f"Research Info: {state['research_info']} \n") print(f"RAG Questions: {state['rag_questions']} \n") print(f"Num Steps: {state['num_steps']} \n") return ``` **步骤 VII:条件边** ``` def route_to_research(state): """ Route email to web search or not. Args: state (dict): The current graph state Returns: str: Next node to call """ print("---ROUTE TO RESEARCH---") initial_email = state["initial_email"] email_category = state["email_category"] router = research_router.invoke({"initial_email": initial_email,"email_category":email_category }) print(router) # print(type(router)) print(router['router_decision']) if router['router_decision'] == 'research_info': print("---ROUTE EMAIL TO RESEARCH INFO---") return "research_info" elif router['router_decision'] == 'draft_email': print("---ROUTE EMAIL TO DRAFT EMAIL---") return "draft_email" def route_to_rewrite(state): print("---ROUTE TO REWRITE---") initial_email = state["initial_email"] email_category = state["email_category"] draft_email = state["draft_email"] # research_info = state["research_info"] # draft_email = "Yo we can't help you, best regards Sarah" router = rewrite_router.invoke({"initial_email": initial_email, "email_category":email_category, "draft_email":draft_email} ) print(router) print(router['router_decision']) if router['router_decision'] == 'rewrite': print("---ROUTE TO ANALYSIS - REWRITE---") return "rewrite" elif router['router_decision'] == 'no_rewrite': print("---ROUTE EMAIL TO FINAL EMAIL---") return "no_rewrite" ``` **步骤 VIII:构建图形** ``` # Add nodes workflow = StateGraph(GraphState) # Define the nodes workflow.add_node("categorize_email", categorize_email) # categorize email workflow.add_node("research_info_search", research_info_search) # web search workflow.add_node("state_printer", state_printer) workflow.add_node("draft_email_writer", draft_email_writer) workflow.add_node("analyze_draft_email", analyze_draft_email) workflow.add_node("rewrite_email", rewrite_email) workflow.add_node("no_rewrite", no_rewrite) # Add Edges workflow.set_entry_point("categorize_email") # workflow.add_conditional_edges( # "categorize_email", # route_to_research, # { # "research_info": "research_info_search", # "draft_email": "draft_email_writer", # }, # ) workflow.add_edge("categorize_email", "research_info_search") workflow.add_edge("research_info_search", "draft_email_writer") workflow.add_conditional_edges( "draft_email_writer", route_to_rewrite, { "rewrite": "analyze_draft_email", "no_rewrite": "no_rewrite", }, ) workflow.add_edge("analyze_draft_email", "rewrite_email") workflow.add_edge("no_rewrite", "state_printer") workflow.add_edge("rewrite_email", "state_printer") workflow.add_edge("state_printer", END) # Compile app = workflow.compile() # EMAIL = """HI there, \n # I am emailing to find out the current price of Bitcoin. \n # Can you please help me/ # Thanks, # John # """ EMAIL = """HI there, \n I am emailing to find out info about your them park and what I can do there. \n I am looking for new experiences. Thanks, Paul """ EMAIL = """HI there, \n I am a big fan of westworld. can I meet Maeve in the park? Really want to chat with her. Thanks, Ringo """ # run the agent inputs = {"initial_email": EMAIL, "num_steps":0} for output in app.stream(inputs): for key, value in output.items(): pprint(f"Finished running: {key}:") # Output ---CATEGORIZING INITIAL EMAIL--- product_enquiry 'Finished running: categorize_email:' ---RESEARCH INFO RAG--- What are the character meet and greet options available in WestWorld? In WestWorld, guests can meet and interact with hosts modeled after Dolores, Maeve, Clementine, Logan, and Teddy. Each character offers unique experiences, such as going on an adventure with Dolores, engaging in conversations with Maeve, or training with Teddy. Are there any special experiences or tours that allow interaction with WestWorld characters like Maeve? Yes, guests can meet and interact with a host based on Maeve, engaging in conversations and storylines that explore her wit, intelligence, and growing self-awareness. You can also embark on a thrilling heist storyline with a host modeled after Hector, which involves working with Maeve. Additionally, you can explore romantic storylines with Maeve or other hosts of your choice. Can guests have personalized conversations with WestWorld characters like Maeve? Yes, guests can have personalized conversations with Westworld characters like Maeve, engaging in conversations and storylines that explore her wit, intelligence, and growing self-awareness. ['What are the character meet and greet options available in WestWorld?\n\nIn WestWorld, guests can meet and interact with hosts modeled after Dolores, Maeve, Clementine, Logan, and Teddy. Each character offers unique experiences, such as going on an adventure with Dolores, engaging in conversations with Maeve, or training with Teddy.\n\n\n', 'Are there any special experiences or tours that allow interaction with WestWorld characters like Maeve?\n\nYes, guests can meet and interact with a host based on Maeve, engaging in conversations and storylines that explore her wit, intelligence, and growing self-awareness. You can also embark on a thrilling heist storyline with a host modeled after Hector, which involves working with Maeve. Additionally, you can explore romantic storylines with Maeve or other hosts of your choice.\n\n\n', 'Can guests have personalized conversations with WestWorld characters like Maeve?\n\nYes, guests can have personalized conversations with Westworld characters like Maeve, engaging in conversations and storylines that explore her wit, intelligence, and growing self-awareness.\n\n\n'] <class 'list'> 'Finished running: research_info_search:' ---DRAFT EMAIL WRITER--- {'email_draft': "Dear Ringo,\n\nThank you for your enthusiasm for Westworld! We're thrilled to hear that you're a big fan of the park. \n\nRegarding your question, I'm delighted to inform you that yes, you can meet Maeve in the park! You can engage in conversations with her, exploring her wit, intelligence, and growing self-awareness. You can also embark on a thrilling heist storyline with a host modeled after Hector, which involves working with Maeve. If you're interested, you can even explore romantic storylines with Maeve or other hosts of your choice.\n\nWe offer various character meet and greet options, including interactions with Dolores, Maeve, Clementine, Logan, and Teddy. Each character offers unique experiences, and we're confident you'll have a fantastic time interacting with Maeve.\n\nIf you have any more questions or would like to know more about our character meet and greet options, please don't hesitate to ask. We're always here to help.\n\nThank you for choosing Westworld, and we look forward to welcoming you to the park!\n\nBest regards,\nSarah\nResident Manager"} ---ROUTE TO REWRITE--- {'router_decision': 'no_rewrite'} no_rewrite ---ROUTE EMAIL TO FINAL EMAIL--- 'Finished running: draft_email_writer:' ---NO REWRITE EMAIL --- 'Finished running: no_rewrite:' ---STATE PRINTER--- Initial Email: HI there, I am a big fan of westworld. can I meet Maeve in the park? Really want to chat with her. Thanks, Ringo Email Category: product_enquiry Draft Email: Dear Ringo, Thank you for your enthusiasm for Westworld! We're thrilled to hear that you're a big fan of the park. Regarding your question, I'm delighted to inform you that yes, you can meet Maeve in the park! You can engage in conversations with her, exploring her wit, intelligence, and growing self-awareness. You can also embark on a thrilling heist storyline with a host modeled after Hector, which involves working with Maeve. If you're interested, you can even explore romantic storylines with Maeve or other hosts of your choice. We offer various character meet and greet options, including interactions with Dolores, Maeve, Clementine, Logan, and Teddy. Each character offers unique experiences, and we're confident you'll have a fantastic time interacting with Maeve. If you have any more questions or would like to know more about our character meet and greet options, please don't hesitate to ask. We're always here to help. Thank you for choosing Westworld, and we look forward to welcoming you to the park! Best regards, Sarah Resident Manager Final Email: Dear Ringo, Thank you for your enthusiasm for Westworld! We're thrilled to hear that you're a big fan of the park. Regarding your question, I'm delighted to inform you that yes, you can meet Maeve in the park! You can engage in conversations with her, exploring her wit, intelligence, and growing self-awareness. You can also embark on a thrilling heist storyline with a host modeled after Hector, which involves working with Maeve. If you're interested, you can even explore romantic storylines with Maeve or other hosts of your choice. We offer various character meet and greet options, including interactions with Dolores, Maeve, Clementine, Logan, and Teddy. Each character offers unique experiences, and we're confident you'll have a fantastic time interacting with Maeve. If you have any more questions or would like to know more about our character meet and greet options, please don't hesitate to ask. We're always here to help. Thank you for choosing Westworld, and we look forward to welcoming you to the park! Best regards, Sarah Resident Manager Research Info: ['What are the character meet and greet options available in WestWorld?\n\nIn WestWorld, guests can meet and interact with hosts modeled after Dolores, Maeve, Clementine, Logan, and Teddy. Each character offers unique experiences, such as going on an adventure with Dolores, engaging in conversations with Maeve, or training with Teddy.\n\n\n', 'Are there any special experiences or tours that allow interaction with WestWorld characters like Maeve?\n\nYes, guests can meet and interact with a host based on Maeve, engaging in conversations and storylines that explore her wit, intelligence, and growing self-awareness. You can also embark on a thrilling heist storyline with a host modeled after Hector, which involves working with Maeve. Additionally, you can explore romantic storylines with Maeve or other hosts of your choice.\n\n\n', 'Can guests have personalized conversations with WestWorld characters like Maeve?\n\nYes, guests can have personalized conversations with Westworld characters like Maeve, engaging in conversations and storylines that explore her wit, intelligence, and growing self-awareness.\n\n\n'] RAG Questions: ['What are the character meet and greet options available in WestWorld?', 'Are there any special experiences or tours that allow interaction with WestWorld characters like Maeve?', 'Can guests have personalized conversations with WestWorld characters like Maeve?'] Num Steps: 4 ``` ## **结论** 通过将RAG与LangChain的LangGraph代理集成,我们可以创建一个强大的系统来制作对客户的智能电子邮件回复。该系统可自动执行电子邮件分类、问题生成和知识检索等任务,从而简化沟通并使企业能够提供卓越的客户服务。效率的提高使座席能够专注于更复杂的问题,而上下文感知的回复草稿确保所有客户查询都得到全面解决。 此外,随着LangChain代理随着时间的推移收到用户反馈,它可以不断提高其性能,确保电子邮件回复变得更加自然和有用。RAG 和 LangChain 代理的这种集成代表了人工智能驱动的通信的重大飞跃,促进了更高效和积极的客户体验。
yg9538
2024年5月5日 14:07
630
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
PDF文档
PDF文档(打印)
分享
链接
类型
密码
更新密码