langchain工具结果透传
在 LangChain / LangGraph 里工具调用结果存起来供下一个工具使用这件事本质上是把结果写回图状态State——Runtime 本身只是一个运行期上下文载体并不是持久存储桶。下面把正确的做法讲清楚。先理清三个概念LangChain v1 基于 LangGraph运行期上下文分三层别搞混 层次性质生命周期用途context配置不可变单次运行user_id、API Key、DB 连接等state状态可变单次运行或单轮对话工具结果、中间变量都存在这里​store长期记忆可变跨对话用户画像、历史偏好工具调用结果要供下一个工具使用正确做法是写回 state——要么作为ToolMessage进messages列表要么写进你自定义的 state 字段 。做法一让结果自然进入 messages最常用LangGraph 的ToolNode执行完工具后会把返回值包装成ToolMessage追加到state[messages]里 。下一轮 LLM 推理时自然能看到这个结果并决定调用下一个工具。关键是 state 里的messages字段必须用累积 reduceradd_messages否则会覆盖掉之前的消息下一轮 LLM 会因为tool 消息找不到配对的 tool_calls而报错 from typing import Annotated, List from langchain_core.messages import BaseMessage from langgraph.graph import StateGraph from langgraph.graph.message import add_messages class State(TypedDict): messages: Annotated[List[BaseMessage], add_messages]工具本身只需要正常返回结果即可ToolNode会自动处理ToolRuntime注入、ToolMessage构造等工作 from langchain_core.tools import tool tool def search_user(user_id: str) - str: 根据用户 ID 查用户信息 return fnameAlice, age30, cityBeijing tool def get_weather(city: str) - str: 根据城市查天气 return f{city} 今天晴25°CLLM 看到search_user返回的ToolMessage后会从中提取cityBeijing再决定调用get_weather(Beijing)——这就是上一个工具的结果供下一个工具使用的自然流转。做法二把结果写进自定义 state 字段结构化传递如果工具结果需要以结构化字段的形式显式存下来而不仅仅是躺在 messages 里让 LLM 自己提取工具需要返回一个Command对象来更新 state from langchain.tools import tool, ToolRuntime from langchain.messages import ToolMessage from langgraph.types import Command from typing import TypedDict class MyState(TypedDict): messages: list user_profile: dict # 自定义字段 current_step: str # 流程控制字段 tool def fetch_user_profile( user_id: str, runtime: ToolRuntime[None, MyState] ) - Command: 获取用户画像并写入 state profile {name: Alice, city: Beijing, vip: True} return Command(update{ # 必须回写 ToolMessage保证消息配对 messages: [ToolMessage( contentstr(profile), tool_call_idruntime.tool_call_id )], # 写入自定义字段下一个工具可从 runtime.state 读取 user_profile: profile, current_step: next_stage })下一个工具通过runtime.state读取上一个工具写入的字段 tool def recommend_plan(runtime: ToolRuntime[None, MyState]) - str: 基于上一个工具写入的用户画像做推荐 profile runtime.state.get(user_profile, {}) if not profile: return 未找到用户画像 city profile.get(city) return f为 {city} 的用户推荐本地服务 调用runtime.state.get()时务必提供默认值——首次调用时该字段可能还没初始化直接[]取值会抛 KeyError 导致 Agent 循环崩溃 。做法三跨工具共享运行期依赖用 context如果下一个工具需要的是user_id、API Key、数据库连接​ 这类运行期依赖不是上一个工具的计算结果应该走context而不是 statefrom dataclasses import dataclass from langchain.tools import ToolRuntime, tool dataclass class AppContext: user_id: str db_conn: object api_key: str tool def query_orders(runtime: ToolRuntime[AppContext]) - str: 工具通过 runtime.context 拿到运行期依赖 uid runtime.context.user_id conn runtime.context.db_conn # ... 查询逻辑 return f用户 {uid} 有 3 笔订单调用时传入 context agent.invoke( {messages: 查询我的订单}, contextAppContext(user_idu_123, db_connconn, api_keyxxx) )完整可运行的最小示例from typing import Annotated, TypedDict, List from langchain_core.messages import BaseMessage from langchain_core.tools import tool from langchain.tools import ToolNode, ToolRuntime from langchain.messages import ToolMessage from langgraph.types import Command from langgraph.graph import StateGraph, START, END from langgraph.graph.message import add_messages # 1. 定义带自定义字段的 state class AgentState(TypedDict): messages: Annotated[List[BaseMessage], add_messages] last_result: dict # 存上一个工具的结构化结果 step: str # 2. 工具 A写入 state tool def tool_a(query: str, runtime: ToolRuntime[None, AgentState]) - Command: result {query: query, answer: f答案:{query}的结果} return Command(update{ messages: [ToolMessage( contentstr(result), tool_call_idruntime.tool_call_id )], last_result: result, step: after_a }) # 3. 工具 B读取上一个工具写入的 last_result tool def tool_b(runtime: ToolRuntime[None, AgentState]) - str: prev runtime.state.get(last_result, {}) if not prev: return 没有前置结果 return f基于 {prev.get(answer)} 做进一步处理 # 4. 构建图用 ToolNode 自动处理 ToolRuntime 注入 tools [tool_a, tool_b] tool_node ToolNode(tools) def call_model(state: AgentState): # 这里绑定 tools 给 LLM response model.bind_tools(tools).invoke(state[messages]) return {messages: [response]} graph (StateGraph(AgentState) .add_node(agent, call_model) .add_node(tools, tool_node) .add_edge(START, agent) .add_conditional_edges(agent, lambda s: tools if s[messages][-1].tool_calls else END, [tools, END]) .add_edge(tools, agent) .compile() )⚠️关键提醒如果你想自己写工具执行节点不用预置ToolNode直接tool.ainvoke()时ToolRuntime不会被自动注入runtime参数会变成必填导致校验失败。这种情况下要么改用ToolNode要么手动构造ToolRuntime注入 ——生产环境强烈建议直接用ToolNode。几种场景的选择建议工具结果是给 LLM 看的最常见→ 直接返回靠messagesToolMessage自然流转state 用add_messagesreducer工具结果需要结构化存下来供后续节点/工具读取​ → 返回Command(update{...})写自定义 state 字段跨会话保留用户偏好、历史记忆→ 用runtime.store长期记忆不是 state运行期依赖user_id、连接、密钥→ 走contextinvoke 时传入多轮对话持久化​ → 编译图时加checkpointerMemorySaver()用thread_id隔离 一句话记住Runtime 是管道State 才是仓库。工具结果要供下一个工具用本质是写回 StateRuntime 只是在这一次调用里帮你把 state、context、store 端到工具面前 。如果你的场景是多 Agent 交接handoff还需要把上一个 Agent 的AIMessageToolMessage配对传给下一个 Agent这部分逻辑稍微特殊需要的话告诉我你的具体架构我给一份针对多 Agent 的写法。

