AI菜鸟向前飞 — LangChain系列之十四 - Agent系列:从现象看机制(上篇)

上一篇介绍了Agent与LangGraph的基础技能Tool的必知必会

AI菜鸟向前飞 — LangChain系列之十三 - 关于Tool的必知必会

前面已经详细介绍了Promp、RAG,终于来到Agent系列(别急后面还有LangGraph),大家可以先看下这张图:    看完我这系列就都懂了:)

图片

牛刀初试

    由于本篇是入门,我们直接边看程序边熟悉整个过程吧 先以BaseTool的方式实现一个Tool,代码如下:

class search_article(BaseTool):
    name = "search_article"
    description = "查询所有的文章来源"
    def _run(self, topic: str):
        return chain_rag.invoke({"question": topic})

关于chain_rag的内容,请参考我的这篇公众号文章

LangChain实战技巧之二:RunnablePassthrough.assign的两则妙用

我们看看两种Agent的“书写”方式

  • 第一种

agent = (
    RunnablePassthrough.assign(agent_scratchpad=lambda x: format_to_tool_messages(x["intermediate_steps"])
    )
    | hub.pull("hwchase17/openai-tools-agent")
    | model.bind_tools(tools=[search_article()])
    | ToolsAgentOutputParser()
)
  • 第二种

agent = create_tool_calling_agent(prompt=hub.pull("hwchase17/openai-tools-agent"), llm=model, tools=[search_article()])

你喜欢哪种呢?

接下来你是不是想执行看看效果,结果会让你大跌眼镜、你没有眼镜的话配一个 先~

res = agent.invoke({"input": "AI菜鸟向前飞系列文章出自哪里?", "intermediate_steps": []})

这里为什么要加这个"intermediate_steps",不加会报错,不信你试试,若要知道这个机制请看下篇:)

输出结果

# 输出了这样一坨
[ToolAgentAction(tool='search_article', tool_input={'topic': 'AI菜鸟向前飞'}, log="\nInvoking: `search_article` with `{'topic': 'AI菜鸟向前飞'}`\n\n\n", message_log=[AIMessage(content='', additional_kwargs={'documents': None, 'citations': None, 'search_results': None, 'search_queries': None, 'is_search_required': None, 'generation_id': 'd12bfa56-e394-48a0-bff1-97f76dabe92f', 'tool_calls': [{'id': '5617aa7b3ed74d1789befac4b6a9d573', 'function': {'name': 'search_article', 'arguments': '{"topic": "AI\\u83dc\\u9e1f\\u5411\\u524d\\u98de"}'}, 'type': 'function'}], 'token_count': {'output_tokens': 12}}, response_metadata={'documents': None, 'citations': None, 'search_results': None, 'search_queries': None, 'is_search_required': None, 'generation_id': 'd12bfa56-e394-48a0-bff1-97f76dabe92f', 'tool_calls': [{'id': '5617aa7b3ed74d1789befac4b6a9d573', 'function': {'name': 'search_article', 'arguments': '{"topic": "AI\\u83dc\\u9e1f\\u5411\\u524d\\u98de"}'}, 'type': 'function'}], 'token_count': {'output_tokens': 12}}, id='run-592cded4-3fb7-48d3-99d7-87166d7bb232-0', tool_calls=[{'name': 'search_article', 'args': {'topic': 'AI菜鸟向前飞'}, 'id': '092624d480bd461daacc54fdda64c7b5'}])], tool_call_id='092624d480bd461daacc54fdda64c7b5')]

直截了当看结果

    通常的教法,应该是你需要引入AgentExecutor,而如果我也是这样跟大家介绍的话,就不是我这个系列的风格了:)

    如果用AgentExecutor的话,代码如下:

agent_executor = AgentExecutor(agent=agent, tools=[search_article()], verbose=True)
# 然后再invoke就能得到你想要的
agent_executor.invoke("AI菜鸟向前飞系列文章出自哪里?")

    直截了当

{'input': 'AI菜鸟向前飞系列文章出自哪里?', 'output': 'AI菜鸟向前飞系列文章出自Song榆钱儿的公众号。'}

(换个方式)直奔Agent

    但是跑题了,我们主要讲的是Agent,而不是AgentExecutor,也就是说如果仅用Agent呢?

    看到输出内容

