LangChain Agent v0.2.0简明教程 (下)

news2024/11/24 20:38:48

    • 5. Agent
        • 5.1 Tools(Function Calling)
        • 5.2 Agent
    • 6. Memory

5. Agent

Agent的核心思想是根据用户输入的prompt,使用LLM来选择要采取的一系列操作(agent调用tools = prompt + llm + tools)。在Chain中,一系列操作被硬编码(在代码中)。在Agent中,LLM被用作推理引擎,来确定要采取哪些操作以及按什么顺序

5.1 Tools(Function Calling)

Tools是Agent可以用来与世界交互的函数APITools应该包含以下信息:

  • 工具名称Tools Name(tool.name)
  • 该工具是什么的描述Tools Description(tool.description)
  • 工具输入内容的 JSON 架构Input Json Mode(tool.args)
  • 要调用的函数Function Calling
  • 工具的结果是否应直接返回给用户Return Result(tool.return_direct)

WikipediaAPI为例:

from langchain_community.tools import WikipediaQueryRun
from langchain_community.utilities import WikipediaAPIWrapper
api_wrapper = WikipediaAPIWrapper(top_k_results=1, doc_content_chars_max=100)
tool = WikipediaQueryRun(api_wrapper=api_wrapper)
print(tool.name)
# wikipedia
print(tool.description)
# A wrapper around Wikipedia. Useful for when you need to answer general questions about people, places, companies, facts, historical events, or other subjects. Input should be a search query.
print(tool.args)
# {'query': {'title': 'Query', 'type': 'string'}}
print(tool.return_direct)
# False

上述信息可以用于提示 LLM,以便它知道如何指定要采取的操作,然后要调用的函数相当于采取该操作。工具的输入越简单,LLM就越容易使用它。许多Agent只能使用具有单个字符串输入的工具。重要的是,Name、Description 和 JSON Mode(如果使用)都在Prompt中使用。因此,清晰并准确地描述如何使用该工具非常重要。如果 LLM 不了解如何使用该工具,您可能需要更改默认Name、Description 和 JSON Mode。

工具包Toolkits:是旨在一起用于特定任务并具有方便的加载方法的工具的集合。from langchain.agents import load_tools中所有工具包都公开一个get_tools返回工具列表的方法,创建Agent的函数也和具体的tools有关,伪代码如下:

# Initialize a toolkit
toolkit = ExampleTookit(...)
# Get list of tools
tools = toolkit.get_tools()
# Create agent
agent = create_agent_method(llm, tools, prompt)

定义自定义工具函数Tools Function:在构建自己的Agent时,您需要为其提供可以使用的工具列表,即上述的tools。除了调用的实际tools执行函数之外,该工具还包含几个组件:

  • name(str),是必需的,并且在提供给代理的一组工具中必须是唯一的
  • description(str),是可选的,但建议使用,因为代理使用它来确定工具的使用
  • args_schema(Pydantic BaseModel) 是可选的,但推荐使用,可用于提供更多信息(例如,少数样本示例)或对预期参数的验证。

@tool装饰器:是定义自定义工具函数Tools Function的最简单方法。装饰器默认使用函数名作为Tools Name,但是可以通过给@tool传递字符串作为第一个参数来覆盖Tools Name。此外,装饰器将使用函数的文档字符串作为Tools Description - 因此必须提供文档字符串。

from langchain.tools import BaseTool, tool
@tool
def search(query: str) -> str:
    """Look up things online."""
    return "LangChain"

print(search.name)
search
print(search.description)
search(query: str) -> str - Look up things online.
print(search.args)
{'query': {'title': 'Query', 'type': 'string'}}

还可以通过将Tools NameJSON 参数传递到工具装饰器@tool("tool_name", args_schema=SearchInput, return_direct=True) 中来自定义它们。

from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools import tool
class SearchInput(BaseModel):
    query: str = Field(description="should be a search query")
    
@tool("search-tool", args_schema=SearchInput, return_direct=True)
def search(query: str) -> str:
    """Look up things online."""
    return "LangChain"
