news 2026/5/9 18:31:11

从零实现ReAct智能体:基于TypeScript的LLM Agent核心架构与实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从零实现ReAct智能体:基于TypeScript的LLM Agent核心架构与实战

1. 项目概述与核心价值

最近在折腾大语言模型应用,发现很多朋友对Agent(智能体)这个概念很感兴趣,但市面上的框架要么过于庞大复杂,要么封装得太好,导致想深入理解其内部运作机制变得困难。这让我想起了自己刚开始学习编程时,总想亲手“造轮子”的经历——只有从零开始搭建一遍,才能真正吃透一个技术的精髓。因此,我决定动手实现一个最经典的Agent范式:ReAct(Reasoning + Acting)

这个项目llm-ReAct就是一个纯粹的、教学向的、从零开始的TypeScript实现。它不依赖任何复杂的Agent框架库,只使用最基础的OpenAI API,完整地走通了ReAct Agent的核心流程:任务规划、工具调用和短期记忆。如果你对LLM如何通过“思考-行动”循环来解决问题感到好奇,或者想为自己的项目添加一个轻量级、可完全掌控的智能决策模块,那么这个项目会是一个绝佳的起点。通过亲手实现,你将彻底理解Prompt工程如何引导模型推理、工具系统如何被调度,以及一个简单的记忆机制如何让Agent在对话中保持连贯性。

2. ReAct框架核心原理与设计思路拆解

在深入代码之前,我们必须先搞清楚ReAct到底在解决什么问题,以及它是如何工作的。传统的大语言模型调用往往是“一次性”的:你给一个输入,它给一个输出。但对于复杂任务,比如“查询北京今天的天气,然后根据天气建议我是否要带伞”,这种单次交互就显得力不从心。模型可能需要先执行查询,再基于结果进行推理,这涉及多个步骤和外部数据的介入。

2.1 ReAct范式:将思考过程“外化”

ReAct的核心思想非常直观:让模型将内部的推理过程(Reasoning)以文本形式“说”出来,并基于此决定下一步要执行的动作(Acting),然后观察(Observation)动作的结果,如此循环,直到任务完成。

这个过程形成了一个经典的循环:Thought -> Action -> Observation

  1. Thought(思考):模型分析当前状况、历史记录和任务目标,规划下一步该做什么。例如:“用户想了解天气并得到建议。我需要先获取北京的天气信息。”
  2. Action(行动):模型根据思考,决定调用哪个工具(Tool)以及传入什么参数。它会输出一个结构化的动作指令,如:Action: SearchWeather[location=“北京”]
  3. Observation(观察):执行工具调用后,将结果(可能是成功的数据或错误信息)返回给模型。例如:Observation: 北京今天晴转多云,气温15-25度,无降水。
  4. 模型接收到观察结果后,开始新一轮的思考,决定是继续调用工具还是给出最终答案。

这个循环的妙处在于,它将模型的黑盒推理过程变成了可监控、可引导的文本流。我们作为开发者,可以通过精心设计的Prompt模板,极大地提升模型任务分解和工具调用的准确率。

2.2 本项目架构设计:清晰的责任分离

基于ReAct范式,我设计了以下几个核心组件,确保每个部分职责单一,易于理解和扩展:

  1. Agent(智能体):这是大脑。它不关心具体的网络请求或工具实现,只负责两件事:接收结构化的上下文(包含任务、历史、可用工具列表),然后生成符合ReAct格式的文本输出(即包含Thought和Action的字符串)。它是对接LLM的抽象层。
  2. Executor(执行器):这是中枢神经系统和指挥中心。它维护着事件循环(Event Loop),负责组装每次调用Agent所需的上下文(包括短期记忆),解析Agent输出的文本以提取动作指令,调用对应的工具,并将结果作为新的观察拼接到历史中,然后决定循环是否继续。
  3. Tool(工具):这是手脚。每个工具都是一个独立的类,有明确的名称、描述和参数定义。当Executor解析出动作指令后,就找到对应的工具实例并执行其call方法。
  4. LLM(大语言模型客户端):这是感官输入。一个极简的OpenAI API封装,只处理发送请求和接收响应,保持底层通信的纯粹性。
  5. Prompt(提示词模板):这是思维模式。它定义了发送给LLM的文本的固定结构,告诉模型它现在是一个ReAct Agent,它有哪些工具可用,历史对话是什么,当前任务是什么,以及它应该以什么格式回复。

这种设计使得增加新工具、更换模型供应商(比如从OpenAI换成Azure OpenAI或本地模型)变得非常容易,只需修改或替换相应组件,而不会影响核心的ReAct逻辑。

3. 核心组件深度解析与实现要点

让我们打开src目录,逐一拆解每个核心文件,看看它们是如何协作的。我会在解释代码逻辑的同时,穿插我在实现过程中踩过的坑和总结的经验。

3.1 工具系统:tool.tstoolkit.ts

工具是Agent与外界交互的唯一途径。一个设计良好的工具接口是系统可扩展性的基石。

tool.ts- 工具抽象基类

// 这是一个简化的示例,展示核心设计 export abstract class Tool { name: string; // 工具唯一标识,如 “SearchWeather” description: string; // 给模型看的工具功能描述 parameters: Record<string, any>; // 参数JSON Schema constructor(config: { name: string; description: string }) { this.name = config.name; this.description = config.description; } // 核心方法:执行工具逻辑 abstract call(args: any): Promise<string>; // 将工具信息格式化为模型可理解的文本,用于拼接到Prompt中 formatForPrompt(): string { return `- ${this.name}: ${this.description}`; } }

实现要点与避坑指南:

  • 描述(description)至关重要:这个描述是给模型看的“说明书”。它必须清晰、无歧义地说明工具的功能、输入和输出。例如,“获取指定城市的当前天气信息”就比“查询天气”要好。好的描述能显著提升模型调用工具的准确率。
  • 错误处理在call方法内部完成:工具执行可能失败(如网络错误、参数无效)。call方法应捕获这些异常,并返回一个格式化的错误字符串,如Error: Network timeout切记不要抛出异常到Executor,因为对Agent来说,执行失败也是一个有效的“Observation”,它可以根据这个错误进行下一步思考(例如重试或提示用户)。
  • 参数设计:对于复杂工具,可以定义详细的parametersJSON Schema。在简单实现中,可以约定args是一个对象,模型输出的动作指令需要包含一个能解析成该对象的字符串(如JSON)。

toolkit.ts- 具体工具实现这里实现了几个示例工具,如计算器、搜索、获取时间等。我们以计算器为例:

import { Tool } from './tool'; export class CalculatorTool extends Tool { constructor() { super({ name: 'Calculator', description: '执行数学计算。输入一个数学表达式字符串,如 “(2 + 3) * 4”。返回计算结果。', }); } async call(args: any): Promise<string> { try { // 安全提示:在实际生产中,直接eval极其危险!这里仅作演示。 // 应使用安全的数学表达式解析库,如 math.js。 const expression = typeof args === 'string' ? args : args?.expression; if (!expression) { return 'Error: 请提供有效的数学表达式。'; } // 这是一个极简示例,实际项目务必替换 const result = eval(expression); return `Result: ${result}`; } catch (error) { return `Error: 计算失败 - ${error.message}`; } } }

重要安全警告:上述示例中的eval仅用于演示ReAct流程的简洁性。在真实、可公开访问的服务中,绝对不允许使用eval来执行用户或模型提供的字符串,这将造成严重的代码注入安全漏洞。必须使用像math.js这类安全的表达式求值库。

3.2 智能体核心:agent.ts

Agent组件是纯逻辑的,它接收所有必要信息,调用LLM,并返回原始文本。

import { LLM } from './llm'; import { Tool } from './tool'; import { getReActPrompt } from './prompt'; export class Agent { private llm: LLM; constructor(llm: LLM) { this.llm = llm; } async run({ task, history, tools, }: { task: string; history: Array<{ thought?: string; action?: string; observation?: string }>; tools: Tool[]; }): Promise<string> { // 1. 构建Prompt const prompt = getReActPrompt(task, history, tools); // 2. 调用LLM const response = await this.llm.generate(prompt); // 3. 返回模型的原始回复 return response; } }

关键设计决策:

  • 输入标准化history是一个数组,每个元素代表一轮“思考-行动-观察”。这种结构化的历史记录比纯文本拼接更清晰,也便于后续扩展(比如加入时间戳、置信度等)。
  • 职责单一:Agent只负责“输入文本 -> 输出文本”。它不解析动作,也不关心输出格式的具体含义。解析工作交给下游的Executor。这样分离使得我们可以轻松替换不同的输出解析器(比如解析JSON格式的Action,而不仅仅是文本)。

3.3 提示词工程:prompt.ts

这是整个系统的“灵魂”。Prompt的质量直接决定了Agent的表现。我们的Prompt需要清晰定义角色、任务、工具、历史、以及最重要的——输出格式指令。

export function getReActPrompt( task: string, history: Array<{ thought?: string; action?: string; observation?: string }>, tools: Tool[] ): string { // 工具列表描述 const toolDescriptions = tools.map(tool => tool.formatForPrompt()).join('\n'); // 格式化历史记录 let historyText = ''; for (const entry of history) { if (entry.thought) historyText += `Thought: ${entry.thought}\n`; if (entry.action) historyText += `Action: ${entry.action}\n`; if (entry.observation) historyText += `Observation: ${entry.observation}\n`; } return `你是一个善于思考和利用工具解决问题的AI助手。请遵循以下格式回答问题: 任务:${task} 你可以使用的工具: ${toolDescriptions} 历史记录: ${historyText} 请开始思考。你必须严格按照以下格式输出: Thought: [你在这里进行思考,分析当前情况和下一步该做什么] Action: [工具名称][输入参数] // 例如:Calculator[“2+2”] 或 Search[“OpenAI官网”] 当你认为任务已经完成,需要给出最终答案时,请输出: Thought: 我已经得到所有必要信息,可以给出最终答案。 Answer: [你的最终答案] 现在,开始处理任务:${task} `; }

Prompt设计心得:

  • 格式指令必须强硬且明确:使用“必须严格按照以下格式输出”这样的措辞。在示例中明确给出Action:的格式,包括工具名和参数如何书写(如Calculator[“2+2”])。模型对示例格式非常敏感。
  • 提供“结束循环”的明确路径:必须告诉模型如何表示任务完成。我们定义了当模型输出Answer:时,循环终止。没有这个,Agent可能会陷入无限循环。
  • 历史记录的呈现方式:将历史记录原样回放给模型,相当于给了它一个“短期记忆”。模型可以基于之前的思考和观察进行连贯推理。

3.4 执行器与事件循环:executor.ts

Executor是粘合剂,它驱动整个ReAct循环运转。

import { Agent } from './agent'; import { Tool } from './tool'; export class Executor { private agent: Agent; private tools: Map<string, Tool>; // 工具名称到实例的映射 constructor(agent: Agent, tools: Tool[]) { this.agent = agent; this.tools = new Map(); tools.forEach(tool => this.tools.set(tool.name, tool)); } async run(task: string, maxIterations: number = 10): Promise<string> { const history: Array<{ thought?: string; action?: string; observation?: string }> = []; for (let i = 0; i < maxIterations; i++) { // 1. 调用Agent进行思考 const agentResponse = await this.agent.run({ task, history, tools: Array.from(this.tools.values()) }); // 2. 解析Agent的回复 const { thought, action, answer } = this.parseResponse(agentResponse); // 记录本次思考 history.push({ thought }); // 3. 判断是否结束 if (answer !== undefined) { history.push({ observation: `Task completed with answer: ${answer}` }); return answer; // 返回最终答案 } // 4. 执行动作 if (action) { const { toolName, input } = this.parseAction(action); const tool = this.tools.get(toolName); if (!tool) { const errorObs = `Error: 未知工具 "${toolName}".`; history.push({ action, observation: errorObs }); continue; // 遇到未知工具,将错误作为Observation,进入下一轮循环 } // 记录行动 history.push({ action }); // 执行工具并获取观察结果 const observation = await tool.call(input); history.push({ observation }); } else { // 如果没有解析出Action也没有Answer,可能模型格式错误,注入一个错误观察 history.push({ observation: 'Error: 响应格式不符合要求,未找到有效的Action或Answer。' }); } } throw new Error(`任务未在${maxIterations}轮内完成。`); } private parseResponse(response: string): { thought?: string; action?: string; answer?: string } { // 使用正则表达式从文本中提取 Thought, Action, Answer // 这是一个简化的解析器,实际应用中需要更健壮的处理 const thoughtMatch = response.match(/Thought:\s*(.*?)(?=\nAction:|\nAnswer:|$)/s); const actionMatch = response.match(/Action:\s*(.*?)(?=\nThought:|\nAnswer:|$)/s); const answerMatch = response.match(/Answer:\s*(.*?)$/s); return { thought: thoughtMatch?.[1]?.trim(), action: actionMatch?.[1]?.trim(), answer: answerMatch?.[1]?.trim(), }; } private parseAction(actionStr: string): { toolName: string; input: any } { // 解析类似 “Calculator[“2+2”]” 的字符串 // 实际实现需要处理各种边界情况,如参数带引号、嵌套等 const match = actionStr.match(/^([\w]+)\[(.*)\]$/); if (!match) { throw new Error(`无法解析动作指令: ${actionStr}`); } const [, toolName, inputStr] = match; let input; try { // 尝试将参数解析为JSON input = JSON.parse(inputStr); } catch { // 如果解析失败,则视为普通字符串 input = inputStr; } return { toolName, input }; } }

Executor实现的关键细节与经验:

  • 循环终止条件:必须有maxIterations限制,防止模型陷入死循环或任务无法完成时消耗过多资源。
  • 健壮的解析器parseResponseparseAction是系统的脆弱点。模型输出可能存在格式偏差(多空格、换行、标点)。这里的正则表达式是简化版。在生产环境中,建议:
    1. 要求模型输出严格的JSON格式,而非自由文本,这样解析更可靠。
    2. 或者使用一个更宽容的多行正则匹配,并做好错误处理,当解析失败时给模型一个友好的错误观察,让它有机会纠正。
  • 错误即观察:无论是工具未找到,还是工具执行出错,都将错误信息作为Observation放入历史。这符合ReAct的设计——模型需要从错误中学习并调整策略。
  • 历史管理history数组在每一轮循环后都被更新。注意,我们将thoughtactionobservation作为独立的步骤记录,这比拼接成一个字符串更清晰,也便于未来做更复杂的记忆处理(如摘要、过滤)。

3.5 大模型客户端:llm.ts

这是一个极简封装,保持灵活性。

import OpenAI from 'openai'; // 假设使用OpenAI官方SDK export class LLM { private client: OpenAI; private model: string; constructor(apiKey: string, model: string = 'gpt-3.5-turbo') { this.client = new OpenAI({ apiKey }); this.model = model; } async generate(prompt: string): Promise<string> { try { const response = await this.client.chat.completions.create({ model: this.model, messages: [{ role: 'user', content: prompt }], temperature: 0.1, // 低温度保证输出格式稳定 max_tokens: 500, }); return response.choices[0]?.message?.content?.trim() || ''; } catch (error) { console.error('LLM调用失败:', error); throw new Error(`LLM生成失败: ${error.message}`); } } }

参数调优建议:

  • temperature(温度):设置为较低值(如0.1-0.3)。对于需要严格遵守输出格式的Agent任务,低温度能减少随机性,使模型输出更稳定、更可预测。
  • max_tokens(最大令牌数):需要根据Prompt长度和预期回复长度设置。设置过小会导致回复被截断,破坏格式。可以适当设大一些,并在Prompt中提醒模型回复要简洁。
  • 错误处理:网络超时、额度不足、模型过载等都可能发生。良好的错误处理能让Executor有机会进行降级处理或给用户友好提示。

4. 从零搭建与运行:完整实操指南

理论讲完了,我们动手把它跑起来。假设你已经有Node.js环境和TypeScript基础。

4.1 环境准备与项目初始化

首先,创建一个新目录并初始化项目:

mkdir my-react-agent cd my-react-agent npm init -y

安装必要的依赖。我们使用TypeScript、OpenAI官方SDK,以及一些开发工具。

npm install openai npm install -D typescript ts-node @types/node

初始化TypeScript配置:

npx tsc --init

在生成的tsconfig.json中,确保targetES2020或更高,modulecommonjs(Node.js环境),并设置outDir./dist

4.2 编写核心代码与配置文件

按照前面章节解析的结构,创建src目录以及agent.ts,executor.ts,llm.ts,prompt.ts,tool.ts,toolkit.ts文件,将上面的示例代码填充进去。

创建项目根目录下的config.json,用于存放敏感配置(切记不要提交到版本控制):

{ "apiKey": "你的OpenAI API Key", "model": "gpt-3.5-turbo" }

创建一个入口文件index.ts,将所有组件组装起来并运行一个示例任务:

import { config } from './config.json'; import { LLM } from './src/llm'; import { Agent } from './src/agent'; import { Executor } from './src/executor'; import { CalculatorTool, SearchTool, GetCurrentTimeTool } from './src/toolkit'; async function main() { // 1. 初始化LLM客户端 const llm = new LLM(config.apiKey, config.model); // 2. 初始化Agent const agent = new Agent(llm); // 3. 准备工具集 const tools = [ new CalculatorTool(), new SearchTool(), // 假设这是一个模拟搜索工具 new GetCurrentTimeTool(), ]; // 4. 初始化执行器 const executor = new Executor(agent, tools); // 5. 运行一个复杂任务 const task = “请计算圆周率π的近似值(使用22/7),然后告诉我现在是什么时间?”; console.log(`开始执行任务: ${task}`); try { const finalAnswer = await executor.run(task); console.log(`\n任务完成!最终答案:\n${finalAnswer}`); } catch (error) { console.error('执行失败:', error.message); } } main();

4.3 编译与运行

package.json中添加启动脚本:

"scripts": { "start": "ts-node index.ts", "build": "tsc" }

现在,运行你的第一个ReAct Agent:

npm start

你应该能在控制台看到Agent的思考过程、工具调用和最终答案。

5. 常见问题、调试技巧与进阶优化

在实际搭建和运行过程中,你几乎一定会遇到下面这些问题。这里是我总结的排查清单和优化方向。

5.1 问题排查速查表

问题现象可能原因解决方案
模型不输出Action或Answer格式1. Prompt格式指令不够强硬或清晰。
2. temperature设置过高,输出随机性大。
3. 模型上下文理解有误。
1. 强化Prompt中的格式指令,添加更明确的示例。
2. 将temperature降至0.1。
3. 在Prompt开头更强调“你必须以指定格式回复”。
解析Action时出错1. 模型输出的Action字符串格式与parseAction函数期望的不符。
2. 参数中包含特殊字符导致解析失败。
1. 在Prompt中提供更精确的Action示例(如Action: Calculator[“expression”])。
2. 增强parseAction函数的鲁棒性,尝试多种解析方式,或要求模型输出JSON。
Agent陷入无限循环1. 任务本身无法通过现有工具完成。
2. 模型无法正确判断何时该结束(输出Answer)。
3. 工具执行结果未能提供有效信息。
1. 检查任务是否合理,工具是否完备。
2. 在Prompt中更清晰地定义任务完成的标志。
3. 为工具添加更明确的错误和结果描述,帮助模型理解。
工具调用结果不准确1. 工具描述(description)不清晰。
2. 模型对参数的理解有偏差。
1. 优化工具描述,明确输入输出格式和示例。
2. 在Prompt中提供工具调用的成功案例。
API调用超时或失败1. 网络问题。
2. API Key无效或额度不足。
3. 请求频率超限。
1. 在llm.ts中添加重试逻辑和超时设置。
2. 检查配置和账单。
3. 在代码中实现简单的速率限制。

5.2 调试与日志记录心得

在开发阶段,详细的日志是定位问题的生命线。我强烈建议在Executor的循环中打印每一轮的关键信息:

// 在Executor的run循环中添加 console.log(`\n=== 迭代 ${i + 1} ===`); console.log(`发送给Agent的Prompt预览:\n${prompt.substring(0, 500)}...`); // 打印部分Prompt console.log(`Agent原始回复:\n${agentResponse}`); console.log(`解析结果:`, { thought, action, answer }); if (action) { console.log(`准备执行工具:${toolName}, 参数:`, input); console.log(`工具执行结果:${observation}`); }

这样你能清晰地看到模型“想”了什么、“做”了什么、以及“看”到了什么,很容易定位是Prompt问题、解析问题还是工具问题。

5.3 性能与进阶优化方向

当这个基础框架跑通后,你可以从以下几个方向进行深化和优化:

  1. 记忆机制升级:目前的“短期记忆”只是简单的历史会话列表。当对话轮次很长时,会消耗大量Token并可能超出模型上下文长度。可以引入记忆摘要(Memory Summarization)技术,定期将冗长的历史压缩成简洁的要点,或者实现一个向量数据库记忆,将历史信息存入向量库,在需要时进行相关性检索。
  2. 工具验证与安全:当前模型可以任意调用任何工具。你需要增加一个工具调用验证层。例如,在执行工具前,检查当前用户是否有权限调用该工具,或者对输入参数进行严格的清洗和验证(防止注入攻击,特别是在使用eval或执行系统命令的工具时)。
  3. 输出格式标准化:将模型的输出格式从自由文本强制转换为JSON Schema。这能极大提高解析的可靠性。你可以使用OpenAI的function calling功能或提示模型输出指定结构的JSON。
  4. 支持流式输出(Streaming):对于耗时较长的任务,可以将模型的“思考”过程流式地输出给前端,提升用户体验。
  5. 集成更多工具:尝试集成真实的API,如网络搜索、数据库查询、发送邮件等,构建真正有用的智能助手。
  6. 更换模型后端:将llm.ts抽象成接口,轻松接入Azure OpenAI、Anthropic Claude、或本地部署的Ollama、LM Studio中的模型。

从零搭建这个ReAct框架的过程,让我对Agent的工作原理有了刻骨铭心的理解。它不仅仅是一个调用LLM的代码,更是一个设计精巧的、模拟人类“感知-思考-行动”循环的系统。最大的收获在于,我认识到了Prompt工程、工具设计、错误处理循环这三者之间的微妙平衡。下次当你使用LangChain或AutoGen这类高级框架时,你会清楚地知道,在那些简洁的API调用背后,正是这样一个不断循环的“思考-行动”引擎在默默工作。

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

CANN PTO瓦片库

【免费下载链接】pto-isa Parallel Tile Operation (PTO) is a virtual instruction set architecture designed by Ascend CANN, focusing on tile-level operations. This repository offers high-performance, cross-platform tile operations across Ascend platforms. 项…

作者头像 李华
网站建设 2026/5/9 18:20:47

CANN/pypto按位异或操作API文档

&#xfeff;# pypto.bitwise_xor 【免费下载链接】pypto PyPTO&#xff08;发音: pai p-t-o&#xff09;&#xff1a;Parallel Tensor/Tile Operation编程范式。 项目地址: https://gitcode.com/cann/pypto 产品支持情况 产品是否支持Ascend 950PR/Ascend 950DT√Atla…

作者头像 李华
网站建设 2026/5/9 18:12:39

为什么选微服务而不是动态扩容单体

动态扩容单体能不能做&#xff1f;能。单体应用部署成集群&#xff0c;前面挂个负载均衡&#xff0c;流量大了加机器。 问题在于&#xff1a;选微服务的驱动力从来不是吞吐量。 如果你面临的问题只是「流量扛不住了」&#xff0c;代码性能又不错&#xff0c;加机器就行&#…

作者头像 李华
网站建设 2026/5/9 18:08:28

AI如何革新文献综述:从NLP、机器学习到知识图谱的智能工作流

1. 项目概述&#xff1a;当AI遇上文献综述&#xff0c;一场效率革命正在发生 如果你是一名研究生、科研人员&#xff0c;或者任何需要大量阅读文献来支撑决策的分析师&#xff0c;那么“系统文献综述”这个词对你来说&#xff0c;可能意味着长达数月的痛苦煎熬。从确定检索式、…

作者头像 李华
网站建设 2026/5/9 18:08:02

CANN/tensorflow NPU性能调优

性能调优 【免费下载链接】tensorflow Ascend TensorFlow Adapter 项目地址: https://gitcode.com/cann/tensorflow 基础配置 iterations_per_loop 针对一次session.run调用&#xff0c;在NPU执行训练迭代的次数&#xff0c;默认为1&#xff0c;且用户设置的训练迭代总…

作者头像 李华
网站建设 2026/5/9 18:08:01

LingBot-Depth部署教程:HTTPS反向代理配置+Nginx负载均衡接入指南

LingBot-Depth部署教程&#xff1a;HTTPS反向代理配置Nginx负载均衡接入指南 1. 引言&#xff1a;为什么需要专业部署 当你成功在本地运行LingBot-Depth后&#xff0c;下一个问题自然而来&#xff1a;如何让团队其他成员也能使用这个强大的深度感知模型&#xff1f;直接暴露D…

作者头像 李华