当前位置:   article > 正文

基于JSON的Ollama和LangChain agent_ollama langchain

ollama langchain

到目前为止,我们都可能意识到,通过为LLMs提供额外的工具,我们可以显著增强它们的功能。

例如,即使是ChatGPT在付费版本中也可以直接使用Bing搜索和Python解释器。OpenAI更进一步,为工具使用提供了经过优化的LLM模型,您可以将可用的工具和提示一起传递给API端点。

然后LLM决定是否可以直接提供回答,或者是否应该首先使用任何可用的工具。

请注意,这些工具不仅仅用于获取额外的信息;它们可以是任何东西,甚至可以让LLMs预订晚餐。我之前实施过一个项目,允许LLM通过一组预定义的工具与图数据库进行交互,我称之为语义层。

一个与图数据库交互的代理LLM。图片由作者提供。

本质上,这些工具通过提供动态、实时的信息访问、通过记忆进行个性化以及通过知识图谱对关系进行复杂的理解,来增强像GPT-4这样的LLM。

它们共同使LLM能够提供更准确的推荐,随着时间的推移了解用户的偏好,并获得更广泛的最新信息,从而实现更具互动性和适应性的用户体验。

正如提到的那样,除了在查询时能够检索到额外的信息外,它们还给LLM提供了一种影响他们环境的选择,例如在日历中预订会议。

虽然OpenAI为我们提供了精细调整的模型来进行工具使用,但事实是,大多数其他LLMs在函数调用和工具使用方面都不及OpenAI水平。

我已经尝试了Ollama中大部分可用的模型,大多数都难以始终生成可用于驱动代理的预定义结构化输出。另一方面,有一些模型是针对函数调用进行了优化的。

然而,这些模型采用了一种自定义的提示工程模式来进行函数调用,但这种模式并没有很好地记录,或者它们不能用于除了函数调用之外的任何其他用途。

最终,我决定遵循现有的LangChain实现,使用基于JSON的代理,使用Mixtral 8x7b LLM。我将Mixtral 8x7b用作电影代理,通过语义层与Neo4j进行交互,Neo4j是一种本地图数据库。代码可作为Langchain模板Jupyter笔记本提供。如果你对工具的实现方式感兴趣,可以查看我之前的博客文章。在这里,我们将讨论如何实现基于JSON的LLM代理。

语义层中的工具

LangChain文档中的示例(JSON代理HuggingFace示例)使用的是只有一个字符串输入的工具。由于语义层中的工具使用稍微复杂一些的输入,我不得不深入研究一下。这是一个推荐工具的示例输入。

  1. all_genres = [
  2. "Action",
  3. "Adventure",
  4. "Animation",
  5. "Children",
  6. "Comedy",
  7. "Crime",
  8. "Documentary",
  9. "Drama",
  10. "Fantasy",
  11. "Film-Noir",
  12. "Horror",
  13. "IMAX",
  14. "Musical",
  15. "Mystery",
  16. "Romance",
  17. "Sci-Fi",
  18. "Thriller",
  19. "War",
  20. "Western",
  21. ]
  22. class RecommenderInput(BaseModel):
  23. movie: Optional[str] = Field(description="movie used for recommendation")
  24. genre: Optional[str] = Field(
  25. description=(
  26. "genre used for recommendation. Available options are:" f"{all_genres}"
  27. )
  28. )

推荐工具有两个可选输入:电影和类型。此外,我们使用一个可用值的枚举来表示类型参数。

虽然输入并不是非常复杂,但仍比单个字符串输入更先进,因此实现方式必须稍有不同。

基于JSON的LLM代理的提示

在我的实现中,我从LangChain hub中现有的 hwchase17/react-json 提示中获得了很大的灵感。该提示使用以下系统消息。

  1. Answer the following questions as best you can. You have access to the following tools:
  2. {tools}
  3. The way you use the tools is by specifying a json blob.
  4. Specifically, this json should have a `action` key (with the name of the tool to use) and a `action_input` key (with the input to the tool going here).
  5. The only values that should be in the "action" field are: {tool_names}
  6. The $JSON_BLOB should only contain a SINGLE action, do NOT return a list of multiple actions. Here is an example of a valid $JSON_BLOB:
  7. ```
  8. {{
  9. "action": $TOOL_NAME,
  10. "action_input": $INPUT
  11. }}
  12. ```
  13. ALWAYS use the following format:
  14. Question: the input question you must answer
  15. Thought: you should always think about what to do
  16. Action:
  17. ```
  18. $JSON_BLOB
  19. ```
  20. Observation: the result of the action
  21. ... (this Thought/Action/Observation can repeat N times)
  22. Thought: I now know the final answer
  23. Final Answer: the final answer to the original input question
  24. Begin! Reminder to always use the exact characters `Final Answer` when responding.

提示从定义可用工具开始,稍后我们将介绍。提示的最重要部分是指示LLM输出应该是什么样子的。当LLM需要调用一个函数时,应该使用以下JSON结构:

  1. {{
  2. "action": $TOOL_NAME,
  3. "action_input": $INPUT
  4. }}

这就是为什么它被称为基于JSON的代理:当LLM想要使用任何可用工具时,我们指示它生成一个JSON。然而,这只是输出定义的一部分。完整的输出应该具有以下结构:

  1. Thought: you should always think about what to do
  2. Action:
  3. ```
  4. $JSON_BLOB
  5. ```
  6. Observation: the result of the action
  7. ... (this Thought/Action/Observation can repeat N times)
  8. Final Answer: the final answer to the original input question