# search-tool
# search-tool(query: str) -> str - Look up things online.
# {'query': {'title': 'Query', 'description': 'should be a search query', 'type': 'string'}}
# True

StructuredTool数据类:也可以用来自定义Tools Function,相比于**@tool装饰器**更加规范:

from langchain.tools import StructuredTool
def search_function(query: str):
    return "LangChain"
search = StructuredTool.from_function(
    func=search_function,
    name="Search",
    description="useful for when you need to answer questions about current events",
    # args_schema=... <也可以自定义以提供有关输入class的更多信息>
    # coroutine= ... <- you can specify an async method if desired as well
)
print(search.name)
# Search
print(search.description)
# Search(query: str) - useful for when you need to answer questions about current events
print(search.args)
# {'query': {'title': 'Query', 'type': 'string'}}
5.2 Agent

常用的Agent类型如下:

  • Conversational Agent
    这类Agent可以根据Language Model的输出决定是否使用指定的Tool,以及使用什么Tool(这里的Tool也可以是一个Chain),以及时的为Model I/O的过程补充信息

  • OpenAI functions Agent
    类似Conversational Agent,但它能够让Agent更进一步地帮忙提取指定Tool的参数等,甚至使用多个Tools

  • Plan and execute Agent
    抽象Agent“决定做什么”的过程为“planning what to do”和“executing the sub tasks”(这种方法来自"Plan-and-Solve"这一篇论文),其中“planning what to do”这一步通常完全由LLM完成,而“executing the sub tasks”这一任务则通常由更多的Tools来完成

  • ReAct Agent
    让LLM反复执行Reasoning推理Action执行的方法,类似OpenAI functions Agent,提供了一个更加明确的框架以及由论文支撑的方法

  • Self ask with search
    这类Agent会基于LLM的输出,自行调用Tools以及LLM来进行额外的搜索和自查,以达到拓展和优化输出的目的
    在这里插入图片描述

这里展示一个查询+本地检索的tools来构建OpenAI Agent任务:

# 1. create search tool 
export TAVILY_API_KEY="..."
from langchain_community.tools.tavily_search import TavilySearchResults
search = TavilySearchResults()

# 2. create retriever tool 
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import WebBaseLoader
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
loader = WebBaseLoader("https://docs.smith.langchain.com/overview")
docs = loader.load()
documents = RecursiveCharacterTextSplitter(
    chunk_size=1000, chunk_overlap=200
).split_documents(docs)
vector = FAISS.from_documents(documents, OpenAIEmbeddings())
retriever = vector.as_retriever()
from langchain.tools.retriever import create_retriever_tool
retriever_tool = create_retriever_tool(
    retriever,
    "langsmith_search",
    "Search for information about LangSmith. For any questions about LangSmith, you must use this tool!",
)

使用 LLMPromptsTools 来初始化Agent。Agent负责接收输入并决定采取什么操作。至关重要的是,Agent不执行这些操作 - 这是由 AgentExecutor 完成的(下一步)。

tools = [search, retriever_tool]

from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)

from langchain import hub
prompt = hub.pull("hwchase17/openai-functions-agent")
prompt.messages

from langchain.agents import create_openai_functions_agent
agent = create_openai_functions_agent(llm, tools, prompt)

from langchain.agents import AgentExecutor
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

agent_executor.invoke({"input": "hi!"})

该Agent是无记忆的。这意味着它不记得以前的交互。为了给它记忆,我们需要传入 chat_history

from langchain_core.messages import AIMessage, HumanMessage
agent_executor.invoke(
    {
        "chat_history": [
            HumanMessage(content="hi! my name is bob"),
            AIMessage(content="Hello Bob! How can I assist you today?"),
        ],
        "input": "what's my name?",
    }
)

6. Memory

Memory可以帮助Language Model补充历史信息的上下文,LangChain中的Memory是一个有点模糊的术语,它可以像记住你过去聊天过的信息一样简单(如history_message),也可以结合向量数据库做更加复杂的历史信息检索,甚至维护相关实体及其关系的具体信息,这取决于具体的应用

