发票分类查询这么Easy?-实战 Claude Code Skills

132 阅读12分钟

前段时间频繁刷到 claude skills 的技术分享,大都是说这玩意有多牛逼。于是周日我打算学一学。花了点时间看了官方的文档后,打算结合业务实际演练下。先是网上各种找实战分享,不是官方文档翻译就是想看更多卖课的。突然想到自己最近在研发如何整理发票,那能不能做一个根据商品名称推荐发票分类的 ai agent。说干咱就干!

看完这篇博客你将学到:

  • claude skills 的实际应用

你需要有的技能:

使用过 claude code

一、方案演进

首先我拥有的材料:

  1. 从国家税务总局下载的【商品和服务税收分类编码表】excel 格式,如下:
  2. 把 excel 的 的分类按照编码层级整理成了一个 json 树categories.json 格式,如下:

方案一:直接询问

要实现我们的需求,其实也很简单,直接基于 claude code 文件询问,如下:

方案一的缺点:

  • category.json 文件有 64486 个字符,每次询问至少消耗的 token 已经被文件字符数锁定,这不符合我们出方案的基础规则:控制问题规模。category.json也可能是 60w 个字符,600w 个字符,打到模型的上下文吞不下。

方案二:使用Claude skills,将发票查询打包成技能

先不要问 skills 有什么用,那个看官方文档就可以,当然也可能看了官方文档也不清楚,跟着做,做完就清楚了!

这里我只会将这个项目中用到的相关知识,各种毛细知识可以查看 官网文档,中文的

  1. claude code 的 skills 定义在项目目录的".claude/skills"文件夹,比如下面我这里有两个 skills:
    1. 第一个是画图表的 skill
    2. 第二个skill 就是根据商品名称查分类的 skill

  1. 现在我们手工新建一个 skill
mkdir -p .claude/skills/product-category-matcher

2.1 编写 SKILL.md

---
name: product-category-matcher
description: 从用户输入的自然语言中识别出商品或商品分类,匹配 发票分类树,返回匹配的Top3分类,适用场景:(1) 用户描述想要采购的物品,(2) 用户提及某类产品需要查询。触发词包括:查找分类、匹配分类、什么分类、属于哪类、推荐分类等。
---

# 商品发票分类匹配器

根据用户输入的自然语言,从发票分类树中推荐最匹配的 Top3 个分类,严格按照输出格式输出。

## 数据结构

分类树


references/
├── categories.json          #发票分类树json


文件结构:


[
  {
    "code": "1000000",
    "name": "货物",
    "level": "pian",
    "children": [...]
  }
]


层级:pian(篇) > lei(类) > zhang(章) > jie(节)

## 匹配流程

1. **提取关键词**:从用户输入中提取商品关键词
2. **加载发票分类树**:加载 categories.json 文件
3. **精确匹配**:在数据中搜索最匹配的分类
4. **返回结果**:输出 Top3 个推荐分类

## 匹配策略

按优先级排序:

1. **精确匹配**:分类名称与用户输入完全一致
2. **包含匹配**:分类名称包含用户关键词,或用户输入包含分类名称
3. **语义匹配**:基于语义理解的相似度匹配(如"电脑"匹配"计算机")
4. **上下文推断**:根据行业、场景推断可能的分类

## 输出格式


{
  "recommendations": [
    {
      "rank": 1,
      "code": "1020304",
      "name": "分类名称",
      "path": "货物 > 大类 > 中类 > 小类",
      "confidence": "high|medium|low",
      "reason": "匹配原因说明"
    }
  ]
}

2.2 创建references文件夹

2.3 将categories.json文件放入references文件夹。

2.4 完成!

现在我们来使用这个技能,如图,我们输入“查询可口可乐的发票分类” claude code 发现并询问我们是否使用这个 skill,选 2:Yes, and don't ask again...

claude code加载categories 文件并输出的结果。

总结:

  1. 我们知道了 claude skills 其实就是沉淀我们一个已经成熟的技能,这个技能可以是“发票分类查询”,也可以是“项目整理架构介绍”,也可以是“使用mermaid绘制流程图(中文纠错)”,我们描述清楚 skill 的使用场景和使用方法,claude code 会在需要的时候主动调用工具。
  2. skill 是工具主动调用的,调用的好不好有的时候与取决于模型的能力。
  3. 我演示的时候使用的模型是 glm4.6

方案三:优化,使用渐进式加载节省 token,提高稳定性

方案二相对于方案一,就是把方案一打包成的技能,但是在 token 使用上并没有节省。本方案我们来优化下:

我们观察,我们的数据是高度结构化、层次化的,这是我们优化的基础。

我们发现可以把唯一的category.json按照二级分类来拆分为不同的分片文件。然后写一个前两级分类的索引文档.MD,让 ai 先根据较小的 索引文档.MD 确定分类,然后加载命中的具体文件识别具体的分类。

