回顾学习笔记3| 豆包MarsCode AI刷题

55 阅读10分钟

全部基础内容学完之后回顾前三节基础课程,对langchain作为 AI 应用开发框架的结构和功能理解更加深入,整个langchain的层次应该为:

Multiagent/任务—Agent—chain—RAG/Model I/O —tools/ LLM /输入解析/输入提示,以下是学习过程中对几个板块分别的理解和笔记摘要(1):

模型I/O

我们可以把对模型的使用过程拆解成三块,分别是输入提示(对应图中的Format)、调用模型(对应图中的Predict)和输出解析(对应图中的Parse)。这三块形成了一个整体,因此在LangChain中这个过程被统称为 Model I/O(Input/Output)。

在模型 I/O的每个环节,LangChain都为咱们提供了模板和工具,快捷地形成调用各种语言模型的接口。

  1. 提示模板:使用模型的第一个环节是把提示信息输入到模型中,你可以创建LangChain模板,根据实际需求动态选择不同的输入,针对特定的任务和应用调整输入。
  2. 语言模型:LangChain允许你通过通用接口来调用语言模型。这意味着无论你要使用的是哪种语言模型,都可以通过同一种方式进行调用,这样就提高了灵活性和便利性。
  3. 输出解析:LangChain还提供了从模型输出中提取信息的功能。通过输出解析器,你可以精确地从模型的输出中获取需要的信息,而不需要处理冗余或不相关的数据,更重要的是还可以把大模型给回的非结构化文本,转换成程序可以处理的结构化数据。

Input:提示词

Output:Output pasers(输出)

输出解析器:LangChain的提示模板可以嵌入对输出格式的定义,以便在后续处理过程中比较方便地处理已经被格式化了的输出。(因为不仅仅需要文字,更多情况下我们需要的是程序能够直接处理的、结构化的数据)

1. 列表解析器(List Parser):这个解析器用于处理模型生成的输出,当需要模型的输出是一个列表的时候使用。例如,如果你询问模型“列出所有鲜花的库存”,模型的回答应该是一个列表。
2. 日期时间解析器(Datetime Parser):这个解析器用于处理日期和时间相关的输出,确保模型的输出是正确的日期或时间格式。
3. 枚举解析器(Enum Parser):这个解析器用于处理预定义的一组值,当模型的输出应该是这组预定义值之一时使用。例如,如果你定义了一个问题的答案只能是“是”或“否”,那么枚举解析器可以确保模型的回答是这两个选项之一。
4. 结构化输出解析器(Structured Output Parser):这个解析器用于处理复杂的、结构化的输出。如果你的应用需要模型生成具有特定结构的复杂回答(例如一份报告、一篇文章等),那么可以使用结构化输出解析器来实现。
5. Pydantic(JSON)解析器: 这个解析器用于处理模型的输出,当模型的输出应该是一个符合特定格式的JSON对象时使用。它使用Pydantic库,这是一个数据验证库,可以用于构建复杂的数据模型,并确保模型的输出符合预期的数据模型。
6. 自动修复解析器(Auto-Fixing Parser) :这个解析器可以自动修复某些常见的模型输出错误。例如,如果模型的输出应该是一段文本,但是模型返回了一段包含语法或拼写错误的文本,自动修复解析器可以自动纠正这些错误。
7. 重试解析器(RetryWithErrorOutputParser) :这个解析器用于在模型的初次输出不符合预期时,尝试修复或重新生成新的输出。例如,如果模型的输出应该是一个日期,但是模型返回了一个字符串,那么重试解析器可以重新提示模型生成正确的日期格式。

langchain相对直接调用openai的优势:

1.提示模板的复用与简洁
  • LangChain:

    • 在 LangChain 中,通过 PromptTemplate.from_template(template) 创建了一个可复用的提示模板。只需要定义一次模板字符串 template,其中包含 {price}{flower_name} 占位符。之后,对于不同的鲜花和价格组合,使用 prompt.format(flower_name=flower, price=price) 就能方便地生成相应的输入提示。这种方式将模板定义和使用分离,代码结构清晰。
    • 当需要处理更多类型的鲜花或修改模板内容时,只需在一处(即原始模板定义处)进行更改,例如添加新的占位符或者修改描述的风格,整个代码中使用该模板的地方都会受到影响,而不需要在每个使用的地方都修改代码,这大大提高了代码的可维护性。
  • 直接调用 OpenAI:

    • 直接使用 OpenAI API 时,提示文本 prompt_text 虽然看起来也简洁,但它只是一个普通的字符串,使用 prompt_text.format(price, flower) 来格式化。如果有大量不同的输入情况或者需要修改提示内容,需要在每个使用格式化的地方都进行逐一修改。
2.LLM方便替换
  • LangChain:

    • 使用 LangChain 提示模板时,可以很方便地将程序切换到不同的模型。因为提示模板与模型的调用是相对独立的,只需要在创建模型实例(只需要修改类似 model = OpenAI(...)model = HuggingFacePipeline(...) 的代码)的地方修改模型名称或配置,而不需要修改与提示相关的代码。这在进行模型选型、对比或者在不同环境中使用不同模型时非常方便。
