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人关注。'}

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

图片

敬请期待下一篇:)

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

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

相关文章

leetcode328. 奇偶链表,附详细解析和代码注释

leetcode328. 奇偶链表 给定单链表的头节点 head ,将所有索引为奇数的节点和索引为偶数的节点分别组合在一起,然后返回重新排序的列表。 第一个节点的索引被认为是 奇数 , 第二个节点的索引为 偶数 ,以此类推。 请注意&#xff0…

轻量级 K8S 环境 安装minikube

文章目录 操作系统DockerDocker CE 镜像源站使用官方安装脚本自动安装 (仅适用于公网环境)安装校验Docker代理docker permission denied while trying to connect to the Docker daemon socket minikubekubectl工具minikube dashboard参考资料 操作系统 …

Docker进入容器查看内容并从容器里拷贝文件到宿主机

工作中需要从docker正在运行的镜像中复制文件到宿主机,于是便将这个过程记录了下来。 (1)查看正在运行的容器 通过以下命令,可以查看正在运行的容器: docker ps (2)进入某个容器执行脚本 我…

react中子传父信息

思路是: 在父组件定义一个函数接受参数,接收的参数用于接收子组件的信息,把函数传给子组件,子组件调用父亲传来的函数并把要告诉父亲的话传到函数中,就实现了子传父消息 import { useState } from reactimport { use…

OpenWrt 安装Quagga 支持ospf Bgp等动态路由协议 软路由实测 系列四

1 Quagga 是一个路由软件套件, 提供 OSPFv2,OSPFv3,RIP v1 和 v2,RIPng 和 BGP-4 的实现. 2 web 登录安装 #或者ssh登录安装 opkg install quagga quagga-zebra quagga-bgpd quagga-watchquagga quagga-vtysh # reboot 3 ssh 登录 #重启服务 /etc/init.d/quagga restart #…

使用kubesphere部署微服务的时候,节点的镜像不是最新的导致部署到旧版本问题

我使用kubesphere部署微服务的时候,发现有很多次,我修改了配置文件,但是部署完才发现部署的是旧版本。 然后我查看了该微服务部署在哪个节点上: kubectl get pods --all-namespaces -o wide例如 gulimall-gateway 这个服务&…

韭菜的自我总结

韭菜的自我总结 股市技术面量价关系左侧右侧右侧技术左侧技术洗盘 韭菜的自我修养虚拟货币的启示韭菜的买入时机韭菜的心理压力成为优秀玩家的关键 股市技术面 技术面分析可以作为买卖时机判定的工具,但是投资还是需要基本面的分析作为支撑。也就是基本面选股&…

langchain进阶一:特殊的chain,轻松实现对话,与数据库操作,抽取数据,以及基于本地知识库的问答

特殊的chain langchain中的Chain有很多,能够轻松实现部分需求,极致简化代码,但是实现效果与模型智慧程度有关 会话链 效果与LLMChain大致相同 javascript 复制代码 from langchain.chains import ConversationChain from langchain_community.llms import OpenAI conversat…

Redis 实战 - 缓存异常及解决方案

文章目录 概述一、缓存穿透1.1 缓存穿透是什么1.2 解决方案 二、缓存击穿2.1 缓存击穿是什么2.2 解决方案 三、缓存雪崩3.1 缓存雪崩是什么3.2 解决方案 四、拓展4.1 缓存预热4.2 缓存降级 五、结语 把今天最好的表现当作明天最新的起点…….~ 概述 在实…

LeetCode 第131场双周赛个人题解

100309. 求出出现两次数字的 XOR 值 原题链接 求出出现两次数字的 XOR 值 - 力扣 (LeetCode) 竞赛 思路分析 签到题,一次遍历 AC代码 class Solution:def duplicateNumbersXOR(self, nums: List[int]) -> int:cnt Counter(nums)res 0st set(nums)for x …

【大模型】Spring AI对接ChatGpt使用详解

目录 一、前言 二、spring ai介绍 2.1 什么是Spring AI 2.2 Spring AI 特点 2.3 Spring AI 为开发带来的便利 2.4 Spring AI应用领域 2.4.1 聊天模型 2.4.2 文本到图像模型 2.4.3 音频转文本 2.4.4 嵌入大模型使用 2.4.5 矢量数据库支持 2.4.6 用于数据工程ETL框架 …

2024-05-22 VS2022使用modules

点击 <C 语言编程核心突破> 快速C语言入门 VS2022使用modules 前言一、准备二、使用其一, 用VS installer 安装模块:第二个选项就是, 与你的代码一同编译std模块, 这个非常简单, 但是也有坑. 总结 前言 要解决问题: 使用VS2022开启modules. 想到的思路: 跟着官方文档整…

Java进阶学习笔记19——内部类

1、 内部类&#xff1a; 是类中五大成分之一&#xff08;成员变量、方法、构造函数、内部类、代码块&#xff09;&#xff0c;如果一个类定义在另一个 类的内部&#xff0c;这个类就是内部类。 场景&#xff1a;当一个类的内部&#xff0c;包含了一个完整的事物&#xff0c;且…

Android ART 虚拟机简析

源码基于&#xff1a;Android U 1. prop 名称选项名称heap 变量名称功能 dalvik.vm.heapstartsize MemoryInitialSize initial_heap_size_ 虚拟机在启动时&#xff0c;向系统申请的起始内存 dalvik.vm.heapgrowthlimit HeapGrowthLimit growth_limit_ 应用可使用的 max…

Scikit-Learn朴素贝叶斯

Scikit-Learn朴素贝叶斯 1、朴素贝叶斯1.1、贝叶斯分类1.2、贝叶斯定理1.3、贝叶斯定理的推导1.4、朴素贝叶斯及原理1.5、朴素贝叶斯的优缺点2、Scikit-Learn朴素贝叶斯2.1、Sklearn中的贝叶斯分类器2.2、Scikit-Learn朴素贝叶斯API2.3、Scikit-Learn朴素贝叶斯实践(新闻分类与…

爬山算法的详细介绍

目录 &#x1f349;概述 &#x1f349; 步骤 &#x1f349; 优缺点 &#x1f348;优点 &#x1f348;缺点 &#x1f348;应对策略 &#x1f349;示例 &#x1f348;旅行商问题 &#x1f34d;步骤 &#x1f34d;分解代码 &#x1f34e;包含头文件 &#x1f34e;定义函…

Cortex-M3的SysTick 定时器

目录 概述 1 SysTick 定时器 1.1 SysTick 定时器功能介绍 1.2 SysTick 定时器功能实现 1.3 SysTick在系统中的作用 2 SysTick应用的实例 2.1 建立异常服务例程 2.2 使能异常 2.3 闹钟功能 2.4 重定位向量表 2.5 消灭二次触发 3 SysTick在FreeRTOS中的应用 3.1 STM…

在docker中运行SLAM十四讲程序

《十四讲》的示例程序依赖比较多&#xff0c;而且系统有点旧。可以在容器中运行。 拉取镜像 docker pull ddhogan/slambook:v0.1这个docker对应的github&#xff1a;HomeLH/slambook2-docker 拉下来之后&#xff0c;假如是Windows系统&#xff0c;需要使用XLaunch用于提供X11…

面试大杂烩之kafka

面试这个领域最近环境不行&#xff0c;所以卷起来流量挺大 关于K8s 其实看我之前的博客&#xff0c;k8s刚有点苗头的时候我就研究过&#xff0c;然后工作的时候间接接触 也自己玩过 但是用的不多就忘记了&#xff0c;正苦于不知道写什么&#xff0c;水一篇 用来面试应该是够了…

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

题目&#xff1a; 题解&#xff1a; class Solution { public:int minDepth(TreeNode *root) {if (root nullptr) {return 0;}queue<pair<TreeNode *, int> > que;que.emplace(root, 1);while (!que.empty()) {TreeNode *node que.front().first;int depth que…