news 2026/10/21 4:30:51

零基础搭建ReAct Agent:LangChain核心原理与工程实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
零基础搭建ReAct Agent:LangChain核心原理与工程实战

市面上讲 LangChain 的教程不少,但大多数一上来就丢一堆抽象概念,什么 Agent、Tool、Memory、Chain,看着头大。这篇东西我打算换个讲法,直接以“零基础”为假设,带你把一个ReAct Agent从零搭出来。ReAct 是 Reasoning + Acting 的组合,说人话就是让大模型先“想清楚再动手”,想一步、做一步、观察结果、再想下一步。LangChain 则是目前把这件事做得最顺手的框架之一,它把模型调用、工具注册、对话记忆这些脏活累活都封装好了,我们只需要关心业务逻辑本身。

这篇文章适合谁?刚接触 Agent 开发、被各种术语劝退的新手,或者是用过 LangChain 但一直是“照着文档抄、不知道为什么要这样写”的朋友。我会把环境搭建、核心代码、运行原理、参数调优、踩坑记录全部分享出来。不整虚的,全部是我自己实测过的方案,你跟着操作就能跑起来。

1. 整体思路拆解:先搞懂 ReAct 到底在解决什么问题

1.1 没有 ReAct 之前,大模型有多“死板”

先看一个很常见的场景。你直接问大模型:“帮我查一下明天北京飞上海的航班,然后订一张最便宜的。”普通对话模型大概率会回你一段“很抱歉,我无法访问实时数据”之类的客套话,或者直接开始编造航班信息。原因很简单——模型本身不具备实时获取外部信息的能力,它的知识截止在训练那一刻,而且它没有“操作外部工具”的接口。

你可能说,那把它接一个 API 不就行了?问题又来了:大模型怎么知道该调用哪个 API、传什么参数、返回结果怎么理解?这就需要一个“推理循环”把大模型和外部工具串联起来,让模型自己决定“我现在需要调用什么工具”,然后根据工具的返回结果继续推理。

1.2 ReAct 的核心循环:思考-行动-观察

ReAct 的灵感来自于人类解决问题的自然方式。比如你让我估算一个房间的面积,我不会直接瞎猜,而是会想:“先量一下长和宽,然后相乘。” 我会思考(Reason)、行动(Act)、观察结果(Observe),再继续思考。

在 Agent 里,这个循环被形式化为三个步骤:

  • Thought(思考):模型分析当前状态,决定下一步要做什么,并给出理由。
  • Action(行动):模型选择一个具体的工具,并提供调用参数。比如搜索航班信息,参数是出发地=北京,目的地=上海,日期=明天。
  • Observation(观察):把工具返回的结果反馈给模型。

这三步不断循环,直到模型判断“我已经拿到了所有需要的信息,可以给出最终答案了”,然后输出Final Answer。

LangChain 的作用,就是把上面这个循环用框架代码固化下来。我们不再需要手动管理“模型调工具→拿结果→再喂给模型”的繁琐流程,LangChain 的AgentExecutor会自动完成这些动作。

1.3 为什么选 LangChain 而不是自己写循环

有人会问:这个循环我自己用while写也就十几行,为什么还要引入 LangChain?

我的回答是:如果只是做一个 Demo,确实自己写更轻。但一旦你的 Agent 需要处理多种工具、多步推理、上下文长度控制、错误重试、流式输出这些“真实世界的问题”,自己写的循环很快就会变得又臭又硬。LangChain 把这些通用能力都抽象好了,而且提供了丰富的工具接入方式——搜索、计算器、数据库查询、自定义 API,都有现成的封装。更重要的是,LangChain 对底层的模型调用做了统一抽象,你可以轻松地在不同大模型之间切换,而不需要改动业务层代码。

当然,LangChain 也有自己的学习曲线,特别是版本迭代很快,网上很多教程用的是旧版 API,导致你照着敲都会报错。我会在后面的实操部分,基于一个稳定的版本来讲解,保证你能跑通。

2. 环境准备与基础概念扫盲

2.1 版本选型:LangChain 版本这事儿真的会坑人

先聊个很多人栽过的跟头——版本。LangChain 目前有两条主要分支:经典的0.x系列(例如0.1.x、0.2.x)和全新的1.0系列。两者在 API 设计上有较大差异,网上大量教程沿用的是0.1或0.2的写法,比如from langchain.agents import initialize_agent这种。如果你装了1.0,很多旧代码直接就是ModuleNotFoundError。