3.I/O方面集成了各类功能
  • LangChain:

    • LangChain 的提示模板整合了多种功能,如 output_parsertemplate_formatvalidate_template 等。这些功能在更复杂的场景中非常有用。例如,output_parser 可以对模型的输出进行特定格式的解析,使其符合应用程序的后续处理要求;validate_template 可以检查模板的正确性,避免因模板错误导致的问题。
    • 这些功能使得在处理自然语言生成任务时,可以更加精细地控制和处理输入输出,而不需要额外编写大量的代码来实现这些功能。

I:PromptTemplate(创建和管理提示词模板)

O:StructuredOutputParser(结构化输出器), ResponseSchema

链(Chain)

Chain是langchain中的一种基本单元,其中可以封装大模型和各组件,或是封装Model I/O的流程;更进一步,也可以通过sequentialchain、routerchain这样的chain将多个chain或组件串联到一起,形成更复杂的chain。

Chain相当于以“工作流”的形式将LLM和模型I/O组件进行了有序的封装,从而具备构建复杂AI工作流的能力。

chain的调用(自己简单通过表格总结):

直接调用通过run方法通过predict方法通过apply方法通过generate方法
当我们像函数一样调用一个对象时,它实际上会调用该对象内部实现的__call__方法。如果你的提示模板中包含多个变量,在调用链的时候,可以使用字典一次性输入它们。等价于直接调用_call_函数。predict方法类似于run,只是输入键被指定为关键字参数而不是 Python 字典。apply方法允许我们针对输入列表运行链,一次处理多个输入。generate方法类似于apply,只不过它返回一个LLMResult对象,而不是字符串。LLMResult通常包含模型生成文本过程中的一些相关信息,例如令牌数量、模型名称等。
```
prompt = PromptTemplate( input_variables=["flower", "season"], template="{flower}在{season}的花语是?", ) llm_chain = LLMChain(llm=llm, prompt=prompt) print(llm_chain({ 'flower': "玫瑰", 'season': "夏季" }))
``````
llm_chain.run("玫瑰")
``````
result = llm_chain.predict(flower="玫瑰") print(result)

  


#### 路由链

**具体步骤如下:**

1.  构建处理模板:为鲜花护理和鲜花装饰分别定义两个字符串模板。
1.  提示信息:使用一个列表来组织和存储这两个处理模板的关键信息,如模板的键、描述和实际内容。
1.  初始化语言模型:导入并实例化语言模型。
1.  构建目标链:根据提示信息中的每个模板构建了对应的LLMChain,并存储在一个字典中。
1.  构建LLM路由链:这是决策的核心部分。首先,它根据提示信息构建了一个路由模板,然后使用这个模板创建了一个LLMRouterChain。
1.  构建默认链:如果输入不适合任何已定义的处理模板,这个默认链会被触发。
1.  构建多提示链:使用MultiPromptChain将LLM路由链、目标链和默认链组合在一起,形成一个完整的决策系统。

  


### 代理(Agent)

#### 1.代理是什么

代理能够**自主判断、自行调用工具、自行决定下一步行动**。它就像一个**多功能的接口**,它能够接触并使用一套工具。根据用户的输入,代理会决定调用哪些工具。它不仅可以同时使用多种工具,而且可以将一个工具的输出数据作为另一个工具的输入数据。

  


2.代理的基础——ReAct框架

ReAct框架:https://arxiv.org/pdf/2210.03629

核心路径:观察环境-进行思考-采取行动,简而言之就是推理(Reasoning)-行动(Acting)

Reasoning包括了**对当前环境和状态的观察,并生成推理轨迹**。这使模型能够诱导、跟踪和更新操作计划,甚至处理异常情况。

Acting在于指导大模型采取下一步的行动,比如**与外部源(如知识库或环境)进行交互并且收集信息**,或者给出最终答案。

案例:

![](https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/14d45a69d9d64bd2b6c6081833142abd~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3NTc5NjAwMTM1Njg3:q75.awebp?rk3s=f64ab15b&x-expires=1772028690&x-signature=EwRtWdZUFpK1hGiKMe6Vr3N7GVQ%3D)

关于代理和链的区别:

**链中,非自治,硬编码行动序列。一系列操作被硬编码(在代码中)。**

**代理中,自治,LLM选择采取的行动序列。LLM被用作推理引擎来确定要采取哪些操作以及按什么顺序执行这些操作。**

  


  


### 索引

索引**可以让文档结构化**,从而LLM可以直接更好的和文档交互;比如用于答疑,知识库等,LLM先从文档中获取答案。LangChain在索引这块也提供了许多有用的函数和工具,方便我们从外部加载与检索不同的文档数据。

在数据索引这块,LangChain提供的主要工具:

1.  Document Loaders:从不同的数据源加载文档,当使用loader加载器读取到数据源后,数据源需要转换成 Document 对象后,后续才能进行使用。
1.  Text Splitters:实现文本分割,我们每次不管是做把文本当作 prompt 发给 openai api ,还是还是使用 openai api embedding 功能都是有字符限制的。比如我们将一份300页的 pdf 发给 openai api,让他进行总结,他肯定会报超过最大 Token 错。所以这里就需要使用文本分割器去分割我们 loader 进来的 Document。
1.  VectorStores:把文档存储为向量结构,因为数据相关性搜索其实是向量运算。所以,不管我们是使用 openai api embedding 功能还是直接通过向量数据库直接查询,都需要将我们的加载进来的数据 Document 进行向量化,才能进行向量运算搜索。转换成向量也很简单,只需要我们把数据存储到对应的向量数据库中即可完成向量的转换。
1.  Retrievers:用于检索文档的数据。