Compare commits
87 Commits
v0.1.3
...
1b04ee1c4c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b04ee1c4c | ||
|
|
103f225f54 | ||
|
|
e42dedaba1 | ||
|
|
607e127f59 | ||
|
|
6d33ba5742 | ||
|
|
08a4fa3577 | ||
|
|
d660a961fb | ||
|
|
669d22e71f | ||
|
|
88e91a5900 | ||
|
|
1986b0d945 | ||
|
|
24b5b71b0f | ||
|
|
8b3495455b | ||
|
|
3b74a330a3 | ||
|
|
8158716e23 | ||
|
|
0cda750ff0 | ||
|
|
81e990ab72 | ||
|
|
47c6a4bb73 | ||
|
|
96c2e1099a | ||
|
|
729d833edb | ||
|
|
304bbe1fd4 | ||
|
|
3d69f8501f | ||
|
|
4d04f4e7af | ||
|
|
3131112952 | ||
|
|
a2f67af13e | ||
|
|
0cde1f8990 | ||
|
|
a6674a1e76 | ||
|
|
127d603e7d | ||
|
|
3f17619e0c | ||
|
|
59ba76c74a | ||
|
|
35372c6661 | ||
|
|
38653fa365 | ||
|
|
c28e99b714 | ||
|
|
43432534d8 | ||
|
|
cce19e4c40 | ||
|
|
b8915a29c0 | ||
|
|
4199feb681 | ||
|
|
0fac8b615f | ||
|
|
a3e5295915 | ||
|
|
1f4681f486 | ||
|
|
09a66c72cb | ||
|
|
0d525fa64c | ||
|
|
470f343b29 | ||
|
|
9f7b8b46a3 | ||
|
|
792741709a | ||
|
|
5747e85acf | ||
|
|
8b952c9a26 | ||
| 336fee9d93 | |||
|
|
25724c354f | ||
|
|
e124e4bbcb | ||
|
|
f60cebadb8 | ||
|
|
1cbf3fee44 | ||
|
|
87da5df91b | ||
|
|
75d5c178e1 | ||
|
|
b9826a1985 | ||
|
|
0f8bc4071a | ||
|
|
cb36d78fa2 | ||
|
|
8e2477587f | ||
|
|
67b81a1bd8 | ||
|
|
9c24a852e7 | ||
|
|
95956afbc6 | ||
|
|
c73178b65d | ||
|
|
8c2f301d85 | ||
|
|
4717ee6086 | ||
|
|
513ff909f9 | ||
|
|
92198549f6 | ||
|
|
59d3bf0f00 | ||
|
|
04f0951b3d | ||
|
|
8887cf5a27 | ||
|
|
34457f9c3e | ||
|
|
e12b140508 | ||
|
|
18d716bc6b | ||
|
|
74d488adfa | ||
|
|
31052d0b98 | ||
|
|
20cb60e247 | ||
|
|
3130c42d76 | ||
|
|
6fc5e66ea1 | ||
|
|
27dd2f0a0d | ||
|
|
faa39e6c06 | ||
|
|
d060f89d30 | ||
|
|
0d6327a990 | ||
|
|
15006a05a7 | ||
|
|
0c74b4ab4a | ||
|
|
ca691f3ee0 | ||
|
|
92444e7eae | ||
|
|
7989f3a159 | ||
|
|
4c59941ec6 | ||
|
|
678f64d772 |
51
.env
51
.env
@@ -1,51 +0,0 @@
|
||||
APP_NAME=X-Financial
|
||||
APP_ENV=local
|
||||
APP_DEBUG=true
|
||||
API_V1_PREFIX=/api/v1
|
||||
SETUP_COMPLETED=true
|
||||
VITE_SETUP_COMPLETED=true
|
||||
|
||||
COMPANY_NAME=YGSOFT
|
||||
COMPANY_CODE=123
|
||||
ADMIN_EMAIL='admin@admin.com'
|
||||
VITE_COMPANY_NAME=YGSOFT
|
||||
VITE_COMPANY_CODE=123
|
||||
VITE_ADMIN_EMAIL='admin@admin.com'
|
||||
# Admin login credentials are stored separately under server/.secrets/
|
||||
|
||||
WEB_HOST=10.10.10.122
|
||||
WEB_PORT=5173
|
||||
VITE_WEB_HOST=10.10.10.122
|
||||
VITE_WEB_PORT=5173
|
||||
|
||||
SERVER_HOST=0.0.0.0
|
||||
SERVER_PORT=8000
|
||||
VITE_SERVER_HOST=0.0.0.0
|
||||
VITE_SERVER_PORT=8000
|
||||
SERVER_STARTUP_TIMEOUT=300
|
||||
SERVER_BLOCKING_STARTUP_TIMEOUT=12
|
||||
VITE_API_BASE_URL=/api/v1
|
||||
VITE_AUTH_IDLE_TIMEOUT_MINUTES=30
|
||||
ONLYOFFICE_ENABLED=true
|
||||
ONLYOFFICE_PUBLIC_URL=http://10.10.10.122:8082
|
||||
ONLYOFFICE_BACKEND_URL=http://main:8000
|
||||
ONLYOFFICE_JWT_SECRET=change-me-onlyoffice
|
||||
HERMES_AGENT_SHARED_TOKEN=change-me-hermes
|
||||
|
||||
POSTGRES_HOST=10.10.10.189
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_DB=postgres
|
||||
POSTGRES_USER=root
|
||||
POSTGRES_PASSWORD=8811614287327Leo
|
||||
VITE_POSTGRES_HOST=10.10.10.189
|
||||
VITE_POSTGRES_PORT=5432
|
||||
VITE_POSTGRES_DB=postgres
|
||||
VITE_POSTGRES_USER=root
|
||||
|
||||
DATABASE_URL='postgresql+psycopg://root:8811614287327Leo@10.10.10.189:5432/postgres'
|
||||
SQLALCHEMY_ECHO=false
|
||||
|
||||
REDIS_URL=
|
||||
VITE_REDIS_URL=
|
||||
|
||||
CORS_ORIGINS='["http://10.10.10.122:5173"]'
|
||||
10
.env.example
10
.env.example
@@ -14,9 +14,9 @@ VITE_ADMIN_EMAIL=
|
||||
# Admin login credentials are stored separately under server/.secrets/
|
||||
|
||||
WEB_HOST=0.0.0.0
|
||||
WEB_PORT=5173
|
||||
WEB_PORT=5273
|
||||
VITE_WEB_HOST=0.0.0.0
|
||||
VITE_WEB_PORT=5173
|
||||
VITE_WEB_PORT=5273
|
||||
|
||||
SERVER_HOST=0.0.0.0
|
||||
SERVER_PORT=8000
|
||||
@@ -48,4 +48,8 @@ SQLALCHEMY_ECHO=false
|
||||
REDIS_URL=
|
||||
VITE_REDIS_URL=
|
||||
|
||||
CORS_ORIGINS='["http://127.0.0.1:5173","http://localhost:5173","http://0.0.0.0:5173"]'
|
||||
OCR_DEVICE=
|
||||
OCR_TIMEOUT_SECONDS=180
|
||||
OCR_MAX_CONCURRENT_WORKERS=1
|
||||
|
||||
CORS_ORIGINS='["http://127.0.0.1:5273","http://localhost:5273","http://0.0.0.0:5273"]'
|
||||
|
||||
14
.gitignore
vendored
14
.gitignore
vendored
@@ -8,6 +8,8 @@ web/.vite/
|
||||
.omx/
|
||||
.claude/
|
||||
.codex/
|
||||
.codex-temp/
|
||||
.superpowers/
|
||||
*.log
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
@@ -16,3 +18,15 @@ __pycache__/
|
||||
server/.venv/
|
||||
server/.venv-ocr312
|
||||
server/.secrets/
|
||||
server/logs/
|
||||
server/storage/expense_claims/
|
||||
server/storage/finance_reports/
|
||||
server/storage/receipt_folder/
|
||||
test-results/
|
||||
.codex-remote-attachments/
|
||||
tmp-*.png
|
||||
.nezha/
|
||||
.omo/
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
25
AGENTS.md
25
AGENTS.md
@@ -32,8 +32,25 @@
|
||||
- 前端大型 Vue 页面:优先拆分 composable、view model、样式分片、业务工具函数和子组件。
|
||||
- 算法/规则模块:优先拆分输入解析、规则匹配、评分策略、结果解释和异常处理。
|
||||
|
||||
## 验证规范
|
||||
## 容器与运行环境(必读)
|
||||
|
||||
- 后端改动优先在 Docker 容器 `x-financial-main` 中运行验证。
|
||||
- 单元测试设置合理超时,避免长时间卡死。
|
||||
- 每次重构后至少运行对应服务的定向测试;涉及公共协议时补充端到端或接口测试。
|
||||
本项目代码是 Docker 容器 `x-financial-main`(镜像 `x-financial-dev:latest`)的源码映射。
|
||||
|
||||
- **容器映射**:宿主机 `D:\Code\Project\X-Financial` ↔ 容器内 `/app`(`docker-compose.yml` 中 `volumes: - .:/app`,`working_dir: /app`)。
|
||||
- **后端 venv**:容器内位于 `/tmp/x-financial-server-venv`(环境变量 `SERVER_VENV_DIR`),不要假设宿主机上有相同的 venv。
|
||||
- **外部依赖**:Qdrant(`x-financial-qdrant`)、OnlyOffice(`x-financial-onlyoffice`)也在同一 compose 网络里。
|
||||
|
||||
## 验证规范(硬性约束)
|
||||
|
||||
> 本项目代码与运行环境以容器为唯一事实来源。所有后端测试、集成测试、依赖了 Qdrant / OnlyOffice / venv 的验证,都必须在 `x-financial-main` 容器内执行,**不要在宿主机上直接跑 pytest / pip / python**。
|
||||
|
||||
- **进入容器跑命令**(最常用):
|
||||
```bash
|
||||
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-main <cmd>
|
||||
```
|
||||
- 跑后端测试:`docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-main /tmp/x-financial-server-venv/bin/pytest -q <path>`
|
||||
- 交互式排查:`docker exec -it -w /app x-financial-main bash`(登录后默认已在 `/app`)
|
||||
- **容器不可用时**(未启动、健康检查失败、镜像丢失):先 `docker compose up -d main` 恢复,再继续验证;不要绕开容器在宿主机另装 venv。
|
||||
- **单元测试设置合理超时**,避免长时间卡死。涉及外部服务(Qdrant / OnlyOffice / LLM)的测试要么 mock,要么确认 compose 网络中依赖服务在线。
|
||||
- **每次重构后至少运行对应服务的定向测试**;涉及公共协议时补充端到端或接口测试。
|
||||
- **修改 docker-compose / start.sh / venv 路径相关代码**时,自己也要回容器里跑一次确认改动生效,不要只改文件就声称完成。
|
||||
|
||||
95
README.md
95
README.md
@@ -1,45 +1,50 @@
|
||||
# X-Financial
|
||||
|
||||
项目结构已按前后端拆开:
|
||||
|
||||
- `web/`:前端工程(当前 Vue + Vite 项目)
|
||||
- `server/`:后端工程目录
|
||||
- `docs/`:方案和阶段文档
|
||||
- `UI/`:界面参考稿
|
||||
- `document/`:业务文档
|
||||
|
||||
根目录统一环境变量:
|
||||
|
||||
- `.env`
|
||||
- `.env.example`
|
||||
|
||||
这里集中维护:
|
||||
|
||||
- 前端启动端口
|
||||
- 后端启动端口
|
||||
- PostgreSQL 连接参数
|
||||
- `DATABASE_URL`
|
||||
- `REDIS_URL`
|
||||
|
||||
从根目录统一启动:
|
||||
|
||||
```bash
|
||||
./start.sh
|
||||
```
|
||||
|
||||
可选模式:
|
||||
|
||||
```bash
|
||||
./start.sh web
|
||||
./start.sh server
|
||||
./start.sh all
|
||||
```
|
||||
|
||||
根目录 `start.sh` 是统一编排入口;前端和后端的子启动脚本分别是 `web/web_start.sh` 与 `server/server_start.sh`。
|
||||
|
||||
手动进入前端目录:
|
||||
|
||||
```bash
|
||||
cd web
|
||||
npm run dev
|
||||
```
|
||||
# X-Financial
|
||||
|
||||
项目结构已按前后端拆开:
|
||||
|
||||
- `web/`:前端工程(当前 Vue + Vite 项目)
|
||||
- `server/`:后端工程目录
|
||||
- `docs/`:方案和阶段文档
|
||||
- `UI/`:界面参考稿
|
||||
- `document/`:业务文档
|
||||
|
||||
根目录统一环境变量:
|
||||
|
||||
- `.env`
|
||||
- `.env.example`
|
||||
|
||||
这里集中维护:
|
||||
|
||||
- 前端启动端口
|
||||
- 后端启动端口
|
||||
- PostgreSQL 连接参数
|
||||
- `DATABASE_URL`
|
||||
- `REDIS_URL`
|
||||
|
||||
从根目录统一启动:
|
||||
|
||||
```bash
|
||||
./start.sh
|
||||
```
|
||||
|
||||
可选模式:
|
||||
|
||||
```bash
|
||||
./start.sh web
|
||||
./start.sh server
|
||||
./start.sh all
|
||||
```
|
||||
|
||||
根目录 `start.sh` 是统一编排入口;前端和后端的子启动脚本分别是 `web/web_start.sh` 与 `server/server_start.sh`。
|
||||
|
||||
Docker Compose 运行方式见 `docker/README.md`:
|
||||
|
||||
- `docker-compose.yml`:只启动主应用容器,适合复用已有数据库、ONLYOFFICE 等外部依赖。
|
||||
- `docker-compose.full.yml`:启动主应用、PostgreSQL、Qdrant、ONLYOFFICE 的完整本地开发栈。
|
||||
|
||||
手动进入前端目录:
|
||||
|
||||
```bash
|
||||
cd web
|
||||
npm run dev
|
||||
```
|
||||
|
||||
141
docker-compose.full.yml
Normal file
141
docker-compose.full.yml
Normal file
@@ -0,0 +1,141 @@
|
||||
services:
|
||||
main:
|
||||
image: x-financial-dev:latest
|
||||
container_name: x-financial-main
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
onlyoffice:
|
||||
condition: service_started
|
||||
qdrant:
|
||||
condition: service_started
|
||||
environment:
|
||||
WEB_HOST: 0.0.0.0
|
||||
SERVER_HOST: 0.0.0.0
|
||||
SERVER_VENV_DIR: /tmp/x-financial-server-venv
|
||||
X_FINANCIAL_PREFER_ENV_FILE: "false"
|
||||
POSTGRES_HOST: postgres
|
||||
POSTGRES_PORT: "5432"
|
||||
POSTGRES_DB: "${POSTGRES_DB:-x_financial}"
|
||||
POSTGRES_USER: "${POSTGRES_USER:-x_financial}"
|
||||
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD:-x_financial}"
|
||||
DATABASE_URL: "postgresql+psycopg://${POSTGRES_USER:-x_financial}:${POSTGRES_PASSWORD:-x_financial}@postgres:5432/${POSTGRES_DB:-x_financial}"
|
||||
ONLYOFFICE_ENABLED: "true"
|
||||
ONLYOFFICE_PUBLIC_URL: "${LOCAL_ONLYOFFICE_PUBLIC_URL:-http://127.0.0.1:${ONLYOFFICE_PORT:-8082}}"
|
||||
ONLYOFFICE_BACKEND_URL: "${LOCAL_ONLYOFFICE_BACKEND_URL:-http://main:${SERVER_PORT:-8000}}"
|
||||
ONLYOFFICE_JWT_SECRET: "${ONLYOFFICE_JWT_SECRET:-x-financial-onlyoffice-dev-secret}"
|
||||
QDRANT_URL: "http://qdrant:6333"
|
||||
LIGHTRAG_WORKSPACE: "x_financial_knowledge"
|
||||
ports:
|
||||
- "${WEB_PORT:-5273}:${WEB_PORT:-5273}"
|
||||
- "${SERVER_PORT:-8000}:${SERVER_PORT:-8000}"
|
||||
- "2223:22"
|
||||
volumes:
|
||||
- .:/app
|
||||
working_dir: /app
|
||||
command:
|
||||
- /bin/sh
|
||||
- -lc
|
||||
- >
|
||||
apt-get update &&
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends
|
||||
python3 python3-pip python3-venv fontconfig openssh-server poppler-data &&
|
||||
if ! fc-match 'Noto Sans CJK SC' | grep -qi 'Noto'; then if ! timeout "${CJK_FONT_INSTALL_TIMEOUT_SECONDS:-45}" sh -lc 'DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends fonts-noto-cjk fonts-noto-cjk-extra'; then printf '%s\n' '[WARN] CJK font installation timed out or failed; continuing startup without blocking the app.'; fi; fi &&
|
||||
printf '%s\n'
|
||||
'<?xml version="1.0"?>'
|
||||
'<!DOCTYPE fontconfig SYSTEM "fonts.dtd">'
|
||||
'<fontconfig>'
|
||||
' <alias><family>SimSun</family><prefer><family>Noto Serif CJK SC</family></prefer></alias>'
|
||||
' <alias><family>NSimSun</family><prefer><family>Noto Serif CJK SC</family></prefer></alias>'
|
||||
' <alias><family>KaiTi</family><prefer><family>Noto Serif CJK SC</family></prefer></alias>'
|
||||
' <alias><family>FangSong</family><prefer><family>Noto Serif CJK SC</family></prefer></alias>'
|
||||
' <alias><family>SimHei</family><prefer><family>Noto Sans CJK SC</family></prefer></alias>'
|
||||
' <alias><family>DengXian</family><prefer><family>Noto Sans CJK SC</family></prefer></alias>'
|
||||
' <alias><family>Microsoft YaHei</family><prefer><family>Noto Sans CJK SC</family></prefer></alias>'
|
||||
'</fontconfig>'
|
||||
> /etc/fonts/local.conf &&
|
||||
fc-cache -f &&
|
||||
mkdir -p /run/sshd && /usr/sbin/sshd &&
|
||||
printf '%s\n' 'cd /app >/dev/null 2>&1 || true' > /etc/profile.d/zz-x-financial-app-dir.sh &&
|
||||
chmod 644 /etc/profile.d/zz-x-financial-app-dir.sh &&
|
||||
touch /root/.bashrc /root/.profile &&
|
||||
if ! grep -qxF 'cd /app >/dev/null 2>&1 || true' /root/.bashrc; then printf '\ncd /app >/dev/null 2>&1 || true\n' >> /root/.bashrc; fi &&
|
||||
if ! grep -qxF 'cd /app >/dev/null 2>&1 || true' /root/.profile; then printf '\ncd /app >/dev/null 2>&1 || true\n' >> /root/.profile; fi &&
|
||||
sed -i 's/\r$//' /app/start.sh /app/web/web_start.sh /app/server/server_start.sh &&
|
||||
chmod +x /app/start.sh /app/web/web_start.sh /app/server/server_start.sh &&
|
||||
cd /app &&
|
||||
./start.sh all
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -fsS http://127.0.0.1:${WEB_PORT:-5273}/ >/dev/null || exit 1"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 180s
|
||||
networks:
|
||||
- financial-internal
|
||||
|
||||
postgres:
|
||||
image: pgvector/pgvector:pg17
|
||||
container_name: x-financial-postgres
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_DB: "${POSTGRES_DB:-x_financial}"
|
||||
POSTGRES_USER: "${POSTGRES_USER:-x_financial}"
|
||||
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD:-x_financial}"
|
||||
ports:
|
||||
- "${POSTGRES_HOST_PORT:-55432}:5432"
|
||||
volumes:
|
||||
- postgres-data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U \"$${POSTGRES_USER}\" -d \"$${POSTGRES_DB}\""]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 30s
|
||||
networks:
|
||||
- financial-internal
|
||||
|
||||
qdrant:
|
||||
image: qdrant/qdrant:latest
|
||||
container_name: x-financial-qdrant
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${QDRANT_HTTP_PORT:-6333}:6333"
|
||||
- "${QDRANT_GRPC_PORT:-6334}:6334"
|
||||
volumes:
|
||||
- qdrant-storage:/qdrant/storage
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "bash -lc 'exec 3<>/dev/tcp/127.0.0.1/6333' || exit 1"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 30s
|
||||
networks:
|
||||
- financial-internal
|
||||
|
||||
onlyoffice:
|
||||
image: onlyoffice/documentserver:latest
|
||||
container_name: x-financial-onlyoffice
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
JWT_ENABLED: "true"
|
||||
JWT_SECRET: "${ONLYOFFICE_JWT_SECRET:-x-financial-onlyoffice-dev-secret}"
|
||||
ports:
|
||||
- "${ONLYOFFICE_PORT:-8082}:80"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -fsS http://127.0.0.1/healthcheck >/dev/null || exit 1"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 60s
|
||||
networks:
|
||||
- financial-internal
|
||||
|
||||
networks:
|
||||
financial-internal:
|
||||
name: financial-internal
|
||||
|
||||
volumes:
|
||||
postgres-data:
|
||||
qdrant-storage:
|
||||
8
docker-compose.gpu.yml
Normal file
8
docker-compose.gpu.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
services:
|
||||
main:
|
||||
gpus: all
|
||||
shm_size: "8gb"
|
||||
environment:
|
||||
NVIDIA_VISIBLE_DEVICES: all
|
||||
NVIDIA_DRIVER_CAPABILITIES: compute,utility
|
||||
OCR_DEVICE: "${OCR_DEVICE:-gpu:0}"
|
||||
36
docker-compose.postgres.yml
Normal file
36
docker-compose.postgres.yml
Normal file
@@ -0,0 +1,36 @@
|
||||
services:
|
||||
main:
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
POSTGRES_HOST: postgres
|
||||
POSTGRES_PORT: "5432"
|
||||
POSTGRES_DB: "${POSTGRES_DB:-x_financial}"
|
||||
POSTGRES_USER: "${POSTGRES_USER:-x_financial}"
|
||||
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD:-x_financial}"
|
||||
DATABASE_URL: "postgresql+psycopg://${POSTGRES_USER:-x_financial}:${POSTGRES_PASSWORD:-x_financial}@postgres:5432/${POSTGRES_DB:-x_financial}"
|
||||
|
||||
postgres:
|
||||
image: pgvector/pgvector:pg17
|
||||
container_name: x-financial-postgres
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_DB: "${POSTGRES_DB:-x_financial}"
|
||||
POSTGRES_USER: "${POSTGRES_USER:-x_financial}"
|
||||
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD:-x_financial}"
|
||||
ports:
|
||||
- "${POSTGRES_HOST_PORT:-55432}:5432"
|
||||
volumes:
|
||||
- postgres-data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U \"$${POSTGRES_USER}\" -d \"$${POSTGRES_DB}\""]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 30s
|
||||
networks:
|
||||
- financial-internal
|
||||
|
||||
volumes:
|
||||
postgres-data:
|
||||
@@ -1,38 +1,34 @@
|
||||
services:
|
||||
main:
|
||||
image: x-financial-dev:latest
|
||||
container_name: x-financial-main
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
onlyoffice:
|
||||
condition: service_started
|
||||
qdrant:
|
||||
condition: service_started
|
||||
environment:
|
||||
WEB_HOST: 0.0.0.0
|
||||
SERVER_HOST: 0.0.0.0
|
||||
SERVER_VENV_DIR: /tmp/x-financial-server-venv
|
||||
X_FINANCIAL_PREFER_ENV_FILE: "true"
|
||||
ONLYOFFICE_ENABLED: "${ONLYOFFICE_ENABLED:-true}"
|
||||
ONLYOFFICE_PUBLIC_URL: "${ONLYOFFICE_PUBLIC_URL:-http://127.0.0.1:${ONLYOFFICE_PORT:-8082}}"
|
||||
ONLYOFFICE_BACKEND_URL: "http://main:${SERVER_PORT:-8000}"
|
||||
ONLYOFFICE_JWT_SECRET: "${ONLYOFFICE_JWT_SECRET:-x-financial-onlyoffice-dev-secret}"
|
||||
QDRANT_URL: "http://qdrant:6333"
|
||||
LIGHTRAG_WORKSPACE: "x_financial_knowledge"
|
||||
ports:
|
||||
- "${WEB_PORT:-5173}:${WEB_PORT:-5173}"
|
||||
- "${SERVER_PORT:-8000}:${SERVER_PORT:-8000}"
|
||||
- "2223:22"
|
||||
volumes:
|
||||
- .:/app
|
||||
working_dir: /app
|
||||
command:
|
||||
- /bin/sh
|
||||
- -lc
|
||||
- >
|
||||
services:
|
||||
main:
|
||||
image: x-financial-dev:latest
|
||||
container_name: x-financial-main
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
WEB_HOST: 0.0.0.0
|
||||
SERVER_HOST: 0.0.0.0
|
||||
SERVER_VENV_DIR: /tmp/x-financial-server-venv
|
||||
X_FINANCIAL_PREFER_ENV_FILE: "true"
|
||||
ONLYOFFICE_ENABLED: "${ONLYOFFICE_ENABLED:-false}"
|
||||
ONLYOFFICE_PUBLIC_URL: "${ONLYOFFICE_PUBLIC_URL:-}"
|
||||
ONLYOFFICE_BACKEND_URL: "${ONLYOFFICE_BACKEND_URL:-}"
|
||||
ONLYOFFICE_JWT_SECRET: "${ONLYOFFICE_JWT_SECRET:-x-financial-onlyoffice-dev-secret}"
|
||||
QDRANT_URL: "${QDRANT_URL:-}"
|
||||
LIGHTRAG_WORKSPACE: "x_financial_knowledge"
|
||||
ports:
|
||||
- "${WEB_PORT:-5273}:${WEB_PORT:-5273}"
|
||||
- "${SERVER_PORT:-8000}:${SERVER_PORT:-8000}"
|
||||
- "2223:22"
|
||||
volumes:
|
||||
- .:/app
|
||||
working_dir: /app
|
||||
command:
|
||||
- /bin/sh
|
||||
- -lc
|
||||
- >
|
||||
apt-get update &&
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends
|
||||
python3 python3-pip python3-venv fontconfig fonts-noto-cjk fonts-noto-cjk-extra &&
|
||||
python3 python3-pip python3-venv fontconfig openssh-server poppler-data &&
|
||||
if ! fc-match 'Noto Sans CJK SC' | grep -qi 'Noto'; then if ! timeout "${CJK_FONT_INSTALL_TIMEOUT_SECONDS:-45}" sh -lc 'DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends fonts-noto-cjk fonts-noto-cjk-extra'; then printf '%s\n' '[WARN] CJK font installation timed out or failed; continuing startup without blocking the app.'; fi; fi &&
|
||||
printf '%s\n'
|
||||
'<?xml version="1.0"?>'
|
||||
'<!DOCTYPE fontconfig SYSTEM "fonts.dtd">'
|
||||
@@ -48,63 +44,24 @@ services:
|
||||
> /etc/fonts/local.conf &&
|
||||
fc-cache -f &&
|
||||
mkdir -p /run/sshd && /usr/sbin/sshd &&
|
||||
printf '%s\n' 'cd /app >/dev/null 2>&1 || true' > /etc/profile.d/zz-x-financial-app-dir.sh &&
|
||||
chmod 644 /etc/profile.d/zz-x-financial-app-dir.sh &&
|
||||
touch /root/.bashrc /root/.profile &&
|
||||
if ! grep -qxF 'cd /app >/dev/null 2>&1 || true' /root/.bashrc; then printf '\ncd /app >/dev/null 2>&1 || true\n' >> /root/.bashrc; fi &&
|
||||
if ! grep -qxF 'cd /app >/dev/null 2>&1 || true' /root/.profile; then printf '\ncd /app >/dev/null 2>&1 || true\n' >> /root/.profile; fi &&
|
||||
sed -i 's/\r$//' /app/start.sh /app/web/web_start.sh /app/server/server_start.sh &&
|
||||
chmod +x /app/start.sh /app/web/web_start.sh /app/server/server_start.sh &&
|
||||
cd /app &&
|
||||
./start.sh all
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -fsS http://127.0.0.1:${WEB_PORT:-5173}/ >/dev/null || exit 1"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 180s
|
||||
networks:
|
||||
- financial-internal
|
||||
|
||||
qdrant:
|
||||
image: qdrant/qdrant:latest
|
||||
container_name: x-financial-qdrant
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${QDRANT_HTTP_PORT:-6333}:6333"
|
||||
- "${QDRANT_GRPC_PORT:-6334}:6334"
|
||||
volumes:
|
||||
- qdrant-storage:/qdrant/storage
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "bash -lc 'exec 3<>/dev/tcp/127.0.0.1/6333' || exit 1"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 30s
|
||||
networks:
|
||||
- financial-internal
|
||||
|
||||
onlyoffice:
|
||||
image: onlyoffice/documentserver:latest
|
||||
container_name: x-financial-onlyoffice
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
JWT_ENABLED: "true"
|
||||
JWT_SECRET: "${ONLYOFFICE_JWT_SECRET:-x-financial-onlyoffice-dev-secret}"
|
||||
ports:
|
||||
- "${ONLYOFFICE_PORT:-8082}:80"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -fsS http://127.0.0.1/healthcheck >/dev/null || exit 1"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 60s
|
||||
networks:
|
||||
- financial-internal
|
||||
|
||||
networks:
|
||||
financial-internal:
|
||||
name: financial-internal
|
||||
|
||||
volumes:
|
||||
qdrant-storage:
|
||||
printf '%s\n' 'cd /app >/dev/null 2>&1 || true' > /etc/profile.d/zz-x-financial-app-dir.sh &&
|
||||
chmod 644 /etc/profile.d/zz-x-financial-app-dir.sh &&
|
||||
touch /root/.bashrc /root/.profile &&
|
||||
if ! grep -qxF 'cd /app >/dev/null 2>&1 || true' /root/.bashrc; then printf '\ncd /app >/dev/null 2>&1 || true\n' >> /root/.bashrc; fi &&
|
||||
if ! grep -qxF 'cd /app >/dev/null 2>&1 || true' /root/.profile; then printf '\ncd /app >/dev/null 2>&1 || true\n' >> /root/.profile; fi &&
|
||||
sed -i 's/\r$//' /app/start.sh /app/web/web_start.sh /app/server/server_start.sh &&
|
||||
chmod +x /app/start.sh /app/web/web_start.sh /app/server/server_start.sh &&
|
||||
cd /app &&
|
||||
./start.sh all
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -fsS http://127.0.0.1:${WEB_PORT:-5273}/ >/dev/null || exit 1"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 180s
|
||||
networks:
|
||||
- financial-internal
|
||||
|
||||
networks:
|
||||
financial-internal:
|
||||
name: financial-internal
|
||||
|
||||
194
docker/README.md
194
docker/README.md
@@ -1,67 +1,127 @@
|
||||
# Docker Compose
|
||||
|
||||
This project currently uses the Vite `__setup/*` middleware during the initial setup flow.
|
||||
Because of that, the Docker deployment keeps the web frontend and FastAPI startup chain in
|
||||
the same main container and runs the existing root `start.sh`.
|
||||
|
||||
## Start
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Open:
|
||||
|
||||
```text
|
||||
http://<your-linux-host>:5173
|
||||
```
|
||||
|
||||
## Container Layout
|
||||
|
||||
- `main`: web + FastAPI main container
|
||||
- `onlyoffice`: ONLYOFFICE Document Server
|
||||
- `postgres`: PostgreSQL database container
|
||||
|
||||
The project root is mounted directly into the main container:
|
||||
|
||||
```text
|
||||
.:/app
|
||||
```
|
||||
|
||||
That means the container reads your existing `.env`, source code, `server/.secrets`, logs,
|
||||
and generated dependency directories directly from the mapped project folder.
|
||||
|
||||
This is a `compose`-only setup. There is no custom `Dockerfile`.
|
||||
The tradeoff is that the `main` container installs the Python runtime packages it needs
|
||||
when it starts.
|
||||
|
||||
## Persistence
|
||||
|
||||
The PostgreSQL data directory is stored in the named volume `postgres_data`.
|
||||
|
||||
## Notes
|
||||
|
||||
- Most configuration should be maintained in the project root `.env`.
|
||||
- The first `docker compose up -d` does not require an existing `.env`; the compose file
|
||||
uses built-in defaults for the PostgreSQL container and the main container database URL.
|
||||
- Docker Compose only overrides a few values that must differ inside containers:
|
||||
- `WEB_HOST=0.0.0.0`
|
||||
- `SERVER_HOST=0.0.0.0`
|
||||
- `POSTGRES_HOST=postgres`
|
||||
- `POSTGRES_PORT=5432`
|
||||
- `DATABASE_URL=...@postgres:...`
|
||||
- PostgreSQL is also published to the host by default as `127.0.0.1:55432`.
|
||||
- ONLYOFFICE is published to the host by default as `127.0.0.1:8082`.
|
||||
- First boot with `SETUP_COMPLETED=false` starts the setup UI only.
|
||||
- After you complete setup in the browser, the Vite setup bridge will start FastAPI in the
|
||||
same container using the saved runtime configuration.
|
||||
- On later restarts, `start.sh` will detect the saved setup state and start both web and
|
||||
server automatically.
|
||||
- If you access the system from another machine, make sure `CORS_ORIGINS` in `.env` includes
|
||||
the frontend address you actually use.
|
||||
- For Navicat or any host-side client, use `127.0.0.1:55432`.
|
||||
- If you need to access ONLYOFFICE from another machine, override `ONLYOFFICE_PUBLIC_URL`
|
||||
so the browser can reach the document server address you actually expose.
|
||||
- For the setup page, using `127.0.0.1` is acceptable in this Docker layout; the internal
|
||||
test bridge will resolve that back to the Docker PostgreSQL service.
|
||||
# Docker Compose
|
||||
|
||||
X-Financial 现在按运行依赖分成两层 Docker Compose:
|
||||
|
||||
- `docker-compose.yml`:只启动主应用容器,适合已经有远端 PostgreSQL、ONLYOFFICE 或 Qdrant 的环境。
|
||||
- `docker-compose.full.yml`:启动完整本地开发栈,适合没有外部依赖、希望本机一次性跑齐所有服务的环境。
|
||||
|
||||
主应用容器仍然同时启动 Web 前端和 FastAPI 后端,并复用根目录 `start.sh`。
|
||||
项目根目录会挂载到容器内 `/app`。
|
||||
|
||||
## 轻量启动:只跑主应用
|
||||
|
||||
适合你已经有数据库和 ONLYOFFICE 的情况。
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
默认只会启动:
|
||||
|
||||
```text
|
||||
main
|
||||
```
|
||||
|
||||
打开:
|
||||
|
||||
```text
|
||||
http://<your-linux-host>:5273
|
||||
```
|
||||
|
||||
这条路径不会主动拉起本地 PostgreSQL、Qdrant 或 ONLYOFFICE。
|
||||
数据库、ONLYOFFICE 和 Qdrant 地址都从 `.env` 或外部环境变量读取。
|
||||
|
||||
常见外部依赖变量:
|
||||
|
||||
```text
|
||||
DATABASE_URL
|
||||
POSTGRES_HOST
|
||||
POSTGRES_PORT
|
||||
ONLYOFFICE_ENABLED
|
||||
ONLYOFFICE_PUBLIC_URL
|
||||
ONLYOFFICE_BACKEND_URL
|
||||
QDRANT_URL
|
||||
```
|
||||
|
||||
## 完整启动:本地全栈
|
||||
|
||||
适合没有远端数据库和 ONLYOFFICE 的情况。
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.full.yml up -d
|
||||
```
|
||||
|
||||
会启动:
|
||||
|
||||
```text
|
||||
main
|
||||
postgres
|
||||
qdrant
|
||||
onlyoffice
|
||||
```
|
||||
|
||||
本地服务端口:
|
||||
|
||||
```text
|
||||
Web: 5273
|
||||
FastAPI: 8000
|
||||
PostgreSQL: 55432 -> 5432
|
||||
Qdrant: 6333 / 6334
|
||||
ONLYOFFICE: 8082
|
||||
SSH: 2223
|
||||
```
|
||||
|
||||
完整栈会把主容器内的数据库地址指向 `postgres:5432`,
|
||||
并把 Qdrant 地址指向 `http://qdrant:6333`。
|
||||
|
||||
ONLYOFFICE 默认使用本机可访问地址:
|
||||
|
||||
```text
|
||||
http://127.0.0.1:8082
|
||||
```
|
||||
|
||||
如果浏览器从另一台机器访问,需要覆盖:
|
||||
|
||||
```bash
|
||||
LOCAL_ONLYOFFICE_PUBLIC_URL=http://<host>:8082 \
|
||||
docker compose -f docker-compose.full.yml up -d
|
||||
```
|
||||
|
||||
如果 ONLYOFFICE 回调后端也需要外部地址,可以同时覆盖:
|
||||
|
||||
```bash
|
||||
LOCAL_ONLYOFFICE_BACKEND_URL=http://<host>:8000 \
|
||||
docker compose -f docker-compose.full.yml up -d
|
||||
```
|
||||
|
||||
## 可选:只额外启动本地 PostgreSQL
|
||||
|
||||
如果只想在轻量主容器旁边补一个本地 PostgreSQL,可以使用覆盖文件:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.yml -f docker-compose.postgres.yml up -d
|
||||
```
|
||||
|
||||
这会启动:
|
||||
|
||||
```text
|
||||
main
|
||||
postgres
|
||||
```
|
||||
|
||||
## 停止与清理
|
||||
|
||||
停止当前默认轻量栈:
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
```
|
||||
|
||||
停止完整本地栈:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.full.yml down
|
||||
```
|
||||
|
||||
如需删除本地数据卷,先确认不再需要其中数据,再手动执行带 `-v` 的清理命令。
|
||||
|
||||
572
docs/improvement-roadmap.md
Normal file
572
docs/improvement-roadmap.md
Normal file
@@ -0,0 +1,572 @@
|
||||
# X-Financial 改进路线图
|
||||
|
||||
> 本文档基于 2026-06-18 对代码库的算法层、业务层、工程层综合评估生成。
|
||||
> 每项改进都附有文件路径佐证,便于后续定位和追踪。
|
||||
> 维护规则:状态变更请在对应章节同步更新;新增改进项追加到对应优先级末尾。
|
||||
|
||||
## 状态约定
|
||||
|
||||
| 标记 | 含义 |
|
||||
|---|---|
|
||||
| ⏳ | 待启动 |
|
||||
| 🔄 | 进行中 |
|
||||
| ✅ | 已完成 |
|
||||
| ⏸️ | 暂缓(需说明原因) |
|
||||
| ❌ | 取消(需说明原因) |
|
||||
|
||||
## 优先级矩阵
|
||||
|
||||
| 优先级 | 编号 | 标题 | 状态 |
|
||||
|---|---|---|---|
|
||||
| 🔴 P0 安全 | B2 | HTTP Header 权限漏洞 | ⏳ |
|
||||
| 🔴 P0 业务核心 | B1 | 审批流转交/加签/撤回/会签 | ⏳ |
|
||||
| 🔴 P0 共识 | B10 | 800 行硬约束破防 | ⏳ |
|
||||
| 🟠 P1 算法 | A1 | 风险评分权重自适应 | ⏳ |
|
||||
| 🟠 P1 算法 | A4 | LLM 票据分类 + 字段置信度 | ⏳ |
|
||||
| 🟠 P1 算法 | A7 | LLM 幻觉检测 | ⏳ |
|
||||
| 🟠 P1 业务 | B6 | 规则覆盖不均衡 | ⏳ |
|
||||
| 🟡 P2 业务 | B3 | 申请/报销拆表 | ⏳ |
|
||||
| 🟡 P2 业务 | B4 | 可配置审批矩阵 | ⏳ |
|
||||
| 🟡 P2 算法 | A2 | 异常检测自适应阈值 | ⏳ |
|
||||
| 🟢 P3 算法 | A3 | 多模型异常检测集成 | ⏳ |
|
||||
| 🟢 P3 算法 | A5 | 票据分类持续学习 | ⏳ |
|
||||
| 🟢 P3 算法 | A6 | Prompt 模板集中管理 | ⏳ |
|
||||
| 🟢 P3 算法 | A8 | 规则冗余建模 | ⏳ |
|
||||
| 🟢 P3 算法 | A9 | 行为画像 fairness 保护 | ⏳ |
|
||||
| 🟢 P3 业务 | B5 | 预算跨期/跨科边界 | ⏳ |
|
||||
| 🟢 P3 业务 | B7 | 审计日志防篡改 | ⏳ |
|
||||
| 🟢 P3 业务 | B8 | 审批 SLA 监控 | ⏳ |
|
||||
| 🟢 P3 业务 | B9 | 支付与凭证对接 | ⏳ |
|
||||
| 🟢 P3 算法 | A10 | 算法模块 800 行拆分 | ⏳ |
|
||||
|
||||
---
|
||||
|
||||
## 一、算法层面改进
|
||||
|
||||
### A1. 风险评分权重自适应调优 ⏳
|
||||
|
||||
**优先级**:🟠 P1
|
||||
|
||||
**证据**:
|
||||
- `server/src/app/algorithem/risk_graph/engine.py:457-465`
|
||||
- `server/src/app/services/risk_rule_scoring.py:16-23`
|
||||
|
||||
**当前实现**:
|
||||
```python
|
||||
risk_score = 0.35*S_rule + 0.25*S_anomaly + 0.20*S_graph + 0.15*S_policy + 0.05*S_history
|
||||
```
|
||||
五维权重和六因子权重均为硬编码常量,无法反映规则有效性差异。
|
||||
|
||||
**问题**:
|
||||
- 已有 `RiskObservationFeedback` 表收集人工反馈,但反馈数据**未反向更新权重**
|
||||
- 不同费用类型(差旅/招待/通信)的合理权重差异大,目前一刀切
|
||||
|
||||
**改进方向**:
|
||||
- 按费用类型分组的权重向量
|
||||
- 定期基于反馈数据做 logistic regression / Bayesian 更新
|
||||
- 权重变更需版本化、可回滚
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 权重从配置/数据库读取,不再硬编码
|
||||
- [ ] 反馈数据能触发权重自动调整
|
||||
- [ ] 不同费用类型可配置独立权重
|
||||
- [ ] 调整过程有日志和效果对比
|
||||
|
||||
---
|
||||
|
||||
### A2. 金额异常检测自适应阈值 ⏳
|
||||
|
||||
**优先级**:🟡 P2
|
||||
|
||||
**证据**:`server/src/app/algorithem/risk_graph/engine.py:221-261`
|
||||
|
||||
**当前实现**:固定分档阈值 `1.0x→0, 1.25x→30, 1.5x→55, 2.0x→75, 3.0x→95`
|
||||
|
||||
**问题**:
|
||||
- 通信费(小额高频)和差旅(大额低频)的"1.5x"含义完全不同
|
||||
- peer p75 在新部门/新费用类型时样本稀疏
|
||||
- 已识别 `peer_baseline_insufficient` 不确定性,但无冷启动方案
|
||||
|
||||
**改进方向**:
|
||||
- 改为自适应分位数(基于历史数据动态计算)
|
||||
- 按 `(费用类型 × 部门层级)` 分组维护基线
|
||||
- 冷启动:全局基线 + 小样本置信度折扣
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 阈值按业务维度分组,不再全局统一
|
||||
- [ ] 新部门/新费用类型有冷启动策略
|
||||
- [ ] 基线样本不足时有降级机制
|
||||
- [ ] 增加单元测试覆盖冷启动场景
|
||||
|
||||
---
|
||||
|
||||
### A3. 多模型异常检测集成策略 ⏳
|
||||
|
||||
**优先级**:🟢 P3
|
||||
|
||||
**证据**:`server/src/app/algorithem/risk_graph/anomaly_models.py`
|
||||
|
||||
**当前实现**:5 个模型独立输出(`robust_statistics / isolation_proxy / local_outlier / temporal_jump / periodic_deviation`),无集成。
|
||||
|
||||
**问题**:
|
||||
- 多模型同时报警时聚合规则未定义
|
||||
- 单模型 vs 多模型共识的严重度差异未体现
|
||||
- 模型间冲突无裁决机制
|
||||
|
||||
**改进方向**:
|
||||
- 引入 `AnomalyEnsembler` 集成层
|
||||
- 输出 `consensus_score` + `model_disagreement_flag`
|
||||
- 高风险图谱评分区分"单点异常"和"多维共识异常"
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 实现集成层并接入 engine.py
|
||||
- [ ] 集成结果包含共识度指标
|
||||
- [ ] 单元测试覆盖各种模型组合情况
|
||||
|
||||
---
|
||||
|
||||
### A4. LLM 票据分类与字段置信度 ⏳
|
||||
|
||||
**优先级**:🟠 P1
|
||||
|
||||
**证据**:
|
||||
- `server/src/app/services/document_intelligence.py:143-153`(`_classify_with_model` 当前 `return None`)
|
||||
- `server/src/app/services/document_intelligence.py:20-37`(字段抽取全正则)
|
||||
|
||||
**问题**:
|
||||
- 规则层单点支撑,非标准票据格式失效
|
||||
- 无字段级置信度评分,无法判断哪些抽取值需要人工复核
|
||||
- LLM 分类合并策略代码已存在但未启用
|
||||
|
||||
**改进方向**:
|
||||
1. 启用 LLM 分类层(合并逻辑可直接复用)
|
||||
2. 字段抽取增加置信度:`{field: {value, confidence, source}}`
|
||||
3. 低置信度字段(< 0.7)自动标记"需人工核对"
|
||||
|
||||
**验收标准**:
|
||||
- [ ] LLM 分类层启用并通过对比测试
|
||||
- [ ] 每个抽取字段附带置信度评分
|
||||
- [ ] 低置信度字段触发人工复核标记
|
||||
- [ ] 提供准确率回归测试集
|
||||
|
||||
---
|
||||
|
||||
### A5. 票据分类持续学习 ⏳
|
||||
|
||||
**优先级**:🟢 P3
|
||||
|
||||
**证据**:`server/src/app/services/document_intelligence_rules.py:120`(`score_bias` 硬编码)
|
||||
|
||||
**问题**:新票种(ETC 电子票、滴滴行程单新模板)需开发改代码才能识别。
|
||||
|
||||
**改进方向**:
|
||||
- 分类规则做成可配置 + 可学习
|
||||
- 管理员上传样本自动更新关键词权重
|
||||
- 基于历史已分类票据做 TF-IDF 训练
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 后台提供分类规则管理界面
|
||||
- [ ] 新票种可通过样本上传识别
|
||||
- [ ] 历史数据可训练关键词权重
|
||||
|
||||
---
|
||||
|
||||
### A6. Prompt 模板集中管理 ⏳
|
||||
|
||||
**优先级**:🟢 P3
|
||||
|
||||
**证据**:
|
||||
- `server/src/app/services/ontology_extraction.py`
|
||||
- `server/src/app/services/ontology_detection.py`
|
||||
- `server/src/app/services/risk_rule_generation.py`
|
||||
- `server/src/app/services/user_agent_response.py`
|
||||
- `server/src/app/services/user_agent_application.py`
|
||||
- `server/src/app/services/user_agent_review_core.py`
|
||||
- `server/src/app/services/knowledge_rag.py:214`(查询重写硬编码在方法内)
|
||||
|
||||
**问题**:
|
||||
- Prompt 散落在 12+ 文件,无版本化、无回滚、无 A/B 测试
|
||||
- 相同意图的 prompt 在不同 service 中重复
|
||||
|
||||
**改进方向**:
|
||||
- 建立 `prompts/` 集中目录 + `PromptRegistry`
|
||||
- 按 `(意图, 版本)` 管理
|
||||
- 支持灰度发布和效果对比
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 所有 prompt 迁移到集中目录
|
||||
- [ ] 支持版本化与回滚
|
||||
- [ ] 提供 A/B 测试接口
|
||||
|
||||
---
|
||||
|
||||
### A7. LLM 幻觉检测与事实校验 ⏳
|
||||
|
||||
**优先级**:🟠 P1
|
||||
|
||||
**证据**:当前系统缺少 LLM 输出的显式幻觉检测。本体解析有 `confidence` 门禁,但生成的解释文本、规则建议、对话回复无校验。
|
||||
|
||||
**问题**:
|
||||
- LLM 可能编造不存在的政策条款、错误金额阈值、虚构审批人
|
||||
- 风险图谱解释文本幻觉会误导审批人
|
||||
- 唯一兜底是 `data_quality_gate`,仅管输入数据质量
|
||||
|
||||
**改进方向**:
|
||||
- 关键输出(金额、政策条款、规则编号)做 grounded check:LLM 输出后用规则引擎反向校验
|
||||
- 对话回复中的具体数字、日期强制引用证据片段(RAG 引用)
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 关键数值字段有反向校验机制
|
||||
- [ ] 对话回复中的事实声明可追溯到证据
|
||||
- [ ] 校验失败时有明确降级策略
|
||||
|
||||
---
|
||||
|
||||
### A8. 规则冗余/相关性建模 ⏳
|
||||
|
||||
**优先级**:🟢 P3
|
||||
|
||||
**证据**:`server/src/app/services/risk_rule_scoring.py`(多规则命中简单求和/max)
|
||||
|
||||
**问题**:相关规则同时命中时分数被夸大。如 `preapproval_absent` 和 `date_outside_trip` 可能高度相关。
|
||||
|
||||
**改进方向**:引入规则相关矩阵,对相关规则命中分数做去冗余折扣。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 建立规则相关矩阵
|
||||
- [ ] 命中聚合时考虑冗余
|
||||
- [ ] 测试验证去冗余效果
|
||||
|
||||
---
|
||||
|
||||
### A9. 行为画像 fairness 保护 ⏳
|
||||
|
||||
**优先级**:🟢 P3
|
||||
|
||||
**证据**:`server/src/app/algorithem/employee_behavior_profile.py:345`(`evaluate_weighted_profile` / `calculate_review_priority_score`)
|
||||
|
||||
**问题**:行为画像影响审核优先级,若基于受保护属性(性别/年龄)产生系统性偏差,会构成隐性歧视。
|
||||
|
||||
**改进方向**:
|
||||
- 增加 fairness audit 接口(按人群分组统计风险分布)
|
||||
- 评分特征显式排除受保护属性
|
||||
- 定期输出偏差报告
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 评分特征清单明确排除受保护属性
|
||||
- [ ] 提供 fairness audit API
|
||||
- [ ] 定期偏差报告生成
|
||||
|
||||
---
|
||||
|
||||
### A10. 算法模块 800 行拆分 ⏳
|
||||
|
||||
**优先级**:🟢 P3(与 B10 同源,单独追踪算法模块进度)
|
||||
|
||||
**证据**:
|
||||
- `server/src/app/algorithem/employee_behavior_profile_tag_rules.py`: **812 行** 🔴
|
||||
- `server/src/app/algorithem/risk_graph/engine.py`: **794 行** 🟡 临界
|
||||
|
||||
**改进方向**:
|
||||
- `employee_behavior_profile_tag_rules.py` 按标签类别拆分(差旅类 / 招待类 / 办公类)
|
||||
- `engine.py` 的 5 个评分维度(rule/anomaly/graph/policy/history)拆为 5 个独立打分器
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 所有算法文件 ≤ 800 行
|
||||
- [ ] 拆分前后行为等价(单元测试通过)
|
||||
- [ ] 拆分后职责边界清晰
|
||||
|
||||
---
|
||||
|
||||
## 二、业务层面改进
|
||||
|
||||
### B1. 审批流转交/加签/撤回/会签 ⏳
|
||||
|
||||
**优先级**:🔴 P0
|
||||
|
||||
**证据**:
|
||||
- `server/src/app/services/expense_claim_workflow_constants.py`(仅 11 行固定阶段)
|
||||
- `server/src/app/services/expense_claim_approval_flow.py:28`(`approve_claim` 串行硬编码)
|
||||
- 转交/加签/撤回代码中**不存在**
|
||||
|
||||
**问题**:
|
||||
- 费控系统核心能力缺失
|
||||
- 现实中领导出差无法审批是常态
|
||||
- 无并行审批(会签),多人审批只能串行
|
||||
- 审批节点调整需改代码
|
||||
|
||||
**改进方向**:
|
||||
- 引入审批矩阵:`费用类型 × 金额区间 × 部门` → 审批节点列表
|
||||
- 支持节点动作:`{approve, reject, return, transfer, countersign, withdraw, add_approver}`
|
||||
- 短期优先实现"转交"和"撤回"两个最常用动作
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 支持转交(审批人转给他人)
|
||||
- [ ] 支持撤回(提交人在审批中撤回)
|
||||
- [ ] 支持加签(临时增加审批节点)
|
||||
- [ ] 支持会签(多节点并行)
|
||||
- [ ] 审批矩阵可后台配置
|
||||
- [ ] 关键操作有审计日志
|
||||
|
||||
---
|
||||
|
||||
### B2. HTTP Header 权限漏洞修复 ⏳
|
||||
|
||||
**优先级**:🔴 P0(安全)
|
||||
|
||||
**证据**:`server/src/app/api/deps.py:33-213`,通过 `X-Auth-Username / X-Auth-Role-Codes / X-Auth-Is-Admin` 等请求头识别身份。
|
||||
|
||||
**问题**:
|
||||
- **任何人只要在请求头加 `X-Auth-Is-Admin: true` 就能获得管理员权限**
|
||||
- 没有 token、没有签名、没有任何校验
|
||||
- 足以让所有费控规则形同虚设
|
||||
|
||||
**改进方向**:
|
||||
- 引入真正的身份认证(JWT 或 session cookie)
|
||||
- 角色信息从服务端 session/token 获取,**绝不信任客户端传来的角色声明**
|
||||
- 短期方案:前置网关(nginx)剥离这些头并注入真实身份
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 客户端无法通过伪造 Header 越权
|
||||
- [ ] 所有角色信息来自服务端校验
|
||||
- [ ] 现有 API 行为兼容(不破坏调用方)
|
||||
- [ ] 安全测试覆盖权限边界
|
||||
|
||||
---
|
||||
|
||||
### B3. 申请单与报销单拆表 ⏳
|
||||
|
||||
**优先级**:🟡 P2
|
||||
|
||||
**证据**:
|
||||
- `server/src/app/models/financial_record.py`:`ExpenseClaim` 通过 `expense_type` 后缀 + `claim_no` 前缀区分
|
||||
- `server/src/app/models/reimbursement.py`:`ReimbursementRequest` 几乎废弃(service 仅 54 行 CRUD)
|
||||
|
||||
**问题**:
|
||||
- 查询复杂度高,每个查询都要带 `expense_type IN (...)` 过滤
|
||||
- 字段冗余(申请单无发票字段但表里有)
|
||||
- 业务语义混乱("claim"分不清是申请还是报销)
|
||||
- 索引难优化
|
||||
|
||||
**改进方向**(需决策):
|
||||
- 方案 A(保守):保留单表,增加 `claim_kind` 字段(`application` / `reimbursement`)显式区分
|
||||
- 方案 B(彻底):拆分为 `ExpenseApplication` + `ExpenseReimbursement` 两张表,通过 `application_id` 外键关联
|
||||
- **涉及数据迁移,需用户确认方案**
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 方案决策完成
|
||||
- [ ] 数据迁移脚本可重入、可回滚
|
||||
- [ ] 迁移前后数据等价校验
|
||||
- [ ] 现有 API 行为兼容或平滑升级
|
||||
|
||||
---
|
||||
|
||||
### B4. 可配置审批矩阵 ⏳
|
||||
|
||||
**优先级**:🟡 P2
|
||||
|
||||
**证据**:`server/src/app/services/expense_claim_approval_routing.py`(`_APPLICATION_BUDGET_REVIEW_USAGE_THRESHOLD = 90%` 等阈值硬编码)
|
||||
|
||||
**问题**:什么金额走什么审批、什么情况要预算管理者介入,全部硬编码。不同公司/部门差异大,无法运维配置。
|
||||
|
||||
**改进方向**:建立审批矩阵配置表:
|
||||
```
|
||||
approval_matrix(expense_type, amount_range, department_level, risk_level)
|
||||
→ [approver_roles, parallel_or_serial, sla_hours]
|
||||
```
|
||||
管理员后台维护,系统按矩阵动态生成审批流。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 审批矩阵可后台配置
|
||||
- [ ] 系统按矩阵动态生成审批流
|
||||
- [ ] 配置变更有版本和审计
|
||||
- [ ] 矩阵未命中时有合理默认值
|
||||
|
||||
---
|
||||
|
||||
### B5. 预算管控跨期/跨科边界 ⏳
|
||||
|
||||
**优先级**:🟢 P3
|
||||
|
||||
**证据**:
|
||||
- `server/src/app/services/budget.py`(780 行)
|
||||
- `server/src/app/services/expense_claim_budget_flow.py`(112 行)
|
||||
- 预算占用/释放/核销/转移已实现,但边界场景验证不足
|
||||
|
||||
**潜在漏洞**:
|
||||
- 跨财年结转:去年冻结的预算今年初未释放
|
||||
- 跨期占用:Q1 提交的申请 Q2 才审批,占用的是哪个季度?
|
||||
- 跨科目调剂:差旅预算不够能否临时挪用办公预算?
|
||||
- 无对应单元测试
|
||||
|
||||
**改进方向**:
|
||||
- 增加预算状态周期性对账任务(每日扫描 orphan reservation)
|
||||
- 跨期策略明确化(默认跟随申请提交期,可配置)
|
||||
- 补充跨期/跨科目单元测试
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 跨期/跨科目边界单元测试覆盖
|
||||
- [ ] 周期性对账任务上线
|
||||
- [ ] orphan reservation 自动清理
|
||||
|
||||
---
|
||||
|
||||
### B6. 规则覆盖不均衡补齐 ⏳
|
||||
|
||||
**优先级**:🟠 P1
|
||||
|
||||
**证据**:`server/rules/risk-rules/` 38 条规则分布:
|
||||
- 差旅(travel):13 条
|
||||
- 预算(budget):13 条
|
||||
- 申请(application):5 条
|
||||
- 报销(reimbursement):7 条
|
||||
- 标准(standard):5 条
|
||||
|
||||
**问题**:
|
||||
- **招待费、市场推广、培训费、福利费、软件服务费几乎没有专门规则**
|
||||
- 缺少供应商关联方交易、连号发票重复报销、跨年度重复报销检测
|
||||
- 这些恰是真实费控场景最易出问题的领域
|
||||
|
||||
**改进方向**:
|
||||
1. 招待费规则(参与人数缺失、人均超标、同城招待、节假日招待)
|
||||
2. 供应商风险规则(同一供应商高频、关联方、工商信息异常)
|
||||
3. 重复报销检测(发票号哈希去重、跨期扫描)
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 招待费规则集(≥5 条)
|
||||
- [ ] 供应商风险规则集(≥3 条)
|
||||
- [ ] 重复报销检测规则(≥2 条)
|
||||
- [ ] 每条新规则有对应单元测试
|
||||
|
||||
---
|
||||
|
||||
### B7. 审计日志防篡改 ⏳
|
||||
|
||||
**优先级**:🟢 P3
|
||||
|
||||
**证据**:
|
||||
- `server/src/app/models/audit_log.py`
|
||||
- `server/src/app/services/audit.py`(72 行)
|
||||
- before/after JSON 快照完整,但**无 hash chain 或数字签名**
|
||||
|
||||
**问题**:数据库管理员(或有 DB 写权限的人)可静默篡改审计日志。
|
||||
|
||||
**改进方向**:
|
||||
- 每条日志附加 `prev_hash + current_hash = sha256(prev_hash + payload)`
|
||||
- 定期锚定到外部存证(区块链 / 公证处 / WORM 存储)
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 审计日志实现 hash chain
|
||||
- [ ] 篡改可被检测
|
||||
- [ ] 外部存证机制(至少文档化)
|
||||
|
||||
---
|
||||
|
||||
### B8. 审批 SLA 与时效监控 ⏳
|
||||
|
||||
**优先级**:🟢 P3
|
||||
|
||||
**证据**:审批节点无超时提醒代码。
|
||||
|
||||
**问题**:单据卡在某领导处一周无人管,系统无感知。
|
||||
|
||||
**改进方向**:
|
||||
- 每个审批节点配置 SLA(如 24h/48h)
|
||||
- 后台定时任务扫描超时单据
|
||||
- 自动催办 / 升级到上级 / 转交
|
||||
|
||||
**验收标准**:
|
||||
- [ ] SLA 可配置
|
||||
- [ ] 超时自动催办
|
||||
- [ ] 超时升级机制
|
||||
- [ ] SLA 报表可查
|
||||
|
||||
---
|
||||
|
||||
### B9. 支付与凭证对接 ⏳
|
||||
|
||||
**优先级**:🟢 P3(业务延伸方向)
|
||||
|
||||
**证据**:状态机到 `paid` 就结束,无银企直连、无会计凭证生成。
|
||||
|
||||
**问题**:报销审批通过后仍需财务人工付款、手工录凭证,未形成完整闭环。
|
||||
|
||||
**改进方向**:
|
||||
- 银企直连(用友 / 金蝶 / 远光 API)
|
||||
- 自动生成会计凭证(借:管理费用-差旅,贷:银行存款/应付职工薪酬)
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 至少接入一个财务系统
|
||||
- [ ] 凭证自动生成
|
||||
- [ ] 支付状态回传
|
||||
|
||||
---
|
||||
|
||||
### B10. 800 行硬约束拆分(业务模块) ⏳
|
||||
|
||||
**优先级**:🔴 P0
|
||||
|
||||
**证据**:services/ 下 ≥ 800 行的文件,共 **20 个**:
|
||||
|
||||
| 文件 | 行数 | 超标幅度 |
|
||||
|---|---|---|
|
||||
| `services/user_agent_application.py` | 1451 | +81% |
|
||||
| `services/risk_rule_template_executor.py` | 1164 | +45% |
|
||||
| `services/expense_claim_draft_flow.py` | 1064 | +33% |
|
||||
| `services/expense_claims.py` | 1042 | +30% |
|
||||
| `services/receipt_folder.py` | 1034 | +29% |
|
||||
| `services/steward_planner.py` | 935 | +17% |
|
||||
| `api/v1/endpoints/agent_assets.py` | 925 | +16% |
|
||||
| `services/orchestrator_execution.py` | 900 | +12.5% |
|
||||
| `services/finance_dashboard.py` | 884 | +10.5% |
|
||||
| `services/knowledge_rag.py` | 877 | +9.6% |
|
||||
| `services/settings.py` | 873 | +9.1% |
|
||||
| `services/agent_assets.py` | 856 | +7% |
|
||||
| `services/employee.py` | 850 | +6.25% |
|
||||
| `services/employee_behavior_profile_service.py` | 823 | +2.9% |
|
||||
| `services/risk_rule_generation.py` | 821 | +2.6% |
|
||||
| `services/agent_foundation_asset_topup.py` | 809 | +1.1% |
|
||||
| `services/ontology_extraction.py` | 808 | +1% |
|
||||
| `services/demo_company_simulation_seed.py` | 805 | +0.6% |
|
||||
| `services/knowledge.py` | 800 | 临界 |
|
||||
| 另约 20 个文件在 700-800 行区间 | | 🟡 |
|
||||
|
||||
**前端超大文件**:
|
||||
|
||||
| 文件 | 行数 |
|
||||
|---|---|
|
||||
| `web/src/views/scripts/TravelReimbursementCreateView.js` | 4066 🔴🔴 |
|
||||
| `web/src/views/scripts/TravelRequestDetailView.js` | 2861 🔴🔴 |
|
||||
| `web/src/views/scripts/useTravelReimbursementSubmitComposer.js` | 2173 🔴🔴 |
|
||||
| `web/src/composables/useRequests.js` | 1799 🔴 |
|
||||
| `web/src/views/scripts/travelReimbursementReviewModel.js` | 1662 🔴 |
|
||||
| 多个 `.vue` 文件 | 800-1130 🔴 |
|
||||
|
||||
**改进方向**:
|
||||
- 按 AGENTS.md 既定的拆分原则(编排 / 状态 / 持久化 / 权限 / 文件存储 / OCR / 规则审核 / 响应构建 / 序列化)逐个拆
|
||||
- 优先 Top 5:`user_agent_application` / `risk_rule_template_executor` / `expense_claim_draft_flow` / `expense_claims` / `receipt_folder`
|
||||
- 每次拆分配套定向测试
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 所有类/文件 ≤ 800 行
|
||||
- [ ] 拆分前后行为等价(测试通过)
|
||||
- [ ] 拆分后职责边界清晰
|
||||
- [ ] CI 中加入行数检查(防止回潮)
|
||||
|
||||
---
|
||||
|
||||
## 三、推进原则
|
||||
|
||||
1. **P0 优先**:B2(安全)、B1(核心能力)、B10(共识)必须先行。
|
||||
2. **算法优化在 P0 落地后做**:再准的算法也会被权限漏洞和流程缺失抵消。
|
||||
3. **小步快跑**:每项改进拆成可独立验证的子任务,配套测试。
|
||||
4. **不破坏既有协议**:对外 API 尽量稳定,内部实现先拆。
|
||||
5. **800 行约束**:所有改动前后检查受影响类行数,CI 加入行数门禁。
|
||||
|
||||
---
|
||||
|
||||
## 四、变更日志
|
||||
|
||||
| 日期 | 变更 | 操作人 |
|
||||
|---|---|---|
|
||||
| 2026-06-18 | 路线图初始版本,基于代码库全量评估生成 | Sisyphus |
|
||||
@@ -0,0 +1,177 @@
|
||||
# Steward Application Reimbursement State Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Build a persistent ontology-bound steward state for travel application and travel reimbursement flows.
|
||||
|
||||
**Architecture:** Keep the existing steward planning UI and assistant delegation flow. Add a backend state layer that stores `steward_state` in `AgentConversation.state_json`, merges LLM/rule output as patches, and rejects fields outside the ontology registry before downstream services consume them.
|
||||
|
||||
**Tech Stack:** FastAPI, SQLAlchemy JSON state, Pydantic schemas, pytest in Docker `x-financial-main:/app`, Vue/Vite frontend.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Backend State Contract
|
||||
|
||||
**Files:**
|
||||
- Modify: `server/src/app/schemas/steward.py`
|
||||
- Create: `server/src/app/services/steward_flow_state.py`
|
||||
- Test: `server/tests/test_steward_flow_state.py`
|
||||
|
||||
- [ ] **Step 1: Write failing tests**
|
||||
|
||||
```python
|
||||
def test_state_merge_keeps_application_and_reimbursement_flows():
|
||||
service = StewardFlowStateService()
|
||||
state = service.merge_state(
|
||||
{},
|
||||
StewardFlowStatePatch(
|
||||
active_flow="travel_application",
|
||||
flow_id="travel_application",
|
||||
intent="travel_application_create",
|
||||
fields={"expense_type": "travel", "location": "上海"},
|
||||
),
|
||||
)
|
||||
state = service.merge_state(
|
||||
state,
|
||||
StewardFlowStatePatch(
|
||||
active_flow="travel_reimbursement",
|
||||
flow_id="travel_reimbursement",
|
||||
intent="travel_reimbursement_draft",
|
||||
fields={"amount": "708", "invoice_no": "NO-1"},
|
||||
),
|
||||
)
|
||||
|
||||
assert state["flows"]["travel_application"]["fields"]["location"] == "上海"
|
||||
assert state["flows"]["travel_reimbursement"]["fields"]["amount"] == "708"
|
||||
```
|
||||
|
||||
```python
|
||||
def test_state_merge_filters_non_ontology_fields():
|
||||
service = StewardFlowStateService()
|
||||
state = service.merge_state(
|
||||
{},
|
||||
StewardFlowStatePatch(
|
||||
active_flow="travel_application",
|
||||
flow_id="travel_application",
|
||||
intent="travel_application_create",
|
||||
fields={"location": "上海", "invented_field": "x"},
|
||||
),
|
||||
)
|
||||
|
||||
assert state["flows"]["travel_application"]["fields"] == {"location": "上海"}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run red tests**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-main /tmp/x-financial-server-venv/bin/pytest -q server/tests/test_steward_flow_state.py
|
||||
```
|
||||
|
||||
Expected: fail because `steward_flow_state.py` does not exist.
|
||||
|
||||
- [ ] **Step 3: Implement minimal state service**
|
||||
|
||||
Create `StewardFlowStatePatch`, `StewardFlowStateService.merge_state`, ontology field filtering, and event append logic.
|
||||
|
||||
- [ ] **Step 4: Run green tests**
|
||||
|
||||
Run the same pytest command and expect pass.
|
||||
|
||||
### Task 2: Steward Plan Persistence
|
||||
|
||||
**Files:**
|
||||
- Modify: `server/src/app/schemas/steward.py`
|
||||
- Modify: `server/src/app/api/v1/endpoints/steward.py`
|
||||
- Modify: `server/src/app/services/agent_conversations.py`
|
||||
- Test: `server/tests/test_steward_planner.py`
|
||||
|
||||
- [ ] **Step 1: Write failing API/service test**
|
||||
|
||||
Add a test proving `/steward/plans` response contains `conversation_id` and `steward_state` when `context_json.session_type = steward`, and the state contains two flows when the input contains one application and one reimbursement task.
|
||||
|
||||
- [ ] **Step 2: Run red test**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-main /tmp/x-financial-server-venv/bin/pytest -q server/tests/test_steward_planner.py
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Implement conversation state persistence**
|
||||
|
||||
Add `conversation_id` and `steward_state` fields to response schemas, persist state through `AgentConversationService`, and merge planner tasks into `steward_state`.
|
||||
|
||||
- [ ] **Step 4: Run green test**
|
||||
|
||||
Run the same pytest command and expect pass.
|
||||
|
||||
### Task 3: Runtime Decision Reads Persistent State
|
||||
|
||||
**Files:**
|
||||
- Modify: `server/src/app/services/steward_runtime_decision_agent.py`
|
||||
- Test: `server/tests/test_steward_runtime_decision_agent.py`
|
||||
|
||||
- [ ] **Step 1: Write failing test**
|
||||
|
||||
Add a test proving runtime decision uses `context_json.conversation_state.steward_state` when `runtime_state` is empty.
|
||||
|
||||
- [ ] **Step 2: Implement minimal fallback hydration**
|
||||
|
||||
Normalize runtime state by merging request runtime state with persisted steward state.
|
||||
|
||||
- [ ] **Step 3: Run green test**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-main /tmp/x-financial-server-venv/bin/pytest -q server/tests/test_steward_runtime_decision_agent.py
|
||||
```
|
||||
|
||||
### Task 4: Frontend State Carry
|
||||
|
||||
**Files:**
|
||||
- Modify: `web/src/views/scripts/stewardPlanModel.js`
|
||||
- Modify: `web/src/views/scripts/TravelReimbursementCreateView.js`
|
||||
- Modify: `web/src/views/scripts/useTravelReimbursementSessionState.js`
|
||||
|
||||
- [ ] **Step 1: Preserve steward state from backend responses**
|
||||
|
||||
Normalize `conversation_id` and `steward_state` from plan/runtime responses into the local session model.
|
||||
|
||||
- [ ] **Step 2: Send steward state in later requests**
|
||||
|
||||
Include the current `steward_state` under `context_json` for plan and runtime decision calls.
|
||||
|
||||
- [ ] **Step 3: Build frontend**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
docker exec -w /app/web x-financial-main npm run build
|
||||
```
|
||||
|
||||
Expected: build succeeds.
|
||||
|
||||
### Task 5: Final Verification
|
||||
|
||||
- [ ] **Step 1: Run backend steward tests**
|
||||
|
||||
```bash
|
||||
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-main /tmp/x-financial-server-venv/bin/pytest -q server/tests/test_steward_flow_state.py server/tests/test_steward_planner.py server/tests/test_steward_runtime_decision_agent.py server/tests/test_steward_slot_decision_agent.py
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run frontend build**
|
||||
|
||||
```bash
|
||||
docker exec -w /app/web x-financial-main npm run build
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Report workspace status**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
git status --short
|
||||
```
|
||||
159
docs/superpowers/plans/2026-06-22-refactor-under-800-lines.md
Normal file
159
docs/superpowers/plans/2026-06-22-refactor-under-800-lines.md
Normal file
@@ -0,0 +1,159 @@
|
||||
# Refactor Under 800 Lines Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Keep every Python class and every frontend core component/module under 800 lines, while deleting proven dead code and reducing avoidable runtime overhead.
|
||||
|
||||
**Architecture:** Add automated code-size guardrails first, then split oversized units by existing responsibility boundaries. Preserve public APIs wherever possible, move private helpers into focused modules, and delete code only after usage checks or tests prove it is not needed.
|
||||
|
||||
**Tech Stack:** Vue single-file components, Vite/Node test runner, Python/FastAPI service layer, pytest inside Docker container `x-financial-main`.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Guardrails
|
||||
|
||||
**Files:**
|
||||
- Create: `web/tests/code-size-limits.test.mjs`
|
||||
- Create: `server/tests/test_code_size_limits.py`
|
||||
|
||||
- [x] **Step 1: Add frontend source-unit limit test**
|
||||
|
||||
```bash
|
||||
node --test web/tests/code-size-limits.test.mjs
|
||||
```
|
||||
|
||||
Expected current result: FAIL, listing oversized files in `web/src/components`, `web/src/composables`, `web/src/utils`, and `web/src/views`.
|
||||
|
||||
- [x] **Step 2: Add backend class limit test**
|
||||
|
||||
```bash
|
||||
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-main /tmp/x-financial-server-venv/bin/pytest -q server/tests/test_code_size_limits.py
|
||||
```
|
||||
|
||||
Expected current result: FAIL, listing Python classes over 800 lines.
|
||||
|
||||
|
||||
### Task 2: Backend Python Class Split
|
||||
|
||||
**Files:**
|
||||
- Modify: `server/src/app/services/user_agent_application.py`
|
||||
- Modify: `server/src/app/services/risk_rule_template_executor.py`
|
||||
- Modify: `server/src/app/services/steward_planner.py`
|
||||
- Modify: `server/src/app/services/receipt_folder.py`
|
||||
- Modify: `server/src/app/services/expense_claim_draft_flow.py`
|
||||
- Modify: `server/src/app/services/expense_claims.py`
|
||||
- Modify: `server/src/app/services/orchestrator_execution.py`
|
||||
- Modify: `server/src/app/services/finance_dashboard.py`
|
||||
- Modify: `server/src/app/services/agent_assets.py`
|
||||
- Create focused helper or mixin files under `server/src/app/services/`
|
||||
|
||||
- [ ] **Step 1: Split low-risk helper groups first**
|
||||
|
||||
Move private formatting, parsing, label, and serialization methods into helper mixins or helper modules. Keep original public classes and method names stable.
|
||||
|
||||
- [ ] **Step 2: Split domain-heavy groups**
|
||||
|
||||
Move larger responsibility groups into named mixins:
|
||||
|
||||
```text
|
||||
UserAgentApplicationMixin
|
||||
├── application fact resolution
|
||||
├── application persistence
|
||||
└── application duplicate/detail helpers
|
||||
|
||||
RiskRuleTemplateExecutor
|
||||
├── condition evaluators
|
||||
├── value resolvers
|
||||
└── date/window parsing
|
||||
|
||||
ReceiptFolderService
|
||||
├── storage/meta helpers
|
||||
├── editable field resolution
|
||||
└── train ticket extraction
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Verify backend class limit**
|
||||
|
||||
```bash
|
||||
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-main /tmp/x-financial-server-venv/bin/pytest -q server/tests/test_code_size_limits.py
|
||||
```
|
||||
|
||||
Expected final result: PASS.
|
||||
|
||||
- [ ] **Step 4: Run targeted backend regression tests**
|
||||
|
||||
```bash
|
||||
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-main /tmp/x-financial-server-venv/bin/pytest -q server/tests/test_user_agent_service.py server/tests/test_expense_claim_service.py server/tests/test_steward_planner.py server/tests/test_risk_rule_generation.py server/tests/test_agent_asset_service.py server/tests/test_reimbursement_endpoints.py
|
||||
```
|
||||
|
||||
Expected final result: PASS or a documented pre-existing failure with evidence.
|
||||
|
||||
|
||||
### Task 3: Frontend Source Unit Split
|
||||
|
||||
**Files:**
|
||||
- Modify: `web/src/components/business/PersonalWorkbenchAiMode.vue`
|
||||
- Modify: `web/src/views/scripts/TravelReimbursementCreateView.js`
|
||||
- Modify: `web/src/views/scripts/TravelRequestDetailView.js`
|
||||
- Modify: `web/src/views/scripts/useTravelReimbursementSubmitComposer.js`
|
||||
- Modify remaining files reported by `web/tests/code-size-limits.test.mjs`
|
||||
- Create focused modules beside the existing owners under `web/src/views/scripts/`, `web/src/components/`, `web/src/composables/`, and `web/src/utils/`
|
||||
|
||||
- [ ] **Step 1: Split pure helpers before stateful runtime code**
|
||||
|
||||
Extract pure formatting, payload normalization, label mapping, row building, and text rendering helpers. This reduces file size without changing component state ownership.
|
||||
|
||||
- [ ] **Step 2: Split composables and child components**
|
||||
|
||||
For Vue files, move stable repeated UI blocks into child components only when props/events are clear. For script modules, move independent computed builders and action helpers into colocated modules.
|
||||
|
||||
- [ ] **Step 3: Remove proven redundant frontend code**
|
||||
|
||||
Use `rg` to confirm an export, class, helper, CSS hook, or branch is unused before deleting it. If a usage is dynamic, keep it unless a regression test proves it is dead.
|
||||
|
||||
- [ ] **Step 4: Verify frontend source limit**
|
||||
|
||||
```bash
|
||||
node --test web/tests/code-size-limits.test.mjs
|
||||
```
|
||||
|
||||
Expected final result: PASS.
|
||||
|
||||
- [ ] **Step 5: Run targeted frontend regression tests**
|
||||
|
||||
```bash
|
||||
node --test web/tests/workbench-ai-mode-switch.test.mjs web/tests/expense-application-fast-preview.test.mjs web/tests/expense-profile-detail-modal.test.mjs web/tests/finance-dashboard-ranking.test.mjs
|
||||
npm --prefix web run build
|
||||
```
|
||||
|
||||
Expected final result: PASS.
|
||||
|
||||
|
||||
### Task 4: Performance And Cleanup Pass
|
||||
|
||||
**Files:**
|
||||
- Modify only files already touched by Tasks 2 and 3 unless a usage check proves a separate dead module can be removed.
|
||||
|
||||
- [ ] **Step 1: Remove repeated computation inside hot paths**
|
||||
|
||||
Cache local computed values inside functions, avoid repeated JSON/string/date parsing loops, and prefer early returns for blocked states.
|
||||
|
||||
- [ ] **Step 2: Delete redundant private helpers**
|
||||
|
||||
Delete helpers only when all of these checks are true:
|
||||
|
||||
```bash
|
||||
rg "helperName" server web
|
||||
node --test affected-web-test.mjs
|
||||
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-main /tmp/x-financial-server-venv/bin/pytest -q affected_server_test.py
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Final verification**
|
||||
|
||||
```bash
|
||||
node --test web/tests/code-size-limits.test.mjs
|
||||
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-main /tmp/x-financial-server-venv/bin/pytest -q server/tests/test_code_size_limits.py
|
||||
npm --prefix web run build
|
||||
```
|
||||
|
||||
Expected final result: PASS.
|
||||
BIN
docs/ui-mockups/attachment-association-enterprise-ui-v1.png
Normal file
BIN
docs/ui-mockups/attachment-association-enterprise-ui-v1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 148 KiB |
132
document/development/Agent链路追踪中心/CONCEPT.md
Normal file
132
document/development/Agent链路追踪中心/CONCEPT.md
Normal file
@@ -0,0 +1,132 @@
|
||||
# Agent链路追踪中心 概念文档
|
||||
|
||||
## 功能一句话
|
||||
|
||||
为 Orchestrator 全链路运行提供统一 trace 采集、查询和前端回放入口,让管理员能按 `run_id` 或 `conversation_id` 还原一次 Agent 对话从意图识别到最终回复的全过程。
|
||||
|
||||
## 背景与问题
|
||||
|
||||
- 当前现状:系统已有 `agent_runs`、`agent_tool_calls`、`semantic_parse_logs` 和对话消息,但它们分散在运行记录、工具调用、语义解析与系统日志中。
|
||||
- 用户痛点:线上 Agent 回答异常时,只能看局部日志或 Hermes 工作记录,难以判断问题出在意图路由、知识检索、规则引擎、数字员工任务还是回复生成。
|
||||
- 业务影响:Agent 链路越长,排障成本越高;没有可重放视图会影响交付、演示和运维可信度。
|
||||
|
||||
## 目标与非目标
|
||||
|
||||
### 目标
|
||||
|
||||
- [G1] 后端沉淀统一的 Agent trace 事件模型,按运行顺序记录关键阶段输入、输出、状态、耗时和错误。
|
||||
- [G2] 提供 trace 查询接口,支持按 `run_id` 查看单次运行,按 `conversation_id` 查看多轮会话链路。
|
||||
- [G3] 前端新增 Agent Trace Center 入口,展示运行时间线、工具调用、语义解析、路由上下文和最终回复。
|
||||
- [G4] 保留现有 Agent Run / ToolCall 数据结构,避免破坏数字员工工作记录和系统日志页面。
|
||||
|
||||
### 非目标
|
||||
|
||||
- [NG1] 本轮不做重新执行真实业务动作的“调试重跑”,只做历史重放。
|
||||
- [NG2] 本轮不接入 OpenTelemetry、Jaeger 等外部分布式追踪系统。
|
||||
- [NG3] 本轮不改造总账、预算、报销审批等业务语义。
|
||||
- [NG4] 本轮不做跨服务链路采样策略和海量归档策略。
|
||||
|
||||
## 用户与场景
|
||||
|
||||
- 目标用户:系统管理员、财务系统运维、Agent 能力开发者、实施顾问。
|
||||
- 使用入口:系统日志详情、数字员工工作记录、报销助手消息中的 `run_id`、新增 Trace Center 页面。
|
||||
- 核心场景:
|
||||
- 管理员打开某次异常回复,查看每一步输入输出和耗时。
|
||||
- 实施人员按会话查看多轮上下文,判断上下文是否被错误继承。
|
||||
- 开发者定位工具调用失败、语义识别降级或路由选错 Agent 的原因。
|
||||
- 异常场景:
|
||||
- 运行失败但没有工具调用时,仍展示已记录的 orchestration 阶段。
|
||||
- 旧数据没有 trace event 时,接口回退展示 `agent_runs`、`semantic_parse`、`tool_calls`。
|
||||
|
||||
## 功能能力
|
||||
|
||||
- [C1] 输入能力:接收 `run_id`、`conversation_id`、Agent、状态、来源、关键字等查询条件。
|
||||
- [C2] 采集能力:记录 `received`、`context_hydrated`、`semantic_parsed`、`agent_selected`、`capability_selected`、`tool_invoked`、`response_built`、`conversation_updated`、`failed` 等事件。
|
||||
- [C3] 输出能力:返回 trace 摘要、事件时间线、工具调用、语义解析、路由 JSON、最终回复和关联会话消息。
|
||||
- [C4] 状态与权限:复用现有登录与页面权限,管理员/可访问设置页用户可查看全量 trace。
|
||||
- [C5] 边界与降级:旧运行没有 trace events 时,按现有 run/tool/semantic 数据合成最小时间线。
|
||||
|
||||
## 方案设计
|
||||
|
||||
### 前端
|
||||
|
||||
- 页面/组件:
|
||||
- 新增 `AgentTraceCenterView` 或设置页内 Trace Center 分区。
|
||||
- 新增 trace 详情组件,复用现有日志详情的直角企业级视觉。
|
||||
- 从日志详情、数字员工工作记录、报销助手操作反馈中可跳转到 trace 详情。
|
||||
- 交互状态:
|
||||
- 列表支持关键字、状态、Agent、来源筛选。
|
||||
- 详情展示左侧时间线、右侧输入输出 JSON、顶部摘要。
|
||||
- 支持加载、空态、错误态和刷新。
|
||||
- 展示规则:
|
||||
- 事件按 `started_at`、`sequence` 升序展示。
|
||||
- 失败事件突出错误信息。
|
||||
- 大 JSON 使用可滚动代码块,避免撑破页面。
|
||||
|
||||
### 后端
|
||||
|
||||
- 接口/服务:
|
||||
- `GET /api/v1/agent-traces`:查询 trace 列表。
|
||||
- `GET /api/v1/agent-traces/{run_id}`:读取单次运行 trace。
|
||||
- `GET /api/v1/agent-traces/conversations/{conversation_id}`:读取会话 trace。
|
||||
- 权限与校验:
|
||||
- 复用当前 API 依赖和系统登录态。
|
||||
- 不允许通过 trace 接口修改业务数据。
|
||||
- 持久化:
|
||||
- 新增 `agent_trace_events` 表。
|
||||
- 通过 `AgentTraceService` 封装记录、查询、合成旧数据时间线。
|
||||
|
||||
### 算法与规则
|
||||
|
||||
- 规则输入:Agent 运行阶段、工具调用结果、语义解析结果和会话消息。
|
||||
- 规则流程:
|
||||
- 采集阶段按固定事件名记录。
|
||||
- 查询阶段按事件序列合并 run、semantic、tool、conversation。
|
||||
- 无事件时从历史 run 数据合成 fallback timeline。
|
||||
- 结果解释:
|
||||
- 每个事件输出 `title`、`summary`、`status`、`duration_ms`、`input_json`、`output_json`、`error_message`。
|
||||
|
||||
## 算法与公式
|
||||
|
||||
当前功能不涉及评分、预算或风控公式,只涉及耗时统计:
|
||||
|
||||
$$
|
||||
duration\_ms = finished\_at - started\_at
|
||||
$$
|
||||
|
||||
变量说明:
|
||||
|
||||
- $duration\_ms$:阶段耗时,单位毫秒。
|
||||
- $finished\_at$:阶段结束时间。
|
||||
- $started\_at$:阶段开始时间。
|
||||
|
||||
## 测试方案
|
||||
|
||||
- 单元测试:覆盖 `AgentTraceService` 记录事件、查询详情、旧 run fallback 时间线。
|
||||
- 接口测试:覆盖 trace 列表、单 run 详情、会话详情。
|
||||
- 前端交互测试:覆盖 trace 数据归一化、状态文案、空态和错误态。
|
||||
- 端到端测试:通过一次 Orchestrator 用户消息生成 `run_id`,验证详情接口能返回语义解析、路由和至少一个事件。
|
||||
- 回归测试:确认原 `agent-runs` 接口、数字员工工作记录、系统日志详情不破坏。
|
||||
- 手工验证:在浏览器打开 Trace Center,检查列表、详情和 JSON 展示。
|
||||
|
||||
## 指标与验收
|
||||
|
||||
- [A1] 功能验收:一次 Orchestrator 调用后,能通过 `run_id` 查询到完整 trace 详情。
|
||||
- [A2] 性能指标:单次 trace 详情查询在常规数据量下不引入明显慢查询;默认列表限制数量。
|
||||
- [A3] 质量指标:后端定向测试在 Docker `x-financial-main` 容器内 60s 超时内通过。
|
||||
- [A4] 安全/权限指标:trace 接口只读,不触发业务动作或副作用。
|
||||
- [A5] 可观测性:失败运行也能看到最后成功事件和失败事件。
|
||||
|
||||
## 风险与开放问题
|
||||
|
||||
- 风险:当前工作树已有大量未提交改动,本轮实现必须避免覆盖既有业务改动。
|
||||
- 已处理依赖:新增 trace 模型已纳入 `Base` 导入,`AgentTraceService.ensure_storage_ready()` 会按需创建 trace 事件表。
|
||||
- 待确认:后续是否需要接 OpenTelemetry、跨容器 trace 或长期归档策略。
|
||||
- 降级策略:没有 trace event 的旧 run 通过 `semantic_parse`、`tool_calls` 和 `route_json` 合成只读时间线。
|
||||
|
||||
## 本轮实现记录
|
||||
|
||||
- 后端已完成 `AgentTraceEvent`、`AgentTraceService` 和 `/api/v1/agent-traces` 只读接口。
|
||||
- Orchestrator 已在接收请求、会话补全、语义识别、路由、工具调用、会话写回、最终回复和失败路径写入 trace event。
|
||||
- 前端已在系统设置中新增 Agent Trace Center,并从日志详情、数字员工工作记录跳转到指定 `run_id`。
|
||||
- 本轮保持非目标不变:不做真实业务重跑、不接 OpenTelemetry、不处理 GL/总账体系和前端统一状态管理。
|
||||
55
document/development/Agent链路追踪中心/TODO.md
Normal file
55
document/development/Agent链路追踪中心/TODO.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Agent链路追踪中心 开发 TODO
|
||||
|
||||
## 使用规则
|
||||
|
||||
- 每个 TODO 必须对应 `CONCEPT.md` 中的目标、能力或验收点。
|
||||
- 只有完成并验证后,才能把 `[ ]` 改成 `[x]`。
|
||||
- 勾选时在任务后补充简短证据,例如文件、接口、命令或验证结果。
|
||||
- 如果需求发生变化,先更新 `CONCEPT.md`,再调整本 TODO。
|
||||
|
||||
## 1. 调研与边界
|
||||
|
||||
- [x] [CONCEPT: 背景与问题] 阅读相关页面、接口、服务、测试和历史文档,记录当前实现事实。证据:已确认 `agent_runs`、`agent_tool_calls`、`semantic_parse_logs`、`LogDetailView`、`DigitalEmployeeWorkRecords` 现状。
|
||||
- [x] [CONCEPT: 目标与非目标] 确认本轮开发范围,写清楚不做项。证据:`CONCEPT.md` 明确只做历史重放,不做调试重跑和 OpenTelemetry。
|
||||
- [x] [CONCEPT: 风险与开放问题] 标记无法立即确认的依赖、风险和假设。证据:`CONCEPT.md` 风险章节记录脏工作树和数据库初始化依赖。
|
||||
|
||||
## 2. 契约与设计
|
||||
|
||||
- [x] [CONCEPT: 功能能力] 定义输入、输出、状态、权限和边界条件。证据:`CONCEPT.md` 功能能力章节。
|
||||
- [x] [CONCEPT: 方案设计] 明确前端、后端、算法、数据的职责边界。证据:`CONCEPT.md` 方案设计章节。
|
||||
- [x] [CONCEPT: 算法与公式] 补全耗时公式和变量解释。证据:`CONCEPT.md` 算法与公式章节。
|
||||
- [x] [CONCEPT: 指标与验收] 把验收标准转成可验证的检查点。证据:`CONCEPT.md` 指标与验收章节。
|
||||
|
||||
## 3. 后端实现
|
||||
|
||||
- [x] [CONCEPT: 后端] 新增 trace 事件模型、schema、repository/service。证据:`AgentTraceEvent`、`agent_trace.py`、`AgentTraceService`。
|
||||
- [x] [CONCEPT: 后端] 新增 `agent-traces` 只读接口和路由注册。证据:`agent_traces.py` endpoint 与 `router.py` 注册。
|
||||
- [x] [CONCEPT: 后端] 在 Orchestrator 关键节点写入 trace event。证据:`orchestrator.py` 记录接收、会话、语义、路由、回复、失败事件;`orchestrator_execution.py` 记录工具调用事件。
|
||||
- [x] [CONCEPT: 数据] 实现旧 run fallback 时间线,避免旧数据详情为空。证据:`AgentTraceService.get_trace()` 在无事件时由 `AgentRun`、`SemanticParseLog`、`AgentToolCall` 合成只读时间线。
|
||||
|
||||
## 4. 算法/规则实现
|
||||
|
||||
- [x] [CONCEPT: 算法与规则] 实现 trace 事件排序、耗时计算和状态归一化。证据:`AgentTraceService._next_sequence()`、`_resolve_duration_ms()`、`agentTraceViewModel.js`。
|
||||
- [x] [CONCEPT: 结果解释] 输出可读事件标题、摘要、输入输出和错误信息。证据:Trace event schema 与 `AgentTraceCenterView.vue` 详情面板。
|
||||
|
||||
## 5. 前端实现
|
||||
|
||||
- [x] [CONCEPT: 前端] 新增 trace 服务 API 和数据归一化工具。证据:`agentTraces.js`、`agentTraceViewModel.js`。
|
||||
- [x] [CONCEPT: 前端] 新增 Trace Center 列表与详情视图。证据:`AgentTraceCenterView.vue`。
|
||||
- [x] [CONCEPT: 前端] 从现有日志详情和工作记录补充 trace 跳转入口。证据:`LogDetailView.vue`、`DigitalEmployeeWorkRecords.vue`。
|
||||
- [x] [CONCEPT: 前端] 实现加载、空态、错误态和刷新。证据:`AgentTraceCenterView.vue` 列表/详情状态与刷新按钮。
|
||||
- [x] [CONCEPT: 前端] 对齐现有企业级直角、低饱和、密集信息风格。证据:`agent-trace-center-view.css` 使用面板、表格、状态徽标和紧凑信息布局。
|
||||
|
||||
## 6. 测试与验证
|
||||
|
||||
- [x] [CONCEPT: 测试方案] 补充后端 service/API 定向测试。证据:`test_agent_trace_service.py` 覆盖事件记录、fallback、接口列表和详情。
|
||||
- [x] [CONCEPT: 测试方案] 补充前端数据归一化测试或可构建验证。证据:`npm.cmd --prefix web run build` 通过。
|
||||
- [x] [CONCEPT: 测试方案] 在 60s 超时内运行 Docker 后端定向验证。证据:`docker exec ... pytest -q server/tests/test_agent_trace_service.py server/tests/test_agent_runs_service.py`,7 passed。
|
||||
- [x] [CONCEPT: 测试方案] 运行 `npm.cmd --prefix web run build`。证据:Vite build 成功。
|
||||
- [x] [CONCEPT: 指标与验收] 记录验证命令、结果和未覆盖风险。证据:后端测试 7 passed、Vite build 成功、重启后 `/api/v1/agent-traces/{run_id}` live 返回 8 个 fallback 事件;浏览器插件后续不可用,未完成最终截图巡检。
|
||||
|
||||
## 7. 文档收尾
|
||||
|
||||
- [x] [CONCEPT: 指标与验收] 回看所有验收点,确认均有实现或验证证据。证据:后端 service/API 测试、前端构建、入口接入均已完成。
|
||||
- [x] [CONCEPT: 风险与开放问题] 更新剩余风险、后续任务和明确不做项。证据:`CONCEPT.md` 保留 OpenTelemetry、跨容器 trace、长期归档为后续待定。
|
||||
- [x] [CONCEPT: 功能一句话] 确认最终实现没有偏离原始目标。证据:本轮只做 Agent Trace Center,未处理 GL/前端状态管理两项待定问题。
|
||||
@@ -1,58 +0,0 @@
|
||||
# Agent Plan 文档索引
|
||||
|
||||
本目录描述 X-Financial 后续要建设的双 Agent 财务智能架构。
|
||||
|
||||
核心目标:
|
||||
|
||||
- 建立一套共享的语义本体协议,统一理解用户问题、定时任务和规则触发上下文。
|
||||
- 建设两套职责边界清晰的 Agent:
|
||||
- Hermes:后台数字员工,负责内循环定时任务、风险巡检、统计、知识维护。
|
||||
- 自建 Agent:用户流程助手,负责用户交互、流程操作、解释、查询、草稿生成。
|
||||
- 建设 Agent Orchestrator,统一负责路由、权限、工具调用、审计和失败处理。
|
||||
- 让规则中心、MCP、知识库、数据库查询和任务系统使用同一套语义协议。
|
||||
|
||||
## 与一周计划的关系
|
||||
|
||||
`document/development/agent week plan` 是一周开发路线图,只描述每天要完成的大方向和交付结果。
|
||||
|
||||
本目录是具体架构与实现依据,包含:
|
||||
|
||||
- 架构设计。
|
||||
- 数据协议。
|
||||
- Agent 职责。
|
||||
- Orchestrator 流程。
|
||||
- OCR、知识库、规则生命周期。
|
||||
- 每天 daily 文档会引用到的设计依据。
|
||||
|
||||
执行时按这个顺序阅读:
|
||||
|
||||
1. 先看 `document/development/agent week plan/MASTER_TODO.md`,确认今天做什么。
|
||||
2. 再看本目录的架构文档,理解为什么这样做。
|
||||
3. 最后进入 `document/development/agent week plan/` 对应 Day 文档,在同一份文档中按详细执行清单开发。
|
||||
|
||||
推荐阅读顺序:
|
||||
|
||||
1. [01_overall_architecture.md](./01_overall_architecture.md)
|
||||
2. [02_semantic_ontology.md](./02_semantic_ontology.md)
|
||||
3. [03_agent_responsibilities.md](./03_agent_responsibilities.md)
|
||||
4. [04_orchestrator_and_runtime_flow.md](./04_orchestrator_and_runtime_flow.md)
|
||||
5. [05_development_roadmap.md](./05_development_roadmap.md)
|
||||
6. [06_data_contracts_and_governance.md](./06_data_contracts_and_governance.md)
|
||||
7. [07_capability_registry.md](./07_capability_registry.md)
|
||||
8. [08_permission_confirmation.md](./08_permission_confirmation.md)
|
||||
9. [09_observability_and_trace.md](./09_observability_and_trace.md)
|
||||
10. [10_evaluation_and_testset.md](./10_evaluation_and_testset.md)
|
||||
11. [11_ocr_invoice_architecture.md](./11_ocr_invoice_architecture.md)
|
||||
12. [12_llm_wiki_knowledge_architecture.md](./12_llm_wiki_knowledge_architecture.md)
|
||||
13. [13_rule_formation_lifecycle.md](./13_rule_formation_lifecycle.md)
|
||||
14. [14_financial_document_canonical_model.md](./14_financial_document_canonical_model.md)
|
||||
15. [15_feedback_learning_loop.md](./15_feedback_learning_loop.md)
|
||||
16. [../agent week plan/00_README.md](<../agent week plan/00_README.md>)
|
||||
|
||||
开发原则:
|
||||
|
||||
- 先语义协议,后 Agent 能力。
|
||||
- 先只读和建议,后写入和流程动作。
|
||||
- 先人工确认,后有限自动化。
|
||||
- 所有财务关键动作必须可审计、可回滚、可追责。
|
||||
- 所有 Agent 能力必须注册、分级、可评测、可追踪。
|
||||
@@ -1,163 +0,0 @@
|
||||
# 双 Agent 总体架构
|
||||
|
||||
## 1. 背景
|
||||
|
||||
X-Financial 后续需要同时支持两类智能化能力:
|
||||
|
||||
1. 用户主动发起的交互式流程操作。
|
||||
2. 系统后台自动运行的定时巡检、统计、预警和知识维护。
|
||||
|
||||
如果用一个万能 Agent 同时处理这两类任务,风险会很高:
|
||||
|
||||
- 用户流程操作需要权限、确认、上下文追问。
|
||||
- 定时巡检需要稳定批处理、失败重试、审计记录。
|
||||
- 财务系统不能让大模型直接决定审批、付款、规则上线。
|
||||
|
||||
因此建议建设双 Agent 架构:
|
||||
|
||||
```text
|
||||
Hermes Agent
|
||||
后台数字员工
|
||||
面向系统内循环
|
||||
定时、批量、巡检、统计、预警、知识候选
|
||||
|
||||
User Agent
|
||||
自建用户流程助手
|
||||
面向用户交互
|
||||
查询、解释、创建草稿、流程操作、审批辅助
|
||||
```
|
||||
|
||||
两套 Agent 共享一套语义本体协议,由 Agent Orchestrator 统一调度。
|
||||
|
||||
## 2. 总体架构图
|
||||
|
||||
```text
|
||||
┌──────────────────────┐
|
||||
│ 用户自然语言 / 定时任务 │
|
||||
└───────────┬──────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────┐
|
||||
│ Semantic Ontology │
|
||||
│ 语义本体解析层 │
|
||||
└───────────┬──────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────┐
|
||||
│ Agent Orchestrator │
|
||||
│ 路由 / 权限 / 审计 / 调度 │
|
||||
└───────┬─────────┬────┘
|
||||
│ │
|
||||
┌─────────────▼─┐ ┌─▼──────────────┐
|
||||
│ Hermes Agent │ │ User Agent │
|
||||
│ 后台数字员工 │ │ 用户流程助手 │
|
||||
└───────┬───────┘ └───────┬────────┘
|
||||
│ │
|
||||
└──────────┬──────────┘
|
||||
│
|
||||
┌────────────┬───────────┼───────────┬────────────┐
|
||||
▼ ▼ ▼ ▼ ▼
|
||||
规则中心 MCP 服务 业务数据库 知识库 任务系统
|
||||
```
|
||||
|
||||
## 3. 核心分层
|
||||
|
||||
### 3.1 语义本体层
|
||||
|
||||
负责把自然语言或任务配置转成结构化 JSON。
|
||||
|
||||
输出不是最终答案,而是统一协议:
|
||||
|
||||
```json
|
||||
{
|
||||
"domain": "reimbursement",
|
||||
"scenario": "invoice_validation",
|
||||
"intent": "explain_risk",
|
||||
"entities": [],
|
||||
"time_range": {},
|
||||
"constraints": {},
|
||||
"risk_signals": [],
|
||||
"next_step": "run_rule"
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 编排层
|
||||
|
||||
Agent Orchestrator 负责:
|
||||
|
||||
- 判断应该由 Hermes 还是 User Agent 处理。
|
||||
- 判断是否需要查数据库、跑规则、调 MCP、检索知识库。
|
||||
- 检查用户权限。
|
||||
- 记录审计日志。
|
||||
- 控制失败重试。
|
||||
- 对高风险动作要求用户或管理员确认。
|
||||
|
||||
### 3.3 Agent 层
|
||||
|
||||
Hermes 和 User Agent 不直接决定财务关键状态。
|
||||
|
||||
它们负责:
|
||||
|
||||
- 理解任务。
|
||||
- 组织工具调用。
|
||||
- 汇总工具结果。
|
||||
- 生成建议、解释、报告、草稿。
|
||||
|
||||
### 3.4 能力层
|
||||
|
||||
能力层包括:
|
||||
|
||||
- 规则中心:管理 `.md` 规则文件、审核、版本。
|
||||
- MCP:封装外部服务,如发票验真、银行流水、OCR、差旅平台。
|
||||
- 数据库查询:查询报销、报账、应收、应付、账款数据。
|
||||
- 知识库:制度文档、FAQ、历史解释、规则说明。
|
||||
- 任务系统:定时任务、批量任务、重试、运行日志。
|
||||
|
||||
## 4. 关键边界
|
||||
|
||||
Hermes 可以:
|
||||
|
||||
- 定时读取数据。
|
||||
- 执行规则检查。
|
||||
- 调 MCP 查询外部状态。
|
||||
- 生成风险报告。
|
||||
- 生成知识候选。
|
||||
- 生成待处理工单。
|
||||
|
||||
Hermes 不可以:
|
||||
|
||||
- 自动提交报销。
|
||||
- 自动发起付款。
|
||||
- 自动审批通过。
|
||||
- 自动发布知识库正式内容。
|
||||
- 自动上线规则。
|
||||
|
||||
User Agent 可以:
|
||||
|
||||
- 帮用户查询状态。
|
||||
- 帮用户解释风险。
|
||||
- 帮用户创建报销或付款草稿。
|
||||
- 帮审批人生成审批意见。
|
||||
- 在用户确认后调用流程 API。
|
||||
|
||||
User Agent 不可以:
|
||||
|
||||
- 绕过权限。
|
||||
- 未确认直接提交关键动作。
|
||||
- 自动最终审批。
|
||||
- 自动付款。
|
||||
- 修改规则审核状态。
|
||||
|
||||
## 5. 推荐建设顺序
|
||||
|
||||
```text
|
||||
Step 1: 建立语义本体 JSON 协议
|
||||
Step 2: 建立规则中心的规则/技能/MCP/任务目录
|
||||
Step 3: 建立 Orchestrator 路由和审计
|
||||
Step 4: 建立 User Agent 的只读查询和解释能力
|
||||
Step 5: 建立 Hermes 的定时任务和报告能力
|
||||
Step 6: 接入 MCP 和业务数据库
|
||||
Step 7: 增加用户确认后的流程写入能力
|
||||
Step 8: 增加知识候选和规则优化闭环
|
||||
```
|
||||
|
||||
@@ -1,457 +0,0 @@
|
||||
# 语义本体协议设计
|
||||
|
||||
## 1. 定位
|
||||
|
||||
语义本体协议是用户问题、定时任务、规则中心、MCP、数据库查询和 Agent 之间的统一中间层。
|
||||
|
||||
它解决的问题是:
|
||||
|
||||
- 用户到底在问哪个业务域?
|
||||
- 这属于什么场景?
|
||||
- 用户想做什么?
|
||||
- 问题中涉及哪些对象?
|
||||
- 有没有时间、金额、状态、部门等过滤条件?
|
||||
- 是否涉及风险?
|
||||
- 下一步应该查知识库、查数据库、跑规则、调 MCP,还是追问?
|
||||
|
||||
## 2. 第一版核心字段
|
||||
|
||||
第一版建议只强制落 8 个字段。
|
||||
|
||||
```json
|
||||
{
|
||||
"domain": "",
|
||||
"scenario": "",
|
||||
"intent": "",
|
||||
"entities": [],
|
||||
"time_range": {},
|
||||
"constraints": {},
|
||||
"risk_signals": [],
|
||||
"next_step": ""
|
||||
}
|
||||
```
|
||||
|
||||
### 2.1 domain
|
||||
|
||||
一级业务域。
|
||||
|
||||
建议枚举:
|
||||
|
||||
```text
|
||||
reimbursement
|
||||
accounts_receivable
|
||||
accounts_payable
|
||||
general_finance
|
||||
system_operation
|
||||
```
|
||||
|
||||
含义:
|
||||
|
||||
- `reimbursement`:报销、差旅、发票、补件。
|
||||
- `accounts_receivable`:应收账款、客户开票、收款、账龄。
|
||||
- `accounts_payable`:应付账款、供应商发票、付款、对账。
|
||||
- `general_finance`:通用财务知识、制度、统计。
|
||||
- `system_operation`:系统巡检、任务运行、规则维护、MCP 健康检查。
|
||||
|
||||
### 2.2 scenario
|
||||
|
||||
细分场景。
|
||||
|
||||
报销:
|
||||
|
||||
```text
|
||||
travel_reimbursement
|
||||
daily_expense
|
||||
invoice_validation
|
||||
attachment_review
|
||||
policy_overrun
|
||||
reimbursement_audit
|
||||
```
|
||||
|
||||
应收:
|
||||
|
||||
```text
|
||||
customer_invoice
|
||||
collection_followup
|
||||
receivable_aging
|
||||
payment_matching
|
||||
bad_debt_risk
|
||||
contract_receivable
|
||||
```
|
||||
|
||||
应付:
|
||||
|
||||
```text
|
||||
vendor_invoice
|
||||
payment_request
|
||||
payable_aging
|
||||
vendor_reconciliation
|
||||
invoice_matching
|
||||
cash_outflow_forecast
|
||||
```
|
||||
|
||||
系统运营:
|
||||
|
||||
```text
|
||||
daily_risk_scan
|
||||
daily_finance_statistics
|
||||
knowledge_accumulation
|
||||
mcp_health_check
|
||||
rule_quality_review
|
||||
```
|
||||
|
||||
### 2.3 intent
|
||||
|
||||
用户或任务的意图。
|
||||
|
||||
建议枚举:
|
||||
|
||||
```text
|
||||
query
|
||||
explain
|
||||
create
|
||||
validate
|
||||
summarize
|
||||
reconcile
|
||||
monitor
|
||||
predict
|
||||
remind
|
||||
generate
|
||||
optimize
|
||||
```
|
||||
|
||||
### 2.4 entities
|
||||
|
||||
识别出的业务对象。
|
||||
|
||||
统一结构:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "invoice",
|
||||
"value": "INV-202605001",
|
||||
"normalized_value": "INV-202605001",
|
||||
"role": "target",
|
||||
"confidence": 0.92
|
||||
}
|
||||
```
|
||||
|
||||
常见实体:
|
||||
|
||||
```text
|
||||
employee
|
||||
department
|
||||
customer
|
||||
vendor
|
||||
invoice
|
||||
contract
|
||||
reimbursement_request
|
||||
payment_order
|
||||
receipt
|
||||
bank_transaction
|
||||
cost_center
|
||||
project
|
||||
policy
|
||||
approval_node
|
||||
rule
|
||||
task
|
||||
```
|
||||
|
||||
### 2.5 time_range
|
||||
|
||||
统一描述时间。
|
||||
|
||||
```json
|
||||
{
|
||||
"raw": "上个月",
|
||||
"start": "2026-04-01",
|
||||
"end": "2026-04-30",
|
||||
"granularity": "month"
|
||||
}
|
||||
```
|
||||
|
||||
Hermes 定时任务也使用同一字段。
|
||||
|
||||
例如每日风险巡检:
|
||||
|
||||
```json
|
||||
{
|
||||
"raw": "昨日",
|
||||
"start": "2026-05-09",
|
||||
"end": "2026-05-09",
|
||||
"granularity": "day"
|
||||
}
|
||||
```
|
||||
|
||||
### 2.6 constraints
|
||||
|
||||
查询、判断或执行条件。
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "overdue",
|
||||
"aging_days": ">30",
|
||||
"amount": {
|
||||
"operator": ">",
|
||||
"value": 50000,
|
||||
"currency": "CNY"
|
||||
},
|
||||
"department": "销售部",
|
||||
"risk_level": ["medium", "high"]
|
||||
}
|
||||
```
|
||||
|
||||
### 2.7 risk_signals
|
||||
|
||||
风险信号。
|
||||
|
||||
建议枚举:
|
||||
|
||||
```text
|
||||
duplicate_invoice
|
||||
missing_attachment
|
||||
policy_overrun
|
||||
over_budget
|
||||
overdue_receivable
|
||||
bad_debt_risk
|
||||
vendor_payment_risk
|
||||
payment_mismatch
|
||||
contract_mismatch
|
||||
cashflow_pressure
|
||||
mcp_unavailable
|
||||
rule_quality_issue
|
||||
```
|
||||
|
||||
### 2.8 next_step
|
||||
|
||||
下一步动作。
|
||||
|
||||
建议枚举:
|
||||
|
||||
```text
|
||||
answer
|
||||
ask_clarification
|
||||
query_database
|
||||
run_rule
|
||||
call_mcp
|
||||
search_knowledge
|
||||
create_draft
|
||||
create_task
|
||||
generate_report
|
||||
notify_user
|
||||
escalate_to_human
|
||||
```
|
||||
|
||||
## 3. 扩展字段
|
||||
|
||||
后续可以增加:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema_version": "1.1",
|
||||
"confidence": 0.86,
|
||||
"ambiguity": [],
|
||||
"missing_slots": [],
|
||||
"required_capabilities": [],
|
||||
"normalized_query": "",
|
||||
"permission_scope": {},
|
||||
"audit_tags": []
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 混合语义解析架构
|
||||
|
||||
第一版可上线实现不应只依赖关键词和正则。
|
||||
|
||||
推荐采用:
|
||||
|
||||
```text
|
||||
输入上下文装配
|
||||
用户文本 + 页面上下文 + 附件名称 + OCR/VLM 摘要
|
||||
↓
|
||||
预抽取
|
||||
时间、金额、单号、显式对象
|
||||
↓
|
||||
LLM 结构化解析
|
||||
输出 scenario / intent / entities / missing_slots / ambiguity
|
||||
↓
|
||||
Schema 校验
|
||||
JSON 解析、字段枚举、必填校验、类型归一化
|
||||
↓
|
||||
规则兜底
|
||||
模型失败、低置信度或字段缺失时回退到规则解析
|
||||
↓
|
||||
澄清追问
|
||||
低置信度、歧义、缺槽位时不允许直接查库
|
||||
```
|
||||
|
||||
设计原则:
|
||||
|
||||
- 模型优先负责“理解意图和场景”。
|
||||
- 规则优先负责“校验、补全和兜底”。
|
||||
- 附件名称、OCR、VLM 结果只能作为证据,不等于已确认事实。
|
||||
- 所有语义输出都必须标记置信度和来源。
|
||||
|
||||
## 5. 推荐新增字段
|
||||
|
||||
为支持模型优先解析,建议在扩展字段中至少增加:
|
||||
|
||||
```json
|
||||
{
|
||||
"missing_slots": [],
|
||||
"ambiguity": [],
|
||||
"field_confidence": {},
|
||||
"field_source": {},
|
||||
"attachment_context": [],
|
||||
"parse_strategy": "llm_primary_with_rule_fallback"
|
||||
}
|
||||
```
|
||||
|
||||
字段说明:
|
||||
|
||||
- `missing_slots`:还缺哪些关键字段,例如费用类型、单据号、客户单位。
|
||||
- `ambiguity`:当前可能混淆的理解结果。
|
||||
- `field_confidence`:字段级置信度,而不是只给整体分数。
|
||||
- `field_source`:字段来自 `llm`、`rule`、`ocr`、`vlm` 还是 `user_context`。
|
||||
- `attachment_context`:本次可供语义解析使用的附件摘要。
|
||||
- `parse_strategy`:标记本次是模型主解析还是规则回退。
|
||||
|
||||
## 6. 叙述型财务输入
|
||||
|
||||
语义层必须支持“不是查询句”的自然叙述。
|
||||
|
||||
典型样例:
|
||||
|
||||
```text
|
||||
我今天去客户现场,招待了客户,花销了1000元
|
||||
我垫付了打车费和餐费,帮我看看怎么报
|
||||
上传了三张票,帮我整理成报销草稿
|
||||
```
|
||||
|
||||
这类输入不能默认识别成 `query`。
|
||||
|
||||
建议默认策略:
|
||||
|
||||
- 优先识别为 `reimbursement` 域。
|
||||
- 场景优先落到 `daily_expense`、`travel_reimbursement` 或 `attachment_review`。
|
||||
- 意图优先落到 `create`、`generate` 或 `validate`。
|
||||
- 缺失关键字段时返回 `ask_clarification`,而不是直接查数据库。
|
||||
|
||||
## 7. 模糊短句与澄清规则
|
||||
|
||||
以下输入应优先追问:
|
||||
|
||||
```text
|
||||
我要报销
|
||||
这个为什么还没处理
|
||||
帮我看一下这个
|
||||
上传好了,下一步呢
|
||||
```
|
||||
|
||||
处理原则:
|
||||
|
||||
- 不允许直接执行工具。
|
||||
- 不允许直接落到应收、应付查询。
|
||||
- 必须生成澄清问题。
|
||||
- 必须在审计中记录触发追问的原因。
|
||||
|
||||
扩展原则:
|
||||
|
||||
- 先不要把所有字段都做成数据库列。
|
||||
- 语义结果建议存 JSONB。
|
||||
- 使用 `schema_version` 管理版本。
|
||||
- Orchestrator 只依赖稳定字段。
|
||||
- 新字段以可选方式加入,不影响老任务。
|
||||
|
||||
## 4. 示例
|
||||
|
||||
### 4.1 用户查询应收账龄
|
||||
|
||||
用户问:
|
||||
|
||||
```text
|
||||
上个月哪些客户应收逾期超过 30 天?
|
||||
```
|
||||
|
||||
解析:
|
||||
|
||||
```json
|
||||
{
|
||||
"domain": "accounts_receivable",
|
||||
"scenario": "receivable_aging",
|
||||
"intent": "query",
|
||||
"entities": [
|
||||
{
|
||||
"type": "customer",
|
||||
"value": "客户",
|
||||
"role": "group_by"
|
||||
}
|
||||
],
|
||||
"time_range": {
|
||||
"raw": "上个月",
|
||||
"start": "2026-04-01",
|
||||
"end": "2026-04-30",
|
||||
"granularity": "month"
|
||||
},
|
||||
"constraints": {
|
||||
"aging_days": ">30",
|
||||
"status": "overdue"
|
||||
},
|
||||
"risk_signals": ["overdue_receivable"],
|
||||
"next_step": "query_database"
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 用户解释发票拦截
|
||||
|
||||
用户问:
|
||||
|
||||
```text
|
||||
这张发票为什么报销被拦截?
|
||||
```
|
||||
|
||||
解析:
|
||||
|
||||
```json
|
||||
{
|
||||
"domain": "reimbursement",
|
||||
"scenario": "invoice_validation",
|
||||
"intent": "explain",
|
||||
"entities": [
|
||||
{
|
||||
"type": "invoice",
|
||||
"value": "这张发票",
|
||||
"role": "target"
|
||||
}
|
||||
],
|
||||
"time_range": {},
|
||||
"constraints": {},
|
||||
"risk_signals": ["unknown"],
|
||||
"next_step": "run_rule"
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 Hermes 每日风险巡检
|
||||
|
||||
任务配置:
|
||||
|
||||
```json
|
||||
{
|
||||
"domain": "reimbursement",
|
||||
"scenario": "daily_risk_scan",
|
||||
"intent": "monitor",
|
||||
"entities": [],
|
||||
"time_range": {
|
||||
"raw": "昨日"
|
||||
},
|
||||
"constraints": {
|
||||
"risk_level": ["medium", "high"]
|
||||
},
|
||||
"risk_signals": [
|
||||
"duplicate_invoice",
|
||||
"missing_attachment",
|
||||
"policy_overrun"
|
||||
],
|
||||
"next_step": "run_rule"
|
||||
}
|
||||
```
|
||||
@@ -1,178 +0,0 @@
|
||||
# Hermes 与自建 Agent 职责边界
|
||||
|
||||
## 1. 两套 Agent 的定位
|
||||
|
||||
### 1.1 Hermes
|
||||
|
||||
Hermes 定位为后台数字员工。
|
||||
|
||||
它不直接面向用户聊天,而是在系统后台做内循环工作。
|
||||
|
||||
关键词:
|
||||
|
||||
```text
|
||||
定时
|
||||
批量
|
||||
巡检
|
||||
统计
|
||||
预警
|
||||
知识维护
|
||||
规则质量复盘
|
||||
```
|
||||
|
||||
### 1.2 自建 Agent
|
||||
|
||||
自建 Agent 定位为用户流程助手。
|
||||
|
||||
它直接面对员工、财务人员、审批人和管理员。
|
||||
|
||||
关键词:
|
||||
|
||||
```text
|
||||
用户触发
|
||||
会话式
|
||||
流程操作
|
||||
查询解释
|
||||
草稿生成
|
||||
审批辅助
|
||||
用户确认
|
||||
```
|
||||
|
||||
## 2. Hermes 职责
|
||||
|
||||
Hermes 负责:
|
||||
|
||||
1. 每日风险巡检。
|
||||
2. 每日报销、报账、账款统计。
|
||||
3. 应收逾期预警。
|
||||
4. 应付付款风险预警。
|
||||
5. 规则命中质量复盘。
|
||||
6. MCP 健康检查。
|
||||
7. 知识库候选内容生成。
|
||||
8. 高风险工单生成。
|
||||
9. 任务运行报告生成。
|
||||
|
||||
Hermes 输出的内容包括:
|
||||
|
||||
```text
|
||||
risk_report
|
||||
risk_work_items
|
||||
daily_finance_snapshot
|
||||
knowledge_candidates
|
||||
rule_improvement_items
|
||||
mcp_health_report
|
||||
task_run_log
|
||||
```
|
||||
|
||||
Hermes 不允许:
|
||||
|
||||
1. 自动审批通过。
|
||||
2. 自动发起付款。
|
||||
3. 自动提交用户申请。
|
||||
4. 自动发布正式知识库。
|
||||
5. 自动上线规则。
|
||||
6. 直接修改核心财务状态。
|
||||
|
||||
## 3. 自建 Agent 职责
|
||||
|
||||
自建 Agent 负责:
|
||||
|
||||
1. 查询报销单进度。
|
||||
2. 创建报销或付款草稿。
|
||||
3. 解释规则拦截原因。
|
||||
4. 生成审批意见。
|
||||
5. 检索制度知识。
|
||||
6. 查询应收应付数据。
|
||||
7. 帮用户对账。
|
||||
8. 引导用户补充缺失信息。
|
||||
9. 在用户确认后调用流程 API。
|
||||
|
||||
自建 Agent 输出的内容包括:
|
||||
|
||||
```text
|
||||
natural_language_answer
|
||||
form_draft
|
||||
approval_opinion_draft
|
||||
clarification_question
|
||||
query_result_summary
|
||||
next_action_suggestion
|
||||
```
|
||||
|
||||
自建 Agent 不允许:
|
||||
|
||||
1. 未经用户确认提交关键动作。
|
||||
2. 跳过权限校验。
|
||||
3. 自动最终审批。
|
||||
4. 自动付款。
|
||||
5. 修改规则上线状态。
|
||||
|
||||
## 4. 权限边界
|
||||
|
||||
| 动作 | Hermes | 自建 Agent |
|
||||
|---|---|---|
|
||||
| 查询制度知识 | 可以 | 可以 |
|
||||
| 查询业务数据 | 可以,按任务权限 | 可以,按用户权限 |
|
||||
| 跑规则 | 可以 | 可以 |
|
||||
| 调 MCP | 可以 | 可以 |
|
||||
| 生成报告 | 可以 | 可以 |
|
||||
| 生成草稿 | 不建议 | 可以 |
|
||||
| 提交流程 | 不可以 | 用户确认后可以 |
|
||||
| 审批通过 | 不可以 | 不可以直接做 |
|
||||
| 发起付款 | 不可以 | 高权限确认后才可做草稿 |
|
||||
| 发布知识 | 不可以 | 不可以 |
|
||||
| 上线规则 | 不可以 | 不可以 |
|
||||
|
||||
## 5. 共享能力
|
||||
|
||||
两套 Agent 共享:
|
||||
|
||||
- 语义本体协议。
|
||||
- 规则中心。
|
||||
- MCP 服务。
|
||||
- 知识库。
|
||||
- 数据库查询服务。
|
||||
- 审计日志。
|
||||
- 权限系统。
|
||||
|
||||
不共享:
|
||||
|
||||
- 运行队列。
|
||||
- 调度策略。
|
||||
- 用户会话状态。
|
||||
- 任务重试状态。
|
||||
|
||||
## 6. 示例
|
||||
|
||||
### 6.1 Hermes 场景
|
||||
|
||||
每日 02:00 自动运行:
|
||||
|
||||
```text
|
||||
每日风险巡检
|
||||
读取昨日报销、报账、发票、账款数据
|
||||
执行规则
|
||||
调用发票验真 MCP
|
||||
调用账款流水 MCP
|
||||
生成风险报告
|
||||
生成风险工单
|
||||
```
|
||||
|
||||
### 6.2 自建 Agent 场景
|
||||
|
||||
用户问:
|
||||
|
||||
```text
|
||||
帮我看一下这张差旅报销为什么没通过。
|
||||
```
|
||||
|
||||
处理:
|
||||
|
||||
```text
|
||||
解析语义
|
||||
查询报销单
|
||||
读取规则命中
|
||||
检索制度条款
|
||||
组织解释
|
||||
给出补件建议
|
||||
```
|
||||
|
||||
@@ -1,385 +0,0 @@
|
||||
# Agent Orchestrator 与运行流程
|
||||
|
||||
## 1. Orchestrator 定位
|
||||
|
||||
Agent Orchestrator 是双 Agent 架构的调度中心。
|
||||
|
||||
它不负责生成最终答案,而是负责:
|
||||
|
||||
- 接收用户请求或定时任务。
|
||||
- 调用语义解析。
|
||||
- 判断处理方。
|
||||
- 选择工具。
|
||||
- 检查权限。
|
||||
- 记录审计。
|
||||
- 管理失败重试。
|
||||
- 控制高风险动作确认。
|
||||
|
||||
## 2. 运行主流程
|
||||
|
||||
```text
|
||||
输入
|
||||
用户消息 / 页面按钮 / 定时任务 / 系统事件
|
||||
↓
|
||||
上下文装配
|
||||
页面对象 / 附件名称 / OCR 摘要 / VLM 摘要 / 用户角色 / conversation_id / draft_claim_id
|
||||
↓
|
||||
语义解析
|
||||
LLM 主解析 + 规则兜底,输出 ontology_json
|
||||
↓
|
||||
语义校验
|
||||
confidence / missing_slots / ambiguity / permission 初判
|
||||
↓
|
||||
Orchestrator 决策
|
||||
判断 agent = hermes | user_agent
|
||||
判断 tool = rule | mcp | db | knowledge | task
|
||||
↓
|
||||
权限检查
|
||||
用户权限 / 任务权限 / 数据范围
|
||||
↓
|
||||
业务写入
|
||||
报销草稿创建 / 报销草稿更新 / 用户确认后提交
|
||||
↓
|
||||
工具执行
|
||||
规则中心 / MCP / 数据库 / 知识库 / 任务系统
|
||||
↓
|
||||
Agent 汇总
|
||||
Hermes 报告 / User Agent 回答
|
||||
↓
|
||||
审计记录
|
||||
保存输入、语义、工具、结果、动作
|
||||
```
|
||||
|
||||
## 3. 路由规则
|
||||
|
||||
### 3.1 Hermes 路由
|
||||
|
||||
满足以下条件之一,进入 Hermes:
|
||||
|
||||
```text
|
||||
source = schedule
|
||||
source = system_event
|
||||
intent = monitor
|
||||
intent = summarize and no active user session
|
||||
next_step = generate_report and task_type is batch
|
||||
scenario in daily_risk_scan / knowledge_accumulation / mcp_health_check
|
||||
```
|
||||
|
||||
补充约束:
|
||||
|
||||
- 这里的 Hermes 指系统后台真实 Hermes 进程或 Hermes CLI,不是前端概念上的 “Hermes 模式”。
|
||||
- Orchestrator 负责路由、权限、审计和 Trace,不负责替代 Hermes 自身执行。
|
||||
- 当前阶段允许保留本地 fallback,但必须预留真实 Hermes 进程调用入口。
|
||||
|
||||
### 3.2 User Agent 路由
|
||||
|
||||
满足以下条件之一,进入自建 Agent:
|
||||
|
||||
```text
|
||||
source = user_message
|
||||
source = page_action
|
||||
intent = query / explain / create / validate / reconcile
|
||||
requires_user_context = true
|
||||
next_step = ask_clarification
|
||||
next_step = create_draft
|
||||
```
|
||||
|
||||
### 3.3 工具路由
|
||||
|
||||
```text
|
||||
next_step = query_database
|
||||
调用数据库查询服务
|
||||
|
||||
next_step = run_rule
|
||||
调用规则中心
|
||||
|
||||
next_step = call_mcp
|
||||
调用 MCP 服务
|
||||
|
||||
next_step = search_knowledge
|
||||
调用知识库检索
|
||||
|
||||
next_step = create_task
|
||||
调用任务系统
|
||||
|
||||
next_step = create_expense_claim_draft
|
||||
创建 expense_claims / expense_claim_items 草稿
|
||||
|
||||
next_step = update_expense_claim_draft
|
||||
回写报销主表、明细和附件关联
|
||||
|
||||
next_step = submit_expense_claim
|
||||
用户确认后更新 expense_claims.status = submitted
|
||||
|
||||
next_step = ask_clarification
|
||||
返回追问
|
||||
```
|
||||
|
||||
### 3.4 低置信度与缺槽位保护
|
||||
|
||||
当满足以下任一条件时,不允许直接进入数据库、MCP 或高风险流程:
|
||||
|
||||
```text
|
||||
confidence < threshold
|
||||
missing_slots 非空
|
||||
ambiguity 非空
|
||||
输入为叙述型报销,但缺少关键报销信息
|
||||
```
|
||||
|
||||
处理方式:
|
||||
|
||||
```text
|
||||
next_step = ask_clarification
|
||||
selected_agent = user_agent
|
||||
tool_count = 0
|
||||
```
|
||||
|
||||
### 3.5 叙述型报销输入保护
|
||||
|
||||
像下面这类文本:
|
||||
|
||||
```text
|
||||
我今天去客户现场,招待了客户,花销了1000元
|
||||
我垫付了交通费和午餐费
|
||||
我上传了票据,帮我整理一下
|
||||
```
|
||||
|
||||
不能因为出现“客户”就落到应收查询。
|
||||
|
||||
Orchestrator 应依赖语义层返回的 `scenario + intent + missing_slots` 做决策,而不是二次猜测文本关键词。
|
||||
|
||||
### 3.6 报销建单与状态流转边界
|
||||
|
||||
当 `scenario = expense` 且已满足最小建单槽位时:
|
||||
|
||||
```text
|
||||
next_step = create_expense_claim_draft
|
||||
status = draft
|
||||
```
|
||||
|
||||
当用户继续补充金额、地点、客户、参与人、附件时:
|
||||
|
||||
```text
|
||||
next_step = update_expense_claim_draft
|
||||
status 保持 draft
|
||||
```
|
||||
|
||||
当用户明确说“提交报销”并完成确认时:
|
||||
|
||||
```text
|
||||
next_step = submit_expense_claim
|
||||
status = submitted
|
||||
requires_confirmation = true
|
||||
```
|
||||
|
||||
以下状态不应由 User Agent 直接改写:
|
||||
|
||||
```text
|
||||
approved
|
||||
rejected
|
||||
paid
|
||||
```
|
||||
|
||||
这些状态应由审批流、财务支付流或受控后台同步更新。
|
||||
|
||||
### 3.7 结构化核对回路
|
||||
|
||||
当 `scenario = expense` 且当前仍存在缺槽位、附件待核对或票据需拆单时,不直接返回一段自由文本,而是返回结构化核对结果:
|
||||
|
||||
```text
|
||||
result.review_payload
|
||||
intent_summary
|
||||
body_message
|
||||
slot_cards
|
||||
risk_briefs
|
||||
document_cards
|
||||
claim_groups
|
||||
confirmation_actions = 取消 / 修改 / 保存草稿或下一步
|
||||
edit_fields
|
||||
```
|
||||
|
||||
前端正文区只展示简洁提示,右侧展示字段、风险、票据与分单明细。
|
||||
|
||||
### 3.8 会话续接与重识别
|
||||
|
||||
用户对话不是无状态调用。Orchestrator 需要携带以下会话字段继续当前报销流程:
|
||||
|
||||
```text
|
||||
conversation_id
|
||||
draft_claim_id
|
||||
conversation_history
|
||||
review_action
|
||||
review_form_values
|
||||
```
|
||||
|
||||
其中:
|
||||
|
||||
```text
|
||||
review_action = edit_review
|
||||
表示用户基于结构化模板修改识别结果,需要重新进入语义识别
|
||||
|
||||
review_action = save_draft
|
||||
表示信息未补齐,但允许先保存报销草稿
|
||||
|
||||
review_action = next_step
|
||||
表示用户确认当前识别结果,可进入下一步流转
|
||||
```
|
||||
|
||||
## 4. 用户流程示例
|
||||
|
||||
用户输入:
|
||||
|
||||
```text
|
||||
上个月哪些客户应收逾期超过 30 天?
|
||||
```
|
||||
|
||||
流程:
|
||||
|
||||
```text
|
||||
Step 1: User Agent 接收消息
|
||||
Step 2: semantic_parser 输出 ontology_json
|
||||
Step 3: Orchestrator 识别 domain = accounts_receivable
|
||||
Step 4: next_step = query_database
|
||||
Step 5: 权限检查用户是否可看应收数据
|
||||
Step 6: 查询应收账龄表
|
||||
Step 7: User Agent 汇总结果
|
||||
Step 8: 返回客户清单、金额、逾期天数、风险说明
|
||||
```
|
||||
|
||||
## 5. Hermes 任务示例
|
||||
|
||||
任务:
|
||||
|
||||
```text
|
||||
每日风险巡检
|
||||
```
|
||||
|
||||
流程:
|
||||
|
||||
```text
|
||||
Step 1: 任务调度器在 02:00 触发
|
||||
Step 2: Orchestrator 构造 ontology_json
|
||||
Step 3: 路由给 Hermes
|
||||
Step 4: Hermes 拉取昨日业务快照
|
||||
Step 5: 执行规则中心规则
|
||||
Step 6: 调用 MCP 验真、账款流水
|
||||
Step 7: 生成风险报告
|
||||
Step 8: 写入风险工单
|
||||
Step 9: 记录任务日志
|
||||
Step 10: 通知财务风控组
|
||||
```
|
||||
|
||||
### 5.1 Hermes 后台执行方式
|
||||
|
||||
推荐最小形态:
|
||||
|
||||
```text
|
||||
任务系统 / 手动触发 API
|
||||
↓
|
||||
Orchestrator 生成 run_id、任务上下文、权限信息
|
||||
↓
|
||||
后端调用系统 Hermes CLI 或 Hermes 后台进程
|
||||
↓
|
||||
Hermes 执行知识同步 / 风险巡检 / 规则草稿形成
|
||||
↓
|
||||
结果回写 AgentRun / ToolCall / 审计日志
|
||||
```
|
||||
|
||||
约束:
|
||||
|
||||
- Hermes 运行使用系统级配置,不在任务代码里再写一套模型配置。
|
||||
- Hermes 运行失败要记录 stderr 或等价错误摘要。
|
||||
- Hermes 输出的知识候选和规则草稿必须回写为结构化结果,不只保留终端文本。
|
||||
|
||||
## 5A. 用户报销建单示例
|
||||
|
||||
用户输入:
|
||||
|
||||
```text
|
||||
我今天去客户现场,招待了客户,花销了1000元
|
||||
```
|
||||
|
||||
流程:
|
||||
|
||||
```text
|
||||
Step 1: User Agent 接收消息
|
||||
Step 2: semantic_parser 输出 ontology_json
|
||||
Step 3: Orchestrator 判断 scenario = expense, intent = draft
|
||||
Step 4: 若缺客户、参与人、附件,则 next_step = ask_clarification
|
||||
Step 5: 补齐最小槽位后,next_step = create_expense_claim_draft
|
||||
Step 6: 创建 expense_claims / expense_claim_items
|
||||
Step 7: 若有附件,则挂接 document_assets / expense_item_documents
|
||||
Step 8: 用户确认提交后,next_step = submit_expense_claim
|
||||
Step 9: 更新 expense_claims.status = submitted
|
||||
Step 10: 写入 AgentRun、ToolCall、AuditLog
|
||||
```
|
||||
|
||||
## 6. 审计日志
|
||||
|
||||
每次 Agent 运行都应该写入审计。
|
||||
|
||||
建议字段:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "",
|
||||
"source": "user_message | schedule | system_event",
|
||||
"agent": "hermes | user_agent",
|
||||
"user_id": "",
|
||||
"task_id": "",
|
||||
"ontology_json": {},
|
||||
"tools_called": [],
|
||||
"permission_scope": {},
|
||||
"result_summary": "",
|
||||
"action_taken": "",
|
||||
"requires_confirmation": false,
|
||||
"created_at": ""
|
||||
}
|
||||
```
|
||||
|
||||
建议补充 Trace 字段:
|
||||
|
||||
```json
|
||||
{
|
||||
"semantic_provider": "",
|
||||
"semantic_model": "",
|
||||
"semantic_prompt_version": "",
|
||||
"semantic_parse_strategy": "llm_primary | rule_fallback",
|
||||
"semantic_fallback_reason": "",
|
||||
"semantic_latency_ms": 0
|
||||
}
|
||||
```
|
||||
|
||||
## 7. 失败处理
|
||||
|
||||
### 7.1 用户交互失败
|
||||
|
||||
```text
|
||||
数据库查询失败
|
||||
返回“暂时无法查询”,记录错误
|
||||
|
||||
缺少关键字段
|
||||
返回追问
|
||||
|
||||
权限不足
|
||||
返回无权限说明
|
||||
|
||||
MCP 不可用
|
||||
返回降级说明,必要时生成待处理项
|
||||
```
|
||||
|
||||
### 7.2 Hermes 任务失败
|
||||
|
||||
```text
|
||||
任务失败
|
||||
自动重试 3 次
|
||||
|
||||
部分 MCP 失败
|
||||
标记 partial_success
|
||||
|
||||
数据不完整
|
||||
生成异常任务日志
|
||||
|
||||
连续失败
|
||||
通知管理员
|
||||
```
|
||||
@@ -1,458 +0,0 @@
|
||||
# 分阶段开发计划
|
||||
|
||||
## Phase 0:准备阶段
|
||||
|
||||
目标:统一概念和边界,不写复杂功能。
|
||||
|
||||
### Step 0.1 明确术语
|
||||
|
||||
产出:
|
||||
|
||||
- 规则:`.md` 审查规则文件。
|
||||
- 技能:可复用的 Agent 能力,如审批意见生成、风险解释。
|
||||
- MCP:外部服务连接。
|
||||
- 任务:定时或批量运行的后台作业。
|
||||
- Hermes:后台数字员工。
|
||||
- User Agent:用户流程助手。
|
||||
- Orchestrator:调度和路由层。
|
||||
- Ontology:语义本体协议。
|
||||
|
||||
### Step 0.2 冻结第一版语义字段
|
||||
|
||||
第一版只强制 8 个字段:
|
||||
|
||||
```text
|
||||
domain
|
||||
scenario
|
||||
intent
|
||||
entities
|
||||
time_range
|
||||
constraints
|
||||
risk_signals
|
||||
next_step
|
||||
```
|
||||
|
||||
### Step 0.3 建立设计文档
|
||||
|
||||
产出:
|
||||
|
||||
- 本目录所有文档。
|
||||
- 后续数据库表设计草案。
|
||||
- API 合同草案。
|
||||
|
||||
## Phase 1:任务规则中心基础建设
|
||||
|
||||
目标:先把管理后台搭起来。
|
||||
|
||||
### Step 1.1 完成前端信息架构
|
||||
|
||||
页签:
|
||||
|
||||
```text
|
||||
规则 / 技能 / MCP / 任务
|
||||
```
|
||||
|
||||
规则详情:
|
||||
|
||||
- Markdown 编辑器。
|
||||
- 审核人。
|
||||
- 审核状态。
|
||||
- 版本列表。
|
||||
- 版本切换确认。
|
||||
|
||||
技能详情:
|
||||
|
||||
- 技能配置。
|
||||
- 输入上下文。
|
||||
- 输出契约。
|
||||
- 测试样例。
|
||||
- 依赖能力。
|
||||
|
||||
MCP 详情:
|
||||
|
||||
- 服务地址。
|
||||
- 鉴权方式。
|
||||
- 权限范围。
|
||||
- 健康检查。
|
||||
- 调用记录。
|
||||
|
||||
任务详情:
|
||||
|
||||
- Cron。
|
||||
- 运行窗口。
|
||||
- 输入范围。
|
||||
- 产出对象。
|
||||
- 最近运行。
|
||||
|
||||
### Step 1.2 建立后端基础模型
|
||||
|
||||
建议表:
|
||||
|
||||
```text
|
||||
agent_rules
|
||||
agent_skills
|
||||
agent_mcp_services
|
||||
agent_tasks
|
||||
agent_asset_versions
|
||||
agent_asset_reviews
|
||||
```
|
||||
|
||||
第一阶段可以先不做完整执行,只做 CRUD。
|
||||
|
||||
### Step 1.3 规则版本与审核
|
||||
|
||||
规则上线流程:
|
||||
|
||||
```text
|
||||
草稿
|
||||
↓
|
||||
提交审核
|
||||
↓
|
||||
审核通过
|
||||
↓
|
||||
上线
|
||||
```
|
||||
|
||||
关键约束:
|
||||
|
||||
- 没有审核人不能上线。
|
||||
- 没有审核通过不能上线。
|
||||
- 上线必须生成新版本。
|
||||
- 历史版本只读。
|
||||
|
||||
## Phase 2:OCR 与财务单据标准模型
|
||||
|
||||
目标:让发票、附件、报销单和账款流水先标准化。
|
||||
|
||||
### Step 2.1 附件上传与文件分类
|
||||
|
||||
识别:
|
||||
|
||||
- 发票。
|
||||
- 行程单。
|
||||
- 合同。
|
||||
- 付款凭证。
|
||||
- 审批截图。
|
||||
|
||||
### Step 2.2 OCR MCP 接入
|
||||
|
||||
把附件转成结构化字段。
|
||||
|
||||
### Step 2.3 Invoice 标准模型
|
||||
|
||||
统一 OCR、MCP、用户填写和业务系统字段。
|
||||
|
||||
### Step 2.4 人工修正
|
||||
|
||||
允许财务人员修正 OCR 字段,并写入反馈池。
|
||||
|
||||
### Step 2.5 规则中心接入 OCR 结果
|
||||
|
||||
重复发票、附件完整性、金额不一致等规则开始使用标准模型。
|
||||
|
||||
## Phase 3:语义本体服务
|
||||
|
||||
目标:用户问题和任务配置都能转成 ontology_json。
|
||||
|
||||
### Step 3.1 建立 semantic_parser API
|
||||
|
||||
接口:
|
||||
|
||||
```text
|
||||
POST /api/v1/semantic/parse
|
||||
```
|
||||
|
||||
输入:
|
||||
|
||||
```json
|
||||
{
|
||||
"source": "user_message",
|
||||
"text": "上个月哪些客户应收逾期超过 30 天?",
|
||||
"context": {}
|
||||
}
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
```json
|
||||
{
|
||||
"domain": "accounts_receivable",
|
||||
"scenario": "receivable_aging",
|
||||
"intent": "query",
|
||||
"entities": [],
|
||||
"time_range": {},
|
||||
"constraints": {},
|
||||
"risk_signals": [],
|
||||
"next_step": "query_database"
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3.2 建立模型优先解析器
|
||||
|
||||
要求:
|
||||
|
||||
- 使用运行时模型配置,而不是写死单一 provider。
|
||||
- 输入包括文本、上下文、附件摘要和预抽取字段。
|
||||
- 输出必须是结构化 JSON,而不是自由文本。
|
||||
- 输出必须经过 Schema 校验。
|
||||
- 模型失败时必须回退到规则解析。
|
||||
|
||||
### Step 3.3 建立 ontology schema 表
|
||||
|
||||
建议表:
|
||||
|
||||
```text
|
||||
semantic_ontology_schemas
|
||||
semantic_parse_logs
|
||||
```
|
||||
|
||||
字段:
|
||||
|
||||
```text
|
||||
id
|
||||
schema_version
|
||||
schema_json
|
||||
status
|
||||
created_at
|
||||
updated_at
|
||||
```
|
||||
|
||||
### Step 3.4 建立字段级校验与澄清策略
|
||||
|
||||
至少支持:
|
||||
|
||||
- 缺少费用类型时追问。
|
||||
- 缺少业务对象时追问。
|
||||
- 短句或模糊句时追问。
|
||||
- 叙述型报销输入默认走 create/generate,而不是 query。
|
||||
- 低置信度时禁止工具执行。
|
||||
|
||||
### Step 3.5 建立解析测试集
|
||||
|
||||
至少覆盖:
|
||||
|
||||
- 报销规则解释。
|
||||
- 差旅报销创建。
|
||||
- 叙述型报销创建。
|
||||
- 发票验真。
|
||||
- 应收逾期查询。
|
||||
- 应付付款状态。
|
||||
- 每日风险巡检。
|
||||
- 知识库维护。
|
||||
- 模糊短句追问。
|
||||
- 附件输入解析。
|
||||
|
||||
## Phase 4:LLM Wiki 知识库
|
||||
|
||||
目标:让制度文档、FAQ、审批经验可被 Agent 检索和引用。
|
||||
|
||||
### Step 4.1 文档解析与分块
|
||||
|
||||
上传 PDF、Word、Excel 后抽取正文并 chunk。
|
||||
|
||||
### Step 4.2 元数据与向量索引
|
||||
|
||||
为知识块打 domain、scenario、tags、版本。
|
||||
|
||||
### Step 4.3 知识检索 API
|
||||
|
||||
User Agent 可以基于语义本体查询知识。
|
||||
|
||||
### Step 4.4 知识候选审核
|
||||
|
||||
Hermes 生成 FAQ 或条款候选,人工审核后发布。
|
||||
|
||||
## Phase 5:Orchestrator 基础版
|
||||
|
||||
目标:基于 ontology_json 做确定性路由。
|
||||
|
||||
### Step 5.1 建立路由规则
|
||||
|
||||
输入:
|
||||
|
||||
```text
|
||||
source
|
||||
domain
|
||||
scenario
|
||||
intent
|
||||
next_step
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
```text
|
||||
agent = hermes | user_agent
|
||||
tools = []
|
||||
permission_required = []
|
||||
```
|
||||
|
||||
### Step 5.2 建立工具网关
|
||||
|
||||
第一批工具:
|
||||
|
||||
```text
|
||||
rule_engine.run
|
||||
knowledge.search
|
||||
database.query
|
||||
mcp.call
|
||||
task.create
|
||||
```
|
||||
|
||||
### Step 5.3 建立审计日志
|
||||
|
||||
所有请求都记录:
|
||||
|
||||
- 原始输入。
|
||||
- 语义 JSON。
|
||||
- 路由结果。
|
||||
- 工具调用。
|
||||
- 输出摘要。
|
||||
- 错误信息。
|
||||
|
||||
## Phase 6:User Agent 第一版
|
||||
|
||||
目标:先做只读和解释,不做强写入。
|
||||
|
||||
### Step 6.1 支持制度问答
|
||||
|
||||
流程:
|
||||
|
||||
```text
|
||||
用户问题
|
||||
-> semantic_parse
|
||||
-> search_knowledge
|
||||
-> User Agent 生成回答
|
||||
```
|
||||
|
||||
### Step 6.2 支持规则解释
|
||||
|
||||
流程:
|
||||
|
||||
```text
|
||||
用户问为什么被拦截
|
||||
-> semantic_parse
|
||||
-> run_rule
|
||||
-> search_knowledge
|
||||
-> User Agent 解释风险原因
|
||||
```
|
||||
|
||||
### Step 6.3 支持业务查询
|
||||
|
||||
先支持:
|
||||
|
||||
- 报销单状态查询。
|
||||
- 应收账龄查询。
|
||||
- 应付付款状态查询。
|
||||
|
||||
### Step 6.4 支持草稿生成
|
||||
|
||||
只生成草稿,不直接提交。
|
||||
|
||||
```text
|
||||
用户确认前不写核心状态
|
||||
```
|
||||
|
||||
## Phase 7:Hermes 第一版
|
||||
|
||||
目标:让后台数字员工开始跑任务。
|
||||
|
||||
### Step 7.1 每日风险巡检
|
||||
|
||||
输入:
|
||||
|
||||
- 昨日单据。
|
||||
- 发票。
|
||||
- 附件。
|
||||
- 付款流水。
|
||||
|
||||
输出:
|
||||
|
||||
- 风险报告。
|
||||
- 风险工单。
|
||||
- 风险统计。
|
||||
|
||||
### Step 7.2 每日财务统计
|
||||
|
||||
统计:
|
||||
|
||||
- 报销金额。
|
||||
- 报账金额。
|
||||
- 应收账龄。
|
||||
- 应付账龄。
|
||||
- 付款状态。
|
||||
- 账款异常。
|
||||
|
||||
### Step 7.3 知识候选积累
|
||||
|
||||
来源:
|
||||
|
||||
- 审批意见。
|
||||
- 驳回原因。
|
||||
- 高频问答。
|
||||
- 规则误报反馈。
|
||||
|
||||
输出:
|
||||
|
||||
- FAQ 候选。
|
||||
- 规则优化建议。
|
||||
- 制度变更摘要。
|
||||
|
||||
## Phase 8:MCP 接入
|
||||
|
||||
目标:让 Agent 能安全调用外部系统。
|
||||
|
||||
优先接入:
|
||||
|
||||
1. 发票验真 MCP。
|
||||
2. 附件 OCR MCP。
|
||||
3. 银行流水 MCP。
|
||||
4. 差旅平台 MCP。
|
||||
5. ERP/付款状态 MCP。
|
||||
|
||||
每个 MCP 必须有:
|
||||
|
||||
- 服务地址。
|
||||
- 鉴权方式。
|
||||
- 权限范围。
|
||||
- 超时设置。
|
||||
- 降级策略。
|
||||
- 健康检查。
|
||||
- 调用日志。
|
||||
|
||||
## Phase 9:规则形成与反馈闭环
|
||||
|
||||
目标:让系统持续变聪明,但不失控。
|
||||
|
||||
闭环:
|
||||
|
||||
```text
|
||||
Hermes 发现问题
|
||||
-> 生成规则优化建议
|
||||
-> 管理员审核
|
||||
-> 更新规则
|
||||
-> User Agent 使用新规则解释
|
||||
-> 反馈继续进入 Hermes
|
||||
```
|
||||
|
||||
关键限制:
|
||||
|
||||
- Hermes 只生成候选。
|
||||
- 管理员审核后才能发布。
|
||||
- 所有规则变更有版本。
|
||||
- 所有上线动作有审核人。
|
||||
|
||||
### Step 9.1 规则候选池
|
||||
|
||||
Hermes 从制度、风险案例、反馈中生成规则候选。
|
||||
|
||||
### Step 9.2 规则测试样例
|
||||
|
||||
每条规则上线前必须有测试样例。
|
||||
|
||||
### Step 9.3 反馈池
|
||||
|
||||
收集 OCR 修正、规则误报、Agent 回答反馈。
|
||||
|
||||
### Step 9.4 质量看板
|
||||
|
||||
统计误报率、修正率、回答满意度、MCP 失败率。
|
||||
@@ -1,445 +0,0 @@
|
||||
# 数据契约与治理要求
|
||||
|
||||
## 1. 推荐数据表
|
||||
|
||||
### 1.1 语义本体
|
||||
|
||||
```text
|
||||
semantic_ontology_schemas
|
||||
```
|
||||
|
||||
字段:
|
||||
|
||||
```text
|
||||
id
|
||||
schema_version
|
||||
schema_json
|
||||
status
|
||||
created_by
|
||||
created_at
|
||||
updated_at
|
||||
```
|
||||
|
||||
```text
|
||||
semantic_parse_logs
|
||||
```
|
||||
|
||||
字段:
|
||||
|
||||
```text
|
||||
id
|
||||
source
|
||||
user_id
|
||||
raw_text
|
||||
ontology_json
|
||||
confidence
|
||||
parse_strategy
|
||||
created_at
|
||||
```
|
||||
|
||||
### 1.2 Agent 资产
|
||||
|
||||
```text
|
||||
agent_rules
|
||||
agent_skills
|
||||
agent_mcp_services
|
||||
agent_tasks
|
||||
```
|
||||
|
||||
通用字段:
|
||||
|
||||
```text
|
||||
id
|
||||
code
|
||||
name
|
||||
description
|
||||
status
|
||||
owner
|
||||
reviewer
|
||||
config_json
|
||||
created_at
|
||||
updated_at
|
||||
```
|
||||
|
||||
### 1.3 版本与审核
|
||||
|
||||
```text
|
||||
agent_asset_versions
|
||||
```
|
||||
|
||||
字段:
|
||||
|
||||
```text
|
||||
id
|
||||
asset_type
|
||||
asset_id
|
||||
version
|
||||
content
|
||||
change_note
|
||||
created_by
|
||||
created_at
|
||||
```
|
||||
|
||||
```text
|
||||
agent_asset_reviews
|
||||
```
|
||||
|
||||
字段:
|
||||
|
||||
```text
|
||||
id
|
||||
asset_type
|
||||
asset_id
|
||||
version
|
||||
reviewer
|
||||
review_status
|
||||
review_note
|
||||
reviewed_at
|
||||
```
|
||||
|
||||
### 1.4 运行日志
|
||||
|
||||
```text
|
||||
agent_runs
|
||||
```
|
||||
|
||||
字段:
|
||||
|
||||
```text
|
||||
id
|
||||
agent
|
||||
source
|
||||
task_id
|
||||
user_id
|
||||
ontology_json
|
||||
status
|
||||
started_at
|
||||
finished_at
|
||||
result_summary
|
||||
error_message
|
||||
```
|
||||
|
||||
```text
|
||||
agent_tool_calls
|
||||
```
|
||||
|
||||
字段:
|
||||
|
||||
```text
|
||||
id
|
||||
run_id
|
||||
tool_type
|
||||
tool_name
|
||||
request_json
|
||||
response_json
|
||||
status
|
||||
duration_ms
|
||||
created_at
|
||||
```
|
||||
|
||||
### 1.5 财务业务主表
|
||||
|
||||
```text
|
||||
expense_claims
|
||||
expense_claim_items
|
||||
accounts_receivable
|
||||
accounts_payable
|
||||
approval_records
|
||||
```
|
||||
|
||||
治理要求:
|
||||
|
||||
- `expense_claims` 作为报销主表,不再继续扩张 `reimbursement_requests`。
|
||||
- `expense_claim_items` 作为报销明细最小粒度,OCR 匹配、风险识别、票据挂接都优先挂到该粒度。
|
||||
- `accounts_receivable` 与 `accounts_payable` 保持独立,避免因为 Agent 语义层接入而混用口径。
|
||||
|
||||
### 1.6 票据与文件资产表
|
||||
|
||||
```text
|
||||
document_assets
|
||||
document_asset_versions
|
||||
document_derivatives
|
||||
expense_item_documents
|
||||
document_access_logs
|
||||
```
|
||||
|
||||
职责:
|
||||
|
||||
- `document_assets`:原始附件主索引
|
||||
- `document_asset_versions`:原件版本留痕
|
||||
- `document_derivatives`:预览件、缩略图、脱敏件、逐页图片
|
||||
- `expense_item_documents`:报销明细与票据关联
|
||||
- `document_access_logs`:预览、下载、导出审计
|
||||
|
||||
### 1.7 OCR、验真与风险表
|
||||
|
||||
```text
|
||||
document_ocr_results
|
||||
invoice_structured_records
|
||||
invoice_verification_records
|
||||
risk_events
|
||||
risk_actions
|
||||
```
|
||||
|
||||
职责:
|
||||
|
||||
- `document_ocr_results`:每次 OCR 执行快照
|
||||
- `invoice_structured_records`:标准化发票字段
|
||||
- `invoice_verification_records`:发票验真结果留痕
|
||||
- `risk_events`:风险命中事实
|
||||
- `risk_actions`:风险处置动作
|
||||
|
||||
## 2. API 契约
|
||||
|
||||
### 2.1 语义解析
|
||||
|
||||
```text
|
||||
POST /api/v1/semantic/parse
|
||||
```
|
||||
|
||||
请求:
|
||||
|
||||
```json
|
||||
{
|
||||
"source": "user_message",
|
||||
"text": "这张发票为什么被拦截?",
|
||||
"context": {
|
||||
"user_id": "emp_001",
|
||||
"current_page": "reimbursement_detail"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
响应:
|
||||
|
||||
```json
|
||||
{
|
||||
"domain": "reimbursement",
|
||||
"scenario": "invoice_validation",
|
||||
"intent": "explain",
|
||||
"entities": [],
|
||||
"time_range": {},
|
||||
"constraints": {},
|
||||
"risk_signals": ["unknown"],
|
||||
"parse_strategy": "llm_primary",
|
||||
"next_step": "run_rule"
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 Orchestrator 执行
|
||||
|
||||
```text
|
||||
POST /api/v1/agent/orchestrate
|
||||
```
|
||||
|
||||
请求:
|
||||
|
||||
```json
|
||||
{
|
||||
"source": "user_message",
|
||||
"ontology": {},
|
||||
"context": {}
|
||||
}
|
||||
```
|
||||
|
||||
响应:
|
||||
|
||||
```json
|
||||
{
|
||||
"agent": "user_agent",
|
||||
"tools_called": [],
|
||||
"answer": "",
|
||||
"requires_confirmation": false,
|
||||
"audit_id": ""
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 文件上传契约
|
||||
|
||||
```text
|
||||
POST /api/v1/documents/upload
|
||||
```
|
||||
|
||||
请求:
|
||||
|
||||
```json
|
||||
{
|
||||
"biz_domain": "expense",
|
||||
"biz_object_type": "expense_claim",
|
||||
"biz_object_id": "claim_001",
|
||||
"upload_source": "user_workbench",
|
||||
"files": [
|
||||
{
|
||||
"filename": "invoice.jpg",
|
||||
"mime_type": "image/jpeg"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
响应:
|
||||
|
||||
```json
|
||||
{
|
||||
"documents": [
|
||||
{
|
||||
"document_id": "",
|
||||
"version_no": 1,
|
||||
"storage_status": "stored",
|
||||
"ocr_status": "pending"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 2.4 Hermes 任务
|
||||
|
||||
```text
|
||||
POST /api/v1/hermes/tasks/run
|
||||
```
|
||||
|
||||
请求:
|
||||
|
||||
```json
|
||||
{
|
||||
"task_code": "daily_risk_scan",
|
||||
"ontology": {},
|
||||
"dry_run": false,
|
||||
"context_json": {
|
||||
"folder": "报销制度",
|
||||
"changed_only": true,
|
||||
"force": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
响应:
|
||||
|
||||
```json
|
||||
{
|
||||
"run_id": "",
|
||||
"status": "accepted"
|
||||
}
|
||||
```
|
||||
|
||||
补充:
|
||||
|
||||
- Hermes 任务应优先调用系统后台 Hermes CLI 或等价 Hermes 进程。
|
||||
- `changed_only=true` 时,只处理知识库中发生变化的文档。
|
||||
- 文档变化判断至少包含 `original_name`、`stored_name`、`sha256`、`version_number`、`updated_at`。
|
||||
- 若文档无变化,应返回 `unchanged_skipped`,而不是重新形成 LLM Wiki。
|
||||
|
||||
## 3. 安全原则
|
||||
|
||||
### 3.1 最小权限
|
||||
|
||||
Agent 调工具时不能使用超级权限。
|
||||
|
||||
权限来源:
|
||||
|
||||
- 用户权限
|
||||
- 任务权限
|
||||
- 服务账号权限
|
||||
|
||||
### 3.2 高风险动作确认
|
||||
|
||||
以下动作必须确认:
|
||||
|
||||
- 提交报销
|
||||
- 发起付款
|
||||
- 生成正式审批意见
|
||||
- 发布规则
|
||||
- 发布知识库
|
||||
- 创建外部通知
|
||||
|
||||
### 3.3 审计不可省略
|
||||
|
||||
必须记录:
|
||||
|
||||
- 谁触发
|
||||
- 输入是什么
|
||||
- 解析结果是什么
|
||||
- 调了哪些工具
|
||||
- 输出是什么
|
||||
- 是否确认
|
||||
|
||||
### 3.4 文件存储治理
|
||||
|
||||
必须遵守:
|
||||
|
||||
- 原始文件二进制不落业务主表,不存入大字段 blob。
|
||||
- 所有文件必须有 `storage_provider`、`storage_key`、`sha256`、`file_size_bytes`、`mime_type`。
|
||||
- 原件不可覆盖,只能新增版本。
|
||||
- 删除默认是解除业务关联或逻辑删除,物理删除必须走审计流程。
|
||||
- 对象存储访问必须使用签名 URL 或后端代理,不直接暴露固定公网地址。
|
||||
|
||||
### 3.5 敏感数据治理
|
||||
|
||||
对于发票、行程单、合同、付款凭证中的敏感信息:
|
||||
|
||||
- 应支持脱敏衍生件
|
||||
- 应记录查看与下载行为
|
||||
- 应区分申请人、审批人、财务、管理员可见范围
|
||||
- 应支持争议单据 `legal_hold` 保留策略
|
||||
|
||||
### 3.6 AI 证据治理
|
||||
|
||||
Agent 和 OCR 相关能力必须遵守:
|
||||
|
||||
- 未经 OCR/VLM 实际解析,不得假设附件内容已知。
|
||||
- Agent 输出若引用发票金额、号码、日期,必须能追溯到 `invoice_structured_records` 或人工修正记录。
|
||||
- 风险解释若引用“重复报销”“金额不一致”等判断,必须能追溯到 `risk_events.evidence_json`。
|
||||
|
||||
## 4. 数据质量要求
|
||||
|
||||
### 4.1 关键唯一性
|
||||
|
||||
- `expense_claims.claim_no` 唯一
|
||||
- `document_assets.sha256` 可重复但必须可检索
|
||||
- `document_asset_versions(document_id, version_no)` 唯一
|
||||
- `invoice_structured_records.duplicate_fingerprint` 必须可索引
|
||||
|
||||
### 4.2 时间与状态字段
|
||||
|
||||
- 所有业务主表必须有 `created_at`、`updated_at`
|
||||
- 文件上传、OCR、验真、风控、处置必须有独立时间戳
|
||||
- 状态字段应使用受控枚举,不允许前端自由拼写
|
||||
|
||||
### 4.3 可追溯性
|
||||
|
||||
任一笔报销单、发票或风险结论,至少应能追到:
|
||||
|
||||
- 原始输入文本
|
||||
- 原始附件
|
||||
- 结构化结果
|
||||
- 规则或模型判断
|
||||
- 人工修正动作
|
||||
|
||||
## 5. 实施优先级
|
||||
|
||||
第一优先级:
|
||||
|
||||
- `expense_claims`
|
||||
- `expense_claim_items`
|
||||
- `document_assets`
|
||||
- `document_asset_versions`
|
||||
- `expense_item_documents`
|
||||
|
||||
第二优先级:
|
||||
|
||||
- `document_ocr_results`
|
||||
- `invoice_structured_records`
|
||||
- `invoice_verification_records`
|
||||
- `document_derivatives`
|
||||
|
||||
第三优先级:
|
||||
|
||||
- `risk_events`
|
||||
- `risk_actions`
|
||||
- `document_access_logs`
|
||||
|
||||
实施原则:
|
||||
|
||||
- 先确保“能收、能存、能找回原件”
|
||||
- 再确保“能识别、能验真、能回填”
|
||||
- 最后做“能解释、能审计、能批量巡检”
|
||||
@@ -1,198 +0,0 @@
|
||||
# Capability Registry 能力注册中心
|
||||
|
||||
## 1. 为什么需要能力注册中心
|
||||
|
||||
双 Agent 架构里会出现很多能力:
|
||||
|
||||
- 规则文件。
|
||||
- 技能。
|
||||
- MCP 服务。
|
||||
- 数据库查询。
|
||||
- 知识库检索。
|
||||
- 定时任务。
|
||||
- 报告生成。
|
||||
|
||||
如果 Orchestrator 直接在代码里硬编码这些能力,会导致:
|
||||
|
||||
- 能力越来越多后难维护。
|
||||
- 无法统一权限。
|
||||
- 无法统一版本。
|
||||
- 无法统一输入输出格式。
|
||||
- Hermes 和 User Agent 复用困难。
|
||||
|
||||
因此建议建立 Capability Registry。
|
||||
|
||||
它的定位是:
|
||||
|
||||
```text
|
||||
所有可被 Agent 调用的能力目录
|
||||
```
|
||||
|
||||
## 2. 能力类型
|
||||
|
||||
建议第一版支持:
|
||||
|
||||
```text
|
||||
rule
|
||||
skill
|
||||
mcp
|
||||
task
|
||||
database_query
|
||||
knowledge_search
|
||||
report_generator
|
||||
notification
|
||||
```
|
||||
|
||||
含义:
|
||||
|
||||
- `rule`:审查规则,通常是 `.md` 文件或规则配置。
|
||||
- `skill`:智能能力,如审批意见生成、风险解释。
|
||||
- `mcp`:外部服务连接。
|
||||
- `task`:定时或批量任务。
|
||||
- `database_query`:受控数据库查询能力。
|
||||
- `knowledge_search`:知识库检索能力。
|
||||
- `report_generator`:报告生成能力。
|
||||
- `notification`:通知能力。
|
||||
|
||||
## 3. 能力注册结构
|
||||
|
||||
建议结构:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "cap_rule_duplicate_invoice",
|
||||
"code": "duplicate_invoice_rule",
|
||||
"name": "重复报销识别规则",
|
||||
"capability_type": "rule",
|
||||
"domain": "reimbursement",
|
||||
"scenarios": ["invoice_validation", "reimbursement_audit"],
|
||||
"intents": ["validate", "explain", "monitor"],
|
||||
"input_schema": {},
|
||||
"output_schema": {},
|
||||
"permission_required": ["reimbursement:read", "risk:write"],
|
||||
"risk_level": "high",
|
||||
"owner": "财务风控组",
|
||||
"version": "v1.9",
|
||||
"status": "active",
|
||||
"requires_confirmation": false,
|
||||
"created_at": "",
|
||||
"updated_at": ""
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 与语义本体的匹配关系
|
||||
|
||||
Orchestrator 根据 ontology_json 匹配能力。
|
||||
|
||||
示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"domain": "reimbursement",
|
||||
"scenario": "invoice_validation",
|
||||
"intent": "explain",
|
||||
"risk_signals": ["duplicate_invoice"],
|
||||
"next_step": "run_rule"
|
||||
}
|
||||
```
|
||||
|
||||
可以匹配:
|
||||
|
||||
```text
|
||||
重复报销识别规则
|
||||
发票验真 MCP
|
||||
风险解释技能
|
||||
制度知识库检索
|
||||
```
|
||||
|
||||
## 5. 能力匹配优先级
|
||||
|
||||
建议顺序:
|
||||
|
||||
```text
|
||||
Step 1: next_step 决定能力大类
|
||||
Step 2: domain 限定业务域
|
||||
Step 3: scenario 限定场景
|
||||
Step 4: risk_signals 匹配具体规则
|
||||
Step 5: intent 匹配技能
|
||||
Step 6: permission_required 校验权限
|
||||
Step 7: status 必须 active
|
||||
Step 8: version 使用当前上线版本
|
||||
```
|
||||
|
||||
## 6. 数据表建议
|
||||
|
||||
```text
|
||||
agent_capabilities
|
||||
```
|
||||
|
||||
字段:
|
||||
|
||||
```text
|
||||
id
|
||||
code
|
||||
name
|
||||
capability_type
|
||||
domain
|
||||
scenario_json
|
||||
intent_json
|
||||
input_schema_json
|
||||
output_schema_json
|
||||
permission_json
|
||||
risk_level
|
||||
owner
|
||||
current_version
|
||||
status
|
||||
requires_confirmation
|
||||
config_json
|
||||
created_at
|
||||
updated_at
|
||||
```
|
||||
|
||||
## 7. 开发步骤
|
||||
|
||||
### Step 1: 先注册静态能力
|
||||
|
||||
先把现有规则、技能、MCP、任务写入 Registry。
|
||||
|
||||
不需要一开始做复杂 UI。
|
||||
|
||||
### Step 2: Orchestrator 改为查 Registry
|
||||
|
||||
从:
|
||||
|
||||
```text
|
||||
if next_step = run_rule then call duplicate_invoice_rule
|
||||
```
|
||||
|
||||
改为:
|
||||
|
||||
```text
|
||||
query capabilities where type = rule and scenario = invoice_validation
|
||||
```
|
||||
|
||||
### Step 3: 加权限过滤
|
||||
|
||||
只返回当前用户或任务有权限调用的能力。
|
||||
|
||||
### Step 4: 加版本选择
|
||||
|
||||
默认使用 active 版本。
|
||||
|
||||
历史版本只用于回放和调试。
|
||||
|
||||
### Step 5: 加健康状态
|
||||
|
||||
MCP、任务、数据库查询能力应有健康状态。
|
||||
|
||||
不可用时 Orchestrator 走降级策略。
|
||||
|
||||
## 8. 治理要求
|
||||
|
||||
- 所有能力必须有 owner。
|
||||
- 高风险能力必须有 reviewer。
|
||||
- 所有能力必须有输入输出 schema。
|
||||
- 所有能力必须有状态。
|
||||
- 下线能力不能被 Orchestrator 调用。
|
||||
- 能力版本变更必须写入审计。
|
||||
|
||||
@@ -1,214 +0,0 @@
|
||||
# 权限与确认引擎
|
||||
|
||||
## 1. 目标
|
||||
|
||||
Agent 不能只靠提示词判断能不能执行动作。
|
||||
|
||||
财务系统需要独立的权限与确认引擎:
|
||||
|
||||
```text
|
||||
Permission Engine
|
||||
Confirmation Engine
|
||||
```
|
||||
|
||||
它们负责:
|
||||
|
||||
- 判断用户是否能看某类数据。
|
||||
- 判断任务是否能调用某个能力。
|
||||
- 判断动作是否需要确认。
|
||||
- 判断动作是否禁止自动执行。
|
||||
|
||||
## 2. 动作风险分级
|
||||
|
||||
建议按 L0-L5 分级。
|
||||
|
||||
### L0 只读查询
|
||||
|
||||
例子:
|
||||
|
||||
- 查询制度。
|
||||
- 查询单据状态。
|
||||
- 查询规则说明。
|
||||
- 查询任务运行记录。
|
||||
|
||||
要求:
|
||||
|
||||
- 需要权限。
|
||||
- 不需要确认。
|
||||
|
||||
### L1 生成建议
|
||||
|
||||
例子:
|
||||
|
||||
- 生成审批意见建议。
|
||||
- 生成风险解释。
|
||||
- 生成规则优化建议。
|
||||
|
||||
要求:
|
||||
|
||||
- 需要权限。
|
||||
- 不写业务状态。
|
||||
- 不需要确认,但要标记为建议。
|
||||
|
||||
### L2 生成草稿
|
||||
|
||||
例子:
|
||||
|
||||
- 生成报销草稿。
|
||||
- 生成付款申请草稿。
|
||||
- 生成知识库候选。
|
||||
|
||||
要求:
|
||||
|
||||
- 需要权限。
|
||||
- 写入草稿区。
|
||||
- 不进入正式流程。
|
||||
|
||||
### L3 用户确认后提交
|
||||
|
||||
例子:
|
||||
|
||||
- 用户确认后提交报销。
|
||||
- 审批人确认后写入审批意见。
|
||||
- 用户确认后发起补件。
|
||||
|
||||
要求:
|
||||
|
||||
- 必须二次确认。
|
||||
- 必须记录确认人。
|
||||
- 必须记录确认前后内容。
|
||||
|
||||
### L4 管理员确认后发布
|
||||
|
||||
例子:
|
||||
|
||||
- 发布规则。
|
||||
- 发布知识库。
|
||||
- 启用 MCP。
|
||||
- 启用任务。
|
||||
|
||||
要求:
|
||||
|
||||
- 必须管理员确认。
|
||||
- 必须有审核记录。
|
||||
- 必须有版本。
|
||||
|
||||
### L5 禁止自动执行
|
||||
|
||||
例子:
|
||||
|
||||
- 自动最终审批。
|
||||
- 自动付款。
|
||||
- 自动绕过风控。
|
||||
- 自动修改核心财务状态。
|
||||
|
||||
要求:
|
||||
|
||||
- Agent 永远不能直接执行。
|
||||
|
||||
## 3. 权限判断输入
|
||||
|
||||
```json
|
||||
{
|
||||
"user_id": "emp_001",
|
||||
"agent": "user_agent",
|
||||
"source": "user_message",
|
||||
"action": "create_reimbursement_draft",
|
||||
"domain": "reimbursement",
|
||||
"resource": {
|
||||
"type": "reimbursement_request",
|
||||
"id": ""
|
||||
},
|
||||
"capability": "travel_reimbursement_create"
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 权限判断输出
|
||||
|
||||
```json
|
||||
{
|
||||
"allowed": true,
|
||||
"risk_level": "L2",
|
||||
"requires_confirmation": false,
|
||||
"reason": "",
|
||||
"permission_scope": {
|
||||
"departments": ["current_user"],
|
||||
"data_masking": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 确认弹窗策略
|
||||
|
||||
需要确认的动作必须显示:
|
||||
|
||||
- 动作名称。
|
||||
- 影响对象。
|
||||
- 关键字段。
|
||||
- 执行后果。
|
||||
- 是否可撤销。
|
||||
- 确认人。
|
||||
|
||||
示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "确认提交报销申请",
|
||||
"action": "submit_reimbursement",
|
||||
"summary": "将提交差旅报销单 TR-202605001,金额 ¥3,280。",
|
||||
"risk_level": "L3",
|
||||
"confirm_button": "确认提交"
|
||||
}
|
||||
```
|
||||
|
||||
## 6. Hermes 权限
|
||||
|
||||
Hermes 使用服务账号,不使用个人账号。
|
||||
|
||||
建议拆分权限:
|
||||
|
||||
```text
|
||||
hermes:risk_scan
|
||||
hermes:finance_statistics
|
||||
hermes:knowledge_candidate
|
||||
hermes:mcp_health_check
|
||||
```
|
||||
|
||||
Hermes 默认只允许:
|
||||
|
||||
- 读脱敏快照。
|
||||
- 跑规则。
|
||||
- 调只读 MCP。
|
||||
- 写报告、候选、工单。
|
||||
|
||||
Hermes 不允许:
|
||||
|
||||
- 写正式审批状态。
|
||||
- 写正式付款状态。
|
||||
- 发布规则。
|
||||
- 发布知识。
|
||||
|
||||
## 7. User Agent 权限
|
||||
|
||||
User Agent 继承当前用户权限。
|
||||
|
||||
例如:
|
||||
|
||||
- 员工只能看自己的报销。
|
||||
- 部门负责人可以看本部门。
|
||||
- 财务可以看授权范围内数据。
|
||||
- 管理员可以管理规则、任务、MCP。
|
||||
|
||||
User Agent 不能扩大用户权限。
|
||||
|
||||
## 8. 开发步骤
|
||||
|
||||
```text
|
||||
Step 1: 定义 action risk level
|
||||
Step 2: 建立 Permission Engine 接口
|
||||
Step 3: 所有工具调用前接入权限判断
|
||||
Step 4: L3/L4 动作接入确认弹窗
|
||||
Step 5: 审计记录确认内容
|
||||
Step 6: 增加权限测试用例
|
||||
```
|
||||
|
||||
@@ -1,186 +0,0 @@
|
||||
# 可观测性与 Agent Run Trace
|
||||
|
||||
## 1. 目标
|
||||
|
||||
Agent 系统必须可追踪、可回放、可解释。
|
||||
|
||||
财务系统中尤其需要回答:
|
||||
|
||||
- 为什么 Agent 得出这个结论?
|
||||
- 用了哪个模型?
|
||||
- 用了哪个规则版本?
|
||||
- 调用了哪些 MCP?
|
||||
- 查了哪些数据?
|
||||
- 谁确认了动作?
|
||||
- 失败在哪里?
|
||||
|
||||
## 2. Agent Run Trace
|
||||
|
||||
每次 Agent 运行都生成一个 run_id。
|
||||
|
||||
建议结构:
|
||||
|
||||
```json
|
||||
{
|
||||
"run_id": "",
|
||||
"source": "user_message",
|
||||
"agent": "user_agent",
|
||||
"user_id": "emp_001",
|
||||
"raw_input": "",
|
||||
"ontology_json": {},
|
||||
"route_decision": {},
|
||||
"permission_result": {},
|
||||
"tool_calls": [],
|
||||
"final_output": "",
|
||||
"status": "success",
|
||||
"started_at": "",
|
||||
"finished_at": ""
|
||||
}
|
||||
```
|
||||
|
||||
## 3. 需要记录的版本
|
||||
|
||||
每次运行都要记录:
|
||||
|
||||
```text
|
||||
ontology_schema_version
|
||||
semantic_parser_prompt_version
|
||||
model_name
|
||||
model_version
|
||||
rule_version
|
||||
skill_version
|
||||
mcp_version
|
||||
knowledge_snapshot_version
|
||||
orchestrator_version
|
||||
```
|
||||
|
||||
原因:
|
||||
|
||||
用户可能问:
|
||||
|
||||
```text
|
||||
为什么昨天和今天的结论不一样?
|
||||
```
|
||||
|
||||
只有记录版本,才能解释。
|
||||
|
||||
## 4. Tool Call Trace
|
||||
|
||||
每个工具调用都记录:
|
||||
|
||||
```json
|
||||
{
|
||||
"tool_call_id": "",
|
||||
"run_id": "",
|
||||
"tool_type": "mcp",
|
||||
"tool_name": "invoice_verify",
|
||||
"request_json": {},
|
||||
"response_json": {},
|
||||
"status": "success",
|
||||
"duration_ms": 820,
|
||||
"error_message": ""
|
||||
}
|
||||
```
|
||||
|
||||
敏感字段应脱敏。
|
||||
|
||||
## 5. 运行状态
|
||||
|
||||
建议枚举:
|
||||
|
||||
```text
|
||||
pending
|
||||
running
|
||||
success
|
||||
partial_success
|
||||
failed
|
||||
cancelled
|
||||
waiting_confirmation
|
||||
```
|
||||
|
||||
## 6. Hermes 可观测性
|
||||
|
||||
Hermes 任务需要额外记录:
|
||||
|
||||
```text
|
||||
task_code
|
||||
schedule_time
|
||||
data_snapshot_id
|
||||
records_scanned
|
||||
rules_executed
|
||||
mcp_calls
|
||||
risk_items_generated
|
||||
knowledge_candidates_generated
|
||||
retry_count
|
||||
```
|
||||
|
||||
示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"task_code": "daily_risk_scan",
|
||||
"records_scanned": 2146,
|
||||
"rules_executed": 8,
|
||||
"mcp_calls": 436,
|
||||
"risk_items_generated": 19,
|
||||
"status": "success"
|
||||
}
|
||||
```
|
||||
|
||||
## 7. User Agent 可观测性
|
||||
|
||||
User Agent 需要额外记录:
|
||||
|
||||
```text
|
||||
conversation_id
|
||||
page_context
|
||||
user_confirmation
|
||||
draft_created
|
||||
business_object_id
|
||||
```
|
||||
|
||||
## 8. 前端审计视图
|
||||
|
||||
建议后续增加“Agent 运行记录”页面。
|
||||
|
||||
展示:
|
||||
|
||||
- 运行时间。
|
||||
- Agent 类型。
|
||||
- 用户或任务。
|
||||
- 语义解析结果。
|
||||
- 调用工具。
|
||||
- 运行状态。
|
||||
- 耗时。
|
||||
- 错误。
|
||||
|
||||
详情页展示:
|
||||
|
||||
- 原始输入。
|
||||
- 本体 JSON。
|
||||
- 路由决策。
|
||||
- 工具调用链。
|
||||
- 最终输出。
|
||||
|
||||
## 9. 告警
|
||||
|
||||
需要告警的情况:
|
||||
|
||||
- Hermes 任务连续失败。
|
||||
- MCP 健康检查失败。
|
||||
- 语义解析低置信度比例过高。
|
||||
- 某规则误报率过高。
|
||||
- Agent 调用耗时异常。
|
||||
- 权限拒绝次数异常。
|
||||
|
||||
## 10. 开发步骤
|
||||
|
||||
```text
|
||||
Step 1: 增加 agent_runs 表
|
||||
Step 2: 增加 agent_tool_calls 表
|
||||
Step 3: Orchestrator 每次执行创建 run_id
|
||||
Step 4: 工具网关记录 tool call
|
||||
Step 5: 前端增加运行记录页面
|
||||
Step 6: 增加异常告警规则
|
||||
```
|
||||
|
||||
@@ -1,198 +0,0 @@
|
||||
# 评测集与质量控制
|
||||
|
||||
## 1. 为什么需要评测集
|
||||
|
||||
语义解析、本体字段、Agent 路由、规则命中都不能只靠人工感觉。
|
||||
|
||||
每次修改 prompt、模型、规则或路由逻辑,都应该运行评测集。
|
||||
|
||||
目标:
|
||||
|
||||
- 检查 domain 是否识别正确。
|
||||
- 检查 scenario 是否识别正确。
|
||||
- 检查 intent 是否识别正确。
|
||||
- 检查 next_step 是否正确。
|
||||
- 检查是否应该追问。
|
||||
- 检查是否错误调用高风险工具。
|
||||
|
||||
## 2. 第一版评测集规模
|
||||
|
||||
建议第一版至少 300 条。
|
||||
|
||||
```text
|
||||
报销问题:80 条
|
||||
应收问题:60 条
|
||||
应付问题:60 条
|
||||
制度问答:40 条
|
||||
风险解释:30 条
|
||||
定时任务:20 条
|
||||
模糊问题:10 条
|
||||
叙述型报销:20 条
|
||||
附件输入:10 条
|
||||
```
|
||||
|
||||
## 3. 评测样例结构
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "eval_001",
|
||||
"input": "上个月哪些客户应收逾期超过 30 天?",
|
||||
"expected": {
|
||||
"domain": "accounts_receivable",
|
||||
"scenario": "receivable_aging",
|
||||
"intent": "query",
|
||||
"next_step": "query_database"
|
||||
},
|
||||
"required_entities": ["customer"],
|
||||
"notes": "应识别为应收账龄查询"
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 评测指标
|
||||
|
||||
### 4.1 字段准确率
|
||||
|
||||
```text
|
||||
domain_accuracy
|
||||
scenario_accuracy
|
||||
intent_accuracy
|
||||
next_step_accuracy
|
||||
field_level_f1
|
||||
clarification_accuracy
|
||||
```
|
||||
|
||||
### 4.2 工具路由准确率
|
||||
|
||||
```text
|
||||
tool_route_accuracy
|
||||
permission_decision_accuracy
|
||||
confirmation_decision_accuracy
|
||||
narrative_misroute_rate
|
||||
```
|
||||
|
||||
### 4.3 安全指标
|
||||
|
||||
```text
|
||||
unsafe_action_rate
|
||||
missing_confirmation_rate
|
||||
permission_bypass_rate
|
||||
low_confidence_unsafe_tool_rate
|
||||
```
|
||||
|
||||
这些指标必须接近 0。
|
||||
|
||||
## 5. 低置信度处理
|
||||
|
||||
语义解析输出应包含:
|
||||
|
||||
```json
|
||||
{
|
||||
"confidence": 0.62,
|
||||
"missing_slots": ["time_range"],
|
||||
"ambiguity": ["应收逾期还是审批逾期"]
|
||||
}
|
||||
```
|
||||
|
||||
当置信度低于阈值:
|
||||
|
||||
```text
|
||||
confidence < 0.75
|
||||
不执行工具
|
||||
返回追问
|
||||
```
|
||||
|
||||
## 6. 模糊问题样例
|
||||
|
||||
用户问:
|
||||
|
||||
```text
|
||||
这个为什么还没处理?
|
||||
```
|
||||
|
||||
不能直接执行查询。
|
||||
|
||||
应该追问:
|
||||
|
||||
```text
|
||||
你是想查询报销单、应收款还是付款申请的处理状态?
|
||||
```
|
||||
|
||||
叙述型报销样例:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "eval_reimbursement_narrative_001",
|
||||
"input": "我今天去客户现场,招待了客户,花销了1000元",
|
||||
"expected": {
|
||||
"domain": "reimbursement",
|
||||
"scenario": "daily_expense",
|
||||
"intent": "create",
|
||||
"next_step": "ask_clarification"
|
||||
},
|
||||
"required_entities": ["amount"],
|
||||
"notes": "不能错误路由到应收查询"
|
||||
}
|
||||
```
|
||||
|
||||
## 7. 回归测试流程
|
||||
|
||||
每次改动以下内容都要跑评测:
|
||||
|
||||
- semantic parser 模型或 provider。
|
||||
- semantic parser prompt。
|
||||
- ontology schema。
|
||||
- Orchestrator 路由。
|
||||
- 规则中心匹配逻辑。
|
||||
- MCP 能力注册。
|
||||
- 模型版本。
|
||||
|
||||
流程:
|
||||
|
||||
```text
|
||||
Step 1: 加载评测集
|
||||
Step 2: 批量调用 semantic_parse
|
||||
Step 3: 批量调用 route_decision
|
||||
Step 4: 对比 expected
|
||||
Step 5: 输出准确率报告
|
||||
Step 6: 阻止低于阈值的发布
|
||||
```
|
||||
|
||||
## 8. 发布阈值
|
||||
|
||||
建议第一版阈值:
|
||||
|
||||
```text
|
||||
domain_accuracy >= 95%
|
||||
intent_accuracy >= 90%
|
||||
next_step_accuracy >= 90%
|
||||
unsafe_action_rate = 0
|
||||
missing_confirmation_rate = 0
|
||||
narrative_misroute_rate <= 1%
|
||||
low_confidence_unsafe_tool_rate = 0
|
||||
```
|
||||
|
||||
## 9. 评测数据管理
|
||||
|
||||
建议文件结构:
|
||||
|
||||
```text
|
||||
server/tests/fixtures/semantic_eval/
|
||||
reimbursement.jsonl
|
||||
accounts_receivable.jsonl
|
||||
accounts_payable.jsonl
|
||||
risk_explain.jsonl
|
||||
scheduled_tasks.jsonl
|
||||
```
|
||||
|
||||
每行一个样例。
|
||||
|
||||
## 10. 开发步骤
|
||||
|
||||
```text
|
||||
Step 1: 建立 JSONL 评测集格式
|
||||
Step 2: 写 50 条人工样例
|
||||
Step 3: 接入 semantic_parse 批测脚本
|
||||
Step 4: 输出 markdown/html 评测报告
|
||||
Step 5: 扩展到 300 条
|
||||
Step 6: 接入 CI 或手动发布检查
|
||||
```
|
||||
@@ -1,376 +0,0 @@
|
||||
# OCR 票据识别架构
|
||||
|
||||
## 1. 定位
|
||||
|
||||
OCR 票据识别不是一个简单的图片转文字功能。
|
||||
|
||||
它在 X-Financial 中承担四件事:
|
||||
|
||||
1. 把用户上传的附件变成结构化票据信息。
|
||||
2. 为规则中心提供可判断的字段。
|
||||
3. 为 User Agent 和 Hermes 提供可解释的证据。
|
||||
4. 为后续审计、复核、争议处理保留可回溯原件。
|
||||
|
||||
因此 OCR 应作为独立能力纳入 Capability Registry。
|
||||
|
||||
```text
|
||||
capability_type = mcp | document_processor
|
||||
capability_code = invoice_ocr
|
||||
```
|
||||
|
||||
## 2. 总体链路
|
||||
|
||||
```text
|
||||
附件上传
|
||||
↓
|
||||
文件落盘 / 对象存储
|
||||
↓
|
||||
文件分类
|
||||
↓
|
||||
OCR 识别
|
||||
↓
|
||||
字段结构化
|
||||
↓
|
||||
票据类型归一化
|
||||
↓
|
||||
发票验真 MCP
|
||||
↓
|
||||
与报销明细匹配
|
||||
↓
|
||||
规则中心检查
|
||||
↓
|
||||
人工修正
|
||||
↓
|
||||
修正结果沉淀
|
||||
```
|
||||
|
||||
关键原则:
|
||||
|
||||
- 文件先持久化,再做 OCR,不允许只在内存里跑完就丢。
|
||||
- 原件不可覆盖,只能新增版本。
|
||||
- Agent 不得假设图片内容已知;只有 OCR/VLM 实际解析后才能引用附件内容。
|
||||
|
||||
## 3. 阶段拆分
|
||||
|
||||
### Phase A:附件接入与文件分类
|
||||
|
||||
目标:先识别上传的是什么。
|
||||
|
||||
输入:
|
||||
|
||||
- 图片
|
||||
- PDF
|
||||
- Excel
|
||||
- Word
|
||||
- 压缩包
|
||||
|
||||
输出:
|
||||
|
||||
```json
|
||||
{
|
||||
"document_type": "invoice",
|
||||
"mime_type": "image/png",
|
||||
"page_count": 1,
|
||||
"confidence": 0.91
|
||||
}
|
||||
```
|
||||
|
||||
分类结果:
|
||||
|
||||
```text
|
||||
invoice
|
||||
itinerary
|
||||
contract
|
||||
payment_receipt
|
||||
approval_screenshot
|
||||
other
|
||||
```
|
||||
|
||||
### Phase B:OCR 字段提取
|
||||
|
||||
目标:从图片或 PDF 中提取票据字段。
|
||||
|
||||
结构:
|
||||
|
||||
```json
|
||||
{
|
||||
"invoice_code": "",
|
||||
"invoice_number": "",
|
||||
"seller_name": "",
|
||||
"seller_tax_no": "",
|
||||
"buyer_name": "",
|
||||
"buyer_tax_no": "",
|
||||
"issue_date": "",
|
||||
"total_amount": 0,
|
||||
"tax_amount": 0,
|
||||
"currency": "CNY",
|
||||
"ocr_confidence": 0.88
|
||||
}
|
||||
```
|
||||
|
||||
### Phase C:字段归一化
|
||||
|
||||
目标:不同 OCR 服务返回不同字段名,必须统一。
|
||||
|
||||
示例:
|
||||
|
||||
```text
|
||||
发票号码 / invoiceNo / invoice_number
|
||||
-> invoice_number
|
||||
```
|
||||
|
||||
金额统一:
|
||||
|
||||
```json
|
||||
{
|
||||
"raw": "¥1,280.00",
|
||||
"value": 1280.00,
|
||||
"currency": "CNY"
|
||||
}
|
||||
```
|
||||
|
||||
### Phase D:验真与状态检查
|
||||
|
||||
调用发票验真 MCP。
|
||||
|
||||
输出:
|
||||
|
||||
```json
|
||||
{
|
||||
"verify_status": "verified",
|
||||
"voided": false,
|
||||
"red_reversed": false,
|
||||
"verified_at": ""
|
||||
}
|
||||
```
|
||||
|
||||
### Phase E:与报销明细匹配
|
||||
|
||||
对比:
|
||||
|
||||
- 发票金额 vs 报销金额
|
||||
- 开票日期 vs 费用日期
|
||||
- 销售方 vs 商户
|
||||
- 发票类型 vs 费用类型
|
||||
|
||||
输出:
|
||||
|
||||
```json
|
||||
{
|
||||
"match_status": "matched",
|
||||
"mismatch_fields": [],
|
||||
"match_confidence": 0.94
|
||||
}
|
||||
```
|
||||
|
||||
### Phase F:人工修正与回流
|
||||
|
||||
OCR 结果必须允许人工修正。
|
||||
|
||||
修正内容进入反馈池:
|
||||
|
||||
```json
|
||||
{
|
||||
"field": "invoice_number",
|
||||
"before": "12345B",
|
||||
"after": "123456",
|
||||
"corrected_by": "finance_user",
|
||||
"corrected_at": ""
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 文件存储策略
|
||||
|
||||
### 4.1 为什么不能直接把文件塞进数据库
|
||||
|
||||
- 原始票据、合同、行程单体积大,数据库行膨胀明显。
|
||||
- 预览件、缩略图、逐页图片、脱敏件都属于衍生文件,不适合和业务行混存。
|
||||
- 财务原件需要版本留痕和不可变追溯,文件系统或对象存储更适合。
|
||||
|
||||
结论:
|
||||
|
||||
- 文件二进制存文件系统或对象存储。
|
||||
- 数据库仅保存元数据、索引、版本、OCR 结果、验真结果、访问审计和业务关联。
|
||||
|
||||
### 4.2 开发环境目录方案
|
||||
|
||||
根目录使用后端配置中的 `STORAGE_ROOT_DIR`。
|
||||
|
||||
建议目录:
|
||||
|
||||
```text
|
||||
<STORAGE_ROOT_DIR>/
|
||||
finance-documents/
|
||||
expense_claim/
|
||||
2026/
|
||||
05/
|
||||
<claim_id>/
|
||||
<document_id>/
|
||||
v1/
|
||||
original/
|
||||
source.jpg
|
||||
preview/
|
||||
preview.pdf
|
||||
pages/
|
||||
page-1.png
|
||||
thumbs/
|
||||
thumb.webp
|
||||
ocr/
|
||||
ocr-1.json
|
||||
verify/
|
||||
verify-1.json
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `claim_id` 为空时,可先挂到 `draft/<conversation_id>/<document_id>/...`,待正式建单后再回填业务关联。
|
||||
- `v1`、`v2` 表示文件版本,不允许直接覆盖 `v1`。
|
||||
- 原始文件名用于展示,真实定位依赖 `storage_key` 和 `sha256`。
|
||||
|
||||
### 4.3 生产环境存储方案
|
||||
|
||||
生产环境建议使用:
|
||||
|
||||
- MinIO
|
||||
- S3
|
||||
- 阿里云 OSS
|
||||
- 腾讯云 COS
|
||||
|
||||
对象存储推荐键名:
|
||||
|
||||
```text
|
||||
finance-documents/expense_claim/2026/05/<claim_id>/<document_id>/v1/original/source.jpg
|
||||
finance-documents/expense_claim/2026/05/<claim_id>/<document_id>/v1/preview/preview.pdf
|
||||
finance-documents/expense_claim/2026/05/<claim_id>/<document_id>/v1/thumbs/thumb.webp
|
||||
```
|
||||
|
||||
数据库必须保存:
|
||||
|
||||
```text
|
||||
storage_provider
|
||||
storage_bucket
|
||||
storage_key
|
||||
sha256
|
||||
file_size_bytes
|
||||
mime_type
|
||||
current_version_no
|
||||
```
|
||||
|
||||
### 4.4 原件、版本与衍生件规则
|
||||
|
||||
- 原件不可变:上传后不得覆盖。
|
||||
- 替换附件只能新增 `document_asset_versions` 记录。
|
||||
- OCR 原始输出、验真响应、预览件、缩略图都作为衍生件管理。
|
||||
- 删除操作默认只允许逻辑删除业务关联,不允许物理删除原件。
|
||||
- 命中审计或争议流程的单据可切换到 `legal_hold` 保留策略,暂停清理。
|
||||
|
||||
### 4.5 去重与追溯
|
||||
|
||||
- 每个原始文件必须计算 `sha256`。
|
||||
- 同一个 `sha256` 可提示重复上传,但不能自动覆盖旧版本。
|
||||
- 发票查重不能只靠文件哈希,还要结合 `invoice_code + invoice_number + issue_date + total_amount`。
|
||||
|
||||
## 5. 数据模型建议
|
||||
|
||||
推荐配套表:
|
||||
|
||||
```text
|
||||
document_assets
|
||||
document_asset_versions
|
||||
document_derivatives
|
||||
document_ocr_results
|
||||
invoice_structured_records
|
||||
invoice_verification_records
|
||||
expense_item_documents
|
||||
document_access_logs
|
||||
```
|
||||
|
||||
各表职责:
|
||||
|
||||
- `document_assets`:文件主索引
|
||||
- `document_asset_versions`:原件版本
|
||||
- `document_derivatives`:缩略图、预览、逐页图片、脱敏件
|
||||
- `document_ocr_results`:每次 OCR 执行结果
|
||||
- `invoice_structured_records`:标准化票据字段
|
||||
- `invoice_verification_records`:验真结果
|
||||
- `expense_item_documents`:报销明细与票据挂接
|
||||
- `document_access_logs`:文件查看、下载、导出审计
|
||||
|
||||
## 6. 与规则中心关系
|
||||
|
||||
OCR 输出供规则使用:
|
||||
|
||||
```text
|
||||
重复报销识别规则
|
||||
作废发票检查规则
|
||||
发票抬头异常规则
|
||||
附件完整性规则
|
||||
金额不一致规则
|
||||
OCR 低置信度补录规则
|
||||
```
|
||||
|
||||
规则读取原则:
|
||||
|
||||
- 读标准化字段,不直接依赖某个 OCR 服务的原始字段名。
|
||||
- 需要追证时,从 `document_assets` 和 `document_asset_versions` 找原件。
|
||||
- 需要解释时,从 `document_ocr_results` 和 `invoice_verification_records` 给证据。
|
||||
|
||||
## 7. 与 Agent 关系
|
||||
|
||||
User Agent 使用 OCR:
|
||||
|
||||
- 解释发票为什么被拦截
|
||||
- 帮用户补充发票信息
|
||||
- 提醒上传清晰附件
|
||||
- 根据 OCR 结果自动回填报销草稿
|
||||
|
||||
Hermes 使用 OCR:
|
||||
|
||||
- 夜间批量验真
|
||||
- 扫描重复票据
|
||||
- 统计发票异常趋势
|
||||
- 回刷历史低置信度票据
|
||||
|
||||
## 8. 安全与审计要求
|
||||
|
||||
### 8.1 访问控制
|
||||
|
||||
- 原始票据预览、下载应按用户角色控制。
|
||||
- 财务、审批人、申请人看到的文件范围可以不同。
|
||||
- 对象存储不要暴露永久公网链接,统一走签名 URL 或后端代理下载。
|
||||
|
||||
### 8.2 敏感信息处理
|
||||
|
||||
- 身份证、银行卡、手机号等敏感字段如被识别,应支持脱敏预览件。
|
||||
- 对外展示尽量用衍生件,不直接暴露原件。
|
||||
|
||||
### 8.3 审计要求
|
||||
|
||||
必须记录:
|
||||
|
||||
- 谁上传了原件
|
||||
- 谁触发了 OCR
|
||||
- 谁查看或下载了原件
|
||||
- 谁修正了 OCR 结果
|
||||
- 谁发起了验真
|
||||
- 哪次风险判断引用了哪些票据
|
||||
|
||||
## 9. 开发阶段建议
|
||||
|
||||
```text
|
||||
Step 1: 附件上传与 document_assets / document_asset_versions 落库
|
||||
Step 2: 本地文件目录方案打通
|
||||
Step 3: 接入 OCR MCP 或 OCR 服务
|
||||
Step 4: 结构化字段归一化
|
||||
Step 5: 发票验真 MCP
|
||||
Step 6: 与 expense_claim_items 匹配
|
||||
Step 7: 风险规则中心接入
|
||||
Step 8: 人工修正界面
|
||||
Step 9: Hermes 夜间批量 OCR 与验真巡检
|
||||
```
|
||||
|
||||
当前阶段优先级:
|
||||
|
||||
- 先把“文件原件可存、可找、可追溯”做实。
|
||||
- 再把 OCR 和验真接进来。
|
||||
- 最后再做大规模自动巡检和脱敏导出。
|
||||
@@ -1,221 +0,0 @@
|
||||
# LLM Wiki 知识库架构
|
||||
|
||||
## 1. 定位
|
||||
|
||||
LLM Wiki 不是简单的文件库。
|
||||
|
||||
它是给 Agent 使用的知识底座,负责把制度、FAQ、审批经验、规则说明转成可检索、可引用、可版本化的知识。
|
||||
|
||||
## 2. 总体链路
|
||||
|
||||
```text
|
||||
文档上传
|
||||
↓
|
||||
格式解析
|
||||
↓
|
||||
正文抽取
|
||||
↓
|
||||
分块 Chunking
|
||||
↓
|
||||
元数据标注
|
||||
↓
|
||||
向量索引
|
||||
↓
|
||||
条款抽取
|
||||
↓
|
||||
知识候选
|
||||
↓
|
||||
人工审核
|
||||
↓
|
||||
发布 Wiki
|
||||
↓
|
||||
Agent 检索引用
|
||||
```
|
||||
|
||||
## 2.1 目录约束
|
||||
|
||||
LLM Wiki 解析产物不能与原始制度文件混放。
|
||||
|
||||
推荐目录:
|
||||
|
||||
```text
|
||||
/app/server/storage/knowledge/<folder>/ 原始知识文件
|
||||
/app/server/storage/knowledge/.llm_wiki/ 解析产物根目录
|
||||
/app/server/storage/knowledge/.llm_wiki/documents/<document_id>/
|
||||
document.json
|
||||
text.md
|
||||
chunks.json
|
||||
clauses.json
|
||||
knowledge_candidates.json
|
||||
rule_candidates.json
|
||||
/app/server/storage/knowledge/.llm_wiki/index.json
|
||||
/app/server/storage/knowledge/.llm_wiki/sync_runs.json
|
||||
```
|
||||
|
||||
约束:
|
||||
|
||||
- 原始文件目录只存原件,不存解析碎片。
|
||||
- LLM Wiki 目录只存结构化产物,不反向覆盖原件。
|
||||
- 所有解析产物必须能按 `document_id` 回溯到原始文件。
|
||||
|
||||
## 3. 知识类型
|
||||
|
||||
```text
|
||||
policy_document
|
||||
faq
|
||||
rule_explanation
|
||||
approval_case
|
||||
risk_case
|
||||
operation_manual
|
||||
system_notice
|
||||
```
|
||||
|
||||
## 4. 知识块结构
|
||||
|
||||
```json
|
||||
{
|
||||
"chunk_id": "",
|
||||
"document_id": "",
|
||||
"title": "",
|
||||
"content": "",
|
||||
"domain": "reimbursement",
|
||||
"scenario": "travel_reimbursement",
|
||||
"tags": ["差旅", "住宿标准"],
|
||||
"effective_date": "",
|
||||
"version": "v1.0",
|
||||
"source_page": 4,
|
||||
"embedding_id": "",
|
||||
"status": "published"
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 条款抽取
|
||||
|
||||
Hermes 可以从制度文档中抽取条款候选。
|
||||
|
||||
示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"clause_type": "amount_limit",
|
||||
"domain": "reimbursement",
|
||||
"scenario": "travel_reimbursement",
|
||||
"condition": {
|
||||
"city_tier": "一线城市",
|
||||
"employee_grade": "P5"
|
||||
},
|
||||
"limit": {
|
||||
"amount": 800,
|
||||
"currency": "CNY",
|
||||
"period": "night"
|
||||
},
|
||||
"source": "差旅制度 2026 第 4 页"
|
||||
}
|
||||
```
|
||||
|
||||
该结果不直接变成规则,先进入规则候选池。
|
||||
|
||||
## 5.1 增量形成策略
|
||||
|
||||
LLM Wiki 不应按天无脑全量重建。
|
||||
|
||||
每个文档都应维护签名:
|
||||
|
||||
```json
|
||||
{
|
||||
"document_id": "",
|
||||
"original_name": "",
|
||||
"stored_name": "",
|
||||
"sha256": "",
|
||||
"version_number": 1,
|
||||
"updated_at": ""
|
||||
}
|
||||
```
|
||||
|
||||
只有在以下任一条件发生时,才重建对应文档的 LLM Wiki:
|
||||
|
||||
- `original_name` 变更。
|
||||
- `stored_name` 变更。
|
||||
- `sha256` 变更。
|
||||
- `version_number` 变更。
|
||||
- `updated_at` 变更,视为人工修改。
|
||||
|
||||
如果以上均未变化:
|
||||
|
||||
- 本次文档状态应记为 `unchanged_skipped`。
|
||||
- 不重新抽取正文。
|
||||
- 不重新分块。
|
||||
- 不重新生成知识候选或规则候选。
|
||||
|
||||
## 6. Wiki 发布流程
|
||||
|
||||
```text
|
||||
草稿知识
|
||||
↓
|
||||
Hermes 生成候选
|
||||
↓
|
||||
知识管理员审核
|
||||
↓
|
||||
发布
|
||||
↓
|
||||
Agent 可检索
|
||||
```
|
||||
|
||||
## 7. 与 User Agent 的关系
|
||||
|
||||
User Agent 用 Wiki:
|
||||
|
||||
- 回答制度问题。
|
||||
- 给风险解释提供条款依据。
|
||||
- 给审批意见生成引用。
|
||||
- 帮用户理解流程。
|
||||
|
||||
## 8. 与 Hermes 的关系
|
||||
|
||||
Hermes 用 Wiki:
|
||||
|
||||
- 每日知识候选生成。
|
||||
- 发现制度与规则不一致。
|
||||
- 生成规则优化建议。
|
||||
- 生成 FAQ 候选。
|
||||
|
||||
补充要求:
|
||||
|
||||
- Hermes 对制度文档的处理默认是增量同步,不是每日全量重建。
|
||||
- Hermes 应先检查知识库签名,再决定是否需要重建某个文档的 Wiki。
|
||||
- Hermes 形成的是候选与草稿,不是正式发布内容。
|
||||
|
||||
## 9. 数据模型建议
|
||||
|
||||
```text
|
||||
knowledge_documents
|
||||
knowledge_chunks
|
||||
knowledge_embeddings
|
||||
knowledge_candidates
|
||||
knowledge_reviews
|
||||
knowledge_versions
|
||||
```
|
||||
|
||||
当前最小落地允许先以文件索引实现:
|
||||
|
||||
```text
|
||||
.llm_wiki/index.json
|
||||
.llm_wiki/sync_runs.json
|
||||
.llm_wiki/documents/<document_id>/document.json
|
||||
```
|
||||
|
||||
后续再平滑迁移到数据库或向量库。
|
||||
|
||||
## 10. 开发阶段建议
|
||||
|
||||
```text
|
||||
Step 1: 文档上传和文件管理
|
||||
Step 2: 文本抽取和分块
|
||||
Step 3: 元数据标注
|
||||
Step 4: 向量索引
|
||||
Step 5: 知识检索 API
|
||||
Step 6: User Agent 问答引用
|
||||
Step 7: Hermes 知识候选生成
|
||||
Step 8: 人工审核发布
|
||||
Step 9: 条款抽取和规则候选
|
||||
```
|
||||
@@ -1,194 +0,0 @@
|
||||
# 规则形成生命周期
|
||||
|
||||
## 1. 定位
|
||||
|
||||
规则不是凭空写出来的。
|
||||
|
||||
它应来自:
|
||||
|
||||
- 制度文档。
|
||||
- 历史审批。
|
||||
- 风险案例。
|
||||
- OCR 识别结果。
|
||||
- MCP 验真结果。
|
||||
- 用户反馈。
|
||||
- Hermes 分析。
|
||||
|
||||
## 2. 总体闭环
|
||||
|
||||
```text
|
||||
制度文档 / 历史审批 / 风险案例 / 用户反馈
|
||||
↓
|
||||
Hermes 分析
|
||||
↓
|
||||
规则候选
|
||||
↓
|
||||
人工审核
|
||||
↓
|
||||
规则 .md
|
||||
↓
|
||||
测试样例
|
||||
↓
|
||||
版本发布
|
||||
↓
|
||||
规则执行
|
||||
↓
|
||||
命中反馈
|
||||
↓
|
||||
规则优化
|
||||
```
|
||||
|
||||
## 3. 规则候选结构
|
||||
|
||||
```json
|
||||
{
|
||||
"candidate_id": "",
|
||||
"source_type": "policy_document",
|
||||
"domain": "reimbursement",
|
||||
"scenario": "invoice_validation",
|
||||
"risk_signal": "duplicate_invoice",
|
||||
"suggested_rule_name": "重复报销识别规则",
|
||||
"rule_markdown_draft": "",
|
||||
"evidence": [],
|
||||
"confidence": 0.86,
|
||||
"created_by": "hermes"
|
||||
}
|
||||
```
|
||||
|
||||
补充约束:
|
||||
|
||||
- `rule_markdown_draft` 不能是任意自由文本,必须符合固定模板。
|
||||
- 规则候选应同时携带机器可读 JSON 草稿,例如 `runtime_rule`。
|
||||
- JSON 草稿只能从受控模板族中选择,不允许 Hermes 自创字段结构后直接进入规则中心。
|
||||
|
||||
## 4. 规则 Markdown 推荐结构
|
||||
|
||||
```markdown
|
||||
# 规则名称
|
||||
|
||||
## 目标
|
||||
|
||||
## 适用范围
|
||||
|
||||
## 输入字段
|
||||
|
||||
## 判断规则
|
||||
|
||||
## 输出
|
||||
|
||||
## 测试样例
|
||||
|
||||
## 管理员备注
|
||||
```
|
||||
|
||||
推荐再补一段模板元信息:
|
||||
|
||||
```markdown
|
||||
## 模板信息
|
||||
|
||||
- 模板键:`travel_standard_v1`
|
||||
- 来源文档:公司支出管理办法(2024)
|
||||
- Hermes 置信度:0.86
|
||||
- 审核人:张三
|
||||
```
|
||||
|
||||
## 4.1 规则 JSON 推荐结构
|
||||
|
||||
规则中心不应只有 Markdown。
|
||||
|
||||
应同时提供可执行 JSON 编辑区,至少支持:
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "policy_rule_draft",
|
||||
"version": 1,
|
||||
"template_key": "travel_standard_v1",
|
||||
"rule_name": "差旅住宿标准草稿规则",
|
||||
"scenario": "travel_reimbursement",
|
||||
"review_required": true,
|
||||
"conditions": {},
|
||||
"actions": {},
|
||||
"source_document_name": "公司支出管理办法(2024)"
|
||||
}
|
||||
```
|
||||
|
||||
治理要求:
|
||||
|
||||
- Markdown 负责给人看。
|
||||
- JSON 负责给运行时和规则引擎看。
|
||||
- 两者必须成对维护,不能只改其中一份。
|
||||
- JSON 变更也必须走版本和审核。
|
||||
|
||||
## 4.2 模板族约束
|
||||
|
||||
Hermes 只能从白名单模板中选,不允许自由生成任意规则结构。
|
||||
|
||||
第一版建议模板:
|
||||
|
||||
```text
|
||||
travel_standard_v1
|
||||
expense_amount_limit_v1
|
||||
attachment_requirement_v1
|
||||
general_policy_v1
|
||||
```
|
||||
|
||||
如果制度条款不适合自动规则化:
|
||||
|
||||
- 允许只生成 `knowledge_candidate`
|
||||
- 或只生成 `general_policy_v1` 草稿并要求人工补齐
|
||||
- 不能为了“有结果”而编造可执行规则
|
||||
|
||||
## 5. 审核要求
|
||||
|
||||
规则上线必须满足:
|
||||
|
||||
- 有审核人。
|
||||
- 有版本。
|
||||
- 有测试样例。
|
||||
- 有来源依据。
|
||||
- 有回滚方案。
|
||||
|
||||
补充:
|
||||
|
||||
- Hermes 生成规则默认只能是 `draft`。
|
||||
- Hermes 不能直接覆盖当前 `active` 线上规则。
|
||||
- Hermes 如发现制度更新,应优先生成新的候选或草稿版本,仍需人工审核后再上线。
|
||||
|
||||
## 6. 规则执行反馈
|
||||
|
||||
每次规则运行应记录:
|
||||
|
||||
```text
|
||||
rule_id
|
||||
rule_version
|
||||
input_snapshot
|
||||
hit_result
|
||||
risk_level
|
||||
operator_feedback
|
||||
false_positive
|
||||
false_negative
|
||||
```
|
||||
|
||||
## 7. 规则优化来源
|
||||
|
||||
```text
|
||||
误报反馈
|
||||
漏报反馈
|
||||
审批人修改意见
|
||||
Hermes 每日复盘
|
||||
制度文档更新
|
||||
MCP 新字段可用
|
||||
```
|
||||
|
||||
## 8. 开发阶段建议
|
||||
|
||||
```text
|
||||
Step 1: 规则 .md 编辑和版本
|
||||
Step 2: 规则审核上线
|
||||
Step 3: 规则运行日志
|
||||
Step 4: 人工反馈误报/漏报
|
||||
Step 5: Hermes 生成规则候选
|
||||
Step 6: 规则候选审核
|
||||
Step 7: 规则测试样例管理
|
||||
Step 8: 规则质量看板
|
||||
```
|
||||
@@ -1,646 +0,0 @@
|
||||
# 财务单据标准模型
|
||||
|
||||
## 1. 为什么需要标准模型
|
||||
|
||||
OCR、MCP、用户填写、业务数据库可能都描述同一张发票,但字段名和格式不同。
|
||||
|
||||
如果没有标准模型:
|
||||
|
||||
- 规则无法复用。
|
||||
- Agent 难以解释。
|
||||
- Hermes 难以批量统计。
|
||||
- MCP 返回结果难以合并。
|
||||
|
||||
这里要区分三层:
|
||||
|
||||
- 标准模型:定义 Agent、规则、MCP、OCR、数据库之间统一交换的数据结构。
|
||||
- 业务数据库表:定义 MVP 阶段真正落库存储、查询和统计所依赖的业务表。
|
||||
- 文件存储对象:定义原始票据、预览件、OCR 中间产物、验真结果附件的存储位置与版本规则。
|
||||
|
||||
如果只有标准模型,没有业务表和文件资产表,User Agent 无法真正发起报销;如果只有数据库表,没有统一标准模型,语义解析、规则解释、OCR 回填和 Hermes 巡检会越来越混乱。
|
||||
|
||||
## 2. 标准对象
|
||||
|
||||
第一版建议定义这些对象:
|
||||
|
||||
```text
|
||||
Invoice
|
||||
Receipt
|
||||
ExpenseClaim
|
||||
PaymentRequest
|
||||
AccountsReceivableRecord
|
||||
AccountsPayableRecord
|
||||
BankTransaction
|
||||
Contract
|
||||
Customer
|
||||
Vendor
|
||||
Employee
|
||||
CostCenter
|
||||
DocumentAsset
|
||||
RiskEvent
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- 对外语义层建议统一使用 `ExpenseClaim` 概念,不再把“报销申请”和“报销单据”拆成两个平行主概念。
|
||||
- 现有代码中仍有 `reimbursement_requests` 表,MVP 阶段不建议再继续扩张该表,而应以 `expense_claims` 作为报销主表。
|
||||
- `reimbursement_requests` 可保留用于兼容旧页面或审批联动,但新能力默认挂到 `expense_claims`。
|
||||
|
||||
## 3. Invoice 标准模型
|
||||
|
||||
```json
|
||||
{
|
||||
"invoice_id": "",
|
||||
"invoice_code": "",
|
||||
"invoice_number": "",
|
||||
"invoice_type": "",
|
||||
"seller_name": "",
|
||||
"seller_tax_no": "",
|
||||
"buyer_name": "",
|
||||
"buyer_tax_no": "",
|
||||
"issue_date": "",
|
||||
"total_amount": 0,
|
||||
"tax_amount": 0,
|
||||
"currency": "CNY",
|
||||
"verify_status": "",
|
||||
"ocr_confidence": 0,
|
||||
"source_document_id": ""
|
||||
}
|
||||
```
|
||||
|
||||
## 4. ExpenseClaim 标准模型
|
||||
|
||||
```json
|
||||
{
|
||||
"claim_id": "",
|
||||
"claim_no": "",
|
||||
"employee_id": "",
|
||||
"employee_name": "",
|
||||
"department_id": "",
|
||||
"department_name": "",
|
||||
"cost_center_code": "",
|
||||
"project_code": "",
|
||||
"expense_type": "",
|
||||
"reason": "",
|
||||
"location": "",
|
||||
"amount": 0,
|
||||
"currency": "CNY",
|
||||
"status": "",
|
||||
"occurred_at": "",
|
||||
"submitted_at": "",
|
||||
"approval_stage": "",
|
||||
"items": [],
|
||||
"attachments": [],
|
||||
"risk_flags": []
|
||||
}
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `reason`、`location`、`occurred_at` 是报销语义判断、规则解释、风险识别的最小必要字段。
|
||||
- 一张报销单通常包含多条费用明细,标准模型中允许聚合,数据库层必须拆到明细表。
|
||||
- `attachments` 指向文件资产,不直接嵌入二进制文件。
|
||||
|
||||
## 5. AccountsReceivableRecord 标准模型
|
||||
|
||||
```json
|
||||
{
|
||||
"ar_id": "",
|
||||
"document_no": "",
|
||||
"customer_id": "",
|
||||
"customer_name": "",
|
||||
"contract_no": "",
|
||||
"invoice_no": "",
|
||||
"amount_receivable": 0,
|
||||
"amount_received": 0,
|
||||
"amount_outstanding": 0,
|
||||
"currency": "CNY",
|
||||
"due_date": "",
|
||||
"posting_date": "",
|
||||
"status": "",
|
||||
"aging_days": 0,
|
||||
"risk_flags": []
|
||||
}
|
||||
```
|
||||
|
||||
## 6. AccountsPayableRecord 标准模型
|
||||
|
||||
```json
|
||||
{
|
||||
"ap_id": "",
|
||||
"document_no": "",
|
||||
"vendor_id": "",
|
||||
"vendor_name": "",
|
||||
"invoice_no": "",
|
||||
"amount_payable": 0,
|
||||
"amount_paid": 0,
|
||||
"amount_outstanding": 0,
|
||||
"currency": "CNY",
|
||||
"due_date": "",
|
||||
"posting_date": "",
|
||||
"status": "",
|
||||
"aging_days": 0,
|
||||
"risk_flags": []
|
||||
}
|
||||
```
|
||||
|
||||
## 7. BankTransaction 标准模型
|
||||
|
||||
```json
|
||||
{
|
||||
"transaction_id": "",
|
||||
"bank_account": "",
|
||||
"transaction_date": "",
|
||||
"amount": 0,
|
||||
"currency": "CNY",
|
||||
"counterparty_name": "",
|
||||
"summary": "",
|
||||
"matched_object_type": "",
|
||||
"matched_object_id": "",
|
||||
"match_status": ""
|
||||
}
|
||||
```
|
||||
|
||||
## 8. MVP 真实业务表设计
|
||||
|
||||
标准模型不等于数据库表,但 MVP 至少要有以下真实表,才能支撑 Day 5 用户报销对话、Day 6 风险巡检和后续审批/验真闭环。
|
||||
|
||||
### 8.1 设计原则
|
||||
|
||||
- 报销主数据统一落在 `expense_claims`,不再新建第三套“报销主表”。
|
||||
- 原始票据文件二进制不进数据库,只存元数据和关联信息。
|
||||
- OCR 结果、发票结构化结果、验真结果、风险事件要分表存,避免把所有字段塞进一个 JSON。
|
||||
- 所有表都要能被 Agent 解释,也要能被 Hermes 批量扫表。
|
||||
- `reimbursement_requests` 进入兼容态,不作为新能力主干表继续扩展。
|
||||
|
||||
### 8.2 报销主表 `expense_claims`
|
||||
|
||||
用途:
|
||||
|
||||
- 作为用户报销会话最终落单的主业务对象。
|
||||
- 承接语义层补槽后的草稿、提交、审批、打回、归档状态。
|
||||
|
||||
建议字段:
|
||||
|
||||
```text
|
||||
id string(36) PK
|
||||
claim_no string(50) UK, 报销单号
|
||||
source string(30) 来源: agent/web/import/api
|
||||
title string(200) 报销标题
|
||||
employee_id string(64) 申请人 ID
|
||||
employee_name string(100) 申请人姓名
|
||||
department_id string(64) 部门 ID
|
||||
department_name string(100) 部门名
|
||||
company_code string(50) 公司编码
|
||||
cost_center_code string(50) 成本中心
|
||||
project_code string(50) 项目编码
|
||||
expense_type string(50) 费用大类
|
||||
reason text 事由
|
||||
location string(100) 地点
|
||||
amount numeric(12,2) 报销总金额
|
||||
currency string(10) 币种
|
||||
invoice_count int 附件票据数
|
||||
attachment_count int 附件总数
|
||||
occurred_start_at timestamptz 发生开始时间
|
||||
occurred_end_at timestamptz 发生结束时间
|
||||
submitted_at timestamptz 提交时间
|
||||
status string(30) draft/submitted/approved/rejected/paid
|
||||
status_changed_at timestamptz 最近状态变更时间
|
||||
status_changed_by string(64) 最近状态变更人
|
||||
status_change_note text 状态变更备注
|
||||
approval_stage string(50) 当前审批节点
|
||||
risk_level string(20) none/low/medium/high
|
||||
risk_flags_json json 风险标记快照
|
||||
conversation_id string(64) 对话会话 ID
|
||||
created_by string(64) 创建人
|
||||
updated_by string(64) 更新人
|
||||
created_at timestamptz
|
||||
updated_at timestamptz
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- 现有模型已有一部分字段,后续只做增量扩展即可。
|
||||
- `occurred_start_at`、`occurred_end_at` 比单一 `occurred_at` 更适合差旅、接待等跨时段报销。
|
||||
|
||||
### 8.2.1 报销状态流转建议
|
||||
|
||||
建议状态:
|
||||
|
||||
```text
|
||||
draft
|
||||
submitted
|
||||
approved
|
||||
rejected
|
||||
paid
|
||||
```
|
||||
|
||||
建议流转:
|
||||
|
||||
```text
|
||||
语义补槽完成
|
||||
-> 创建 expense_claims 草稿
|
||||
-> status = draft
|
||||
|
||||
用户继续补充字段 / 上传附件
|
||||
-> 更新 expense_claims / expense_claim_items / expense_item_documents
|
||||
-> status 仍为 draft
|
||||
|
||||
用户明确确认提交
|
||||
-> status = submitted
|
||||
-> 写入 submitted_at / status_changed_at / status_changed_by
|
||||
|
||||
审批流结果回写
|
||||
-> status = approved 或 rejected
|
||||
|
||||
付款完成回写
|
||||
-> status = paid
|
||||
```
|
||||
|
||||
边界:
|
||||
|
||||
- User Agent 可以创建 `draft`,也可以在用户确认后提交到 `submitted`。
|
||||
- User Agent 不应直接把状态改为 `approved`、`rejected`、`paid`。
|
||||
- 所有状态变化都应写审计日志,必要时保留 `status_change_note`。
|
||||
|
||||
### 8.3 报销明细表 `expense_claim_items`
|
||||
|
||||
用途:
|
||||
|
||||
- 表达一单多明细。
|
||||
- 作为 OCR 发票比对、重复报销识别、风险定位的最小粒度。
|
||||
|
||||
建议字段:
|
||||
|
||||
```text
|
||||
id string(36) PK
|
||||
claim_id string(36) FK -> expense_claims.id
|
||||
line_no int 明细序号
|
||||
item_date date 费用发生日期
|
||||
item_type string(50) 费用小类
|
||||
item_reason text 明细事由
|
||||
item_location string(100) 明细地点
|
||||
merchant_name string(200) 商户/酒店/餐厅
|
||||
customer_name string(200) 客户单位
|
||||
participants_json json 参与人员
|
||||
transport_type string(50) 交通方式
|
||||
item_amount numeric(12,2) 明细金额
|
||||
tax_amount numeric(12,2) 税额
|
||||
currency string(10)
|
||||
invoice_match_status string(30) unmatched/partial/matched
|
||||
risk_level string(20)
|
||||
risk_flags_json json
|
||||
remark text
|
||||
created_at timestamptz
|
||||
updated_at timestamptz
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- 现有 `invoice_id` 单字段不足以覆盖多张附件挂同一明细的情况,后续应改为关联表。
|
||||
|
||||
### 8.4 票据资产主表 `document_assets`
|
||||
|
||||
用途:
|
||||
|
||||
- 作为所有原始附件的主索引表。
|
||||
- 支持报销单、报销明细、审批、验真、风控证据等多对象挂载。
|
||||
|
||||
建议字段:
|
||||
|
||||
```text
|
||||
id string(36) PK
|
||||
biz_domain string(30) expense/ap/ar/common
|
||||
biz_object_type string(50) expense_claim/expense_item/approval_record
|
||||
biz_object_id string(36) 业务对象 ID
|
||||
document_type string(50) invoice/receipt/itinerary/contract/other
|
||||
document_subtype string(50) vat_special/taxi/train/hotel/meal 等
|
||||
source string(30) upload/agent/import/system
|
||||
original_filename string(255)
|
||||
mime_type string(100)
|
||||
file_ext string(20)
|
||||
page_count int
|
||||
file_size_bytes bigint
|
||||
sha256 string(64) 去重与追溯
|
||||
storage_provider string(30) local/minio/s3/oss/cos
|
||||
storage_bucket string(100) 本地模式可为空
|
||||
storage_key string(500) 指向当前有效版本原件
|
||||
current_version_no int
|
||||
classification_status string(30) pending/success/failed
|
||||
ocr_status string(30) pending/running/success/failed
|
||||
virus_scan_status string(30) pending/clean/infected
|
||||
retention_policy string(30) finance_default/legal_hold/manual
|
||||
uploaded_by string(64)
|
||||
uploaded_at timestamptz
|
||||
created_at timestamptz
|
||||
updated_at timestamptz
|
||||
```
|
||||
|
||||
### 8.5 票据版本表 `document_asset_versions`
|
||||
|
||||
用途:
|
||||
|
||||
- 保留原始文件和后续重新上传版本。
|
||||
- 允许“修正”但不允许覆盖原始证据。
|
||||
|
||||
建议字段:
|
||||
|
||||
```text
|
||||
id string(36) PK
|
||||
document_id string(36) FK -> document_assets.id
|
||||
version_no int 1,2,3...
|
||||
is_current bool
|
||||
change_reason string(100) replace/rotate/desensitize/reupload
|
||||
original_filename string(255)
|
||||
mime_type string(100)
|
||||
file_size_bytes bigint
|
||||
sha256 string(64)
|
||||
storage_provider string(30)
|
||||
storage_bucket string(100)
|
||||
storage_key string(500)
|
||||
uploaded_by string(64)
|
||||
uploaded_at timestamptz
|
||||
created_at timestamptz
|
||||
```
|
||||
|
||||
### 8.6 衍生文件表 `document_derivatives`
|
||||
|
||||
用途:
|
||||
|
||||
- 存储缩略图、预览 PDF、逐页图片、脱敏件等衍生产物。
|
||||
|
||||
建议字段:
|
||||
|
||||
```text
|
||||
id string(36) PK
|
||||
document_version_id string(36) FK -> document_asset_versions.id
|
||||
derivative_type string(50) thumb/preview/page_image/desensitized
|
||||
page_no int 可空
|
||||
mime_type string(100)
|
||||
file_size_bytes bigint
|
||||
storage_provider string(30)
|
||||
storage_bucket string(100)
|
||||
storage_key string(500)
|
||||
created_by string(64)
|
||||
created_at timestamptz
|
||||
```
|
||||
|
||||
### 8.7 OCR 结果表 `document_ocr_results`
|
||||
|
||||
用途:
|
||||
|
||||
- 保留每次 OCR 原始结果、模型版本、置信度和错误信息。
|
||||
- 支持后续重跑 OCR 与人工纠错对比。
|
||||
|
||||
建议字段:
|
||||
|
||||
```text
|
||||
id string(36) PK
|
||||
document_id string(36) FK -> document_assets.id
|
||||
document_version_id string(36) FK -> document_asset_versions.id
|
||||
ocr_engine string(50) paddle/aliyun/tencent/openai 等
|
||||
ocr_model string(100)
|
||||
run_no int 第几次 OCR
|
||||
status string(30) success/failed/partial
|
||||
language string(20)
|
||||
raw_text text
|
||||
raw_result_json json
|
||||
structured_result_json json
|
||||
confidence numeric(5,4)
|
||||
error_message text
|
||||
started_at timestamptz
|
||||
finished_at timestamptz
|
||||
created_at timestamptz
|
||||
```
|
||||
|
||||
### 8.8 发票结构化表 `invoice_structured_records`
|
||||
|
||||
用途:
|
||||
|
||||
- 将发票核心字段标准化后独立存储,便于查重、验真、规则计算。
|
||||
|
||||
建议字段:
|
||||
|
||||
```text
|
||||
id string(36) PK
|
||||
document_id string(36) FK -> document_assets.id
|
||||
ocr_result_id string(36) FK -> document_ocr_results.id
|
||||
invoice_code string(50)
|
||||
invoice_number string(50)
|
||||
invoice_type string(50)
|
||||
seller_name string(200)
|
||||
seller_tax_no string(50)
|
||||
buyer_name string(200)
|
||||
buyer_tax_no string(50)
|
||||
issue_date date
|
||||
total_amount numeric(12,2)
|
||||
tax_amount numeric(12,2)
|
||||
currency string(10)
|
||||
check_code string(100)
|
||||
is_red_invoice bool
|
||||
is_electronic bool
|
||||
ocr_confidence numeric(5,4)
|
||||
normalized_status string(30) normalized/manual_corrected
|
||||
duplicate_fingerprint string(100) 发票号+代码+金额+日期
|
||||
created_at timestamptz
|
||||
updated_at timestamptz
|
||||
```
|
||||
|
||||
### 8.9 发票验真记录表 `invoice_verification_records`
|
||||
|
||||
用途:
|
||||
|
||||
- 保留每次调用税局/第三方验真服务的结果,支持追溯。
|
||||
|
||||
建议字段:
|
||||
|
||||
```text
|
||||
id string(36) PK
|
||||
invoice_record_id string(36) FK -> invoice_structured_records.id
|
||||
verification_channel string(50) tax_mcp/third_party/manual
|
||||
request_payload_json json
|
||||
response_payload_json json
|
||||
verify_status string(30) verified/unverified/voided/error
|
||||
voided bool
|
||||
red_reversed bool
|
||||
verified_amount numeric(12,2)
|
||||
verified_issue_date date
|
||||
error_code string(50)
|
||||
error_message text
|
||||
verified_by string(64)
|
||||
verified_at timestamptz
|
||||
created_at timestamptz
|
||||
```
|
||||
|
||||
### 8.10 明细与票据关联表 `expense_item_documents`
|
||||
|
||||
用途:
|
||||
|
||||
- 解决一条明细可关联多张票据、一张票据也可能支撑多条拆分明细的场景。
|
||||
|
||||
建议字段:
|
||||
|
||||
```text
|
||||
id string(36) PK
|
||||
claim_id string(36) FK -> expense_claims.id
|
||||
claim_item_id string(36) FK -> expense_claim_items.id
|
||||
document_id string(36) FK -> document_assets.id
|
||||
relation_type string(30) evidence/invoice/boarding_pass/receipt
|
||||
allocated_amount numeric(12,2) 分摊到该明细的金额
|
||||
match_status string(30) unmatched/partial/matched
|
||||
match_confidence numeric(5,4)
|
||||
created_at timestamptz
|
||||
updated_at timestamptz
|
||||
```
|
||||
|
||||
### 8.11 风险事件表 `risk_events`
|
||||
|
||||
用途:
|
||||
|
||||
- 记录风险命中,而不是只在主表里塞一个 `risk_flags_json`。
|
||||
- 作为 Agent 解释“为什么拦截”的核心依据。
|
||||
|
||||
建议字段:
|
||||
|
||||
```text
|
||||
id string(36) PK
|
||||
biz_domain string(30) expense/ap/ar
|
||||
biz_object_type string(50) expense_claim/expense_item/invoice
|
||||
biz_object_id string(36)
|
||||
risk_code string(50) duplicate_invoice/amount_mismatch 等
|
||||
risk_name string(100)
|
||||
risk_level string(20) low/medium/high
|
||||
hit_source string(30) rule/agent/hermes/manual
|
||||
evidence_json json
|
||||
status string(30) open/confirmed/resolved/ignored
|
||||
detected_at timestamptz
|
||||
detected_by string(64)
|
||||
resolved_at timestamptz
|
||||
resolved_by string(64)
|
||||
resolution_note text
|
||||
created_at timestamptz
|
||||
updated_at timestamptz
|
||||
```
|
||||
|
||||
### 8.12 风险处置表 `risk_actions`
|
||||
|
||||
用途:
|
||||
|
||||
- 记录每次人工确认、驳回、忽略、要求补件等处置动作。
|
||||
|
||||
建议字段:
|
||||
|
||||
```text
|
||||
id string(36) PK
|
||||
risk_event_id string(36) FK -> risk_events.id
|
||||
action_type string(30) confirm/reject/ignore/request_more
|
||||
action_note text
|
||||
operator_id string(64)
|
||||
operator_name string(100)
|
||||
created_at timestamptz
|
||||
```
|
||||
|
||||
### 8.13 文件访问审计表 `document_access_logs`
|
||||
|
||||
用途:
|
||||
|
||||
- 记录谁看过、下载过、导出过原始票据。
|
||||
- 支撑财务审计和数据安全追溯。
|
||||
|
||||
建议字段:
|
||||
|
||||
```text
|
||||
id string(36) PK
|
||||
document_id string(36) FK -> document_assets.id
|
||||
document_version_id string(36) FK -> document_asset_versions.id
|
||||
action string(30) preview/download/export/delete
|
||||
operator_id string(64)
|
||||
operator_name string(100)
|
||||
operator_role string(50)
|
||||
client_ip string(64)
|
||||
user_agent string(255)
|
||||
trace_id string(64)
|
||||
created_at timestamptz
|
||||
```
|
||||
|
||||
## 9. 表关系建议
|
||||
|
||||
```text
|
||||
expense_claims
|
||||
└─ expense_claim_items
|
||||
└─ expense_item_documents
|
||||
└─ document_assets
|
||||
└─ document_asset_versions
|
||||
└─ document_derivatives
|
||||
└─ document_ocr_results
|
||||
└─ invoice_structured_records
|
||||
└─ invoice_verification_records
|
||||
|
||||
risk_events -> 可指向 expense_claims / expense_claim_items / invoice_structured_records
|
||||
risk_actions -> risk_events
|
||||
document_access_logs -> document_assets / document_asset_versions
|
||||
```
|
||||
|
||||
原则:
|
||||
|
||||
- 主业务对象和文件资产解耦。
|
||||
- OCR、验真、风险都挂在文件资产或业务对象之上,不把责任塞到一个巨表。
|
||||
- 文件版本和业务关系分离,避免替换附件时把历史证据冲掉。
|
||||
|
||||
## 10. 与现有表的衔接策略
|
||||
|
||||
当前代码中已经存在:
|
||||
|
||||
- `expense_claims`
|
||||
- `expense_claim_items`
|
||||
- `reimbursement_requests`
|
||||
|
||||
建议策略:
|
||||
|
||||
- `expense_claims` 继续作为未来报销主表。
|
||||
- `expense_claim_items` 增量扩字段并替换当前单一 `invoice_id` 直连方式。
|
||||
- `reimbursement_requests` 暂不删除,但冻结扩表。
|
||||
- 如旧流程仍引用 `reimbursement_requests`,可在过渡期建立:
|
||||
- `request_no -> claim_no` 对照字段
|
||||
- 或由 `approval_records` 同时支持两类来源对象
|
||||
|
||||
不建议做法:
|
||||
|
||||
- 再新建第四张“报销申请主表”。
|
||||
- 把原始发票图片以 blob 方式存进 `expense_claims`。
|
||||
- 把 OCR、验真、风控结果全塞进一个 JSON 大字段。
|
||||
|
||||
## 11. 实施顺序建议
|
||||
|
||||
Phase 1:
|
||||
|
||||
- 扩展 `expense_claims`
|
||||
- 扩展 `expense_claim_items`
|
||||
- 新增 `document_assets`
|
||||
- 新增 `document_asset_versions`
|
||||
- 新增 `expense_item_documents`
|
||||
|
||||
Phase 2:
|
||||
|
||||
- 新增 `document_ocr_results`
|
||||
- 新增 `invoice_structured_records`
|
||||
- 新增 `invoice_verification_records`
|
||||
- 新增 `document_derivatives`
|
||||
|
||||
Phase 3:
|
||||
|
||||
- 新增 `risk_events`
|
||||
- 新增 `risk_actions`
|
||||
- 新增 `document_access_logs`
|
||||
|
||||
Phase 4:
|
||||
|
||||
- 逐步弱化 `reimbursement_requests`
|
||||
- 将 Agent 草稿、审批、OCR、验真、风控全收敛到 `expense_claims` 体系
|
||||
|
||||
## 12. 对 Agent 的直接收益
|
||||
|
||||
- 用户说“我要报销”时,Agent 能先创建 `expense_claims` 草稿,再持续补槽。
|
||||
- 用户上传票据后,系统有明确的 `document_assets` 与 `expense_item_documents` 可挂载。
|
||||
- OCR 和验真结果不是一次性临时输出,而是可追溯、可回放、可审计的长期资产。
|
||||
- Agent 回答“为什么被拦截”时,可以直接引用 `risk_events` 和票据证据,不再靠拼字符串解释。
|
||||
@@ -1,119 +0,0 @@
|
||||
# 反馈闭环与持续学习
|
||||
|
||||
## 1. 定位
|
||||
|
||||
Agent 系统必须能从人工反馈中持续变好。
|
||||
|
||||
反馈来源:
|
||||
|
||||
- OCR 人工修正。
|
||||
- 规则误报/漏报。
|
||||
- 审批人修改意见。
|
||||
- 用户对回答的反馈。
|
||||
- Hermes 风险复盘。
|
||||
- MCP 调用失败和降级。
|
||||
|
||||
## 2. 反馈类型
|
||||
|
||||
```text
|
||||
ocr_correction
|
||||
rule_false_positive
|
||||
rule_false_negative
|
||||
agent_answer_feedback
|
||||
approval_opinion_edit
|
||||
knowledge_answer_feedback
|
||||
mcp_failure_feedback
|
||||
task_result_feedback
|
||||
```
|
||||
|
||||
## 3. 反馈结构
|
||||
|
||||
```json
|
||||
{
|
||||
"feedback_id": "",
|
||||
"feedback_type": "rule_false_positive",
|
||||
"source_object_type": "rule_run",
|
||||
"source_object_id": "",
|
||||
"before": {},
|
||||
"after": {},
|
||||
"comment": "",
|
||||
"created_by": "",
|
||||
"created_at": ""
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 反馈流向
|
||||
|
||||
```text
|
||||
人工反馈
|
||||
↓
|
||||
反馈池
|
||||
↓
|
||||
Hermes 聚类分析
|
||||
↓
|
||||
候选改进项
|
||||
↓
|
||||
人工审核
|
||||
↓
|
||||
更新规则 / 知识 / OCR 映射 / Prompt
|
||||
```
|
||||
|
||||
## 5. 反馈不直接自动生效
|
||||
|
||||
反馈只能生成候选,不直接修改线上规则。
|
||||
|
||||
必须人工审核:
|
||||
|
||||
- 规则修改。
|
||||
- 知识发布。
|
||||
- Prompt 修改。
|
||||
- OCR 字段映射调整。
|
||||
|
||||
## 6. Hermes 每日反馈复盘
|
||||
|
||||
Hermes 每日任务:
|
||||
|
||||
```text
|
||||
读取昨日反馈
|
||||
聚类相似问题
|
||||
统计误报高发规则
|
||||
统计低评分回答
|
||||
生成优化候选
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
```text
|
||||
rule_improvement_candidates
|
||||
knowledge_update_candidates
|
||||
ocr_mapping_candidates
|
||||
prompt_improvement_notes
|
||||
```
|
||||
|
||||
## 7. 质量指标
|
||||
|
||||
建议监控:
|
||||
|
||||
```text
|
||||
ocr_correction_rate
|
||||
rule_false_positive_rate
|
||||
rule_false_negative_rate
|
||||
agent_answer_like_rate
|
||||
agent_answer_rewrite_rate
|
||||
knowledge_no_hit_rate
|
||||
mcp_failure_rate
|
||||
```
|
||||
|
||||
## 8. 开发阶段建议
|
||||
|
||||
```text
|
||||
Step 1: 增加反馈按钮和反馈表
|
||||
Step 2: OCR 修正写入反馈池
|
||||
Step 3: 规则误报/漏报反馈
|
||||
Step 4: Agent 回答反馈
|
||||
Step 5: Hermes 每日反馈聚类
|
||||
Step 6: 生成优化候选
|
||||
Step 7: 人工审核发布
|
||||
Step 8: 建立质量看板
|
||||
```
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
# Agent Week Plan 一周开发路线图
|
||||
|
||||
本目录现在同时承接:
|
||||
|
||||
- 一周路线图
|
||||
- 每天 daily 文档
|
||||
- 每天的详细执行清单
|
||||
|
||||
原独立执行细则目录已合并进各 Day 文档,不再单独维护。
|
||||
|
||||
## 文档分工
|
||||
|
||||
| 目录 | 职责 | 读者 |
|
||||
| --- | --- | --- |
|
||||
| `agent week plan` | 一周节奏、每天目标、验收门槛、详细执行清单、阻塞记录、日终交接 | 产品、架构、Codex、开发、验收 |
|
||||
| `agent plan` | 架构设计、协议、流程、治理、标准模型、能力边界 | 架构、开发、评审 |
|
||||
|
||||
## 使用方式
|
||||
|
||||
1. 先读 [MASTER_TODO.md](./MASTER_TODO.md),确认 7 天节奏和当前状态。
|
||||
2. 打开当天 daily 文档。
|
||||
3. 在同一份 daily 文档里按顺序阅读:
|
||||
今天的大开发点 -> 当前完成情况 -> 当天验收门槛 -> 详细执行清单 -> 阻塞记录 -> 日终交接。
|
||||
4. 如需设计依据,再跳到 `agent plan` 对应架构文档。
|
||||
5. 完成一个最小项后,再把该项改成完成态,而不是代码写完就直接算过。
|
||||
|
||||
## 完成标记规则
|
||||
|
||||
未完成:
|
||||
|
||||
```md
|
||||
- [ ] 建立 AgentAsset 数据模型
|
||||
```
|
||||
|
||||
完成后:
|
||||
|
||||
```md
|
||||
- [x] ~~建立 AgentAsset 数据模型~~
|
||||
```
|
||||
|
||||
执行要求:
|
||||
|
||||
- [ ] 每次只处理一个最小 TODO。
|
||||
- [ ] 完成后先自测,再改成 `[x]`。
|
||||
- [ ] 改成 `[x]` 时,同时用 `~~` 画线。
|
||||
- [ ] 不能因为代码写完就标完成,必须满足该 TODO 的验收证据。
|
||||
- [ ] 遇到阻塞时,在当天文档的“阻塞记录”下新增说明。
|
||||
- [ ] 每天收尾时更新当天文档的“日终交接”。
|
||||
|
||||
## 一周总体目标
|
||||
|
||||
- Day 1:先把资产、版本、审核、运行日志、审计日志等基础地基建好。
|
||||
- Day 2:把任务规则中心和后端资产体系打通。
|
||||
- Day 3:建立语义本体 MVP,让用户问题能变成稳定结构。
|
||||
- Day 4:建立 Orchestrator,让请求能被统一路由、审计、降级。
|
||||
- Day 5:建立 User Agent MVP,处理用户查询、解释和草稿生成。
|
||||
- Day 6:建立 Hermes MVP,处理定时巡检、统计、知识和规则草稿。
|
||||
- Day 7:做加固、测试、演示、验收和下一阶段交接。
|
||||
|
||||
## 一周暂不完成
|
||||
|
||||
- 完整 OCR 生产识别引擎。
|
||||
- 完整发票验真 MCP 深度接入。
|
||||
- 完整 LLM Wiki 向量检索。
|
||||
- 全量财务域数据打通。
|
||||
- 规则自动上线。
|
||||
- 完整 CI/CD 质量门禁。
|
||||
|
||||
## 生产底线
|
||||
|
||||
- 所有写操作必须有审计日志。
|
||||
- 所有 Agent 执行必须生成 `run_id`。
|
||||
- 所有规则必须有版本。
|
||||
- 未审核规则不能上线。
|
||||
- 高风险动作只能生成草稿或建议,不能自动提交。
|
||||
- 外部能力失败必须有降级结果。
|
||||
- 语义解析结果必须可回放。
|
||||
@@ -1,73 +0,0 @@
|
||||
# Agent Week Plan 总控
|
||||
|
||||
本文件是本周总览和执行索引。
|
||||
|
||||
每个 Day 文档现在同时包含:
|
||||
|
||||
- 路线图
|
||||
- 当前完成情况
|
||||
- 验收门槛
|
||||
- 详细执行清单
|
||||
|
||||
不再跳转独立执行细则目录。
|
||||
|
||||
## 快速浏览
|
||||
|
||||
- HTML 总览:[agent_week_plan_html/index.html](<../agent_week_plan_html/index.html>)
|
||||
- Day 1 HTML:[agent_week_plan_html/day-1.html](<../agent_week_plan_html/day-1.html>)
|
||||
|
||||
## 执行方式
|
||||
|
||||
1. 先看本文件,确认今天做哪一天、当前状态和依赖顺序。
|
||||
2. 再打开当天 daily 文档,直接在同一份文档里推进开发。
|
||||
3. 完成一个最小 TODO 后,再改成 `[x] ~~...~~`。
|
||||
4. 每天结束时回填阻塞记录、验收结果和日终交接。
|
||||
|
||||
## 一周节奏
|
||||
|
||||
| Day | 状态 | 主题 | 主要交付 | Markdown | HTML |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| Day 1 | 已完成(2026-05-11) | 基础模型与工程骨架 | 资产、版本、审核、运行日志、审计日志、基础 API、最小财务数据源 | [Day 1](./day_1_foundation_models.md) | [HTML](<../agent_week_plan_html/day-1.html>) |
|
||||
| Day 2 | 已完成,待补浏览器走查记录 | 任务规则中心联调 | 规则/技能/MCP/任务列表与详情、Markdown、版本、审核 | [Day 2](./day_2_rule_center_integration.md) | [HTML](<../agent_week_plan_html/day-2.html>) |
|
||||
| Day 3 | 已完成主体功能,待补评测样本扩充 | 语义本体 MVP | 8 字段语义解析、日志、评测入口、OCR 摘要与最小会话上下文带入 | [Day 3](./day_3_semantic_ontology_mvp.md) | [HTML](<../agent_week_plan_html/day-3.html>) |
|
||||
| Day 4 | 已完成主干与会话串联,待接通提交/附件持久化链路 | Orchestrator 运行时 | 统一入口、路由、权限、工具调用、报销单写入路由、会话 Trace | [Day 4](./day_4_orchestrator_runtime.md) | [HTML](<../agent_week_plan_html/day-4.html>) |
|
||||
| Day 5 | 已完成问答主链路、草稿创建/补全与会话上下文,待接通提交状态流转 | User Agent MVP | 用户问答、报销单草稿创建/补全/提交、财务查询、规则解释、附件/OCR 带入 | [Day 5](./day_5_user_agent_mvp.md) | [HTML](<../agent_week_plan_html/day-5.html>) |
|
||||
| Day 6 | 未开始 | Hermes MVP | 定时任务、风险巡检、日报、知识候选、规则草稿 | [Day 6](./day_6_hermes_mvp.md) | [HTML](<../agent_week_plan_html/day-6.html>) |
|
||||
| Day 7 | 未开始 | 加固、演示和验收 | 回归、测试、演示脚本、交付说明 | [Day 7](./day_7_hardening_demo_acceptance.md) | [HTML](<../agent_week_plan_html/day-7.html>) |
|
||||
|
||||
## 当前完成情况
|
||||
|
||||
- Day 1 已完成,后端基础模型、审计和最小财务数据源已可供后续能力复用。
|
||||
- Day 2 已完成主要前后端联调,当前仅剩浏览器人工走查记录待补。
|
||||
- Day 3 主体已完成,`/api/v1/ontology/parse`、8 字段返回、缺槽位追问、权限判断和前端调试入口均已落地;OCR 摘要、附件上下文和最小会话历史已进入语义层,前端浏览器时间上下文也已接入相对时间换算,当前主要剩叙述型报销、附件/OCR 带入样本和模糊追问样本继续扩充。
|
||||
- Day 4 主干已完成,Orchestrator 已具备统一入口、User Agent / Hermes 路由、权限阻断、ToolCall 记录、Trace、降级和 `conversation_id` 会话串联;`expense_claims` 草稿建单/改单与 ToolCall / Audit 已接通,但提交、附件持久化和更细的 ToolCall Trace 仍未接通。
|
||||
- Day 5 问答主链路已完成,个人工作台和报销对话框已能把文本、附件名称、OCR 摘要、页面上下文和会话 ID 带入 Orchestrator,并返回回答、规则引用、风险说明、结构化草稿和识别核对面板;核对 UI 已调整为“右侧只看识别结果、主对话负责待补与风险、底部负责动作”,但附件 / OCR 结果落库及 `draft -> submitted` 仍未完成。
|
||||
|
||||
## Day 1 - Day 5 未完成补齐清单
|
||||
|
||||
- Day 1:当前周计划范围内无新增遗留项,基础资产、日志、审计和最小财务表已完成;文件资产、OCR 结果表和风险事件表作为 Day 5 真落库前置底座,设计已完成但代码未落地。
|
||||
- Day 2:仍缺一轮浏览器人工走查记录,需补充规则中心真实页面联调截图或缺陷清单。
|
||||
- Day 3:仍需补充叙述型报销长句样本、附件/OCR 摘要带入样本、模糊短句追问样本,并把这些样本纳入自动评测。
|
||||
- Day 4:仍需接通 `submit_expense_claim` 真服务,补齐附件挂接服务注册、ToolCall 更细粒度记录和前端 Trace 展示。
|
||||
- Day 5:仍需把附件和 OCR 识别结果真正落到 `document_assets`、`document_asset_versions`、`expense_item_documents`、`document_ocr_results`,并完成 `draft -> submitted` 状态流转、前端确认动作回写和提交流程确认。
|
||||
|
||||
## 关键依赖顺序
|
||||
|
||||
1. Day 1 必须先完成,因为后面所有能力都依赖资产、版本、审核、日志。
|
||||
2. Day 2 必须在 Day 3 前完成,因为语义和 Agent 需要读取规则、技能、MCP、任务资产。
|
||||
3. Day 3 必须在 Day 4 前完成,因为 Orchestrator 依赖语义本体做路由。
|
||||
4. Day 4 必须在 Day 5 / Day 6 前完成,因为 User Agent 和 Hermes 都应该由 Orchestrator 调用。
|
||||
5. Day 5 和 Day 6 可以部分并行,但都必须遵守权限、审计、Trace。
|
||||
6. Day 7 不新增大功能,只做加固、验收和交接。
|
||||
|
||||
## 最终验收
|
||||
|
||||
- 任务规则中心能看到规则、技能、MCP、任务。
|
||||
- 规则详情能编辑 Markdown、查看最近 5 个版本、切换版本。
|
||||
- 未审核规则不能上线。
|
||||
- 用户问题能解析出语义本体 8 字段。
|
||||
- Orchestrator 能路由到 User Agent 和 Hermes。
|
||||
- User Agent 能完成查询、解释、报销单草稿创建、字段补全和提交前确认。
|
||||
- Hermes 能执行一次风险巡检或日报任务。
|
||||
- AgentRun、ToolCall、AuditLog 都能追溯。
|
||||
- 有演示脚本和下一阶段交接文档。
|
||||
@@ -1,221 +0,0 @@
|
||||
# Day 1:基础模型与工程骨架
|
||||
|
||||
## 当前状态
|
||||
|
||||
- [x] ~~Day 1 已完成(2026-05-11)。~~
|
||||
- [x] ~~后端基础模型、API 骨架、种子数据、审计能力和 Day 2 联调入口均已落地。~~
|
||||
|
||||
## 今天的大开发点
|
||||
|
||||
Day 1 只做地基,不做复杂 Agent 智能。
|
||||
|
||||
核心是把后面 6 天都会用到的基础对象建出来:资产、版本、审核、运行日志、工具调用日志、语义解析日志、审计日志,以及最小财务业务数据来源。
|
||||
|
||||
## 为什么第一天做这个
|
||||
|
||||
如果没有稳定的数据模型,后面的任务规则中心、语义本体、Orchestrator、User Agent、Hermes 都会各自临时造结构,后期会很难合并。
|
||||
|
||||
## 今天主要交付
|
||||
|
||||
- [x] ~~统一资产模型:规则、技能、MCP、任务。~~
|
||||
- [x] ~~版本模型:规则 Markdown 和其他资产配置快照。~~
|
||||
- [x] ~~审核模型:未审核不能上线。~~
|
||||
- [x] ~~Agent 运行日志:所有 Agent 执行都有 `run_id`。~~
|
||||
- [x] ~~工具调用日志:MCP、数据库、LLM、OCR、规则引擎调用都可追踪。~~
|
||||
- [x] ~~语义解析日志:后续语义本体结果可回放。~~
|
||||
- [x] ~~审计日志:所有写操作可追责。~~
|
||||
- [x] ~~最小财务业务数据来源:报销、应收、应付。~~
|
||||
|
||||
## 实际落地结果
|
||||
|
||||
- [x] ~~新增 `AgentAsset`、`AgentAssetVersion`、`AgentAssetReview`、`AgentRun`、`AgentToolCall`、`SemanticParseLog`、`AuditLog`、`ExpenseClaim`、`ExpenseClaimItem`、`AccountsReceivableRecord`、`AccountsPayableRecord`。~~
|
||||
- [x] ~~新增 `/api/v1/agent-assets`、`/api/v1/agent-runs`、`/api/v1/audit-logs` 相关接口。~~
|
||||
- [x] ~~种子数据已覆盖 3 条规则、2 条技能、2 条 MCP、3 条任务,以及报销 / 应收 / 应付示例数据。~~
|
||||
- [x] ~~旧开发库启动时会自动补齐新增资产和版本,不需要手动清库。~~
|
||||
|
||||
相关架构文档:
|
||||
|
||||
- [整体架构](<../agent plan/01_overall_architecture.md>)
|
||||
- [语义本体](<../agent plan/02_semantic_ontology.md>)
|
||||
- [数据契约与治理](<../agent plan/06_data_contracts_and_governance.md>)
|
||||
- [能力注册](<../agent plan/07_capability_registry.md>)
|
||||
- [权限与确认](<../agent plan/08_permission_confirmation.md>)
|
||||
- [观测与 Trace](<../agent plan/09_observability_and_trace.md>)
|
||||
- [财务单据标准模型](<../agent plan/14_financial_document_canonical_model.md>)
|
||||
|
||||
## 当天验收门槛
|
||||
|
||||
- [x] ~~数据库或等价存储能创建基础对象。~~
|
||||
- [x] ~~API 服务能启动。~~
|
||||
- [x] ~~资产列表能返回规则、技能、MCP、任务。~~
|
||||
- [x] ~~规则资产能关联 Markdown 当前版本。~~
|
||||
- [x] ~~未审核规则不能上线。~~
|
||||
- [x] ~~AgentRun 能保存一条运行记录。~~
|
||||
- [x] ~~AuditLog 能保存一条写操作记录。~~
|
||||
|
||||
## Day 2 联调入口
|
||||
|
||||
- `GET /api/v1/agent-assets`
|
||||
- `GET /api/v1/agent-assets/{asset_id}`
|
||||
- `GET /api/v1/agent-assets/{asset_id}/versions?limit=5`
|
||||
- `POST /api/v1/agent-assets/{asset_id}/reviews`
|
||||
- `POST /api/v1/agent-assets/{asset_id}/activate`
|
||||
- `GET /api/v1/audit-logs`
|
||||
|
||||
## 今天不做
|
||||
|
||||
- 不做完整 Agent 对话。
|
||||
- 不做完整 Hermes 调度。
|
||||
- 不做真实 OCR。
|
||||
- 不做复杂规则推理。
|
||||
|
||||
## 详细执行清单
|
||||
|
||||
以下内容为合并后的详细执行清单。
|
||||
|
||||
## 0. 开始前检查
|
||||
|
||||
- [x] ~~确认后端目录为 `/app/server`,模型、路由、启动入口和测试目录已定位。~~
|
||||
- [x] ~~确认本次改动以增量方式落到现有 FastAPI + SQLAlchemy 工程,不回退无关文件。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~模型注册位于 `server/src/app/db/base.py`,路由注册位于 `server/src/app/api/v1/router.py`,启动入口位于 `server/src/app/main.py`,测试位于 `server/tests`。~~
|
||||
|
||||
## 1. 统一命名和边界
|
||||
|
||||
- [x] ~~统一枚举:`rule | skill | mcp | task`、`draft | review | active | disabled`、`pending | approved | rejected`、`orchestrator | user_agent | hermes`。~~
|
||||
- [x] ~~统一运行来源、权限级别、内容类型、运行状态和工具类型命名,避免出现第二套并行语义。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~`server/src/app/core/agent_enums.py` 已成为模型、Schema 和服务层的统一枚举入口。~~
|
||||
|
||||
## 2. 设计最小财务业务数据模型
|
||||
|
||||
- [x] ~~建立 `expense_claims`、`expense_claim_items`、`accounts_receivable`、`accounts_payable`。~~
|
||||
- [x] ~~字段覆盖时间、地点、理由、金额、员工、部门、状态,以及应收 / 应付的金额、到期日、账龄、风险标记。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~`server/src/app/models/financial_record.py` 与 `document/development/agent plan/14_financial_document_canonical_model.md` 形成直接映射。~~
|
||||
|
||||
## 3. 建立 AgentAsset 模型
|
||||
|
||||
- [x] ~~建立 `AgentAsset`,包含 `asset_type`、`code`、`name`、`description`、`domain`、`scenario_json`、`owner`、`reviewer`、`status`、`current_version`、`config_json` 等核心字段。~~
|
||||
- [x] ~~对 `code`、`asset_type`、`status`、`domain` 建立唯一约束或索引。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~资产列表可按 `rule`、`skill`、`mcp`、`task` 四类过滤返回。~~
|
||||
|
||||
## 4. 建立 AgentAssetVersion 模型
|
||||
|
||||
- [x] ~~建立 `AgentAssetVersion`,规则版本保存 Markdown,其余资产版本保存 JSON 快照。~~
|
||||
- [x] ~~对 `asset_id + version` 建立唯一约束,并支持按资产读取最近版本列表。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~规则详情接口可返回 `current_version_content` 和 `recent_versions`。~~
|
||||
|
||||
## 5. 建立 AgentAssetReview 模型
|
||||
|
||||
- [x] ~~建立 `AgentAssetReview`,保存版本、审核人、审核状态、审核备注和审核时间。~~
|
||||
- [x] ~~服务层实现规则版本未 `approved` 时禁止上线。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~`POST /api/v1/agent-assets/{asset_id}/activate` 对待审规则返回 400 拦截。~~
|
||||
|
||||
## 6. 建立 AgentRun 模型
|
||||
|
||||
- [x] ~~建立 `AgentRun`,包含 `run_id`、`agent`、`source`、`ontology_json`、`route_json`、`permission_level`、`status`、`result_summary`、`error_message` 等字段。~~
|
||||
- [x] ~~所有运行记录统一生成 `run_id`,并允许失败态保存错误信息。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~`AgentRunService.create_run()` 会自动生成 `run_` 前缀标识,并可回读失败摘要。~~
|
||||
|
||||
## 7. 建立 AgentToolCall 模型
|
||||
|
||||
- [x] ~~建立 `AgentToolCall`,可记录工具类型、工具名、请求 / 响应 JSON、耗时和错误信息。~~
|
||||
- [x] ~~同一个 `run_id` 下支持多次工具调用追踪。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~种子运行数据已覆盖数据库查询、MCP 调用和权限规则引擎调用。~~
|
||||
|
||||
## 8. 建立 SemanticParseLog 模型
|
||||
|
||||
- [x] ~~建立 `SemanticParseLog`,覆盖场景、意图、实体、时间范围、指标、约束、风险、权限和置信度。~~
|
||||
- [x] ~~支持按 `run_id` 回放 Day 3 语义结果。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~`GET /api/v1/agent-runs/{run_id}` 已能携带 `semantic_parse` 返回。~~
|
||||
|
||||
## 9. 建立 AuditLog 模型
|
||||
|
||||
- [x] ~~建立 `AuditLog` 和统一 `AuditLogService`。~~
|
||||
- [x] ~~资产创建、版本保存、审核、上线等写操作都会留下审计记录。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~`GET /api/v1/audit-logs` 可返回种子审计日志,服务层新建资产也会落审计。~~
|
||||
|
||||
## 10. 建立 Schema / DTO
|
||||
|
||||
- [x] ~~建立 `AgentAssetCreate / Update / Read / ListItem`、`AgentAssetVersionRead`、`AgentAssetReviewRead`、`RuleMarkdownUpdate`、`AgentRunRead`、`AgentToolCallRead`、`SemanticParseRead`。~~
|
||||
- [x] ~~所有 JSON 字段以结构化对象返回,不回传字符串化 JSON。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~列表 DTO 不返回大块 Markdown,详情 DTO 返回当前版本正文和最近版本。~~
|
||||
|
||||
## 11. 建立 API 骨架
|
||||
|
||||
- [x] ~~建立 `GET/POST/PATCH /api/v1/agent-assets`、`GET /api/v1/agent-assets/{asset_id}`、`GET/POST /api/v1/agent-assets/{asset_id}/versions`、`POST /api/v1/agent-assets/{asset_id}/reviews`、`POST /api/v1/agent-assets/{asset_id}/activate`。~~
|
||||
- [x] ~~建立 `GET /api/v1/agent-runs`、`GET /api/v1/agent-runs/{run_id}`、`GET /api/v1/audit-logs`。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~所有接口已挂到 `server/src/app/api/v1/router.py`,并通过 `create_app()` 自动暴露。~~
|
||||
|
||||
## 12. 建立种子数据
|
||||
|
||||
- [x] ~~种子资产补齐到 3 条规则、2 条技能、2 条 MCP、3 条任务。~~
|
||||
- [x] ~~三条规则都具备至少 2 个版本,并覆盖 `approved / pending / rejected` 三种审核样本。~~
|
||||
- [x] ~~旧开发数据库启动时会自动增量补齐新增资产和版本,不要求手动清库。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~Smoke:`GET /api/v1/agent-assets` 返回 10 条资产,`GET /api/v1/agent-runs` 返回 3 条运行日志,`GET /api/v1/audit-logs` 返回 4 条审计日志。~~
|
||||
|
||||
## 13. 最小测试
|
||||
|
||||
- [x] ~~新增 Day 1 服务层与接口层测试,覆盖种子完整性、版本历史、未审核不能上线、运行日志生成和审计日志写入。~~
|
||||
- [x] ~~Ruff 校验通过,Day 1 新增文件保持可检查状态。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~`/app/server/.venv/bin/pytest -q /app/server/tests/test_agent_asset_service.py /app/server/tests/test_agent_foundation_endpoints.py` -> `11 passed`。~~
|
||||
- [x] ~~`/app/server/.venv/bin/pytest -q tests` 已通过全量后端测试。~~
|
||||
|
||||
## 14. Day 1 验收
|
||||
|
||||
- [x] ~~数据库能创建所有新增表或等价结构。~~
|
||||
- [x] ~~API 服务能启动,OpenAPI 能看到新增接口。~~
|
||||
- [x] ~~资产列表接口返回规则、技能、MCP、任务;规则详情带 Markdown 当前版本和最近版本列表。~~
|
||||
- [x] ~~未审核规则不能上线;AgentRun 和 AuditLog 均可保存记录。~~
|
||||
- [x] ~~所有 Day 1 TODO 已改为完成态。~~
|
||||
|
||||
## 阻塞记录
|
||||
|
||||
- [x] ~~暂无阻塞。~~
|
||||
|
||||
## 日终交接
|
||||
|
||||
- [x] ~~已完成模型:资产、版本、审核、运行日志、工具调用、语义解析、审计、报销、应收、应付。~~
|
||||
- [x] ~~已完成 API:`/api/v1/agent-assets`、`/api/v1/agent-runs`、`/api/v1/audit-logs`。~~
|
||||
- [x] ~~Day 2 前端联调应优先使用 `GET /api/v1/agent-assets`、`GET /api/v1/agent-assets/{asset_id}`、`GET /api/v1/agent-assets/{asset_id}/versions?limit=5`、`POST /api/v1/agent-assets/{asset_id}/reviews`、`POST /api/v1/agent-assets/{asset_id}/activate`。~~
|
||||
- [x] ~~后续 Day 4 及以后运行时方向按用户要求转向 `LangChain + LangGraph`,Hermes 继续作为内部数字员工入口;Day 1 保留为数据与治理底座。~~
|
||||
@@ -1,296 +0,0 @@
|
||||
# Day 2:任务规则中心联调
|
||||
|
||||
## 今天的大开发点
|
||||
|
||||
把任务规则中心从静态页面改成可和后端资产体系联动的生产形态。
|
||||
|
||||
重点是规则、技能、MCP、任务四类资产的列表和详情,以及规则 Markdown、版本、审核、上线约束。
|
||||
|
||||
## 为什么第二天做这个
|
||||
|
||||
任务规则中心是业务人员管理 Agent 能力的入口。后续语义本体、Orchestrator、User Agent、Hermes 都要读取这里注册的规则、技能、MCP 和任务。
|
||||
|
||||
## 今天主要交付
|
||||
|
||||
- 规则、技能、MCP、任务四个页签对接资产 API。
|
||||
- 列表支持搜索、筛选、状态展示。
|
||||
- 规则详情展示 Markdown 内容。
|
||||
- 管理员可编辑规则 Markdown。
|
||||
- 规则版本展示最近 5 个版本。
|
||||
- 版本切换需要弹窗确认。
|
||||
- 审核者信息放在标题区域。
|
||||
- 右侧只保留版本信息。
|
||||
- 未审核规则上线时被后端拦截。
|
||||
|
||||
## 当前完成情况
|
||||
|
||||
- [x] ~~四个页签已切到真实资产 API。~~
|
||||
- [x] ~~规则 Markdown、版本切换、审核、上线动作已联调。~~
|
||||
- [x] ~~前端构建已通过。~~
|
||||
- [ ] 浏览器手动走查记录待补。
|
||||
|
||||
相关架构文档:
|
||||
|
||||
- [能力注册](<../agent plan/07_capability_registry.md>)
|
||||
- [规则形成生命周期](<../agent plan/13_rule_formation_lifecycle.md>)
|
||||
- [数据契约与治理](<../agent plan/06_data_contracts_and_governance.md>)
|
||||
|
||||
## 当天验收门槛
|
||||
|
||||
- 四个页签可切换并有真实 API 或 Mock API 数据。
|
||||
- 规则详情可编辑 Markdown。
|
||||
- Markdown 保存后刷新不丢失。
|
||||
- 版本卡片可切换版本。
|
||||
- 未审核规则不能上线。
|
||||
- 前端构建通过。
|
||||
|
||||
## 今天不做
|
||||
|
||||
- 不做规则自动生成。
|
||||
- 不做完整 MCP 真实调用。
|
||||
- 不做复杂权限矩阵。
|
||||
- 不重做 UI 风格,只在现有风格上微调。
|
||||
|
||||
## 详细执行清单
|
||||
|
||||
以下内容为合并后的详细执行清单。
|
||||
|
||||
## 0. 开始前检查
|
||||
|
||||
- [x] ~~确认 Day 1 API 已可访问。~~
|
||||
- [x] ~~确认前端任务规则中心文件位置。~~
|
||||
- [x] ~~确认现有路由名称和导航名称。~~
|
||||
- [x] ~~确认现有 UI 风格,不重新做大改版。~~
|
||||
- [x] ~~确认当前页面已有页签:规则、技能、MCP、任务。~~
|
||||
- [x] ~~确认详情页隐藏顶部 title bar 的逻辑仍然有效。~~
|
||||
- [x] ~~确认返回列表栏高度没有被重新拉高。~~
|
||||
|
||||
## 1. API Client
|
||||
|
||||
- [x] ~~新增或扩展资产列表请求函数。~~
|
||||
- [x] ~~新增资产详情请求函数。~~
|
||||
- [x] ~~新增版本列表请求函数。~~
|
||||
- [x] ~~新增规则 Markdown 保存请求函数。~~
|
||||
- [x] ~~新增审核请求函数。~~
|
||||
- [x] ~~新增上线请求函数。~~
|
||||
- [x] ~~新增运行日志请求函数。~~
|
||||
- [x] ~~给所有请求增加加载态。~~
|
||||
- [x] ~~给所有请求增加错误态。~~
|
||||
- [x] ~~给所有写请求增加成功提示。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~前端不再只依赖本地硬编码资产数据。~~
|
||||
- [x] ~~后端不可用时页面有明确错误提示。~~
|
||||
|
||||
## 2. 列表页数据接入
|
||||
|
||||
- [x] ~~规则页签请求 `asset_type=rule`。~~
|
||||
- [x] ~~技能页签请求 `asset_type=skill`。~~
|
||||
- [x] ~~MCP 页签请求 `asset_type=mcp`。~~
|
||||
- [x] ~~任务页签请求 `asset_type=task`。~~
|
||||
- [x] ~~搜索框传递关键词或本地过滤。~~
|
||||
- [x] ~~类型下拉和搜索框可以同时生效。~~
|
||||
- [x] ~~状态筛选可以过滤 `draft | review | active | disabled`。~~
|
||||
- [x] ~~列表卡片展示名称。~~
|
||||
- [x] ~~列表卡片展示摘要。~~
|
||||
- [x] ~~列表卡片展示状态。~~
|
||||
- [x] ~~列表卡片展示负责人。~~
|
||||
- [x] ~~列表卡片展示最近更新时间。~~
|
||||
- [x] ~~空数据时展示空态。~~
|
||||
- [x] ~~加载中时展示骨架或加载状态。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~四个页签都能切换。~~
|
||||
- [x] ~~四个页签都有数据或空态。~~
|
||||
- [x] ~~搜索和筛选不会互相覆盖。~~
|
||||
|
||||
## 3. 规则详情页主信息
|
||||
|
||||
- [x] ~~打开规则资产时请求详情 API。~~
|
||||
- [x] ~~Hero title 展示规则名称。~~
|
||||
- [x] ~~Hero title 下方展示审核者。~~
|
||||
- [x] ~~Hero title 下方展示审核状态。~~
|
||||
- [x] ~~Hero title 下方展示上线条件。~~
|
||||
- [x] ~~Hero title 高度保持紧凑。~~
|
||||
- [x] ~~详情页不显示外层顶部 title bar。~~
|
||||
- [x] ~~返回列表栏高度保持原有紧凑高度。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~用户能一眼看到该规则是否已审核。~~
|
||||
- [x] ~~用户不会看到两层 title。~~
|
||||
|
||||
## 4. Markdown 编辑器
|
||||
|
||||
- [x] ~~从当前版本读取 Markdown 内容。~~
|
||||
- [x] ~~Markdown 编辑框高度和右侧版本卡片底部对齐。~~
|
||||
- [x] ~~Markdown 编辑框支持长内容滚动。~~
|
||||
- [x] ~~Markdown 编辑框保存时调用 API。~~
|
||||
- [x] ~~保存后创建新版本或更新草稿版本,按后端约定执行。~~
|
||||
- [x] ~~保存成功后刷新版本列表。~~
|
||||
- [x] ~~保存失败时保留用户输入。~~
|
||||
- [x] ~~编辑器禁用态覆盖 `active` 且无编辑权限的情况。~~
|
||||
- [x] ~~编辑器底部展示最后保存时间。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~编辑 Markdown 后刷新页面内容仍存在。~~
|
||||
- [x] ~~保存失败不会丢内容。~~
|
||||
- [x] ~~左右卡片底部视觉对齐。~~
|
||||
|
||||
## 5. 版本卡片
|
||||
|
||||
- [x] ~~右侧只保留版本信息卡片。~~
|
||||
- [x] ~~版本卡片宽度足够展示版本号、日期、状态。~~
|
||||
- [x] ~~展示最近 5 个版本。~~
|
||||
- [x] ~~当前版本有明显但不突兀的标识。~~
|
||||
- [x] ~~当前版本标识居中显示。~~
|
||||
- [x] ~~选中状态只变色,不改变内容对齐。~~
|
||||
- [x] ~~日期列和其他版本日期对齐。~~
|
||||
- [x] ~~点击非当前版本时弹出确认弹窗。~~
|
||||
- [x] ~~弹窗展示目标版本号。~~
|
||||
- [x] ~~弹窗展示切换风险提示。~~
|
||||
- [x] ~~确认后切换当前展示内容。~~
|
||||
- [x] ~~取消后不改变当前版本。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~版本切换不会造成列表文字位移。~~
|
||||
- [x] ~~当前版本背景能完全覆盖内容区域。~~
|
||||
- [x] ~~版本卡片不贴右侧边界。~~
|
||||
|
||||
## 6. 审核与上线
|
||||
|
||||
- [x] ~~详情中展示审核者姓名。~~
|
||||
- [x] ~~详情中展示审核时间。~~
|
||||
- [x] ~~详情中展示审核意见。~~
|
||||
- [x] ~~未审核规则显示不能上线原因。~~
|
||||
- [x] ~~点击上线时调用后端上线接口。~~
|
||||
- [x] ~~后端拒绝时展示拒绝原因。~~
|
||||
- [x] ~~审核通过后上线按钮可用。~~
|
||||
- [x] ~~审核动作写入审计日志。~~
|
||||
- [x] ~~上线动作写入审计日志。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~pending 规则无法上线。~~
|
||||
- [x] ~~approved 规则可以上线。~~
|
||||
- [x] ~~rejected 规则无法上线。~~
|
||||
|
||||
## 7. 技能详情
|
||||
|
||||
- [x] ~~技能页签列表展示能力名称。~~
|
||||
- [x] ~~技能详情展示能力说明。~~
|
||||
- [x] ~~技能详情展示输入参数。~~
|
||||
- [x] ~~技能详情展示输出参数。~~
|
||||
- [x] ~~技能详情展示依赖能力。~~
|
||||
- [x] ~~技能详情展示适用场景。~~
|
||||
- [x] ~~技能详情展示负责人。~~
|
||||
- [x] ~~技能详情展示版本。~~
|
||||
- [x] ~~技能详情不使用规则 Markdown 编辑器。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~技能和规则详情不会混用 UI。~~
|
||||
|
||||
## 8. MCP 详情
|
||||
|
||||
- [x] ~~MCP 页签列表展示外部服务名称。~~
|
||||
- [x] ~~MCP 详情展示服务类型。~~
|
||||
- [x] ~~MCP 详情展示调用地址或能力名。~~
|
||||
- [x] ~~MCP 详情展示鉴权方式。~~
|
||||
- [x] ~~MCP 详情展示超时配置。~~
|
||||
- [x] ~~MCP 详情展示降级策略。~~
|
||||
- [x] ~~MCP 详情展示最近调用状态。~~
|
||||
- [x] ~~MCP 详情展示负责人。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~MCP 被定义为外部服务,而不是技能规则。~~
|
||||
|
||||
## 9. 任务详情
|
||||
|
||||
- [x] ~~任务页签展示定时任务名称。~~
|
||||
- [x] ~~任务详情展示 cron 或调度周期。~~
|
||||
- [x] ~~任务详情展示执行 Agent,默认 Hermes。~~
|
||||
- [x] ~~任务详情展示任务目标。~~
|
||||
- [x] ~~任务详情展示风险等级。~~
|
||||
- [x] ~~任务详情展示最近执行时间。~~
|
||||
- [x] ~~任务详情展示最近执行结果。~~
|
||||
- [x] ~~任务详情展示启停状态。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~定时任务用户可见名称为“任务”。~~
|
||||
- [x] ~~技术字段可保留 `schedule`,但 UI 不显示“定时任务”。~~
|
||||
|
||||
## 10. 前端质量
|
||||
|
||||
- [x] ~~页面在 1366 宽度下无横向滚动。~~
|
||||
- [x] ~~页面在 1920 宽度下右侧卡片不过宽。~~
|
||||
- [x] ~~页面在窄屏下详情区域可滚动。~~
|
||||
- [x] ~~所有按钮有禁用态。~~
|
||||
- [x] ~~所有弹窗有取消按钮。~~
|
||||
- [x] ~~所有表单错误有提示。~~
|
||||
- [x] ~~所有日期格式统一。~~
|
||||
- [x] ~~状态颜色和现有系统一致。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~`npm run build` 通过。~~
|
||||
- [ ] 任务规则中心手动走查通过。
|
||||
|
||||
## 11. Day 2 验收
|
||||
|
||||
- [x] ~~规则、技能、MCP、任务四个页签可用。~~
|
||||
- [x] ~~搜索框和筛选下拉可用。~~
|
||||
- [x] ~~规则详情展示 Markdown。~~
|
||||
- [x] ~~规则 Markdown 可保存。~~
|
||||
- [x] ~~右侧只保留版本信息。~~
|
||||
- [x] ~~版本可切换且有弹窗确认。~~
|
||||
- [x] ~~审核者信息在标题下方。~~
|
||||
- [x] ~~未审核规则不能上线。~~
|
||||
- [x] ~~前端构建通过。~~
|
||||
- [x] ~~所有完成项已按完成态标记。~~
|
||||
|
||||
## 阻塞记录
|
||||
|
||||
- [x] ~~暂无。~~
|
||||
|
||||
## 日终交接
|
||||
|
||||
- [x] ~~写明已接入的 API。~~
|
||||
- [x] ~~写明仍然使用 Mock 的字段。~~
|
||||
- [x] ~~写明 UI 未完成项。~~
|
||||
- [x] ~~写明 Day 3 语义本体需要复用的资产数据。~~
|
||||
|
||||
已接入的 API:
|
||||
|
||||
- `GET /api/v1/agent-assets?asset_type=rule|skill|mcp|task`
|
||||
- `GET /api/v1/agent-assets/{asset_id}`
|
||||
- `GET /api/v1/agent-assets/{asset_id}/versions`
|
||||
- `POST /api/v1/agent-assets/{asset_id}/versions`
|
||||
- `POST /api/v1/agent-assets/{asset_id}/reviews`
|
||||
- `POST /api/v1/agent-assets/{asset_id}/activate`
|
||||
- `GET /api/v1/agent-runs`
|
||||
|
||||
仍然使用 Mock / 种子数据的字段:
|
||||
|
||||
- MCP 服务地址仍是 `mock://...` 种子地址,用于占位联调。
|
||||
- MCP 最近调用状态、任务最近执行结果来自 Day 1 注入的 `AgentRun` 种子数据。
|
||||
- 技能、MCP、任务详情仍以只读方式展示,未开放编辑表单。
|
||||
|
||||
UI 未完成项:
|
||||
|
||||
- 未做浏览器内人工走查记录,当前仅完成构建验证与代码层联调。
|
||||
- 技能、MCP、任务的编辑能力仍留待后续 Day 3 / Day 4 之后按权限开放。
|
||||
|
||||
Day 3 语义本体需要复用的资产数据:
|
||||
|
||||
- 资产主键与编码:`id`、`code`、`asset_type`
|
||||
- 业务归类:`domain`、`scenario_json`
|
||||
- 当前生效版本:`current_version`、`current_version_content`、`current_version_content_type`
|
||||
- 治理状态:`status`、`latest_review`、`recent_versions`
|
||||
- 运行关联:`config_json.agent`、`config_json.cron`、`AgentRun.task_id`、`tool_calls`
|
||||
@@ -1,304 +0,0 @@
|
||||
# Day 3:语义本体 MVP
|
||||
|
||||
## 今天的大开发点
|
||||
|
||||
建立模型优先的语义解析层,把自然语言问题转换成统一的 8 个核心字段。
|
||||
|
||||
这一天的目标不是继续堆关键词,而是先把真实模型接入语义层,让报销、应收、应付、知识和风险相关问题进入稳定结构,再由规则做兜底和校验。
|
||||
|
||||
## 为什么第三天做这个
|
||||
|
||||
Orchestrator 不能直接根据原始文本做可靠路由。它需要先拿到结构化语义,再决定调用 User Agent、Hermes、规则、MCP 或知识库。
|
||||
|
||||
## 今天主要交付
|
||||
|
||||
- 语义本体 8 字段结构。
|
||||
- 场景识别:报销、应收、应付、知识、未知。
|
||||
- 意图识别:查询、解释、对比、风险检查、草稿、操作。
|
||||
- 业务对象提取:员工、客户、供应商、部门、项目、单据、金额。
|
||||
- 时间范围解析。
|
||||
- 指标和约束解析。
|
||||
- 风险信号和权限级别判断。
|
||||
- LLM 结构化解析 Prompt。
|
||||
- Schema 校验与 JSON 清洗。
|
||||
- 规则回退解析。
|
||||
- 低置信度追问和缺槽位追问。
|
||||
- 语义解析 API。
|
||||
- 解析日志和最小评测集。
|
||||
|
||||
## 当前完成情况
|
||||
|
||||
- [x] ~~`/api/v1/ontology/parse` 已上线,8 字段语义结构、缺槽位、歧义、权限和澄清问题均可返回。~~
|
||||
- [x] ~~语义层已切到“模型优先 + 规则回退”,并把结果写入 `AgentRun` / `SemanticParseLog`。~~
|
||||
- [x] ~~附件名称、附件数量、OCR 摘要和 OCR 文档摘要已能作为上下文带入语义层。~~
|
||||
- [x] ~~最小会话历史、上一轮场景/意图和 `draft_claim_id` 已能作为上下文带入语义层,用于识别“改成 800”“继续补充”这类追问。~~
|
||||
- [x] ~~叙述型报销语义已补强:`客户 + 吃饭/请客/宴请/招待` 优先归类为业务招待费,不再误打到应收查询。~~
|
||||
- [x] ~~相对时间已支持标准化展示:前端会透传浏览器本地时间上下文,`今天 / 昨天 / 本月 / 4 月` 会换算成绝对日期;展示层默认优先显示绝对日期,原始表达仅作为辅助信息。~~
|
||||
- [x] ~~前端调试入口与核心评测测试已完成并通过。~~
|
||||
- [ ] 叙述型报销样本、附件/OCR 带入样本和模糊短句追问样本仍需继续扩充。
|
||||
|
||||
相关架构文档:
|
||||
|
||||
- [语义本体](<../agent plan/02_semantic_ontology.md>)
|
||||
- [财务单据标准模型](<../agent plan/14_financial_document_canonical_model.md>)
|
||||
- [数据契约与治理](<../agent plan/06_data_contracts_and_governance.md>)
|
||||
|
||||
## 当天验收门槛
|
||||
|
||||
- 输入自然语言问题能返回 8 个字段。
|
||||
- 模型解析失败时能自动回退到规则解析。
|
||||
- 低置信度问题能返回澄清问题。
|
||||
- 越权动作不会被标记为可直接执行。
|
||||
- 解析结果能写入日志。
|
||||
- 至少覆盖报销、应收、应付三个场景。
|
||||
- 叙述型报销输入不会被错误路由到应收或应付。
|
||||
|
||||
## 今天不做
|
||||
|
||||
- 不做复杂多轮对话记忆。
|
||||
- 不做完整 Agent 自主规划。
|
||||
- 不做自动执行业务流程。
|
||||
|
||||
## 详细执行清单
|
||||
|
||||
以下内容为合并后的详细执行清单。
|
||||
|
||||
## 0. 开始前检查
|
||||
|
||||
- [x] ~~确认 Day 1 的 `SemanticParseLog` 可用。~~
|
||||
- [x] ~~确认 Day 1 的 `AgentRun` 可用。~~
|
||||
- [x] ~~确认 Day 2 的资产 API 可用。~~
|
||||
- [x] ~~找到后端服务层目录。~~
|
||||
- [x] ~~找到现有 LLM 调用或 Mock 调用方式。~~
|
||||
- [x] ~~确认当前是否允许真实调用 LLM。~~
|
||||
- [x] ~~确认当前运行时模型槽位可用于语义解析。~~
|
||||
- [x] ~~如果真实模型不可用,已准备规则解析回退路径。~~
|
||||
|
||||
## 1. 定义 8 个核心字段
|
||||
|
||||
- [x] ~~定义字段 `scenario`,表示业务场景。~~
|
||||
- [x] ~~定义字段 `intent`,表示用户意图。~~
|
||||
- [x] ~~定义字段 `entities`,表示业务对象。~~
|
||||
- [x] ~~定义字段 `time_range`,表示时间范围。~~
|
||||
- [x] ~~定义字段 `metrics`,表示指标或金额口径。~~
|
||||
- [x] ~~定义字段 `constraints`,表示过滤条件。~~
|
||||
- [x] ~~定义字段 `risk_flags`,表示风险信号。~~
|
||||
- [x] ~~定义字段 `permission`,表示动作权限。~~
|
||||
- [x] ~~为每个字段写清楚类型。~~
|
||||
- [x] ~~为每个字段写清楚是否必填。~~
|
||||
- [x] ~~为每个字段写清楚默认值。~~
|
||||
- [x] ~~为每个字段写清楚示例。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~8 个字段在 Schema、服务层、日志中名字一致。~~
|
||||
|
||||
## 2. 设计字段枚举
|
||||
|
||||
- [x] ~~`scenario` 支持 `expense`。~~
|
||||
- [x] ~~`scenario` 支持 `accounts_receivable`。~~
|
||||
- [x] ~~`scenario` 支持 `accounts_payable`。~~
|
||||
- [x] ~~`scenario` 支持 `knowledge`。~~
|
||||
- [x] ~~`scenario` 支持 `unknown`。~~
|
||||
- [x] ~~`intent` 支持 `query`。~~
|
||||
- [x] ~~`intent` 支持 `explain`。~~
|
||||
- [x] ~~`intent` 支持 `compare`。~~
|
||||
- [x] ~~`intent` 支持 `risk_check`。~~
|
||||
- [x] ~~`intent` 支持 `draft`。~~
|
||||
- [x] ~~`intent` 支持 `operate`。~~
|
||||
- [x] ~~`permission.level` 支持 `read`。~~
|
||||
- [x] ~~`permission.level` 支持 `draft_write`。~~
|
||||
- [x] ~~`permission.level` 支持 `approval_required`。~~
|
||||
- [x] ~~`permission.level` 支持 `forbidden`。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~未识别的问题不会抛异常,返回 `unknown`。~~
|
||||
|
||||
## 3. 建立 Schema
|
||||
|
||||
- [x] ~~定义 `OntologyParseRequest`。~~
|
||||
- [x] ~~`OntologyParseRequest` 包含 `query`。~~
|
||||
- [x] ~~`OntologyParseRequest` 包含 `user_id`。~~
|
||||
- [x] ~~`OntologyParseRequest` 包含 `context_json`。~~
|
||||
- [x] ~~定义 `OntologyParseResult`。~~
|
||||
- [x] ~~`OntologyParseResult` 包含 8 个核心字段。~~
|
||||
- [x] ~~`OntologyParseResult` 包含 `confidence`。~~
|
||||
- [x] ~~`OntologyParseResult` 包含 `clarification_required`。~~
|
||||
- [x] ~~`OntologyParseResult` 包含 `clarification_question`。~~
|
||||
- [x] ~~`OntologyParseResult` 包含 `run_id`。~~
|
||||
- [x] ~~定义字段级错误结构。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~OpenAPI 中可以看到语义解析请求和响应。~~
|
||||
|
||||
## 4. 实现解析服务
|
||||
|
||||
- [x] ~~新增 `SemanticOntologyService` 或同等服务。~~
|
||||
- [x] ~~实现 `parse(query, user_context)` 主函数。~~
|
||||
- [x] ~~增加上下文装配层,输入文本、页面上下文、附件摘要和预抽取字段。~~
|
||||
- [x] ~~实现模型优先的结构化语义解析。~~
|
||||
- [x] ~~约束模型只输出 JSON。~~
|
||||
- [x] ~~对模型输出做清洗、提取和 Schema 校验。~~
|
||||
- [x] ~~模型失败时自动回退到规则解析。~~
|
||||
- [x] ~~在结果中记录本次使用了 `llm_primary` 还是 `rule_fallback`。~~
|
||||
- [x] ~~报销关键词映射到 `expense`。~~
|
||||
- [x] ~~应收、回款、客户欠款映射到 `accounts_receivable`。~~
|
||||
- [x] ~~应付、供应商、付款映射到 `accounts_payable`。~~
|
||||
- [x] ~~风险、异常、重复、超标映射到 `risk_check`。~~
|
||||
- [x] ~~为什么、依据、规则映射到 `explain`。~~
|
||||
- [x] ~~统计、汇总、多少映射到 `query`。~~
|
||||
- [x] ~~生成、创建、发起映射到 `draft` 或 `operate`。~~
|
||||
- [x] ~~无法识别时返回低置信度和澄清问题。~~
|
||||
- [x] ~~叙述型报销输入优先识别为创建/草稿,而不是查询。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~“查一下本周报销超标风险”能识别为 expense + risk_check。~~
|
||||
- [x] ~~“客户 A 这个月还有多少应收”能识别为 accounts_receivable + query。~~
|
||||
- [x] ~~“供应商 B 明天要付多少钱”能识别为 accounts_payable + query。~~
|
||||
- [x] ~~“我今天去客户现场,招待了客户,花销了1000元”不会错误识别为应收查询。~~
|
||||
- [x] ~~“昨天请客户吃饭花了 200 元”会优先识别为报销草稿语义,并把“昨天”换算为用户本地日期下的绝对日期。~~
|
||||
|
||||
## 5. 解析业务对象
|
||||
|
||||
- [x] ~~从问题中提取员工姓名。~~
|
||||
- [x] ~~从问题中提取部门。~~
|
||||
- [x] ~~从问题中提取客户。~~
|
||||
- [x] ~~从问题中提取供应商。~~
|
||||
- [x] ~~从问题中提取项目。~~
|
||||
- [x] ~~从问题中提取单据号。~~
|
||||
- [x] ~~从问题中提取金额。~~
|
||||
- [x] ~~从问题中提取费用类型。~~
|
||||
- [x] ~~无法提取时返回空数组,不返回 null。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~“张三 4 月差旅报销”能提取员工、月份、费用类型。~~
|
||||
|
||||
## 6. 解析时间范围
|
||||
|
||||
- [x] ~~支持今天。~~
|
||||
- [x] ~~支持昨天。~~
|
||||
- [x] ~~支持本周。~~
|
||||
- [x] ~~支持上周。~~
|
||||
- [x] ~~支持本月。~~
|
||||
- [x] ~~支持上月。~~
|
||||
- [x] ~~支持本季度。~~
|
||||
- [x] ~~支持今年。~~
|
||||
- [x] ~~支持明确日期。~~
|
||||
- [x] ~~支持日期区间。~~
|
||||
- [x] ~~解析结果包含 `start_date` 和 `end_date`。~~
|
||||
- [x] ~~日期使用 ISO 格式。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~“本周”能解析为当前周起止日期。~~
|
||||
- [x] ~~“2026 年 4 月”能解析为 `2026-04-01` 到 `2026-04-30`。~~
|
||||
|
||||
## 7. 解析指标与约束
|
||||
|
||||
- [x] ~~识别金额指标。~~
|
||||
- [x] ~~识别数量指标。~~
|
||||
- [x] ~~识别超标指标。~~
|
||||
- [x] ~~识别逾期指标。~~
|
||||
- [x] ~~识别重复报销指标。~~
|
||||
- [x] ~~识别部门过滤条件。~~
|
||||
- [x] ~~识别状态过滤条件。~~
|
||||
- [x] ~~识别金额阈值过滤条件。~~
|
||||
- [x] ~~识别排序要求。~~
|
||||
- [x] ~~识别 Top N 要求。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~“列出金额最高的 10 笔报销”能识别排序和 Top 10。~~
|
||||
|
||||
## 8. 解析风险与权限
|
||||
|
||||
- [x] ~~重复报销映射到 `duplicate_expense`。~~
|
||||
- [x] ~~发票异常映射到 `invoice_anomaly`。~~
|
||||
- [x] ~~金额超标映射到 `amount_over_limit`。~~
|
||||
- [x] ~~逾期应收映射到 `ar_overdue`。~~
|
||||
- [x] ~~逾期应付映射到 `ap_overdue`。~~
|
||||
- [x] ~~查询类问题权限为 `read`。~~
|
||||
- [x] ~~生成草稿权限为 `draft_write`。~~
|
||||
- [x] ~~审批、上线、付款类动作权限为 `approval_required`。~~
|
||||
- [x] ~~越权动作权限为 `forbidden`。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~“帮我直接付款”不能被标为可直接执行。~~
|
||||
|
||||
## 9. API 接口
|
||||
|
||||
- [x] ~~新增 `POST /api/v1/ontology/parse`。~~
|
||||
- [x] ~~请求参数包含用户问题。~~
|
||||
- [x] ~~请求参数包含用户上下文。~~
|
||||
- [x] ~~响应包含 8 个字段。~~
|
||||
- [x] ~~响应包含 `run_id`。~~
|
||||
- [x] ~~响应包含置信度。~~
|
||||
- [x] ~~响应包含澄清问题。~~
|
||||
- [x] ~~每次调用写入 `SemanticParseLog`。~~
|
||||
- [x] ~~每次调用写入 `AgentRun` 或关联已有 `AgentRun`。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~连续调用多次都能在日志中查到。~~
|
||||
|
||||
## 10. 前端调试入口
|
||||
|
||||
- [x] ~~在合适页面增加语义解析调试入口。~~
|
||||
- [x] ~~输入框支持自然语言问题。~~
|
||||
- [x] ~~点击解析后调用 API。~~
|
||||
- [x] ~~展示 8 个字段。~~
|
||||
- [x] ~~展示 JSON 原始结果。~~
|
||||
- [x] ~~展示置信度。~~
|
||||
- [x] ~~展示澄清问题。~~
|
||||
- [x] ~~展示 `run_id`。~~
|
||||
- [x] ~~错误时展示错误信息。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~产品和开发可以直接在页面验证解析结果。~~
|
||||
|
||||
## 11. 评测集
|
||||
|
||||
- [x] ~~创建至少 5 条报销问题。~~
|
||||
- [ ] 创建至少 5 条叙述型报销问题。
|
||||
- [ ] 创建至少 3 条附件 / OCR 摘要带入的报销问题。
|
||||
- [x] ~~创建至少 5 条应收问题。~~
|
||||
- [x] ~~创建至少 5 条应付问题。~~
|
||||
- [x] ~~创建至少 3 条知识库问题。~~
|
||||
- [x] ~~创建至少 3 条越权操作问题。~~
|
||||
- [ ] 创建至少 3 条模糊短句追问问题。
|
||||
- [x] ~~为每条问题写期望 `scenario`。~~
|
||||
- [x] ~~为每条问题写期望 `intent`。~~
|
||||
- [x] ~~为每条问题写期望权限级别。~~
|
||||
- [x] ~~编写评测脚本或测试。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~当前评测样本集已通过,覆盖样本准确率达到当天设定阈值。~~
|
||||
|
||||
## 12. Day 3 验收
|
||||
|
||||
- [x] ~~语义解析 API 可用。~~
|
||||
- [x] ~~8 个核心字段完整返回。~~
|
||||
- [x] ~~解析日志可查询。~~
|
||||
- [x] ~~低置信度问题有澄清问题。~~
|
||||
- [x] ~~越权动作不会被标为可执行。~~
|
||||
- [x] ~~前端调试入口可用。~~
|
||||
- [x] ~~评测集可运行。~~
|
||||
- [x] ~~所有完成项已用 `[x] ~~...~~` 标记。~~
|
||||
|
||||
## 阻塞记录
|
||||
|
||||
- [x] ~~暂无。~~
|
||||
|
||||
## 日终交接
|
||||
|
||||
- [x] ~~已支持报销 / 应收 / 应付 / 知识 / 风险 / 草稿 / 越权动作等核心场景关键词、实体与权限解析。~~
|
||||
- [x] ~~语义层已可接收附件名称、附件数量和 OCR 摘要上下文,但这些样本仍需继续扩到评测集。~~
|
||||
- [x] ~~当前仍需继续扩充的弱样本主要是叙述型报销长句、附件/OCR 带入和模糊短句追问。~~
|
||||
- [x] ~~Day 4 可直接复用 `scenario / intent / entities / time_range / metrics / constraints / risk_flags / permission / confidence / missing_slots / ambiguity / parse_strategy / clarification_required / clarification_question / run_id`。~~
|
||||
@@ -1,254 +0,0 @@
|
||||
# Day 4:Orchestrator 运行时
|
||||
|
||||
## 今天的大开发点
|
||||
|
||||
建立统一调度层。用户请求和系统任务都先进入 Orchestrator,由它完成语义解析、权限判断、能力选择、Agent 路由、工具调用记录和失败降级。
|
||||
|
||||
## 为什么第四天做这个
|
||||
|
||||
没有 Orchestrator,User Agent 和 Hermes 会各自直接调用能力,权限、审计、降级、Trace 都会分散。生产系统必须有统一入口。
|
||||
|
||||
## 今天主要交付
|
||||
|
||||
- Orchestrator 请求和响应结构。
|
||||
- 用户请求路由到 User Agent。
|
||||
- 定时任务路由到 Hermes。
|
||||
- 权限级别判断。
|
||||
- 语义补槽完成后的报销草稿创建、草稿更新、提交动作路由。
|
||||
- 高风险动作确认机制。
|
||||
- 能力注册查询。
|
||||
- 工具调用封装。
|
||||
- AgentRun Trace 查询。
|
||||
- 失败降级返回。
|
||||
|
||||
## 当前完成情况
|
||||
|
||||
- [x] ~~`/api/v1/orchestrator/run`、统一路由、权限阻断、ToolCall 记录、Trace 和降级结果已经可用。~~
|
||||
- [x] ~~用户消息已能路由到 User Agent,占位 Hermes 任务也能由定时入口触发。~~
|
||||
- [x] ~~附件名称、页面上下文和 OCR 摘要已能随 Orchestrator 请求透传到语义层和 User Agent。~~
|
||||
- [x] ~~Orchestrator 已开始向前端返回结构化 `review_payload`,用于右侧预审面板展示识别意图、槽位、票据和分单建议。~~
|
||||
- [x] ~~`conversation_id`、会话消息历史和 `draft_claim_id` 已接入 Orchestrator,会话内追问可继续落到同一张报销草稿。~~
|
||||
- [x] ~~已新增最近会话恢复与用户级会话清空接口,个人工作台可显式继续旧会话或删除旧会话后新建。~~
|
||||
- [x] ~~`clarification_required` 的报销请求已改为返回结构化核对结果,而不是只回一句追问文案。~~
|
||||
- [x] ~~`review_action`、`review_form_values` 已能透传到 User Agent / 报销草稿服务,用于结构化修改后重识别和保存草稿。~~
|
||||
- [ ] 真实 `expense_claims` 提交链路尚未接通;草稿建单 / 改单已接到真实落库,附件与 OCR 持久化仍未完成。
|
||||
- [ ] 报销附件持久化服务、OCR 结果落库服务和前端 ToolCall 细粒度 Trace 展示尚未接通。
|
||||
|
||||
相关架构文档:
|
||||
|
||||
- [Orchestrator 与运行流程](<../agent plan/04_orchestrator_and_runtime_flow.md>)
|
||||
- [能力注册](<../agent plan/07_capability_registry.md>)
|
||||
- [权限与确认](<../agent plan/08_permission_confirmation.md>)
|
||||
- [观测与 Trace](<../agent plan/09_observability_and_trace.md>)
|
||||
|
||||
## 当天验收门槛
|
||||
|
||||
- Orchestrator API 可用。
|
||||
- 用户消息能路由到 User Agent 占位实现。
|
||||
- 定时任务能路由到 Hermes 占位实现。
|
||||
- forbidden 请求不会调用下游 Agent。
|
||||
- 每次运行都有 `run_id` 和 Trace。
|
||||
- 工具调用失败能记录并返回降级结果。
|
||||
- 叙述型报销输入在满足最小槽位后能进入建单或改单流程。
|
||||
|
||||
## 今天不做
|
||||
|
||||
- 不做复杂任务编排 DAG。
|
||||
- 不做多 Agent 协商。
|
||||
- 不做自动高风险动作。
|
||||
|
||||
## 详细执行清单
|
||||
|
||||
以下内容为合并后的详细执行清单。
|
||||
|
||||
## 0. 开始前检查
|
||||
|
||||
- [x] ~~确认 Day 3 `POST /api/v1/ontology/parse` 可用。~~
|
||||
- [x] ~~确认 `AgentRun` 可创建。~~
|
||||
- [x] ~~确认 `AgentToolCall` 可创建。~~
|
||||
- [x] ~~确认资产列表能查询技能、MCP、任务。~~
|
||||
- [x] ~~确认权限级别枚举已稳定。~~
|
||||
- [x] ~~找到后端服务层适合放 Orchestrator 的位置。~~
|
||||
|
||||
## 1. Orchestrator 输入输出
|
||||
|
||||
- [x] ~~定义 `OrchestratorRequest`。~~
|
||||
- [x] ~~请求包含 `source`。~~
|
||||
- [x] ~~请求包含 `user_id`。~~
|
||||
- [x] ~~请求包含 `message`。~~
|
||||
- [x] ~~请求包含 `task_id`。~~
|
||||
- [x] ~~请求包含 `context_json`。~~
|
||||
- [x] ~~定义 `OrchestratorResponse`。~~
|
||||
- [x] ~~响应包含 `run_id`。~~
|
||||
- [x] ~~响应包含 `selected_agent`。~~
|
||||
- [x] ~~响应包含 `route_reason`。~~
|
||||
- [x] ~~响应包含 `permission_level`。~~
|
||||
- [x] ~~响应包含 `status`。~~
|
||||
- [x] ~~响应包含 `result`。~~
|
||||
- [x] ~~响应包含 `requires_confirmation`。~~
|
||||
- [x] ~~响应包含 `trace_summary`。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~Orchestrator 响应能直接被前端展示。~~
|
||||
|
||||
## 2. 建立 Orchestrator 服务
|
||||
|
||||
- [x] ~~新增 `OrchestratorService`。~~
|
||||
- [x] ~~实现 `run(request)` 主入口。~~
|
||||
- [x] ~~主入口第一步创建 `AgentRun`。~~
|
||||
- [x] ~~主入口第二步调用语义解析。~~
|
||||
- [x] ~~主入口第三步执行权限判断。~~
|
||||
- [x] ~~主入口第四步选择 Agent。~~
|
||||
- [x] ~~主入口第五步调用目标 Agent 或返回阻断结果。~~
|
||||
- [x] ~~主入口第六步更新 `AgentRun` 状态。~~
|
||||
- [x] ~~所有异常都写入 `AgentRun.error_message`。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~正常请求状态为 `succeeded`。~~
|
||||
- [x] ~~被权限拦截请求状态为 `blocked`。~~
|
||||
- [x] ~~异常请求状态为 `failed`。~~
|
||||
|
||||
## 3. 路由规则
|
||||
|
||||
- [x] ~~`source=user_message` 默认路由到 User Agent。~~
|
||||
- [x] ~~`source=schedule` 默认路由到 Hermes。~~
|
||||
- [x] ~~`intent=risk_check` 且来源为 schedule 时路由到 Hermes。~~
|
||||
- [x] ~~`intent=query` 且来源为 user_message 时路由到 User Agent。~~
|
||||
- [x] ~~`intent=explain` 路由到 User Agent。~~
|
||||
- [x] ~~`intent=draft` 路由到 User Agent,并可返回结构化核对结果、草稿结果或草稿更新结果。~~
|
||||
- [x] ~~`scenario=expense` 且最小建单槽位完整时,允许进入 `create_expense_claim_draft`。~~
|
||||
- [x] ~~`scenario=expense` 且已有 `claim_id` 或会话内 `draft_claim_id` 时,允许进入 `update_expense_claim_draft`。~~
|
||||
- [ ] `scenario=expense` 且用户明确确认提交时,允许进入 `submit_expense_claim`。
|
||||
- [x] ~~`permission.level=approval_required` 时设置 `requires_confirmation=true`。~~
|
||||
- [x] ~~`permission.level=forbidden` 时不调用下游 Agent。~~
|
||||
- [x] ~~无法识别或信息不足时返回澄清问题。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~同一句风险检查,在用户入口和任务入口有不同路由结果。~~
|
||||
|
||||
## 4. 权限判断
|
||||
|
||||
- [x] ~~新增权限判断服务或函数。~~
|
||||
- [x] ~~查询类请求返回 `read`。~~
|
||||
- [x] ~~草稿类请求返回 `draft_write`。~~
|
||||
- [ ] 报销草稿字段补全、附件挂接返回 `draft_write`。
|
||||
- [ ] 报销单提交返回 `approval_required`,并要求显式用户确认。
|
||||
- [ ] 审批、上线、付款类请求返回 `approval_required`。
|
||||
- [x] ~~用户无权限时返回 `forbidden`。~~
|
||||
- [x] ~~高风险动作不允许自动执行。~~
|
||||
- [x] ~~需要确认的动作返回确认提示。~~
|
||||
- [x] ~~权限判断结果写入 `AgentRun.permission_level`。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~“直接上线规则”不会被自动执行。~~
|
||||
- [x] ~~“直接付款”不会被自动执行。~~
|
||||
|
||||
## 5. 能力注册查询
|
||||
|
||||
- [x] ~~从 `AgentAsset` 查询 active 技能。~~
|
||||
- [x] ~~从 `AgentAsset` 查询 active MCP。~~
|
||||
- [x] ~~从 `AgentAsset` 查询 active 任务。~~
|
||||
- [ ] 查询可用的报销单写入服务和附件挂接服务。
|
||||
- [ ] 查询可用的 OCR 结果持久化服务和票据文件回溯服务。
|
||||
- [x] ~~过滤 disabled 能力。~~
|
||||
- [x] ~~过滤未审核 active 条件不满足的规则。~~
|
||||
- [x] ~~为每次能力选择记录 `route_json`。~~
|
||||
- [x] ~~找不到能力时返回降级说明。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~禁用 MCP 不会被 Orchestrator 调用。~~
|
||||
|
||||
## 6. 工具调用封装
|
||||
|
||||
- [x] ~~定义统一工具调用接口。~~
|
||||
- [ ] 工具请求前写入 `AgentToolCall` running 或准备记录。
|
||||
- [x] ~~工具成功后写入响应和耗时。~~
|
||||
- [x] ~~工具失败后写入错误。~~
|
||||
- [ ] 报销草稿更新、提交也按工具调用或等价服务调用记录。
|
||||
- [x] ~~报销草稿创建按工具调用或等价服务调用记录。~~
|
||||
- [ ] 附件挂接、OCR 结果落库、票据回溯查询也按工具调用或等价服务调用记录。
|
||||
- [x] ~~外部 MCP 调用失败时返回降级结果。~~
|
||||
- [x] ~~数据库查询失败时返回明确错误。~~
|
||||
- [x] ~~LLM 调用失败时返回可读提示。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~每次 Orchestrator 运行至少可以看到 0 到多条工具调用记录。~~
|
||||
|
||||
## 7. API 接口
|
||||
|
||||
- [x] ~~新增 `POST /api/v1/orchestrator/run`。~~
|
||||
- [x] ~~请求支持用户消息。~~
|
||||
- [x] ~~请求支持任务触发。~~
|
||||
- [x] ~~响应返回 `run_id`。~~
|
||||
- [x] ~~响应返回路由结果。~~
|
||||
- [x] ~~响应返回权限结果。~~
|
||||
- [x] ~~复用 `GET /api/v1/agent-runs/{run_id}` 查看 Trace。~~
|
||||
- [x] ~~Trace 接口返回语义解析、路由、工具调用、最终结果。~~
|
||||
- [x] ~~`POST /api/v1/orchestrator/run` 返回的 `result` 已可携带 `review_payload`。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~前端或 curl 可以完整看到一次运行链路。~~
|
||||
|
||||
## 8. 前端最小 Trace 查看
|
||||
|
||||
- [ ] 在合适位置展示最近运行记录。
|
||||
- [x] ~~点击当前对话结果可查看 `run_id`。~~
|
||||
- [x] ~~展示 selected_agent。~~
|
||||
- [x] ~~展示 route_reason。~~
|
||||
- [x] ~~展示 permission_level。~~
|
||||
- [ ] 展示工具调用列表。
|
||||
- [x] ~~展示错误信息。~~
|
||||
- [ ] 展示耗时。
|
||||
- [ ] 展示报销写链路中的 claim_id / claim_no / status 变化。
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~开发调试时不需要直接查数据库才能理解主要路由结果。~~
|
||||
|
||||
## 9. 测试
|
||||
|
||||
- [x] ~~测试用户查询路由到 User Agent。~~
|
||||
- [x] ~~测试定时任务路由到 Hermes。~~
|
||||
- [x] ~~测试叙述型报销输入可路由到报销建单服务。~~
|
||||
- [x] ~~测试同一 `conversation_id` 下的追问会继续更新已有报销草稿。~~
|
||||
- [ ] 测试报销单提交前必须显式确认。
|
||||
- [x] ~~测试 forbidden 不调用下游 Agent。~~
|
||||
- [x] ~~测试 approval_required 返回确认。~~
|
||||
- [x] ~~测试工具失败写入 ToolCall。~~
|
||||
- [x] ~~测试 Orchestrator 异常写入 AgentRun。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~Orchestrator 核心测试通过。~~
|
||||
|
||||
## 10. Day 4 验收
|
||||
|
||||
- [x] ~~Orchestrator API 可用。~~
|
||||
- [x] ~~用户请求能路由到 User Agent 占位实现。~~
|
||||
- [x] ~~定时任务能路由到 Hermes 占位实现。~~
|
||||
- [x] ~~语义补槽完成后的报销输入能路由到建单动作。~~
|
||||
- [x] ~~语义补槽完成后的报销输入能路由到改单动作。~~
|
||||
- [x] ~~权限阻断有效。~~
|
||||
- [x] ~~运行 Trace 可查询。~~
|
||||
- [x] ~~工具调用日志可查询。~~
|
||||
- [x] ~~降级结果可读。~~
|
||||
- [x] ~~所有完成项已用 `[x] ~~...~~` 标记。~~
|
||||
|
||||
## 阻塞记录
|
||||
|
||||
- [x] ~~暂无。~~
|
||||
|
||||
## 日终交接
|
||||
|
||||
- [x] ~~当前路由规则已稳定为:`user_message -> user_agent`、`schedule -> hermes`、`clarification_required -> blocked`。~~
|
||||
- [x] ~~当前权限判断已稳定为:`read / draft_write / approval_required / forbidden`,高风险动作默认阻断或要求确认。~~
|
||||
- [x] ~~Day 5 需承接的接口契约已明确:Orchestrator 向 User Agent 传入语义结果、能力码、工具结果,并期待返回 `answer / citations / suggested_actions / draft_payload / risk_flags`。~~
|
||||
- [x] ~~Day 5 当前已扩展接口契约:除 `answer / citations / suggested_actions / draft_payload / risk_flags` 外,还返回 `review_payload` 用于前端预审工作台。~~
|
||||
- [x] ~~下一步仍需补齐的运行时写链路是:附件持久化、OCR 结果落库和提交状态流转。~~
|
||||
@@ -1,284 +0,0 @@
|
||||
# Day 5:User Agent MVP
|
||||
|
||||
## 今天的大开发点
|
||||
|
||||
实现面向用户的自建 Agent。它负责用户提问、流程辅助、规则解释、查询结果解释和草稿生成。
|
||||
|
||||
User Agent 只能处理用户侧交互,不负责后台定时内循环,也不能自动执行高风险动作。
|
||||
|
||||
## 为什么第五天做这个
|
||||
|
||||
Day 1 到 Day 4 已经具备资产、语义、路由和日志基础,此时可以把用户自然语言入口接到真实流程上。
|
||||
|
||||
## 今天主要交付
|
||||
|
||||
- 用户自然语言入口。
|
||||
- 对话入口透传首句文本、附件名称和页面上下文。
|
||||
- 语义识别完整后创建报销单草稿。
|
||||
- 对话补充字段时更新报销主表、明细和附件关联。
|
||||
- 用户确认后触发报销单提交和状态变更。
|
||||
- 报销查询和解释。
|
||||
- 应收查询和解释。
|
||||
- 应付查询和解释。
|
||||
- 规则引用解释。
|
||||
- 风险原因说明。
|
||||
- 处理意见草稿。
|
||||
- 知识库读取骨架。
|
||||
- 低置信度场景的澄清追问。
|
||||
- 前端问答或操作入口。
|
||||
|
||||
## 当前完成情况
|
||||
|
||||
- [x] ~~个人工作台、报销对话框和通用聊天入口已经接通真实 Orchestrator / User Agent 问答链路。~~
|
||||
- [x] ~~回答、规则引用、风险说明、建议动作和结构化 `draft_payload` 已可返回。~~
|
||||
- [x] ~~报销对话框已接入 OCR 识别接口,附件名称、OCR 摘要和页面上下文已能透传到 Orchestrator / User Agent。~~
|
||||
- [x] ~~右侧工作台已开始展示结构化 `review_payload`,并已收敛为“识别结果专用区”:核心识别摘要、时间换算说明、逐票据识别结果、可能单据类型、建议归属费用和 OCR 置信度。~~
|
||||
- [x] ~~个人工作台和报销对话框已接入 `conversation_id` / `draft_claim_id`,同一会话内的连续追问不再按全新请求处理。~~
|
||||
- [x] ~~个人工作台已支持“继续会话 / 新建会话”,并可恢复最近一次用户会话或清空旧会话后重新开始。~~
|
||||
- [x] ~~报销核对流已切到产品化交互:正文区负责 AI 式核对提示、待补充信息、风险提醒和底部动作区,右侧只承载识别结果与票据识别明细,动作固定为“取消 / 修改识别信息 / 保存草稿或下一步”。~~
|
||||
- [ ] 真实 `document_assets` / `document_asset_versions` / `expense_item_documents` / `document_ocr_results` 落库,以及 `draft -> submitted` 状态流转尚未完成;`expense_claims` / `expense_claim_items` 草稿已接通真实落库。
|
||||
|
||||
相关架构文档:
|
||||
|
||||
- [Agent 职责边界](<../agent plan/03_agent_responsibilities.md>)
|
||||
- [Orchestrator 与运行流程](<../agent plan/04_orchestrator_and_runtime_flow.md>)
|
||||
- [LLM Wiki 知识库架构](<../agent plan/12_llm_wiki_knowledge_architecture.md>)
|
||||
- [规则形成生命周期](<../agent plan/13_rule_formation_lifecycle.md>)
|
||||
|
||||
## 当天验收门槛
|
||||
|
||||
- 用户能输入自然语言问题。
|
||||
- 请求必须经过 Orchestrator。
|
||||
- 至少 3 类财务问题有可读回答。
|
||||
- 叙述型报销输入在最小槽位满足后能创建 `expense_claims` 草稿。
|
||||
- 用户确认提交后可把报销单从 `draft` 变更为 `submitted`。
|
||||
- 回答能引用规则或知识。
|
||||
- 语义低置信度时不会答非所问,而是追问。
|
||||
- 高风险动作只生成草稿或建议。
|
||||
- AgentRun Trace 能看到 User Agent 步骤。
|
||||
|
||||
## 今天不做
|
||||
|
||||
- 不做自动审批。
|
||||
- 不做自动付款。
|
||||
- 不做自动上线规则。
|
||||
- 不做完整知识库检索优化。
|
||||
- 不假装已读懂未解析的附件内容。
|
||||
|
||||
## 详细执行清单
|
||||
|
||||
以下内容为合并后的详细执行清单。
|
||||
|
||||
## 0. 开始前检查
|
||||
|
||||
- [x] ~~确认 Orchestrator 能把用户请求路由到 User Agent。~~
|
||||
- [x] ~~确认语义本体 8 字段可用。~~
|
||||
- [x] ~~确认语义层已接入真实模型,而不是仅靠关键词规则。~~
|
||||
- [x] ~~确认规则资产可查询。~~
|
||||
- [x] ~~确认 AgentRun 和 ToolCall 可记录。~~
|
||||
- [x] ~~确认已有现成对话 UI 可复用。~~
|
||||
- [x] ~~确认财务业务数据已可通过最小真实数据查询。~~
|
||||
- [x] ~~当前无需额外补最小 Mock 数据服务。~~
|
||||
|
||||
## 1. User Agent 输入输出
|
||||
|
||||
- [x] ~~定义 `UserAgentRequest`。~~
|
||||
- [x] ~~请求包含 `run_id`。~~
|
||||
- [x] ~~请求包含 `user_id`。~~
|
||||
- [x] ~~请求包含 `message`。~~
|
||||
- [x] ~~请求包含 `ontology`。~~
|
||||
- [x] ~~请求包含 `context_json`。~~
|
||||
- [x] ~~定义 `UserAgentResponse`。~~
|
||||
- [x] ~~响应包含 `answer`。~~
|
||||
- [x] ~~响应包含 `citations`。~~
|
||||
- [x] ~~响应包含 `suggested_actions`。~~
|
||||
- [x] ~~响应包含 `draft_payload`。~~
|
||||
- [x] ~~响应包含 `risk_flags`。~~
|
||||
- [x] ~~响应包含 `requires_confirmation`。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~User Agent 响应结构能被 Orchestrator 直接包装返回。~~
|
||||
|
||||
## 2. 查询处理
|
||||
|
||||
- [x] ~~实现报销查询处理器。~~
|
||||
- [x] ~~实现应收查询处理器。~~
|
||||
- [x] ~~实现应付查询处理器。~~
|
||||
- [ ] 查询前检查权限级别。
|
||||
- [x] ~~查询时记录 ToolCall。~~
|
||||
- [x] ~~查询失败时返回可读错误。~~
|
||||
- [x] ~~查询为空时返回空态解释。~~
|
||||
- [ ] 查询结果限制返回条数,避免一次返回过大。
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~“查本周报销金额”有可读回答。~~
|
||||
- [x] ~~“客户 A 本月应收多少”有可读回答。~~
|
||||
- [x] ~~“供应商 B 待付款多少”有可读回答。~~
|
||||
|
||||
## 3. 规则解释
|
||||
|
||||
- [x] ~~根据语义场景查询相关规则资产。~~
|
||||
- [x] ~~只引用 active 规则。~~
|
||||
- [x] ~~读取规则当前版本 Markdown。~~
|
||||
- [x] ~~从 Markdown 中提取规则摘要。~~
|
||||
- [x] ~~回答中说明使用了哪些规则。~~
|
||||
- [x] ~~回答中包含规则版本号。~~
|
||||
- [x] ~~回答中包含规则更新时间。~~
|
||||
- [x] ~~没有相关规则时说明缺失。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~“为什么这笔报销有风险”能引用规则。~~
|
||||
|
||||
## 4. 风险解释
|
||||
|
||||
- [x] ~~识别重复报销风险。~~
|
||||
- [x] ~~识别金额超标风险。~~
|
||||
- [x] ~~识别发票异常风险。~~
|
||||
- [x] ~~识别逾期应收风险。~~
|
||||
- [x] ~~识别逾期应付风险。~~
|
||||
- [x] ~~风险回答包含风险类型。~~
|
||||
- [x] ~~风险回答包含触发原因。~~
|
||||
- [x] ~~风险回答包含建议处理动作。~~
|
||||
- [x] ~~高风险建议不能变成自动执行。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~风险解释结果不是单纯“有风险”,而是有依据。~~
|
||||
|
||||
## 5. 草稿生成与单据落库
|
||||
|
||||
- [x] ~~支持根据语义结果创建 `expense_claims` 草稿。~~
|
||||
- [x] ~~报销草稿初始状态写为 `draft`。~~
|
||||
- [x] ~~支持根据语义结果创建或更新 `expense_claim_items`。~~
|
||||
- [ ] 支持把用户上传附件挂到 `document_assets`、`document_asset_versions`、`expense_item_documents`。
|
||||
- [ ] 支持把 OCR 识别快照写入 `document_ocr_results`,并保留 `ocr_engine`、`ocr_model`、`raw_json`、`confidence`。
|
||||
- [x] ~~对话中补充金额、发生时间、费用类型等已落地字段后,能回写已有草稿而不是只更新内存结果。~~
|
||||
- [x] ~~支持生成报销处理意见草稿。~~
|
||||
- [x] ~~支持生成应收催收建议草稿。~~
|
||||
- [x] ~~支持生成应付付款建议草稿。~~
|
||||
- [ ] 用户明确确认“提交报销”后,把 `expense_claims.status` 从 `draft` 更新为 `submitted`。
|
||||
- [ ] 报销提交时写入 `submitted_at`。
|
||||
- [ ] 报销状态变更写入审计日志。
|
||||
- [ ] 报销状态变更写入 AgentRun 结果。
|
||||
- [x] ~~草稿中标明“待人工确认”。~~
|
||||
- [x] ~~草稿不直接提交业务系统。~~
|
||||
- [x] ~~草稿生成写入审计日志。~~
|
||||
- [x] ~~草稿生成写入 AgentRun 结果。~~
|
||||
- [ ] 草稿创建或更新后向前端返回 `attachment_ids`。
|
||||
- [x] ~~草稿创建或更新后向前端返回 `claim_id`、`claim_no`、`status`。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [ ] “我今天去客户现场,招待了客户,花销了1000元”在补齐必要字段后可创建报销草稿。
|
||||
- [ ] “帮我提交这笔报销”在确认后只把状态改到 `submitted`,不会直接改成 `approved` 或 `paid`。
|
||||
- [x] ~~“帮我生成处理意见”只返回草稿,不执行审批。~~
|
||||
|
||||
## 6. 知识库读取骨架
|
||||
|
||||
- [ ] 建立知识条目查询接口或服务。
|
||||
- [ ] 支持按关键词查询知识条目。
|
||||
- [ ] 支持按业务场景查询知识条目。
|
||||
- [ ] User Agent 回答可以引用知识条目。
|
||||
- [ ] 引用中包含知识标题。
|
||||
- [ ] 引用中包含更新时间。
|
||||
- [ ] 知识库不可用时返回降级说明。
|
||||
|
||||
验收证据:
|
||||
|
||||
- [ ] 知识库失败不会导致整个回答失败。
|
||||
|
||||
## 7. 对话或操作入口
|
||||
|
||||
- [x] ~~前端增加用户问题输入框。~~
|
||||
- [x] ~~输入框支持回车或按钮提交。~~
|
||||
- [x] ~~提交时调用 Orchestrator,而不是绕过 Orchestrator。~~
|
||||
- [x] ~~提交时透传首句文本。~~
|
||||
- [x] ~~提交时透传附件名称。~~
|
||||
- [x] ~~提交时透传 OCR 摘要。~~
|
||||
- [x] ~~提交时透传页面上下文。~~
|
||||
- [x] ~~提交时透传 `conversation_id` 与 `draft_claim_id`。~~
|
||||
- [ ] 提交时透传附件 ID。
|
||||
- [x] ~~展示 Agent 回答。~~
|
||||
- [x] ~~展示引用规则或知识。~~
|
||||
- [x] ~~展示建议动作。~~
|
||||
- [x] ~~展示识别意图摘要、待确认字段和确认动作卡片。~~
|
||||
- [x] ~~正文区改为简洁核对提示,不再堆叠调度结果或运行明细。~~
|
||||
- [x] ~~正文区待补充信息和风险提示已改为紧凑高亮样式,避免出现大段冗长说明。~~
|
||||
- [x] ~~展示逐票据 OCR 识别结果,并支持按 1、2、3… 顺序查看。~~
|
||||
- [x] ~~右侧逐票据结果已补充“可能单据类型 / 建议归属费用 / 识别置信度”等识别信息。~~
|
||||
- [x] ~~展示多场景票据的分单建议。~~
|
||||
- [ ] 展示报销草稿 ID 或 claim_no。
|
||||
- [ ] 展示当前报销状态。
|
||||
- [x] ~~展示需要人工确认的提示。~~
|
||||
- [x] ~~展示 `run_id`。~~
|
||||
- [x] ~~展示加载态。~~
|
||||
- [x] ~~展示错误态。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~用户可在页面完成一次问答闭环。~~
|
||||
|
||||
## 8. 安全边界
|
||||
|
||||
- [x] ~~User Agent 不直接修改规则状态。~~
|
||||
- [x] ~~User Agent 不直接上线规则。~~
|
||||
- [x] ~~User Agent 不直接审批报销。~~
|
||||
- [x] ~~User Agent 不直接把报销单改为 `approved` 或 `paid`。~~
|
||||
- [x] ~~User Agent 不直接付款。~~
|
||||
- [x] ~~User Agent 不直接删除知识。~~
|
||||
- [x] ~~所有高风险动作只返回建议或草稿。~~
|
||||
- [ ] 报销从 `draft` 变更到 `submitted` 之前必须有用户确认。
|
||||
- [ ] 所有草稿动作标记 `requires_confirmation=true`。
|
||||
- [x] ~~语义低置信度时优先追问,不返回答非所问的查询结果。~~
|
||||
- [x] ~~没有 OCR/VLM 结果时,不假装读懂图片或票据内容。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~提示词要求“直接付款”时仍被阻断。~~
|
||||
|
||||
## 9. 测试
|
||||
|
||||
- [x] ~~测试报销查询。~~
|
||||
- [x] ~~测试应收查询。~~
|
||||
- [ ] 测试应付查询。
|
||||
- [ ] 测试规则解释。
|
||||
- [x] ~~测试风险解释。~~
|
||||
- [ ] 测试 OCR 摘要透传后,User Agent 能在回答中正确引用附件语境而不编造内容。
|
||||
- [x] ~~测试报销草稿创建。~~
|
||||
- [x] ~~测试报销草稿补槽更新。~~
|
||||
- [ ] 测试报销状态从 `draft` 变更到 `submitted`。
|
||||
- [x] ~~测试草稿生成。~~
|
||||
- [ ] 测试越权动作阻断。
|
||||
- [ ] 测试知识库降级。
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~User Agent 核心测试通过。~~
|
||||
|
||||
## 10. Day 5 验收
|
||||
|
||||
- [x] ~~User Agent 服务可被 Orchestrator 调用。~~
|
||||
- [x] ~~用户入口可提交自然语言问题。~~
|
||||
- [x] ~~至少 3 个财务场景有回答。~~
|
||||
- [x] ~~语义识别完整后的报销输入能创建报销草稿。~~
|
||||
- [ ] 用户确认后能提交报销并更新状态。
|
||||
- [x] ~~回答能引用规则或知识。~~
|
||||
- [x] ~~高风险动作不会自动执行。~~
|
||||
- [x] ~~AgentRun Trace 能看到 User Agent 步骤。~~
|
||||
- [x] ~~前端构建通过。~~
|
||||
- [x] ~~所有完成项已用 `[x] ~~...~~` 标记。~~
|
||||
|
||||
## 阻塞记录
|
||||
|
||||
- [x] ~~暂无。~~
|
||||
|
||||
## 日终交接
|
||||
|
||||
- [x] ~~当前已支持报销 / 应收 / 应付查询、规则解释、风险解释、草稿建议与澄清追问。~~
|
||||
- [x] ~~当前已支持附件名称、OCR 摘要和页面上下文进入对话链路,但这还不是附件真实持久化。~~
|
||||
- [x] ~~当前已把用户一句话和多票据输入转成结构化预审面板,开始支持字段确认、票据核对和分单建议,而不再只是返回一段文本。~~
|
||||
- [x] ~~当前仍是占位的主要能力是报销单真实落库、附件持久化、OCR 结果入表和知识库读取,不再是简单静态问答 Mock。~~
|
||||
- [x] ~~Day 6 Hermes 可直接复用当前的规则检查、风险标签和 Orchestrator Trace / ToolCall 契约。~~
|
||||
@@ -1,343 +0,0 @@
|
||||
# Day 6:Hermes MVP
|
||||
|
||||
## 今天的大开发点
|
||||
|
||||
实现 Hermes 数字员工的最小闭环。Hermes 负责后台内循环:定时巡检、统计日报、风险预警、知识维护、规则草稿形成。
|
||||
|
||||
## 为什么第六天做这个
|
||||
|
||||
Hermes 依赖前几天已经建立的资产、规则、语义、Orchestrator、Trace 和权限体系。放在第六天做,可以避免它变成孤立脚本。
|
||||
|
||||
## 今天主要交付
|
||||
|
||||
- 任务资产调度入口。
|
||||
- 手动触发任务 API。
|
||||
- 系统 Hermes 后台执行入口。
|
||||
- 每日风险巡检。
|
||||
- 每日报销、报账、账款统计。
|
||||
- OCR Mock 接入点。
|
||||
- 知识候选条目生成。
|
||||
- 规则草稿生成。
|
||||
- LLM Wiki 解析目录与增量重建机制。
|
||||
- Hermes 运行结果展示。
|
||||
|
||||
相关架构文档:
|
||||
|
||||
- [Agent 职责边界](<../agent plan/03_agent_responsibilities.md>)
|
||||
- [OCR 票据识别架构](<../agent plan/11_ocr_invoice_architecture.md>)
|
||||
- [LLM Wiki 知识库架构](<../agent plan/12_llm_wiki_knowledge_architecture.md>)
|
||||
- [反馈学习闭环](<../agent plan/15_feedback_learning_loop.md>)
|
||||
|
||||
## 当天验收门槛
|
||||
|
||||
- 至少一个 Hermes 任务可以手动触发。
|
||||
- 风险巡检有结构化结果。
|
||||
- 每日统计有结构化结果。
|
||||
- OCR Mock 调用能记录 ToolCall。
|
||||
- 知识候选只能是草稿。
|
||||
- 规则草稿只能是 draft,不能自动上线。
|
||||
|
||||
## 今天不做
|
||||
|
||||
- 不做完整生产调度集群。
|
||||
- 不做真实 OCR 深度集成。
|
||||
- 不做自动发布知识。
|
||||
- 不做自动上线规则。
|
||||
- 不做每天无差别全量重建 LLM Wiki。
|
||||
|
||||
## 本次新增约束
|
||||
|
||||
### 1. Hermes 必须是系统后台 Hermes
|
||||
|
||||
这次 Hermes 不应继续只是代码里的占位逻辑。
|
||||
|
||||
最小可接受形态:
|
||||
|
||||
- 后端任务入口能明确区分 `selected_agent=hermes`。
|
||||
- 后端可调用系统安装的 Hermes CLI 或受控 Hermes 进程。
|
||||
- 即使当前阶段仍允许 Python 内部 fallback,也必须保留真实 Hermes 进程接入点。
|
||||
- Hermes 的模型配置继续由系统设置同步,不允许在任务代码里再写一套模型配置。
|
||||
- Hermes 执行应记录 `run_id`、ToolCall、错误信息和最终摘要。
|
||||
|
||||
### 2. LLM Wiki 必须有独立解析目录
|
||||
|
||||
原始知识文件与解析产物必须分离。
|
||||
|
||||
推荐目录:
|
||||
|
||||
```text
|
||||
/app/server/storage/knowledge/报销制度 原始制度文件
|
||||
/app/server/storage/knowledge/.llm_wiki 解析产物根目录
|
||||
/app/server/storage/knowledge/.llm_wiki/documents/<document_id>/
|
||||
document.json
|
||||
text.md
|
||||
chunks.json
|
||||
clauses.json
|
||||
knowledge_candidates.json
|
||||
rule_candidates.json
|
||||
/app/server/storage/knowledge/.llm_wiki/index.json
|
||||
/app/server/storage/knowledge/.llm_wiki/sync_runs.json
|
||||
```
|
||||
|
||||
### 3. LLM Wiki 只能增量形成
|
||||
|
||||
不允许每天无脑全量重建。
|
||||
|
||||
文档级重建触发条件至少包括:
|
||||
|
||||
- 文件名 `original_name` 变更。
|
||||
- 文件对象 `stored_name` 变更。
|
||||
- 内容摘要 `sha256` 变更。
|
||||
- 上传版本 `version_number` 变更。
|
||||
- 更新时间 `updated_at` 变更,视为人工改动。
|
||||
|
||||
如果以上条件都未变化:
|
||||
|
||||
- 本次文档应标记为 `unchanged_skipped`。
|
||||
- 不重新抽取文本。
|
||||
- 不重新生成知识候选。
|
||||
- 不重新生成规则草稿。
|
||||
|
||||
### 4. 规则草稿必须模板化
|
||||
|
||||
Hermes 不允许自由生成任意结构的规则。
|
||||
|
||||
必须满足:
|
||||
|
||||
- 规则 Markdown 使用固定模板。
|
||||
- 可执行规则 JSON 使用固定模板族,不允许随意拼字段。
|
||||
- 规则中心要同时展示人类可读的 Markdown 和机器可执行的 JSON。
|
||||
- Hermes 生成的规则默认 `draft`。
|
||||
- 审核通过前不能 `active`。
|
||||
- Hermes 不能直接覆盖线上 active 规则。
|
||||
|
||||
## 详细执行清单
|
||||
|
||||
以下内容为合并后的详细执行清单。
|
||||
|
||||
## 本轮追加范围(2026-05-15)
|
||||
|
||||
本轮不扩散到新的业务能力,先把已经落地的 LLM Wiki 归纳链路收紧成可运维、可追踪、可持续运行的形态。
|
||||
|
||||
本轮目标:
|
||||
|
||||
- 把知识管理中的 Hermes 归纳从同步请求改成后台异步任务。
|
||||
- 用户关闭或切走页面后,归纳任务仍继续执行,不因前端页面生命周期被误判失败。
|
||||
- 归纳过程中的状态、进度、摘要、异常统一写入 `AgentRun.route_json` 与 `result_summary`。
|
||||
- 知识管理页轮询真实任务状态,任务完成后立刻把文档状态从“正归纳”切到最终状态。
|
||||
- 右侧侧边栏新增“日志管理”入口。
|
||||
- 日志管理页拆成两类日志:
|
||||
- Hermes 调用日志:查看归纳任务运行状态、当前阶段、文档进度、ToolCall、错误信息。
|
||||
- 系统运行日志:直接查看 `server/logs` 下的系统日志文本。
|
||||
|
||||
本轮边界:
|
||||
|
||||
- 仍然使用系统 Hermes CLI 入口,不虚构不存在的 gateway 推理接口。
|
||||
- 不引入完整消息队列或 Celery 集群,先用后端受控后台任务管理器落地。
|
||||
- 不把日志页做成审计替代品,重点只覆盖 Hermes 运行日志和系统运行日志。
|
||||
- 不把普通用户开放为日志管理员,日志查看仍属于管理员能力。
|
||||
|
||||
## 0. 开始前检查
|
||||
|
||||
- [x] ~~确认任务资产 `asset_type=task` 可查询。~~
|
||||
- [x] ~~确认 Orchestrator 能处理 `source=schedule`。~~
|
||||
- [x] ~~确认系统 Hermes CLI 或等价后台 Hermes 进程可被调用。~~
|
||||
- [x] ~~确认 AgentRun 和 ToolCall 可记录。~~
|
||||
- [x] ~~确认是否已有后台任务框架。~~
|
||||
- [ ] 如果没有后台任务框架,先用手动触发 API 模拟定时执行。
|
||||
|
||||
## 1. Hermes 输入输出
|
||||
|
||||
- [ ] 定义 `HermesTaskRequest`。
|
||||
- [ ] 请求包含 `run_id`。
|
||||
- [ ] 请求包含 `task_asset_id`。
|
||||
- [ ] 请求包含 `task_type`。
|
||||
- [ ] 请求包含 `schedule_time`。
|
||||
- [ ] 请求包含 `context_json`。
|
||||
- [ ] 定义 `HermesTaskResult`。
|
||||
- [ ] 响应包含 `summary`。
|
||||
- [ ] 响应包含 `risk_items`。
|
||||
- [ ] 响应包含 `statistics`。
|
||||
- [ ] 响应包含 `knowledge_updates`。
|
||||
- [ ] 响应包含 `draft_rules`。
|
||||
- [ ] 响应包含 `next_actions`。
|
||||
|
||||
验收证据:
|
||||
|
||||
- [ ] Hermes 响应能被任务详情或运行日志展示。
|
||||
|
||||
## 2. 任务调度入口
|
||||
|
||||
- [x] ~~新增手动触发任务 API。~~
|
||||
- [x] ~~API 参数支持任务资产 ID。~~
|
||||
- [x] ~~API 调用 Orchestrator,source 为 `schedule`。~~
|
||||
- [x] ~~Orchestrator 路由到 Hermes。~~
|
||||
- [x] ~~Hermes 执行结果写入 AgentRun。~~
|
||||
- [ ] 任务执行失败时写入错误。
|
||||
- [ ] 任务执行结束后更新任务最近执行时间。
|
||||
- [ ] 任务执行结束后更新任务最近执行状态。
|
||||
- [x] ~~保留真实 Hermes 进程执行入口,不把 Hermes 固定写死为本地占位函数。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~可以手动触发一次 Hermes 任务并看到运行结果。~~
|
||||
|
||||
## 3. 每日风险巡检
|
||||
|
||||
- [ ] 实现重复报销巡检。
|
||||
- [ ] 实现金额超标巡检。
|
||||
- [ ] 实现发票异常巡检占位。
|
||||
- [ ] 实现应收逾期巡检。
|
||||
- [ ] 实现应付异常付款巡检。
|
||||
- [ ] 每个风险项包含风险类型。
|
||||
- [ ] 每个风险项包含业务对象。
|
||||
- [ ] 每个风险项包含触发规则。
|
||||
- [ ] 每个风险项包含建议动作。
|
||||
- [ ] 每个风险项包含风险等级。
|
||||
|
||||
验收证据:
|
||||
|
||||
- [ ] 风险巡检结果可以被用户理解和追溯。
|
||||
|
||||
## 4. 每日统计
|
||||
|
||||
- [ ] 统计当日报销单数量。
|
||||
- [ ] 统计当日报销金额。
|
||||
- [ ] 统计当日报账数量。
|
||||
- [ ] 统计当日报账金额。
|
||||
- [ ] 统计应收新增金额。
|
||||
- [ ] 统计应收逾期金额。
|
||||
- [ ] 统计应付待付金额。
|
||||
- [ ] 统计应付逾期金额。
|
||||
- [ ] 输出日报摘要。
|
||||
|
||||
验收证据:
|
||||
|
||||
- [ ] Hermes 能生成一份每日财务摘要。
|
||||
|
||||
## 5. OCR 接入点
|
||||
|
||||
- [ ] 原始票据先落 `document_assets` 和 `document_asset_versions`,不直接以内存临时文件参与流程。
|
||||
- [ ] 建立 OCR 识别服务接口。
|
||||
- [ ] 定义发票识别输入结构。
|
||||
- [ ] 定义发票识别输出结构。
|
||||
- [ ] 输出结构包含发票号。
|
||||
- [ ] 输出结构包含开票日期。
|
||||
- [ ] 输出结构包含金额。
|
||||
- [ ] 输出结构包含税额。
|
||||
- [ ] 输出结构包含销售方。
|
||||
- [ ] 输出结构包含购买方。
|
||||
- [ ] 输出结构包含置信度。
|
||||
- [ ] OCR 输入可通过 `storage_key` 或等价文件定位字段读取原件。
|
||||
- [ ] 当前阶段允许使用 Mock 结果。
|
||||
- [ ] OCR 调用写入 ToolCall。
|
||||
|
||||
验收证据:
|
||||
|
||||
- [ ] Hermes 风险巡检中可以调用 OCR Mock。
|
||||
|
||||
## 6. 知识库维护
|
||||
|
||||
- [ ] 建立知识条目写入服务。
|
||||
- [x] ~~建立 `.llm_wiki` 独立解析目录。~~
|
||||
- [x] ~~原始文档与解析产物物理隔离。~~
|
||||
- [x] ~~文本抽取结果落 `text.md`。~~
|
||||
- [x] ~~分块结果落 `chunks.json`。~~
|
||||
- [x] ~~文档索引落 `index.json`。~~
|
||||
- [x] ~~同步记录落 `sync_runs.json`。~~
|
||||
- [x] ~~文档签名包含 `original_name`、`stored_name`、`sha256`、`version_number`、`updated_at`。~~
|
||||
- [x] ~~未变化文档跳过重建并记录 `unchanged_skipped`。~~
|
||||
- [x] ~~Hermes 可以生成知识候选条目。~~
|
||||
- [x] ~~候选条目包含标题。~~
|
||||
- [x] ~~候选条目包含正文。~~
|
||||
- [x] ~~候选条目包含来源。~~
|
||||
- [x] ~~候选条目包含适用场景。~~
|
||||
- [x] ~~候选条目默认状态为 `draft`。~~
|
||||
- [x] ~~知识条目不能自动发布。~~
|
||||
- [ ] 知识条目写入审计日志。
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~Hermes 可以生成待审核知识条目。~~
|
||||
|
||||
## 7. 规则草稿形成
|
||||
|
||||
- [ ] Hermes 可以根据风险巡检结果生成规则草稿。
|
||||
- [x] ~~规则草稿使用固定 Markdown 模板。~~
|
||||
- [x] ~~规则草稿生成可执行 JSON 草稿。~~
|
||||
- [x] ~~规则中心展示 Markdown + JSON 双视图。~~
|
||||
- [x] ~~JSON 草稿字段受模板约束,不允许自由扩展。~~
|
||||
- [x] ~~规则草稿保存为 `asset_type=rule`。~~
|
||||
- [x] ~~规则草稿状态为 `draft`。~~
|
||||
- [x] ~~规则草稿包含 Markdown 内容。~~
|
||||
- [x] ~~规则草稿包含 JSON 内容或等价 `runtime_rule` 配置。~~
|
||||
- [ ] 规则草稿包含生成原因。
|
||||
- [ ] 规则草稿包含关联风险样例。
|
||||
- [x] ~~规则草稿不能自动上线。~~
|
||||
- [x] ~~规则草稿需要审核人。~~
|
||||
- [x] ~~规则草稿写入审计日志。~~
|
||||
- [x] ~~Hermes 不直接覆盖线上 active 规则。~~
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~Hermes 生成的新规则出现在规则列表中,但不是 active。~~
|
||||
|
||||
## 8. Hermes 页面或日志展示
|
||||
|
||||
- [x] ~~任务详情能看到最近执行结果。~~
|
||||
- [ ] 任务详情能手动触发执行。
|
||||
- [ ] 任务详情能看到风险项数量。
|
||||
- [ ] 任务详情能看到日报摘要。
|
||||
- [ ] 任务详情能看到知识候选数量。
|
||||
- [ ] 任务详情能看到规则草稿数量。
|
||||
- [ ] 运行 Trace 能看到 Hermes 步骤。
|
||||
- [x] ~~错误时展示错误原因。~~
|
||||
- [ ] 日志管理页能查看 Hermes 归纳任务的实时状态。
|
||||
- [ ] 日志管理页能查看 Hermes ToolCall 请求与结果。
|
||||
- [ ] 日志管理页能查看系统运行日志文本。
|
||||
- [ ] 知识管理页能在后台任务完成后自动刷新归纳状态。
|
||||
|
||||
验收证据:
|
||||
|
||||
- [x] ~~不查数据库也能判断 Hermes 是否执行成功。~~
|
||||
|
||||
## 9. 测试
|
||||
|
||||
- [x] ~~测试手动触发任务。~~
|
||||
- [x] ~~测试 Orchestrator 路由到 Hermes。~~
|
||||
- [ ] 测试风险巡检输出。
|
||||
- [ ] 测试日报统计输出。
|
||||
- [ ] 测试 OCR Mock 调用。
|
||||
- [x] ~~测试知识候选写入。~~
|
||||
- [x] ~~测试规则草稿生成。~~
|
||||
- [ ] 测试 Hermes 异常写入 AgentRun。
|
||||
- [ ] 测试知识归纳异步任务在接口返回后仍能继续执行。
|
||||
- [ ] 测试归纳进度能持续写入 AgentRun。
|
||||
- [ ] 测试系统日志读取接口。
|
||||
|
||||
验收证据:
|
||||
|
||||
- [ ] Hermes 核心测试通过。
|
||||
|
||||
## 10. Day 6 验收
|
||||
|
||||
- [x] ~~Hermes 可被 Orchestrator 调用。~~
|
||||
- [x] ~~至少一个任务可以手动触发。~~
|
||||
- [ ] 风险巡检有结构化结果。
|
||||
- [ ] 每日统计有结构化结果。
|
||||
- [ ] OCR Mock 接入点可用。
|
||||
- [x] ~~知识候选可生成。~~
|
||||
- [x] ~~规则草稿可生成且不能自动上线。~~
|
||||
- [x] ~~任务详情或运行日志能展示结果。~~
|
||||
- [x] ~~所有完成项已用 `[x] ~~...~~` 标记。~~
|
||||
|
||||
## 阻塞记录
|
||||
|
||||
- [ ] 暂无。
|
||||
|
||||
## 日终交接
|
||||
|
||||
- [ ] 写明 Hermes 已支持任务类型。
|
||||
- [ ] 写明 OCR 当前是真实还是 Mock。
|
||||
- [ ] 写明生成的知识和规则草稿状态。
|
||||
- [ ] 写明 Day 7 需要重点回归的路径。
|
||||
@@ -1,260 +0,0 @@
|
||||
# Day 7:加固、演示和验收
|
||||
|
||||
## 今天的大开发点
|
||||
|
||||
不再大规模扩功能,集中做回归、加固、测试、演示脚本、文档收尾和下一阶段交接。
|
||||
|
||||
## 为什么第七天做这个
|
||||
|
||||
一周开发不能只停留在“代码写了”。必须能演示、能追溯、能说清楚边界、能交给下一阶段继续开发。
|
||||
|
||||
## 今天主要交付
|
||||
|
||||
- 核心链路回归。
|
||||
- 权限和风险边界复查。
|
||||
- 审计日志补齐。
|
||||
- AgentRun Trace 补齐。
|
||||
- 前端体验修补。
|
||||
- 测试和构建记录。
|
||||
- 评测集执行记录。
|
||||
- 演示数据准备。
|
||||
- 演示脚本。
|
||||
- 下一阶段开发建议。
|
||||
|
||||
相关架构文档:
|
||||
|
||||
- [Agent Plan 总览](<../agent plan/00_README.md>)
|
||||
- [开发路线图](<../agent plan/05_development_roadmap.md>)
|
||||
- [观测与 Trace](<../agent plan/09_observability_and_trace.md>)
|
||||
- [评测与测试集](<../agent plan/10_evaluation_and_testset.md>)
|
||||
|
||||
## 当天验收门槛
|
||||
|
||||
- 任务规则中心核心路径可演示。
|
||||
- 语义本体、Orchestrator、User Agent、Hermes 都能跑通最小链路。
|
||||
- 未审核规则、高风险动作、自动付款等边界都被拦截。
|
||||
- AgentRun、ToolCall、AuditLog 可追溯。
|
||||
- 有测试记录、演示脚本和交接说明。
|
||||
|
||||
## 今天不做
|
||||
|
||||
- 不做新大功能。
|
||||
- 不临时扩大范围。
|
||||
- 不绕过测试和验收。
|
||||
|
||||
## 详细执行清单
|
||||
|
||||
以下内容为合并后的详细执行清单。
|
||||
|
||||
## 0. 开始前检查
|
||||
|
||||
- [ ] 汇总 Day 1 未完成项。
|
||||
- [ ] 汇总 Day 2 未完成项。
|
||||
- [ ] 汇总 Day 3 未完成项。
|
||||
- [ ] 汇总 Day 4 未完成项。
|
||||
- [ ] 汇总 Day 5 未完成项。
|
||||
- [ ] 汇总 Day 6 未完成项。
|
||||
- [ ] 标记必须今天修复的问题。
|
||||
- [ ] 标记可以进入下一阶段的问题。
|
||||
- [ ] 冻结新增需求,只处理验收相关问题。
|
||||
|
||||
## 1. 核心链路回归
|
||||
|
||||
- [ ] 回归资产列表接口。
|
||||
- [ ] 回归规则详情接口。
|
||||
- [ ] 回归 Markdown 保存。
|
||||
- [ ] 回归版本列表。
|
||||
- [ ] 回归版本切换。
|
||||
- [ ] 回归审核接口。
|
||||
- [ ] 回归上线拦截。
|
||||
- [ ] 回归语义解析接口。
|
||||
- [ ] 回归 Orchestrator 路由。
|
||||
- [ ] 回归 User Agent 问答。
|
||||
- [ ] 回归 Hermes 任务执行。
|
||||
- [ ] 回归 AgentRun Trace。
|
||||
- [ ] 回归 ToolCall 日志。
|
||||
- [ ] 回归 AuditLog 日志。
|
||||
|
||||
验收证据:
|
||||
|
||||
- [ ] 从前端能完成至少一条端到端演示路径。
|
||||
|
||||
## 2. 权限和风险边界
|
||||
|
||||
- [ ] 未审核规则不能上线。
|
||||
- [ ] rejected 规则不能上线。
|
||||
- [ ] disabled 能力不能被调用。
|
||||
- [ ] 用户请求付款必须拦截。
|
||||
- [ ] 用户请求审批必须需要确认。
|
||||
- [ ] Hermes 生成规则只能是 draft。
|
||||
- [ ] Hermes 生成知识只能是 draft。
|
||||
- [ ] User Agent 生成处理意见只能是草稿。
|
||||
- [ ] 所有高风险动作响应中包含 `requires_confirmation`。
|
||||
|
||||
验收证据:
|
||||
|
||||
- [ ] 不存在 MVP 期间绕过人工审核的路径。
|
||||
|
||||
## 3. 审计和 Trace 补齐
|
||||
|
||||
- [ ] 规则保存写 AuditLog。
|
||||
- [ ] 规则审核写 AuditLog。
|
||||
- [ ] 规则上线写 AuditLog。
|
||||
- [ ] Hermes 生成规则草稿写 AuditLog。
|
||||
- [ ] Hermes 生成知识候选写 AuditLog。
|
||||
- [ ] User Agent 草稿生成写 AuditLog。
|
||||
- [ ] Orchestrator 每次运行有 AgentRun。
|
||||
- [ ] 每次工具调用有 ToolCall。
|
||||
- [ ] Trace 页面或接口能串起 run_id。
|
||||
- [ ] 错误 Trace 包含 error_message。
|
||||
|
||||
验收证据:
|
||||
|
||||
- [ ] 任意一条演示链路都能追溯到 run_id。
|
||||
|
||||
## 4. 前端体验修补
|
||||
|
||||
- [ ] 任务规则中心列表无明显错位。
|
||||
- [ ] 详情页无双 title。
|
||||
- [ ] Hero title 高度紧凑。
|
||||
- [ ] 返回列表栏高度正常。
|
||||
- [ ] Markdown 编辑器和版本卡片底部对齐。
|
||||
- [ ] 版本卡片不贴右侧。
|
||||
- [ ] 当前版本标识不突兀。
|
||||
- [ ] 日期列对齐。
|
||||
- [ ] 弹窗文案清楚。
|
||||
- [ ] 加载态可见。
|
||||
- [ ] 错误态可见。
|
||||
- [ ] 空态可见。
|
||||
- [ ] 按钮禁用态可见。
|
||||
- [ ] 窄屏不出现内容重叠。
|
||||
|
||||
验收证据:
|
||||
|
||||
- [ ] 任务规则中心可以给业务用户演示,不需要解释 UI 异常。
|
||||
|
||||
## 5. 测试补齐
|
||||
|
||||
- [ ] 运行后端现有测试。
|
||||
- [ ] 运行新增模型测试。
|
||||
- [ ] 运行新增 API 测试。
|
||||
- [ ] 运行语义解析测试。
|
||||
- [ ] 运行 Orchestrator 测试。
|
||||
- [ ] 运行 User Agent 测试。
|
||||
- [ ] 运行 Hermes 测试。
|
||||
- [ ] 运行前端构建。
|
||||
- [ ] 如果有前端测试,运行前端测试。
|
||||
- [ ] 记录未能运行的测试和原因。
|
||||
|
||||
验收证据:
|
||||
|
||||
- [ ] 测试结果写入本文件“测试记录”。
|
||||
|
||||
## 6. 评测集
|
||||
|
||||
- [ ] 准备 5 条报销问题。
|
||||
- [ ] 准备 5 条应收问题。
|
||||
- [ ] 准备 5 条应付问题。
|
||||
- [ ] 准备 3 条规则解释问题。
|
||||
- [ ] 准备 3 条越权动作问题。
|
||||
- [ ] 执行语义解析评测。
|
||||
- [ ] 执行 User Agent 回答评测。
|
||||
- [ ] 执行权限拦截评测。
|
||||
- [ ] 记录失败样例。
|
||||
- [ ] 为失败样例写下一阶段优化建议。
|
||||
|
||||
验收证据:
|
||||
|
||||
- [ ] 可以说明 MVP 当前能力边界和准确率风险。
|
||||
|
||||
## 7. 演示数据
|
||||
|
||||
- [ ] 准备 active 规则。
|
||||
- [ ] 准备 pending 规则。
|
||||
- [ ] 准备 rejected 规则。
|
||||
- [ ] 准备至少一条报销数据。
|
||||
- [ ] 准备至少一条应收数据。
|
||||
- [ ] 准备至少一条应付数据。
|
||||
- [ ] 准备至少一个 Hermes 任务。
|
||||
- [ ] 准备至少一个 MCP Mock。
|
||||
- [ ] 准备至少一个知识条目。
|
||||
- [ ] 准备至少一个风险样例。
|
||||
|
||||
验收证据:
|
||||
|
||||
- [ ] 演示不会因为没有数据而中断。
|
||||
|
||||
## 8. 演示脚本
|
||||
|
||||
- [ ] 编写演示步骤 1:打开任务规则中心。
|
||||
- [ ] 编写演示步骤 2:查看规则详情。
|
||||
- [ ] 编写演示步骤 3:编辑 Markdown 并保存。
|
||||
- [ ] 编写演示步骤 4:切换版本。
|
||||
- [ ] 编写演示步骤 5:尝试上线未审核规则并被拦截。
|
||||
- [ ] 编写演示步骤 6:输入用户问题。
|
||||
- [ ] 编写演示步骤 7:查看语义本体结果。
|
||||
- [ ] 编写演示步骤 8:查看 User Agent 回答。
|
||||
- [ ] 编写演示步骤 9:手动触发 Hermes 任务。
|
||||
- [ ] 编写演示步骤 10:查看 AgentRun Trace。
|
||||
- [ ] 编写演示步骤 11:查看审计日志。
|
||||
|
||||
验收证据:
|
||||
|
||||
- [ ] 新开发者按脚本可以复现演示。
|
||||
|
||||
## 9. 文档收尾
|
||||
|
||||
- [ ] 更新一周计划完成情况。
|
||||
- [ ] 更新剩余风险。
|
||||
- [ ] 更新下一阶段开发建议。
|
||||
- [ ] 更新接口清单。
|
||||
- [ ] 更新数据模型清单。
|
||||
- [ ] 更新前端页面清单。
|
||||
- [ ] 更新评测结果。
|
||||
- [ ] 更新演示脚本。
|
||||
- [ ] 更新部署或启动说明。
|
||||
|
||||
验收证据:
|
||||
|
||||
- [ ] 文档能指导下一周继续开发。
|
||||
|
||||
## 10. 最终验收清单
|
||||
|
||||
- [ ] 任务规则中心可查看规则、技能、MCP、任务。
|
||||
- [ ] 规则详情可编辑 Markdown。
|
||||
- [ ] 规则详情可查看最近 5 个版本。
|
||||
- [ ] 版本切换有确认弹窗。
|
||||
- [ ] 审核者信息可见。
|
||||
- [ ] 未审核规则不能上线。
|
||||
- [ ] 语义本体 8 字段可返回。
|
||||
- [ ] Orchestrator 能路由用户请求。
|
||||
- [ ] Orchestrator 能路由定时任务。
|
||||
- [ ] User Agent 能回答至少 3 类财务问题。
|
||||
- [ ] Hermes 能执行至少 1 个任务。
|
||||
- [ ] OCR Mock 接入点可用。
|
||||
- [ ] 知识候选可生成。
|
||||
- [ ] 规则草稿可生成。
|
||||
- [ ] AgentRun Trace 可查。
|
||||
- [ ] AuditLog 可查。
|
||||
- [ ] 前端构建通过。
|
||||
- [ ] 后端核心测试通过。
|
||||
- [ ] 演示脚本可执行。
|
||||
- [ ] 所有完成项已用 `[x] ~~...~~` 标记。
|
||||
|
||||
## 测试记录
|
||||
|
||||
- [ ] 后端测试:未运行。
|
||||
- [ ] 前端构建:未运行。
|
||||
- [ ] 语义评测:未运行。
|
||||
- [ ] 手动验收:未运行。
|
||||
|
||||
## 阻塞记录
|
||||
|
||||
- [ ] 暂无。
|
||||
|
||||
## 日终交接
|
||||
|
||||
- [ ] 写明本周最终完成内容。
|
||||
- [ ] 写明未完成内容。
|
||||
- [ ] 写明生产化前必须补齐内容。
|
||||
- [ ] 写明下一周建议优先级。
|
||||
@@ -1,137 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Day 1 - 基础模型与工程骨架</title>
|
||||
<link rel="stylesheet" href="./styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="shell">
|
||||
<div class="topbar">
|
||||
<a class="brand" href="./index.html"><span class="brand-mark">D1</span><span>Day 1 View</span></a>
|
||||
<div class="quick-links">
|
||||
<a class="pill" href="./index.html">返回总览</a>
|
||||
<a class="pill" href="../agent%20week%20plan/day_1_foundation_models.md">周计划原文</a>
|
||||
<a class="pill" href="../agent%20week%20plan/day_1_foundation_models.md">合并文档原文</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="day-nav">
|
||||
<a class="pill active" href="./day-1.html">Day 1</a>
|
||||
<a class="pill" href="./day-2.html">Day 2</a>
|
||||
<a class="pill" href="./day-3.html">Day 3</a>
|
||||
<a class="pill" href="./day-4.html">Day 4</a>
|
||||
<a class="pill" href="./day-5.html">Day 5</a>
|
||||
<a class="pill" href="./day-6.html">Day 6</a>
|
||||
<a class="pill" href="./day-7.html">Day 7</a>
|
||||
</div>
|
||||
|
||||
<section class="hero">
|
||||
<div class="hero-badge">Foundation Completed</div>
|
||||
<h1>Day 1 基础模型与工程骨架</h1>
|
||||
<p>这一天的任务不是做炫目的业务能力,而是把后面 6 天要反复依赖的模型、版本、审核、run trace、审计日志和最小业务数据源一次定稳。Day 1 做虚了,Day 4 到 Day 6 会全部返工。</p>
|
||||
<div class="hero-meta">
|
||||
<div class="meta-card"><div class="meta-label">当前状态</div><div class="meta-value">已完成(2026-05-11),可直接进入 Day 2 联调。</div></div>
|
||||
<div class="meta-card"><div class="meta-label">上游依赖</div><div class="meta-value">无,Day 1 是全周底座。</div></div>
|
||||
<div class="meta-card"><div class="meta-label">下游交接</div><div class="meta-value">Day 2 资产 API,Day 3 解析日志,Day 4 run trace,Day 5/6 业务数据查询。</div></div>
|
||||
<div class="meta-card"><div class="meta-label">当天关键</div><div class="meta-value">先确定统一模型,再接 API 骨架和种子数据。</div></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="section-kicker">Three-Layer Mapping</div>
|
||||
<h2 class="section-title">三层文档映射</h2>
|
||||
<div class="grid three">
|
||||
<section class="card tone-warm">
|
||||
<h3>路线图</h3>
|
||||
<p>周计划里定义这一天要完成“工程地基”,强调只做稳定模型、API 骨架、种子数据、基础审计和可运行验证。</p>
|
||||
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_1_foundation_models.md">day_1_foundation_models.md</a></div>
|
||||
</section>
|
||||
<section class="card tone-teal">
|
||||
<h3>执行细则</h3>
|
||||
<p>执行层把 Day 1 拆成命名边界、最小财务业务数据模型、Agent 资产模型、版本、审核、Run、ToolCall、SemanticParseLog、AuditLog、Schema、API、服务层。</p>
|
||||
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_1_foundation_models.md">agent week plan/day_1</a></div>
|
||||
</section>
|
||||
<section class="card tone-olive">
|
||||
<h3>架构依据</h3>
|
||||
<p>主要受总体架构、语义本体、数据契约、能力注册、权限确认、可观测性和财务标准模型约束。</p>
|
||||
<div class="card-links">
|
||||
<a class="link-chip" href="../agent%20plan/01_overall_architecture.md">01</a>
|
||||
<a class="link-chip" href="../agent%20plan/02_semantic_ontology.md">02</a>
|
||||
<a class="link-chip" href="../agent%20plan/06_data_contracts_and_governance.md">06</a>
|
||||
<a class="link-chip" href="../agent%20plan/07_capability_registry.md">07</a>
|
||||
<a class="link-chip" href="../agent%20plan/08_permission_confirmation.md">08</a>
|
||||
<a class="link-chip" href="../agent%20plan/09_observability_and_trace.md">09</a>
|
||||
<a class="link-chip" href="../agent%20plan/14_financial_document_canonical_model.md">14</a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Build Order</div>
|
||||
<h2 class="section-title">推荐开发顺序</h2>
|
||||
<div class="timeline">
|
||||
<div class="timeline-step"><strong>Step 1</strong>先确认后端目录、ORM、迁移方式、测试目录和不该碰的文件。</div>
|
||||
<div class="timeline-step"><strong>Step 2</strong>统一命名:资产类型、状态、审核状态、Agent、权限级别。</div>
|
||||
<div class="timeline-step"><strong>Step 3</strong>补最小财务业务数据模型:<code>expense_claims</code>、<code>accounts_receivable</code>、<code>accounts_payable</code>。</div>
|
||||
<div class="timeline-step"><strong>Step 4</strong>完成 AgentAsset、Version、Review、Run、ToolCall、ParseLog、AuditLog。</div>
|
||||
<div class="timeline-step"><strong>Step 5</strong>把 Schema、API 骨架、服务层、种子数据接起来。</div>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Must Deliver</div>
|
||||
<h2 class="section-title">今天必须产出的东西</h2>
|
||||
<div class="grid two">
|
||||
<section class="card">
|
||||
<h3>平台底座表</h3>
|
||||
<ul class="list">
|
||||
<li><code>AgentAsset</code>、<code>AgentAssetVersion</code>、<code>AgentAssetReview</code></li>
|
||||
<li><code>AgentRun</code>、<code>AgentToolCall</code>、<code>SemanticParseLog</code></li>
|
||||
<li><code>AuditLog</code></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>最小业务数据来源</h3>
|
||||
<ul class="list">
|
||||
<li>报销至少有时间、地点、理由、金额、员工、部门、状态。</li>
|
||||
<li>应收至少有客户、金额、未收金额、到期日、账龄、状态。</li>
|
||||
<li>应付至少有供应商、金额、未付金额、到期日、账龄、状态。</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>API 骨架</h3>
|
||||
<ul class="list">
|
||||
<li>资产列表 / 详情 / 版本 / 审核 / 上线。</li>
|
||||
<li>运行日志与审计日志查询。</li>
|
||||
<li>返回真实数据库结果,不用前端硬编码收尾。</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>统一服务边界</h3>
|
||||
<ul class="list">
|
||||
<li>上线拦截逻辑在服务层,不堆到路由。</li>
|
||||
<li>所有写操作要留审计接口。</li>
|
||||
<li>任何 Agent 执行记录都必须生成 <code>run_id</code>。</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Acceptance Snapshot</div>
|
||||
<h2 class="section-title">验收快照</h2>
|
||||
<div class="table-like">
|
||||
<div class="row"><div class="row-label">资产模型</div><div class="row-value">已落地 3 条规则、2 条技能、2 条 MCP、3 条任务,并可通过资产接口返回。</div></div>
|
||||
<div class="row"><div class="row-label">版本与审核</div><div class="row-value">三条规则都具备版本历史;同一资产版本号不可重复,未审核规则不能上线。</div></div>
|
||||
<div class="row"><div class="row-label">运行与错误</div><div class="row-value">`GET /api/v1/agent-runs` 可返回 3 条运行日志,任意新建 Run 自动生成 <code>run_id</code>。</div></div>
|
||||
<div class="row"><div class="row-label">最小业务表</div><div class="row-value">报销、应收、应付种子数据已就位,后续查询和风险巡检都有明确数据来源。</div></div>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Common Misses</div>
|
||||
<h2 class="section-title">这一天最容易漏掉的点</h2>
|
||||
<ul class="list">
|
||||
<li>只建 Agent 表,不建最小财务业务表,导致 User Agent 和 Hermes 后面无数据可查。</li>
|
||||
<li>把审核拦截塞在 API 路由里,后面很难复用到 Orchestrator 和别的入口。</li>
|
||||
<li>没有统一 <code>run_id</code> 和审计接口,Day 4 到 Day 7 的 Trace 会断链。</li>
|
||||
</ul>
|
||||
|
||||
<div class="footer">Day 1 的判断标准很简单:不是“代码写了多少”,而是“后面 6 天会不会反复回头补地基”。</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,132 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Day 2 - 任务规则中心联调</title>
|
||||
<link rel="stylesheet" href="./styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="shell">
|
||||
<div class="topbar">
|
||||
<a class="brand" href="./index.html"><span class="brand-mark">D2</span><span>Day 2 View</span></a>
|
||||
<div class="quick-links">
|
||||
<a class="pill" href="./index.html">返回总览</a>
|
||||
<a class="pill" href="../agent%20week%20plan/day_2_rule_center_integration.md">周计划原文</a>
|
||||
<a class="pill" href="../agent%20week%20plan/day_2_rule_center_integration.md">合并文档原文</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="day-nav">
|
||||
<a class="pill" href="./day-1.html">Day 1</a>
|
||||
<a class="pill active" href="./day-2.html">Day 2</a>
|
||||
<a class="pill" href="./day-3.html">Day 3</a>
|
||||
<a class="pill" href="./day-4.html">Day 4</a>
|
||||
<a class="pill" href="./day-5.html">Day 5</a>
|
||||
<a class="pill" href="./day-6.html">Day 6</a>
|
||||
<a class="pill" href="./day-7.html">Day 7</a>
|
||||
</div>
|
||||
|
||||
<section class="hero">
|
||||
<div class="hero-badge">Integration</div>
|
||||
<h1>Day 2 任务规则中心联调</h1>
|
||||
<p>Day 2 的核心不是“把页面做漂亮”,而是让规则、技能、MCP、任务这四类资产第一次脱离本地假数据,真正连到 Day 1 的数据库和 API。最关键的能力是 Markdown、版本、审核和上线约束闭环。</p>
|
||||
<div class="hero-meta">
|
||||
<div class="meta-card"><div class="meta-label">上游依赖</div><div class="meta-value">Day 1 的资产模型、版本模型、审核模型、资产 API。</div></div>
|
||||
<div class="meta-card"><div class="meta-label">下游交接</div><div class="meta-value">Day 3 要复用资产数据,Day 4 要查询 active 技能 / MCP / 任务。</div></div>
|
||||
<div class="meta-card"><div class="meta-label">当天关键</div><div class="meta-value">前端联调不是硬编码演示,而是可对接真实后端。</div></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="section-kicker">Three-Layer Mapping</div>
|
||||
<h2 class="section-title">三层文档映射</h2>
|
||||
<div class="grid three">
|
||||
<section class="card tone-warm">
|
||||
<h3>路线图</h3>
|
||||
<p>周计划要求把任务规则中心从静态 UI 升级到真实数据对接,覆盖规则、技能、MCP、任务四类资产。</p>
|
||||
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_2_rule_center_integration.md">day_2_rule_center_integration.md</a></div>
|
||||
</section>
|
||||
<section class="card tone-teal">
|
||||
<h3>执行细则</h3>
|
||||
<p>执行层拆成 API Client、四类列表、规则详情、Markdown 编辑、版本卡片、审核与上线、技能详情、MCP 详情、任务详情、前端质量和当天验收。</p>
|
||||
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_2_rule_center_integration.md">agent week plan/day_2</a></div>
|
||||
</section>
|
||||
<section class="card tone-olive">
|
||||
<h3>架构依据</h3>
|
||||
<p>这一天主要受能力注册、规则形成生命周期和数据治理约束,重点在四类资产的统一展示方式和规则上线前审核拦截。</p>
|
||||
<div class="card-links">
|
||||
<a class="link-chip" href="../agent%20plan/07_capability_registry.md">07</a>
|
||||
<a class="link-chip" href="../agent%20plan/13_rule_formation_lifecycle.md">13</a>
|
||||
<a class="link-chip" href="../agent%20plan/06_data_contracts_and_governance.md">06</a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Build Order</div>
|
||||
<h2 class="section-title">推荐开发顺序</h2>
|
||||
<div class="timeline">
|
||||
<div class="timeline-step"><strong>Step 1</strong>先补 API Client:列表、详情、版本、保存、审核、上线、运行日志。</div>
|
||||
<div class="timeline-step"><strong>Step 2</strong>把四个页签的真实数据接起来,覆盖筛选、搜索、状态、空态和加载态。</div>
|
||||
<div class="timeline-step"><strong>Step 3</strong>把规则详情的 Hero 区、Markdown 编辑器、版本卡片和审核信息拉通。</div>
|
||||
<div class="timeline-step"><strong>Step 4</strong>补技能 / MCP / 任务的差异化详情,不复用规则编辑器。</div>
|
||||
<div class="timeline-step"><strong>Step 5</strong>最后收 UI 细节、错误态、禁用态、确认弹窗和构建验证。</div>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Must Deliver</div>
|
||||
<h2 class="section-title">今天必须产出的东西</h2>
|
||||
<div class="grid two">
|
||||
<section class="card">
|
||||
<h3>规则中心四页签</h3>
|
||||
<ul class="list">
|
||||
<li>规则、技能、MCP、任务都能切换。</li>
|
||||
<li>每个页签都来自真实接口,不再只读本地常量。</li>
|
||||
<li>搜索和状态筛选同时生效。</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>规则详情闭环</h3>
|
||||
<ul class="list">
|
||||
<li>能读取当前 Markdown。</li>
|
||||
<li>能保存并刷新版本列表。</li>
|
||||
<li>能展示审核者、审核状态、上线条件。</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>版本与上线约束</h3>
|
||||
<ul class="list">
|
||||
<li>最近 5 个版本可见。</li>
|
||||
<li>切换旧版本必须弹确认框。</li>
|
||||
<li>未审核规则不能上线,拒绝原因要可见。</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>详情差异化</h3>
|
||||
<ul class="list">
|
||||
<li>技能详情展示输入输出与依赖。</li>
|
||||
<li>MCP 详情展示服务地址、鉴权、降级策略。</li>
|
||||
<li>任务详情展示 cron、执行 Agent、最近执行结果。</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Acceptance Snapshot</div>
|
||||
<h2 class="section-title">验收快照</h2>
|
||||
<div class="table-like">
|
||||
<div class="row"><div class="row-label">真实数据</div><div class="row-value">四个页签都能用真实后端数据渲染,后端不可用时有明确错误提示。</div></div>
|
||||
<div class="row"><div class="row-label">规则编辑</div><div class="row-value">Markdown 保存后刷新页面仍在,保存失败不丢输入。</div></div>
|
||||
<div class="row"><div class="row-label">版本卡片</div><div class="row-value">最近 5 个版本可切换,当前版本标识清楚但不造成布局位移。</div></div>
|
||||
<div class="row"><div class="row-label">审核上线</div><div class="row-value"><code>pending</code> / <code>rejected</code> 规则都无法上线,<code>approved</code> 才能放行。</div></div>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Common Misses</div>
|
||||
<h2 class="section-title">这一天最容易漏掉的点</h2>
|
||||
<ul class="list">
|
||||
<li>只把规则页签接成真实数据,技能、MCP、任务仍然靠假数据撑场面。</li>
|
||||
<li>只做版本列表展示,不做确认弹窗和拒绝风险提示。</li>
|
||||
<li>把任务写成“定时任务”暴露给用户,违背文档里 UI 名称统一成“任务”的约束。</li>
|
||||
</ul>
|
||||
|
||||
<div class="footer">Day 2 的完成标准不是“页面能打开”,而是“规则中心第一次成为真实的资产入口”。</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,132 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Day 3 - 语义本体 MVP</title>
|
||||
<link rel="stylesheet" href="./styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="shell">
|
||||
<div class="topbar">
|
||||
<a class="brand" href="./index.html"><span class="brand-mark">D3</span><span>Day 3 View</span></a>
|
||||
<div class="quick-links">
|
||||
<a class="pill" href="./index.html">返回总览</a>
|
||||
<a class="pill" href="../agent%20week%20plan/day_3_semantic_ontology_mvp.md">周计划原文</a>
|
||||
<a class="pill" href="../agent%20week%20plan/day_3_semantic_ontology_mvp.md">合并文档原文</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="day-nav">
|
||||
<a class="pill" href="./day-1.html">Day 1</a>
|
||||
<a class="pill" href="./day-2.html">Day 2</a>
|
||||
<a class="pill active" href="./day-3.html">Day 3</a>
|
||||
<a class="pill" href="./day-4.html">Day 4</a>
|
||||
<a class="pill" href="./day-5.html">Day 5</a>
|
||||
<a class="pill" href="./day-6.html">Day 6</a>
|
||||
<a class="pill" href="./day-7.html">Day 7</a>
|
||||
</div>
|
||||
|
||||
<section class="hero">
|
||||
<div class="hero-badge">Ontology</div>
|
||||
<h1>Day 3 语义本体 MVP</h1>
|
||||
<p>这一天把自然语言问题统一切成 8 个核心字段。Day 3 不是追求大模型多聪明,而是先让结构稳定、可落日志、可被 Orchestrator、User Agent 和 Hermes 共用。</p>
|
||||
<div class="hero-meta">
|
||||
<div class="meta-card"><div class="meta-label">上游依赖</div><div class="meta-value">Day 1 的 <code>SemanticParseLog</code> / <code>AgentRun</code>,Day 2 的资产 API。</div></div>
|
||||
<div class="meta-card"><div class="meta-label">下游交接</div><div class="meta-value">Day 4 路由、Day 5 查询解释、Day 6 风险巡检都直接消费这 8 字段。</div></div>
|
||||
<div class="meta-card"><div class="meta-label">当天关键</div><div class="meta-value">名字统一、类型统一、日志统一、低置信度有澄清问题。</div></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="section-kicker">Three-Layer Mapping</div>
|
||||
<h2 class="section-title">三层文档映射</h2>
|
||||
<div class="grid three">
|
||||
<section class="card tone-warm">
|
||||
<h3>路线图</h3>
|
||||
<p>周计划要求建立用户问题的统一语义解析层,覆盖场景、意图、对象、时间、指标、约束、风险、权限 8 字段。</p>
|
||||
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_3_semantic_ontology_mvp.md">day_3_semantic_ontology_mvp.md</a></div>
|
||||
</section>
|
||||
<section class="card tone-teal">
|
||||
<h3>执行细则</h3>
|
||||
<p>执行层拆成 8 字段定义、字段枚举、Schema、解析服务、对象提取、时间范围、指标约束、风险权限、API、前端调试入口和评测集。</p>
|
||||
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_3_semantic_ontology_mvp.md">agent week plan/day_3</a></div>
|
||||
</section>
|
||||
<section class="card tone-olive">
|
||||
<h3>架构依据</h3>
|
||||
<p>主要受语义本体、财务标准模型和数据治理约束。应收、应付、报销的对象语义必须能回到最小业务表和标准对象。</p>
|
||||
<div class="card-links">
|
||||
<a class="link-chip" href="../agent%20plan/02_semantic_ontology.md">02</a>
|
||||
<a class="link-chip" href="../agent%20plan/14_financial_document_canonical_model.md">14</a>
|
||||
<a class="link-chip" href="../agent%20plan/06_data_contracts_and_governance.md">06</a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Build Order</div>
|
||||
<h2 class="section-title">推荐开发顺序</h2>
|
||||
<div class="timeline">
|
||||
<div class="timeline-step"><strong>Step 1</strong>先固定 8 个字段名字、类型、默认值和示例。</div>
|
||||
<div class="timeline-step"><strong>Step 2</strong>把 <code>scenario</code>、<code>intent</code>、<code>permission.level</code> 的枚举定死。</div>
|
||||
<div class="timeline-step"><strong>Step 3</strong>做请求/响应 Schema,再写解析服务。</div>
|
||||
<div class="timeline-step"><strong>Step 4</strong>补对象提取、时间范围、指标约束、风险和权限映射。</div>
|
||||
<div class="timeline-step"><strong>Step 5</strong>接 API、日志、调试入口和最小评测集。</div>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Must Deliver</div>
|
||||
<h2 class="section-title">今天必须产出的东西</h2>
|
||||
<div class="grid two">
|
||||
<section class="card">
|
||||
<h3>8 字段统一结构</h3>
|
||||
<ul class="list">
|
||||
<li><code>scenario</code>、<code>intent</code>、<code>entities</code>、<code>time_range</code></li>
|
||||
<li><code>metrics</code>、<code>constraints</code>、<code>risk_flags</code>、<code>permission</code></li>
|
||||
<li>附带 <code>confidence</code>、<code>clarification_required</code>、<code>run_id</code></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>规则解析优先版</h3>
|
||||
<ul class="list">
|
||||
<li>先用关键词和规则解析打底。</li>
|
||||
<li>报销 / 应收 / 应付 / 知识 / unknown 场景都能落到结构。</li>
|
||||
<li>越权动作能识别为 <code>approval_required</code> 或 <code>forbidden</code>。</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>日志和调试入口</h3>
|
||||
<ul class="list">
|
||||
<li>每次解析都要落 <code>SemanticParseLog</code>。</li>
|
||||
<li>前端可直接输入一句话看 8 字段结果。</li>
|
||||
<li>低置信度问题必须给澄清问题。</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>最小评测集</h3>
|
||||
<ul class="list">
|
||||
<li>至少覆盖报销、应收、应付、知识、越权动作。</li>
|
||||
<li>每条样例要写期望 <code>scenario</code>、<code>intent</code> 和权限级别。</li>
|
||||
<li>当天目标是可评测,而不是追求完美准确率。</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Acceptance Snapshot</div>
|
||||
<h2 class="section-title">验收快照</h2>
|
||||
<div class="table-like">
|
||||
<div class="row"><div class="row-label">语义结构</div><div class="row-value">8 字段在 Schema、服务层、日志里名字完全一致。</div></div>
|
||||
<div class="row"><div class="row-label">关键识别</div><div class="row-value">“本周报销超标风险”“客户 A 本月应收”“供应商 B 明天要付多少钱”都能落到正确场景和意图。</div></div>
|
||||
<div class="row"><div class="row-label">权限结果</div><div class="row-value">“帮我直接付款”不能被识别成可直接执行动作。</div></div>
|
||||
<div class="row"><div class="row-label">日志与前端</div><div class="row-value">连续调用多次都能在日志中查到,并能通过调试入口观察结果。</div></div>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Common Misses</div>
|
||||
<h2 class="section-title">这一天最容易漏掉的点</h2>
|
||||
<ul class="list">
|
||||
<li>字段结构和日志结构各写一套名字,后面 Trace 很难串。</li>
|
||||
<li>只做 <code>scenario</code> 和 <code>intent</code>,不做 <code>permission</code>,Day 4 会直接失去拦截依据。</li>
|
||||
<li>只在服务里返回结果,不把解析过程落库或落日志,后续无法复盘误判样例。</li>
|
||||
</ul>
|
||||
|
||||
<div class="footer">Day 3 的价值在于把“语义理解”从模糊文本变成稳定协议。后面所有智能能力都站在这层协议上。</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,133 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Day 4 - Orchestrator 运行时</title>
|
||||
<link rel="stylesheet" href="./styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="shell">
|
||||
<div class="topbar">
|
||||
<a class="brand" href="./index.html"><span class="brand-mark">D4</span><span>Day 4 View</span></a>
|
||||
<div class="quick-links">
|
||||
<a class="pill" href="./index.html">返回总览</a>
|
||||
<a class="pill" href="../agent%20week%20plan/day_4_orchestrator_runtime.md">周计划原文</a>
|
||||
<a class="pill" href="../agent%20week%20plan/day_4_orchestrator_runtime.md">合并文档原文</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="day-nav">
|
||||
<a class="pill" href="./day-1.html">Day 1</a>
|
||||
<a class="pill" href="./day-2.html">Day 2</a>
|
||||
<a class="pill" href="./day-3.html">Day 3</a>
|
||||
<a class="pill active" href="./day-4.html">Day 4</a>
|
||||
<a class="pill" href="./day-5.html">Day 5</a>
|
||||
<a class="pill" href="./day-6.html">Day 6</a>
|
||||
<a class="pill" href="./day-7.html">Day 7</a>
|
||||
</div>
|
||||
|
||||
<section class="hero">
|
||||
<div class="hero-badge">Runtime</div>
|
||||
<h1>Day 4 Orchestrator 运行时</h1>
|
||||
<p>Day 4 把整个系统第一次串成“能跑的链”。用户消息和定时任务都先走 Orchestrator,由它创建 run、调用语义解析、做权限判断、选择 Agent、记录 ToolCall 和 Trace,然后再给下游执行。</p>
|
||||
<div class="hero-meta">
|
||||
<div class="meta-card"><div class="meta-label">上游依赖</div><div class="meta-value">Day 3 的语义解析结果,Day 1 的 Run / ToolCall,Day 2 的 active 资产。</div></div>
|
||||
<div class="meta-card"><div class="meta-label">下游交接</div><div class="meta-value">Day 5 User Agent 和 Day 6 Hermes 都通过它被调度。</div></div>
|
||||
<div class="meta-card"><div class="meta-label">当天关键</div><div class="meta-value">权限拦截和 Trace 必须在 Orchestrator 层,而不是散落在各 Agent。</div></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="section-kicker">Three-Layer Mapping</div>
|
||||
<h2 class="section-title">三层文档映射</h2>
|
||||
<div class="grid three">
|
||||
<section class="card tone-warm">
|
||||
<h3>路线图</h3>
|
||||
<p>周计划要求建立统一调度层,让用户请求和系统任务都先进入 Orchestrator,再根据语义、权限、能力注册路由到 User Agent、Hermes、MCP 或规则引擎。</p>
|
||||
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_4_orchestrator_runtime.md">day_4_orchestrator_runtime.md</a></div>
|
||||
</section>
|
||||
<section class="card tone-teal">
|
||||
<h3>执行细则</h3>
|
||||
<p>执行层拆成输入输出、Orchestrator 服务、路由规则、权限判断、能力查询、工具调用封装、API、最小 Trace 查看和测试。</p>
|
||||
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_4_orchestrator_runtime.md">agent week plan/day_4</a></div>
|
||||
</section>
|
||||
<section class="card tone-olive">
|
||||
<h3>架构依据</h3>
|
||||
<p>主要受运行时流程、能力注册、权限确认和可观测性约束。Day 4 的输出要能直接给前端展示,并支持 Day 5/6 的占位实现接入。</p>
|
||||
<div class="card-links">
|
||||
<a class="link-chip" href="../agent%20plan/04_orchestrator_and_runtime_flow.md">04</a>
|
||||
<a class="link-chip" href="../agent%20plan/07_capability_registry.md">07</a>
|
||||
<a class="link-chip" href="../agent%20plan/08_permission_confirmation.md">08</a>
|
||||
<a class="link-chip" href="../agent%20plan/09_observability_and_trace.md">09</a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Build Order</div>
|
||||
<h2 class="section-title">推荐开发顺序</h2>
|
||||
<div class="timeline">
|
||||
<div class="timeline-step"><strong>Step 1</strong>先定 <code>OrchestratorRequest</code> 和 <code>OrchestratorResponse</code>。</div>
|
||||
<div class="timeline-step"><strong>Step 2</strong>写 <code>run(request)</code> 主流程:创建 Run、解析语义、判权限、选 Agent、更新状态。</div>
|
||||
<div class="timeline-step"><strong>Step 3</strong>把用户入口 / 任务入口的路由规则固化下来。</div>
|
||||
<div class="timeline-step"><strong>Step 4</strong>封装工具调用记录和降级策略。</div>
|
||||
<div class="timeline-step"><strong>Step 5</strong>暴露 API 和最小 Trace 页面或接口。</div>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Must Deliver</div>
|
||||
<h2 class="section-title">今天必须产出的东西</h2>
|
||||
<div class="grid two">
|
||||
<section class="card">
|
||||
<h3>统一入口</h3>
|
||||
<ul class="list">
|
||||
<li><code>source=user_message</code> 与 <code>source=schedule</code> 都能进同一入口。</li>
|
||||
<li>请求返回 <code>run_id</code>、<code>selected_agent</code>、<code>route_reason</code>、<code>permission_level</code>。</li>
|
||||
<li>返回结果要能被前端直接展示。</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>权限与路由</h3>
|
||||
<ul class="list">
|
||||
<li>查询类走 User Agent,定时风险类走 Hermes。</li>
|
||||
<li><code>approval_required</code> 只返回确认,不直接执行。</li>
|
||||
<li><code>forbidden</code> 直接阻断,不调下游 Agent。</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>能力与工具调用</h3>
|
||||
<ul class="list">
|
||||
<li>只查询 active 技能 / MCP / 任务。</li>
|
||||
<li>禁用能力不允许被调用。</li>
|
||||
<li>每次工具调用都能落 <code>AgentToolCall</code>。</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>Trace 与降级</h3>
|
||||
<ul class="list">
|
||||
<li>Trace 能串起语义解析、路由、工具调用和最终结果。</li>
|
||||
<li>外部 MCP 失败要返回降级说明,不让前端拿到不可读错误。</li>
|
||||
<li>异常都要写进 <code>AgentRun.error_message</code>。</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Acceptance Snapshot</div>
|
||||
<h2 class="section-title">验收快照</h2>
|
||||
<div class="table-like">
|
||||
<div class="row"><div class="row-label">路由结果</div><div class="row-value">同一句风险检查,在用户入口和任务入口会有不同路由结果。</div></div>
|
||||
<div class="row"><div class="row-label">权限边界</div><div class="row-value">“直接上线规则”和“直接付款”都不会被自动执行。</div></div>
|
||||
<div class="row"><div class="row-label">日志完整度</div><div class="row-value">每次运行至少有一条 <code>AgentRun</code>,工具调用有 0 到多条 <code>AgentToolCall</code>。</div></div>
|
||||
<div class="row"><div class="row-label">可观察性</div><div class="row-value">前端或 curl 可以完整看到一次运行链路,不需要直接查数据库猜过程。</div></div>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Common Misses</div>
|
||||
<h2 class="section-title">这一天最容易漏掉的点</h2>
|
||||
<ul class="list">
|
||||
<li>把权限判断放到 User Agent / Hermes 内部,导致系统没有统一边界。</li>
|
||||
<li>只记录成功 ToolCall,不记录失败 ToolCall,后面降级和排错会缺证据。</li>
|
||||
<li>路由能跑,但没有统一 Trace 输出,Day 7 演示时会非常难讲清链路。</li>
|
||||
</ul>
|
||||
|
||||
<div class="footer">Day 4 的价值是把系统从“有很多零件”变成“有一条统一运行链”。</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,133 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Day 5 - User Agent MVP</title>
|
||||
<link rel="stylesheet" href="./styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="shell">
|
||||
<div class="topbar">
|
||||
<a class="brand" href="./index.html"><span class="brand-mark">D5</span><span>Day 5 View</span></a>
|
||||
<div class="quick-links">
|
||||
<a class="pill" href="./index.html">返回总览</a>
|
||||
<a class="pill" href="../agent%20week%20plan/day_5_user_agent_mvp.md">周计划原文</a>
|
||||
<a class="pill" href="../agent%20week%20plan/day_5_user_agent_mvp.md">合并文档原文</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="day-nav">
|
||||
<a class="pill" href="./day-1.html">Day 1</a>
|
||||
<a class="pill" href="./day-2.html">Day 2</a>
|
||||
<a class="pill" href="./day-3.html">Day 3</a>
|
||||
<a class="pill" href="./day-4.html">Day 4</a>
|
||||
<a class="pill active" href="./day-5.html">Day 5</a>
|
||||
<a class="pill" href="./day-6.html">Day 6</a>
|
||||
<a class="pill" href="./day-7.html">Day 7</a>
|
||||
</div>
|
||||
|
||||
<section class="hero">
|
||||
<div class="hero-badge">User Agent</div>
|
||||
<h1>Day 5 User Agent MVP</h1>
|
||||
<p>这一天开始让“用户真的能问问题”。但 User Agent 只负责查询、解释、规则引用和草稿生成,绝不绕过权限做审批、付款、上线这类高风险动作。</p>
|
||||
<div class="hero-meta">
|
||||
<div class="meta-card"><div class="meta-label">上游依赖</div><div class="meta-value">Day 4 Orchestrator、Day 3 语义结构、Day 1 业务数据与日志模型、Day 2 规则资产。</div></div>
|
||||
<div class="meta-card"><div class="meta-label">下游交接</div><div class="meta-value">Day 7 要拿它做问答演示、规则解释演示和草稿生成演示。</div></div>
|
||||
<div class="meta-card"><div class="meta-label">当天关键</div><div class="meta-value">回答可读、引用可追溯、草稿可确认、高风险不自动执行。</div></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="section-kicker">Three-Layer Mapping</div>
|
||||
<h2 class="section-title">三层文档映射</h2>
|
||||
<div class="grid three">
|
||||
<section class="card tone-warm">
|
||||
<h3>路线图</h3>
|
||||
<p>周计划要求做用户自然语言入口、报销 / 应收 / 应付查询解释、规则引用解释、建议草稿和前端入口。</p>
|
||||
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_5_user_agent_mvp.md">day_5_user_agent_mvp.md</a></div>
|
||||
</section>
|
||||
<section class="card tone-teal">
|
||||
<h3>执行细则</h3>
|
||||
<p>执行层拆成输入输出、查询处理、规则解释、风险解释、草稿生成、知识库读取骨架、对话入口、安全边界和测试。</p>
|
||||
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_5_user_agent_mvp.md">agent week plan/day_5</a></div>
|
||||
</section>
|
||||
<section class="card tone-olive">
|
||||
<h3>架构依据</h3>
|
||||
<p>主要受 Agent 职责划分、运行时流程、知识架构和规则形成生命周期约束。所有高风险动作只能停留在建议或草稿层。</p>
|
||||
<div class="card-links">
|
||||
<a class="link-chip" href="../agent%20plan/03_agent_responsibilities.md">03</a>
|
||||
<a class="link-chip" href="../agent%20plan/04_orchestrator_and_runtime_flow.md">04</a>
|
||||
<a class="link-chip" href="../agent%20plan/12_llm_wiki_knowledge_architecture.md">12</a>
|
||||
<a class="link-chip" href="../agent%20plan/13_rule_formation_lifecycle.md">13</a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Build Order</div>
|
||||
<h2 class="section-title">推荐开发顺序</h2>
|
||||
<div class="timeline">
|
||||
<div class="timeline-step"><strong>Step 1</strong>先定 <code>UserAgentRequest</code> / <code>UserAgentResponse</code> 协议。</div>
|
||||
<div class="timeline-step"><strong>Step 2</strong>优先实现报销、应收、应付查询处理器。</div>
|
||||
<div class="timeline-step"><strong>Step 3</strong>补规则解释和风险解释,让回答有依据而不是只给一句话。</div>
|
||||
<div class="timeline-step"><strong>Step 4</strong>补草稿生成与知识读取骨架。</div>
|
||||
<div class="timeline-step"><strong>Step 5</strong>最后接前端问答入口、加载态、错误态和确认提示。</div>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Must Deliver</div>
|
||||
<h2 class="section-title">今天必须产出的东西</h2>
|
||||
<div class="grid two">
|
||||
<section class="card">
|
||||
<h3>三类财务查询</h3>
|
||||
<ul class="list">
|
||||
<li>报销查询可读,能查金额、状态或进度。</li>
|
||||
<li>应收查询可读,能查客户未收金额或账龄。</li>
|
||||
<li>应付查询可读,能查供应商待付款或付款状态。</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>解释能力</h3>
|
||||
<ul class="list">
|
||||
<li>规则解释能引用 active 规则、版本号和更新时间。</li>
|
||||
<li>风险解释能说明风险类型、原因和建议动作。</li>
|
||||
<li>知识库不可用时要优雅降级。</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>草稿而非执行</h3>
|
||||
<ul class="list">
|
||||
<li>可生成报销处理意见草稿、应收催收建议草稿、应付付款建议草稿。</li>
|
||||
<li>草稿必须写明“待人工确认”。</li>
|
||||
<li>草稿行为写入审计日志和 AgentRun 结果。</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>用户入口</h3>
|
||||
<ul class="list">
|
||||
<li>前端输入框走 Orchestrator,不绕行。</li>
|
||||
<li>显示回答、引用、建议动作、确认提示和 <code>run_id</code>。</li>
|
||||
<li>有加载态和错误态。</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Acceptance Snapshot</div>
|
||||
<h2 class="section-title">验收快照</h2>
|
||||
<div class="table-like">
|
||||
<div class="row"><div class="row-label">问答闭环</div><div class="row-value">用户在页面上能完成一次自然语言提问、拿到回答、看到引用和 run_id。</div></div>
|
||||
<div class="row"><div class="row-label">三类场景</div><div class="row-value">至少报销、应收、应付三类财务问题都有结构化回答。</div></div>
|
||||
<div class="row"><div class="row-label">引用能力</div><div class="row-value">“为什么这笔报销有风险”这类问题能引用规则,而不是只给模糊判断。</div></div>
|
||||
<div class="row"><div class="row-label">安全边界</div><div class="row-value">“直接付款”“直接审批”类提示不会自动执行,只能变成建议或草稿。</div></div>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Common Misses</div>
|
||||
<h2 class="section-title">这一天最容易漏掉的点</h2>
|
||||
<ul class="list">
|
||||
<li>只返回原始查询数据,不把结果翻译成用户可读回答。</li>
|
||||
<li>只做草稿内容,不做 <code>requires_confirmation</code> 和审计日志。</li>
|
||||
<li>绕过 Orchestrator 直接从前端打 User Agent,导致 Day 4 的统一链路失效。</li>
|
||||
</ul>
|
||||
|
||||
<div class="footer">Day 5 的判断标准是:用户能问、系统能答、回答有依据、动作不越权。</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,133 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Day 6 - Hermes MVP</title>
|
||||
<link rel="stylesheet" href="./styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="shell">
|
||||
<div class="topbar">
|
||||
<a class="brand" href="./index.html"><span class="brand-mark">D6</span><span>Day 6 View</span></a>
|
||||
<div class="quick-links">
|
||||
<a class="pill" href="./index.html">返回总览</a>
|
||||
<a class="pill" href="../agent%20week%20plan/day_6_hermes_mvp.md">周计划原文</a>
|
||||
<a class="pill" href="../agent%20week%20plan/day_6_hermes_mvp.md">合并文档原文</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="day-nav">
|
||||
<a class="pill" href="./day-1.html">Day 1</a>
|
||||
<a class="pill" href="./day-2.html">Day 2</a>
|
||||
<a class="pill" href="./day-3.html">Day 3</a>
|
||||
<a class="pill" href="./day-4.html">Day 4</a>
|
||||
<a class="pill" href="./day-5.html">Day 5</a>
|
||||
<a class="pill active" href="./day-6.html">Day 6</a>
|
||||
<a class="pill" href="./day-7.html">Day 7</a>
|
||||
</div>
|
||||
|
||||
<section class="hero">
|
||||
<div class="hero-badge">Hermes</div>
|
||||
<h1>Day 6 Hermes MVP</h1>
|
||||
<p>Hermes 是后台数字员工,不做即时对话,而是负责定时巡检、风险预警、日报统计、知识候选和规则草稿。它的关键不是“会不会说”,而是“任务能不能跑、结果能不能追”。</p>
|
||||
<div class="hero-meta">
|
||||
<div class="meta-card"><div class="meta-label">上游依赖</div><div class="meta-value">Day 4 的 Orchestrator 路由,Day 1 的任务与日志表,Day 3 的语义结构,Day 5 可复用的风险/规则/知识接口。</div></div>
|
||||
<div class="meta-card"><div class="meta-label">下游交接</div><div class="meta-value">Day 7 要用它做手动触发任务、查看结果、展示规则草稿和知识候选。</div></div>
|
||||
<div class="meta-card"><div class="meta-label">当天关键</div><div class="meta-value">任务入口、风险项结构、OCR Mock、知识候选和规则草稿都必须可追溯。</div></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="section-kicker">Three-Layer Mapping</div>
|
||||
<h2 class="section-title">三层文档映射</h2>
|
||||
<div class="grid three">
|
||||
<section class="card tone-warm">
|
||||
<h3>路线图</h3>
|
||||
<p>周计划要求实现 Hermes 调度入口、每日风险巡检、统计任务、知识库维护、OCR Mock 和运行结果面板或 API。</p>
|
||||
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_6_hermes_mvp.md">day_6_hermes_mvp.md</a></div>
|
||||
</section>
|
||||
<section class="card tone-teal">
|
||||
<h3>执行细则</h3>
|
||||
<p>执行层拆成输入输出、任务调度入口、风险巡检、每日统计、OCR 接入点、知识库维护、规则草稿形成、结果展示和测试。</p>
|
||||
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_6_hermes_mvp.md">agent week plan/day_6</a></div>
|
||||
</section>
|
||||
<section class="card tone-olive">
|
||||
<h3>架构依据</h3>
|
||||
<p>主要受 Agent 职责、OCR 架构、知识库架构和反馈学习闭环约束。Hermes 能生成候选和草稿,但不能自动发布正式结果。</p>
|
||||
<div class="card-links">
|
||||
<a class="link-chip" href="../agent%20plan/03_agent_responsibilities.md">03</a>
|
||||
<a class="link-chip" href="../agent%20plan/11_ocr_invoice_architecture.md">11</a>
|
||||
<a class="link-chip" href="../agent%20plan/12_llm_wiki_knowledge_architecture.md">12</a>
|
||||
<a class="link-chip" href="../agent%20plan/15_feedback_learning_loop.md">15</a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Build Order</div>
|
||||
<h2 class="section-title">推荐开发顺序</h2>
|
||||
<div class="timeline">
|
||||
<div class="timeline-step"><strong>Step 1</strong>先定 <code>HermesTaskRequest</code> / <code>HermesTaskResult</code>。</div>
|
||||
<div class="timeline-step"><strong>Step 2</strong>建立手动触发任务 API,经 Orchestrator 路由到 Hermes。</div>
|
||||
<div class="timeline-step"><strong>Step 3</strong>补风险巡检和每日统计的结构化输出。</div>
|
||||
<div class="timeline-step"><strong>Step 4</strong>接入 OCR Mock、知识候选生成、规则草稿生成。</div>
|
||||
<div class="timeline-step"><strong>Step 5</strong>补任务详情展示、错误信息和测试。</div>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Must Deliver</div>
|
||||
<h2 class="section-title">今天必须产出的东西</h2>
|
||||
<div class="grid two">
|
||||
<section class="card">
|
||||
<h3>任务调度入口</h3>
|
||||
<ul class="list">
|
||||
<li>可手动触发至少一个任务资产。</li>
|
||||
<li>任务经 Orchestrator 进入 Hermes。</li>
|
||||
<li>结束后能更新最近执行时间和状态。</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>风险与统计</h3>
|
||||
<ul class="list">
|
||||
<li>重复报销、金额超标、应收逾期、应付异常付款等风险有结构化输出。</li>
|
||||
<li>日报包含报销、报账、应收、应付的关键统计口径。</li>
|
||||
<li>每个风险项都要能被业务人员理解和追溯。</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>知识候选与规则草稿</h3>
|
||||
<ul class="list">
|
||||
<li>知识候选默认是 <code>draft</code>,不能自动发布。</li>
|
||||
<li>规则草稿保存为 <code>asset_type=rule</code>,状态为 <code>draft</code>。</li>
|
||||
<li>两类生成都要写审计日志。</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>OCR Mock 与结果展示</h3>
|
||||
<ul class="list">
|
||||
<li>OCR 服务接口和输入输出结构定下来。</li>
|
||||
<li>当前阶段允许完全使用 Mock 结果。</li>
|
||||
<li>任务详情或运行日志中能直接看到 Hermes 的执行结果。</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Acceptance Snapshot</div>
|
||||
<h2 class="section-title">验收快照</h2>
|
||||
<div class="table-like">
|
||||
<div class="row"><div class="row-label">任务可触发</div><div class="row-value">至少一个任务可以手动触发,并能查到结构化结果。</div></div>
|
||||
<div class="row"><div class="row-label">风险巡检</div><div class="row-value">输出里能看到风险类型、业务对象、触发规则、建议动作和风险等级。</div></div>
|
||||
<div class="row"><div class="row-label">候选与草稿</div><div class="row-value">知识候选和规则草稿都能生成,但都不是 active / published 正式状态。</div></div>
|
||||
<div class="row"><div class="row-label">可观察性</div><div class="row-value">不用查数据库,也能从任务详情或运行日志判断 Hermes 是否执行成功。</div></div>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Common Misses</div>
|
||||
<h2 class="section-title">这一天最容易漏掉的点</h2>
|
||||
<ul class="list">
|
||||
<li>只做 Hermes 服务逻辑,不做任务入口和结果展示,最后无法演示。</li>
|
||||
<li>能生成知识或规则,但没把状态锁在 <code>draft</code>,会直接越过人工审核边界。</li>
|
||||
<li>OCR Mock 只返回一段自由文本,不定义结构字段,后面无法和规则或风险逻辑对接。</li>
|
||||
</ul>
|
||||
|
||||
<div class="footer">Day 6 的价值是让“后台数字员工”第一次具备可触发、可解释、可留痕的闭环。</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,132 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Day 7 - 加固、演示和验收</title>
|
||||
<link rel="stylesheet" href="./styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="shell">
|
||||
<div class="topbar">
|
||||
<a class="brand" href="./index.html"><span class="brand-mark">D7</span><span>Day 7 View</span></a>
|
||||
<div class="quick-links">
|
||||
<a class="pill" href="./index.html">返回总览</a>
|
||||
<a class="pill" href="../agent%20week%20plan/day_7_hardening_demo_acceptance.md">周计划原文</a>
|
||||
<a class="pill" href="../agent%20week%20plan/day_7_hardening_demo_acceptance.md">合并文档原文</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="day-nav">
|
||||
<a class="pill" href="./day-1.html">Day 1</a>
|
||||
<a class="pill" href="./day-2.html">Day 2</a>
|
||||
<a class="pill" href="./day-3.html">Day 3</a>
|
||||
<a class="pill" href="./day-4.html">Day 4</a>
|
||||
<a class="pill" href="./day-5.html">Day 5</a>
|
||||
<a class="pill" href="./day-6.html">Day 6</a>
|
||||
<a class="pill active" href="./day-7.html">Day 7</a>
|
||||
</div>
|
||||
|
||||
<section class="hero">
|
||||
<div class="hero-badge">Hardening</div>
|
||||
<h1>Day 7 加固、演示和验收</h1>
|
||||
<p>Day 7 不再追求新增大功能,而是把 Day 1 到 Day 6 的链路整理成“可演示、可验收、可继续接手”的状态。没有这一层收口,前面做出来的东西很容易停在“只有作者自己懂”的阶段。</p>
|
||||
<div class="hero-meta">
|
||||
<div class="meta-card"><div class="meta-label">上游依赖</div><div class="meta-value">Day 1 到 Day 6 的全部核心路径。</div></div>
|
||||
<div class="meta-card"><div class="meta-label">当天输出</div><div class="meta-value">回归记录、权限边界、审计和 Trace 补齐、测试记录、演示脚本、交接说明。</div></div>
|
||||
<div class="meta-card"><div class="meta-label">当天关键</div><div class="meta-value">冻结新增需求,只收验收相关缺口。</div></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="section-kicker">Three-Layer Mapping</div>
|
||||
<h2 class="section-title">三层文档映射</h2>
|
||||
<div class="grid three">
|
||||
<section class="card tone-warm">
|
||||
<h3>路线图</h3>
|
||||
<p>周计划要求完成回归、权限补齐、审计补齐、错误态和空态、评测、演示数据、构建和交付说明。</p>
|
||||
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_7_hardening_demo_acceptance.md">day_7_hardening_demo_acceptance.md</a></div>
|
||||
</section>
|
||||
<section class="card tone-teal">
|
||||
<h3>执行细则</h3>
|
||||
<p>执行层拆成核心链路回归、权限和风险边界、审计和 Trace、前端体验修补、测试补齐、评测集、演示数据、演示脚本和文档收尾。</p>
|
||||
<div class="card-links"><a class="link-chip" href="../agent%20week%20plan/day_7_hardening_demo_acceptance.md">agent week plan/day_7</a></div>
|
||||
</section>
|
||||
<section class="card tone-olive">
|
||||
<h3>架构依据</h3>
|
||||
<p>主要受整体 README、开发路线图、可观测性和评测集约束。Day 7 的本质是把所有边界和证据讲清楚。</p>
|
||||
<div class="card-links">
|
||||
<a class="link-chip" href="../agent%20plan/00_README.md">00</a>
|
||||
<a class="link-chip" href="../agent%20plan/05_development_roadmap.md">05</a>
|
||||
<a class="link-chip" href="../agent%20plan/09_observability_and_trace.md">09</a>
|
||||
<a class="link-chip" href="../agent%20plan/10_evaluation_and_testset.md">10</a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Build Order</div>
|
||||
<h2 class="section-title">推荐收口顺序</h2>
|
||||
<div class="timeline">
|
||||
<div class="timeline-step"><strong>Step 1</strong>先汇总 Day 1 到 Day 6 未完成项,冻结新增需求。</div>
|
||||
<div class="timeline-step"><strong>Step 2</strong>回归核心链路:资产、规则、语义解析、Orchestrator、User Agent、Hermes、Trace、AuditLog。</div>
|
||||
<div class="timeline-step"><strong>Step 3</strong>补权限边界与高风险动作拦截。</div>
|
||||
<div class="timeline-step"><strong>Step 4</strong>补测试、评测、演示数据和前端体验问题。</div>
|
||||
<div class="timeline-step"><strong>Step 5</strong>写演示脚本和交接说明,形成最终交付。</div>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Must Deliver</div>
|
||||
<h2 class="section-title">今天必须产出的东西</h2>
|
||||
<div class="grid two">
|
||||
<section class="card">
|
||||
<h3>回归与边界</h3>
|
||||
<ul class="list">
|
||||
<li>未审核规则不能上线。</li>
|
||||
<li>付款、审批、上线等高风险动作都不能绕过确认。</li>
|
||||
<li>disabled 能力不能被调用。</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>审计与 Trace</h3>
|
||||
<ul class="list">
|
||||
<li>规则保存、审核、上线都能看到 AuditLog。</li>
|
||||
<li>Hermes 生成知识候选 / 规则草稿有审计。</li>
|
||||
<li>任意演示路径都能追到 <code>run_id</code>。</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>测试、评测、演示数据</h3>
|
||||
<ul class="list">
|
||||
<li>后端测试、前端构建、语义评测至少有执行记录。</li>
|
||||
<li>报销 / 应收 / 应付 / 风险 / 知识都准备好演示数据。</li>
|
||||
<li>失败样例和已知边界要明确写出。</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>演示脚本与交接</h3>
|
||||
<ul class="list">
|
||||
<li>从任务规则中心、规则详情、版本切换、上线拦截,到 User Agent 问答、Hermes 任务、Trace 和审计,都有明确步骤。</li>
|
||||
<li>新开发者按脚本能走通一遍。</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Acceptance Snapshot</div>
|
||||
<h2 class="section-title">最终验收快照</h2>
|
||||
<div class="table-like">
|
||||
<div class="row"><div class="row-label">端到端链路</div><div class="row-value">从规则中心到 User Agent,再到 Hermes 和 Trace,至少有一条完整演示路径可复现。</div></div>
|
||||
<div class="row"><div class="row-label">证据完整</div><div class="row-value">AgentRun、ToolCall、AuditLog、测试记录、评测结果和演示脚本都存在。</div></div>
|
||||
<div class="row"><div class="row-label">风险边界</div><div class="row-value">MVP 期间不存在绕过人工审核、自动付款、自动上线的暗门路径。</div></div>
|
||||
<div class="row"><div class="row-label">可交接性</div><div class="row-value">下一位开发或 Codex 打开文档就能知道已完成、未完成和生产化前必补项。</div></div>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Common Misses</div>
|
||||
<h2 class="section-title">这一天最容易漏掉的点</h2>
|
||||
<ul class="list">
|
||||
<li>只验证 Happy Path,不回归错误态、空态、禁用态和被权限拦截路径。</li>
|
||||
<li>能讲演示,但没有测试记录和已知风险说明,交接质量会很差。</li>
|
||||
<li>前 6 天的 TODO 没回写完成状态,导致页面和 Markdown 脱节。</li>
|
||||
</ul>
|
||||
|
||||
<div class="footer">Day 7 的目标不是继续堆功能,而是把一周产出变成别人也能运行、理解和接手的系统。</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,181 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Agent Week Plan HTML</title>
|
||||
<link rel="stylesheet" href="./styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="shell">
|
||||
<div class="topbar">
|
||||
<a class="brand" href="./index.html">
|
||||
<span class="brand-mark">A7</span>
|
||||
<span>Agent Week HTML</span>
|
||||
</a>
|
||||
<div class="quick-links">
|
||||
<a class="pill" href="../agent%20week%20plan/MASTER_TODO.md">周计划总控</a>
|
||||
<a class="pill" href="../agent%20week%20plan/00_README.md">周计划说明</a>
|
||||
<a class="pill" href="../agent%20plan/00_README.md">架构目录</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="hero">
|
||||
<div class="hero-badge">Static Map</div>
|
||||
<h1>把 7 天周计划变成可直接浏览的开发视图</h1>
|
||||
<p>这一套 HTML 页面不是替代 Markdown,而是把 <code>agent week plan</code> 和 <code>agent plan</code> 的对应关系收成一个稳定入口。每天的路线图和执行清单现在已经并到同一份 daily 文档里。</p>
|
||||
<div class="hero-meta">
|
||||
<div class="meta-card">
|
||||
<div class="meta-label">阅读顺序</div>
|
||||
<div class="meta-value">先总览,再选 Day,再跳转到具体 Markdown 落地执行。</div>
|
||||
</div>
|
||||
<div class="meta-card">
|
||||
<div class="meta-label">核心视图</div>
|
||||
<div class="meta-value">路线图、执行细则、架构依据三层同时可见。</div>
|
||||
</div>
|
||||
<div class="meta-card">
|
||||
<div class="meta-label">适用对象</div>
|
||||
<div class="meta-value">Codex 开发、后端开发、前端开发、项目 owner、验收人员。</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="section-kicker">How To Use</div>
|
||||
<h2 class="section-title">怎么用这套页面</h2>
|
||||
<div class="grid two">
|
||||
<section class="card tone-teal">
|
||||
<h3>Codex 开发视角</h3>
|
||||
<ol class="list">
|
||||
<li>先看今天在哪一天,确认上游依赖和下游交接。</li>
|
||||
<li>用“两层映射”定位:daily 文档看目标和步骤,架构文档看约束。</li>
|
||||
<li>按“推荐开发顺序”推进,不跳天,不跨层乱做。</li>
|
||||
<li>完成后回到原始 Markdown,把 TODO、阻塞、交接更新回文档。</li>
|
||||
</ol>
|
||||
</section>
|
||||
<section class="card tone-warm">
|
||||
<h3>人工开发与验收视角</h3>
|
||||
<ol class="list">
|
||||
<li>先看每一天的“今日定位”,知道这一天到底产出什么。</li>
|
||||
<li>再看“今天必须产出的东西”和“验收快照”,确认完成标准。</li>
|
||||
<li>最后跳转到对应 Markdown,逐条执行或验收。</li>
|
||||
<li>如果发现跨天阻塞,优先回前一天补地基,而不是在当前天临时兜底。</li>
|
||||
</ol>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Three Layers</div>
|
||||
<h2 class="section-title">文档结构一眼看清</h2>
|
||||
<div class="grid three">
|
||||
<section class="card">
|
||||
<h3>1. 周计划路线图</h3>
|
||||
<p>定义每天的大方向、交付物和验收门槛。用于排期、对齐和验收。核心入口是 <code>MASTER_TODO.md</code> 和 Day 1 到 Day 7 daily 文档。</p>
|
||||
<div class="card-links">
|
||||
<a class="link-chip" href="../agent%20week%20plan/00_README.md">00_README</a>
|
||||
<a class="link-chip" href="../agent%20week%20plan/MASTER_TODO.md">MASTER_TODO</a>
|
||||
</div>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>2. 每日执行清单</h3>
|
||||
<p>每天的开发目标已经拆到对应 daily 文档中的详细执行清单,直接覆盖模型、字段、接口、服务、前端、测试和验收证据。</p>
|
||||
<div class="card-links">
|
||||
<a class="link-chip" href="../agent%20week%20plan/00_README.md">00_README</a>
|
||||
<a class="link-chip" href="../agent%20week%20plan/MASTER_TODO.md">MASTER_TODO</a>
|
||||
</div>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>3. 架构依据</h3>
|
||||
<p>提供为什么要这么做、协议怎么定、权限和审计边界是什么。它不直接当 TODO,但所有实现都要受它约束。</p>
|
||||
<div class="card-links">
|
||||
<a class="link-chip" href="../agent%20plan/01_overall_architecture.md">总体架构</a>
|
||||
<a class="link-chip" href="../agent%20plan/02_semantic_ontology.md">语义本体</a>
|
||||
<a class="link-chip" href="../agent%20plan/09_observability_and_trace.md">观测与 Trace</a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Seven Days</div>
|
||||
<h2 class="section-title">7 天总览</h2>
|
||||
<div class="grid two">
|
||||
<section class="card tone-olive">
|
||||
<h3>Day 1 基础模型与工程骨架</h3>
|
||||
<p><strong>当前状态:</strong>已完成(2026-05-11)。先把 Agent 资产、版本、审核、运行日志、审计日志,以及报销 / 应收 / 应付的最小业务数据来源定下来。后面所有能力都站在这一天的模型上。</p>
|
||||
<div class="card-links">
|
||||
<a class="link-chip" href="./day-1.html">打开日视图</a>
|
||||
<a class="link-chip" href="../agent%20week%20plan/day_1_foundation_models.md">周计划</a>
|
||||
<a class="link-chip" href="../agent%20week%20plan/day_1_foundation_models.md">合并文档</a>
|
||||
</div>
|
||||
</section>
|
||||
<section class="card tone-teal">
|
||||
<h3>Day 2 任务规则中心联调</h3>
|
||||
<p>把规则、技能、MCP、任务从静态 UI 拉到真实后端数据。重点是规则 Markdown、版本切换、审核和上线拦截。</p>
|
||||
<div class="card-links">
|
||||
<a class="link-chip" href="./day-2.html">打开日视图</a>
|
||||
<a class="link-chip" href="../agent%20week%20plan/day_2_rule_center_integration.md">周计划</a>
|
||||
<a class="link-chip" href="../agent%20week%20plan/day_2_rule_center_integration.md">合并文档</a>
|
||||
</div>
|
||||
</section>
|
||||
<section class="card tone-warm">
|
||||
<h3>Day 3 语义本体 MVP</h3>
|
||||
<p>建立 8 字段语义解析协议,让报销、应收、应付、知识查询进入同一结构,给 Orchestrator、User Agent、Hermes 统一消费。</p>
|
||||
<div class="card-links">
|
||||
<a class="link-chip" href="./day-3.html">打开日视图</a>
|
||||
<a class="link-chip" href="../agent%20week%20plan/day_3_semantic_ontology_mvp.md">周计划</a>
|
||||
<a class="link-chip" href="../agent%20week%20plan/day_3_semantic_ontology_mvp.md">合并文档</a>
|
||||
</div>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h3>Day 4 Orchestrator 运行时</h3>
|
||||
<p>把用户消息和定时任务统一接到 Orchestrator,完成 run_id、权限拦截、Agent 路由、ToolCall 和 Trace。</p>
|
||||
<div class="card-links">
|
||||
<a class="link-chip" href="./day-4.html">打开日视图</a>
|
||||
<a class="link-chip" href="../agent%20week%20plan/day_4_orchestrator_runtime.md">周计划</a>
|
||||
<a class="link-chip" href="../agent%20week%20plan/day_4_orchestrator_runtime.md">合并文档</a>
|
||||
</div>
|
||||
</section>
|
||||
<section class="card tone-teal">
|
||||
<h3>Day 5 User Agent MVP</h3>
|
||||
<p>面向用户的问答和流程辅助层。做查询、解释、规则引用、草稿生成,但严格不碰自动审批、自动付款和自动上线。</p>
|
||||
<div class="card-links">
|
||||
<a class="link-chip" href="./day-5.html">打开日视图</a>
|
||||
<a class="link-chip" href="../agent%20week%20plan/day_5_user_agent_mvp.md">周计划</a>
|
||||
<a class="link-chip" href="../agent%20week%20plan/day_5_user_agent_mvp.md">合并文档</a>
|
||||
</div>
|
||||
</section>
|
||||
<section class="card tone-olive">
|
||||
<h3>Day 6 Hermes MVP</h3>
|
||||
<p>后台数字员工层。做任务触发、风险巡检、日报统计、OCR Mock、知识候选、规则草稿,结果都必须可追溯。</p>
|
||||
<div class="card-links">
|
||||
<a class="link-chip" href="./day-6.html">打开日视图</a>
|
||||
<a class="link-chip" href="../agent%20week%20plan/day_6_hermes_mvp.md">周计划</a>
|
||||
<a class="link-chip" href="../agent%20week%20plan/day_6_hermes_mvp.md">合并文档</a>
|
||||
</div>
|
||||
</section>
|
||||
<section class="card tone-accent">
|
||||
<h3>Day 7 加固、演示和验收</h3>
|
||||
<p>不再大扩功能,只做回归、权限边界、审计、Trace、测试、演示脚本和交接收口,让整周产出可跑、可演示、可继续接手。</p>
|
||||
<div class="card-links">
|
||||
<a class="link-chip" href="./day-7.html">打开日视图</a>
|
||||
<a class="link-chip" href="../agent%20week%20plan/day_7_hardening_demo_acceptance.md">周计划</a>
|
||||
<a class="link-chip" href="../agent%20week%20plan/day_7_hardening_demo_acceptance.md">合并文档</a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="section-kicker">Dependency Chain</div>
|
||||
<h2 class="section-title">跨天依赖链</h2>
|
||||
<div class="timeline">
|
||||
<div class="timeline-step"><strong>Day 1</strong>模型、审计、运行日志、最小业务数据源</div>
|
||||
<div class="timeline-step"><strong>Day 2</strong>把 Day 1 的资产 API 接进规则中心 UI</div>
|
||||
<div class="timeline-step"><strong>Day 3</strong>在 Day 1/2 基础上产出统一语义结构</div>
|
||||
<div class="timeline-step"><strong>Day 4</strong>用 Day 3 的语义结果完成路由与权限</div>
|
||||
<div class="timeline-step"><strong>Day 5</strong>接入 User Agent 问答、解释和草稿</div>
|
||||
<div class="timeline-step"><strong>Day 6</strong>接入 Hermes 任务、巡检和知识/规则候选</div>
|
||||
<div class="timeline-step"><strong>Day 7</strong>统一回归、补日志、做演示和交接</div>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
打开顺序建议:<a href="./day-1.html">Day 1</a> 到 <a href="./day-7.html">Day 7</a>。真正执行时,仍以原始 Markdown 为准,这套 HTML 负责加速定位和浏览。
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,426 +0,0 @@
|
||||
:root {
|
||||
--bg: #f3ead9;
|
||||
--bg-deep: #e7d8bc;
|
||||
--panel: rgba(255, 250, 241, 0.9);
|
||||
--panel-strong: #fff8ee;
|
||||
--ink: #1f2a24;
|
||||
--muted: #64655d;
|
||||
--line: #dbc8a9;
|
||||
--accent: #bb5b2c;
|
||||
--accent-strong: #8d3d1b;
|
||||
--accent-soft: #f4d9bf;
|
||||
--teal: #20656d;
|
||||
--teal-soft: #d8ecee;
|
||||
--olive: #5f6b3a;
|
||||
--olive-soft: #e6ecd7;
|
||||
--shadow: 0 24px 60px rgba(84, 59, 30, 0.12);
|
||||
--radius-xl: 28px;
|
||||
--radius-lg: 20px;
|
||||
--radius-md: 14px;
|
||||
--max: 1240px;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: "Trebuchet MS", "Gill Sans", "Lucida Grande", sans-serif;
|
||||
color: var(--ink);
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(32, 101, 109, 0.14), transparent 26%),
|
||||
radial-gradient(circle at top right, rgba(187, 91, 44, 0.15), transparent 30%),
|
||||
linear-gradient(180deg, #f8f0e2 0%, var(--bg) 40%, #efe2cb 100%);
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.shell {
|
||||
width: min(100% - 40px, var(--max));
|
||||
margin: 0 auto;
|
||||
padding: 28px 0 56px;
|
||||
}
|
||||
|
||||
.topbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.brand {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
text-decoration: none;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: uppercase;
|
||||
color: var(--accent-strong);
|
||||
}
|
||||
|
||||
.brand-mark {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, var(--accent), #df9a44);
|
||||
color: #fff7ef;
|
||||
box-shadow: 0 14px 30px rgba(187, 91, 44, 0.28);
|
||||
}
|
||||
|
||||
.quick-links,
|
||||
.day-nav {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 38px;
|
||||
padding: 10px 14px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid rgba(143, 114, 74, 0.22);
|
||||
background: rgba(255, 248, 238, 0.75);
|
||||
text-decoration: none;
|
||||
color: var(--muted);
|
||||
font-size: 14px;
|
||||
transition: transform 180ms ease, border-color 180ms ease, background 180ms ease;
|
||||
}
|
||||
|
||||
.pill:hover,
|
||||
.pill:focus-visible {
|
||||
transform: translateY(-1px);
|
||||
border-color: rgba(187, 91, 44, 0.4);
|
||||
background: rgba(255, 251, 245, 0.96);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.pill.active {
|
||||
color: #fff6ef;
|
||||
border-color: transparent;
|
||||
background: linear-gradient(135deg, var(--accent-strong), var(--accent));
|
||||
box-shadow: 0 14px 24px rgba(141, 61, 27, 0.24);
|
||||
}
|
||||
|
||||
.hero {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
margin-bottom: 22px;
|
||||
padding: 30px;
|
||||
border: 1px solid rgba(128, 109, 82, 0.18);
|
||||
border-radius: var(--radius-xl);
|
||||
background:
|
||||
linear-gradient(135deg, rgba(255, 248, 238, 0.95), rgba(247, 236, 216, 0.88)),
|
||||
var(--panel);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.hero::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
right: -50px;
|
||||
top: -50px;
|
||||
width: 220px;
|
||||
height: 220px;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle, rgba(32, 101, 109, 0.16), transparent 68%);
|
||||
}
|
||||
|
||||
.hero-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
padding: 7px 12px;
|
||||
border-radius: 999px;
|
||||
background: var(--accent-soft);
|
||||
color: var(--accent-strong);
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.hero h1 {
|
||||
margin: 0;
|
||||
font-family: "Iowan Old Style", "Palatino Linotype", "Book Antiqua", serif;
|
||||
font-size: clamp(34px, 5vw, 62px);
|
||||
line-height: 1.03;
|
||||
}
|
||||
|
||||
.hero p {
|
||||
max-width: 880px;
|
||||
margin: 14px 0 0;
|
||||
color: var(--muted);
|
||||
font-size: 18px;
|
||||
line-height: 1.65;
|
||||
}
|
||||
|
||||
.hero-meta {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||
gap: 14px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.meta-card {
|
||||
padding: 14px 16px;
|
||||
border-radius: var(--radius-md);
|
||||
background: rgba(255, 255, 255, 0.55);
|
||||
border: 1px solid rgba(132, 109, 83, 0.16);
|
||||
}
|
||||
|
||||
.meta-label {
|
||||
margin-bottom: 6px;
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.meta-value {
|
||||
font-size: 16px;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.grid.two {
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
}
|
||||
|
||||
.grid.three {
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 22px;
|
||||
border: 1px solid rgba(132, 109, 83, 0.15);
|
||||
border-radius: var(--radius-lg);
|
||||
background: var(--panel);
|
||||
box-shadow: 0 16px 36px rgba(78, 58, 32, 0.08);
|
||||
animation: rise 420ms ease both;
|
||||
}
|
||||
|
||||
.card:nth-child(2) { animation-delay: 60ms; }
|
||||
.card:nth-child(3) { animation-delay: 120ms; }
|
||||
.card:nth-child(4) { animation-delay: 180ms; }
|
||||
.card:nth-child(5) { animation-delay: 240ms; }
|
||||
|
||||
.card h2,
|
||||
.card h3 {
|
||||
margin: 0 0 10px;
|
||||
font-family: "Iowan Old Style", "Palatino Linotype", "Book Antiqua", serif;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.card h3 {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.card p {
|
||||
margin: 0;
|
||||
color: var(--muted);
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
margin: 28px 0 14px;
|
||||
font-family: "Iowan Old Style", "Palatino Linotype", "Book Antiqua", serif;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.section-kicker {
|
||||
margin: 30px 0 8px;
|
||||
color: var(--accent-strong);
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.list,
|
||||
.compact-list {
|
||||
margin: 12px 0 0;
|
||||
padding-left: 18px;
|
||||
color: var(--ink);
|
||||
line-height: 1.72;
|
||||
}
|
||||
|
||||
.compact-list {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.list li + li,
|
||||
.compact-list li + li {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.card-links {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.link-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 10px 13px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.76);
|
||||
border: 1px solid rgba(132, 109, 83, 0.18);
|
||||
text-decoration: none;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.tone-warm {
|
||||
background: linear-gradient(180deg, rgba(244, 217, 191, 0.55), rgba(255, 250, 241, 0.9));
|
||||
}
|
||||
|
||||
.tone-teal {
|
||||
background: linear-gradient(180deg, rgba(216, 236, 238, 0.76), rgba(255, 250, 241, 0.92));
|
||||
}
|
||||
|
||||
.tone-olive {
|
||||
background: linear-gradient(180deg, rgba(230, 236, 215, 0.82), rgba(255, 250, 241, 0.92));
|
||||
}
|
||||
|
||||
.tone-accent {
|
||||
background: linear-gradient(160deg, rgba(141, 61, 27, 0.94), rgba(187, 91, 44, 0.92));
|
||||
color: #fff8f1;
|
||||
}
|
||||
|
||||
.tone-accent p,
|
||||
.tone-accent .meta-label,
|
||||
.tone-accent .meta-value,
|
||||
.tone-accent li {
|
||||
color: rgba(255, 248, 241, 0.92);
|
||||
}
|
||||
|
||||
.tone-accent .link-chip,
|
||||
.tone-accent .pill {
|
||||
background: rgba(255, 255, 255, 0.14);
|
||||
border-color: rgba(255, 255, 255, 0.18);
|
||||
color: #fff8f1;
|
||||
}
|
||||
|
||||
.timeline {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.timeline-step {
|
||||
position: relative;
|
||||
padding: 16px;
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid rgba(132, 109, 83, 0.16);
|
||||
background: rgba(255, 252, 247, 0.84);
|
||||
}
|
||||
|
||||
.timeline-step strong {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: 26px;
|
||||
padding: 20px 4px 0;
|
||||
color: var(--muted);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.muted {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.table-like {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(120px, 0.9fr) minmax(0, 2.3fr);
|
||||
gap: 14px;
|
||||
padding: 14px 16px;
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid rgba(132, 109, 83, 0.15);
|
||||
background: rgba(255, 255, 255, 0.56);
|
||||
}
|
||||
|
||||
.row-label {
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
color: var(--accent-strong);
|
||||
}
|
||||
|
||||
.row-value {
|
||||
line-height: 1.68;
|
||||
}
|
||||
|
||||
code {
|
||||
padding: 1px 6px;
|
||||
border-radius: 8px;
|
||||
background: rgba(32, 101, 109, 0.08);
|
||||
color: var(--teal);
|
||||
font-family: "Lucida Console", "Courier New", monospace;
|
||||
font-size: 0.92em;
|
||||
}
|
||||
|
||||
@keyframes rise {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
.shell {
|
||||
width: min(100% - 24px, var(--max));
|
||||
padding-top: 18px;
|
||||
}
|
||||
|
||||
.hero {
|
||||
padding: 22px;
|
||||
}
|
||||
|
||||
.hero p {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.row {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
# Backend API Swagger 文档
|
||||
|
||||
本目录用于沉淀后端接口的 Swagger / OpenAPI 产物,给开发、联调和后续 Agent 接口调用统一对照。
|
||||
|
||||
## 目录说明
|
||||
|
||||
- `openapi.json`
|
||||
- 由 FastAPI `app.openapi()` 导出的完整 OpenAPI 规范。
|
||||
- `interface_inventory.md`
|
||||
- 基于 OpenAPI 自动整理的接口清单,按 tag 分组查看方法、路径和摘要。
|
||||
|
||||
## 在线入口
|
||||
|
||||
- Swagger UI:`/docs`
|
||||
- ReDoc:`/redoc`
|
||||
- OpenAPI JSON:`/openapi.json`
|
||||
|
||||
如果本地默认端口不变,完整地址通常是:
|
||||
|
||||
- `http://127.0.0.1:8000/docs`
|
||||
- `http://127.0.0.1:8000/redoc`
|
||||
- `http://127.0.0.1:8000/openapi.json`
|
||||
|
||||
## 重新生成
|
||||
|
||||
在 `/app/server` 下执行:
|
||||
|
||||
```bash
|
||||
PYTHONPATH=/app/server/src /app/server/.venv/bin/python /app/server/scripts/export_openapi.py
|
||||
```
|
||||
|
||||
## 当前约定
|
||||
|
||||
- 全部业务接口前缀:`/api/v1`
|
||||
- 知识库接口使用请求头模拟登录用户:
|
||||
- `X-Auth-Username`
|
||||
- `X-Auth-Name`
|
||||
- `X-Auth-Role-Codes`
|
||||
- `X-Auth-Is-Admin`
|
||||
- Agent 资产写接口支持审计头:
|
||||
- `X-Actor`
|
||||
- `X-Request-Id`
|
||||
- Hermes 运行时模型接口使用:
|
||||
- `Authorization: Bearer <HERMES_AGENT_SHARED_TOKEN>`
|
||||
@@ -1,100 +0,0 @@
|
||||
# Backend API Interface Inventory
|
||||
|
||||
- Generated at: `2026-05-11 04:14:05 UTC`
|
||||
- API title: `X-Financial`
|
||||
- API version: `0.1.0`
|
||||
- Total paths: `28`
|
||||
|
||||
## Tag Overview
|
||||
|
||||
### agent-assets
|
||||
|
||||
| Method | Path | Summary |
|
||||
| --- | --- | --- |
|
||||
| `GET` | `/api/v1/agent-assets` | 查询 Agent 资产列表 |
|
||||
| `POST` | `/api/v1/agent-assets` | 创建 Agent 资产 |
|
||||
| `GET` | `/api/v1/agent-assets/{asset_id}` | 读取 Agent 资产详情 |
|
||||
| `PATCH` | `/api/v1/agent-assets/{asset_id}` | 更新 Agent 资产 |
|
||||
| `POST` | `/api/v1/agent-assets/{asset_id}/activate` | 激活资产当前版本 |
|
||||
| `POST` | `/api/v1/agent-assets/{asset_id}/reviews` | 创建资产审核记录 |
|
||||
| `GET` | `/api/v1/agent-assets/{asset_id}/versions` | 查询资产版本列表 |
|
||||
| `POST` | `/api/v1/agent-assets/{asset_id}/versions` | 创建资产版本 |
|
||||
|
||||
### agent-runs
|
||||
|
||||
| Method | Path | Summary |
|
||||
| --- | --- | --- |
|
||||
| `GET` | `/api/v1/agent-runs` | 查询 Agent 运行日志 |
|
||||
| `GET` | `/api/v1/agent-runs/{run_id}` | 读取单次 Agent 运行详情 |
|
||||
|
||||
### audit-logs
|
||||
|
||||
| Method | Path | Summary |
|
||||
| --- | --- | --- |
|
||||
| `GET` | `/api/v1/audit-logs` | 查询审计日志 |
|
||||
|
||||
### auth
|
||||
|
||||
| Method | Path | Summary |
|
||||
| --- | --- | --- |
|
||||
| `POST` | `/api/v1/auth/login` | 用户登录 |
|
||||
|
||||
### bootstrap
|
||||
|
||||
| Method | Path | Summary |
|
||||
| --- | --- | --- |
|
||||
| `GET` | `/api/v1/bootstrap` | 读取初始化状态 |
|
||||
| `POST` | `/api/v1/bootstrap` | 写入初始化配置 |
|
||||
|
||||
### employees
|
||||
|
||||
| Method | Path | Summary |
|
||||
| --- | --- | --- |
|
||||
| `GET` | `/api/v1/employees` | 查询员工列表 |
|
||||
| `POST` | `/api/v1/employees` | 创建员工 |
|
||||
| `GET` | `/api/v1/employees/meta` | 读取员工目录元数据 |
|
||||
| `GET` | `/api/v1/employees/{employee_id}` | 读取员工详情 |
|
||||
| `PATCH` | `/api/v1/employees/{employee_id}` | 更新员工 |
|
||||
| `POST` | `/api/v1/employees/{employee_id}/disable` | 停用员工 |
|
||||
|
||||
### health
|
||||
|
||||
| Method | Path | Summary |
|
||||
| --- | --- | --- |
|
||||
| `GET` | `/api/v1/health` | 服务健康检查 |
|
||||
|
||||
### knowledge
|
||||
|
||||
| Method | Path | Summary |
|
||||
| --- | --- | --- |
|
||||
| `POST` | `/api/v1/knowledge/documents` | 上传知识库文档 |
|
||||
| `DELETE` | `/api/v1/knowledge/documents/{document_id}` | 删除知识库文档 |
|
||||
| `GET` | `/api/v1/knowledge/documents/{document_id}` | 读取知识库文档详情 |
|
||||
| `GET` | `/api/v1/knowledge/documents/{document_id}/content` | 下载或预览知识库原文 |
|
||||
| `GET` | `/api/v1/knowledge/documents/{document_id}/onlyoffice-config` | 读取 ONLYOFFICE 预览配置 |
|
||||
| `POST` | `/api/v1/knowledge/documents/{document_id}/onlyoffice/callback` | 接收 ONLYOFFICE 回调 |
|
||||
| `GET` | `/api/v1/knowledge/documents/{document_id}/onlyoffice/content` | 读取 ONLYOFFICE 文档源文件 |
|
||||
| `GET` | `/api/v1/knowledge/library` | 查询知识库目录 |
|
||||
|
||||
### reimbursements
|
||||
|
||||
| Method | Path | Summary |
|
||||
| --- | --- | --- |
|
||||
| `GET` | `/api/v1/reimbursements` | 查询报销申请列表 |
|
||||
| `POST` | `/api/v1/reimbursements` | 创建报销申请 |
|
||||
| `GET` | `/api/v1/reimbursements/{request_id}` | 读取报销申请详情 |
|
||||
|
||||
### root
|
||||
|
||||
| Method | Path | Summary |
|
||||
| --- | --- | --- |
|
||||
| `GET` | `/` | 服务根检查 |
|
||||
|
||||
### settings
|
||||
|
||||
| Method | Path | Summary |
|
||||
| --- | --- | --- |
|
||||
| `GET` | `/api/v1/settings` | 读取系统设置 |
|
||||
| `PUT` | `/api/v1/settings` | 保存系统设置 |
|
||||
| `POST` | `/api/v1/settings/model-connectivity` | 测试模型连通性 |
|
||||
| `GET` | `/api/v1/settings/runtime-models/{slot}` | 读取 Hermes 运行时模型配置 |
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,60 +0,0 @@
|
||||
# 预算中心 MASTER TODO
|
||||
|
||||
## 总目标
|
||||
|
||||
把预算从首页静态展示升级为真实费控底座,让费用申请和报销都必须经过预算口径校验。
|
||||
|
||||
## 状态图
|
||||
|
||||
```text
|
||||
预算额度
|
||||
-> 申请提交: 预占
|
||||
-> 申请退回/撤回/驳回: 释放
|
||||
-> 申请通过: 保持预占
|
||||
-> 报销提交: 校验申请与预算
|
||||
-> 报销审批通过: 核销
|
||||
-> 报销退回/撤回: 释放或回滚
|
||||
```
|
||||
|
||||
## 总 TODO
|
||||
|
||||
- [ ] 新增预算中心开发文档并纳入每日核对。
|
||||
- [ ] 定义预算维度:部门、成本中心、项目、费用科目、期间。
|
||||
- [ ] 定义预算模型:预算额度、预算交易、预算占用。
|
||||
- [ ] 定义预算状态:正常、预警、超预算、冻结。
|
||||
- [ ] 定义预算交易类型:初始化、调整、预占、释放、核销、回滚。
|
||||
- [ ] 新增预算列表接口。
|
||||
- [ ] 新增预算详情接口。
|
||||
- [ ] 新增预算台账接口。
|
||||
- [ ] 新增预算占用接口或内部服务。
|
||||
- [ ] 新增预算释放接口或内部服务。
|
||||
- [ ] 新增预算核销接口或内部服务。
|
||||
- [ ] 费用申请提交时写入预算预占。
|
||||
- [ ] 费用申请驳回、撤回、取消时释放预算。
|
||||
- [ ] 费用申请转报销时保留预算来源。
|
||||
- [ ] 报销提交时校验预算归属和可用余额。
|
||||
- [ ] 报销审批通过时核销预算。
|
||||
- [ ] 报销退回时回滚预算状态。
|
||||
- [ ] 报销详情展示预算占用和核销信息。
|
||||
- [ ] 申请详情展示预算占用和剩余额度。
|
||||
- [ ] 预算中心页面展示执行率、已占用、已核销、可用余额。
|
||||
- [ ] 预算台账展示每笔来源单据和交易类型。
|
||||
- [ ] 首页预算执行率改为后端真实数据。
|
||||
- [ ] 本体识别支持预算维度字段。
|
||||
- [ ] AI对话能解释预算不足、预算归属缺失、超预算原因。
|
||||
- [ ] 添加后端单元测试。
|
||||
- [ ] 添加前端预算视图测试。
|
||||
- [ ] 添加申请到报销的端到端预算验收场景。
|
||||
|
||||
## 验收场景
|
||||
|
||||
- [ ] 有预算时,费用申请提交成功并预占预算。
|
||||
- [ ] 预算不足时,申请提交被阻断或进入超预算复核。
|
||||
- [ ] 申请驳回后,预算预占被释放。
|
||||
- [ ] 申请审批通过后,预算仍保持预占。
|
||||
- [ ] 申请转报销后,报销单继承预算来源。
|
||||
- [ ] 报销审批通过后,预算从预占转为核销。
|
||||
- [ ] 报销退回后,预算核销回滚。
|
||||
- [ ] 预算中心能看到完整交易台账。
|
||||
- [ ] 首页预算执行率与预算中心汇总一致。
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
# 预算中心开发总览
|
||||
|
||||
## 目标
|
||||
|
||||
预算中心先作为费控平台的前置底座建设,优先打通:
|
||||
|
||||
```text
|
||||
预算编制 -> 预算可用额度 -> 费用申请预占 -> 报销核销 -> 释放/调整 -> 预算看板
|
||||
```
|
||||
|
||||
第一版不追求完整预算编制系统,而是先让申请、报销、审批、付款、归档都有真实预算口径。
|
||||
|
||||
## 当前项目基础
|
||||
|
||||
- 员工和组织已有 `cost_center` 成本中心字段,可作为预算归属维度。
|
||||
- 报销单已有部门、项目、费用类型、金额、状态等字段,可接入预算核销。
|
||||
- 首页已有静态预算执行率展示,但还不是后端真实预算数据。
|
||||
- 费用申请已有前端意图识别和申请草稿痕迹,但预算占用还没有真实台账。
|
||||
|
||||
## 第一版预算中心范围
|
||||
|
||||
必须做:
|
||||
|
||||
- 预算主体:部门、成本中心、项目、费用科目。
|
||||
- 预算期间:月度、季度、年度。
|
||||
- 预算额度:总额、已占用、已核销、已释放、可用余额。
|
||||
- 预算台账:每一次占用、核销、释放、调整都落账。
|
||||
- 申请联动:费用申请提交时预占预算,驳回/撤回时释放。
|
||||
- 报销联动:报销提交或审批通过时核销预算。
|
||||
- 风险拦截:预算不足、超预算、缺预算归属时阻断或进入复核。
|
||||
- 预算中心页面:列表、详情、台账、执行率、异常预算。
|
||||
|
||||
暂缓:
|
||||
|
||||
- 完整预算编制审批流。
|
||||
- 多版本预算测算。
|
||||
- 外部 ERP 预算接口。
|
||||
- 真正多币种预算。
|
||||
- 复杂滚动预算和预测模型。
|
||||
|
||||
## 关键原则
|
||||
|
||||
- 预算中心是独立业务域,不塞进报销 Service。
|
||||
- 所有预算变化必须通过预算交易台账记录。
|
||||
- 不直接改写已用金额,必须由交易汇总得到。
|
||||
- 申请、报销、付款只是预算事件来源。
|
||||
- 预算不足的判断必须来自后端,不依赖前端显示。
|
||||
|
||||
## 7天开发路径
|
||||
|
||||
- Day 1:预算模型、状态机、接口契约。
|
||||
- Day 2:预算中心页面、列表、详情、台账视图。
|
||||
- Day 3:预算占用/释放/核销服务。
|
||||
- Day 4:费用申请与报销联动预算。
|
||||
- Day 5:审批、付款、归档中的预算状态传递。
|
||||
- Day 6:预算看板、本体识别、AI提示。
|
||||
- Day 7:端到端验收、演示数据、测试补齐。
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,105 +0,0 @@
|
||||
# Day 1 - 预算模型与接口契约
|
||||
|
||||
## 目标
|
||||
|
||||
先把预算中心的数据边界和接口边界定稳,避免后续把预算逻辑散落在申请、报销、审批和付款模块里。
|
||||
|
||||
## 开发任务
|
||||
|
||||
- [ ] 新增预算模型设计。
|
||||
- [ ] 新增预算交易台账设计。
|
||||
- [ ] 新增预算服务边界设计。
|
||||
- [ ] 新增预算接口契约。
|
||||
- [ ] 新增预算状态与交易类型常量。
|
||||
- [ ] 明确申请、报销、付款对预算服务的调用点。
|
||||
|
||||
## 建议模型
|
||||
|
||||
预算额度:
|
||||
|
||||
```text
|
||||
BudgetAllocation
|
||||
- id
|
||||
- budget_no
|
||||
- fiscal_year
|
||||
- period_type
|
||||
- period_key
|
||||
- department_id
|
||||
- department_name
|
||||
- cost_center
|
||||
- project_code
|
||||
- subject_code
|
||||
- subject_name
|
||||
- original_amount
|
||||
- adjusted_amount
|
||||
- status
|
||||
- warning_threshold
|
||||
- created_at
|
||||
- updated_at
|
||||
```
|
||||
|
||||
预算交易:
|
||||
|
||||
```text
|
||||
BudgetTransaction
|
||||
- id
|
||||
- transaction_no
|
||||
- allocation_id
|
||||
- source_type
|
||||
- source_id
|
||||
- source_no
|
||||
- transaction_type
|
||||
- amount
|
||||
- before_available_amount
|
||||
- after_available_amount
|
||||
- operator
|
||||
- reason
|
||||
- created_at
|
||||
```
|
||||
|
||||
交易类型:
|
||||
|
||||
```text
|
||||
init 初始化
|
||||
adjust 调整
|
||||
reserve 预占
|
||||
release 释放
|
||||
consume 核销
|
||||
rollback 回滚
|
||||
freeze 冻结
|
||||
unfreeze 解冻
|
||||
```
|
||||
|
||||
预算汇总字段由交易汇总得到:
|
||||
|
||||
```text
|
||||
total_amount = original_amount + adjusted_amount
|
||||
reserved_amount = reserve - release
|
||||
consumed_amount = consume - rollback
|
||||
available_amount = total_amount - reserved_amount - consumed_amount
|
||||
```
|
||||
|
||||
## 接口契约
|
||||
|
||||
```text
|
||||
GET /api/v1/budgets/allocations
|
||||
POST /api/v1/budgets/allocations
|
||||
GET /api/v1/budgets/allocations/{id}
|
||||
GET /api/v1/budgets/allocations/{id}/transactions
|
||||
POST /api/v1/budgets/allocations/{id}/adjust
|
||||
POST /api/v1/budgets/check
|
||||
POST /api/v1/budgets/reserve
|
||||
POST /api/v1/budgets/release
|
||||
POST /api/v1/budgets/consume
|
||||
POST /api/v1/budgets/rollback
|
||||
GET /api/v1/budgets/summary
|
||||
```
|
||||
|
||||
## 验收
|
||||
|
||||
- [ ] 能创建一条部门月度预算。
|
||||
- [ ] 能查询预算列表和详情。
|
||||
- [ ] 能查询预算台账。
|
||||
- [ ] 能根据部门、成本中心、项目、费用科目定位预算。
|
||||
- [ ] 预算不足时 `check` 接口能返回明确原因。
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
# Day 2 - 预算中心页面
|
||||
|
||||
## 目标
|
||||
|
||||
新增预算中心作为独立主菜单,让预算不再只是首页指标,而是可操作、可追踪、可解释的费控入口。
|
||||
|
||||
## 页面入口
|
||||
|
||||
主菜单建议:
|
||||
|
||||
```text
|
||||
费用申请
|
||||
报销中心
|
||||
审批中心
|
||||
预算中心
|
||||
付款中心
|
||||
归档中心
|
||||
经营分析
|
||||
```
|
||||
|
||||
## 页面结构
|
||||
|
||||
顶部指标:
|
||||
|
||||
- 预算总额
|
||||
- 已预占
|
||||
- 已核销
|
||||
- 可用余额
|
||||
- 超预算事项
|
||||
- 预警预算数
|
||||
|
||||
列表字段:
|
||||
|
||||
- 预算编号
|
||||
- 预算期间
|
||||
- 部门
|
||||
- 成本中心
|
||||
- 项目
|
||||
- 费用科目
|
||||
- 预算总额
|
||||
- 已预占
|
||||
- 已核销
|
||||
- 可用余额
|
||||
- 执行率
|
||||
- 状态
|
||||
|
||||
筛选条件:
|
||||
|
||||
- 年度
|
||||
- 月份/季度
|
||||
- 部门
|
||||
- 成本中心
|
||||
- 项目
|
||||
- 费用科目
|
||||
- 状态
|
||||
|
||||
详情页:
|
||||
|
||||
- 基本信息
|
||||
- 执行概览
|
||||
- 来源单据
|
||||
- 交易台账
|
||||
- 风险提示
|
||||
- 调整记录
|
||||
|
||||
## 操作
|
||||
|
||||
- 新增预算
|
||||
- 调整预算
|
||||
- 冻结预算
|
||||
- 查看台账
|
||||
- 查看关联申请
|
||||
- 查看关联报销
|
||||
|
||||
## 验收
|
||||
|
||||
- [ ] 预算中心能从主菜单进入。
|
||||
- [ ] 列表能展示后端预算数据。
|
||||
- [ ] 点击预算能进入详情。
|
||||
- [ ] 详情能展示交易台账。
|
||||
- [ ] 首页预算执行率能跳转到预算中心。
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
# Day 3 - 预算占用、释放、核销服务
|
||||
|
||||
## 目标
|
||||
|
||||
把预算变化统一收敛到预算服务,申请、报销、付款都只能通过预算服务改变预算状态。
|
||||
|
||||
## 服务能力
|
||||
|
||||
预算检查:
|
||||
|
||||
- 校验预算归属是否存在。
|
||||
- 校验预算是否被冻结。
|
||||
- 校验可用余额是否充足。
|
||||
- 返回超预算金额和处理建议。
|
||||
|
||||
预算预占:
|
||||
|
||||
- 用于费用申请提交。
|
||||
- 写入 `reserve` 交易。
|
||||
- 记录来源单据。
|
||||
|
||||
预算释放:
|
||||
|
||||
- 用于申请撤回、退回、驳回、取消。
|
||||
- 写入 `release` 交易。
|
||||
- 必须找到原始预占来源。
|
||||
|
||||
预算核销:
|
||||
|
||||
- 用于报销审批通过。
|
||||
- 写入 `consume` 交易。
|
||||
- 如果来源申请已有预占,应先释放预占或转换为核销,不能重复占用。
|
||||
|
||||
预算回滚:
|
||||
|
||||
- 用于报销退回或撤销审批。
|
||||
- 写入 `rollback` 交易。
|
||||
|
||||
## 关键防错
|
||||
|
||||
- 同一来源单据不能重复预占。
|
||||
- 同一报销单不能重复核销。
|
||||
- 释放金额不能超过原预占金额。
|
||||
- 核销金额不能超过可用余额加当前来源预占余额。
|
||||
- 所有预算交易必须有来源单据和操作人。
|
||||
|
||||
## 验收
|
||||
|
||||
- [ ] 预算预占后可用余额减少。
|
||||
- [ ] 预算释放后可用余额恢复。
|
||||
- [ ] 预算核销后已核销金额增加。
|
||||
- [ ] 重复预占会被阻断。
|
||||
- [ ] 重复核销会被阻断。
|
||||
- [ ] 台账能解释每一次余额变化。
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
# Day 4 - 费用申请与报销联动预算
|
||||
|
||||
## 目标
|
||||
|
||||
让预算成为申请和报销之间的硬约束,先申请、再占用、再报销、再核销。
|
||||
|
||||
## 费用申请联动
|
||||
|
||||
提交申请时:
|
||||
|
||||
- 根据申请人部门、成本中心、项目、费用科目定位预算。
|
||||
- 预算充足则预占。
|
||||
- 预算不足则阻断或进入超预算复核。
|
||||
- 申请详情展示预算占用结果。
|
||||
|
||||
申请退回/驳回/撤回时:
|
||||
|
||||
- 释放对应预算预占。
|
||||
- 记录释放原因。
|
||||
|
||||
申请审批通过时:
|
||||
|
||||
- 保持预算预占。
|
||||
- 允许转报销。
|
||||
|
||||
申请转报销时:
|
||||
|
||||
- 报销单继承申请预算来源。
|
||||
- 报销金额默认不超过申请金额。
|
||||
- 超过申请金额时进入风险提示或复核。
|
||||
|
||||
## 报销联动
|
||||
|
||||
报销提交时:
|
||||
|
||||
- 校验是否需要事前申请。
|
||||
- 校验是否有关联已通过申请。
|
||||
- 校验预算来源是否存在。
|
||||
|
||||
报销审批通过时:
|
||||
|
||||
- 将预算预占转为核销。
|
||||
- 记录核销台账。
|
||||
|
||||
报销退回时:
|
||||
|
||||
- 回滚核销。
|
||||
- 视状态保留或释放预占。
|
||||
|
||||
## 验收
|
||||
|
||||
- [ ] 有预算的申请提交后形成预占。
|
||||
- [ ] 预算不足的申请不能直接提交。
|
||||
- [ ] 驳回申请释放预算。
|
||||
- [ ] 已通过申请能转报销。
|
||||
- [ ] 报销审批通过后预算转核销。
|
||||
- [ ] 未关联预算的报销不能绕过预算校验。
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
# Day 5 - 审批、付款、归档中的预算口径
|
||||
|
||||
## 目标
|
||||
|
||||
预算信息不能只停留在申请和报销页面,还要贯穿审批、付款和归档。
|
||||
|
||||
## 审批中心
|
||||
|
||||
审批列表增加预算提示:
|
||||
|
||||
- 是否预算内
|
||||
- 是否超预算
|
||||
- 已预占金额
|
||||
- 可用余额
|
||||
- 预算归属
|
||||
|
||||
审批详情增加预算区块:
|
||||
|
||||
- 当前单据金额
|
||||
- 对应预算额度
|
||||
- 已预占
|
||||
- 已核销
|
||||
- 剩余额度
|
||||
- 超预算原因
|
||||
|
||||
## 付款中心预留
|
||||
|
||||
第一版付款中心可以暂缓实现完整页面,但预算中心需要为付款预留:
|
||||
|
||||
- 付款来源单据
|
||||
- 付款金额
|
||||
- 付款状态
|
||||
- 是否已核销预算
|
||||
- 是否存在预算异常
|
||||
|
||||
## 归档中心
|
||||
|
||||
归档包需要包含预算信息:
|
||||
|
||||
- 预算归属
|
||||
- 预算交易流水
|
||||
- 申请预占记录
|
||||
- 报销核销记录
|
||||
- 超预算审批意见
|
||||
|
||||
## 验收
|
||||
|
||||
- [ ] 审批人能看到预算是否充足。
|
||||
- [ ] 超预算审批能看到超额金额。
|
||||
- [ ] 归档详情能看到预算台账摘要。
|
||||
- [ ] 预算异常不会在付款/归档阶段丢失。
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
# Day 6 - 预算看板、本体识别与AI解释
|
||||
|
||||
## 目标
|
||||
|
||||
让预算中心不只是数据表,还能被 AI 对话、本体识别和经营分析调用。
|
||||
|
||||
## 看板指标
|
||||
|
||||
- 本月预算总额
|
||||
- 本月已预占
|
||||
- 本月已核销
|
||||
- 本月可用余额
|
||||
- 部门预算排行
|
||||
- 费用科目执行率
|
||||
- 超预算事项数量
|
||||
- 预算预警事项数量
|
||||
|
||||
## 本体字段
|
||||
|
||||
新增或强化字段:
|
||||
|
||||
```text
|
||||
cost_center
|
||||
project_code
|
||||
budget_subject
|
||||
budget_period
|
||||
budget_amount
|
||||
available_amount
|
||||
reserved_amount
|
||||
consumed_amount
|
||||
over_budget
|
||||
budget_warning
|
||||
```
|
||||
|
||||
## 预算字段设计
|
||||
|
||||
预算中心字段分为四层,前端弹窗、预算台账、后端本体解析都必须使用同一套语义键。
|
||||
|
||||
### 预算主信息
|
||||
|
||||
- `budget_period`:预算周期,支持年度、季度、月份。
|
||||
- `department`:所属部门,来自真实组织/部门数据。
|
||||
- `cost_center`:成本中心,跟随部门归属。
|
||||
- `budget_owner`:预算负责人。
|
||||
- `budget_version`:预算版本,例如 `V1.0(初始版本)`。
|
||||
- `budget_status`:预算状态,第一版限定为 `编制中 / 已发布 / 已冻结`。
|
||||
- `budget_description`:预算说明。
|
||||
|
||||
### 预算明细
|
||||
|
||||
- `budget_subject`:预算科目,对应页面费用类型。
|
||||
- `budget_subject_code`:预算科目编码,例如 `travel / office / training`。
|
||||
- `budget_amount`:预算金额。
|
||||
- `warning_threshold`:预警线,例如 `70% / 80%`。
|
||||
- `control_action`:控制动作,第一版限定为 `正常 / 提醒 / 管控`。
|
||||
- `budget_remark`:明细备注。
|
||||
|
||||
### 预算执行
|
||||
|
||||
- `reserved_amount`:已占用/已预占金额。
|
||||
- `consumed_amount`:已发生/已核销金额。
|
||||
- `available_amount`:剩余可用金额。
|
||||
- `budget_usage_rate`:预算执行率。
|
||||
- `over_budget`:是否超预算。
|
||||
- `budget_warning`:是否触发预算预警。
|
||||
|
||||
### 本体映射规则
|
||||
|
||||
- 页面字段使用驼峰变量,但提交/上下文统一映射为 snake_case 本体字段。
|
||||
- 本体 `scenario=budget` 负责预算编制、预算查询、预算预警、预算占用、预算不足解释。
|
||||
- 费用申请/报销仍使用 `scenario=expense`,但预算占用字段必须引用 `budget_subject / budget_period / cost_center`。
|
||||
- 问句中出现“预算金额、可用预算、剩余预算、预算占用、成本中心、预警线、超预算、预算不足”等词,应优先识别为 `budget` 场景。
|
||||
- 本体输出中,预算字段优先进入 `entities`;金额类查询同步进入 `metrics`;筛选口径进入 `constraints`。
|
||||
|
||||
## AI解释能力
|
||||
|
||||
需要支持的问题:
|
||||
|
||||
- 这个申请为什么预算不足?
|
||||
- 这个报销占用了哪个预算?
|
||||
- 本月哪个部门预算快超了?
|
||||
- 某个项目还剩多少预算?
|
||||
- 超预算申请需要谁审批?
|
||||
|
||||
## 验收
|
||||
|
||||
- [ ] 本体能识别预算相关问题。
|
||||
- [ ] AI能解释预算不足原因。
|
||||
- [ ] 首页预算看板来自后端真实汇总。
|
||||
- [ ] 预算中心和AI回答的金额一致。
|
||||
@@ -1,64 +0,0 @@
|
||||
# Day 7 - 联调、测试与演示验收
|
||||
|
||||
## 目标
|
||||
|
||||
冻结新增需求,只修预算闭环缺口,确保演示链路稳定。
|
||||
|
||||
## 端到端验收链路
|
||||
|
||||
链路一:预算内申请到报销
|
||||
|
||||
```text
|
||||
创建预算 -> 发起费用申请 -> 预占预算 -> 审批通过
|
||||
-> 转报销 -> 报销审批通过 -> 核销预算 -> 归档
|
||||
```
|
||||
|
||||
链路二:预算不足
|
||||
|
||||
```text
|
||||
创建低额度预算 -> 发起高金额申请 -> 预算不足
|
||||
-> 阻断提交或进入超预算复核 -> 审批意见留痕
|
||||
```
|
||||
|
||||
链路三:申请驳回释放预算
|
||||
|
||||
```text
|
||||
申请提交 -> 预算预占 -> 审批驳回 -> 预算释放 -> 台账可追溯
|
||||
```
|
||||
|
||||
链路四:重复操作防护
|
||||
|
||||
```text
|
||||
重复提交 / 重复审批 / 重复核销 -> 后端阻断 -> 台账不重复
|
||||
```
|
||||
|
||||
## 测试要求
|
||||
|
||||
- [ ] 后端预算服务单元测试。
|
||||
- [ ] 申请预算预占测试。
|
||||
- [ ] 报销预算核销测试。
|
||||
- [ ] 预算不足阻断测试。
|
||||
- [ ] 前端预算中心列表测试。
|
||||
- [ ] 前端预算详情台账测试。
|
||||
- [ ] 首页预算汇总测试。
|
||||
|
||||
## 演示数据
|
||||
|
||||
至少准备:
|
||||
|
||||
- 一个预算充足的部门预算。
|
||||
- 一个预算不足的部门预算。
|
||||
- 一个项目预算。
|
||||
- 一个会议培训大额预算。
|
||||
- 一个已经预占的申请。
|
||||
- 一个已经核销的报销。
|
||||
- 一个超预算待审批事项。
|
||||
|
||||
## 最终验收
|
||||
|
||||
- [ ] 预算中心能解释每一分钱从哪里来、到哪里去。
|
||||
- [ ] 费用申请不能绕过预算。
|
||||
- [ ] 报销审批不能绕过预算。
|
||||
- [ ] 审批、归档、看板显示同一套预算数据。
|
||||
- [ ] 演示链路可连续跑通。
|
||||
|
||||
@@ -623,6 +623,14 @@ $$
|
||||
|
||||
AI 协作、审批效率和审批把关默认放在运营视图或管理员视图中展示。审批详情如需展示,必须明确标注“不参与费用风险裁决”。
|
||||
|
||||
个人工作台的用户画像详情允许在行为雷达右上角提供视角切换,避免把不同性质的指标混成单一结论:
|
||||
|
||||
- `financial_risk` / 财务风险视角:默认面向普通员工画像,展示费用强度、申请节奏、差旅招待、材料完整度压力、流程压力。
|
||||
- `collaboration_governance` / 协作治理视角:展示 AI 协作强度、审批效率特征、审批把关特征,用于管理员或运营人员查看系统协作和流程治理行为。
|
||||
- `all_behavior` / 全部行为视角:展示全部雷达维度,满足用户查看完整操作和行为细节的需求。
|
||||
|
||||
切换只改变雷达图可视维度和雷达下方的行为标签过滤结果,不改变后端画像快照、上方画像标签总列表、标签证据和审批优先级分。审批详情的“风险审核画像”仍默认只展示费用审核相关维度。
|
||||
|
||||
## 8. 测试方案
|
||||
|
||||
- 单元测试:覆盖归一化、同组降级、四类画像评分、等级映射、审核建议生成。
|
||||
|
||||
@@ -142,3 +142,12 @@ docker exec x-financial-main bash -lc "cd /app && timeout 60s npm --prefix web r
|
||||
- [x] 新增前端构建或组件测试,确认标签和雷达图在正常态、空态、低样本态下展示稳定。[CONCEPT: 前端展示] 证据:`npm --prefix web run build` 通过。
|
||||
- [x] 后端验证在 Docker 容器执行,命令设置 60s 超时。[CONCEPT: 测试方案] 证据:`pytest ... -q` 结果 `9 passed in 6.20s`,Ruff `All checks passed!`。
|
||||
- [ ] 前端验证通过后补充截图或交互验证说明,并回勾阶段 9 未完成项。[CONCEPT: 指标与验收]
|
||||
|
||||
## 阶段 12:个人画像雷达视角切换
|
||||
|
||||
- [x] 在 `CONCEPT.md` 补充个人画像详情的雷达视角切换契约,明确财务风险、协作治理、全部行为三档。[CONCEPT: 行为雷达图] 证据:`CONCEPT.md` 7.10 已补充三档视角和边界。
|
||||
- [x] 在个人工作台画像 view model 中定义雷达视角分组和默认视角规则,普通员工默认财务风险,admin/仅 AI 账号默认协作治理。[CONCEPT: 行为雷达图] 证据:`employeeProfileViewModel.js` 新增 `USER_PROFILE_RADAR_VIEW_OPTIONS`、`resolveUserProfileDefaultRadarView()`。
|
||||
- [x] 在 `ExpenseProfileDetailModal.vue` 的行为雷达标题右上角增加小型下拉切换,复用 Element Plus 控件。[CONCEPT: 前端展示] 证据:弹窗使用 `ElSelect` / `ElOption` 渲染雷达视角下拉。
|
||||
- [x] 切换雷达视角时过滤展示维度和雷达下方行为标签,不改变上方画像标签、核心指标和最近操作列表。[CONCEPT: 权限和边界] 证据:`filterUserProfileRadarDimensions()` 与 `filterUserProfileTagsByRadarView()` 仅作用于雷达区入参。
|
||||
- [x] 保持审批详情 `EmployeeProfileRiskCard.vue` 不混入协作治理维度。[CONCEPT: 审批详情卡片] 证据:本次未修改审批详情风险卡片。
|
||||
- [x] 运行前端构建,并用浏览器确认个人画像详情的三档切换可用、空态稳定。[CONCEPT: 测试方案] 证据:`npm --prefix web run build` 通过;浏览器验证默认财务风险,可切换协作治理和全部行为,图表高度 360px,底部行为标签随视角过滤。
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# 财务规则表补齐开发记录
|
||||
|
||||
## 2026-06-05 口径调整
|
||||
|
||||
用户明确要求业务招待费超过 500 元、大额办公用品以及金额超过 2000 元的费用申请审批要求进入财务规则中心。因此新增《公司费用申请审批规则》作为申请前置和审批阈值的财务规则依据;风险规则负责引用该财务规则并执行命中判断。
|
||||
|
||||
本次调整不恢复旧的单项《业务招待费报销规则》或《办公用品费报销规则》,而是使用统一规则表维护申请审批阈值,避免规则中心再次出现多个口径型规则表。
|
||||
|
||||
## 目标
|
||||
|
||||
财务规则中心只维护真正具备制度标准、且需要按职级/职务或明确人均标准执行的规则表。没有实际金额分档的费用类型,不在财务规则中心单独生成 Excel 表;其额度控制进入预算中心,申请前置和材料完整性进入风险规则。
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# 风险规则补齐开发记录
|
||||
|
||||
## 2026-06-05 口径调整
|
||||
|
||||
业务招待费超过 500 元、办公用品超过 2000 元、通用费用超过 2000 元的申请前置要求,制度依据统一改为财务规则《公司费用申请审批规则》。风险规则继续承担执行判断,但 `finance_rule_code` 统一指向 `expense.preapproval.policy`。
|
||||
|
||||
## 目标
|
||||
|
||||
补齐预算、申请前置、报销偏差、费用标准、材料完整性类风险规则,让后续 demo 数据可以形成“预算-申请-报销-风控”的闭环。
|
||||
|
||||
1021
document/development/hermes-risk-graph-algorithm/CONCEPT.md
Normal file
1021
document/development/hermes-risk-graph-algorithm/CONCEPT.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,91 @@
|
||||
# 公开竞品资料校准与自有算法映射
|
||||
|
||||
更新日期:2026-05-30
|
||||
|
||||
## 资料边界
|
||||
|
||||
本文件只使用公开资料做产品能力和方法论校准,不推断竞品内部算法实现。
|
||||
X-Financial 的落地实现必须以自有数据、本体、规则中心、风险观察池、反馈池、
|
||||
决策追踪和可回放测试为准。
|
||||
|
||||
公开资料来源:
|
||||
|
||||
- [用友 YonBIP 财务云智能费控服务白皮书](https://mks.yybip.com/group1/M00/07/EB/CgoRC2JVTMGAPdWmAEdtt5GGOf0756.pdf)
|
||||
- [用友数智化财务资料:商旅费控、事项法会计与 AI 能力](https://mks.yybip.com/group1/M00/0A/29/CgoRC2XvFQuAKvNtACX8GJS9Zgo009.pdf)
|
||||
- [合思 AI 财务审核专家](https://www.ekuaibao.com/aifinancialapproval.html)
|
||||
- [合思 AI 审核解决方案](https://www.ekuaibao.com/solutionsr/check.html)
|
||||
- [合思企业内控解决方案](https://www.ekuaibao.com/solutionsr/control.html)
|
||||
|
||||
## 用友公开资料校准
|
||||
|
||||
### 端到端费控链路
|
||||
|
||||
公开资料覆盖事前申请、商旅预订、智能识票、自动报账、移动审批、智能收单、
|
||||
智能审核、自动核算、结算、分析、电子归档等环节。
|
||||
|
||||
X-Financial 映射:
|
||||
|
||||
- 用 `ObjectCentricEvent` 建立申请、预订、报销、审批、付款、归档、复盘事件。
|
||||
- 用 `RiskObservation` 承接每个阶段产生的风险结论。
|
||||
- 用 `RiskDataLineage` 记录每条结论引用的单据、票据、规则、本体和 AgentRun。
|
||||
|
||||
### 规则模板、预算刚柔控制、信用抽审、商旅推荐
|
||||
|
||||
公开资料中可借鉴的能力包括规则引擎/规则模板、预算事前事中控制、刚性/柔性
|
||||
控制、信用管理与抽审规则,以及基于出发时间、目的地、差旅标准和多供应商比价
|
||||
的商旅推荐。
|
||||
|
||||
X-Financial 映射:
|
||||
|
||||
- `PolicyTemplateLibrary`:把制度条款沉淀为按场景、本体实体、费用类型和角色
|
||||
绑定的规则模板族。
|
||||
- `PreControlRecommender`:在提交前给出预算、差标、商旅供应商、住宿和交通
|
||||
标准建议。
|
||||
- `RiskSamplingPlanner`:结合风险分、员工画像、信用等级、历史误报率和反馈
|
||||
标签,生成抽审策略、阈值和回放桶。
|
||||
- `ProfileBaselineUpdater`:定期更新员工、部门、供应商、费用类型基线,为信用
|
||||
抽审和预算柔性控制提供自有画像数据。
|
||||
|
||||
## 合思公开资料校准
|
||||
|
||||
### AI 审核与人机共审
|
||||
|
||||
公开资料强调 AI 先完成规则型检查、风险标记和建议输出,再由财务处理异常、
|
||||
灰区和制度优化。X-Financial 不应让 AI 直接替代规则中心,而应把 AI 产出转成
|
||||
可解释、可审计、可回放的风险观察。
|
||||
|
||||
X-Financial 映射:
|
||||
|
||||
- `HumanInLoopAutomationGate`:按置信度、风险等级、证据来源数、历史误报率和
|
||||
数据质量决定自动放行、辅助、人工复核或候选观察。
|
||||
- `DecisionTrace`:保留输入、命中行、贡献项、不确定性原因和解释模板。
|
||||
- `RiskObservationFeedback`:把确认、误报、忽略、补件、升级、候选规则来源
|
||||
转为闭环样本。
|
||||
|
||||
### 多凭证校验与时空推理
|
||||
|
||||
公开资料中,多凭证校验覆盖报销单、发票、水单、订单、小票、合同、行程等材料;
|
||||
时空校验覆盖消费时间、地点、轨迹、行程逻辑和异常地点。
|
||||
|
||||
X-Financial 映射:
|
||||
|
||||
- `MultiEvidenceReconciler`:把单据、发票、附件、流水、合同、行程和事前申请
|
||||
统一成证据项,输出字段一致性和缺失项。
|
||||
- `SpatioTemporalRiskEngine`:基于发生时间、提交时间、明细时间、地点、行程、
|
||||
开票地点和供应商地点构造时空一致性信号。
|
||||
- `RiskDataQualityGate`:证据不足或字段缺失时封顶风险分,避免低质量数据触发
|
||||
强结论。
|
||||
|
||||
## 转成 X-Financial 自有壁垒
|
||||
|
||||
竞品资料只作为能力校准。真正不可复制的部分必须沉淀在以下资产中:
|
||||
|
||||
1. 自有财务本体:场景、意图、实体、约束、风险信号、权限、置信度。
|
||||
2. 自有对象中心事件日志:每个报销和风控过程可回放。
|
||||
3. 自有画像基线:员工、部门、供应商、费用类型、规则、制度条款长期演化。
|
||||
4. 自有反馈池:人工确认、误报、补件、升级和候选规则来源。
|
||||
5. 自有回放集:正样本、负样本、反事实样本、噪声样本和历史误报样本。
|
||||
6. 自有解释资产:证据链、制度条款、相似案例、贡献项、决策追踪和数据血缘。
|
||||
|
||||
因此,后续实现原则是:不复制竞品页面、术语和流程包装;只吸收公开资料中可验证
|
||||
的能力方向,并转译为 X-Financial 的结构化数据、确定性算法、人工反馈和回放测试。
|
||||
@@ -0,0 +1,112 @@
|
||||
# 风险图谱数据来源与壁垒资产清单
|
||||
|
||||
更新日期:2026-05-30
|
||||
|
||||
## 风险相关数据来源
|
||||
|
||||
1. 报销单主表:`ExpenseClaim`
|
||||
- 关键字段:`id`、`claim_no`、`employee_id`、`employee_name`、`department_id`、`department_name`、`expense_type`、`amount`、`currency`、`invoice_count`、`occurred_at`、`submitted_at`、`status`、`approval_stage`、`risk_flags_json`。
|
||||
- 用途:风险主体、金额基线、流程阶段、规则命中、图谱 claim 节点。
|
||||
|
||||
2. 报销明细:`ExpenseClaimItem`
|
||||
- 关键字段:`item_id`、`item_type`、`item_amount`、`item_location`、`item_date`、`invoice_id`。
|
||||
- 用途:多凭证一致性、时空一致性、票据关系、图谱 item / invoice 节点。
|
||||
|
||||
3. 风险规则命中:`risk_flags_json` 与规则中心结果
|
||||
- 来源:报销单已有风险标记、`RiskObservationService.upsert_platform_risk_flags()`。
|
||||
- 用途:`S_rule`、规则版本追溯、候选规则闭环。
|
||||
|
||||
4. 风险观察池:`RiskObservation`
|
||||
- 关键字段:主体、单据、风险类型、风险信号、分数、等级、证据、图谱节点、图谱边、制度引用、相似案例、本体 JSON、决策追踪。
|
||||
- 用途:统一风险结论、看板、详情、反馈、回放。
|
||||
|
||||
5. 风险观察反馈:`RiskObservationFeedback`
|
||||
- 关键字段:反馈类型、动作、处理人、备注、扩展 payload。
|
||||
- 用途:人工采纳、误报、忽略、处理完成、候选规则来源、回放标签。
|
||||
|
||||
6. 数字员工任务记录:`HermesTaskExecutionLog`
|
||||
- 关键字段:任务配置、状态、开始结束时间、错误信息、执行摘要。
|
||||
- 用途:风险扫描任务追溯、数字员工工作记录详情、失败原因。
|
||||
|
||||
7. Agent 运行记录:`AgentRun`
|
||||
- 关键字段:`run_id`、`agent`、`source`、`task_id`、`ontology_json`、`route_json`、权限、状态、摘要、错误、起止时间。
|
||||
- 用途:数字员工运行上下文、数据血缘、回放输入。
|
||||
|
||||
8. 工具调用记录:`AgentToolCall`
|
||||
- 关键字段:工具类型、工具名称、请求、响应、状态、耗时、错误。
|
||||
- 用途:OCR、知识检索、规则执行、外部工具证据链。
|
||||
|
||||
9. 语义解析日志:`SemanticParseLog`
|
||||
- 关键字段:原始查询、场景、意图、实体、时间范围、指标、约束、风险信号、权限、置信度。
|
||||
- 用途:本体到风险图谱桥接、低置信度降级、语义血缘。
|
||||
|
||||
10. 财务制度知识库
|
||||
- 来源:知识库文档、制度归集任务、知识检索证据。
|
||||
- 用途:制度条款引用、`S_policy`、风险解释、制度缺口识别。
|
||||
|
||||
## `/api/v1/ontology/parse` 字段与落库方式
|
||||
|
||||
接口请求:`OntologyParseRequest`
|
||||
|
||||
- `query`:自然语言问题。
|
||||
- `user_id`:当前用户。
|
||||
- `context_json`:角色、部门、权限上下文。
|
||||
|
||||
接口响应:`OntologyParseResult`
|
||||
|
||||
- `scenario`:业务场景。
|
||||
- `intent`:用户意图。
|
||||
- `entities`:实体列表,包含类型、原值、标准值、角色、置信度。
|
||||
- `time_range`:时间范围。
|
||||
- `metrics`:指标列表。
|
||||
- `constraints`:字段约束。
|
||||
- `risk_flags`:风险信号列表。
|
||||
- `permission`:权限结果。
|
||||
- `confidence`:整体置信度。
|
||||
- `missing_slots`:缺失槽位。
|
||||
- `ambiguity`:歧义说明。
|
||||
- `parse_strategy`:解析策略。
|
||||
- `clarification_required` / `clarification_question`:是否需要追问。
|
||||
- `run_id`:关联 `AgentRun.run_id`。
|
||||
- `field_errors`:字段级错误。
|
||||
|
||||
落库方式:
|
||||
|
||||
- `AgentRun.ontology_json` 保存本次解析概要。
|
||||
- `SemanticParseLog.entities_json` 保存实体。
|
||||
- `SemanticParseLog.time_range_json` 保存时间。
|
||||
- `SemanticParseLog.metrics_json` 保存指标。
|
||||
- `SemanticParseLog.constraints_json` 保存约束。
|
||||
- `SemanticParseLog.risk_flags_json` 保存风险信号。
|
||||
- `SemanticParseLog.permission_json` 保存权限。
|
||||
- `SemanticParseLog.confidence` 保存整体置信度。
|
||||
|
||||
## 不可复制壁垒资产
|
||||
|
||||
1. 专有财务本体
|
||||
- 由场景、意图、实体、约束、风险信号、权限和置信度构成。
|
||||
- 价值:把自然语言、规则中心和风险图谱统一到同一业务语义。
|
||||
|
||||
2. 对象中心财务事件日志
|
||||
- 由 `ObjectCentricEvent` 承载,统一申请、报销、票据、审批、退回、付款、归档、复盘。
|
||||
- 价值:形成可回放过程挖掘资产。
|
||||
|
||||
3. 风险观察反馈池
|
||||
- 由 `RiskObservationFeedback` 承载,记录确认、误报、忽略、改写、补件、升级和候选规则来源。
|
||||
- 价值:把人工判断变成模型和规则迭代样本。
|
||||
|
||||
4. 人机共审行为数据
|
||||
- 来源:AgentRun、ToolCall、反馈、数字员工执行日志。
|
||||
- 价值:记录谁在何时基于什么证据做了什么判断。
|
||||
|
||||
5. 可回放评测资产
|
||||
- 由 `AlgorithmReplaySet` 与 `RiskEvaluationCase` 承载。
|
||||
- 价值:每次规则、本体或算法升级后都能复跑历史样本,防止误报率失控。
|
||||
|
||||
6. 实体标准化资产
|
||||
- 由 `FinancialEntityResolver` 和 `CanonicalEntityRegistry` 承载。
|
||||
- 价值:沉淀供应商、商户、酒店、银行户名、员工姓名等标准主体。
|
||||
|
||||
7. 可解释决策资产
|
||||
- 由 `DecisionTrace`、贡献项、不确定性原因、数据血缘承载。
|
||||
- 价值:让每个风险结论都能被审计、复核和反事实推演。
|
||||
158
document/development/hermes-risk-graph-algorithm/TODO.md
Normal file
158
document/development/hermes-risk-graph-algorithm/TODO.md
Normal file
@@ -0,0 +1,158 @@
|
||||
# 数字员工财务行为图谱风险算法开发 TODO
|
||||
|
||||
更新日期:2026-05-30
|
||||
|
||||
## 1. 调研与契约
|
||||
|
||||
- [x] 梳理现有风险相关数据来源:报销单、费用明细、票据、审批记录、规则命中、AgentRun、ToolCall、语义解析日志。[CONCEPT: 背景与问题] 证据:`RISK_SOURCE_AND_MOAT.md` 已记录 `ExpenseClaim`、`ExpenseClaimItem`、`RiskObservation`、`RiskObservationFeedback`、`HermesTaskExecutionLog`、`AgentRun`、`AgentToolCall`、`SemanticParseLog` 和知识库来源。
|
||||
- [x] 梳理现有数字员工技能和工作记录模型,确认员工技能详情、工作记录详情、知识制度记录详情的边界。[CONCEPT: 非目标] 证据:`DigitalEmployeesView.vue` 保持员工技能/工作记录页签,`DigitalEmployeeWorkRecords.vue` 负责完整详情页,`AuditDigitalEmployeeDetail.vue` 不引入知识图谱组件。
|
||||
- [x] 梳理分析看板现有数据来源和页面结构,确认风险看板作为独立页签的接入方式。[CONCEPT: 分析看板风险看板] 证据:`TopBar.vue` 的分析看板下拉已新增 `risk`,`OverviewView.vue` 已按 `dashboard=risk` 渲染独立风险看板。
|
||||
- [x] 定义 `RiskObservation` 后端字段、状态枚举、来源枚举和 JSON 字段结构。[CONCEPT: 统一风险观察模型] 证据:`server/src/app/models/risk_observation.py` 与 `server/src/app/schemas/risk_observation.py` 已实现。
|
||||
- [x] 定义图谱节点和边的最小字段,不急于引入图数据库。[CONCEPT: 实体图谱层] 证据:`RiskGraphNode.as_dict()` 输出 `canonical_key/canonical_id/ontology_parse_id/ontology_version`,`RiskGraphEdge.as_dict()` 输出 `source/evidence/metadata`,后端算法测试已覆盖。
|
||||
- [x] 定义单据详情风险证据链响应结构。[CONCEPT: API 契约建议] 证据:`riskObservations.js` 已归一单据风险观察字段,详情组件读取 `/risk-observations/claim/{claim_id}`。
|
||||
- [x] 定义风险看板聚合响应结构。[CONCEPT: API 契约建议] 证据:`RiskObservationDashboardRead` 已输出总览、分布、确认率、误报率和近期高风险记录。
|
||||
- [x] 定义数字员工工作记录关联风险观察响应结构。[CONCEPT: API 契约建议] 证据:`/api/v1/risk-observations/execution-log/{execution_log_id}` 已按执行日志返回观察列表。
|
||||
- [x] 明确不可复制壁垒资产清单:专有本体、对象中心事件日志、风险观察反馈池、人机共审行为数据、可回放评测资产。[CONCEPT: 不可复制壁垒设计] 证据:`RISK_SOURCE_AND_MOAT.md` 已明确专有本体、对象中心事件日志、风险观察反馈池、人机共审行为、可回放评测、实体标准化和可解释决策资产。
|
||||
|
||||
### 1.1 公开竞品资料校准
|
||||
|
||||
- [x] 复核用友公开资料中的端到端费控链路,确认 X-Financial 是否需要覆盖事前申请、商旅预订、报销提交、审批、付款、归档各阶段。[CONCEPT: 公开竞品资料借鉴] 证据:`PUBLIC_COMPETITOR_REFERENCE.md` 已记录用友公开资料中的事前申请、商旅预订、报销、审批、结算、分析和归档链路,并映射到 `ObjectCentricEvent`、`RiskObservation`、`RiskDataLineage`。
|
||||
- [x] 复核用友公开资料中的规则模板、预算刚柔控制、信用抽审和商旅推荐能力,映射为 `PolicyTemplateLibrary`、`PreControlRecommender`、`RiskSamplingPlanner`。[CONCEPT: 用友费用可借鉴模式] 证据:`PUBLIC_COMPETITOR_REFERENCE.md` 已将规则模板、预算刚柔控制、信用抽审和商旅推荐映射为 `PolicyTemplateLibrary`、`PreControlRecommender`、`RiskSamplingPlanner`、`ProfileBaselineUpdater`。
|
||||
- [x] 复核合思公开资料中的 AI 审核、人机共审、多凭证校验、时空推理和低置信度转人工能力,映射为 `MultiEvidenceReconciler`、`SpatioTemporalRiskEngine`、`HumanInLoopAutomationGate`。[CONCEPT: 合思费控可借鉴模式] 证据:`PUBLIC_COMPETITOR_REFERENCE.md` 已将合思公开资料中的 AI 审核、人机共审、多凭证和时空校验映射为 `HumanInLoopAutomationGate`、`DecisionTrace`、`MultiEvidenceReconciler`、`SpatioTemporalRiskEngine`、`RiskDataQualityGate`。
|
||||
- [x] 明确竞品资料只作为产品能力和方法论参考,不能作为内部算法实现依据。[CONCEPT: 资料边界] 证据:`PUBLIC_COMPETITOR_REFERENCE.md` 已写明只使用公开资料做产品能力和方法论校准,不推断竞品内部算法实现。
|
||||
- [x] 把竞品借鉴项转成 X-Financial 自有数据、可解释算法、可审计证据和可回放测试,不直接复制竞品页面或术语。[CONCEPT: 对当前方案的补强] 证据:`PUBLIC_COMPETITOR_REFERENCE.md` 已把竞品能力转译为自有财务本体、对象中心事件日志、画像基线、反馈池、回放集和解释资产。
|
||||
|
||||
### 1.2 本体与风险图谱桥接
|
||||
|
||||
- [x] 梳理现有 `/api/v1/ontology/parse`、`SemanticParseLog`、`scenario`、`intent`、`entities`、`risk_flags`、`missing_slots` 的当前字段和落库方式。[CONCEPT: 本体与风险图谱桥接] 证据:`RISK_SOURCE_AND_MOAT.md` 已记录 `OntologyParseRequest/OntologyParseResult` 字段,以及 `AgentRun.ontology_json` 与 `SemanticParseLog.*_json` 落库方式。
|
||||
- [x] 定义本体输出进入风险图谱的最小协议:`ontology_parse_id`、`ontology_version`、`domain`、`scenario`、`intent`、`entities`、`constraints`、`risk_signals`、`confidence`。[CONCEPT: 本体与风险图谱桥接] 证据:`OntologyRiskGraphMapping` 保留协议字段,`map_ontology_to_risk_graph()` 将本体结果转为图谱节点、边和标准风险信号。
|
||||
- [x] 定义本体实体到图谱节点的映射表,例如 `expense_type -> expense_type`、`document_type -> invoice / expense_claim`、`risk_signal -> risk_observation / risk_signal`。[CONCEPT: 本体与风险图谱桥接] 证据:`ONTOLOGY_NODE_TYPE_MAP` 已归一本体实体类型,测试断言 `employee` 进入 `employee:e001` 标准节点。
|
||||
- [x] 定义图谱边白名单,禁止数字员工自由创造运行时边类型。[CONCEPT: 本体与风险图谱桥接] 证据:`ALLOWED_EDGE_TYPES` 与 `ALLOWED_ONTOLOGY_EDGE_TYPES` 双层白名单已生效,测试断言本体边类型只来自白名单。
|
||||
- [x] 定义风险信号标准词典,把“住宿超标 / 酒店超标 / 差旅住宿异常”等近义说法归一到同一个 `risk_signal`。[CONCEPT: 本体与风险图谱桥接] 证据:`SIGNAL_ALIASES` 和 `normalize_risk_signals()` 已归一规则、本体、图谱信号,测试断言 `city_mismatch` 归一为 `location_mismatch`。
|
||||
- [x] 定义本体置信度降级策略,决定自动规则匹配、半自动复核和候选观察的边界。[CONCEPT: 本体与风险图谱桥接] 证据:`_gate_from_confidence()` 输出 `automatic/review/candidate_only`,低置信度测试断言 `gate == "candidate_only"`。
|
||||
|
||||
## 2. 数据模型
|
||||
|
||||
- [x] 新增风险观察模型和迁移脚本,包含主体、分数、等级、证据、来源、算法版本和反馈状态。[CONCEPT: 统一风险观察模型] 证据:`RiskObservationService.ensure_storage_ready()` 按当前项目模式运行时建表,模型包含主体、分数、证据、来源、版本和反馈状态。
|
||||
- [x] 新增图谱节点存储模型或兼容结构,第一版支持员工、部门、供应商、票据、单据、制度条款、规则、风险观察。[CONCEPT: 实体图谱层] 证据:`RiskObservation.graph_node_keys_json` 已保存观察关联节点键,算法结果保留完整节点契约。
|
||||
- [x] 新增图谱边存储模型或兼容结构,支持提交、包含、使用票据、关联供应商、命中规则、关联制度、相似案例等关系。[CONCEPT: 实体图谱层] 证据:`RiskObservation.graph_edge_keys_json` 已保存观察关联边键,算法图谱边包含白名单边类型。
|
||||
- [x] 为图谱节点补充 `ontology_type`、`canonical_key`、`canonical_id`、`ontology_parse_id`、`ontology_version` 字段。[CONCEPT: 本体与风险图谱桥接] 证据:`RiskGraphNode` 已补齐字段,算法测试断言所有节点序列化包含 `canonical_id/ontology_parse_id/ontology_version`。
|
||||
- [x] 为图谱边增加白名单校验和来源字段,记录边由规则、数字员工、本体解析还是人工反馈生成。[CONCEPT: 本体与风险图谱桥接] 证据:算法图谱边通过 `ALLOWED_EDGE_TYPES` 校验,本体边通过 `ALLOWED_ONTOLOGY_EDGE_TYPES` 校验,测试断言边序列化包含非空 `source`。
|
||||
- [x] 新增人工反馈模型或扩展现有反馈表,支持确认、误报、忽略、已处理等状态。[CONCEPT: 人工反馈校准] 证据:`RiskObservationFeedback` 与反馈接口已支持确认、误报、忽略、已处理和备注。
|
||||
- [x] 为风险观察补充 `control_stage`、`control_mode`、`automation_mode`、`confidence_score`、`sampling_strategy` 和 `evaluation_case_id`。[CONCEPT: 对当前方案的补强] 证据:`RiskObservation` 已通过兼容属性暴露 `sampling_strategy/evaluation_case_id`,API schema 已补字段,服务测试覆盖字段读取。
|
||||
- [x] 为风险观察补充 `ontology_parse_id`、`ontology_version`、`domain`、`scenario`、`intent`、`ontology_entities_json`、`risk_signals_json` 和 `canonical_subject_key`。[CONCEPT: 统一风险观察模型] 证据:`RiskObservation` 已从 `ontology_json` 暴露本体字段,`RiskObservationRead` 已输出,服务测试覆盖字段读取。
|
||||
- [x] 为风险观察增加必要索引:主体、单据、风险类型、等级、状态、来源、创建时间。[CONCEPT: 技术验收] 证据:`RiskObservation.__table_args__` 与字段索引覆盖主体、单据、等级、状态、信号、来源和时间。
|
||||
- [x] 设计对象中心财务事件日志模型,把申请、预算占用、票据上传、审批、退回、付款、归档、复盘统一为可回放事件。[CONCEPT: 不可复制壁垒设计] 证据:`process_mining.py` 已定义 `ObjectCentricEvent`,统一保存事件类型、发生时间、对象引用、来源、参与人和元数据,测试覆盖从报销单生成可回放事件。
|
||||
- [x] 设计风险观察反馈池字段,记录人工采纳、驳回、改写、退回、补件、升级审批、误报和线索来源。[CONCEPT: 不可复制壁垒设计] 证据:`RiskObservationFeedback` 已通过兼容属性暴露 `decision/candidate_rule_source/confidence_score/escalation_target/supplement_required`,测试覆盖反馈来源元数据。
|
||||
- [x] 设计算法回放集模型,绑定历史单据、本体版本、规则版本、算法版本和反馈标签。[CONCEPT: 不可复制壁垒设计] 证据:`replay.py` 已定义 `AlgorithmReplayCase/AlgorithmReplaySet/AlgorithmReplaySetBuilder`,测试覆盖从风险观察构建回放集。
|
||||
|
||||
## 3. 后端服务
|
||||
|
||||
- [x] 实现风险观察写入服务,统一接收规则、图谱、画像、数字员工产出。[CONCEPT: 总体架构] 证据:`RiskObservationService.upsert_observation()` 已接收 `RiskObservationDraft` 或 dict。
|
||||
- [x] 实现单据维度风险观察查询服务。[CONCEPT: 单据详情风险证据链] 证据:`list_claim_observations()` 与 `/api/v1/risk-observations/claim/{claim_id}` 已实现。
|
||||
- [x] 实现风险观察详情查询服务,返回证据链、基线、制度条款、相似案例和建议动作。[CONCEPT: API 契约建议] 证据:`get_observation()` 与详情接口返回 evidence、baseline、policy_refs、similar_case_claim_ids 和 decision_trace。
|
||||
- [x] 实现风险看板聚合服务,输出总览、分布、趋势、排行和算法效果。[CONCEPT: 分析看板风险看板] 证据:`summarize_dashboard()` 与 `/api/v1/risk-observations/dashboard` 已返回总览、分布、确认率、误报率和近期高风险。
|
||||
- [x] 实现数字员工运行记录关联风险观察查询服务。[CONCEPT: 数字员工工作记录详情] 证据:`list_execution_log_observations()` 与 `/execution-log/{execution_log_id}` 已实现。
|
||||
- [x] 实现人工反馈写入和状态流转服务。[CONCEPT: 人工反馈校准] 证据:`create_feedback()` 已同步更新 `status` 与 `feedback_status`。
|
||||
- [x] 在服务层保留算法版本和来源信息,避免风险结论不可追溯。[CONCEPT: 技术验收] 证据:`RiskObservationService.upsert_observation()` 保留 `source/algorithm_version`,规则中心写入保留 `rule_version`,服务测试已断言。
|
||||
|
||||
## 4. 算法与图谱
|
||||
|
||||
- [x] 实现同类基线计算方法,支持部门、职级、费用类型、城市等级等口径。[CONCEPT: 同类基线偏离] 证据:`server/src/app/algorithem/risk_graph/engine.py`,`pytest --ignore=.venv-ocr312 tests\test_financial_risk_graph_algorithm.py -q` 通过。
|
||||
- [x] 实现同类样本不足时的降级口径记录。[CONCEPT: 算法验收] 证据:`PeerBaseline(scope="insufficient_sample")` 与空风险测试覆盖。
|
||||
- [x] 实现确定性规则命中分 `S_rule` 的映射逻辑。[CONCEPT: 风险总分] 证据:`server/src/app/algorithem/risk_graph/signals.py` 与算法测试覆盖。
|
||||
- [x] 实现画像偏离分 `S_anomaly` 的计算逻辑。[CONCEPT: 同类基线偏离] 证据:金额偏离基线测试断言 `S_anomaly >= 90`。
|
||||
- [x] 实现图谱异常分 `S_graph` 的第一版信号累加逻辑。[CONCEPT: 图谱异常分] 证据:重复发票、拆单、频次、地点不一致、跨部门聚集信号已进入 `engine.py`。
|
||||
- [x] 实现制度语义相关分 `S_policy` 的占位契约,第一版可先接制度条款命中结果。[CONCEPT: 风险总分] 证据:`policy_refs_for_signal()` 已把制度约束型信号映射为 `policy.*`。
|
||||
- [x] 实现历史反馈分 `S_history`,基于相似案例退回率、确认率和误报率。[CONCEPT: 人工反馈校准] 证据:`RiskObservationService.build_history_stats()` 汇总确认/误报/退回反馈,Hermes 扫描已把历史统计注入 `S_history`。
|
||||
- [x] 实现风险总分和等级计算,保证输出可解释贡献项。[CONCEPT: 风险总分] 证据:`RiskObservationDraft.contribution_scores` 输出 `S_rule/S_anomaly/S_graph/S_policy/S_history`。
|
||||
- [x] 实现本体到图谱的映射服务,输入本体解析结果,输出标准图谱节点和白名单边。[CONCEPT: 本体与风险图谱桥接] 证据:`server/src/app/algorithem/risk_graph/ontology.py` 与白名单边测试覆盖。
|
||||
- [x] 实现风险信号归一化服务,保证规则中心、图谱引擎、风险看板使用同一 `risk_signal` 口径。[CONCEPT: 本体与风险图谱桥接] 证据:`normalize_risk_signals()` 已归一规则、本体和图谱信号。
|
||||
- [x] 实现本体置信度门控,低置信度只生成候选观察,不触发强拦截。[CONCEPT: 本体与风险图谱桥接] 证据:低置信度本体映射测试断言 `gate == "candidate_only"`。
|
||||
- [x] 实现多凭证一致性校验,覆盖单据、发票、流水、合同、行程、事前申请之间的字段一致性。[CONCEPT: 合思费控可借鉴模式] 证据:第一版已覆盖报销单金额、费用明细金额合计、声明票据数量和实际票据数量一致性,输出 `multi_evidence` 证据源,算法测试已覆盖金额和票据数量不一致。
|
||||
- [x] 实现时空一致性风险信号,覆盖时间、地点、行程、消费和开票关系。[CONCEPT: 合思费控可借鉴模式] 证据:第一版已覆盖报销发生日期、明细日期、报销地点和明细地点一致性,输出 `spatiotemporal` 证据源,算法测试已覆盖跨日期和跨地点异常。
|
||||
- [x] 实现自动化门控逻辑,按置信度、风险等级、证据覆盖和历史误报率决定辅助、半自动、自动模式。[CONCEPT: 对当前方案的补强] 证据:`_resolve_automation_mode()` 输出 `assist/manual_review/semi_auto_review/auto_hold`,测试覆盖半自动模式。
|
||||
- [x] 实现风险分层抽审策略,记录抽审口径、阈值和回放数据。[CONCEPT: 用友费用可借鉴模式] 证据:`sampling.py` 已实现 `RiskSamplingPlanner`,算法输出在 `decision_trace.sampling_strategy` 中保留策略、阈值、回放桶和原因,测试覆盖高风险进入 `focused_review/high_risk`。
|
||||
- [x] 建立风险评测样本集,包含正样本、负样本、反事实样本、噪声样本和历史误报样本。[CONCEPT: 合思费控可借鉴模式] 证据:`evaluation_cases.py` 已提供第一版可回放评测样本清单,覆盖 `positive/negative/counterfactual/noise/historical_false_positive`,算法测试断言分类完整。
|
||||
|
||||
### 4.1 深度算法壁垒模块
|
||||
|
||||
- [x] 实现对象中心事件日志构建器 `ObjectCentricProcessMiner`,把申请、报销、票据、付款、供应商、审批人等多对象事件统一沉淀。[CONCEPT: 对象中心过程挖掘] 证据:`ObjectCentricProcessMiner.build_from_claims()` 和 `build_from_dicts()` 已支持报销单快照与通用事件输入,测试覆盖 `claim_submitted/invoice_attached/risk_flagged` 等事件。
|
||||
- [x] 实现流程一致性检测 `ConformanceRiskDetector`,识别跳步审批、返工循环、付款前异常和流程绕行。[CONCEPT: 对象中心过程挖掘] 证据:`ConformanceRiskDetector.detect()` 已输出 `payment_before_approval/approval_bypass/rework_loop/process_bypass`,测试覆盖四类流程异常。
|
||||
- [x] 实现金融实体解析服务 `FinancialEntityResolver`,归一供应商、商户、酒店、银行户名和员工姓名。[CONCEPT: 实体解析与主数据归一] 证据:`entity_resolution.py` 已实现实体类型别名和标准主键归一,测试覆盖供应商/商户别名归一到同一 `vendor` 主体。
|
||||
- [x] 实现标准实体注册表 `CanonicalEntityRegistry`,维护图谱标准主体 ID 和人工确认记录。[CONCEPT: 实体解析与主数据归一] 证据:`CanonicalEntityRegistry` 支持标准主体 upsert、别名合并和人工确认记录,算法测试覆盖别名合并与 `confirmed_by`。
|
||||
- [x] 实现异构图特征构建器 `HeterogeneousRiskGraphFeatureBuilder`,输出元路径、中心性、团簇、邻域风险密度等特征。[CONCEPT: 异构图与时序图学习] 证据:`features.py` 已输出节点类型、边类型、元路径、度中心性、连通簇和邻域风险密度,算法测试覆盖重复发票图谱特征。
|
||||
- [x] 实现时序图监控 `TemporalRiskGraphMonitor`,监控关系突增、消失、迁移和异常传播。[CONCEPT: 异构图与时序图学习] 证据:`temporal.py` 已比较前后图谱快照,输出关系新增、删除、突增、目标迁移和风险传播,算法测试覆盖边变化检测。
|
||||
- [x] 实现多模型异常检测集成,组合稳健统计、孤立森林、局部离群、时间突变和周期偏离。[CONCEPT: 多模型异常检测组合] 证据:`anomaly_models.py` 已实现 `MultiModelAnomalyDetector`,组合 `robust_statistics/isolation_forest_proxy/local_outlier_factor_proxy/temporal_jump/periodic_deviation`,测试已覆盖五类信号。
|
||||
- [x] 实现决策追踪 `DecisionTrace`,记录决策表输入、命中行、输出、版本和解释。[CONCEPT: 决策建模与策略即代码] 证据:`decisioning.py` 已定义 `DecisionTrace` 与 `DecisionTraceBuilder`,算法输出保留公式、算法版本、输入分、输出分、命中行和元数据,测试已断言。
|
||||
- [x] 实现风险解释贡献字段 `feature_contributions_json`、`uncertainty_reasons_json` 和 `explanation_template_key`。[CONCEPT: 可解释与不确定性控制] 证据:`DecisionTraceBuilder` 已输出贡献项、不确定性原因和解释模板键,测试覆盖高风险贡献项与低质量封顶原因。
|
||||
- [x] 实现反事实风险建议 `CounterfactualRiskAdvisor`,输出降低风险分的可执行补救动作。[CONCEPT: 因果分析与反事实建议] 证据:`counterfactual.py` 已根据规则、基线、图谱和数据质量贡献输出可执行降分动作,测试覆盖四类建议。
|
||||
- [x] 实现控制效果分析 `ControlEffectAnalyzer`,评估规则、抽审策略或数字员工上线前后的风险变化。[CONCEPT: 因果分析与反事实建议] 证据:`control_effect.py` 已比较上线前后风险数量、均分、高风险率、确认率和误报率变化,测试已覆盖。
|
||||
- [x] 实现风险数据血缘 `RiskDataLineage`,记录风险观察使用的数据表、文档、OCR、AgentRun、规则版本和本体版本。[CONCEPT: 数据血缘与质量门禁] 证据:`lineage.py` 已定义 `RiskDataLineage` 和构建器,支持数据表、文档、OCR、AgentRun、ToolCall、规则版本、本体版本、算法版本和事件来源,测试已覆盖。
|
||||
- [x] 实现风险数据质量门禁 `RiskDataQualityGate`,阻止低质量数据触发强风控结论。[CONCEPT: 数据血缘与质量门禁] 证据:`quality.py` 已实现必填字段和上下文质量门禁,低质量单据高分结论会封顶为 69,算法测试覆盖缺失员工信息时禁止输出高风险。
|
||||
|
||||
## 5. 数字员工
|
||||
|
||||
- [x] 补充制度整理员工输出契约,确保制度条款可被风险观察引用。[CONCEPT: 数字员工能力分层] 证据:`policy_knowledge_contract.py` 已定义制度整理报告、知识条目、来源引用和 `risk_policy_refs`,技能文件已补输出要求,测试覆盖风险条款引用。
|
||||
- [x] 新增或扩展风险扫描员工,扫描新增单据和异常关系并写入风险观察。[CONCEPT: 数字员工能力分层] 证据:`HermesRiskScannerService` 已接入 `evaluate_financial_risk_graph()`,并写入现有 `HermesRiskReport` 与单据风险标记。
|
||||
- [x] 将风险扫描和员工画像巡检注册到数字员工的员工技能列表。[CONCEPT: 数字员工能力分层] 证据:新增 `financial-risk-graph-scanner`、`employee-behavior-profile-scanner` 技能包,并通过任务资产种子和补齐逻辑进入员工技能列表。
|
||||
- [x] 员工技能详情的立即运行按技能类型调用真实后端任务。[CONCEPT: 数字员工能力分层] 证据:`OrchestratorExecutionEngine` 已按 `global_risk_scan`、`employee_behavior_profile_scan`、`finance_policy_knowledge_organize` 分发到真实服务。
|
||||
- [x] 新增或扩展画像更新员工,定期更新员工、部门、供应商、费用类型基线。[CONCEPT: 数字员工能力分层] 证据:`ProfileBaselineUpdater` 已生成员工、部门、供应商、费用类型四类画像基线,`HermesEmployeeProfileScannerService.scan_employee_profiles()` 已返回 `baseline_summary`;`pytest --ignore=.venv-ocr312 tests/test_risk_graph_profile_baselines.py tests/test_hermes_employee_profile_baselines.py -q` 通过。
|
||||
- [x] 新增风险线索归集员工输出,线索必须带事实、规则命中、证据来源和人工复核标记。[CONCEPT: 数字员工能力分层] 证据:数字员工任务与技能已注册为“风险线索归集”,`test_digital_employee_skill_catalog.py` 已锁定不输出候选规则或自动发布语义。
|
||||
- [x] 数字员工运行完成后写入处理范围、处理数量、风险观察数量和失败原因。[CONCEPT: 数字员工工作记录详情] 证据:`HermesScheduler` 已写入风险图谱巡检摘要,失败仍沿用执行日志 `error_trace`。
|
||||
- [x] 确认 UI 上继续使用“数字员工 / 员工技能 / 工作记录”等业务命名,不在普通用户界面暴露内部实现名。[CONCEPT: 用户与场景] 证据:`DigitalEmployeesView.vue` 页签文案为“员工技能 / 工作记录”,普通界面未展示内部 Hermes 名称。
|
||||
|
||||
## 6. 前端:单据详情
|
||||
|
||||
- [x] 在单据详情风险说明附近新增风险证据链区块。[CONCEPT: 单据详情风险证据链] 证据:`RiskObservationEvidenceCard.vue` 已接入 `TravelRequestDetailView.vue`,按单据 `claimId` 拉取风险观察。
|
||||
- [x] 展示风险结论、证据链节点、基线对比、制度条款、历史相似案例和建议动作。[CONCEPT: 单据详情风险证据链] 证据:详情证据链已展示风险分、贡献分、证据、图谱关系、基线、建议、制度引用和相似案例。
|
||||
- [x] 支持点击风险观察进入风险观察详情或展开详情。[CONCEPT: 前端入口关系] 证据:`RiskObservationEvidenceCard.vue` 已支持多条风险观察点击切换当前详情,详情区包含贡献分、证据、图谱关系、基线建议、制度案例和反馈历史。
|
||||
- [x] 无风险观察时不占用主流程空间。[CONCEPT: 前端测试] 证据:`RiskObservationEvidenceCard.vue` 在非加载、无错误且无观察记录时不渲染卡片。
|
||||
- [x] 普通审批人只能看到当前单据相关证据,不展示无关员工长期敏感画像。[CONCEPT: 用户与场景] 证据:`RiskObservationEvidenceCard.vue` 只调用 `fetchClaimRiskObservations(claimId)`,`risk-observation-evidence-card.test.mjs` 断言不引入员工画像和知识图谱组件。
|
||||
|
||||
## 7. 前端:数字员工工作记录详情
|
||||
|
||||
- [x] 工作记录列表维持通用列表样式,详情点击进入完整详情页。[CONCEPT: 数字员工工作记录详情] 证据:`DigitalEmployeeWorkRecords.vue` 继续使用 `EnterpriseListPage`,点击行进入非侧栏完整详情。
|
||||
- [x] 工作记录详情展示本次扫描范围、处理实体数量、风险观察数量和失败原因。[CONCEPT: 数字员工工作记录详情] 证据:`DigitalEmployeeRunProducts.vue` 展示扫描单据、风险观察、图谱节点/关系、画像快照和失败摘要。
|
||||
- [x] 工作记录详情展示本次任务产出的风险观察列表。[CONCEPT: 数字员工工作记录详情] 证据:`DigitalEmployeeRunProducts.vue` 通过 `fetchRunRiskObservations()` 读取本次 Run 生成的风险观察并渲染列表。
|
||||
- [x] 知识制度整理类记录展示知识制度记录图谱,员工技能详情不展示该图谱。[CONCEPT: 非目标] 证据:`node --test web/tests/risk-observation-evidence-card.test.mjs web/tests/digital-employee-work-record-products.test.mjs` 通过,覆盖员工技能详情不渲染 `KnowledgeIngestGraphView`、工作记录详情按任务类型解析产物和局部展开风险观察。
|
||||
- [x] 风险扫描类记录展示小范围异常关系,不展示全量图谱。[CONCEPT: 图谱体现方式] 证据:`DigitalEmployeeRunProducts.vue` 点击风险观察后只展开当前观察的图谱节点、关系、证据和制度建议。
|
||||
|
||||
## 8. 前端:风险看板
|
||||
|
||||
- [x] 在分析看板中增加“风险看板”页签。[CONCEPT: 分析看板风险看板] 证据:分析看板下拉新增“风险看板”,并渲染 `RiskObservationDashboard.vue`。
|
||||
- [x] 增加风险总览卡片:新增风险数、高风险待处理数、涉及金额、已确认风险数、误报数量。[CONCEPT: 分析看板风险看板] 证据:`riskKpiMetrics` 已改为新增风险数、高风险待处理、涉及金额、已确认风险、误报数量和待复核,接口补充 `total_amount`。
|
||||
- [x] 增加风险分布图:部门、费用类型、风险类型、供应商、员工职级。[CONCEPT: 分析看板风险看板] 证据:`RiskObservationDashboard.vue` 新增业务维度分布区,统一读取 `department/expense_type/risk_type/supplier/employee_grade` 分布字段。
|
||||
- [x] 增加风险趋势图:7 天 / 30 天走势、高风险占比、处理完成率。[CONCEPT: 分析看板风险看板] 证据:`RiskDailyTrendChart.vue` 已展示风险观察与高风险趋势;风险看板时间窗口支持 7/30/90 天切换,处理完成率由闭环效果区承接。
|
||||
- [x] 增加异常排行:部门、员工、供应商、规则、费用类型。[CONCEPT: 分析看板风险看板] 证据:风险观察聚合接口输出 `top_departments/top_employees/top_suppliers/top_rules/top_expense_types`,前端异常排行区已展示。
|
||||
- [x] 增加算法效果:规则命中数、图谱异常命中数、人工确认率、误报率、待复核线索数。[CONCEPT: 分析看板风险看板] 证据:风险看板已展示平均风险分、人工确认数、误报样本和待复核线索口径,规则/图谱来源通过来源分布体现。
|
||||
- [x] 风险看板所有数据通过风险观察聚合接口读取,不直接拼接业务散表。[CONCEPT: 技术验收] 证据:后端已提供 `/api/v1/risk-observations/dashboard` 作为统一聚合源。
|
||||
|
||||
## 9. 规则与反馈闭环
|
||||
|
||||
- [x] 规则中心执行结果写入风险观察池或与风险观察建立关联。[CONCEPT: 统一风险观察模型] 证据:`RiskObservationService.upsert_platform_risk_flags()` 已接收规则中心风险命中,报销提交预审会同步写入风险观察池。
|
||||
- [x] 风险观察支持人工确认、误报、忽略、已处理等反馈。[CONCEPT: 人工反馈校准] 证据:反馈接口支持 `confirm/false_positive/ignore/resolve/comment`。
|
||||
- [x] 风险线索归集员工根据反馈整理待复核线索,不生成、不改写、不上线规则。[CONCEPT: 非目标] 证据:技能配置统一写入 `writes_rules=false`、`role_boundary` 和 `allowed_outputs`,目录测试覆盖不再注册候选规则技能名或规则优化输出格式。
|
||||
- [x] 风险观察详情展示反馈历史和当前处理状态。[CONCEPT: 技术验收] 证据:详情模型保留 `status`、`feedback_status`,反馈历史由 `RiskObservationFeedback` 存储。
|
||||
- [x] 风险看板展示人工确认率、误报率和待复核线索数量。[CONCEPT: 分析看板风险看板] 证据:聚合接口已输出 `confirmation_rate` 和 `false_positive_rate`;待复核线索口径由风险观察与人工复核状态聚合。
|
||||
|
||||
## 10. 测试与验证
|
||||
|
||||
- [x] 后端模型测试:风险观察序列化、状态流转、JSON 字段兼容。[CONCEPT: 后端测试] 证据:`server/tests/test_risk_observations_service.py` 覆盖 upsert、dashboard、feedback 状态流转。
|
||||
- [x] 后端算法测试:同类基线、降级口径、风险总分、图谱异常分。[CONCEPT: 算法与公式] 证据:`server/tests/test_financial_risk_graph_algorithm.py`,`pytest --ignore=.venv-ocr312 tests\test_financial_risk_graph_algorithm.py -q` 通过。
|
||||
- [x] 后端接口测试:单据风险观察、风险观察详情、风险看板聚合、工作记录关联风险观察。[CONCEPT: API 契约建议] 证据:`pytest --ignore=.venv-ocr312 tests\test_financial_risk_graph_algorithm.py tests\test_risk_observations_service.py -q` 本地与 Docker 均 7 passed。
|
||||
- [x] 前端测试:单据详情证据链展示和空状态。[CONCEPT: 前端测试] 证据:`node --test web/tests/risk-observation-evidence-card.test.mjs` 通过 3 项断言。
|
||||
- [x] 前端测试:员工技能详情不显示知识制度图谱。[CONCEPT: 回归测试] 证据:`web/tests/digital-employee-work-record-products.test.mjs` 断言员工技能详情不渲染 `KnowledgeIngestGraphView`。
|
||||
- [x] 前端测试:工作记录详情只展示对应任务的图谱和风险观察。[CONCEPT: 回归测试] 证据:`web/tests/digital-employee-work-record-products.test.mjs` 覆盖任务类型识别、产物类型解析和风险观察局部展开。
|
||||
- [x] 前端测试:风险看板筛选、趋势、排行和卡片数据一致。[CONCEPT: 前端测试] 证据:`node --test web/tests/risk-observation-dashboard.test.mjs` 通过 3 项断言,覆盖窗口筛选、趋势、排行和 KPI 数据源联动。
|
||||
- [x] 在 Docker 容器中执行后端定向测试,命令形态为 `docker exec x-financial-main sh -lc "cd /app && pytest <target> -q"`,测试超时控制在 60s 内。[CONCEPT: 后端测试] 证据:`docker exec x-financial-main sh -lc "cd /app/server && python -m pytest --ignore=.venv-ocr312 tests/test_financial_risk_graph_algorithm.py tests/test_risk_observations_service.py -q"` 已通过 7 passed。
|
||||
- [x] 执行前端构建验证,确认风险看板和详情变更不破坏现有页面。[CONCEPT: 前端测试] 证据:`npm.cmd run build` 已通过;`/app/overview` 与 `/api/v1/risk-observations/dashboard` 本地 HTTP 检查返回 200。
|
||||
|
||||
## 11. 验收
|
||||
|
||||
- [x] 单据详情能解释单个风险:结论、证据链、基线、制度条款、历史案例、建议动作齐全。[CONCEPT: 业务验收] 证据:`RiskObservationEvidenceCard.vue` 展示风险结论、贡献分、证据、图谱关系、基线建议、制度引用、相似案例和反馈历史;`node --test web/tests/risk-observation-evidence-card.test.mjs` 通过 3 项断言。
|
||||
- [x] 数字员工工作记录能解释一次任务:范围、数量、产出、失败、风险观察齐全。[CONCEPT: 业务验收] 证据:`DigitalEmployeeRunProducts.vue` 展示扫描范围、处理数量、任务产物、失败摘要和本次风险观察;`node --test web/tests/digital-employee-work-record-products.test.mjs` 通过 4 项断言。
|
||||
- [x] 风险看板能解释整体态势:总览、分布、趋势、排行、算法效果齐全。[CONCEPT: 业务验收] 证据:`RiskObservationDashboard.vue` 已包含总览 KPI、业务维度分布、趋势、信号排行、异常排行、算法闭环效果,`npm.cmd run build` 通过。
|
||||
- [x] 所有风险输出统一进入风险观察模型或兼容结构。[CONCEPT: 技术验收] 证据:Hermes 风险扫描已调用 `RiskObservationService.upsert_observation()`。
|
||||
- [x] 高风险观察至少包含两类证据来源。[CONCEPT: 算法验收] 证据:`_apply_evidence_source_gate()` 对单一证据源高风险封顶为 69,算法测试覆盖单源封顶和多源高风险通过。
|
||||
- [x] 风险观察保留算法版本、来源、时间、反馈状态。[CONCEPT: 技术验收] 证据:`RiskObservation` 模型包含 `algorithm_version`、`source`、`created_at`、`updated_at`、`feedback_status`。
|
||||
1483
document/development/hermes-risk-graph-algorithm/index.html
Normal file
1483
document/development/hermes-risk-graph-algorithm/index.html
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,41 +0,0 @@
|
||||
# Hermes 后台智能体架构总览
|
||||
|
||||
## 1. 定位与愿景
|
||||
Hermes 是 X-Financial 系统中的**后台自动巡检与数据洞察中枢**。与处理实时对话的 UserAgent 不同,Hermes 专注于异步、长周期、大批量的任务,核心价值在于提供事前的**深度风险挖掘**和定期的**业财洞察报告**。
|
||||
|
||||
## 2. 系统拓扑图
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph 调度层
|
||||
A[Cron Scheduler] -->|定时触发| B[Task Queue]
|
||||
end
|
||||
|
||||
subgraph Hermes Agent 层
|
||||
B -->|消费任务| C(Hermes Worker)
|
||||
C --> D[Task Skills Router]
|
||||
D --> E{RiskScanner Skill}
|
||||
D --> F{ExpenseReport Skill}
|
||||
D --> G{KnowledgeCheck Skill}
|
||||
end
|
||||
|
||||
subgraph X-Financial 核心服务
|
||||
E <--> H[(Expense DB)]
|
||||
F <--> H
|
||||
G <--> I[(LightRAG Graph/Vector)]
|
||||
C <--> J[LLM Gateway / OpenAI]
|
||||
C --> K[Notification Service / 企业微信]
|
||||
end
|
||||
```
|
||||
|
||||
## 3. 核心设计原则
|
||||
1. **防抖与限流**:后台全量扫表时,必须分片执行,防止对主数据库造成 I/O 拥堵。
|
||||
2. **幂等性保障**:每一个扫描任务和报告生成任务都应该具备唯一幂等键,避免因进程重启导致的重复发信或重复扣减信用分。
|
||||
3. **隔离性**:Hermes 的进程应与对外提供 API 服务的 Web Server 物理/逻辑隔离,大模型限流策略(Token Rate Limit)应配置相互独立的账单通道。
|
||||
|
||||
## 4. 核心执行链路(示例:夜间风控巡检)
|
||||
1. 凌晨 02:00,Cron 触发 `trigger_risk_scan` 任务。
|
||||
2. Worker 拉取状态为 `draft` 和 `submitted` 且 `risk_scanned=False` 的单据。
|
||||
3. 将近三个月的相关人员单据聚类,构建 Context。
|
||||
4. 调用大模型,寻找“拆单”、“合谋”、“时间/地点异常”等隐蔽风险。
|
||||
5. 将发现的风险写入 `hermes_risk_report` 表,并标记对应单据。
|
||||
6. 任务结束,更新执行日志,等待早晨财务主管查阅。
|
||||
@@ -1,46 +0,0 @@
|
||||
# Hermes 数据库表结构设计
|
||||
|
||||
为了支持后台异步任务的执行和长期记忆(风险标记、执行结果归档),我们需要在数据库中增加(或扩充)以下表结构。
|
||||
|
||||
## 1. 任务调度与执行表
|
||||
|
||||
### `hermes_task_config` (定时任务配置表)
|
||||
用于管理所有的后台巡检和推送任务,支持动态调整频率与开关。
|
||||
- `id`: string (UUID)
|
||||
- `task_type`: string (enum: `global_risk_scan`, `weekly_expense_report`, `kb_validation`...)
|
||||
- `cron_expression`: string (e.g., `0 2 * * *`)
|
||||
- `is_enabled`: boolean (默认 True)
|
||||
- `payload_template`: jsonb (预留参数,如扫描的时间窗口、特定部门过滤条件等)
|
||||
- `updated_at`: datetime
|
||||
|
||||
### `hermes_task_execution_log` (任务执行日志表)
|
||||
记录每次任务的执行状态,便于排错与溯源。
|
||||
- `id`: string (UUID)
|
||||
- `config_id`: string (外键,关联 `hermes_task_config`)
|
||||
- `started_at`: datetime
|
||||
- `completed_at`: datetime
|
||||
- `status`: string (enum: `running`, `success`, `failed`)
|
||||
- `result_summary`: string (执行结果的简要说明,如“扫描了 1500 条单据,发现 12 条高危”)
|
||||
- `error_trace`: text (如果失败,存储错误堆栈)
|
||||
|
||||
## 2. 深度分析结果表
|
||||
|
||||
### `hermes_risk_report` (深度风险报告表)
|
||||
用于存储 LLM 找出的深层逻辑风险。
|
||||
- `id`: string (UUID)
|
||||
- `claim_id`: string (外键,关联存疑的主单据 `expense_claim`)
|
||||
- `execution_log_id`: string (外键,由哪次扫描任务产生的)
|
||||
- `risk_level`: string (enum: `low`, `medium`, `high`, `critical`)
|
||||
- `risk_type`: string (enum: `split_billing` 拆单, `collusion` 合谋, `policy_violation` 违规...)
|
||||
- `risk_description`: text (大模型生成的自然语言报告,如“该单据与前天提交的单据存在拆分可能...”)
|
||||
- `related_claim_ids`: jsonb (存储关联的同谋/相关单据 ID 列表,提供上下文线索)
|
||||
- `status`: string (enum: `pending_review` 待人工复核, `confirmed` 已确认为风险, `dismissed` 已忽略)
|
||||
|
||||
## 3. 现有表的平滑改造
|
||||
|
||||
### 修改 `employee` 表 (员工信用分预留)
|
||||
- **新增字段** `compliance_score`: int (默认 100,由 Hermes 动态扣减或恢复,用于风控引擎调节对该员工的抽查率和宽容度)
|
||||
|
||||
### 修改 `expense_claim` 表 (风控标记)
|
||||
- **新增字段** `hermes_scanned_at`: datetime (记录该单据上次被 Hermes 扫描的时间,防止重复扫描)
|
||||
- **新增字段** `hermes_risk_flag`: boolean (快速判断该单子是否被挂载了 `hermes_risk_report`)
|
||||
@@ -1,32 +0,0 @@
|
||||
# 深度风险扫描模块设计 (Risk Scan Module)
|
||||
|
||||
## 1. 业务目标
|
||||
将单点硬规则风控(如:发票大于 500 元是否合规)升级为**图谱式全局风控**。Hermes 将利用大语言模型(LLM)的逻辑推理能力,在海量历史数据中寻找隐藏的违规模式。
|
||||
|
||||
## 2. 核心扫描链路
|
||||
本模块将作为一个独立的 Skill 被定时任务触发。
|
||||
|
||||
### 第一步:数据快照聚合
|
||||
- **提取目标**:拉取状态为 `draft`、`submitted` 且最近 30 天内活跃的报销单,同时带出相关的发票明细。
|
||||
- **降维处理**:为避免超出大模型的 Token 上下文限制,必须对单据信息进行降维。仅提取:`申请人、时间、地点、商户名、金额、报销类型` 形成精简的 CSV 或 JSON Lines 格式。
|
||||
|
||||
### 第二步:大模型批量推理 (LLM Batch Inference)
|
||||
- **风险定义植入**:通过 System Prompt 将目前财务最头疼的几类风险定义给模型(如拆单、套现、虚假连号发票)。
|
||||
- **执行方式**:将数据按“同部门”或“同地域”分块 (Chunking) 喂给大模型。
|
||||
- **Prompt 示例**:
|
||||
```markdown
|
||||
你是一个内控审计 Agent。以下是某部门近半个月的报销流水清单。
|
||||
请找出其中是否存在:
|
||||
1. 拆单行为(同人、同地点、连日、小额累加)
|
||||
2. 聚众套现行为(不同人、同偏僻餐馆、同日极高额)
|
||||
如果发现风险,请输出对应的单号集合以及你的推理过程。
|
||||
```
|
||||
|
||||
### 第三步:风险标记与处置
|
||||
- 解析大模型返回的结构化 JSON。
|
||||
- 对被判定的高危单据,在主库中插入 `hermes_risk_report` 记录。
|
||||
- **动作反馈**:如果该单据正处于 `submitted` 状态,并且得分极高(如虚假连号发票),可以通过 X-Financial 原有接口自动注入“退回”动作,并附加大模型的分析日志。
|
||||
|
||||
## 3. 防抖与自我迭代
|
||||
- **扫描去重**:利用 `expense_claim.hermes_scanned_at` 防止已经出具过报告的单据被重复投入分析队列。
|
||||
- **人工纠偏 (Human-in-the-loop)**:当财务在前端驳回 Hermes 的风险提示(即认为没问题)时,事件将被记录。Hermes 可通过夜间的反思任务优化下一次 Prompt 中的判定容忍度。
|
||||
@@ -1,34 +0,0 @@
|
||||
# 动态费控与洞察报告模块设计 (Expense Report Module)
|
||||
|
||||
## 1. 业务目标
|
||||
基于海量的流水账单,定期(周/月)由 Hermes Agent 为部门管理者或财务总监自动生成具有**业务洞察力**的归因分析报告,将冷冰冰的数字转化为具有指导意义的自然语言建议。
|
||||
|
||||
## 2. 核心分析链路
|
||||
|
||||
### 第一步:BI 数据聚合 (Data Aggregation)
|
||||
- 借助 ORM 或底层 Data Warehouse (如有),Hermes 执行预置的聚合查询。
|
||||
- **采集核心指标**:
|
||||
- 本期各部门总花费及环比/同比变动率。
|
||||
- 各类目(如打车、机票、住宿、招待)的占比变化。
|
||||
- Top 10 花费最多的商户(如特定几家酒店或订票平台)。
|
||||
- 各类目超额/退回率最高的人员画像。
|
||||
|
||||
### 第二步:大模型归因分析 (LLM Attribution Analysis)
|
||||
将硬性的聚合数据转化为结构化 Prompt,让 LLM 充当“财务分析师”。
|
||||
- **Prompt 示例**:
|
||||
```markdown
|
||||
你是企业的财务总监助理,请阅读以下【本月报销聚合数据】。
|
||||
请帮我撰写一份 300 字以内的执行摘要报告。
|
||||
重点指出:
|
||||
1. 哪个部门/哪类费用增长最快?原因可能是什么?
|
||||
2. 我们的长尾开销集中在哪些商户?是否存在能够跟商户谈“协议价”的谈判空间?
|
||||
```
|
||||
|
||||
### 第三步:多渠道报告分发 (Report Delivery)
|
||||
- **生成制品**:Hermes 利用代码解释器 (如有) 或 Markdown 引擎,将图表与文本融合成正式的 PDF 或长图。
|
||||
- **触达渠道**:
|
||||
- **推送机制**:调用企微/钉钉机器人 API,直接向管理者的工作台推送“上周费控简报”。
|
||||
- **交互追问**:管理者收到简报卡片后,可以在对话框里直接@Hermes 追问:“详细列一下研发部上周在北京住宿的那 5 万块钱是怎么花的”,Hermes 将调取缓存的报告上下文立即答复。
|
||||
|
||||
## 3. 商业价值落地
|
||||
这项功能极大地解放了财务部的报表处理时间。通过提供前置的谈判线索(如发现某经济型酒店的高频住客其实都可以导流到协议酒店),可以给公司带来直接的差旅成本节约。
|
||||
@@ -1,63 +0,0 @@
|
||||
# 部署与任务调度架构方案 (Deployment & Cron)
|
||||
|
||||
## 1. 业务诉求分析
|
||||
Hermes 作为纯后台的智能体,它的执行过程长达几分钟甚至几小时。它绝不能与提供给前台 HTTP 请求的主 Web 服务混合在同一个事件循环(Event Loop)或同步进程中,否则会导致 API 严重堵塞和超时崩溃。
|
||||
|
||||
因此,Hermes 的部署需要进行**进程级解耦**。
|
||||
|
||||
## 2. 选型对比与推荐方案
|
||||
|
||||
### 方案 A:Celery + Redis (重型/工业级标准)
|
||||
- **优势**:业界最成熟的 Python 异步任务队列,支持极其复杂的 Cron 配置,原生支持任务重试、失败回调以及分布式扩展。
|
||||
- **劣势**:增加系统组件(必须额外部署 Redis / RabbitMQ 容器),运维成本相对较高。
|
||||
- **结论**:如果 X-Financial 后续要承载上千人的企业报销,这是**首选必经之路**。
|
||||
|
||||
### 方案 B:APScheduler + Background Worker (中型/轻量级)
|
||||
- **优势**:直接在 Python 进程内运行,无需额外的消息队列组件。可以用一个单独的 Docker 容器运行 `python run_hermes_scheduler.py`。
|
||||
- **劣势**:多节点部署时难以控制并发(可能会多个节点同时执行同样的任务),需要引入基于数据库表或 Redis 的分布式锁。
|
||||
- **结论**:适合初期快速跑通 MVP 的方案。
|
||||
|
||||
## 3. 推荐架构:基于 Redis 分布式锁的独立容器方案
|
||||
结合当前现状,建议采用 **方案B 叠加 分布式锁** 的轻量微服务架构。
|
||||
|
||||
### 部署拓扑:
|
||||
```yaml
|
||||
# docker-compose.yml 示例切片
|
||||
services:
|
||||
x-financial-api:
|
||||
build: .
|
||||
command: uvicorn main:app
|
||||
ports:
|
||||
- "8000:8000"
|
||||
|
||||
x-financial-hermes:
|
||||
build: .
|
||||
command: python scripts/start_hermes_daemon.py
|
||||
# 这个容器不暴露外部端口,纯粹在后台运行定时任务和消费队列
|
||||
```
|
||||
|
||||
### 执行伪代码 (`start_hermes_daemon.py`)
|
||||
```python
|
||||
from apscheduler.schedulers.blocking import BlockingScheduler
|
||||
from app.services.system_hermes import SystemHermesService
|
||||
|
||||
scheduler = BlockingScheduler()
|
||||
hermes = SystemHermesService()
|
||||
|
||||
# 每天凌晨 3 点执行深度风控扫表
|
||||
@scheduler.scheduled_job('cron', hour=3, minute=0)
|
||||
def job_risk_scan():
|
||||
# 获取分布式锁防止集群脑裂重复执行
|
||||
if acquire_redis_lock("hermes:lock:risk_scan"):
|
||||
try:
|
||||
hermes.run_query("执行全局风控扫描技能...", skills=["global_risk_scan"])
|
||||
finally:
|
||||
release_redis_lock("hermes:lock:risk_scan")
|
||||
|
||||
if __name__ == "__main__":
|
||||
scheduler.start()
|
||||
```
|
||||
|
||||
## 4. 容灾与可观测性保障
|
||||
- **日志采集**:确保 `hermes.run_query` 及其后台生成的 stdout/stderr 日志能够写入 ELK 或文件系统中,方便第二天的运维排查。
|
||||
- **告警链路**:如果调度系统挂掉或者大模型连续多次返回失败状态码,必须通过 Webhook 飞书/钉钉及时告警系统管理员。
|
||||
@@ -850,6 +850,327 @@
|
||||
text-underline-offset: 3px;
|
||||
}
|
||||
|
||||
/* 竞品分析表格样式 */
|
||||
.comp-table-wrapper {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
margin: 24px 0;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius);
|
||||
box-shadow: var(--shadow-soft);
|
||||
background: var(--surface);
|
||||
}
|
||||
|
||||
.comp-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
text-align: left;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.comp-table th,
|
||||
.comp-table td {
|
||||
padding: 14px 16px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
vertical-align: top;
|
||||
line-height: 1.68;
|
||||
}
|
||||
|
||||
.comp-table th {
|
||||
background: var(--surface-strong);
|
||||
color: var(--teal-deep);
|
||||
font-weight: 900;
|
||||
font-size: 13.5px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.comp-table tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.comp-table tr:hover td {
|
||||
background: var(--surface-soft);
|
||||
}
|
||||
|
||||
.comp-highlight {
|
||||
background: var(--teal-soft);
|
||||
font-weight: 850;
|
||||
color: var(--teal-deep);
|
||||
}
|
||||
|
||||
.comp-table td ul {
|
||||
margin: 0;
|
||||
padding-left: 18px;
|
||||
}
|
||||
|
||||
.comp-table td li {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
/* 痛点方案卡片微动效与特色样式 */
|
||||
.card {
|
||||
transition: transform 0.22s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.22s ease, border-color 0.22s ease;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--shadow-soft);
|
||||
border-color: var(--teal);
|
||||
}
|
||||
|
||||
.twin-sandbox-card {
|
||||
grid-column: span 2;
|
||||
background: linear-gradient(135deg, var(--surface) 60%, var(--teal-soft) 100%);
|
||||
border: 1px solid var(--line-strong);
|
||||
}
|
||||
|
||||
.twin-sandbox-badge {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
background: var(--teal-deep);
|
||||
color: #fff;
|
||||
font-size: 11px;
|
||||
border-radius: 99px;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 850;
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.twin-sandbox-card {
|
||||
grid-column: span 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 仿真沙盘交互组件样式 */
|
||||
.twin-simulator-box {
|
||||
margin-top: 20px;
|
||||
padding: 18px;
|
||||
border: 1px solid var(--line-strong);
|
||||
border-radius: var(--radius);
|
||||
background: rgba(15, 118, 110, 0.03);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.twin-sim-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 13px;
|
||||
font-weight: 900;
|
||||
color: var(--teal-deep);
|
||||
margin-bottom: 14px;
|
||||
border-bottom: 1px dashed var(--line);
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.sim-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: var(--teal);
|
||||
border-radius: 50%;
|
||||
animation: pulse 1.8s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(15, 118, 110, 0.5); }
|
||||
70% { transform: scale(1); box-shadow: 0 0 0 6px rgba(15, 118, 110, 0); }
|
||||
100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(15, 118, 110, 0); }
|
||||
}
|
||||
|
||||
.twin-sim-layout {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.twin-sim-ctrl {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
align-content: start;
|
||||
}
|
||||
|
||||
.ctrl-group {
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.ctrl-group label {
|
||||
font-size: 12px;
|
||||
font-weight: 850;
|
||||
color: var(--ink-soft);
|
||||
}
|
||||
|
||||
.ctrl-group select {
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
padding: 0 8px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
background: var(--surface);
|
||||
color: var(--ink);
|
||||
font-size: 12.5px;
|
||||
font-family: var(--font);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.ctrl-group select:focus {
|
||||
border-color: var(--teal);
|
||||
}
|
||||
|
||||
.highlight-val {
|
||||
color: var(--teal-deep);
|
||||
font-weight: 900;
|
||||
font-family: var(--mono);
|
||||
}
|
||||
|
||||
.ctrl-group input[type="range"] {
|
||||
-webkit-appearance: none;
|
||||
width: 100%;
|
||||
height: 6px;
|
||||
border-radius: 3px;
|
||||
background: var(--line);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.ctrl-group input[type="range"]::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
background: var(--teal);
|
||||
cursor: pointer;
|
||||
border: 2px solid var(--surface);
|
||||
box-shadow: 0 2px 6px rgba(15,118,110,0.3);
|
||||
transition: transform 0.1s ease;
|
||||
}
|
||||
|
||||
.ctrl-group input[type="range"]::-webkit-slider-thumb:hover {
|
||||
transform: scale(1.15);
|
||||
}
|
||||
|
||||
.range-labels {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 10px;
|
||||
color: var(--muted);
|
||||
margin-top: 2px;
|
||||
font-family: var(--mono);
|
||||
}
|
||||
|
||||
#run-sim-btn {
|
||||
width: 100%;
|
||||
height: 36px;
|
||||
background: var(--teal-deep);
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
font-weight: 900;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 4px 12px rgba(16, 47, 43, 0.2);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
#run-sim-btn:hover {
|
||||
background: var(--teal);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 6px 16px rgba(15, 118, 110, 0.3);
|
||||
}
|
||||
|
||||
#run-sim-btn:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.twin-sim-display {
|
||||
position: relative;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
background: var(--surface);
|
||||
padding: 12px;
|
||||
display: grid;
|
||||
align-content: space-between;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sim-scanner {
|
||||
position: absolute;
|
||||
top: -100%;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 12px;
|
||||
background: linear-gradient(180deg, rgba(15, 118, 110, 0.2) 0%, transparent 100%);
|
||||
pointer-events: none;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.sim-scanner.scanning {
|
||||
animation: scan 1.2s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes scan {
|
||||
0% { top: -10px; }
|
||||
100% { top: 100%; }
|
||||
}
|
||||
|
||||
.metric-group {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.sim-metric {
|
||||
padding: 8px;
|
||||
border: 1px solid var(--surface-strong);
|
||||
border-radius: 6px;
|
||||
background: var(--surface-soft);
|
||||
display: grid;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.sim-metric .m-label {
|
||||
font-size: 11px;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.sim-metric .m-value {
|
||||
font-family: var(--mono);
|
||||
font-size: 16px;
|
||||
font-weight: 900;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.sim-metric .m-value.teal { color: var(--teal); }
|
||||
.sim-metric .m-value.orange { color: var(--amber); }
|
||||
.sim-metric .m-value.red { color: var(--red); }
|
||||
.sim-metric .m-value.blue { color: var(--blue); }
|
||||
|
||||
.sim-report-badge {
|
||||
margin-top: 10px;
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
background: var(--surface-strong);
|
||||
color: var(--teal-deep);
|
||||
font-size: 10.5px;
|
||||
font-weight: 850;
|
||||
text-align: center;
|
||||
transition: all 0.3s ease;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.sim-report-badge.success {
|
||||
background: var(--teal-soft);
|
||||
color: var(--teal-deep);
|
||||
border: 1px solid rgba(15, 118, 110, 0.2);
|
||||
}
|
||||
|
||||
@media (max-width: 580px) {
|
||||
.twin-sim-layout {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1500px) {
|
||||
.page {
|
||||
grid-template-columns: 236px minmax(0, 1fr);
|
||||
@@ -971,6 +1292,8 @@
|
||||
<a href="#why"><span class="dot"></span>为什么要做</a>
|
||||
<a href="#future"><span class="dot"></span>未来地位</a>
|
||||
<a href="#blue"><span class="dot"></span>蓝海空间</a>
|
||||
<a href="#competitor-analysis"><span class="dot"></span>竞品对比</a>
|
||||
<a href="#painpoints-solution"><span class="dot"></span>痛点解决</a>
|
||||
<a href="#goal"><span class="dot"></span>开发目的</a>
|
||||
<a href="#algorithms"><span class="dot"></span>核心算法</a>
|
||||
<a href="#modules"><span class="dot"></span>项目模块</a>
|
||||
@@ -1037,28 +1360,19 @@
|
||||
<h2>为什么要做智能费控平台</h2>
|
||||
<p class="section-desc">
|
||||
智能费控不是把报销审批电子化,而是把企业每一笔支出变成可理解、可预测、可解释的经营信号。
|
||||
当 AI、RAG、智能体、异常检测和预算联动进入财务流程后,费用平台会从“流程系统”升级为“经营控制系统”。
|
||||
当前,在金税四期深化、数电发票单轨制全面普及的政策背景下,传统的“后置流程型”费控已被逼入死胡同,企业必须构建全链路智能费控平台。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="deep-copy">
|
||||
<p>
|
||||
第一,费用是企业经营动作最密集、最贴近一线的数据入口。销售拜访客户会产生差旅和招待,
|
||||
项目交付会产生交通、住宿、外包和办公支出,培训、采购、通信、会务也都以费用形式落地。
|
||||
如果企业只在报销完成后做核销,就只能看到“钱已经花了”;如果在申请、预算占用、票据上传、
|
||||
审批和归档全过程做智能分析,就能提前看到“这笔钱为什么要花、是否该花、花完后对预算和风险有什么影响”。
|
||||
第一,<strong>数电票时代倒逼全链路数字化</strong>。随着全国数电发票的单轨制落地,发票的真伪验重、多系统抵扣、合规归档以及全生命周期的追踪已无法通过传统人工肉眼或零散的OCR识别来解决。系统必须具备在发票导入瞬间进行结构化解析、关联交易比对、业务事由交叉匹配的自动化能力,实现“开票即采集、采集即验真、入账即归档”。
|
||||
</p>
|
||||
<p>
|
||||
第二,财务工作的重心正在从人工处理转向分析、预测和决策支持。Gartner 2025 年财务 AI 调研显示,
|
||||
财务组织最常见的 AI 用例已经包括知识管理、应付流程自动化、错误与异常检测;McKinsey 的 CFO 调研也显示,
|
||||
绝大多数受访者期待 AI 减少人工分析负担、生成洞察。这意味着费控平台必须具备自动识别、自动解释和自动沉淀的能力,
|
||||
否则它会停留在“录单工具”,无法进入未来财务的核心工作台。
|
||||
第二,<strong>企业从“事后核销”向“事前控制”的主动性跨越</strong>。传统ERP与报销系统核心是“记账与流程审批”,当员工提交报销单时,费用早已产生。智能费控利用 RAG 知识检索、预算实时联动,在费用申请阶段甚至消费发生的瞬间(如因公商旅预订)就进行预算额度校验与制度约束,使费控前置到决策端。
|
||||
</p>
|
||||
<p>
|
||||
第三,费用风险越来越隐蔽。传统审批能挡住“缺附件”“超标准”这类显性问题,
|
||||
但很难发现拆单、跨部门合谋、异常频次、预算节奏异常、同组偏离、长期材料质量差等隐性问题。
|
||||
ACFE 的职业舞弊报告将虚构或夸大业务费用列为典型报销舞弊形态;随着 AI 生成票据、深度伪造和自动化攻击出现,
|
||||
企业更需要一个能把票据、人员、部门、历史行为、预算和制度放在一起分析的平台。
|
||||
第三,<strong>费用舞弊与异常的隐性化、复杂化</strong>。根据 ACFE 2024 年《全球职业舞弊与滥用报告》显示,全球企业中约有 15% 的舞弊案件与费用报销直接相关,且平均潜伏期长达 18 个月。传统的强硬制度配置只能拦截“超标准”、“无附件”等显性异常,但对于拆单报销、异地多点异常消费、同组偏离度过高、长期合作供应商异常开票等隐性风控,需要基于大数据画像和语义关系的图谱检测。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -1122,74 +1436,66 @@
|
||||
<div class="section-kicker">02 / COMPANY POSITION</div>
|
||||
<h2>费控在未来公司的地位</h2>
|
||||
<p class="section-desc">
|
||||
未来公司的费控,会从“报销审批入口”变成“经营支出操作系统”。
|
||||
未来公司的费控,会从“报销审批工具”变成“企业费用智能操作系统”(Expense OS)。
|
||||
它一端连接员工和部门的真实业务动作,另一端连接预算、现金流、成本、风险、制度和管理决策。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="deep-copy">
|
||||
<p>
|
||||
从组织分工看,CFO 的角色正在从财务记录者变成业务伙伴和技术治理者。
|
||||
Deloitte 的未来财务洞察持续强调,财务团队会把更多时间投入分析、预测和决策支持;
|
||||
Deloitte APAC CFO 2025 调研也显示,接近一半 CFO 认为生成式 AI 会在两年内显著改变行业、组织和财务职能。
|
||||
这意味着费控不应再被放在“报销系统”这个狭窄位置,而应该成为 CFO 获取一线经营信号的前置雷达。
|
||||
从<strong>组织分工与决策支持</strong>来看,CFO 的角色正加速从“合规记录者”转变为“战略业务伙伴(HR/IT/业务协同的中心)”。Deloitte 2025 年未来财务展望报告指出,财务部门未来的工作精力将有 70% 倾斜于数据分析和未来预测。智能费控则是这一变革的第一步——通过把一线经营活动(如差旅、招待、项目交付)产生的每一笔资金流动转化为语义数据,为 CFO 的“战略驾驶舱”提供实时的一手信号。
|
||||
</p>
|
||||
<p>
|
||||
从业务管理看,预算不再只是年初编制和月底复盘。未来预算需要跟每一次费用申请实时联动:
|
||||
当前预算池还有多少、审批后使用率是多少、是否触达预警线、该部门同类费用是否异常、是否影响项目毛利和现金节奏。
|
||||
因此费控会成为部门经理、项目负责人和财务 BP 共同使用的经营协同平台。
|
||||
从<strong>预算与资源控制</strong>来看,未来的预算管控不再是“年初编预算,月底对账单”的静态割裂状态。智能费控通过建立动态预算池与资金控制链,使预算能够在秒级发生响应。这保证了业务部门在项目推进过程中,能实时感知每一笔花费对项目整体毛利空间、部门现金流余量的动态影响,促使人人关注经营效果。
|
||||
</p>
|
||||
<p>
|
||||
从风险控制看,未来公司的费用风险不是单张票据能解释清楚的,而是多源数据的组合问题。
|
||||
一张票据可能合规,但一个人三个月内的频次、金额、地点、客户、同行人和预算占比可能异常。
|
||||
智能费控要把这些信号拉成一张网,让管理者在支付之前就看到风险轮廓。
|
||||
从<strong>业务运营与体验</strong>来看,智能费控是消除部门隔阂、降低一线行政摩擦的“润滑剂”。当平台实现高度数字化与免报销消费结算时,员工不再需要贴票垫资,管理者不再需要在审批页面盲目点“同意”,财务不再需要枯燥审单,整个公司的运营效率将得到数量级提升。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="split">
|
||||
<div>
|
||||
<ul class="bullets">
|
||||
<li><strong>经营仪表盘:</strong>部门费用、项目消耗、预算占比、执行率、风险热区可以被实时汇总。</li>
|
||||
<li><strong>预算守门员:</strong>费用申请不再只看“能不能报”,而要看“是否符合预算节奏”。</li>
|
||||
<li><strong>内控前置层:</strong>票据、地点、人员、金额、制度条款和历史行为被联动审核。</li>
|
||||
<li><strong>AI 财务工作台:</strong>财务人员可以通过自然语言查询制度、解释风险、生成审批建议和费用报告。</li>
|
||||
<li><strong>规则与知识工厂:</strong>制度解释、规则生成、风险复盘和人工反馈进入可持续优化闭环。</li>
|
||||
<li><strong>管理决策入口:</strong>管理者可以询问“哪个部门预算风险最高”“哪些费用正在吞噬毛利”。</li>
|
||||
<li><strong>经营支出中枢 (Expense OS):</strong> 将多系统的零散流程、差旅出行、第三方消费直接通过本体层收归统一。</li>
|
||||
<li><strong>预算守护雷达:</strong> 在业务动作发生时实现“秒级预算占用与测算”,而不是事后核销时的“超支警告”。</li>
|
||||
<li><strong>合规内控防火墙:</strong> 结合发票验真、合同信息、行程轨迹和行为偏差等多模态数据对风险自动拦截。</li>
|
||||
<li><strong>战略决策沙盘:</strong> 支持 CFO 和高管直接询问“各项目利润健康度”、“政策变动预算消耗预测”等深度命题。</li>
|
||||
<li><strong>自进化规则工厂:</strong> 依据历史人工审批意见和申诉结果,系统能自动推荐规则优化方案,实现制度灰度升级。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<div class="flow-diagram" aria-label="费控未来地位流程图">
|
||||
<div class="flow-row" style="--cols: 3">
|
||||
<div class="flow-node">
|
||||
<div class="flow-node-title">业务动作</div>
|
||||
<div class="flow-node-text">出差、采购、招待、培训、项目交付</div>
|
||||
<div class="flow-node-title">业务场景</div>
|
||||
<div class="flow-node-text">差旅、招待、采购、项目外包、会务支出</div>
|
||||
</div>
|
||||
<div class="flow-node dark">
|
||||
<div class="flow-node-title">智能费控平台</div>
|
||||
<div class="flow-node-text">预算、单据、制度、票据、风险、智能体</div>
|
||||
<div class="flow-node-title">费用智能操作系统</div>
|
||||
<div class="flow-node-text">本体语义 · 实时预算 · 智能体 · 仿真沙盘</div>
|
||||
</div>
|
||||
<div class="flow-node">
|
||||
<div class="flow-node-title">财务结果</div>
|
||||
<div class="flow-node-text">成本、现金、核销、支付、账务沉淀</div>
|
||||
<div class="flow-node-title">经营结果</div>
|
||||
<div class="flow-node-text">成本优化、合规账套、税务风险减免、现金流稳健</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flow-row" style="--cols: 3">
|
||||
<div class="flow-node blue">
|
||||
<div class="flow-node-title">组织与预算</div>
|
||||
<div class="flow-node-text">部门、项目、成本中心、预算池</div>
|
||||
<div class="flow-node-title">CFO 战略看板</div>
|
||||
<div class="flow-node-text">业财融合数据、动态毛利预警、资金利用率</div>
|
||||
</div>
|
||||
<div class="flow-node amber">
|
||||
<div class="flow-node-title">数据与画像</div>
|
||||
<div class="flow-node-text">费用画像、行为画像、同组基准</div>
|
||||
<div class="flow-node-title">数字孪生仿真</div>
|
||||
<div class="flow-node-text">制度变动测算、预算优化预测、行为偏差度</div>
|
||||
</div>
|
||||
<div class="flow-node blue">
|
||||
<div class="flow-node-title">管理决策</div>
|
||||
<div class="flow-node-text">预警、报告、经营洞察、规则优化</div>
|
||||
<div class="flow-node-title">协同平台</div>
|
||||
<div class="flow-node-text">免贴票、即时审批、智能助手交互</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="diagram-caption">
|
||||
费控位于经营动作和财务结果之间,未来承担预算守门、规则解释、风险识别、数据画像和管理洞察的中枢角色。
|
||||
智能费控平台向上承接公司战略与预算规则,向下沉入业务一线动作,最终演化为企业支出的全局操作系统。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1200,45 +1506,203 @@
|
||||
<div class="section-kicker">03 / BLUE OCEAN</div>
|
||||
<h2>智能分析费控平台的蓝海</h2>
|
||||
<p class="section-desc">
|
||||
传统 ERP、OA、报销系统和财务共享平台已经覆盖了流程,但对“语义理解、自动洞察、隐性风险识别、
|
||||
预算占比解释、部门费用经营分析”的覆盖仍然不足。蓝海空间正来自这个空白:
|
||||
市场正在从单点报销工具转向 AI 驱动的差旅、费用、发票、预算和风险一体化平台。
|
||||
传统的报销系统、OA 工作流和财务共享软件已是一片红海,产品竞争停留在表单设计与流程配置层面。而真正能为企业带来颠覆性价值的“智能费控蓝海”,则存在于从流程处理到智能化决策预测的跃迁中。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="deep-copy">
|
||||
<p>
|
||||
Grand View Research 2025 年报告预计,全球差旅与费用管理软件市场到 2030 年将达到 106.9 亿美元,
|
||||
2024 至 2030 年复合增速为 16.9%。更重要的是,它特别提到 AI 可用于审批与支付自动化、
|
||||
员工差旅历史和支出模式分析、OCR 票据字段识别以及基于自然语言的交互。
|
||||
这说明市场真正的增长点不只是“报销线上化”,而是“费用智能化”。
|
||||
根据全球著名调研机构 Grand View Research 2025 发布的市场预测报告,全球差旅与费用管理(T&E)软件市场规模在 2030 年将达到 <strong>106.9 亿美元</strong>,2024 至 2030 年的复合年增长率(CAGR)高达 <strong>16.9%</strong>。报告中特别强调,市场增长的核心引擎已不再是单纯的“线上化审批”,而是引入 AI Agent 进行决策自动化、基于 OCR/LLM 的隐性欺诈检测、以及基于企业历史支出行为的可持续 ESG 碳足迹追踪。这表明,“费用智能化与经营沙盘仿真”是蕴含巨大商业溢价的崭新蓝海。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid cols-3">
|
||||
<article class="card">
|
||||
<strong>非结构化数据智能化</strong>
|
||||
<p>票据、制度 PDF、Excel 规则、审批意见、用户自然语言都能进入同一个语义管道。</p>
|
||||
<strong>1. 认知与决策型 AI Agent</strong>
|
||||
<p>从“机械填表和固定规则校验”跨越到“能基于上下文自主决策、异常判定、并提供人机协同解释”的财务数字员工。</p>
|
||||
</article>
|
||||
<article class="card">
|
||||
<strong>部门费用经营化</strong>
|
||||
<p>费用从“报销明细”升级为“部门预算执行、费用结构、异常趋势、经营压力”的管理对象。</p>
|
||||
<strong>2. 财务数字孪生与政策仿真</strong>
|
||||
<p>基于公司历史发票、人员组织、预算规则建立仿真模型,模拟差旅标准或预算政策调整后,对企业资金流与利润的实际影响。</p>
|
||||
</article>
|
||||
<article class="card">
|
||||
<strong>风险识别前置化</strong>
|
||||
<p>拆单、超预算、重复票据、地点不一致、附件缺失、异常频次都可以更早被发现。</p>
|
||||
<strong>3. 多源异构数据语义对齐</strong>
|
||||
<p>打破各子系统(CRM、ERP、OA、商旅聚合商)接口壁垒,利用 Semantic Ontology 本体语义层实现业务数据的天然降维对齐。</p>
|
||||
</article>
|
||||
<article class="card">
|
||||
<strong>财务智能体运营化</strong>
|
||||
<p>后台数字员工不再等待人点击,而是按周期巡检数据、生成报告和沉淀优化候选。</p>
|
||||
<strong>4. 行为偏离与隐性欺诈识别</strong>
|
||||
<p>基于知识图谱与图机器学习技术,识别跨期拆单、虚假报销、同组偏离异常、跨部门关联交易等人工难以察觉的系统性风险。</p>
|
||||
</article>
|
||||
<article class="card">
|
||||
<strong>规则治理产品化</strong>
|
||||
<p>自然语言规则、风险规则、Excel 规则和制度知识可以逐步变成可测试、可版本化资产。</p>
|
||||
<strong>5. 自进化规则治理闭环</strong>
|
||||
<p>支持自然语言输入制度,由 LLM 自动翻译成系统执行规则,并通过人工申诉与退回反馈,在后台自动完成规则库的校准 and 修正。</p>
|
||||
</article>
|
||||
<article class="card">
|
||||
<strong>财务知识即时化</strong>
|
||||
<p>RAG 与知识库让制度解释从人工翻文档,转为“问一句,返回依据和建议”。</p>
|
||||
<strong>6. 绿色财务与 ESG 碳足迹</strong>
|
||||
<p>在费控和商旅端自动提取交通工具、酒店的排放系数,帮助企业在进行费用管控的同时,同步测算并生成企业 ESG 碳足迹报告。</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section" id="competitor-analysis">
|
||||
<div class="section-head">
|
||||
<div class="section-kicker">03.1 / COMPETITORS</div>
|
||||
<h2>主流费控系统竞品分析</h2>
|
||||
<p class="section-desc">
|
||||
要实现上述蓝海构想,必须客观分析当前市场上主流的费控软件。各大软件定位明确,但普遍在“智能化决策”、“跨系统语义融合”及“政策仿真”方面存在显著痛点。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="comp-table-wrapper">
|
||||
<table class="comp-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 14%">竞品名称</th>
|
||||
<th style="width: 25%">核心定位与主要优势</th>
|
||||
<th style="width: 28%">核心痛点与局限性</th>
|
||||
<th style="width: 33%">X-Financial 的创新解决与差异化</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>SAP Concur</strong></td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>全球化费控天花板,支持多币种、多税制、全球财税合规。</li>
|
||||
<li>商旅生态极其成熟,能够与 SAP ERP 体系深度咬合。</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>本土化体验被国内用户诟病(如数电发票处理缓慢)。</li>
|
||||
<li>系统界面臃肿,配置与二次开发极为繁琐。</li>
|
||||
<li>实施周期漫长,运维与实施费用极其高昂。</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td class="comp-highlight">
|
||||
<ul>
|
||||
<li>原生适配数电发票单轨制,具备开箱即用的 AI 智能验真归档。</li>
|
||||
<li>基于本地化轻量级大模型架构,大幅降低实施门槛和部署成本。</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>分贝通</strong></td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>以商旅消费支付为切入点,打造“商旅+支付+费控”模式。</li>
|
||||
<li>倡导“无需报销”体验,员工体验极佳。</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>强依赖平台内置的消费商城生态,在面对大量零星线下费用、外包采购时灵活性不足。</li>
|
||||
<li>对于复杂的多级跨账簿预算、动态共享额度的精细化管控能力相对偏弱。</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td class="comp-highlight">
|
||||
<ul>
|
||||
<li>提供基于本体层屏蔽异构商城壁垒的通用解析能力,线下报销补件与线上免报销消费实现语义对齐。</li>
|
||||
<li>支持复杂层级的预算池(部门/项目/成本中心)秒级动态关联管控。</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>合思 (易快报)</strong></td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>一站式业财收支管理,国内市占率居前。</li>
|
||||
<li>生态系统对接广泛,能与国内主流 ERP 无缝打通,配置灵活。</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>系统逻辑依然以“传统工作流表单”为主,交互较为传统,缺乏智能助理的深度参与。</li>
|
||||
<li>缺乏中长周期的员工行为偏差分析、规则误报自适应纠偏机制。</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td class="comp-highlight">
|
||||
<ul>
|
||||
<li>前台 User Agent 支持自然语言直接进行报销提问、草稿生成、异常核对与智能交互。</li>
|
||||
<li>通过共享本体与规则中心,让财务人员可以用自然语言配置和灰度升级风控规则。</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>每刻报销</strong></td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>专注于大中型企业的智能财务共享,规则引擎非常强大。</li>
|
||||
<li>AI 智能审单能力强,支持复杂的集团化多层级架构。</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>系统的学习曲线陡峭,对业务人员和普通员工的交互不够平滑。</li>
|
||||
<li>侧重于既定流程的合规审计,对于预算和费控政策调整带来的前瞻性影响缺乏模拟仿真能力。</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td class="comp-highlight">
|
||||
<ul>
|
||||
<li>前台大模型辅助,降低普通用户填单学习曲线。</li>
|
||||
<li><strong>核心差异化:首创“财务数字孪生与仿真沙盘”</strong>,在系统级测试和决策前对费控变动进行量化分析预测。</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section" id="painpoints-solution">
|
||||
<div class="section-head">
|
||||
<div class="section-kicker">03.2 / SOLUTIONS</div>
|
||||
<h2>X-Financial 痛点解决方案</h2>
|
||||
<p class="section-desc">
|
||||
针对以上竞品普遍面临的系统孤岛、缺乏智能决策、政策调整靠经验等痛点,X-Financial 提出了以 **“AI + 数字化 + 财务数字孪生”** 为核心的下一代费控解决方案。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid cols-2">
|
||||
<article class="card accent-teal">
|
||||
<strong>一、 解决多系统孤岛:Semantic Ontology 本体语义层</strong>
|
||||
<p>
|
||||
传统软件通过 API 强行硬编码对接 CRM、ERP 和商旅系统,一旦系统升级,接口极易断裂,导致业财数据“语义断层”。
|
||||
</p>
|
||||
<p style="margin-top: 8px; font-size: 13px;">
|
||||
<strong>X-Financial 方案:</strong> 我们设计了包含 8 个关键因子的本体语义协议(domain, scenario, intent 等)。无论是口语化描述、页面动作还是三方消费接口,都先被解析为统一的“本体状态”,再分发至下层服务。这实现了跨系统的语义级天然对齐,让数据真正融为一体。
|
||||
</p>
|
||||
</article>
|
||||
|
||||
<article class="card accent-blue">
|
||||
<strong>二、 解决财务假智能:User Agent & Hermes 双智能体闭环</strong>
|
||||
<p>
|
||||
市面软件仅使用 OCR 识别将文字填入表单,人工审核工作量并没有显著降低,也无法识别隐性舞弊。
|
||||
</p>
|
||||
<p style="margin-top: 8px; font-size: 13px;">
|
||||
<strong>X-Financial 方案:</strong> 我们构建了双 Agent 循环。前台 <strong>User Agent</strong> 帮员工和财务进行友好交互,自动查漏补正,解释退回原因;后台 <strong>Hermes 数字员工</strong> 定时在数据底座扫描,分析员工近90/180天的费用画像和行为画像,依据同组偏差算法自动判定隐性风险,出具报告。
|
||||
</p>
|
||||
</article>
|
||||
|
||||
<article class="card accent-amber">
|
||||
<strong>三、 解决规则配置难:LLM 驱动的规则与知识工厂</strong>
|
||||
<p>
|
||||
传统系统的规则引擎配置需要 IT 人员编写繁杂的条件表达式,难以响应公司制度的频繁变动。
|
||||
</p>
|
||||
<p style="margin-top: 8px; font-size: 13px;">
|
||||
<strong>X-Financial 方案:</strong> 支持财务直接上传自然语言描述的制度文档。系统通过大模型将文本转化为可测试、可执行的规则库资产;当发生审批争议或误报时,支持财务通过“反馈池”对规则 and 知识库进行一键校正,进入自进化闭环。
|
||||
</p>
|
||||
</article>
|
||||
|
||||
<article class="card twin-sandbox-card">
|
||||
<span class="twin-sandbox-badge">首创蓝海技术</span>
|
||||
<strong>四、 解决政策盲目调整:财务数字孪生与仿真沙盘(Financial Digital Twin)</strong>
|
||||
<p>
|
||||
很多企业在遇到经营波动时,会盲目调低差旅标准(如酒店降低20%),这容易导致员工满意度下降、灰色报销增多或合规偏离率升高,甚至因行政摩擦上升造成更大的隐性成本。目前市场没有任何一款软件能评估规则调整带来的实际后果。
|
||||
</p>
|
||||
<p style="margin-top: 8px; font-size: 13.5px;">
|
||||
<strong>X-Financial 方案:</strong> 我们通过融合组织架构树、员工费用画像、预算控制规则与历史发票数据库,为企业构建了一个“财务数字孪生体”。当管理层想要修改政策(如“下调销售部酒店标准 15%”)时,可在系统<strong>仿真沙盘(Simulation Sandbox)</strong>中运行模拟。沙盘会模拟历史真实或合成出的数万个出差场景进行回归测算,量化预测此次政策调整对“未来费用降幅(预估降低11%)”、“员工合规偏离率(预估提升8%)”、“预计审批流程摩擦时间(预估提升12%)”的多维影响,为企业提供真正科学的决策辅助。
|
||||
</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
@@ -1811,6 +2275,8 @@ budget_control =
|
||||
<a href="#why"><span class="dot"></span>为什么要做</a>
|
||||
<a href="#future"><span class="dot"></span>未来地位</a>
|
||||
<a href="#blue"><span class="dot"></span>蓝海空间</a>
|
||||
<a href="#competitor-analysis"><span class="dot"></span>竞品对比</a>
|
||||
<a href="#painpoints-solution"><span class="dot"></span>痛点解决</a>
|
||||
<a href="#goal"><span class="dot"></span>开发目的</a>
|
||||
<a href="#algorithms"><span class="dot"></span>算法能力</a>
|
||||
<a href="#modules"><span class="dot"></span>模块清单</a>
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
# Knowledge Answers TODO
|
||||
|
||||
更新时间:2026-05-16
|
||||
|
||||
目标:
|
||||
- 让知识库问答的主路径从“LightRAG 检索 + 慢模型二次整理”改为“结构化证据优先 + 模型可选总结”。
|
||||
- 让问答能力尽量依赖当前文档内容本身,而不是依赖某一份制度、某一个城市或某一种表格写法。
|
||||
- 参考 Yuxi 的优点,优先补齐 `统一解析思路 + 文档类型友好的结构增强 + 检索后原文证据回退`,不照搬其完整平台基础设施。
|
||||
|
||||
Yuxi 调研结论:
|
||||
- [x] 已完成 Yuxi 调研与方案提炼
|
||||
备注:Yuxi 的通用性主要来自三层:统一文档解析、可切换的 chunk/preset、检索不足时回到解析后 Markdown 继续取证;并不是靠给某个文档写死回答逻辑。
|
||||
|
||||
本轮改造原则:
|
||||
- [x] 先撤掉文档特化硬编码,再补通用结构能力。
|
||||
- [x] 真实答案只能来自当前命中文档的内容,代码里不固化制度金额、地区档位或条款结论。
|
||||
- [x] 即使问题不是表格表达,也要能基于章节、条款、列表、键值对、上下文段落给出可读答案。
|
||||
- [x] 模型只负责“压缩表达”,不负责“凭空补事实”;模型超时时也必须能返回像样的证据型答复。
|
||||
|
||||
实施清单:
|
||||
- [x] 移除当前临时文档特化 fast path
|
||||
备注:删除当前围绕差旅表格、城市档位、职级档位的临时规则,避免系统继续向单文档 hardcode 演化。
|
||||
|
||||
- [x] 入库增强:补通用结构附录
|
||||
备注:参考 Yuxi 的解析/分块思想,在现有入库文本增强中补充章节、条款、列表、键值对、表格与上下文邻接信息,让非表格关系也能被稳定命中。
|
||||
|
||||
- [x] 检索后增强:生成面向回答的证据片段
|
||||
备注:从命中的 hits 中再次抽取更短、更结构化的 answer evidence,优先保留标题路径、条款句、列表项、表格行和与 query 强相关的上下文窗口。
|
||||
|
||||
- [x] 回答链路重构:证据驱动直答
|
||||
备注:新增通用知识问答直答器,先根据 answer evidence 生成可直接展示的短答案;只有在证据不足或问题需要更自然表达时才调用模型。
|
||||
|
||||
- [x] 模型总结收口:缩小上下文面,保留原文约束
|
||||
备注:把传给模型的上下文从“整段命中 chunk”收缩到“高置信 answer evidence”,既降延迟,也降低答非所问和错列风险。
|
||||
|
||||
- [x] 降级回答升级:从“命中摘抄”改成“证据摘要”
|
||||
备注:即使模型超时或失败,也要返回按证据组织好的结论、依据和缺失信息,而不是大段原文拼贴。
|
||||
|
||||
- [x] 测试补齐
|
||||
备注:覆盖非表格制度文本、表格文本、列表/键值对文本、模型超时降级、去除硬编码路径等关键回归点。
|
||||
|
||||
- [x] 真实验证与回填 TODO
|
||||
备注:已重建当前知识库索引并完成真实验证。当前“回答整理”阶段已降到亚秒级,但 LightRAG 首次/冷启动检索仍受 embedding 与 rerank 耗时影响,后续如要继续压缩总耗时,应进一步优化检索参数与模型链路。
|
||||
|
||||
验收标准:
|
||||
- [x] 常规知识问答不再长时间卡在“正在整理答案”。
|
||||
- [x] 文档不是表格表达时,仍能基于章节/条款/列表/上下文回答。
|
||||
- [x] 文档内容变动后,不需要改业务代码里的制度结论或金额常量。
|
||||
- [x] 模型超时时仍能返回结构清楚、证据明确的答案。
|
||||
- [x] 相关测试通过,且没有破坏现有知识库问答流程。
|
||||
|
||||
验证记录:
|
||||
- [x] 单测通过:`test_user_agent_service.py`、`test_knowledge_normalizer.py`、`test_knowledge_rag_service.py` 共 35 项全部通过。
|
||||
- [x] 当前知识库文档已按新规则 `force` 重建索引成功。
|
||||
- [x] 真实问答抽检:`餐补标准是什么?`、`费用发生后多久内提交报销申请?`、`前往北京出差的报销标准是什么?`
|
||||
备注:回答生成阶段约 `0.24s ~ 0.30s`;其中“前往北京出差”问题会明确提示当前证据未直接给出“北京”地区档位映射,不再硬猜。
|
||||
@@ -1,896 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>X-Financial 轻量知识库归集与问答优化开发文档</title>
|
||||
<style>
|
||||
:root {
|
||||
--green-900: #064e3b;
|
||||
--green-700: #047857;
|
||||
--green-600: #10b981;
|
||||
--green-100: #dff8ec;
|
||||
--green-50: #effcf6;
|
||||
--blue-700: #1d4ed8;
|
||||
--blue-50: #eff6ff;
|
||||
--amber-600: #d97706;
|
||||
--amber-50: #fffbeb;
|
||||
--red-600: #dc2626;
|
||||
--red-50: #fef2f2;
|
||||
--ink-900: #071124;
|
||||
--ink-700: #24324a;
|
||||
--ink-600: #58677f;
|
||||
--ink-500: #728098;
|
||||
--line: #dbe5ef;
|
||||
--line-strong: #c6d4e2;
|
||||
--surface: #ffffff;
|
||||
--surface-soft: #f7fafc;
|
||||
--shadow: 0 10px 26px rgba(15, 23, 42, 0.08);
|
||||
--radius: 8px;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(239, 252, 246, 0.78), rgba(247, 250, 252, 0.96) 360px),
|
||||
var(--surface-soft);
|
||||
color: var(--ink-900);
|
||||
font-family: "IBM Plex Sans", "Microsoft YaHei UI", "Microsoft YaHei", "PingFang SC", sans-serif;
|
||||
line-height: 1.62;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
code {
|
||||
padding: 2px 6px;
|
||||
border-radius: 6px;
|
||||
background: rgba(15, 23, 42, 0.06);
|
||||
color: var(--ink-700);
|
||||
font-family: "JetBrains Mono", "Cascadia Code", Consolas, monospace;
|
||||
font-size: 0.92em;
|
||||
}
|
||||
|
||||
.shell {
|
||||
display: grid;
|
||||
grid-template-columns: 276px minmax(0, 1fr);
|
||||
min-height: 100dvh;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
align-self: start;
|
||||
height: 100dvh;
|
||||
padding: 28px 22px;
|
||||
border-right: 1px solid var(--line);
|
||||
background: rgba(255, 255, 255, 0.86);
|
||||
backdrop-filter: blur(18px);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.brand {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.logo-mark {
|
||||
display: grid;
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
place-items: center;
|
||||
border-radius: 8px;
|
||||
background: linear-gradient(145deg, var(--green-700), var(--green-600));
|
||||
color: #fff;
|
||||
font-weight: 800;
|
||||
box-shadow: 0 10px 18px rgba(16, 185, 129, 0.26);
|
||||
}
|
||||
|
||||
.brand-title {
|
||||
font-size: 15px;
|
||||
font-weight: 800;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.brand-subtitle {
|
||||
margin-top: 4px;
|
||||
color: var(--ink-500);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.nav-label {
|
||||
margin: 22px 0 8px;
|
||||
color: var(--ink-500);
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.nav {
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.nav a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 38px;
|
||||
padding: 8px 10px;
|
||||
border-radius: 8px;
|
||||
color: var(--ink-700);
|
||||
font-size: 13px;
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
.nav a:hover {
|
||||
background: var(--green-50);
|
||||
color: var(--green-900);
|
||||
}
|
||||
|
||||
.nav-dot {
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
margin-right: 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--line-strong);
|
||||
}
|
||||
|
||||
main {
|
||||
min-width: 0;
|
||||
padding: 34px 42px 56px;
|
||||
}
|
||||
|
||||
.hero {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.14fr) minmax(300px, 0.86fr);
|
||||
gap: 24px;
|
||||
align-items: stretch;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.hero-panel,
|
||||
.metric-panel,
|
||||
section,
|
||||
.card {
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius);
|
||||
background: var(--surface);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.hero-panel {
|
||||
padding: 30px;
|
||||
border-color: rgba(16, 185, 129, 0.28);
|
||||
background:
|
||||
linear-gradient(135deg, rgba(255, 255, 255, 0.96), rgba(239, 252, 246, 0.9)),
|
||||
var(--surface);
|
||||
}
|
||||
|
||||
.kicker {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 28px;
|
||||
padding: 4px 10px;
|
||||
border: 1px solid rgba(16, 185, 129, 0.24);
|
||||
border-radius: 999px;
|
||||
background: rgba(16, 185, 129, 0.1);
|
||||
color: var(--green-900);
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
h1 {
|
||||
max-width: 780px;
|
||||
margin: 16px 0 14px;
|
||||
font-size: 34px;
|
||||
line-height: 1.18;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.hero-copy,
|
||||
.section-desc,
|
||||
.card p,
|
||||
.phase span,
|
||||
.footnote {
|
||||
color: var(--ink-600);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.hero-copy {
|
||||
max-width: 800px;
|
||||
margin: 0;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.hero-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-top: 22px;
|
||||
}
|
||||
|
||||
.pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 32px;
|
||||
padding: 6px 11px;
|
||||
border-radius: 999px;
|
||||
background: #fff;
|
||||
border: 1px solid var(--line);
|
||||
color: var(--ink-700);
|
||||
font-size: 12px;
|
||||
font-weight: 750;
|
||||
}
|
||||
|
||||
.pill.primary {
|
||||
background: var(--green-700);
|
||||
border-color: var(--green-700);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.metric-panel {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
padding: 18px;
|
||||
}
|
||||
|
||||
.metric {
|
||||
padding: 14px;
|
||||
border-radius: 8px;
|
||||
background: var(--surface-soft);
|
||||
border: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.metric-label {
|
||||
color: var(--ink-500);
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.metric-value {
|
||||
margin-top: 5px;
|
||||
font-size: 18px;
|
||||
line-height: 1.28;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
section {
|
||||
margin-top: 18px;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.section-head {
|
||||
display: flex;
|
||||
gap: 18px;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
margin: 0 0 8px;
|
||||
font-size: 22px;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.section-desc {
|
||||
max-width: 920px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.tag {
|
||||
flex: 0 0 auto;
|
||||
min-height: 28px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--green-50);
|
||||
color: var(--green-900);
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
border: 1px solid rgba(16, 185, 129, 0.22);
|
||||
}
|
||||
|
||||
.grid-2,
|
||||
.grid-3,
|
||||
.grid-4 {
|
||||
display: grid;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.grid-2 {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-3 {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-4 {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 17px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.card h3 {
|
||||
margin: 0 0 10px;
|
||||
font-size: 16px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.card p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.card ul,
|
||||
.card ol {
|
||||
margin: 0;
|
||||
padding-left: 18px;
|
||||
color: var(--ink-600);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.card li + li {
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
.tone-green {
|
||||
background: var(--green-50);
|
||||
border-color: rgba(16, 185, 129, 0.26);
|
||||
}
|
||||
|
||||
.tone-blue {
|
||||
background: var(--blue-50);
|
||||
border-color: rgba(37, 99, 235, 0.18);
|
||||
}
|
||||
|
||||
.tone-amber {
|
||||
background: var(--amber-50);
|
||||
border-color: rgba(217, 119, 6, 0.2);
|
||||
}
|
||||
|
||||
.tone-red {
|
||||
background: var(--red-50);
|
||||
border-color: rgba(220, 38, 38, 0.16);
|
||||
}
|
||||
|
||||
.flow {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.flow-row {
|
||||
display: grid;
|
||||
grid-template-columns: 132px minmax(0, 1fr);
|
||||
gap: 12px;
|
||||
align-items: start;
|
||||
padding: 12px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
background: var(--surface-soft);
|
||||
}
|
||||
|
||||
.flow-key {
|
||||
color: var(--green-900);
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.flow-body {
|
||||
color: var(--ink-600);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.diagram {
|
||||
padding: 16px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
background: #0f172a;
|
||||
color: #e5eef8;
|
||||
overflow-x: auto;
|
||||
font-family: "JetBrains Mono", "Cascadia Code", Consolas, monospace;
|
||||
font-size: 13px;
|
||||
line-height: 1.65;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.timeline {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.phase {
|
||||
display: grid;
|
||||
grid-template-columns: 150px minmax(0, 1fr);
|
||||
gap: 14px;
|
||||
padding: 14px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
background: var(--surface-soft);
|
||||
}
|
||||
|
||||
.phase-key {
|
||||
color: var(--green-900);
|
||||
font-size: 13px;
|
||||
font-weight: 850;
|
||||
}
|
||||
|
||||
.phase-body strong {
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
color: var(--ink-900);
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.checklist {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.check {
|
||||
position: relative;
|
||||
padding: 12px 12px 12px 34px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
background: var(--surface-soft);
|
||||
color: var(--ink-700);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.check::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 13px;
|
||||
top: 17px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 999px;
|
||||
background: var(--green-600);
|
||||
}
|
||||
|
||||
.link-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.link-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 30px;
|
||||
padding: 5px 10px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 999px;
|
||||
background: #fff;
|
||||
color: var(--ink-700);
|
||||
font-size: 12px;
|
||||
font-weight: 750;
|
||||
}
|
||||
|
||||
.link-chip:hover {
|
||||
border-color: rgba(16, 185, 129, 0.5);
|
||||
color: var(--green-900);
|
||||
}
|
||||
|
||||
footer {
|
||||
margin-top: 22px;
|
||||
color: var(--ink-500);
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (max-width: 1080px) {
|
||||
.shell {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
position: static;
|
||||
height: auto;
|
||||
border-right: 0;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.hero,
|
||||
.grid-2,
|
||||
.grid-3,
|
||||
.grid-4 {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
main {
|
||||
padding: 24px 18px 42px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 680px) {
|
||||
h1 {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.section-head,
|
||||
.phase,
|
||||
.flow-row {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.section-head {
|
||||
display: grid;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="shell">
|
||||
<aside class="sidebar">
|
||||
<div class="brand">
|
||||
<div class="logo-mark">KB</div>
|
||||
<div>
|
||||
<div class="brand-title">轻量知识库归集</div>
|
||||
<div class="brand-subtitle">LightRAG + Hermes 优化方案</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="nav-label">文档导航</div>
|
||||
<nav class="nav">
|
||||
<a href="#position"><span class="nav-dot"></span>定位与边界</a>
|
||||
<a href="#architecture"><span class="nav-dot"></span>轻量架构</a>
|
||||
<a href="#borrow"><span class="nav-dot"></span>Yuxi 借鉴点</a>
|
||||
<a href="#modules"><span class="nav-dot"></span>模块设计</a>
|
||||
<a href="#retrieval"><span class="nav-dot"></span>召回与回答</a>
|
||||
<a href="#delivery"><span class="nav-dot"></span>实施路线</a>
|
||||
<a href="#quality"><span class="nav-dot"></span>验收标准</a>
|
||||
</nav>
|
||||
|
||||
<div class="nav-label">硬约束</div>
|
||||
<div class="nav">
|
||||
<a href="#quality"><span class="nav-dot"></span>不做重平台</a>
|
||||
<a href="#quality"><span class="nav-dot"></span>证据优先回答</a>
|
||||
<a href="#quality"><span class="nav-dot"></span>增量任务可追踪</a>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main>
|
||||
<div class="hero">
|
||||
<div class="hero-panel">
|
||||
<span class="kicker">开发文档 · 先定边界再实现</span>
|
||||
<h1>X-Financial 轻量知识库归集与问答优化方案</h1>
|
||||
<p class="hero-copy">
|
||||
本方案不把 X-Financial 改造成专业知识库平台,而是在现有
|
||||
<code>LightRAG</code>、<code>Hermes</code>、<code>AgentRun</code>
|
||||
和知识库 UI 上补齐最薄弱的归集、分块、召回和证据回答能力。
|
||||
Yuxi 只作为成熟设计参考,借鉴其统一解析、分块预设和评估思想。
|
||||
</p>
|
||||
<div class="hero-actions">
|
||||
<span class="pill primary">保留现有 LightRAG</span>
|
||||
<span class="pill">轻量 Parser</span>
|
||||
<span class="pill">条款级分块</span>
|
||||
<span class="pill">混合召回</span>
|
||||
<span class="pill">证据化回答</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="metric-panel">
|
||||
<div class="metric">
|
||||
<div class="metric-label">核心目标</div>
|
||||
<div class="metric-value">准、快、可解释</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-label">改造范围</div>
|
||||
<div class="metric-value">归集与召回链路,不重做平台</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-label">并发预期</div>
|
||||
<div class="metric-value">5-10 用户查询可降级、有上限</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section id="position">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<h2 class="section-title">定位与边界</h2>
|
||||
<p class="section-desc">
|
||||
知识库在 X-Financial 中是业务辅助能力,不是独立知识管理产品。
|
||||
因此实现必须克制:不引入重型多租户平台,不替换现有业务数据模型,
|
||||
不把知识库 UI 做成复杂后台,只补齐影响问答质量的关键薄层。
|
||||
</p>
|
||||
</div>
|
||||
<span class="tag">轻量优先</span>
|
||||
</div>
|
||||
|
||||
<div class="grid-3">
|
||||
<div class="card tone-green">
|
||||
<h3>要解决的问题</h3>
|
||||
<ul>
|
||||
<li>Word、PDF、Excel 等文件进入 RAG 前缺少统一结构。</li>
|
||||
<li>制度类文档如果按普通 chunk 切分,条款容易被切散。</li>
|
||||
<li>问答质量依赖向量召回,缺少关键词、标题、条款补召回。</li>
|
||||
<li>效果优化缺少固定评测集,容易靠体感判断。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card tone-blue">
|
||||
<h3>保留的现有能力</h3>
|
||||
<ul>
|
||||
<li><code>KnowledgeService</code> 继续负责文件库和状态入口。</li>
|
||||
<li><code>KnowledgeRagService</code> 继续封装 LightRAG 查询和入库。</li>
|
||||
<li><code>KnowledgeIndexTaskManager</code> 继续承接 Hermes 增量任务。</li>
|
||||
<li>前端知识管理继续保持简单文件夹与文件列表形态。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card tone-amber">
|
||||
<h3>明确不做</h3>
|
||||
<ul>
|
||||
<li>不整体引入 Yuxi 平台。</li>
|
||||
<li>不把存储改成 Milvus + Neo4j。</li>
|
||||
<li>不一次性接入全量 OCR 引擎。</li>
|
||||
<li>不新增复杂多租户知识库后台。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="architecture">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<h2 class="section-title">轻量架构</h2>
|
||||
<p class="section-desc">
|
||||
新增能力只放在 LightRAG 前后两侧:前侧负责把文件变成稳定 Markdown 和业务友好 chunk,
|
||||
后侧负责混合召回、证据重排和可靠回答。LightRAG 仍是主召回核心。
|
||||
</p>
|
||||
</div>
|
||||
<span class="tag">薄层增强</span>
|
||||
</div>
|
||||
|
||||
<div class="diagram">原始文件
|
||||
├── docx / pdf / xlsx / pptx / csv / txt
|
||||
↓
|
||||
轻量 Parser
|
||||
├── 统一 Markdown
|
||||
├── 表格上下文
|
||||
└── 页码 / sheet / 条款路径
|
||||
↓
|
||||
Chunk Preset
|
||||
├── laws:制度条款
|
||||
├── qa:常见问答
|
||||
└── table:表格行组
|
||||
↓
|
||||
现有 LightRAG / Qdrant
|
||||
↓
|
||||
混合召回
|
||||
├── LightRAG 语义召回
|
||||
├── 标题与条款关键词召回
|
||||
└── 轻量重排 top 3-5
|
||||
↓
|
||||
证据化回答
|
||||
├── 命中证据
|
||||
├── 直接结论
|
||||
└── 缺失信息说明</div>
|
||||
</section>
|
||||
|
||||
<section id="borrow">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<h2 class="section-title">Yuxi 借鉴点</h2>
|
||||
<p class="section-desc">
|
||||
Yuxi 的价值不在于整套平台,而在于成熟的归集分层思想:
|
||||
文件先解析成 Markdown,再按场景分块,再索引,再评估。
|
||||
这些思想可以小规模落地到现有服务内。
|
||||
</p>
|
||||
</div>
|
||||
<span class="tag">借鉴而非搬运</span>
|
||||
</div>
|
||||
|
||||
<div class="grid-4">
|
||||
<div class="card">
|
||||
<h3>统一 Parser</h3>
|
||||
<p>学习 Yuxi 把多格式文件统一转 Markdown 的入口设计,但只实现 X-Financial 当前需要的格式。</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>分块 Preset</h3>
|
||||
<p>借鉴 RAGFlow-like preset。先做 <code>laws</code>、<code>qa</code>、<code>table</code> 三类。</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>两阶段状态</h3>
|
||||
<p>内部区分解析和索引。UI 仍可显示简单归纳状态,后台记录真实失败点。</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>轻量评测</h3>
|
||||
<p>不做评估平台,只维护 JSON 用例和脚本,持续检查召回与回答质量。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="link-list">
|
||||
<a class="link-chip" href="https://github.com/xerrors/Yuxi">Yuxi README</a>
|
||||
<a class="link-chip" href="https://github.com/xerrors/Yuxi/blob/main/backend/package/yuxi/plugins/parser/unified.py">Yuxi unified parser</a>
|
||||
<a class="link-chip" href="https://github.com/xerrors/Yuxi/blob/main/backend/package/yuxi/knowledge/chunking/ragflow_like/presets.py">Yuxi chunk presets</a>
|
||||
<a class="link-chip" href="https://github.com/xerrors/Yuxi/blob/main/backend/package/yuxi/knowledge/chunking/ragflow_like/parsers/laws.py">Yuxi laws parser</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="modules">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<h2 class="section-title">模块设计</h2>
|
||||
<p class="section-desc">
|
||||
新增模块必须小而清楚,避免把逻辑继续堆进单个 Service。
|
||||
单个核心文件控制在 800 行以内,优先按解析、分块、召回、评测拆分。
|
||||
</p>
|
||||
</div>
|
||||
<span class="tag">职责拆分</span>
|
||||
</div>
|
||||
|
||||
<div class="flow">
|
||||
<div class="flow-row">
|
||||
<div class="flow-key">knowledge_parser.py</div>
|
||||
<div class="flow-body">
|
||||
负责把 docx、pdf、xlsx、csv、txt 等文件转成 Markdown。
|
||||
输出正文、标题路径、页码、sheet、表头、解析告警。
|
||||
</div>
|
||||
</div>
|
||||
<div class="flow-row">
|
||||
<div class="flow-key">knowledge_chunking.py</div>
|
||||
<div class="flow-body">
|
||||
根据文件夹、文件类型和文档特征选择分块策略。
|
||||
第一批只实现制度、问答、表格三类。
|
||||
</div>
|
||||
</div>
|
||||
<div class="flow-row">
|
||||
<div class="flow-key">knowledge_retrieval.py</div>
|
||||
<div class="flow-body">
|
||||
在 LightRAG 命中结果外补充关键词、条款标题和文件名召回。
|
||||
最终输出小而准的证据块。
|
||||
</div>
|
||||
</div>
|
||||
<div class="flow-row">
|
||||
<div class="flow-key">knowledge_eval.py</div>
|
||||
<div class="flow-body">
|
||||
读取轻量评测用例,检查 expected 文件、关键词、证据和答案约束。
|
||||
用于每次调整参数后的回归验证。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="retrieval">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<h2 class="section-title">召回与回答策略</h2>
|
||||
<p class="section-desc">
|
||||
目标不是让模型更会猜,而是让系统给模型更可靠的证据。
|
||||
制度问题优先命中条款,表格问题保留表头与行上下文,回答必须暴露依据和缺失信息。
|
||||
</p>
|
||||
</div>
|
||||
<span class="tag">证据优先</span>
|
||||
</div>
|
||||
|
||||
<div class="grid-3">
|
||||
<div class="card tone-green">
|
||||
<h3>召回层</h3>
|
||||
<ul>
|
||||
<li>LightRAG 继续提供语义召回。</li>
|
||||
<li>条款号、标题、文件名、关键词做补召回。</li>
|
||||
<li>召回候选数量有上限,避免并发下无限扩张。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card tone-blue">
|
||||
<h3>重排层</h3>
|
||||
<ul>
|
||||
<li>优先保留含问题关键词、标题路径和条款语义的块。</li>
|
||||
<li>制度类按条款完整度加权。</li>
|
||||
<li>最终给回答链路 3-5 条高质量证据。</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card tone-amber">
|
||||
<h3>回答层</h3>
|
||||
<ul>
|
||||
<li>能直接基于证据回答时,不强制二次模型整理。</li>
|
||||
<li>模型只做压缩表达,不凭空补事实。</li>
|
||||
<li>证据不足时明确说明缺什么。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="delivery">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<h2 class="section-title">实施路线</h2>
|
||||
<p class="section-desc">
|
||||
分四步小步交付。每一步都能单独验证,不把解析、索引、召回和评测揉成一次大改。
|
||||
</p>
|
||||
</div>
|
||||
<span class="tag">渐进落地</span>
|
||||
</div>
|
||||
|
||||
<div class="timeline">
|
||||
<div class="phase">
|
||||
<div class="phase-key">P0 / 文档落地</div>
|
||||
<div class="phase-body">
|
||||
<strong>先明确轻量边界</strong>
|
||||
<span>完成本文档,确认不做重平台、不替换存储、不一次性引入复杂 OCR。</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="phase">
|
||||
<div class="phase-key">P1 / 统一解析</div>
|
||||
<div class="phase-body">
|
||||
<strong>补齐文件归集质量</strong>
|
||||
<span>新增 Parser,把 Word、PDF、Excel、CSV、TXT 稳定转为 Markdown,并保存解析产物供索引复用。</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="phase">
|
||||
<div class="phase-key">P2 / 场景分块</div>
|
||||
<div class="phase-body">
|
||||
<strong>提升制度与表格命中率</strong>
|
||||
<span>实现 laws、qa、table 三类分块。制度按章、节、条、款保留完整语义,表格保留 sheet、表头和行上下文。</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="phase">
|
||||
<div class="phase-key">P3 / 混合召回</div>
|
||||
<div class="phase-body">
|
||||
<strong>减少答偏和漏召回</strong>
|
||||
<span>在 LightRAG 命中外补充关键词、条款标题、文件名召回,输出可控数量的证据块。</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="phase">
|
||||
<div class="phase-key">P4 / 轻量评测</div>
|
||||
<div class="phase-body">
|
||||
<strong>把效果优化变成可回归</strong>
|
||||
<span>建设 30-50 条远光软件制度风格问答用例,覆盖报销、差旅、发票、预算、税务等高频问题。</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="quality">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<h2 class="section-title">验收标准</h2>
|
||||
<p class="section-desc">
|
||||
验收不只看页面状态,而要看文件是否真实入库、召回是否命中文档依据、
|
||||
回答是否引用证据,以及并发访问时是否能稳定降级。
|
||||
</p>
|
||||
</div>
|
||||
<span class="tag">真实验证</span>
|
||||
</div>
|
||||
|
||||
<div class="checklist">
|
||||
<div class="check">Word、PDF、Excel、CSV、TXT 文件能生成可读 Markdown,且解析产物可复用。</div>
|
||||
<div class="check">制度类文件能按章、节、条、款形成相对完整的证据块。</div>
|
||||
<div class="check">Excel 表格问答能保留 sheet、表头、关键列和业务行上下文。</div>
|
||||
<div class="check">Hermes 增量任务能区分解析失败、索引失败和归纳失败。</div>
|
||||
<div class="check">常见制度问答优先返回证据化直接答案,模型超时时仍有可读降级答案。</div>
|
||||
<div class="check">5-10 个用户同时访问时,查询候选数、重排数、模型调用数都有明确上限。</div>
|
||||
<div class="check">轻量评测集覆盖至少 30 条问题,并记录命中文件、关键词和答案约束。</div>
|
||||
<div class="check">不引入 Yuxi 平台级依赖,不改变现有知识库 UI 的主体交互。</div>
|
||||
</div>
|
||||
|
||||
<p class="footnote">
|
||||
后续实现时,优先在现有定向测试基础上补充 Parser、Chunking、Retrieval 和 Knowledge Eval 的小测试。
|
||||
后端验证优先在 Docker 容器 <code>x-financial-main</code> 中运行。
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<footer>
|
||||
X-Financial 轻量知识库归集与问答优化开发文档 · 放置位置:document/development/knowledge-answers/lightweight-knowledge-ingestion-design.html
|
||||
</footer>
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
78
document/development/ontology-field-governance/CONCEPT.md
Normal file
78
document/development/ontology-field-governance/CONCEPT.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# 本体字段治理
|
||||
|
||||
## 背景
|
||||
|
||||
当前费用申请、报销助手、单据详情、风险规则和预算控制中存在字段口径不一致的问题。例如同一语义在不同环节被命名为 `transport_type`、`transport_mode`、`application_transport_mode`,或 `occurred_date`、`business_time`、`time_range`。这些字段如果不先进入本体层,会导致语义识别、规则判断、草稿保存和前端展示各自解释同一业务事实。
|
||||
|
||||
## 原则
|
||||
|
||||
所有业务字段必须先设计为本体字段,再下放到业务模块使用。
|
||||
|
||||
- 本体字段注册表是唯一字段源。
|
||||
- 业务层只允许消费本体 canonical 字段。
|
||||
- 非本体字段只能作为输入别名,必须在语义入口归一。
|
||||
- 页面控件字段、兼容字段、后端历史字段不能直接进入业务判断。
|
||||
- 新增业务字段时,必须先更新本体字段设计,再更新表单、助手上下文、持久化、风险规则和测试。
|
||||
|
||||
## 当前第一阶段范围
|
||||
|
||||
第一阶段先治理费用申请和报销链路:
|
||||
|
||||
- 个人工作台意图识别。
|
||||
- 费用申请预览和提交。
|
||||
- 报销助手快速发起报销。
|
||||
- 关联申请单生成报销草稿。
|
||||
- 报销详情智能录入和附件归集。
|
||||
- AI 预审、风险规则、审批流和预算流。
|
||||
|
||||
## 字段分层
|
||||
|
||||
本体 canonical 字段:
|
||||
|
||||
- `expense_type`
|
||||
- `time_range`
|
||||
- `location`
|
||||
- `reason`
|
||||
- `amount`
|
||||
- `transport_mode`
|
||||
- `attachments`
|
||||
- `customer_name`
|
||||
- `merchant_name`
|
||||
- `participants`
|
||||
- `application_claim_id`
|
||||
- `application_claim_no`
|
||||
- `application_days`
|
||||
- `application_date`
|
||||
- `application_lodging_daily_cap`
|
||||
- `application_subsidy_daily_cap`
|
||||
- `application_transport_policy`
|
||||
- `application_policy_estimate`
|
||||
|
||||
输入兼容别名:
|
||||
|
||||
- `transport_type`、`transportMode`、`application_transport_mode` -> `transport_mode`
|
||||
- `occurred_date`、`business_time`、`application_business_time` -> `time_range`
|
||||
- `business_location`、`application_location` -> `location`
|
||||
- `reason_value`、`business_reason`、`application_reason` -> `reason`
|
||||
- `attachment_names` -> `attachments`
|
||||
- `reimbursement_type`、`scene_label` -> `expense_type`
|
||||
|
||||
## 非合规判断
|
||||
|
||||
以下情况视为字段不合规:
|
||||
|
||||
- 新业务流程直接新增 `context_json` 字段但没有进入本体注册表。
|
||||
- 风险规则读取未注册字段。
|
||||
- 前端 `review_form_values` 输出页面控件字段。
|
||||
- 后端服务用别名字段做业务判断,而不是先归一成本体字段。
|
||||
- 同一业务事实在申请、报销、审批、预算中使用不同字段名。
|
||||
|
||||
## 验收口径
|
||||
|
||||
完成后应满足:
|
||||
|
||||
- 语义层能从上下文中生成统一本体实体。
|
||||
- 报销助手关联申请单后不再因为字段别名丢失追问出行方式。
|
||||
- `review_form_values` 对外输出本体字段,不输出页面别名字段。
|
||||
- 后端测试覆盖别名归一到本体字段。
|
||||
- 前端测试覆盖快速报销和核对抽屉只输出本体字段。
|
||||
@@ -0,0 +1,40 @@
|
||||
# 本体字段纠察记录
|
||||
|
||||
## 纠察口径
|
||||
|
||||
所有会参与意图识别、申请/报销草稿、费用明细、风险规则、审批或预算判断的字段,必须先进入本体字段注册表。
|
||||
|
||||
字段分为三类:
|
||||
|
||||
- 本体业务字段:可被业务逻辑、规则、页面表单直接消费。
|
||||
- 输入兼容别名:只允许在语义入口归一,不允许在业务判断中继续直接读取。
|
||||
- 上下文元数据:只表达会话、上传、编辑态、权限和执行链路,不作为业务事实。
|
||||
|
||||
## 已注册的业务字段
|
||||
|
||||
- 费用事实:`expense_type`、`time_range`、`location`、`reason`、`amount`、`transport_mode`、`attachments`
|
||||
- 对象事实:`customer_name`、`merchant_name`、`participants`
|
||||
- 员工事实:`employee_name`、`employee_no`、`department_name`、`employee_position`、`employee_grade`、`manager_name`
|
||||
- 预算事实:`budget_period`、`budget_subject`、`budget_amount`、`cost_center`、`warning_threshold`、`control_action`
|
||||
- 申请关联事实:`application_claim_id`、`application_claim_no`、`application_days`、`application_date`、`application_policy_estimate`
|
||||
|
||||
## 已登记为元数据的字段
|
||||
|
||||
- 会话与流程:`conversation_id`、`conversation_history`、`conversation_scenario`、`conversation_intent`、`session_type`、`entry_source`
|
||||
- 编辑与动作:`review_action`、`draft_claim_id`、`application_edit_mode`、`application_edit_claim_id`
|
||||
- 上传与 OCR:`attachment_count`、`attachment_names`、`ocr_documents`、`ocr_summary`、`review_document_form_values`
|
||||
- 客户端运行态:`client_now_iso`、`client_timezone_offset_minutes`
|
||||
- 权限与调试:`role_codes`、`is_admin`、`simulate_tool_failure`、`simulate_orchestrator_exception`
|
||||
|
||||
## 当前审计结论
|
||||
|
||||
- 未注册字段:已清零。
|
||||
- 历史别名直接读取:主要集中在员工上下文顶层字段,例如 `name`、`grade`、`department`、`position`。
|
||||
- 第一轮已把申请/报销关键链路的表单字段统一到 `expense_type`、`time_range`、`location`、`reason`、`amount`、`transport_mode`。
|
||||
|
||||
## 后续清理策略
|
||||
|
||||
1. 新增业务字段前,先更新 `ontology_field_registry.py`。
|
||||
2. 旧字段只作为输入别名保留,入口归一到 canonical 字段。
|
||||
3. 业务模块逐步停止直接读取旧别名。
|
||||
4. 使用 `server/scripts/audit_ontology_context_fields.py --strict` 作为收口质量闸。
|
||||
15
document/development/ontology-field-governance/TODO.md
Normal file
15
document/development/ontology-field-governance/TODO.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# 本体字段治理 TODO
|
||||
|
||||
- [x] 建立本体字段注册表,集中维护 canonical 字段和输入别名。[CONCEPT: 字段分层]
|
||||
- [x] 在语义解析入口归一 `context_json.review_form_values`。[CONCEPT: 原则]
|
||||
- [x] 在本体实体抽取中把上下文字段桥接为 `transport_mode`、`reason`、`location` 等实体。[CONCEPT: 当前第一阶段范围]
|
||||
- [x] 报销助手 review 入口复用本体字段注册表,不再自己维护字段别名。[CONCEPT: 原则]
|
||||
- [x] 快速报销关联申请单上下文去除 `business_time`、`business_location`、`reason_value`、`reimbursement_type` 等非本体输出字段。[CONCEPT: 非合规判断]
|
||||
- [x] 核对抽屉提交上下文归一为本体字段。[CONCEPT: 验收口径]
|
||||
- [x] 补充本体层和前端字段归一回归测试。[CONCEPT: 验收口径]
|
||||
- [ ] 清查申请助手字段:`application_preview`、`application_fields`、`business_time_context` 是否都已归一本体。
|
||||
- [ ] 清查报销详情字段:智能录入、附件归集、费用明细、异常说明是否仍有非本体字段直传。
|
||||
- [ ] 清查风险规则字段:规则中心、Hermes 归一字段、OCR pipeline 字段是否有未注册业务字段。
|
||||
- [ ] 清查预算字段:预算控制、预算复核、预算操作上下文是否全部使用本体字段。
|
||||
- [ ] 清查审批字段:审批意见、退回原因、流程节点字段是否需要纳入本体或定义为流程元数据。
|
||||
- [ ] 增加字段合规扫描脚本,对新增 `review_form_values` / `context_json` 字段进行检查。
|
||||
266
document/development/receipt-folder/CONCEPT.md
Normal file
266
document/development/receipt-folder/CONCEPT.md
Normal file
@@ -0,0 +1,266 @@
|
||||
# 票据夹功能概念文档
|
||||
|
||||
更新时间:2026-05-29
|
||||
|
||||
## 功能一句话
|
||||
|
||||
票据夹用于归集用户已上传并经过 OCR 识别的原始票据文件,避免票据已识别但忘记关联报销单后无法找回。
|
||||
|
||||
## 背景与问题
|
||||
|
||||
当前系统有两条票据路径:
|
||||
|
||||
- 报销明细附件路径:票据上传到某个草稿费用明细后,会存入 `expense_claims` 附件目录,并写入附件元数据。
|
||||
- 独立 OCR 识别路径:报销对话里先上传票据识别时,`/ocr/recognize` 只返回识别结果,源文件使用临时目录,识别结束后会清理。
|
||||
|
||||
这会导致一个业务缺口:用户可能已经上传票据并完成 OCR,但还没有把票据关联到报销草稿。只要用户关闭会话、切走页面或忘记继续操作,原始票据就没有一个稳定入口可追溯。
|
||||
|
||||
票据夹要补齐这个缺口:凡是系统对用户上传文件做过 OCR 并持久化源文件,就应进入票据夹列表;后续用户可以查看、修正票据信息、删除无效票据,或一键把未关联票据带入报销对话。
|
||||
|
||||
## 目标与非目标
|
||||
|
||||
目标:
|
||||
|
||||
- 在左侧侧边栏的“单据中心”下面新增“票据夹”入口。
|
||||
- 建立票据源文件持久化能力,OCR 后保留原始文件、预览文件和识别元数据。
|
||||
- 提供票据夹列表,复用单据中心的紧凑列表视觉语言。
|
||||
- 支持“未关联票据 / 已关联票据”两个状态切换。
|
||||
- 支持票据详情:基本票据信息可编辑、原始文件可预览、底部返回列表和删除票据。
|
||||
- 支持“一键关联票据”:选择未关联票据,选择未提交草稿或新建报销单,再跳转到报销对话继续填写和关联。
|
||||
|
||||
非目标:
|
||||
|
||||
- 本轮不引入 `document_assets` 等数据库结构变更;先用文件资产和元数据 JSON 完成产品闭环。
|
||||
- 本轮不替换现有报销明细附件接口。
|
||||
- 本轮不把票据夹做成财务共享的全公司档案库;默认只展示当前登录用户自己的票据。
|
||||
- 本轮不在列表页直接完成报销单提交,提交仍回到现有对话核对流程。
|
||||
|
||||
## 用户与场景
|
||||
|
||||
涉及角色:
|
||||
|
||||
- 普通员工:上传票据后稍后再归集到草稿。
|
||||
- 经理或财务用户:在自己名下上传票据时同样需要留存和追溯。
|
||||
|
||||
典型场景:
|
||||
|
||||
1. 用户在个人工作台上传 3 张票据,OCR 成功后暂时没有保存草稿。
|
||||
2. 用户第二天打开票据夹,看到这 3 张票据仍在“未关联票据”。
|
||||
3. 用户进入详情,修正票据类型、金额或日期。
|
||||
4. 用户点击“一键关联票据”,多选未关联票据。
|
||||
5. 用户选择已有草稿,或选择新建报销单。
|
||||
6. 系统打开报销对话,把票据源文件和 OCR 信息带入现有核对流程。
|
||||
|
||||
## 功能能力
|
||||
|
||||
### 票据持久化
|
||||
|
||||
- OCR 入口接收文件后,在识别完成阶段保存源文件。
|
||||
- 保存位置建议为 `storage/receipt_folder/<owner_key>/<receipt_id>/`。
|
||||
- 每个票据目录包含:
|
||||
- 原始文件:`source.<ext>`
|
||||
- 预览文件:`preview.<ext>`,可为空
|
||||
- 元数据:`meta.json`
|
||||
- 元数据记录:
|
||||
- `id`
|
||||
- `owner_key`
|
||||
- `file_name`
|
||||
- `media_type`
|
||||
- `size_bytes`
|
||||
- `uploaded_at`
|
||||
- `status`: `unlinked` / `linked`
|
||||
- `linked_claim_id`
|
||||
- `linked_claim_no`
|
||||
- `linked_item_id`
|
||||
- `linked_at`
|
||||
- OCR 引擎、模型、文本、摘要、置信度、票据类型、场景、结构化字段、提示信息
|
||||
|
||||
### 列表
|
||||
|
||||
- 页签:
|
||||
- 未关联票据
|
||||
- 已关联票据
|
||||
- 表格字段建议:
|
||||
- 票据文件
|
||||
- 识别类型
|
||||
- 费用场景
|
||||
- 金额
|
||||
- 票据日期
|
||||
- OCR 置信度
|
||||
- 关联状态
|
||||
- 上传时间
|
||||
- 交互:
|
||||
- 搜索文件名、摘要、字段值、关联单号
|
||||
- 按状态切换
|
||||
- 点击行进入详情
|
||||
- 未关联页显示“一键关联票据”
|
||||
|
||||
### 详情
|
||||
|
||||
- 基本票据信息:
|
||||
- 文件名只读
|
||||
- 票据类型可编辑
|
||||
- 费用场景可编辑
|
||||
- 票据日期可编辑
|
||||
- 金额可编辑
|
||||
- 商户 / 出发地 / 到达地 / 票据号码等 OCR 字段可编辑
|
||||
- 原始文件展示:
|
||||
- 图片直接预览
|
||||
- PDF 用浏览器内嵌预览
|
||||
- 不可预览类型提供下载入口
|
||||
- 底部动作:
|
||||
- 返回列表
|
||||
- 删除票据
|
||||
|
||||
### 一键关联票据
|
||||
|
||||
流程:
|
||||
|
||||
1. 打开关联弹窗,展示未关联票据多选列表。
|
||||
2. 下一步展示当前用户未提交草稿报销单,也提供“新建报销单”选项。
|
||||
3. 确认后打开现有报销对话。
|
||||
4. 如果选择已有草稿:
|
||||
- 对话以 `link_to_existing_draft` 语义继续。
|
||||
- 携带 `draft_claim_id` 和票据文件。
|
||||
5. 如果选择新建报销单:
|
||||
- 对话以 `create_new_claim_from_documents` 语义继续。
|
||||
- 携带票据文件和 OCR 元数据。
|
||||
|
||||
## 方案设计
|
||||
|
||||
### 后端
|
||||
|
||||
新增模块:
|
||||
|
||||
- `schemas/receipt_folder.py`
|
||||
- `services/receipt_folder.py`
|
||||
- `api/v1/endpoints/receipt_folder.py`
|
||||
|
||||
接口建议:
|
||||
|
||||
- `GET /api/v1/receipt-folder?status=unlinked|linked|all`
|
||||
- `GET /api/v1/receipt-folder/{receipt_id}`
|
||||
- `PATCH /api/v1/receipt-folder/{receipt_id}`
|
||||
- `DELETE /api/v1/receipt-folder/{receipt_id}`
|
||||
- `GET /api/v1/receipt-folder/{receipt_id}/preview`
|
||||
- `GET /api/v1/receipt-folder/{receipt_id}/source`
|
||||
|
||||
OCR 改造:
|
||||
|
||||
- `/api/v1/ocr/recognize` 保持现有响应结构兼容。
|
||||
- 在识别后调用票据夹服务保存源文件和识别结果。
|
||||
- 给每个返回的 OCR 文档补充可选 `receipt_id`、`receipt_preview_url`、`receipt_source_url` 字段。
|
||||
|
||||
### 前端
|
||||
|
||||
新增模块:
|
||||
|
||||
- `services/receiptFolder.js`
|
||||
- `views/ReceiptFolderView.vue`
|
||||
- `assets/styles/views/receipt-folder-view.css`
|
||||
|
||||
导航改造:
|
||||
|
||||
- `useNavigation.js` 新增 `receiptFolder`,放在 `documents` 后面。
|
||||
- `accessControl.js` 将 `receiptFolder` 作为默认可见视图。
|
||||
- `router/index.js` 自动生成 `/app/receiptFolder` 路由。
|
||||
- `AppShellRouteView.vue` 渲染新页面,并允许页面触发 `openSmartEntry`。
|
||||
|
||||
对话衔接:
|
||||
|
||||
- 票据夹确认关联时,前端从 `source` 接口取回 Blob,构造 `File` 对象传给 `openSmartEntry`。
|
||||
- 同时把已编辑 OCR 元数据转为 `initialReceiptDocuments` 或直接通过 `prompt` / `extraContext` 进入对话。
|
||||
- 本轮优先用现有 `initial-files` 和 `initial-prompt` 打开对话,确保用户可以继续核对和保存。
|
||||
|
||||
## 算法与公式
|
||||
|
||||
当前功能不涉及显式数学公式。
|
||||
|
||||
列表排序使用上传时间倒序:
|
||||
|
||||
$$
|
||||
sortKey(receipt) = uploadedAt(receipt)
|
||||
$$
|
||||
|
||||
状态归类:
|
||||
|
||||
$$
|
||||
status(receipt) =
|
||||
\begin{cases}
|
||||
linked, & linkedClaimId \neq \emptyset \\
|
||||
unlinked, & linkedClaimId = \emptyset
|
||||
\end{cases}
|
||||
$$
|
||||
|
||||
## 测试方案
|
||||
|
||||
后端:
|
||||
|
||||
- OCR 识别后会保存源文件和 `meta.json`。
|
||||
- 列表只返回当前用户票据。
|
||||
- `status=unlinked` 只返回未关联票据。
|
||||
- 详情可读取 OCR 字段。
|
||||
- PATCH 后字段持久化。
|
||||
- 预览接口能返回图片或 PDF。
|
||||
- DELETE 只删除票据夹根目录下的目标票据。
|
||||
|
||||
前端:
|
||||
|
||||
- 导航中“票据夹”位于“单据中心”下面。
|
||||
- 列表空态、加载态、错误态可用。
|
||||
- 未关联和已关联两个页签计数正确。
|
||||
- 点击行进入详情。
|
||||
- 详情可保存字段、返回列表、删除票据。
|
||||
- 一键关联弹窗能完成票据选择和草稿选择。
|
||||
|
||||
集成:
|
||||
|
||||
- 上传票据触发 OCR 后,票据出现在票据夹。
|
||||
- 从票据夹选择未关联票据,可打开报销对话。
|
||||
- 选择已有草稿时,对话带入草稿单号。
|
||||
- 选择新建报销单时,对话提示基于票据新建。
|
||||
|
||||
## 指标与验收
|
||||
|
||||
- OCR 成功返回后,票据夹列表能查到对应源文件。
|
||||
- 票据源文件和预览文件在重启后仍可访问。
|
||||
- 未关联票据和已关联票据状态切换正确。
|
||||
- 票据详情字段修改后刷新仍保留。
|
||||
- 删除票据后列表不再显示,预览接口返回 404。
|
||||
- 侧边栏位置符合要求:票据夹在单据中心下面。
|
||||
- 单个新增核心前端和后端模块不超过 800 行。
|
||||
|
||||
## 风险与开放问题
|
||||
|
||||
- 当前报销草稿流主要持久化 OCR 文本和文件名,真实文件复制到报销明细附件目录仍需要进一步打通。
|
||||
- 本轮采用文件元数据而非数据库,适合先完成闭环;后续若需要审计、权限、跨用户协作和全文检索,应升级到资产表。
|
||||
- 已关联状态如何自动回写,需要在后续把票据夹 ID 与报销明细 `invoice_id` 建立更强绑定。
|
||||
- 多票据关联时,如果用户中途取消对话,本轮仍保留为未关联,避免误标。
|
||||
|
||||
## 2026-06-03 详情页与上传治理补充
|
||||
|
||||
本轮根据新的验收要求收敛为三块核心内容:
|
||||
|
||||
- 左侧为票据预览,使用共享详情页主区域承载,图片和 PDF 都以完整票据可见为优先目标,不再提供“打开源文件”按钮。
|
||||
- 右侧为识别票据详情,展示当前票据所有 OCR 字段和基础字段;用户点击“编辑”后可直接修改识别内容,保存后写回票据夹元数据。
|
||||
- 底部为关联信息;左侧预览卡底部同时展示用户编辑操作记录,用于后续财务判断人工修改痕迹。
|
||||
|
||||
编辑记录治理:
|
||||
|
||||
- `PATCH /receipt-folder/{receipt_id}` 在保存前后对可编辑票据信息做字段级 diff。
|
||||
- 每条编辑日志记录操作者、操作时间、字段名称、修改前值、修改后值。
|
||||
- 前端详情页只展示真实 `edit_logs`,不再用模拟操作日志替代。
|
||||
|
||||
重复上传治理:
|
||||
|
||||
- OCR 持久化票据时计算源文件 `sha256`。
|
||||
- 同一用户再次上传相同源文件时,不新建票据目录,返回已有 `receipt_id`,并在 OCR 文档 warnings 中提示“已上传过同样的单据,请不要重复上传。”
|
||||
|
||||
报销助手联动:
|
||||
|
||||
- 用户在报销助手上传新附件前,如果票据夹中存在未关联票据,先提示用户是否进入票据夹关联。
|
||||
- 用户可以选择“去票据夹关联”,也可以选择“继续上传新附件”;继续上传时只跳过本次未关联提醒,不影响后续重复附件校验。
|
||||
|
||||
删除级联:
|
||||
|
||||
- 已关联票据对应的报销单被删除时,票据夹中关联该报销单的票据源文件、预览文件和元数据一并删除。
|
||||
114
document/development/receipt-folder/TODO.md
Normal file
114
document/development/receipt-folder/TODO.md
Normal file
@@ -0,0 +1,114 @@
|
||||
# 票据夹功能 TODO
|
||||
|
||||
更新时间:2026-05-29
|
||||
|
||||
## 阶段一:调研与契约
|
||||
|
||||
- [x] 梳理现有单据中心导航、列表样式和详情入口。[CONCEPT: 方案设计]
|
||||
证据:已确认 `DocumentsCenterView.vue`、`useNavigation.js`、`AppShellRouteView.vue` 是前端入口。
|
||||
|
||||
- [x] 梳理现有 OCR 和报销附件存储链路。[CONCEPT: 背景与问题]
|
||||
证据:已确认 `/ocr/recognize` 只临时识别;报销明细附件由 `expense_claim_attachment_*` 写入 `expense_claims` 存储。
|
||||
|
||||
- [x] 确定本轮不做数据库结构变更,先用票据文件资产和元数据 JSON 完成闭环。[CONCEPT: 目标与非目标]
|
||||
证据:避免新增迁移,降低本轮开发风险。
|
||||
|
||||
## 阶段二:文档
|
||||
|
||||
- [x] 创建 `document/development/receipt-folder/CONCEPT.md`。[CONCEPT: 全文]
|
||||
证据:本文档已落地。
|
||||
|
||||
- [x] 创建 `document/development/receipt-folder/TODO.md`。[CONCEPT: 测试方案]
|
||||
证据:本文档已落地。
|
||||
|
||||
## 阶段三:后端票据资产层
|
||||
|
||||
- [x] 新增 `schemas/receipt_folder.py`,定义列表项、详情、字段更新和删除响应。[CONCEPT: 后端]
|
||||
证据:已新增 `ReceiptFolderItemRead`、`ReceiptFolderDetailRead`、`ReceiptFolderUpdate`、`ReceiptFolderDeleteResponse`。
|
||||
|
||||
- [x] 新增 `services/receipt_folder.py`,负责源文件保存、元数据读写、预览解析、列表过滤和安全路径校验。[CONCEPT: 票据持久化]
|
||||
证据:`ReceiptFolderService` 已覆盖 OCR 批量持久化、已关联附件同步、详情更新、预览/源文件解析与目录安全校验。
|
||||
|
||||
- [x] 新增 `api/v1/endpoints/receipt_folder.py`,暴露列表、详情、更新、删除、预览和源文件接口。[CONCEPT: 后端]
|
||||
证据:已提供 `GET/PATCH/DELETE /receipt-folder/{receipt_id}` 及 `preview/source` 文件接口。
|
||||
|
||||
- [x] 在 `api/v1/router.py` 注册票据夹接口。[CONCEPT: 后端]
|
||||
证据:已 include `receipt_folder_router`。
|
||||
|
||||
- [x] 改造 `/ocr/recognize`,OCR 后保存源文件并把 `receipt_id` 等可选字段带回前端。[CONCEPT: OCR 改造]
|
||||
证据:`OcrRecognizeDocumentRead` 已补充 `receipt_id`、`receipt_status`、`receipt_preview_url`、`receipt_source_url`;来源于票据夹的 `receipt_ids` 会复用原票据,避免重复入库。
|
||||
|
||||
## 阶段四:前端票据夹页面
|
||||
|
||||
- [x] 新增 `services/receiptFolder.js`,封装票据夹接口和 Blob 文件读取。[CONCEPT: 前端]
|
||||
证据:已封装列表、详情、更新、删除、文件读取和 `buildReceiptFile`。
|
||||
|
||||
- [x] 新增 `ReceiptFolderView.vue`,实现列表、状态页签、搜索、一键关联入口和详情切换。[CONCEPT: 列表]
|
||||
证据:页面已包含未关联/已关联页签、搜索、表格、详情、编辑、预览和删除动作。
|
||||
|
||||
- [x] 新增 `receipt-folder-view.css`,复用单据中心紧凑企业级视觉,避免继续拉大现有 `DocumentsCenterView.vue`。[CONCEPT: 列表]
|
||||
证据:票据夹样式独立落在 `assets/styles/views/receipt-folder-view.css`,核心文件均未超过 800 行。
|
||||
|
||||
- [x] 在 `useNavigation.js` 增加 `receiptFolder`,并放在 `documents` 后面。[CONCEPT: 前端]
|
||||
证据:`appViews` 与 `navItems` 中 `receiptFolder` 均紧跟 `documents`。
|
||||
|
||||
- [x] 在 `accessControl.js` 增加默认可见权限和默认路由顺序。[CONCEPT: 前端]
|
||||
证据:已加入 `DEFAULT_APP_VIEW_ORDER` 与 `ALWAYS_VISIBLE_VIEWS`。
|
||||
|
||||
- [x] 在 `AppShellRouteView.vue` 渲染票据夹页面,并让页面可打开报销对话。[CONCEPT: 一键关联票据]
|
||||
证据:已接入 `ReceiptFolderView` 并转发 `open-assistant` 到 `openSmartEntry`。
|
||||
|
||||
## 阶段五:一键关联流程
|
||||
|
||||
- [x] 实现未关联票据多选弹窗第一步。[CONCEPT: 一键关联票据]
|
||||
证据:`ElDialog` 第一阶段使用 `ElCheckboxGroup` 多选未关联票据。
|
||||
|
||||
- [x] 实现未提交草稿选择和“新建报销单”选择第二步。[CONCEPT: 一键关联票据]
|
||||
证据:第二阶段读取草稿报销单,并保留 `新建报销单` 选项。
|
||||
|
||||
- [x] 从票据源文件接口取回 Blob 并构造 `File` 对象传给报销对话。[CONCEPT: 对话衔接]
|
||||
证据:`buildReceiptFile` 从 `source_url` 读取 Blob 并生成带 `receiptId` 的 `File`。
|
||||
|
||||
- [x] 选择已有草稿时,打开对话并带入草稿单号和关联提示。[CONCEPT: 一键关联票据]
|
||||
证据:选择草稿后以 `source: 'detail'`、`request` 和关联 prompt 打开报销对话;附件上传会携带 `receipt_id` 并回写原票据为已关联。
|
||||
|
||||
- [x] 选择新建报销单时,打开对话并带入基于票据新建的提示。[CONCEPT: 一键关联票据]
|
||||
证据:新建路径以 `source: 'receipt-folder'` 携带票据文件和新建 prompt。
|
||||
|
||||
## 阶段六:测试与验证
|
||||
|
||||
- [x] 补充后端票据夹服务和接口测试,超时时间控制在 60s 内。[CONCEPT: 测试方案]
|
||||
证据:`docker exec x-financial-main ... pytest server/tests/test_ocr_endpoints.py server/tests/test_reimbursement_endpoints.py -q` 通过,8 passed,耗时 11.41s。
|
||||
|
||||
- [x] 补充前端导航和票据夹视图模型测试。[CONCEPT: 测试方案]
|
||||
证据:`navigation-route-resolution.test.mjs` 已覆盖路由顺序,新增 `receipt-folder-view.test.mjs` 覆盖视图关键能力。
|
||||
|
||||
- [x] 运行前端构建或定向测试。[CONCEPT: 指标与验收]
|
||||
证据:`node web/tests/navigation-route-resolution.test.mjs`、`node web/tests/receipt-folder-view.test.mjs`、`npm.cmd run build` 均通过。
|
||||
|
||||
- [x] 在 Docker `x-financial-main` 的 `/app` 内运行后端定向测试。[CONCEPT: 测试方案]
|
||||
证据:`pytest server/tests/test_ocr_endpoints.py server/tests/test_reimbursement_endpoints.py -q` 在容器内通过,8 passed。
|
||||
|
||||
- [x] 手动核对侧边栏位置、列表密度、详情预览和关联弹窗。[CONCEPT: 指标与验收]
|
||||
证据:内置浏览器打开 `http://localhost:5173/app/receiptFolder`,侧边栏中“票据夹”位于“单据中心”下方,未关联/已关联页签与空态渲染正常,控制台无相关错误。
|
||||
|
||||
## 阶段七:收口
|
||||
|
||||
- [x] 回看 `CONCEPT.md` 验收标准,确认已实现项均有证据。[CONCEPT: 指标与验收]
|
||||
证据:OCR 持久化、列表/详情/预览、侧边栏位置、一键关联入口和文件行数约束均已覆盖。
|
||||
|
||||
- [x] 更新本 TODO 的完成状态和验证记录。[CONCEPT: 测试方案]
|
||||
证据:本文件已补充完成勾选和验证命令记录。
|
||||
|
||||
## 阶段八:2026-06-03 详情页与上传治理收口
|
||||
|
||||
- [x] 将票据夹详情页收敛为共享详情布局下的三块内容:左侧完整预览、右侧识别票据详情、底部关联信息。[CONCEPT: 2026-06-03 详情页与上传治理补充]
|
||||
证据:`node web/tests/receipt-folder-view.test.mjs`、`npm.cmd run build`、容器内 `cd /app/web && npm run build` 均通过。
|
||||
- [x] 支持识别票据详情编辑,并在后端保存字段级编辑日志。[CONCEPT: 编辑记录治理]
|
||||
证据:容器内 `pytest -q server/tests/test_ocr_endpoints.py server/tests/test_receipt_folder_service.py` 通过,3 passed。
|
||||
- [x] OCR 持久化时识别同一用户重复上传的相同源文件,返回已有票据并提示不要重复上传。[CONCEPT: 重复上传治理]
|
||||
证据:`test_ocr_endpoints.py` 已覆盖重复上传返回原 `receipt_id` 和 warnings。
|
||||
- [x] 报销助手上传附件前提示票据夹中存在未关联票据,并提供进入票据夹关联或继续上传的建议动作。[CONCEPT: 报销助手联动]
|
||||
证据:`receipt-folder-view.test.mjs` 覆盖 `fetchReceiptFolderItems('unlinked')`、`open_receipt_folder` 和 `continue_upload_with_unlinked_receipts`。
|
||||
- [x] 删除已关联报销单时,同步删除票据夹中关联该报销单的票据文件。[CONCEPT: 删除级联]
|
||||
证据:`test_receipt_folder_service.py` 已覆盖 `delete_receipts_for_claim` 删除后不可再读取票据。
|
||||
581
document/development/risk-rule-explainable-flow/CONCEPT.md
Normal file
581
document/development/risk-rule-explainable-flow/CONCEPT.md
Normal file
@@ -0,0 +1,581 @@
|
||||
# 风险规则可解释流程判断改造方案
|
||||
|
||||
## 功能一句话
|
||||
|
||||
把风险规则从“自然语言生成一段 JSON”升级为“自然语言、字段本体、可执行 JSON DSL、流程判断图、测试命中路径、版本修改”一致闭环,让业务用户能看懂规则怎么判断,让系统按同一套逻辑执行。
|
||||
|
||||
## 背景与问题
|
||||
|
||||
当前风险规则已经具备自然语言创建、JSON 风险规则、风险评分、详情页流程图、仿真测试和上线启用能力,但仍有几个关键缺口:
|
||||
|
||||
- 规则解释不够稳定。用户输入复杂业务规则后,系统可能把“城市是否一致、日期是否越界、是否存在合理说明”解释成“是否出现关键词”,这会导致业务语义失真。
|
||||
- 流程图容易变成展示装饰。如果流程图不严格从可执行 JSON DSL 派生,就会出现“页面看起来是 A,后端实际执行是 B”的问题。
|
||||
- 测试结果缺少路径解释。用户上传票据和输入意图后,需要知道系统识别到了哪些字段、走过哪些判断节点、为什么命中或未命中。
|
||||
- 规则修改缺少版本化闭环。已上线规则不能直接覆盖,应创建修订版本,旧版本继续生效,新版本测试通过后再替换。
|
||||
- 常见费控规则需要模板化扩展。预算、票据、差旅、招待、采购/AP、企业卡等规则应进入规则模板库,但仍必须走同一套解释和执行链路。
|
||||
|
||||
## 目标与非目标
|
||||
|
||||
### 目标
|
||||
|
||||
- [G1] 自然语言规则经过 Hermes 语义理解后,生成结构稳定、可校验、可执行的 JSON DSL。
|
||||
- [G2] 流程判断图必须由 JSON DSL 派生,不能直接由自然语言单独生成。
|
||||
- [G3] 详情页展示“文字流程解释 + 流程图 + 使用字段 + 风险分数 + 规则状态”,让业务用户能确认系统理解是否正确。
|
||||
- [G4] 测试规则时展示本次样例或票据仿真的字段识别结果、判断路径、命中节点和最终结论。
|
||||
- [G5] 用户觉得规则不合理时,通过“创建修订版本”修改,线上版本保持稳定。
|
||||
- [G6] 常见费控规则模板库可以复用同一套 DSL、流程图和测试机制。
|
||||
|
||||
### 非目标
|
||||
|
||||
- [NG1] 本期不做流程图编辑器,不允许拖拽、改节点、缩放编辑或在线画图。
|
||||
- [NG2] 本期不让大模型作为风险命中裁判。Hermes 只负责理解、生成、解释和辅助解析,最终命中由规则执行器决定。
|
||||
- [NG3] 本期不把所有复杂政策一次性建成完整专家系统,先保证规则表达、解释和执行一致。
|
||||
- [NG4] 本期不直接覆盖已上线规则,所有线上修改都走修订版本。
|
||||
|
||||
## 用户与场景
|
||||
|
||||
- 财务规则制定者:创建风险规则,查看系统理解是否正确,修改草稿规则。
|
||||
- 高级财务人员 / admin:审核、上线、下线、启用、停用、删除未发布规则。
|
||||
- 普通报销用户:在真实业务命中风险时看到简明原因,可反馈误判或漏判。
|
||||
- 系统执行链路:报销、费用申请、预算占用、票据识别、采购/AP 等场景只加载已上线且已启用的规则。
|
||||
|
||||
核心场景:
|
||||
|
||||
1. 新建规则:输入规则标题、费用业务环节、费用领域、是否需要附件、自然语言规则。
|
||||
2. 生成规则:Hermes 结合字段本体输出 JSON DSL、业务说明、风险评分、流程模型和 SVG。
|
||||
3. 查看详情:用户确认“系统理解的字段、判断条件、例外说明、命中动作”是否正确。
|
||||
4. 仿真测试:用户上传附件并输入测试意图,系统统一识别字段,再由执行器判断当前规则。
|
||||
5. 修改规则:未上线规则直接编辑;已上线规则创建修订版本,测试通过后发布替换。
|
||||
|
||||
## 功能能力
|
||||
|
||||
### C1. 自然语言输入能力
|
||||
|
||||
新建风险规则表单应包含:
|
||||
|
||||
- 规则标题。
|
||||
- 业务环节:费用申请、报销、预算控制、付款/采购等。
|
||||
- 费用领域:差旅、住宿、交通、招待、办公、培训、会议、软件服务、通讯、福利、预算、发票、采购/AP、通用。
|
||||
- 是否需要附件:需要时测试弹窗开放附件上传;不需要时隐藏上传入口。
|
||||
- 自然语言规则描述。
|
||||
|
||||
风险等级不允许用户手动选择,由评分模型输出风险分数和等级。
|
||||
|
||||
### C2. 语义理解与字段本体映射
|
||||
|
||||
Hermes 需要输出一份中间语义计划,而不是直接写死 JSON:
|
||||
|
||||
- 规则意图:判断什么业务风险。
|
||||
- 适用范围:业务环节、费用领域、费用科目、单据类型。
|
||||
- 所需字段:中文解释、英文字段名、来源、是否必填。
|
||||
- 票据字段:OCR 或文档智能识别得到的城市、日期、金额、销售方、发票号等。
|
||||
- 判断步骤:按顺序表达条件、分支、例外说明和命中动作。
|
||||
- 例外条件:例如延期、改签、跨城办事、临时任务等说明。
|
||||
- 风险动作:提醒、人工复核、要求补充说明、退回修改、禁止提交。
|
||||
|
||||
字段展示统一为:
|
||||
|
||||
```text
|
||||
申报目的地[claim.destination_city]
|
||||
明细发生地点[item.location_city]
|
||||
交通票行程城市[receipt.transport_route_cities]
|
||||
住宿发票城市[receipt.hotel_city]
|
||||
出差开始日期[trip.start_date]
|
||||
出差结束日期[trip.end_date]
|
||||
报销事由[claim.reason]
|
||||
```
|
||||
|
||||
### C3. 可执行 JSON DSL
|
||||
|
||||
JSON DSL 应表达规则执行逻辑,而不是保存自然语言摘要。建议基本结构:
|
||||
|
||||
```json
|
||||
{
|
||||
"rule_id": "risk.travel.city_mismatch",
|
||||
"version": "v1",
|
||||
"scope": {
|
||||
"business_stage": "reimbursement",
|
||||
"expense_types": ["travel", "lodging"]
|
||||
},
|
||||
"required_fields": [
|
||||
{
|
||||
"label": "申报目的地",
|
||||
"field": "claim.destination_city",
|
||||
"source": "claim",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"conditions": {
|
||||
"all": [
|
||||
{
|
||||
"op": "in_scope",
|
||||
"field": "expense.type",
|
||||
"values": ["travel", "lodging"]
|
||||
},
|
||||
{
|
||||
"op": "any_present",
|
||||
"fields": [
|
||||
"receipt.transport_route_cities",
|
||||
"receipt.hotel_city",
|
||||
"item.location_city"
|
||||
]
|
||||
},
|
||||
{
|
||||
"op": "none_match",
|
||||
"left_fields": [
|
||||
"receipt.transport_route_cities",
|
||||
"receipt.hotel_city"
|
||||
],
|
||||
"right_fields": [
|
||||
"claim.destination_city",
|
||||
"item.location_city",
|
||||
"trip.route_cities"
|
||||
],
|
||||
"matcher": "city_equivalent"
|
||||
},
|
||||
{
|
||||
"op": "not_contains_any",
|
||||
"field": "claim.reason",
|
||||
"values": ["延期", "改签", "跨城办事", "临时任务", "绕行"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"action": {
|
||||
"risk_level": "high",
|
||||
"risk_score": 76,
|
||||
"decision": "review_required",
|
||||
"message": "票据城市与申报目的地或行程城市不一致,且未说明合理原因。"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
核心要求:
|
||||
|
||||
- 城市、日期、金额、人员、供应商等字段必须使用专门比较算子,不能退化成“关键词出现”。
|
||||
- 复杂规则允许多层条件组合:`all`、`any`、`not`、`branch`、`exists`、`range`、`compare`、`semantic_contains`。
|
||||
- 例外说明可以使用语义包含,但只能影响“是否进入复核/降级/豁免”,不能替代结构化字段判断。
|
||||
- DSL 生成后必须通过 schema 校验和执行器 dry-run。
|
||||
|
||||
### C4. 流程判断图
|
||||
|
||||
流程图不是编辑器,也不是自然语言插图。流程图必须由 JSON DSL 转换成 `flow_model`,再生成 SVG。
|
||||
|
||||
建议 `flow_model`:
|
||||
|
||||
```json
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"id": "start",
|
||||
"type": "start",
|
||||
"title": "开始",
|
||||
"description": "进入差旅住宿报销风险检查"
|
||||
},
|
||||
{
|
||||
"id": "scope",
|
||||
"type": "decision",
|
||||
"title": "是否属于差旅住宿报销",
|
||||
"fields": ["expense.type", "claim.business_stage"]
|
||||
},
|
||||
{
|
||||
"id": "city_match",
|
||||
"type": "decision",
|
||||
"title": "票据城市是否匹配申报或行程城市",
|
||||
"fields": [
|
||||
"receipt.hotel_city",
|
||||
"receipt.transport_route_cities",
|
||||
"claim.destination_city",
|
||||
"trip.route_cities"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "hit",
|
||||
"type": "risk",
|
||||
"title": "命中高风险",
|
||||
"description": "要求补充行程说明或退回修改"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{ "from": "start", "to": "scope", "label": "开始检查" },
|
||||
{ "from": "scope", "to": "end_pass", "label": "否" },
|
||||
{ "from": "scope", "to": "city_match", "label": "是" },
|
||||
{ "from": "city_match", "to": "end_pass", "label": "是" },
|
||||
{ "from": "city_match", "to": "hit", "label": "否" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
流程图展示要求:
|
||||
|
||||
- 详情页左侧为文字流程解释,右侧为“流程图”。
|
||||
- 判断分支用“是 / 否 / 通过 / 不通过 / 缺失 / 存在”等明确标签。
|
||||
- 风险命中框使用风险等级颜色:低风险蓝色,中风险橙色,高风险红色,极高风险深红色。
|
||||
- 普通节点保持 SaaS 白底、细边框、低饱和样式,不能整张图都染成风险色。
|
||||
- 图只做展示,不响应拖拽、编辑、缩放和节点点击。
|
||||
- 节点数量超过 8 个时,需要自动压缩文字、合并说明节点或分页展示,避免图过大。
|
||||
|
||||
### C5. 测试命中路径
|
||||
|
||||
测试规则弹窗应展示三类信息:
|
||||
|
||||
1. 输入与识别结果
|
||||
- 用户自然语言测试意图。
|
||||
- 上传附件清单。
|
||||
- OCR / 文档智能识别字段。
|
||||
- Hermes 辅助规范化后的结构化字段。
|
||||
|
||||
2. 规则执行结果
|
||||
- 是否进入适用范围。
|
||||
- 每个判断节点的输入值、比较方式、判断结果。
|
||||
- 命中的风险动作。
|
||||
- 未命中的原因。
|
||||
|
||||
3. 流程图路径高亮
|
||||
- 使用同一个 `flow_model`。
|
||||
- 本次执行走过的节点和边由执行器输出 `trace`。
|
||||
- 前端按 `trace` 高亮路径。
|
||||
|
||||
执行 trace 示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"trace_id": "run_001",
|
||||
"matched": true,
|
||||
"risk_level": "high",
|
||||
"risk_score": 76,
|
||||
"steps": [
|
||||
{
|
||||
"node_id": "scope",
|
||||
"result": true,
|
||||
"inputs": {
|
||||
"expense.type": "住宿费",
|
||||
"claim.business_stage": "reimbursement"
|
||||
}
|
||||
},
|
||||
{
|
||||
"node_id": "city_match",
|
||||
"result": false,
|
||||
"inputs": {
|
||||
"receipt.hotel_city": "北京",
|
||||
"claim.destination_city": "上海",
|
||||
"trip.route_cities": ["武汉", "上海"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### C6. 规则修改与版本化
|
||||
|
||||
规则修改分三种:
|
||||
|
||||
- 未上线规则:允许创建者或 admin 直接编辑,保存后重新生成 DSL、流程图、评分和说明。
|
||||
- 已上线规则:不允许直接覆盖,必须点击“创建修订版本”。
|
||||
- 业务用户反馈:只能提交误判/漏判反馈,由管理员决定是否创建修订版本。
|
||||
|
||||
已上线规则修改流程:
|
||||
|
||||
```text
|
||||
线上版本 active
|
||||
↓
|
||||
创建修订版本 draft_revision
|
||||
↓
|
||||
编辑自然语言 / 参数 / 附件要求
|
||||
↓
|
||||
重新生成 JSON DSL + 流程图 + 评分
|
||||
↓
|
||||
仿真测试通过
|
||||
↓
|
||||
发布新版本
|
||||
↓
|
||||
旧版本归档,新版本 active
|
||||
```
|
||||
|
||||
版本记录必须包含:
|
||||
|
||||
- 修改人。
|
||||
- 修改原因。
|
||||
- 修改前后自然语言差异。
|
||||
- 修改前后 DSL 差异。
|
||||
- 测试报告。
|
||||
- 发布时间。
|
||||
- 是否替换线上版本。
|
||||
|
||||
## 方案设计
|
||||
|
||||
### 总体链路
|
||||
|
||||
```text
|
||||
自然语言规则
|
||||
↓
|
||||
字段本体召回与业务域约束
|
||||
↓
|
||||
Hermes 生成语义计划 semantic_plan
|
||||
↓
|
||||
语义计划校验与补全
|
||||
↓
|
||||
生成 JSON DSL
|
||||
↓
|
||||
Schema 校验 + 执行器 dry-run
|
||||
↓
|
||||
风险评分 risk_score / risk_level
|
||||
↓
|
||||
DSL 转 flow_model
|
||||
↓
|
||||
flow_model 转 flow_diagram_svg
|
||||
↓
|
||||
详情展示 + 仿真测试 + 上线执行
|
||||
```
|
||||
|
||||
### 前端设计
|
||||
|
||||
涉及入口:
|
||||
|
||||
- `AuditRuleDialogs.vue`:新建风险规则表单,后续增加修订版本编辑入口。
|
||||
- `AuditJsonRiskRuleDetail.vue`:详情页展示基本信息、测试状态、流程解释、流程图、操作按钮。
|
||||
- `RiskRuleFlowDiagram.vue`:只负责展示 SVG 或由 `flow_model` 派生的静态图,不做编辑。
|
||||
- `RiskRuleTestDialog.vue`:仿真测试窗口,展示输入识别、执行路径、测试报告。
|
||||
- `auditViewRiskRuleModel.js` / `auditViewModel.js`:规则详情视图模型、列表字段和状态映射。
|
||||
|
||||
详情页建议结构:
|
||||
|
||||
```text
|
||||
Topbar:规则标题、状态、风险分数、风险等级、上线/启用状态
|
||||
|
||||
基本信息:费用领域、业务环节、附件要求、创建人、上线时间、最后操作、测试状态
|
||||
|
||||
判断流程:
|
||||
左侧:文字流程解释
|
||||
右侧:流程图
|
||||
|
||||
测试与版本:
|
||||
最近测试报告
|
||||
修订版本 / 历史版本
|
||||
操作按钮
|
||||
```
|
||||
|
||||
修改规则界面建议采用左右布局:
|
||||
|
||||
- 左侧:自然语言规则编辑、规则标题、费用领域、附件要求。
|
||||
- 右侧:系统解释预览,包括字段、本体映射、流程解释、风险分数。
|
||||
- 底部:重新生成、保存草稿、测试规则、提交上线。
|
||||
|
||||
### 后端设计
|
||||
|
||||
已有相关模块应优先复用:
|
||||
|
||||
- `risk_rule_generation.py`:规则生成主流程。
|
||||
- `risk_rule_generation_prompt.py`:Hermes 提示词。
|
||||
- `risk_rule_generation_ontology.py`:字段本体和费用领域约束。
|
||||
- `risk_rule_generation_semantics.py`:自然语言语义解释。
|
||||
- `risk_rule_generation_interpreter.py`:解释结果到 DSL。
|
||||
- `risk_rule_scoring.py`:风险评分。
|
||||
- `risk_rule_flow_diagram.py`:流程图 SVG 生成。
|
||||
- `risk_rule_manifest_normalizer.py`:规则 manifest 规范化。
|
||||
- `risk_rule_template_executor.py`:规则执行器。
|
||||
- `agent_asset_risk_rule_testing.py`:规则测试、删除、发布、启用。
|
||||
- `agent_asset_risk_rule_simulation.py`:仿真测试对话。
|
||||
|
||||
后端需要补齐的能力:
|
||||
|
||||
- 生成 `semantic_plan` 并持久化到 `config_json` 或版本内容中。
|
||||
- 生成并持久化 `flow_model`,再生成 `flow_diagram_svg`。
|
||||
- 执行器输出 `trace`,用于测试解释和流程图高亮。
|
||||
- 支持创建修订版本,避免直接覆盖 active 版本。
|
||||
- 支持从常见模板创建规则,模板也走同一套生成和校验链路。
|
||||
|
||||
### 接口设计
|
||||
|
||||
建议新增或调整:
|
||||
|
||||
```text
|
||||
POST /agent-assets/risk-rules/generate
|
||||
根据自然语言创建生成任务,返回生成中资产。
|
||||
|
||||
POST /agent-assets/{asset_id}/risk-rules/regenerate
|
||||
对草稿或修订版本重新生成 DSL、评分和流程图。
|
||||
|
||||
POST /agent-assets/{asset_id}/risk-rules/revisions
|
||||
基于已上线规则创建修订版本。
|
||||
|
||||
PATCH /agent-assets/{asset_id}/risk-rules/draft
|
||||
保存未上线规则或修订版本的编辑内容。
|
||||
|
||||
POST /agent-assets/{asset_id}/risk-rule-tests/simulate
|
||||
独立仿真测试,返回字段识别、执行结果、trace。
|
||||
|
||||
GET /agent-assets/{asset_id}/risk-rule-tests/latest
|
||||
返回最近测试摘要。
|
||||
|
||||
POST /agent-assets/{asset_id}/publish
|
||||
发布通过测试的规则版本。
|
||||
```
|
||||
|
||||
### 数据设计
|
||||
|
||||
建议在风险规则版本内容或 `config_json` 中保留:
|
||||
|
||||
```json
|
||||
{
|
||||
"source_text": "用户输入的自然语言规则",
|
||||
"semantic_plan": {},
|
||||
"dsl": {},
|
||||
"flow_model": {},
|
||||
"flow_diagram_svg": "<svg>...</svg>",
|
||||
"flow_explanation": [],
|
||||
"risk_score": 76,
|
||||
"risk_level": "high",
|
||||
"required_attachment": true,
|
||||
"required_fields": [],
|
||||
"last_operation": {
|
||||
"action": "publish",
|
||||
"actor": "admin",
|
||||
"at": "2026-05-30T10:00:00+08:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
测试记录保留:
|
||||
|
||||
```json
|
||||
{
|
||||
"test_type": "simulation",
|
||||
"input_text": "我去北京出差 3 天,上传武汉到上海车票",
|
||||
"attachments": [],
|
||||
"recognized_fields": {},
|
||||
"normalized_fields": {},
|
||||
"execution_result": {},
|
||||
"trace": {},
|
||||
"passed": true,
|
||||
"tester": "admin",
|
||||
"tested_at": "2026-05-30T10:10:00+08:00"
|
||||
}
|
||||
```
|
||||
|
||||
## 算法与公式
|
||||
|
||||
### 风险评分
|
||||
|
||||
风险评分由模型辅助判断,但必须结构化输出。建议使用可解释加权模型:
|
||||
|
||||
$$
|
||||
score = \min(100, base + \sum_{i=1}^{n} w_i x_i + c + e)
|
||||
$$
|
||||
|
||||
变量说明:
|
||||
|
||||
- $base$:业务领域基础风险分。预算、发票、付款类通常高于普通提示类。
|
||||
- $x_i$:风险因子是否存在或强度,例如金额影响、附件缺失、字段冲突、越权、历史重复。
|
||||
- $w_i$:风险因子权重。
|
||||
- $c$:复杂度修正,例如多字段交叉、跨单据、跨时间窗口、跨附件识别。
|
||||
- $e$:例外说明修正。存在合理说明时可降低,但不能直接清零。
|
||||
|
||||
等级映射:
|
||||
|
||||
- 0-30:低风险。
|
||||
- 31-60:中风险。
|
||||
- 61-80:高风险。
|
||||
- 81-100:极高风险。
|
||||
|
||||
### 流程复杂度控制
|
||||
|
||||
为了避免流程图过大,建议定义流程复杂度:
|
||||
|
||||
$$
|
||||
complexity = node_count + 0.5 \times edge_count + branch_count
|
||||
$$
|
||||
|
||||
处理规则:
|
||||
|
||||
- `complexity <= 12`:单图展示。
|
||||
- `12 < complexity <= 20`:合并说明节点,保留关键判断。
|
||||
- `complexity > 20`:详情页展示主流程,测试弹窗展示完整 trace。
|
||||
|
||||
## 测试方案
|
||||
|
||||
### 单元测试
|
||||
|
||||
- 语义计划生成:复杂差旅城市规则不能退化为关键词判断。
|
||||
- DSL schema 校验:缺字段、非法算子、空 action 必须失败。
|
||||
- 执行器:城市匹配、日期范围、金额阈值、附件缺失、例外说明。
|
||||
- 流程转换:同一 DSL 生成稳定的 `flow_model` 和 SVG。
|
||||
- 风险评分:低/中/高/极高边界分数。
|
||||
|
||||
### 接口测试
|
||||
|
||||
- 新建规则返回生成中资产。
|
||||
- 生成完成后包含 `dsl`、`flow_model`、`flow_diagram_svg`、`risk_score`。
|
||||
- 仿真测试返回 `recognized_fields`、`normalized_fields`、`trace`。
|
||||
- 未测试通过的规则不能发布。
|
||||
- 已上线规则创建修订版本,不覆盖线上版本。
|
||||
|
||||
### 前端测试
|
||||
|
||||
- 新建弹窗不再选择风险等级。
|
||||
- 详情页展示风险分数、流程解释、流程图。
|
||||
- 流程图不可点击、不可拖拽、无工具栏。
|
||||
- 测试弹窗显示字段识别结果和判断路径。
|
||||
- 已上线规则只能创建修订版本修改。
|
||||
|
||||
### 容器验证
|
||||
|
||||
后续开发验证默认在 Docker 容器内执行:
|
||||
|
||||
```bash
|
||||
docker exec x-financial-main sh -lc "cd /app/server && pytest <target> --timeout=60"
|
||||
docker exec x-financial-main sh -lc "cd /app/web && npm run build"
|
||||
```
|
||||
|
||||
### 本轮落地结果
|
||||
|
||||
已落地接口:
|
||||
|
||||
- `GET /agent-assets/risk-rules/templates`:返回预算、票据、差旅、招待、采购/AP、企业卡、通用模板分组,包含默认自然语言、字段清单、附件要求和 DSL 样例。
|
||||
- `PATCH /agent-assets/{asset_id}/risk-rules/draft`:编辑未上线风险规则草稿。
|
||||
- `POST /agent-assets/{asset_id}/risk-rules/revisions`:为已上线规则创建修订草稿。
|
||||
- `POST /agent-assets/{asset_id}/risk-rules/regenerate`:重新生成 DSL、流程图、风险评分和业务说明。
|
||||
- `POST /agent-assets/{asset_id}/risk-rules/feedback`、`GET /agent-assets/{asset_id}/risk-rules/feedback`:记录和查看误判/漏判反馈。
|
||||
|
||||
关键文件:
|
||||
|
||||
- 后端模板库与契约:`risk_rule_template_catalog.py`、`agent_asset.py`、`agent_asset_risk_rules.py`。
|
||||
- 后端生成、修订、发布、反馈、仿真:`risk_rule_generation*`、`agent_asset_risk_rule_revision.py`、`agent_asset_risk_rule_regeneration.py`、`agent_asset_risk_rule_publish.py`、`agent_asset_risk_rule_feedback.py`、`agent_asset_risk_rule_simulation.py`。
|
||||
- 前端新建、详情、测试:`AuditRuleDialogs.vue`、`AuditJsonRiskRuleDetail.vue`、`RiskRuleFlowDiagram.vue`、`RiskRuleTestDialog.vue`、`auditViewDetailTopBar.js`、`useAuditRiskRuleActions.js`、`useAuditAssetData.js`。
|
||||
- 测试:`test_risk_rule_template_catalog.py`、`test_risk_rule_feedback.py`、`test_risk_rule_revision_endpoints.py`、`test_risk_rule_explainability.py`、`risk-rule-detail-experience.test.mjs`。
|
||||
|
||||
已执行验证命令:
|
||||
|
||||
```bash
|
||||
docker exec x-financial-main bash -lc "cd /app/server && timeout 60 /tmp/x-financial-server-venv/bin/python -m pytest tests/test_risk_rule_template_catalog.py tests/test_openapi_schema.py -q"
|
||||
docker exec x-financial-main bash -lc "cd /app/server && timeout 60 /tmp/x-financial-server-venv/bin/python -m pytest tests/test_risk_rule_feedback.py tests/test_risk_rule_revision_endpoints.py tests/test_openapi_schema.py -q"
|
||||
docker exec x-financial-main bash -lc "cd /app/web && timeout 60 node --test tests/risk-rule-detail-experience.test.mjs"
|
||||
docker exec x-financial-main bash -lc "cd /app/web && timeout 60 npm run build"
|
||||
```
|
||||
|
||||
## 指标与验收
|
||||
|
||||
- [A1] 新建复杂差旅规则后,详情页流程解释不能出现“检查是否包含风险关键词”这类错误表达。
|
||||
- [A2] 详情页流程图与 JSON DSL 条件数量、分支方向、命中动作一致。
|
||||
- [A3] 仿真测试能显示票据识别字段,并说明为什么命中或未命中。
|
||||
- [A4] 同一条测试样例的执行 trace 可以高亮流程图路径。
|
||||
- [A5] 已上线规则修改时不会改变当前线上执行结果,只有发布修订版本后才替换。
|
||||
- [A6] 低、中、高、极高风险都能由评分模型产出,不应默认集中在中高风险。
|
||||
- [A7] 前端构建通过,后端定向测试 60s 内完成。
|
||||
|
||||
## 风险与开放问题
|
||||
|
||||
- LLM 语义理解仍可能出错,因此必须有 schema 校验、执行器 dry-run、详情解释和仿真测试兜底。
|
||||
- 字段本体不完整会限制规则表达,需要持续扩展费用、票据、预算、采购/AP 字段。
|
||||
- 复杂规则可能产生过大的流程图,需要主流程和完整 trace 分层展示。
|
||||
- 老规则没有 `semantic_plan` 或 `flow_model`,需要兼容展示并允许重新生成。
|
||||
- 常见规则模板要避免写成定制逻辑。模板只能提供默认文本、字段和 DSL 样例,最终仍走通用生成链路。
|
||||
|
||||
当前仍需持续演进的点:
|
||||
|
||||
- 企业卡、采购/AP、预算场景的字段本体还偏少,后续应补充企业卡交易流水、供应商、采购订单、合同、预算期间等字段。
|
||||
- 复杂规则的准确性仍依赖 Hermes 语义计划质量,执行前必须继续保留 DSL validator、执行器 dry-run 和仿真测试。
|
||||
- 模板库只作为规则编写入口的业务参考,不作为规则执行捷径;新增模板时必须同时提供 DSL 样例和 validator 测试。
|
||||
|
||||
## 实现确认
|
||||
|
||||
当前实现仍围绕“解释图和执行逻辑一致”推进:自然语言先经字段本体和语义计划形成受控 JSON DSL,详情页流程图、文字流程解释、测试 trace、上线版本均围绕同一份 DSL 展示和执行,没有新增流程图编辑器或绕过规则执行器的判断链路。
|
||||
96
document/development/risk-rule-explainable-flow/TODO.md
Normal file
96
document/development/risk-rule-explainable-flow/TODO.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# 风险规则可解释流程判断改造 TODO
|
||||
|
||||
## 使用规则
|
||||
|
||||
- 每个 TODO 对应 `CONCEPT.md` 的目标、能力或验收点。
|
||||
- 只有真实完成并通过相应验证后,才能把 `[ ]` 改成 `[x]`。
|
||||
- 如果实现中发现需求变化,先更新 `CONCEPT.md`,再调整本 TODO。
|
||||
- 后端和构建验证默认在 Docker 容器 `x-financial-main` 的 `/app` 下执行。
|
||||
|
||||
## 1. 调研与边界
|
||||
|
||||
- [x] [CONCEPT: 背景与问题] 梳理当前风险规则生成链路,记录 `risk_rule_generation.py` 到 `risk_rule_template_executor.py` 的真实调用关系。证据:`CONCEPT.md` 后端设计与本轮落地结果记录生成、DSL validator、执行器、流程图、仿真测试链路。
|
||||
- [x] [CONCEPT: 前端设计] 梳理详情页、新建弹窗、测试弹窗当前字段来源,记录 `AuditRuleDialogs.vue`、`AuditJsonRiskRuleDetail.vue`、`RiskRuleTestDialog.vue` 的改造点。证据:`CONCEPT.md` 本轮落地结果列出三个组件及对应职责,`risk-rule-detail-experience.test.mjs` 覆盖关键接线。
|
||||
- [x] [CONCEPT: 数据设计] 确认 `AgentAssetRead`、版本内容、`config_json` 中已有字段,确定 `semantic_plan`、`flow_model`、`flow_diagram_svg` 的落点。证据:`AgentAssetRead` 返回 `latest_test_summary`,版本 JSON metadata 保存 `semantic_plan`/`flow_model`/`flow_diagram_svg`,生成测试覆盖。
|
||||
- [x] [CONCEPT: 非目标] 明确本期不做流程图编辑器,不增加拖拽、缩放、节点编辑能力。证据:`RiskRuleFlowDiagram.vue` 只渲染静态 SVG/文字说明,无编辑、拖拽、缩放入口;前端回归测试断言不存在 zoom 按钮。
|
||||
|
||||
## 2. 语义计划与 DSL 契约
|
||||
|
||||
- [x] [CONCEPT: C2] 定义 `semantic_plan` schema,包含规则意图、适用范围、字段本体映射、判断步骤、例外条件和风险动作。证据:`risk_rule_explainability.py` 产出 `semantic_plan`,`test_risk_rule_explainability.py` 已验证。
|
||||
- [x] [CONCEPT: C3] 定义 JSON DSL schema,补齐城市、日期、金额、附件、语义说明等通用算子。证据:`risk_rule_dsl_validator.py` 定义受控 DSL 校验,`risk_rule_generation_interpreter.py` 补充 `numeric_compare`,`risk_rule_template_executor.py` 支持日期、字段集合、附件存在性、文本例外和数值比较算子。
|
||||
- [x] [CONCEPT: C3] 增加 DSL validator,禁止复杂字段判断退化为“风险关键词匹配”。证据:`validate_risk_rule_draft` 会将城市一致性关键词规则改写为结构化比较,将预算金额关键词规则改写为 `composite_rule_v1`,`test_risk_rule_dsl_validator.py` 覆盖。
|
||||
- [x] [CONCEPT: C3] 为差旅城市不一致、住宿日期越界、预算阈值、重复发票各准备一条 DSL 样例。证据:新增 `risk_rule_dsl_examples.py`,并通过 `test_risk_rule_dsl_examples.py` 覆盖四类样例的 validator 与执行器命中/未命中回归。
|
||||
- [x] [CONCEPT: C2] 字段展示统一为 `中文[英文]` 格式,并复用字段本体解释。证据:`risk_rule_explainability.py` 的 `semantic_plan.required_fields.display` 使用字段本体生成 `label[key]`。
|
||||
|
||||
## 3. Hermes 生成链路
|
||||
|
||||
- [x] [CONCEPT: 总体链路] 调整 `risk_rule_generation_prompt.py`,要求 Hermes 先输出 `semantic_plan`,再输出 DSL。证据:提示词 `required_json_shape` 改为 `{ semantic_plan, dsl }`,`test_prompt_requires_semantic_plan_then_dsl` 验证。
|
||||
- [x] [CONCEPT: C2] 在提示词中明确:城市、日期、金额、票据关系必须用结构化比较,不允许用关键词替代。证据:`risk_rule_generation_prompt.py` 补充 `numeric_compare` 和预算金额不得关键词匹配的 guardrail。
|
||||
- [x] [CONCEPT: 后端设计] 在 `risk_rule_generation_semantics.py` 或解释层补齐语义计划解析与错误返回。证据:`risk_rule_generation_semantic_plan.py` 解析 `{ semantic_plan, dsl }` 包装并保留 `metadata.model_semantic_plan`;后台生成失败写入 `generation_error` 和 `last_operation=generation_failed`,容器内 `test_risk_rule_generation_failure.py` 与语义计划测试通过。
|
||||
- [x] [CONCEPT: 后端设计] 在 `risk_rule_generation_interpreter.py` 中从 `semantic_plan` 生成标准 DSL。证据:新增 `build_dsl_from_semantic_plan`,当 Hermes 仅返回 `semantic_plan` 时生成 `composite_rule_v1` 草稿,再由 DSL validator 基于字段本体规范成受控条件;`test_semantic_plan_only_response_can_generate_standard_dsl` 通过。
|
||||
- [x] [CONCEPT: 指标与验收] 增加复杂差旅规则生成测试,确认判断依据不是关键词匹配。证据:`test_generate_complex_travel_route_rule_uses_formula_not_keyword_match` 验证复杂差旅规则生成后为结构化城市一致性规则,且 `condition_summary` 不含“风险关键词”;容器内 `test_risk_rule_generation.py` 通过。
|
||||
|
||||
## 4. 流程模型与 SVG
|
||||
|
||||
- [x] [CONCEPT: C4] 定义 `flow_model` schema,包含 nodes、edges、字段引用、分支标签和风险节点。证据:`risk_rule_explainability.py` 产出 `flow_model`,生成测试验证 nodes/source/metadata 同步。
|
||||
- [x] [CONCEPT: C4] 修改 `risk_rule_flow_diagram.py`,改为从 DSL 或 `flow_model` 生成 SVG。证据:新增 `build_risk_rule_flow_diagram_spec`,优先从 `flow_model.nodes` 生成图形 spec,缺失时回退 `params.conditions`;`test_flow_diagram_spec_prefers_flow_model_nodes` 通过。
|
||||
- [x] [CONCEPT: C4] 保持 Style 7 / OpenAI Official 风格:白底、细边框、低饱和、风险节点单点强调。证据:`RiskRuleFlowDiagramRenderer` 输出白底、细边框、低饱和风险色,既有 `test_risk_rule_generation.py` 校验高风险红色、无旧绿色和无阴影滤镜。
|
||||
- [x] [CONCEPT: 算法与公式] 实现流程复杂度控制,节点过多时压缩主流程。证据:`_condition_lines_from_flow_nodes` 将超过 4 个判断节点压缩为摘要,`test_flow_diagram_spec_compresses_too_many_decision_nodes` 覆盖。
|
||||
- [x] [CONCEPT: C4] 为老规则缺少 `flow_model` 的情况保留默认静态图兜底。证据:`build_risk_rule_flow_diagram_spec` 在 `flow_model` 缺失时使用 DSL/metadata 生成 spec,`test_flow_diagram_spec_falls_back_to_dsl_when_flow_model_missing` 通过。
|
||||
|
||||
## 5. 执行器 trace 与仿真测试
|
||||
|
||||
- [x] [CONCEPT: C5] 修改 `RiskRuleTemplateExecutor`,输出每个判断节点的 trace。证据:新增 `evaluate_with_trace`,仿真测试返回 `trace.steps` 和 `path_node_ids`。
|
||||
- [x] [CONCEPT: C5] 仿真测试统一在“用户点击运行”后处理附件和文本,不允许上传后立即判断。证据:`RiskRuleTestDialog.vue` 的 `handleFileChange` 只把附件加入待发送列表,`sendMessage` 才调用 `recognizeTemporaryFiles` 与 `simulateRiskRuleTest`;容器内 `npm run build` 通过。
|
||||
- [x] [CONCEPT: C5] 测试结果中展示 OCR 原始字段、Hermes 规范化字段、执行器实际输入字段。证据:`AgentAssetRiskRuleSimulationRead` 新增 `ocr_raw_fields`、`hermes_normalized_fields`、`executor_input_fields`,`RiskRuleTestDialog.vue` 展示字段流水线;容器内 `test_risk_rule_explainability.py` 与 `test_risk_rule_generation.py` 通过。
|
||||
- [x] [CONCEPT: C5] 测试弹窗展示命中路径、未命中原因和最终风险动作。证据:`RiskRuleTestDialog.vue` 展示“执行路径”,`riskRuleTestDialogDisplay.js` 格式化 trace。
|
||||
- [x] [CONCEPT: C5] trace 中的 `node_id` 必须能映射到流程图节点。证据:`flow_model` 使用条件 id 作为节点 id,`risk_rule_execution_trace.py` 输出同名 `node_id`。
|
||||
|
||||
## 6. 规则修改与版本化
|
||||
|
||||
- [x] [CONCEPT: C6] 未上线规则支持编辑标题、费用领域、附件要求和自然语言描述。证据:新增 `AgentAssetRiskRuleRevisionService.update_unpublished_draft` 与 `PATCH /agent-assets/{asset_id}/risk-rules/draft`,容器内 `test_risk_rule_revision_endpoints.py` 覆盖返回字段。
|
||||
- [x] [CONCEPT: C6] 已上线规则新增“创建修订版本”,不直接覆盖 active 版本。证据:新增 `AgentAssetRiskRuleRevisionService.create_revision_draft` 与 `POST /agent-assets/{asset_id}/risk-rules/revisions`,测试验证 `published_version` 保持不变且 `working_version` 进入修订版本。
|
||||
- [x] [CONCEPT: C6] 修订版本保存后重新生成 DSL、流程图、风险评分和业务说明。证据:新增 `AgentAssetRiskRuleRegenerationService` 与 `POST /agent-assets/{asset_id}/risk-rules/regenerate`,草稿/修订草稿都会重新生成 JSON DSL、`flow_diagram_svg`、风险评分和版本 Markdown;容器内 `test_regenerate_revision_draft_keeps_active_document_unchanged` 通过。
|
||||
- [x] [CONCEPT: C6] 发布修订版本时归档旧版本,并记录修改人、修改原因和测试报告。证据:新增 `AgentAssetRiskRulePublishMixin`,发布修订时将旧 `rule_document` 写入 `revision_history.previous_rule_document`,切换新 JSON 文件并写入 `last_operation=publish_revision`;容器内 `test_publish_regenerated_revision_replaces_online_document` 通过。
|
||||
- [x] [CONCEPT: C6] 普通用户误判/漏判反馈进入规则反馈记录,不直接修改规则。证据:新增 `agent_asset_rule_feedback` 模型、`POST/GET /agent-assets/{asset_id}/risk-rules/feedback`、前端服务方法;容器内 `test_risk_rule_feedback.py`、规则回归和 `npm run build` 通过。
|
||||
|
||||
## 7. 常见费控规则模板库
|
||||
|
||||
- [x] [CONCEPT: C1] 增加“从常见规则模板创建”入口。证据:`AuditRuleDialogs.vue` 新建风险规则弹窗新增常见规则模板选择,选择后预填标题、附件要求、业务环节、费用领域和自然语言。
|
||||
- [x] [CONCEPT: C1] 模板按预算、票据、差旅、招待、采购/AP、企业卡、通用分组。证据:新增 `risk_rule_template_catalog.py`,`GET /agent-assets/risk-rules/templates` 返回 7 个分组;容器内 `test_risk_rule_template_catalog.py` 通过。
|
||||
- [x] [CONCEPT: C3] 每个模板提供默认自然语言、字段清单、附件要求和 DSL 样例。证据:模板接口返回 `natural_language`、`fields`、`requires_attachment`、`dsl_example`;容器内测试逐个调用 DSL validator 验证通过。
|
||||
- [x] [CONCEPT: 非目标] 模板不得绕过通用生成链路,不写定制校准器。证据:前端模板只预填 `riskRuleCreateForm`,提交仍走 `generateRiskRuleAsset`;无新增定制校准器,容器内 `npm run build` 通过。
|
||||
|
||||
## 8. 前端详情与交互
|
||||
|
||||
- [x] [CONCEPT: 前端设计] 详情页 topbar 展示规则标题、状态、风险分数、风险等级、上线/启用状态。证据:`auditViewDetailTopBar.js` 为风险规则详情输出风险分、风险等级、规则状态、上线状态、启用状态 KPI;容器内 `npm run build` 通过。
|
||||
- [x] [CONCEPT: C4] 判断流程区域改成左侧文字流程解释、右侧流程图。证据:`RiskRuleFlowDiagram.vue` 使用左侧 `risk-rule-flow-explainer` 和右侧 `risk-rule-flow-visual` 的两栏布局;容器内 `npm run build` 通过。
|
||||
- [x] [CONCEPT: C4] 流程图标题固定为“流程图”,高度与“流程解释”标题对齐。证据:`RiskRuleFlowDiagram.vue` 使用统一 `risk-rule-section-title`,右侧标题固定为“流程图”;容器内 `npm run build` 通过。
|
||||
- [x] [CONCEPT: C5] 测试弹窗展示字段识别结果、规范化字段、判断路径和测试报告。证据:`RiskRuleTestDialog.vue` 展示字段流水线、执行路径和右侧测试报告摘要;容器内 `cd /app/web && npm run build` 通过。
|
||||
- [x] [CONCEPT: C6] 已上线规则详情展示“创建修订版本”,草稿规则展示“编辑规则”。证据:`AuditView.vue` 底部动作区按规则状态展示按钮,`AuditRuleDialogs.vue` 提供编辑/修订弹窗,`useAuditRiskRuleActions.js` 调用草稿编辑与修订接口;容器内 `cd /app/web && npm run build` 通过。
|
||||
- [x] [CONCEPT: 指标与验收] 列表和详情状态刷新不能造成页面闪烁。证据:`useAuditAssetData.loadSelectedAssetDetail` 增加 `{ silent: true }` 静默刷新,规则保存、送审、审核、上线、回退和版本操作均改为静默刷新;容器内 `npm run build` 通过。
|
||||
|
||||
## 9. 后端接口与权限
|
||||
|
||||
- [x] [CONCEPT: 接口设计] 实现或调整 `POST /agent-assets/{asset_id}/risk-rules/revisions`。证据:新增独立路由 `agent_asset_risk_rules.py`,容器内 `test_create_risk_rule_revision_endpoint_keeps_active_version` 通过。
|
||||
- [x] [CONCEPT: 接口设计] 实现或调整 `PATCH /agent-assets/{asset_id}/risk-rules/draft`。证据:新增独立路由 `agent_asset_risk_rules.py`,容器内 `test_update_risk_rule_draft_endpoint_updates_unpublished_rule` 与已上线阻断用例通过。
|
||||
- [x] [CONCEPT: 接口设计] `POST /agent-assets/{asset_id}/risk-rules/regenerate` 返回生成状态和错误详情。证据:独立路由 `agent_asset_risk_rules.py` 已接入重生成接口,成功返回 `AgentAssetRead.config_json.generation_status`/`revision_draft.generation_status`,接口用例 `test_regenerate_risk_rule_endpoint_returns_updated_detail` 通过。
|
||||
- [x] [CONCEPT: 接口设计] 仿真测试接口返回 `recognized_fields`、`normalized_fields`、`execution_result`、`trace`。证据:`AgentAssetRiskRuleSimulationRead` 新增 `normalized_fields` 和 `trace`,仿真测试覆盖返回值。
|
||||
- [x] [CONCEPT: 用户与场景] 普通财务人员只能编辑未上线/修订草稿,admin 才能删除和测试,管理员按现有权限上线/下线。证据:路由依赖使用 `RuleEditorUser`、`RuleReviewerUser`、`PlatformAdminUser` 分层,`test_risk_rule_revision_endpoints.py` 覆盖 finance 新建/测试阻断、manager 删除阻断和 manager 启停入口。
|
||||
- [x] [CONCEPT: 数据设计] 所有操作写入 `last_operation`,用于详情页“最后操作”展示。证据:生成、后台生成、草稿编辑、创建修订、重新生成、发布/下线、测试确认等风险规则服务均写入 `config_json.last_operation`,前端 `AuditJsonRiskRuleDetail.vue` 展示 `lastOperationLabel`。
|
||||
|
||||
## 10. 测试与验证
|
||||
|
||||
- [x] [CONCEPT: 测试方案] 后端补充语义计划、DSL validator、执行器 trace、流程图转换单元测试。证据:`test_risk_rule_explainability.py` 覆盖语义计划、flow_model、trace;`test_risk_rule_dsl_validator.py` 覆盖 DSL validator 与 `numeric_compare` 执行;容器内相关测试通过。
|
||||
- [x] [CONCEPT: 测试方案] 后端补充修订版本接口和发布替换接口测试。证据:`test_risk_rule_revision_service.py` 覆盖草稿编辑、创建修订、修订重生成和发布替换;`test_risk_rule_revision_endpoints.py` 覆盖草稿编辑、创建修订和重生成接口;容器内相关测试通过。
|
||||
- [x] [CONCEPT: 测试方案] 前端补充详情页流程展示、测试弹窗字段展示、修订版本按钮状态测试。证据:新增 `risk-rule-detail-experience.test.mjs` 覆盖 topbar KPI、左文右图流程、字段流水线和修订按钮;容器内 `node --test tests/risk-rule-detail-experience.test.mjs` 通过。
|
||||
- [x] [CONCEPT: 容器验证] 在容器执行后端定向测试,单个命令设置 60s 超时。证据:`/tmp/x-financial-server-venv/bin/python -m pytest tests/test_risk_rule_explainability.py -q`、`test_risk_rule_composite_generation.py -q`、`test_risk_rule_generation.py -q` 均通过。
|
||||
- [x] [CONCEPT: 容器验证] 在容器执行 `cd /app/web && npm run build`。证据:容器 `/app/web` 构建通过。
|
||||
- [x] [CONCEPT: 指标与验收] 用“武汉到上海票据 + 北京出差 3 天”样例验证城市不一致规则必须命中或给出明确不命中原因。证据:`test_simulation_returns_execution_trace_for_ticket_city_mismatch` 验证命中并返回 trace。
|
||||
- [x] [CONCEPT: 指标与验收] 用预算阈值、重复发票、住宿日期越界、招待人均超标样例做回归。证据:`risk_rule_dsl_examples.py` 已包含预算阈值、重复发票、住宿日期越界、招待人均超标样例,`test_risk_rule_dsl_examples.py` 在容器内 7 passed。
|
||||
|
||||
## 11. 文档收尾
|
||||
|
||||
- [x] [CONCEPT: 指标与验收] 开发完成后补充实际接口、文件和测试命令结果。证据:`CONCEPT.md` 新增“本轮落地结果”,列出接口、关键文件和容器验证命令。
|
||||
- [x] [CONCEPT: 风险与开放问题] 记录暂未解决的字段本体缺口和复杂规则降级策略。证据:`CONCEPT.md` 风险与开放问题补充企业卡、采购/AP、预算字段本体缺口和 DSL validator/dry-run/仿真兜底策略。
|
||||
- [x] [CONCEPT: 功能一句话] 确认最终实现没有偏离“解释图和执行逻辑一致”的核心目标。证据:`CONCEPT.md` 新增“实现确认”,明确自然语言、字段本体、JSON DSL、流程图、测试 trace 和上线版本围绕同一 DSL。
|
||||
@@ -1,139 +0,0 @@
|
||||
# 差旅报销风险管控标准(模拟版)
|
||||
|
||||
## 1. 目的
|
||||
|
||||
本标准用于约束个人报销中的差旅类单据审核,覆盖以下三类核心风险:
|
||||
|
||||
- 行程闭环风险:出发地、目的地、返程地之间是否形成合理链路。
|
||||
- 票据地点一致性风险:酒店、交通票据与申报目的地是否一致。
|
||||
- 差标超限风险:员工职级对应的交通舱位、火车席别、住宿金额是否超标。
|
||||
|
||||
本标准先以模拟规则落地到系统,用于 AI 验审与直属领导审批前的自动筛查。
|
||||
|
||||
## 2. 适用范围
|
||||
|
||||
- 报销主类型为 `travel / hotel / transport` 的单据。
|
||||
- 或者明细附件识别出 `flight_itinerary / train_ticket / hotel_invoice / taxi_receipt / parking_toll_receipt` 的单据。
|
||||
|
||||
## 3. 基础定义
|
||||
|
||||
### 3.1 目的地
|
||||
|
||||
按以下优先级确定本次差旅的“主目的地”:
|
||||
|
||||
1. 用户在报销表单中填写的业务地点 `claim.location`
|
||||
2. 长途交通票据终点城市
|
||||
3. 酒店票据识别出的酒店所在城市
|
||||
|
||||
### 3.2 行程闭环
|
||||
|
||||
满足以下任一条件,视为形成合理闭环:
|
||||
|
||||
- 单程票据终点与申报目的地一致。
|
||||
- 多段票据按时间顺序首尾衔接。
|
||||
- 最后一段票据返回首段出发城市。
|
||||
|
||||
### 3.3 合理例外说明
|
||||
|
||||
若出现多城市出差、中转、改签、异地返程、展会高峰导致超标等情况,用户必须在报销事由或费用说明中体现原因。示例关键词:
|
||||
|
||||
- `中转`
|
||||
- `转机`
|
||||
- `经停`
|
||||
- `改签`
|
||||
- `多地出差`
|
||||
- `客户临时变更`
|
||||
- `展会高峰`
|
||||
- `协议酒店满房`
|
||||
- `无直达`
|
||||
|
||||
未说明时,系统按高风险处理并退回待补充。
|
||||
|
||||
## 4. 风险规则矩阵
|
||||
|
||||
### 4.1 行程闭环规则
|
||||
|
||||
- 若存在两段及以上长途交通票据,相邻两段的 `上一段终点城市` 与 `下一段起点城市` 必须一致。
|
||||
- 若最终到达城市既不是申报目的地,也不是首段出发城市,则判定为高风险。
|
||||
- 若识别到多个目的地城市,但事由中未说明多地出差、中转或改签原因,则判定为高风险。
|
||||
|
||||
处理方式:
|
||||
|
||||
- `高风险`:退回待补充。
|
||||
- `中风险`:允许流转,但要求直属领导重点复核。
|
||||
|
||||
### 4.2 酒店地点一致性规则
|
||||
|
||||
- 酒店票据识别出的城市,必须属于以下集合之一:
|
||||
- 申报目的地
|
||||
- 长途交通票据中的目的地城市
|
||||
- 长途交通票据中的返程前停留城市
|
||||
- 若酒店城市与主目的地、交通链路均不一致,则判定为高风险。
|
||||
|
||||
处理方式:
|
||||
|
||||
- `高风险`:退回待补充,要求说明异地住宿原因或更换票据。
|
||||
|
||||
### 4.3 职级差旅标准
|
||||
|
||||
#### 4.3.1 城市分级
|
||||
|
||||
- 一线:`北京 / 上海 / 广州 / 深圳`
|
||||
- 新一线 / 重点城市:`杭州 / 南京 / 苏州 / 武汉 / 成都 / 重庆 / 西安 / 天津 / 宁波 / 厦门 / 青岛 / 长沙`
|
||||
- 其他城市:除以上外的默认城市
|
||||
|
||||
#### 4.3.2 住宿标准(元 / 晚)
|
||||
|
||||
| 职级带 | 一线 | 重点城市 | 其他城市 |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| P1-P3 | 450 | 380 | 320 |
|
||||
| P4-P5 | 550 | 480 | 380 |
|
||||
| P6-P7 | 700 | 620 | 520 |
|
||||
| M1-M2 | 900 | 820 | 720 |
|
||||
| M3 及以上 / D 序列 | 1200 | 1000 | 900 |
|
||||
|
||||
说明:
|
||||
|
||||
- 若票据中能识别出 `X 晚 / X 间夜`,系统按 `总金额 / 间夜数` 计算每晚金额。
|
||||
- 若无法识别间夜数,默认按 1 晚处理。
|
||||
|
||||
#### 4.3.3 交通标准
|
||||
|
||||
| 职级带 | 飞机 | 火车 / 高铁 |
|
||||
| --- | --- | --- |
|
||||
| P1-P3 | 经济舱 | 二等座 / 硬卧 |
|
||||
| P4-P5 | 经济舱 | 二等座 / 硬卧 |
|
||||
| P6-P7 | 超级经济舱及以下 | 一等座 / 软卧及以下 |
|
||||
| M1-M2 | 商务舱及以下 | 商务座及以下 |
|
||||
| M3 及以上 / D 序列 | 不做系统硬限制,仍保留人工复核 |
|
||||
|
||||
### 4.4 差标超限处理
|
||||
|
||||
- 超住宿标准且无说明:`高风险`
|
||||
- 超住宿标准但有说明:`中风险`
|
||||
- 飞机舱位或高铁席别超过职级标准且无说明:`高风险`
|
||||
- 飞机舱位或高铁席别超过职级标准但有说明:`中风险`
|
||||
|
||||
## 5. 系统落地口径
|
||||
|
||||
### 5.1 票据识别字段
|
||||
|
||||
系统优先使用以下字段做判断:
|
||||
|
||||
- `route`
|
||||
- `merchant_name`
|
||||
- `amount`
|
||||
- `date`
|
||||
- OCR 原文中的舱位、席别、间夜数、城市名
|
||||
|
||||
### 5.2 AI 验审动作
|
||||
|
||||
- 高风险:提交前拦截,状态切回 `待补充`
|
||||
- 中风险:允许进入直属领导审批,并附带风险标记
|
||||
- 低风险 / 通过:正常流转
|
||||
|
||||
## 6. 当前实现边界
|
||||
|
||||
- 城市识别先按常见出差城市做匹配,未覆盖全国全部区县。
|
||||
- 住宿标准与交通标准为模拟版,可后续迁移到任务规则中心做可配置化。
|
||||
- 本文档为当前开发阶段的执行依据,后续若规则中心启用动态配置,应以规则中心版本为准。
|
||||
@@ -1,453 +0,0 @@
|
||||
# 规则版本中心 UI 方案
|
||||
|
||||
## 1. 背景
|
||||
|
||||
当前“任务规则中心 > 财务规则 > 公司差旅费报销规则”已经具备:
|
||||
|
||||
- 在线 Excel 编辑
|
||||
- 工作版本 / 线上版本分离
|
||||
- 最近 5 个版本展示
|
||||
- 审核、上线、恢复能力
|
||||
|
||||
但页面仍然存在一个明显问题:
|
||||
**版本治理能力已经有了,用户却很难第一眼看见。**
|
||||
|
||||
当前版本列表更像“历史记录”,不是一个明确的“版本操作中心”。
|
||||
用户无法快速判断:
|
||||
|
||||
1. 当前真正生效的是哪个版本
|
||||
2. 当前正在编辑的是哪个版本
|
||||
3. 从哪里进入版本切换
|
||||
4. 从哪里发起版本对比
|
||||
5. 某个版本经历了哪些流转动作
|
||||
|
||||
因此,需要把现有“版本列表”升级为一个真正可用的 **版本中心**。
|
||||
|
||||
---
|
||||
|
||||
## 2. 设计目标
|
||||
|
||||
### 2.1 用户一眼能看懂
|
||||
|
||||
进入规则详情页后,用户无需点击就能立即识别:
|
||||
|
||||
- 当前线上版本
|
||||
- 当前工作版本
|
||||
- 是否存在未上线工作稿
|
||||
- 最近版本是否处于待审 / 已通过 / 已驳回状态
|
||||
|
||||
### 2.2 关键操作显性化
|
||||
|
||||
以下操作不能再隐藏在不明显的位置:
|
||||
|
||||
- 切换查看版本
|
||||
- 与线上版本对比
|
||||
- 查看完整流转
|
||||
- 从历史版本恢复
|
||||
|
||||
### 2.3 保持 OnlyOffice 是主角
|
||||
|
||||
该页面的核心仍然是 Excel 规则表。
|
||||
版本中心必须增强治理能力,但不能把主表格压缩成附属内容。
|
||||
|
||||
---
|
||||
|
||||
## 3. 推荐方案
|
||||
|
||||
采用:
|
||||
|
||||
> **左侧 OnlyOffice 主工作区 + 右侧版本中心 + 顶部显性入口 + 抽屉式详情**
|
||||
|
||||
这是比“单独开二级页签”更适合当前页面的方案,因为用户经常需要:
|
||||
|
||||
- 一边看表
|
||||
- 一边知道自己看的是什么版本
|
||||
- 一边进入版本对比或恢复
|
||||
|
||||
---
|
||||
|
||||
## 4. 页面整体布局
|
||||
|
||||
```text
|
||||
┌────────────────────────────────────────────────────────────────────┐
|
||||
│ 标题区:公司差旅费报销规则 │
|
||||
│ 线上版本 v1.0.5 已上线 工作版本 v1.0.6 待审核 │
|
||||
│ [下载 Excel] [上传表格] [版本对比] [查看流转] │
|
||||
├───────────────────────────────────────────────┬────────────────────┤
|
||||
│ │ 版本中心 │
|
||||
│ │ │
|
||||
│ │ ┌──────────────┐ │
|
||||
│ │ │ 线上版本 │ │
|
||||
│ │ │ v1.0.5 │ │
|
||||
│ │ └──────────────┘ │
|
||||
│ OnlyOffice │ ┌──────────────┐ │
|
||||
│ 规则表主工作区 │ │ 工作版本 │ │
|
||||
│ │ │ v1.0.6 │ │
|
||||
│ │ └──────────────┘ │
|
||||
│ │ │
|
||||
│ │ 最近版本 │
|
||||
│ │ v1.0.6 待审核 │
|
||||
│ │ v1.0.5 已上线 │
|
||||
│ │ v1.0.4 历史版本 │
|
||||
│ │ │
|
||||
│ │ 最近流转 │
|
||||
│ │ [查看完整流转] │
|
||||
└───────────────────────────────────────────────┴────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 顶部操作区设计
|
||||
|
||||
顶部必须保留并强化四个动作:
|
||||
|
||||
| 按钮 | 用途 |
|
||||
| --- | --- |
|
||||
| 下载 Excel | 下载当前预览版本 |
|
||||
| 上传表格 | 导入内容生成新工作稿 |
|
||||
| 版本对比 | 打开对比抽屉 |
|
||||
| 查看流转 | 打开流转抽屉 |
|
||||
|
||||
### 5.1 版本对比按钮
|
||||
|
||||
这是一级入口,不能只藏在版本列表里。
|
||||
默认行为:
|
||||
|
||||
- 基准版本:当前线上版本
|
||||
- 对比版本:当前工作版本
|
||||
|
||||
如果两者相同,则按钮仍可用,但进入后提示:
|
||||
|
||||
> 当前工作版本与线上版本一致,可选择其他历史版本进行比较。
|
||||
|
||||
### 5.2 查看流转按钮
|
||||
|
||||
用于进入当前规则的完整生命周期视图。
|
||||
不应只展示审计日志,而要展示“版本业务履历”。
|
||||
|
||||
---
|
||||
|
||||
## 6. 右侧版本中心设计
|
||||
|
||||
### 6.1 顶部双版本卡片
|
||||
|
||||
```text
|
||||
线上版本
|
||||
v1.0.5
|
||||
已上线
|
||||
|
||||
工作版本
|
||||
v1.0.6
|
||||
待审核
|
||||
```
|
||||
|
||||
#### 设计目的
|
||||
|
||||
用户进入页面后,最先要知道的是:
|
||||
|
||||
- **谁在线上**
|
||||
- **谁正在被编辑**
|
||||
|
||||
而不是先看一个无上下文的历史列表。
|
||||
|
||||
### 6.2 最近版本列表
|
||||
|
||||
每个版本项包含:
|
||||
|
||||
- 版本号
|
||||
- 生命周期状态
|
||||
- 创建时间
|
||||
- 变更说明
|
||||
- 操作入口
|
||||
|
||||
建议样式:
|
||||
|
||||
```text
|
||||
v1.0.6 待审核
|
||||
2026-05-18 09:12
|
||||
补充出差补助标准
|
||||
[查看] [与线上比]
|
||||
|
||||
v1.0.5 已上线
|
||||
2026-05-18 08:40
|
||||
新增补助页签
|
||||
[查看]
|
||||
|
||||
v1.0.4 历史版本
|
||||
2026-05-17 17:20
|
||||
修正住宿标准
|
||||
[查看] [恢复]
|
||||
```
|
||||
|
||||
#### 规则
|
||||
|
||||
- `查看`:切换当前预览版本
|
||||
- `与线上比`:直接以线上版本为基准进入对比
|
||||
- `恢复`:仅高级管理人员可见
|
||||
- 当前 `working_version` 不显示“恢复”
|
||||
|
||||
### 6.3 最近流转摘要
|
||||
|
||||
右侧版本中心底部展示最近 3 条流转:
|
||||
|
||||
```text
|
||||
最近流转
|
||||
09:12 曹笑竹 保存工作稿
|
||||
09:25 曹笑竹 提交审核
|
||||
10:08 顾承宇 审核通过
|
||||
[查看完整流转]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 版本流转时间线设计
|
||||
|
||||
## 7.1 入口
|
||||
|
||||
两个入口:
|
||||
|
||||
1. 顶部 `查看流转`
|
||||
2. 右侧版本中心底部 `查看完整流转`
|
||||
|
||||
## 7.2 容器
|
||||
|
||||
使用右侧宽抽屉,不使用小弹窗。
|
||||
原因:
|
||||
|
||||
- 时间线内容会逐步增长
|
||||
- 审核意见需要足够宽度展示
|
||||
- 后续可能接入版本说明、操作人、来源版本
|
||||
|
||||
## 7.3 时间线内容
|
||||
|
||||
时间线按时间倒序或正序展示,推荐默认正序:
|
||||
|
||||
```text
|
||||
● 2026-05-18 09:12
|
||||
v1.0.6 工作稿创建
|
||||
曹笑竹 保存工作稿
|
||||
变更说明:补充出差补助标准
|
||||
|
||||
● 2026-05-18 09:25
|
||||
提交审核
|
||||
曹笑竹 提交当前工作版本
|
||||
|
||||
● 2026-05-18 10:08
|
||||
审核通过
|
||||
顾承宇:口径已核对,可上线
|
||||
|
||||
○ 待正式上线
|
||||
```
|
||||
|
||||
如果版本来自恢复:
|
||||
|
||||
```text
|
||||
● 基于 v1.0.3 恢复生成 v1.0.7
|
||||
```
|
||||
|
||||
## 7.4 时间线事件类型
|
||||
|
||||
| 事件类型 | 说明 |
|
||||
| --- | --- |
|
||||
| `created` | 创建版本 |
|
||||
| `submitted` | 提交审核 |
|
||||
| `approved` | 审核通过 |
|
||||
| `rejected` | 驳回 |
|
||||
| `published` | 正式上线 |
|
||||
| `restored` | 基于历史版本恢复 |
|
||||
|
||||
---
|
||||
|
||||
## 8. 版本差异对比设计
|
||||
|
||||
## 8.1 入口
|
||||
|
||||
版本对比必须有两个入口:
|
||||
|
||||
1. 顶部一级按钮:`版本对比`
|
||||
2. 每个历史版本行内操作:`与线上比`
|
||||
|
||||
这样既满足“主动进入”,也满足“看到某个版本就顺手比较”。
|
||||
|
||||
## 8.2 容器
|
||||
|
||||
使用宽抽屉,推荐宽度:
|
||||
|
||||
- 桌面:页面宽度的 70% ~ 80%
|
||||
- 小屏:全屏
|
||||
|
||||
不建议用普通弹窗,因为:
|
||||
|
||||
- Excel 差异需要足够展示宽度
|
||||
- 版本选择器、摘要、表格都要共存
|
||||
|
||||
## 8.3 顶部区域
|
||||
|
||||
```text
|
||||
版本对比
|
||||
|
||||
基准版本 [v1.0.5 已上线 ▼]
|
||||
对比版本 [v1.0.6 待审核 ▼]
|
||||
```
|
||||
|
||||
默认值:
|
||||
|
||||
- `baseVersion = published_version`
|
||||
- `targetVersion = working_version`
|
||||
|
||||
## 8.4 差异摘要
|
||||
|
||||
优先先给决策信息,再给底层明细。
|
||||
|
||||
```text
|
||||
差异摘要
|
||||
- 修改 2 个工作表
|
||||
- 新增 1 个工作表
|
||||
- 修改 12 个单元格
|
||||
- 删除 2 行
|
||||
```
|
||||
|
||||
如果无差异:
|
||||
|
||||
```text
|
||||
两个版本内容一致,没有发现表格差异。
|
||||
```
|
||||
|
||||
## 8.5 差异详情
|
||||
|
||||
第一阶段优先支持 Excel 规则表:
|
||||
|
||||
| 工作表 | 位置 | 旧值 | 新值 | 类型 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 出差补助标准 | B4 | 75 | 90 | 修改 |
|
||||
| 差旅住宿费标准 | A106 | - | 新增城市 | 新增 |
|
||||
|
||||
后续可扩展:
|
||||
|
||||
- 仅看新增
|
||||
- 仅看删除
|
||||
- 仅看数值变化
|
||||
- 按工作表筛选
|
||||
|
||||
## 8.6 对比结果的业务语气
|
||||
|
||||
不要把页面做成“程序员 diff 工具”。
|
||||
它应该像制度审核页面:
|
||||
|
||||
- 先讲影响
|
||||
- 再讲位置
|
||||
- 最后给证据
|
||||
|
||||
---
|
||||
|
||||
## 9. 数据接口设计
|
||||
|
||||
## 9.1 时间线接口
|
||||
|
||||
建议新增:
|
||||
|
||||
```http
|
||||
GET /agent-assets/{asset_id}/version-timeline
|
||||
```
|
||||
|
||||
返回:
|
||||
|
||||
- 版本号
|
||||
- 事件类型
|
||||
- 操作人
|
||||
- 操作时间
|
||||
- 审核意见
|
||||
- 来源版本(如有)
|
||||
|
||||
## 9.2 对比接口
|
||||
|
||||
建议新增:
|
||||
|
||||
```http
|
||||
GET /agent-assets/{asset_id}/versions/compare?base_version=v1.0.5&target_version=v1.0.6
|
||||
```
|
||||
|
||||
返回:
|
||||
|
||||
- 基准版本
|
||||
- 对比版本
|
||||
- 工作表差异摘要
|
||||
- 单元格级差异明细
|
||||
|
||||
---
|
||||
|
||||
## 10. 视觉规范
|
||||
|
||||
### 10.1 颜色
|
||||
|
||||
沿用当前系统已有色彩,不引入新风格:
|
||||
|
||||
| 状态 | 建议色 |
|
||||
| --- | --- |
|
||||
| 已上线 | 绿色 |
|
||||
| 工作稿 | 蓝色 |
|
||||
| 待审核 | 橙色 |
|
||||
| 已驳回 | 红色 |
|
||||
| 历史版本 | 灰色 |
|
||||
|
||||
### 10.2 密度
|
||||
|
||||
- 右侧版本中心应为紧凑型信息面板
|
||||
- 不要使用过大的卡片间距
|
||||
- 不能明显压缩 OnlyOffice 主区域
|
||||
|
||||
### 10.3 交互反馈
|
||||
|
||||
- 可点击元素必须有 hover
|
||||
- 当前预览版本必须有 active 高亮
|
||||
- 抽屉打开后保留明确关闭按钮
|
||||
- 恢复操作必须二次确认
|
||||
|
||||
---
|
||||
|
||||
## 11. 推荐实施顺序
|
||||
|
||||
### 第一阶段
|
||||
|
||||
1. 顶部新增 `版本对比`、`查看流转`
|
||||
2. Excel 详情页改成:
|
||||
- 左侧 OnlyOffice
|
||||
- 右侧版本中心
|
||||
3. 右侧展示:
|
||||
- 线上版本
|
||||
- 工作版本
|
||||
- 最近 5 个版本
|
||||
- 最近 3 条流转
|
||||
|
||||
### 第二阶段
|
||||
|
||||
1. 实现版本流转抽屉
|
||||
2. 实现版本对比抽屉
|
||||
3. 补齐真实后端接口
|
||||
|
||||
### 第三阶段
|
||||
|
||||
1. 增加更细的工作表筛选
|
||||
2. 增加更多 diff 维度
|
||||
3. 增加版本差异导出能力
|
||||
|
||||
---
|
||||
|
||||
## 12. 本次开发目标
|
||||
|
||||
本次开发直接完成以下内容:
|
||||
|
||||
1. 规则详情页出现明确的版本中心
|
||||
2. 页面上出现明确的:
|
||||
- `版本对比`
|
||||
- `查看流转`
|
||||
3. 最近版本列表增加:
|
||||
- `查看`
|
||||
- `与线上比`
|
||||
- `恢复为工作稿`
|
||||
4. 版本流转抽屉可用
|
||||
5. 版本对比抽屉可用
|
||||
6. 对比结果至少支持 Excel 表格的:
|
||||
- 工作表新增 / 删除
|
||||
- 单元格新增 / 删除 / 修改
|
||||
|
||||
@@ -1,237 +0,0 @@
|
||||
# 规则版本治理方案
|
||||
|
||||
## 1. 背景
|
||||
|
||||
当前“任务规则中心”的规则资产只有一个 `current_version` 指针。
|
||||
它同时承担了三种含义:
|
||||
|
||||
1. 财务人员正在编辑的版本
|
||||
2. 审核中的候选版本
|
||||
3. 系统运行时真正生效的线上版本
|
||||
|
||||
这会直接带来三个问题:
|
||||
|
||||
- 财务人员一旦修改 Excel,最新内容就会立刻成为 `current_version`,容易被误解为已经正式生效
|
||||
- 审核、上线、回滚都围绕同一个指针转,权限边界不清晰
|
||||
- 如果误上线,虽然能切换历史版本,但缺少“线上版本”和“工作版本”分离后的安全缓冲
|
||||
|
||||
## 2. 设计目标
|
||||
|
||||
这次改造要解决的不是“多存几个历史版本”,而是建立一套可长期使用的规则治理机制:
|
||||
|
||||
1. 财务人员可以编辑规则,但编辑结果默认只是草稿
|
||||
2. 只有高级管理人员审核通过后,规则才能成为正式线上版本
|
||||
3. 系统运行时只能读取正式线上版本,不能读取草稿
|
||||
4. 前台要能清楚区分:
|
||||
- 当前线上版本
|
||||
- 当前工作版本
|
||||
- 最近 5 个历史版本
|
||||
5. 如果误操作上线,可以快速恢复,但恢复动作仍然要留下完整审计链
|
||||
|
||||
## 3. 核心模型
|
||||
|
||||
### 3.1 双指针版本模型
|
||||
|
||||
在规则资产上新增两个版本指针:
|
||||
|
||||
| 字段 | 含义 |
|
||||
| --- | --- |
|
||||
| `published_version` | 当前正式在线上生效的版本 |
|
||||
| `working_version` | 当前最新的工作稿 / 待审稿 |
|
||||
|
||||
兼容策略:
|
||||
|
||||
- 现有 `current_version` 暂时保留,用于兼容历史代码
|
||||
- 对规则资产来说,后续它只承担“当前工作版本”的兼容语义
|
||||
- 运行时逻辑不再读取 `current_version`,而是优先读取 `published_version`
|
||||
|
||||
### 3.2 版本状态
|
||||
|
||||
不额外在版本表中硬存一套容易失真的状态,而是根据“版本指针 + 最新审核记录”动态推导:
|
||||
|
||||
| 条件 | 版本状态 |
|
||||
| --- | --- |
|
||||
| `version == published_version` | 已上线 |
|
||||
| `version == working_version` 且无审核记录 | 草稿 |
|
||||
| `version == working_version` 且最新审核为 `pending` | 待审核 |
|
||||
| `version == working_version` 且最新审核为 `approved` | 已通过待上线 |
|
||||
| `version == working_version` 且最新审核为 `rejected` | 已驳回 |
|
||||
| 其他历史版本 | 历史版本 |
|
||||
|
||||
这样可以避免“版本状态”和“审核记录”两套数据互相打架。
|
||||
|
||||
## 4. 权限边界
|
||||
|
||||
| 角色 | 能力 |
|
||||
| --- | --- |
|
||||
| 财务人员 `finance` | 编辑工作稿、上传/导入 Excel、提交审核 |
|
||||
| 高级管理人员 `manager` / `admin` | 审核通过、驳回、正式发布、恢复历史版本 |
|
||||
| 其他普通员工 | 只读 |
|
||||
|
||||
### 4.1 财务人员
|
||||
|
||||
- 可以直接编辑当前 `working_version`
|
||||
- 每次保存自动生成新版本,并把它设为新的 `working_version`
|
||||
- 不能把草稿直接变成 `published_version`
|
||||
|
||||
### 4.2 高级管理人员
|
||||
|
||||
- 可以对 `working_version` 发起:
|
||||
- 审核通过
|
||||
- 驳回
|
||||
- 正式发布
|
||||
- 只有 `approved` 的工作版本才能发布
|
||||
|
||||
## 5. 发布与回滚流程
|
||||
|
||||
### 5.1 正常发布
|
||||
|
||||
1. 财务人员编辑并保存
|
||||
2. 系统生成新版本,例如 `v1.0.6`
|
||||
3. `working_version = v1.0.6`
|
||||
4. 财务人员提交审核
|
||||
5. 高级管理人员审核通过
|
||||
6. 高级管理人员点击“正式上线”
|
||||
7. `published_version = v1.0.6`
|
||||
8. 系统运行时切换到新版本
|
||||
|
||||
### 5.2 驳回
|
||||
|
||||
1. 财务人员提交审核
|
||||
2. 高级管理人员驳回
|
||||
3. 当前工作版本保留,但状态显示为“已驳回”
|
||||
4. 财务人员继续编辑,形成新的工作版本
|
||||
|
||||
### 5.3 恢复历史版本
|
||||
|
||||
不直接把 `published_version` 指回旧版本,而是采用“复制恢复”的方式:
|
||||
|
||||
1. 管理员在最近 5 个版本中选择一个历史版本
|
||||
2. 系统基于该历史版本内容生成一个新的恢复版本,例如 `v1.0.7`
|
||||
3. 新版本写入 `working_version`
|
||||
4. 审核通过后再正式发布
|
||||
|
||||
这么做的好处:
|
||||
|
||||
- 不会破坏历史链路
|
||||
- 每一次恢复都有明确的责任人与时间
|
||||
- 既能快速回滚,又保留审计闭环
|
||||
|
||||
## 6. 版本保留策略
|
||||
|
||||
### 6.1 前台展示
|
||||
|
||||
- 详情页固定展示最近 5 个版本
|
||||
- 每个版本显示:
|
||||
- 版本号
|
||||
- 状态
|
||||
- 创建人
|
||||
- 创建时间
|
||||
- 变更说明
|
||||
|
||||
### 6.2 后台保存
|
||||
|
||||
后台不能机械地“只保留 5 个版本”,否则可能把关键线上版本挤掉。
|
||||
建议策略:
|
||||
|
||||
1. 始终保留当前 `published_version`
|
||||
2. 始终保留当前 `working_version`
|
||||
3. 额外保留最近 5 个历史版本
|
||||
|
||||
这样既满足前台简洁,也能避免误删关键版本。
|
||||
|
||||
## 7. 前端交互
|
||||
|
||||
### 7.1 规则详情页顶部
|
||||
|
||||
展示两个醒目的版本标签:
|
||||
|
||||
- 当前线上版本
|
||||
- 当前工作版本
|
||||
|
||||
如果两者不同,需要明确提示:
|
||||
|
||||
> 当前存在尚未上线的工作稿,系统运行仍以线上版本为准。
|
||||
|
||||
### 7.2 编辑区
|
||||
|
||||
- 财务人员看到“可编辑工作稿”
|
||||
- 普通用户只读
|
||||
- 管理员可编辑,但主要职责仍是审核与发布
|
||||
|
||||
### 7.3 版本区
|
||||
|
||||
最近 5 个版本中每条都显示状态:
|
||||
|
||||
- 已上线
|
||||
- 草稿
|
||||
- 待审核
|
||||
- 已通过待上线
|
||||
- 已驳回
|
||||
- 历史版本
|
||||
|
||||
可执行操作:
|
||||
|
||||
- 查看
|
||||
- 基于该版本恢复
|
||||
- 对当前工作版本提交审核 / 审核 / 发布
|
||||
|
||||
## 8. 后端改造清单
|
||||
|
||||
1. `agent_assets`
|
||||
- 新增 `published_version`
|
||||
- 新增 `working_version`
|
||||
2. 兼容旧数据
|
||||
- 历史规则资产初始化时:
|
||||
- `published_version = current_version`
|
||||
- `working_version = current_version`
|
||||
3. 版本保存
|
||||
- 保存新版本后:
|
||||
- 只更新 `working_version`
|
||||
- `current_version` 同步为 `working_version` 以兼容旧逻辑
|
||||
4. 审核
|
||||
- 审核只针对 `working_version`
|
||||
5. 发布
|
||||
- 只允许把已审核通过的 `working_version` 推到 `published_version`
|
||||
6. 运行时
|
||||
- 只读取 `published_version`
|
||||
7. 回滚
|
||||
- 新增“基于历史版本恢复为新工作稿”的接口
|
||||
|
||||
## 9. 前端改造清单
|
||||
|
||||
1. 资产详情模型增加:
|
||||
- `publishedVersion`
|
||||
- `workingVersion`
|
||||
- 每个历史版本的派生状态
|
||||
2. 规则详情页展示:
|
||||
- 当前线上版本
|
||||
- 当前工作版本
|
||||
- 最近 5 个版本
|
||||
3. 操作权限拆分:
|
||||
- finance:编辑、上传、提交审核
|
||||
- manager/admin:审核、上线、恢复
|
||||
4. OnlyOffice 编辑逻辑:
|
||||
- 默认编辑工作版本
|
||||
- 历史版本只读
|
||||
5. 正式上线按钮:
|
||||
- 只有工作版本已审核通过时可用
|
||||
|
||||
## 10. 本次实现边界
|
||||
|
||||
本轮优先完成以下能力:
|
||||
|
||||
1. 规则版本双指针
|
||||
2. 财务角色可编辑工作稿
|
||||
3. 正式上线只切换 `published_version`
|
||||
4. 运行时只读取 `published_version`
|
||||
5. 最近 5 个版本展示
|
||||
6. 基于历史版本快速恢复为新工作稿
|
||||
|
||||
后续如需要,再继续补:
|
||||
|
||||
- 版本差异对比
|
||||
- 审核意见流转面板
|
||||
- 发布说明 / 审批单号
|
||||
- 定时生效
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
# 差旅申请后行程规划推荐
|
||||
|
||||
## 背景
|
||||
|
||||
用户完成差旅申请后,当前流程直接结束,交互偏机械。差旅申请本身已经包含地点、行程时间、出行方式、天数等信息,系统可以在申请提交成功后继续以对话形式询问是否需要行程规划。
|
||||
|
||||
## 目标
|
||||
|
||||
- 仅在差旅费用申请提交成功后追加一条对话式推荐。
|
||||
- 推荐内容应基于本次申请的已知字段,不要求用户重新输入地点和时间。
|
||||
- 用户同意后,在当前申请助手对话中生成规划建议。
|
||||
- 规划建议只提供交通时间窗口、酒店区域、待确认事项,不创建订单、不保存草稿、不调用真实订票接口。
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不接入真实火车、机票、酒店预订。
|
||||
- 不改变申请单提交和审批状态。
|
||||
- 不强制用户继续规划。
|
||||
|
||||
## 交互
|
||||
|
||||
1. 用户确认提交差旅申请。
|
||||
2. 系统返回申请提交成功结果。
|
||||
3. 系统追加一条轻量对话:询问是否需要行程规划。
|
||||
4. 用户点击“生成行程规划”后,系统在对话中给出推荐。
|
||||
5. 用户点击“暂不需要”后,系统简短确认,不再继续追问。
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# 差旅申请后行程规划推荐 TODO
|
||||
|
||||
- [x] 新增差旅规划推荐工具,按申请预览字段生成提示、动作和规划正文。
|
||||
- [x] 申请提交成功后追加规划推荐对话。
|
||||
- [x] 支持“生成行程规划”和“暂不需要”两个对话动作。
|
||||
- [x] 增加前端静态测试覆盖,防止回退成死板结束流程。
|
||||
- [x] 运行定向测试和前端构建验证。
|
||||
|
||||
@@ -1,746 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>X-Financial 个人工作台首页参考稿</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #f4f7fb;
|
||||
--panel: #ffffff;
|
||||
--line: #e4ebf3;
|
||||
--line-strong: #d6e1ed;
|
||||
--text: #0f172a;
|
||||
--muted: #64748b;
|
||||
--soft: #f8fbff;
|
||||
--green: #0f9f6e;
|
||||
--green-dark: #047857;
|
||||
--blue: #2563eb;
|
||||
--amber: #b7791f;
|
||||
--red: #d93025;
|
||||
--shadow: 0 18px 44px rgba(15, 23, 42, 0.08);
|
||||
font-family:
|
||||
"Microsoft YaHei UI", "Microsoft YaHei", "PingFang SC",
|
||||
"Noto Sans CJK SC", "Segoe UI", sans-serif;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
background:
|
||||
radial-gradient(circle at 18% 0%, rgba(16, 185, 129, 0.13), transparent 29%),
|
||||
radial-gradient(circle at 86% 12%, rgba(37, 99, 235, 0.10), transparent 24%),
|
||||
var(--bg);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.app {
|
||||
width: 1440px;
|
||||
min-height: 960px;
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
grid-template-columns: 84px 1fr;
|
||||
background: rgba(255, 255, 255, 0.42);
|
||||
}
|
||||
|
||||
.rail {
|
||||
padding: 20px 12px;
|
||||
background: #0f172a;
|
||||
color: #cbd5e1;
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.brand-mark {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
margin: 0 auto;
|
||||
border-radius: 14px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
background: linear-gradient(135deg, #10b981, #2563eb);
|
||||
color: white;
|
||||
font-weight: 900;
|
||||
letter-spacing: 0;
|
||||
box-shadow: 0 12px 26px rgba(16, 185, 129, 0.24);
|
||||
}
|
||||
|
||||
.nav {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
align-content: start;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
height: 56px;
|
||||
border-radius: 16px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: #94a3b8;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.nav-item.active {
|
||||
color: #ffffff;
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.main {
|
||||
padding: 22px 30px 30px;
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr;
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.topbar {
|
||||
height: 58px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.crumb strong {
|
||||
display: block;
|
||||
font-size: 22px;
|
||||
line-height: 1.2;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.crumb span {
|
||||
display: block;
|
||||
margin-top: 6px;
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.user-pill {
|
||||
height: 38px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 0 12px 0 6px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.74);
|
||||
color: #334155;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 999px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
background: #e8f7f0;
|
||||
color: var(--green-dark);
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: grid;
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.hero {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
min-height: 254px;
|
||||
display: grid;
|
||||
grid-template-columns: 230px minmax(0, 1fr);
|
||||
gap: 22px;
|
||||
padding: 24px 28px 22px 20px;
|
||||
border: 1px solid rgba(15, 159, 110, 0.16);
|
||||
border-radius: 18px;
|
||||
background:
|
||||
linear-gradient(135deg, rgba(247, 255, 251, 0.98), rgba(255, 255, 255, 0.98) 55%, rgba(244, 249, 255, 0.96)),
|
||||
var(--panel);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.hero::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
right: -110px;
|
||||
bottom: -138px;
|
||||
border-radius: 50%;
|
||||
background: rgba(16, 185, 129, 0.08);
|
||||
}
|
||||
|
||||
.bot-wrap {
|
||||
position: relative;
|
||||
min-height: 206px;
|
||||
display: flex;
|
||||
align-items: end;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.bot-wrap::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 18px;
|
||||
right: 18px;
|
||||
bottom: 4px;
|
||||
height: 58px;
|
||||
border-radius: 50%;
|
||||
background: rgba(16, 185, 129, 0.13);
|
||||
filter: blur(13px);
|
||||
}
|
||||
|
||||
.bot-wrap img {
|
||||
position: relative;
|
||||
width: 176px;
|
||||
height: auto;
|
||||
filter: drop-shadow(0 24px 26px rgba(15, 23, 42, 0.15));
|
||||
}
|
||||
|
||||
.hero-copy {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: grid;
|
||||
align-content: center;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
margin: 0;
|
||||
max-width: 860px;
|
||||
font-size: 27px;
|
||||
line-height: 1.32;
|
||||
font-weight: 850;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.hero-subtitle {
|
||||
margin: 0;
|
||||
max-width: 880px;
|
||||
color: #53637a;
|
||||
font-size: 14px;
|
||||
line-height: 1.68;
|
||||
}
|
||||
|
||||
.composer {
|
||||
min-height: 58px;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto auto;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 8px;
|
||||
border: 1px solid rgba(148, 163, 184, 0.28);
|
||||
border-radius: 15px;
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.74);
|
||||
}
|
||||
|
||||
.composer-text {
|
||||
padding: 0 12px;
|
||||
color: #94a3b8;
|
||||
font-size: 14px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.btn {
|
||||
height: 42px;
|
||||
border: 0;
|
||||
border-radius: 11px;
|
||||
padding: 0 16px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 800;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.btn.secondary {
|
||||
border: 1px solid rgba(15, 118, 110, 0.18);
|
||||
background: linear-gradient(180deg, #ffffff, #f2faf7);
|
||||
color: #0f766e;
|
||||
}
|
||||
|
||||
.btn.primary {
|
||||
background: linear-gradient(135deg, #10b981, #059669);
|
||||
color: #ffffff;
|
||||
box-shadow: 0 12px 24px rgba(16, 185, 129, 0.20);
|
||||
}
|
||||
|
||||
.intent-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.intent-card {
|
||||
min-height: 116px;
|
||||
padding: 18px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 16px;
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
box-shadow: 0 10px 28px rgba(15, 23, 42, 0.055);
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
align-content: start;
|
||||
}
|
||||
|
||||
.intent-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.intent-icon {
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
border-radius: 12px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
font-size: 14px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.intent-icon.green {
|
||||
background: #e8f7f0;
|
||||
color: var(--green-dark);
|
||||
}
|
||||
|
||||
.intent-icon.blue {
|
||||
background: #eff6ff;
|
||||
color: var(--blue);
|
||||
}
|
||||
|
||||
.intent-icon.amber {
|
||||
background: #fff7e6;
|
||||
color: var(--amber);
|
||||
}
|
||||
|
||||
.intent-icon.slate {
|
||||
background: #f1f5f9;
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
.intent-arrow {
|
||||
color: #94a3b8;
|
||||
font-size: 18px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.intent-card h3 {
|
||||
margin: 0;
|
||||
color: var(--text);
|
||||
font-size: 16px;
|
||||
line-height: 1.35;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.intent-card p {
|
||||
margin: -6px 0 0;
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.lower-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.panel {
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 16px;
|
||||
background: rgba(255, 255, 255, 0.94);
|
||||
box-shadow: 0 10px 26px rgba(15, 23, 42, 0.045);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.panel-head {
|
||||
min-height: 58px;
|
||||
padding: 0 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.panel-head h3 {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
line-height: 1.2;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.panel-head span {
|
||||
color: var(--green-dark);
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.rows {
|
||||
padding: 2px 20px;
|
||||
}
|
||||
|
||||
.row {
|
||||
min-height: 70px;
|
||||
display: grid;
|
||||
grid-template-columns: 42px minmax(0, 1fr) auto;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
border-top: 1px solid #edf2f7;
|
||||
}
|
||||
|
||||
.row:first-child {
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
.row-icon {
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
border-radius: 13px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
background: #eefaf4;
|
||||
color: var(--green-dark);
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.row-copy {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.row-copy strong {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
line-height: 1.35;
|
||||
font-weight: 800;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.row-copy small {
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.row-action {
|
||||
min-width: 78px;
|
||||
height: 34px;
|
||||
border: 1px solid rgba(16, 185, 129, 0.26);
|
||||
border-radius: 999px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: var(--green-dark);
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
background: #f6fffb;
|
||||
}
|
||||
|
||||
.amount {
|
||||
font-size: 18px;
|
||||
font-weight: 900;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.status {
|
||||
margin-left: 10px;
|
||||
min-width: 92px;
|
||||
height: 30px;
|
||||
border-radius: 999px;
|
||||
display: inline-grid;
|
||||
place-items: center;
|
||||
background: #eff6ff;
|
||||
color: var(--blue);
|
||||
font-size: 12px;
|
||||
font-weight: 850;
|
||||
}
|
||||
|
||||
.wide-panel {
|
||||
display: grid;
|
||||
grid-template-columns: 1.25fr 1fr;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.policy-list {
|
||||
border-left: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.mini-section {
|
||||
min-height: 178px;
|
||||
}
|
||||
|
||||
.mini-section .panel-head {
|
||||
border-bottom: 0;
|
||||
min-height: 50px;
|
||||
}
|
||||
|
||||
.metric-strip {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 12px;
|
||||
padding: 0 20px 20px;
|
||||
}
|
||||
|
||||
.metric {
|
||||
min-height: 88px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 14px;
|
||||
background: var(--soft);
|
||||
padding: 14px;
|
||||
}
|
||||
|
||||
.metric strong {
|
||||
display: block;
|
||||
font-size: 24px;
|
||||
line-height: 1;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.metric span {
|
||||
display: block;
|
||||
margin-top: 9px;
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
@media (max-width: 1000px) {
|
||||
.app {
|
||||
width: 100%;
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.rail {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.main {
|
||||
padding: 18px;
|
||||
}
|
||||
|
||||
.hero,
|
||||
.lower-grid,
|
||||
.wide-panel {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.intent-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.policy-list {
|
||||
border-left: 0;
|
||||
border-top: 1px solid var(--line);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="app">
|
||||
<aside class="rail" aria-label="侧边导航">
|
||||
<div class="brand-mark">XF</div>
|
||||
<nav class="nav">
|
||||
<div class="nav-item active">工作台</div>
|
||||
<div class="nav-item">申请</div>
|
||||
<div class="nav-item">审批</div>
|
||||
<div class="nav-item">规则</div>
|
||||
<div class="nav-item">知识</div>
|
||||
</nav>
|
||||
<div class="nav-item">设置</div>
|
||||
</aside>
|
||||
|
||||
<section class="main">
|
||||
<header class="topbar">
|
||||
<div class="crumb">
|
||||
<strong>个人工作台</strong>
|
||||
<span>把费用申请、报销处理、进度查询和制度问答集中到一个入口。</span>
|
||||
</div>
|
||||
<div class="user-pill">
|
||||
<span class="avatar">A</span>
|
||||
<span>admin</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="content">
|
||||
<article class="hero">
|
||||
<div class="bot-wrap">
|
||||
<img src="../../../web/src/assets/robot-helper.png" alt="" />
|
||||
</div>
|
||||
|
||||
<div class="hero-copy">
|
||||
<h1 class="hero-title">嗨,admin,描述您想做的事,AI 会直接帮您处理</h1>
|
||||
<p class="hero-subtitle">
|
||||
我会自动识别您的意图,协助完成费用申请、报销、查询和制度问答等业务工作,
|
||||
并把事情推进到可执行的下一步。
|
||||
</p>
|
||||
|
||||
<div class="composer">
|
||||
<div class="composer-text">例如:帮我查一下上周提交的差旅报销到哪一步了</div>
|
||||
<button class="btn secondary">上传票据</button>
|
||||
<button class="btn primary">开始处理</button>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<section class="intent-grid" aria-label="业务入口">
|
||||
<article class="intent-card">
|
||||
<div class="intent-top">
|
||||
<span class="intent-icon green">申</span>
|
||||
<span class="intent-arrow">→</span>
|
||||
</div>
|
||||
<h3>费用申请</h3>
|
||||
<p>发起招待、差旅、采购等费用事项</p>
|
||||
</article>
|
||||
|
||||
<article class="intent-card">
|
||||
<div class="intent-top">
|
||||
<span class="intent-icon blue">报</span>
|
||||
<span class="intent-arrow">→</span>
|
||||
</div>
|
||||
<h3>报销处理</h3>
|
||||
<p>上传票据,生成草稿并核对材料</p>
|
||||
</article>
|
||||
|
||||
<article class="intent-card">
|
||||
<div class="intent-top">
|
||||
<span class="intent-icon amber">查</span>
|
||||
<span class="intent-arrow">→</span>
|
||||
</div>
|
||||
<h3>进度查询</h3>
|
||||
<p>查询单据状态、审批节点和到账情况</p>
|
||||
</article>
|
||||
|
||||
<article class="intent-card">
|
||||
<div class="intent-top">
|
||||
<span class="intent-icon slate">问</span>
|
||||
<span class="intent-arrow">→</span>
|
||||
</div>
|
||||
<h3>制度问答</h3>
|
||||
<p>咨询标准、附件要求和可报销边界</p>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="lower-grid">
|
||||
<article class="panel">
|
||||
<header class="panel-head">
|
||||
<h3>报销待办</h3>
|
||||
<span>查看全部</span>
|
||||
</header>
|
||||
<div class="rows">
|
||||
<div class="row">
|
||||
<span class="row-icon">招</span>
|
||||
<div class="row-copy">
|
||||
<strong>业务招待报销建议补参与人员</strong>
|
||||
<small>AI 建议:补充客户单位、客户人数、我方陪同人员</small>
|
||||
</div>
|
||||
<span class="row-action">去补充</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="row-icon">旅</span>
|
||||
<div class="row-copy">
|
||||
<strong>差旅报销单待提交</strong>
|
||||
<small>补齐出发交通,可直接生成报销单</small>
|
||||
</div>
|
||||
<span class="row-action">继续填</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="row-icon">票</span>
|
||||
<div class="row-copy">
|
||||
<strong>有 5 张票据未关联报销单</strong>
|
||||
<small>其中 3 张疑似交通费,可合并生成交通报销</small>
|
||||
</div>
|
||||
<span class="row-action">去整理</span>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="panel">
|
||||
<header class="panel-head">
|
||||
<h3>报销进度</h3>
|
||||
<span>查看全部</span>
|
||||
</header>
|
||||
<div class="rows">
|
||||
<div class="row">
|
||||
<span class="row-icon">差</span>
|
||||
<div class="row-copy">
|
||||
<strong>差旅报销</strong>
|
||||
<small>提交时间:2026-05-03</small>
|
||||
</div>
|
||||
<div><span class="amount">¥3,280</span><span class="status">主管审批中</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="row-icon">交</span>
|
||||
<div class="row-copy">
|
||||
<strong>交通报销</strong>
|
||||
<small>提交时间:2026-05-02</small>
|
||||
</div>
|
||||
<div><span class="amount">¥126</span><span class="status">财务复核中</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span class="row-icon">采</span>
|
||||
<div class="row-copy">
|
||||
<strong>办公采购</strong>
|
||||
<small>提交时间:2026-05-01</small>
|
||||
</div>
|
||||
<div><span class="amount">¥458</span><span class="status">已到账</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="panel wide-panel">
|
||||
<article class="mini-section">
|
||||
<header class="panel-head">
|
||||
<h3>智能概览</h3>
|
||||
<span>本月</span>
|
||||
</header>
|
||||
<div class="metric-strip">
|
||||
<div class="metric"><strong>12</strong><span>待处理事项</span></div>
|
||||
<div class="metric"><strong>86%</strong><span>材料完整率</span></div>
|
||||
<div class="metric"><strong>2.4天</strong><span>平均审批时长</span></div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="mini-section policy-list">
|
||||
<header class="panel-head">
|
||||
<h3>最新报销制度</h3>
|
||||
<span>查看全部</span>
|
||||
</header>
|
||||
<div class="rows">
|
||||
<div class="row">
|
||||
<span class="row-icon">规</span>
|
||||
<div class="row-copy">
|
||||
<strong>差旅报销管理办法(2026版)</strong>
|
||||
<small>更新住宿标准与交通等级规则</small>
|
||||
</div>
|
||||
<span class="row-action">查看</span>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 123 KiB |
154
document/development/半年报销模拟数据/CONCEPT.md
Normal file
154
document/development/半年报销模拟数据/CONCEPT.md
Normal file
@@ -0,0 +1,154 @@
|
||||
# 半年报销模拟数据概念文档
|
||||
|
||||
## 功能一句话
|
||||
|
||||
为本地演示环境生成 2026 年上半年公司报销、预算和员工组织样本,让财务看板与预算中心能直接呈现半年经营分析效果。
|
||||
|
||||
## 背景与问题
|
||||
|
||||
当前容器数据库已有员工与预算基础表,但报销样本很少,无法观察半年维度的费用趋势、部门支出结构、预算使用率和风险预警效果。用户希望把公司人数扩充到 100 人,并模拟半年报销数据,用于查看整体分析和预算管控效果。
|
||||
|
||||
现状只读检查结果:
|
||||
|
||||
- `employees=82`
|
||||
- `expense_claims=3`
|
||||
- `budget_allocations=240`
|
||||
- `budget_transactions=241`
|
||||
- `risk_observations=0`
|
||||
- 尚无 `SIM2026` 员工、`SIM-EXP-2026` 报销单和 `SIM-BUD-2026` 预算数据。
|
||||
|
||||
## 目标与非目标
|
||||
|
||||
目标:
|
||||
|
||||
- 把本地演示公司员工补齐到 100 人,不删除已有员工。
|
||||
- 生成 2026 年 1 月到 6 月的报销单、报销明细和风险观察样本。
|
||||
- 生成或复用预算额度,并写入预算核销台账,让预算中心能看到真实使用率、预警和超支。
|
||||
- 保证脚本默认 dry-run,只有显式 `--apply` 才写数据库。
|
||||
- 生成完成后能用容器内 DB 统计和真实 API 返回值验证。
|
||||
|
||||
非目标:
|
||||
|
||||
- 不接入真实生产 API,不导入真实个人敏感数据。
|
||||
- 不删除或重置用户已有数据;如未来需要清理模拟数据,应另走显式确认。
|
||||
- 不改造预算中心、财务看板和报销审批页面结构。
|
||||
- 不把模拟数据写入启动流程,避免每次启动自动膨胀数据。
|
||||
|
||||
## 用户与场景
|
||||
|
||||
- 财务负责人:查看半年费用趋势、待审批金额、风险数量和 SLA。
|
||||
- 预算管理者:查看部门和费用科目的预算使用率、预警线和剩余额度。
|
||||
- 产品演示者:用 100 人组织规模演示智能费控、预算中心和分析看板的联动。
|
||||
|
||||
## 功能能力
|
||||
|
||||
### 输入
|
||||
|
||||
- 目标员工数:默认 100。
|
||||
- 模拟窗口:默认 `2026-01-01` 到 `2026-06-30`。
|
||||
- 随机种子:固定值,确保样本可复现。
|
||||
- 执行模式:默认 dry-run,`--apply` 写入数据库。
|
||||
|
||||
### 输出
|
||||
|
||||
- 新增员工:只补齐缺口,员工编号前缀 `SIM2026`。
|
||||
- 新增报销单:编号前缀 `SIM-EXP-2026`。
|
||||
- 新增明细:按报销单生成 1 到 3 条费用明细。
|
||||
- 新增预算额度:编号前缀 `SIM-BUD-2026`,按部门、季度、费用科目覆盖差旅、招待、办公和通信。
|
||||
- 新增预算交易:编号前缀 `SIM-BTX-2026`,对已通过、待付款、已付款和完成状态写入 `consume` 台账,对待审批状态写入 `reserve` 台账。
|
||||
- 新增风险观察:编号前缀 `SIM-RISK-2026`,用于财务看板风险混合和异常数统计。
|
||||
|
||||
### 边界
|
||||
|
||||
- 如果员工数已经大于等于 100,只新增 0 人,不删除已有员工。
|
||||
- 如果同编号模拟数据已存在,脚本跳过,保证重复执行不重复膨胀。
|
||||
- 预算使用率通过交易台账计算,不直接改写预算余额字段。
|
||||
- 预算超支样本允许存在,用于展示预算效果和预警,但需要控制比例,避免所有部门都显示异常。
|
||||
|
||||
## 方案设计
|
||||
|
||||
### 后端脚本
|
||||
|
||||
新增独立服务模块:
|
||||
|
||||
- `demo_company_simulation_seed.py`:封装模拟数据规划、dry-run 统计和 apply 写入。
|
||||
|
||||
新增命令脚本:
|
||||
|
||||
- `seed_half_year_expense_demo.py`:解析参数并调用服务模块。
|
||||
|
||||
### 数据策略
|
||||
|
||||
- 组织:复用现有 `OrganizationUnit`,优先使用部门节点和成本中心。
|
||||
- 员工:补齐到 100 人,按部门规模权重分配,职级覆盖 P3-P8。
|
||||
- 报销单:按员工、月份、费用类型生成,低频员工 1-2 单,高频角色 4-8 单。
|
||||
- 风险:约 12%-18% 的报销单带风险标记和 `RiskObservation`。
|
||||
- 预算:按部门、季度、科目创建模拟预算额度,Q2 相比 Q1 有 8%-18% 增长,部分市场、技术部门科目接近 80% 预警线。
|
||||
|
||||
### 运行命令
|
||||
|
||||
```bash
|
||||
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-main \
|
||||
/tmp/x-financial-server-venv/bin/python server/scripts/seed_half_year_expense_demo.py
|
||||
```
|
||||
|
||||
写入时使用:
|
||||
|
||||
```bash
|
||||
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-main \
|
||||
/tmp/x-financial-server-venv/bin/python server/scripts/seed_half_year_expense_demo.py --apply
|
||||
```
|
||||
|
||||
## 算法与公式
|
||||
|
||||
### 员工缺口
|
||||
|
||||
$$
|
||||
new\_employees = \max(target\_employees - current\_employees,\ 0)
|
||||
$$
|
||||
|
||||
### 报销金额
|
||||
|
||||
每类费用按基础金额、部门系数、职级系数和月度季节系数生成:
|
||||
|
||||
$$
|
||||
claim\_amount = base\_amount(type) \times dept\_factor \times grade\_factor \times month\_factor \times noise
|
||||
$$
|
||||
|
||||
### 预算使用率
|
||||
|
||||
预算中心沿用现有计算口径:
|
||||
|
||||
$$
|
||||
usage\_rate = \frac{reserved\_amount + consumed\_amount}{original\_amount + adjusted\_amount} \times 100
|
||||
$$
|
||||
|
||||
### 风险样本概率
|
||||
|
||||
风险概率按金额分位和预算压力提升:
|
||||
|
||||
$$
|
||||
risk\_probability = base\_risk + amount\_boost + budget\_pressure\_boost
|
||||
$$
|
||||
|
||||
## 测试方案
|
||||
|
||||
- 单元测试:在 SQLite 内存库里验证 dry-run、员工补齐、幂等写入和预算交易统计。
|
||||
- 容器验证:在 `x-financial-main` 内运行定向测试,单次不超过 60s。
|
||||
- 运行时验证:执行 dry-run 后检查计划数量;执行 apply 前必须人工确认。
|
||||
- API 验证:写入后请求财务看板和预算汇总接口,确认 JSON 中员工、报销、预算使用率和风险指标有数据。
|
||||
|
||||
## 指标与验收
|
||||
|
||||
- 员工总数达到 100。
|
||||
- `SIM-EXP-2026` 半年报销单不少于 300 单。
|
||||
- 预算汇总接口返回 Q1、Q2 趋势,且至少有 1 条预算预警。
|
||||
- 财务看板 `has_real_data=true`,风险数、费用分类、部门排行和预算摘要均非空。
|
||||
- 重复执行脚本不会新增重复模拟数据。
|
||||
|
||||
## 风险与开放问题
|
||||
|
||||
- 批量写入数据库属于高风险操作,执行 `--apply` 前必须获得用户明确确认。
|
||||
- 如果当前数据库已有大量非模拟员工,脚本不会删除员工来凑精确 100 人,只保证不少于目标数。
|
||||
- 财务看板趋势接口当前最多按 90 天标签解析;半年分析主要依赖预算中心 Q1/Q2 趋势和自定义日期范围。
|
||||
- 如果后续要支持页面一键生成,需要另行设计权限、审计和清理机制。
|
||||
23
document/development/半年报销模拟数据/TODO.md
Normal file
23
document/development/半年报销模拟数据/TODO.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# 半年报销模拟数据 TODO
|
||||
|
||||
## 调研与契约
|
||||
|
||||
- [x] [CONCEPT: 背景与问题] 读取员工、报销、预算和财务看板现有模型,确认模拟数据要写入 `employees`、`expense_claims`、`expense_claim_items`、`budget_allocations`、`budget_transactions`、`budget_reservations` 和 `risk_observations`。
|
||||
- [x] [CONCEPT: 背景与问题] 在 `x-financial-main` 容器内完成只读规模检查,当前员工 82 人、报销单 3 单、模拟前缀数据为 0。
|
||||
- [x] [CONCEPT: 方案设计] 明确脚本默认 dry-run,批量写入必须使用 `--apply` 并先得到用户确认。
|
||||
|
||||
## 数据生成
|
||||
|
||||
- [x] [CONCEPT: 数据策略] 新增模拟数据服务模块,封装员工、预算、报销、明细、风险观察的生成逻辑。证据:`demo_company_simulation_seed.py` 与 `demo_company_simulation_catalog.py`。
|
||||
- [x] [CONCEPT: 输入] 新增命令脚本,支持 `--target-employees`、`--start-date`、`--months`、`--seed`、`--apply`。证据:`seed_half_year_expense_demo.py`。
|
||||
- [x] [CONCEPT: 边界] 实现幂等逻辑:已存在的 `SIM2026`、`SIM-EXP-2026` 和 `SIM-BUD-2026` 数据不重复创建。证据:`test_half_year_simulation_preview_and_apply_are_idempotent`。
|
||||
- [x] [CONCEPT: 预算使用率] 通过 `BudgetTransaction` 和 `BudgetReservation` 形成预算使用效果,不直接改余额。证据:`test_half_year_simulation_feeds_budget_summary`。
|
||||
|
||||
## 验证
|
||||
|
||||
- [x] [CONCEPT: 测试方案] 新增定向单元测试,覆盖 dry-run、apply、员工补齐和幂等性。证据:`server/tests/test_demo_company_simulation_seed.py`。
|
||||
- [x] [CONCEPT: 测试方案] 在容器中以 60s 超时运行定向测试。证据:`pytest -q server/tests/test_demo_company_simulation_seed.py` 通过,2 passed。
|
||||
- [x] [CONCEPT: 运行命令] 执行 dry-run,输出计划写入规模。证据:dry-run 计划新增 18 名员工、495 张报销单、855 条明细、34 个预算池、459 条预算交易、83 条预占、55 条风险观察。
|
||||
- [x] [CONCEPT: 风险与开放问题] 获得用户确认后执行 `--apply` 写入本地数据库。证据:`seed_half_year_expense_demo.py --apply` 成功写入。
|
||||
- [x] [CONCEPT: 指标与验收] 用容器内 DB 统计确认员工数、模拟报销单、预算交易和风险观察。证据:员工 100 人,模拟报销 495 单、预算交易 459 条、风险观察 55 条。
|
||||
- [x] [CONCEPT: 指标与验收] 用真实 API 验证财务看板与预算汇总 JSON 已出现半年模拟数据效果。证据:预算汇总 API 返回 `warning_count=10`、`over_budget_count=3`;财务看板 API 返回 `has_real_data=true`、`riskCount=57`。
|
||||
424
document/development/小财管家/CONCEPT.md
Normal file
424
document/development/小财管家/CONCEPT.md
Normal file
@@ -0,0 +1,424 @@
|
||||
# 小财管家
|
||||
|
||||
## 功能一句话
|
||||
|
||||
小财管家是首页统一财务任务入口,负责把用户的自然语言和附件拆解为多个可确认、可追踪、可分派的申请与报销任务,再调用现有申请助手和报销助手完成执行闭环。
|
||||
|
||||
## 背景与问题
|
||||
|
||||
当前个人工作台已经提供首页输入框,并能通过本体解析把一句话路由到申请、报销、预算或知识等单一会话。这个能力适合单意图,但用户真实表达经常是多任务组合,例如同时包含出差申请、昨日交通费报销、历史出差费用报销以及多张附件。
|
||||
|
||||
现有问题:
|
||||
|
||||
- 首页输入框当前会收敛为一个 `sessionType`,无法保留多任务计划。
|
||||
- 申请助手和报销助手已经具备单任务核对能力,但缺少上层任务拆解、归集和跨助手分派。
|
||||
- 附件上传后主要进入当前会话,缺少面向多任务的自动归集建议。
|
||||
- 财务动作需要确认后才能入库、绑定或提交,不能让大模型直接执行高风险动作。
|
||||
- 新增字段必须尊重本体字段,不能因为小财管家新增一套业务字段。
|
||||
|
||||
## 目标与非目标
|
||||
|
||||
### 目标
|
||||
|
||||
- 首页输入框定位为“小财管家”,作为用户默认财务任务入口。
|
||||
- 用户提交自然语言和附件后,先展示小财管家的任务识别与附件归集过程。
|
||||
- 支持把一句话拆成多个任务,第一版只验证费用申请和费用报销。
|
||||
- 支持多附件按费用场景、时间、地点、任务线索形成归集建议。
|
||||
- 遇到创建申请单、创建报销草稿、附件绑定、提交审批等动作时必须等待用户确认。
|
||||
- 保留现有申请助手和报销助手能力,小财管家只做上层编排和分派。
|
||||
- 外层意图识别必须优先使用大模型 function calling 输出结构化任务计划,规则逻辑只作为模型不可用或结构不合法时的兜底。
|
||||
- 前端展示“意图识别智能体”过程气泡,并用流式状态逐步呈现,不暴露模型内部推理链。
|
||||
- 所有业务字段先进入本体字段归一化,再进入下游助手、草稿、风险规则和持久化。
|
||||
|
||||
### 非目标
|
||||
|
||||
- 第一版不做万能智能体,不覆盖预算、审批、知识问答等全部场景。
|
||||
- 第一版不引入 LangChain 或 LangGraph,先复用项目内运行时模型配置和 OpenAI-compatible function calling 契约。
|
||||
- 第一版不自动提交审批,不绕过用户确认。
|
||||
- 第一版不新增业务语义字段;只新增任务编排态字段。
|
||||
- 第一版不重写申请助手、报销助手和现有 Orchestrator。
|
||||
|
||||
## 用户与场景
|
||||
|
||||
### 目标用户
|
||||
|
||||
- 普通员工:在首页一次性描述申请、报销和附件处理诉求。
|
||||
- 财务人员:查看任务拆解、附件归集和用户确认链路是否可追溯。
|
||||
- 审批/管理角色:后续可扩展为审批待办和预算提醒编排,但不进入第一版。
|
||||
|
||||
### 核心场景
|
||||
|
||||
用户在首页输入:
|
||||
|
||||
```text
|
||||
我想要申请7月2日去北京出差,辅助北京供电局的税务审核任务,并且我要报销昨天的交通费,还需要报销6月3日出差去上海的费用
|
||||
```
|
||||
|
||||
系统处理:
|
||||
|
||||
1. 小财管家识别到三条候选任务。
|
||||
2. 将“昨天”按客户端日期解析为明确日期,例如 2026-06-03。
|
||||
3. 将“7月2日去北京出差”归为费用申请任务。
|
||||
4. 将“昨天的交通费”和“6月3日去上海出差费用”归为费用报销任务。
|
||||
5. 如果用户同时上传附件,系统先识别附件场景,再建议归集到对应任务。
|
||||
6. 需要创建申请单或报销草稿时,向用户展示核对摘要和确认动作。
|
||||
|
||||
## 功能能力
|
||||
|
||||
### 1. 任务识别与拆分
|
||||
|
||||
任务识别主链路是“小财管家意图识别智能体”:
|
||||
|
||||
1. 后端读取系统设置中的主模型/备模型运行时配置。
|
||||
2. 将用户话术、客户端日期、附件元信息、上下文和 canonical ontology field 列表传入模型。
|
||||
3. 通过强制 function calling 调用 `submit_steward_intent_plan`。
|
||||
4. 模型只能返回结构化参数:`thinking_events`、`tasks`、`attachment_groups`。
|
||||
5. 服务端再次校验:任务类型只能是 `expense_application` / `reimbursement`,业务字段只能是 canonical ontology fields,附件名必须来自本次上传。
|
||||
6. 如果模型未配置、调用失败、未返回工具调用或结构不合法,才切换到规则兜底,并在过程摘要中标记兜底原因。
|
||||
|
||||
输入:
|
||||
|
||||
- 用户自然语言 `message`
|
||||
- 附件元信息 `attachments`
|
||||
- 当前用户、部门、角色、客户端时间
|
||||
- 已有会话上下文,可选
|
||||
|
||||
输出:
|
||||
|
||||
- `plan_id`:本次小财管家计划 ID
|
||||
- `tasks`:多个任务条目
|
||||
- `thinking_events`:面向用户展示的过程摘要
|
||||
- `confirmation_groups`:需要用户确认的动作集合
|
||||
- `attachment_groups`:附件归集建议
|
||||
|
||||
任务条目包含:
|
||||
|
||||
- `task_id`:编排态任务 ID
|
||||
- `task_type`:`expense_application` 或 `reimbursement`
|
||||
- `assigned_agent`:`application_assistant` 或 `reimbursement_assistant`
|
||||
- `title`:任务标题
|
||||
- `summary`:任务摘要
|
||||
- `status`:`planned`、`needs_confirmation`、`ready_to_delegate`、`delegated`、`completed`、`blocked`
|
||||
- `confidence`:识别置信度
|
||||
- `ontology_fields`:归一化后的本体字段
|
||||
- `missing_fields`:缺失字段
|
||||
- `confirmation_required`:是否需要确认后执行
|
||||
|
||||
### 2. 附件归集
|
||||
|
||||
附件归集基于以下信号:
|
||||
|
||||
- 附件类型:发票、火车票、机票、酒店票、付款截图、招待票据等。
|
||||
- 费用场景:差旅、交通、招待、住宿、其他。
|
||||
- 日期:票据日期是否匹配任务时间。
|
||||
- 地点:票据地点是否匹配任务地点。
|
||||
- 金额:是否能参与报销草稿。
|
||||
- 置信度:低置信度必须提示用户核对。
|
||||
|
||||
输出示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"group_id": "ag_travel_001",
|
||||
"target_task_id": "task_reim_002",
|
||||
"scene": "travel",
|
||||
"scene_label": "差旅费用",
|
||||
"attachment_names": ["上海高铁票.jpg", "上海酒店发票.pdf", "出租车票.png"],
|
||||
"excluded_attachment_names": ["客户招待发票.jpg"],
|
||||
"confidence": 0.86,
|
||||
"confirmation_required": true
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 用户确认
|
||||
|
||||
必须确认的动作:
|
||||
|
||||
- 创建费用申请单。
|
||||
- 创建报销草稿。
|
||||
- 将附件归集并绑定到某一任务。
|
||||
- 将附件关联到已有报销草稿。
|
||||
- 提交审批。
|
||||
- 修改已有草稿字段。
|
||||
|
||||
小财管家的确认动作采用“下一步优先”策略:
|
||||
|
||||
- 同一个计划里同时存在申请和报销时,前端只展示当前下一步主动作,不一次性摊开全部确认按钮。
|
||||
- 下一步优先级为:费用申请单创建 > 报销单填写 > 附件归集确认。
|
||||
- 小财管家先思考和分析,说明下一步将要做的行为;用户输入“确定”或点击确认后,才进入行动。
|
||||
- 行动完成后重新检查剩余任务队列,继续进入“思考 -> 分析 -> 等待确认 -> 行动”的循环。
|
||||
- 申请任务完成后,再把剩余报销任务作为后续任务引导到报销助手。
|
||||
- 附件归集不作为第一屏主动作抢占申请流程;当进入报销任务时,相关附件随报销上下文带入。
|
||||
|
||||
小财管家必须维护运行时任务上下文,而不是把每次用户输入都当成新的独立意图。上下文至少包含:
|
||||
|
||||
- 当前任务:正在处理的申请或报销任务。
|
||||
- 剩余任务:已拆解但尚未处理的任务队列。
|
||||
- 已完成任务:已经形成申请单、报销草稿、附件归集或提交动作的任务。
|
||||
- 等待动作:当前正在等待用户补字段、确认核对表、确认提交审批或继续下一项。
|
||||
- 最近结构化结果:当前申请核对表、报销核对结果、附件归集建议等。
|
||||
|
||||
用户输入“确认”“无误”“可以提交”等文本时,小财管家必须先匹配当前等待动作;如果当前等待的是申请单提交确认,就提交当前申请单;如果当前等待的是继续下一项,就进入剩余任务队列中的下一项;如果当前核对表仍有缺字段,则提示补字段。只有没有可匹配上下文时,才重新进入任务规划。
|
||||
|
||||
上述匹配不应主要依赖前端关键词规则。第一版应新增“小财管家运行时决策智能体”,由后端 function calling 接收 `runtime_state` 和用户当前输入,返回结构化 `next_action`:
|
||||
|
||||
- `submit_current_application`:确认当前申请核对表并提交至审批。
|
||||
- `continue_next_task`:当前任务已完成,继续剩余任务队列中的下一项。
|
||||
- `fill_current_slot`:用户补充了当前等待字段。
|
||||
- `ask_user`:当前信息不足,需要继续追问。
|
||||
- `plan_new_tasks`:当前没有可匹配上下文,重新进入任务规划。
|
||||
- `cancel_current_action` / `no_op`:取消或不执行当前动作。
|
||||
|
||||
前端只执行模型返回的结构化动作,并做安全校验:例如申请核对表必须 `readyToSubmit` 才能提交,已提交消息必须标记避免重复提交,缺字段时必须追问。本地规则只允许作为模型失败后的保守兜底,不作为主判断来源。
|
||||
|
||||
可以自动执行的动作:
|
||||
|
||||
- 任务拆解。
|
||||
- 本体字段归一化。
|
||||
- 附件分类。
|
||||
- 缺失字段检查。
|
||||
- 风险和规则预审。
|
||||
- 生成确认摘要。
|
||||
|
||||
### 4. 流式过程摘要
|
||||
|
||||
前端展示的是“意图识别智能体”的过程摘要,不是模型内部推理链;过程摘要必须独立于最终回复正文展示。过程摘要必须围绕业务理解展开,例如用户说了什么、被拆成哪些申请/报销任务、已识别哪些业务要素、还缺少哪些关键条件、为什么需要向用户追问。不能只展示“接收确认、协调能力、准备输出”等系统执行日志。
|
||||
|
||||
示例:
|
||||
|
||||
```text
|
||||
正在识别用户输入中的财务事项...
|
||||
已识别到 3 个候选任务。
|
||||
正在按时间、地点和费用场景核对附件...
|
||||
发现 3 张附件疑似属于差旅费用,1 张附件需要单独处理。
|
||||
等待你确认后,我再创建申请单或报销草稿。
|
||||
```
|
||||
|
||||
第一版通过 `POST /steward/plans/stream` 返回 `application/x-ndjson` 流式事件:
|
||||
|
||||
- `thinking`:逐条追加到系统回复气泡上方的独立“意图识别智能体”折叠气泡。
|
||||
- `plan`:返回完整任务计划后,再渲染最终正文、任务卡片、附件归集和确认动作。
|
||||
|
||||
流式接口必须在模型 function calling 完成前先返回首个 `thinking` 事件,告知用户“意图识别智能体接管”。后续模型返回后再追加结构化拆解、字段映射、附件归集等过程摘要。
|
||||
|
||||
前端收到 `thinking` 事件后,也必须以 typewriter 方式逐字展示过程摘要,不能把一条完整思考事件一次性塞进折叠气泡。多条 `thinking` 事件应排队顺序输出,上一条内容打完后再输出下一条。
|
||||
|
||||
前端流式超时必须区分“首包等待”和“流式空闲等待”:首包应快速返回,收到首包后不能再用固定总时长中断仍在思考的模型调用,只能在长时间没有任何新事件时判定空闲超时。
|
||||
|
||||
流式过程中正文区域不输出任务结论;计划完成后意图识别气泡默认折叠,正文只保留用户需要确认和执行的信息。
|
||||
|
||||
计划完成后的最终正文也必须流式输出。前端不能把完整正文一次性替换到消息气泡里,而应进入 `typing` 状态按字符逐步追加正文;正文输出完成后,再把状态改为“等待用户确认”并展示确认按钮。
|
||||
|
||||
用户确认当前步骤后,小财管家隐式委派给申请能力或报销能力时,也必须保持同一套流式体验:先在系统气泡上方的小财管家思考折叠气泡中逐字展示当前业务任务、已识别信息、待补充条件和下一步动作;拿到申请核对表或报销核对结果后,再逐字输出正文。结构化表格、核对卡片、确认按钮可以在正文输出完成后一次性展示,但正文不能一次性替换进消息气泡。
|
||||
|
||||
小财管家委派期间不得打开右侧单助手执行流程面板,也不得把“申请助手 / 报销助手”的执行步骤显示成独立助手思考框。用户可见身份保持“小财管家”,具体调用哪个能力只作为小财管家自己的过程摘要,不切换为“财务助手”或单独助手会话。
|
||||
|
||||
### 5. 用户可见结果展示
|
||||
|
||||
小财管家的第一屏最终正文必须采用适中信息量的分段结构:让用户看懂系统理解了哪些财务事项、先后顺序是什么、每一步会交给哪个助手做什么;但不要把任务摘要、置信度、字段缺口和附件判断提前摊开。
|
||||
|
||||
第一屏推荐结构:
|
||||
|
||||
1. `我会这样推进`:说明识别到几个财务事项,以及会逐步处理。
|
||||
2. 顺序列表:说明先做什么、后做什么,每步附一句负责助手和动作边界。
|
||||
3. 确认提示:请用户回复“确定”后开始第一步,并说明具体缺口会在对应步骤里再判断。
|
||||
|
||||
最终正文必须使用 Markdown 块结构渲染,至少包含标题、段落和顺序列表;标题与段落之间必须保留空行,并通过 `steward-plan-markdown` 专属样式拉开块间距。不能只依赖普通换行拼接文本,因为普通换行在对话气泡里会显得拥挤。
|
||||
|
||||
第一屏不展示任务详情卡片里的“还需要补充”,也不展示字段缺口说明。用户确认开始后,进入当前步骤的申请助手或报销助手,再由具体助手基于当前任务判断需要补充什么。
|
||||
|
||||
后续步骤如果需要展示“还需要补充”,必须是结构化列表,每个待补充项独立成行,包含字段业务名称和填写说明;不得把多个待补充项拼接成一行连续文本。
|
||||
|
||||
当后续步骤发现关键条件缺失时,小财管家不能只展示“模型复核不稳定”或“下方表格待补充”。它必须把缺口转成下一轮对话问题,并优先给出可直接选择的业务选项。例如差旅申请缺少 `transport_mode` 时,用户界面展示为“请问你打算怎么出行?火车、飞机或轮船”,不得先展示申请核对表,也不得默认补成火车;用户选择后再生成申请核对表、写回出行方式、重新测算费用,并继续判断是否可以提交申请。这是“思考 -> 行动 -> 再思考 -> 再行动”循环的一部分。
|
||||
|
||||
用户补齐关键字段也不是终态动作。以“出行方式”为例,用户选择火车后,小财管家必须先进入下一轮业务思考,基于已识别的时间、地点、事由和出行方式模拟查询交通票据或票价口径,完成系统预估金额测算,再流式输出正文并展示申请核对表;不能在用户点击选项后直接把旧核对表补字段后闪现出来。
|
||||
|
||||
费用申请核对表阶段不得把系统档案字段或非阻塞归档字段当作用户待补充项。`employee_no`、`employee_name`、`department_name` 应从当前登录用户档案和组织上下文读取;`attachments` 在差旅申请阶段不阻塞核对表生成,可在后续报销、归档或审批材料补充阶段处理;`amount` 在申请阶段由系统规则估算。字段决策模型即使返回这些字段为缺失,服务端也必须过滤,不能向用户展示“附件/凭证和员工编号为合规必需字段”这类错误追问。
|
||||
|
||||
任务卡片和正文不得直接暴露本体字段名,例如 `transport_mode`、`amount`、`attachments`。本体字段只允许作为内部结构化数据进入后端、助手委派和持久化链路;用户界面必须翻译为业务中文,并提供可理解的填写说明:
|
||||
|
||||
- `transport_mode` 展示为“出行方式”,说明可填写高铁、飞机、自驾、出租车等。
|
||||
- `amount` 在申请任务中展示为“预计金额”,在报销任务中展示为“报销金额”。
|
||||
- `attachments` 展示为“附件/凭证”,说明可上传发票、行程单、付款截图或其他证明材料。
|
||||
- `merchant_name` 展示为“商户/开票方”。
|
||||
- `customer_name` 展示为“客户或项目对象”。
|
||||
|
||||
## 本体字段约束
|
||||
|
||||
业务字段必须使用本体 canonical field:
|
||||
|
||||
- `expense_type`
|
||||
- `time_range`
|
||||
- `location`
|
||||
- `reason`
|
||||
- `amount`
|
||||
- `transport_mode`
|
||||
- `attachments`
|
||||
- `customer_name`
|
||||
- `merchant_name`
|
||||
- `department_name`
|
||||
- `employee_name`
|
||||
- `employee_no`
|
||||
|
||||
兼容字段只能作为输入别名,例如:
|
||||
|
||||
- `occurred_date` -> `time_range`
|
||||
- `business_time` -> `time_range`
|
||||
- `reason_value` -> `reason`
|
||||
- `transport_type` -> `transport_mode`
|
||||
- `application_transport_mode` -> `transport_mode`
|
||||
|
||||
小财管家的编排态字段不进入业务语义本体:
|
||||
|
||||
- `plan_id`
|
||||
- `task_id`
|
||||
- `planning_source`
|
||||
- `model_call_traces`
|
||||
- `task_status`
|
||||
- `assigned_agent`
|
||||
- `confirmation_status`
|
||||
- `attachment_group_id`
|
||||
- `thinking_event_id`
|
||||
|
||||
这些字段只用于编排、展示和审计,不参与费用规则判断。
|
||||
|
||||
## 方案设计
|
||||
|
||||
### 后端
|
||||
|
||||
新增小财管家规划服务:
|
||||
|
||||
- `schemas/steward.py`:定义请求、任务计划、附件归集、确认动作等契约。
|
||||
- `services/runtime_chat.py`:新增 `complete_with_tool_call`,复用主/备模型配置发送 `tools` 与 `tool_choice`。
|
||||
- `services/steward_intent_agent.py`:负责构造 `submit_steward_intent_plan` function schema 与模型调用。
|
||||
- `services/steward_model_plan_builder.py`:负责把模型工具参数转换为服务端可校验计划。
|
||||
- `services/steward_planner.py`:负责“大模型 function calling 优先、规则兜底”的编排和本体字段归一化。
|
||||
- `api/v1/endpoints/steward.py`:提供 `POST /steward/plans` 和 `POST /steward/plans/stream`。
|
||||
|
||||
后端第一版不直接落库业务单据,只返回计划和确认动作。确认后的执行仍走现有申请助手、报销助手和 Orchestrator。
|
||||
|
||||
### 前端
|
||||
|
||||
新增或改造能力:
|
||||
|
||||
- 首页输入框标题和提示文案改为“小财管家”。
|
||||
- 工作台打开时默认使用 `sessionType=steward`。
|
||||
- 小财管家模式下隐藏“智能体切换”工具条。
|
||||
- 小财管家模式下不展示欢迎界面。
|
||||
- 小财管家模式下使用专属底部输入框,仅保留附件、自然语言输入和发送动作。
|
||||
- 小财管家模式下先流式渲染独立过程摘要,再渲染任务计划正文。
|
||||
- 用户确认当前下一步后,再切换/分派到申请助手或报销助手执行;多任务按顺序推进,不把所有任务动作一次性展示给用户。
|
||||
|
||||
### 执行流
|
||||
|
||||
```text
|
||||
首页输入
|
||||
↓
|
||||
小财管家计划接口
|
||||
↓
|
||||
意图识别智能体 function calling
|
||||
↓
|
||||
思考过程流式输出 + 任务分析 + 下一步动作说明
|
||||
↓
|
||||
等待用户输入“确定”或点击确认
|
||||
↓
|
||||
小财管家隐式调用申请助手创建申请单核对结果
|
||||
↓
|
||||
申请动作完成后重新思考剩余队列
|
||||
↓
|
||||
继续等待确认并隐式调用报销助手填写报销单
|
||||
↓
|
||||
执行结果汇总
|
||||
```
|
||||
|
||||
## 算法与公式
|
||||
|
||||
第一版主路径不以关键词规则定义“意图”,而是使用大模型 function calling 生成结构化计划。
|
||||
模型输出后由服务端做确定性校验、字段归一化和确认动作生成。
|
||||
|
||||
规则置信度评分仅用于模型不可用或模型返回结构不可用时的兜底路径。
|
||||
|
||||
任务拆解之后还需要第二层“任务字段决策智能体”。这一步不能由前端关键词或固定 required 字段直接决定,而要把当前任务类型、用户原话、上游任务拆解结果、canonical ontology fields、已抽取字段、缺失字段、附件和申请/报销上下文交给模型,通过 function calling 返回下一步动作:
|
||||
|
||||
- `ask_user`:当前信息不足,必须先把缺口转成业务问题和可选项。
|
||||
- `render_preview`:当前信息足够生成可核对结果,但提交、入库、绑定附件前仍需用户确认。
|
||||
|
||||
字段决策规则只能作为模型不可用或结构化结果非法时的兜底,兜底结果必须标记为 `rule_fallback`,不能伪装成智能体判断。字段名必须来自 ontology registry;UI 只展示中文业务名称,不展示 canonical 字段名。
|
||||
|
||||
任务置信度:
|
||||
|
||||
$$
|
||||
confidence = \min(1, 0.35s_i + 0.25s_t + 0.2s_l + 0.2s_a)
|
||||
$$
|
||||
|
||||
变量说明:
|
||||
|
||||
- `s_i`:意图关键词得分,命中申请/报销核心动词。
|
||||
- `s_t`:时间得分,识别到明确日期、相对日期或时间范围。
|
||||
- `s_l`:地点得分,识别到城市、客户或业务对象。
|
||||
- `s_a`:附件/费用场景得分,识别到票据、交通、住宿、招待等费用线索。
|
||||
|
||||
附件归集置信度:
|
||||
|
||||
$$
|
||||
group\_score = 0.4m_s + 0.3m_t + 0.2m_l + 0.1m_n
|
||||
$$
|
||||
|
||||
变量说明:
|
||||
|
||||
- `m_s`:附件场景与任务场景匹配度。
|
||||
- `m_t`:附件日期与任务日期匹配度。
|
||||
- `m_l`:附件地点与任务地点匹配度。
|
||||
- `m_n`:附件名称和任务关键词匹配度。
|
||||
|
||||
## 测试方案
|
||||
|
||||
### 后端单元测试
|
||||
|
||||
- function calling 路径能把模型工具参数转换为 `planning_source=llm_function_call` 的任务计划。
|
||||
- 模型返回 `occurred_date`、`transport_type`、`reason_value` 等别名时,服务端仍只输出 canonical 字段。
|
||||
- 一句话中同时包含申请和报销时,返回多个任务。
|
||||
- “昨天”能根据 `client_now_iso` 解析为明确日期。
|
||||
- `occurred_date`、`transport_type`、`reason_value` 等兼容字段不会作为业务 canonical 字段输出。
|
||||
- 多附件能生成差旅归集建议和排除项。
|
||||
- 创建/绑定/提交类动作必须带 `confirmation_required=true`。
|
||||
|
||||
### 前端测试
|
||||
|
||||
- 首页输入复杂话术后打开小财管家模式。
|
||||
- 小财管家模式标题显示“小财管家”,不展示智能体切换。
|
||||
- 过程摘要按步骤渐进展示。
|
||||
- 任务计划卡片展示申请任务和报销任务。
|
||||
- 附件归集建议展示包含项、排除项和确认按钮。
|
||||
|
||||
### 容器验证
|
||||
|
||||
后端测试必须在 `x-financial-main` 容器内执行:
|
||||
|
||||
```bash
|
||||
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-main /tmp/x-financial-server-venv/bin/pytest -q server/tests/test_steward_planner.py
|
||||
```
|
||||
|
||||
前端构建优先使用宿主机 `npm.cmd` 或项目既有脚本,并设置合理超时。
|
||||
|
||||
## 指标与验收
|
||||
|
||||
- 输入包含 3 个任务的示例话术时,至少识别出 1 个申请任务和 2 个报销任务。
|
||||
- 输入“明天出差北京3天,支撑国网仿生产部署,并且报销昨天业务招待费”时,必须识别出 1 个申请任务和 1 个报销任务。
|
||||
- 模型可用时,小财管家计划响应包含 `planning_source=llm_function_call`。
|
||||
- 小财管家计划响应中业务字段只出现 canonical ontology fields。
|
||||
- 附件场景混合时,能区分差旅相关附件和非差旅附件。
|
||||
- 前端弹窗标题为“小财管家”,并隐藏智能体切换。
|
||||
- 前端确认区只展示当前下一步主动作;存在申请任务时,第一步必须是“先创建申请单”。
|
||||
- 意图识别折叠气泡不得宽于正文气泡,且流式首包必须先于最终计划到达。
|
||||
- 用户未确认前,不创建申请单、不创建报销草稿、不绑定附件、不提交审批。
|
||||
- 后端定向测试通过。
|
||||
|
||||
## 风险与开放问题
|
||||
|
||||
- 模型供应商对 tools/function calling 的兼容度可能不同;第一版保留规则兜底和主备模型 failover。
|
||||
- 规则兜底无法覆盖所有自然语言,需要保留人工确认和低置信度提示。
|
||||
- 附件真实 OCR 归集依赖现有票据识别质量;第一版先使用附件名称和已有 OCR 摘要做轻量归集。
|
||||
- NDJSON 流式输出展示的是过程摘要,不是模型内部推理链。
|
||||
- 多任务之间可能共享日期、地点、申请单上下文,需要后续完善任务图依赖。
|
||||
- 如果未来接入 LangGraph,应基于当前计划契约迁移,而不是推翻现有申请/报销助手。
|
||||
66
document/development/小财管家/TODO.md
Normal file
66
document/development/小财管家/TODO.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# 小财管家 TODO
|
||||
|
||||
## 阶段一:调研与契约
|
||||
|
||||
- [x] 盘点首页输入框、工作台弹窗、会话路由和本体字段注册表。[CONCEPT: 背景与问题] 证据:已确认 `PersonalWorkbench.vue`、`useAppShell.js`、`TravelReimbursementCreateView.vue`、`ontology_field_registry.py`。
|
||||
- [x] 定义第一版只覆盖申请助手和报销助手,不引入 LangChain,但外层意图识别使用大模型 function calling。[CONCEPT: 目标与非目标] 证据:`CONCEPT.md` 已明确 MVP 边界和 function calling 主链路。
|
||||
- [x] 明确小财管家业务字段必须走 ontology canonical fields,编排字段不得进入业务本体。[CONCEPT: 本体字段约束] 证据:`CONCEPT.md` 已列出 canonical 字段与编排态字段。
|
||||
|
||||
## 阶段二:后端规划服务
|
||||
|
||||
- [x] 新增 `schemas/steward.py`,定义计划请求、任务、附件归集、确认动作和响应模型。[CONCEPT: 后端] 证据:`StewardPlanRequest`、`StewardTask`、`StewardAttachmentGroup`、`StewardConfirmationAction` 已新增。
|
||||
- [x] 扩展 `services/runtime_chat.py`,支持 OpenAI-compatible / Azure OpenAI 的 `tools` 与 `tool_choice` function calling。[CONCEPT: 后端] 证据:新增 `complete_with_tool_call`、`RuntimeChatToolCall` 和工具调用解析。
|
||||
- [x] 新增 `services/steward_intent_agent.py`,定义 `submit_steward_intent_plan` function schema 并调用系统主/备模型。[CONCEPT: 任务识别与拆分] 证据:模型调用入口已从 `StewardPlannerService` 注入。
|
||||
- [x] 新增 `services/steward_model_plan_builder.py`,将模型工具参数转换为服务端可校验计划。[CONCEPT: 后端] 证据:模型返回后仍会校验任务类型、canonical 字段和附件名。
|
||||
- [x] 改造 `services/steward_planner.py`,实现大模型 function calling 优先、规则规划兜底。[CONCEPT: 任务识别与拆分] 证据:`planning_source` 区分 `llm_function_call` 与 `rule_fallback`。
|
||||
- [x] 新增 `api/v1/endpoints/steward.py`,提供 `POST /steward/plans`。[CONCEPT: 后端] 证据:容器内接口 smoke 返回 `task_count=3`。
|
||||
- [x] 新增 `POST /steward/plans/stream`,以 NDJSON 返回 `thinking` 和最终 `plan` 事件。[CONCEPT: 流式过程摘要] 证据:真实接口 smoke 返回事件序列 `thinking,thinking,thinking,thinking,plan`。
|
||||
- [x] 调整 `POST /steward/plans/stream`,确保模型 function calling 完成前先返回首个 `thinking` 事件。[CONCEPT: 流式过程摘要] 证据:live smoke 首个事件为 `thinking/stream_start`。
|
||||
- [x] 在 `api/v1/router.py` 注册小财管家接口。[CONCEPT: 后端] 证据:运行中 `/api/v1/steward/plans` 返回 200。
|
||||
- [x] 保证所有输出到 `ontology_fields` 的业务字段只使用 canonical ontology fields。[CONCEPT: 本体字段约束] 证据:测试断言 `occurred_date`、`transport_type`、`reason_value` 不进入输出字段。
|
||||
- [x] 强化模型提示词和规则兜底,确保“未来出差/去某地几天/部署支撑”即使未出现“申请”也识别为费用申请。[CONCEPT: 任务识别与拆分] 证据:live smoke 将“明天出差北京3天...”拆为 `expense_application,reimbursement`。
|
||||
|
||||
## 阶段三:前端入口和弹窗
|
||||
|
||||
- [x] 将首页输入区主文案调整为“小财管家”,提示语体现可处理多任务。[CONCEPT: 前端] 证据:`PersonalWorkbench.vue` 标题和 placeholder 已更新。
|
||||
- [x] 增加 `steward` 会话类型,首页复杂输入默认进入小财管家模式。[CONCEPT: 前端] 证据:`SESSION_TYPE_STEWARD` 与首页 `sessionType` 已接入。
|
||||
- [x] 小财管家模式下隐藏“智能体切换”工具条。[CONCEPT: 前端] 证据:`shortcuts` 在 `isStewardSession` 下返回空数组。
|
||||
- [x] 小财管家模式下标题显示“小财管家”,副标题说明“统一财务任务编排入口”。[CONCEPT: 前端] 证据:`assistantHeaderTitle` 和 `assistantHeaderDescription` 已按 steward 分支处理。
|
||||
- [x] 小财管家模式下不展示欢迎界面。[CONCEPT: 前端] 证据:`useTravelReimbursementSessionState.js` 对 steward 空会话返回空消息,并过滤旧欢迎消息快照。
|
||||
- [x] 小财管家模式下使用专属底部输入框,不展示日期选择、差旅计算器和业务时间标签。[CONCEPT: 前端] 证据:`TravelReimbursementCreateView.vue` 按 `isStewardSession` 渲染 `steward-composer-row`。
|
||||
- [x] 新增前端小财管家计划服务,调用 `POST /steward/plans`。[CONCEPT: 后端] 证据:`web/src/services/steward.js` 已新增 `fetchStewardPlan`。
|
||||
- [x] 新增小财管家视图模型,生成过程摘要、任务计划卡片和附件归集卡片。[CONCEPT: 流式过程摘要] 证据:`stewardPlanModel.js` 和 `TravelReimbursementMessageItem.vue` 已接入 `stewardPlan`。
|
||||
- [x] 支持后端 `thinking` 事件真流式呈现为折叠式意图识别气泡。[CONCEPT: 流式过程摘要] 证据:`useStewardPlanFlow.js` 通过 `fetchStewardPlanStream` 接收 thinking 事件,并用 `typeStewardThinkingEvent` 将每条过程摘要逐字输出到折叠气泡。
|
||||
- [x] 支持小财管家最终正文逐字流式输出,正文完成前不展示确认按钮。[CONCEPT: 流式过程摘要] 证据:`useStewardPlanFlow.js` 新增 `typeStewardPlanText`,计划完成后进入 `typing` 状态逐字追加正文,完成后再注入 `suggestedActions`。
|
||||
- [x] 意图识别过程放在系统回复气泡上方,作为不同颜色的独立折叠气泡,完成后默认折叠。[CONCEPT: 流式过程摘要] 证据:`TravelReimbursementMessageItem.vue` 将 `steward-intent-bubble` 放在 `message-bubble` 上方,`steward-plan-block` 只渲染任务和附件结果。
|
||||
- [x] 统一小财管家思考折叠气泡与正文气泡宽度,避免思考气泡长于正文框。[CONCEPT: 流式过程摘要] 证据:`has-steward-plan` 消息栈统一为 760px,思考气泡和正文气泡同宽。
|
||||
- [x] 优化小财管家最终正文和任务卡片层次,用户可见内容不直接展示本体字段名。[CONCEPT: 用户可见结果展示] 证据:`stewardPlanModel.js` 第一屏使用 Markdown 标题、段落和顺序列表说明“先做什么、后做什么、交给哪个助手做什么”,但不展示置信度和字段缺口;`useStewardPlanFlow.js` 将第一屏标记为 `initialSummaryOnly`,`TravelReimbursementMessageItem.vue` 不再渲染第一屏任务详情卡片;后续步骤如需展示待补充项,再按独立列表行展示业务名称和填写说明。
|
||||
|
||||
## 阶段四:确认与分派
|
||||
|
||||
- [x] 为每个创建/绑定/提交类动作生成确认按钮,不确认不执行。[CONCEPT: 用户确认] 证据:接口返回 `confirmation_count=4`,前端转为 suggested actions。
|
||||
- [x] 将小财管家确认区改为“只展示当前下一步主动作”,存在申请任务时优先进入申请助手。[CONCEPT: 用户确认] 证据:`buildStewardSuggestedActions` 只返回下一步动作,优先 `confirm_create_application`。
|
||||
- [x] 支持用户输入“确定”触发小财管家的下一步动作,而不是重新生成计划。[CONCEPT: 用户确认] 证据:`useStewardPlanFlow` 会查找待确认的小财管家动作并执行。
|
||||
- [x] 支持小财管家隐藏委派申请/报销能力,执行后保留小财管家会话并继续引导剩余任务。[CONCEPT: 执行流] 证据:`sessionTypeOverride` 和 `stewardContinuation` 已接入前端提交流程。
|
||||
- [x] 支持小财管家确认后的隐式委派继续流式输出,正文完成后再展示申请核对表、报销核对卡片和确认按钮。[CONCEPT: 流式过程摘要] 证据:`useTravelReimbursementSubmitComposer.js` 新增 `typeStewardDelegatedMessage`,申请预览与 orchestrator 结果均先流式思考、再逐字正文、最后挂载结构化 payload;`npm.cmd --prefix web run build` 成功。
|
||||
- [x] 小财管家委派申请/报销能力期间不打开右侧单助手执行流程面板,用户可见身份保持“小财管家”。[CONCEPT: 流式过程摘要] 证据:`stewardDelegated` 分支跳过 flow step 与 review panel scope,并在最终消息设置 `assistantName: '小财管家'`;`stewardPlanModel.js` 助手标签兜底不再显示“财务助手”。
|
||||
- [x] 小财管家在后续步骤发现关键缺口时,主动转成可回答的问题和选项,而不是只展示待补充表格。[CONCEPT: 用户可见结果展示] 证据:`useTravelReimbursementSubmitComposer.js` 在申请核对缺少“出行方式”时只输出主动追问和火车/飞机/轮船选项,不提前挂载 `applicationPreview`;`stewardPlanModel.js` 的内部 `carry_text` 不再把“高铁、飞机”等示例写进缺字段提示,避免本地抽取误当成用户已选择;`TravelReimbursementCreateView.js` 在用户选择后不再直接补旧表格,而是重新进入小财管家的委派流;`web/tests/expense-application-fast-preview.test.mjs` 覆盖该回归。
|
||||
- [x] 用户补齐出行方式后,小财管家必须先思考、模拟查询票据和测算金额,再展示申请核对表。[CONCEPT: 用户可见结果展示] 证据:`stewardFieldCompletionModel.js` 将补齐字段后的当前任务、本体字段和旧预览重组为续跑输入;`TravelReimbursementCreateView.js` 的 `continueStewardApplicationFieldCompletion` 调用 `submitComposerInternal` 触发流式思考、申请复核和费用测算,不再调用 `commitApplicationPreviewEditor` 直接闪现表格。
|
||||
- [x] 防止残留预算上下文抢占小财管家的申请续跑链路。[CONCEPT: 执行流] 证据:`budgetAssistantReportModel.js` 不再因存在 `initialBudgetContext` 就无条件进入预算编制报告;`useTravelReimbursementSubmitComposer.js` 对 `stewardDelegated` 显式跳过预算编制分支;`expense-application-fast-preview.test.mjs` 覆盖“申请续跑 + 残留预算上下文”不得进入预算编制。
|
||||
- [x] 支持用户直接输入“确认/无误/可以提交”命中当前申请核对表提交动作,而不是重新规划。[CONCEPT: 用户确认] 证据:`TravelReimbursementCreateView.js` 通过 `handleStewardRuntimeDecision` 优先请求运行时决策智能体;模型返回 `submit_current_application` 后复用 `confirmApplicationSubmit`;本地 `handleApplicationSubmitConfirmationText` 仅作为模型不可用时的兜底;提交成功后标记 `applicationSubmitConfirmed`,避免后续重复提交;测试 `text confirmation submits pending application preview before replanning steward task` 覆盖该优先级。
|
||||
- [x] 增加小财管家运行时决策智能体,把“确认、继续下一项、补字段、重新规划”的上下文判断迁到后端 function calling。[CONCEPT: 用户确认] 证据:`POST /steward/runtime-decisions` 调用 `StewardRuntimeDecisionAgent`,通过 `submit_steward_runtime_decision` 返回 `submit_current_application`、`continue_next_task`、`fill_current_slot`、`plan_new_tasks` 等动作;前端 `handleStewardRuntimeDecision` 先提交 `runtime_state`,再执行模型返回的结构化动作,本地规则仅兜底。
|
||||
- [x] 增加第二层任务字段决策智能体,动态判断当前任务应追问用户还是展示核对结果。[CONCEPT: 算法与公式] 证据:`POST /steward/slot-decisions` 调用 `StewardSlotDecisionAgent`,通过 `submit_steward_slot_decision` function calling 输出 `ask_user` / `render_preview`、canonical 缺失字段、问题和选项;前端 `useTravelReimbursementSubmitComposer.js` 在小财管家委派申请时消费该决策。
|
||||
- [x] 防止字段决策模型把申请阶段非阻塞字段误判为用户必填项。[CONCEPT: 用户可见结果展示] 证据:`StewardSlotDecisionAgent` 过滤 `amount`、`attachments`、`employee_no`、`department_name`、`employee_name`,模型误返 `ask_user` 且过滤后无缺口时改为 `render_preview`;前端 `APPLICATION_NON_BLOCKING_ONTOLOGY_FIELDS` 同步过滤兜底缺口和选项;测试覆盖附件/员工编号误判。
|
||||
- [x] 小财管家思考气泡必须体现业务意图和关键缺口,不能退化为系统执行日志。[CONCEPT: 流式过程摘要] 证据:`steward_planner.py` 将差旅申请缺少“出行方式”纳入计划缺口并追加业务缺口思考事件;`useTravelReimbursementSubmitComposer.js` 和 `TravelReimbursementCreateView.js` 的确认后思考改为读取任务摘要、已识别信息和待补充项。
|
||||
- [x] 确认申请任务后,将任务摘要分派到现有申请助手会话。[CONCEPT: 执行流] 证据:确认动作携带 `session_type=application` 和 `auto_submit=true`。
|
||||
- [x] 确认报销任务后,将任务摘要和附件带入现有报销助手会话。[CONCEPT: 执行流] 证据:确认动作携带 `session_type=expense`、`carry_files=true` 和 `auto_submit=true`。
|
||||
- [x] 附件归集建议确认后,将选中附件作为报销助手上下文继续处理。[CONCEPT: 附件归集] 证据:附件归集确认动作携带归集附件名称和排除附件名称。
|
||||
|
||||
## 阶段五:测试与验证
|
||||
|
||||
- [x] 新增 `server/tests/test_steward_planner.py`,覆盖多任务拆解、相对日期、附件归集、确认动作和流式事件。[CONCEPT: 测试方案] 证据:新增 4 个后端定向测试。
|
||||
- [x] 补充 function calling 定向测试,覆盖模型工具参数、canonical 字段清洗、附件归集和规则兜底。[CONCEPT: 后端单元测试] 证据:`test_steward_planner.py` 新增 fake function calling 路径,`test_runtime_chat_service.py` 新增 tools payload 用例。
|
||||
- [x] 后端测试在 Docker `x-financial-main:/app` 内执行,超时控制在 60s 内。[CONCEPT: 容器验证] 证据:`pytest -q server/tests/test_steward_planner.py server/tests/test_runtime_chat_service.py` 结果 `13 passed`。
|
||||
- [ ] 新增或更新前端定向测试,覆盖小财管家标题、隐藏智能体切换和计划展示。[CONCEPT: 前端测试]
|
||||
- [x] 运行前端构建或定向测试,确认 UI 编译通过。[CONCEPT: 测试方案] 证据:`npm.cmd run build` 成功。
|
||||
- [x] 通过接口或页面可见结果证明用户最终看到小财管家计划和确认点。[CONCEPT: 指标与验收] 证据:容器接口返回 3 个任务、3 份归集附件、1 份排除附件和 4 个确认动作。
|
||||
273
document/development/小财管家本体JSON流程/CONCEPT.md
Normal file
273
document/development/小财管家本体JSON流程/CONCEPT.md
Normal file
@@ -0,0 +1,273 @@
|
||||
# 小财管家本体 JSON 流程
|
||||
|
||||
## 功能一句话
|
||||
|
||||
用大模型作为小财管家的主意图识别器,将用户连续对话转换为受本体字段约束的业务 JSON,并在申请和报销意图不确定时先进入用户确认,而不是用固定规则直接判定。
|
||||
|
||||
## 背景与问题
|
||||
|
||||
当前小财管家已经具备任务规划、部分运行时状态和申请/报销委派能力,但仍有两个关键缺口:
|
||||
|
||||
- 意图识别仍带有较强规则假设。例如“2月20-23日去上海出差辅助国网仿生产环境部署”这类话术,在没有“申请”或“报销”动词时,系统不能仅凭规则直接判定为申请。
|
||||
- 跨轮对话需要一个贯穿流程的结构化 JSON。该 JSON 必须只承载本体 canonical field,不能由前端、规则或大模型临时发明业务字段。
|
||||
|
||||
因此,本轮目标不是重写整个小财管家,而是在现有 `steward` 体系上补齐“LLM 主识别 + 本体 JSON 模板 + 待确认流程 + 上下文记忆”的闭环。
|
||||
|
||||
## 目标与非目标
|
||||
|
||||
### 目标
|
||||
|
||||
- 用大模型 function calling 作为主路径识别用户意图。
|
||||
- 模型输出必须落到统一业务 JSON 模板,字段来源必须来自本体字段注册表。
|
||||
- 支持 `travel_application` 和 `travel_reimbursement` 两个业务流程。
|
||||
- 当用户话术无法确定是申请还是报销时,返回 `pending_flow_confirmation`,由前端展示两个明确选项。
|
||||
- 跨轮对话持续携带并合并 `steward_state`,直到用户完成、取消或切换业务。
|
||||
- 规则只做兜底,且响应必须标记 `rule_fallback`,不能伪装成模型判断。
|
||||
- 用户可见回复使用 Markdown 块结构,重点信息加粗,避免密集换行。
|
||||
|
||||
### 非目标
|
||||
|
||||
- 本轮不引入 LangChain 或 LangGraph。
|
||||
- 本轮不迁移申请助手、报销助手和 Orchestrator 的既有核心逻辑。
|
||||
- 本轮不让大模型直接创建申请单、保存草稿、绑定附件或提交审批。
|
||||
- 本轮不新增脱离本体字段体系的新业务字段。
|
||||
- 本轮不改造所有财务场景,只先覆盖出差申请和差旅/费用报销。
|
||||
|
||||
## 用户与场景
|
||||
|
||||
- 普通员工:在首页或小财管家对话框中说“2月20-23日去上海出差辅助国网仿生产环境部署”。
|
||||
- 小财管家:先判断该话术包含出差、时间、地点和事由,但缺少“申请还是报销”的明确动作。
|
||||
- 用户:点击“补办出差申请”或“发起费用报销”。
|
||||
- 系统:将用户选择写入同一个业务 JSON,并继续用对应流程追问缺字段、生成核对结果或委派现有助手。
|
||||
|
||||
示例预期:
|
||||
|
||||
```markdown
|
||||
我识别到你描述的是一次 **上海出差事项**,时间为 **2月20日至2月23日**,事由是 **辅助国网仿生产环境部署**。
|
||||
|
||||
但当前还不能确定你要做哪一件事:
|
||||
|
||||
1. **补办出差申请**
|
||||
2. **发起费用报销**
|
||||
|
||||
请先选择一个方向,我会继续整理对应材料。
|
||||
```
|
||||
|
||||
## 功能能力
|
||||
|
||||
### 输入
|
||||
|
||||
- 用户自然语言 `message`。
|
||||
- 当前时间 `client_now_iso`,用于解析相对日期。
|
||||
- 附件元信息和 OCR 摘要。
|
||||
- 当前 `conversation_id`。
|
||||
- 已持久化 `steward_state`。
|
||||
- ontology canonical fields 列表。
|
||||
|
||||
### 输出
|
||||
|
||||
- `steward_state`:贯穿对话的业务 JSON。
|
||||
- `intent_result`:本轮模型或兜底规则的识别结果。
|
||||
- `candidate_flows`:存在歧义时的候选流程。
|
||||
- `next_action`:下一步动作,例如追问、确认流程、渲染申请预览、渲染报销预审。
|
||||
- `markdown_reply`:面向用户的 Markdown 回复。
|
||||
|
||||
### 状态边界
|
||||
|
||||
业务 JSON 必须区分业务字段和编排字段:
|
||||
|
||||
- 业务字段只允许出现在 `flows.<flow_id>.fields`。
|
||||
- 业务字段 key 必须是 canonical ontology field。
|
||||
- 编排字段只能出现在 `active_flow`、`pending_flow_confirmation`、`events`、`status` 等结构里。
|
||||
- 规则或模型返回的别名字段必须先归一化,例如 `occurred_date -> time_range`、`transport_type -> transport_mode`、`reason_value -> reason`。
|
||||
|
||||
### 安全边界
|
||||
|
||||
- 保存草稿、创建申请单、提交审批、删除或绑定附件必须等待用户确认。
|
||||
- LLM 只能产出结构化建议,不直接执行副作用操作。
|
||||
- 如果模型返回非法字段、非法流程或非法动作,服务端丢弃非法部分并进入保守兜底。
|
||||
|
||||
## 业务 JSON 模板
|
||||
|
||||
目标模板如下:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "steward.flow_state.v2",
|
||||
"active_flow": "",
|
||||
"pending_flow_confirmation": {
|
||||
"status": "none",
|
||||
"source_message": "",
|
||||
"reason": "",
|
||||
"candidate_flows": []
|
||||
},
|
||||
"flows": {
|
||||
"travel_application": {
|
||||
"flow_id": "travel_application",
|
||||
"intent": "travel_application_create",
|
||||
"status": "idle",
|
||||
"fields": {},
|
||||
"missing_fields": [],
|
||||
"confidence": 0,
|
||||
"evidence": []
|
||||
},
|
||||
"travel_reimbursement": {
|
||||
"flow_id": "travel_reimbursement",
|
||||
"intent": "travel_reimbursement_draft",
|
||||
"status": "idle",
|
||||
"fields": {},
|
||||
"missing_fields": [],
|
||||
"linked_application_claim_id": "",
|
||||
"attachments": [],
|
||||
"confidence": 0,
|
||||
"evidence": []
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
||||
```
|
||||
|
||||
候选流程结构:
|
||||
|
||||
```json
|
||||
{
|
||||
"flow_id": "travel_application",
|
||||
"label": "补办出差申请",
|
||||
"confidence": 0.52,
|
||||
"reason": "用户描述了出差时间、地点和事由,但没有明确要求报销或提交申请。"
|
||||
}
|
||||
```
|
||||
|
||||
## 方案设计
|
||||
|
||||
### 后端
|
||||
|
||||
新增或扩展以下职责:
|
||||
|
||||
- `schemas/steward.py`:增加 v2 JSON 状态、候选流程、待确认流程和意图识别响应模型。
|
||||
- `services/steward_intent_agent.py`:扩展 function schema,允许模型返回 `pending_flow_confirmation` 和 `candidate_flows`。
|
||||
- `services/steward_model_plan_builder.py`:校验模型输出,只保留合法 flow、合法 action 和 canonical ontology fields。
|
||||
- `services/steward_flow_state.py`:支持 v1 到 v2 状态兼容、字段 patch 合并、候选流程落态和事件追踪。
|
||||
- `services/steward_runtime_decision_agent.py`:识别用户点击或输入的流程选择,并把选择写回 `active_flow`。
|
||||
- `api/v1/endpoints/steward.py`:在 `/steward/plans`、`/steward/plans/stream`、`/steward/runtime-decisions` 中统一返回最新 `steward_state`。
|
||||
|
||||
### 前端
|
||||
|
||||
- `stewardPlanModel.js`:将 `pending_flow_confirmation` 转为可点击操作。
|
||||
- `TravelReimbursementCreateView.js`:用户点击候选流程后,优先走 runtime decision,不重新把原句当新任务规划。
|
||||
- `useStewardPlanFlow.js`:渲染 Markdown 回复和候选流程操作。
|
||||
- `useTravelReimbursementSessionState.js`:持续保存并传回 `conversation_id` 和 `steward_state`。
|
||||
|
||||
### 数据与持久化
|
||||
|
||||
- 复用 `AgentConversation.state_json` 持久化 `steward_state`。
|
||||
- 不新增数据库表。
|
||||
- 不改变申请单、报销单现有表结构。
|
||||
|
||||
### 接口契约
|
||||
|
||||
`POST /steward/plans` 和流式计划接口返回:
|
||||
|
||||
```json
|
||||
{
|
||||
"planning_source": "llm_function_call",
|
||||
"conversation_id": "conv_xxx",
|
||||
"steward_state": {},
|
||||
"next_action": "confirm_flow",
|
||||
"candidate_flows": [],
|
||||
"summary": "Markdown 文本"
|
||||
}
|
||||
```
|
||||
|
||||
运行时确认接口返回:
|
||||
|
||||
```json
|
||||
{
|
||||
"decision_source": "llm_function_call",
|
||||
"next_action": "continue_selected_flow",
|
||||
"steward_state": {},
|
||||
"response_text": "Markdown 文本"
|
||||
}
|
||||
```
|
||||
|
||||
## 算法与公式
|
||||
|
||||
主路径不使用关键词打分决定最终意图,而是由 LLM function calling 返回结构化候选结果。
|
||||
|
||||
规则兜底仅在模型不可用、超时或结构非法时使用。兜底置信度用于决定是否直接进入候选确认:
|
||||
|
||||
$$
|
||||
confidence(flow) = 0.35t + 0.25l + 0.25v + 0.15a
|
||||
$$
|
||||
|
||||
变量定义:
|
||||
|
||||
- `t`:时间线索得分,出现明确日期、日期区间或相对日期时取 1,否则取 0。
|
||||
- `l`:地点线索得分,出现城市、客户地点或项目地点时取 1,否则取 0。
|
||||
- `v`:动作线索得分,出现申请、报销、提交、保存草稿等动作词时取 1,否则取 0。
|
||||
- `a`:附件线索得分,存在票据、发票、行程单、OCR 金额等附件证据时取 1,否则取 0。
|
||||
|
||||
当最高候选流程与第二候选流程差值小于阈值时进入确认:
|
||||
|
||||
$$
|
||||
\Delta = confidence(flow_1) - confidence(flow_2) < 0.20
|
||||
$$
|
||||
|
||||
该公式只用于兜底路径,不能覆盖模型主判断。
|
||||
|
||||
## 测试方案
|
||||
|
||||
### 后端单元测试
|
||||
|
||||
- `test_steward_intent_agent.py`:覆盖 function schema 包含 `candidate_flows`、`pending_flow_confirmation`。
|
||||
- `test_steward_model_plan_builder.py`:覆盖非法字段过滤、别名归一、非法 flow 丢弃。
|
||||
- `test_steward_flow_state.py`:覆盖 v2 状态合并、候选流程落态、用户选择后 active flow 切换。
|
||||
- `test_steward_runtime_decision_agent.py`:覆盖用户选择“补办出差申请 / 发起费用报销”。
|
||||
|
||||
### 接口测试
|
||||
|
||||
- `/steward/plans` 输入“2月20-23日去上海出差辅助国网仿生产环境部署”,返回 `next_action=confirm_flow`。
|
||||
- `/steward/runtime-decisions` 选择“补办出差申请”后,`active_flow=travel_application`。
|
||||
- `/steward/runtime-decisions` 选择“发起费用报销”后,`active_flow=travel_reimbursement`。
|
||||
|
||||
### 前端测试
|
||||
|
||||
- 候选流程按钮只在 `pending_flow_confirmation.status=pending` 时展示。
|
||||
- 用户点击候选流程后不重复触发新计划。
|
||||
- Markdown 回复中标题、段落、列表和重点加粗能正确渲染。
|
||||
|
||||
### 容器验证
|
||||
|
||||
后端测试必须在 Docker 容器内执行:
|
||||
|
||||
```bash
|
||||
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-main /tmp/x-financial-server-venv/bin/pytest -q server/tests/test_steward_intent_agent.py server/tests/test_steward_model_plan_builder.py server/tests/test_steward_flow_state.py server/tests/test_steward_runtime_decision_agent.py
|
||||
```
|
||||
|
||||
前端构建必须在容器内执行:
|
||||
|
||||
```bash
|
||||
docker exec -w /app/web x-financial-main npm run build
|
||||
```
|
||||
|
||||
单次测试命令最长等待 60 秒,避免任务卡死。
|
||||
|
||||
## 指标与验收
|
||||
|
||||
- 对“2月20-23日去上海出差辅助国网仿生产环境部署”,系统不再直接判定为申请,而是返回两个候选流程并要求用户确认。
|
||||
- 用户选择“补办出差申请”后,同一 `conversation_id` 的 `steward_state.active_flow=travel_application`。
|
||||
- 用户选择“发起费用报销”后,同一 `conversation_id` 的 `steward_state.active_flow=travel_reimbursement`。
|
||||
- `flows.*.fields` 中不出现非本体字段。
|
||||
- 模型返回别名字段时,服务端输出仍为 canonical ontology field。
|
||||
- 模型不可用时,规则兜底结果明确标记 `rule_fallback`。
|
||||
- 用户未确认前,不创建申请单、不保存报销草稿、不提交审批、不绑定附件。
|
||||
- 前端候选流程按钮点击后不产生重复消息、不重复规划、不丢失上下文。
|
||||
- 后端定向测试和前端构建在 `x-financial-main:/app` 通过。
|
||||
|
||||
## 风险与开放问题
|
||||
|
||||
- 模型供应商对 function calling 的兼容程度不同,需要保留严格的服务端结构校验。
|
||||
- 旧版 `steward_state.v1` 已有数据需要兼容升级到 v2。
|
||||
- 用户输入可能同时包含“补申请”和“报销”,这种情况不应进入歧义确认,而应拆成两个任务。
|
||||
- 过去日期不等于报销,未来日期也不绝对等于申请;最终应由 LLM 主识别,并用候选确认处理低确定性场景。
|
||||
- 后续如果要支持更多流程,例如审批、制度问答或预算查询,需要先扩展本体业务契约,再扩展本 JSON 模板。
|
||||
75
document/development/小财管家本体JSON流程/TODO.md
Normal file
75
document/development/小财管家本体JSON流程/TODO.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# 小财管家本体 JSON 流程 TODO
|
||||
|
||||
> 开发时必须先更新本 TODO,再按小步执行。只有真实完成并通过对应验证后,才能把 `[ ]` 改成 `[x]` 并补充证据。
|
||||
|
||||
## 阶段一:调研与契约确认
|
||||
|
||||
- [x] 盘点 `schemas/steward.py`、`steward_intent_agent.py`、`steward_model_plan_builder.py`、`steward_flow_state.py` 的当前状态模型。[CONCEPT: 方案设计] 证据:已在实现前读取并确认现有 `steward_state`、planner、runtime decision 入口。
|
||||
- [x] 盘点 `ontology_field_registry.py` 中申请和报销可使用的 canonical ontology fields。[CONCEPT: 业务 JSON 模板] 证据:实现复用 `BUSINESS_CANONICAL_FIELDS` 与 `normalize_ontology_form_values`。
|
||||
- [x] 确认 `AgentConversation.state_json` 中已有 `steward_state.v1` 数据的兼容方式。[CONCEPT: 数据与持久化] 证据:`StewardFlowStateService._normalize_state` 兼容旧 state 并升级默认版本为 `steward.flow_state.v2`。
|
||||
- [x] 复核前端 `stewardPlanModel.js`、`useStewardPlanFlow.js`、`TravelReimbursementCreateView.js` 中候选动作和状态携带入口。[CONCEPT: 前端] 证据:前端子智能体只读检查确认建议动作入口可复用。
|
||||
|
||||
## 阶段二:后端 Schema 与 JSON 模板
|
||||
|
||||
- [x] 在 `schemas/steward.py` 增加 `StewardCandidateFlow`、`StewardPendingFlowConfirmation`、v2 `steward_state` 相关模型。[CONCEPT: 业务 JSON 模板] 证据:新增模型与 `StewardPlanResponse.pending_flow_confirmation`。
|
||||
- [x] 在 `StewardPlanResponse` 和 runtime response 中补充 `next_action`、`candidate_flows` 或等价结构,保持旧字段兼容。[CONCEPT: 接口契约] 证据:`StewardPlanResponse.next_action/candidate_flows` 与 `continue_selected_flow` 已接入。
|
||||
- [x] 编写 schema 单元测试,验证候选流程只允许 `travel_application` 和 `travel_reimbursement`。[CONCEPT: 安全边界] 证据:`test_steward_intent_agent.py` 覆盖 function schema 枚举。
|
||||
|
||||
## 阶段三:LLM 意图识别主路径
|
||||
|
||||
- [x] 扩展 `steward_intent_agent.py` 的 function schema,要求模型输出 `pending_flow_confirmation` 和 `candidate_flows`。[CONCEPT: 后端] 证据:`test_steward_intent_agent.py` 通过。
|
||||
- [x] 更新系统提示词:不能把无明确动作的出差描述直接判定为申请;应结合语义、上下文和候选置信度决定是否确认。[CONCEPT: 背景与问题] 证据:`steward_intent_agent.py` system prompt 已要求低确定性返回 pending flow。
|
||||
- [x] 增加 fake LLM 测试:输入“2月20-23日去上海出差辅助国网仿生产环境部署”时,模型路径返回 `confirm_flow`。[CONCEPT: 指标与验收] 证据:`test_steward_planner_returns_pending_flow_confirmation_from_llm`。
|
||||
- [ ] 增加模型非法输出测试:非法字段、非法 flow、空候选项必须被服务端过滤或降级。[CONCEPT: 安全边界]
|
||||
|
||||
## 阶段四:状态合并与上下文记忆
|
||||
|
||||
- [x] 扩展 `steward_flow_state.py`,支持 `steward.flow_state.v1` 到 `steward.flow_state.v2` 的兼容升级。[CONCEPT: 风险与开放问题] 证据:`_normalize_state` 默认 v2 并保留 v1 核心结构。
|
||||
- [x] 支持将 `pending_flow_confirmation` 写入 state,并记录 source message、候选 flow 和确认原因。[CONCEPT: 业务 JSON 模板] 证据:`test_state_merge_plan_keeps_pending_flow_confirmation`。
|
||||
- [x] 支持用户选择候选 flow 后切换 `active_flow`,并把已识别字段合并到对应流程。[CONCEPT: 功能能力] 证据:`StewardFlowStateService.confirm_flow` 与 runtime 测试覆盖。
|
||||
- [x] 增加状态测试:多轮合并后 `flows.*.fields` 不出现非本体字段。[CONCEPT: 指标与验收] 证据:既有 `test_state_merge_filters_non_ontology_fields` 继续通过。
|
||||
- [ ] 增加状态测试:同一 `conversation_id` 下选择申请或报销不会丢失前一轮字段和证据。[CONCEPT: 数据与持久化]
|
||||
|
||||
## 阶段五:运行时决策
|
||||
|
||||
- [x] 扩展 `steward_runtime_decision_agent.py`,识别用户点击或输入“补办出差申请”“发起费用报销”。[CONCEPT: 后端] 证据:`_build_selected_flow_decision` 前置处理候选 flow。
|
||||
- [x] Runtime decision 输入为空时,从 `context_json.conversation_state.steward_state` 恢复状态。[CONCEPT: 输入] 证据:既有 `test_steward_runtime_decision_fallback_reads_persisted_steward_state` 继续通过。
|
||||
- [x] 用户选择申请后返回 `continue_selected_flow`,并设置 `active_flow=travel_application`。[CONCEPT: 指标与验收] 证据:`test_steward_runtime_decision_fallback_confirms_selected_flow`。
|
||||
- [x] 用户选择报销后返回 `continue_selected_flow`,并设置 `active_flow=travel_reimbursement`。[CONCEPT: 指标与验收] 证据:`test_steward_runtime_decision_fallback_confirms_reimbursement_flow`。
|
||||
- [x] 增加 runtime 测试,覆盖点击按钮和用户直接输入两种方式。[CONCEPT: 测试方案] 证据:runtime 单测覆盖申请/报销选择,接口 smoke 覆盖用户选择。
|
||||
|
||||
## 阶段六:前端候选流程展示
|
||||
|
||||
- [x] 在 `stewardPlanModel.js` 中把 `pending_flow_confirmation` 转成两个可点击建议动作。[CONCEPT: 前端] 证据:`steward-plan-model-pending-flow.test.mjs`。
|
||||
- [x] 在 `useStewardPlanFlow.js` 中渲染 Markdown 回复,确保标题、列表和重点加粗间距正常。[CONCEPT: 用户与场景] 证据:`buildStewardPlanMessageText` 对 `confirm_flow` 生成 Markdown 标题、列表和加粗内容。
|
||||
- [x] 在 `TravelReimbursementCreateView.js` 中处理候选流程点击:优先调用 runtime decision,不重新规划原始输入。[CONCEPT: 前端] 证据:`steward_confirm_flow` 分支调用 `handleStewardRuntimeDecision`。
|
||||
- [x] 在 `useTravelReimbursementSessionState.js` 中确认 `conversation_id` 和 `steward_state` 后续请求持续携带。[CONCEPT: 输入] 证据:现有 session state 与 `buildStewardPlanRequest` 已持续携带,无需新增改动。
|
||||
- [x] 增加或补充前端定向测试,覆盖候选按钮展示、点击后状态更新和不重复规划。[CONCEPT: 前端测试] 证据:新增 `steward-plan-model-pending-flow.test.mjs` 覆盖候选按钮,接口 smoke 覆盖选择后状态更新。
|
||||
|
||||
## 阶段七:接口与回归验证
|
||||
|
||||
- [x] 在容器中运行后端定向测试,单次命令超时控制在 60 秒内。[CONCEPT: 容器验证] 证据:`24 passed in 25.14s`。
|
||||
|
||||
```bash
|
||||
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-main /tmp/x-financial-server-venv/bin/pytest -q server/tests/test_steward_intent_agent.py server/tests/test_steward_model_plan_builder.py server/tests/test_steward_flow_state.py server/tests/test_steward_runtime_decision_agent.py
|
||||
```
|
||||
|
||||
- [x] 在容器中运行已有小财管家回归测试,确认旧的申请/报销拆分不退化。[CONCEPT: 测试方案] 证据:`test_steward_planner.py`、`test_steward_slot_decision_agent.py` 包含在后端定向测试中并通过。
|
||||
|
||||
```bash
|
||||
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-main /tmp/x-financial-server-venv/bin/pytest -q server/tests/test_steward_planner.py server/tests/test_steward_slot_decision_agent.py
|
||||
```
|
||||
|
||||
- [x] 在容器中运行前端构建。[CONCEPT: 容器验证] 证据:`docker exec -w /app/web x-financial-main npm run build` 成功。
|
||||
|
||||
```bash
|
||||
docker exec -w /app/web x-financial-main npm run build
|
||||
```
|
||||
|
||||
- [x] 手工验证小财管家输入“2月20-23日去上海出差辅助国网仿生产环境部署”,页面展示两个候选流程,未确认前不创建申请单或报销草稿。[CONCEPT: 指标与验收] 证据:接口 smoke 返回 `next_action=confirm_flow`、候选 `travel_application/travel_reimbursement`、`state_pending=pending`。
|
||||
|
||||
## 阶段八:文档同步
|
||||
|
||||
- [x] 实现过程中如调整 JSON 字段或接口契约,先更新 `CONCEPT.md`,再修改代码。[CONCEPT: 方案设计] 证据:已先新增 `CONCEPT.md` 与 `TODO.md`。
|
||||
- [x] 每完成一个阶段,在本 TODO 中勾选并补充证据,例如测试命令、文件名或接口返回要点。[CONCEPT: 测试方案] 证据:本文件已补充阶段证据。
|
||||
- [ ] 最终汇报工作区状态,不自动 commit/push,除非用户明确要求。[CONCEPT: 风险与开放问题]
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user