LangChain(八)构建多Agent的AI系统-实战!

系列文章目录

LangChain(二)基础问答大模型,纯新手向-CSDN博客

LangChain(三)基础问答大模型,从LLMchain开始了解chain!纯新手向-CSDN博客

LangChain(四)工具调用的底层原理!给大模型按上双手吧!(新手向)-CSDN博客

LangChain(五)工具调用的底层原理进阶!依旧纯新手向~-CSDN博客

LangChain(六)LLMRouteChain的基本原理和构建方式-新手向-CSDN博客

LangChain(七)让大模型拥有记忆!新手向_chatprompttemplate是什么-CSDN博客


前言

好久没有更新LangChian系列的文章了,最近一直在给我们的项目进行集成工作。代码集成、系统优化、多线程操作等等……交给一个算法工程师真的好吗……不得已恶补了一下这方面的知识,写了很多有关于系统集成、代码规范、多线程编程方面的文章。时至今日终于告一段落……

针对项目中实际编写的有关多链路由多Agent的模块,总结后也有了一些心得体悟,遂有此文。

预备知识

在阅读本文之前,需要有一些预备知识,如下:

  • 基础问答大模型的开发(基础的聊天机器人构建能力) 

LangChain(二)基础问答大模型,纯新手向-CSDN博客

  • 大模型工具调用的方法(大模型如何调用函数工具的能力)

LangChain(四)工具调用的底层原理!给大模型按上双手吧!(新手向)-CSDN博客

LangChain(五)工具调用的底层原理进阶!依旧纯新手向~-CSDN博客

  • 路由链的构建原理(多Agent的选择路由模块的构建能力)

 LangChain(六)LLMRouteChain的基本原理和构建方式-新手向-CSDN博客

实战详解!

项目背景与需求

本项目是旨在实现某个垂直领域专业操作的同时满足水平领域横展聊天问答的功能……

用人话说就是,既要大模型有工具调用能力,还要大模型和你聊天……

思考过程

显然,这需要三个Agent来完成任务,

  • 一个Agent用于工具调用,
  • 一个Agent用于聊天。
  • 以及最后一个Agent用以把问题具体路由到上面的哪一个Agent

此处可能会有人想,为什么不能在一个Agent内完成任务呢?在prompt中设定不就好了?

例如:

'''你是一个人工智能助手,当你判断用户在和你聊天的时候你和用户聊天,回复语以“chat”开头。当你判断用户想要操作***的时候,你需要调用工具,工具的描述:{ai_tools.rendered_tools},此时Return your response as a JSON blob with 'name' and 'arguments' keys.'''

实际上,上诉方案看似可行,然而在实际操作中会存在很多很多错误,大模型会经常搞不清楚自己的返回,因为上面的prompt太复杂。且关于返回的格式有两种,会给大模型产生混淆。所以在实际操作过程中,效果很差。

注意:prompt的原则是简短而精准

step1:大模型的构建

当然,第一步,也是最基础的一部,就是先构建llm聊天大模型,此处没啥好说的。亮出代码即可

from langchain_community.llms import QianfanLLMEndpoint
import os

# 设定百度千帆大模型的AK和SK
os.environ["QIANFAN_AK"] = "your_AK"
os.environ["QIANFAN_SK"] = "your_SK"

# 创建千帆LLM模型
llm = QianfanLLMEndpoint()

step2:工具函数的编写

此处,基于我实际的项目经验,所有相关的调用函数,最好统一构建为一个python文件。

此处我构建了一个新的python文件:“ai_tools.py”。由于项目的保密性,我在此虚构几个函数。

from langchain.tools.render import render_text_description
from langchain_core.tools import tool

'''
step1: 构建工具调用的工具函数
'''

@tool
def kick_your_ass(power: int = 1):
    '''
    踢用户的屁股

    参数:
        power->int:用以描述踢的力气
    '''
    # some funtion……
    return True
        
@tool
def kiss_your_ass(power: int = 1):
    '''
    亲用户的屁股

    参数:
        power->int:用以描述亲的力气
    '''
    # some funtion……
    return True

@tool
def kick_your_face(power: int = 1):
    '''
    踢用户的脸

    参数:
        power->int:用以描述踢的力气
    '''
    # some funtion……
    return True