LLM应该在输出的思考部分解释它正在做什么。当它想要使用任何可用的工具时,应该将动作输入提供为JSON blob。

观察部分保留给工具输出,当代理决定可以向用户返回答案时,应使用最终答案键。以下是使用此结构的电影代理的示例。

在这个例子中,我们要求代理人推荐一部好的喜剧片。由于代理人可用的工具之一是推荐工具,它决定利用推荐工具,通过提供JSON语法来定义其输入。幸运的是,LangChain具有内置的JSON代理输出解析器,所以我们不必担心实现它。接下来,LLM从工具中获得一个响应,并将其作为提示中的观察。

由于工具提供了所有所需的信息,LLM决定它已经有足够的信息来构建最终答案,并将其返回给用户。

我注意到很难促使工程师Mixtral只在需要使用工具时使用JSON语法。在我的实验中,当它不想使用任何工具时,有时会使用以下JSON动作输入。

  1. {{
  2. "action": Null,
  3. "action_input": ""
  4. }}

LangChain中的输出解析函数不会忽略空或类似的操作,而是返回一个错误,指出未定义空工具。我试图向工程师提供解决这个问题的提示,但无法以一致的方式做到。

因此,我决定添加一个虚拟的闲聊工具,当用户想要闲聊时,代理可以调用它。

  1. response = (
  2. "Create a final answer that says if they "
  3. "have any questions about movies or actors"
  4. )
  5. class SmalltalkInput(BaseModel):
  6. query: Optional[str] = Field(description="user query")
  7. class SmalltalkTool(BaseTool):
  8. name = "Smalltalk"
  9. description = "useful for when user greets you or wants to smalltalk"
  10. args_schema: Type[BaseModel] = SmalltalkInput
  11. def _run(
  12. self,
  13. query: Optional[str] = None,
  14. run_manager: Optional[CallbackManagerForToolRun] = None,
  15. ) -> str:
  16. """Use the tool."""
  17. return response

这样,代理可以在用户打招呼时决定使用一个虚拟的Smalltalk工具,我们不再遇到解析空或缺失工具名称的问题。

这个解决方法非常有效,所以我决定保留它。正如提到的,大多数模型没有经过训练来产生行动输入或文本,如果不需要行动,我们必须使用当前可用的内容。

然而,有时候模型在第一次迭代时成功地不调用任何工具,这取决于情况。但是给它一个像smalltalk工具这样的逃逸选项似乎可以防止异常。

在系统提示中定义工具输入

如前所述,我必须弄清楚如何定义稍微复杂的工具输入,以便LLM能够正确解释它们。

有趣的是,在实施自定义函数之后,我发现了一个现有的LangChain函数,它将自定义的Pydantic工具输入定义转换为Mixtral可以识别的JSON对象。

  1. from langchain.tools.render import render_text_description_and_args
  2. tools = [RecommenderTool(), InformationTool(), Smalltalk()]
  3. tool_input = render_text_description_and_args(tools)
  4. print(tool_input)

生成以下字符串描述:

  1. "Recommender":"useful for when you need to recommend a movie",
  2. "args":{
  3. {
  4. "movie":{
  5. {
  6. "title":"Movie",
  7. "description":"movie used for recommendation",
  8. "type":"string"
  9. }
  10. },
  11. "genre":{
  12. {
  13. "title":"Genre",
  14. "description":"genre used for recommendation. Available options are:['Action', 'Adventure', 'Animation', 'Children', 'Comedy', 'Crime', 'Documentary', 'Drama', 'Fantasy', 'Film-Noir', 'Horror', 'IMAX', 'Musical', 'Mystery', 'Romance', 'Sci-Fi', 'Thriller', 'War', 'Western']",
  15. "type":"string"
  16. }
  17. }
  18. }
  19. },
  20. "Information":"useful for when you need to answer questions about various actors or movies",
  21. "args":{
  22. {
  23. "entity":{
  24. {
  25. "title":"Entity",
  26. "description":"movie or a person mentioned in the question",
  27. "type":"string"
  28. }
  29. },
  30. "entity_type":{
  31. {
  32. "title":"Entity Type",
  33. "description":"type of the entity. Available options are 'movie' or 'person'",
  34. "type":"string"
  35. }
  36. }
  37. }
  38. },
  39. "Smalltalk":"useful for when user greets you or wants to smalltalk",
  40. "args":{
  41. {
  42. "query":{
  43. {
  44. "title":"Query",
  45. "description":"user query",
  46. "type":"string"
  47. }
  48. }
  49. }
  50. }

我们可以简单地将这个工具描述复制到系统提示中,Mixtral就能够使用定义好的工具,这非常酷。

 结论

JSON-based agent的大部分工作是由Harrison Chase和LangChain团队完成的,我对此表示感谢。我所要做的就是找到拼图的碎片并将它们组合起来。正如前面提到的,不要期望与GPT-4一样的代理性能水平。然而,我认为像Mixtral这样更强大的OSSLLMs可以作为代理使用(比GPT-4需要更多的异常处理)。

我期待更多的开源LLMs被调整得更好作为代理。

代码可作为Langchain模板Jupyter笔记本提供。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/煮酒与君饮/article/detail/845538
推荐阅读
相关标签
  

闽ICP备14008679号