通常Memory用于较长的Chain,能一定程度上提高模型的推理表现
在这里插入图片描述
常用的Memory类型如下:

  • Chat Messages:: 最简单Memory,将历史Chat记录作为补充信息放入prompt中
  • Vector store-based memory :基于向量数据库的Memory,将memory存储在向量数据库中,并在每次调用时查询TopK的最“重要”的文档 这与大多数其他memory类型的不同之处在于,它不显式跟踪交互的顺序,最多基于部分元数据筛选一下向量数据库的查询范围
  • Conversation buffer(window) memory 保存一段时间内的历史Chat记录,它只使用最后K个记录(仅保持最近交互的滑动窗口),这样buffer也就不会变得太大,避免超过token上限
  • Conversation summary memory: 这种类型的Memory会随着Chat的进行创建对话的摘要,并将当前摘要存储在Memory中,用于后续对话的history提示;这种memory方案对长会话非常有用,但频繁的总结摘要会耗费大量的token
  • Conversation Summary Buffer Memory: 结合了buffer memory和summary memory的策略,依旧会在内存中保留最后的一些Chat记录作为buffer,并在buffer的总token数达到预置的上限后,对所有Chat记录总结摘要作为SystemMessage并清理其它历史Messages;这种memory方案结合了buffer memory和summary memory的优点,既不会频繁地总结摘要消耗token,也不会让buffer缺失过多信息

下面是一个Conversation Summary Buffer Memory在ConversationChain中的使用示例,包含了切换会话时恢复现场memory的方法以及自定义summary prompt的方法:

from langchain.chains import ConversationChain
from langchain.memory import ConversationSummaryBufferMemory
from langchain.llms import OpenAI
from langchain.schema import SystemMessage, AIMessage, HumanMessage
from langchain.memory.prompt import SUMMARY_PROMPT
from langchain.prompts import PromptTemplate

llm = OpenAI(temperature=0.7, openai_api_key=OPENAI_API_KEY, openai_api_base=OPENAI_PROXY_URL+"/v1")
# ConversationSummaryBufferMemory默认使用langchain.memory.prompt.SUMMARY_PROMPT作为summary的PromptTemplate
# 如果对它summary的格式/内容有特殊要求,可以自定义PromptTemplate(实测默认的summary有些流水账)
prompt_template_str = """
## Instruction
Progressively summarize the lines of conversation provided, adding onto the previous summary returning a new concise and detailed summary.
Don't repeat the conversation directly in the summary, extract key information instead.

## EXAMPLE
Current summary:
The human asks what the AI thinks of artificial intelligence. The AI thinks artificial intelligence is a force for good.

New lines of conversation:
Human: Why do you think artificial intelligence is a force for good?
AI: Because artificial intelligence will help humans reach their full potential.

New summary:
The human inquires about the AI's opinion on artificial intelligence. The AI believes that it is a force for good as it can help humans reach their full potential.

## Current summary
{summary}

## New lines of conversation
{new_lines}

## New summary

"""
prompt = PromptTemplate(
    input_variables=SUMMARY_PROMPT.input_variables, # input_variables为SUMMARY_PROMPT中的input_variables不变
    template=prompt_template_str, # template替换为上面重新编写的prompt_template_str
)
memory = ConversationSummaryBufferMemory(llm=llm, prompt=prompt, max_token_limit=60)
# 添加历史memory,其中第一条SystemMessage为历史对话中Summary的内容,第二条HumanMessage和第三条AIMessage为历史对话中最后的对话内容
memory.chat_memory.add_message(SystemMessage(content="The human asks what the AI thinks of artificial intelligence. The AI thinks artificial intelligence is a force for good because it will help humans reach their full potential. The human then asks the difference between python and golang in short. The AI responds that python is a high-level interpreted language with an emphasis on readability and code readability, while golang is a statically typed compiled language with a focus on concurrency and performance. Python is typically used for general-purpose programming, while golang is often used for building distributed systems."))
memory.chat_memory.add_user_message("Then if I want to build a distributed system, which language should I choose?")
memory.chat_memory.add_ai_message("If you want to build a distributed system, I would recommend golang as it is a statically typed compiled language that is designed to facilitate concurrency and performance.")
# 调用memory.prune()确保chat_memory中的对话内容不超过max_token_limit
memory.prune()
conversation_with_summary = ConversationChain(
    llm=llm,
    # We set a very low max_token_limit for the purposes of testing.
    memory=memory,
    verbose=True,
)
# memory.prune()会在每次调用predict()后自动执行
conversation_with_summary.predict(input="Is there any well-known distributed system built with golang?")
conversation_with_summary.predict(input="Is there a substitutes for Kubernetes in python?")

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1579149.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