为了兼容性和稳定性,本篇所有代码基于0.2.x版本。定版本是个好习惯,不要总是追最新——最新版本往往伴随着 breaking changes,API 说变就变,线上环境跑着跑着就崩了,谁疼谁知道。

建议创建虚拟环境后执行:

pip install langchain==0.2.17 langchain-openai==0.1.25 langchain-community==0.2.19

2.2 你需要准备的密钥与模型选择

ReAct 的推理能力高度依赖底层大模型。推荐选择支持Function Calling或指令遵循能力强的模型。如果你使用国内可直连的模型服务,可以选择支持 OpenAI 兼容接口的各大厂商模型,只需要修改base_url和模型名称即可。

我建议准备好以下几个东西:

项目说明
大模型 API Key最核心的依赖,没有它 Agent 就是空壳
模型 Base URL如果使用第三方兼容接口,需要配置转发地址
Python 环境3.9 以上,推荐 3.10 或 3.11
搜索工具 API Key可选,需要联网搜索能力时使用

2.3 先搭一个最小骨架:不写 Agent,先确认模型能通

很多新手一上来就盯着 Agent 写,结果出了问题都不知道是自己代码写错了还是模型没配置好。我的建议是:先做一个最小化的模型调用测试。

from langchain_openai import ChatOpenAI llm = ChatOpenAI( model="gpt-4o-mini", temperature=0, api_key="sk-xxx", base_url="https://api.example.com/v1" ) response = llm.invoke("你好,请简单介绍一下你自己") print(response.content)

这段代码做的事情很简单:创建一个 ChatOpenAI 实例,传入模型名、密钥和 base_url,然后发一条消息。如果这段代码能正常返回内容,说明模型连接没问题,我们才能放心去写 Agent。

注意:temperature设置为 0,这是 ReAct Agent 的正确姿势之一。原因很简单——Agent 的推理需要稳定、确定性的决策,随机性太强会导致它在一个错误分支上反复横跳,甚至陷入死循环。后面我会详细讲参数调优。

3. 核心实操:手写一个带搜索能力的 ReAct Agent

3.1 初始化项目结构

我把项目的文件结构先列出来,避免后面写着写着乱了:

react_agent_demo/ ├── requirements.txt ├── main.py ├── tools.py └── config.py
  • config.py放密钥和模型配置。
  • tools.py放自定义工具和工具加载逻辑。
  • main.py放 Agent 的创建和执行入口。

3.2 定义我们自己的 Tool:计算器和当前时间

LangChain 里的Tool是一个基础组件,本质上就是一个“名字 + 描述 + 函数”的组合。模型根据描述来决定是否调用这个工具,所以描述写得好不好,直接影响 Agent 的聪明程度。这一块很多人忽视,我多说两句。

先定义一个计算器工具和当前时间工具。计算器很经典,因为它能让 Agent 完成数值推理;当前时间工具则能避免“今天星期几都不知道”的尴尬场景。

# tools.py from datetime import datetime from langchain_core.tools import Tool def calculator_plugin(expression: str) -> str: """计算数学表达式的值,例如 '(3.14 * 5) + 2'""" try: # 安全起见,只允许计算基本数学表达式 result = eval(expression, {"__builtins__": {}}, {}) return f"计算结果: {result}" except Exception as e: return f"计算失败,错误信息: {e}" def get_current_time() -> str: """获取当前的日期和时间""" now = datetime.now() return f"当前时间是: {now.strftime('%Y-%m-%d %H:%M:%S')}" calculator_tool = Tool( name="calculator", func=calculator_plugin, description="计算数学表达式时使用。输入必须是合法的数学表达式,如 '1+2*3' 或 '(3.14*5)/2'" ) time_tool = Tool( name="current_time", func=get_current_time, description="当需要知道当前日期或时间时使用,不需要额外参数" ) tools = [calculator_tool, time_tool]

这里有个很重要的细节:我把calculator_plugin里的eval用空字典限制了内置函数,防止恶意代码注入。虽然演示场景一般不会出安全问题,但做工具开发时,永远不要直接信任用户的输入,尤其是涉及eval和exec的时候。生产环境建议用ast.literal_eval或者专门的数学解析库。

3.3 创建一个带 ReAct 提示模板的 Agent

接下来到了核心环节。在 LangChain0.2.x中,我推荐直接用create_react_agent方法,它比旧的initialize_agent更清晰、也更好理解。

