《深入理解 AI Agent:设计原理与工程实践 》实验1-2 深度搜索能力

1. 项目概览

项目地址:https://github.com/bojieli/ai-agent-book

web-search-agent 是《深入理解 AI Agent》第 1 章实验 1-2 的配套项目,展示如何基于 Kimi K3 与 Moonshot 官方 Formula 工具实现一个自主网络搜索 Agent。它不是简单的"模型 + 搜索 API 拼接",而是完整实现了 ReAct 循环:模型先思考是否需要搜索,再通过官方 web_search 工具发起检索,读取 Fiber 结果后继续多轮推理,直到证据充分并生成最终答案。

从工程角度看,该仓库重点演示了以下能力:

  • 使用 Kimi K3 的官方工具调用协议,而不是自定义伪工具。
  • 通过 Formula 路由动态获取标准 web_search function declaration。
  • 将模型返回的工具名与原始参数不做篡改地转发给 Formula Fibers。
  • 仅接受 HTTP 成功且 status == "succeeded" 的 Fiber 结果。
  • 支持多轮搜索、对话历史、trace 记录、离线演示、CLI 交互与实验验证。
  • 提供 pytest 测试套件,覆盖 Agent 循环、配置解析、CLI、示例与实验验收逻辑。

1.1 学习价值

这个项目适合作为 AI Agent 工程入门样本,原因在于它同时覆盖了 Agent 应用的几个核心层面:

学习层面 项目中的体现
Agent 基础范式 ReAct:think → act → observe → answer
工具调用 动态拉取 Moonshot 官方 web_search 工具声明
多轮执行 search_and_answer(..., max_iterations) 控制搜索轮数
可观测性 trace 记录每一步模型思考、工具调用、观察结果与最终回答
工程封装 agent.pyconfig.pymain.pyexamples.py 职责分离
测试保障 单元测试覆盖工具流、异常 JSON、迭代上限、配置映射等
实验复现 run_experiment_1_2.py 生成带校验信息的实验证据

对于新手,它能帮助理解"为什么 Agent 不是一次 ChatCompletion 调用";对于有经验的开发者,它提供了一个可扩展的官方工具接入模板。

1.2 解决的行业痛点

很多搜索型 Agent demo 存在以下问题:

  • 工具 schema 手写,容易与平台官方定义不一致。
  • 搜索参数被中间层擅自修改,导致行为不可复现。
  • 只演示单轮搜索,无法处理复杂问题。
  • 缺少失败处理、trace 记录和测试。
  • 在线结果不可验证,实验结论难以追溯。

本项目通过官方 Formula 路由、原始参数转发、严格 Fiber 成功判定、trace 与 evidence 机制,缓解了这些问题。它强调"模型作为 Agent"的最小可信实现:工具定义来自官方,执行路径可追踪,实验结果可校验。

1.3 前置知识要求

阅读和运行本项目前,建议具备以下基础:

  • Python 基础:函数、类、类型注解、虚拟环境。
  • HTTP/JSON 基础:理解 API 请求、响应状态码、JSON 序列化。
  • LLM API 基础:了解 chat completions、messages、tool calls。
  • Agent 基础概念:了解 ReAct、工具调用、多轮推理。
  • 命令行基础:会执行 pip installpython script.pypytest
  • 可选:了解 pytestunittest.mockdotenvargparse

如果不了解 Kimi Formula 也没关系,项目 README 已明确说明其核心流程;但需要注意,本仓库不实现本地搜索引擎,搜索能力由 Moonshot 托管。

2. 目录结构速览

仓库目录较小,适合从入口文件、核心 Agent、测试与验证数据四个方向阅读。

text 复制代码
.
├── README.md
├── agent.py
├── config.py
├── env.example
├── examples.py
├── main.py
├── pytest.ini
├── quickstart.py
├── requirements.txt
├── run_experiment_1_2.py
├── tests/
│   ├── conftest.py
│   ├── test_agent.py
│   ├── test_config.py
│   ├── test_examples.py
│   ├── test_experiment_1_2.py
│   ├── test_main.py
│   └── test_offline_demo.py
└── validation/
    ├── latest.json
    ├── real_20260729T154442Z/
    │   ├── evidence.json
    │   └── evidence.sha256
    ├── real_20260729T155735Z/
    │   ├── evidence.json
    │   └── evidence.sha256
    ├── real_20260729T163003Z/
    │   ├── evidence.json
    │   └── evidence.sha256
    └── real_20260729T163623Z/
        ├── evidence.json
        └── evidence.sha256

目录职责如下:

路径 职责
README.md 项目说明、架构图、Formula 路由说明、快速开始
agent.py 核心 Web Search Agent、工具执行、离线 demo、CLI 入口
config.py Kimi/OpenRouter 等配置读取与校验
main.py 主 CLI,支持单问、交互模式、JSON 输出
quickstart.py 面向新手的一键体验脚本
examples.py 高级用法:批量搜索、上下文搜索、对比搜索、事实核查
run_experiment_1_2.py 实验 1-2 执行与 evidence 校验
tests/ pytest 测试套件
validation/ 已生成的实验证据与 SHA256 校验文件
requirements.txt 单项目兼容安装依赖
env.example 环境变量示例文件
pytest.ini pytest 配置

