LangChain v1.0迁移实战:从LCEL链到LangGraph状态机

最近在把一个基于 LangChain v0.x 的老应用往 v1.0 迁,版本从 v0.3 一路推到 v1.0,中间恰好踩在 LangGraph v1.0-11 这个节点上。这一轮迁移最核心的目标不是“把 import 改一改跑通”,而是系统性梳理升级策略和 Breaking Changes,真正把旧链路切到新版推荐的编排方式上。这篇东西就是这次迁移的完整记录,适合手里有 v0.x 代码、准备升 v1.0 但对变化范围心里没底的团队,也适合那些刚接触 v1.0、想知道新旧版本边界在哪的开发者。

先说一个结论:v1.0 不是 v0.x 的“修修补补”,它把 LangGraph 放到了框架中心,把原来 LCEL 链的很多职责收编进图里。如果从一开始就按“v0.x 怎么写,v1.0 就换个 import 继续写”的思路去迁,百分之百会中途卡住。我这次迁移前后花了一周,中间反复回滚了三次,最后才整理出一套相对平滑的升级路径。下面按升级顺序展开。

1. 升级前先搞清楚 v1.0 到底动了哪些筋骨

1.1 用一张对照表看懂变化范围

v0.x 到 v1.0 的破坏性变更并不集中在某一个 API 上,而是分散在包结构、模型调用、工具注册、流式事件、持久化这几个层面。如果只盯着某一个报错去改,会陷入“改一个崩一个”的循环。我先列一张我自己的对照表,建议你迁移前也建一张类似的:

变化领域v0.x 写法v1.0 推荐写法影响程度
核心抽象导入langchain.llms/langchain.chat_models统一走langchain_core与集成子包致命
编排方式LCEL链(prompt | llm | parser)StateGraph/LangGraph图高
消息输入llm.invoke("一句话")llm.invoke([HumanMessage(content="...")])中高
结构化输出output_parsers.PydanticOutputParserllm.with_structured_output(Schema)中
工具调用@tool+bind_tools@tool+ToolNode+ 图节点高
流式事件astream_events()老版本默认参数astream_events(..., version="v2")中高
会话记忆ConversationBufferMemorycheckpointer+MessagesState高

这张表不是我拍脑袋列的,而是迁移过程中真实遇到的报错和重写点。看完这张表你会发现,v1.0 的设计逻辑很明确:核心抽象全部下沉到langchain_core,业务编排统一交给 LangGraph,模型和向量库等外部依赖用独立集成包安装。理解了这个逻辑,后面改代码就有方向了。

1.2 升级前必须完成的三件准备工作

第一件事,锁定旧版本快照。迁移不是一蹴而就的,你需要一个能随时回滚的基线。我当时先把requirements.txt里所有langchain/langgraph/langchain-openai等版本号固定下来,用pip freeze导出当前环境,保存成requirements-lock-v0.txt。后面每次尝试迁移都可以回到这个状态重来。

第二件事,打开 deprecation 警告。v0.x 的多数废弃 API 在真正删除前都保留了过渡期,代码运行时会有DeprecationWarning。不要忽略这些警告,它们是官方给你的免费迁移清单。运行应用时加上-W default::DeprecationWarning,或者直接在脚本顶部写warnings.filterwarnings("default", category=DeprecationWarning),把所有废弃调用收集到日志里。我靠这个方式一次性抓出了十几个隐藏的旧接口引用。

第三件事,全局扫描旧的导入路径。在项目根目录执行:

grep -rn "from langchain.llms\|from langchain.chat_models\|from langchain.chains\|from langchain.memory" --include="*.py" .

把所有命中的文件列出来,按“纯内部模块”和“对外服务入口”分类。这里要特别注意:不要用正则一键全局替换,因为同一个函数名在新旧包里的语义可能有细微差别,需要逐文件确认。我建议把扫描结果先放一边,等理解了核心 API 变化后再动手改。

2. 依赖与 import 路径的系统性迁移

2.1 顶层入口收敛到 langchain_core

