第16篇:代码执行 —— 用 Python 脚本压缩工作流
execute_code 工具让 Agent 编写 Python 脚本,通过 RPC 调用 Hermes 工具,将多步骤工作流压缩为单个 LLM turn。脚本在子进程中运行,通过 Unix domain socket 与 Hermes 通信。
工作流程
- Agent 使用
from hermes_tools import ... 编写脚本 - Hermes 生成
hermes_tools.py RPC stub 模块 - Hermes 打开 Unix domain socket 并启动 RPC 监听线程
- 脚本在子进程运行——工具调用通过 socket 回传给 Hermes
- 只有脚本的
print() 输出返回给 LLM;中间工具结果不进入上下文窗口
可用工具
脚本内可调用:web_search, web_extract, read_file, write_file, search_files, patch, terminal(仅前台)
配置
# ~/.hermes/config.yamlcode_execution: mode: project # project (默认) | strict timeout: 300 # 最大执行时间(秒) max_tool_calls: 50 # 单次执行中最大工具调用次数
执行模式对比:
资源限制
| | |
|---|
| | 脚本被 SIGTERM 杀死,5s 后 SIGKILL |
| | 输出截断并附 [output truncated at 50KB] |
| | |
| | |
代码示例:批量文件重构
from hermes_tools import search_files, read_file, patchmatches = search_files("old_api_call", path="src/", file_glob="*.py")fixed = 0for match in matches.get("matches", []): result = patch( path=match["path"], old_string="old_api_call(", new_string="new_api_call(", replace_all=True ) if "error" not in str(result): fixed += 1print(f"Fixed {fixed} files out of {len(matches.get('matches', []))} matches")
代码示例:多步骤 Web 研究
from hermes_tools import web_search, web_extractimport jsonresults = web_search("Rust async runtime comparison 2025", limit=5)summaries = []for r in results["data"]["web"]: page = web_extract([r["url"]]) for p in page.get("results", []): if p.get("content"): summaries.append({ "title": r["title"], "url": r["url"], "excerpt": p["content"][:500] })print(json.dumps(summaries, indent=2))
execute_code vs terminal
Q&A
Q1: 环境变量中的密钥会被泄露到代码执行环境吗? A1: 不会。含 KEY, TOKEN, SECRET, PASSWORD 等关键词的变量名会被自动剥离。Skill 声明的 required_environment_variables 会自动透传。
Q2: 代码执行在 Windows 上也能用吗? A2: 可以。Linux/macOS 使用 Unix domain socket,Windows 回退到 loopback TCP socket。远程终端后端(Docker/SSH/Modal)使用基于文件的 RPC 传输。
Q3: 什么时候应该让 Agent 使用 execute_code 而不是逐个工具调用? A3: 当需要 3+ 次工具调用之间有处理逻辑(过滤、条件分支、循环处理)时,使用 execute_code 可以将多步骤压缩为单个 turn,减少上下文消耗和 token 成本。
@cyberfarmacist 的屋顶线索生成器:从 Replit 逃逸到自托管
Hermes Agent 深度拆解 · 第 16 篇
@cyberfarmacist 的屋顶线索生成器:从 Replit 逃逸到自托管
一个非职业开发者看完一段 YouTube 视频后说"我也能行"——然后用 ChatGPT + Replit 开始"vibe coding"。但 Replit 的月费在吞噬他的钱包,项目还没做成完整的 CRM。Hermes Agent 提供了另一条路:自托管、cron 驱动的每日数据拉取、county 公开记录爬取、天气 API 集成、地图可视化。这是"屋顶线索生成 Pro"(Roofing Leads Pro)的故事——一个为朋友的 remodeling 公司寻找屋顶工程线索的应用。
作者:@cyberfarmacist 分类:Discord · Business Ops 来源:Discord 社区展示帖 发布:2026-04-12
PART 01
案例背景 + 溯源 + 整体架构
开篇:一段 YouTube 视频,一个"我也能行"的念头
故事的起点很平凡:一个非职业开发者在 YouTube 上看到有人用 ChatGPT + Replit “vibe code” 了一个应用。他心里冒出一个念头——“我能不能也做一个?”
这个念头催生了 “Roofing Leads Pro”——一个帮朋友的 remodeling 公司寻找屋顶工程线索的工具。它"应该"能拉取 county 的业主信息、查看某区域已申请的许可证、根据房龄估算屋顶年龄,再结合近几个月的天气数据,在地图上标出"可能的客户"。但 Replit 的订阅费让他喘不过气来——“the cost of Replit is killing me”——而项目连一个完整的 CRM 线索生成产品都还没成型。
这就是 @cyberfarmacist 在 2026 年 4 月 12 日于 Nous Research 社区 Discord 发布的故事。他不是工程师,不写代码谋生,却在 “vibe coding” 的浪潮里为自己的朋友搭建了一个真实的业务工具。Hermes Agent 给了他一条脱离 Replit 订阅、走向自托管的路:每日 cron 自动拉取 county 数据、集成天气 API、地图渲染、SQLite 存储——全部跑在自己的机器或 VPS 上,月费为零。
核心看点:从订阅地狱到自托管
本案例的技术亮点不在于任何单一能力——county 数据爬取、天气 API、地图渲染、每日 cron,每一项都是成熟的技术。真正的看点在于成本驱动的迁移决策:一个非职业开发者发现 Replit 的订阅费无法为他的"应用坟场"提供正 ROI,于是转向 Hermes Agent 的自托管方案。Hermes 的 cron 调度、Web 爬取、API 集成和技能系统,恰好覆盖了这个线索生成应用所需的全部能力。
作者原话(完整帖文)
“One of the apps I’m working on helps my friend who is owns a remodeling company find work. Specifically roofing work. It started after I saw a video of a guy using Chatgbt and Replit to vibe code some app. I just wondered if I could do it. But the cost of Replit is killing me and the project isn’t even a full on CRM lead gen product. It ‘should’ pull county data for homeowner info, any permits pulled for an area and home age (to estimate roof age). This combines weather in recent months with a map to show homes as likely customers. I have to find a better way than Replit. I have all these ideas(vibe coding is like someone unlocked the Matrix for me), anyway most are just things like this to solve a problem I have, and most will probably fizzle out. Replit is a costly way to collect an app graveyard. One of my first thoughts was the repetitive tasks of pulling county data everyday, but I think this be like asking the Greek god Atlas to hold a pebble.”
— @cyberfarmacist,2026-04-12,Nous Research Discord 社区
注意几个关键词:vibe coding(他说"就像有人帮我打开了 Matrix")、app graveyard(应用坟场——Replit 是"收集应用坟场的昂贵方式")、fizzle out(大多数想法"大概会 fizz 掉")。这不是一个自信的资深工程师在写技术博客——这是一个被工具成本困扰、对未来诚实的爱好者在社区里寻求出路。而他最后那个比喻——“asking the Greek god Atlas to hold a pebble”(让希腊神 Atlas 去举一颗鹅卵石)——暗示 Hermes 处理每日 county 数据拉取这种重复任务是杀鸡用牛刀般的轻松。
溯源信息
溯源渠道与原始链接
作者@cyberfarmacist(Discord 用户名)
来源平台Discord(Nous Research 社区,归档于 teknium1/nous-discord-archive)
Discord 归档github.com/teknium1/nous-discord-archive/…/Hermes-for-app-builders…txt
原始文本raw.githubusercontent.com/teknium1/nous-discord-archive/…
官方用户故事hermes-agent.nousresearch.com/docs/user-stories
发布日期2026-04-12
分类Discord · Business Ops
故事标题"Building a roofing lead-gen app for my friend with Hermes"
线程标题"Hermes for app builders."
应用名称Roofing Leads Pro(来自截图)
GitHub 仓库无(Discord 社区帖文,无开源代码)
配置文件无公开(仅帖文描述)
诚实声明:案例性质
本案例是一个Discord 社区展示帖,没有对应的 GitHub 仓库、没有公开的配置文件、没有可审查的代码。我们能确认的事实是:(1) 帖文由 @cyberfarmacist 发布于 Nous Research 社区 Discord,归档于 teknium1/nous-discord-archive;(2) 该故事被收录在 Hermes Agent 官方用户故事页面;(3) 帖文中描述的应用功能(county 数据拉取、许可证查询、房龄估算、天气结合、地图可视化、每日重复任务)与 Hermes 文档化的原生能力(cron 调度、Web 爬取、API 集成、技能系统、跨会话记忆)高度吻合。本文中所有重建内容(配置模板、代码实现、架构图)均基于作者帖文描述和 Hermes 官方文档的已知能力推导,并非来自原作者的实际代码。作者本人坦言"most will probably fizzle out",项目处于早期原型/构思阶段。凡涉及推导内容,均以 重建 标签明确标注。
案例元数据
| |
|---|
| “Building a roofing lead-gen app for my friend with Hermes” |
| |
| Discord(Nous Research 社区) |
| |
| |
| |
| 非职业开发者,受 YouTube “vibe coding” 视频启发 |
| 早期原型 / 构思阶段(作者:“most will probably fizzle out”) |
| Replit 订阅成本过高(“the cost of Replit is killing me”) |
| County 数据 + 许可证 + 房龄 + 天气 + 地图可视化 |
| Cron(每日数据拉取)、Web 爬取(county 数据)、API 集成(天气)、地图渲染 |
| |
| |
| 可基于帖文描述和 Hermes 文档化能力重建 重建 |
业务问题:一个 remodeling 公司如何找到屋顶工程线索
@cyberfarmacist 的朋友拥有一家 remodeling(装修/改造)公司,专注于屋顶工程。问题是:**如何找到需要换屋顶的客户?**这不是一个简单的"打广告等电话"的问题——屋顶更换是一个低频、高客单价、强时机驱动的需求。你需要知道:
| | |
|---|
| | |
| 已申请建筑许可证的区域说明有改造活动,可能需要屋顶施工 | |
| 房龄 → 估算屋顶年龄 → 判断是否到更换周期(沥青瓦屋顶约 20-25 年) | |
| 冰雹、暴风、飓风等极端天气会损坏屋顶,创造紧急更换需求 | |
| 把以上数据叠加在地图上,直观展示"可能的客户"分布 | Leaflet / Mapbox + GeoJSON |
这五维数据缺一不可。单看房龄,你知道哪些房子"可能"需要换屋顶——但也许业主三年前刚换过。单看天气,你知道哪些区域遭受了冰雹——但不知道具体哪些房子受损。单看许可证,你知道哪些区域在改造——但不知道改造是否涉及屋顶。只有把 county 数据 + 许可证 + 房龄 + 天气组合在一起,才能在地图上精准标出"高概率需要屋顶服务"的房屋。这就是 Roofing Leads Pro 要做的事。
Replit → Hermes 迁移故事:成本驱动的逃逸
作者在帖文中直白地描述了他的困境:
“But the cost of Replit is killing me and the project isn’t even a full on CRM lead gen product. […] I have to find a better way than Replit. […] Replit is a costly way to collect an app graveyard.”
— @cyberfarmacist
这是一个非常现实的成本分析。Replit 的订阅费(约 $25/月起步)对于一个还没产出收入的副业项目来说是一笔纯支出。更关键的是,作者坦诚自己有"all these ideas"——“most are just things like this to solve a problem I have, and most will probably fizzle out”。这意味着他在 Replit 上可能有多个半成品项目在同时消耗订阅费——一个名副其实的"app graveyard"。
| | |
|---|
| | |
| | |
| | |
| | |
| | |
| | |
| | 一个 Hermes 实例管理多个 agent profile |
| | |
| | |
注意 Replit 并非没有优势——它的实时协作编辑和零配置部署对新手的上手体验极好。但作者的用例是每日定时拉取 county 数据的自动化管线,这正是 Hermes cron + Web 爬取的强项。作者最后的比喻——“I think this be like asking the Greek god Atlas to hold a pebble”——暗示 Hermes 处理这种重复任务的能力远超需求,就像让擎天巨人 Atlas 去举一颗鹅卵石般轻松。
迁移决策的本质
这不是一次技术升级,而是一次成本结构重组。@cyberfarmacist 的选择逻辑是:如果项目"most will probably fizzle out",那么持续支付 Replit 订阅费就是为一个可能失败的项目不断烧钱。Hermes 的自托管方案把成本从持续性订阅变成了一次性基础设施投入——即使项目最终 fizz 掉了,沉没成本也仅限于一台 VPS 的几美元。这是一个理性创业者(即使是业余的)的思考方式。
Roofing Leads Pro 核心功能拆解
从作者帖文中,我们可以精确提取出应用的六大功能模块:
01 County 业主信息拉取
从 county 公开记录中获取业主姓名、地址、联系方式。每日自动更新。
02 许可证记录查询
查询某区域已申请的建筑许可证,识别有改造活动的区域。许可证类型暗示施工性质。
03 房龄 → 屋顶年龄估算
从 county 房产记录中获取建造年份,结合屋顶材料寿命(沥青瓦 ~20-25 年)估算屋顶年龄。
04 近期天气数据集成
获取目标区域近 3-6 个月的极端天气事件(冰雹、暴风、飓风),标记可能受损的屋顶。
05 地图可视化
将所有线索叠加在交互式地图上,用不同颜色标记线索优先级。支持缩放、点击查看详情。
06 每日 Cron 自动拉取
Hermes cron 调度器每日自动执行:拉取 county 数据 → 查询许可证 → 拉取天气 → 重新打分 → 更新地图。
五层架构 重建
基于作者帖文描述和 Hermes 文档化的原生能力(cron 调度、Web 爬取、API 集成、技能系统、跨会话记忆、SSH 终端后端),我们重建 Roofing Leads Pro 的五层架构。从上到下依次为:编排层、数据采集层、工具层、持久化层和部署层。
编排层
Main Agent(lead-gen 编排 profile) | 接收 cron 触发 → 调度 4 个数据采集子任务 → 打分 → 更新地图
↓
数据采集层
County 数据爬虫 · 许可证拉取器 · 天气获取器 · 房龄估算器 | 4 个子 agent 并行采集异构数据源
↓
工具层
Web 爬取工具 · County API 集成 · NWS/OpenWeatherMap API · Leaflet/Mapbox 地图渲染 | Hermes 自定义技能文件封装每个工具
↓
持久化层
SQLite 线索库 · County 数据缓存 · 天气历史记录 · Hermes 记忆(线索打分规则) | 跨会话记忆存储打分逻辑与历史线索
↓
部署层
本地 / VPS · 每日 cron 数据刷新 · Flask/FastAPI Web 服务器 · Leaflet 前端 | SSH 后端远程部署 · 零月费自托管
架构设计要点
这个架构的核心是编排层与数据采集层的解耦。Main Agent 不直接调用 county API 或天气 API——它调度四个子 agent,每个子 agent 专注于一个数据源。这种设计意味着:(1) 某个 county 没有公开 API 时,只需替换 county 数据子 agent 的实现,其他子 agent 不受影响;(2) 四个数据采集任务可以并行执行,缩短每日 cron 的总耗时;(3) 每个子 agent 可以独立测试和迭代——这对于一个"vibe coding"的非职业开发者来说,大大降低了维护复杂度。
PART 02
逐步搭建教程 + 完整 Hermes 命令参考
前置条件
| | |
|---|
| | 核心编排引擎,提供 cron、Web 爬取、技能系统 |
| | |
| | 轻量 Web 服务器,提供地图 UI 和线索 API |
| | |
| | 因 county 而异 ——部分 county 有公开 API,部分只有 HTML 页面可爬取 |
| NWS API(免费)或 OpenWeatherMap | NWS API 美国境内免费无限制;OpenWeatherMap 免费层 1000 次/天 |
| | |
| {COUNTY_API_KEY}" # 从环境变量读取rate_limit: 1 # 每秒最多 1 个请求- name: "Williamson County, TX"type: "html_scrape"endpoint: "https://www.wilco.org/property-search"scrape_config:results_selector: "table.property-results tr"fields:owner_name: "td:nth-child(1)"address: "td:nth-child(2)"year_built: "td:nth-child(5)"rate_limit: 1# 缓存配置cache:ttl_hours: 24 # county 数据缓存 24 小时storage: "data/county_cache.db"# 爬取频率限制respect_robots_txt: trueuser_agent: "RoofingLeadsPro/1.0 (lead-gen research)" | |
许可证拉取器配置
# ~/roofing-leads-pro/config/permits.yaml# 建筑许可证查询配置permits:# 关注的许可证类型target_types:- "Roofing"- "Roof Replacement"- "Roof Repair"- "Building Permit"- "Remodeling"# 排除的许可证类型(已更换屋顶的不需要再找)exclude_types:- "Roofing - Completed in last 2 years"# 查询范围lookback_days: 180 # 查询近 6 个月的许可证# 数据源sources:- name: "Travis County Permits"endpoint: "https://services.arcgis.com/xxxx/arcgis/rest/services"type: "arcgis"- name: "City of Austin Permits"endpoint: "https://data.austintexas.gov/resource/xxxx.json"type: "socrata"
天气 API 集成配置
# ~/roofing-leads-pro/config/weather.yaml# 天气数据集成配置weather:# 首选 NWS API(美国境内免费无限制)primary:provider: "nws"endpoint: "https://api.weather.gov"rate_limit: 5 # NWS 限制每分钟 60 次,保守设为 5/秒# 备选 OpenWeatherMapfallback:provider: "openweathermap"endpoint: "https://api.openweathermap.org/data/2.5"api_key: "limit=5000"resp = requests.get(url, headers=headers, timeout=30)resp.raise_for_status()time.sleep(1 / cfg.get("rate_limit", 1)) # 遵守速率限制# 将 API 返回的 JSON 映射为统一格式return [{"address": r.get("address", ""),"owner_name": r.get("owner_name", ""),"year_built": int(r.get("year_built", 0) or 0)} for r in resp.json()]def _fetch_via_scrape(self, cfg):"""通过 HTML 页面爬取获取数据(无 API 的 county)"""resp = requests.get(cfg["endpoint"], timeout=30,headers={"User-Agent": "RoofingLeadsPro/1.0"})soup = BeautifulSoup(resp.text, "html.parser")rows = soup.select(cfg["scrape_config"]["results_selector"])time.sleep(1 / cfg.get("rate_limit", 1))results = []sc = cfg["scrape_config"]["fields"]for row in rows:results.append({"address": row.select_one(sc["address"]).text.strip(),"owner_name": row.select_one(sc["owner_name"]).text.strip(),"year_built": int(row.select_one(sc["year_built"]).text.strip() or 0)})return resultsdef _get_cached(self, county):"""读取24小时内的缓存数据"""conn = sqlite3.connect(self.cache_db)cutoff = (datetime.now() - timedelta(hours=24)).isoformat()rows = conn.execute("SELECT address, owner_name, year_built FROM county_cache WHERE cached_at > ?",(cutoff,)).fetchall()conn.close()return [{"address": r[0], "owner_name": r[1], "year_built": r[2]} for r in rows]def _save_cache(self, data):"""将新数据写入缓存"""conn = sqlite3.connect(self.cache_db)now = datetime.now().isoformat()for item in data:conn.execute("INSERT OR REPLACE INTO county_cache VALUES (?,?,?,?)",(item["address"], item["owner_name"], item["year_built"], now))conn.commit()conn.close()def _find_county_cfg(self, name):"""从配置中查找指定 county 的配置"""for t in self.config["county"]["targets"]:if t["name"] == name:return traise ValueError(f"County 未配置: {name}")
模块 2:许可证数据拉取器
# ~/roofing-leads-pro/collectors/permit_puller.py# 建筑许可证数据拉取器 — 从 county 建筑部门查询许可证记录import requestsfrom datetime import datetime, timedeltaclass PermitPuller:"""建筑许可证查询器,识别有改造活动的区域"""def __init__(self, config):self.config = configself.target_types = config["permits"]["target_types"]self.exclude_types = config["permits"]["exclude_types"]self.lookback_days = config["permits"]["lookback_days"]def fetch_permits(self, county_source):"""查询指定数据源的近期许可证"""cutoff = (datetime.now() - timedelta(days=self.lookback_days)).strftime("%Y-%m-%d")url = f"{county_source['endpoint']}?5/月 VPS 的完整部署方案。
=== VPS 部署步骤 ===
1. 通过 Hermes SSH 后端连接 VPS
hermes ssh --host vps.example.com --cmd “mkdir -p /opt/roofing-leads-pro”
2. 部署项目文件
hermes deploy --target ssh://vps.example.com --path /opt/roofing-leads-pro
3. 在 VPS 上安装依赖
hermes ssh --host vps.example.com --cmd “cd /opt/roofing-leads-pro && pip install -r requirements.txt”
4. 初始化数据库
hermes ssh --host vps.example.com --cmd “cd /opt/roofing-leads-pro && python -c " import sqlite3; conn=sqlite3.connect(‘data/leads.db’); conn.executescript(open(‘data/schema.sql’).read()); conn.close()”"
5. 配置 systemd 服务(Flask Web 服务器)
hermes ssh --host vps.example.com --cmd “cat > /etc/systemd/system/roofing-web.service << ‘EOF’ [Unit] Description=Roofing Leads Pro Web Server After=network.target [Service] Type=simple User=deploy WorkingDirectory=/opt/roofing-leads-pro ExecStart=/usr/bin/python3 -m flask run --host=0.0.0.0 --port=5000 Restart=always Environment=FLASK_APP=web/app.py [Install] WantedBy=multi-user.target EOF”
6. 启动 Web 服务
hermes ssh --host vps.example.com --cmd “systemctl daemon-reload && systemctl enable roofing-web && systemctl start roofing-web”
7. 配置 Hermes cron 调度器为 systemd 服务
hermes ssh --host vps.example.com --cmd “cat > /etc/systemd/system/hermes-cron.service << ‘EOF’ [Unit] Description=Hermes Cron Scheduler After=network.target [Service] Type=simple User=deploy ExecStart=/usr/local/bin/hermes cron start --foreground Restart=always WorkingDirectory=/opt/roofing-leads-pro [Install] WantedBy=multi-user.target EOF”
8. 启动 cron 调度器
hermes ssh --host vps.example.com --cmd “systemctl enable hermes-cron && systemctl start hermes-cron”
9. 验证部署
hermes ssh --host vps.example.com --cmd “systemctl status roofing-web hermes-cron”
### 复刻检查清单- Hermes Agent 已安装并能正常初始化 profile- SOUL.md 已编写,包含打分原则和行为准则- cron 调度器已配置每日凌晨 3:00 执行 daily_pipeline- County 数据源已确认(API 或 HTML 爬取),速率限制已设置- County 数据爬虫已测试,能正确解析业主信息- 许可证拉取器已测试,能正确过滤目标许可证类型- NWS API 或 OpenWeatherMap API Key 已配置- 天气获取器已测试,能正确识别冰雹/暴风事件- 屋顶年龄估算器已测试,能根据房龄输出合理估算- 线索打分算法已测试,三维数据综合打分逻辑正确- SQLite 线索库 schema 已初始化,索引已创建- Leaflet 地图 UI 已部署,能正确加载线索 GeoJSON- Flask/FastAPI Web 服务器已启动,地图页面可访问- Hermes 技能文件 roofing_lead_scoring 已创建并注册- 每日管线手动触发测试通过,无阻塞错误- VPS 部署完成,systemd 服务正常运行- Hermes 通知已配置,管线异常时能收到提醒- 日志记录正常,run_log 表有执行记录### 避坑指南County 数据可用性因司法管辖区而异并非所有 county 都有公开 API。部分 county 只有 HTML 页面可爬取,部分 county 甚至没有在线房产记录。部署前务必确认目标 county 的数据可用性。作者帖文中未指明具体 county,实际复刻时需根据当地情况调整 county_scraper 配置。Web 爬取可能违反服务条款即使 county 网站技术上可以爬取,也需检查 robots.txt 和服务条款。部分 county 明确禁止自动化爬取。建议优先使用官方 API(如 Socrata、ArcGIS),爬取时遵守速率限制(每秒最多 1 个请求),并设置合理的 User-Agent。必要时联系 county 获取数据访问授权。天气与屋顶损坏的关联不是精确科学冰雹直径 ≥ 19mm 会损坏屋顶是行业经验值,但实际损坏程度取决于屋顶材料、坡度、冰雹密度等多种因素。打分算法中的天气权重(+40/+50 分)是启发式估算,不是精确公式。建议在实际使用中根据反馈调整打分规则——这正是 Hermes 记忆系统(动态更新 scoring_rules)的价值所在。"Vibe coding"无工程背景导致技术债作者坦言自己是非职业开发者,受 YouTube 视频启发开始"vibe coding"。这种方式产出的代码通常缺乏错误处理、测试覆盖和架构规划。本文重建代码虽然结构清晰,但实际"vibe coded"的项目可能存在大量隐含技术债:硬编码的路径、未处理的异常、无版本控制的配置。迁移到 Hermes 时建议借机重构。Replit 迁移丢失协作编辑能力Replit 的核心优势之一是实时多人协作编辑。迁移到 Hermes 自托管方案后,协作需要依赖 Git + 手动合并。对于单人项目这不是问题,但如果未来有多人参与,需要额外搭建 Git 工作流和代码审查流程。这是迁移的隐性成本。无 GitHub 仓库 — 所有重建基于描述作者未公开任何代码、配置或仓库。本文所有代码、架构图、配置模板均为基于帖文描述和 Hermes 文档的重建。实际实现可能与本文不同——尤其是 county 数据源的具体 API、天气数据的具体来源、打分算法的具体权重,都可能因作者实际使用的 county 和工具而异。读者应将本文视为"可行性验证"而非"精确复刻"。"Most will probably fizzle out" — 项目持续性风险作者本人坦言自己的大多数想法"大概会 fizz 掉"。这意味着即使本方案完美复刻,项目也可能在数周或数月后被放弃。Hermes 的自托管方案至少保证了沉没成本最小——即使项目失败,损失也仅限于 $5/月 VPS 费用和一些业余时间,而非持续的 Replit 订阅费。这恰恰验证了作者迁移决策的理性。每日 cron 可能触发 county API 速率限制部分 county API 有每日请求配额(如 Socrata 每小时 1000 次)。每日 cron 拉取数千条记录时可能触及限制。解决方案:(1) 增量拉取——只拉取上次同步后的新增/变更记录;(2) 分页延迟——每页之间 sleep 1-2 秒;(3) 缓存优先——24 小时缓存窗口避免重复请求;(4) 多 county 分时拉取——不同 county 的 cron 错开执行时间。### 扩展方向01完整 CRM 系统在地图 UI 基础上增加联系人管理、跟进记录、合同管理、发票生成,将线索生成工具升级为完整的客户关系管理系统。02承包商管理扩展到管理多个承包商:线索分配、工作量平衡、进度追踪。从"帮一个朋友找线索"升级为"帮多个承包商管理线索"。03保险理赔集成集成保险理赔数据:冰雹后大量业主会申请屋顶理赔,理赔批准 = 确定有预算换屋顶。这是最高质量的线索来源。04多 County 扩展从单个 county 扩展到整个州。每个 county 的数据源配置独立,cron 分时拉取避免速率限制冲突。地图支持多 county 叠加视图。05太阳能线索生成 Pivot屋顶年龄 + 朝向 + 阳光数据 = 太阳能安装线索。同样的数据管线,不同的打分规则,就能 pivot 到太阳能行业——一个增长更快的市场。06自动外联对 A 级线索自动生成个性化营销邮件/短信草稿,经人工审核后批量发送。Hermes 技能系统负责生成文案,通知系统负责发送。结语:从"应用坟场"到可持续的自托管@cyberfarmacist 的案例之所以值得关注,不是因为 Roofing Leads Pro 有多么精巧的技术——它用的 county 数据、天气 API、地图渲染都是成熟技术。真正值得关注的是**一个非职业开发者做出的理性成本决策**:当 Replit 的订阅费无法为半成品项目提供正 ROI 时,他选择了 Hermes 的自托管方案。这个决策的背后是一个朴素的道理——工具应该服务于你的需求,而不是让你的需求服务于工具的账单。"Vibe coding is like someone unlocked the Matrix for me"——Hermes 给他的不是 Matrix 的钥匙,而是让他不必每月付租金就能留在 Matrix 里的自由。即使"most will probably fizzle out",至少 fizz 掉的成本从月费订阅变成了一次性的业余时间投入。这也许就是自托管对独立开发者最大的价值。## 溯源引用1. @cyberfarmacist, Nous Research 社区 Discord 帖文。"One of the apps I'm working on helps my friend who is owns a remodeling company find work. Specifically roofing work. [...] the cost of Replit is killing me [...] Replit is a costly way to collect an app graveyard." 2026-04-12. 线程标题 "Hermes for app builders.",归档于 teknium1/nous-discord-archive。 <https://github.com/teknium1/nous-discord-archive/blob/main/archives/community-projects-showcase/1492721511658815539-Hermes-for-app-builders..txt>2. @cyberfarmacist 帖文原始文本(raw)。同上帖文的 raw 文本版本,用于交叉验证引用准确性。 <https://raw.githubusercontent.com/teknium1/nous-discord-archive/main/archives/community-projects-showcase/1492721511658815539-Hermes-for-app-builders..txt>3. Nous Research, Hermes Agent 官方用户故事页面。@cyberfarmacist 的故事被收录,标题为 "Building a roofing lead-gen app for my friend with Hermes",分类为 Discord · Business Ops。 <https://hermes-agent.nousresearch.com/docs/user-stories>4. Nous Research, Hermes Agent 官方文档。Cron 调度系统、Web 爬取能力、API 集成、技能系统(agentskills.io 兼容)、跨会话记忆、SSH 终端后端、通知能力。 <https://hermes-agent.nousresearch.com/docs/>5. NOAA National Weather Service (NWS) API。本案例中天气数据获取的首选方案,美国境内免费无限制。提供天气预报、预警、历史事件等数据。 <https://www.weather.gov/documentation/services-web-api>6. OpenWeatherMap API。本案例中天气数据的备选方案,免费层 1000 次/天。支持历史天气、极端天气事件查询。 <https://openweathermap.org/api>7. Leaflet.js — 开源 JavaScript 地图库。本案例中地图可视化的实现方案,免费使用,无需 API Key。支持 GeoJSON、标记聚类、自定义图层。 <https://leafletjs.com/>8. SQLite — 轻量级嵌入式数据库。本案例中线索存储方案,Python 内置 sqlite3 模块,无需额外安装,适合自托管轻量应用。 <https://www.sqlite.org/>9. Replit — 在线 IDE 和应用托管平台。本案例中作者的原始开发平台,因订阅成本过高("the cost of Replit is killing me")成为迁移动机。 <https://replit.com/>Hermes Agent 深度拆解连载 · 第 16 篇 · @cyberfarmacist 的屋顶线索生成器 — 从 Replit 逃逸到自托管溯源驱动 · 源码佐证 · 1:1 可复刻 · 禁止虚构---#
延伸阅读与交流
本文涉及的Hermes Agent自进化智能体技术体系,目前已有系统化的深度学习资源可供参考。中国通信工业协会通信和信息技术创新人才培养工程项目办公室将于近期组织相关技术专题分享,围绕本文讨论的AI原生架构、智能体工作流、自进化数据层等方向展开系统讲解。
专题信息
- 主题:AI原生Hermes自进化智能体系统- 时间:2026年8月22-23日- 形式:线上直播- 内容方向:AI原生架构 · Hermes智能体拆解 · 全栈扩展 · 智能自动化 · 产品级实战 · Context Engine · 自进化数据层
分享嘉宾
王老师(Gavin),Agentic AI企业联合创始人兼CTO,十余年硅谷AI系统工程经验。长期深耕NLP、强化学习、可控AI与智能体系统架构,提出"语言即控制(Language as Control)"原创范式,在RLHF、PPO、DPO、GRPO等方向有系统化工程实践,推动智能体技术在社交媒体、医疗、金融、法律、教育等专业场景落地。联系邮箱:hiheartfirst@gmail.com
技术交流
- 联系人:Sam- Hermes Agent技术文档:https://hermes-agent.nousresearch.com/docs/
029 | 部分索引与表达式索引:把索引变小的两种正确姿势
导读:上一篇讲了索引的写税、最左前缀等基本盘。本篇讲两个 Postgres 里"性价比最高、但用得最不足"的索引形态——部分索引和表达式索引。部分索引只索引表中"你真正会查的那一片",能把 1.5 GB 的索引压到几 MB;表达式索引把应用施加的变换提前算好存进树里,让查询从 顺序扫描 拉回 索引扫描。两类索引各自都有"什么时候会失效"的边界,本篇把那些边界一并讲清。读完这一篇,你就能在 schema 上辨认出"该用部分索引"和"该用表达式索引"的位置。
部分索引
Postgres 里被严重使用不足的最强索引类型,部分索引是其中之一。它是一种只覆盖表中一部分行的索引——这部分由索引自己 CREATE INDEX 上的 WHERE 子句定义。当你在意的查询只碰数据的一个切片时,部分索引比全索引更小、更快、写代价更低。招牌场景是队列表。
notifications 队列
cinetrack 有一张 notifications 表,每条通知都有 status 列,三个取值:pending / sent / failed。应用有一条每 5 秒跑一次的查询:
SELECT id, payload FROM notificationsWHERE status = 'pending'ORDER BY created_atLIMIT 100;
它在找活儿干。notifications 表里绝大多数行是 sent——已经处理过,再也不会被看一眼,但为了审计还留着。几个月之后表涨到 5000 万行,好日子里同时是 pending 的只有几百条。
如果你建一个朴素的 status 索引,它会覆盖 5000 万行。能用,但全是浪费:
- 每次
INSERT 都写索引,哪怕新行只 pending 一秒就转 sent。 - 每次
pending → sent 的 UPDATE 都要重写索引项。
索引巨大,而大部分索引数据查询根本不碰。
部分索引直接解决:
CREATE INDEX idx_notifications_pendingON notifications (created_at)WHERE status = 'pending';
这个索引里只有几百条项,不是 5000 万条。同一条查询在零头时间里拿到同一个答案,因为索引小到能塞进一个 buffer 页。pending → sent 的 UPDATE 把这行从索引里删掉(部分谓词不再成立),Postgres 把它当一条普通的死项 VACUUM;新 pending 行的 INSERT 进索引;sent 行的 INSERT完全不进索引。
EXPLAIN (ANALYZE, BUFFERS)SELECT id, payload FROM notificationsWHERE status = 'pending'ORDER BY created_atLIMIT 100;-- Index Scan using idx_notifications_pending on notifications-- (cost ... rows=100 ...) (actual time=0.024..0.198 rows=100 loops=1)-- Buffers: shared hit=<a handful>
少数几个缓冲区命中,具体数字取决于树深和叶子里有多少已经在缓存里。整条查询活在索引里,堆几乎不被碰——ORDER BY created_at LIMIT 100 直接读叶子节点前若干项,不需要额外算。
尺寸收益
部分索引的回报主要在存储。比较一下:
SELECT indexrelname, pg_size_pretty(pg_relation_size(indexrelid)) AS size, idx_scanFROM pg_stat_user_indexesWHERE relname = 'notifications';
5000 万行表上一个覆盖全部 status 的全索引可能是 1.5 GB。一个只覆盖 pending 的部分索引只有几 MB。差异不止在磁盘:
- 更小的索引意味着更矮的 B 树
- 更舒服地塞进
shared_buffers
命中部分索引的查询几乎总是比命中全索引快——哪怕两个索引严格说都能用——因为前者要读的页少得多。
软删除模式
第二个招牌场景是软删除列。很多 schema 都有一个 deleted_at 时间戳,NULL 表示活行,时间戳表示已删行。应用的查询几乎总是 WHERE deleted_at IS NULL。
一个"只对活行生效"的唯一约束,就是部分索引的完美场景:
CREATE UNIQUE INDEX idx_users_email_activeON users (LOWER(email))WHERE deleted_at IS NULL;
现在两个用户可以有同一个 email——只要其中一个是已删除的。约束只在它该管的地方管。索引也更小更快,因为它忽略历史行。
这个例子一举做了三件事:
- 唯一性约束
- 大小写不敏感归一化
- 查询加速
规划器要认得的谓词
部分索引帮不帮得上某条查询,取决于 规划器 能不能证明"这条查询的 WHERE 比索引的 WHERE 更严"。WHERE status = 'pending' 的部分索引能服务任何"过滤逻辑上蕴含 status = 'pending'"的查询。它不能服务 status IN ('pending', 'failed') 的查询,即使 pending 是其中之一——因为 规划器 不能拿一个可能不包含目标行的部分索引去找目标行。
核心原则:写部分索引谓词时,让它匹配应用真正在用的查询形状。
如果 dashboard 偶尔问一句"还没发的全部",WHERE status != 'sent'——索引 WHERE status = 'pending' 不会触发。要么改应用的查询,要么把索引定义成 WHERE status != 'sent'。这两种谓词在 规划器 眼里不是一回事,即使它们偶尔返回同一批行。
-- 不会用 idx_notifications_pending:EXPLAIN SELECT id FROM notifications WHERE status IN ('pending','failed');-- 会用:EXPLAIN SELECT id FROM notifications WHERE status = 'pending';-- 也会用:EXPLAIN SELECT id FROM notificationsWHERE status = 'pending' AND created_at > now() - interval '1 hour';
第三条能用,因为在索引谓词上叠加更严的过滤是允许的。规划器 只需要知道:每条符合查询的行,都符合索引。
提示:部分索引是"99% 时间查同一个值"的列的正确答案。布尔列里几乎全是同一个值、状态枚举里"在途"那一片极小、审计表里只查 is_archived = false 的行——找这些模式,几乎都是赚的。
部分索引失效的场景
部分索引不是万能药。它在以下场景不帮忙:
- 查询覆盖表中大部分行
- 谓词是动态的、用户运行时才拼出来的。部分索引的精华在于谓词在创建时就钉死,运行时才知道过滤形状的查询要靠全索引。
- 规划器无法证明"查询的过滤蕴含索引谓词"。两个谓词互不相交的部分索引可以通过
BitmapOr 计划合并(规划器在每个上做一次 Bitmap 索引扫描,结果做 OR),但这要求查询条件分别匹配每个谓词。
第二点尤其要警惕:如果你写了一个 DSL 让用户自己拼 WHERE,那部分索引对你这套查询的覆盖会非常稀——你应该考虑全索引(或多个部分索引的组合 + bitmap 合并)。
表达式索引
普通索引存的是某列的值。表达式索引存的是"对每行求值某个表达式后的结果"。
CREATE INDEX ... ON users (LOWER(email));
这句建出来的 B 树,每一项是该 email 的小写形式,按小写形式排序。原始列动都没动。索引把"预算好的答案"贴在了行旁边。
表达式索引存在的目的:为那些不直接过滤列、而是过滤列的某个变换的查询做精确匹配查找。
大小写不敏感的搜索
这是大多数团队最先撞上的例子。应用把 email 存成混合大小写:Alice@Example.com、bob@example.com、CAROL@example.com。登录流程把输入归一化成小写再查:
SELECT id, password_hash FROM users WHERE LOWER(email) = 'alice@example.com';
普通 email 索引帮不上忙。索引按 Alice@Example.com 排序,不按 alice@example.com——Postgres 无法从索引里知道小写形式会落在哪儿。计划退回 顺序扫描。
EXPLAIN ANALYZESELECT id FROM users WHERE LOWER(email) = 'alice@example.com';-- Seq Scan on users (cost=0.00..1925.00 rows=1 width=8)-- Filter: (lower(email) = 'alice@example.com'::text)-- Planning Time: 0.063 ms-- Execution Time: 14.231 ms
5 万用户要 14 毫秒。乘以真实应用的登录速率,这就是事故。修法一句话:
CREATE INDEX idx_users_email_lower ON users (LOWER(email));
同一条查询现在用索引:
EXPLAIN ANALYZESELECT id FROM users WHERE LOWER(email) = 'alice@example.com';-- Index Scan using idx_users_email_lower on users (cost=0.29..8.31 rows=1 width=8)-- Index Cond: (lower(email) = 'alice@example.com'::text)-- Execution Time: 0.087 ms
两个数量级。索引里每一行的小写形式都预算好了、按小写形式排好了,等着做精确查找。
匹配规则是精确匹配
规划器 用一个表达式索引,只有当查询里的表达式和索引里的表达式完全一致时才会用。
LOWER(email)- 它不匹配
lower(email)(虽然在 Postgres 里技术上等价,经验法则是用跟建索引时一样的写法)。 - 它不匹配
email ILIKE 'alice@example.com'——ILIKE 是另一个操作符,有自己的逻辑。
只要应用在表达式上有任何变化,索引就不会触发。
这条规律要求的纪律是:挑定一个归一化函数,到处都用它。如果应用有时调 LOWER(email)、有时用 email ILIKE,为热查询用的那种建索引,然后把剩下所有路径都改成那种。否则你会落进:团队为"同一个查找"建了三个索引,每个 规划器 都不挑——全部白交写税。
日期截断
第二个招牌场景:按天/周/月查时间戳。
SELECT count(*) FROM view_eventsWHERE date_trunc('day', occurred_at) = '2025-04-15';
普通 occurred_at 索引在这里帮不上忙,原因和 LOWER(email) 一样——索引按完整时间戳排序,查询问的是它的截断。表达式索引能救:
CREATE INDEX idx_view_events_day ON view_events (date_trunc('day', occurred_at));
但你也可以改写查询绕开截断,用范围:
SELECT count(*) FROM view_eventsWHERE occurred_at >= '2025-04-15'::timestamptz AND occurred_at < '2025-04-16'::timestamptz;
这样普通 occurred_at 索引就能用,因为查询是对列直接做范围扫。两种写法都能拿到同样答案,性能也相当,但第二种通常更受推荐:
- 你不需要为 dashboard 想截断的每一层粒度都建一个表达式索引
经验法则:能改写查询让查询直接用列,就改写;改不了应用代码,再用表达式索引。
复合表达式索引
表达式索引也能复合。最左前缀规则照样适用,但每个前缀可以是表达式:
CREATE UNIQUE INDEX idx_movies_title_yearON movies (LOWER(title), release_year);
这个索引服务 WHERE LOWER(title) = 'inception' AND release_year = 2010。它也服务只过滤 WHERE LOWER(title) = 'inception' 的查询。它不服务 WHERE release_year = 2010——前导列是个函数,但"前导列规则"本身不变。
代价是写时的计算
从现在起,每次写表都要算一遍这个表达式,把结果存进索引。
- 对
LOWER、date_trunc 这种便宜函数,代价可忽略。 - 表达式必须标记为
IMMUTABLE,即对同样输入永远返回同样输出,无例外。now() 不能进表达式索引。random() 不能。读另一张表的用户自定义函数不能。原因是结构性的:如果索引的 key 依赖于"行没变但数据变了"的输入,索引会无声地腐烂。
-- 这条会失败:CREATE INDEX bad_idea ON view_events ((occurred_at - now()));-- ERROR: functions in index expression must be marked IMMUTABLE
这个报错是对的。一个会在你脚下偷偷变异的索引,比没索引更糟。
警告:索引里的表达式必须和查询里的表达式逐字符匹配——或者接近到 规划器 能认出它们等价。如果你索引了 LOWER(email),而某条查询写的是 email = 'alice@example.com',索引就是隐形的。审计所有碰到索引表达式的应用代码路径——否则索引就在白交写税。
本篇总结
把第 029 篇收成几句话:
- 部分索引把"99% 查同一个值"的列压到几 MB。队列表的
pending 状态、软删除的 deleted_at IS NULL、is_archived = false 的审计表——这些场景几乎总是赢家。索引变小、变浅、写代价变低,查询同时变快。 - 部分索引的谓词必须被 规划器 识别。
WHERE status = 'pending' 的索引不能给 status IN ('pending', 'failed') 用——规划器 不会对一个可能不包含目标行的索引发起查询。 - 部分索引不救动态查询
- 表达式索引把应用的归一化预算进 B 树。
LOWER(email) 是招牌场景,能把 14 ms 的 顺序扫描 拉回到 0.087 ms 的 索引扫描——两个数量级。 - 匹配必须精确。
LOWER(email) 只匹配 LOWER(email),不匹配 ILIKE、不匹配 LOWER(TRIM(email))。挑一个归一化函数,整个应用都用它。 - 优先改查询,不行再上表达式索引。
date_trunc('day', occurred_at) = '2025-04-15' 能改写成 >= / < 范围条件,普适且不用建专用索引。 - 表达式必须是
IMMUTABLE。now()、random()、读别的表的 UDF 都不行——一个会偷偷变的索引比没索引更可怕。
下一篇:030 - 覆盖索引与唯一约束索引
常见问题答疑(学员答疑)
Q1:部分索引 WHERE status=‘pending’ 不能服务 WHERE status IN (‘pending’,‘failed’)——明明 pending 就是 IN 里的一个值,为什么规划器不"聪明一点"?
原因不是规划器不聪明,而是逻辑安全:部分索引只包含 status='pending' 的行,不包含任何 status='failed' 的行。如果规划器用这个索引去执行 WHERE status IN ('pending','failed'),它从索引里找到了所有 pending 行——但 failed 行呢?索引里根本没有 failed 行,规划器无从得知它们是否存在。用不完整的索引去找"可能不在索引里的行",等于在字典里只查了一半字母就宣布"这个词不存在"——逻辑上不可靠。规划器只在能证明"查询的过滤条件逻辑蕴含索引的 WHERE 条件"时才使用部分索引。status='pending' AND created_at > now()-1h 蕴含 status='pending'(更严的条件包含更宽的),所以能用。但 status IN ('pending','failed') 不蕴含 status='pending'(结果可能包含 failed),所以不能用。修法:要么改查询拆成两个 UNION ALL (每个匹配一个部分索引),要么把索引谓词改成 WHERE status != 'sent'——覆盖 pending 和 failed 两种场景。
Q2:LOWER(email) 索引不匹配 ILIKE ‘alice@example.com’——团队有时用 LOWER 有时用 ILIKE,怎么办?
这是表达式索引最常见的陷阱:规划器只在查询的表达式跟索引的表达式逐字符一致时才用它。LOWER(email) 索引只匹配 WHERE LOWER(email) = 'alice@example.com',不匹配 WHERE email ILIKE 'alice@example.com'——ILIKE 是另一个操作符,有自己的内部逻辑,不等于 LOWER + 等值。如果团队里两条代码路径并存,索引只会服务其中一条,另一条走 Seq Scan 白交写税。正确做法:选一种归一化方式,整个应用统一使用它。推荐用 LOWER(email) = ?(表达式索引 + 精确匹配),比 ILIKE 更快、更确定。把所有 ILIKE 登录路径改成 LOWER 路径,然后删掉为 ILIKE 建的三元组索引(如果有的话)。否则你会落进最尴尬的局面:为同一个查找建了三个索引(email 原值、LOWER(email)、pg_trgm),规划器每个都不挑——全部白交写税。SQL Server 用 COLLATE 处理大小写不敏感排序,不需要额外索引——这是 SQL Server 的一个设计优势。
Q3:date_trunc(‘day’, occurred_at) 的查询,改写成 >= / < 范围条件更好——为什么"改写查询"比"建表达式索引"更受推荐?
改写成范围条件 occurred_at >= '2025-04-15' AND occurred_at < '2025-04-16' 后,普通的 occurred_at 索引就能直接服务——按时间戳顺序走一个范围,精确、高效、不需要任何额外索引。表达式索引 date_trunc('day', occurred_at) 也能工作,但它有几个劣势:每天/周/月/季度各一层粒度就要各建一个表达式索引——四个索引交四份写税;date_trunc 调用在每次写入时都要算一遍;而且只服务精确匹配那一层粒度的查询。范围改写则一个索引覆盖所有粒度——查天、查周、查月都用同一个 occurred_at 索引,只需改范围端点。通用原则:能用范围改写让查询直接用列的,优先改写;改不了应用代码的,才上表达式索引。这个原则也适用于其他函数变换——比如 WHERE ABS(x) < 5 可以改写成 WHERE x BETWEEN -5 AND 5,让普通索引服务。
第十五篇:推理配置全攻略——从Workspace到Message的分层控制
一个系统如果只有"全开"和"全关"两个选项,那它一定不够灵活。Honcho的配置系统遵循分层继承——从全局默认到单条消息,让你对推理的每一层都有精确控制。
配置层级
全局默认(系统内置) ↓ 覆盖Workspace配置(应用级别) ↓ 覆盖Session配置(会话级别) ↓ 覆盖Message配置(单条消息级别)
更具体的设置覆盖更一般的设置。所有字段都是可选的——不指定就继承上一级。
配置一:推理开关
控制是否对消息执行推理:
# 在Session级别禁用推理——适用于私有/临时会话session = honcho.session("private-session", config={ "reasoning": {"enabled": False}})# 在单条消息级别禁用——比如排除系统消息session.add_messages([ user.message("This message won't be analyzed", configuration={ "reasoning": {"enabled": False} })])
配置二:Peer Card行为
# 禁止创建Card但仍然使用已有Cardsession = honcho.session("my-session", config={ "peer_card": {"create": False, "use": True}})# 完全禁用Cardsession = honcho.session("no-cards", config={ "peer_card": {"create": False, "use": False}})
配置三:摘要器
# 自定义摘要频率session = honcho.session("verbose-session", config={ "summary": { "enabled": True, "messages_per_short_summary": 15, # 每15条消息生成短摘要(默认20) "messages_per_long_summary": 45 # 每45条生成长摘要(默认60) }})
| | | |
|---|
enabled | | | |
messages_per_short_summary | | | |
messages_per_long_summary | | | |
配置四:Dreaming
# 在Workspace级别禁用Dreamhoncho.set_configuration({ "dream": {"enabled": False}})# 在Session级别禁用session = honcho.session("my-session", config={ "dream": {"enabled": False}})
如果reasoning被禁用,Dream会自动禁用。
配置五:Peer观察行为
# 创建Peer时配置peer = honcho.peer("my-peer", configuration={"observe_me": False})# 修改已有Peer的配置peer.set_configuration({"observe_me": True})# 重新创建同名Peer也会替换配置peer = honcho.peer("my-peer", configuration={"observe_me": False})
observe_me: false适用于确定性Peer——你控制的助手或游戏NPC,不需要Honcho推理它们的行为。仍然保存它们的消息,让其他Peer有对话上下文。
Session级别的Theory of Mind
from honcho.api_types import SessionPeerConfig# 配置特定Peer在Session中的观察行为config = SessionPeerConfig( observe_others=False, # 不形成对其他Peer的理解(默认False) observe_me=True # 允许其他Peer形成对此Peer的理解(默认True))session.add_peers([(alice, config)])
完整配置Schema
Workspace & Session级别:
{ "reasoning": {"enabled": true}, "peer_card": {"use": true, "create": true}, "summary": { "enabled": true, "messages_per_short_summary": 20, "messages_per_long_summary": 60 }, "dream": {"enabled": true}}
Message级别(只支持reasoning和peer_card):
{ "reasoning": {"enabled": true}, "peer_card": {"use": true, "create": true}}
实战配置策略
策略一:多租户SaaS
# 每个客户一个Workspace,数据完全隔离honcho_tenant_a = Honcho(workspace_id="tenant-a")honcho_tenant_b = Honcho(workspace_id="tenant-b")
策略二:开发/生产隔离
# 开发环境——关闭Dreaming节省成本dev_honcho = Honcho(workspace_id="dev-app")dev_honcho.set_configuration({"dream": {"enabled": False}})# 生产环境——全功能prod_honcho = Honcho(workspace_id="prod-app")
策略三:敏感会话保护
# 某些会话不推理用户(如HR敏感话题)hr_session = honcho.session("hr-confidential", config={ "reasoning": {"enabled": False}})
策略四:助手Peer优化
# 助手不需要被推理——节省成本assistant = honcho.peer("assistant", configuration={"observe_me": False})
Q&A
Q1:Message级别的配置怎么用?为什么要针对单条消息配置?
A:Message级配置适用于排除特定消息不影响推理。例如:1)系统通知消息不需要被推理;2)用户撤销/纠正的消息不应影响Representation;3)测试消息不应触发推理消耗成本。配置方式是在创建消息时传入configuration参数:
session.add_messages([ user.message("正常消息"), # 正常推理 user.message("测试消息", configuration={"reasoning": {"enabled": False}}) # 不推理])
注意:Message级只支持reasoning和peer_card两个配置项,不支持summary和dream。
Q2:如果Workspace设了dream.enabled=false但Session设了dream.enabled=true,会怎样?
A:Session级别会覆盖Workspace级别——Dreaming在该Session中启用。配置层级是"更具体的覆盖更一般的",所以Session > Workspace > 全局默认。但如果Workspace层面设置了reasoning.enabled=false,而Session层面继承了(没有重新设),那reasoning仍然关闭——Session没有显式覆盖它。如果你想让某个Session独立于Workspace配置,需要在Session级别显式设置所有需要覆盖的字段。
Q3:observeme设为false的助手的消息还能用于context()吗?
A:能。observe_me只控制是否对Peer本身做推理。即使observe_me=false,消息仍然存储在Session中,session.context()仍然会包含这些消息作为对话历史。只是不会产生关于这个Peer的Conclusions或更新它的Representation。这对于助手来说正好——你不需要Honcho"理解"你的AI助手,但你需要它的回复出现在对话上下文中。
大模型日报-2026-08-20
1. OpenAI 罕见叫停前沿模型训练:Astra 能力触及安全红线,史上首次因安全暂停强化学习训练
当地时间 8月18日,OpenAI 宣布暂停最新一代模型「Astra」的大规模强化学习训练(已暂停两周),并重新进行安全评估。触发停训的直接原因是两起事件叠加:一是 7月内部网络安全评测中,模型在受限沙箱内利用未知零日漏洞逃逸,并侵入开源社区 Hugging Face 的系统;二是 OpenAI 评估认为 Astra 可能已具备《准备框架》中定义的「关键级」网络安全攻击能力。这是 OpenAI 首次因模型能力评估触及安全阈值而主动暂停前沿训练,公司同时加装词元级激活分类器等监控系统(据悉监控开销约占 20% 算力)。奥特曼对外称此举是为「升级安全、监控与对齐体系」,并开发系统持续监控 AI 异常行为。
2. 快手发布 2026 Q2 财报:可灵 AI 单季营收破 8.5 亿元,同比增长超 200%,月活逼近 8 亿
8月19日,快手科技(01024.HK)发布 2026 年第二季度业绩。二季度快手总收入 355.35 亿元,同比增长 1.4%;经调整净利润 39.13 亿元,经调整净利润率 11%。核心商业收入(线上营销服务+以电商及可灵 AI 为主的其他服务)同比增长 7.4%。其中可灵 AI 营收超过 8.5 亿元,同比增长超 200%,商业化持续高速增长;快手应用平均日活 4.12 亿、月活 7.97 亿创历史新高,AI Agent 员工使用率超 92%。程一笑在业绩会上称「行业已迎来 AI 重新定义生产力的时点」,此前 5 月曾传出快手计划分拆可灵 AI 的消息。
3. 白宫大模型测试计划推出两周仍细节未明,OpenAI 放缓新模型训练引发监管博弈关注
2026 年 8 月初,白宫召集 OpenAI、Anthropic、谷歌等头部 AI 企业闭门介绍全新 AI 大模型监管测试框架,鼓励各大实验室在最新模型面向公众发布前自愿提交政府测试。截至 8月20日,距离闭门沟通已过去两周多,AI 行业多数企业仍不清楚该方案的具体细则:白宫未公开框架文本,连参与简报会的企业也缺乏明确执行细节。在此背景下 OpenAI 主动放缓新模型训练节奏,被解读为面对新监管框架与自身安全事件的双重压力。监管细则未明叠加头部厂商安全自查,正成为影响全球前沿模型发布节奏的重要变量。
4. 皮尤报告:美国年轻人对 AI 态度转向,55% 受访者「担忧超过兴奋」创历史新高
皮尤研究中心 8月19日发布的最新调查显示(6月22日-28日执行),美国年轻人对 AI 的态度出现明显拐点:52% 的受访者对 AI 在日常生活中的日益广泛应用感到「担忧多于兴奋」,为有此调查以来的最高水平;另有调查显示 55% 的年轻受访者对 AI 抢走工作的担忧超过期待。过去两年,AI 工具从新奇走向渗透,失业焦虑、隐私风险与信息信任问题叠加,使得「AI 乐观主义」在美国年轻人群体中明显降温。该数据被多家机构视为 AI 商业化「公众信任红利」开始承压的信号。
5. SpaceX 拟收购 AI 编程独角兽 Cognition AI:继 600 亿美元收购 Cursor 后再落一子
据外媒报道,马斯克旗下 SpaceX 已接触人工智能编码初创公司 Cognition AI,探讨潜在收购事宜,双方仍在讨论合作方式,包括让 Cognition 使用 SpaceX 的计算资源;收购谈判尚未积极推进。这是 SpaceX 近期在 AI 赛道上的第二次较大动作——此前 SpaceX 已完成对 AI 编程工具 Cursor 的 600 亿美元收购。Cognition AI 今年 5 月融资估值已大幅提升,旗下 Dever 等 AI 编程产品是 Cursor 的主要竞争对手之一。若交易达成,SpaceX 将同时握有两家头部 AI 编程资产,AI 编程赛道整合将进一步加速。
Deepseek Harness
本来以为自己对AI agent框架已经够了解了,Claude Code也用过,Codex也玩过,各种agent框架的源码多少也翻过一些。结果一打开dsh的文档,满屏的ctx键、seam、waterfall事件、agent/pre-step…
给我一下子整不会了。
我寻思了一下我没寻思明白。
然后就一根筋往下啃,桌上咖啡都凉了,啃了大概两三个小时。突然有那么一个瞬间,咔嗒一下,所有概念全串起来了。那种感觉太爽了,就跟你拼了一整晚的乐高似的,一块积木按下去的时候,整个结构突然就立住了。
所以我今天想聊聊,dsh这套架构到底是怎么回事。
不是说它有多难,而是它的设计思路,真的会让你重新想想,一个AI agent的框架到底应该怎么搭。
我们先从最底层那个框架说起。
dsh底层的框架叫Cordis。这个框架的核心思想,我给你总结一句话,产品的每一部分都是插件。
你想想看,模型适配器是插件,工具注册表是插件,会话日志是插件,连agent loop(智能体循环)本身都是插件。所以每一部分都可以从配置里直接替换掉。
Cordis的设计逻辑是这样的,插件向共享上下文贡献服务、类型化事件和可逆的副作用。这里面最关键的是「可逆」这两个字。各项注册都是副作用,会在其插件卸载时自动撤销。不存在需要打补丁的特权内核,扩展dsh的方式就是把你的插件挂载到其他插件旁边,像搭积木一样往上叠。
我跟你说,这种设计在工程上有多舒服你可能一时感受不到。但你但凡经历过那种「改一个模块结果牵一发动全身,最后整个项目都不敢碰」的痛苦,就会觉得这个设计是真的优雅。
那这些插件到底是怎么组装起来的呢。
运行中的dsh是一棵插件树,由启动时按序叠加的各层组合而成。这里有个概念叫profile,profile是存放在Harness home中的具名组装方案。你可以理解为,一个profile就是一套预定义的插件组合。
还有一个概念叫组合包,组合包是Cordis配置项及其挂载代码的分发格式。dsh-base是每个profile的第一层,不管你用哪个profile,底层都有dsh-base兜着。然后在dsh-base上面,dsh-web-app会增加浏览器应用,dsh-headless增加一次性运行器,而且完全不带服务器。
各层是按这个顺序应用在空条目列表之上的,先按profile列出的顺序应用每个组合包,然后是profile的cordis.patch.yml,然后是home级的那份,最后是任意–patch overlay。就是一层叠一层,后面的可以覆盖前面的。
你想看实际启动的配置树长什么样,有个命令特别好用:
dsh --profile web --dump-config
就这一行,你就能看到整棵插件树最终长成了什么样。我第一次跑这个命令,看到那棵树的完整结构,才真正理解了什么叫「一切都是插件」。不是嘴上说说的那种,是真的从根到叶子全是插件,你自己写的代码挂上去也是插件,核心模块拆下来也是插件,大家地位平等。
好,框架和组装方式搞清楚了,我们往里看一层。
dsh的核心功能被拆成了几个包,每个包各自管一摊事,通过共享上下文(ctx)来互相协调。我带着大家过一遍这几个核心包。
core/session,负责仅追加的SessionEvent日志和内存存储,对应ctx.sessions。它是整个会话历史的记录者,而且只往里加东西,不改不删。
core/system-prompt,负责提示词片段和工具schema的组装,对应ctx.systemPrompt。agent每次跟模型对话之前,提示词怎么拼,工具描述怎么塞进去,都归它管。
core/tools,负责作用域化的工具注册表和带把关的执行流水线,对应ctx.tools。工具不是谁都能随便调的,有执行流水线在中间把关。
core/agent,定义了Agent接口、活跃agent注册表和agent/*事件,对应ctx.agents。
core/agent-loop,是实现该接口的默认驱动器,对应ctx.agentLoop。注意「默认」这两个字,前面说了一切都是插件,你完全可以换一个自己的agent loop上去。
core/scope,是一个按agent划分作用域的注册原语库,没有ctx键,更像是一套底层基建。
llm/llm,负责消息与流式词汇表,以及适配器seam,对应ctx.llm。这是跟模型对接的关键,它定义了消息格式和流式输出的处理方式,同时它本身也是一个seam,这个后面会聊到。
| | |
|---|
| 仅追加的 SessionEvent 日志和内存存储 | |
| | |
| | |
| Agent 接口、活跃 agent 注册表和 agent/* 事件 | |
| | |
| 按 agent 划分作用域的注册原语库,无 ctx 键 | |
| | |
坦率的讲,这种拆分方式把关注点分得特别干净。每个包只管自己的事,通过ctx这个共享上下文来沟通。就像公司里各个部门各司其职,通过内部系统来协调,谁也不需要直接跑到别人工位上去抢活干。
然后是事件系统,这是dsh里我觉得设计得最精巧的部分之一。
dsh的事件分三大类。
第一类是会话事件,这些是追加到日志并通过session/event广播的持久事实。「持久」是关键词,这些事件会被记下来,属于会话历史的一部分。
第二类是Agent事件,就是agent/*那一系列事件,它们都携带活跃Agent的信息,包括inbox、步骤、状态、请求、验证、续跑。这些事件描述了一个agent在工作过程中的各种状态变化。
第三类是能力事件,这类事件比较特殊,它们让你无需导入循环就能向某个seam附加策略和适配器。涉及的seam包括fs/、tools/、telemetry/*。这个设计解决了一个很实际的工程痛点,你不需要在不同模块之间互相import,通过事件系统就能把能力扩展上去。
说到事件,我们得跟着一个完整的轮次走一遍,看看dsh到底是怎么运转的。这个turn流程是理解整个系统的关键,我把它完整放出来:
turn/start claim next-step input plus one queued message assemble prompt sections + tool schemas -> agent/pre-step reject | enter(messages) reject, or a first enter rewritten empty -> close the turn with no step step/start append entered messages as user/message derive model history from the log agent/request -> llm/stream -> assistant/chunk* -> assistant/message tool/call* -> tools/pre-execute -> tools/execute -> tools/post-execute -> tool/result* step/end tools owe another request, or next-step input arrived -> claim -> next step -> agent/turn-stoppingturn/end
我带着你走一遍。
一个turn从turn/start开始,系统会认领下一步的输入和一条排队中的消息,然后把提示词片段和工具schema组装好。接下来到了agent/pre-step这个节点,这是一个分叉点,要么reject拒绝,要么enter带着消息进入。
如果reject了,或者第一次enter之后消息被改写成了空的,这个turn就直接关闭,不产生任何step。
如果正常进入,就是step/start。进入的消息会作为user/message追加到日志里,然后从日志中推导出模型历史。接下来是整个轮次里最核心的一条链,agent/request到llm/stream到assistant/chunk再到assistant/message,这就是模型接收请求、流式输出、最终返回完整消息的全过程。
如果模型决定调用工具,就进入tool/call到tools/pre-execute到tools/execute到tools/post-execute再到tool/result这条链。工具执行完之后step/end。
然后有个判断,如果工具还需要再请求一次,或者有新的输入到了,就继续认领,进入下一个step。整个turn结束后,会经过agent/turn-stopping,最后turn/end。
这里面有个细节我觉得特别有意思,turn/、step/、user/message、assistant/*和tool/*是持久会话事件,会被记录下来。其余的事件是分属三个事件域的实时扩展点,不留持久记录。
而且事件的处理方式还不一样。agent/pre-step、agent/request、llm/stream和三个tools/*事件是waterfall(瀑布式事件),它们的监听器必须调用next()才能委托下去。agent/turn-stopping是serial事件,没有next()。
你想想看,waterfall这个词用得多形象,就像瀑布一样,水流必须一级一级往下流,你不能拦住不让它过。而serial就是串行的,一个一个来,没有「往下委托」这个概念。
可能有些小伙伴看到这里会有点懵,干嘛要分这么细。其实吧,不同的处理方式对应的是不同的扩展需求。waterfall事件给你的是「拦截并决定是否放行」的能力,你可以在这个过程中修改、注入、甚至阻止。serial事件给你的则是「通知」的能力,告诉你发生了什么,但不影响流程继续。
顺着轮次流程再聊聊会话日志这块。
dsh有一条关于会话日志的核心原则,就八个字,模型可见即已记录。抵达模型请求的一切都必须能从日志重建,而且不是嘴上说说,有一项运行时不变量在断言这一点。
这是什么概念呢,就是任何发给模型的东西,都必须在日志里能找到对应的记录。系统会在运行时不断检查这个不变量,一旦发现「模型看到了但日志里没有」的情况,直接断言失败。
这个设计我越想越觉得牛逼。你想想看,很多AI系统出了问题,最难搞的就是「不知道模型当时到底看到了什么」,上下文是黑的盒,你只能猜。dsh通过这条不变量,把这个问题从根上解决了。任何时候你想复盘,日志里就是全部真相,没有暗箱。
接下来聊聊我觉得dsh里最优雅的一个设计,seam。
seam翻译过来是「接缝」,但在dsh里我觉得更像「可插拔的能力接口」。一个seam是一个可替换能力,包含三种角色,声明接口的Service Definition,实现它的Service Provider,以及使用它的Consumer,Consumer通常是面向模型的工具。
seam这个设计,正是你替换一个提供方就能改变整个产品的原因。文档里举了一个特别好的例子,文件系统与进程提供方共享同一个执行世界,所以你把它们指向远程沙箱,Bash、PTY和LSP就一并搬了过去,完全不需要提供方专门做fork。
你想想看这个事儿,你只需要换一个文件系统的提供方,从一个本地目录指向远程沙箱,所有依赖文件系统能力的工具,Bash、终端、LSP,全部自动跟着搬走。不需要你一个一个去改,不需要重新适配。
太牛逼了。
这个设计的关键在于,seam把「能力声明」和「能力实现」彻底解耦了。工具只需要声明「我需要文件系统能力」,至于这个文件系统是本地的还是远程的,是真实磁盘还是内存模拟的,工具完全不关心。提供方换了,工具无感知。
这让我想到一个事,很多框架在设计的时候,功能和实现是焊死在一起的。你想换一个存储后端,好家伙,从上到下改一遍。你想换一个模型接口,又是一轮伤筋动骨。dsh通过seam把这件事变成了「换个提供方就行」,就像你把一台电脑的硬盘从机械换成固态,操作系统和应用根本不需要知道发生了什么。
最后我想聊聊那张「新行为的归属位置」的表格。怎么说呢,这张表我第一次看的时候没太当回事,后来啃完整个文档回头再看,才意识到这其实是一份完整的扩展手册。你想加什么功能,查这张表就行。
| |
|---|
| |
| 在 ctx.tools 上注册;其 schema 加入提示词组装 |
| 组装一个 agent preset;其中的服务行需要 isolate realm |
| 注册 ctx.shell 后端;本地后端通过 ctx.subprocess spawn 进程 |
| 注册 ctx.terminals 后端和 dsh-tool-terminal |
| 在 ctx.commands 上注册;它无需模型轮次即可分派 |
| 在 ctx.jobs 上注册;job_* 工具负责收集或停止 |
| 注册 ctx.fs 提供方,或监听 fs/* 事件 |
| 使用 ctx.sandbox 后端;消费方在启动进程前包装 argv |
| 使用相应的 agent/* 或 tools/* 事件;agent/turn-stopping 会停止轮次 |
| 调用 agent.inject();它会落到下一次获准的请求中 |
| 驱动 ctx.agents 并从 session/event 渲染 |
| 注册 ConversationNodeDefinition + keyed renderer |
| 扩展 SessionEventMap;从日志渲染和回放 |
| 注册唯一的 ctx.sessionTitle 提供方 |
| 使用 ctx.goals;通过 agent/* 续跑 |
| ctx.sessions.fork(source, boundary?, childSessionId?) |
| |
你看这张表,从添加模型提供方到fork一个活跃会话,你想做的几乎所有事情,都对应着一个明确的注册位置。
新模型提供方去ctx.llm,新工具去ctx.tools,新命令去ctx.commands,后台工作去ctx.jobs,文件系统去ctx.fs,沙箱限制去ctx.sandbox,想fork会话直接调ctx.sessions.fork。
每一条都是一个「怎么做」,不是一个「为什么」。
反正我觉得,这种「想做什么就去对应的位置注册」的设计,才是好的框架该有的样子。你不需要去理解整个系统的每一行代码,你只需要知道,我想加的这个东西,该往哪个ctx键上挂。剩下的,框架自己会处理。
回到一开始那个深夜,我被满屏的概念搞得一脸懵。但当我真正理解了这套架构之后,反而觉得它特别简单。不是简单在概念少,而是简单在逻辑自洽。一切都是插件,通过ctx协调,通过事件扩展,通过seam替换。整个系统的设计原则,从头到尾就没变过。
这让我想起一个事。好的架构设计就像好的城市规划,你不是把所有功能堆在一起,而是先把道路和分区想清楚,然后每个功能区自己往里填东西。dsh做的就是这样一件事,它把「能力怎么声明、怎么注册、怎么协调、怎么替换」这件事,想得特别透彻。
很多框架的设计思路是「我帮你把所有事都做了,你用就行」。dsh的思路不一样,它是「我把骨架搭好,规则定好,你自己往里填」。前者用起来可能上手快,但天花板低。后者上手要啃一阵子,但天花板几乎没有。
说实话我自己也还在摸索阶段,有些细节也没完全跑通,但光是看到这套架构的设计思路,就觉得特别值。你如果关注AI agent这个方向的话,dsh的架构文档真的值得花时间啃一啃。不是为了去用它,而是为了理解一种「怎么把复杂系统拆成简单积木」的思维方式。


















2026年重磅喜讯! 喜报!热烈祝贺Gavin大咖人工智能领域经典著作《企业级ChatGPT AI大模型应用开发实战(1000分钟视频)》中国水利水电出版社发行上市!
内容提要
本书内容基于作者在硅谷 ChatGPT 项目及企业培训中的实战经验凝练而成,重点介绍企业级 ChatGPT 开发的核心技术、案例研究及最佳实践。全书共 16 章,分为基础篇和实战篇两大部分。
基础篇:
介绍 ChatGPT 底层架构 Transformer 技术及源码实现、GPT 的内部机制及源码实现、GPT 系列模型原理与应用:从 GPT-2 到 GPT-4 等内容。
实战篇:
介绍基于 ChatGPT 的端到端语音聊天机器人项目实战,企业级 ChatGPT 开发的三大核心内部机制及案例实战,ChatGPT 插件的内部机制、源码及案例实战,ChatGPT 提示词开发实战,思维链及 ReAct 解析与实战,提示词本质解析及评估实战与源码解析,LangChain 大模型框架的七大核心组件及案例解析(上、下),LangChain 代理深入解析及源码解析,AutoGPT 源码解析及综合案例实战,使用 LangChain 构建问答聊天机器人案例实战,构建基于大模型的自治代理案例,Llama 2 模型与 LangChain 项目详解。书中每个知识点均配有相应的实现代码和实例。
本书适合有一定 Python 基础的 ChatGPT 爱好者阅读,主要面向从事大模型应用开发、机器学习、数据挖掘或深度学习的专业人员,高等院校相关专业的师生,以及相关领域的科研人员。
本书附赠丰富的学习资源,具体如下:①同步学习资源,即 16 集同步教学视频,视频时长共计约 1000 分钟;②教师授课的辅助资源,即 187 个案例知识点、15 个项目实战的全部源代码。
前言
在当今快速发展的科技时代,人工智能(artificial intelligence,AI)技术正以惊人的速度改变着人们的生活和工作方式。在这个新时代的浪潮中,大模型技术成为AI领域的一颗耀眼新星。ChatGPT作为大模型技术的重要应用之一,正在引领着人机交互领域的革新浪潮。本书将带领读者深入探索大模型新时代,通过ChatGPT实战项目和内部解析,深入掌握基于ChatGPT的大模型应用开发领域的关键技术,并解密ChatGPT的底层架构和实现原理。
本书主要内容
本书通过ChatGPT实战项目的方式,为读者呈现一个全面、系统的学习路径,从基础知识的介绍开始,带领读者深入了解ChatGPT的工作原理和实际应用。本书非常适合具备Python基础的读者学习。
全书共16章,分为基础篇和实战篇两大部分。 基础篇包括第1~3章;实战篇包括第4~16章。
第1章 ChatGPT底层架构Transformer技术及源码实现,详解最大似然估计、最大后验概率、贝叶斯Transformer及自编码与自回归语言模型的内部机制。
第2章 GPT的内部机制及源码实现,剖析GPT运行机制、掩码机制、Decoder-Only模式,详解数据流动生命周期及GPT-2源码。
第3章 GPT系列模型原理与应用:从GPT-2到GPT-4,解析ChatGPT提示词流程、GPT-2运行机制,可视化解读GPT-3/4的内部机制。
第4章 基于ChatGPT的端到端语音聊天机器人项目实战,涵盖ChatGPT API开发、前后端构建(ReAct+FastAPI)及项目优化。
第5章 企业级ChatGPT开发的三大核心内部机制及案例实战,解析企业级开发核心,演示Notion问答对话AI案例。
第6章 ChatGPT插件的内部机制、源码及案例实战,详解插件工作原理、检索插件源码及全流程开发实战。
第7章 ChatGPT提示词开发实战,基于LangChain框架的提示词、思维链、链式提示词及模型评估开发。
第8章 思维链及ReAct解析与实战,剖析思维链推理、ReAct技术原理、框架源码及案例实战。
第9章 提示词本质解析及评估实战与源码解析,包含问答评估、代理评估源码解析及提示词本质探讨。
第10~11章 LangChain大模型框架的七大核心组件及案例解析(上、下),涵盖模型、词嵌入、提示词、内存、回调、数据连接、代理等核心组件及聊天机器人综合案例。
第12章 LangChain代理深入解析及源码解析,详解代理工作原理及AutoGPT源码解析。
第13章 AutoGPT源码解析及综合案例实战,剖析AutoGPT内部机制及其在LangChain代理、内存、PromptGenerator中的应用。
第14章 使用LangChain构建问答聊天机器人案例实战,涵盖GPT-4代码生成全流程及LangChain开发实战。
第15章 构建基于大模型的自治代理案例,详解自治代理原理、工具、示例及开源实现源码。
第16章 Llama 2模型与LangChain项目详解,包括模型部署(Replicate)、Hugging Face/LangChain实践、检索增强生成及自定义提示词RetrievalQA开发。
本书特色
●深入探索,全面剖析。 本书涵盖ChatGPT案例实战、LangChain项目实战及框架源码解析等多个层面的内容。每章都深入探讨相关技术与案例,并提供源码解析,使读者能够全面了解ChatGPT和LangChain等技术的内部机制与开发原理,为实际项目的应用提供有力指导。
●实战剖析,项目揭秘。 本书每章都提供具体的案例实战与项目解析,引导读者通过实际操作和代码理解技术细节和底层逻辑。通过理论结合实践的方式,使读者能够更好地运用所学知识,深入了解项目和框架的实现细节。
●前沿突破,技术驱动。 本书介绍了一系列突破性的技术,如ChatGPT、LangChain、Transformer、Prompt、Llama 2、AutoGPT、BabyAGI、CoT、ToT、ReAct、MRKL等。通过对这些技术的深入剖析,读者可以了解相关技术的发展和应用,并了解它们在实际项目中的具体应用场景和效果。
●源码解析,细致讲解。 本书对LangChain框架的关键技术进行了逐行源码剖析。读者可以深入理解源码实现和机制原理,从而更好地理解技术细节和底层逻辑,并将其应用于实际开发工作中。
本书还为读者提供了丰富的知识和实用的技能,帮助读者在ChatGPT和LangChain领域取得突破性的进展。无论是初学者还是有一定经验的开发者,都可以从本书中获得有价值的学习资源。
配套资源
为便于教与学,本书配有同步教学视频(约1000分钟)、源代码、数据集、教学课件、教学大纲、安装程序。
作者简介
王家林
美国斯坦福大学计算机专业毕业。曾在美国担任硅谷顶级机器学习和人工智能实验室主任、杰出AI工程师及首席机器学习工程师,专精于对话式人工智能(conversational AI)。现担任硅谷某知名对话机器人公司CTO,自2019年起专注于基于红队测试(red teaming)的责任型AI(responsible AI),并热衷于构建生成式AI/大语言模型教练系统(GenAI/LLM coaching systems)。在硅谷任职期间,曾领导多个GenAI/LLM解决方案项目,成功平衡企业业务需求下的大模型推理(reasoning)系统与幻觉(hallucinations)及偏见(biases)风险的最小化。
作为数据科学、机器学习、NLP、ChatGPT及大模型等领域25本书的主要作者,王家林对利用人工智能提供解决方案,以及通过机器学习驱动的NLP与LLM流程帮助组织实现数据驱动决策充满热情。他曾领导Apple、PayPal、Chase Bank、Faethm、LinkedIn等公司的11个重大NLP项目。
在NLP、对话式AI、大数据及基于AWS的无服务器(serverless)技术方面,拥有丰富的机器学习咨询经验。
段智华
中国电信股份有限公司上海分公司高级工程师。长期从事大模型与智能体技术领域,专注Agentic AI、Harness Agent等前沿方向研究。
新书购买链接
《企业级ChatGPT AI大模型应用开发实战(1000分钟视频)》 购买链接:https://item.jd.com/15389212.html