( 教学 )Agent 构建 Memory(提示词对话存储)4. ConversationEntityMemory(保存对话过程中提及的特定实体的相关信息, 版本>1.0和<1.0的区别)
ConversationEntityMemory功能使对话系统能够保存对话过程中提及的特定实体的相关信息。
它会从对话中提取有关实体的信息(利用语言模型),并随着时间的推移积累关于这些实体的知识(同样利用语言模型)
该类,是之前的版本1.0以前的,版本1.0以后的。我会列出两个版本的使用方式和特点。
实体记忆对话示例
使用 ConversationEntityMemory 来存储和管理对话过程中提到的实体信息。
在保持自然对话流程的同时,系统能够不断积累关于这些实体的知识。
from langchain_openai import ChatOpenAI
from langchain_core.chains import ConversationChain
from langchain_classic.memory.entity import ConversationEntityMemory
from langchain_core.prompts import PromptTemplate
entity_memory_conversation_template = PromptTemplate(
input_variables=["entities", "history", "input"],
template="""
你是一个由OpenAI训练的大型语言模型驱动的人工智能助手。
你可以协助完成各种任务,从回答简单问题到就广泛的主题进行详细讨论。你能够生成类人的文本,实现自然的对话并提供连贯、相关的回应。
你在不断学习和进步,能够处理大量文本以提供准确和信息丰富的回答。你可以使用下文提供的个性化信息,结合自己生成的知识来回答。
上下文:
{entities}
当前对话:
{history}
最后一行:
人类: {input}
你:
""",
)
from dotenv import load_dotenv
import os
load_dotenv()
Qwen2_5_7B_Instruct_llm = ChatOpenAI(
temperature=0.1, # 控制输出的随机性和创造性,值越低输出越稳定可预测,值越高输出越有创意但可能偏离预期 (范围: 0.0 ~ 2.0)
model_name="Qwen/Qwen2.5-7B-Instruct", # 硅基流动支持的模型名称
openai_api_key=os.getenv("SILICONFLOW_API_KEY"), # 从环境变量获取API密钥
openai_api_base="https://api.siliconflow.cn/v1" # 硅基流动API的基础URL
)
conversation = ConversationChain(
llm=Qwen2_5_7B_Instruct_llm,
prompt=entity_memory_conversation_template,
memory=ConversationEntityMemory(llm=Qwen2_5_7B_Instruct_llm),
)
response = conversation.predict(
input=(
"Amelia是一位获奖的风景摄影师,她走遍世界各地捕捉自然奇观。"
"David是一位致力于保护濒危物种的野生动物保护主义者。"
"他们计划开设一个以自然为主题的摄影画廊和学习中心,为保护项目筹集资金。"
)
)
# Print the assistant's response
print(response)
打印内容:
这是一个非常有意义的项目!结合Amelia的专业摄影技能和David的保护知识,这个摄影画廊和学习中心将能够向公众展示自然界的美丽,同时提高人们对保护濒危物种和自然环境的认识。你们计划如何开始这个项目呢?需要在资金、场地、合作伙伴等方面做哪些准备?
获取实体记忆
让我们使用 memory.entity_store.store 方法来检查存储在记忆中的对话历史,以验证记忆的保留情况。
print(conversation.memory.entity_store.store)
{'Amelia': 'Amelia是一位获奖的风景摄影师,她走遍世界各地捕捉自然奇观。', 'David': 'David是一位致力于保护濒危物种的野生动物保护主义者。'}
使用最新版本逻辑实现
通过构建结构体 EntityState 来存储实体信息。对比上方的实现方式明显有了更多的结构化信息,以及横向拓展的能力。
from langgraph.graph import MessagesState, START, StateGraph
from langgraph.checkpoint.memory import MemorySaver
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
checkpointer = MemorySaver()
from typing import Dict, TypedDict
from enum import Enum
class EntityType(str, Enum):
PERSON = "人名"
LOCATION = "地点"
ORGANIZATION = "组织"
class EntityState(TypedDict):
messages: list
entities: Dict[str, EntityType] # {"Bob": "PERSON", "上海": "LOCATION"}
entity_scores: Dict[str, float] # 实体置信度
def extract_entities(state: EntityState):
"""提取实体节点"""
model = ChatOpenAI(
temperature=0.1, # 控制输出的随机性和创造性,值越低输出越稳定可预测,值越高输出越有创意但可能偏离预期 (范围: 0.0 ~ 2.0)
model_name="Qwen/Qwen2.5-7B-Instruct", # 硅基流动支持的模型名称
openai_api_key=os.getenv("SILICONFLOW_API_KEY"), # 从环境变量获取API密钥
openai_api_base="https://api.siliconflow.cn/v1" # 硅基流动API的基础URL
)
prompt = f"""
从对话中提取实体(人名、地名、组织),格式:{{"实体": "类型"}}
对话:{state["messages"][-1].content}
当前已知实体:{state["entities"]}
"""
response = model.invoke([("user", prompt)])
# 解析实体(简化版)
new_entities = eval(response.content.replace("```", "")) # 生产中用 JSON
state["entities"].update(new_entities)
return state
def chat_with_entities(state: EntityState):
"""带实体记忆的聊天"""
model = ChatOpenAI(
temperature=0.1, # 控制输出的随机性和创造性,值越低输出越稳定可预测,值越高输出越有创意但可能偏离预期 (范围: 0.0 ~ 2.0)
model_name="Qwen/Qwen2.5-7B-Instruct", # 硅基流动支持的模型名称
openai_api_key=os.getenv("SILICONFLOW_API_KEY"), # 从环境变量获取API密钥
openai_api_base="https://api.siliconflow.cn/v1" # 硅基流动API的基础URL
)
entities_str = "\n".join([f"{k}: {v}" for k, v in state["entities"].items()])
prompt = f"""
已知实体信息:
{entities_str}
对话历史:{state["messages"]}
请自然回应,引用相关实体。
"""
response = model.invoke([("user", prompt)])
return {"messages": [response]}
# 构建图
builder = StateGraph(state_schema=EntityState)
builder.add_node("extract_entities", extract_entities)
builder.add_node("chat", chat_with_entities)
builder.add_edge(START, "extract_entities")
builder.add_edge("extract_entities", "chat")
graph = builder.compile(checkpointer=checkpointer)
# 测试
config = {"configurable": {"thread_id": "user-1"}}
result = graph.invoke(
{"messages": [HumanMessage(content="我叫Bob,在上海的公司工作")]},
config
)
print(result["messages"][-1].content)
# 后续对话会记住实体
result2 = graph.invoke(
{"messages": [HumanMessage(content="我在哪里工作?")]},
config
)
print(result2["messages"][-1].content) # 记住 "上海"