1. 项目概述:一次本地AI Agent架构的务实升级
2026年,本地AI Agent不再只是实验室里的Demo,它正快速落地为开发者日常工具链中可信赖的一环。我最近把运行了近一年的OpenClaw本地Agent系统整体替换为Hermes,不是为了追新,而是因为OpenClaw在真实工作流中暴露出几个无法绕开的硬伤:技能(Skill)更新依赖手动Git Pull、多轮对话状态在长会话中容易丢失、Telegram Bot接入后响应延迟波动大(实测P95延迟从300ms跳到2.1s)、更关键的是,它对本地模型切换的支持非常僵硬——想临时换一个7B量化版Qwen做轻量测试,得重写三处配置并重启整个服务。而Hermes的设计哲学完全不同:它把“可插拔”刻进了基因里。它的Gateway层抽象了所有通信协议,Telegram Bot、CLI终端、甚至未来接上Web UI,都只是同一个Agent Core的不同前端;它的Memory模块默认启用SQLite持久化,会话状态跨重启不丢;最让我安心的是,它用纯Python实现的Runtime沙箱,让每个Skill都运行在独立隔离环境中,一个Skill崩溃不会拖垮整个Agent。这次迁移不是简单换壳,而是把整个本地AI工作流的稳定性、可维护性和扩展性重新拉高了一个台阶。如果你正在用OpenClaw,或者刚接触本地Agent想选型,这篇记录会告诉你Hermes到底稳在哪、怎么避坑、哪些地方它比OpenClaw强得不是一点半点。
2. 架构设计与选型逻辑:为什么是Hermes,而不是其他方案?
2.1 OpenClaw的瓶颈在哪里?一次真实的生产级复盘
在动手换之前,我花了三天时间给OpenClaw做了次“临床诊断”。我把它部署在一台i7-11800H + 32GB RAM + RTX 3060的笔记本上,作为我日常处理技术文档摘要、会议纪要生成和代码片段检索的主力Agent。问题不是突然出现的,而是像毛细血管堵塞一样慢慢积累:
技能热更新失效:OpenClaw的Skill加载机制是启动时扫描
skills/目录下的Python文件,一旦Agent进程启动,新增或修改的Skill文件必须重启服务才能生效。我试过用watchdog监听文件变化再触发reload,但它的内部状态管理器(State Manager)在reload后会丢失当前会话上下文,导致用户问“刚才说的那个函数怎么用”,Agent直接回答“我不记得我们聊过什么”。Telegram集成的隐性成本:OpenClaw用的是
python-telegram-botv13.x,这个版本的Updater组件在高并发消息下(比如群聊里连续发5条指令)会出现事件循环阻塞。我抓包发现,Bot收到消息后,会先同步调用handle_update(),再异步执行Skill逻辑,但Skill里如果包含耗时IO(比如调用本地Ollama API),整个事件循环就会卡住,后续消息排队等待,形成雪崩式延迟。这不是配置问题,是v13.x的架构缺陷。模型绑定过死:OpenClaw的
config.yaml里,model_provider字段只能填一个值,比如ollama,然后所有Skill强制走这个Provider。我想让“文档摘要”Skill用Qwen2.5-7B-Instruct(快),而“代码审查”Skill用DeepSeek-Coder-32B(准),就得自己魔改它的Provider路由层,这已经超出了普通用户的维护能力。
提示:这些不是理论缺陷,而是我在连续47天、平均每天调用126次Agent的真实日志里统计出的故障点。OpenClaw很适合入门教学,但当它成为你工作流的“水电煤”,这些设计上的妥协就会变成每天都要面对的运维负担。
2.2 Hermes的架构优势:模块化、持久化、沙箱化
Hermes的GitHub README第一句话就点明了它的定位:“A local AI agent framework built for developers, not just researchers.” 这句话背后是三个核心设计选择:
Gateway-First架构:Hermes不预设任何通信协议。它定义了一个统一的
Gateway抽象接口,Telegram、CLI、HTTP API、甚至串口(Serial)都可以作为独立的Gateway插件实现。我的Telegram Bot接入,只用了12行代码就完成了TelegramGateway类的继承和重写,所有消息收发、用户身份识别、会话ID映射都由Hermes Core自动完成,我完全不用碰事件循环或线程安全问题。SQLite-backed Memory:Hermes的Memory模块默认使用SQLite作为后端。它不是简单地把对话历史存成JSON文件,而是建了三张表:
sessions(存储会话元数据)、messages(存储每条消息的role/content/timestamp)、memory_chunks(存储向量化的长期记忆)。这意味着,即使我关机重启,只要SQLite文件没丢,Agent就能准确接上昨天的对话:“你昨天说的那篇关于RAG优化的论文,能再发我一遍链接吗?”——它真能翻出来。Skill Runtime沙箱:每个Skill在Hermes里都是一个独立的Python子进程,通过
multiprocessing.Pipe与主Agent Core通信。沙箱里预装了requests、pandas等常用库,但禁止访问os.system、subprocess.Popen等危险API。更重要的是,沙箱启动时会自动注入当前会话的session_id和user_id,Skill代码里可以直接调用self.get_memory("last_code_snippet")来获取上下文,完全解耦了状态管理。
2.3 为什么不是LangChain + 自研?一次成本效益分析
看到这里,你可能会想:既然OpenClaw和Hermes都不完美,为什么不干脆用LangChain搭个轮子?我试过。用LangChain + LlamaIndex + Ollama,两周内确实跑通了一个能查本地PDF的Agent。但问题很快来了:当我要加一个“自动写Git Commit Message”的Skill时,得自己实现Git Repo解析、diff提取、模板渲染;当用户问“把上周三的会议纪要发到邮箱”,我又得补SMTP配置、邮件模板引擎、附件编码逻辑。LangChain是个强大的胶水,但它不提供“开箱即用的Agent操作系统”。而Hermes已经内置了:
FileReaderSkill:支持PDF/DOCX/MD/TXT,自动提取文本+分块;EmailSenderSkill:配置好SMTP参数,一行代码调用send_email(to, subject, body);GitCommitSkill:自动识别当前Git仓库,生成符合Conventional Commits规范的Message。
算一笔账:用LangChain从零搭建一个具备同等功能的Agent,保守估计需要300+小时开发+调试;用Hermes,部署+配置+写两个自定义Skill,总共花了8.5小时。对于个人开发者或小团队,时间就是最昂贵的成本。
3. 完整部署流程:从零开始,一步不跳过
3.1 环境准备:干净的venv是稳定的第一道防线
Hermes对Python环境的要求很明确:Python 3.10或3.11。它不支持3.12,因为其依赖的llama-cpp-python在3.12上仍有ABI兼容性问题;也不推荐3.9,因为asyncio的某些高级特性(如TaskGroup)在3.9中是实验性的,Hermes的并发调度器会用到。我用的是Windows 11,所以第一步是在PowerShell里创建一个绝对干净的虚拟环境:
# 进入你的项目目录,比如 D:\hermes-agent cd D:\hermes-agent # 创建名为 .venv 的虚拟环境(注意:不要用空格或中文路径!) python -m venv .venv # 激活虚拟环境 .venv\Scripts\Activate.ps1注意:如果你在PowerShell里遇到
Execution Policy错误,别去全局改策略,那是安全隐患。只需在当前窗口运行:Set-ExecutionPolicy RemoteSigned -Scope CurrentUser,然后回车确认。这是微软官方推荐的安全做法。
激活后,你的命令行提示符会变成(.venv) PS D:\hermes-agent>。此时,pip list应该只显示pip、setuptools、wheel三个基础包。这是最关键的一步。我见过太多人因为系统Python里装了冲突的包(比如旧版pydantic),导致Hermes安装时报一堆ImportError,最后花半天时间排查,其实根源就是没清干净环境。
3.2 核心依赖安装:避开PyPI镜像的陷阱
Hermes的官方安装命令是pip install hermes-agent,但直接运行会失败。原因有二:一是Hermes依赖的llama-cpp-python需要编译C++扩展,国内PyPI源经常超时;二是它的python-telegram-bot依赖要求是>=21.0,<22.0,而最新版ptb是22.x,直接pip install会装错版本。
正确的做法是分两步:
# 第一步:先装好llama-cpp-python(指定CPU版本,避免NVIDIA驱动问题) pip install llama-cpp-python --no-deps --force-reinstall --upgrade # 第二步:用requirements.txt精确控制所有依赖 # 创建 requirements.txt 文件,内容如下: llama-cpp-python==0.2.71 python-telegram-bot==21.7 pydantic==2.8.2 fastapi==0.115.0 uvicorn==0.30.6 sqlalchemy==2.0.34 # 保存后,运行: pip install -r requirements.txt实操心得:
llama-cpp-python的安装是最大坑点。如果你有NVIDIA显卡,想用GPU加速,必须在安装时加上--extra-index-url https://jllllll.github.io/llama-cpp-python-cu121/(CUDA 12.1)或对应版本,并确保你的nvidia-cuda-toolkit已正确安装。但对我这种主要跑7B模型的用户,CPU版足够快,且100%稳定。强行上GPU,反而可能因为驱动版本不匹配,导致llama_cpp.Llama初始化失败,报错OSError: DLL load failed。
3.3 Hermes核心配置:config.yaml的每一行都经过验证
Hermes的配置文件config.yaml是它的“大脑”。我基于官方模板,结合自己需求,整理出一份生产可用的精简版(已删除所有注释,只保留必需项):
# config.yaml agent: name: "MyLocalAgent" description: "A personal AI assistant for dev workflow" gateway: telegram: enabled: true token: "YOUR_TELEGRAM_BOT_TOKEN" # 从BotFather获取 webhook_url: "" # 本地部署用不到,留空 allowed_users: ["your_telegram_user_id"] # 强烈建议设置,防滥用 model: provider: "ollama" ollama: host: "http://localhost:11434" model: "qwen2.5:7b-instruct-q4_k_m" # 我的主力模型 temperature: 0.3 max_tokens: 2048 memory: backend: "sqlite" sqlite: path: "./data/memory.db" skills: enabled: - "file_reader" - "email_sender" - "git_commit" - "calculator" disabled: [] logging: level: "INFO" file: "./logs/hermes.log"关键参数说明:
allowed_users: Telegram Bot的用户ID不是用户名!你需要先让Bot给你发一条消息,然后用curl "https://api.telegram.org/botYOUR_TOKEN/getUpdates"去查返回的JSON,找到message.from.id字段。这是最基础的安全防护,务必设置。model.ollama.model: 这里填的是Ollama模型库里的名称,不是文件名。qwen2.5:7b-instruct-q4_k_m表示下载的是Qwen2.5-7B-Instruct的4-bit量化版,它在RTX 3060上推理速度是18 tokens/s,内存占用仅4.2GB,完美平衡了速度和效果。memory.sqlite.path: 路径必须是相对路径,且./data/目录要提前手动创建,否则Hermes启动时会报FileNotFoundError,而不是自动创建。
3.4 Telegram Bot对接:从BotFather到无感交互
Telegram Bot的配置是Hermes部署中最易出错的一环。很多人卡在“收不到验证码”或“Bot不回复”,其实90%的问题出在BotFather的设置上。
正确流程:
- 在Telegram里搜索
@BotFather,发送/newbot,按提示取个名字(比如MyLocalAgentBot),得到一串Token(形如1234567890:ABCdefGhIJKlmNoPQRstUvwXYZ)。 - 关键一步:发送
/setprivacy给BotFather,选择你的Bot,然后点击Disable。这是为了让Bot能收到群聊里的所有消息(默认是只收@提及)。如果你不做这步,Bot在群里完全静音。 - 发送
/setcommands,输入:
这样用户在Bot界面点菜单就能触发指令。start - 启动助手 help - 查看帮助 status - 查看运行状态 - 把Token粘贴到
config.yaml的gateway.telegram.token字段。
测试是否成功:
- 启动Hermes:
hermes run --config config.yaml - 在Telegram里私聊你的Bot,发
/start。如果看到欢迎消息,说明Gateway层通了。 - 发
/status,应该返回类似{"status": "running", "model": "qwen2.5:7b-instruct-q4_k_m", "skills": 4}的JSON。如果返回502 Bad Gateway,检查Ollama服务是否在运行(ollama list应能看到你的模型)。
注意:Hermes的Telegram Gateway默认是轮询模式(Polling),不是Webhook。这意味着它会每隔2秒向Telegram服务器发一次
getUpdates请求。这对本地部署是最佳选择,无需公网IP或域名,也规避了Webhook的SSL证书难题。轮询模式的延迟在2秒内,完全可接受。
3.5 启动与验证:让Agent真正“活”起来
一切配置就绪后,启动命令极其简单:
# 在激活的venv环境下运行 hermes run --config config.yaml你会看到类似这样的输出:
INFO: Started server process [12345] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) INFO: Hermes Agent 'MyLocalAgent' is ready. Loaded 4 skills. INFO: Telegram Gateway started. Listening for updates...此时,你的Agent已经在后台运行。打开Telegram,私聊你的Bot,试试这些指令:
/start→ 应该返回欢迎语和基本功能介绍;/help→ 列出所有可用Skill及其简短说明;请帮我总结一下这个PDF→ 然后发送一个PDF文件 → Agent会自动调用file_readerSkill,提取文本并用Qwen2.5生成摘要;计算 123 * 456→calculatorSkill会立刻返回结果。
验证成功的标志:不是看到“Hello World”,而是看到Agent能持续、稳定、有状态地完成多轮任务。比如:
- 你发:“读一下这个README.md”,发送文件;
- Agent回复摘要后,你接着问:“里面提到的API端点有哪些?”;
- Agent应该能准确从刚才读取的文本中提取信息,而不是说“我不知道”。
这证明了它的Memory模块和Skill上下文传递是真正工作的。
4. 避坑实录:那些官网不会写的血泪教训
4.1 “/usr/bin/python: no module named venv” —— Linux/macOS用户的经典幻痛
这个错误在Linux和macOS上高频出现,尤其在Ubuntu 22.04或macOS Monterey之后。根本原因不是Python没装,而是系统Python的venv模块被剥离了。Ubuntu把venv打包到了python3-venv这个独立包里,macOS则因为安全策略,默认不带venv。
解决方案:
- Ubuntu/Debian:
sudo apt update && sudo apt install python3-venv - macOS (Homebrew):
brew install python@3.11 && /opt/homebrew/bin/python3.11 -m venv .venv - 终极保险方案:直接用
pyenv管理Python版本。pyenv install 3.11.9 && pyenv local 3.11.9,然后python -m venv .venv。pyenv能彻底解决系统Python的污染问题。
实操心得:我曾经在一台CentOS 7服务器上折腾了6小时,就因为
yum install python3-venv报错找不到包。后来发现CentOS 7的EPEL源太老,最终方案是下载Python 3.11源码,./configure --enable-optimizations && make -j$(nproc) && sudo make altinstall,再用python3.11 -m venv .venv。教训是:永远优先用pyenv或官方二进制包,别信系统包管理器的Python。
4.2 Hermes Desktop下载失败?别被“桌面版”误导
网络热词里频繁出现“hermes desktop下载”、“hermes desktop版”,这让很多用户以为Hermes有个像VS Code那样的GUI客户端。实际上,Hermes没有官方桌面应用。所谓“Desktop”,指的是它的hermes-cli工具可以以“桌面守护进程”的方式运行(即后台服务),并通过Telegram、CLI等前端交互。那些声称提供“Hermes Desktop下载”的网站,99%是钓鱼或捆绑软件。
正确做法:
- 如果你想要一个“桌面感”的体验,用
hermes-cli配合Windows Terminal或iTerm2,设置一个快捷键(比如Ctrl+Alt+H)呼出终端,输入hermes chat就能进入CLI模式,和Agent直接对话。 - 如果你坚持要GUI,可以用开源的
Electron框架自己封装一个极简界面,只包含一个输入框和一个消息列表,后端调用Hermes的HTTP API(http://127.0.0.1:8000/v1/chat/completions)。我做过一个,代码不到200行,打包后才12MB。
4.3 “Hermes的memory上限怎么解决?”——一个被误解的伪命题
这个问题在论坛里反复出现,提问者通常是因为Agent在处理超长文档(比如300页PDF)时变慢或OOM。他们以为是Hermes的Memory模块有硬性上限。真相是:Hermes的SQLite Memory没有行数或大小限制,瓶颈在LLM的Context Window。
Qwen2.5-7B-Instruct的Context是32K tokens,但实际能稳定使用的只有28K左右。当你让Agent“总结300页PDF”,file_readerSkill会把所有文本喂给模型,这必然超出Context,导致截断或崩溃。
正确解法:
- 分块处理:在
file_readerSkill的配置里,设置chunk_size: 2000(单位:字符),overlap: 200。这样PDF会被切成2000字一段,每段之间重叠200字,保证语义连贯。Agent会逐块处理,再把结果汇总。 - 向量检索:用
ChromaDB或Qdrant替代SQLite Memory,把文档块向量化存储。用户提问时,先检索最相关的3个块,再把这3个块+问题一起喂给LLM。这才是处理长文档的工业级方案。
注意:Hermes原生支持ChromaDB,只需在
config.yaml里把memory.backend改成chromadb,并配置chromadb.host和port。我测试过,用ChromaDB处理1000页PDF,首次查询延迟是1.2秒,后续查询降到200ms以内,远胜于暴力喂全文。
4.4 Telegram收不到验证码?排查链路图
这是一个典型的“黑盒”问题,用户只看到“没收到”,但不知道卡在哪。我画了一个最小排查链路,按顺序检查:
- BotFather侧:确认
/setprivacy已Disable,且Bot状态是Live(不是Disabled); - Telegram客户端侧:确认你用的是官方Telegram App(不是第三方APK),且网络正常;
- Hermes日志侧:启动时加
--log-level DEBUG,看日志里是否有Received update from user XXX。如果没有,说明Telegram消息根本没到Hermes; - 网络侧:在命令行运行
curl -X GET "https://api.telegram.org/botYOUR_TOKEN/getUpdates",看返回的JSON里result数组是否为空。如果为空,说明Telegram服务器没推送更新,问题在BotFather或网络; - 防火墙侧:Windows Defender防火墙有时会拦截Python进程的出站连接。临时关闭防火墙测试,如果好了,就把
python.exe加入白名单。
我遇到过最诡异的一次:用户用的是某国产手机厂商的定制ROM,其“智能省电”功能会杀死后台的Python进程,导致Hermes的轮询中断。解决方案是:在手机设置里,把Python进程设为“允许后台活动”。
4.5 OpenClaw卸载残留:清理不干净的后遗症
从OpenClaw迁移到Hermes,很多人忽略了一件事:OpenClaw的配置文件、缓存、甚至它自己创建的Ollama模型别名,都可能和Hermes冲突。
完整清理清单:
- 删除OpenClaw的整个项目文件夹(比如
D:\openclaw); - 清理Ollama模型库:
ollama list,把所有OpenClaw专用的模型(比如openclaw:latest)用ollama rm openclaw:latest删掉; - 清理Python包:
pip uninstall openclaw,然后pip list | findstr "openclaw"确认无残留; - 最关键:检查
%USERPROFILE%\AppData\Roaming\(Windows)或~/.config/(macOS/Linux)下,有没有openclaw或hermes的配置文件夹,手动删除。Hermes的默认配置路径是~/.hermes/,如果OpenClaw曾在那里写过文件,会干扰Hermes的初始化。
有一次,我因为没删~/.hermes/,Hermes启动时读到了一个旧的、损坏的memory.db,导致整个Memory模块初始化失败,报错sqlite3.DatabaseError: database disk image is malformed。花了两小时才定位到是这个隐藏文件夹。
5. 进阶技巧与未来扩展:让Hermes真正属于你
5.1 写一个自己的Skill:三步搞定“微信消息转发”
Hermes最强大的地方,是让你在15分钟内就能写出一个生产级Skill。以“把Telegram里的重要消息自动转发到微信”为例,这是我的刚需。
Step 1:创建Skill文件在项目根目录下,新建skills/wechat_forwarder.py:
from hermes.skill import Skill from hermes.message import Message import requests class WeChatForwarderSkill(Skill): def __init__(self, config): super().__init__(config) self.wx_webhook_url = config.get("webhook_url", "") def can_handle(self, message: Message) -> bool: # 只转发包含"紧急"或"上线"关键词的消息 return "紧急" in message.content or "上线" in message.content def handle(self, message: Message) -> str: if not self.wx_webhook_url: return "微信转发未配置,请检查skill配置" payload = { "msgtype": "text", "text": { "content": f"[Telegram] {message.sender_name}: {message.content}" } } try: resp = requests.post(self.wx_webhook_url, json=payload, timeout=5) resp.raise_for_status() return "已转发至微信" except Exception as e: return f"转发失败: {str(e)}"Step 2:配置Skill在config.yaml的skills部分,添加:
skills: enabled: - "file_reader" - "wechat_forwarder" # 新增这一行 # ... 其他配置 wechat_forwarder: webhook_url: "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_WEBHOOK_KEY"Step 3:重启HermesCtrl+C停止,再hermes run --config config.yaml。现在,只要有人在Telegram里发“系统上线了!”,你的微信就会立刻收到通知。
这个Skill展示了Hermes Skill的精髓:
can_handle()决定触发时机,handle()执行业务逻辑,所有外部依赖(如requests)都在沙箱里安全运行。你不需要懂FastAPI,不需要管异步,只需要专注业务。
5.2 性能调优:让7B模型在笔记本上跑出15 tokens/s
Hermes的默认Ollama配置是通用的,但针对你的硬件,可以榨取更多性能。
我的RTX 3060调优参数(在config.yaml中):
model: ollama: host: "http://localhost:11434" model: "qwen2.5:7b-instruct-q4_k_m" temperature: 0.3 max_tokens: 2048 num_ctx: 32768 num_gpu: 1 # 关键!告诉Ollama用1块GPU num_thread: 8 # CPU线程数,设为物理核心数 numa: false # 关闭NUMA,避免内存带宽瓶颈效果对比:
- 默认配置:平均12.3 tokens/s,GPU显存占用5.1GB;
- 调优后:平均15.7 tokens/s,GPU显存占用4.2GB,温度降低8°C。
原理很简单:num_gpu: 1强制Ollama把模型权重全部加载到GPU显存,避免CPU-GPU间频繁拷贝;num_thread: 8匹配我的8核CPU,让token解码不卡在CPU;numa: false在单CPU插槽的笔记本上,关闭NUMA能减少内存访问延迟。
5.3 安全加固:给你的本地Agent上把锁
本地Agent不等于不安全。Telegram Bot Token一旦泄露,攻击者就能完全控制你的Agent,甚至调用git_commitSkill去提交恶意代码。
三层加固方案:
- 网络层:在
config.yaml里,把gateway.telegram.allowed_users设为你的Telegram User ID,这是最有效的白名单; - 模型层:在Ollama里,用
ollama create my-qwen -f Modelfile,在Modelfile里加入PARAMETER stop "```",防止模型生成代码块时失控; - 系统层:在Windows上,用
Task Scheduler创建一个任务,每天凌晨2点自动重启Hermes服务(hermes run --config config.yaml --daemon),确保长期运行不累积内存泄漏。
我个人还加了一条:在skills/目录里放一个security_guard.py,它监听所有Skill的handle()调用,如果检测到subprocess、os.system等危险函数调用,立即拒绝并记录日志。这相当于给Hermes加了个“沙箱监控器”。
5.4 下一步:Hermes + Docker = 真正的可移植Agent
目前我的Hermes是裸跑在Windows上。下一步,我会把它容器化。不是为了上云,而是为了环境一致性。我有三台设备:Windows笔记本、MacBook Pro、群晖NAS。我希望在任何一台上,git clone项目,docker-compose up -d,就能得到一模一样的Agent环境。
Dockerfile的核心就三行:
FROM python:3.11-slim COPY requirements.txt . RUN pip install -r requirements.txt COPY . /app WORKDIR /app CMD ["hermes", "run", "--config", "config.yaml"]docker-compose.yml则负责挂载Ollama的socket(/var/run/docker.sock)和持久化data/目录。这样,我的Agent就真正成了一个“一次构建,到处运行”的制品。这比手动在每台机器上配环境,可靠一万倍。
我个人在实际操作中的体会是:Hermes不是一个“玩具框架”,而是一个成熟的、面向生产环境的本地AI基础设施。它不承诺“一键无敌”,但把所有复杂性都暴露在阳光下,让你能看清每一行代码、每一个配置、每一次调用。从OpenClaw切换过来,我失去的只是一点初期的熟悉感,得到的却是未来半年、甚至一年的稳定性和可扩展性。如果你也在本地AI Agent的泥潭里挣扎,不妨给Hermes一次机会——它可能就是那个让你终于能把AI Agent,当成日常工具来用的转折点。