阅读建议顺序:

  1. 先读 README.md 的 Architecture 与 Exact Formula route。
  2. 再读 agent.pyWebSearchAgent.search_and_answer
  3. 接着看 _get_tools_execute_formula_chat 如何串起工具调用。
  4. 然后看 main.py 了解 CLI 参数与输出。
  5. 最后阅读 tests/run_experiment_1_2.py,理解验收标准。

3. 核心模块与职责

3.1 agent.py:核心 Agent 实现

agent.py 是仓库最重要的模块,类为 WebSearchAgent。它负责:

  • 初始化 API Key、base URL、模型名与 verbose 模式。
  • 获取官方 Formula 工具声明。
  • 调用 Kimi chat completions。
  • 执行模型请求的 web_search 工具。
  • 将 Fiber 输出作为 observation 继续送回模型。
  • 控制最大迭代次数。
  • 记录 conversation history 与 trace。
  • 提供离线确定性 demo。

核心类方法清单:

方法 作用
__init__(api_key, base_url, model, verbose) 初始化 Agent 配置
_emit(step) 输出或记录 trace step
_get_tools() 获取 Formula 工具声明
_execute_formula(name, raw_arguments) 调用 Formula Fiber 执行工具
_get_system_prompt() 返回系统提示词
_chat(messages) 调用 chat completions
search_and_answer(user_question, max_iterations) 执行 ReAct 主循环
clear_history() 清空对话历史
get_conversation_history() 获取对话历史
get_trace() 获取执行 trace

模块级函数还包括:

  • _reasoning_safe_temperature(model, requested):为推理模型调整到支持的 temperature。
  • format_trace_step(step, max_len):格式化 trace,避免内容过长。
  • search_impl(arguments):搜索实现相关函数。
  • is_failure_answer(answer):判断答案是否为失败兜底。
  • run_offline_demo(question, verbose):运行离线 ReAct 演示。
  • main()agent.py 的命令行入口。

3.2 config.py:配置与 Provider 选择

config.py 定义 Config 类,负责从环境变量和 .env 中读取配置。摘要显示其包含:

  • Config.validate(cls)
  • Config.get_api_key(cls, api_key)

测试文件进一步表明该模块还涉及:

  • 模型到 OpenRouter 的映射。
  • 未知模型使用配置的 OpenRouter 默认模型。
  • 未启用替换时保留未知模型。
  • 主 Provider key 存在时保留主 Provider。
  • 主 key 缺失时使用 OpenRouter。
  • GPT-5 在两个 key 都存在时优先 OpenRouter。
  • Provider 解析必须存在 key。

具体环境变量名称未在解析摘要中完整列出,需以 env.example 或源码为准。

3.3 main.py:命令行主程序

main.py 提供更正式的 CLI 封装,主要函数包括:

函数 职责
_save_output(path, payload) 将输出保存到 JSON 文件
run_interactive_mode(agent, output) 运行交互式问答
run_single_question(agent, question, max_iterations, output) 运行单次问题
build_parser() 构建 argparse 参数解析器
main(argv) CLI 主入口

测试显示 CLI 默认进入 interactive Kimi 模式,也支持命令行参数覆盖;离线 CLI 可写入 UTF-8 JSON,且不需要 API 凭证;未提供 query 时会使用默认问题。

3.4 quickstart.py:新手快速体验

quickstart.py 面向第一次运行项目的用户,包含:

  • Colors:终端颜色类。
  • print_colored(text, color):彩色输出。
  • print_banner():打印欢迎横幅。
  • check_api_key():检查 API Key。
  • demo_search(agent):演示搜索。
  • interactive_mode(agent):交互模式。
  • main():快速开始入口。

它更强调体验流程,而不是完整参数控制。

3.5 examples.py:高级用法示例

examples.py 定义 AdvancedWebSearchAgent(WebSearchAgent),扩展了以下能力:

方法 作用
batch_search(questions) 批量处理多个问题
search_with_context(question, context) 带上下文搜索
comparative_search(items, aspect) 对多个对象做对比搜索
fact_check(statement) 对陈述做事实核查

模块还提供多个示例函数:

  • example_basic_search()
  • example_batch_search()
  • example_contextual_search()
  • example_comparative_search()
  • example_fact_check()
  • example_research_assistant()
  • main()

测试显示,失败兜底答案会被标记为 error,批量搜索会覆盖所有失败 fallback。

3.6 run_experiment_1_2.py:实验执行与验收

该脚本用于"Run Experiment 1-2 through Kimi K3's official Formula web-search tool"。摘要中的函数包括:

函数 作用
git_value(*args) 获取 git 相关值
response_ids(turns) 提取响应 ID
fiber_ids(turns) 提取 Fiber ID
has_web_search_declaration(tools) 判断工具声明是否包含 web search
usage(turns) 汇总 token/usage 信息
validate(payload) 校验实验 payload
write_json(path, value) 写入 JSON
run_once(model, timeout) 执行一次实验
main() CLI 入口

测试文件揭示了关键验收规则:

  • 只接受真实成功的 Fiber receipts。
  • 验收要求存在不同的、顺序发生的 Formula Fibers 与链接。
  • 如果一轮搜索中产生两个 Fibers,会被拒绝。

