新智能体的开发循环

在 Agent OS 平台上创建新 AI 智能体的分步流程—— 从用例到部署和持续监控。智能体的全部逻辑 通过配置(YAML)描述,无需修改 Rust 代码。开发 遵循 test-first:先确定智能体应解决哪些问题, 再针对这些用例构建数据和工具。

  1. 用例
  2. 数据
  3. 工具
  4. 调试
  5. 测试
  6. 智能体
  7. 钩子
  8. 基准测试
  9. 部署
  10. 监控

↻ 监控 → 新用例 → 第 1 步:循环重复

第 1 步. 用例与基准测试场景(test-first)

在编写任何代码之前,先确定智能体应具备哪些能力:用户的 真实问题及预期回答。智能体类型各异,用例取决于 智能体类型(关于类型的更多内容——见「解决方案」栏目,Вектор Решений 网站):

智能体类型 用例示例 回答中检查什么
知识库支持(FAQ) «如何报考 НГУ?»、«有哪些奖学金?» 基于知识库的回答、来源链接、无杜撰内容
顾问 / 销售(e-commerce) «推荐一台 8 万以内的学习用笔记本»、«比较这两款型号» 找到的商品及链接、考虑了筛选条件、给出推荐
员工助理 «办理 8 月 1 日起的休假»、«重置邮箱密码» 正确调用操作、澄清缺失数据、确认
数据分析师 «7 月各地区的订单量是多少?» 正确的 SQL → 回答 + 图表/表格
观察者 / 监控 «如果冷藏车温度高于正常值就提醒我» 触发触发器、预警通知

再加上复杂场景(筛选条件组合、边界情况)、 多步链路(选择 → 比较 → 下单)以及多轮对话 (检查上下文保持:«详细讲讲第一个»)。

用例写在 config/agents/<агент>/bench/scenarios.yaml 中—— 同一个文件之后会用于运行基准测试(第 8 步):

name: "NGU Agent"
model: "ngu-agent"

scenarios:
  - name: "Поступление"
    turns:
      - user: "Как поступить в нгу"
        assert:
          contains: [поступлен]
          min_links: 1
          valid_urls: true

检查类型:contains(子串)、min_links/min_urls(最少 markdown 链接数)、valid_urls(所有链接均为 http/https)。建议:对于 罕见结果使用 min_links: 1;valid_urls: true 可捕获 失效链接;面向俄语智能体使用俄语查询。

第 2 步. 数据与来源:API、适配器、抓取

首先要弄清楚智能体将从哪里获取数据,以及有哪些 API 可用。为每个来源挑选现成的引擎(第 3 步),如果没有 现成的——就编写适配器。

2a. 梳理来源与 API

来源 是什么 引擎
网站公开页面 内含结构化 JSON 的 HTML <script> site_tool(live fetch + extract)
网站内部 API JSON 端点(搜索、目录、筛选) 针对 API 的适配器或带 method: POST 的 site_tool
RSS 订阅源 新闻和更新 rss_tool
文档(PDF) 说明、目录、规程 pdf_tool
现成的数据转储/导出 含数据的 JSON 文件(品牌、商品) json_tool(预加载的 JSON)
用于搜索的大型页面语料库 整个网站用于 RAG 搜索 archive_tool(第 2c 步)

关于每个来源需要弄清:响应格式、请求参数、 是否需要请求头/密钥(通过 env_var() 从环境注入)、 限制和分页、数据更新频率。

适配器——要么是现有引擎的 YAML 配置(对于 site_tool 只需描述 fetch + extract + output),要么,如果需要 非标准行为(复杂逻辑、非 HTTP 来源),则是新的 Rust 引擎:实现 ToolHandler 并在 crates/tools/src/registry.rs 中注册工厂。对于现成的数据转储/导出,有 通用引擎 json_tool(对 JSON 文件的声明式搜索: search + 基于 MiniJinja 的 computed 字段)。示例—— config/agents/drom/tools/drom_find_brands.yaml:按 预加载的 data/drom_brands.json 搜索品牌。

2b. 网站抓取

cargo run --bin agent-os -- scrape https://nsu.ru -w 8 -d 3 -n 500