记录一下前端定时器清除失效的问题

目录 一、问题引入 二、错误代码&#xff1a; 三、错误原因 四、修正的代码 附 vue提供的线上运行代码网址以便证实可用性 一、问题引入 按理说&#xff0c;打开定时器 xxx setInterval(()>{ },100)&#xff0c;之后只要 clearInterval(xxx) 就可以顺利关闭定时器…

汇编入门--基础知识(1)

1.汇编语言的概念 汇编语言是一种低级编程语言&#xff0c;它与计算机的机器语言非常接近&#xff0c;但比机器语言更易于人类阅读和理解。汇编语言是用一系列的助记符来表示机器语言的操作码和操作数。每种计算机体系结构&#xff08;如x86、ARM等&#xff09;都有自己的汇编语…

『羊毛教程』免费使用一个月的GPT-4、Claude 3 Opus!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;所以创建了“AI信息Gap”这个公众号&#xff0c;专注于分享AI全维度知识…

2024-04-08 NO.5 Quest3 手势追踪进行 UI 交互

文章目录 1 玩家配置2 物体配置3 添加视觉效果4 添加文字5 其他操作5.1 双面渲染5.2 替换图片 ​ 在开始操作前&#xff0c;我们导入先前配置好的预制体 MyOVRCameraRig&#xff0c;相关介绍在 《2024-04-03 NO.4 Quest3 手势追踪抓取物体-CSDN博客》 文章中。 1 玩家配置 &a…

[数据结构]双向带头循环链表制作

前面我们有提到&#xff0c;单向不带头循环链表的制作 这里我们介绍一个双向带头循环链表的制作方法 双向带头循环链表的示意图如下 带头指针的作用体现在哪呢? 第一、防止头节点为空,既有头结点&#xff0c;头指针始终指向头结点&#xff0c;那么无论链表是否为空&#xf…

前端用Scss简化媒体查询