这说明实验关注的是"独立问题中多轮顺序搜索"的真实性,而不是任意工具调用次数。

3.7 tests/:测试体系

测试目录结构清晰:

测试文件 覆盖范围
conftest.py 共享 fixtures:隔离 Provider 环境、阻断外部网络、构造 tool call/choice
test_agent.py ReAct 格式化、工具定义、Fiber 转发、Agent 循环、异常处理
test_config.py 模型映射、Provider 选择、key 解析
test_examples.py 高级 Agent helper、失败分类
test_experiment_1_2.py Fiber 验收规则
test_main.py CLI 参数、离线分发、JSON 输出
test_offline_demo.py 离线 demo 的确定性与输出模式

特别值得学习的是 conftest.py 中的 block_external_network(monkeypatch),它表明测试默认避免真实外网调用,适合 CI 与离线验证。

3.8 核心原理通俗解读

可以把这个 Agent 理解成一个"会自己查资料的研究助理":

  1. 用户提出问题。
  2. 助理先判断:我现有知识够不够?
  3. 如果不够,就按照官方提供的 web_search 表单填写查询词。
  4. 系统把表单原样交给 Moonshot 的搜索 Fiber。
  5. 搜索结果返回后,助理阅读结果。
  6. 如果信息仍不足,就继续查;如果足够,就写最终答案。

这里的关键不是"调用了搜索",而是模型自己决定:

  • 要不要搜索。
  • 搜索什么。
  • 搜几次。
  • 何时停止。
  • 如何综合结果。

工程代码的职责则是保证这个循环可靠执行:工具声明准确、参数不被篡改、失败可识别、过程可追踪、结果可验证。

4. 关键数据流与调用链

根据 README 与 agent.py 摘要,核心在线调用链如下:

text 复制代码
用户问题
  ↓
WebSearchAgent.search_and_answer()
  ↓
_get_system_prompt()
  ↓
_get_tools()
  ↓
GET /v1/formulas/moonshot/web-search:latest/tools
  ↓
POST /v1/chat/completions
  ↓
模型返回 web_search tool call
  ↓
_execute_formula(name, raw_arguments)
  ↓
POST /v1/formulas/moonshot/web-search:latest/fibers
  ↓
仅接受 HTTP 成功且 status == "succeeded" 的结果
  ↓
将 context.output 或 encrypted output 作为 tool result 返回模型
  ↓
模型继续推理 / 再次搜索 / 输出最终答案

4.1 在线搜索主流程

步骤 1:获取工具声明

Agent 不手写 web_search schema,而是请求:

text 复制代码
GET /v1/formulas/moonshot/web-search:latest/tools

目的是获取 Moonshot 权威的标准 function declaration。这样可以避免本地 schema 与平台不一致。

步骤 2:发起模型推理

Agent 将系统提示词、历史消息、用户问题和工具声明一起发送到:

text 复制代码
POST /v1/chat/completions

模型决定是否调用工具、调用几次,以及参数是什么。

步骤 3:执行 Formula Fiber

对于每个模型工具调用,Agent 将返回的:

  • name
  • raw serialized arguments

原样转发到:

text 复制代码
POST /v1/formulas/moonshot/web-search:latest/fibers

这是 README 中强调的"Exact Formula route",中间层不应擅自改参数。

步骤 4:过滤有效结果

只有满足以下条件的 Fiber 才能作为 observation:

  • HTTP 请求成功。
  • Fiber status == "succeeded"

随后读取:

  • context.output
  • 或 encrypted output

具体字段结构未在摘要中完整展开,需以源码和实际响应为准。

步骤 5:多轮迭代

模型拿到 observation 后可能:

  • 继续调用 web_search
  • 要求更多信息。
  • 直接生成最终答案。

循环由 max_iterations 限制,防止无限搜索。

4.2 离线 Demo 调用链

agent.py 提供 run_offline_demo(question, verbose),测试表明它:

  • 返回完整且确定的 trace。
  • verbose 模式会打印每一步。
  • quiet 模式不打印内容。

离线流程不依赖真实 API,适合在没有 API Key 时理解 ReAct 循环,也适合测试 CLI 输出。

4.3 CLI 调用链

main.py 的典型调用链:

text 复制代码
python main.py [参数]
  ↓
build_parser()
  ↓
main(argv)
  ↓
根据参数选择:
  ├─ run_single_question()
  └─ run_interactive_mode()
  ↓
必要时调用 agent.search_and_answer()
  ↓
可选 _save_output() 写入 JSON

quickstart.py 的调用链更偏引导式:

text 复制代码
python quickstart.py
  ↓
print_banner()
  ↓
check_api_key()
  ↓
创建 WebSearchAgent
  ↓
demo_search() 或 interactive_mode()

4.4 实验证据生成链路

run_experiment_1_2.py 的链路可概括为:

text 复制代码
main()
  ↓
run_once(model, timeout)
  ↓
收集 turns / response IDs / fiber IDs / usage
  ↓
validate(payload)
  ↓
write_json() 写入 evidence.json
  ↓
生成 evidence.sha256
  ↓
validation/ 目录保存可追溯证据

4.5 流程易错节点标注

