当前位置: 首页 > news >正文

智能体上下文选择-记忆工具知识

选择上下文是智能体架构中的核心机制,旨在根据任务动态筛选最有价值的信息进入上下文窗口,提升推理质量与效率。实现从状态、记忆、工具、知识等提取关键上下文,有效控制大语言模型的“注意力焦点”。

1 上下文选择能力拆解

在这里插入图片描述

📊 状态选择:选择哪些字段参与LLM调用;记忆选择:在长期存储中检索最相关事实;工具选择:用向量检索缩小可用工具集合;知识选择:RAG层面选择最有价值的文档碎片。这些选择技术既能最大化输出质量,又避免token浪费。

1️⃣ 状态选择
原理:智能体内部维护的状态即“草稿本”,记录中间步骤与历史轨迹。根据任务需求有选择性拉取其中的部分信息。

技术手段:节点内部实现状态选择机制,支持多步骤工作流中的上下文定向传递。

2️⃣ 记忆选择
原理:从长时记忆中仅选取与当前任务强相关的信息,避免检索噪声。

技术手段命名空间记忆检索将不同类型记忆隔离存储,按需检索。结合任务语义动态控制检索范围。

3️⃣ 工具选择
原理:在拥有大量工具的智能体中,盲目加载会浪费token或误调用。

技术手段:为工具集合构建向量索引,基于任务上下文语义检索最相关的工具。

4️⃣ 知识选择
原理:采用标准RAG架构,将外部知识库作为智能体的延伸记忆。

技术手段:文档拆分与向量化,构建高效检索器,实现多轮对话中的上下文感知知识选择。

2 状态选择的具体实现

状态选择在LangGraph中是通过state中选择上下文实现。

在下游节点的 LLM 调用里使用,让我们可以控制传递给LLM的上下文。

作为运行时状态的一部分,可以在每步决定要暴露哪些状态字段,从而精细控制向LLM调用暴露的上下文。

class State(TypedDict):topic: strjoke: str
def generate_joke(state: State) -> dict[str, str]:#生成关于topic的初始笑话.msg = llm.invoke(f"Write a short joke about {state['topic']}")return {"joke": msg.content}
def improve_joke(state: State) -> dict[str, str]:# 从state选择笑话给到LLMmsg = llm.invoke(f"Make this joke funnier by adding wordplay: {state['joke']}")return {"improved_joke": msg.content}    

📊 State包含 topicjoke 两个字段。函数 generate_jokestate['topic'] 读取主题,请求LLM生成笑话,并把结果写回新的状态键 joke。返回值会与工作流的全局 State 合并,形成数据流。improve_joke 展示了如何从 state 读取已生成的内容(joke)再传回 LLM 进行二次加工

3 记忆选择的具体实现

记忆选择可用于:

  • 元例(episodic):为 LLM 提供 few‑shot 示例;
  • 过程性(procedural):保存指令或规则以指导行为;
  • 语义(semantic):保存长期事实供后续检索。

一个挑战是如何确保选中真正相关的记忆。例如 ChatGPT 曾错误地检索用户位置并注入生成的图片,引发“上下文不属于用户”的不适。常用做法是用 embeddings 向量或知识图索引记忆以提高匹配度。

记忆选择在LangGraph中是通过store实现记忆。以键值对形式存储数据(key + value);使用 .put() 存入,用 .get() 读取。

from langgraph.store.memory import InMemoryStore
# 初始化内存存储
store = InMemoryStore()
# 定义命名空间,用于组织记忆
namespace = ("rlm", "joke_generator")
# 将生成的笑话存入内存
store.put(namespace,                             # 命名空间(用于分类管理)"last_joke",                           # 记忆的键(key),类似于变量名{"joke": joke_generator_state["joke"]} # 存储的值(value)
)
# 从内存中读取之前存储的笑话
retrieved_joke = store.get(namespace, "last_joke").value

📊 在 LangGraph 中选择记忆,InMemoryStore 提供键值存储,支持嵌套命名空间。put 写入记忆;get 检索。通过命名空间将不同任务的记忆隔离。value 字段取出真正的数据项。

def generate_joke(state: State, store: BaseStore):# 从memory选择之前的记忆的笑话prior_joke = store.get(namespace, "last_joke")if prior_joke:prior_joke_text = prior_joke.value["joke"]#生成新的笑话prompt = (f"写一个关于{state['topic']}的笑话, "f"但是要和之前写的不同 {prior_joke_text}")msg = llm.invoke(prompt)# 保存新的笑话store.put(namespace, "last_joke", {"joke": msg.content})return {"joke": msg.content}

📊 此函数每次生成新的笑话前,都会从内存读取上一个笑话。提示词中显式要求避免与上一个笑话重复,新生成的笑话会重新写回内存。先从 memory_store 读取同一主题的上一条笑话,将旧笑话注入 prompt,引导 LLM 生成不同内容。将新笑话写回memory_store,保持最新上下文。

4 工具选择的具体实现

智能体会使用工具,但若提供过多工具会导致上下文负载过高,因为工具描述可能相似,模型难以正确选择。解决方案是对工具描述应用 RAG(检索增强生成)以按语义相似度提取最相关工具。

