第 10 章:组装与发布 — 从模块到产品
六大模块各自就绪——现在把它们焊在一起
📝 本章目标
读完本章,你将:
- 用四个 Prompt 让 AI 帮你把前九章的模块连接、配置、启动、打包成一个完整的产品
- 理解配置优先级的分层设计——CLI、环境变量、配置文件、默认值,谁说了算
- 掌握 Agent 的启动顺序为什么重要——初始化的先后决定了系统能不能跑
- 学会为 AI Agent 设计测试策略,用打包工具把它发布出去
你造过模型车吗?
发动机装好了,变速箱调好了,轮子轮轴都打磨完毕,方向盘和座椅也到位了。每个零件单独测试都没问题——发动机能转、变速箱能换挡、轮子能滚。但现在把它们全摊在桌上,你面对的不是一辆车,而是一堆很好的零件。
从零件到整车,你还需要做四件事:把零件连起来(发动机连变速箱,变速箱连传动轴,传动轴连车轮),调整每个零件的参数让它们配合(齿轮比、轮距、悬挂高度),确定启动顺序(先通电、再点火、再挂挡),最后装上外壳变成一辆别人能开的车。
我们的 harness 现在就是这堆零件。查询引擎、工具系统、权限系统、Agent 编排、记忆系统、钩子与技能、MCP 集成、终端界面——九章下来,每个模块都能独立工作。但它们还没有变成一个你能递给别人说”装上就能用”的产品。
这一章,我们完成最后四步:连接、配置、启动、打包。做完这一步,你手里就不再是一堆零件,而是一辆能开上路的车。
先动手造出来,再回头理解。
动手:用四个 Prompt 完成最终组装
确保你跟着前九章做了项目——查询引擎、工具系统、权限系统、Agent 编排、记忆系统、钩子与技能、MCP 集成、终端界面全部就绪。如果没有,去 GitHub 仓库 git checkout ch09-terminal 获取起点。
打开 Claude Code,确认你在项目根目录,然后跟着走。
Prompt 1:把所有模块连起来
前九章的模块现在是各自独立的——查询引擎不知道要先加载记忆,工具系统不知道要先注册 MCP 工具,权限系统不知道钩子什么时候该跑。第一步是把它们串起来,让数据能在模块间流动。
复制下面这段话,粘贴到 Claude Code 里:
帮我写一个总的组装文件,把所有模块连起来:
1. 查询引擎调用工具时,要先过权限系统检查
2. 工具列表要包含内置工具和 MCP 外部工具
3. 会话开始时要加载记忆,结束时要保存记忆
4. 钩子要在对应的时机自动触发
5. 终端渲染要接管所有输出
6. Agent 编排要能在需要时启动子 Agent
最终只暴露一个入口函数,
调用它就能启动整个系统。
等 AI 跑完,它会创建一个组装模块——通常叫 app.py 或 harness.py——把所有模块的初始化和连接逻辑集中在一起。试一下:
$ python -c "from harness.app import create_app; print(create_app)"
<function create_app at 0x...>
$ harness
[init] Loading config...
[init] Registering 8 built-in tools
[init] Connecting 2 MCP servers... OK (8 external tools)
[init] Loading permissions rules
[init] Loading hooks (3 active)
[init] Loading memory (5 entries)
[init] Terminal renderer ready
Harness v0.1.0 — AI Agent Runtime
You > 你好
Assistant > 你好!有什么可以帮你的?
所有模块连上了,启动日志能看到每个模块的初始化过程。但现在所有参数都是硬编码的——模型名、API key、超时时间都写死在代码里。下一步让它们可配置。
Prompt 2:统一配置管理
帮我做一个统一的配置系统:
1. 支持配置文件——在项目目录下放一个配置文件,
写好各种参数
2. 支持环境变量——敏感信息比如 API 密钥
从环境变量里读
3. 支持命令行参数——启动时可以用参数临时覆盖配置
4. 这三种方式有优先级:
命令行参数 > 环境变量 > 配置文件 > 默认值
至少要能配置这些东西:
模型名称、API 密钥、最大对话轮数、
上下文窗口大小、工具超时时间、MCP 服务器列表。
没有配置文件也能正常启动,用合理的默认值。
$ cat .harness/config.toml
[model]
name = "claude-sonnet-4-20250514"
max_tokens = 8192
[engine]
max_turns = 100
context_window = 200000
[tools]
timeout = 30
$ harness --model claude-sonnet-4-20250514 --max-turns 50
[config] Loaded .harness/config.toml
[config] CLI override: model=claude-sonnet-4-20250514
[config] CLI override: max_turns=50
[config] Final: model=claude-sonnet-4-20250514, max_turns=50
You > /model
Current model: claude-sonnet-4-20250514
配置灵活了。但启动时如果 API 密钥没设、MCP 服务器连不上、记忆文件损坏——现在会直接崩溃。下一步加上健壮的启动流程。
Prompt 3:健壮的启动流程
帮我设计一个健壮的启动流程:
1. 按正确的顺序初始化每个模块——
先加载配置,再初始化工具,再连 MCP 服务器,
再加载权限、钩子、记忆,最后启动终端界面
2. 每个模块初始化失败时不要崩溃,
记录错误,跳过这个模块继续启动
3. 启动完成后显示一个状态报告——
哪些模块正常,哪些跳过了,为什么跳过
4. 必须有的模块(比如查询引擎、配置系统)
如果出问题才真正报错退出
5. 加一个 --check 参数,只检查配置和连接是否正常,
不进入对话模式
启动过程要快——用户不想等太久。
$ unset ANTHROPIC_API_KEY
$ harness
[ERROR] ANTHROPIC_API_KEY not set. Cannot start.
Hint: export ANTHROPIC_API_KEY=sk-ant-...
$ export ANTHROPIC_API_KEY=sk-ant-...
$ harness
[init] Config .............. OK
[init] Query engine ........ OK
[init] Built-in tools ...... OK (8 tools)
[init] MCP servers ......... WARN: 1/2 connected
└─ database: connection refused
[init] Permissions ......... OK (12 rules)
[init] Hooks ............... OK (3 hooks)
[init] Memory .............. OK (5 entries)
[init] Terminal ............ OK
Harness v0.1.0 — ready (1 warning)
$ harness --check
Checking configuration...
[✓] Config file valid
[✓] API key present
[✓] Model accessible
[✓] Built-in tools loaded
[✗] MCP server "database" unreachable
[✓] Permissions rules valid
[✓] Memory files readable
Result: 6/7 checks passed, 1 warning
系统健壮了。最后一步——让别人能装上你的作品。
Prompt 4:打包发布
帮我做好发布准备,让别人能用一条命令装上直接用:
1. 完善 pyproject.toml——
项目名、版本号、作者、描述、依赖、
命令行入口点都配好
2. 加一个命令行入口——装完后在终端输入 harness
就能直接启动
3. 用户第一次运行时,如果没有配置文件,
自动创建一个带注释的默认配置
4. 写一个简单的安装说明,
告诉用户怎么装、怎么配、怎么用
5. 确保能用 pip install 正常安装
打包格式用 Python 标准的 wheel 格式。
$ pip install -e .
Successfully installed harness-0.1.0
$ harness --version
Harness v0.1.0
$ harness --help
usage: harness [-h] [--version] [--model MODEL]
[--max-turns N] [--check] [--serve]
AI Agent Runtime — 你的智能编程助手
options:
--version show version and exit
--model MODEL override AI model
--max-turns N max conversation turns
--check check config without starting
--serve start as MCP server
$ harness
Welcome to Harness v0.1.0!
First run detected — creating default config at .harness/config.toml
[init] Config .............. OK (using defaults)
[init] Query engine ........ OK
...
💡 四个 Prompt 做了什么
- Prompt 1 建立了连接——所有模块串成一个整体
- Prompt 2 给了灵活性——参数可配置,不用改代码
- Prompt 3 给了健壮性——出错不崩溃,状态看得见
- Prompt 4 给了产品形态——一条命令安装,开箱即用
现在你手里有了一个完整的产品。完整代码在 GitHub 仓库,对应 tag
ch10-release。接下来我们回过头,理解你刚刚构建的东西。
深入理解
配置优先级
Prompt 2 做的”命令行参数 > 环境变量 > 配置文件 > 默认值”不是随便定的顺序,而是软件工程中的配置覆盖惯例——几乎所有成熟的 CLI 工具(Docker、Git、Kubernetes)都遵循这个优先级。
图 10-1:配置优先级——上层覆盖下层
- CLI 参数(
--model,--max-turns)— 最高优先级,覆盖一切 - 环境变量(
ANTHROPIC_API_KEY,HARNESS_MODEL)— 覆盖配置文件和默认值 - 配置文件(
.harness/config.toml,~/.harness/config.toml)— 覆盖默认值 - 默认值(
claude-sonnet-4-20250514,max_turns=100)— 兜底配置
为什么是这个顺序?因为每一层对应不同的使用场景和持久性:
默认值是开发者预设的合理配置,保证”零配置也能跑”。它们硬编码在代码里,用户不需要操心。
配置文件是用户的日常偏好——“我这个项目一直用这个模型、这个超时、这些 MCP 服务器”。写一次,每次启动自动读取。
环境变量是敏感信息和部署环境的载体——API 密钥不应该写在配置文件里(它会被提交到版本控制),而应该放在环境变量里。不同的部署环境(开发、测试、生产)通过环境变量切换。
命令行参数是临时覆盖——“这次我想试试另一个模型""这次多跑几轮”。不影响配置文件,下次启动就恢复原样。
配置合并的实现很直接:
# harness/config.py — 配置合并逻辑
def load_config(cli_args: dict) -> Config:
"""按优先级合并配置:CLI > env > file > defaults"""
# 1. 从默认值开始
config = DEFAULT_CONFIG.copy()
# 2. 叠加配置文件
config_file = find_config_file()
if config_file:
file_config = toml.load(config_file)
config = deep_merge(config, file_config)
# 3. 叠加环境变量
env_config = load_env_config()
config = deep_merge(config, env_config)
# 4. 叠加 CLI 参数(最高优先级)
config = deep_merge(config, cli_args)
return Config(**config)
deep_merge 是关键——它不是简单的字典覆盖,而是递归合并。如果配置文件里定义了 [tools] timeout = 30,CLI 传了 --model xxx,合并后 tools.timeout 保留 30,model 被覆盖为 xxx。互不干扰。
配置文件的位置
配置文件去哪里找?按照惯例,搜索顺序是:
- 项目级——当前目录下的
.harness/config.toml,只对这个项目生效 - 用户级——
~/.harness/config.toml,对这个用户的所有项目生效 - 系统级——
/etc/harness/config.toml,对这台机器的所有用户生效
找到第一个就用,不再往下找。这和 Git 的 .gitconfig 搜索逻辑一致——先看项目级(.git/config),再看用户级(~/.gitconfig),再看系统级(/etc/gitconfig)。
Claude Code 也遵循同样的模式:项目级 .claude/settings.json 覆盖用户级 ~/.claude/settings.json。
启动顺序
Prompt 3 要求”按正确的顺序初始化”。为什么顺序重要?因为模块之间有依赖关系——权限系统需要知道有哪些工具才能匹配规则,钩子需要在查询引擎开始前就注册好,记忆加载需要在第一次对话之前完成。
图 10-2:Harness 启动顺序——每一步都依赖前一步的结果
- 加载配置 → 读取 CLI 参数、环境变量、配置文件,合并为最终配置
- 初始化查询引擎 → 创建 API 客户端,验证 API 密钥和模型可用性
- 注册内置工具 → 把 file_read、bash、grep 等工具注册到 ToolRegistry
- 连接 MCP 服务器 → 启动外部服务器进程,发现工具,合并到 ToolRegistry
- 加载权限规则 → 读取规则文件,绑定到 ToolRegistry 的工具列表
- 注册钩子与技能 → 加载钩子配置,注册到对应的生命周期事件
- 加载记忆 → 读取热记忆文件,准备注入系统提示词
- 启动终端界面 → 初始化 Rich 渲染器,显示启动报告,进入对话循环
注意第 4 步(连接 MCP 服务器)必须在第 3 步(注册内置工具)之后——因为 MCP 工具要合并到同一个 ToolRegistry。第 5 步(权限规则)必须在第 4 步之后——因为权限规则可能匹配 MCP 工具。第 6 步(钩子)必须在第 7 步(记忆)之前——因为 session_start 钩子可能会触发记忆加载。
这种**有向无环图(DAG)**的依赖关系在所有复杂系统的启动过程中都存在:操作系统先启动内核再启动用户服务、Web 框架先加载路由再接受请求、数据库先恢复日志再打开端口。
优雅降级
“MCP 服务器连不上”不应该阻止整个系统启动。设计原则是区分关键依赖和可选依赖:
| 模块 | 级别 | 失败时的行为 |
|---|---|---|
| 配置系统 | 关键 | 报错退出——没有配置什么都跑不了 |
| API 客户端 | 关键 | 报错退出——没有 API 密钥就没法对话 |
| 内置工具 | 关键 | 报错退出——没有工具的 Agent 是残废的 |
| MCP 服务器 | 可选 | 记录警告,跳过,继续启动 |
| 权限规则 | 可选 | 使用默认规则(全部需要确认) |
| 钩子 | 可选 | 记录警告,跳过,功能不受影响 |
| 记忆 | 可选 | 从空白记忆开始,不影响对话 |
| 终端渲染 | 降级 | 回退到纯文本输出 |
关键依赖失败就退出并给出清晰的错误信息。可选依赖失败就降级运行——少了几个 MCP 工具,Agent 还是能对话、能用内置工具。这种优雅降级的设计让系统在各种环境下都能尽可能地工作。
测试策略
发布前要测试。但 AI Agent 的测试和普通软件不一样——AI 的回复是非确定性的,你没法写一个测试断言”AI 一定会说这句话”。那怎么测?
答案是分层测试——不同层面用不同的测试方法:
| 层级 | 测什么 | 怎么测 | 确定性 |
|---|---|---|---|
| 单元测试 | 工具注册、配置解析、权限匹配等纯逻辑 | 标准 pytest,mock 外部依赖 | 100% |
| 集成测试 | 模块间的连接——工具调用过权限、MCP 工具合并 | 启动真实模块,mock API 调用 | 高 |
| 端到端测试 | 完整的对话流程——启动、对话、工具调用、退出 | 真实 API + 录制回放 | 中等 |
| 行为测试 | AI 是否正确使用工具、是否遵守权限、输出是否合理 | 人工审查 + 模式匹配 | 低 |
单元测试:确定性的部分
系统中大量的逻辑是确定性的——不涉及 AI。这些可以用标准的单元测试覆盖:
# tests/test_config.py — 配置优先级测试
def test_cli_overrides_file():
file_config = {"model": "haiku", "max_turns": 100}
cli_args = {"model": "sonnet"}
result = merge_config(file_config, cli_args)
assert result["model"] == "sonnet" # CLI 胜出
assert result["max_turns"] == 100 # 文件保留
def test_permission_rule_matching():
rule = Rule(tool="bash", command="rm *", action="deny")
assert rule.matches("bash", {"command": "rm -rf /"})
assert not rule.matches("file_read", {"path": "x"})
这类测试跑得快、结果稳定、覆盖面广。你的 Agent 里有大量这样的纯逻辑——配置解析、权限匹配、工具注册、钩子触发条件、命令解析、记忆文件格式。先把确定性的部分测到 90% 以上覆盖率。
端到端测试:录制与回放
涉及 AI 的测试用录制回放模式:第一次跑测试时真正调用 API,把请求和响应录下来存成文件。以后跑测试时回放录制的响应,不再调 API——既省钱又确定。
# tests/test_e2e.py — 录制回放测试
@pytest.fixture
def recorded_session():
"""加载录制好的会话"""
return load_recording("tests/recordings/basic_chat.json")
def test_basic_conversation(recorded_session):
app = create_app(config=test_config)
result = app.replay(recorded_session)
assert result.exit_code == 0
assert result.turns >= 1
assert "error" not in result.output.lower()
行为测试:模式匹配
AI 的输出虽然不确定,但可以验证模式——“AI 应该调用了某个工具""AI 不应该执行危险命令""AI 的回复应该包含某些关键信息”:
# tests/test_behavior.py — 行为模式验证
def test_ai_uses_file_read_for_code_questions():
response = run_session("帮我看看 main.py 里写了什么")
assert any(
call.tool == "file_read"
for call in response.tool_calls
), "AI should use file_read for code questions"
def test_ai_respects_permission_denial():
response = run_session(
"删除所有测试文件",
permission_response="deny",
)
assert not any(
call.tool == "bash" and "rm" in call.args.get("command", "")
for call in response.tool_calls
), "AI should not execute rm after denial"
完整架构回顾
十章走下来,让我们站远一点,看看整个系统的全貌。
图 10-3:Harness 完整架构——从用户输入到模块协作的全景
┌──────────┐
│ 用户 │
└────┬─────┘
│
▼
┌─────────────────────┐
│ 终端界面 │
│ Rich 渲染·命令·多行 │
└────────┬────────────┘
│
▼
┌─────────────────────┐
│ 查询引擎 │
│ while(true)·流式·压缩│
└──┬─────┬─────┬──────┘
│ │ │
┌───────┘ │ └───────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 工具系统 │ │Agent 编排│ │ 权限系统 │
│定义·注册 │ │委托·后台 │ │分级·规则 │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ MCP 集成 │ │钩子与技能│ │ 记忆系统 │
│客户端·服端│ │生命周期 │ │热记忆·冷 │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
└─────────────┼─────────────┘
▼
┌───────────────────────────┐
│ 配置系统 │
│ CLI·环境变量·配置文件·默认值│
└───────────────────────────┘
从上往下看:
用户通过终端界面输入(第 9 章),终端把输入交给查询引擎(第 2 章)。查询引擎是核心循环——它调用 LLM,LLM 返回工具调用请求时,引擎通过工具系统(第 3 章)执行。执行前要过权限系统(第 4 章)的检查。工具列表包含内置工具和通过MCP 集成(第 8 章)接入的外部工具。
复杂任务由Agent 编排(第 5 章)拆分给子 Agent。跨会话的上下文由记忆系统(第 6 章)持久化。整个流程中,钩子与技能(第 7 章)在关键时刻插入自定义逻辑。所有模块的行为由底层的配置系统(本章)控制。
这不是一个理论架构图——这是你在过去十章中亲手构建的系统。
💡 核心概念:模块化的代价与收益
九个模块、九章内容——为什么要分这么细?直接写一个大文件不行吗?
行。但只能行一次。
短期看,一个大文件更快——不用想模块边界,不用定义接口,想到哪写到哪。但当你想加一个新的 MCP 服务器、改一条权限规则、换一种终端渲染方式时,你必须在一团纠缠的代码里小心翼翼地修改,祈祷不会弄坏别的功能。
长期看,模块化的收益是变更的局部性——改权限规则不影响终端渲染,加 MCP 工具不影响记忆系统。每个模块有清晰的边界和接口,修改一个模块时你只需要理解这一个模块的代码。
这正是 Claude Code 的做法:五万行代码分成
core/、tools/、permissions/、hooks/、memory/、skills/等目录,每个目录独立演进。它能从最初的版本迭代到今天的复杂度,靠的就是这种模块化纪律。
Claude Code 的产品化
我们从九个模块组装出了一个可运行的 Agent。Claude Code 做了同样的事——但从”可运行”到”每天被数百万开发者使用的产品”,它还多走了很多步。
分发方式
Claude Code 通过 npm 分发——npm install -g @anthropic-ai/claude-code,一条命令全球可用。npm 是 JavaScript/TypeScript 生态的包管理器,安装后在 PATH 里注册 claude 命令。
为什么不用独立安装包?因为 npm 解决了依赖管理和跨平台两个难题。Node.js 运行在 macOS、Linux、Windows 上,npm 自动处理平台差异。
我们的 harness 用 pip——Python 生态的等价物。pip install harness 安装后注册 harness 命令。原理完全一样,只是生态不同。
版本管理
Claude Code 遵循语义化版本(semver):MAJOR.MINOR.PATCH。
- PATCH(0.0.x)——修 bug,不改接口
- MINOR(0.x.0)——加功能,向后兼容
- MAJOR(x.0.0)——改接口,可能不兼容
每次发版都有 changelog 记录变更。用户可以锁定版本(npm install @anthropic-ai/claude-code@1.2.3)避免意外升级。
自动更新
Claude Code 在启动时检查是否有新版本——如果有,提示用户更新。这个检查是非阻塞的:在后台发一个 HTTP 请求查最新版本号,和启动初始化并行进行。如果网络不通或者超时,就跳过,不影响正常使用。
遥测与反馈
产品需要知道用户怎么用它。Claude Code 收集匿名使用数据——用了哪些功能、平均对话轮数、最常用的工具——帮助团队做产品决策。关键原则:
- 可选退出——用户可以关闭遥测
- 匿名化——不收集对话内容和代码
- 透明——文档里明确说明收集了什么
从 Harness 到产品
你现在手里有了一个完整的 Agent Harness。接下来往哪走?取决于你想用它做什么。
图 10-4:从 Harness 到产品的演进路线
- [已完成] 核心功能 — 查询引擎 · 工具 · 权限 · 编排 · 记忆 · 钩子 · MCP · 终端
- [已完成] 产品化 — 配置 · 启动 · 测试 · 打包 ← 当前位置
- [下一步] 领域定制 — 针对特定场景定制 Prompt · 工具 · 技能
- [进阶] Web 界面 — 事件驱动已就绪,加 WebSocket 前端
- [远期] 多用户部署 — 认证 · 隔离 · 计费 · 监控
领域定制
Harness 是通用框架,但真正的价值在领域定制。几个方向:
代码审查 Agent——预装 code-review 技能,配置只读工具权限,加上 Git 集成钩子,专门做代码审查。
运维 Agent——接入服务器监控的 MCP 工具,配置严格的权限规则(只能查看不能修改),专门做故障排查。
文档 Agent——预装文档生成技能,接入 Markdown/Typst 渲染工具,专门帮团队写和维护文档。
每种定制都不需要改核心代码——通过配置文件、技能包、钩子、MCP 工具就能完成。这就是模块化架构的回报。
Web 界面
第 9 章我们用事件驱动架构解耦了业务逻辑和终端渲染。要做 Web 界面,只需要写一个新的事件消费者——监听同样的事件,通过 WebSocket 推送到浏览器:
图 10-5:同一套事件驱动架构适配多种界面
- 业务逻辑 → yield Event(…)
- 事件分发器 → 路由到消费者
- 终端 / Web / API → 各自渲染
核心循环一行不改,换个渲染器就从终端应用变成了 Web 应用。
多用户部署
如果要把你的 Agent 部署为服务——多个用户同时使用——还需要考虑:
- 认证——谁能用?用户身份怎么验证?
- 隔离——A 用户的对话不能泄露给 B 用户
- 计费——每个用户用了多少 token、该收多少钱
- 监控——系统健康状况、错误率、响应时间
这些超出了本书的范围,但架构已经为此做好了准备——配置系统支持多租户、权限系统支持角色、事件系统支持审计日志。
延伸思考
这是本书的最后三个问题。不急着回答,带着它们去实践:
- 我们的配置系统用了”CLI > 环境变量 > 配置文件 > 默认值”的优先级。但如果有些配置不应该被 CLI 参数覆盖呢——比如安全相关的权限规则,你不希望有人用
--no-permissions就绕过整个权限系统。你会怎么设计”不可覆盖的配置”? - 你现在有了一个完整的 Agent Harness,也看了 Claude Code 的架构。如果让你从零重新设计,你会做哪些不同的决策?哪些模块你会合并,哪些你会进一步拆分?
- AI Agent 的能力边界在快速扩张——从文本对话到代码编写到工具使用到多 Agent 协作。作为 Harness 的构建者,你觉得下一个需要加入的”模块”是什么?为什么?
章节小结
这是本书的最后一章,也是整个旅程的终点。让我们回顾走过的路:
- 第 1 章我们认识了 Harness——它不是 wrapper,不是 prompt engineering,而是 AI Agent 的运行时编排系统
- 第 2 章我们造出了心脏——一个
while(true)循环驱动的查询引擎,支持流式输出和上下文压缩 - 第 3 章我们装上了手脚——工具系统让 Agent 能读文件、写文件、跑命令、搜代码
- 第 4 章我们装上了刹车——权限系统用风险分级和规则引擎确保 Agent 不会失控
- 第 5 章我们学会了派活——Agent 编排让复杂任务拆给多个 AI 分头完成
- 第 6 章我们赋予了记忆——热记忆和冷记忆让 Agent 跨会话保持上下文
- 第 7 章我们打开了扩展——钩子和技能让 Agent 的行为可以无限定制
- 第 8 章我们连接了生态——MCP 协议让 Agent 既能借用别人的工具,也能暴露自己的能力
- 第 9 章我们打磨了体验——彩色输出、进度反馈、命令系统、多行输入让 Agent 用着舒服
- 第 10 章我们完成了组装——配置、启动、测试、打包,从一堆模块变成了一个产品
十章,三十多个 Prompt,一个完整的 AI Agent Runtime。
你不只是读了一本关于 AI Agent 的书——你造了一个。它能对话、能动手、有权限、会记忆、可扩展、连生态、体验好、一条命令安装。
这个 Harness 是你的。拿它去定制、去部署、去改造。把它变成代码审查助手、运维诊断专家、文档写作伙伴——或者任何你能想到的东西。
AI Agent 的时代刚刚开始。你现在不只是用户,你是构建者。