# main.py from langchain.agents import create_react_agent, AgentExecutor from langchain_openai import ChatOpenAI from tools import tools def create_agent(): llm = ChatOpenAI( model="gpt-4o-mini", temperature=0, api_key="sk-xxx", base_url="https://api.example.com/v1" ) prompt = """你是一个智能助手,需要使用工具来回答用户的问题。 请严格遵循以下流程: 1. 如果需要使用工具,必须按照下面的格式输出: Thought: 你思考的过程 Action: 工具名称(必须从 [{tool_names}] 中选择) Action Input: 工具的输入参数(JSON格式) 2. 如果你已经获得了足够的信息来回答用户,必须输出: Thought: 我已经知道答案了 Final Answer: 对用户的最终回答 可用工具: - calculator: 计算数学表达式 - current_time: 获取当前时间 {chat_history} 用户问题:{input} {agent_scratchpad} """ agent = create_react_agent(llm=llm, tools=tools, prompt=prompt) executor = AgentExecutor( agent=agent, tools=tools, verbose=True, max_iterations=5, handle_parsing_errors=True ) return executor if __name__ == "__main__": executor = create_agent() result = executor.invoke({"input": "现在几点了?顺便告诉我 230 * 45 等于多少"}) print(result["output"])

你现在可以直接跑python main.py,看看输出。

3.4 跑起来以后发生了什么:用 verbose 观察 Agent 的“内心戏”

我自己第一次跑通的时候,最兴奋的就是看到 LangChain 把 Agent 的思考过程打印出来。因为在AgentExecutor里我设置了verbose=True,所以你会看到类似这样的输出:

> Entering new AgentExecutor chain... Thought: 用户问了两个问题,一个是时间,一个是计算。我应该先获取当前时间。 Action: current_time Action Input: {} Observation: 当前时间是: 2025-06-15 14:32:18 Thought: 我已经获取到时间了。接下来需要计算 230 * 45。 Action: calculator Action Input: {'expression': '230 * 45'} Observation: 计算结果: 10350 Thought: 我现在有了所有需要的答案。 Final Answer: 现在是 2025年6月15日 14:32:18。230 × 45 = 10350。

看到没有?模型确实是在“思考-行动-观察”的循环里走。它不是一次性生成那个最终答案,而是一步步来。这个过程中,Action 和 Action Input 的格式至关重要,如果模型输出格式不对,create_react_agent内部的output_parser就无法解析,后续动作就中断了。这也是为什么我们要在 Prompt 里反复强调格式。

3.5 Prompt 里的占位符都是干嘛的

刚才的 Prompt 里有几个占位符,眼熟但可能不懂,这里一次性讲清楚:

  • {tool_names}:LangChain 在运行时会把可用工具名列表自动填进去,这样模型才知道该输出什么 Action。
  • {input}:用户的具体问题。
  • {chat_history}:对话历史,如果你的 Agent 需要多轮记忆,这个占位符就是关键。
  • {agent_scratchpad}:最重要的占位符,它会被 Agent 之前的思考、行动、观察记录填满。模型每走一轮,scratchpad 就会多一段内容,相当于它的“草稿纸”。

理解agent_scratchpad是搞懂 ReAct 的钥匙。你可以把它想象成模型的“便签本”,每一次 Thought、Action、Observation 都会写在这张便签上。模型每次生成新内容时,都会把便签本上已有的内容作为上下文,所以它能记住自己之前做了哪些操作。如果没有这个机制,模型每轮都“失忆”,Agent 就没法完成多步推理了。

4. 进阶增强:加入联网搜索、自定义 API 和记忆能力

4.1 给 Agent 装上“眼睛”:复现 DuckDuckGo 搜索工具

只有计算器和时间工具的 Agent 还是太雏形了。真实场景里,Agent 最常用的工具是联网搜索。很多搜索工具需要申请 API Key,比如 SerpAPI、Bing Search 等,配置起来稍微麻烦点。LangChain 社区里有一个很实用的搜索封装——DuckDuckGoSearch,不需要 API Key,直接就能用。

安装依赖:

pip install -U duckduckgo-search

然后在tools.py里增加:

from langchain_community.tools import DuckDuckGoSearchRun def get_search_tool(): search = DuckDuckGoSearchRun() return Tool( name="web_search", func=search.run, description="当需要查询实时的新闻、事实性信息或最近发生的事情时使用。输入一个搜索关键词,返回搜索结果摘要。" )