v1.0 最直观的变化是顶层包结构。老的langchain.chains、langchain.agents、langchain.llms这些模块基本都被拆掉了,核心的数据结构、端口、抽象类统一集中在langchain-core这个包里。听起来变化很大,但实际操作起来反而比 v0.x 清晰。

我举几个最常见的旧写法以及对应的新写法:

# 旧写法(v0.x) from langchain.llms import OpenAI from langchain.chat_models import ChatAnthropic from langchain.chains import LLMChain from langchain.prompts import ChatPromptTemplate from langchain.output_parsers import PydanticOutputParser
# 新写法(v1.0) from langchain_openai import ChatOpenAI from langchain_anthropic import ChatAnthropic from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import PydanticOutputParser from langchain_core.messages import HumanMessage, SystemMessage, AIMessage

注意,这里langchain_core并非要你直接依赖一个叫core的包名,而是一个独立的 PyPI 包,权限模型、消息对象、提示词模板、回调基类全在这里。langchain本身保留的是少数上层工具,但它不再是“什么都能 import 的瑞士军刀”。我建议迁移时先把langchain_core的版本也固定住,最好和langchain主版本保持同一大版本,避免小版本之间的隐性不兼容。

2.2 模型集成包统一命名与依赖声明

第二件事是模型供应商的包拆分。v0.x 时代,OpenAI、Anthropic、各种本地模型都可以从langchain或langchain_community里导入。v1.0 则明确要求模型接入使用独立的langchain-*集成包。

我这次项目的依赖从这样:

langchain==0.3.x langchain-community openai

变成这样:

langchain>=1.0,<2 langchain-core>=1.0,<2 langgraph>=1.0.11,<2 langchain-openai langchain-anthropic langgraph-checkpoint

这里有个关键点:langchain-openai和直接装openaiSDK 是两回事。langchain-openai是 LangChain 官方封装层,它内部会依赖 OpenAI 的 Python SDK,但你在业务代码里只跟ChatOpenAI打交道,不需要自己管理OpenAIclient。升级后ChatOpenAI的初始化参数和 v0.x 基本一致:

from langchain_openai import ChatOpenAI llm = ChatOpenAI( model="gpt-4o-mini", temperature=0, )

实测下来,这种拆分让重装有依赖问题的概率大幅下降。以前装一个langchain-community会把一堆可能用不到的驱动全拉进来,现在每个集成包都是轻量的,装错、冲突的概率小很多。

2.3 需要手动处理的“幽灵 import”

最隐蔽的一类问题,是代码里并没有直接写“被删除的模块”,但通过其他方式间接依赖老路径。比如某个工具函数里写了from langchain.agents import Tool,这个在 v1.0 里已经不再推荐,Tool应该来自langchain_core.tools。我当时用grep扫出来 30 多个文件里有这类引用,逐个确认后统一改掉。

另一个容易漏的是动态导入或者字符串形式的类引用,例如某些配置系统用importlib.import_module("langchain.llms")。对于这种情况,建议直接全局搜索关键词langchain.开头的 import,逐条对照新的路径规则。

如果项目规模大、担心漏改,我建议先把pytest基线的用例跑熟,再动 import。没有测试保护直接改 import,后期报错会非常痛苦。至少要有冒烟用例,覆盖“模型能调用”“一条消息能走通”“一个简单工具能被绑定”这三条主线。

3. 把 LCEL 链改成 LangGraph 图的编排迁移

3.1 为什么要从链过渡到图

v0.x 时代,LCEL 是官方推荐的编排方式,prompt | llm | parser这种管道式写法简洁优雅,我也很喜欢。但 v1.0 实际上把 LangGraph 作为默认的编排框架了,原因是 LCEL 倾向于表达“固定管线”,一写死就是单向流,很难处理循环、条件分支、人工介入、多 Agent 协作这些真实业务场景。

为了讲清楚这个变化,我用一个常见的“客服问答”逻辑来对比。老的 LCEL 写法大概是:

# v0.x LCEL prompt = ChatPromptTemplate.from_messages([ ("system", "你是客服助手"), ("human", "{input}"), ]) chain = prompt | llm | StrOutputParser() response = chain.invoke({"input": "请问退货流程是什么?"})

