Files
iAs/docs/TOOLKIT_WORKFLOW.md
wunianxiao 7d5140c8d2 feat: AI 工具架构重构与微信增强 (0.2.17 → 0.2.22)
0.2.17 收束模型初始工具列表:
- 仅暴露 query_capabilities/query_capability_detail/call_capability 三个入口
- API 能力统一通过 iAs HTTP API 封装,删除重复 YAML 工具

0.2.18 系统提示词拆分:
- 固定系统提示词硬编码,动态附加部分 AI 可维护
- 新增 update_additional_system_prompt 能力和持久化

0.2.19 上下文增强与打断语义:
- /new 拥有最高打断语义,取消运行中任务并清除当前 turn
- raw_message JSONB 原文入库,群聊按 group_id 隔离作用域
- 工具调用说明替代动态附加系统提示词

0.2.20 微信输入中状态:
- 改用官方 getconfig + sendtyping 流程,显式管理 typing 状态

0.2.21 API 文档功能分组:
- /v1/api-docs 返回 groups,帮助 AI 按功能面发现接口

0.2.22 AI API 能力去重:
- 移除与 HTTP endpoint 重复的专用能力,统一用 query_api_docs + call_http_api
- 删除不再编译的 web/memory 工具文件
2026-07-08 14:58:13 +08:00