[ToolAgentAction(tool='search_article', tool_input={'topic': 'AI菜鸟向前飞'}, ……

    聪明的小伙伴可以用Python去解决问题,如下:

# 为啥这里要用这个,因为它是列表啊,为啥是列表,以后再介绍
for each in res:
    result = {"search_article": search_article()}[each.tool].invoke(each.tool_input)
    print(result)

    最后它确实被执行,结果如下:

content='AI菜鸟向前飞系列文章是出自公众号"Song榆钱儿"的原创作品。截至目前,该系列已经有20多篇原创文章,并且拥有109名关注者。' additional_kwargs={'documents': None, 'citations': None, 'search_results': None, 'search_queries': None, 'is_search_required': None, 'generation_id': 'f12940a2-38de-4bba-a7b0-254f40c90596', 'token_count': {'input_tokens': 156, 'output_tokens': 44}} response_metadata={'documents': None, 'citations': None, 'search_results': None, 'search_queries': None, 'is_search_required': None, 'generation_id': 'f12940a2-38de-4bba-a7b0-254f40c90596', 'token_count': {'input_tokens': 156, 'output_tokens': 44}} id='run-f7cc290b-34f8-4eca-bcfa-85c3bcf2b74e-0'

也就是都是RAG的“功劳”,上面代码提到的:

………………
return chain_rag.invoke({"question": topic})

柳暗花明

    各位看官会想,这跟我单独执行Tool函数有啥区别,绕了一个大圈子,这秘密就存在于"intermediate_steps"当中(卖个关子,后面介绍)先看如下代码:

intermediate_steps = []
while not isinstance(
    res := agent.invoke({"input": "AI菜鸟向前飞系列文章出自哪里?", "intermediate_steps": intermediate_steps}), AgentFinish):

    for each in res:
        func_ret = {"search_article": search_article()}[each.tool].invoke(each.tool_input)
        intermediate_steps.append((each, func_ret.content))

    是不是感觉跟用AgentExecutor一样了:)

简述ReAct

    最后分享一个聊到Agent 大部分博文都会提到的ReAct (Reason Act),以一个示例来演示下吧,各处重要内容,我都加上了注释来为大家解释:)

> Entering new AgentExecutor chain...
# 思考
Thought: I can answer this question by searching for the source of the "AI菜鸟向前飞" series.

# 行动
Action: search_article
Action Input: AI菜鸟向前飞

# 观察
Observation content='AI菜鸟向前飞系列文章是出自Song榆钱儿的公众号。该系列文章目前已经有20多篇原创文章,并且已有109人关注。' additional_kwargs={'documents': None, 'citations': None, 'search_results': None, 'search_queries': None, 'is_search_required': None, 'generation_id': 'e07bf920-967a-4269-bae0-6acd4358a90f', 'token_count': {'input_tokens': 158, 'output_tokens': 38}} response_metadata={'documents': None, 'citations': None, 'search_results': None, 'search_queries': None, 'is_search_required': None, 'generation_id': 'e07bf920-967a-4269-bae0-6acd4358a90f', 'token_count': {'input_tokens': 158, 'output_tokens': 38}} id='run-efd02271-a86f-4dee-bd0e-0e9133efd7b7-0'
# 找到正解
Final Answer: AI菜鸟向前飞系列文章出自Song榆钱儿的公众号。该系列文章目前已经有20多篇原创文章,并且已有109人关注。

> Finished chain.
{'input': 'AI菜鸟向前飞系列文章出自哪里?', 'output': 'AI菜鸟向前飞系列文章出自Song榆钱儿的公众号。该系列文章目前已经有20多篇原创文章,并且已有109人关注。'}

原理过程图:关于这张图,后面若大家有需要我再详细深入讲解

图片

敬请期待下一篇:)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网络模型-路由策略

一、路由策略 路由策略(Routing Policy)作用于路由,主要实现了路由过滤和路由属性设置等功能,它通过改变路由属性(包括可达性)来改变网络流量所经过的路径。目的:设备在发布、接收和引入路由信息时,根据实际组网需要实施一些策略&#xff0c…

C++:关联容器及综合运用:

关联容器和顺序容器有着根本的不同:关联容器中的元素是按关键字来保存和访问的,而顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的。关联容器因此相比与顺序容器支持高效的关键字查找和访问。 其底层数据结构:顺序关联容器 ->红黑树,插入…

Redis离线安装(单机)

目录 1-环境准备1-1下载redis-4.0.11.tar.gz1-2gcc环境 2-上传解压3-编译安装(需要gcc环境)4-配置redis5-启动Redis6-开启防火墙(root)7-添加开机启动脚本8-设置权限9-设置开机启动10-测试redis服务11-检查是否安装成功12-创建redis命令软连接13-测试redis14-必要时设置防火墙 …

禅道密码正确但是登录异常处理

禅道密码正确,但是登录提示密码错误的异常处理 排查内容 # 1、服务器异常,存储空间、数据库异常 # 2、服务异常,文件丢失等异常问题定位 # 1、df -h 排查服务器存储空间 # 2、根据my.php排查数据库连接是否正常 # 3、修改my.pho,debugtrue…

外企也半夜发布上线吗?

0 别把问题想得太复杂 如果有灰度发布的能力,最好白天发布;如果没有灰度发布,只能在半夜发布。 即使有灰度发布能力,也不要沾沾自喜,好好反思一下你们的灰度发布是否真的经得起考验,还是仅仅是装装样子。…

区块链技术和应用二