@tool
def kiss_your_face(power: int = 1):
    '''
    亲用户的脸

    参数:
        power->int:用以描述亲的力气
    '''
    # some funtion……
    return True

'''
step2:构建工具集合和工具描述
'''
tools =[
    kick_your_ass,
    kiss_your_ass,
    kiss_your_face, 
    kick_your_face
]

tool_map = {tool.name: tool for tool in tools}

# 构建工具条件和调用描述
rendered_tools = render_text_description(tools)


'''
step3:构建工具调用路由函数
'''
def tools_call(model_output):
    chosen_tool = tool_map[model_output["name"]]
    return chosen_tool.invoke(model_output["arguments"])
   

注意:所有有关于工具相关的函数都应该写在此处,保持良好的代码习惯……

step3:工具调用Agent和聊天Agent的撰写!

链的构建!

chat_chain = PromptTemplate.from_template(
    """你是一个聊天陪聊机器人,你的名字叫:小黑。
你的编写者是***,你需要使用中文并以谦卑尊敬的态度对用户的输入进行回复。
Always answer questions starting with "阿巴阿巴". \
Respond to the following question:

Question: {question}
Answer:"""
) | llm

tools_call_chain = (
    ChatPromptTemplate.from_messages(
        [
            ("system", f"""You are an assistant that has access to the following set of tools. Here are the names and descriptions for each tool:

{ai_tools.rendered_tools}

Given the user input, return the name and input of the tool to use. 
用户若没有给你具体的参数,则使用默认参数。
Return your response as a JSON blob with 'name' and 'arguments' keys."""), 
            ("user", "{question}")
        ]
    ) 
    | llm
    | JsonOutputParser()
    | ai_tools.tools_call
)

有关于中英文混用的问题:

这里需要稍微解释一下。 这个世界上最精确最容易理解的语言是英文,这是公理,所以有关于prompt中,与中文强相关的部分由中文来写,和中文不强相关的部分,尤其是针对回复格式这种需要精确表述的部分,最好使用英文来写。

各位可以看到,两个chain中的系统人设prompt我使用了两种构建方式,一个是使用PromptTemplate,一个是使用ChatPromptTemplate。这里没什么特别的理由,仅仅是复习一下过去的知识。但是对我个人而言,我更喜欢ChatPromptTemplate,更正规,可操作性更大。

注意:第二个tools_call_chain,由于我们返回的是一个json的str格式文本,所以需要JsonOutputParser函数对于返回值进行处理成真正的json格式数据,最后再调用tools_call函数。该函数在上面的工具调用文件中有。

step4:路由Agent的构建

路由Agent最好不要使用langchain官网给的现成链,非常麻烦不说,可扩展性也很差,也很有些莫名其妙的操作方式。

chain = (
    PromptTemplate.from_template("""
根据下面提供的问题输入,将其分类为:`test`或`chat`.
当输入的文本有关于车载仪表符号灯测试的时候,分类为:test
否则,分类为:chat

Return your response as a JSON blob with 'Classification' keys.

<question>
{question}
</question>
"""
    )
    | llm
    | JsonOutputParser()
)

def route(info):
    print("info = ", info)
    try:
        if info["topic"]["Classification"] == "chat":
            print("chat")
            return chat_chain
        elif info["topic"]["Classification"] == "test":
            print("test")
            return tools_call_chain
        else:
            return chat_chain
    except Exception as e:
        print("e = ", e)
        return chat_chain
        
from langchain_core.runnables import RunnableLambda

full_chain = {"topic": chain, "question": lambda x: x["question"]} | RunnableLambda(
    route
)

if __name__ == "__main__":
    print(full_chain.invoke({"question": "你好呀,你叫什么?"}))

详细内容可以移步 LangChain(六)LLMRouteChain的基本原理和构建方式-新手向_langchain llmrouterchain-CSDN博客

有非常详尽的操作思路。

总结

本篇对于多链路由、工具调用、大模型构建方式进行了复习,并给出实战代码!

最合适的函数,不是官网现成的函数,而是你自己搭建的啊

  • 26
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千天夜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值