大模型agent开发之chains

 

新版langchain中已经弃用了LLMChain等内置链的组装和框架,取而代之的是使用 runables包中内置的类和方法 来构建更灵活的链,其中最主要的方法是RunablesSequence,RunnableLambda和RunnableMap。

一:RunnablesSenquence

RunnablesSenquence可以直接实例化,更常用的方式是使用|运算符实例化,其中左操作数或右操作数(或两者)必须是 Runnable,任何 RunnableSequence 都会自动支持同步、异步、批处理。batch 和 abatch 的默认实现利用线程池和 asyncio 收集,并且比对 IO 绑定 Runnable 的invoke 或 ainvoke 的简单调用更快。通过按顺序调用 RunnableSequence 的每个组件上的 batch 方法来实现批处理。RunnableSequence 保留其组件的流式传输属性,因此如果序列的所有组件都实现了转换方法(即实现将流式传输输入映射到流式传输输出的逻辑的方法),那么序列将能够将输入流式传输到输出!如果序列的任何组件未实现转换,则只有在运行此组件后才会开始流式传输。如果有多个阻塞组件,则流式传输将在最后一个组件之后开始。

二:RunnableLambda

RunnableLambda将 Python 可调用函数转换为 Runnable。将可调用函数包装在 RunnableLambda 中可使可调用函数在同步或异步上下文中可用。RunnableLambda 可以像任何其他 Runnable 一样组合,并提供与 LangChain 跟踪的无缝集成。RunnableLambda不支持流式传输代码,如果要传输流式数据代码需要使用RunnableGenerator。

三: RunnableMap

 RunnableMap是RunnableParallel 的别名,RunnableParallel 是 LCEL 的两个主要组合原语之一,与 RunnableSequence 并列。它同时调用 Runnable,为每个 Runnable 提供相同的输入。RunnableParallel 可以直接实例化,也可以通过使用序列中的字典文字来实例化。

通过对RunnableLambda和RunnableMap的组合使用可以实现大模型顺序链式模块的功能。

复制代码
    # 顺序链
    def seq_chain(self):
        # 链一任务:翻译成中文
        first_chain = RunnableLambda(
            lambda content: self.llm.invoke(str(self.prompt[0].invoke(content))),
            afunc=lambda content: self.llm.ainvoke(str(self.prompt[0].invoke(content)))  # 如果需要异步支持
        )

        # 链二任务:对翻译的中文进行总结
        second_chain = RunnableLambda(
            lambda chinese_review: self.llm.invoke(str(self.prompt[1].invoke(chinese_review))),
            afunc=lambda chinese_review: self.llm.ainvoke(str(self.prompt[1].invoke(chinese_review)))
        )

        # 链三任务:智能识别语言
        third_chain = RunnableLambda(
            lambda summary: self.llm.invoke(str(self.prompt[2].invoke(summary))),
            afunc=lambda summary: self.llm.ainvoke(str(self.prompt[2].invoke(summary)))
        )

        # 链四任务:针对摘要使用语言进行评论
        four_chain = RunnableLambda(
            lambda language: self.llm.invoke(str(self.prompt[3].invoke(language))),
            afunc=lambda language: self.llm.ainvoke(str(self.prompt[3].invoke(language)))
        )

        # 使用 RunnableMap 来串联所有任务
        overall_chain = RunnableMap(
            {
                "Chinese_Rview": first_chain,
                "Chinese_Summary": second_chain,
                "Language": third_chain,
                "Reply": four_chain
            }
        )

        # 读取文件
        content = self.question

        # 依次调用各个链
        ans = overall_chain.invoke(content)
        print(f"chains answer: {ans}")

        return ans
复制代码

每个链都使用 RunnableLambda 来定义其执行逻辑。输入被传递给下一个链的输入。所有的 RunnableLambda 被组合在 RunnableMap 中,这样可以按照顺序执行,并且方便管理每个链的输出。

通过对RunnableLambda的使用可以实现路由链,设置俩种完全不同的提示词模版,根据问题的不同,使其可以路由到对应的链中,从而返回准确的答案。

复制代码
        # 路由链
    def route_chain(self):
        # 模版格式化
        prompt_infos = [
            {
                "name": "economy",
                "description": "Good at answering economic questions",
                "prompt_template": self.prompt[0],
            },
            {
                "name": "zhouyi",
                "description": "Good at fortune telling",
                "prompt_template": self.prompt[1],
            },
        ]

        # 创建提示链
        description_chains = {}
        for p_info in prompt_infos:
            name = p_info["name"]
            prompt_template = p_info["prompt_template"]
            prompt = PromptTemplate(template=prompt_template, input_variables=["input"])

            # 使用 RunnableLambda 创建每个提示链
            chain = RunnableLambda(lambda input_value: self.llm.invoke(str(prompt.invoke(input_value))))
            description_chains[name] = chain

        # 使用 Router 模板生成路由提示
        destinations = [f"{p['name']}: {p['description']}" for p in prompt_infos]
        destinations_str = "\n".join(destinations)
        router_template = MULTI_PROMPT_ROUTER_TEMPLATE.format(destinations=destinations_str)
        router_prompt = PromptTemplate(template=router_template, input_variables=["input"])

        # 创建路由链
        router_chain = RunnableLambda(lambda input_value: self.llm.invoke(str(router_prompt.invoke(input_value))))

        # 创建默认链
        default_chain = RunnableLambda(lambda input_value: self.llm.invoke(str(input_value)))  # 假设默认链是直接调用 LLM

        # 创建 MultiPromptChain
        chains = RunnableLambda(
            lambda input_value: (
                description_chains.get(self.route(input_value), router_chain).invoke(input_value)
            ),
            afunc=lambda input_value: (
                description_chains.get(self.route(input_value), default_chain).invoke(input_value)
            )
        )

        # 运行链
        ans = chains.invoke(self.question)
        print(f"chains answer: {ans}")

    def route(self, input_value):
        # 示例路由逻辑
        if "economics" in input_value:
            return "economy"
        elif "zhouyi" in input_value:
            return "zhouyi"
        else:
            return None  # 或者返回默认链的名称
复制代码

self.route(input_value) 来决定将输入内容发送到哪个链中,这里self.route(input_value) 返回的字符串将用于查找 description_chains 字典中的相应链。如果没有找到,就会使用 default_chain 作为备选处理。

posted @   我刀呢?  阅读(39)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
历史上的今天:
2020-10-28 作业要求 20201022-1 每周例行报告
点击右上角即可分享
微信分享提示