这个步骤甚至都不需要自己做,既然你使用了 claude code,让它写一个脚本,按这种规则拆分就行。比如我拆分成如下结构

代码分享在最后

_index.md文件的内容

# 分类分片索引

本目录包含按二级分类(类)拆分的 JSON 文件。

> 去重统计:原始 390 个叶子节点,去重后 359 个,移除 31 个重复项

## 使用方法

1. 根据用户输入的关键词,在下表中找到匹配的分类
2. 加载对应的 JSON 文件进行精确匹配

## 分片列表

### 货物

| 编码    | 名称             | 文件                    | 节点数 | 关键词                                                       |
| ------- | ---------------- | ----------------------- | ------ | ------------------------------------------------------------ |
| 1010000 | 农产品           | `农产品.json`           | 32     | 农业产品、动物及其产品、林业产品、油料、活家禽、活牲畜       |
| 1020000 | 矿产品           | `矿产品.json`           | 22     | 原油、原盐、天然气、有色金属矿石、液化天然气、煤炭           |
| 1030000 | 食品类产品       | `食品类产品.json`       | 39     | 农副食品、方便食品、烟草制品、焙烤食品、糖果类食品、薯豆加工品 |
| 1040000 | 纺织服装皮革产品 | `纺织服装皮革产品.json` | 9      | 帽子、服装、服装鞋帽、皮革毛皮制品、纺织产品、鞋             |
| 1050000 | 木制品           | `木制品.json`           | 8      | 家具、家具及配件、家具配件、木制品、棕藤草制品、竹制品       |
| 1060000 | 纸印刷品文教产品 | `纸印刷品文教产品.json` | 25     | 保健休闲用品、印刷品、墨水、工艺品、教具、文具               |
| 1070000 | 石化医药产品     | `石化医药产品.json`     | 46     | 中药饮片、人造能源、化学原料及制品、化学纤维、化学药品制剂、化学药品原药 |
| 1080000 | 金属及非金属制品 | `金属及非金属制品.json` | 19     | 有色金属冶炼压延品、核燃料、稀有稀土金属、贵金属、金属制品、非金属矿物制品 |
| 1090000 | 机械设备         | `机械设备.json`         | 155    | 专用设备、交通运输设备、仪器仪表办公用机械、其他机械设备、发动机、发电机 |
| 1100000 | 电力热力水燃气   | `电力热力水燃气.json`   | 9      | 冷气、发电及供电、水冰雪、热力、燃气、电力热力冷气           |

### 劳务

| 编码    | 名称 | 文件        | 节点数 | 关键词 |
| ------- | ---- | ----------- | ------ | ------ |
| 2010000 | 劳务 | `劳务.json` | 2      | 劳务   |

### 销售服务

| 编码    | 名称     | 文件            | 节点数 | 关键词                                                       |
| ------- | -------- | --------------- | ------ | ------------------------------------------------------------ |
| 3010000 | 运输服务 | `运输服务.json` | 3      | 运输服务                                                     |
| 3020000 | 邮政服务 | `邮政服务.json` | 4      | 邮政服务                                                     |
| 3030000 | 电信服务 | `电信服务.json` | 3      | 电信服务                                                     |
| 3040000 | 现代服务 | `现代服务.json` | 24     | 人力资源服务、企业管理服务、会展服务、信息技术服务、商务辅助服务、广告服务 |
| 3050000 | 建筑服务 | `建筑服务.json` | 2      | 建筑服务                                                     |
| 3060000 | 金融服务 | `金融服务.json` | 6      | 保险服务、金融服务                                           |
| 3070000 | 生活服务 | `生活服务.json` | 9      | 住宿服务、旅游服务、生活服务、餐饮服务                       |

### 无形资产

| 编码    | 名称     | 文件            | 节点数 | 关键词   |
| ------- | -------- | --------------- | ------ | -------- |
| 4010000 | 无形资产 | `无形资产.json` | 4      | 无形资产 |

### 不动产

| 编码    | 名称   | 文件          | 节点数 | 关键词 |
| ------- | ------ | ------------- | ------ | ------ |
| 5010000 | 不动产 | `不动产.json` | 4      | 不动产 |

### 不征税项目