把这个工具加进tools列表后,你再问 Agent 一些“今天有什么热点新闻”之类的问题,它就会自己去搜索。这就是“能联网的 Agent”和普通聊天机器人的本质区别——它能根据实时结果回答,而不是只靠模型内部记忆硬编。

4.2 Agent 接入你自己的 API:Tool 的万能封装法

真实项目里,你需要 Agent 查询公司内部的订单接口、或执行某个运维操作。这种场景就需要把我们自己的 API 封装成 Tool。

我举个例子,假设你有一个接口能查询某个城市当前天气:

import requests def weather_api(city: str) -> str: """根据城市名获取当前天气""" try: url = f"https://api.example.com/weather?city={city}" resp = requests.get(url, timeout=10) data = resp.json() return f"{city} 当前天气: {data['weather']},温度 {data['temp']}°C" except Exception as e: return f"天气查询失败: {e}" weather_tool = Tool( name="weather_query", func=weather_api, description="查询某个城市当前天气情况时使用。参数为城市中文名,如'北京'。" )

这段代码最重要的又是description。你在实际使用中会发现,模型判断“该不该用这个工具”,完全依赖于描述与用户问题的匹配度。如果你的描述写得含糊,比如只写“天气查询”,模型可能懵,不知道该传什么参数。好的描述应该包含:什么时候用、输入什么、输出大概长什么样。

4.3 多轮对话的记忆:让 Agent 记得“刚才说了什么”

默认情况下,AgentExecutor是无状态的,也就是说每个invoke都是独立的,Agent 不记得你上一轮问过什么。例如:

  • 用户第一轮问:“我叫小明。”
  • 用户第二轮问:“我叫什么名字?”

如果 Agent 没有记忆,第二轮就会愣住。要在 Agent 中加入记忆,我们通常需要引入记忆组件。这里我推荐使用SqliteHistory(LangChain 0.2.x 的类),示例代码如下:

from langchain.memory import SqliteHistory # 持久化保存历史消息 memory = SqliteHistory( session_id="user_001", database_path="chat_history.db" ) # 注意:使用 memory 时需要将 prompt 中的 {chat_history} 替换为 history.messages from langchain.agents import create_react_agent, AgentExecutor prompt = prompt.replace("{chat_history}", "{history.messages}") agent = create_react_agent(llm=llm, tools=tools, prompt=prompt) executor = AgentExecutor( agent=agent, tools=tools, memory=memory, verbose=True )

这里有个坑:当启用了记忆后,Prompt 中的占位符{chat_history}不再由 LangChain 自动填充,必须改成{history.messages},否则 Agent 会报ValueError: Missing some input keys: chat_history。

加了记忆之后,再问“我叫什么名字”就能得到正确答案了。注意记忆会累积所有轮的对话内容,长时间运行会导致上下文过长、Token 费用飙升。建议在真实场景中设置最大轮数,或者定期清理。

4.4 流式输出:不要让你的用户干等着

如果 Agent 要执行好几轮工具调用,整个执行过程可能要几十秒。用户界面上如果一片空白,体验极差。LangChain 的AgentExecutor支持流式输出,可以通过stream方法逐块获取结果。

for chunk in executor.stream({"input": "帮我查一下今天北京天气,再算一下 12*12 等于多少"}): if "output" in chunk: print(chunk["output"], end="", flush=True)

但在实际生产环境中,由于 Agent 在“思考”和“调用工具”阶段并不会产出最终文本,流式输出的中间过程可能不连续。设计上建议把 Agent 交互放到后端异步任务中,前端提供“正在推理”状态提示,等最终答案出来后一次性展示,后续可以用更细粒度的回调来增强体验。

5. 参数调优与代码加固:从能跑到能上线

5.1 temperature、max_iterations、max_execution_time 怎么配

很多教程跑通 Demo 就结束了,但真实的工程化改造第一步就是调参数。我总结了一张表,直接抄作业就行:

参数推荐值说明
temperature0(重要)高温度会让模型随机性变强,Agent 决策不稳定,容易偏题或死循环
max_iterations5限制“思考-行动-观察”的最大循环次数,防止模型无限循环
max_execution_time60(秒)硬性超时上限,避免 Agent 卡死导致资源浪费
handle_parsing_errorsTrue当模型输出格式错误时,LangChain 会自动把错误信息回填给模型请求它修正,而不是直接崩溃