参数:-w 个工作线程、-d 遍历深度、-n 最大页面数、 -r 请求间隔、-o 归档路径、-m 导航地图路径。

分析收集到的归档——找出重复出现的块(页眉、页脚、 菜单),需要从文本中清除:

cargo run --bin agent-os -- scrape --analyze site.archive

2c. RAG 归档

对于全文搜索,页面被存入二进制归档 ArchiveBuilder(带重叠的分块、1–3 阶 n-gram 作为俄语的隐式 词干提取、BM25)。归档结构:

data/<источник>/
├── meta.json      — 来源名称、文档数量、缩写
├── docs.bin       — 文档分块
└── terms.bin      — 术语词典和倒排索引

缩写会从形如 «Автоматизации Физико-Технических Исследований (АФТИ)» 的模式中自动提取——搜索 «афти» 能找到完整名称。

现成示例:data/ngu/(НГУ,启动时从 crawled pages 组装)、 data/hg/(HobbyGames,约 4300 件商品)。

第 3 步. 工具

工具 = config/agents/<агент>/tools/*.yaml 中的 YAML 文件。可用的 引擎(kind:):

kind 作用
site_tool HTTP 请求 → 字段提取(JSON 指针、数组匹配、转换)→ 格式化
archive_tool 归档搜索:search、search_grouped、lookup、read_chunks、outline + 按元字段过滤
pdf_tool 下载 PDF 并按页读取
rss_tool 搜索 RSS 订阅源
json_tool 对预加载 JSON 的声明式搜索(search.paths、computed)

外加内核内置工具:http_fetch、fs_read、job_done。

最小 site_tool 示例:

kind: site_tool
name: my_scraper
description: Scrapes example.com product pages.
parameters:
  type: object
  properties:
    url: { type: string, description: "Product page URL" }
  required: [url]

fetch:
  url: "{{ input.url }}"        # MiniJinja-шаблон
  timeout_secs: 10

source:
  type: script_json             # JSON внутри <script> на странице
  contains: productData

extract:
  title:
    pointer: /productData/title
  price:
    pointer: /productData/price
    transform: int

site_tool 的关键能力:

步骤 4. 工具本地调试

任何 YAML 工具都可以在没有服务器、没有 LLM 的情况下检查:

cargo build --bin agent-os --release
./target/release/agent-os tool config/agents/ngu/tools/ngu_search.yaml '{"query":"поступление"}'

输出显示:传入的参数、call_template(用户在调用前 看到的内容)、LLM 的响应以及 result_template。支持 所有引擎:site_tool、archive_tool、pdf_tool、rss_tool、json_tool。

步骤 5. 工具测试

测试是 config/agents/<агент>/tests/*.yaml 中的 YAML 文件,会被 自动发现。有两种类型:

Fixture 测试(kind: site_tool_tests)—— 无网络,数据直接 提供。运行:cargo test。

kind: site_tool_tests
tool: tools/my_tool.yaml

tests:
  - name: "extracts correctly"
    input: { url: "https://example.com/p/1" }
    fixture: { productData: { title: "Widget", price: 99 } }
    assert:
      - { path: /title, equals: "Widget" }
      - { path: /price, equals: 99 }

Live 测试(kind: site_tool_live_tests、 archive_tool_live_tests、rss_tool_live_tests)—— 真实 HTTP 请求, 标记为 #[ignore]。运行:cargo test -- --ignored。

kind: site_tool_live_tests
tool: tools/my_tool.yaml

tests:
  - name: "structure smoke test"
    fetch: true
    input: { url: "https://example.com/p/1" }
    assert:
      - { path: /title, not_null: true }

检查类型:equals、not_null、len、contains。

步骤 6. 智能体配置

config/agents/<агент>/agent.yaml —— 智能体的全部行为:

name: ngu-agent
welcome: |
  👋 Привет! Я ассистент НГУ...
instructions: |
  You are an assistant for NGU (nsu.ru).
  Use ngu_search to find ANY information...
  Answer in Russian, helpful and informative. Always cite source URLs.
tools:                # встроенные инструменты ядра
  - http_fetch
tool_files:           # YAML-инструменты (пути относительно каталога агента)
  - tools/ngu_search.yaml
hook_files:           # хуки (см. шаг 7)
  - hooks/faq_cache.yaml

关于 instructions 的建议:

步骤 7. 钩子(可选)

钩子拦截管道中的消息。现成示例 —— faq_cache (DuckDB):记住问答对,由 LLM 裁判判断相似 问题,缓存的答案要么作为提示插入 (short_circuit: false),要么直接返回而不调用 LLM (short_circuit: true)—— 节省 token 并加快响应。

kind: faq_cache
name: faq_cache
db_path: data/faq_cache_ngu.db
max_candidates: 5
min_confidence: 0.7
short_circuit: true
store: { enabled: true, min_question_chars: 8, min_answer_chars: 8 }
llm:
  base_url: https://api.deepseek.com
  api_key_env: DEEPSEEK_API_KEY
  model: deepseek-chat

步骤 8. 运行基准测试并迭代

运行步骤 1 中的场景:

# Продакшн-сервер
cargo run --bin agent-os --release -- bench --url=https://176.108.251.90 --agent=ngu --max=5

# Локальный сервер (нужен DEEPSEEK_API_KEY в .env)
cargo run --bin agent-os --release -- bench --port=3001 --max=3

标志:--agent= 按智能体过滤,--name= 按场景名称 (正则),--parallel=、--max= 限制,--timeout=。

运行之后:在控制台查看 ✓/✗,分析 bench_report_*.json(字段 failures、error),比较两份报告 以查找回归。失败通过修改 instructions、 工具或数据来修复 —— 必要时向 scenarios.yaml 添加新用例 —— 然后循环重复。

步骤 9. 发布与部署

网站页面

  1. 内容:config/web/pages/<агент>.md;
  2. 注册:在 cards: 中添加卡片,或在 extra_pages: 的 config/web/index.md 中添加条目;
  3. 在真实网站上的演示 —— 在 demos: 中添加条目(打开 /demo/overlay?model=<агент>)。

网站在服务器启动时从 config/web/ 读取 —— 内容修改 只需重启,无需重新构建。

部署到服务器

scp -i ~/.ssh/ssh-pk-025d38 -r config/ data/ realityfaker@176.108.251.90:/home/realityfaker/agent_os/
ssh -i ~/.ssh/ssh-pk-025d38 realityfaker@176.108.251.90 "sudo kill \$(pgrep agent-os); cd /home/realityfaker/agent_os && sudo bash -c 'set -a && source .env && set +a && nohup ./target/release/agent-os serve > agent_os.log 2>&1 &'"
curl -sk https://176.108.251.90/health

如果修改了 Rust 代码(新工具引擎、钩子)—— 在重启前 重新构建 cargo build --release -p agent_web_bot。

步骤 10. 监控与迭代

部署后循环并未结束 —— 智能体在生产环境中运行,这是 下一次迭代的主要数据来源。

需要关注什么

来源 位置 提供什么
服务器日志 ssh ... "tail -50 agent_os.log" 启动错误、崩溃、警告
JSONL 日志 服务器上的 logs/*.jsonl 内核事件:spawn、消息、工具调用、错误
Event DB(DuckDB) logs/events.db 对事件的 SQL 查询:错误频率、热门请求
FAQ 缓存 data/faq_cache_<агент>.db 用户的真实问题 —— 新用例的热门来源
生产环境基准测试 agent-os bench --url=... --max=5 更新后的回归
Health curl -sk https://.../health 服务是否存活

迭代

  1. 定期(或每次部署后)在生产环境运行基准测试并 比较报告 —— 捕捉回归;
  2. 从 FAQ 缓存和日志中收集真实问题 —— 智能体 回答得不好或未回答的问题,会成为 bench/scenarios.yaml 中的新用例(步骤 1);
  3. 修改 instructions、工具或数据 —— 然后重新走一遍 循环:测试 → 基准测试 → 部署;
  4. 随着源网站的变化,更新知识库/归档。

这样循环就闭合了:每一轮都让智能体更准确,用例也 更贴近用户的真实请求。

检查清单