| 编码    | 名称                         | 文件                                | 节点数 | 关键词 |
| ------- | ---------------------------- | ----------------------------------- | ------ | ------ |
| 6010000 | 预付卡销售                   | `预付卡销售.json`                   | 1      | -      |
| 6020000 | 房地产预收款                 | `房地产预收款.json`                 | 1      | -      |
| 6030000 | 补开营业税发票               | `补开营业税发票.json`               | 1      | -      |
| 6040000 | 代收印花税                   | `代收印花税.json`                   | 1      | -      |
| 6050000 | 代收车船使用税               | `代收车船使用税.json`               | 1      | -      |
| 6060000 | 融资性售后回租承租方出售资产 | `融资性售后回租承租方出售资产.json` | 1      | -      |
| 6070000 | 资产重组涉及的不动产         | `资产重组涉及的不动产.json`         | 1      | -      |
| 6080000 | 资产重组涉及的土地使用权     | `资产重组涉及的土地使用权.json`     | 1      | -      |
| 6090000 | 代理进口免税货物货款         | `代理进口免税货物货款.json`         | 1      | -      |
| 6100000 | 有奖发票奖金                 | `有奖发票奖金.json`                 | 1      | -      |
| 6110000 | 不征税自来水                 | `不征税自来水.json`                 | 1      | -      |
| 6120000 | 建筑服务预收款               | `建筑服务预收款.json`               | 1      | -      |

---

SKILL.md 文件加上加载索引的说明

---
name: product-category-matcher
description: 从用户输入的自然语言中识别出商品或商品分类,匹配 发票分类树,返回匹配的Top3分类,适用场景:(1) 用户描述想要采购的物品,(2) 用户提及某类产品需要查询。触发词包括:查找分类、匹配分类、什么分类、属于哪类、推荐分类等。
---

# 商品发票分类匹配器

根据用户输入的自然语言,从发票分类树中推荐最匹配的 Top3 个分类,严格按照输出格式输出。

## 数据结构

分类数据按二级分类(lei)拆分存储,减少单次加载的数据量:

references/
├── categories/
│   ├── _index.md                    # 分片索引(必读)
│   ├── _manifest.json               # 分片清单
│   ├── 1010000-农产品.json          # 按二级分类拆分的数据
│   ├── 1020000-食品饮料.json
│   └── ...
└── categories-index.md              # 总体概览索引

分片文件结构:

{
  "parent": {"code": "1000000", "name": "货物", "level": "pian"},
  "category": {
    "code": "1010000",
    "name": "农产品",
    "level": "lei",
    "children": [...]
  }
}

层级:pian(篇) > lei(类) > zhang(章) > jie(节)

## 匹配流程

1. **提取关键词**:从用户输入中提取标的物关键词
2. **查阅分片索引**:读取 `references/categories/_index.md`,根据关键词定位可能的二级分类
3. **加载目标分片**:只加载匹配的 1-3 个分片 JSON 文件
4. **精确匹配**:在分片数据中搜索最匹配的分类
5. **返回结果**:输出 TopN 个推荐分类

**重要**:不要一次性加载所有分片,只加载与用户查询相关的分片文件。

## 匹配策略

按优先级排序:

1. **精确匹配**:分类名称与用户输入完全一致
2. **包含匹配**:分类名称包含用户关键词,或用户输入包含分类名称
3. **语义匹配**:基于语义理解的相似度匹配(如"电脑"匹配"计算机")
4. **上下文推断**:根据行业、场景推断可能的分类

## 输出格式

{
  "query": "用户原始输入",
  "keywords": ["提取的关键词"],
  "recommendations": [
    {
      "rank": 1,
      "code": "1020304",
      "name": "分类名称",
      "path": "货物 > 大类 > 中类 > 小类",
      "confidence": "high|medium|low",
      "reason": "匹配原因说明"
    }
  ]
}

## 示例

**输入**:我想采购一批办公用的激光打印机

**输出**:

{
  "query": "我想采购一批办公用的激光打印机",
  "keywords": ["激光打印机", "办公", "打印机"],
  "recommendations": [
    {
      "rank": 1,
      "code": "1090504",
      "name": "打印机",
      "path": "货物 > 办公消耗用品及类似物品 > 办公设备 > 打印机",
      "confidence": "high",
      "reason": "精确匹配'打印机'"
    },
    {
      "rank": 2,
      "code": "1090501",
      "name": "办公设备及配件",
      "path": "货物 > 办公消耗用品及类似物品 > 办公设备 > 办公设备及配件",
      "confidence": "medium",
      "reason": "上级分类,覆盖更广"
    }
  ]
}

## 注意事项

- 优先推荐最细粒度(jie 节)的分类
- 同时提供上级分类作为备选,增加容错性
- 当匹配不确定时,说明置信度为 low 并解释原因
- 如用户输入过于模糊,可请求补充信息

再次执行,发现 ai 已经按需加载文件了。

总结:

  • 这里我们主要是要打开思路,对结构化的上下文进行分片和按需加载,后续碰到大上下文的场景时候都可以考虑能不能用这样的方式处理。
  • 没一个新的事物产生,这些事物的推崇者都会热衷于创造一些新词,这些新词其实就是新瓶装旧酒。不要被它吓到。

github 链接:github.com/roylee1024/…