节点 易错点 后果 建议
工具声明获取 手写或缓存旧 schema 工具调用失败或行为不一致 通过 _get_tools() 拉取官方声明
参数转发 修改模型生成的 arguments 破坏官方 Formula 路由,结果不可复现 原样转发 raw serialized arguments
Fiber 判定 只看 HTTP 200,不看 status 可能接受失败搜索结果 同时校验 HTTP 成功与 status == "succeeded"
多轮循环 不限制迭代次数 成本失控或死循环 使用 max_iterations
工具结果回填 未把 observation 加入 messages 模型无法基于搜索结果回答 按 chat completions tool message 规范回填
异常 JSON 工具参数 JSON 损坏 Agent 循环崩溃 测试中已覆盖 malformed JSON,应保留错误处理
实验验收 把同一轮两个 Fiber 当成多轮搜索 实验结论无效 遵循 test_experiment_1_2.py 的顺序 Fiber 规则
离线/在线混淆 无 Key 时直接运行在线模式 启动失败 使用 offline demo 或先配置 API Key

5. 关键类/函数速查表

5.1 agent.py

名称 类型 摘要
WebSearchAgent Kimi Web Search Agent 核心类
WebSearchAgent.__init__ 方法 初始化 API Key、base URL、model、verbose
WebSearchAgent._emit 方法 发出 trace step
WebSearchAgent._get_tools 方法 获取官方 Formula 工具声明
WebSearchAgent._execute_formula 方法 执行 Formula Fiber
WebSearchAgent._get_system_prompt 方法 返回系统提示词
WebSearchAgent._chat 方法 调用 chat completions
WebSearchAgent.search_and_answer 方法 执行多轮搜索与回答主循环
WebSearchAgent.clear_history 方法 清空历史
WebSearchAgent.get_conversation_history 方法 获取对话历史
WebSearchAgent.get_trace 方法 获取 trace
_reasoning_safe_temperature 函数 为推理模型限制 temperature
format_trace_step 函数 格式化并截断 trace step
search_impl 函数 搜索实现相关逻辑
is_failure_answer 函数 判断失败兜底答案
run_offline_demo 函数 运行确定性离线演示
main 函数 agent.py 入口

5.2 config.py

名称 类型 摘要
Config 配置读取与校验
Config.validate 类方法 校验配置
Config.get_api_key 类方法 获取 API Key

5.3 main.py

名称 类型 摘要
_save_output 函数 保存 JSON 输出
run_interactive_mode 函数 运行交互模式
run_single_question 函数 运行单次问题
build_parser 函数 构建 CLI parser
main 函数 CLI 主入口

5.4 quickstart.py

名称 类型 摘要
Colors 终端颜色定义
print_colored 函数 打印彩色文本
print_banner 函数 打印启动横幅
check_api_key 函数 检查 API Key
demo_search 函数 演示搜索
interactive_mode 函数 快速交互模式
main 函数 quickstart 入口

5.5 examples.py

名称 类型 摘要
AdvancedWebSearchAgent 扩展批量、上下文、对比、事实核查能力
batch_search 方法 批量搜索多个问题
search_with_context 方法 带上下文搜索
comparative_search 方法 多对象对比搜索
fact_check 方法 事实核查
example_basic_search 函数 基础搜索示例
example_batch_search 函数 批量搜索示例
example_contextual_search 函数 上下文搜索示例
example_comparative_search 函数 对比搜索示例
example_fact_check 函数 事实核查示例
example_research_assistant 函数 研究助理示例
main 函数 examples 入口

5.6 run_experiment_1_2.py

名称 类型 摘要
git_value 函数 获取 git 信息
response_ids 函数 提取响应 ID
fiber_ids 函数 提取 Fiber ID
has_web_search_declaration 函数 检查是否包含 web search 声明
usage 函数 汇总 usage
validate 函数 校验实验 payload
write_json 函数 写入 JSON 文件
run_once 函数 执行一次实验
main 函数 实验脚本入口

6. 如何运行与调试(基于摘要推断,无法确定则说明)

以下步骤严格依据 README 摘要与模块摘要整理。未在摘要中出现的参数、环境变量名、输出内容不做编造。

6.1 环境准备

步骤 1:进入仓库根目录

README 推荐从书籍仓库根目录使用 Chapter 1 共享环境。

执行目的:使用统一依赖环境,避免子项目单独安装导致版本不一致。

README 给出的推荐命令:

bash 复制代码
uv sync --locked --extra ch1

如果没有安装 uv,README 提供 pip fallback:

bash 复制代码
python -m pip install -e ".[ch1]"

步骤 2:激活虚拟环境

macOS/Linux:

bash 复制代码
source .venv/bin/activate

Windows PowerShell:

powershell 复制代码
.venv\Scripts\Activate.ps1

Windows cmd:

bat 复制代码
.venv\Scripts\activate.bat

执行目的:确保后续 pythonpytest 使用项目依赖。

步骤 3:进入本实验目录

bash 复制代码
cd chapter1/web-search-agent

如果不使用根目录共享环境,README 也说明仍支持单项目兼容路径:

bash 复制代码
python -m pip install -r requirements.txt

执行目的:安装当前实验目录的依赖。

可能生成或变化的内容:

  • Python 虚拟环境目录,通常为 .venv/
  • 本地 pip 包缓存。
  • 若使用 editable install,可能生成 egg-info/构建缓存,具体取决于环境。