这段代码没什么问题,但如果要加上“先判断用户是否在问退货,再决定要不要调用售后系统工具”,LCEL 就只能在一边旁路写RunnableBranch,代码很快就变拧巴了。LangGraph 的方式是把每条处理逻辑定义成节点,节点之间的连线就是状态转换,复杂逻辑只是加节点和边而已。

3.2 一条典型链的图式改写

我用刚才那个客服场景,展示 v1.0 的最小 LangGraph 写法:

from typing import Annotated from typing_extensions import TypedDict from langgraph.graph import StateGraph, START, END from langgraph.graph.message import add_messages from langgraph.checkpoint.memory import MemorySaver class State(TypedDict): messages: Annotated[list, add_messages] def chat_node(state: State): response = llm.invoke(state["messages"]) return {"messages": [response]} builder = StateGraph(State) builder.add_node("chat", chat_node) builder.add_edge(START, "chat") builder.add_edge("chat", END) graph = builder.compile(checkpointer=MemorySaver())

这段代码里最需要理解的是State和add_messages。State是整个图执行过程的“共享黑板”,所有节点读它、写它。add_messages是一个 reducer,定义了“当多个节点往messages字段里写值时应如何合并”——它不是覆盖,而是追加。这一下就解决了老代码里“手动维护对话历史列表”的麻烦,LangGraph 会自动把上一轮的状态传给下一轮执行。

调用方式也简单:

config = {"configurable": {"thread_id": "user-123"}} result = graph.invoke({ "messages": [HumanMessage(content="请问退货流程是什么?")] }, config=config)

thread_id就是会话标识,同一个会话的多次调用会共享历史状态。这一点对老代码迁移特别有价值,因为它直接替代了以前ConversationBufferMemory的职责,而且状态存储在 Checkpointer 里,天然支持持久化和并发隔离。

3.3 状态定义与 reducer 的入门避坑

第一次从链迁移到图的人最容易在Annotated和 reducer 上栽跟头。state["messages"]本身是一个普通的列表,add_messages做的事是把新消息与已有消息合并,而不是简单append。如果你在自定义节点里直接返回{"messages": state["messages"] + [new_msg]},虽然也能跑,但会丢失 LangGraph 针对重复消息去重的内置行为。

另一个容易踩的坑是节点返回值里不需要回传整个 state。LangGraph 只更新你返回的那些字段,其他字段保持不动。所以节点函数写得短小干净就好,不要产生“手动搬运全局状态”的冲动。我在迁移一个老 Agent 时,就是因为每个节点都把整个 state 传了一遍,导致图运行速度明显下降,后来砍掉了大量冗余字段才恢复。

4. 模型调用、结构化输出与工具调用的破坏性变更

4.1 字符串消息不再是无脑可用的输入

v0.x 后期虽然也推荐用消息对象,但很多代码里仍然习惯直接llm.invoke("你好")。v1.0 对这个行为收紧了:规范化直接传字符串的做法被抛弃,推荐显式传消息列表。原因是字符串输入缺少对角色、工具调用记录这些上下文的表达能力,容易出现歧义。

改成:

from langchain_core.messages import HumanMessage response = llm.invoke([HumanMessage(content="你好")])

别小看这个变化。它会牵连出一批业务代码:比如以前在 Agent 里拼 prompt 字符串的写法,现在都要改成构造消息序列。不过习惯之后会发现,消息列表的方式反而更符合“对话系统”的直觉,system、user、assistant、tool 四种角色各有各的载体,上下文的层次清晰很多。

4.2 结构化输出统一走 with_structured_output

v0.x 时代要做 JSON 输出,不少人用的是PydanticOutputParser加format_instructions,或者自己写提示词让模型输出 JSON。这种方案的问题在于格式提示是一条“软约束”,模型偶尔会不遵守,解析就崩。v1.0 推荐的with_structured_output把 schema 直接交给模型 API,由模型端原生保证结构,解析成功率提升非常明显。

最小示例:

from pydantic import BaseModel, Field from langchain_openai import ChatOpenAI class MovieReview(BaseModel): title: str = Field(description="电影名") score: int = Field(description="评分,1到10") llm = ChatOpenAI(model="gpt-4o-mini") structured_llm = llm.with_structured_output(MovieReview) review = structured_llm.invoke([HumanMessage(content="评价一下某部电影")]) print(review.title, review.score)

从PydanticOutputParser迁移到with_structured_output,不只是换个 API,还涉及业务判断:如果模型输出失败,异常类型和捕获逻辑会不同。with_structured_output在模型端不返回合法 JSON 时通常会直接抛错,需要做好try/except和 fallback。如果你的下游要求高可用,我建议加一段兜底逻辑:结构化输出失败时降级成普通文本输出,再用传统 parser 二次解析。

4.3 工具注册从 bind_tools 到 ToolNode

v0.x 时代,工具调用的常见路径是@tool定义工具,然后用llm.bind_tools(tools)让模型看到工具。到了 v1.0,虽然bind_tools本身没有消失,但更完整的方案变成了ToolNode。

我这次踩了一个很真实的坑:直接把 v0.x 的agent_executor = AgentExecutor(agent=agent, tools=tools)代码往上搬,结果发现AgentExecutor在 v1.0 里已经边缘化了。官方推荐的是create_react_agent或者自己用StateGraph搭建带ToolNode的图。

最简单的迁移方式是直接用langgraph.prebuilt:

from langchain_core.tools import tool from langgraph.prebuilt import create_react_agent @tool def get_weather(city: str) -> str: """查询指定城市的天气。""" return f"{city} 今天多云,25度" tools = [get_weather] agent = create_react_agent(llm, tools) result = agent.invoke({ "messages": [HumanMessage(content="北京天气怎么样?")] })

create_react_agent的好处是把“模型决策→调用工具→返回结果→再决策”这条循环封装好了,不需要你自己手动写循环节点。如果你的场景需要严格控制工具调用时机,再演进到自定义StateGraph+ToolNode:

from langgraph.prebuilt import ToolNode builder = StateGraph(State) builder.add_node("agent", agent_node) builder.add_node("tools", ToolNode(tools)) builder.add_edge(START, "agent") builder.add_conditional_edges("agent", should_continue, ["tools", END]) builder.add_edge("tools", "agent")

这里should_continue是一个判断函数:如果模型给出的最后一条消息带tool_calls,就去tools节点;否则结束。这样一套下来,对工具循环的控制力比老的AgentExecutor强很多。

5. 流式事件、回调与持久化改造

5.1 astream_events 在 v1.0 里的行为变化

如果你负责的模块里有前端打字机效果,那必然绕不开流式输出。v0.x 里的astream_events有个很烦的问题是默认会输出大量嵌套事件,需要层层过滤才能拿到真正的 token。v1.0 把默认行为改成了“只显示引擎层的关键事件”,减少噪音。代价是,老代码如果没指定version参数,事件结构会变,前端解析逻辑就得跟着改。

新版推荐写法:

async for event in graph.astream_events( {"messages": [HumanMessage(content="讲个故事")]}, version="v2", ): if event["event"] == "on_chat_model_stream": chunk = event["data"].get("chunk") if chunk is not None: print(chunk.content, end="")

注意这里有两个细节。第一,version="v2"必须显式传,不传它会按新的默认规则走,但为了兼容,很多老代码其实还挂着旧事件结构。第二,事件的event名称仍以on_chat_model_stream这类为准,但chunk的取法略有差异。我建议先写一个小脚本把完整事件打出来看一遍,再改前端对事件的过滤条件,不要一眼都不看就按老代码改。

5.2 Checkpointer 与持久化带来的状态管理革命

v1.0 中会话记忆从“内存里的变量”变成了“可插拔的持久化存储”。MemorySaver只适合本地调试,重启后状态会丢。线上场景一般用SqliteSaver或PostgresSaver。

一个 Sqlite 持久化示例:

