博客配套代码发布于github:05 LangChain 进阶
相关Agent专栏:Ai Agent教学
本系列所有博客均配套Gihub开源代码,开箱即用,仅需配置API_KEY。
如果该Agent教学系列帮到了你,欢迎给我个Star⭐,非常感谢!
知识点:Agent 构建 (ReAct & Tool-Calling)|特化 Agent (create_sql_agent)|Agent 与 Memory 融合|高阶技巧 (缓存 & 流式)
上篇文章我们已经把llm、prompt、chain、memory四大模块啃了下来。但这时的它还有点笨:不会调用工具函数来工作。所以本篇我们就要聚焦于此——为它接入这个手:Agents。
(注:这两个概念务必不要弄混。Agent是ai界通用的对智能体的表达;而这里的Agents则是Langchain中的核心模块,代指Function callings,函数调用的思想)
除了主要讲述的Agents外,本篇还会加入一些Langchain的高阶技巧,进一步提升agent的灵活性。
其实在我们之前的文章[Ai Agent] 03 Function Calling实战:让AI真正“调用工具”完成任务中,我们就已经手动造过轮子了,知道其原理与过程。Langchain的Agents模块的思路大体也是一致的,只是使用方法变更了下。
在开始学习Agents之前,我们需要先了解下俩Agents的关键零件:
1. 零件一:ReAct循环——agent的大脑
ReAct=Reason(推理/思考)+Action(行动)
这就是Agent内部思考的逻辑循环:
思考:LLM分析任务(我要查看天气)
行动:调用find_weather函数
观察:Langchain自动调用该工具函数并返回数据
思考:LLM观察到结果,并思考(我已经拿到数据,可以回答用户了)
行动:回复用户今天天气。
如果你想真正看到这个流程,推荐输出时,带上verbose=True,来看看ai内部的思考过程。
2. 零件二:工具——@tool
Agent的手和脚,用以定义Agent能做什么。
Langchain为我们封装了一个@tool装饰器,可以一键将任意Python函数封装为Agent可用的工具。
我们接下来用一段自定义代码感受下:
这里有些关键点要注意一下:
当用@tool封装某个函数作为工具时,必须要用”””xx”””来为其添加描述信息。
这段描述信息可不是注释,而是这个工具的“提示词”。如果你不为它添加该提示词就为直接报错。
添加完后,llm就会根据该提示词来判断是否应该调用这个工具。
成功打印后,我们接下来让llm真正调用这个工具。
当我们构建一个涵盖Agents(工具调用)模块的智能体时,我们就必须借助一些新的创建agent的函数了。create_xx_agent有几个不同的函数,这里我们只拿出两个最为常用的来讲。
create_tool_calling_agent:它返回结构化的tool_calls请求,最稳定并且准确。
组成顺序:
1. LLM 2. Prompt 3. Tools(工具列表)
4. create_tool_calling_agent:把上面三个组装成agent(大脑)
5. AgentExecutor:Agent的执行器(身体),负责真正运行ReAct循环。
当使用create_tool_calling_agent时,必须加上这行MessagePlaceholder(varibale_name=”agent_scratchpad”),它代表一个临时记事本,会记录整个ReAct流程(思考-动作-观察),并将整个思考过程再让llm看到,从而做出下步决策。
tools配置也跟之前差不多,这里重点要记一下agent与agent_executor的创建流程:
此处verbose=True即代表输出思考链。
整个输出流程就是:
llm — prompt — tools — create_tool_calling_agent — AgentExecutor
哎,你看这个agent = create_tool_calling_agent(llm=llm,prompt=prompt,tools=tools)
有没有感觉它很像当初的chain=prompt | llm | parser?但为什么这里甚至都没有用到chain?
因为这个重要模块已经被封装进create_tool_calling_agent里面了。
这个函数将Chain作为内部推理的核心环节,并在此基础上构建了一个支持记忆、工具调用和循环决策的智能体框架。
之前因为我们还不需要用到这个函数来使用Tools,所以当涉及Chain这个概念时还需要造下轮子,学下它怎么使用。
所以之后虽然我们不会再显式创建Chain,但实际上我们仍在沿用这种思想,这点可别忘掉。
输出结果:
![[Ai Agent] 05 LangChain Agents 实战:从 ReAct 到带记忆的流式智能体](https://javaforall.net/wp-content/uploads/2020/11/2020110817443450.jpg)
输出成功。
这种通用Agent我们了解了,可以自由根据场景选择来自己DIY工具调用,是一个可扩展Agent框架。它足以应付我们绝大场景下的工具使用。但也有些场景用它来,得干很多脏活累活。这点Langchain也想到了,接下来介绍另一个特化Agent。
领域专用 Agent 的封装要求极高:需场景广泛、接口标准、结构清晰。正因如此,真正合适的案例极少。
而 SQL 查询正是这样的完美范例。
它高频、规范、结构明确,却重复繁琐。如果每次都手动构建工具链,效率将非常差。
正是为此而生——开箱即用,一键实现自然语言查数据库,大幅简化开发流程。
- 你不需要手动定义tools,只用给它一个db连接
- 它会自动“反思”:先查表结构,再编写sql,执行sql,再根据结果回答
- 它的Prompt已经高度优化,能处理复杂的SQL逻辑。
代码编写如下:
可以看出,我们仅配置了llm与db,其他啥都没干,就做好了sql_agent。
再来看看执行结果:
![[Ai Agent] 05 LangChain Agents 实战:从 ReAct 到带记忆的流式智能体](https://javaforall.net/wp-content/uploads/2020/11/2020110817443450.jpg)
![[Ai Agent] 05 LangChain Agents 实战:从 ReAct 到带记忆的流式智能体](https://javaforall.net/wp-content/uploads/2020/11/2020110817443450.jpg)
AI先是思考:我要查sql,再去表里编写对应sql语句。获得对应数据后,就会将查询结果输出。
我们05的Agent很智能,我们04的Chain有记忆。现在我们把二者合二为一,让它变得更高级。
就拿本模块的第二章的通用Agent为例,我们接着为其加入记忆功能。
prompt这里就是俩占位符都需要,分别作为记忆与工具查询使用。
tool配置如常。
到最终memory的位置,就由它来包裹所有其他的部件,当做一个长期存在的状态:
测试结果:
![[Ai Agent] 05 LangChain Agents 实战:从 ReAct 到带记忆的流式智能体](https://javaforall.net/wp-content/uploads/2020/11/2020110817443450.jpg)
很明显,此时的agent已经可以工具调用与持续记忆。
至此我们的Agents(工具调用代理)的知识点已基本掌握完毕。
我们所做的agent现在看起来已经非常不错了,但真正放到生产端还有俩致命问题:
其一、贵:每次运行invoke都在烧钱;
其二、慢:用户每次运行都必须等整个ReAct跑完才能得到想要的答案。
下面我们依次来解决这俩问题:
1. 缓存
想象这么个场景:
你写好了一个比较复杂的项目Agent,有七八个重要组件,你需要确定它们都能成功运行。于是你开始调试,调试了二三十次,确定满意没有问题了。接着一看llm的token调用:也花了二三十次的token钱…
所以我们就要引入缓存这个概念:简单讲就是跳过llm调用这一环节,优先保证其他所有模块测试没啥问题。等其他都完毕后再去掉缓存测试一遍llm调用,这样只用花费一次token调用的钱。
所以在开发测试时强烈推荐加入该功能。但真正在生产端环境必须去掉:毕竟它只是回答结果复用,没有任何智能。
使用方法也简单:
# 设置全局缓存
set_llm_cache(InMemoryCache())
![[Ai Agent] 05 LangChain Agents 实战:从 ReAct 到带记忆的流式智能体](https://javaforall.net/wp-content/uploads/2020/11/2020110817443450.jpg)
如上,当缓存命中时几乎不费时,而且也不会调用token花钱。
但如果文件项目比较大时,这样一行的内存缓存还是有点不够用,推荐上个文件或者redis缓存。
2.流式
回想一下,当你在网页端用ai工具时,是否它们输出都是一点点排列给你看的?这就是流式输出,像流水一样。
而我们目前的输出必须得全部跑完才能返回看到答案,这明显不是我们想要的,接下来我们就为其加入流式输出:
这里llm注意下llm的配置:
streaming=True:即允许流式输出;
callback=[StreamingStdOutCallbackHandler()]:一个回调处理器,当LLM每生成一个token时,自动将其打印到终端上。
其他代码不用动,最后循环时稍微改一下:
这里已经不需要print了,因为我们之前搞callbacks已经做到生成token时自动打印到终端上。再print也只是重复输出。
Agent 智能体
同时之前我们的AI: 就需要单独列出来写一下,不能直接跟response一块输出了。
![[Ai Agent] 05 LangChain Agents 实战:从 ReAct 到带记忆的流式智能体](https://javaforall.net/wp-content/uploads/2020/11/2020110817443450.jpg)
如图,流式输出成功。
六、总结
知识点概括:Agent 构建 (ReAct & Tool-Calling)|特化 Agent (create_sql_agent)|Agent 与 Memory 融合|高阶技巧 (缓存 & 流式)
如果你能看到这里,那你真的很厉害了!
至此你已掌握了Langchain的核心交互能力:从LLM调用、Prompt设计、链式编排、记忆管理到Agent决策与工具调用。这些技能足够你构建一个能“动”起来的智能体。
那么接下来就是另一个重头戏了:RAG
这玩意儿也是个狠角。当我们想将海量文档、数据库、知识库与 LLM 结合,打造真正可用的企业级智能系统时,就必须引入这个模块的思想来做。
它的知识点与实战同样繁琐,但笔者仍会将其庖丁解牛式将其细分拆开,确保讲解透彻到位。收拾收拾,下篇进RAG接着干!
🚀一键跳转:
📌 项目代码 + 后续案例合集 全部发布在 Github 仓库 agent-craft ,持续更新中,欢迎Star⭐!
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/243391.html原文链接:https://javaforall.net