6.2 配置 API Key

仓库包含 env.example,说明项目通过环境变量或 .env 配置 API Key。config.py 导入了 dotenv,因此支持从 .env 加载配置。

建议操作:

  1. 复制 env.example.env
  2. 根据文件中的提示填入 Kimi/Moonshot API Key 或其他 Provider 配置。
  3. 不要把 .env 提交到版本控制。

由于解析摘要未展示 env.example 的具体字段,本文不编造变量名。配置字段请以 env.exampleconfig.py 源码和 README 未展示部分为准。

执行目的:让在线 Agent 能通过 Config.get_api_key 或相关配置逻辑获取凭证。

6.3 运行快速开始

入口文件:

bash 复制代码
python quickstart.py

执行目的:

  • 打印欢迎横幅。
  • 检查 API Key。
  • 创建 Agent。
  • 进入演示搜索或交互模式。

正常控制台输出特征:

  • 可能出现彩色 banner,因为 quickstart.py 定义了 Colorsprint_colored
  • 如果 API Key 缺失,check_api_key() 应提示配置问题。
  • 如果配置正确,会进入 demo 或交互流程。

运行后是否生成文件:

  • 摘要未显示 quickstart.py 会写文件。
  • 通常应只产生控制台输出;若实际脚本支持输出文件,需以源码为准。

6.4 运行主 CLI

入口文件:

bash 复制代码
python main.py

根据测试摘要,不带参数时默认进入 interactive Kimi 模式。

执行目的:启动交互式 Web Search Agent。

正常控制台输出特征:

  • 进入交互模式后,程序应等待用户输入问题。
  • Agent 可能打印 trace、最终答案或错误信息。
  • verbose 行为取决于 CLI 参数和 Agent 初始化配置。

单次问题模式

main.py 提供 run_single_question(agent, question, max_iterations, output),说明 CLI 应支持传入问题、最大迭代次数和输出路径。

参数解析由 build_parser() 定义,但解析摘要未列出完整参数名。可通过以下方式查看实际帮助:

bash 复制代码
python main.py --help

执行目的:在不阅读源码的情况下确认 CLI 支持的参数。

保存 JSON 输出

main.py 包含 _save_output(path, payload),说明可将结果保存为 JSON。若 CLI 暴露了 output 参数,典型形式可能类似:

bash 复制代码
python main.py <问题参数> <你的问题> <输出参数> result.json

注意:以上只是基于函数职责的形式推断,具体参数名未在解析摘要中发现,请以 python main.py --help 为准。

运行后可能生成:

  • 指定路径的 JSON 文件。
  • 内容应包含问题、答案、trace 或相关元数据,具体结构以源码为准。

6.5 运行离线 Demo

测试显示离线 CLI 可写入 UTF-8 JSON,且不需要 API 凭证;未提供 query 时使用默认问题。

agent.py 也提供:

python 复制代码
run_offline_demo(question, verbose)

可通过 agent.pymain.py 的离线参数运行。由于摘要未列出明确 CLI 参数,建议先查看:

bash 复制代码
python agent.py --help
python main.py --help

执行目的:

  • 在没有 API Key 的情况下理解 ReAct 流程。
  • 验证本地环境和 CLI 输出是否正常。
  • 用于自动化测试,避免外部网络依赖。

正常控制台输出特征:

  • verbose 模式:打印每个 trace step。
  • quiet 模式:不打印内容。
  • 返回结果应是完整且确定性的 trace。

运行后可能生成:

  • 如果传入 output 路径,会生成 UTF-8 JSON 文件。
  • 文件名取决于命令参数。

6.6 运行高级示例

入口文件:

bash 复制代码
python examples.py

执行目的:体验以下高级能力:

  • 基础搜索。
  • 批量搜索。
  • 上下文搜索。
  • 对比搜索。
  • 事实核查。
  • 研究助理流程。

正常控制台输出特征:

  • 每个 example_* 函数可能打印对应示例标题与结果。
  • 批量搜索会对多个问题分别执行。
  • 失败兜底答案应被标记为 error。

运行后是否生成文件:

  • 摘要未显示 examples.py 会保存文件。
  • 若需要保存,可参考 main.py_save_output 自行扩展。

6.7 运行实验 1-2

入口文件:

bash 复制代码
python run_experiment_1_2.py

该脚本使用 argparse,但摘要未列出完整参数。建议先执行:

bash 复制代码
python run_experiment_1_2.py --help

执行目的:

  • 通过 Kimi K3 官方 Formula web-search tool 运行实验。
  • 收集 turns、response IDs、fiber IDs、usage。
  • 验证是否满足多轮顺序搜索要求。
  • 写入 evidence 文件。

运行后可能生成:

  • validation/ 下新的时间戳目录。
  • evidence.json
  • evidence.sha256
  • validation/latest.json 可能被更新。

正常结果特征:

  • evidence 中应包含真实成功的 Fiber receipts。
  • 不同的、顺序发生的 Formula Fibers 与链接。
  • 不应把同一轮中的两个 Fibers 当作合格多轮搜索。

无实测结果:解析摘要未提供本次运行的实验数据、耗时、token 用量或准确率,因此这里不编造实验结果。可预留如下结果对比模块:

实验项 预期 本次实测
是否调用官方 web_search 声明 未实测
Fiber 是否 succeeded 未实测
是否产生多轮顺序 Fibers 未实测
evidence 是否通过校验 未实测
token/耗时 未在摘要中发现 未实测

6.8 运行测试

仓库包含 pytest.ini,测试框架为 pytest。

chapter1/web-search-agent 目录下执行:

bash 复制代码
pytest

执行目的:

  • 验证 Agent 循环、配置、CLI、示例、实验验收逻辑是否正常。
  • 在不调用真实外部网络的情况下完成大部分单元测试。

正常测试特征:

  • conftest.py 提供外部网络阻断 fixture。
  • 测试覆盖 malformed tool arguments、迭代上限、空答案、部分答案等边界情况。
  • 离线 demo 测试可验证确定性输出。

运行后通常生成:

  • pytest 控制台结果。
  • 若启用 coverage,可能生成覆盖率文件;摘要未显示 coverage 配置,因此默认不应假设存在。

6.9 调试建议

建议 1:先跑离线 demo

如果在线 API 不通,先运行离线模式,确认 Python 环境、CLI 参数和 JSON 输出正常。

建议 2:查看 trace

WebSearchAgent.get_trace() 可获取执行轨迹。调试时重点查看:

  • 模型是否请求了 web_search
  • 工具名是否为官方声明中的名称。
  • arguments 是否是合法 JSON。
  • Fiber 是否 succeeded。
  • observation 是否正确回填。
  • 是否达到 max_iterations

建议 3:打开 verbose

WebSearchAgent.__init__ 支持 verbose 参数。verbose 模式有助于观察每一步,但生产环境或批量任务中应谨慎使用,避免日志过长。

建议 4:使用 mock 复现问题

tests/test_agent.py 中已有 FakeResponsemake_choicemake_tool_call 等测试工具。排查在线问题时,可先用 mock 构造模型响应,隔离 API 网络问题。

建议 5:校验实验 evidence

如果实验结果异常,优先检查:

  • Fiber receipt 是否真实成功。
  • Fiber ID 是否不同。
  • Fibers 是否来自不同顺序轮次。
  • 是否存在同一轮两个 Fibers。
  • evidence.sha256 是否与 evidence.json 匹配。

7. 可扩展点与二次开发建议

7.1 扩展新的官方工具

当前项目只接入 Moonshot 官方 web_search。如果未来要支持其他 Formula 工具,可参考现有模式:

  1. _get_tools() 中获取对应工具声明。
  2. _execute_formula() 中按工具名转发到对应 Fiber endpoint。
  3. 保持模型返回的 name 与 raw arguments 原样传递。
  4. 对 Fiber 结果执行严格状态校验。
  5. 为新工具补充单元测试。

注意:摘要未显示通用多工具注册机制,因此当前实现可能与 moonshot/web-search:latest 耦合较深。二次开发时可抽象出:

  • ToolProvider
  • ToolDeclarationFetcher
  • ToolExecutor
  • ToolResultValidator

7.2 增强 trace 与可观测性

现有 trace 已记录 Agent 步骤。可扩展方向包括:

  • 将 trace 输出为 JSONL,方便日志系统采集。
  • 为每一步增加时间戳、耗时、token usage。
  • 记录 Fiber request ID,便于向平台排查。
  • 对长 observation 做结构化截断与原文存档。
  • 接入 OpenTelemetry 或 Langfuse 等观测平台。

需要注意 format_trace_step(step, max_len) 已经有截断逻辑,扩展时不要丢失关键证据。

7.3 增强错误恢复

测试已覆盖以下异常:

  • malformed tool arguments JSON。
  • 迭代上限。
  • 空答案或截断答案。
  • 可读错误返回。

可继续增强:

  • Fiber 超时重试。
  • 429/5xx 指数退避。
  • 搜索结果为空时让模型换查询词。
  • 失败答案分类与用户友好提示。
  • 将网络异常与模型异常区分开。

7.4 扩展高级研究能力

AdvancedWebSearchAgent 已提供批量、上下文、对比和事实核查能力。可进一步增加:

  • 多语言搜索策略。
  • 来源可信度评分。
  • 引用链接与证据片段对齐。
  • 报告生成:摘要、对比表、参考文献。
  • 长任务断点续跑。
  • 并发批量搜索与限流。

开发并发能力时要注意模型 API 限流,不能简单无限制并发。

7.5 抽象 Provider 配置

config.py 测试显示项目已处理 Kimi、OpenRouter、模型映射和 key 选择。可进一步抽象:

  • ProviderConfig
  • ModelRouter
  • CredentialResolver

这样可以把"模型名映射""base URL 选择""key 优先级"从 Agent 主逻辑中剥离。

7.6 方案优劣对比

方案 优点 缺点 适用场景
官方 Formula web-search 工具声明权威、行为贴近平台、支持原生 Agent 能力 依赖 Moonshot 托管搜索,自定义空间有限 教学演示、官方能力验证、生产搜索 Agent
自定义搜索工具 可接入任意搜索引擎、可控排序与过滤 schema 和执行逻辑需自行维护,复杂度高 企业内部搜索、垂直领域检索
单次搜索后回答 实现简单、成本低 复杂问题容易证据不足 简单事实查询
多轮 ReAct 搜索 证据更充分、能处理复杂问题 成本更高、需控制迭代与失败 研究助理、事实核查、对比分析
离线 demo 无 API 成本、确定性强、适合测试 不反映真实网络结果 教学、CI、UI 调试
在线实验 evidence 结果可追溯、可校验 需要真实 API 与网络,成本不可完全避免 论文/课程实验、能力验收

