Jelajahi Sumber

fix:更新环境变量的依赖项

lingmin_package@163.com 2 minggu lalu
induk
melakukan
01fb39f4cf
7 mengubah file dengan 470 tambahan dan 42 penghapusan
  1. 2 9
      Dockerfile.dev
  2. 2 9
      Dockerfile.prod
  3. 2 9
      Dockerfile.test
  4. 2 9
      Dockerfile.uat
  5. 103 5
      README.md
  6. 12 1
      docs/test.md
  7. 347 0
      docs/本地规范检索服务设计.md

+ 2 - 9
Dockerfile.dev

@@ -1,16 +1,9 @@
 FROM python:3.12-slim
 
-ENV DEBIAN_FRONTEND=noninteractive \
-    TZ=Asia/Shanghai \
+ENV TZ=Asia/Shanghai \
     APP_ENV=dev
 
-# 安装系统依赖
-RUN apt-get update \
-    && apt-get install -y --no-install-recommends \
-        tzdata \
-    && apt-get clean \
-    && rm -rf /var/lib/apt/lists/* \
-    && python -m venv /venv
+RUN python -m venv /venv
 
 ENV PATH="/venv/bin:$PATH"
 

+ 2 - 9
Dockerfile.prod

@@ -1,16 +1,9 @@
 FROM python:3.12-slim
 
-ENV DEBIAN_FRONTEND=noninteractive \
-    TZ=Asia/Shanghai \
+ENV TZ=Asia/Shanghai \
     APP_ENV=prod
 
-# 安装系统依赖
-RUN apt-get update \
-    && apt-get install -y --no-install-recommends \
-        tzdata \
-    && apt-get clean \
-    && rm -rf /var/lib/apt/lists/* \
-    && python -m venv /venv
+RUN python -m venv /venv
 
 ENV PATH="/venv/bin:$PATH"
 

+ 2 - 9
Dockerfile.test

@@ -1,16 +1,9 @@
 FROM python:3.12-slim
 
-ENV DEBIAN_FRONTEND=noninteractive \
-    TZ=Asia/Shanghai \
+ENV TZ=Asia/Shanghai \
     APP_ENV=test
 
-# 安装系统依赖
-RUN apt-get update \
-    && apt-get install -y --no-install-recommends \
-        tzdata \
-    && apt-get clean \
-    && rm -rf /var/lib/apt/lists/* \
-    && python -m venv /venv
+RUN python -m venv /venv
 
 ENV PATH="/venv/bin:$PATH"
 

+ 2 - 9
Dockerfile.uat

@@ -1,16 +1,9 @@
 FROM python:3.12-slim
 
-ENV DEBIAN_FRONTEND=noninteractive \
-    TZ=Asia/Shanghai \
+ENV TZ=Asia/Shanghai \
     APP_ENV=uat
 
-# 安装系统依赖
-RUN apt-get update \
-    && apt-get install -y --no-install-recommends \
-        tzdata \
-    && apt-get clean \
-    && rm -rf /var/lib/apt/lists/* \
-    && python -m venv /venv
+RUN python -m venv /venv
 
 ENV PATH="/venv/bin:$PATH"
 

+ 103 - 5
README.md

@@ -21,7 +21,7 @@ pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/
 
 ```bash
 source .venv/bin/activate
-uvicorn standards_service.app:app --host 127.0.0.1 --port 18765
+uvicorn app:app --host 127.0.0.1 --port 8107
 ```
 
 默认读取项目根目录下的 `归集617清洗.csv`,默认把查询日志写入 `standards_service/logs/query.jsonl`。
@@ -29,15 +29,15 @@ uvicorn standards_service.app:app --host 127.0.0.1 --port 18765
 可以通过环境变量覆盖路径:
 
 ```bash
-export STANDARDS_CSV_PATH=/path/to/standards.csv
-export STANDARDS_LOG_PATH=/path/to/query.jsonl
+export STANDARDS_CSV_PATH=/app/data/归集617清洗.csv`
+export STANDARDS_LOG_PATH=/app/logs/query.jsonl
 ```
 
 ## 调用
 
 ```bash
 curl --noproxy '*' \
-  -X POST http://127.0.0.1:18765/v1/search \
+  -X POST http://127.0.0.1:8107/v1/search \
   -H 'Content-Type: application/json' \
   -d '{"keywords":["GB 50330","建筑边坡工程技术规范"]}'
 ```
@@ -48,7 +48,7 @@ curl --noproxy '*' \
 
 ```bash
 source .venv/bin/activate
-python -m pytest -q standards_service/tests
+python -m pytest -q tests
 ```
 
 测试同时覆盖合成数据和项目中的真实规范清单。
@@ -63,3 +63,101 @@ python -m pytest -q standards_service/tests
 - 10 个并发请求,每个请求 100 条关键词,建议调用端超时设置不低于 15 秒。
 
 如果后续使用多进程部署,需要重新设计日志写入方式,避免多个进程同时写同一个 JSONL(逐行结构化日志)文件。
+
+
+
+
+### API 访问
+  - URL http://127.0.0.1:8107/v1/search
+  - 请求参数
+    - {
+      "keywords": [
+        "GB 50330-2013 建筑边坡工程技术规范",
+        "混凝土结构设计规范",
+        "GB 50330"
+      ]
+    }
+  - 响应结果
+      - {
+      "results": [
+          {
+              "query": "GB 50330-2013 建筑边坡工程技术规范",
+              "candidates": [
+                  {
+                      "code": "GB 50330-2013",
+                      "title": "建筑边坡工程技术规范",
+                      "status": "现行",
+                      "relation_text": "替代 GB 50330-2002;自《建筑与市政地基基础通用规范》 GB 55003-2021 实施之日起,该标准相关强制性条文第3.1.3、3.3.6、18.4.1、19.1.1条同时废止。",
+                      "implement_date": "2014-6-1",
+                      "match_score": 1.0
+                  },
+                  {
+                      "code": "GB 50330-2002",
+                      "title": "建筑边坡工程技术规范",
+                      "status": "已作废",
+                      "relation_text": "被 GB/T 50330-2013 代替",
+                      "implement_date": "2002-8-1",
+                      "match_score": 0.91
+                  },
+                  {
+                      "code": "GB 50339-2013",
+                      "title": "智能建筑工程质量验收规范",
+                      "status": "现行",
+                      "relation_text": "替代 GB 50339-2003;自《建筑电气与智能化通用规范》 GB 55024-2022 实施之日起,该标准相关强制性条文第12.0.2、22.0.4条同时废止",
+                      "implement_date": "2014-2-1",
+                      "match_score": 0.6886
+                  }
+              ]
+          },
+          {
+              "query": "混凝土结构设计规范",
+              "candidates": [
+                  {
+                      "code": "GB 50367-2013",
+                      "title": "混凝土结构加固设计规范",
+                      "status": "现行",
+                      "relation_text": "替代 GB 50367-2006;自《既有建筑鉴定与加固通用规范》 GB 55021-2021 实施之日起,该标准相关强制性条文第3.1.8、4.3.1、4.3.3、4.4.2、4.5.3条同时废止。",
+                      "implement_date": "2014-6-1",
+                      "match_score": 0.9
+                  },
+                  {
+                      "code": "GB/T 50476-2008",
+                      "title": "混凝土结构耐久性设计规范",
+                      "status": "已作废",
+                      "relation_text": "被 GB/T 50476-2019 代替",
+                      "implement_date": "2009-5-1",
+                      "match_score": 0.8571
+                  },
+                  {
+                      "code": "TB 10092-2017",
+                      "title": "铁路桥涵混凝土结构设计规范(2026年局部修订)",
+                      "status": "现行",
+                      "relation_text": "替代 TB 10002.3-2005;TB 10002.4-2005 废止;公告:国家铁路局公告 2025年第31号",
+                      "implement_date": "2017-5-1",
+                      "match_score": 0.7932
+                  }
+              ]
+          },
+          {
+              "query": "GB 50330",
+              "candidates": [
+                  {
+                      "code": "GB 50330-2013",
+                      "title": "建筑边坡工程技术规范",
+                      "status": "现行",
+                      "relation_text": "替代 GB 50330-2002;自《建筑与市政地基基础通用规范》 GB 55003-2021 实施之日起,该标准相关强制性条文第3.1.3、3.3.6、18.4.1、19.1.1条同时废止。",
+                      "implement_date": "2014-6-1",
+                      "match_score": 0.9
+                  },
+                  {
+                      "code": "GB 50330-2002",
+                      "title": "建筑边坡工程技术规范",
+                      "status": "已作废",
+                      "relation_text": "被 GB/T 50330-2013 代替",
+                      "implement_date": "2002-8-1",
+                      "match_score": 0.9
+                  }
+              ]
+          }
+      ]
+  }

+ 12 - 1
docs/test.md

@@ -22,4 +22,15 @@
 
 uvicorn LQStandardsService.app:app --host 127.0.0.1 --port 8107 
 uvicorn app:app --host 127.0.0.1 --port 8107 
-python -m uvicorn app:app --host 127.0.0.1 --port 8107
+python -m uvicorn app:app --host 127.0.0.1 --port 8107
+
+
+
+### 分析下 如下Dockerfile.xx 系统依赖项 是否有必要
+  - 安装系统依赖
+    RUN apt-get update \
+        && apt-get install -y --no-install-recommends \
+            tzdata \
+        && apt-get clean \
+        && rm -rf /var/lib/apt/lists/* \
+        && python -m venv /venv

+ 347 - 0
docs/本地规范检索服务设计.md

@@ -0,0 +1,347 @@
+# 本地规范检索服务设计
+
+## 1. 文档目的
+
+本文档记录本地规范检索服务当前已经达成共识的需求和接口边界,作为后续讨论匹配算法、阈值、日志及实现方案的基础。
+
+本文档同时记录第一版匹配算法、初始阈值和测试用例。后续可根据真实查询日志调整参数,但不得改变服务的职责边界。
+
+## 2. 建设目标
+
+施工方案审查 Agent(智能体)需要检查方案中引用规范的时效性。为减少 Web Search(网页搜索)的调用和等待时间,建设一个基于本地人工维护规范库的检索服务。
+
+服务接收规范查询关键词,从本地规范库中检索相关规范,并返回最多 3 条候选。Agent(智能体)结合候选内容,自行判断引用规范的时效性。
+
+本地规范库由人工维护,默认其中的数据准确可信。
+
+## 3. 服务职责边界
+
+### 3.1 服务负责
+
+- 接收一批规范查询关键词。
+- 支持按规范名称、规范编号、名称加编号进行查询。
+- 根据规范名称和规范编号执行本地匹配。
+- 每条查询最多返回 3 条候选规范。
+- 按匹配度从高到低排列候选规范。
+- 返回候选规范的状态、实施日期和替代情况。
+- 记录查询日志,支持后续分析、清洗和补充本地规范库。
+
+### 3.2 服务不负责
+
+- 不直接判断引用规范是否有效或是否过期。
+- 不替 Agent(智能体)选择最终采用的规范。
+- 不声明查询结果是否唯一或是否存在歧义。
+- 不使用替代情况参与检索、召回或排序。
+- 不根据替代情况自动关联、扩展其他规范。
+- 不返回 `data_trust(数据可信度)`。
+- 不进行 Web Search(网页搜索)兜底。
+
+## 4. 接口设计
+
+服务只提供一个批量查询业务接口:
+
+```text
+POST /v1/search
+```
+
+### 4.1 请求结构
+
+```json
+{
+  "keywords": [
+    "GB 50330-2013 建筑边坡工程技术规范",
+    "混凝土结构设计规范",
+    "GB 50330"
+  ]
+}
+```
+
+请求说明:
+
+- `keywords(关键词列表)`为必填数组,第一版每批允许 1~100 条。
+- 每个元素代表一条独立的规范查询。
+- 查询内容允许为规范名称、规范编号,或者名称加编号。
+
+### 4.2 响应结构
+
+```json
+{
+  "results": [
+    {
+      "query": "GB 50330-2013 建筑边坡工程技术规范",
+      "candidates": [
+        {
+          "code": "GB 50330-2013",
+          "title": "建筑边坡工程技术规范",
+          "status": "现行",
+          "relation_text": "替代 GB 50330-2002",
+          "implement_date": "2014-06-01",
+          "match_score": 1.0
+        }
+      ]
+    },
+    {
+      "query": "本地规范库中不存在的规范",
+      "candidates": []
+    }
+  ]
+}
+```
+
+响应说明:
+
+- `results(查询结果列表)`与请求中的查询顺序一致。
+- `query(原始查询)`原样返回,方便调用方建立对应关系。
+- `candidates(候选列表)`包含 0~3 条规范。
+- 候选列表为空表示本地没有达到返回条件的候选规范。
+- 服务不返回 `resolution(解析状态)`或 `matched(是否命中)`。
+
+## 5. 候选规范字段
+
+每条候选规范当前返回以下字段:
+
+| 字段 | 含义 |
+|---|---|
+| `code` | 规范编号 |
+| `title` | 规范名称 |
+| `status` | 规范状态,例如现行、已作废、已废止 |
+| `relation_text` | 本地库中的替代情况原文 |
+| `implement_date` | 实施日期 |
+| `match_score` | 查询关键词与候选规范的匹配度 |
+
+替代情况仅作为候选规范的附带信息原样返回,不参与匹配计算。
+
+## 6. 匹配范围
+
+服务只使用以下内容进行匹配:
+
+- 规范编号。
+- 规范名称。
+
+允许处理的典型查询包括:
+
+- 完整规范编号,例如 `GB 50330-2013`。
+- 不含年份的规范编号,例如 `GB 50330`。
+- 规范名称,例如 `建筑边坡工程技术规范`。
+- 规范编号加名称,例如 `GB 50330-2013 建筑边坡工程技术规范`。
+
+当名称或不含年份的编号匹配到多个规范版本时,服务可以返回多个候选,但最多返回 3 条。
+
+### 6.1 本地索引字段
+
+第一版使用以下字段建立检索索引:
+
+- `csres_code(官方编号)`。
+- `csres_normalized_code(标准化编号)`,作为编号别名使用。
+- `csres_title(规范名称)`。
+
+`query_keyword(原始采集关键词)`不作为规范名称索引,避免采集页面标题、应用指南等噪声影响匹配。
+
+### 6.2 查询解析
+
+每条查询先拆分为“规范编号”和“规范名称”两个部分。例如:
+
+```text
+输入:《建筑边坡工程技术规范》GB 50330—2013
+编号:GB 50330-2013
+名称:建筑边坡工程技术规范
+```
+
+编号解析支持编号出现在文本开头、末尾或括号内。第一版约定每条关键词描述一项规范;如果一条关键词中包含多个规范编号,服务仍按相关度返回最多 3 条候选,但调用方应尽量提前拆分。
+
+### 6.3 编号标准化
+
+编号比较前进行以下处理:
+
+- 统一全角和半角字符。
+- 统一不同样式的横线和冒号。
+- 删除编号内部多余空格。
+- 英文字母统一为大写。
+- 保留编号中的斜杠、点号、冒号和横线。
+
+编号匹配分级如下:
+
+| 编号情况 | 编号匹配度 |
+|---|---:|
+| 标准化后完整编号一致 | 1.00 |
+| 两位年份与四位年份对应 | 0.98 |
+| 编号主体和年份一致,但 `GB/GB/T` 等属性不同 | 0.93 |
+| 编号主体一致,但查询缺少年份 | 0.90 |
+| 查询缺少分册号、分部分号或年份 | 0.80 |
+| 编号疑似存在一个字符错误,且年份一致 | 0.75 |
+| 编号主体一致但年份不同 | 0.70 |
+
+年份不同只降低编号匹配度,不直接淘汰候选。服务返回相关规范及其实际编号,由 Agent(智能体)判断查询年份是否错误。
+
+### 6.4 名称标准化和匹配
+
+名称比较前进行以下处理:
+
+- 统一全角和半角字符。
+- 删除空格、书名号和普通标点。
+- 英文字母统一为小写。
+- 保留“规范”“规程”“标准”等具有区分意义的词语。
+
+名称匹配依次考虑:
+
+1. 标准化后完全一致,匹配度为 1.00。
+2. 官方名称完整包含在查询名称中,根据覆盖比例计算 0.90~0.98 的匹配度。
+3. 查询名称完整包含在官方名称中,根据覆盖比例计算 0.65~0.95 的匹配度。
+4. 使用字符相似度计算模糊匹配度。
+
+查询名称少于 6 个中文字符时,不启用宽松模糊匹配,只允许完全一致或完整包含匹配。短名称包含匹配必须按覆盖比例降低分数,避免“验收规程”等通用短语获得虚高匹配度。
+
+### 6.5 编号和名称的并行匹配
+
+第一版采用编号、名称双通道并行匹配:
+
+1. 对本地库中的每条规范分别计算编号匹配度和名称匹配度。
+2. 编号或名称任一维度达到相关度阈值,该规范即可进入候选池。
+3. 编号、名称相互冲突时不淘汰候选,只降低最终匹配度。
+4. 年份不同不阻止名称高度相关的规范进入候选池。
+5. 所有候选统一评分、去重、排序后返回前 3 条。
+
+这样既能召回类似 `TG/T 5440-2018` 与 `JTG/T 5440-2018` 的单字符编号错误,也能让 `JGJ 18-2022`查询看到名称完全一致的 `JGJ 18-2012`,最终由 Agent(智能体)判断编号冲突。
+
+## 7. 匹配度
+
+`match_score(匹配度)`采用 `0~1`的数值范围:
+
+- 数值越大,表示查询关键词与候选规范越相关。
+- 匹配度只表示文本和编号的相关程度。
+- 匹配度不是候选规范正确的概率。
+- 多个不同年份的规范可能具有相同的高匹配度。
+
+### 7.1 最终匹配度
+
+只有编号时:
+
+```text
+match_score = 编号匹配度
+```
+
+只有名称时:
+
+```text
+match_score = 名称匹配度
+```
+
+同时包含编号和名称时:
+
+```text
+较高分 = max(编号匹配度, 名称匹配度)
+较低分 = min(编号匹配度, 名称匹配度)
+match_score = 较高分 × 70% + 较低分 × 30%
+```
+
+该公式保证编号或名称任一维度高度相关时仍可返回,同时在另一维度冲突时降低最终匹配度。服务不再设置名称兜底分数上限。
+
+### 7.2 候选进入条件
+
+候选满足以下任一条件即可进入排序:
+
+- 查询包含编号,且编号匹配度不低于 0.70。
+- 查询包含名称,且名称匹配度不低于 0.75。
+
+准入条件按两个通道独立判断,不使用最终加权分数淘汰单项高度相关的候选。
+
+### 7.3 排序和截断
+
+- 候选按照最终匹配度降序排列。
+- 分数相同时,编号匹配度更高的候选优先。
+- 同一编号不同年份且前述分数相同时,按年份从新到旧展示。
+- 按官方规范编号去重。
+- 每条查询最多返回 3 条候选。
+- 状态、实施日期和替代情况不参与召回、评分或排序。
+
+## 8. Agent(智能体)使用原则
+
+调用服务的 Agent(智能体)应遵守以下原则:
+
+- 自行核对查询中的规范编号、年份和名称。
+- 不能因为服务只返回一条候选,就认定该候选一定唯一。
+- 当返回多个版本时,根据方案原文和候选信息自行判断。
+- 当无法确定具体版本时,应指出引用信息不足,而不是猜测。
+- 候选列表为空时,不进行规范时效性判断。
+- 根据候选规范的状态、实施日期和替代情况判断时效性。
+
+## 9. 日志要求
+
+服务后台需要记录查询日志,最低包含:
+
+- 查询时间。
+- 原始查询内容。
+- 查询结果。
+
+日志用于:
+
+- 分析未命中的规范。
+- 发现误匹配和低质量匹配。
+- 指导后续补充和清洗本地规范库。
+- 复盘服务返回结果。
+
+第一版使用 JSONL(逐行结构化日志),每条子查询记录一行,至少包含:
+
+- 带时区的查询时间。
+- 原始查询内容。
+- 返回的候选规范及匹配度。
+- 查询耗时。
+
+日志文件使用 UTF-8(统一字符编码)写入。第一版不实现自动轮转,待实际运行后根据日志增长速度确定轮转和保留策略。
+
+## 10. 并发处理
+
+服务支持多个 HTTP(网络请求)并发访问。规范库在服务启动时加载到内存,查询阶段只读本地数据;单进程内日志写入使用线程锁保护。
+
+第一版实现重点保证并发下不出现共享状态写坏的问题。匹配计算仍属于 CPU(计算密集型)工作,因此吞吐能力主要受单机 CPU(中央处理器)、Uvicorn(Python ASGI 服务)进程数和单批关键词数量影响。
+
+当前建议:
+
+- 每批关键词最多 100 条。
+- 如果调用端存在 10 个左右并发请求,建议 HTTP 客户端读取超时不低于 15 秒。
+- 如果部署为多进程服务,需要重新设计日志写入方式,例如按进程分日志文件或接入标准 logging(日志模块)方案。
+
+## 11. 当前已确认事项
+
+- 只提供一个批量查询业务接口。
+- 输入为规范查询关键词列表。
+- 查询支持名称、编号、名称加编号。
+- 只根据名称和编号匹配。
+- 每条查询最多返回 3 条候选。
+- 候选按匹配度降序排列。
+- 返回匹配度,但不返回解析状态或数据可信度。
+- 替代情况仅随候选结果原样返回。
+- Agent(智能体)负责最终时效性判断。
+- 本地未找到合适候选时返回空候选列表,不进行外部搜索。
+- 服务记录查询时间、查询内容和查询结果。
+
+## 12. 后续待讨论事项
+
+- 单条关键词长度限制。
+- 日志轮转、保留时间和维护分析流程。
+- 本地规范库的加载、更新和版本管理方式。
+- 服务进程的部署、守护和开机启动方式。
+- 根据真实日志校准匹配阈值和编号纠错规则。
+
+## 13. 第一版测试用例
+
+| 编号 | 测试场景 | 示例查询 | 预期结果 |
+|---:|---|---|---|
+| 1 | 完整编号和名称 | `GB 50330-2013 建筑边坡工程技术规范` | 2013 版排第一,匹配度为 1.00 |
+| 2 | 全角符号和多余空格 | `GB 50330—2013` | 命中 `GB 50330-2013` |
+| 3 | 两位年份 | `CJJ 69-95` | 命中 `CJJ 69-1995` |
+| 4 | 规范属性差异 | `GB/T 6441-1986` | 可以召回 `GB 6441-1986`,匹配度低于精确编号 |
+| 5 | 编号缺少年份 | `GB 50330` | 返回本地库中相关年份版本,最多 3 条 |
+| 6 | 名称对应多个版本 | `建筑边坡工程技术规范` | 返回同名版本,最多 3 条 |
+| 7 | 名称错别字 | `绕结多孔砖和多孔砌块` | 可以召回“烧结多孔砖和多孔砌块” |
+| 8 | 编号单字符错误且名称一致 | `TG/T 5440-2018 公路隧道加固技术规范` | 召回 `JTG/T 5440-2018`,匹配度低于精确编号 |
+| 9 | 编号年份冲突 | `JTG D70/2-2014 公路隧道设计规范` | 可以返回名称相关的 `JTG D70-2004`,但匹配度应体现编号冲突 |
+| 10 | 替代关系不参与查询 | 只输入一个仅出现在 `relation_text` 中的编号 | 不得因为替代关系召回规范 |
+| 11 | 候选上限 | 名称或编号匹配到 4 条以上记录 | 只返回匹配度最高的 3 条 |
+| 12 | 无匹配结果 | `本地规范库中不存在的规范` | 返回空候选列表 |
+| 13 | 批量查询 | 一次输入多条关键词 | 结果数量和顺序与输入一致 |
+| 14 | 日志记录 | 执行一次批量查询 | 每条子查询都有时间、查询内容、结果和耗时日志 |
+| 15 | 文件编码 | 加载 UTF-8 或 GB18030 编码的规范清单 | 均可正确读取中文内容 |
+| 16 | 名称相同但年份不同 | `钢筋焊接及验收规程JGJ 18-2022` | 返回 `JGJ 18-2012`供 Agent(智能体)判断,匹配度为 0.91 |
+| 17 | 编号分隔符周围有空格 | `GB / T 6441 - 1986` | 正确解析并召回 `GB 6441-1986` |
+| 18 | 通用短名称 | `验收规程` | 可以返回相关候选,但匹配度不得虚高到 0.90 以上 |