( 教学 )Agent 构建 Memory(提示词对话存储)4. ConversationEntityMemory(保存对话过程中提及的特定实体的相关信息, 版

25 阅读4分钟

( 教学 )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)  # 记住 "上海"