前言 学习长安链的一些基本原理 官网:长安链开源文档 b站课程:区块链基础与应用 一、共识算法 1.1 POW工作量证明 最长链共识,没听明白 1.2 51%攻击 二、区块链的发展 2.1 区块链1.0到3.0 2.2 共有链、联盟链、私有链 2.3 发展趋势 2.4 扩…

Spring Boot Interceptor(拦截器使用及原理)

之前的博客中讲解了关于 Spring AOP的思想和原理,而实际开发中Spring Boot对于AOP的思想的具体实现就是Spring Boot Interceptor。在 Spring Boot 应用程序开发中,拦截器(Interceptor)是一个非常有用的工具。它允许我们在 HTTP 请…

Unity修改Project下的Assets的子文件的图标

Unity修改文件夹的图标 示例: 在右键可以创建指定文件夹。 github链接 https://github.com/SeaeeesSan/SimpleFolderIconCSDN资源的链接 https://download.csdn.net/download/GoodCooking/89347361 去GitHub下载支持原作者哦。重要的事情 截图来自GitHub 。 U…

文件编码格式查看和转换

1、查看文件编码格式 记事本:打开文件后,点击“文件”--“另存为”,可查看文件的编码格式。**Notepad**:打开文件后,即可在右下角查看文件的编码格式。vim:打开文件后,输入“:set fileencoding…

网络安全基础技术扫盲篇 — 名词解释

网络模块基础(网络拓扑图、网络设备、安全设备) 用通俗易懂的话说: 网络拓扑图:它就像一张网络世界的地图,它展现了我们数不清的网站、服务器和设备是如何相互连接的。用简单的话说,它就是给我们指路、告…

人工智能 框架 paddlepaddle 飞桨 使用指南 使用例子 线性回归模型demo 详解

安装过程&使用指南&线性回归模型 使用例子 本来预想 是安装 到 conda 版本的 11.7的 但是电脑没有gpu 所以 安装过程稍有变动,下面简单讲下 conda create -n paddle_env117 python=3.9 由于想安装11.7版本 py 是3.9 所以虚拟环境名称也是 paddle_env117 activa…

C语言 | Leetcode C语言题解之第111题二叉树的最小深度

题目: 题解: typedef struct {int val;struct TreeNode *node;struct queNode *next; } queNode;void init(queNode **p, int val, struct TreeNode *node) {(*p) (queNode *)malloc(sizeof(queNode));(*p)->val val;(*p)->node node;(*p)->…

【pyspark速成专家】7_SparkSQL编程1

目录 一,RDD,DataFrame和DataSet对比 二,创建DataFrame 本节将介绍SparkSQL编程基本概念和基本用法。 不同于RDD编程的命令式编程范式,SparkSQL编程是一种声明式编程范式,我们可以通过SQL语句或者调用DataFrame的相…

编程实现标题栏窗口摇动——显示桌面的未公开细节研究

目录 前言 一、“窗口摇动”功能内部原理 二、explorer.exe 中的 “窗口抖动” 实现 三、“切换到桌面” 功能所扩展的内部细节 四、概念验证 五、进一步研究如何自定义保留窗口列表 原文出处链接:[https://blog.csdn.net/qq_59075481/article/details/139204…

ELK 日志监控平台(二)- 优化日志格式

文章目录 ELK 日志监控平台(二)- 优化日志格式1.日志输出要点2.优化应用的日志格式2.1.确定日志输出要点来源2.1.1.服务名称2.1.2.服务环境2.1.3.日志级别2.1.4.日志输出时间2.1.5.日志内容2.1.6.日志输出对象2.1.7.线程名称 2.2.logback.xml修改日志输出…

win10安装rabbitmq

安装 第一步:下载并安装erlang RabbitMQ服务端代码是使用并发式语言Erlang编写,因此首先需要安装Erlang下载地址:http://www.erlang.org/downloads采用默认安装即可,选择适合的安装路径 添加环境变量 第二步:下载并…

【DevOps】深入了解RabbitMQ:AMQP协议基础、消息队列工作原理和应用场景

目录 一、核心功能 二、优势 三、核心概念 四、工作原理 五、交换机类型 六、消息确认 七、持久性和可靠性 八、插件和扩展 九、集群和镜像队列 十、客户端库 十一、管理界面 十二、应用场景 RabbitMQ是一个基于AMQP协议的消息队列中间件,提供高可用、可…

【数据结构与算法 刷题系列】移除链表元素

💓 博客主页:倔强的石头的CSDN主页 📝Gitee主页:倔强的石头的gitee主页 ⏩ 文章专栏:数据结构与算法刷题系列(C语言) 期待您的关注 目录 一、问题描述 二、解题思路 三、源代码实现 一、问题…

Qt for android 获取USB设备列表(二)JNI方式 获取

简介 基于上篇 [Qt for android 获取USB设备列表(一)Java方式 获取], 这篇就纯粹多了, 直接将上篇代码转换成JNI方式即可。即所有的设备连接与上篇一致。 (https://listentome.blog.csdn.net/article/details/139205850) 关键代码…