330 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TOOLKIT WORKFLOW — YAML 驱动的 HTTP 工具链引擎
## 概述
TOOLKIT WORKFLOW 让你通过编写 YAML 文件来定义外部 HTTP 能力。一个 YAML 文件描述一个能力:它接受哪些参数、调用哪些外部 HTTP API、如何从响应中提取数据、以及最终返回什么给 LLM。
模型初始只暴露三个入口工具:`query_capabilities``query_capability_detail``call_capability`。YAML 能力不会直接出现在初始 tools 数组中,必须先查询能力列表或详情,再通过 `call_capability` 按能力名称和参数调用。
核心能力:
- 一个 YAML 文件 = 一个完整的 HTTP 能力,无需写代码
- 支持多步 HTTP 请求链,步骤之间可以传递变量
- 流程控制:`next` 跳转步骤、`jump` 降级到备源、`abort` 终止执行
- 键级缓存:`cache` 缓存变量,同一调用中缺键自动重请求
- 统一提取:`extract` 字段,语法自描述引擎(路径 / 正则)
- 工具分类:`api` 能力用于发现和调用 iAs 内部 HTTP API`http` 能力来自 `tools/*.yaml` 外部 API 配置。
- 内部 HTTP API 不再为每个 endpoint 维护一个重复 AI 能力。模型应先调用 `query_api_docs` 查询功能分组、endpoint_id、参数和请求体,再调用 `call_http_api` 执行具体 endpoint。
---
## YAML 顶层结构
一个工具 YAML 文件包含以下顶层字段:
| 字段 | 必填 | 类型 | 说明 |
|------|------|------|------|
| `name` | 是 | string | 能力名,对应 `call_capability.name` |
| `desc` | 是 | string | 能力描述,会出现在 `query_capabilities` 和能力详情中 |
| `params` | 否 | array | 能力参数定义,映射为 `query_capability_detail` 返回的 JSON Schema |
| `env` | 否 | array[string] | 该工具依赖的环境变量名列表,仅作文档和校验 |
| `steps` | 是 | array | 请求步骤链,按顺序执行 |
---
## `params` — 参数定义
定义 LLM 可以传入的参数,映射为 function calling 的 parameters schema。
| 字段 | 必填 | 类型 | 说明 |
|------|------|------|------|
| `name` | 是 | string | 参数名,在模板中通过 `${param:key}` 引用 |
| `type` | 是 | string | 取值:`string` / `number` / `integer` / `boolean` |
| `required` | 是 | boolean | 是否必填 |
| `description` | 是 | string | 参数说明,LLM 据此理解参数含义 |
| `default` | 否 | any | 默认值,LLM 未传时自动使用 |
---
## `steps` — 请求步骤
每个步骤定义一个 HTTP 请求及其后续处理。
### 步骤字段
| 字段 | 必填 | 类型 | 默认值 | 说明 |
|------|------|------|--------|------|
| `url` | 是 | string | — | 请求 URL,支持模板语法 |
| `method` | 否 | string | `GET` | HTTP 方法:`GET` / `POST` / `PUT` / `DELETE` / `PATCH` |
| `headers` | 否 | map | — | 请求头键值对,值支持模板语法 |
| `query` | 否 | array | — | URL 查询参数,格式为 `[{key, value}]` 元组列表,值支持模板语法 |
| `body` | 否 | string | — | 请求体,支持模板语法 |
| `timeout` | 否 | integer | 30 | 超时时间(秒) |
| `cache` | 否 | boolean | false | 是否对该步骤启用键级缓存 |
| `next` | 否 | integer | — | 步骤成功后跳转到第几个步骤(0-based),不设则顺序执行下一步 |
| `var` | 否 | array | — | 变量提取列表 |
| `result` | 否 | string | — | 最终返回模板,有此字段则该步为终步 |
### 步骤示例
```yaml
steps:
- url: ${env:BASE_URL}/auth/token
method: POST
headers:
Content-Type: application/json
body: |
{"client_id": "${env:CLIENT_ID}", "client_secret": "${env:CLIENT_SECRET}"}
timeout: 15
cache: true
var:
- name: token
extract: access_token
abort: true
next: 1
- url: ${env:BASE_URL}/orders/${param:order_id}
method: GET
headers:
Authorization: Bearer ${step0:token}
var:
- name: status
extract: data.status
- name: amount
extract: data.amount
result: |
订单号: ${param:order_id}
状态: ${step1:status}
金额: ${step1:amount}
```
---
## `var` — 变量提取
每个步骤执行完 HTTP 请求后,按顺序处理 `var` 列表中的条目,从响应中提取命名变量。提取的变量通过 `${stepN:var_name}` 在后续步骤中引用。
### `extract` — 提取表达式
一个字段覆盖所有提取场景。值的语法决定使用的引擎:
| 语法 | 引擎 | 说明 |
|------|------|------|
| 不以 `/` 开头 | 路径引擎 | 对 JSON/YAML 响应执行结构化路径导航 |
| 以 `/` 开头且以 `/` 结尾 | 正则引擎 | 对原始响应文本执行正则匹配,取捕获组 1 |
**路径引擎**:自动检测响应格式(先 JSON,失败则 YAML),然后按路径导航取值。
| 语法 | 含义 | 示例 |
|------|------|------|
| `key` | 访问对象字段 | `data.status` |
| `key[N]` | 访问数组第 N 个元素 | `items[0].name` |
| `key[]` | 遍历数组所有元素 | `books[]` |
| `key[].field` | 遍历数组,对每个元素取字段 | `books[].title` |
> 键名建议仅使用 `[a-zA-Z0-9_]`,避免含 `.` `[` `]` 的特殊键名。
**正则引擎**`/pattern/` 形式,对原始响应文本执行正则匹配,取第一个捕获组。
```yaml
# 路径:从 JSON 响应中提取
var:
- name: token
extract: auth.access_token
# 正则:从任意文本中提取
var:
- name: session
extract: /session[= ]([a-f0-9]+)/
```
### 提取失败处理(每个条目最多选一种)
| 配置 | 提取成功 | 提取失败 |
|------|---------|---------|
| 不设任何失败处理 | 存入变量 | 存入空字符串 `""`,继续执行 |
| `default: "值"` | 存入变量 | 存入默认值,继续执行 |
| `abort: true` | 存入变量 | 终止整个工具,返回错误给 LLM |
| `jump: N` | 存入变量 | 跳转到第 N 个步骤执行,N 从 0 开始 |
### var 条目完整字段
| 字段 | 必填 | 类型 | 默认值 | 说明 |
|------|------|------|--------|------|
| `name` | 是 | string | — | 变量名,通过 `${stepN:name}` 引用 |
| `extract` | 否 | string | — | 提取表达式,语法自描述引擎(路径 / 正则) |
| `default` | 否 | string | — | 提取失败时的默认值 |
| `abort` | 否 | boolean | false | 提取失败时是否终止工具 |
| `jump` | 否 | integer | — | 提取失败时跳转到第几个步骤(0-based) |
---
## 流程控制
三种流程控制机制,覆盖顺序执行、条件跳转和异常终止。
### `next` — 成功后跳转
- 位置:步骤级别
- 触发条件:步骤所有 var 都没有因 abort/jump 而失败
- 效果:跳转到指定步骤号(0-based),不设则顺序执行下一步
- 用途:跳过某些步骤、实现条件分支
### `jump` — 提取失败时降级
- 位置:var 条目级别
- 触发条件:该条目的提取失败且未设置 default
- 效果:跳转到指定步骤号(0-based),当前步骤剩余 var 不再执行
- 用途:主数据源失败时自动切换到备数据源
### `abort` — 提取失败时终止
- 位置:var 条目级别
- 触发条件:该条目的提取失败
- 效果:终止整个工具执行,返回错误信息给 LLM
- 用途:关键变量(如认证 token)获取失败时立即报错
---
## `cache` — 键级缓存
当步骤设置 `cache: true` 时,该步骤提取的所有变量会被缓存。
缓存行为:
- **命中**:缓存中存在该步骤所有 var.name → 跳过 HTTP 请求,直接返回缓存值
- **未命中**:任意一个 var.name 缺失 → 发起 HTTP 请求,提取所有变量,全部存入缓存
- **生命周期**:单次工具调用期间(内存级),工具返回后释放
- **缓存键**:由步骤的 `url + method + headers + body` 模板展开后的哈希确定
典型用法:第一步获取认证 token 并缓存,后续多步复用 token 时不会重复请求认证接口。
---
## 模板语法
以下字段支持模板语法:`url``headers` 的值、`body``result`
### 三种引用
| 语法 | 来源 | 示例 |
|------|------|------|
| `${param:key}` | `call_capability.parameters` 传入的能力参数 | `${param:city}``${param:order_id}` |
| `${env:VAR}` | 系统环境变量 | `${env:API_KEY}``${env:BASE_URL}` |
| `${stepN:var_name}` | 第 N 个步骤提取的变量,N 从 0 开始 | `${step0:token}``${step1:status}` |
### 约束
1. 禁止嵌套引用:`${step0:${env:KEY}}` 不允许
2. 禁止原始步骤引用:`${step:0}` 不允许,必须先通过 var 提取为命名变量
---
## `result` — 最终返回
步骤的 `result` 字段定义该工具最终返回给 LLM 的内容。
- 如果某步设置了 `result`,该步即为**终步**,执行后不再继续后续步骤
- 如果所有步骤都未设置 `result`,默认返回最后一步的原始响应体
- `result` 支持模板语法,可以拼接多个变量和文字
```yaml
# 返回单个变量
result: ${step1:status}
# 多行模板拼接
result: |
订单号: ${param:order_id}
状态: ${step1:status}
金额: ${step1:amount}
```
---
## 执行流程
```
1. 加载 YAML → 解析为 YamlToolDef
2. 解析 LLM 参数 → params HashMap
3. 加载 env 声明的环境变量 → env HashMap
4. 初始化 cache = {}
5. step_idx = 0
while step_idx < steps.len():
┌─ 当前步骤执行 ──────────────────────────────┐
│ │
│ [cache: true?] │
│ ├─ 缓存命中(所有 var 键都存在)→ 跳过HTTP │
│ └─ 缓存未命中 → 继续 │
│ │
│ 展开 url/headers/body 中的模板 │
│ ${param:key} → params["key"] │
│ ${env:VAR} → env["VAR"] │
│ ${stepN:var} → ctx.vars[(N, var)] │
│ │
│ HttpRequest 执行 → HttpResponse │
│ 保存到 ctx.steps[step_num] │
│ │
│ for each var: │
│ extract 语法分发: │
│ ├─ /.../ → 正则引擎,取捕获组1 │
│ └─ 其他 → 路径引擎(JSON→YAML 自动检测) │
│ ├─ 成功 → 存入 ctx.vars + step_vars │
│ └─ 失败 → │
│ ├─ abort:true → 终止,返回错误 │
│ ├─ default:x → 使用默认值 │
│ ├─ jump:N → step_idx = N, break │
│ └─ (无) → 空字符串 │
│ │
│ [cache: true?] → 将 step_vars 存入 cache │
│ │
│ [result 存在?] │
│ └─ 展开 result 模板 → 返回给 LLM → 结束 │
│ │
│ [next 存在?] │
│ ├─ next:N → step_idx = N │
│ └─ (无) → step_idx += 1 │
│ │
└──────────────────────────────────────────────┘
6. 循环结束 → 返回最后一步原始响应体
```
---
## 错误处理
| 场景 | 处理方式 |
|------|---------|
| YAML 文件格式错误 | 启动时打印警告,跳过该文件 |
| 模板引用了未定义的参数 | 替换为空字符串,记录警告日志 |
| 环境变量未设置 | 替换为空字符串,记录警告日志 |
| HTTP 请求失败(连接/超时) | 返回错误详情给 LLM |
| `var.abort: true` 且提取失败 | 终止,返回 "变量 xxx 提取失败" |
| `var.jump: N` 且提取失败 | 跳转到第 N 个步骤,N 从 0 开始,不报错 |
| `var.default` 且提取失败 | 使用默认值,不报错 |
| 路径语法错误(空段、非法索引) | 返回错误给 LLM,附带路径表达式 |
| 路径键不存在 / 索引越界 | 提取失败,触发 default/abort/jump |
| 正则语法错误 | 返回错误给 LLM,附带正则表达式 |
| 正则无匹配 | 提取失败,触发 default/abort/jump |
| 响应体非 JSON 也非 YAML(路径引擎) | 返回错误给 LLM |
| `next` / `jump` 目标步骤不存在 | 终止,返回配置错误 |
---
## 扩展预留
以下字段预留供后续版本实现:
| 字段 | 位置 | 用途 |
|------|------|------|
| `retry` | `steps[]` | 失败重试次数与退避策略 |
| `cache.ttl` | `steps[]` | 缓存有效期(秒) |
| `validate` | `params[]` | 参数级正则校验 |
| `sensitive` | `env[]` | 标记敏感环境变量,日志脱敏 |
| `loop` | `steps[]` | 条件循环(分页自动翻页) |
| `export` | `steps[]` | 将变量导出为环境变量供子进程使用 |
| `pre_request` | 顶层 | 工具级别的前置请求(全局认证) |