from langgraph.checkpoint.sqlite import SqliteSaver with SqliteSaver.from_conn_string("checkpoints.sqlite") as saver: graph = builder.compile(checkpointer=saver) config = {"configurable": {"thread_id": "session-a"}} result = graph.invoke( {"messages": [HumanMessage(content="你还记得我名字吗?")]}, config=config, )

从ConversationBufferMemory迁移到这个模式,有一个思维转换:以前你在一个链对象里塞一个全局 memory,每次调用自动记住;现在你必须在每次调用时都带上config里的thread_id,否则每次调用都是独立会话,模型“失忆”。我当时踩的坑就是前端每次请求都生成一个新的thread_id,结果用户对话永远接不上。修复方式很简单——把thread_id和用户 ID 绑定,存到前端 cookie 或后端 session 里。

5.3 回调与可观测性迁移

v1.0 里回调体系和 v0.x 相比变化不大,但导入路径清了。像from langchain_core.callbacks import BaseCallbackHandler这类写法在 v0.x 后期已经逐渐统一到 core,升级到 v1.0 反而更顺。真正需要留意的是,当图执行时,回调事件会嵌套在节点执行过程中,你要在on_chat_model_start、on_tool_start这些事件里区分当前处于哪个节点。

我在实践里的做法是自定义一个 Handler,在事件里打上run_id和节点名。然后配合 LangSmith 之类的可观测平台排查问题。不要小看这一步,图和链的调试方式完全不同,链是单向的,出错看栈就能定位;图有循环、有分支,不加 trace 几乎没法调。

6. 高概率踩坑清单与迁移节奏建议

6.1 高频报错对照速查表

迁移过程中我记录了一批出现频率最高的报错,这会是你升级时最实用的速查表:

报错或现象大概率原因处理动作
ModuleNotFoundError: No module named 'langchain.llms'旧顶层模块已移除改为langchain_openai/langchain_anthropic等子包
TypeError: invoke() got an unexpected keyword argument 'input'旧链的入参方式和图/模型接口不兼容改用{"messages": [...]}或messages入参
ValueError: Must provideversionwhen using astream_events流式事件版本参数缺失显式传version="v2"
对话总是丢失上文每次调用没有复用thread_id将thread_id与会话绑定
工具调用报“Tool not found“工具未注册到ToolNode或模型不可见检查bind_tools或tools=[...]列表
AttributeError: 'AgentExecutor' object has no attribute ... '仍在使用旧版编排器迁移到create_react_agent或自定义 StateGraph
Pydantic 校验报错结构化输出 schema 使用了旧版Field语法统一升级到 Pydantic v2 字段写法

这些报错有个共同特点:它们不会一次性出现,而是修一个冒一个。所以不要指望一个晚上改完,最好留出充足的时间做回归。

6.2 迁移节奏怎么安排才算“平滑”

我这次按三个阶段推进,效果不错。

第一阶段,保守迁移。只替换 import 路径和包名,不重写业务逻辑。目标是让原有链在 v1.0 依赖下能跑通,哪怕还在用 LCEL 也没关系。这个阶段能快速暴露存量问题,风险最低。

第二阶段,编排重构。把核心业务链逐步改成 LangGraph 图,优先迁“有状态”的 Agent 和“有工具调用”的链路。像那种纯 Prompt + 模型输出的简单链,可以留着用 LCEL,不强制一步到位。

第三阶段,能力升级。全部链路切到图后,再统一上持久化、流式事件 v2、结构化输出这些新能力。这一步才是真正吃透 v1.0 的时刻,前面两步不过关,直接上这一步会把问题搅在一起。

6.3 几个我后来觉得“幸好提前做了”的决定

回看这次迁移,有几个决定帮我省了很多时间。第一,我保留了完整的requirements-lock-v0.txt,每次改一半想放弃时都能快速还原,这让我试错成本极低。第二,我新写了一套最小回归脚本,专门覆盖“模型调用、简单对话续接、工具调用、结构化输出”四条路径,任何一次改动后跑一遍脚本,五分钟就能确认有没有引入新的破坏。第三,我没有删除任何旧工具函数,只在接口层做了适配,等新链路验证稳定后再逐步清掉旧代码。