相关新闻

三步搞定百度文库付费限制:免费保存纯净文档的终极指南

三步搞定百度文库付费限制:免费保存纯净文档的终极指南

三步搞定百度文库付费限制:免费保存纯净文档的终极指南 【免费下载链接】baidu-wenku fetch the document for free 项目地址: https://gitcode.com/gh_mirrors/ba/baidu-wenku 还在为百度文库的付费下载券和烦人广告而烦恼吗?今天我要分享一个简…

2026/10/15 0:43:11 阅读更多 →
Java/Python/Node.js项目路径获取与管理实践

Java/Python/Node.js项目路径获取与管理实践

1. 为什么需要获取项目路径在开发过程中,获取项目路径是一个看似简单却至关重要的基础操作。我第一次意识到这个问题的重要性是在接手一个遗留项目时,发现代码中到处都是硬编码的绝对路径。当项目从开发环境迁移到测试环境时,所有路径都失效了…

2026/10/15 14:32:06 阅读更多 →
什么胶辊耐高温?工业耐高温胶辊选型指南

什么胶辊耐高温?工业耐高温胶辊选型指南

在工业生产中,印刷、热复合、覆膜、烘干等工序长期处于高温工况,普通胶辊极易出现软化、变形、脱胶、开裂等问题,直接影响生产效率与产品质量。很多企业采购选型时都会疑惑什么胶辊耐高温,适合工业高温场景使用。市面上耐高温胶辊…

2026/10/9 19:10:43 阅读更多 →

最新新闻

NLog 项目贡献指南:从 Issue 报告、多目标编译到 CI 构建的完整实战手册

NLog 项目贡献指南:从 Issue 报告、多目标编译到 CI 构建的完整实战手册

后端运维观测 【免费下载链接】NLog NLog - Flexible and Structured Logging for various .NET Platforms 项目地址: https://gitcode.com/gh_mirrors/nl/NLog 点击查看 免费下载 本文档是 NLog 开源仓库(.NET 平台灵活的结构化日志框架)中…

2026/10/15 18:31:45 阅读更多 →
2026 必应(Bing)关键词 SEO 优化排名全攻略:算法逻辑 + 落地实操 + 效果监测

2026 必应(Bing)关键词 SEO 优化排名全攻略:算法逻辑 + 落地实操 + 效果监测

国内搜索引擎市场,百度始终占据主流地位,多数企业的 SEO 布局也围绕百度展开,但往往忽略了第二大桌面搜索引擎必应(Bing)的流量价值。随着 2025 年必应搜索算法持续迭代,AI 语义识别能力大幅提升&#xff0…

2026/10/15 18:31:45 阅读更多 →
5分钟搞懂 octo-server 交互式卡片协议:一份 JSON 如何搞定消息渲染与交互

5分钟搞懂 octo-server 交互式卡片协议:一份 JSON 如何搞定消息渲染与交互

【免费下载链接】octo-server 🐙 The Go backend powering OCTO — an open workplace built for humans AI agents. REST & WebSocket APIs, Lobster (AI agent) orchestration, and WuKongIM real-time messaging control plane. 项目地址: https…

2026/10/15 18:31:45 阅读更多 →
Trae中设置 Skill

Trae中设置 Skill

前提:登录Trae什么是 Skill?定义一个 Skill 是一份清晰、严谨、可执行的指令文档,用于明确告诉模型——在什么条件下(When),按照哪些步骤(How),产出什么结果(…

2026/10/15 18:31:45 阅读更多 →
Camping World EDI 项目注意事项:订单变更、ASN、库存同步与供应商合规细节

Camping World EDI 项目注意事项:订单变更、ASN、库存同步与供应商合规细节

对接 Camping World EDI,需要把采购订单、订单变更、商品编码、仓库装箱、发货通知和发票处理连接起来。单据发送成功之后,数据是否符合订单要求、ASN 是否与实物一致、标签是否能够匹配收货流程,都会影响订单履约和回款。 此前发布的文章 …

2026/10/15 18:31:45 阅读更多 →
LED点阵显示任意汉字:从字模生成到串口协议全链路实现

LED点阵显示任意汉字:从字模生成到串口协议全链路实现

简介:本资源是一套完整的LED点阵汉字显示系统开发包,面向嵌入式初学者、单片机课程设计者及AVR实践爱好者,解决“如何让88或1616点阵动态显示任意GB2312汉字”这一典型硬件交互问题。压缩包共18个文件,含AVR下位机核心代码&#x…

2026/10/15 18:30:45 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →