news 2026/9/7 16:50:01

从零实现AI Agent:掌握主链路、工具调用与工程化落地

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从零实现AI Agent:掌握主链路、工具调用与工程化落地

很多视频教程最大的问题,是让观众以为“看懂了”就等于“会做了”。你跟着屏幕敲一遍代码,模型能回答了,工具能调用了,关掉视频之后,老板让你做一个真正能交付的Agent,你却发现脑子里只剩下一堆名词。

这篇文章给你一个更务实的判断:学AI Agent,不要从框架学起,要从最小主链路学起。所谓主链路,就是“大模型负责理解与决策、工具负责与外部世界交互、记忆负责保留上下文、循环负责把这三者串起来”这条运行主干。只要你亲手把这条主干跑通,再看LangChain、AutoGen、多Agent编排这些上层框架,都会轻松很多。

这篇文章会带大家完成一个从0到1的完整项目:一个能调用工具、能自主规划、能对外提供HTTP接口的资料查询与任务处理Agent。你会看到它的概念拆解、架构设计、完整代码、运行验证,以及从Demo走向工程时最容易踩的坑。

1. 这篇文章真正要解决的问题

先说结论:2026年,AI Agent已经进入“工程化落地”阶段,拼的不是谁更懂概念,而是谁能稳定交付项目

为什么这么说?看几个真实场景。

场景一,你做后端开发,公司要求把内部知识库、工单系统、数据库查询能力整合到一个“智能助手”里。如果只是接一个大模型API做聊天,用户问“上周订单量多少”,模型答不上来,因为数据在数据库里。你需要让模型能够生成SQL、执行查询、再把结果转成自然语言。这就是Agent要解决的事。

场景二,你做测试或运维,希望让AI定时巡检服务、发现异常、调用接口重试或者发通知。这也不是一次对话能完成的,而是一个“目标驱动、反复决策、调用工具”的过程。

场景三,你准备换工作,面试官问“Agent和普通对话机器人有什么区别”“你的Agent怎么管理上下文”“工具调用失败怎么处理”。如果只背过概念,这些问题很容易被追问到哑口无言。

这些场景指向同一个能力:你能不能让大模型不只会说话,还会办事。这篇文章的目标,就是用一个最小但完整的项目,把“会办事”的工程链路讲透。项目不复杂,但覆盖了Agent的核心要素,学完可以直接在此基础上扩展成真实业务项目。

2. AI Agent的核心概念与运行逻辑

2.1 什么是AI Agent

AI Agent(智能体)最简单的定义是:以大语言模型为大脑,能够自主规划、调用工具、记忆上下文,并最终完成用户目标的程序系统

它和普通对话机器人的区别,是理解Agent的起点。

维度传统对话式AIAI Agent
交互方式一问一答目标驱动,多轮决策
外部能力文本生成调用工具、查询数据、执行操作
记忆单轮或少量上下文任务记忆 + 长期记忆
失败处理答错只能重问可以规划重试、换工具
应用边界信息问答任务自动执行

一个常见的比喻是:聊天机器人像是在问路,Agent则像是你雇了一个实习生。你给实习生一个目标,他会自己拆解任务,查资料、打电话确认、遇到问题换方案,最后给你一份结果。Agent的运行逻辑就是把这个“实习生”的做事流程用代码实现出来。

2.2 Agent运行的四个核心要素

一个可工作的Agent,至少包含四个要素:

第一,目标(Goal)。用户输入的诉求就是目标,Agent的所有行动都围绕目标展开。没有清晰目标的Agent,会陷入“模型随机发挥”的状态。

第二,规划(Planning)。Agent要把大目标拆成小步骤。拆解方式可能是一次性输出完整计划,也可能是边做边调整。复杂任务中,规划能力直接决定了任务能否完成。

第三,记忆(Memory)。记忆分为短期和长期:短期记忆是本次任务中的对话历史和中间结果,长期记忆是跨会话保留的用户偏好、业务知识或历史经验。当前大模型的上下文窗口有限,怎么管理记忆,是Agent工程里最考验功力的地方。

第四,工具(Tools)。模型自身无法实时获取天气、查询数据库、发送邮件,这些能力要通过工具函数暴露给模型。工具是Agent与外部世界交互的“手脚”。

2.3 ReAct模式:Agent运行的灵魂

讲Agent绕不开ReAct模式。这个名字是Reasoning(推理)和Acting(行动)的组合,核心思路是:让模型在“思考”和“行动”之间循环,而不是一次推理就给出答案

一个ReAct循环大致是这样:

  1. 用户提出目标。
  2. 模型根据目标和已有信息,输出推理过程:当前需要做什么,缺少什么信息。
  3. 如果需要外部信息或操作,模型选择一个工具并给出参数。
  4. 系统执行工具,把结果返回给模型。
  5. 模型根据工具结果继续推理,可能再次调用工具,也可能直接生成最终答案。

这个循环会重复执行,直到得到最终答案或达到最大步数限制。工具执行结果返回给模型,是Agent和普通调用API最大的区别。主流的Agent框架,本质上都是对这个循环的不同封装。

3. 示例项目设计:架构、技术选型与目录结构

3.1 项目要做什么

为了让概念落到实处,我们做一个名为“Smart Assistant”的最小Agent服务。它支持两类任务:

用户可以问“现在几点了”,Agent会调用时间工具获取准确时间。 用户可以要求计算表达式,比如“计算23乘7加5”,Agent会调用数学计算工具。

功能听起来很简单,但它完整包含了Agent运行主链路:大模型理解用户意图、选择工具、执行工具、根据结果生成答案。把这个跑通,后续换成“查数据库”“查订单”“发通知”,难度只在于实现具体工具函数。

3.2 技术选型

组件选型说明
大模型接口任意兼容OpenAI Chat Completions的模型通过环境变量配置,不写死模型名
开发语言Python 3.9+生态成熟,AI类项目首选
Agent运行核心原生实现ReAct循环不依赖重型框架,便于理解原理
HTTP服务FastAPI + Uvicorn提供对外接口,便于前后端分离对接
配置管理环境变量 + .env密钥和模型地址不硬编码

这里刻意不引入LangChain等框架,是因为新手最容易犯的错误就是“上来就学框架,底层原理一塌糊涂”。先用原生代码把Agent循环写明白,后面再看框架会事半功倍。

3.3 目录结构

agent-demo/ ├── requirements.txt # 依赖清单 ├── .env.example # 环境变量示例 ├── llm_client.py # 大模型调用封装 ├── tools.py # 工具注册与实现 ├── agent.py # Agent运行循环 ├── app.py # FastAPI服务封装 └── frontend/ └── index.html # 简易前端测试页

4. 环境准备与依赖安装

确保本机已安装Python 3.9及以上版本,然后创建项目目录并安装依赖。

mkdir agent-demo cd agent-demo python -m venv venv source venv/bin/activate # Windows下使用 venv\Scripts\activate

创建requirements.txt,内容如下:

# 文件路径:agent-demo/requirements.txt openai>=1.0.0 fastapi uvicorn pydantic python-dotenv

安装依赖:

pip install -r requirements.txt

关于版本说明:上述依赖均未固定到具体小版本,安装时以当前可用的稳定版本为准。openai库建议使用1.x以上的新版,因为工具调用(tool calling)相关API在1.x中已经稳定。

接着配置环境变量。新建.env.example文件:

# 文件路径:agent-demo/.env.example # 大模型API密钥 OPENAI_API_KEY=sk-xxxxxxxx # 大模型接口地址,使用兼容OpenAI协议的服务时修改为对应地址 OPENAI_BASE_URL=https://api.openai.com/v1 # 模型名称 OPENAI_MODEL=gpt-4o-mini

复制一份为.env,填入你自己的密钥和模型地址。在国内使用兼容OpenAI协议的服务时,只需要修改OPENAI_BASE_URLOPENAI_MODEL即可,业务代码无需改动。

随后在llm_client.py中加载环境变量:

# 文件路径:agent-demo/llm_client.py import os from dotenv import load_dotenv load_dotenv() from openai import OpenAI client = OpenAI( api_key=os.getenv("OPENAI_API_KEY"), base_url=os.getenv("OPENAI_BASE_URL", "https://api.openai.com/v1"), ) def chat_with_tools(messages, tools=None): """ 调用大模型接口,支持传入工具定义。 """ model = os.getenv("OPENAI_MODEL", "gpt-4o-mini") response = client.chat.completions.create( model=model, messages=messages, tools=tools, temperature=0.2, ) return response

这里真正值得记录的经验是:base_url是接入各类兼容服务的关键配置,很多国内模型服务都提供OpenAI兼容协议,这意味着你的Agent代码只需要修改环境变量,就可以在不同模型之间切换。

5. 核心代码实现:工具注册与Agent运行循环

5.1 实现并注册工具

tools.py中实现两个工具函数:获取当前时间、计算数学表达式。

# 文件路径:agent-demo/tools.py from datetime import datetime # 使用安全计算库替代 eval 也可以 try: import asteval _aeval = asteval.Interpreter() except ImportError: _aeval = None def get_current_time(): """获取当前日期和时间""" return datetime.now().strftime("%Y-%m-%d %H:%M:%S") def calculate(expression): """ 计算简单的数学表达式。 注意:这里为了教学演示使用 eval,生产环境必须替换为安全计算方案。 """ forbidden = ["__", "import", "os", "system", "exec", "open"] if any(word in expression for word in forbidden): return "表达式包含非法内容,已拒绝计算" try: if _aeval is not None: return str(_aeval(expression)) return str(eval(expression, {"__builtins__": {}}, {})) except Exception as e: return f"计算失败: {e}" TOOLS = { "get_current_time": get_current_time, "calculate": calculate, } # 工具定义,按 OpenAI Function Calling 格式声明 TOOL_SCHEMAS = [ { "type": "function", "function": { "name": "get_current_time", "description": "获取当前日期和时间", "parameters": { "type": "object", "properties": {}, }, }, }, { "type": "function", "function": { "name": "calculate", "description": "计算数学表达式,例如 '23*7+5'", "parameters": { "type": "object", "properties": { "expression": { "type": "string", "description": "需要计算的数学表达式", } }, "required": ["expression"], }, }, }, ]

重点解释三个设计:

第一,工具函数必须返回字符串。大模型通过文本方式“读”工具结果,返回字符串最稳妥。如果返回复杂对象,建议先序列化成JSON。

第二,TOOL_SCHEMAS是给模型看的“工具说明书”。模型根据描述决定调用哪个工具、传什么参数。描述写得越清楚,模型的选择越准确。很多Agent效果差,问题就出在工具描述含糊。

第三,calculate中演示了输入校验和安全过滤。在生产环境中,不要直接信任模型生成的表达式,可以进一步限制支持的操作符和数字,或者使用专业的表达式解析库。

5.2 实现Agent运行循环

agent.py中实现ReAct主循环:

# 文件路径:agent-demo/agent.py import json from llm_client import chat_with_tools from tools import TOOLS, TOOL_SCHEMAS SYSTEM_PROMPT = ( "你是一个智能助手。你可以调用工具来获取信息或执行计算。" "如果用户需要查询时间或计算数学表达式,请调用对应工具。" "拿到工具返回的结果后,请用自然语言回复用户。" ) def run_agent(user_input, max_steps=5): """ 运行 Agent 主循环: 1. 把用户请求交给大模型 2. 如果模型请求调用工具,执行工具并把结果返回给模型 3. 循环直到模型给出最终回复或超过最大步数 """ messages = [ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": user_input}, ] for step in range(max_steps): print(f"[step {step + 1}] 调用大模型...") response = chat_with_tools(messages, tools=TOOL_SCHEMAS) message = response.choices[0].message messages.append(message) # 模型没有要求调用工具,说明它给出了最终答案 if not message.tool_calls: return message.content # 模型要求调用一个或多个工具 for tool_call in message.tool_calls: fn_name = tool_call.function.name try: fn_args = json.loads(tool_call.function.arguments or "{}") except json.JSONDecodeError: fn_args = {} print(f" 调用工具: {fn_name}, 参数: {fn_args}") if fn_name not in TOOLS: tool_result = f"工具 {fn_name} 不存在" else: try: tool_result = TOOLS[fn_name](**fn_args) except TypeError as e: tool_result = f"工具参数错误: {e}" # 把工具执行结果写回消息列表 messages.append({ "role": "tool", "tool_call_id": tool_call.id, "name": fn_name, "content": str(tool_result), }) return "已达到最大步骤数,任务未能完成。请简化问题后重试。" if __name__ == "__main__": result = run_agent("现在是几点?顺便计算 23*7+5 等于多少") print("最终回答:", result)

这段代码是整个Agent的最小主链路,理解它比理解任何框架都重要。

运行逻辑可以概括为四步:模型决策、工具执行、结果回流、循环判断。消息列表messages是整个循环的“黑board”,每次对话和工具结果都追加进去,模型能看到完整的推理轨迹。

这里还要解释一个关键细节:message.tool_calls是OpenAI协议中的标准工具调用字段。当模型判断需要调用工具时,它会返回这个字段,而不是直接输出文字。这也是为什么我们不需要自己解析“JSON格式的中间输出”,框架级能力已经由协议层完成。

max_steps是用来防止死循环的安全阀。真实项目中,一个任务的步骤数建议控制在8到15步以内,超过就终止并输出中间状态,避免模型无限循环消耗token。

5.3 命令行验证

先用命令行方式验证Agent是否工作:

python agent.py

预期输出大致如下(具体模型和接口不同,文本可能有差异):

[step 1] 调用大模型... 调用工具: get_current_time, 参数: {} 调用工具: calculate, 参数: {'expression': '23*7+5'} [step 2] 调用大模型... 最终回答: 现在是2026年xx月xx日 14:30:25。另外,23*7+5 的结果是 166。

注意观察输出中的两次步骤:第一步模型决定调用工具,第二步模型拿到工具结果后生成了最终回答。这就是ReAct循环的直观体现。

如果输出卡在中间或报错,先检查以下两点:API密钥是否正确、模型是否支持工具调用。部分轻量模型在工具调用上能力较弱,可以换用支持程度更好的模型再试。

6. 将Agent封装为HTTP服务,实现前后端分离

命令行能跑通,说明Agent运行逻辑正确。但真实项目里,Agent通常作为后端服务提供接口,由前端页面或其他系统调用。这一节用FastAPI封装。

6.1 创建FastAPI服务

# 文件路径:agent-demo/app.py from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from pydantic import BaseModel from agent import run_agent app = FastAPI(title="AI Agent Demo", version="1.0.0") # 开发环境放开跨域,生产环境请收紧为具体域名 app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"], ) class AgentRequest(BaseModel): prompt: str class AgentResponse(BaseModel): answer: str @app.post("/agent", response_model=AgentResponse) def agent_endpoint(req: AgentRequest): answer = run_agent(req.prompt) return AgentResponse(answer=answer) @app.get("/health") def health(): return {"status": "ok"} if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)

代码本身很简单,但有两个地方需要说明。

第一,CORS中间件。如果你是让浏览器中的前端页面直接调用这个接口,一定会遇到跨域问题。开发时可以放开为*,生产环境必须收敛为实际前端域名或网关域名,否则等于向任意网站开放了这个接口。

第二,这里选择了同步接口,Agent执行期间请求会阻塞。真实项目中,如果Agent执行时间较长,应考虑异步任务队列(比如提交任务后返回task_id,前端轮询结果),避免HTTP请求超时。

6.2 编写一个极简前端测试页面

<!-- 文件路径:agent-demo/frontend/index.html --> <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>AI Agent Demo</title> </head> <body> <h2>AI Agent 测试台</h2> <input id="prompt" type="text" style="width:60%; padding:8px;" placeholder="例如:现在几点?顺便计算 23*7+5" /> <button onclick="send()">发送</button> <pre id="result" style="margin-top:20px; font-size:16px;"></pre> <script> async function send() { const prompt = document.getElementById('prompt').value; const resp = await fetch('http://localhost:8000/agent', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({prompt: prompt}) }); const data = await resp.json(); document.getElementById('result').textContent = data.answer; } </script> </body> </html>

这个页面体现了典型的前后端分离思路:前端负责交互,后端负责Agent逻辑。实际项目中,前端可以是Vue、React应用,只要调用同一个HTTP接口即可。

7. 启动服务与效果验证

7.1 启动后端

uvicorn app:app --host 0.0.0.0 --port 8000 --reload

看到如下日志,说明服务启动成功:

INFO: Uvicorn running on http://0.0.0.0:8000 INFO: Application startup complete.

7.2 验证接口

用curl验证Agent接口:

curl -X POST http://localhost:8000/agent \ -H "Content-Type: application/json" \ -d '{"prompt": "今天是几号?帮我计算 128 / 4 + 3 的结果"}'

预期返回JSON:

{"answer": "今天是2026年xx月xx日。128除以4等于32,再加3,结果是35。"}

再验证健康检查接口:

curl http://localhost:8000/health

预期返回:

{"status": "ok"}

7.3 如何判断成功

一个Agent,不只是“能回答”,还要满足三个判断标准:

模型正确识别了需要调用工具。如果用户问时间,模型直接编造一个时间而没有调工具,说明工具调用决策失效。

工具参数传递正确。模型生成的expression应该是一个可执行的数学表达式,而不是自然语言句子。

最终回答基于工具结果。最终答案里的数字和时间,应该来自工具返回,而不是模型凭空生成的。

如果这三条都满足,说明Agent主链路完全打通。

7.4 调试建议

Agent出问题时,第一个该看的地方是“消息列表”。建议在循环里把每一步的messages内容打印到日志,尤其是工具调用和工具结果这两类消息。绝大多数Agent问题,本质都是“模型看到的信息不够准确”或“工具结果格式不清晰”。先看消息里传了什么,再调整提示词或工具描述,比盲目换模型更有效。

8. 从Demo到工程:多Agent协作与AI辅助开发趋势

跑通上面这个最小项目,你已经掌握了Agent的核心主链路。但2026年的行业现实是,单个Agent很少能解决复杂业务问题,工程上更多是“多Agent协作”和“AI辅助开发工具链”的配合。

多Agent不是神秘概念。它只是把不同职责划分给不同Agent:一个Agent负责理解用户、一个负责查数据库、一个负责写代码、一个负责质检。它们之间通过消息队列或共享任务状态协作。理解这些的前提,仍然是你已经理解了单个Agent的运行循环。

同时,AI辅助开发也在从“聊天式”走向“流程化”。近两年出现的Spec驱动开发、技能插件(Skills)等实践,本质上是在解决同一个问题:让AI的输出更可控、更可验证。比如用规范文档(Spec)先把需求、实现方案写清楚,再让编码Agent按规范逐步实现;用技能插件把团队的最佳实践固化下来,供多个Agent复用。这背后对应的工程能力,是需求拆解、接口设计、代码审查和回归测试,这些能力不会因为AI出现而贬值,反而更加值钱。

对开发者来说,一个清醒的判断是:2026年,AI Agent相关岗位的竞争点已经从“会不会调模型API”转移到“能不能稳定交付可维护的Agent系统”。系统设计、工具链集成、可观测性、成本控制、安全边界,这些才是稀缺能力。

9. 常见问题与排查思路

问题现象可能原因排查方式解决方案
模型永远不调用工具,直接编答案模型能力较弱,或工具描述不清晰打印模型返回的完整响应,观察是否生成tool_calls换用工具调用能力更强的模型;重写工具name和description,说明“什么时候用”
工具调用成功,但最终答案与工具结果不一致上下文被截断或提示词约束不够查看最终回答前的tool消息是否完整确认消息列表完整,在系统提示词中强调“必须基于工具结果回答”
调用工具时报参数错误模型生成的参数类型或字段名与工具函数不匹配打印fn_args,对比工具函数签名在工具schema中增加更严格的参数描述;代码中增加TypeError捕获并反馈给模型
接口请求超时Agent执行步骤多,同步接口阻塞查看日志中步骤耗时改为异步任务,前端轮询;收敛max_steps
前端页面调用接口报跨域错误后端未配置CORS浏览器控制台查看错误信息在FastAPI中增加CORSMiddleware
达到最大步骤数仍无法完成任务拆解不当,循环内反复调用同一工具打印每个step的工具调用序列优化提示词引导规划;将复杂任务拆成多个子任务
成本快速上升每次请求携带消息越来越多,token膨胀查看OpenAI账单或调用日志的token数截断早期历史;用摘要压缩历史;限制max_steps

新手上路最需要注意的是最后一行:token成本。Agent的本质是“多次调用模型”,一次任务可能消耗普通对话5到10倍的token。没有成本控制意识的Agent系统,很容易在真实业务里翻车。

10. 最佳实践与工程建议

10.1 工具设计

工具函数要做到“单一职责”,一个工具只做一件事。工具名用动词开头,比如query_ordersend_emailget_weather。工具描述要写清楚“在什么时候调用”,而不是只写功能。工具返回结果尽量结构化,复杂数据转成JSON字符串,便于模型解析。

10.2 提示词管理