在LangGraph中,让LLM+RAG智能体自动选择并调用Python math库函数。

  1. 工具注册:收集math库函数 → 转换为工具 → 分配唯一ID → 注册成tool_registry。

  2. 向量索引:提取每个工具的描述 → 生成嵌入向量 → 写入内存向量数据库store。

  3. 智能体创建:使用LLM和注册工具 → 构建支持向量检索的RAG Agent。

  4. 智能调用:接收自然语言指令; * 通过描述向量检索匹配工具(RAG); * 调用最佳工具返回结果。

核心机制

  • 向量检索:用工具的“描述”生成向量,实现自然语言到工具的语义匹配。

  • 自动调用:选到工具后,LLM代理负责实际参数处理和调用,无需手写映射逻辑。

# 将math库中的所有函数注册为“工具”
all_tools = []
for function_name in dir(math):function = getattr(math, function_name)# math模块的函数多为仅支持位置参数,需特殊转换if tool := convert_positional_only_function_to_tool(function):all_tools.append(tool)
# 为每个工具生成唯一ID并注册
tool_registry = {str(uuid.uuid4()): toolfor tool in all_tools
}
# 创建向量索引:用于描述文本的检索
embeddings = init_embeddings()
store = InMemoryStore(index={"embed": embeddings,   # 嵌入模型"dims": 1536,          # 向量维度"fields": ["description"],  # 用工具描述生成向量}
)
# 把工具的描述文本写入向量索引
for tool_id, tool in tool_registry.items():store.put(("tools",), tool_id,{ "description": f"{tool.name}: {tool.description}",  # 工具名+说明作为检索字段},)

📊 基于RAG的多工具智能体:动态选择与自动调用math函数。核心代码示范把 Python 内置 math 库的所有函数注册为工具,并用 RAG 选择最合适的。收集到的工具将用于后续向量索引。为每个工具生成描述文本后写入向量索引。

5 知识选择的具体实现

在实践中,RAG 往往成为上下文工程(context engineering)的核心挑战

在 LangGraph 中实现 Agentic RAG 的典型流程:

加载并拆分文档 → 2. 向量索引 + 检索器 → 3. 封装成 Tool →4. 编写系统提示 → 5. 构建节点(LLM 调用 / 工具执行)

通过这种方式,LLM 能够在对话中按需检索,从而给出更精准、可溯源的答案。

docs_list = [item for sublist in docs for item in sublist]text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(chunk_size=2000, chunk_overlap=50
)
doc_splits = text_splitter.split_documents(docs_list)vectorstore = InMemoryVectorStore.from_documents(documents=doc_splits, embedding=embeddings
)
retriever = vectorstore.as_retriever()
retriever_tool = create_retriever_tool(retriever,"retrieve_blog_posts","查询和返回信息",
)
tools = [retriever_tool]
tools_by_name = {tool.name: tool for tool in tools}
llm_with_tools = llm.bind_tools(tools)

📊 获取要供 RAG 系统检索的文档。docs_list:把“列表里的列表”拍平成单层列表,方便后续处理。递归式字符分割器确保分块符合 token 限制。将已拆分的文档索引到向量存储,以便后续语义检索。创建一个检索工具让代理能够通过它检索博客内容。llm.bind_tools(tools)` 使得 LLM 拥有调用这些工具的能力

llm_with_tools = llm.bind_tools(tools)


📊 获取要供 RAG 系统检索的文档。`docs_list`:把“列表里的列表”拍平成单层列表,方便后续处理。递归式字符分割器确保分块符合 token 限制。将已拆分的文档索引到向量存储,以便后续语义检索。创建一个检索工具让代理能够通过它检索博客内容。llm.bind_tools(tools)` 使得 LLM 拥有调用这些工具的能力
http://www.lryc.cn/news/593747.html

相关文章:

  • 工程图矢量化 笔记 | potrace ezdxf svgpathtools | png转svg保存dxf用matplotlib画出来
  • Qt笔记整理(1)
  • 高速SAR架构ADC选型设计
  • LVS——nat模式
  • 分立元件线性稳压器12V转5VMultisim仿真
  • 最终分配算法【论文材料】
  • 力扣24:两两交换链表中的节点
  • [FFmpeg] 输入输出访问 | 管道系统 | AVIOContext 与 URLProtocol | 门面模式
  • 外观设计模式
  • 零基础学习性能测试第二章-linux服务器监控:CPU监控
  • Redis字符串操作指南:从入门到实战应用
  • SQLShift:一款异构数据库存储过程迁移工具
  • c++ 基本语法易错与技巧总结
  • 模型的评估与选择
  • 【52】MFC入门到精通——(CComboBox)下拉框选项顺序与初始化不一致,默认显示项也不一致
  • yolov8-pos/yolov11-pos openvino C++部署
  • bash方式启动模型训练
  • OpenCV特征点提取算法orb、surf、sift对比
  • 相机参数的格式与作用
  • 算法基础知识总结
  • MYSQL 第一次作业
  • 量子计算与AI融合的技术突破与实践路径
  • scalelsd 笔记 线段识别 本地部署 模型架构
  • 【面试题】大厂高压面经实录丨第三期
  • SpringBoot服装推荐系统实战
  • 石子问题(区间dp)
  • 泛型机制详解
  • Java中缓存的使用浅讲
  • 从代码学习深度强化学习 - SAC PyTorch版
  • openmv小车追小球