7.7 落地场景

该架构可迁移到以下场景:

  1. 企业知识库检索 Agent:将 Formula web-search 替换为内部搜索工具,保留 ReAct 循环。
  2. 市场研究助理 :使用 comparative_search 思路对比产品、价格、评价。
  3. 事实核查系统:对用户陈述进行多轮搜索,并保留证据链接。
  4. 技术文档问答:接入官方文档搜索,生成带引用的答案。
  5. 教学实验平台:用 trace 展示 Agent 的思考、行动和观察过程。
  6. 自动化报告生成:批量收集资料,再汇总为结构化报告。

7.8 面试考点提炼

考点 对应项目实现
ReAct 循环 think → act → observe → answer
工具调用协议 动态获取 function declaration,模型返回 tool call
官方工具接入 GET tools、POST chat/completions、POST fibers
多轮 Agent 控制 max_iterations 防止无限循环
工具参数安全 raw arguments 原样转发,不擅自修改
失败处理 Fiber 状态校验、异常 JSON、失败答案分类
可观测性 trace、conversation history
测试设计 mock 网络、构造 tool call、验证循环边界
实验可复现 evidence.json 与 evidence.sha256
Provider 抽象 API key、base URL、model mapping、OpenRouter 选择

8. 常见问题与排查清单

8.1 API Key 未配置或读取失败

  • 【故障现象】 运行 quickstart.pymain.py 或在线示例时提示缺少 API Key,或无法创建 Agent。
  • 【根因】 未创建 .env、环境变量未生效、虚拟环境未激活,或填入的 key 不属于当前 Provider。
  • 【修复方案】
    1. 确认已从 env.example 复制出 .env
    2. env.exampleconfig.py 要求填写正确变量。
    3. 激活当前虚拟环境后再运行。
    4. 如使用 OpenRouter,确认相关 key 与模型映射配置正确。

8.2 离线模式与在线模式混淆

  • 【故障现象】 没有 API Key 时运行主程序失败,或误以为离线 demo 会访问真实网络。
  • 【根因】 未区分在线 Kimi 模式和离线 deterministic demo。
  • 【修复方案】
    1. 无网络或无 Key 时运行离线 demo。
    2. 通过 python agent.py --helppython main.py --help 查看离线参数。
    3. 需要真实搜索结果时再配置 API Key 并运行在线模式。

8.3 工具声明获取失败

  • 【故障现象】 Agent 在 _get_tools() 阶段报错,无法获取 web_search function declaration。
  • 【根因】 网络不可达、base URL 错误、API Key 无效、平台接口变更或权限不足。
  • 【修复方案】
    1. 检查 Config 中的 base URL。
    2. 确认 API Key 有权限访问 Formula tools。
    3. 检查本地网络、代理和防火墙。
    4. 不要手写旧 schema 绕过,应优先修复官方声明获取流程。

8.4 Fiber 调用失败

  • 【故障现象】 模型请求了 web_search,但工具执行阶段报错,或 Agent 返回可读错误。
  • 【根因】 Fiber endpoint 不可达、参数格式异常、搜索服务失败、HTTP 非 2xx,或 Fiber status 不是 succeeded
  • 【修复方案】
    1. 查看 trace 中记录的工具名和 raw arguments。
    2. 确认参数是模型返回的原始序列化 JSON,未被中间层破坏。
    3. 检查 Fiber 响应中的状态码和 status 字段。
    4. 对超时或临时错误增加重试,但不要把失败 Fiber 当成成功 observation。

8.5 工具参数 JSON 解析失败

  • 【故障现象】 Agent 循环遇到 malformed tool arguments JSON,测试中也专门覆盖该场景。
  • 【根因】 模型返回的 arguments 格式不完整,或中间处理破坏了 JSON 字符串。
  • 【修复方案】
    1. 保留现有异常捕获逻辑,避免整个 Agent 崩溃。
    2. 将解析错误作为 observation 返回模型,让模型修正。
    3. 不要在转发前"修复"模型参数,以免破坏官方路由。
    4. 在 trace 中记录原始 arguments,便于排查。

8.6 Agent 一直搜索或达到迭代上限

  • 【故障现象】 Agent 多轮调用搜索仍不回答,最终触发 iteration limit。
  • 【根因】 问题过于复杂、搜索结果不充分、模型未判断证据足够,或 max_iterations 设置过小。
  • 【修复方案】
    1. 适当增大 max_iterations
    2. 在系统提示词中明确停止条件。
    3. 检查 Fiber 输出是否被正确回填。
    4. 对空结果提示模型改写查询词。
    5. 设置成本与轮数上限,避免无限调用。

