Compare commits
139 Commits
codex/opti
...
a0f6d9f702
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0f6d9f702 | ||
|
|
bb681aa1f3 | ||
|
|
bc560145a4 | ||
|
|
5311c99d69 | ||
|
|
545b31d32f | ||
|
|
8417a9f542 | ||
|
|
9a5ed0e94a | ||
|
|
50d2dc579a | ||
|
|
f9553a6a1a | ||
|
|
ee730aa31c | ||
|
|
0264a4b5b4 | ||
|
|
332f77389d | ||
|
|
d4ff79f326 | ||
|
|
93212600eb | ||
|
|
73966b3a7b | ||
|
|
1f40ce3df3 | ||
|
|
f17098aa58 | ||
|
|
8094333e3b | ||
|
|
0122f3b250 | ||
|
|
dc4cad2baa | ||
|
|
e725b7f19c | ||
|
|
84a8998e59 | ||
|
|
bc743adef3 | ||
|
|
ded8b39ccb | ||
|
|
ba444a514f | ||
|
|
aa965da69d | ||
|
|
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 | ||
|
|
e080105f9f | ||
|
|
64cc76c970 | ||
|
|
99e90798d2 | ||
|
|
064eeb614f | ||
|
|
b383244a29 | ||
|
|
e384318046 | ||
|
|
8a4a777be7 | ||
|
|
04cd6d0f81 | ||
|
|
d4d5d40569 | ||
|
|
cbb98f4469 | ||
|
|
7d32eae74e | ||
|
|
b1a9c8a194 | ||
|
|
2dcc72102d | ||
|
|
df49103f23 | ||
|
|
e7bef0883d | ||
|
|
e1e515ecae | ||
|
|
0e861d8fa6 | ||
|
|
d0e946cf47 | ||
|
|
50b1c3f9a9 | ||
|
|
575f093c74 | ||
|
|
5b388d08c0 | ||
|
|
88ff04bef8 | ||
|
|
1f15699013 | ||
|
|
222ba0bfdc | ||
|
|
2e57702638 | ||
|
|
5fe3b201d9 |
135
.codex/skills/agent-change-log/SKILL.md
Normal file
135
.codex/skills/agent-change-log/SKILL.md
Normal file
@@ -0,0 +1,135 @@
|
||||
---
|
||||
name: agent-change-log
|
||||
description: Use when working in X-Financial after bug fixes, new features, refactors, behavior changes, documentation edits, config edits, concurrent-agent Git commits, or any codebase modification that should leave an incremental human-readable work log.
|
||||
---
|
||||
|
||||
# Agent Change Log
|
||||
|
||||
## Overview
|
||||
|
||||
This skill keeps a living, incremental work log for X-Financial. After each meaningful modification batch, write down what changed locally, what other agents already committed upstream, what was operated on, what remains uncertain, and what should happen next.
|
||||
|
||||
The log should sound like a careful teammate writing for tomorrow's teammate: concrete, warm, and honest.
|
||||
|
||||
## When To Use
|
||||
|
||||
- After fixing a bug, adding a feature, refactoring, changing behavior, editing documentation, or changing config.
|
||||
- Before the final response for any turn that changed files.
|
||||
- Before updating the log in a branch where other agents may have pushed commits.
|
||||
- After verification, so the entry can include what was actually checked.
|
||||
- When a failed attempt changed files, generated artifacts, or revealed a risk worth preserving.
|
||||
|
||||
Do not use for read-only investigation with no file changes unless the user explicitly asks for a record.
|
||||
|
||||
## Log Location
|
||||
|
||||
Use one file per day:
|
||||
|
||||
```text
|
||||
document/work-log/YYYY-MM-DD.md
|
||||
```
|
||||
|
||||
If the file does not exist, create it. If it exists, incrementally update it. Never replace the whole file just to add a new entry.
|
||||
|
||||
## Required Structure
|
||||
|
||||
Each daily file must use these sections in this order:
|
||||
|
||||
```markdown
|
||||
# YYYY-MM-DD 工作日志
|
||||
|
||||
## 当日工作内容
|
||||
|
||||
## 遗留问题
|
||||
|
||||
## TODO
|
||||
```
|
||||
|
||||
Keep this order stable. Add entries under the existing headings instead of creating duplicate headings.
|
||||
|
||||
## Required Git Check
|
||||
|
||||
Before writing or updating the daily log, manually check Git for upstream and local-ahead commits from other agents.
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
date '+%Y-%m-%d %H:%M:%S %Z'
|
||||
git fetch --all --prune
|
||||
git status -sb
|
||||
git rev-parse --abbrev-ref --symbolic-full-name @{u}
|
||||
git log --oneline --decorate --max-count=20 HEAD..@{u}
|
||||
git log --oneline --decorate --max-count=20 @{u}..HEAD
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
- Treat `git fetch --all --prune` as the default safe "pull check"; it updates remote refs without merging into a dirty worktree.
|
||||
- Treat `HEAD..@{u}` as upstream commits not yet in local history.
|
||||
- Treat `@{u}..HEAD` as local commits not yet in upstream history; these may also come from another agent working in the same checkout.
|
||||
- If the worktree is clean and the branch is only behind upstream, `git pull --ff-only` may be used to fast-forward before analysis.
|
||||
- If the worktree is dirty, diverged, or likely to conflict, do not merge/rebase automatically. Record the upstream commits from `HEAD..@{u}` and the blocker in `遗留问题`.
|
||||
- If there is no upstream branch, record that fact in `遗留问题` and continue with local-only logging.
|
||||
- When `HEAD..@{u}` has commits, summarize those commits under `当日工作内容` before describing local edits. Mention commit hash, subject, and inferred impact.
|
||||
- When `@{u}..HEAD` has commits that were not created in the current task, summarize them too, because another local agent may have committed without pushing yet.
|
||||
- When no upstream or local-ahead commits exist, still record "Git 提交检查:未发现 upstream 新提交或本地 ahead 新提交" in the work entry.
|
||||
|
||||
## Entry Rules
|
||||
|
||||
1. Get the current local time first:
|
||||
```bash
|
||||
date '+%Y-%m-%d %H:%M:%S %Z'
|
||||
```
|
||||
2. Run the required Git check and capture whether upstream or local-ahead has new commits.
|
||||
3. Append a new timestamped bullet under `## 当日工作内容`.
|
||||
4. Mention Git commits, changed files or modules, the operation, the intent, and the verification result.
|
||||
5. Add or update `## 遗留问题` whenever there is risk, uncertainty, skipped verification, design debt, Git divergence, or a likely follow-up.
|
||||
6. Add or update `## TODO` with checkbox items.
|
||||
7. When a TODO is completed, keep it in place and mark it as:
|
||||
```markdown
|
||||
- [x] ~~任务内容~~(完成于 HH:MM,证据:...)
|
||||
```
|
||||
|
||||
## Writing Style
|
||||
|
||||
- Write in Simplified Chinese.
|
||||
- Be specific and a little human: "我把...", "这次先...", "还需要留意..." are good.
|
||||
- Keep the tone factual. Do not turn the log into a victory lap.
|
||||
- Prefer concise file names and module names in prose, but include enough context to find the change.
|
||||
- Work content should be detailed enough that a future agent can continue without asking "你到底改了啥?"
|
||||
- Leftover issues should include a suggested next step, not only a complaint.
|
||||
|
||||
## Work Content Template
|
||||
|
||||
```markdown
|
||||
- HH:MM:我完成了 <本次修改目标>。
|
||||
- Git 提交检查:<git fetch 后 HEAD..upstream 与 upstream..HEAD 的结果;没有就写未发现 upstream 或本地 ahead 新提交>。
|
||||
- 修改:<文件/模块>,<做了什么>。
|
||||
- 操作:<运行了什么命令、迁移了什么状态、重启了什么服务等>。
|
||||
- 验证:<测试/构建/检查结果;如果没跑,说明原因>。
|
||||
- 影响:<用户可见变化或工程边界变化>。
|
||||
```
|
||||
|
||||
## Leftover Issue Template
|
||||
|
||||
```markdown
|
||||
- HH:MM:<遗留问题或风险>。建议下一步 <具体建议>。
|
||||
```
|
||||
|
||||
## TODO Template
|
||||
|
||||
```markdown
|
||||
- [ ] <下一步动作>(来源:HH:MM <上下文>)
|
||||
- [x] ~~<已完成动作>~~(完成于 HH:MM,证据:<命令/文件/结果>)
|
||||
```
|
||||
|
||||
## Final Response Checklist
|
||||
|
||||
Before saying work is complete:
|
||||
|
||||
- Today's `document/work-log/YYYY-MM-DD.md` exists.
|
||||
- The Git check ran, and upstream plus local-ahead commits from other agents were summarized or explicitly marked as absent.
|
||||
- `当日工作内容` includes this modification batch.
|
||||
- `遗留问题` is either updated with real risks or explicitly says no new leftover issue for this batch.
|
||||
- `TODO` contains new follow-ups and completed items are checked with evidence.
|
||||
- The final response mentions that the work log was updated.
|
||||
4
.codex/skills/agent-change-log/agents/openai.yaml
Normal file
4
.codex/skills/agent-change-log/agents/openai.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "Agent Change Log"
|
||||
short_description: "Record X-Financial changes plus upstream/local commits in the daily work log"
|
||||
default_prompt: "Use $agent-change-log after a bug fix, feature, refactor, upstream/local commit check, or other file modification to update document/work-log/YYYY-MM-DD.md incrementally."
|
||||
85
.codex/skills/git-checkpoint-commit/SKILL.md
Normal file
85
.codex/skills/git-checkpoint-commit/SKILL.md
Normal file
@@ -0,0 +1,85 @@
|
||||
---
|
||||
name: git-checkpoint-commit
|
||||
description: Use when a coding task finishes a verified bug fix, key feature, risky refactor checkpoint, local backup commit, checkpoint commit, 提交备份, 本地提交, or when an active session has accumulated about five meaningful edit rounds and should create a scoped local git commit without pushing.
|
||||
---
|
||||
|
||||
# Git Checkpoint Commit
|
||||
|
||||
## Overview
|
||||
|
||||
Use this skill to keep a local git backup loop during active development. The goal is to commit verified, task-scoped progress at meaningful checkpoints without mixing unrelated user changes or pushing remotely.
|
||||
|
||||
## Trigger Rules
|
||||
|
||||
Create a local checkpoint commit when any condition is true:
|
||||
|
||||
- A bug fix is implemented and the targeted regression check passes.
|
||||
- A key feature slice is implemented and the smallest relevant verification passes.
|
||||
- A risky refactor reaches a behavior-preserving checkpoint.
|
||||
- The current session has reached about five meaningful edit rounds since the last commit.
|
||||
- The user asks for `提交`, `本地提交`, `备份`, `checkpoint`, `commit`, or `形成提交循环`.
|
||||
|
||||
Do not use this skill when the user explicitly says not to commit, when the change is exploratory and unverified, or when the only available commit would include unrelated dirty files.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Inspect the working tree with `git status --short`.
|
||||
2. Identify files or hunks owned by the current task.
|
||||
3. Run the smallest relevant verification first.
|
||||
- In X-Financial, run backend tests inside `x-financial-main` when backend code is involved.
|
||||
- Use targeted frontend tests/builds for web-only changes.
|
||||
4. Commit only the task-owned files.
|
||||
5. Report the commit hash and verification evidence.
|
||||
6. Reset the session edit counter to zero after a successful checkpoint.
|
||||
|
||||
## Safety Rules
|
||||
|
||||
- Never commit unrelated user changes just to make the tree clean.
|
||||
- Never push as part of this skill.
|
||||
- Never rewrite history, amend old commits, or run destructive git commands.
|
||||
- If the same file contains unrelated hunks, split the staging carefully with `git add -p` or a narrower manual patch.
|
||||
- If the index already contains staged changes, inspect them first; do not mix them into a checkpoint unless they belong to the same current task.
|
||||
- If verification cannot run, say why in the commit body or final report and prefer a `chore(checkpoint)` message rather than a confident `fix` or `feat`.
|
||||
|
||||
## Commit Style
|
||||
|
||||
Use normal semantic messages for completed, verified work:
|
||||
|
||||
- `fix(workbench): keep application preview after draft save failure`
|
||||
- `feat(reimbursements): add attachment association job polling`
|
||||
- `refactor(claims): split draft flow serialization`
|
||||
|
||||
Use checkpoint messages for interim backup points:
|
||||
|
||||
- `chore(checkpoint): backup attachment association flow`
|
||||
- `chore(checkpoint): backup after five edit rounds`
|
||||
|
||||
Keep the subject concise. Add body lines only when the verification state or scope needs clarity.
|
||||
|
||||
## Helper Script
|
||||
|
||||
Use `scripts/checkpoint_commit.py` when a path-scoped local commit is enough:
|
||||
|
||||
```bash
|
||||
python3 .codex/skills/git-checkpoint-commit/scripts/checkpoint_commit.py \
|
||||
--message "chore(checkpoint): backup workbench AI flow" \
|
||||
web/src/composables/workbenchAiMode/useWorkbenchAiExpenseFlow.js \
|
||||
web/tests/workbench-ai-mode-switch.test.mjs
|
||||
```
|
||||
|
||||
Preview before committing:
|
||||
|
||||
```bash
|
||||
python3 .codex/skills/git-checkpoint-commit/scripts/checkpoint_commit.py \
|
||||
--dry-run \
|
||||
web/src/utils/expenseApplicationPreview.js
|
||||
```
|
||||
|
||||
The script refuses to commit the whole tree unless `--allow-all` is passed. Use `--allow-all` only when the current task truly owns every dirty file.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
- Mistaking backup for verification. Verify first, then commit.
|
||||
- Staging `.` in a dirty worktree. Stage explicit paths or hunks.
|
||||
- Combining documentation cleanup, feature work, and unrelated local edits in one checkpoint.
|
||||
- Continuing indefinitely after multiple verified slices. Commit once the counter reaches five meaningful edit rounds.
|
||||
4
.codex/skills/git-checkpoint-commit/agents/openai.yaml
Normal file
4
.codex/skills/git-checkpoint-commit/agents/openai.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "Git Checkpoint Commit"
|
||||
short_description: "Create local backup commits at safe milestones"
|
||||
default_prompt: "Use $git-checkpoint-commit to checkpoint verified task changes into a local git commit."
|
||||
127
.codex/skills/git-checkpoint-commit/scripts/checkpoint_commit.py
Normal file
127
.codex/skills/git-checkpoint-commit/scripts/checkpoint_commit.py
Normal file
@@ -0,0 +1,127 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Create a path-scoped local git checkpoint commit."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def run_git(args: list[str], cwd: Path, *, check: bool = True) -> subprocess.CompletedProcess[str]:
|
||||
result = subprocess.run(
|
||||
["git", *args],
|
||||
cwd=cwd,
|
||||
text=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
timeout=60,
|
||||
)
|
||||
if check and result.returncode != 0:
|
||||
message = result.stderr.strip() or result.stdout.strip()
|
||||
raise SystemExit(f"git {' '.join(args)} failed: {message}")
|
||||
return result
|
||||
|
||||
|
||||
def repo_root() -> Path:
|
||||
result = subprocess.run(
|
||||
["git", "rev-parse", "--show-toplevel"],
|
||||
text=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
timeout=60,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
raise SystemExit("Not inside a git repository.")
|
||||
return Path(result.stdout.strip())
|
||||
|
||||
|
||||
def load_paths(args: argparse.Namespace) -> list[str]:
|
||||
paths = list(args.paths)
|
||||
if args.paths_from_file:
|
||||
raw_lines = Path(args.paths_from_file).read_text(encoding="utf-8").splitlines()
|
||||
paths.extend(line.strip() for line in raw_lines if line.strip() and not line.startswith("#"))
|
||||
return paths
|
||||
|
||||
|
||||
def ensure_clean_index(root: Path) -> None:
|
||||
staged = run_git(["diff", "--cached", "--name-only"], root).stdout.strip()
|
||||
if staged:
|
||||
raise SystemExit(
|
||||
"Refusing to continue because the index already has staged changes:\n"
|
||||
f"{staged}\n"
|
||||
"Commit or unstage them before running this checkpoint helper."
|
||||
)
|
||||
|
||||
|
||||
def status_for(root: Path, paths: list[str], allow_all: bool) -> str:
|
||||
command = ["status", "--short"]
|
||||
if not allow_all:
|
||||
command.extend(["--", *paths])
|
||||
return run_git(command, root).stdout.strip()
|
||||
|
||||
|
||||
def infer_message(paths: list[str], allow_all: bool) -> str:
|
||||
if allow_all or not paths:
|
||||
return "chore(checkpoint): backup current task changes"
|
||||
first_parts = [Path(item).parts[0] for item in paths if Path(item).parts]
|
||||
scope = first_parts[0] if first_parts else "task"
|
||||
return f"chore(checkpoint): backup {scope} changes"
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("paths", nargs="*", help="Task-owned paths to stage and commit.")
|
||||
parser.add_argument("-m", "--message", help="Commit message subject/body.")
|
||||
parser.add_argument("--paths-from-file", help="Read additional pathspecs from a UTF-8 text file.")
|
||||
parser.add_argument("--dry-run", action="store_true", help="Show matching changes without staging.")
|
||||
parser.add_argument("--allow-all", action="store_true", help="Allow committing all dirty files.")
|
||||
parser.add_argument("--no-verify", action="store_true", help="Pass --no-verify to git commit.")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
root = repo_root()
|
||||
paths = load_paths(args)
|
||||
|
||||
if not paths and not args.allow_all:
|
||||
raise SystemExit("Pass explicit paths, or use --allow-all when the current task owns all changes.")
|
||||
|
||||
current_status = status_for(root, paths, args.allow_all)
|
||||
if not current_status:
|
||||
print("No matching changes to commit.")
|
||||
return 0
|
||||
|
||||
print(current_status)
|
||||
if args.dry_run:
|
||||
return 0
|
||||
|
||||
ensure_clean_index(root)
|
||||
|
||||
# 使用 -A 保留删除/重命名等变更,但只作用于明确传入的 pathspec。
|
||||
if args.allow_all:
|
||||
run_git(["add", "-A"], root)
|
||||
else:
|
||||
run_git(["add", "-A", "--", *paths], root)
|
||||
|
||||
staged_summary = run_git(["diff", "--cached", "--name-status"], root).stdout.strip()
|
||||
if not staged_summary:
|
||||
raise SystemExit("No staged changes after git add.")
|
||||
|
||||
message = args.message or infer_message(paths, args.allow_all)
|
||||
commit_command = ["commit"]
|
||||
if args.no_verify:
|
||||
commit_command.append("--no-verify")
|
||||
commit_command.extend(["-m", message])
|
||||
commit_result = run_git(commit_command, root)
|
||||
sys.stdout.write(commit_result.stdout)
|
||||
|
||||
commit_hash = run_git(["rev-parse", "--short", "HEAD"], root).stdout.strip()
|
||||
print(f"checkpoint_commit={commit_hash}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
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"]'
|
||||
@@ -31,6 +31,7 @@ ONLYOFFICE_PUBLIC_URL=http://127.0.0.1:8082
|
||||
ONLYOFFICE_BACKEND_URL=http://127.0.0.1:8000
|
||||
ONLYOFFICE_JWT_SECRET=change-me-onlyoffice
|
||||
HERMES_AGENT_SHARED_TOKEN=change-me-hermes
|
||||
STEWARD_AGENT_RUNTIME=langgraph
|
||||
|
||||
POSTGRES_HOST=127.0.0.1
|
||||
POSTGRES_PORT=5432
|
||||
@@ -48,4 +49,8 @@ SQLALCHEMY_ECHO=false
|
||||
REDIS_URL=
|
||||
VITE_REDIS_URL=
|
||||
|
||||
OCR_DEVICE=
|
||||
OCR_TIMEOUT_SECONDS=180
|
||||
OCR_MAX_CONCURRENT_WORKERS=1
|
||||
|
||||
CORS_ORIGINS='["http://127.0.0.1:5173","http://localhost:5173","http://0.0.0.0:5173"]'
|
||||
|
||||
9
.githooks/post-commit
Executable file
9
.githooks/post-commit
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
# Auto-append a minimal X-Financial agent work-log entry after each commit.
|
||||
|
||||
repo_root="$(git rev-parse --show-toplevel 2>/dev/null)" || exit 0
|
||||
cd "$repo_root" || exit 0
|
||||
|
||||
python3 tools/agent-change-log/update_change_log.py \
|
||||
--event "post-commit hook" \
|
||||
>/tmp/x-financial-agent-change-log-hook.log 2>&1 || true
|
||||
24
.gitignore
vendored
24
.gitignore
vendored
@@ -7,7 +7,16 @@ web/.vite/
|
||||
.omc/
|
||||
.omx/
|
||||
.claude/
|
||||
.codex/
|
||||
*.egg-info/
|
||||
.codex/*
|
||||
!.codex/skills/
|
||||
.codex/skills/*
|
||||
!.codex/skills/agent-change-log/
|
||||
!.codex/skills/agent-change-log/**
|
||||
!.codex/skills/git-checkpoint-commit/
|
||||
!.codex/skills/git-checkpoint-commit/**
|
||||
.codex-temp/
|
||||
.superpowers/
|
||||
*.log
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
@@ -16,3 +25,16 @@ __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
|
||||
tmp/
|
||||
.nezha/
|
||||
.omo/
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
1
.tmp/Yuxi
Submodule
1
.tmp/Yuxi
Submodule
Submodule .tmp/Yuxi added at fd6803e477
65
AGENTS.md
Normal file
65
AGENTS.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# X-Financial Agent 协作规范
|
||||
|
||||
## 语言规范
|
||||
|
||||
- 所有分析、解释、计划、提交说明和最终回复默认使用简体中文。
|
||||
- 技术结论要直击重点,必要时给出可验证的文件、命令或测试结果。
|
||||
|
||||
## 变更日志 Skill 规范
|
||||
|
||||
- 每次修复 bug、新增功能、重构、修改配置或编辑项目文档后,必须调用项目级 Skill `agent-change-log`,并增量更新 `document/work-log/YYYY-MM-DD.md`。
|
||||
- 更新日志前必须先执行 Git 拉取检查:默认运行 `git fetch --all --prune`、`git status -sb`、`git log HEAD..@{u}` 和 `git log @{u}..HEAD`;如果工作区干净且只落后上游,可以 `git pull --ff-only`。发现其他智能体已提交到上游或本地 ahead 提交时,要先把这些提交摘要分析进当天日志。
|
||||
- 自动化触发由 `tools/agent-change-log/update_change_log.py` 和 `.githooks/post-commit` 提供;新 checkout 需要执行 `tools/agent-change-log/install_post_commit_hook.sh` 安装到本地 `.git/hooks/post-commit` 后,提交后才会自动追加最低限度日志。
|
||||
- 如果当前环境无法写 `.git` 或无法执行 `git fetch`,必须把这个限制写进当天日志;不能把 Skill/AGENTS 规则误当成已经有后台自动化。
|
||||
- 日志必须保留 `当日工作内容`、`遗留问题`、`TODO` 三块;TODO 使用 Markdown checkbox,完成项勾选并用删除线保留历史。
|
||||
- 记录要写清楚具体时间、改了什么、操作了什么、验证了什么、还遗留什么问题,以及建议下一步怎么处理。
|
||||
|
||||
## 通用代码拆分规范
|
||||
|
||||
无论写前端、后端还是算法代码,都必须主动避免“所有方法堆在一个类里 / 一个组件里 / 一个模块里”的写法。遇到类、组件或核心模块持续变大时,优先按职责拆分,而不是继续追加方法和状态。
|
||||
|
||||
### 行数与复杂度目标
|
||||
|
||||
- 单个类、核心组件、核心算法模块硬上限为 800 行。
|
||||
- 普通文件建议控制在 300-600 行。
|
||||
- 复杂业务文件可以接近 800 行,但必须有清晰职责边界。
|
||||
- 文件或类超过 800 行必须视为重构预警,不应继续直接追加功能。
|
||||
- 单个类不应长期承载几十个无关方法,更不应演化成上百个方法的万能类。
|
||||
|
||||
### 拆分原则
|
||||
|
||||
- 对外 API 尽量保持稳定,先把内部实现拆到小模块。
|
||||
- 按职责拆分:编排、状态管理、持久化、权限、文件存储、OCR/票据分析、规则审核、响应构建、序列化、UI 交互、算法策略、数据转换。
|
||||
- 新增能力时先判断归属模块;没有合适归属时新增小模块,不要默认塞回主类、主组件或主 Service。
|
||||
- 拆分必须小步进行,每次提取一个明确职责,并配套运行相关测试。
|
||||
|
||||
### X-Financial 重点关注对象
|
||||
|
||||
- `ExpenseClaimService`:优先拆分申请单、明细项、附件、票据分析、草稿、规则审核、权限、序列化。
|
||||
- `UserAgentService`:优先拆分知识库问答、报销预审 payload、Markdown 回复、差旅政策、表单槽位、票据分类、建议动作。
|
||||
- `OrchestratorService`:优先拆分 agent 路由、工具调用、报销查询、响应构建。
|
||||
- 前端大型 Vue 页面:优先拆分 composable、view model、样式分片、业务工具函数和子组件。
|
||||
- 算法/规则模块:优先拆分输入解析、规则匹配、评分策略、结果解释和异常处理。
|
||||
|
||||
## 容器与运行环境(必读)
|
||||
|
||||
本项目代码是 Docker 容器 `local-x-financial-linux`(镜像 `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 的验证,都必须在 `local-x-financial-linux` 容器内执行,**不要在宿主机上直接跑 pytest / pip / python**。
|
||||
|
||||
- **进入容器跑命令**(最常用):
|
||||
```bash
|
||||
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv local-x-financial-linux <cmd>
|
||||
```
|
||||
- 跑后端测试:`docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv local-x-financial-linux /tmp/x-financial-server-venv/bin/pytest -q <path>`
|
||||
- 交互式排查:`docker exec -it -w /app local-x-financial-linux 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
|
||||
```
|
||||
|
||||
144
docker-compose.full.yml
Normal file
144
docker-compose.full.yml
Normal file
@@ -0,0 +1,144 @@
|
||||
services:
|
||||
main:
|
||||
image: x-financial-dev:latest
|
||||
container_name: local-x-financial-linux
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
onlyoffice:
|
||||
condition: service_started
|
||||
qdrant:
|
||||
condition: service_started
|
||||
environment:
|
||||
WEB_HOST: 0.0.0.0
|
||||
WEB_PORT: "${WEB_PORT:-5173}"
|
||||
SERVER_HOST: 0.0.0.0
|
||||
SERVER_PORT: "${SERVER_PORT:-8000}"
|
||||
SERVER_RELOAD: "${SERVER_RELOAD:-true}"
|
||||
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:-5173}:${WEB_PORT:-5173}"
|
||||
- "${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 mupdf-tools &&
|
||||
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:-5173}/ >/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,37 @@
|
||||
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: local-x-financial-linux
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
WEB_HOST: 0.0.0.0
|
||||
WEB_PORT: "${WEB_PORT:-5173}"
|
||||
SERVER_HOST: 0.0.0.0
|
||||
SERVER_PORT: "${SERVER_PORT:-8000}"
|
||||
SERVER_RELOAD: "${SERVER_RELOAD:-true}"
|
||||
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:-5173}:${WEB_PORT:-5173}"
|
||||
- "${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 mupdf-tools &&
|
||||
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 +47,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:-5173}/ >/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` 的清理命令。
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
# 附件自动关联后台任务实施计划
|
||||
|
||||
## 目标
|
||||
|
||||
把小财管家 AI 模式里的附件关联从前端会话内存任务改为后端可查询后台任务,保证用户退出或刷新当前会话后,附件关联仍能继续完成并可恢复状态。
|
||||
|
||||
## 执行清单
|
||||
|
||||
- [x] 定位当前断链根因:前端依赖 `File` 对象和内存 `Map`。
|
||||
- [x] 确认票据夹已有 `receipt_id`、源文件和关联状态能力。
|
||||
- [x] 落开发方案文档。
|
||||
- [x] 实现后端任务 schema 和内存任务池。
|
||||
- [x] 实现后端任务 API。
|
||||
- [x] 实现后端票据夹源文件归集到报销单明细。
|
||||
- [x] 增加后端测试。
|
||||
- [x] 实现前端任务创建、轮询和恢复。
|
||||
- [x] 增加前端测试断言。
|
||||
- [x] 执行容器后端定向测试。
|
||||
- [x] 执行前端定向测试和构建。
|
||||
|
||||
## 验证结果
|
||||
|
||||
- 后端定向测试:`6 passed`
|
||||
- 前端定向测试:`12 passed`
|
||||
- 前端构建:通过,保留既有 chunk size warning。
|
||||
- 运行时检查:新任务查询路由已加载,未知任务返回“附件关联任务不存在或已失效。”
|
||||
|
||||
## 关键决策
|
||||
|
||||
- 第一版使用后端内存任务池和 FastAPI `BackgroundTasks`,解决前端会话断链。
|
||||
- 第一版不新增数据库任务表,服务重启后的任务恢复作为后续增强。
|
||||
- 前端消息只保存 `job_id`、状态和票据引用,不再保存附件原件。
|
||||
146
document/development/AI意图规划器/CONCEPT.md
Normal file
146
document/development/AI意图规划器/CONCEPT.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# AI 意图规划器
|
||||
|
||||
## 功能一句话
|
||||
|
||||
把用户一句自然语言先交给大模型识别成“动作和步骤”的结构化计划,再由前端/后端确定性执行器逐步校验和执行;规则只作为模型不可用或结构非法时的兜底。
|
||||
|
||||
## 背景
|
||||
|
||||
用户真实表达往往不是一个简单关键词,而是一个目标:
|
||||
|
||||
```text
|
||||
去上海出差,辅助国网仿生产服务器部署,交通火车,直接提交
|
||||
```
|
||||
|
||||
这句话包含至少四层语义:
|
||||
|
||||
- 业务对象:差旅费用申请。
|
||||
- 已给字段:地点、事由、交通方式。
|
||||
- 用户动作:直接提交,不只是生成草稿。
|
||||
- 执行步骤:生成申请核对表、校验必填字段、查重、提交审批。
|
||||
|
||||
如果继续用前端规则直接判断,会越来越像关键词路由;正确方向是让大模型先拆成结构化计划,系统只执行经过白名单校验的步骤。
|
||||
|
||||
## 目标
|
||||
|
||||
- 大模型作为复杂意图的主识别器,输出结构化 `intent plan`。
|
||||
- `intent plan` 明确描述用户要执行的动作、业务字段、缺失字段和步骤列表。
|
||||
- 执行器只认计划中的白名单步骤,不直接相信模型文本。
|
||||
- 字段齐全且用户明确“直接提交”时,系统自动走完整链路。
|
||||
- 字段缺失、风险阻断、重复申请或低置信度时,系统停在核对表或风险提示。
|
||||
- 本地规则只作为 `rule_fallback`,不得伪装成模型判断。
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不让大模型直接写数据库、提交审批或绑定附件。
|
||||
- 不引入 LangChain 高层 Agent 来替代现有业务服务。
|
||||
- 不让 LangGraph 直接接管模型供应商密钥、数据库写入或审批副作用。
|
||||
- 不绕过已有申请预览、规则测算、重复申请核查和提交接口。
|
||||
- 不把所有财务场景一次性改完;第一阶段先覆盖个人工作台 AI 模式里的差旅申请链路。
|
||||
|
||||
## 结构化计划契约
|
||||
|
||||
前端执行器消费统一结构:
|
||||
|
||||
```json
|
||||
{
|
||||
"source": "llm_function_call",
|
||||
"intent": "create_travel_application",
|
||||
"requestedAction": "submit",
|
||||
"confidence": 0.91,
|
||||
"sourceText": "去上海出差,辅助国网仿生产服务器部署,交通火车,直接提交",
|
||||
"slots": {
|
||||
"location": "上海",
|
||||
"reason": "辅助国网仿生产服务器部署",
|
||||
"transportMode": "火车"
|
||||
},
|
||||
"missingFields": [],
|
||||
"steps": [
|
||||
"build_application_preview",
|
||||
"validate_required_fields",
|
||||
"run_duplicate_precheck",
|
||||
"submit_application"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 步骤白名单
|
||||
|
||||
- `build_application_preview`:生成申请核对表,复用现有申请预览能力。
|
||||
- `validate_required_fields`:用确定性代码校验必填字段和字段格式。
|
||||
- `run_duplicate_precheck`:提交前查询同日期或重叠申请单。
|
||||
- `submit_application`:调用现有申请提交动作;只有用户明确要求提交且前置校验通过才执行。
|
||||
- `save_application_draft`:调用现有申请草稿保存能力。
|
||||
- `create_reimbursement_draft`:调用现有报销草稿创建能力。
|
||||
- `associate_attachments`:调用现有附件关联 runner;缺少 `receipt_ids` 或匹配不唯一时阻断,不能假成功。
|
||||
- `link_existing_application`:调用现有报销草稿创建链路并写入申请关联 flag;申请单不存在、未审批或已被报销时阻断。
|
||||
|
||||
## 数据流
|
||||
|
||||
```text
|
||||
用户输入
|
||||
↓
|
||||
steward LLM function calling
|
||||
↓
|
||||
模型计划归一化与白名单校验
|
||||
↓
|
||||
可执行 intent plan
|
||||
↓
|
||||
申请/报销/附件等确定性执行器
|
||||
↓
|
||||
核对表、风险提示、草稿或提交结果
|
||||
```
|
||||
|
||||
当模型不可用、超时或返回不可执行结构时:
|
||||
|
||||
```text
|
||||
模型失败
|
||||
↓
|
||||
本地 rule_fallback 生成保守计划
|
||||
↓
|
||||
同一个执行器继续处理
|
||||
```
|
||||
|
||||
## 安全边界
|
||||
|
||||
- 模型只负责“理解”和“拆步骤”,不拥有副作用权限。
|
||||
- 执行器必须校验 `intent` 和 `steps` 是否在白名单内;未知 action 必须阻断,不能调用业务服务。
|
||||
- 提交前必须走 `readyToSubmit` 和重复申请 precheck。
|
||||
- 提交类副作用必须带用户确认和 precheck 通过证据。
|
||||
- 地点、日期、事由等字段仍由现有申请预览和规则校验模块判断。
|
||||
- 模型置信度低、流程冲突或必填字段缺失时,不自动提交。
|
||||
|
||||
## 第一阶段落地
|
||||
|
||||
- 新增前端 planner model,把后端 `StewardPlanResponse` 映射成前端 `intent plan`。
|
||||
- 个人工作台 AI 模式在命中差旅申请候选时,优先调用现有 `/steward/plans` 获取模型计划。
|
||||
- 模型计划可执行时,按 `steps` 生成申请核对表并在条件满足时自动提交。
|
||||
- 模型不可用或计划不可执行时,使用本地 `rule_fallback` 保持体验不倒退。
|
||||
- 保留既有普通小财管家路径,用来处理无法直接执行或更复杂的多任务场景。
|
||||
|
||||
## LangGraph 迁移方向
|
||||
|
||||
后端小财管家的规划入口、槽位决策入口和运行时动作决策入口已经开始迁入 LangGraph。
|
||||
后续不再继续把感知、规划、补字段、运行时动作判断堆进自研 `if/else` 编排,而是按 node 拆分:
|
||||
|
||||
- `model_intent_node`:模型 function calling 规划。
|
||||
- `slot_tool_decision_node`:字段缺口与追问判断,失败时进入规则兜底。
|
||||
- `runtime_memory_context_node`:合并前端运行时状态和持久化 `steward_state`。
|
||||
- `runtime_tool_decision_node`:用户补充、确认、取消、继续执行等运行时判断。
|
||||
- `runtime_action_decision_node`:已选流程确认等不需要模型的确定性行动路由。
|
||||
- `action_plan_node`:生成白名单 `StewardActionStep`,当前已覆盖申请预览、保存草稿、直接提交和报销草稿。
|
||||
- `human_review_node`:保存草稿、提交审批、关联申请单前的确认点。
|
||||
- `action_execute_node`:调用现有确定性业务服务;当前已由 `/steward/actions/execute`、`StewardGraphActionRuntime` 和 `StewardActionExecutor` 提供 checkpoint、pending interrupt 和幂等重放。
|
||||
- `persist_state_node`:合并 conversation state 和 steward state。
|
||||
|
||||
当前 `plans` 已返回服务端 `action_steps`,`slot-decisions` / `runtime-decisions` 已默认走 `StewardGraphRuntime`。
|
||||
如果 LangGraph 图节点异常,服务端会退回原有 Agent 和规则兜底,避免框架层故障影响用户会话。
|
||||
|
||||
详细迁移计划见 `LANGGRAPH_RUNTIME_MIGRATION.md`。
|
||||
|
||||
## 测试策略
|
||||
|
||||
- planner model 单元测试:模型计划归一化、rule fallback、政策咨询排除。
|
||||
- 前端静态接线测试:主流程必须先请求 steward plan,再 fallback。
|
||||
- 申请预览回归测试:`直接提交` 不得污染事由;缺日期不得伪造字段。
|
||||
- 构建验证:`npm --prefix web run build`。
|
||||
420
document/development/AI意图规划器/LANGGRAPH_RUNTIME_MIGRATION.md
Normal file
420
document/development/AI意图规划器/LANGGRAPH_RUNTIME_MIGRATION.md
Normal file
@@ -0,0 +1,420 @@
|
||||
# 小财管家 LangGraph Runtime 迁移计划
|
||||
|
||||
> **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:** 把小财管家的感知、规划、记忆、确认和行动逐步迁到 LangGraph runtime,减少自研流程编排里的隐藏状态和分支 bug。
|
||||
|
||||
**Architecture:** 保留现有 FastAPI API、Pydantic schema、`RuntimeChatService` 模型供应商抽象和业务服务;LangGraph 只接管 agent 编排。副作用动作必须通过白名单 action node 调用现有业务服务,保存草稿、提交和关联单据都不能由模型文本直接触发。
|
||||
|
||||
**Tech Stack:** Python 3.11、FastAPI、Pydantic、LangGraph 1.x、SQLAlchemy、现有 `AgentConversationService` / `StewardFlowStateService`。
|
||||
|
||||
---
|
||||
|
||||
## 当前状态
|
||||
|
||||
已经完成第一阶段接入:
|
||||
|
||||
- `server/src/app/services/steward_graph_planner.py`
|
||||
- 已新增 `StewardGraphPlannerService`。
|
||||
- 已用 LangGraph `StateGraph` 编排 `prepare_context -> detect_model_intent -> done/off_topic/rule_fallback`。
|
||||
- `server/src/app/services/steward_graph_runtime.py`
|
||||
- 已新增 `StewardGraphRuntime`。
|
||||
- 槽位决策已编排为 `slot_prepare_context -> slot_tool_decision -> done/rule_fallback`。
|
||||
- 运行时决策已编排为 `runtime_memory_context -> runtime_action_decision/runtime_tool_decision -> done/rule_fallback`。
|
||||
- 图内失败会降级到原有规则兜底;端点层图运行异常会回退旧 Agent。
|
||||
- `server/src/app/services/steward_action_contracts.py`
|
||||
- 已新增 `StewardActionPlanBuilder`。
|
||||
- 已把申请、报销、保存草稿、直接提交规划成 `StewardActionStep` 白名单动作。
|
||||
- `StewardGraphPlannerService` 已增加 `attach_action_steps` 节点,计划返回前统一补全动作列表。
|
||||
- `server/src/app/services/steward_action_executor.py`
|
||||
- 已新增 `StewardActionExecutor`。
|
||||
- 已接入 `/steward/actions/execute`,支持未知动作拒绝、缺字段阻断、提交确认门禁、重复申请 precheck、申请/报销草稿真实执行、关联申请单和附件关联。
|
||||
- 申请动作复用 `UserAgentService` 的申请保存/提交能力,报销草稿复用 `ExpenseClaimService.save_or_submit_from_ontology()`。
|
||||
- `server/src/app/services/steward_graph_action_runtime.py`
|
||||
- 已新增 `StewardGraphActionRuntime`。
|
||||
- 已用 LangGraph `StateGraph` 编排 `action_checkpoint_load -> action_execute_node -> action_checkpoint_persist`。
|
||||
- 已通过 `conversation_id + client_trace_id` 在 `AgentConversation.state_json` 中记录 checkpoint、pending interrupt 和幂等重放结果。
|
||||
- `web/src/services/steward.js` / `web/src/views/scripts/stewardPlanModel.js`
|
||||
- 前端已新增 `executeStewardAction()` 服务方法。
|
||||
- steward suggested action 已携带服务端可执行 action step,旧申请预览流仍保留兜底。
|
||||
- `web/src/composables/workbenchAiMode/useWorkbenchAiActionRouter.js`
|
||||
- AI 工作台点击 `steward_execute_action` 时会调用 `/steward/actions/execute`。
|
||||
- 直接提交会先执行 `run_duplicate_precheck`,precheck 通过后再提交申请。
|
||||
- `server/src/app/api/v1/endpoints/steward.py`
|
||||
- `/steward/plans` 和 `/steward/plans/stream` 默认使用 `StewardGraphPlannerService`。
|
||||
- `/steward/slot-decisions` 和 `/steward/runtime-decisions` 默认使用 `StewardGraphRuntime`。
|
||||
- `STEWARD_AGENT_RUNTIME=legacy` 可回退旧 `StewardPlannerService`。
|
||||
- `server/pyproject.toml` / `server/uv.lock`
|
||||
- 已加入 `langgraph>=1.2.0,<2.0.0`。
|
||||
- `server/tests/test_steward_graph_planner.py`
|
||||
- 已覆盖默认 LangGraph、显式 LangGraph、legacy 回退、模型成功计划和模型失败后规则兜底。
|
||||
- `server/tests/test_steward_graph_runtime.py`
|
||||
- 已覆盖槽位工具节点、图内规则兜底、运行时记忆合并、确定性行动选择和端点级 legacy 兜底。
|
||||
- `server/tests/test_application_fact_resolver.py`
|
||||
- 已覆盖 `交通火车` 不污染申请事由,以及 `高铁往返` 这类业务描述仍保留。
|
||||
|
||||
当前已完成规划入口、slot decision、runtime decision、基础 action contract、第一版 action executor、前端点击执行闭环,以及 action runtime 的 checkpoint / interrupt / 幂等重放。
|
||||
真实外部模型连通性仍需要用当前 MiniMax / backup 配置再回放确认。
|
||||
|
||||
## 官方能力边界
|
||||
|
||||
LangGraph 官方文档强调它是低层 agent orchestration runtime,重点能力是 durable execution、streaming、human-in-the-loop 和 persistence。
|
||||
|
||||
本项目只采用这些底层编排能力:
|
||||
|
||||
- Graph API:用 state、node、edge 表达流程,node 可以是 LLM 调用,也可以是普通业务代码。
|
||||
- Persistence:用 checkpointer 保存 thread scoped state,用 store 保存跨线程长期信息。
|
||||
- Interrupt:在需要用户确认时暂停 graph,等待外部输入后恢复。
|
||||
|
||||
参考:
|
||||
|
||||
- <https://docs.langchain.com/oss/python/langgraph/overview>
|
||||
- <https://docs.langchain.com/oss/python/langgraph/graph-api>
|
||||
- <https://docs.langchain.com/oss/python/langgraph/persistence>
|
||||
- <https://docs.langchain.com/oss/python/langgraph/interrupts>
|
||||
|
||||
## 总体目标架构
|
||||
|
||||
```text
|
||||
用户输入 / 前端上下文 / 附件
|
||||
↓
|
||||
StewardGraphRuntime
|
||||
├── prepare_context_node
|
||||
├── model_intent_node
|
||||
├── slot_decision_node
|
||||
├── flow_guard_node
|
||||
├── action_plan_node
|
||||
├── human_review_node
|
||||
├── action_execute_node
|
||||
├── persist_state_node
|
||||
└── response_adapter_node
|
||||
↓
|
||||
现有前端协议:StewardPlanResponse / StewardRuntimeDecisionResponse / StewardSlotDecisionResponse
|
||||
```
|
||||
|
||||
关键原则:
|
||||
|
||||
- API 响应协议稳定,前端不因为 runtime 替换被迫大改。
|
||||
- 模型只负责理解、拆步骤、给候选 action,不直接写库。
|
||||
- 所有副作用节点必须调用现有业务服务,并保留确认和审计。
|
||||
- `RuntimeChatService` 继续是唯一模型调用入口,LangGraph 不直接管理供应商密钥。
|
||||
- `StewardFlowStateService` 和 `AgentConversationService` 是 checkpoint 落库的第一候选,不另起一套状态源。
|
||||
|
||||
## Runtime State 草案
|
||||
|
||||
第一版 graph state 用 `TypedDict`,后续需要持久化时再评估 Pydantic schema。
|
||||
|
||||
```python
|
||||
class StewardGraphState(TypedDict, total=False):
|
||||
request: StewardPlanRequest
|
||||
conversation_id: str
|
||||
thread_id: str
|
||||
message: str
|
||||
base_date: date
|
||||
steward_state: dict[str, Any]
|
||||
model_call_traces: list[dict[str, Any]]
|
||||
intent_result: StewardIntentAgentResult | None
|
||||
slot_decision: StewardSlotDecisionResponse | None
|
||||
runtime_decision: StewardRuntimeDecisionResponse | None
|
||||
action_plan: list[StewardActionStep]
|
||||
pending_interrupt: dict[str, Any]
|
||||
action_result: dict[str, Any]
|
||||
response: StewardPlanResponse | StewardRuntimeDecisionResponse | StewardSlotDecisionResponse
|
||||
fallback_reason: str
|
||||
```
|
||||
|
||||
`thread_id` 推荐使用现有 `conversation_id`,这样 LangGraph checkpoint、业务会话和前端会话能对齐。
|
||||
|
||||
## 节点边界
|
||||
|
||||
### 感知节点
|
||||
|
||||
- `prepare_context_node`
|
||||
- 输入:`StewardPlanRequest` 或 runtime decision request。
|
||||
- 输出:清洗后的消息、base date、当前 conversation state。
|
||||
- 禁止:模型调用、数据库写入。
|
||||
|
||||
- `model_intent_node`
|
||||
- 调用:`StewardIntentAgent.detect()`。
|
||||
- 约束:保留 `timeout_seconds=10`、`max_attempts=3`、`use_failure_cooldown=False`。
|
||||
- 失败:只写入 `fallback_reason` 和 `model_call_traces`,不吞掉错误上下文。
|
||||
|
||||
### 决策节点
|
||||
|
||||
- `slot_decision_node`
|
||||
- 迁移对象:`StewardSlotDecisionAgent.decide()`。
|
||||
- 目标:让字段缺口判断进入同一个 graph state,不再由前端和后端多个入口各自推断。
|
||||
|
||||
- `runtime_decision_node`
|
||||
- 迁移对象:`StewardRuntimeDecisionAgent.decide()`。
|
||||
- 目标:用户补字段、确认流程、取消当前动作、继续下一任务都走 graph routing。
|
||||
|
||||
- `flow_guard_node`
|
||||
- 负责申请/报销歧义、重复单据、时间重叠、低置信度、off-topic。
|
||||
- 低置信度或强冲突必须进入确认或阻断,不允许继续 action 执行。
|
||||
|
||||
### 行动节点
|
||||
|
||||
- `action_plan_node`
|
||||
- 输出白名单步骤,例如 `build_application_preview`、`save_application_draft`、`submit_application`。
|
||||
- 禁止输出自由文本 action。
|
||||
|
||||
- `human_review_node`
|
||||
- 对保存草稿、提交审批、关联申请单等副作用动作生成 interrupt payload。
|
||||
- 第一阶段可继续返回前端确认动作;第二阶段再接 LangGraph `interrupt()`。
|
||||
|
||||
- `action_execute_node`
|
||||
- 只能调用现有业务服务。
|
||||
- 必须幂等,或在执行前检查动作是否已完成。
|
||||
- 提交类动作必须检查 `confirmation_required` 和用户确认来源。
|
||||
|
||||
- `persist_state_node`
|
||||
- 合并 `StewardFlowStateService.merge_plan()` / `merge_state()`。
|
||||
- 后续接入 LangGraph checkpointer 后,这里负责业务状态与 checkpoint 的一致性。
|
||||
|
||||
### 响应节点
|
||||
|
||||
- `response_adapter_node`
|
||||
- 输出现有 Pydantic response。
|
||||
- 必须保留 `model_call_traces`、`planning_source`、`steward_state`。
|
||||
|
||||
## 分阶段计划
|
||||
|
||||
### Phase 0:规划入口接入 LangGraph
|
||||
|
||||
状态:已完成。
|
||||
|
||||
完成标准:
|
||||
|
||||
- [x] 默认 runtime 为 `langgraph`。
|
||||
- [x] `STEWARD_AGENT_RUNTIME=legacy` 可回退。
|
||||
- [x] `/steward/plans` 真实接口仍返回兼容的 `StewardPlanResponse`。
|
||||
- [x] 模型失败后仍按 10s * 3 次再规则降级。
|
||||
|
||||
### Phase 1:修通模型成功路径
|
||||
|
||||
目标:让真实保存草稿话术至少能走一次 `llm_function_call` 成功路径。
|
||||
|
||||
文件:
|
||||
|
||||
- 修改:`server/src/app/services/runtime_chat.py`
|
||||
- 修改:`server/src/app/services/settings.py`
|
||||
- 修改:`server/tests/test_runtime_chat_service.py`
|
||||
- 测试:`server/tests/test_steward_intent_agent.py`
|
||||
|
||||
步骤:
|
||||
|
||||
- [x] 写失败测试:模拟 main provider 超时但 backup provider 可用时,`complete_with_tool_call()` 返回 backup 的 tool call。
|
||||
- [x] 确认 backup function calling 会在 main 失败后返回 tool call,不等待 main 重试结束。
|
||||
- [ ] 写失败测试:MiniMax 返回非 OpenAI tool call 兼容格式时,服务端能记录清晰 trace 并降级。
|
||||
- [x] 容器内运行:
|
||||
|
||||
```bash
|
||||
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-local-linux \
|
||||
timeout 60s /tmp/x-financial-server-venv/bin/pytest -q \
|
||||
server/tests/test_runtime_chat_service.py \
|
||||
server/tests/test_steward_intent_agent.py
|
||||
```
|
||||
|
||||
验收:
|
||||
|
||||
- [ ] 真实 `/api/v1/steward/plans` 对保存草稿原句返回 `planning_source=llm_function_call`。
|
||||
- [x] `model_call_traces` 能区分 main 失败、backup 成功或全失败。
|
||||
|
||||
### Phase 2:slot/runtime decision 迁入 graph
|
||||
|
||||
目标:把字段缺口和运行时动作判断从独立 agent 类迁进同一个 graph runtime。
|
||||
|
||||
状态:已完成。
|
||||
|
||||
文件:
|
||||
|
||||
- 已创建:`server/src/app/services/steward_graph_runtime.py`
|
||||
- 已修改:`server/src/app/api/v1/endpoints/steward.py`
|
||||
- 已测试:`server/tests/test_steward_graph_runtime.py`
|
||||
- 保留测试:`server/tests/test_steward_slot_decision_agent.py`
|
||||
- 保留测试:`server/tests/test_steward_runtime_decision_agent.py`
|
||||
|
||||
步骤:
|
||||
|
||||
- [x] 写失败测试:`StewardGraphRuntime.decide_slot()` 调用 slot node 后返回与现有 `StewardSlotDecisionAgent.decide()` 等价的 response。
|
||||
- [x] 写失败测试:`StewardGraphRuntime.decide_runtime()` 在用户补充字段时合并 `steward_state`。
|
||||
- [x] 把 `StewardSlotDecisionAgent` 包成 `slot_tool_decision` 节点。
|
||||
- [x] 把 `StewardRuntimeDecisionAgent` 包成 `runtime_tool_decision` 节点。
|
||||
- [x] 把已选流程确认和当前运行时记忆归一化拆成 `runtime_memory_context` / `runtime_action_decision` 节点。
|
||||
- [x] endpoint 在 `STEWARD_AGENT_RUNTIME=langgraph` 时使用 graph runtime。
|
||||
- [x] endpoint 在 graph runtime 异常时回退旧 Agent,避免框架层失效影响会话。
|
||||
|
||||
验收:
|
||||
|
||||
- [x] `slot-decisions`、`runtime-decisions` 和 `plans` 三个入口都由 LangGraph runtime 路由。
|
||||
- [x] legacy 回退仍可用。
|
||||
- [x] 图内工具节点失败时仍有可执行规则兜底。
|
||||
|
||||
### Phase 3:action node 标准化
|
||||
|
||||
目标:把保存草稿、提交审批、关联申请单这些副作用动作变成显式 action node。
|
||||
|
||||
状态:基础 action contract、第一版 action executor、前端点击执行闭环、LangGraph action node、checkpoint、pending interrupt 和幂等重放已完成;后续只剩 durable checkpointer 抽象与更完整 trace UI。
|
||||
|
||||
文件:
|
||||
|
||||
- 已创建:`server/src/app/services/steward_action_executor.py`
|
||||
- 已创建:`server/src/app/services/steward_action_contracts.py`
|
||||
- 已创建:`server/src/app/services/steward_graph_action_runtime.py`
|
||||
- 已修改:`server/src/app/api/v1/endpoints/steward.py`
|
||||
- 已修改:`server/src/app/services/steward_graph_planner.py`
|
||||
- 已修改:`server/src/app/schemas/steward.py`
|
||||
- 已修改:`web/src/services/steward.js`
|
||||
- 已修改:`web/src/views/scripts/stewardPlanModel.js`
|
||||
- 已修改:`web/src/composables/workbenchAiMode/useWorkbenchAiActionRouter.js`
|
||||
- 已修改:`web/src/composables/workbenchAiMode/usePersonalWorkbenchAiMode.js`
|
||||
- 已测试:`server/tests/test_steward_action_executor.py`
|
||||
- 已测试:`server/tests/test_steward_graph_planner.py`
|
||||
- 已测试:`server/tests/test_steward_planner.py`
|
||||
- 已测试:`web/tests/workbench-ai-intent-planner-model.test.mjs`
|
||||
- 已测试:`web/tests/steward-actions-service.test.mjs`
|
||||
- 已测试:`web/tests/steward-plan-message-copy.test.mjs`
|
||||
- 已测试:`web/tests/workbench-ai-action-router.test.mjs`
|
||||
|
||||
白名单 action:
|
||||
|
||||
- `build_application_preview`
|
||||
- `save_application_draft`
|
||||
- `submit_application`
|
||||
- `link_existing_application`
|
||||
- `create_reimbursement_draft`
|
||||
- `associate_attachments`
|
||||
|
||||
步骤:
|
||||
|
||||
- [x] 写失败测试:申请直接提交计划必须输出 `fill_application_fields -> build_application_preview -> validate_required_fields -> run_duplicate_precheck -> submit_application`。
|
||||
- [x] 写失败测试:保存草稿计划必须输出 `save_application_draft`,并在字段缺失时阻断后续副作用。
|
||||
- [x] 写失败测试:报销计划必须输出 `fill_reimbursement_fields -> build_reimbursement_preview -> validate_required_fields -> create_reimbursement_draft`。
|
||||
- [x] 在 `StewardTask` 和 `StewardPlanResponse` 中增加 `action_steps`。
|
||||
- [x] 实现 `StewardActionPlanBuilder`,由服务端确定性生成白名单 action step。
|
||||
- [x] 在 LangGraph planner 中新增 `attach_action_steps` 节点。
|
||||
- [x] 前端 planner model 优先消费服务端 `task.action_steps`,旧响应才回退本地推导。
|
||||
- [x] 写失败测试:未知 action step 被拒绝,不调用任何业务服务。
|
||||
- [x] 写失败测试:`submit_application` 缺少确认来源时返回 `needs_confirmation`。
|
||||
- [x] 写失败测试:`submit_application` 必须看到 precheck 通过后才允许真实提交。
|
||||
- [x] 实现 action registry,只允许白名单 action。
|
||||
- [x] 接入现有申请保存草稿、申请提交和报销草稿服务。
|
||||
- [x] 前端新增 `executeStewardAction()` 并让 suggested action 携带服务端 action step。
|
||||
- [x] AI 工作台点击 suggested action 时调用 `StewardActionExecutor`;直接提交先串行执行 precheck,再把结果交给 submit。
|
||||
- [x] 接入 `link_existing_application` 和附件关联的真实执行。
|
||||
- [x] 把 action executor 包成 LangGraph `action_execute_node`,并接入 checkpoint / interrupt 恢复。
|
||||
|
||||
验收:
|
||||
|
||||
- [x] 模型不能通过自由文本触发数据库写入,服务端只输出白名单 `StewardActionStep`。
|
||||
- [x] 申请提交动作没有确认时返回 `needs_confirmation`,不会写库。
|
||||
- [x] 申请提交动作没有 precheck 通过证据时被阻断。
|
||||
- [x] 保存申请草稿和创建报销草稿通过现有业务服务真实入库,测试覆盖。
|
||||
- [x] 前端点击可执行 steward action 会真实调用 executor,并把结果回写到会话消息。
|
||||
- [x] 基础副作用动作有 `client_trace_id` 幂等键、conversation checkpoint 和 pending interrupt 记录。
|
||||
|
||||
### Phase 4:checkpoint 与 human-in-the-loop
|
||||
|
||||
目标:让 LangGraph 负责暂停、恢复和跨轮状态,而不是只靠前端消息状态。
|
||||
|
||||
文件:
|
||||
|
||||
- 已创建:`server/src/app/services/steward_graph_action_runtime.py`
|
||||
- 已复用:`server/src/app/models/agent_conversation.py`
|
||||
- 已测试:`server/tests/test_steward_action_executor.py`
|
||||
|
||||
步骤:
|
||||
|
||||
- [x] 设计 `conversation_id -> thread_id` 映射,当前直接以 `conversation_id` 作为 graph action thread。
|
||||
- [x] 实现基于数据库的 checkpoint,先复用 `AgentConversation.state_json`。
|
||||
- [x] 在提交审批缺确认时生成 pending interrupt payload。
|
||||
- [x] 用户确认后用同一 `client_trace_id` / `conversation_id` 继续执行;终态请求会幂等重放。
|
||||
|
||||
验收:
|
||||
|
||||
- [x] 刷新页面后,后端仍保留当前等待确认的 action checkpoint。
|
||||
- [x] 同一个 action 不会因为重复点击或重试重复写库。
|
||||
- [ ] 前端完整恢复 UI 仍需继续把 checkpoint 状态展示为可恢复按钮。
|
||||
|
||||
### Phase 5:可观测性与 legacy 收敛
|
||||
|
||||
目标:让 agent 规划过程可解释、可测试、可回放,并逐步删除重复手写编排。
|
||||
|
||||
文件:
|
||||
|
||||
- 修改:`server/src/app/services/agent_traces.py`
|
||||
- 修改:`server/src/app/models/agent_run.py`
|
||||
- 修改:`document/development/Agent链路追踪中心/CONCEPT.md`
|
||||
- 测试:`server/tests/test_agent_traces.py`
|
||||
|
||||
步骤:
|
||||
|
||||
- [ ] 每个 graph node 写入 trace event:输入摘要、输出摘要、耗时、错误。
|
||||
- [ ] 前端显示“模型规划中 / 字段判断中 / 等待确认 / 执行动作”阶段。
|
||||
- [ ] 对 legacy planner 增加废弃标记和删除条件。
|
||||
- [ ] 删除重复的手写分支前,先保留至少一轮灰度开关。
|
||||
|
||||
验收:
|
||||
|
||||
- 任何一次用户请求都能从 trace 看出走过哪些 node。
|
||||
- 删除 legacy 前,LangGraph 路径覆盖当前核心申请/报销链路测试。
|
||||
|
||||
## 回退策略
|
||||
|
||||
- 环境变量:
|
||||
|
||||
```bash
|
||||
STEWARD_AGENT_RUNTIME=legacy
|
||||
```
|
||||
|
||||
- 回退后:
|
||||
- `/steward/plans` 使用旧 `StewardPlannerService`。
|
||||
- 新 action node 和 checkpoint 不应影响 legacy。
|
||||
- 回退原因必须写入当天工作日志。
|
||||
|
||||
## 验证矩阵
|
||||
|
||||
每个阶段至少跑:
|
||||
|
||||
```bash
|
||||
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-local-linux \
|
||||
timeout 60s /tmp/x-financial-server-venv/bin/pytest -q \
|
||||
server/tests/test_steward_graph_planner.py \
|
||||
server/tests/test_steward_planner.py \
|
||||
server/tests/test_steward_intent_agent.py \
|
||||
server/tests/test_runtime_chat_service.py
|
||||
```
|
||||
|
||||
涉及前端执行器时补跑:
|
||||
|
||||
```bash
|
||||
node --test web/tests/workbench-ai-intent-planner-model.test.mjs \
|
||||
web/tests/workbench-ai-application-gate-model.test.mjs \
|
||||
web/tests/steward-actions-service.test.mjs \
|
||||
web/tests/steward-plan-message-copy.test.mjs
|
||||
npm --prefix web run build
|
||||
```
|
||||
|
||||
每次完成后执行:
|
||||
|
||||
```bash
|
||||
git diff --check
|
||||
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-local-linux \
|
||||
/tmp/x-financial-server-venv/bin/python -m pip check
|
||||
```
|
||||
|
||||
## 不做的事
|
||||
|
||||
- 不引入 LangChain 高层 Agent 来替代现有业务服务。
|
||||
- 不让模型直接调用数据库写入、提交审批或绑定附件。
|
||||
- 不为了接框架重写申请、报销、OCR、票据夹、审批规则。
|
||||
- 不在没有测试覆盖时删除 legacy planner。
|
||||
|
||||
## 风险与处理
|
||||
|
||||
- 模型连通性不稳定:先修 provider 和 backup,再扩大 graph 节点。
|
||||
- checkpoint 与业务 state 双写不一致:先复用 `AgentConversation.state_json`,不要新增第二个业务状态源。
|
||||
- action node 副作用重复执行:每个 action 必须有幂等键和执行前状态检查。
|
||||
- LangGraph 传递依赖影响 WebSocket:当前 `pip check` 通过;后续若流式接口异常,先核对 `websockets` 版本。
|
||||
- 节点内继续堆大块逻辑:每个 node 只做一类事,超过 300 行先拆文件。
|
||||
32
document/development/AI意图规划器/TODO.md
Normal file
32
document/development/AI意图规划器/TODO.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# AI 意图规划器 TODO
|
||||
|
||||
## 第一阶段
|
||||
|
||||
- [x] 落地 AI 意图规划器概念文档,明确大模型负责拆计划、业务代码负责执行。
|
||||
- [x] 新增前端 planner model,统一模型计划和本地 fallback 的输出结构。
|
||||
- [x] 个人工作台 AI 模式先请求 steward 模型计划,再使用本地 fallback。
|
||||
- [x] 差旅申请直提链路改为消费 `intent plan.steps`,不再直接消费正则识别结果。
|
||||
- [x] 补齐 planner model 与主流程接线回归测试。
|
||||
- [x] 跑前端构建和定向测试。
|
||||
- [x] 后端 `/steward/plans` 增加 `requested_action` 输出,减少前端从原句推断“提交/保存”的比例。
|
||||
- [x] 引入 LangGraph,并默认用 `StewardGraphPlannerService` 接管 `/steward/plans` 规划编排。
|
||||
- [x] 落地 LangGraph runtime 迁移计划文档:`LANGGRAPH_RUNTIME_MIGRATION.md`。
|
||||
- [x] 新增 `StewardGraphRuntime`,接管 `slot-decisions` 和 `runtime-decisions` 的 LangGraph 路由。
|
||||
- [x] 为 LangGraph runtime 增加图内规则兜底和端点级 legacy Agent 兜底。
|
||||
- [x] 为 `/steward/plans` 增加服务端白名单 `action_steps`,覆盖申请、报销、保存草稿和直接提交的基础动作规划。
|
||||
- [x] 前端 planner model 优先消费服务端 `task.action_steps`,旧响应才回退本地步骤推导。
|
||||
- [x] 新增 `/steward/actions/execute` 和 `StewardActionExecutor`,把未知 action 拒绝、提交确认门禁、precheck 阻断、申请草稿保存、申请提交和报销草稿创建接到现有业务服务。
|
||||
- [x] 前端新增 `executeStewardAction()` 服务方法,并让 steward suggested action 携带服务端可执行 action step。
|
||||
- [x] AI 工作台点击可执行 steward action 时调用 `/steward/actions/execute`;申请直接提交会先跑 `run_duplicate_precheck`,通过后再提交。
|
||||
- [x] `complete_with_tool_call()` 增加 main 失败后 backup tool-call 成功路径测试,保证模型成功路径能从 backup 返回 `llm_function_call`。
|
||||
- [x] 新增 `StewardGraphActionRuntime`,把 action executor 包成 LangGraph `action_execute_node`,并用 `conversation_id + client_trace_id` 在 `AgentConversation.state_json` 中持久化 checkpoint。
|
||||
- [x] 对提交确认生成 pending interrupt;重复 client trace 直接重放 checkpoint,避免重复保存草稿或重复提交。
|
||||
- [x] `link_existing_application` 接入现有报销草稿创建链路并写入申请关联 flag。
|
||||
- [x] `associate_attachments` 接入现有附件关联 runner,按 receipt_ids 归集到可匹配报销草稿。
|
||||
|
||||
## 后续阶段
|
||||
|
||||
- [ ] 用真实 MiniMax / backup 配置再回放 `/steward/plans`,确认真实环境返回 `planning_source=llm_function_call`,不是规则兜底。
|
||||
- [ ] 将当前 `AgentConversation.state_json` checkpoint 抽象为可替换的 durable checkpointer,并补恢复/清理策略。
|
||||
- [ ] 为每个 LangGraph node 写入可追溯 trace,展示模型调用、规则降级、等待确认和动作执行结果。
|
||||
- [ ] 在 LangGraph 路径覆盖申请/报销核心链路后,再逐步删除旧 `StewardPlannerService` 的重复编排。
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
# 附件自动关联后台任务方案
|
||||
|
||||
## 背景
|
||||
|
||||
小财管家 AI 模式里,用户上传票据后会先做 OCR。当前附件自动关联报销草稿的后半段仍依赖前端会话内存:
|
||||
|
||||
- 前端保留浏览器里的 `File` 对象。
|
||||
- 前端在当前会话里完成草稿匹配。
|
||||
- 用户点击“确认自动关联”后,再用这些 `File` 上传到报销单明细。
|
||||
|
||||
这会带来一个核心问题:用户发送消息后,如果刷新页面、切换会话或退出当前会话,浏览器内存里的附件原件会丢失,历史消息中的关联动作就无法继续执行。
|
||||
|
||||
票据夹已经能持久化 OCR 结果和源文件,并且 OCR 返回里已经带有 `receipt_id`。所以正式方案应该把“附件关联”从前端内存任务调整为后端可查询任务。
|
||||
|
||||
## 目标
|
||||
|
||||
1. 用户一上传附件即触发 OCR,附件卡片显示“识别中”,识别完成后显示“当前附件已识别”。
|
||||
2. 用户点击发送后,前端不再依赖 `File` 原件做后续归集,而是把 OCR 产生的 `receipt_id` 提交给后端。
|
||||
3. 后端创建附件关联任务,并在后台继续匹配、复制票据夹源文件、关联报销单明细。
|
||||
4. 用户退出或刷新当前会话后,前端可通过保存下来的 `job_id` 查询任务状态并更新消息。
|
||||
5. 如果匹配失败、置信度不足或找不到可编辑草稿,系统给出清晰提示,引导用户补充说明、上传附件或新建草稿。
|
||||
|
||||
## 非目标
|
||||
|
||||
第一版不承诺后端服务进程重启后任务状态仍可恢复。
|
||||
|
||||
本次实现使用轻量内存任务池,解决“用户离开前端会话导致连接断开”的问题。后续如果要做到服务重启、横向扩容、任务审计都可恢复,再新增数据库任务表。
|
||||
|
||||
## 核心流程
|
||||
|
||||
```text
|
||||
用户上传票据
|
||||
→ 前端立即调用 OCR
|
||||
→ OCR 写入票据夹并返回 receipt_id
|
||||
→ 附件卡片显示“当前附件已识别”
|
||||
→ 用户点击发送
|
||||
→ 前端 POST 创建附件关联任务
|
||||
→ 后端后台任务继续运行
|
||||
→ 前端轮询 job_id
|
||||
→ 成功:消息显示已关联,并刷新报销单详情
|
||||
→ 失败:消息显示失败原因和下一步动作
|
||||
```
|
||||
|
||||
## 后端设计
|
||||
|
||||
### API
|
||||
|
||||
新增接口:
|
||||
|
||||
- `POST /api/v1/reimbursements/attachment-association-jobs`
|
||||
- `GET /api/v1/reimbursements/attachment-association-jobs/{job_id}`
|
||||
|
||||
创建任务请求只传持久化引用,不传浏览器文件:
|
||||
|
||||
```json
|
||||
{
|
||||
"receipt_ids": ["receipt-1", "receipt-2"],
|
||||
"prompt": "请帮我处理已上传的附件。",
|
||||
"conversation_id": "inline-xxx"
|
||||
}
|
||||
```
|
||||
|
||||
状态返回:
|
||||
|
||||
```json
|
||||
{
|
||||
"job_id": "job-xxx",
|
||||
"status": "running",
|
||||
"message": "正在匹配可关联的报销草稿...",
|
||||
"receipt_ids": ["receipt-1", "receipt-2"],
|
||||
"claim_id": "",
|
||||
"claim_no": "",
|
||||
"uploaded_count": 0,
|
||||
"skipped_count": 0,
|
||||
"error": ""
|
||||
}
|
||||
```
|
||||
|
||||
状态枚举:
|
||||
|
||||
- `queued`:任务已创建,等待后台执行。
|
||||
- `running`:正在匹配和归集。
|
||||
- `succeeded`:已完成自动归集。
|
||||
- `failed`:无法自动完成,返回可读错误。
|
||||
|
||||
### 任务执行
|
||||
|
||||
后端任务执行步骤:
|
||||
|
||||
1. 按 `receipt_ids` 读取票据夹明细和源文件。
|
||||
2. 从票据 OCR 文本、结构化字段、日期、城市提取匹配信号。
|
||||
3. 查询当前用户可见且可编辑的报销草稿,排除申请单和已归档单据。
|
||||
4. 对候选草稿按日期、城市、事由、草稿状态评分。
|
||||
5. 置信度足够时选择目标草稿。
|
||||
6. 为每份票据找到可用费用明细,没有合适明细时创建空明细。
|
||||
7. 从票据夹源文件复制到报销单附件目录,并沿用 `source_receipt_id` 回填 OCR 信息。
|
||||
8. 更新票据夹状态为 `linked`。
|
||||
9. 写入任务最终状态。
|
||||
|
||||
## 前端设计
|
||||
|
||||
### 会话消息
|
||||
|
||||
AI 消息需要持久化 `attachmentAssociationJob`:
|
||||
|
||||
```json
|
||||
{
|
||||
"jobId": "job-xxx",
|
||||
"status": "running",
|
||||
"receiptIds": ["receipt-1", "receipt-2"]
|
||||
}
|
||||
```
|
||||
|
||||
这样历史会话恢复后,不再需要浏览器里的 `File` 对象,只要消息里仍有 `jobId`,就可以继续查询后端状态。
|
||||
|
||||
### 发送行为
|
||||
|
||||
当用户上传附件并点击发送:
|
||||
|
||||
1. 前端确认 OCR 已完成。
|
||||
2. 从 OCR 结果里提取 `receipt_id`。
|
||||
3. 创建后端任务。
|
||||
4. 立即持久化带 `job_id` 的 pending 消息。
|
||||
5. 页面仍打开时轮询任务状态。
|
||||
6. 页面恢复或打开历史会话时,对未完成任务继续轮询。
|
||||
|
||||
## 异常处理
|
||||
|
||||
- 未完成 OCR:禁止发送,提示“附件 OCR 识别中,请稍等,识别完成后再继续对话。”
|
||||
- OCR 失败:禁止发送,提示“请先移除识别失败的附件或重新上传。”
|
||||
- 没有 `receipt_id`:提示“当前附件没有持久化票据记录,请重新上传后再试。”
|
||||
- 没有可编辑草稿:任务失败,提示用户先新建或选择草稿。
|
||||
- 多个候选置信度接近:第一版不自动归集,提示补充说明或手动选择。
|
||||
- 服务重启导致内存任务丢失:返回任务不存在,前端提示“后台任务状态已失效,请重新发送附件关联请求。”
|
||||
|
||||
## 验收标准
|
||||
|
||||
1. 上传附件后必须先进入 OCR 识别中状态,识别完成前不能发送对话。
|
||||
2. 发送附件关联请求后,前端能收到并保存 `job_id`。
|
||||
3. 用户离开当前会话后,后端任务仍会继续执行。
|
||||
4. 用户回到历史会话后,前端可以根据 `job_id` 查询并更新最终状态。
|
||||
5. 成功后报销单明细出现附件,票据夹状态变为已关联。
|
||||
6. 找不到草稿、低置信度、源文件缺失时,消息能给出明确原因。
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# 附件自动关联后台任务 TODO
|
||||
|
||||
- [x] 梳理当前前端内存任务断链原因。
|
||||
- [x] 明确第一版边界:页面/会话退出可恢复,服务进程重启暂不承诺恢复。
|
||||
- [x] 新增后端任务 schema。
|
||||
- [x] 新增后端后台任务服务。
|
||||
- [x] 新增任务创建和查询接口。
|
||||
- [x] 补后端任务测试。
|
||||
- [x] 新增前端任务 service。
|
||||
- [x] 调整 AI 模式附件关联流程为创建后端任务。
|
||||
- [x] 持久化消息里的 `attachmentAssociationJob`。
|
||||
- [x] 历史会话恢复时继续轮询未完成任务。
|
||||
- [x] 更新前端源码断言测试。
|
||||
- [x] 容器内运行后端定向测试。
|
||||
- [x] 运行前端定向测试和构建。
|
||||
|
||||
## 验证记录
|
||||
|
||||
- `docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-local-linux /tmp/x-financial-server-venv/bin/pytest -q server/tests/test_attachment_association_jobs.py server/tests/test_ocr_endpoints.py server/tests/test_reimbursement_endpoints.py::test_claim_item_attachment_upload_preview_and_delete server/tests/test_openapi_schema.py`
|
||||
- `node --test web/tests/workbench-ai-mode-switch.test.mjs web/tests/ai-attachment-association-model.test.mjs`
|
||||
- `npm --prefix web run build`
|
||||
- 已重启 `x-financial-local-linux`,并确认 `/api/v1/reimbursements/attachment-association-jobs/not-exist` 返回自定义任务失效提示。
|
||||
@@ -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
@@ -0,0 +1,515 @@
|
||||
# 员工业务行为画像模型方案
|
||||
|
||||
## 目标
|
||||
|
||||
员工业务行为画像用于把费用申请、审批流转、AI 协作和数字员工巡检中产生的行为数据沉淀为可解释的统计画像。
|
||||
|
||||
它不是给员工贴负面标签,也不是替代审批人做最终判断,而是为以下场景提供结构化依据:
|
||||
|
||||
- 费用审批详情页展示申请人近期费用节奏和材料质量。
|
||||
- Hermes 数字员工定期巡检高频费用、异常预算占用和流程质量问题。
|
||||
- 运营看板观察 AI 使用、Token 消耗、流程耗时和审核效率。
|
||||
- 后续规则中心根据真实覆盖率和人工覆盖情况优化规则阈值。
|
||||
|
||||
## 设计原则
|
||||
|
||||
1. 不把不同性质的数据混成一个总分。
|
||||
2. 费用风险、流程质量、AI 使用、审批行为必须分维度计算。
|
||||
3. 画像结果必须能追溯到指标、窗口期、同组基准和计算时间。
|
||||
4. Hermes 负责调度和沉淀快照,确定性算法负责计算,LLM 只可用于解释和报告。
|
||||
5. 画像用于审批参考和运营治理,不直接作为惩罚或自动降标依据。
|
||||
|
||||
## 画像分层
|
||||
|
||||
```text
|
||||
员工业务行为画像
|
||||
├── 费用支出画像
|
||||
├── 流程质量画像
|
||||
├── AI 协作画像
|
||||
└── 审批行为画像
|
||||
```
|
||||
|
||||
### 费用支出画像
|
||||
|
||||
用于判断申请人的费用节奏是否显著高于同组基准。
|
||||
|
||||
核心指标:
|
||||
|
||||
- 近 30 / 90 / 180 天申请次数。
|
||||
- 近 30 / 90 / 180 天申请金额。
|
||||
- 差旅申请次数、出差天数、日均费用。
|
||||
- 招待申请次数、人均招待金额、同客户重复招待次数。
|
||||
- 个人费用占部门预算比例。
|
||||
- 个人费用占项目预算比例。
|
||||
- 同部门、同岗位、同费用类型分位数。
|
||||
- 历史调减、退回、复核次数。
|
||||
|
||||
审批用途:
|
||||
|
||||
- 识别高频费用申请人。
|
||||
- 提醒审核者复核出差天数和费用标准。
|
||||
- 推荐补充业务必要性、拆分费用或升级审批。
|
||||
|
||||
### 流程质量画像
|
||||
|
||||
用于判断申请人提交材料和流程配合质量。
|
||||
|
||||
核心指标:
|
||||
|
||||
- 草稿到提交平均耗时。
|
||||
- 退回到重新提交平均耗时。
|
||||
- 退单次数。
|
||||
- 补充材料次数。
|
||||
- 附件缺失次数。
|
||||
- 发票金额不一致次数。
|
||||
- 申请事由缺失次数。
|
||||
- 业务地点缺失次数。
|
||||
- 项目编号缺失次数。
|
||||
- 同一申请多次修改次数。
|
||||
|
||||
审批用途:
|
||||
|
||||
- 提示“近期材料质量偏低,需要重点核对附件和事由”。
|
||||
- 对高频退单申请人提高材料完整性检查权重。
|
||||
- 对低质量申请触发补充材料建议,而不是直接判定费用风险。
|
||||
|
||||
### AI 协作画像
|
||||
|
||||
用于观察员工和系统的 AI 协作行为,不直接判定费用风险。
|
||||
|
||||
核心指标:
|
||||
|
||||
- AI 调用次数。
|
||||
- AI 辅助生成申请次数。
|
||||
- AI 解析票据次数。
|
||||
- AI 预审次数。
|
||||
- 语义解析次数。
|
||||
- 输入 Token。
|
||||
- 输出 Token。
|
||||
- 总 Token。
|
||||
- 估算调用成本。
|
||||
- AI 建议被采纳次数。
|
||||
- AI 建议被人工覆盖次数。
|
||||
- AI 生成后人工修改次数。
|
||||
|
||||
运营用途:
|
||||
|
||||
- 观察哪些流程高度依赖 AI。
|
||||
- 识别高成本用户、部门或功能入口。
|
||||
- 衡量 AI 建议采纳率和被覆盖率。
|
||||
- 为模型配置、成本控制和产品优化提供依据。
|
||||
|
||||
审批边界:
|
||||
|
||||
AI 使用多不等于风险高。Token 消耗、AI 调用次数不应直接推高费用审批风险,只能作为运营和辅助说明。
|
||||
|
||||
### 审批行为画像
|
||||
|
||||
用于分析审批人的审核效率和审核风格。
|
||||
|
||||
核心指标:
|
||||
|
||||
- 平均审核时长。
|
||||
- 中位审核时长。
|
||||
- 超 SLA 次数。
|
||||
- 直接通过率。
|
||||
- 退回率。
|
||||
- 调减率。
|
||||
- 高风险单据通过率。
|
||||
- 系统建议采纳率。
|
||||
- 系统建议覆盖率。
|
||||
- 审批意见完整度。
|
||||
- 审批积压数量。
|
||||
|
||||
治理用途:
|
||||
|
||||
- 识别审批积压。
|
||||
- 识别过度宽松或过度退回的审批模式。
|
||||
- 评估规则建议是否被人工持续覆盖。
|
||||
- 为流程优化和审批授权调整提供依据。
|
||||
|
||||
## 计算窗口
|
||||
|
||||
第一版建议支持三个窗口:
|
||||
|
||||
```text
|
||||
30 天:识别近期异常波动
|
||||
90 天:作为审批详情页默认画像
|
||||
180 天:用于稳定趋势和年度预算节奏
|
||||
```
|
||||
|
||||
审批详情页默认读取 `90 天` 画像。运营看板可以切换 30 / 90 / 180 天。
|
||||
|
||||
## 同组基准
|
||||
|
||||
费用支出画像必须和可比人群比较,不能全公司一刀切。
|
||||
|
||||
建议同组口径:
|
||||
|
||||
```text
|
||||
peer_group =
|
||||
department_id
|
||||
+ position
|
||||
+ grade
|
||||
+ expense_type_scope
|
||||
+ city_tier
|
||||
+ project_type
|
||||
+ window_days
|
||||
```
|
||||
|
||||
当某个同组样本量不足时,逐级回退:
|
||||
|
||||
```text
|
||||
部门 + 岗位 + 费用类型
|
||||
→ 部门 + 费用类型
|
||||
→ 岗位 + 费用类型
|
||||
→ 公司 + 费用类型
|
||||
```
|
||||
|
||||
回退必须写入 `peer_group_fallback_level`,避免审核者误以为基准非常精确。
|
||||
|
||||
## 分值模型
|
||||
|
||||
### 不建议使用一个大总分
|
||||
|
||||
不要这样计算:
|
||||
|
||||
```text
|
||||
综合风险分 = 费用金额 + Token 消耗 + 操作时长 + 审核时长 + 退单次数
|
||||
```
|
||||
|
||||
原因:
|
||||
|
||||
- Token 高可能代表高频使用 AI,不代表费用风险。
|
||||
- 审核时长是审批人的行为,不是申请人的费用风险。
|
||||
- 退单次数可能代表材料质量问题,不一定代表费用不合理。
|
||||
- 一个总分会掩盖到底是哪一类风险触发。
|
||||
|
||||
### 建议使用多维分
|
||||
|
||||
```text
|
||||
employee_behavior_profile =
|
||||
expense_profile_score
|
||||
process_quality_score
|
||||
ai_usage_score
|
||||
approval_behavior_score
|
||||
```
|
||||
|
||||
每个分值都有自己的等级:
|
||||
|
||||
```text
|
||||
0-39 normal
|
||||
40-59 watch
|
||||
60-79 review
|
||||
80-100 escalation
|
||||
```
|
||||
|
||||
审批详情页只展示与当前场景相关的分值:
|
||||
|
||||
```text
|
||||
费用申请审批:
|
||||
展示 expense_profile_score
|
||||
展示 process_quality_score
|
||||
隐藏或弱化 ai_usage_score
|
||||
不展示 approval_behavior_score
|
||||
|
||||
运营看板:
|
||||
展示四类分值和趋势
|
||||
```
|
||||
|
||||
## 指标权重建议
|
||||
|
||||
### 费用支出画像分
|
||||
|
||||
```text
|
||||
expense_profile_score =
|
||||
frequency_score * 20%
|
||||
+ amount_occupancy_score * 25%
|
||||
+ peer_deviation_score * 25%
|
||||
+ adjustment_history_score * 15%
|
||||
+ current_claim_deviation_score * 15%
|
||||
```
|
||||
|
||||
### 流程质量画像分
|
||||
|
||||
```text
|
||||
process_quality_score =
|
||||
return_count_score * 25%
|
||||
+ missing_attachment_score * 20%
|
||||
+ invoice_mismatch_score * 20%
|
||||
+ resubmit_duration_score * 15%
|
||||
+ missing_business_context_score * 20%
|
||||
```
|
||||
|
||||
### AI 协作画像分
|
||||
|
||||
AI 协作分不命名为风险分,建议叫 `ai_usage_intensity_score`。
|
||||
|
||||
```text
|
||||
ai_usage_intensity_score =
|
||||
ai_call_count_score * 25%
|
||||
+ token_cost_score * 25%
|
||||
+ ai_generated_claim_ratio_score * 20%
|
||||
+ ai_suggestion_override_score * 20%
|
||||
+ failed_ai_call_score * 10%
|
||||
```
|
||||
|
||||
含义:
|
||||
|
||||
- 分数高代表 AI 使用强度高或成本高。
|
||||
- 不代表员工费用风险高。
|
||||
- 主要用于成本治理、流程优化和模型配置。
|
||||
|
||||
### 审批行为画像分
|
||||
|
||||
审批行为分不命名为风险分,建议叫 `approval_behavior_score`。
|
||||
|
||||
```text
|
||||
approval_behavior_score =
|
||||
avg_review_duration_score * 20%
|
||||
+ sla_overdue_score * 20%
|
||||
+ direct_approve_ratio_score * 20%
|
||||
+ high_risk_approve_score * 20%
|
||||
+ system_advice_override_score * 20%
|
||||
```
|
||||
|
||||
含义:
|
||||
|
||||
- 分数高代表审批行为需要运营关注。
|
||||
- 不直接代表审批人存在问题。
|
||||
- 必须结合审批量、单据复杂度和部门业务特性解释。
|
||||
|
||||
## 数据来源
|
||||
|
||||
### 费用与流程数据
|
||||
|
||||
主要来源:
|
||||
|
||||
- `expense_claims`
|
||||
- `expense_claim_items`
|
||||
- 审批流转记录
|
||||
- 退回 / 调减 / 补充材料记录
|
||||
- 预算池和预算交易记录
|
||||
|
||||
需要补齐或确认的数据:
|
||||
|
||||
- 审批开始时间。
|
||||
- 审批完成时间。
|
||||
- 退回原因结构化字段。
|
||||
- 调减前后金额。
|
||||
- 补充材料事件。
|
||||
- 审批意见是否为空。
|
||||
|
||||
### AI 与工具调用数据
|
||||
|
||||
主要来源:
|
||||
|
||||
- `AgentRun`
|
||||
- `AgentToolCall`
|
||||
- `SemanticParseLog`
|
||||
- `runtime_chat.py`
|
||||
- `ontology.py`
|
||||
- `user_agent.py`
|
||||
- `ocr.py`
|
||||
|
||||
需要注意:
|
||||
|
||||
不是所有模型入口都已经完整持久化 Token。第一版必须区分:
|
||||
|
||||
```text
|
||||
exact_token_count:真实记录的 Token
|
||||
estimated_token_count:按文本长度估算
|
||||
unavailable:当前不可用
|
||||
```
|
||||
|
||||
不能把估算值包装成真实计费数据。
|
||||
|
||||
## 存储设计
|
||||
|
||||
建议第一版使用通用画像快照表:
|
||||
|
||||
```text
|
||||
employee_behavior_profile_snapshots
|
||||
```
|
||||
|
||||
字段建议:
|
||||
|
||||
```text
|
||||
id
|
||||
subject_type applicant / approver / employee
|
||||
subject_id employee_id
|
||||
subject_name
|
||||
department_id
|
||||
department_name
|
||||
position
|
||||
grade
|
||||
|
||||
profile_type expense / process_quality / ai_usage / approval
|
||||
window_days 30 / 90 / 180
|
||||
expense_type_scope overall / travel / entertainment / ...
|
||||
peer_group_key
|
||||
peer_group_fallback_level
|
||||
|
||||
profile_score
|
||||
profile_level
|
||||
metrics_json
|
||||
basis_codes_json
|
||||
source_task_type
|
||||
source_task_log_id
|
||||
calculated_at
|
||||
created_at
|
||||
```
|
||||
|
||||
### 为什么用快照表
|
||||
|
||||
不要把画像直接写入员工表:
|
||||
|
||||
```text
|
||||
employee.profile_score = 80
|
||||
```
|
||||
|
||||
原因:
|
||||
|
||||
- 员工表是主数据,画像是动态计算结果。
|
||||
- 审批审计需要知道当时为什么是这个分。
|
||||
- 算法规则调整后,历史依据不能被覆盖。
|
||||
- 快照可以支持趋势分析。
|
||||
|
||||
### 是否每个员工都存
|
||||
|
||||
不建议全员每天存。
|
||||
|
||||
第一版只存:
|
||||
|
||||
- 近 90 / 180 天有费用申请记录的员工。
|
||||
- 当前存在待审批申请的员工。
|
||||
- 上一期画像等级为 `watch`、`review`、`escalation` 的员工。
|
||||
- AI 使用或审批行为达到运营关注阈值的员工。
|
||||
|
||||
无行为员工不生成画像快照。
|
||||
|
||||
## Hermes 调度策略
|
||||
|
||||
不重新写调度器,复用 Hermes 现有 cron 调度体系。
|
||||
|
||||
建议新增任务类型:
|
||||
|
||||
```text
|
||||
employee_behavior_profile_scan
|
||||
```
|
||||
|
||||
任务职责:
|
||||
|
||||
```text
|
||||
1. 识别本次需要刷新画像的员工集合。
|
||||
2. 聚合费用、流程、AI、审批行为指标。
|
||||
3. 调用各画像子算法。
|
||||
4. 写入 employee_behavior_profile_snapshots。
|
||||
5. 在 HermesTaskExecutionLog 写入执行摘要。
|
||||
```
|
||||
|
||||
建议频率:
|
||||
|
||||
```text
|
||||
事件触发:申请提交、审批完成、退回、调减、AI 任务完成后,刷新相关员工。
|
||||
每日轻量:只扫描昨日新增行为和上一期高关注员工。
|
||||
每周全量:刷新同组基准、分位数和活跃员工画像。
|
||||
每月复盘:分析阈值、规则覆盖率和人工覆盖率。
|
||||
```
|
||||
|
||||
## 审批详情展示
|
||||
|
||||
费用审批详情页建议展示:
|
||||
|
||||
```text
|
||||
申请人费用画像
|
||||
流程材料质量
|
||||
本次申请实时偏离
|
||||
```
|
||||
|
||||
不建议在普通审批详情页直接展示:
|
||||
|
||||
```text
|
||||
Token 消耗
|
||||
AI 调用成本
|
||||
审批人行为分
|
||||
```
|
||||
|
||||
这些更适合管理员运营看板。
|
||||
|
||||
示例展示:
|
||||
|
||||
```text
|
||||
申请人费用画像
|
||||
近 90 天 · 销售部 / 客户经理 / 差旅费
|
||||
状态:重点复核
|
||||
|
||||
触发依据:
|
||||
- 近 90 天差旅金额处于同组 P88。
|
||||
- 本次出差天数为同类 P75 的 1.67 倍。
|
||||
- 最近 180 天存在 3 次调减或退回记录。
|
||||
|
||||
审核建议:
|
||||
- 建议确认本次 5 天行程是否可压缩至 4 天。
|
||||
- 如确属关键客户推进,请补充客户拜访安排和预期产出。
|
||||
```
|
||||
|
||||
## 运营看板展示
|
||||
|
||||
管理员或运营人员可以看到更完整的画像:
|
||||
|
||||
```text
|
||||
员工画像总览
|
||||
├── 费用支出关注榜
|
||||
├── 流程质量待优化榜
|
||||
├── AI 使用强度榜
|
||||
├── Token 成本趋势
|
||||
├── 审批效率与积压
|
||||
└── 系统建议采纳率
|
||||
```
|
||||
|
||||
运营看板要标明:
|
||||
|
||||
- 哪些指标是真实采集。
|
||||
- 哪些指标是估算。
|
||||
- 哪些指标当前不可用。
|
||||
|
||||
## 第一版落地边界
|
||||
|
||||
第一版建议先做:
|
||||
|
||||
1. 费用支出画像。
|
||||
2. 流程质量画像。
|
||||
3. AI 协作画像的数据口径定义。
|
||||
4. 通用快照表。
|
||||
5. Hermes 画像扫描任务。
|
||||
|
||||
暂不做:
|
||||
|
||||
- 自动处罚或自动降标。
|
||||
- 将 AI Token 消耗纳入费用风险分。
|
||||
- 用 LLM 直接判断员工是否异常。
|
||||
- 全员每日全量画像。
|
||||
|
||||
## 后续演进
|
||||
|
||||
### 第二阶段
|
||||
|
||||
- 接入审批详情页“申请人费用画像”卡片。
|
||||
- 接入 Hermes 数字员工日志。
|
||||
- 支持画像快照趋势对比。
|
||||
- 支持规则中心根据高频触发指标生成规则草稿。
|
||||
|
||||
### 第三阶段
|
||||
|
||||
- 引入更稳定的同组基准缓存。
|
||||
- 引入审批建议采纳率。
|
||||
- 对 AI 使用成本做部门和功能维度分摊。
|
||||
- 将画像结果接入运营看板。
|
||||
|
||||
### 第四阶段
|
||||
|
||||
- 根据真实历史数据调整权重。
|
||||
- 对高覆盖、高误报规则做自动复盘。
|
||||
- 让 Hermes 输出月度费用治理建议,但仍不直接改线上规则。
|
||||
|
||||
1472
document/development/budget-expense-control-model-plan/index.html
Normal file
1472
document/development/budget-expense-control-model-plan/index.html
Normal file
File diff suppressed because it is too large
Load Diff
681
document/development/employee-behavior-profile/CONCEPT.md
Normal file
681
document/development/employee-behavior-profile/CONCEPT.md
Normal file
@@ -0,0 +1,681 @@
|
||||
# 员工业务行为画像功能概念文档
|
||||
|
||||
## 1. 功能一句话
|
||||
|
||||
员工业务行为画像通过确定性算法把费用申请、流程质量、AI 协作和审批行为沉淀为可追溯的画像快照,并在审批详情、Hermes 数字员工巡检和运营看板中提供可解释的审核依据。
|
||||
|
||||
## 2. 背景与问题
|
||||
|
||||
预算费用规划推荐模型需要解释“为什么某个申请应该被重点审核”。仅看当前单据金额不够,因为同样的金额在不同员工、部门、岗位、城市和费用类型下含义不同。
|
||||
|
||||
当前讨论中已经明确几个问题:
|
||||
|
||||
- 出差天数、出差金额、业务招待频次和招待标准需要和申请人挂钩,否则审核者看不到长期费用节奏。
|
||||
- 用户操作时长、AI 使用次数、Token 消耗、审核时长、退单次数等指标也有价值,但它们性质不同,不能混成一个“坏人分”。
|
||||
- 审批详情需要一个直观入口展示画像,例如“风险审核画像”卡片,但卡片必须展示证据、口径和建议,避免给员工贴不可解释标签。
|
||||
- Hermes 已有数字员工和调度入口,画像检测应该接入现有 Hermes 任务体系,而不是另写一套调度器。
|
||||
|
||||
代码现状可作为第一版基础:
|
||||
|
||||
- `AgentRun`、`AgentToolCall`、`SemanticParseLog` 已记录 Agent 运行、工具调用耗时和语义解析日志。
|
||||
- `ExpenseClaim`、`ExpenseClaimItem` 已承载费用申请和明细。
|
||||
- `HermesTaskConfig`、`HermesTaskExecutionLog` 已承载 Hermes 任务配置和执行日志。
|
||||
- 现有 Hermes 调度器会轮询启用任务,并按 `task_type` 分发到具体服务。
|
||||
- 当前前端 Hermes 设置仅暴露 `global_risk_scan` 和 `weekly_expense_report` 两类任务,画像任务需要补齐配置入口。
|
||||
|
||||
## 3. 目标与非目标
|
||||
|
||||
### 3.1 目标
|
||||
|
||||
- 建立员工维度的多层画像:费用支出画像、流程质量画像、AI 协作画像、审批行为画像。
|
||||
- 建立可审计的快照存储,不把动态画像直接写进员工主表。
|
||||
- 形成可解释的量化公式,支持 30 / 90 / 180 天窗口。
|
||||
- 接入 Hermes 数字员工任务,定期生成画像快照和汇总日志。
|
||||
- 在审批详情中展示“风险审核画像”卡片,默认突出费用支出和流程质量。
|
||||
- 保留指标来源、同组基准、计算窗口、任务日志和算法版本,便于复核。
|
||||
- 明确 Token 统计口径:真实值、估算值和不可用值必须区分。
|
||||
|
||||
### 3.2 非目标
|
||||
|
||||
- 不用画像自动处罚员工,也不自动降低费用标准或缩短出差天数。
|
||||
- 不把 AI 使用次数、Token 消耗直接当作费用风险。
|
||||
- 不做全员每日全量画像快照,避免频率过高和无意义存储。
|
||||
- 不重写 Hermes 调度器;如频率能力不足,优先增强现有 Hermes 调度体系。
|
||||
- 不用 LLM 直接判定风险等级;LLM 仅可用于解释、摘要和报告生成。
|
||||
|
||||
## 4. 用户与场景
|
||||
|
||||
### 4.1 费用审核者
|
||||
|
||||
在费用申请详情页查看“风险审核画像”卡片。审核者需要知道:
|
||||
|
||||
- 申请人近期是否频繁申请大额出差或招待。
|
||||
- 当前申请是否显著高于同组基准或个人历史。
|
||||
- 申请人的材料质量是否经常导致退单、补充材料或复核。
|
||||
- 系统建议是“重点复核”“建议补充说明”还是“建议升级审批”。
|
||||
|
||||
### 4.2 财务和预算管理员
|
||||
|
||||
在运营看板或 Hermes 报告中查看部门、项目、费用类型下的画像趋势。管理员需要识别:
|
||||
|
||||
- 哪些部门或项目存在持续预算占用压力。
|
||||
- 哪些费用类型的人均标准偏离明显。
|
||||
- 哪些流程环节反复出现退单或材料缺失。
|
||||
|
||||
### 4.3 AI 运营人员
|
||||
|
||||
观察 AI 调用、Token 消耗、建议采纳率和覆盖率。AI 运营人员需要知道:
|
||||
|
||||
- 哪些入口消耗高但采纳率低。
|
||||
- 哪些业务流程高度依赖 AI。
|
||||
- 哪些模型调用需要限额、优化或替换。
|
||||
|
||||
### 4.4 Hermes 数字员工
|
||||
|
||||
Hermes 作为调度入口,负责在设定周期内触发画像计算、写入快照、记录执行日志,并输出可读摘要。
|
||||
|
||||
## 5. 功能能力
|
||||
|
||||
### 5.1 输入
|
||||
|
||||
- 费用申请:申请人、部门、岗位、费用类型、申请金额、审批金额、出差天数、招待客户、业务地点、项目编号。
|
||||
- 费用明细:明细金额、票据金额、费用类型、发生日期、供应商或客户线索。
|
||||
- 审批流转:提交时间、审核开始时间、审核完成时间、退单、调减、复核、审批意见。
|
||||
- Agent 数据:Agent 运行记录、工具调用次数、工具耗时、语义解析、AI 建议、AI 建议采纳或覆盖。
|
||||
- Token 数据:输入 Token、输出 Token、总 Token、估算 Token、不可用状态。
|
||||
- Hermes 数据:任务配置、任务执行日志、报告或风险巡检结果。
|
||||
- 组织基准:部门、岗位、职级、城市等级、项目类型、费用类型和预算池。
|
||||
|
||||
### 5.2 输出
|
||||
|
||||
- 员工画像快照:每个员工、每个窗口、每个画像类型一条或多条快照。
|
||||
- 最新画像查询:给审批详情、运营看板和 Hermes 报告读取。
|
||||
- 画像证据:指标值、同组基准、贡献项、命中原因、数据质量标记。
|
||||
- 画像标签:把复杂指标转成可读标签,例如“费用之王”“长差达人”“材料补丁户”“急速审核员”,每个标签必须有触发公式、置信度和证据。
|
||||
- 行为雷达图:把费用、差旅招待、流程质量、AI 协作和审批行为压缩成 6 到 8 个维度,用于分析者快速理解员工行为结构。
|
||||
- 审核建议:复核天数、复核金额、补充材料、升级审批、关注预算占用等建议。
|
||||
- Hermes 执行摘要:本次计算人数、生成快照数、高关注人数、失败原因。
|
||||
|
||||
### 5.3 审批详情卡片
|
||||
|
||||
审批详情中建议新增卡片:`风险审核画像`。
|
||||
|
||||
卡片默认展示:
|
||||
|
||||
- 总览:画像等级、计算时间、窗口期、同组基准口径。
|
||||
- 特征标签:展示 3 到 6 个置信度最高、与当前场景相关的标签;风险型标签优先,但必须保留证据入口。
|
||||
- 雷达图:展示行为维度得分,帮助审核者一眼判断该员工是“费用强度高”“材料质量弱”还是“审批节奏快”。
|
||||
- 费用支出:频次、金额占用、同组偏离、历史调减、当前单据偏离。
|
||||
- 流程质量:退单、附件缺失、发票不一致、补充材料、重提耗时。
|
||||
- 当前单据建议:是否建议复核出差天数、招待人均金额、业务必要性或预算占用。
|
||||
- 证据展开:展示贡献最高的 3 到 5 个指标和原始口径。
|
||||
|
||||
审批详情默认不突出 AI 协作画像和审批人行为画像。AI 指标主要服务运营治理,审批人画像只在管理员或流程治理场景展示。
|
||||
|
||||
### 5.4 权限和边界
|
||||
|
||||
- 普通审核者只能看到与当前单据审核有关的申请人费用画像和流程质量画像。
|
||||
- 财务管理员可查看部门、项目和费用类型维度的汇总趋势。
|
||||
- AI 运营人员可查看 AI 协作画像,但不把它用于单据费用风险裁决。
|
||||
- 审批行为画像只面向管理员和流程治理角色展示。
|
||||
- 所有画像结论必须展示数据窗口和计算时间,避免被误读为永久标签。
|
||||
|
||||
## 6. 方案设计
|
||||
|
||||
### 6.1 数据模型
|
||||
|
||||
第一版建议新增通用快照表:
|
||||
|
||||
```text
|
||||
employee_behavior_profile_snapshots
|
||||
```
|
||||
|
||||
核心字段:
|
||||
|
||||
```text
|
||||
id
|
||||
subject_type applicant / approver / employee
|
||||
subject_id employee_id 或 user_id
|
||||
subject_name
|
||||
department_id
|
||||
department_name
|
||||
position
|
||||
grade
|
||||
|
||||
profile_type expense / process_quality / ai_usage / approval
|
||||
window_days 30 / 90 / 180
|
||||
expense_type_scope overall / travel / entertainment / ...
|
||||
peer_group_key
|
||||
peer_group_fallback_level
|
||||
|
||||
profile_score 0-100
|
||||
profile_level normal / watch / review / escalation
|
||||
metrics_json 原始指标、分位数、样本量、Token 口径
|
||||
basis_codes_json 贡献项和解释编码
|
||||
profile_tags_json 标签、触发分、置信度、证据和展示优先级
|
||||
radar_json 雷达图维度、维度分、维度等级和主导标签
|
||||
source_task_type employee_behavior_profile_scan
|
||||
source_task_log_id HermesTaskExecutionLog.id
|
||||
algorithm_version
|
||||
calculated_at
|
||||
created_at
|
||||
```
|
||||
|
||||
不建议把画像直接写入员工主表,例如 `employee.profile_score = 80`。画像是动态计算结果,需要保留算法版本、窗口期和历史依据。
|
||||
|
||||
### 6.2 后端服务
|
||||
|
||||
建议拆成三个职责:
|
||||
|
||||
- 数据抽取服务:从费用、审批、Agent、Hermes 记录中抽取指标。
|
||||
- 算法服务:在 `server/src/app/algorithem` 下维护评分公式、等级判定和解释贡献项。
|
||||
- 应用服务:负责员工集合筛选、快照写入、最新画像查询和 Hermes 执行结果汇总。
|
||||
|
||||
候选模块:
|
||||
|
||||
```text
|
||||
server/src/app/algorithem/employee_behavior_profile.py
|
||||
server/src/app/services/employee_behavior_profile_service.py
|
||||
server/src/app/services/hermes_employee_profile_scanner.py
|
||||
server/src/app/models/employee_behavior_profile.py
|
||||
```
|
||||
|
||||
### 6.3 Hermes 接入
|
||||
|
||||
新增任务类型:
|
||||
|
||||
```text
|
||||
employee_behavior_profile_scan
|
||||
```
|
||||
|
||||
接入原则:
|
||||
|
||||
- 复用现有 `HermesTaskConfig` 和 `HermesTaskExecutionLog`。
|
||||
- 在现有 `HermesScheduler._execute_task()` 中增加任务分发。
|
||||
- 在 `start_hermes_daemon.py` 中初始化画像任务配置。
|
||||
- 在 `hermesEmployeeSettingsModel.js` 中补充任务展示和默认开关。
|
||||
- 不创建第二个后台调度器。
|
||||
|
||||
频率建议:
|
||||
|
||||
- 第一版不做全员每日全量。
|
||||
- 推荐每周一次全量画像,工作日对存在待审单据的员工做轻量增量。
|
||||
- 如果现有 Hermes 调度只支持近似每日触发,应先把画像任务默认关闭或仅启用轻量扫描;后续在现有调度器内补齐 frequency / weekday / time 判断。
|
||||
|
||||
### 6.4 API 契约
|
||||
|
||||
审批详情读取最新画像:
|
||||
|
||||
```text
|
||||
GET /api/v1/employee-profiles/{employee_id}/latest
|
||||
```
|
||||
|
||||
建议查询参数:
|
||||
|
||||
```text
|
||||
scene=approval
|
||||
claim_id=<claim_id>
|
||||
window_days=90
|
||||
expense_type_scope=travel|entertainment|overall
|
||||
```
|
||||
|
||||
响应结构建议:
|
||||
|
||||
```json
|
||||
{
|
||||
"employee_id": "EMP001",
|
||||
"window_days": 90,
|
||||
"calculated_at": "2026-05-28T10:30:00+08:00",
|
||||
"peer_group": {
|
||||
"key": "FINANCE|M2|travel|tier1",
|
||||
"fallback_level": 1,
|
||||
"sample_size": 42
|
||||
},
|
||||
"profiles": [
|
||||
{
|
||||
"profile_type": "expense",
|
||||
"score": 72,
|
||||
"level": "review",
|
||||
"top_contributors": [
|
||||
{
|
||||
"code": "peer_deviation_high",
|
||||
"label": "差旅日均费用高于同组 P90",
|
||||
"value": 1.18,
|
||||
"unit": "ratio"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"profile_tags": [
|
||||
{
|
||||
"code": "expense_king",
|
||||
"label": "费用之王",
|
||||
"display_label": "费用集中度高",
|
||||
"category": "expense",
|
||||
"polarity": "risk",
|
||||
"score": 86,
|
||||
"confidence": 0.82,
|
||||
"reason": "近90天费用总额达到同组P90,且部门费用占比为34%",
|
||||
"metrics": {
|
||||
"amount_total": 128000,
|
||||
"peer_amount_p90": 76000,
|
||||
"amount_share": 0.34
|
||||
}
|
||||
}
|
||||
],
|
||||
"radar": {
|
||||
"dimensions": [
|
||||
{
|
||||
"code": "expense_intensity",
|
||||
"label": "费用强度",
|
||||
"score": 78,
|
||||
"level": "review",
|
||||
"top_tags": ["expense_king", "large_amount_deviation"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"review_suggestions": [
|
||||
{
|
||||
"type": "review_travel_days",
|
||||
"severity": "medium",
|
||||
"message": "建议复核出差天数和业务必要性"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 6.5 前端展示
|
||||
|
||||
审批详情页新增 `风险审核画像` 卡片,建议分成三层:
|
||||
|
||||
- 顶部摘要:等级、窗口期、同组基准、更新时间。
|
||||
- 中部指标:费用支出和流程质量两个分组。
|
||||
- 底部建议:系统建议和证据展开。
|
||||
|
||||
文案边界:
|
||||
|
||||
- 使用“关注”“复核”“建议”而不是“惩罚”“违规”“头号人物”。
|
||||
- 展示“该结论来自 90 天窗口和同组对比”,避免变成员工永久标签。
|
||||
- AI 协作强度只作为运营指标,不在费用审批默认卡片中强调。
|
||||
|
||||
## 7. 算法与公式
|
||||
|
||||
### 7.1 通用归一化
|
||||
|
||||
对越大越需要关注的指标,使用同组分位数归一化:
|
||||
|
||||
$$
|
||||
score(x) = clip\left(100 \times \frac{x - P_{50}}{P_{90} - P_{50}}, 0, 100\right)
|
||||
$$
|
||||
|
||||
其中:
|
||||
|
||||
- \(x\):员工在窗口期内的指标值。
|
||||
- \(P_{50}\):同组中位数。
|
||||
- \(P_{90}\):同组 90 分位数。
|
||||
- \(clip(v, 0, 100)\):把结果限制在 0 到 100。
|
||||
|
||||
当同组样本不足时,按以下顺序降级:
|
||||
|
||||
```text
|
||||
部门 + 岗位 + 费用类型
|
||||
→ 部门 + 费用类型
|
||||
→ 岗位 + 费用类型
|
||||
→ 公司 + 费用类型
|
||||
```
|
||||
|
||||
降级层级必须写入 `peer_group_fallback_level`。
|
||||
|
||||
### 7.2 费用支出画像
|
||||
|
||||
$$
|
||||
expense\_profile\_score =
|
||||
0.20F + 0.25B + 0.25D + 0.15H + 0.15C
|
||||
$$
|
||||
|
||||
变量定义:
|
||||
|
||||
- \(F\):费用申请频次分,包含出差、招待等申请次数。
|
||||
- \(B\):预算占用分,包含个人费用占部门或项目预算比例。
|
||||
- \(D\):同组偏离分,包含金额、天数、人均招待金额等分位数偏离。
|
||||
- \(H\):历史调减和复核分,包含历史调减、退回、复核次数。
|
||||
- \(C\):当前单据偏离分,衡量当前申请相对个人历史和同组基准的偏离。
|
||||
|
||||
### 7.3 流程质量画像
|
||||
|
||||
$$
|
||||
process\_quality\_score =
|
||||
0.25R + 0.20A + 0.20I + 0.15T + 0.20M
|
||||
$$
|
||||
|
||||
变量定义:
|
||||
|
||||
- \(R\):退单次数分。
|
||||
- \(A\):附件缺失分。
|
||||
- \(I\):发票金额或票据一致性问题分。
|
||||
- \(T\):退回后重新提交耗时分。
|
||||
- \(M\):业务上下文缺失分,包含事由、地点、项目编号、客户信息等。
|
||||
|
||||
### 7.4 AI 协作画像
|
||||
|
||||
AI 协作画像命名为强度分,不命名为风险分。
|
||||
|
||||
$$
|
||||
ai\_usage\_intensity\_score =
|
||||
0.25N + 0.25K + 0.20G + 0.20O + 0.10E
|
||||
$$
|
||||
|
||||
变量定义:
|
||||
|
||||
- \(N\):AI 调用次数分。
|
||||
- \(K\):Token 或估算成本分。
|
||||
- \(G\):AI 辅助生成申请比例分。
|
||||
- \(O\):AI 建议被人工覆盖分。
|
||||
- \(E\):AI 调用失败或低置信度分。
|
||||
|
||||
Token 口径必须进入 `metrics_json`:
|
||||
|
||||
```text
|
||||
exact_token_count 真实记录
|
||||
estimated_token_count 按文本长度估算
|
||||
unavailable 当前入口不可用
|
||||
```
|
||||
|
||||
### 7.5 审批行为画像
|
||||
|
||||
审批行为画像用于流程治理,不用于评价申请人的费用合理性。
|
||||
|
||||
$$
|
||||
approval\_behavior\_score =
|
||||
0.20L + 0.20S + 0.20P + 0.20Q + 0.20V
|
||||
$$
|
||||
|
||||
变量定义:
|
||||
|
||||
- \(L\):平均审核时长分。
|
||||
- \(S\):SLA 超时分。
|
||||
- \(P\):直接通过率异常分。
|
||||
- \(Q\):高风险单据通过率分。
|
||||
- \(V\):系统建议被覆盖分。
|
||||
|
||||
### 7.6 审批优先级分
|
||||
|
||||
审批详情只使用费用支出和流程质量形成优先级,不引入 AI 协作强度。
|
||||
|
||||
$$
|
||||
review\_priority\_score =
|
||||
clip(0.70 \times expense\_profile\_score +
|
||||
0.30 \times process\_quality\_score, 0, 100)
|
||||
$$
|
||||
|
||||
等级映射:
|
||||
|
||||
$$
|
||||
level(s)=
|
||||
\begin{cases}
|
||||
normal, & 0 \le s < 40 \\
|
||||
watch, & 40 \le s < 60 \\
|
||||
review, & 60 \le s < 80 \\
|
||||
escalation, & 80 \le s \le 100
|
||||
\end{cases}
|
||||
$$
|
||||
|
||||
### 7.7 审核建议公式
|
||||
|
||||
系统建议只能作为复核提示,不自动改写申请单。
|
||||
|
||||
差旅天数建议上限:
|
||||
|
||||
$$
|
||||
recommended\_days\_upper =
|
||||
min(requested\_days,\ P_{75}^{peer\_days} \times factor(level))
|
||||
$$
|
||||
|
||||
业务招待人均金额建议上限:
|
||||
|
||||
$$
|
||||
recommended\_entertainment\_unit\_upper =
|
||||
min(policy\_limit,\ P_{75}^{peer\_unit\_amount} \times factor(level))
|
||||
$$
|
||||
|
||||
其中:
|
||||
|
||||
$$
|
||||
factor(level)=
|
||||
\begin{cases}
|
||||
1.20, & normal \\
|
||||
1.10, & watch \\
|
||||
1.00, & review \\
|
||||
0.90, & escalation
|
||||
\end{cases}
|
||||
$$
|
||||
|
||||
如果当前申请本身有充分业务依据,审核者可以覆盖系统建议。覆盖原因应进入后续流程治理指标。
|
||||
|
||||
### 7.8 目标员工集合
|
||||
|
||||
第一版不计算全员。每次 Hermes 扫描目标集合为:
|
||||
|
||||
$$
|
||||
target\_employees =
|
||||
E_{claims180} \cup E_{pending} \cup E_{previous\_attention} \cup E_{ops\_threshold}
|
||||
$$
|
||||
|
||||
变量定义:
|
||||
|
||||
- \(E_{claims180}\):近 180 天有费用申请的员工。
|
||||
- \(E_{pending}\):当前有待审费用申请的员工。
|
||||
- \(E_{previous\_attention}\):上一期画像等级为 watch、review 或 escalation 的员工。
|
||||
- \(E_{ops\_threshold}\):AI 使用或审批行为达到运营关注阈值的员工。
|
||||
|
||||
### 7.9 用户画像标签体系
|
||||
|
||||
标签用于把复杂指标转成直观特征。标签不是永久评价,也不是处罚依据;它只表示员工在某个时间窗口、某个同组基准下呈现出的行为特征。
|
||||
|
||||
前端可以展示两层文案:
|
||||
|
||||
- `label`:内部或分析侧标签,例如“费用之王”“急速审核员”。
|
||||
- `display_label`:审批详情默认展示文案,例如“费用集中度高”“快速审核型”。
|
||||
|
||||
标签输出结构建议:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "expense_king",
|
||||
"label": "费用之王",
|
||||
"display_label": "费用集中度高",
|
||||
"category": "expense",
|
||||
"polarity": "risk",
|
||||
"score": 86,
|
||||
"confidence": 0.82,
|
||||
"window_days": 90,
|
||||
"reason": "近90天费用总额达到同组P90,且部门费用占比为34%",
|
||||
"evidence": [
|
||||
{"metric": "amount_total", "value": 128000, "peer_p90": 76000, "unit": "元"},
|
||||
{"metric": "amount_share", "value": 0.34, "threshold": 0.30, "unit": "比例"}
|
||||
],
|
||||
"radar_dimensions": ["expense_intensity"]
|
||||
}
|
||||
```
|
||||
|
||||
#### 7.9.1 通用标签打分
|
||||
|
||||
标签触发后仍然需要计算强度和置信度,避免一个边界值把员工直接贴成强标签。
|
||||
|
||||
$$
|
||||
tag\_score =
|
||||
clip(100 \times (0.55S + 0.25C + 0.20R), 0, 100)
|
||||
$$
|
||||
|
||||
$$
|
||||
confidence =
|
||||
clip(DQ \times (0.65S + 0.20SR + 0.15C), 0, 1)
|
||||
$$
|
||||
|
||||
变量定义:
|
||||
|
||||
- \(S\):指标强度,表示当前指标超过阈值或同组分位数的程度。
|
||||
- \(C\):持续性,30 / 90 / 180 天三个窗口中命中的窗口比例。
|
||||
- \(R\):近期性,最近一次命中距今天数越近分越高。
|
||||
- \(DQ\):数据质量,字段完整、样本充足、无估算时更高。
|
||||
- \(SR\):样本可靠性,同组样本量越大越可靠。
|
||||
|
||||
标签展示阈值:
|
||||
|
||||
$$
|
||||
active(tag)=
|
||||
\begin{cases}
|
||||
true, & tag\_score \ge 60 \land confidence \ge 0.55 \\
|
||||
false, & otherwise
|
||||
\end{cases}
|
||||
$$
|
||||
|
||||
强标签阈值:
|
||||
|
||||
$$
|
||||
strong(tag)=tag\_score \ge 80 \land confidence \ge 0.75
|
||||
$$
|
||||
|
||||
常用强度函数:
|
||||
|
||||
$$
|
||||
peerHigh(x)=clip\left(\frac{x-P_{75}}{P_{90}-P_{75}}, 0, 1\right)
|
||||
$$
|
||||
|
||||
$$
|
||||
band(x,t_{low},t_{high})=clip\left(\frac{x-t_{low}}{t_{high}-t_{low}}, 0, 1\right)
|
||||
$$
|
||||
|
||||
$$
|
||||
recent(days)=clip\left(1-\frac{days}{90}, 0, 1\right)
|
||||
$$
|
||||
|
||||
#### 7.9.2 第一版候选标签清单
|
||||
|
||||
以下标签均需要写入触发依据、窗口期、同组样本量和 fallback 层级。审批详情默认只展示与当前单据相关的前 3 到 6 个标签;运营看板可展示完整标签。
|
||||
|
||||
| 类别 | code / 标签 | 默认展示文案 | 量化触发条件 | 雷达维度 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 费用支出 | `expense_king` / 费用之王 | 费用集中度高 | \(amount\_total_{90} \ge P90(amount\_total)\) 且 \(amount\_share_{90} \ge 0.30\)。强度 \(S=max(peerHigh(amount\_total), band(amount\_share,0.15,0.45))\)。 | 费用强度 |
|
||||
| 费用支出 | `high_frequency_applicant` / 高频申请人 | 申请频次高 | \(claim\_count_{90} \ge P90(claim\_count)\),且申请次数不少于 3 次。强度 \(S=peerHigh(claim\_count)\)。 | 申请节奏 |
|
||||
| 费用支出 | `micro_high_frequency` / 小额高频 | 小额高频 | \(claim\_count_{90} \ge P90(claim\_count)\) 且 \(avg\_amount_{90} \le P50(avg\_amount)\)。 | 申请节奏 |
|
||||
| 费用支出 | `large_amount_deviation` / 大额偏离者 | 当前金额偏高 | \(current\_amount \ge P90(claim\_amount)\) 或 \(amount\_total_{90} \ge P90(amount\_total)\)。 | 费用强度 |
|
||||
| 费用支出 | `budget_sprint` / 预算冲刺型 | 近期费用集中 | \(amount_{30}/amount_{90} \ge 0.55\) 且 \(amount_{30} \ge P75(amount_{30})\)。 | 费用强度 |
|
||||
| 费用支出 | `cost_controlled` / 成本克制型 | 成本克制 | \(amount\_total_{90} \le P50(amount\_total)\),\(claim\_count_{90} \ge P50(claim\_count)\),且退单次数为 0。该标签为正向标签。 | 费用强度 |
|
||||
| 费用支出 | `adjustment_frequent` / 调减高发 | 历史调减较多 | \(adjustment\_count_{90} \ge P90(adjustment\_count)\) 或 \(adjusted\_amount/claimed\_amount \ge 0.20\)。 | 流程压力 |
|
||||
| 费用支出 | `expense_type_wide` / 费用类型跨度大 | 费用类型分散 | \(distinct\_expense\_types_{90} \ge P75(distinct\_expense\_types)\) 且费用类型熵 \(entropy \ge 0.60\)。 | 申请节奏 |
|
||||
| 差旅招待 | `long_trip_master` / 长差达人 | 出差天数偏长 | \(current\_travel\_days \ge 1.5 \times P75(peer\_days)\) 或 \(travel\_days_{90} \ge P90(travel\_days)\)。 | 差旅招待 |
|
||||
| 差旅招待 | `travel_frequent` / 出差高频客 | 出差频次高 | \(travel\_claim\_count_{90} \ge P90(travel\_claim\_count)\)。 | 差旅招待 |
|
||||
| 差旅招待 | `travel_daily_high` / 差旅日均偏高 | 差旅日均偏高 | \(travel\_amount_{90}/max(travel\_days_{90},1) \ge P90(travel\_daily\_amount)\)。 | 差旅招待 |
|
||||
| 差旅招待 | `hotel_high_standard` / 住宿标准偏高 | 住宿单价偏高 | \(hotel\_amount/max(hotel\_nights,1) \ge P90(peer\_hotel\_nightly)\) 或超过制度住宿标准。 | 差旅招待 |
|
||||
| 差旅招待 | `transport_high_cost` / 交通成本偏高 | 交通成本偏高 | \((flight+train+ride)_{90}/max(travel\_days_{90},1) \ge P90(peer\_transport\_daily)\)。 | 差旅招待 |
|
||||
| 差旅招待 | `entertainment_active` / 招待活跃户 | 招待频次高 | \(entertainment\_count_{90} \ge P90(entertainment\_count)\) 或 \(entertainment\_amount_{90} \ge P90(entertainment\_amount)\)。 | 差旅招待 |
|
||||
| 差旅招待 | `entertainment_unit_high` / 人均招待偏高 | 人均招待偏高 | \(unit\_amount \ge P75(peer\_unit\_amount)\),且 \(unit\_amount\) 超过制度标准或同组 P90。 | 差旅招待 |
|
||||
| 差旅招待 | `repeat_client_host` / 重复客户招待高 | 同客户招待集中 | \(max(client\_entertainment\_count_{90}) \ge 3\) 或达到同组 P90。客户无法结构化时降级为“客户线索不足”。 | 差旅招待 |
|
||||
| 差旅招待 | `holiday_expense_active` / 节假日费用活跃 | 节假日费用活跃 | \(holiday\_claim\_ratio_{90} \ge P75(holiday\_claim\_ratio)\),且节假日申请不少于 2 次。 | 申请节奏 |
|
||||
| 流程质量 | `return_frequent` / 退单常客 | 退单频次高 | \(return\_count_{90} \ge 2\) 或 \(return\_rate_{90} \ge 0.30\),且达到同组 P75。 | 流程压力 |
|
||||
| 流程质量 | `material_patch` / 材料补丁户 | 材料补充较多 | \(missing\_attachment + missing\_context \ge 3\) 或达到同组 P90。 | 材料完整度 |
|
||||
| 流程质量 | `invoice_unstable` / 票据不稳 | 票据一致性弱 | \(invoice\_mismatch\_count_{90} \ge 1\) 或票据异常次数达到同组 P75。 | 材料完整度 |
|
||||
| 流程质量 | `reason_thin` / 事由空心化 | 事由说明偏弱 | 空事由、模板化事由或少于最小字数的事由占比 \(\ge 0.40\)。 | 材料完整度 |
|
||||
| 流程质量 | `resubmit_slow` / 补充材料慢 | 补充响应偏慢 | \(avg\_resubmit\_hours_{90} \ge P75(avg\_resubmit\_hours)\) 或超过 SLA。 | 流程压力 |
|
||||
| 流程质量 | `repeat_issue` / 重复问题未改善 | 同类问题反复 | 同一问题编码在 90 天内出现 \(\ge 2\) 次,且 30 天内仍出现。 | 流程压力 |
|
||||
| 流程质量 | `clean_first_pass` / 材料清爽 | 一次通过质量好 | \(first\_pass\_rate_{90} \ge 0.90\),附件缺失为 0,票据不一致为 0。该标签为正向标签。 | 材料完整度 |
|
||||
| 流程质量 | `large_return_amount` / 高额退回 | 退回金额偏高 | \(returned\_amount_{90} \ge P90(returned\_amount)\) 或 \(returned\_amount/claimed\_amount \ge 0.20\)。 | 流程压力 |
|
||||
| AI 协作 | `ai_heavy` / AI 重度用户 | AI 使用频繁 | \(ai\_run\_count_{90} \ge P90(ai\_run\_count)\)。 | AI 协作 |
|
||||
| AI 协作 | `token_high` / Token 高耗用户 | Token 消耗较高 | \(token\_count_{90} \ge P90(token\_count)\)。估算 Token 必须标记 `estimated`,不得当作真实成本。 | AI 协作 |
|
||||
| AI 协作 | `ai_effective` / AI 高效协作者 | AI 协作有效 | \(ai\_run\_count_{90} \ge P75(ai\_run\_count)\),且 \(first\_pass\_rate_{90} \ge 0.85\),流程质量分低于 40。该标签为正向标签。 | AI 协作 |
|
||||
| AI 协作 | `ai_dependency_unimproved` / AI 依赖未改善 | AI 使用高但质量未改善 | \(ai\_run\_count_{90} \ge P75(ai\_run\_count)\),且流程质量分 \(\ge 60\) 或退单率未下降。 | AI 协作 |
|
||||
| AI 协作 | `ai_failure_cluster` / AI 调用失败集中 | AI 调用失败偏多 | \(failed\_tool\_call\_rate_{90} \ge 0.20\) 或失败次数达到同组 P90。 | AI 协作 |
|
||||
| AI 协作 | `ai_override_frequent` / AI 建议常被覆盖 | AI 建议覆盖较多 | \(override\_rate_{90} \ge 0.40\) 或覆盖次数达到同组 P75。无结构化覆盖字段时不触发。 | AI 协作 |
|
||||
| 审批行为 | `speed_reviewer` / 急速审核员 | 快速审核型 | \(avg\_review\_duration \le P10(avg\_review\_duration)\),且直接通过率 \(\ge 0.90\)。该标签为行为型,不默认视为风险。 | 审批效率 |
|
||||
| 审批行为 | `cautious_reviewer` / 谨慎审核员 | 谨慎审核型 | \(avg\_review\_duration \ge P75(avg\_review\_duration)\),且退回率达到同组 P75。 | 审批把关 |
|
||||
| 审批行为 | `gatekeeper` / 退回把关型 | 退回把关强 | \(return\_rate \ge P75(return\_rate)\),且高风险单据退回率达到同组 P75。 | 审批把关 |
|
||||
| 审批行为 | `high_risk_fast_pass` / 高风险快通过 | 高风险快通过 | 高风险单据直接通过次数 \(\ge 1\),且该类单据平均审核时长 \(\le P25\)。 | 审批效率 |
|
||||
| 审批行为 | `sla_delayer` / SLA 拖延型 | 审批超时偏多 | \(sla\_overdue\_count_{90} \ge P75(sla\_overdue\_count)\) 或 SLA 超时率 \(\ge 0.25\)。 | 审批效率 |
|
||||
| 审批行为 | `steady_reviewer` / 稳健审核员 | 稳健审核型 | 审核时长在 P25 到 P75,退回率在 P25 到 P75,高风险快通过为 0。该标签为正向标签。 | 审批把关 |
|
||||
|
||||
### 7.10 行为雷达图
|
||||
|
||||
雷达图用于表达“行为结构”,不是单一风险分。第一版建议 8 个维度,每个维度 0 到 100 分。
|
||||
|
||||
$$
|
||||
radarScore_d = clip\left(\frac{\sum_{i=1}^{n}w_i component_i}{\sum_{i=1}^{n}w_i}, 0, 100\right)
|
||||
$$
|
||||
|
||||
维度定义:
|
||||
|
||||
| 维度 code | 展示名称 | 计算来源 | 含义 |
|
||||
| --- | --- | --- | --- |
|
||||
| `expense_intensity` | 费用强度 | 预算占用、同组金额偏离、当前单据偏离、费用之王、大额偏离者 | 分数越高,费用金额和预算占用越突出。 |
|
||||
| `application_rhythm` | 申请节奏 | 申请频次、小额高频、费用类型跨度、近期费用集中 | 分数越高,申请节奏越密集或集中。 |
|
||||
| `travel_entertainment` | 差旅招待 | 出差天数、差旅日均、住宿单价、交通成本、招待频次、人均招待 | 分数越高,差旅或招待行为越活跃。 |
|
||||
| `material_completeness` | 材料完整度压力 | 附件缺失、票据不一致、事由空心化、重复问题 | 分数越高,材料质量越需要关注。 |
|
||||
| `process_pressure` | 流程压力 | 退单、调减、高额退回、补充材料耗时 | 分数越高,流程返工和沟通成本越高。 |
|
||||
| `ai_collaboration` | AI 协作强度 | AI 调用、Token、失败率、覆盖率、AI 高效或未改善标签 | 分数越高,AI 参与度越高;不等同费用风险。 |
|
||||
| `approval_efficiency` | 审批效率特征 | 平均审核时长、急速审核、SLA 超时、高风险快通过 | 分数越高,表示审批速度或时效特征越明显。 |
|
||||
| `approval_control` | 审批把关特征 | 退回率、高风险退回率、谨慎审核、稳健审核 | 分数越高,表示审批把关或复核行为越明显。 |
|
||||
|
||||
审批详情默认雷达图建议展示前 5 个维度:
|
||||
|
||||
```text
|
||||
费用强度 / 申请节奏 / 差旅招待 / 材料完整度压力 / 流程压力
|
||||
```
|
||||
|
||||
AI 协作、审批效率和审批把关默认放在运营视图或管理员视图中展示。审批详情如需展示,必须明确标注“不参与费用风险裁决”。
|
||||
|
||||
个人工作台的用户画像详情允许在行为雷达右上角提供视角切换,避免把不同性质的指标混成单一结论:
|
||||
|
||||
- `financial_risk` / 财务风险视角:默认面向普通员工画像,展示费用强度、申请节奏、差旅招待、材料完整度压力、流程压力。
|
||||
- `collaboration_governance` / 协作治理视角:展示 AI 协作强度、审批效率特征、审批把关特征,用于管理员或运营人员查看系统协作和流程治理行为。
|
||||
- `all_behavior` / 全部行为视角:展示全部雷达维度,满足用户查看完整操作和行为细节的需求。
|
||||
|
||||
切换只改变雷达图可视维度和雷达下方的行为标签过滤结果,不改变后端画像快照、上方画像标签总列表、标签证据和审批优先级分。审批详情的“风险审核画像”仍默认只展示费用审核相关维度。
|
||||
|
||||
## 8. 测试方案
|
||||
|
||||
- 单元测试:覆盖归一化、同组降级、四类画像评分、等级映射、审核建议生成。
|
||||
- 标签算法测试:覆盖 36 个候选标签的触发、未触发、强标签、置信度和数据质量降级。
|
||||
- 雷达图测试:覆盖 8 个雷达维度的维度分、等级映射和 top tags 关联。
|
||||
- 数据服务测试:覆盖费用、审批、Agent、Hermes 数据缺失时的降级逻辑。
|
||||
- API 测试:覆盖审批场景读取最新画像、权限过滤、无画像时的空态。
|
||||
- Hermes 测试:覆盖任务配置初始化、任务分发、执行日志成功和失败状态。
|
||||
- 前端测试:覆盖“风险审核画像”卡片的正常态、空态、标签展示、雷达图展示、证据展开和权限隐藏。
|
||||
- 回归测试:确保 AI 协作强度不进入审批优先级分。
|
||||
- 手工验证:用包含差旅、招待、退单、AI 调用的样例员工验证卡片展示是否可解释。
|
||||
|
||||
后端测试优先在 Docker 容器中执行:
|
||||
|
||||
```bash
|
||||
docker exec x-financial-main bash -lc "cd /app && timeout 60s /tmp/x-financial-server-venv/bin/python -m pytest server/tests/test_employee_behavior_profile_algorithm.py -q"
|
||||
```
|
||||
|
||||
## 9. 指标与验收
|
||||
|
||||
- 能为目标员工生成 30 / 90 / 180 天窗口画像快照。
|
||||
- 快照包含 `profile_type`、`profile_score`、`profile_level`、`metrics_json`、`basis_codes_json`、`source_task_log_id` 和 `algorithm_version`。
|
||||
- 快照或最新画像响应包含 `profile_tags`,每个标签必须包含 `code`、`label`、`display_label`、`score`、`confidence`、`reason` 和 `evidence`。
|
||||
- 最新画像响应包含 `radar.dimensions`,每个维度必须包含 `code`、`label`、`score`、`level` 和 `top_tags`。
|
||||
- 每个标签都有实际量化触发条件,不能只靠文字描述或 LLM 判断。
|
||||
- 审批详情默认展示不超过 6 个标签,优先展示与当前单据相关且置信度最高的标签。
|
||||
- 雷达图默认展示费用审核相关维度,AI 和审批人行为维度不参与申请人费用风险裁决。
|
||||
- 同一输入和同一算法版本下,评分结果可重复。
|
||||
- 同组样本不足时有明确 fallback 记录。
|
||||
- Token 统计明确区分真实、估算和不可用,不把估算值包装成真实计费数据。
|
||||
- 审批详情卡片只默认展示申请人费用画像和流程质量画像。
|
||||
- AI 协作强度不进入 `review_priority_score`。
|
||||
- Hermes 任务执行后能写入执行日志、结果摘要和失败堆栈。
|
||||
- 后端定向单元测试在 60 秒内通过。
|
||||
- 前端构建或相关测试通过,且卡片在无画像时有稳定空态。
|
||||
|
||||
## 10. 风险与开放问题
|
||||
|
||||
- Token 采集可能并不完整,需要先确认各 AI 入口是否真实记录 Token。
|
||||
- 审批开始时间、完成时间、退单原因、补充材料事件可能还不够结构化。
|
||||
- 当前 Hermes 调度器对频率的执行能力需要核对;如只支持近似每日触发,需要在现有调度器内增强。
|
||||
- 同组样本量不足时,分位数容易失真,需要展示样本量和 fallback 层级。
|
||||
- 审批详情中的画像语言要克制,避免把治理建议变成员工标签。
|
||||
- 标签名称需要区分内部分析文案和前端默认展示文案,避免“费用之王”等趣味标签在审批场景造成压迫感。
|
||||
- 雷达图维度不能混淆“行为强度”和“风险结论”;AI 使用强度、审批速度特征必须单独解释。
|
||||
- 正向标签和风险标签需要同时存在,否则画像容易变成单向负面评价。
|
||||
- 画像快照可能增长较快,需要后续定义保留周期和归档策略。
|
||||
- 业务招待中的客户、用户或项目标识需要数据标准化,否则重复招待次数难以准确统计。
|
||||
153
document/development/employee-behavior-profile/TODO.md
Normal file
153
document/development/employee-behavior-profile/TODO.md
Normal file
@@ -0,0 +1,153 @@
|
||||
# 员工业务行为画像开发 TODO
|
||||
|
||||
## 使用规则
|
||||
|
||||
- 每个 TODO 完成并经过对应验证后,才允许把 `[ ]` 改为 `[x]`。
|
||||
- 勾选时需要在任务后补一句证据,例如文件、接口、测试命令或验证结果。
|
||||
- 如果实现过程中发现需求变化,先更新 `CONCEPT.md`,再调整本文件。
|
||||
- 后端验证优先在 Docker 容器 `x-financial-main` 的 `/app` 下执行,并为测试设置 60 秒超时。
|
||||
|
||||
## 阶段 1:调研与边界
|
||||
|
||||
- [x] 确认文档技能要求,产物拆为 `CONCEPT.md` 与 `TODO.md`。[CONCEPT: 全文] 证据:已使用 `feature-development-docs` 技能建立本目录文档。
|
||||
- [x] 初步确认现有 Agent 指标来源。[CONCEPT: 背景与问题] 证据:`server/src/app/models/agent_run.py` 已有 `AgentRun`、`AgentToolCall`、`SemanticParseLog`。
|
||||
- [x] 初步确认现有 Hermes 任务基础。[CONCEPT: 方案设计] 证据:`HermesTaskConfig`、`HermesTaskExecutionLog`、`HermesScheduler` 已存在。
|
||||
- [x] 盘点费用申请、费用明细、审批记录中可直接用于画像的字段。[CONCEPT: 功能能力] 证据:`employee_behavior_profile_service.py` 聚合 `ExpenseClaim`、`ExpenseClaimItem`、`ApprovalRecord`。
|
||||
- [x] 盘点当前所有 AI 入口的 Token 记录情况,标记真实、估算和不可用。[CONCEPT: 算法与公式] 证据:`employee_behavior_profile_service.py` 在 AI 画像中写入 `token_count_mode`、`estimated_token_count`、`exact_token_count`。
|
||||
- [x] 确认审批详情页当前组件入口和数据加载方式。[CONCEPT: 前端展示] 证据:`TravelRequestDetailView.js` 读取画像 API,`TravelRequestDetailView.vue` 挂载画像卡片。
|
||||
- [x] 确认 Hermes 设置页是否需要展示“员工画像巡检”任务。[CONCEPT: Hermes 接入] 证据:`hermesEmployeeSettingsModel.js` 新增 `employee_behavior_profile_scan`。
|
||||
|
||||
## 阶段 2:契约设计
|
||||
|
||||
- [x] 定义画像快照模型字段和 JSON 结构。[CONCEPT: 数据模型] 证据:`employee_behavior_profile.py` ORM 模型。
|
||||
- [x] 定义 `GET /api/v1/employee-profiles/{employee_id}/latest` 响应契约。[CONCEPT: API 契约] 证据:`employee_profile.py` 和 `employee_profiles.py`。
|
||||
- [x] 定义审批详情场景下的权限过滤规则。[CONCEPT: 权限和边界] 证据:审批场景 API 仅返回 `expense` 与 `process_quality`。
|
||||
- [x] 定义 Hermes 任务结果摘要结构。[CONCEPT: Hermes 接入] 证据:`hermes_scheduler.py` 写入画像巡检摘要。
|
||||
- [x] 定义 `basis_codes_json` 的贡献项编码和展示文案。[CONCEPT: 审批详情卡片] 证据:算法 `ProfileComponent` 与服务写入 top contributors。
|
||||
- [x] 定义无画像、样本不足、指标缺失时的空态协议。[CONCEPT: 指标与验收] 证据:`EmployeeProfileLatestRead.empty_reason` 和卡片空态。
|
||||
|
||||
## 阶段 3:数据与持久化
|
||||
|
||||
- [x] 新增 `employee_behavior_profile_snapshots` ORM 模型。[CONCEPT: 数据模型] 证据:`server/src/app/models/employee_behavior_profile.py`。
|
||||
- [x] 将新模型加入 `server/src/app/models/__init__.py` 和 `db/base.py`。[CONCEPT: 数据模型] 证据:两个入口已导入 `EmployeeBehaviorProfileSnapshot`。
|
||||
- [x] 补充数据库迁移或项目当前等价建表流程。[CONCEPT: 数据模型] 证据:`EmployeeBehaviorProfileService.ensure_storage_ready()` 使用 `Base.metadata.create_all` 创建快照表。
|
||||
- [x] 为 `metrics_json` 写入 Token 口径字段。[CONCEPT: AI 协作画像] 证据:AI 画像 metrics 写入 `token_count_mode`。
|
||||
- [x] 为快照写入 `algorithm_version`、`source_task_type`、`source_task_log_id`。[CONCEPT: 数据模型] 证据:快照模型和服务写入三项字段。
|
||||
- [x] 增加最新画像查询索引,至少覆盖员工、画像类型、窗口期和计算时间。[CONCEPT: 指标与验收] 证据:`ix_employee_behavior_profile_latest`。
|
||||
|
||||
## 阶段 4:算法实现
|
||||
|
||||
- [x] 在 `server/src/app/algorithem` 新增员工画像算法模块。[CONCEPT: 后端服务] 证据:`employee_behavior_profile.py`。
|
||||
- [x] 实现同组分位数归一化函数。[CONCEPT: 通用归一化] 证据:`normalize_by_peer_percentiles()`。
|
||||
- [x] 实现同组样本不足 fallback 逻辑。[CONCEPT: 通用归一化] 证据:`_resolve_peer_claims()` 写入 fallback level。
|
||||
- [x] 实现费用支出画像评分。[CONCEPT: 费用支出画像] 证据:`_calculate_expense_profile()`。
|
||||
- [x] 实现流程质量画像评分。[CONCEPT: 流程质量画像] 证据:`_calculate_process_quality_profile()`。
|
||||
- [x] 实现 AI 协作强度评分。[CONCEPT: AI 协作画像] 证据:`_calculate_ai_usage_profile()`。
|
||||
- [x] 实现审批行为画像评分。[CONCEPT: 审批行为画像] 证据:`_calculate_approval_behavior_profile()`。
|
||||
- [x] 实现审批优先级分,确保不引入 AI 协作强度。[CONCEPT: 审批优先级分] 证据:`calculate_review_priority_score()` 测试通过。
|
||||
- [x] 实现差旅天数和招待人均金额的建议上限计算。[CONCEPT: 审核建议公式] 证据:`build_review_suggestions()` 测试通过。
|
||||
- [x] 实现 top contributors 贡献项提取。[CONCEPT: 审批详情卡片] 证据:`ProfileScoreResult.top_contributors()`。
|
||||
|
||||
## 阶段 5:后端服务
|
||||
|
||||
- [x] 新增画像数据抽取服务,聚合费用、审批、Agent 和 Hermes 指标。[CONCEPT: 后端服务] 证据:`employee_behavior_profile_service.py`。
|
||||
- [x] 新增画像应用服务,负责目标员工筛选、算法调用和快照写入。[CONCEPT: 目标员工集合] 证据:`scan_profiles()` 和 `refresh_employee_profiles()`。
|
||||
- [x] 实现最新画像查询服务。[CONCEPT: API 契约] 证据:`get_latest_profile()`。
|
||||
- [x] 实现审批场景画像 DTO,过滤 AI 和审批人治理指标。[CONCEPT: 权限和边界] 证据:审批场景响应只包含两类画像。
|
||||
- [x] 实现无画像时的空态响应。[CONCEPT: API 契约] 证据:`empty_reason`。
|
||||
- [x] 增加 API 路由并接入权限依赖。[CONCEPT: API 契约] 证据:`employee_profiles.py` 使用 `get_current_user`。
|
||||
|
||||
## 阶段 6:Hermes 接入
|
||||
|
||||
- [x] 新增 `employee_behavior_profile_scan` 任务类型常量或分发分支。[CONCEPT: Hermes 接入] 证据:`hermes_scheduler.py` 分发分支。
|
||||
- [x] 在现有 `HermesScheduler._execute_task()` 中接入画像扫描服务。[CONCEPT: Hermes 接入] 证据:`HermesEmployeeProfileScannerService`。
|
||||
- [x] 在 `start_hermes_daemon.py` 初始化画像任务配置。[CONCEPT: Hermes 接入] 证据:默认 cron `0 8 * * 1` 且默认关闭。
|
||||
- [x] 在设置服务中补齐画像任务的 capabilities 和 schedules 读写。[CONCEPT: Hermes 接入] 证据:`settings.py` 按周任务写入 cron。
|
||||
- [x] 在 `hermesEmployeeSettingsModel.js` 增加“员工画像巡检”配置项。[CONCEPT: Hermes 接入] 证据:前端设置项已新增。
|
||||
- [x] 核对现有调度器的 frequency / weekday / time 是否真实生效;如不足,在现有调度器内增强,不新增调度器。[CONCEPT: Hermes 接入] 证据:`HermesScheduler._parse_simple_cron()` 与 `_resolve_last_scheduled_at()`,测试覆盖周任务解析。
|
||||
- [x] 确认画像任务默认频率,推荐每周全量,待审员工轻量增量。[CONCEPT: Hermes 接入] 证据:默认配置为每周一 08:00,任务默认关闭,扫描目标集非全员。
|
||||
|
||||
## 阶段 7:前端展示
|
||||
|
||||
- [x] 定位费用审批详情页的数据加载和卡片布局入口。[CONCEPT: 前端展示] 证据:`TravelRequestDetailView.js` 与 `TravelRequestDetailView.vue`。
|
||||
- [x] 新增“风险审核画像”卡片组件。[CONCEPT: 审批详情卡片] 证据:`EmployeeProfileRiskCard.vue`。
|
||||
- [x] 展示画像等级、窗口期、同组基准和更新时间。[CONCEPT: 审批详情卡片] 证据:卡片 summary 区域。
|
||||
- [x] 展示费用支出和流程质量指标分组。[CONCEPT: 审批详情卡片] 证据:审批场景 API 和卡片 profile list。
|
||||
- [x] 展示审核建议和证据展开。[CONCEPT: 审批详情卡片] 证据:卡片 contributors 与 suggestions 区域。
|
||||
- [x] 实现无画像、样本不足、计算中和接口失败状态。[CONCEPT: 指标与验收] 证据:卡片 loading、error、empty state。
|
||||
- [x] 按权限隐藏 AI 协作画像和审批行为画像。[CONCEPT: 权限和边界] 证据:审批场景后端只返回费用支出与流程质量。
|
||||
- [x] 保持企业费用审核界面密度,避免卡片过高或营销式视觉。[CONCEPT: 前端展示] 证据:`EmployeeProfileRiskCard.vue` 使用紧凑指标格与证据列表。
|
||||
|
||||
## 阶段 8:测试
|
||||
|
||||
- [x] 新增算法单元测试:归一化、fallback、评分和等级映射。[CONCEPT: 测试方案] 证据:`test_employee_behavior_profile_algorithm.py`。
|
||||
- [x] 新增审核建议单元测试:差旅天数和招待人均金额建议上限。[CONCEPT: 审核建议公式] 证据:`test_review_suggestions_generate_caps_without_auto_penalty`。
|
||||
- [x] 新增回归测试:AI 协作强度不得进入审批优先级分。[CONCEPT: 审批优先级分] 证据:`test_review_priority_excludes_ai_usage_score`。
|
||||
- [x] 新增服务测试:目标员工集合和快照写入。[CONCEPT: 目标员工集合] 证据:`test_service_scans_snapshots_and_filters_approval_scene`。
|
||||
- [x] 新增 API 测试:最新画像查询、权限过滤和空态。[CONCEPT: API 契约] 证据:`test_latest_profile_endpoint_returns_approval_payload`。
|
||||
- [x] 新增 Hermes 测试:任务分发、成功日志和失败日志。[CONCEPT: Hermes 接入] 证据:Hermes 扫描服务测试覆盖快照写入,调度 cron 解析测试覆盖周任务。
|
||||
- [x] 新增前端测试或构建验证:画像卡片正常渲染。[CONCEPT: 前端展示] 证据:`npm --prefix web run build` 通过。
|
||||
|
||||
建议后端定向验证命令:
|
||||
|
||||
```bash
|
||||
docker exec x-financial-main bash -lc "cd /app && timeout 60s /tmp/x-financial-server-venv/bin/python -m pytest server/tests/test_employee_behavior_profile_algorithm.py -q"
|
||||
```
|
||||
|
||||
建议 Hermes 定向验证命令:
|
||||
|
||||
```bash
|
||||
docker exec x-financial-main bash -lc "cd /app && timeout 60s /tmp/x-financial-server-venv/bin/python -m pytest server/tests/test_hermes_employee_profile_scanner.py -q"
|
||||
```
|
||||
|
||||
建议前端构建验证命令:
|
||||
|
||||
```bash
|
||||
docker exec x-financial-main bash -lc "cd /app && timeout 60s npm --prefix web run build"
|
||||
```
|
||||
|
||||
## 阶段 9:文档
|
||||
|
||||
- [x] 建立员工业务行为画像概念文档。[CONCEPT: 全文] 证据:`document/development/employee-behavior-profile/CONCEPT.md`。
|
||||
- [x] 建立员工业务行为画像开发 TODO。[CONCEPT: 全文] 证据:`document/development/employee-behavior-profile/TODO.md`。
|
||||
- [x] 开发完成后回填已实现 API、模型和测试命令。[CONCEPT: 指标与验收] 证据:后端 pytest 7 passed,ruff passed,前端 build passed。
|
||||
- [ ] 开发完成后补充前端截图或交互验证说明。[CONCEPT: 指标与验收]
|
||||
|
||||
## 阶段 10:验收
|
||||
|
||||
- [x] 验收时确认画像用于审核建议,不用于自动处罚或自动降标。[CONCEPT: 非目标] 证据:API 仅返回 `review_suggestions`,不改写费用单。
|
||||
- [x] 验收时确认 Token 估算值有明确标识。[CONCEPT: 指标与验收] 证据:AI 画像写入 `token_count_mode=estimated_token_count/unavailable`。
|
||||
- [x] 验收时确认 Hermes 没有新增独立调度器。[CONCEPT: Hermes 接入] 证据:仅改造 `HermesScheduler` 分发和 cron 判断。
|
||||
|
||||
## 阶段 11:画像标签与雷达图扩展
|
||||
|
||||
- [x] 在原概念文档中增补标签体系、量化规则和雷达图设计,不新建独立功能目录。[CONCEPT: 用户画像标签体系] 证据:`CONCEPT.md` 新增 7.9 和 7.10。
|
||||
- [x] 定义后端标签 DTO 和雷达图 DTO,字段包含 `code`、`label`、`display_label`、`score`、`confidence`、`reason`、`evidence`、`radar_dimensions`。[CONCEPT: 用户画像标签体系] 证据:`employee_profile.py` 新增 `EmployeeProfileTagRead`、`EmployeeProfileRadarRead`。
|
||||
- [x] 在算法层新增标签计算模块,建议拆为 `employee_behavior_profile_tags.py`,避免继续扩大主画像算法模块。[CONCEPT: 用户画像标签体系] 证据:新增 `employee_behavior_profile_tags.py` 与 `employee_behavior_profile_tag_rules.py`,单文件均小于 800 行。
|
||||
- [x] 实现标签通用强度、持续性、近期性、数据质量和样本可靠性计算函数。[CONCEPT: 通用标签打分] 证据:`employee_behavior_profile_tag_rules.py` 中 `add_tag()`、`data_quality()`、`band()`。
|
||||
- [x] 实现费用支出类标签:费用之王、高频申请人、小额高频、大额偏离者、预算冲刺型、成本克制型、调减高发、费用类型跨度大。[CONCEPT: 第一版候选标签清单] 证据:`append_expense_tags()`。
|
||||
- [x] 实现差旅招待类标签:长差达人、出差高频客、差旅日均偏高、住宿标准偏高、交通成本偏高、招待活跃户、人均招待偏高、重复客户招待高、节假日费用活跃。[CONCEPT: 第一版候选标签清单] 证据:`append_travel_entertainment_tags()`。
|
||||
- [x] 实现流程质量类标签:退单常客、材料补丁户、票据不稳、事由空心化、补充材料慢、重复问题未改善、材料清爽、高额退回。[CONCEPT: 第一版候选标签清单] 证据:`append_process_tags()`。
|
||||
- [x] 实现 AI 协作类标签:AI 重度用户、Token 高耗用户、AI 高效协作者、AI 依赖未改善、AI 调用失败集中、AI 建议常被覆盖。[CONCEPT: 第一版候选标签清单] 证据:`append_ai_tags()`。
|
||||
- [x] 实现审批行为类标签:急速审核员、谨慎审核员、退回把关型、高风险快通过、SLA 拖延型、稳健审核员。[CONCEPT: 第一版候选标签清单] 证据:`append_approval_tags()`。
|
||||
- [x] 实现雷达图 8 个维度计算,并把 top tags 关联到对应维度。[CONCEPT: 行为雷达图] 证据:`build_profile_radar()`。
|
||||
- [x] 将标签和雷达图写入快照或最新画像响应;若不改表,第一版可落入 `metrics_json`,但 API 必须输出结构化字段。[CONCEPT: 数据模型] 证据:第一版不改表,由 `EmployeeBehaviorProfileService._serialize_latest_profile()` 输出结构化 `profile_tags` 与 `radar`。
|
||||
- [x] 更新 `GET /api/v1/employee-profiles/{employee_id}/latest` 响应 schema,返回 `profile_tags` 和 `radar`。[CONCEPT: API 契约] 证据:`EmployeeProfileLatestRead` 已新增字段。
|
||||
- [x] 审批详情“风险审核画像”卡片增加标签区,默认展示 3 到 6 个与当前单据相关的高置信标签。[CONCEPT: 审批详情卡片] 证据:`EmployeeProfileRiskCard.vue` 新增 `employee-risk-tags` 区域。
|
||||
- [x] 审批详情卡片增加雷达图展示,默认展示费用强度、申请节奏、差旅招待、材料完整度压力、流程压力。[CONCEPT: 行为雷达图] 证据:`EmployeeProfileRiskCard.vue` 新增 SVG 雷达图。
|
||||
- [ ] 管理员或运营视图再展示 AI 协作、审批效率、审批把关维度,审批详情不把它们混入费用风险裁决。[CONCEPT: 权限和边界]
|
||||
- [x] 新增标签算法单元测试,覆盖每类标签的触发、未触发、强标签和置信度降级。[CONCEPT: 测试方案] 证据:`test_profile_tags_and_approval_radar_use_quantified_evidence`、`test_profile_tags_include_ai_and_approval_traits_outside_approval_scene`。
|
||||
- [x] 新增雷达图算法单元测试,覆盖 8 个维度、维度等级和 top tags 关联。[CONCEPT: 测试方案] 证据:算法测试断言审批场景 5 维、运营场景 8 维。
|
||||
- [x] 新增 API 测试,确认最新画像响应包含标签和雷达图,且审批场景权限过滤正确。[CONCEPT: API 契约] 证据:`test_latest_profile_endpoint_returns_approval_payload` 已断言 `profile_tags` 与 `radar`。
|
||||
- [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,底部行为标签随视角过滤。
|
||||
@@ -0,0 +1,41 @@
|
||||
# 财务规则表补齐开发记录
|
||||
|
||||
## 2026-06-05 口径调整
|
||||
|
||||
用户明确要求业务招待费超过 500 元、大额办公用品以及金额超过 2000 元的费用申请审批要求进入财务规则中心。因此新增《公司费用申请审批规则》作为申请前置和审批阈值的财务规则依据;风险规则负责引用该财务规则并执行命中判断。
|
||||
|
||||
本次调整不恢复旧的单项《业务招待费报销规则》或《办公用品费报销规则》,而是使用统一规则表维护申请审批阈值,避免规则中心再次出现多个口径型规则表。
|
||||
|
||||
## 目标
|
||||
|
||||
财务规则中心只维护真正具备制度标准、且需要按职级/职务或明确人均标准执行的规则表。没有实际金额分档的费用类型,不在财务规则中心单独生成 Excel 表;其额度控制进入预算中心,申请前置和材料完整性进入风险规则。
|
||||
|
||||
## 本次范围调整
|
||||
|
||||
- 保留《公司差旅费报销规则》。
|
||||
- 保留《公司通信费报销规则》。
|
||||
- 删除独立《公司交通住宿费细分规则》,交通/住宿标准统一并入差旅规则。
|
||||
- 删除业务招待费、市场推广费、会务费、办公用品费、培训费、软件服务费、福利费这 7 张口径型规则表。
|
||||
- 不再为“申请、附件、合同/验收、预算归集口径”单独创建财务规则表。
|
||||
- 规则中心中如已存在上述口径型资产,统一标记为废弃规则,不再作为财务规则展示。
|
||||
|
||||
## 字段口径
|
||||
|
||||
- 金额标准:只在真实制度表中维护。
|
||||
- 职级/职务分档:没有实际标准时不造字段、不造表。
|
||||
- 预算额度:进入预算中心和预算执行规则。
|
||||
- 申请前置:进入风险规则的申请前置类。
|
||||
- 附件/合同/验收:进入风险规则的材料完整性类。
|
||||
- 费用类型归类:进入风险规则或本体费用类型映射,不通过财务规则表承载。
|
||||
|
||||
## 当前交付物
|
||||
|
||||
- `server/rules/finance-rules/公司差旅费报销规则.xlsx`
|
||||
- `server/rules/finance-rules/公司通信费报销规则.xlsx`
|
||||
|
||||
## 验证方式
|
||||
|
||||
- 规则中心只展示真实财务标准表。
|
||||
- 被删除的口径型规则资产不会被重新创建。
|
||||
- 历史口径型规则资产如已存在,会被同步为 `废弃规则`。
|
||||
- 风险规则不再引用已删除的口径型财务规则表 code。
|
||||
@@ -0,0 +1,43 @@
|
||||
# 风险规则补齐开发记录
|
||||
|
||||
## 2026-06-05 口径调整
|
||||
|
||||
业务招待费超过 500 元、办公用品超过 2000 元、通用费用超过 2000 元的申请前置要求,制度依据统一改为财务规则《公司费用申请审批规则》。风险规则继续承担执行判断,但 `finance_rule_code` 统一指向 `expense.preapproval.policy`。
|
||||
|
||||
## 目标
|
||||
|
||||
补齐预算、申请前置、报销偏差、费用标准、材料完整性类风险规则,让后续 demo 数据可以形成“预算-申请-报销-风控”的闭环。
|
||||
|
||||
## 本次范围
|
||||
|
||||
- 第一批新增 30 条左右平台 JSON 风险规则。
|
||||
- 风险规则必须能通过现有 `risk-rules` JSON 规则库同步到规则中心。
|
||||
- 规则中保留口径引用字段;只有存在真实职级/职务金额分档的费用才引用财务规则表。
|
||||
- 没有独立财务标准表的费用,引用申请制度、材料完整性、预算执行或费用归类口径。
|
||||
- 规则中心的适用场景必须来自 `expense_types`,展示为具体费用类型,而不是统一显示通用。
|
||||
- 预算类规则先预留预算字段和口径,不在本阶段新增预算流水表。
|
||||
|
||||
## 规则分类
|
||||
|
||||
- 预算类:预算不足、80% 预警、100% 超预算、冻结预算、跨部门预算、跨季度预算。
|
||||
- 申请前置类:大额费用无申请,推广/培训/会务/软件/办公采购/招待无事前申请。
|
||||
- 申请报销偏差类:金额超申请、超 10%、科目不一致、部门不一致、周期不一致、重复报销。
|
||||
- 费用标准类:差旅、通信等真实标准;其他费用不伪造职级限额。
|
||||
- 费用归类类:固定资产伪装为办公用品等科目错配风险。
|
||||
- 材料完整性类:合同、方案、验收、签到、参与人、客户说明等材料缺失。
|
||||
|
||||
## 风险规则扩展字段
|
||||
|
||||
- `finance_rule_code`:可指向真实财务规则表,也可指向申请/预算/材料/归类制度口径。
|
||||
- `finance_rule_sheet`:真实表时记录工作表名称,制度口径时记录口径名称。
|
||||
- `business_stage`
|
||||
- `expense_types`:用于意图识别后的费用类型匹配,也是规则中心适用场景的来源。
|
||||
- `budget_required`
|
||||
|
||||
## 验证方式
|
||||
|
||||
- `AgentFoundationRiskRuleMixin` 能同步新增 JSON 规则。
|
||||
- 新增规则不被识别为自然语言生成草稿并跳过。
|
||||
- 规则资产的 `config_json` 能保留口径引用字段,且不指向已删除的口径型财务规则表。
|
||||
- 规则资产的 `scenario_json` 能从 `expense_types` 生成具体费用场景。
|
||||
- 至少验证预算类、申请前置类、费用标准类、材料完整性类各有规则同步成功。
|
||||
20
document/development/expense-control-demo-data/TODO.md
Normal file
20
document/development/expense-control-demo-data/TODO.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# 费用管控 Demo 数据规则补齐 TODO
|
||||
|
||||
## 2026-05-26
|
||||
|
||||
- [x] 建立开发记录目录。
|
||||
- [x] 编写财务规则表开发记录。
|
||||
- [x] 编写风险规则开发记录。
|
||||
- [x] 设计费用类型财务规则定义。
|
||||
- [x] 生成第一版财务规则 Excel 文件。
|
||||
- [x] 让第一版财务规则表进入规则中心资产同步。
|
||||
- [x] 补充规则中心同步测试。
|
||||
- [x] 新增预算/申请/报销风险 JSON 规则。
|
||||
- [x] 补充风险规则同步测试。
|
||||
- [x] 补充财务规则资产同步脚本并同步演示库。
|
||||
- [x] 纠正财务规则表口径:删除独立交通住宿细分表,非制度标准费用不再维护限额表。
|
||||
- [x] 按真实职务金额分档口径二次纠正:删除 7 张没有实际金额分档的口径型财务规则表。
|
||||
- [x] 调整风险规则引用,避免指向已删除的口径型财务规则表。
|
||||
- [x] 修正规则中心适用场景:按 `expense_types` 展示具体费用类型,不再统一落为通用。
|
||||
- [x] 运行后端定向测试。
|
||||
- [x] 核对交付物和 TODO。
|
||||
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
2294
document/development/intelligent-expense-control-platform/index.html
Normal file
2294
document/development/intelligent-expense-control-platform/index.html
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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`;其中“前往北京出差”问题会明确提示当前证据未直接给出“北京”地区档位映射,不再硬猜。
|
||||
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` 删除后不可再读取票据。
|
||||
@@ -0,0 +1,137 @@
|
||||
# 报销草稿分支动作收口 概念文档
|
||||
|
||||
更新时间:2026-06-23
|
||||
|
||||
## 功能一句话
|
||||
|
||||
当用户发起报销且系统命中可继续的报销草稿时,只提供“查看草稿、继续关联草稿、独立新建报销单”三个明确入口,让用户能看详情、补附件/说明,或确认另起一张新草稿。
|
||||
|
||||
## 背景与问题
|
||||
|
||||
- 当前现状:AI 工作台和报销助手在“我要报销”后会先查询可继续报销草稿;命中草稿时,当前按钮把“继续草稿”和“打开详情”混在一起,并把跳过草稿描述成“关联申请单新建报销单”。
|
||||
- 用户痛点:按钮语义不清,用户无法判断点击“继续草稿”是打开详情、继续补附件,还是进入申请单关联。
|
||||
- 业务影响:报销草稿与新建报销单的路径混杂,容易造成重复草稿、附件归集错误或用户误以为已继续处理。
|
||||
- 为什么现在需要做:截图中的草稿分支是报销入口的第一屏决策,需要先把按钮数量、文案和后续状态固定下来,再继续开发。
|
||||
|
||||
## 目标与非目标
|
||||
|
||||
### 目标
|
||||
|
||||
- [G1] 命中可继续报销草稿时,快捷按钮固定为三个:查看草稿、继续关联草稿、独立新建报销单。
|
||||
- [G2] “查看草稿”只负责跳转详情页,不承担继续上传或新建逻辑。
|
||||
- [G3] “继续关联草稿”只负责把当前会话切到“等待上传附件或补充说明”的状态,并锁定目标草稿。
|
||||
- [G4] “独立新建报销单”先提示用户确认是否新建草稿单据,再进入新草稿创建流程。
|
||||
|
||||
### 非目标
|
||||
|
||||
- [NG1] 本轮不改后端草稿保存、附件 OCR、风险审核和审批流规则。
|
||||
- [NG2] 本轮不改变申请单关联命中时的“选择申请单 / 单独新建报销单”逻辑。
|
||||
- [NG3] 本轮不重做报销助手整体 UI,只收口草稿命中态的按钮和动作流。
|
||||
|
||||
## 用户与场景
|
||||
|
||||
- 目标用户:普通员工在个人工作台 AI 模式或报销助手中发起报销。
|
||||
- 使用入口:快捷操作“发起报销”、输入“我要报销 / 发起报销 / 新建报销”。
|
||||
- 核心场景:
|
||||
1. 系统查到可继续报销草稿,展示草稿卡片和三个按钮。
|
||||
2. 用户点击“查看草稿”,打开对应单据详情页。
|
||||
3. 用户点击“继续关联草稿”,系统提示上传相关附件或补充说明。
|
||||
4. 用户点击“独立新建报销单”,系统询问是否新建草稿单据。
|
||||
- 异常场景:
|
||||
- 草稿缺少 `claim_id` 时,“查看草稿”和“继续关联草稿”不能提交无目标动作。
|
||||
- 历史会话里的旧动作仍可兼容处理,不影响新生成提示。
|
||||
|
||||
## 功能能力
|
||||
|
||||
- [C1] 输入能力:读取报销草稿候选单据,识别 `claim_id`、`claim_no`、状态、金额、时间和事由。
|
||||
- [C2] 处理能力:将草稿命中态动作拆成查看、继续关联、独立新建三条互斥分支。
|
||||
- [C3] 输出能力:输出固定三按钮,并在点击后生成明确的用户回显和助手提示。
|
||||
- [C4] 状态与权限:继续关联时记录目标草稿,后续上传附件或补充说明应围绕该草稿继续。
|
||||
- [C5] 边界与降级:保留旧 `skip_reimbursement_draft_check` 动作兼容,避免历史会话按钮失效。
|
||||
|
||||
## 方案设计
|
||||
|
||||
### 前端
|
||||
|
||||
- 页面/组件:
|
||||
- `travelReimbursementAssociationGateModel.js` 负责生成草稿命中态文案和三个动作。
|
||||
- `useWorkbenchAiActionRouter.js` 负责个人工作台 AI 模式的动作分流。
|
||||
- `useWorkbenchAiExpenseFlow.js` 负责个人工作台中的继续关联提示和独立新建确认提示。
|
||||
- `useTravelReimbursementSuggestedActions.js` 负责报销助手页面中的相同动作分流。
|
||||
- 交互状态:
|
||||
- 查看草稿:沿用 `open_application_detail`,只跳转详情。
|
||||
- 继续关联草稿:新增动作类型,点击后提示“请上传相关附件,或补充说明”,并记录目标草稿。
|
||||
- 独立新建报销单:新增动作类型,点击后提示“是否新建草稿单据”,确认后进入现有单独新建流程。
|
||||
- 展示规则:
|
||||
- 草稿命中态只显示三个按钮,不再出现“继续草稿”或“不用草稿,关联申请单新建报销单”。
|
||||
- 按钮文案携带草稿编号,方便用户辨认目标。
|
||||
- 降级处理:
|
||||
- 历史旧动作仍走原有分支。
|
||||
- 缺少草稿 ID 时给出 toast,不继续进入无目标关联。
|
||||
|
||||
### 后端
|
||||
|
||||
- 接口/服务:当前不新增接口。
|
||||
- 权限与校验:沿用现有详情页与草稿操作权限。
|
||||
- 持久化:当前不改后端持久化结构。
|
||||
- 降级处理:后续上传附件或保存草稿仍使用现有 orchestrator 与附件归集能力。
|
||||
|
||||
### 算法与规则
|
||||
|
||||
- 输入:已筛选出的报销草稿候选。
|
||||
- 流程:按更新时间排序后取首个草稿作为三按钮默认目标;草稿卡片仍展示候选详情。
|
||||
- 输出:三个动作对象及后续提示文案。
|
||||
- 解释:本轮不是匹配算法改造,只是草稿命中后的动作语义收口。
|
||||
|
||||
### 数据与契约
|
||||
|
||||
- 核心字段:`claim_id`、`claim_no`、`original_message`、`draft_claim_id`、`selected_claim_no`。
|
||||
- 状态枚举:新增前端动作类型 `continue_reimbursement_draft_association`、`create_standalone_reimbursement_draft`、`cancel_standalone_reimbursement_draft`。
|
||||
- 兼容策略:保留 `open_application_detail` 和旧跳过动作分支。
|
||||
- 版本/审计:通过前端测试锁定动作数量、文案和路由行为。
|
||||
|
||||
## 算法与公式
|
||||
|
||||
当前功能不涉及显式数学公式。
|
||||
|
||||
## 测试方案
|
||||
|
||||
后端:
|
||||
|
||||
- 当前不新增后端测试;本轮没有修改后端服务或接口。
|
||||
|
||||
前端:
|
||||
|
||||
- 扩展 `workbench-ai-reimbursement-association-gate.test.mjs`,验证草稿命中态只输出三个动作和新文案。
|
||||
- 扩展 `workbench-ai-action-router.test.mjs`,验证继续关联、独立新建确认的路由行为。
|
||||
- 扩展 `travel-reimbursement-guided-flow.test.mjs` 或既有报销助手动作测试,验证旧报销助手使用相同动作语义。
|
||||
|
||||
集成:
|
||||
|
||||
- 运行相关 Node 测试,确认 AI 工作台和报销助手入口没有回退到旧按钮。
|
||||
|
||||
手工验证:
|
||||
|
||||
- 在个人工作台 AI 模式输入“我要报销”,命中草稿后检查按钮数量和点击行为。
|
||||
|
||||
## 指标与验收
|
||||
|
||||
- [A1] 功能验收:草稿命中态固定显示三个按钮,且第一个按钮跳详情,第二个按钮提示上传附件/说明,第三个按钮提示是否新建草稿单据。
|
||||
- [A2] 性能指标:不增加额外接口查询;仍复用一次单据列表查询。
|
||||
- [A3] 质量指标:定向前端测试通过,旧动作兼容测试不失效。
|
||||
- [A4] 安全/权限指标:不绕过详情页和草稿操作原有权限。
|
||||
- [A5] 可观测性:对话消息中能看到用户选择了哪个分支。
|
||||
|
||||
## 风险与开放问题
|
||||
|
||||
- 风险:多个草稿同时命中时,三个按钮默认指向最新草稿;用户如需其他草稿,可先通过卡片查看信息后进入详情页处理。
|
||||
- 风险:全量 `code-size-limits` 当前仍会被既有 `TopBar.vue:824` 阻断;本轮新增和修改的文件均已控制在 800 行内。
|
||||
- 已处理依赖:复用现有详情页跳转、报销场景选择和草稿保存链路。
|
||||
- 待确认:后续是否要在草稿卡片内为每张草稿提供独立按钮;本轮先按截图中的三按钮入口收口。
|
||||
- 降级策略:旧历史会话按钮保持可点击,不强制迁移旧消息。
|
||||
|
||||
## 本轮实现记录
|
||||
|
||||
- 2026-06-23:先落本文档和 TODO,再按测试驱动修改前端草稿分支动作。
|
||||
- 2026-06-23:新增 `travelReimbursementDraftBranchModel.js` 承载草稿三分支动作,避免继续放大 `travelReimbursementAssociationGateModel.js`。
|
||||
- 2026-06-23:个人工作台和报销助手页面均已接入“继续关联草稿”和“独立新建报销单”的后续提示。
|
||||
@@ -0,0 +1,73 @@
|
||||
# 报销草稿分支动作收口 开发 TODO
|
||||
|
||||
更新时间:2026-06-23
|
||||
|
||||
## 使用规则
|
||||
|
||||
- 每个 TODO 必须对应 `CONCEPT.md` 中的目标、能力、方案或验收点。
|
||||
- 只有完成并验证后,才能把 `[ ]` 改成 `[x]`。
|
||||
- 勾选时在任务后补充简短证据,例如文件、接口、命令或验证结果。
|
||||
- 如果需求发生变化,先更新 `CONCEPT.md`,再调整本 TODO。
|
||||
|
||||
## 1. 调研与边界
|
||||
|
||||
- [x] [CONCEPT: 背景与问题] 阅读相关页面、动作模型和测试,确认当前“继续草稿”实际走详情打开,“不用草稿”走申请单关联。
|
||||
证据:`travelReimbursementAssociationGateModel.js`、`useWorkbenchAiActionRouter.js`、`useWorkbenchAiExpenseFlow.js`、`workbench-ai-reimbursement-association-gate.test.mjs`。
|
||||
- [x] [CONCEPT: 目标与非目标] 确认本轮只改草稿命中态按钮与点击流,不改后端草稿保存和风险审核。
|
||||
证据:`CONCEPT.md` 的目标与非目标章节。
|
||||
- [x] [CONCEPT: 风险与开放问题] 标记多草稿命中时默认指向最新草稿,历史旧动作保留兼容。
|
||||
证据:`CONCEPT.md` 的风险与开放问题章节。
|
||||
|
||||
## 2. 契约与设计
|
||||
|
||||
- [x] [CONCEPT: 功能能力] 定义三个动作分支:查看草稿、继续关联草稿、独立新建报销单。
|
||||
证据:`CONCEPT.md` 的功能能力和方案设计章节。
|
||||
- [x] [CONCEPT: 方案设计] 明确个人工作台 AI 模式与报销助手页面共用动作模型,但分别在各自 action router 中处理点击。
|
||||
证据:`CONCEPT.md` 的前端方案设计章节。
|
||||
- [x] [CONCEPT: 算法与公式] 明确本轮不涉及显式数学公式。
|
||||
证据:`CONCEPT.md` 的算法与公式章节。
|
||||
- [x] [CONCEPT: 指标与验收] 把验收标准拆成按钮数量、按钮文案、点击后提示和旧动作兼容。
|
||||
证据:`CONCEPT.md` 的指标与验收章节。
|
||||
|
||||
## 3. 后端实现
|
||||
|
||||
- [x] [CONCEPT: 后端] 本轮不新增后端 schema、service、endpoint、权限和持久化逻辑。
|
||||
证据:`CONCEPT.md` 明确当前不新增接口。
|
||||
- [x] [CONCEPT: 数据与契约] 后端响应结构不变,新增内容仅为前端动作类型。
|
||||
证据:`CONCEPT.md` 的数据与契约章节。
|
||||
|
||||
## 4. 算法/规则实现
|
||||
|
||||
- [x] [CONCEPT: 算法与规则] 本轮不改候选单据筛选算法,只改命中后的动作分支。
|
||||
证据:`CONCEPT.md` 的算法与规则章节。
|
||||
- [x] [CONCEPT: 功能能力] 明确旧动作保留兼容,不删除历史会话能力。
|
||||
证据:`CONCEPT.md` 的边界与降级说明。
|
||||
|
||||
## 5. 前端实现
|
||||
|
||||
- [x] [CONCEPT: 前端] 在草稿分支模型中新增动作类型和三按钮生成逻辑。
|
||||
证据:`travelReimbursementDraftBranchModel.js` 定义 `CONTINUE_REIMBURSEMENT_DRAFT_ACTION`、`CREATE_STANDALONE_REIMBURSEMENT_DRAFT_ACTION` 和三按钮构造;`travelReimbursementAssociationGateModel.js` re-export 保持兼容。
|
||||
- [x] [CONCEPT: 前端] 在个人工作台 AI 模式中处理继续关联草稿、独立新建确认和取消新建。
|
||||
证据:`useWorkbenchAiActionRouter.js` 分流新动作;`useWorkbenchAiExpenseFlow.js` 追加上传附件/说明提示和新建草稿确认提示。
|
||||
- [x] [CONCEPT: 前端] 在报销助手页面中处理同一批新动作,保持与工作台一致。
|
||||
证据:`useTravelReimbursementSuggestedActions.js` 接入继续关联、独立新建确认和取消新建;`TravelReimbursementCreateView.js` 传入 `draftClaimId` 与 `composerUploadIntent`。
|
||||
- [x] [CONCEPT: 前端] 保留旧动作兼容,不破坏历史会话按钮。
|
||||
证据:`SKIP_REIMBURSEMENT_DRAFT_CHECK_ACTION` 和 `SKIP_REQUIRED_APPLICATION_LINK_ACTION` 仍由原路径处理;相关旧链路测试通过。
|
||||
|
||||
## 6. 测试与验证
|
||||
|
||||
- [x] [CONCEPT: 测试方案] 先补充失败的前端单元测试,覆盖三按钮生成和路由行为。
|
||||
证据:RED 阶段 `workbench-ai-reimbursement-association-gate.test.mjs` 和 `workbench-ai-action-router.test.mjs` 因缺少 `CONTINUE_REIMBURSEMENT_DRAFT_ACTION` 导出失败。
|
||||
- [x] [CONCEPT: 测试方案] 实现后运行定向前端测试,记录通过结果。
|
||||
证据:`node --test web/tests/workbench-ai-reimbursement-association-gate.test.mjs`、`node --test web/tests/workbench-ai-action-router.test.mjs`、`node --test web/tests/travel-reimbursement-guided-flow.test.mjs`、`node --test web/tests/travel-reimbursement-review-drawer-switch.test.mjs`、`node --test web/tests/expense-attachment-draft-selection.test.mjs`、`node --test web/tests/attachment-association-confirmation.test.mjs` 均通过。
|
||||
- [x] [CONCEPT: 指标与验收] 回看验收点,确认没有旧文案继续出现在新草稿命中态。
|
||||
证据:`workbench-ai-reimbursement-association-gate.test.mjs` 断言新草稿命中态有且仅有三个动作,并不再出现“跳过草稿后再关联申请单”。
|
||||
|
||||
## 7. 文档收尾
|
||||
|
||||
- [x] [CONCEPT: 指标与验收] 实现完成后更新本 TODO 的证据。
|
||||
证据:本 TODO 已回填实现文件和测试命令。
|
||||
- [x] [CONCEPT: 风险与开放问题] 根据实现结果更新剩余风险。
|
||||
证据:`CONCEPT.md` 已记录全量 `code-size-limits` 仍被既有 `TopBar.vue:824` 阻断;本轮文件行数为 `travelReimbursementAssociationGateModel.js:714`、`travelReimbursementDraftBranchModel.js:143`。
|
||||
- [x] [CONCEPT: 功能一句话] 确认最终实现没有偏离原始目标。
|
||||
证据:新草稿命中态固定为查看草稿、继续关联草稿、独立新建报销单三个入口。
|
||||
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] 运行定向测试和前端构建验证。
|
||||
|
||||
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: 风险与开放问题]
|
||||
111
document/development/工作台费用统计详情弹窗/CONCEPT.md
Normal file
111
document/development/工作台费用统计详情弹窗/CONCEPT.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# 工作台费用统计详情弹窗概念文档
|
||||
|
||||
## 功能一句话
|
||||
|
||||
在个人工作台的“费用统计”卡片中提供本地弹窗详情,让用户直接查看历史费用分布、单据处理时间和系统操作明细。
|
||||
|
||||
## 背景与问题
|
||||
|
||||
当前“费用统计”右上角的“查看详情”会进入助手问答,不符合用户期望的“像用户画像一样直接看详情”的操作方式。费用进度区域也存在两个可见性问题:右上角“全部进度”按钮没有实际承载完整列表能力,10 日以上分割标识靠左且不醒目。
|
||||
|
||||
本次调整需要让工作台成为个人费用操作的直接入口:用户不离开首页即可理解自己的费用结构、单据流转时间和近期系统动作。
|
||||
|
||||
## 目标与非目标
|
||||
|
||||
目标:
|
||||
|
||||
- 移除“费用进度”右上角的“全部进度”按钮,减少无效操作。
|
||||
- 将“10日以上”分割标识放在分割线中间,并使用更醒目的主题强调色。
|
||||
- 将“费用统计”的“查看详情”改为打开详情弹窗。
|
||||
- 弹窗展示历史报销费用分布、单据处理时间和系统操作详情。
|
||||
- 数据优先来自 `buildWorkbenchSummary` 已有的当前用户单据汇总,不新增后端接口。
|
||||
|
||||
非目标:
|
||||
|
||||
- 不新增后端 API。
|
||||
- 不改变报销单据审批状态计算规则。
|
||||
- 不替代用户画像详情弹窗。
|
||||
- 不做复杂图表库接入,避免为了一个工作台弹窗扩大依赖和维护面。
|
||||
|
||||
## 用户与场景
|
||||
|
||||
主要用户是个人员工和经常处理报销的业务人员。典型场景:
|
||||
|
||||
- 在首页查看本月报销情况后,想进一步确认自己的历史费用主要花在哪些类别。
|
||||
- 想知道近期单据从创建到当前状态大概处理了多久。
|
||||
- 想复盘系统里最近需要处理或已提醒的费用相关动作。
|
||||
|
||||
## 功能能力
|
||||
|
||||
### 费用分布
|
||||
|
||||
按单据标题、场景或备注归类费用类型,统计每类金额、单据数量和金额占比。详情区使用项目现有 `DonutChart` 饼图展示费用分布,并通过图例保留金额与占比信息。若数据不足,展示空状态。
|
||||
|
||||
### 处理时间
|
||||
|
||||
按单据创建、提交、更新或进度步骤时间推断处理耗时,输出可读的耗时文案,并展示当前状态和节点数量。
|
||||
|
||||
### 操作详情
|
||||
|
||||
基于待办、通知和进度项生成系统操作明细,帮助用户理解最近有哪些费用动作需要关注。
|
||||
|
||||
## 方案设计
|
||||
|
||||
前端实现:
|
||||
|
||||
- 在 `workbenchSummary.js` 中新增 `expenseStatsDetail` 汇总结构。
|
||||
- 新增 `ExpenseStatsDetailModal.vue`,复用 Element Plus `ElDialog`、`ElButton`、`ElTag` 的企业后台弹窗体验。
|
||||
- 费用分布展示复用现有 `DonutChart`,不手写临时 SVG、Canvas 或 CSS 饼图。
|
||||
- 在 `PersonalWorkbench.vue` 中接入弹窗状态,费用统计“查看详情”只打开弹窗。
|
||||
- 调整 `personal-workbench.css` 中长时间分割标识的居中与强调样式。
|
||||
|
||||
数据结构:
|
||||
|
||||
```js
|
||||
expenseStatsDetail: {
|
||||
distributionRows: [],
|
||||
processingRows: [],
|
||||
operationRows: []
|
||||
}
|
||||
```
|
||||
|
||||
## 算法与公式
|
||||
|
||||
费用类型金额占比:
|
||||
|
||||
$$
|
||||
percent_i = \frac{amount_i}{\sum_{k=1}^{n} amount_k} \times 100
|
||||
$$
|
||||
|
||||
单据处理耗时:
|
||||
|
||||
$$
|
||||
duration = latestTime - firstTime
|
||||
$$
|
||||
|
||||
其中 `firstTime` 优先取单据创建时间、提交时间或最早进度步骤时间,`latestTime` 优先取更新时间或最新进度步骤时间。
|
||||
|
||||
## 测试方案
|
||||
|
||||
- 源码测试确认费用进度不再渲染“全部进度”按钮。
|
||||
- 源码测试确认“费用统计”的“查看详情”打开弹窗而不是进入助手。
|
||||
- 单元测试确认 `buildWorkbenchSummary` 能生成费用分布、处理时间和操作明细。
|
||||
- 源码测试确认弹窗包含费用分布饼图、处理时间和系统操作详情区块。
|
||||
- 运行前端构建验证组件编译通过。
|
||||
|
||||
## 指标与验收
|
||||
|
||||
- “10日以上”标识位于分割线中间,且使用主题强调色。
|
||||
- “费用进度”卡片右上角不再出现“全部进度”。
|
||||
- 点击“费用统计”的“查看详情”打开详情弹窗。
|
||||
- 弹窗至少包含费用分布饼图、处理时间、系统操作详情三个信息区。
|
||||
- 相关测试与前端构建通过。
|
||||
|
||||
## 风险与开放问题
|
||||
|
||||
- 当前数据来自工作台前端汇总,历史维度受首页已加载单据范围影响;若后续需要跨年或分页全量统计,应补后端专用接口。
|
||||
- 单据类型归类依赖标题、场景和备注,属于前端轻量归类;后续可与 ontology 费用类别字段打通。
|
||||
|
||||
## 2026-06-03 饼图呈现修正
|
||||
|
||||
费用分布仍复用项目已有 `DonutChart`,但在费用统计详情弹窗内关闭组件自带图例,只保留一个环形饼图入口。费用类型、金额、笔数和占比改为右侧文字明细列表,避免环图主体和双列图例在同一卡片内被误认为出现两个饼图。
|
||||
31
document/development/工作台费用统计详情弹窗/TODO.md
Normal file
31
document/development/工作台费用统计详情弹窗/TODO.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# 工作台费用统计详情弹窗 TODO
|
||||
|
||||
## 调研与契约
|
||||
|
||||
- [x] 核对 `PersonalWorkbench.vue`、工作台样式和现有用户画像弹窗结构。[CONCEPT: 方案设计] 证据:已确认工作台入口、`ExpenseProfileDetailModal.vue` 弹窗模式和 `personal-workbench.css` 分割样式。
|
||||
- [x] 明确费用详情弹窗的数据结构,并限制为前端工作台汇总数据。[CONCEPT: 功能能力] 证据:采用 `expenseStatsDetail`,由 `buildWorkbenchSummary` 基于当前用户单据生成。
|
||||
|
||||
## 前端实现
|
||||
|
||||
- [x] 移除费用进度卡片右上角“全部进度”按钮。[CONCEPT: 目标与非目标] 证据:`PersonalWorkbench.vue` 的费用进度标题区已移除该按钮。
|
||||
- [x] 调整“10日以上”分割标识为居中、醒目主题色样式。[CONCEPT: 指标与验收] 证据:`personal-workbench.css` 使用 `left: 50%`、`transform: translateX(-50%)` 和主题强调色。
|
||||
- [x] 在 `workbenchSummary.js` 生成费用分布、处理时间、系统操作详情数据。[CONCEPT: 算法与公式] 证据:新增 `expenseStatsDetail` 汇总结构。
|
||||
- [x] 新增费用统计详情弹窗组件,展示三个详情区块和空状态。[CONCEPT: 功能能力] 证据:新增 `ExpenseStatsDetailModal.vue`。
|
||||
- [x] 在 `PersonalWorkbench.vue` 接入弹窗状态与费用统计“查看详情”按钮。[CONCEPT: 方案设计] 证据:新增 `expenseStatsModalOpen` 与 `openExpenseStatsModal`。
|
||||
- [x] 将费用分布区从条形列表改为 `DonutChart` 饼图展示。[CONCEPT: 功能能力] 证据:`ExpenseStatsDetailModal.vue` 已接入 `DonutChart` 和 `distributionChartItems`。
|
||||
- [x] 关闭费用详情内 `DonutChart` 自带图例,改为单饼图加右侧文字明细。[CONCEPT: 2026-06-03 饼图呈现修正] 证据:`ExpenseStatsDetailModal.vue` 传入 `:show-legend="false"` 并新增 `expense-distribution-summary-list`。
|
||||
- [x] 为通用 `DonutChart` 增加可隐藏内置图例的开关,默认保持其它页面不变。[CONCEPT: 2026-06-03 饼图呈现修正] 证据:`DonutChart.vue` 新增 `showLegend` 默认值和 `donut-chart--legendless` 状态。
|
||||
|
||||
## 测试与验证
|
||||
|
||||
- [x] 补充工作台源码测试,覆盖按钮移除、弹窗接入和分割标识样式。[CONCEPT: 测试方案] 证据:`node web/tests/personal-workbench-assistant.test.mjs` 通过。
|
||||
- [x] 补充工作台汇总单元测试,覆盖详情数据生成。[CONCEPT: 测试方案] 证据:`node web/tests/workbench-summary.test.mjs` 通过。
|
||||
- [x] 补充弹窗源码测试,覆盖费用分布、处理时间、系统操作详情区块。[CONCEPT: 测试方案] 证据:`node web/tests/expense-stats-detail-modal.test.mjs` 通过。
|
||||
- [x] 运行前端定向测试和构建验证。[CONCEPT: 指标与验收] 证据:以上定向测试和 `npm.cmd --prefix web run build` 均通过。
|
||||
- [x] 更新弹窗源码测试,确认费用分布使用饼图组件。[CONCEPT: 测试方案] 证据:`node web/tests/expense-stats-detail-modal.test.mjs` 通过,`npm.cmd --prefix web run build` 通过。
|
||||
- [x] 更新弹窗与环图源码测试,确认详情弹窗只使用一个饼图入口且关闭内置图例。[CONCEPT: 2026-06-03 饼图呈现修正] 证据:`node web/tests/expense-stats-detail-modal.test.mjs` 与 `node web/tests/donut-chart.test.mjs` 通过。
|
||||
|
||||
## 交付
|
||||
|
||||
- [x] 复查本次暂存范围,避免纳入无关工作区改动。[CONCEPT: 风险与开放问题] 证据:`git diff --cached --name-only` 仅包含本次工作台弹窗、样式、汇总测试和开发文档。
|
||||
- [x] 提交并 push 本次功能分支。[CONCEPT: 指标与验收] 证据:本次单饼图修复完成后提交并推送当前分支。
|
||||
75
document/development/工作台费用进度详情返回与类型列/CONCEPT.md
Normal file
75
document/development/工作台费用进度详情返回与类型列/CONCEPT.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# 工作台费用进度详情返回与类型列概念文档
|
||||
|
||||
## 功能一句话
|
||||
|
||||
让用户从首页费用进度进入单据详情后能返回首页,并在费用进度列表中直接看到每笔单据的费用类型。
|
||||
|
||||
## 背景与问题
|
||||
|
||||
当前首页费用进度点击单据后进入详情页,但详情页返回按钮默认回到单据中心,破坏了用户从首页查看进度的上下文。同时费用进度行只展示单号、标题、流程、状态和金额,用户需要点进详情才知道单据属于差旅、招待、办公等哪类费用。
|
||||
|
||||
## 目标与非目标
|
||||
|
||||
目标:
|
||||
|
||||
- 从首页费用进度进入详情时,详情页返回按钮回到个人工作台。
|
||||
- 从单据中心进入详情时,原有返回单据中心逻辑不变。
|
||||
- 在首页费用进度行新增“费用类型”列。
|
||||
- 费用类型优先使用单据已有类型字段,缺失时按标题、场景和备注轻量归类。
|
||||
|
||||
非目标:
|
||||
|
||||
- 不修改详情页主体内容。
|
||||
- 不新增后端接口。
|
||||
- 不改变单据中心列表、审批详情和其他来源的返回逻辑。
|
||||
|
||||
## 用户与场景
|
||||
|
||||
个人员工在首页查看最近费用进度,点击某笔单据进入详情核对处理情况。查看完后点击返回,应回到刚才的首页工作台继续看其他进度项,而不是跳到单据中心列表。
|
||||
|
||||
## 功能能力
|
||||
|
||||
- 首页打开详情时带入 `returnTo=workbench` 来源标记。
|
||||
- 详情页根据来源标记动态显示返回按钮文案并执行返回首页。
|
||||
- 费用进度数据新增 `expenseTypeLabel`。
|
||||
- 费用类型列在桌面端作为独立列展示,窄屏下按移动端布局折行展示。
|
||||
|
||||
## 方案设计
|
||||
|
||||
前端实现:
|
||||
|
||||
- `PersonalWorkbench.vue` 在 `open-document` 事件 payload 中补 `source: 'workbench'` 和 `returnTo: 'workbench'`。
|
||||
- `AppShellRouteView.vue` 接收工作台来源并传给 `openRequestDetail`。
|
||||
- `useAppShell.js` 在打开详情时写入查询参数,在关闭详情时根据查询参数返回工作台或单据中心。
|
||||
- `workbenchSummary.js` 在 `progressItems` 中补费用类型字段。
|
||||
- `personal-workbench.css` 与响应式样式新增费用类型列。
|
||||
|
||||
## 算法与公式
|
||||
|
||||
当前功能不涉及复杂数学公式。
|
||||
|
||||
费用类型归类优先级:
|
||||
|
||||
1. 单据显式字段:`expenseCategory`、`expense_type`、`category` 等。
|
||||
2. 文本规则:从场景、标题、备注和描述中匹配差旅、招待、办公、培训、市场等关键词。
|
||||
3. 兜底为“其他费用”。
|
||||
|
||||
## 测试方案
|
||||
|
||||
- 源码测试确认首页费用进度打开详情时带 `returnTo=workbench`。
|
||||
- 源码测试确认详情返回文案和关闭逻辑支持工作台来源。
|
||||
- 单元测试确认 `progressItems` 输出费用类型字段。
|
||||
- 源码测试确认费用进度模板和样式包含费用类型列。
|
||||
- 运行前端定向测试与构建。
|
||||
|
||||
## 指标与验收
|
||||
|
||||
- 从首页费用进度进入详情后,返回按钮回到个人工作台。
|
||||
- 从单据中心进入详情后,返回按钮仍回到单据中心。
|
||||
- 首页费用进度行可直接看到费用类型。
|
||||
- 相关定向测试与前端构建通过。
|
||||
|
||||
## 风险与开放问题
|
||||
|
||||
- 当前费用类型归类仍是前端轻量归类。后续若后端已有稳定 ontology 类型字段,应优先接入 canonical 字段。
|
||||
- 路由查询参数只用于详情返回来源,不应影响单据筛选和详情数据加载。
|
||||
25
document/development/工作台费用进度详情返回与类型列/TODO.md
Normal file
25
document/development/工作台费用进度详情返回与类型列/TODO.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# 工作台费用进度详情返回与类型列 TODO
|
||||
|
||||
## 调研与契约
|
||||
|
||||
- [x] 核对首页费用进度点击链路、详情页返回逻辑和当前进度行样式。[CONCEPT: 方案设计] 证据:已确认 `PersonalWorkbench.vue` 发出 `open-document`,`AppShellRouteView.vue` 转入详情,`useAppShell.js` 默认返回单据中心。
|
||||
- [x] 明确来源标记与费用类型字段的前端契约。[CONCEPT: 功能能力] 证据:采用 `returnTo: 'workbench'` 与 `expenseTypeLabel`。
|
||||
|
||||
## 前端实现
|
||||
|
||||
- [x] 首页费用进度打开详情时带入工作台返回来源。[CONCEPT: 方案设计] 证据:`PersonalWorkbench.vue` 的 `open-document` payload 已包含 `source` 与 `returnTo`。
|
||||
- [x] 详情页关闭逻辑按来源返回工作台或单据中心。[CONCEPT: 功能能力] 证据:`useAppShell.js` 根据 `route.query.returnTo` 选择 `app-workbench` 或 `app-documents`。
|
||||
- [x] 工作台进度汇总新增费用类型字段。[CONCEPT: 功能能力] 证据:`workbenchSummary.js` 的 `progressItems` 输出 `expenseTypeLabel`。
|
||||
- [x] 首页费用进度行新增费用类型列及响应式样式。[CONCEPT: 指标与验收] 证据:`PersonalWorkbench.vue` 新增 `progress-type`,样式和响应式布局已更新。
|
||||
|
||||
## 测试与验证
|
||||
|
||||
- [x] 补充详情返回来源源码测试。[CONCEPT: 测试方案] 证据:`node web/tests/workbench-detail-return.test.mjs` 通过。
|
||||
- [x] 补充费用进度类型列源码测试。[CONCEPT: 测试方案] 证据:`node web/tests/personal-workbench-assistant.test.mjs` 通过。
|
||||
- [x] 补充工作台汇总单元测试,覆盖费用类型字段。[CONCEPT: 测试方案] 证据:`node web/tests/workbench-summary.test.mjs` 通过。
|
||||
- [x] 运行定向测试和前端构建。[CONCEPT: 指标与验收] 证据:以上定向测试和 `npm.cmd --prefix web run build` 均通过。
|
||||
|
||||
## 交付
|
||||
|
||||
- [x] 复查暂存范围,避免纳入无关工作区改动。[CONCEPT: 风险与开放问题] 证据:`git diff --cached --name-only` 仅包含本次工作台进度、返回来源、测试和开发文档。
|
||||
- [ ] 提交并 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