1、演示 2、未优化前的代码 .header {width: 100px;height: 100px;background-color: red; } media (min-width: 320px) and (max-width: 480px) {.header {width: 10px;} } media (min-width: 320px) and (max-width: 480px) {.header {height: 20px;} } media (min-width: 48…

【测试篇】Selenium + Java环境搭建

文章目录 Selenium Java环境搭建配置系统环境变量PATH验证环境是否搭建成功常见问题&解决办法 Selenium Java环境搭建 Java版本最低要求为8&#xff0c;这里默认大家都下载好了Java。&#x1f606; 下载chrome浏览器&#xff08;点我下载&#xff09; 观察chrome版本。…

你知道哪几种当前流行的lisp语言的方言?

估计很多人都看过《黑客与画家》这本书&#xff0c;这本书主要介绍黑客即优秀程序员的爱好和动机&#xff0c;讨论黑客成长、黑客对世界的贡献以及编程语言和黑客工作方法等所有对计算机时代感兴趣的人的一些话题。作者保罗格雷厄姆字里行间不经意间向大家推介Lisp是最好的编程…

python|drop的应用

drop 删除列B 删除索引为1的行 删除列为‘A’&#xff0c;‘C’的列&#xff0c;axis表示方向 删除时保留原始 DataFrame&#xff08;使用 inplaceFalse&#xff09; 删除时直接修改原始 DataFrame&#xff08;使用 inplaceTrue&#xff09;

Unity面经(自整)——Unity基础知识

Unity基础知识 1. Image和RawImage的区别 Image比RawImage更耗性能。Image只能使用sprite属性的图片。而RawImage什么都可以使用 2. Unity3D中的碰撞器Collider和触发器Trigger的区别 碰撞器是触发器的载体&#xff0c;而触发器是碰撞器上的一个属性。 如果IsTrigger为fal…

Map接口及其实现类及常用方法

1.Map接口及其实现类 java.util.Map : 存储一对一对的数据(key-value键值对)|----->HashMap : 主要实现类,线程不安全,效率高,可以添加null的键值对;底层使用数组单向链表红黑树。|------->LinkedHashMap : 是HashMap的子类,在HashMap的数据结构的基础上,添加了一对双向…

222222222222222222222222

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和…

低温漂、低功耗电压基准,用在精密数据采集系统,供电类设备,工业仪表,测试设备等领域

MSR015/MSR025 是低温漂、低功耗、高精度 CMOS 电压基准&#xff0c; 具有 0.05% 初始精度、低功耗特点。该器件的低输出电压迟滞和低长期输出电压 漂移特性&#xff0c;进一步提高稳定性和系统可靠性。 此外&#xff0c;器件的小尺寸和低运行 电流特性使其非常适合便携…

吴恩达深度学习笔记:深层神经网络(Deep Neural Networks)4.5-4.8

目录 第一门课&#xff1a;神经网络和深度学习 (Neural Networks and Deep Learning)第四周&#xff1a;深层神经网络(Deep Neural Networks)4.5 为什么使用深层表示&#xff1f;&#xff08;Why deep representations?&#xff09; 第一门课&#xff1a;神经网络和深度学习 (…

若依ts版本(vue3+element plus+ts)

1、项目简介 本项目参考若依前后端分离版&#xff0c;前端由[若依vue3]改写为ts版本[ruoyi-web-vue3-ts]&#xff0c;后端对[若依V3.8.7]进行了修改[后端版本分支vue3.ts.3.8.7]&#xff0c;具体文档参见[若依官方文档]。本项目对部分代码做了优化&#xff0c;增加了activiti7…

二维数组及其内存图解

二维数组 在一维数组的介绍当中曾说&#xff0c;数组中可以储存任何同类型的元素&#xff0c;那么这个元素是不是可以也是数组呢&#xff1f;答案是可以&#xff0c;即在数组之中储存数组元素。这种情况就是多维数组&#xff0c;当一个数组中的元素是数组时叫做二维数组&#x…

公网环境下如何端口映射?

公网端口映射是一种网络技术&#xff0c;它允许将本地网络中的设备暴露在公共互联网上&#xff0c;以便能够从任何地方访问这些设备。通过公网端口映射&#xff0c;用户可以通过互联网直接访问和控制局域网中的设备&#xff0c;而无需在本地网络中进行复杂的配置。 公网端口映射…

自动驾驶---Motion Planning之STSC轨迹优化

1 背景 在之前的博客《自动驾驶---Motion Planning之构建SLT Driving Corridor》中,为读者讲解了SLT图构建的思路---通过构建Driving Corridor的方式确定SL两个方向的boundary。但是并没有去详细讲解如何去构造优化问题,以及如何去生成最终的轨迹,所以本篇博客将继续为读者讲…

如果用大模型考公,kimi、通义千问谁能考高分?

都说大模型要超越人类了&#xff0c;今天就试试让kimi和通义千问做公务员考试题目&#xff0c;谁能考高分&#xff1f; 测评结果再次让人震惊&#xff01; 问题提干&#xff1a;大小两种规格的盒装鸡蛋&#xff0c;大盒装23个&#xff0c;小盒装16个&#xff0c;采购员小王买了…

libVLC 音频立体声模式切换

在libVLC中&#xff0c;可以使用libvlc_audio_set_channel函数来设置音频的立体声模式。这个函数允许选择不同的音频通道&#xff0c;例如立体声、左声道、右声道、环绕声等。 /*** Set current audio channel.** \param p_mi media player* \param channel the audio channel…