8.7 搜索结果没有被模型使用

  • 【故障现象】 工具调用成功,但最终答案与搜索结果无关,或像没有看到 observation。
  • 【根因】 tool result 没有按 chat completions 规范加入 messages,或 trace 中 observation 被截断/丢失。
  • 【修复方案】
    1. 检查每次 Fiber 输出后是否追加了对应的 tool message。
    2. 确认 tool call ID 与 tool result ID 对应。
    3. 检查 format_trace_step 的截断是否只影响展示,不影响模型输入。
    4. 通过 get_conversation_history() 检查消息序列。

8.8 CLI 参数不确定

  • 【故障现象】 不知道如何传入问题、输出路径或最大迭代次数。
  • 【根因】 解析摘要未完整列出 argparse 参数。
  • 【修复方案】
    1. 运行 python main.py --help
    2. 运行 python agent.py --help
    3. 运行 python run_experiment_1_2.py --help
    4. 查看 build_parser() 源码确认参数名。

8.9 测试无法运行或导入失败

  • 【故障现象】 执行 pytest 时报模块找不到、依赖缺失或配置错误。
  • 【根因】 未安装依赖、未激活虚拟环境、运行目录不正确,或没有使用 Chapter 1 共享环境。
  • 【修复方案】
    1. 在仓库根目录执行 README 推荐的 uv sync --locked --extra ch1
    2. 或在本目录执行 python -m pip install -r requirements.txt
    3. 激活 .venv
    4. chapter1/web-search-agent 目录下执行 pytest

8.10 测试触发外部网络

  • 【故障现象】 单元测试尝试访问真实 Kimi/Moonshot 接口。
  • 【根因】 测试没有使用网络隔离 fixture,或本地环境变量影响了 Provider 初始化。
  • 【修复方案】
    1. 使用 tests/conftest.py 中的 isolate_provider_environmentblock_external_network
    2. 检查是否有本地 .env 在测试时被自动加载。
    3. 对外部调用继续使用 unittest.mock 或 fake response。
    4. 不要在单元测试中依赖真实网络结果。

8.11 实验校验失败

  • 【故障现象】 run_experiment_1_2.py 生成结果但 validate(payload) 不通过。
  • 【根因】 Fiber 不是真实成功状态、Fiber ID 不满足顺序要求、同一轮中出现两个 Fibers,或 evidence 被修改。
  • 【修复方案】
    1. 检查每个 Fiber 是否 HTTP 成功且 status == "succeeded"
    2. 确认多轮搜索是独立顺序发生,而不是一轮中并发两个 Fibers。
    3. 检查 response IDs、fiber IDs 和链接是否完整。
    4. 重新运行实验并生成新的 evidence.jsonevidence.sha256
    5. 不要手动编辑 evidence 文件。

8.12 Windows 激活脚本无法执行

  • 【故障现象】 Windows PowerShell 执行 .venv\Scripts\Activate.ps1 时提示脚本被禁止。
  • 【根因】 PowerShell 执行策略限制。
  • 【修复方案】
    1. 使用 cmd 执行 .venv\Scripts\activate.bat
    2. 或按组织允许的方式调整 PowerShell 执行策略。
    3. 也可直接使用 .venv\Scripts\python.exe 运行脚本,避免激活。

8.13 JSON 输出乱码

  • 【故障现象】 保存的 JSON 文件中中文显示为转义字符或乱码。
  • 【根因】 写入时未指定 UTF-8,或 json.dump 启用了 ASCII 转义。
  • 【修复方案】
    1. 参考 test_main.py 中"offline CLI writes UTF-8 JSON"的预期。
    2. 保存文件时使用 UTF-8 编码。
    3. 如需可读中文,确认 json.dump(..., ensure_ascii=False) 是否按项目设计启用。
    4. 不要修改与测试预期冲突的输出格式。

8.14 verbose 日志过长

  • 【故障现象】 控制台输出大量搜索内容,影响阅读或泄露敏感信息。
  • 【根因】 verbose 会打印 trace step,而搜索结果可能很长。
  • 【修复方案】
    1. 普通使用时关闭 verbose。
    2. 依赖 format_trace_step(step, max_len) 做截断展示。
    3. 将完整 trace 写入受控日志文件,而不是直接打印。
    4. 对敏感字段做脱敏。
相关推荐
2601_965798471 小时前
Why Most WordPress Themes Break Elementor and How I Fixed It
数据库·人工智能·php
苏灿烤鱼1 小时前
今日 GitHub 热门|Agent 记忆重回榜首,+2,690 项目却只排第三
typescript·agent·资讯
苏灿烤鱼1 小时前
GitHub #2 拆解|把工程经验装进 Agent,为什么仍会“静默失效”?
javascript·人工智能·agent
额恩662 小时前
预训练模型:从BERT到GPT的进化之路
人工智能·自然语言处理
继续商行3 小时前
彻底解决数据库慢查询:深入B+树索引与执行计划优化
人工智能
Shockang9 小时前
AI 编码智能体生产化工程
人工智能
jay神10 小时前
深度学习确定baseline之后怎么做改进?
人工智能·深度学习·yolo·计算机视觉·分类
acrel710 小时前
安科瑞Acrel-1000变电站综合自动化系统在合肥某新材料公司35kV综合自动化项目中的应用分析
大数据·人工智能
UWA10 小时前
隐藏视频变“常驻刺客”,VideoPlayer与“N/A”纹理该怎么查
人工智能·性能优化·音视频·memory·cpu·游戏开发