系统提示词是Agent的“行为基线”。建议把角色设定、可用工具说明、回答风格、安全约束分块维护,方便后续调整。提示词不要写成一段话,而要用清晰的分节。

10.3 安全边界

这是Agent工程最重要的一件事。让模型能调用工具,意味着把“执行权”交给了模型。生产环境中必须做到最小权限原则:工具函数只开放必要操作,数据库账号只用只读权限,执行类工具必须加审批或二次确认。所有外部输入和工具参数都要做校验,绝不能因为参数来自模型就放松校验。

10.4 可观测性

给每个Agent请求分配一个trace_id,记录完整的消息时间线和每个工具调用的耗时、参数、结果。没有可观测性的Agent系统,在出问题时几乎无法排查。这一步建议在项目初期就做,不要等项目上线再补。

10.5 成本控制

设置单次任务的最大步骤数和token上限,为不同模型设置不同的用量告警。对高频、固定的子任务,考虑用更小更便宜的模型;对复杂推理任务,才使用更强模型。做好分级,整体成本能下降很多。

10.6 测试与回归

Agent的“不确定性”意味着传统用例式测试不够,还需要组合测试和回归测试。每次修改提示词或工具后,都应该跑一遍固定的测试任务集,确保核心能力没有回退。测试集要覆盖正常输入、边界输入、恶意输入三类场景。

11. 总结与下一步学习方向

这篇文章真正讲透的事情是:Agent不是神秘的新技术,它是一条“大模型+规划+工具+记忆+循环”的工程链路。我们用最小项目完整实现了这条链路,没有依赖任何重型框架,因为理解主链路比会用框架重要得多。你也看到了,从命令行到HTTP服务再到简单前端,Agent上线的路径并不复杂,真正的挑战在于工程化:安全、成本、可观测性、测试。

下一步,建议你按这个顺序继续深入:先给这个Demo增加一个新的真实工具,比如查数据库或查天气API;再引入长期记忆,把用户偏好保存到数据库;然后尝试把Agent接入一个真实业务系统;最后再学习多Agent协作框架。每一步都和本文的主链路一脉相承。

很多教程把“学完即就业”挂在嘴边,但就业的本质是你能交付项目。建议你花一周时间,基于本文的骨架做一个自己业务场景的小Agent,把工程细节补全,这比刷十个小时视频更有价值。把这个项目放进简历,面试时能讲清楚Agent运行循环、工具调用机制、安全与成本设计,你就已经超过大多数只会背概念的候选人了。

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

基于RuoYi和Spring Boot的在线智能IoT管理系统搭建指南

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

作者头像 李华
网站建设 2026/9/7 16:49:01

Kali Linux BackTrack Mode 复古化改造完整指南

如果你是从 BackTrack 那个年代一路用过来的老用户&#xff0c;打开新版 Kali Linux 的第一反应大概率和我一样&#xff1a;这界面怎么完全变样了&#xff1f;终端不再是黑底绿字的 rootbt:~# &#xff0c;菜单也不是熟悉的 BackTrack 五个大分类&#xff0c;就连很多老命令都…

作者头像 李华
网站建设 2026/9/7 16:48:41

CS-Notes 剑指 Offer 动态规划:跳台阶问题的递推建模与 O(1) 空间解法

CS-Notes 剑指 Offer 动态规划:跳台阶问题的递推建模与 O(1) 空间解法 【免费下载链接】CS-Notes :books: 技术面试必备基础知识、Leetcode、计算机操作系统、计算机网络、系统设计 项目地址: https://gitcode.com/GitHub_Trending/cs/CS-Notes 本文基于 CS-Notes 仓库中…

作者头像 李华
网站建设 2026/9/7 16:47:39

Windows系统DLL修复工具:解决运行库与DirectX错误

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

作者头像 李华
网站建设 2026/9/7 16:45:53

git reset 超全解析:三种模式、底层原理与实战恢复技巧

我玩 Git 这么多年&#xff0c;git reset是我用得最多、也最容易被它坑过的命令之一。很多 Git 教程会把reset、checkout、revert放在一起讲&#xff0c;结果初学者越看越懵。这篇笔记我不打算面面俱到&#xff0c;就专注讲透git reset这一个命令&#xff1a;它到底移动了什么、…

作者头像 李华
网站建设 2026/9/7 16:44:46

零基础备考系统规划与管理师:别再盲目刷课,跑通闭环才是关键

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

作者头像 李华