max_iterations尤其重要。没有这个限制,模型可能会在一定指令诱导下不断调用工具——比如“请一直调用 calculator 计算 1+1、1+1、1+1……”——每一次工具调用都是实打实的 Token 消耗和延迟。

5.2 添加重试机制与异常捕获

企业应用里,网络抖动、API Key 过期、工具接口超时等异常经常发生。原生AgentExecutor不会自动重试工具调用,所以需要在工具函数内部做好异常处理。

一个更健壮的工具封装模板:

def safe_run(func, *args, **kwargs): attempts = 0 while attempts < 3: try: return func(*args, **kwargs) except Exception as e: attempts += 1 if attempts >= 3: return f"工具执行失败: {str(e)}" time.sleep(1)

虽然这只是一个朴素的循环重试,但往往缺失的就是这种最朴素的防护。加一层不会带来多少代码复杂度,收益却是实打实的。

5.3 限制工具权限:Agent 不是万能的

永远不要让 Agent 随手调用所有工具。比如一个工具是delete_database,你把它注册进 Agent,模型在某个奇怪指令下真的可能调它。

在 LangChain 里,你可以通过白名单配置控制 Agent 可用的工具子集:

DEBUG_TOOLS = ["current_time", "calculator"] PROD_TOOLS = ["current_time", "calculator", "web_search"] def build_executor(env="debug"): available = DEBUG_TOOLS if env == "debug" else PROD_TOOLS selected_tools = [t for t in tools if t.name in available] ...

这个做法我在实际项目中用过,非常实用。尤其在多人协作时,新同事接手的第一个任务就是搞清楚“哪些工具是安全的、哪些工具绝对不能开”,白名单机制让权限边界一目了然。

6. 常见问题与排查技巧实录

6.1 模型乱输出 Action:结果无法解析

现象:Agent 执行时报错:Could not parse LLM output: ...。

原因:模型没有严格按照Thought -> Action -> Action Input的格式输出,可能是模型本身指令遵循能力弱,也可能是 Prompt 里的格式示例不够清晰。

解法:

  • 换一个更强的模型;
  • 在 Prompt 里增加“逐步思考”和“严格按照格式”的强调;
  • 确保agent_scratchpad占位符存在,并保留系统提示中的格式示例。

6.2 Agent 陷入死循环,反复调用同一个工具

现象:Agent 来回调用同一个工具,Observation结果没变,但就是不停重试。

原因:工具返回的结果没有给模型提供新信息,或者结果里存在大量噪声,模型无法从中提取有效线索。

解法:

  • 设置max_iterations=5,硬性止损;
  • 检查工具返回的文本质量。例如搜索工具的摘要太乱,可以在 Tool 函数里做结果清洗和截断,保留最关键的内容。

6.3 上下文太长,Token 费用爆炸

现象:Agent 每次执行都要把agent_scratchpad里所有历史步骤都发给模型,多轮对话时 Token 消耗指数上升。

原因:没有对agent_scratchpad和chat_history做长度裁剪。

解法:

  • 在 Prompt 中限制最后 N 步,或者在工具内部对返回值做truncate(500);
  • 大轮次任务用memory做滑动窗口,只保留最近几轮;
  • 对返回结果做摘要:“如果超过 2000 字符,简述核心结论”。

6.4 模型不能正确传参:Action Input 总是缺字段

现象:Tools 期望输入{"city": "北京"},模型却输出{"城市": "北京"}或者干脆漏掉参数。

原因:模型看到的是工具的描述,而不是严格的 JSON Schema。如果你的描述里没写清楚参数名,它就会脑补。

解法:描述里务必给出参数示例。比如:

description="查询城市天气。输入必须是 JSON 格式,包含字段 city,例如:'{\"city\": \"上海\"}'"

这一步做不好,后面所有工具的调用成功率都会很低。我见过不少团队的 Agent 代码,80% 的失败都出现在工具参数传错上,而不是模型能力不行。

6.5 使用记忆后报错 Missing some input keys

现象:加入SqliteHistory后立即报错ValueError: Missing some input keys: chat_history。

原因:启用 memory 后,{chat_history}不会再被自动填充,需要把 Prompt 里的占位符改为{history.messages}。

解法:替换占位符,或者自定义get_inputs方法在调用前注入历史消息。这种方法我第一次踩坑时找了半天才明白,所以特意把它写在这里。

6.6 一个验证 Agent 是否健康的自检清单