这次迁移让我最大的体会是:升级框架真正的成本从来不在“换包名”,而在“换心智模型”。LCEL 链的思维是“数据流”,LangGraph 的思维是“状态机”,两者看着都能实现同一个 Demo,但面对真实业务场景时,状态机的表达力和可维护性高太多了。如果你正在计划升级,我建议第一周只做一件事:把官方文档里关于 State、节点、边的三个概念吃透,再用最简单的两节点图跑通一次对话。这一步走顺了,剩下的迁移就是体力活。

相关新闻

artcraft:模板+参数+渲染三层架构实现批量创意图片生成

artcraft:模板+参数+渲染三层架构实现批量创意图片生成

1. 从“artcraft”这个名字说起&#xff1a;它到底想解决什么问题第一次看到“artcraft”这个标题&#xff0c;我脑子里蹦出来的第一反应是&#xff1a;这大概率是一个把“艺术&#xff08;art&#xff09;”和“手工艺/工程化&#xff08;craft&#xff09;”揉在一起的项目。…

2026/10/21 9:03:19 阅读更多 →
Java异常处理最佳实践:从异常体系到线上排查的完整指南

Java异常处理最佳实践:从异常体系到线上排查的完整指南

写 Java 的人&#xff0c;几乎每天都在跟异常处理打交道。不过说实话&#xff0c;大多数项目里异常处理这块的代码质量&#xff0c;往往是整个工程里最容易被忽视的部分。我做过不少代码评审&#xff0c;发现一个规律&#xff1a;业务逻辑写得再花哨&#xff0c;只要异常处理随…

2026/10/21 9:02:18 阅读更多 →
C++异常处理从原理到实战:栈展开、RAII与noexcept深度解析

C++异常处理从原理到实战:栈展开、RAII与noexcept深度解析

1. 别再说异常处理只是“try-catch”了很多刚入门的C开发者觉得异常处理就是写个try、catch、throw&#xff0c;把可能出错的地方包起来就完事了。我见过太多项目里&#xff0c;开发者把整个函数体塞进try块&#xff0c;然后catch(...)一接&#xff0c;空转一下&#xff0c;假装…

2026/10/22 10:58:13 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年&#xff0c;我大部分时间都在跟浏览器标签页打交道&#xff0c;直到第一次把桌面应用跑起来&#xff0c;才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词&#xff0c;最开始是在某段时间频繁出现在同事的讨论里&#xff0c;一个用HTML…

2026/10/22 10:18:38 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介&#xff1a;亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档&#xff0c;主要面向智能锁安装人员、终端用户及售后维护者&#xff0c;帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件&#xff0c;大小4.37MB&#xff0c;内容结构清晰&#xff…

2026/10/22 11:01:53 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统&#xff0c;整车要求空载跑到8m/s&#xff0c;电机转速已经拉到额定点&#xff0c;驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令&#xff0c;转速纹丝不动&#xff0c;三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/22 9:44:47 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年&#xff0c;用它写过嵌入式驱动、做过游戏服务端&#xff0c;也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词&#xff0c;我其实挺感慨的——这门语言的难点从来不是语法多&#xff0c;而是知识点之间的耦合太深…

2026/10/22 10:42:00 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介&#xff1a;亚太天能T109滑盖智能锁产品说明书以PDF格式发布&#xff0c;适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开&#xff0c;先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能&#xff0c;再给出完整安装步骤&…

2026/10/22 10:40:08 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历&#xff1a;翻开源码注释、论文摘要或者一份专业报告&#xff0c;每个字都认识&#xff0c;连在一起却像天书。想找人聊聊&#xff0c;身边要么没人懂&#xff0c;要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型&#xff0c;几秒钟之后&a…

2026/10/22 10:56:37 阅读更多 →

日新闻

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/22 1:47:45 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/21 21:32:28 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/22 5:12:39 阅读更多 →

月新闻

我发现了一个新思路:用 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/21 21:50:56 阅读更多 →
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/21 21:51:55 阅读更多 →
黑夜航拍船只数据集训练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/21 16:24:48 阅读更多 →