一、RunnableLambda:自定义函数加入Chain
普通函数不能直接用 | 加入链,需要用 RunnableLambda 包装(也可直接传入lambda,会自动转换)。
python
from langchain_core.runnables import RunnableLambda
# 函数接收AIMessage,返回dict
my_func = RunnableLambda(lambda ai_msg: {"name": ai_msg.content})
# 直接传lambda也可以,自动转换
chain = first_prompt | model | (lambda ai_msg: {"name": ai_msg.content}) | second_prompt | model | str_parser
两种入链方式 :封装为 RunnableLambda 对象再入链,或直接将函数入链自动转换。函数在链中接收上一个组件的输出,返回值传给下一个组件。可以在链中用自定义函数做数据格式转换、打印调试信息等。
二、Memory临时会话记忆
RunnableWithMessageHistory 在原链基础上创建带历史记录的新链,InMemoryChatMessageHistory 在内存中存储历史。
python
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_core.chat_history import InMemoryChatMessageHistory
store = {}
def get_history(session_id):
if session_id not in store:
store[session_id] = InMemoryChatMessageHistory()
return store[session_id]
conversation_chain = RunnableWithMessageHistory(
base_chain, # 被增强的原链
get_history, # 通过session_id获取历史记录对象
input_messages_key="input", # 用户输入在模板中的占位符名
history_messages_key="chat_history" # 历史记录在模板中的占位符名
)
# 调用时需传入session_id
session_config = {"configurable": {"session_id": "user_001"}}
res = conversation_chain.invoke({"input": "小明有2个猫"}, session_config)
工作流程 :每次调用时根据 session_id 获取该用户的历史记录,把历史填入模板的 chat_history 位置,模型结合历史回答问题,新的问答自动追加到历史中。不同 session_id 的历史互不影响。InMemoryChatMessageHistory 存在内存中,重启程序后消失,适合临时测试。
三、Memory长期会话记忆:FileChatMessageHistory
继承 BaseChatMessageHistory,重写三个方法,以 session_id 为文件名存到本地。
python
from langchain_core.chat_history import BaseChatMessageHistory
class FileChatMessageHistory(BaseChatMessageHistory):
def __init__(self, session_id, storage_path):
self.session_id = session_id
self.file_path = os.path.join(storage_path, session_id)
os.makedirs(os.path.dirname(self.file_path), exist_ok=True)
def add_messages(self, messages):
all_messages = list(self.messages)
all_messages.extend(messages)
new_messages = [message_to_dict(m) for m in all_messages]
with open(self.file_path, "w", encoding="utf-8") as f:
json.dump(new_messages, f)
@property
def messages(self):
try:
with open(self.file_path, encoding="utf-8") as f:
return messages_from_dict(json.load(f))
except FileNotFoundError:
return []
def clear(self):
with open(self.file_path, "w", encoding="utf-8") as f:
json.dump([], f)
只需把 get_history 函数换成 return FileChatMessageHistory(session_id, "./chat_history"),历史记录就能持久化到磁盘文件。@property 装饰器让 messages 方法像属性一样访问。
四、两种记忆方案对比
| 方案 | 存储位置 | 重启后 | 适用场景 |
|---|---|---|---|
InMemoryChatMessageHistory |
内存 | 丢失 | 临时测试 |
FileChatMessageHistory(自实现) |
本地文件 | 保留 | 持久化存储 |
核心流程 :base_chain(原有链)→ RunnableWithMessageHistory(增强为带记忆的链)→ 调用时传 session_config 指定会话ID。
今日核心总结
- RunnableLambda:将自定义函数转为Runnable实例入链,lambda可直接传入
- 临时记忆 :
RunnableWithMessageHistory+InMemoryChatMessageHistory,按session_id隔离 - 长期记忆 :继承
BaseChatMessageHistory,实现文件读写,持久化保存 - 调用格式 :invoke时传
{"configurable": {"session_id": "xxx"}},自动关联历史 - 调试技巧:链中加入自定义函数print信息,原样返回不破坏业务