我每次写完 Agent 都会跑一遍下面的自检清单,建议你也养成这个习惯:

检查项操作
模型连通性单独调一次llm.invoke
单工具调用只注册一个简单的 time 工具,看 Agent 能不能选择并使用
双工具组合加入 calculator,问一个需要先查时间再计算的复合问题
错误输入故意给一个无法处理的问题,看 Agent 会不会礼貌地给出“无法回答”而不是瞎编
超时与迭代上限设置max_iterations=3,看 Agent 是否能在限制内收敛
多轮记忆分两轮提问验证历史记忆是否生效

总结与经验分享

我一路做下来最大的体会是:ReAct Agent 的价值不在于代码多复杂,而在于你愿不愿意把“思考过程”显式地交给模型。很多时候我们习惯用一堆 if-else 去编排任务流程,但 ReAct 的思路是完全不同——让模型自己决定流程,你只需要提供可靠的工具和清晰的边界。

如果你是想做一个真正的产品,我强烈建议从一开始就考虑工具的描述质量和异常保护机制,而不是先跑通 Demo 再补课。工具描述写得烂,Agent 再聪明也白搭;工具函数没有异常处理,一个超时就能让你整个流程卡死。

最后再分享一个小技巧:调试 ReAct Agent 的时候,不要把verbose=False关掉。第一次跑通时,亲眼看一遍 Agent 的 Thought → Action → Observation → Final Answer 全流程,会让你的理解深入很多。之后熟悉了再关掉也不迟。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 4:30:05

Llama-Guard 3垂直行业微调实战:让安全模型更懂业务

让安全更懂业务&#xff1a;针对垂直行业定制 Llama-Guard 3 守卫模型的微调实战全指南我一直觉得&#xff0c;做安全模型的微调&#xff0c;最迷人的地方不在于把准确率刷到多高&#xff0c;而在于让模型真正"读懂"业务。过去大半年我一直在折腾 Llama-Guard 3&…

作者头像 李华
网站建设 2026/10/21 4:28:19

SVM支持向量机核心原理、核函数选择与调参实战指南

1. 先从一个经常翻车的分类场景说起我最早接触支持向量机&#xff08;SVM&#xff09;的时候&#xff0c;其实是被一个问题逼的。当时我在做某电商平台的用户流失预测&#xff0c;数据大概几万条&#xff0c;特征有消费频次、最近登录时间、客单价、投诉次数这些。一开始我用的…

作者头像 李华
网站建设 2026/10/21 4:27:58

知识工作插件:面向认知活动的本地化AI能力增强层

1. 项目概述&#xff1a;这不是一个插件包&#xff0c;而是一套知识工作者的“操作系统增强层”“knowledge-work-plugins”这个名称乍看像某个开源仓库的简单命名&#xff0c;但拆开来看——knowledge&#xff08;知识&#xff09;、work&#xff08;工作&#xff09;、plugin…

作者头像 李华
网站建设 2026/10/21 4:27:55

CIS-RAN重构6G智能底座:端边网协同与内生AI的融合路径

CIS-RAN重构6G智能底座&#xff1a;端边网协同的内生AI体系&#xff0c;如何让通信与AI双向奔赴&#xff1f;做通信系统的人&#xff0c;这几年应该都有一个很直观的感受&#xff1a;传统RAN的架构&#xff0c;正在变成进一步演进的瓶颈。我们过去引以为傲的“云化”“集中化”…

作者头像 李华
网站建设 2026/10/21 4:27:19

显存不够?用显存虚拟化让老显卡也能跑大模型

1. 显存不够用这件事&#xff0c;卡在哪了这两年玩大模型的朋友应该都体会过那种滋味——好不容易把依赖环境配好了&#xff0c;模型权重也下下来了&#xff0c;结果程序一启动就弹出来一行红色的CUDA out of memory。尤其是手头只有一块11GB显存卡的朋友&#xff0c;面对时下主…

作者头像 李华
网站建设 2026/10/21 4:27:18

相机内参标定从入门到实战:原理、流程与避坑指南

写这篇东西的起因&#xff0c;是我前阵子拿一台老相机做三维重建&#xff0c;重建出来的点云距离一量&#xff0c;歪得离谱。排查了半天&#xff0c;发现连最基础的内参都是凭感觉填的&#xff0c;压根没正经标定过。后来把标定这块踏踏实实补上&#xff0c;重投影误差从好几个…

作者头像 李华