wechat_ai/docs/go-backend-development-plan.md

1069 lines
39 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 微信 AI 助手 Go 后端与多智能体开发方案
> 本文基于 `docs/api-design.md` 的目标契约制定,供技术评审和实施拆分使用。
>
> 当前 API 文档是目标契约,不代表接口已经实现;当前 `agent/` 目录是单次运行的 RPA demo不应直接作为生产后端继续堆功能。
## 1. 评审结论
推荐采用“模块化单体 Go sidecar + 本地原生自动化宿主 + 受控多智能体运行时”的架构:
- Go sidecar 只监听 `127.0.0.1:8766`,承载 HTTP、WebSocket、SQLite、文件中心、模型网关、多智能体调度、知识库、蒸馏、员工和审计日志。
- Tauri/Rust 继续独占窗口选择、截图、坐标、标注、鼠标键盘和 Windows 原生生命周期。
- 多智能体首期运行在同一个 Go 进程内,不拆微服务,不引入 Redis、Kafka、Temporal 或 Kubernetes。
- SQLite 是唯一业务事实源文件使用应用数据目录下的内容寻址存储Windows Credential Manager 保存模型密钥。
- 智能体采用 Supervisor + 有限 DAG/状态机,不允许子 Agent 自由递归、自主扩权或直接执行桌面动作。
- LLM/VLM 是模型能力提供者;业务 Agent 才负责目标、状态、权限和流程。代码层应将两者分开,避免把一次模型调用误当成完整 Agent。
此方案适合当前“单机 Windows、单操作者、本地 sidecar”的产品边界。将来如果要多账号、多设备或云端协作应另行设计不在首期预埋分布式复杂度。
## 2. 当前代码判断
当前 `agent/` 的实际状态:
- `main.go` 是命令行单次运行入口,不是常驻 HTTP/WS 服务。
- `config.go` 直接读取 `config.toml`,并且默认路径仍包含 macOS `~/Library/Application Support`
- `llm.go`/`planner.go` 直接调用单一兼容 OpenAI 的模型,缺少 provider 抽象、限流、重试分类、结构化输出校验和调用审计。
- `task.go` 只有 `click/type_text/press_enter/scroll/wait` 等简单动作白名单,任务和历史保存为 JSON 文件。
- `chat_sync.go` 直接读取标注文件和截图,再调用多模态模型提取聊天。这与当前 API 文档“标注调试数据不进入 Go 后端”的边界不能直接兼容。
- Go 模块当前只有 TOML 依赖,没有 HTTP、SQLite、WebSocket、迁移、后台任务或测试基础设施。
- 当前代码强制 `DryRun=true`,真实 Windows 自动化链路尚不能视为完成。
因此建议新建正式服务结构,逐步迁移可复用代码;不要直接把所有接口继续写进现有 `package main`
## 3. 编码前必须修正的契约缺口
`api-design.md` 可以覆盖当前页面,但要实现多智能体仍有以下缺口。建议先在 API 文档中确认,再冻结 OpenAPI。
### 3.1 本地标注边界与引擎接口存在冲突
API 同时规定:
- 标注调试状态、截图、区域和窗口信息不得进入 Go
- `/bootstrap``/engine/state` 又包含 `annotationComplete`
- `/engine/startup-checks` 包含 annotation check
- Go WebSocket 事件表包含 `engine.annotation.changed`
推荐修正:
1. `annotationComplete` 由 Tauri 前端通过本地 IPC 合并展示,不由 Go 持久化。
2. `engine.annotation.changed` 改为 Tauri event不进入 Go WebSocket。
3. Rust 在启动生产引擎前完成本地检查,仅向 Go 提交一次性 `nativeReadinessToken` 或布尔能力证明Go 不接收标注内容。
4. Go 的启动检查只负责模型、配置、知识库、任务队列等业务检查;窗口和标注检查由 Rust 返回。
### 3.2 单模型设置不足以支持 LLM/VLM
现有 `/settings` 只有一个 `model`。多模型至少需要:
- `modelProfiles[]``id``kind=llm|vlm|embedding`、provider、endpoint、modelName、超时、并发、能力标签
- 每个 Agent 引用 `modelProfileId`,而不是读取全局唯一模型;
- 密钥按 provider/profile 保存,但响应只返回 `keyConfigured`
首期也可以只有一个 LLM profile 和一个 VLM profile但数据结构不能把二者写死成同一个模型。
### 3.3 Agent 对象缺少运行类型和工具策略
现有 `AgentSummary.type=builtin|custom` 只是来源类型。建议补充:
- `agentKind``conversation | llm_worker | vlm_worker | wechat_action | chat_reader | employee_distill | knowledge_summary | knowledge_entity`
- `capabilities[]`:可被 Supervisor 路由的能力;
- `modelProfileId`
- `toolPolicy`:允许工具、最大步骤、超时、是否必须人工确认;
- `inputSchemaVersion``outputSchemaVersion`
- `runtimeVersion`:用于重放和问题定位。
`builtin|custom` 保留为 `sourceType` 更清晰。
### 3.4 VLM 测试入口不足
当前 `agent_test_attachment` 不接受图片和视频。如果产品需要在智能体测试窗口验证 VLM应补充图片格式视频首期建议只接受明确抽取后的若干用户选择帧避免隐式视频理解。
知识库图片/视频仍必须遵守现有规则:只使用人工描述,不允许 Knowledge Agent 或 VLM 自动生成描述。
### 3.5 缺少 Agent Run 可观测接口
建议增加只读诊断接口:
- `GET /agent-runs/{runId}`:运行状态、开始/结束时间、最终结果和错误;
- `GET /agent-runs/{runId}/steps`Agent 步骤、工具名、耗时、token、结果摘要
- `POST /agent-runs/{runId}/cancel`:取消仍在运行的测试或后台任务。
不得返回完整系统提示词、API Key、未脱敏聊天原文或模型内部推理文本。
## 4. 总体架构
```mermaid
flowchart LR
UI[React UI] -->|HTTP/WS 8766| API[Go API Server]
UI -->|Tauri invoke/event| Native[Tauri/Rust Native Host]
API --> APP[Application Services]
APP --> AR[Multi-Agent Runtime]
APP --> JOB[Durable Job Runner]
APP --> DB[(SQLite + FTS5)]
APP --> FS[Content-addressed File Store]
APP --> EVT[Transactional Outbox + WS Hub]
AR --> MG[Model Gateway]
AR --> TOOL[Tool Registry]
MG --> LLM[LLM Providers]
MG --> VLM[VLM Providers]
Native -->|Sanitized native bridge| BRIDGE[Local Agent Bridge]
BRIDGE --> AR
AR -->|Semantic action plan| BRIDGE
Native --> WX[WeChat Window]
```
### 4.1 进程职责
#### React/Tauri 前端
- 页面交互、loading/error、表单 dirty 状态和本地主题;
- 通过 HTTP/WS 访问 Go 业务服务;
- 通过 Tauri IPC 使用标注、窗口选择和本地生命周期能力;
- 不把 mock/localStorage 当作业务事实源。
#### Tauri/Rust Native Host
- 启停并监督 Go sidecar
- 生成 session token并通过继承管道或受限文件句柄安全传递
- 独占标注文件、截图、窗口句柄、DPI、区域坐标和鼠标键盘执行
- 把生产运行期观察结果转换为不含坐标、截图路径和窗口句柄的语义对象;
- 校验 Go 返回的动作计划,在必要时请求人工确认,再执行动作;
- 保持标注调试链路完全不进入 Go。
#### Go Business/Agent Sidecar
- 提供 `api/v1` HTTP 和 WebSocket
- 管理设置、文件、知识库、Agent、蒸馏、员工、日志和导出
- 运行模型网关和多智能体调度;
- 保存结构化运行记录和业务状态;
- 不直接调用 Windows 鼠标键盘 API不读取标注文件。
### 4.2 Native Agent Bridge
生产自动化不建议复用公开 HTTP。使用 Tauri 启动 Go 时建立的匿名管道或当前用户受限的 Windows named pipe传输长度前缀 JSON 消息。
Rust 到 Go 的最小语义消息:
```json
{
"type": "conversation.observed",
"observationId": "obs_01...",
"conversationFingerprint": "sha256:...",
"messages": [
{
"messageFingerprint": "sha256:...",
"role": "other",
"content": "请问可以退款吗?",
"occurredAt": null
}
],
"observedAt": "2026-07-21T09:35:01Z"
}
```
Go 到 Rust 的语义动作计划:
```json
{
"type": "wechat.action.plan",
"planId": "plan_01...",
"conversationFingerprint": "sha256:...",
"expectedObservationId": "obs_01...",
"actions": [
{ "type": "focus_input" },
{ "type": "replace_text", "text": "可以,请提供订单号。" },
{ "type": "request_send", "confirmationRequired": true }
],
"expiresAt": "2026-07-21T09:35:11Z"
}
```
关键约束:
- Go 只使用语义目标不下发屏幕坐标Rust 根据当前本地标注解析目标。
- 动作计划必须绑定 conversation fingerprint 和 observation ID防止窗口切换后误发。
- 计划短时过期;执行前重新检查窗口、会话和输入框状态。
- `request_send` 与“是否自动发送”分离;最终策略由 Rust 和托管设置共同裁决。
- Bridge 不传输标注截图、标注坐标、窗口句柄或标注文件路径。
## 5. Go 工程结构
推荐目录:
```text
agent/
cmd/wechat-ai-sidecar/main.go
internal/
bootstrap/ # 依赖装配、启动和优雅关闭
api/
httpapi/ # route、handler、middleware、DTO
realtime/ # ticket、WS hub、订阅和续传
app/ # command/query application services
domain/
engine/
files/
knowledge/
agents/
distill/
employees/
settings/
logs/
agentruntime/
supervisor/
registry/
runner/
tools/
policies/
trace/
agents/
conversation/
llmworker/
vlmworker/
wechataction/
chatreader/
employeedistill/
knowledgesummary/
knowledgeentity/
model/
gateway/
openaicompat/
volcengine/
nativebridge/
jobs/
persistence/
sqlite/
migrations/
filestore/
secrets/
parsing/
txt/
pdf/
docx/
pptx/
observability/
migrations/
testdata/
```
规则:
- `domain` 不依赖 HTTP、SQLite 或具体模型 SDK。
- handler 只负责协议解析、鉴权和 DTO 映射,业务事务放在 `app`
- repository 接口定义在使用方模块SQLite 实现在 `persistence/sqlite`
- Agent 只能通过 Tool Registry 使用受控能力,不能直接访问数据库或任意文件路径。
- 模型 provider 只实现模型调用,不承载业务 prompt。
## 6. 建议技术选型
| 能力 | 建议 | 原因 |
|---|---|---|
| HTTP | Go `net/http` + `chi` | 中间件和路由清晰,不引入重框架 |
| WebSocket | `coder/websocket` | API 简洁,支持 context 取消 |
| SQLite | `database/sql` + `modernc.org/sqlite` | Windows 构建避免 CGO实施前必须实测 FTS5 |
| 迁移 | 内嵌 SQL migrations + migration table | 单机服务简单、可审计,避免运行时外部文件依赖 |
| 日志 | `log/slog` JSON handler | 标准库、结构化、方便敏感字段过滤 |
| ID | ULID | 可排序、适合 cursor 和本地日志 |
| 配置 | 业务配置存 SQLite启动参数仅包含端口和路径 | 避免 TOML/DB 两个事实源 |
| Secret | `SecretStore` 接口 + Windows Credential Manager | API Key 不进 SQLite、日志和普通配置文件 |
| 模型协议 | 自建窄接口 + OpenAI-compatible adapter | 避免业务层被特定 SDK 数据结构绑定 |
| 后台任务 | SQLite durable jobs + 固定 worker pool | 单机足够,可恢复,无需外部队列 |
| 文件 | 应用目录内容寻址存储 + SQLite metadata | 去重、原子完成、便于引用计数和清理 |
不建议首期引入通用 Agent 框架。多智能体的状态、权限、重放和审计是本项目核心,使用显式 Go 接口和状态机更可控。
## 7. HTTP 接口实现方式
### 7.1 通用请求链
每个请求依次经过:
1. loopback 来源检查;
2. Bearer session token 鉴权;
3. request ID 生成或透传;
4. body 大小和 Content-Type 限制;
5. JSON 严格解码,拒绝未知字段;
6. handler DTO 校验;
7. application command/query
8. SQLite 事务和 revision 校验;
9. outbox 事件写入;
10. 标准成功或错误包络。
错误必须使用稳定 code内部错误原因只写脱敏日志不直接返回堆栈。
### 7.2 幂等性
`idempotency_keys` 保存:
- key、route、requestBodyHash
- responseStatus、responseBody
- resourceId、createdAt、expiresAt。
处理流程:
- 在事务内锁定/插入 key
- 相同 key、相同 body 返回首次结果;
- 相同 key、不同 body 返回 `409 IDEMPOTENCY_CONFLICT`
- 24 小时后后台清理。
长任务创建必须先落 job 和幂等记录,再返回 `202`,避免响应丢失后重复创建任务。
### 7.3 Revision
所有可变聚合根包含整数 `revision`。更新 SQL 必须使用:
```sql
UPDATE agents
SET enabled = ?, revision = revision + 1, updated_at = ?
WHERE id = ? AND revision = ?;
```
`RowsAffected=0` 后重新查询:不存在返回 404存在则返回 `REVISION_CONFLICT`
### 7.4 Cursor
cursor 使用 base64url 编码的服务端签名结构,例如:
```json
{ "sortValue": "2026-07-21T09:35:01Z", "id": "agent_01...", "sort": "updatedAt:desc" }
```
客户端不得解析;查询使用稳定二元排序 `(updated_at, id)`,避免翻页重复或遗漏。
## 8. SQLite 与文件存储
### 8.1 核心表
建议按聚合建立:
- 基础:`schema_migrations``settings``idempotency_keys``realtime_tickets``events_outbox``logs`
- 文件:`files``file_uploads``file_upload_parts``file_references`
- 知识库:`knowledge_bases``knowledge_drafts``knowledge_draft_files``knowledge_versions``knowledge_version_files``knowledge_chunks``knowledge_fts`
- Agent`agents``agent_drafts``agent_releases``agent_knowledge_bindings``agent_test_sessions``agent_messages``agent_test_records`
- 运行时:`agent_runs``agent_steps``agent_tool_calls``agent_usage`
- 蒸馏:`distill_drafts``distill_draft_files``distill_jobs``distill_stages``distill_evaluations`
- 员工:`employees``employee_versions``employee_agent_bindings``employee_knowledge_bindings``employee_calls`
- 对话:`conversations``conversation_messages``conversation_memories`
### 8.2 SQLite 配置
启动时设置并校验:
- `journal_mode=WAL`
- `foreign_keys=ON`
- 合理的 `busy_timeout`
- 单写连接或应用层串行写入;
- 读连接池数量受控;
- 每次迁移前创建可恢复备份。
不依赖 SQLite 自动清理文件引用。发布、删除和草稿清理都在显式事务内维护引用关系。
### 8.3 文件中心
存储布局建议:
```text
app-data/
files/sha256/ab/cd/<full-sha256>
files/converted/<fileId>.txt
uploads/<uploadId>/<partNumber>.part
exports/<exportId>.<ext>
```
流程:
1. 上传写入临时文件,同时流式计算 SHA-256不把完整文件读入内存
2. 同时校验扩展名、MIME 和 magic bytes
3. fsync 后原子 rename 到内容寻址路径;
4. 事务更新 FileAsset
5. 文档投递 parser job媒体直接进入 `parseStatus=not_required`
6. 分片完成时逐片复核哈希和总长度,再合并并校验整体哈希;
7. Range 下载严格处理 `206/416`、Content-Range 和最大并发;
8. 清理任务删除过期 upload、无引用测试附件和孤立导出文件。
### 8.4 文档解析
首期可行实现:
- TXTBOM 检测、UTF-8 校验、换行归一化;
- PDF使用支持文本层提取的库或隔离命令只读取文本对象
- DOCX按 ZIP/XML 规范读取段落和表格,不执行宏;
- PPTX按 ZIP/XML 读取文本框、表格和备注;
-`.ppt`Go 原生解析生态不足,建议通过受限的 LibreOffice headless 转换到 PPTX/TXT若产品不接受外部依赖应从首期支持列表移除 `.ppt`
所有解析器必须有超时、文件大小限制、压缩炸弹限制和临时目录隔离。解析失败只影响该文件 job不能拖垮 API 进程。
## 9. WebSocket 与后台任务
### 9.1 WebSocket
- `POST /realtime-tickets` 在 SQLite 中创建 30 秒单次票据;
- upgrade 时事务性消费票据,防止重放;
- 每个连接维护允许频道集合,不允许订阅任意资源 ID
- 业务事务同时写聚合数据和 `events_outbox`
- publisher 从 outbox 发到内存 WS hub并标记 dispatched
- 最近 10 分钟事件保留,用 `lastEventId` 续传;
- 续传窗口外返回 `resumeAccepted=false`,客户端重新 GET。
模型 token delta 是高频临时事件,可直接流式发送并定期落消息快照;完成、失败和取消事件必须持久化。
### 9.2 Durable Job Runner
`jobs` 至少保存:
- id、type、state、payloadRef
- attempt、maxAttempts、availableAt
- leaseOwner、leaseUntil
- progress、stage、cancelRequested
- lastErrorCode、createdAt、updatedAt。
worker 通过短租约 claim job。进程崩溃后租约过期可恢复。重试只针对网络暂时失败、模型 429/5xx 和可恢复文件错误;校验错误、权限错误和结构化输出长期不合法不可无限重试。
建议并发池:
- 文件解析2
- LLM按 provider/profile 限制;
- VLM1避免本机内存和上游限流
- 蒸馏1 个 job但 job 内可小批量并发;
- 导出1。
## 10. 多智能体运行时
### 10.1 核心原则
- Supervisor 唯一负责路由和结束条件;子 Agent 不得自由调用任意子 Agent。
- 每次运行都有 `runId`、输入 schema、权限快照、token/time/step budget 和取消 context。
- 所有 Agent 输出必须通过 JSON Schema 或显式 Go struct 校验。
- 工具调用必须经过 Tool Registry 和 Policy Engine模型输出不能直接执行 SQL、HTTP、文件或桌面动作。
- 每一步都持久化状态和可审计摘要,但不保存模型隐藏推理链。
- 同一业务事件通过 dedupe key 保证不会重复执行。
- 自动发送属于高风险副作用,生成回复和执行发送必须是两个独立步骤。
### 10.2 Go 接口示意
```go
type Agent interface {
Descriptor() Descriptor
Run(ctx context.Context, req RunRequest) (RunResult, error)
}
type Descriptor struct {
Kind string
Capabilities []string
InputVersion string
OutputVersion string
}
type RunRequest struct {
RunID string
ParentStepID string
Input json.RawMessage
Permissions PermissionSet
Budget Budget
Trace TraceContext
}
type Tool interface {
Name() string
Validate(input json.RawMessage, permissions PermissionSet) error
Execute(ctx context.Context, input json.RawMessage) (json.RawMessage, error)
}
```
模型调用应为单独接口:
```go
type ModelGateway interface {
Generate(ctx context.Context, req GenerateRequest) (GenerateResponse, error)
Stream(ctx context.Context, req GenerateRequest, sink DeltaSink) (GenerateResponse, error)
}
```
### 10.3 运行状态
`queued -> running -> waiting_confirmation | completed | failed | cancelled`
步骤状态:
`pending -> running -> completed | skipped | failed | cancelled`
Supervisor 在每一步检查:
- run 是否取消;
- deadline
- 剩余 token、模型调用数和工具调用数
- agent/tool 是否在权限快照内;
- 输入是否仍绑定最新 conversation observation
- 是否需要人工确认。
## 11. Agent 设计
### 11.1 Conversation Supervisor Agent
职责:处理一条新聊天观察或测试消息,选择必要的子 Agent生成最终候选回复。
典型 DAG
```text
ChatRecordReader
-> Intent/LLM Worker
-> Knowledge Entity Agent
-> Employee Policy Agent
-> Response LLM Worker
-> Safety/Boundary Validator
-> WeChat Action Orchestration Agent
```
约束:
- 无需 VLM 时不调用 VLM
- 无需知识时不强制检索;
- 子 Agent 失败按类型降级,不能悄悄编造结果;
- 关键知识必须带 `knowledgeId/version/chunkId` 引用;
- 没有足够事实时输出澄清问题或转人工,不强行回答。
### 11.2 LLM Model Agent
定位:受控文本模型 worker不持有业务状态。
能力:
- 意图分类;
- 结构化信息抽取;
- 回复生成;
- 文本摘要;
- 蒸馏阶段的策略归纳和反例生成。
实现:
- 根据 `modelProfileId` 路由 provider
- 请求包含固定 system policy、Agent prompt、最小上下文和 JSON schema
- 支持 streaming 和 non-streaming
- provider 429/5xx 使用抖动退避,超时和取消立即终止;
- 记录 model、latency、token usage、finish reason 和错误类别;
- 对结构化输出只允许有限次 repair仍失败则返回明确错误。
禁止:
- 直接执行桌面动作;
- 任意读取数据库和文件;
- 自己扩展工具权限;
- 将模型生成内容当作已验证事实。
### 11.3 VLM Model Agent
定位:处理明确授权的图片输入和测试附件,输出结构化视觉结果。
适用:
- 用户在对话或 Agent 测试中明确提交的图片;
- 产品未来允许的显式视频帧分析;
- 非标注调试的视觉能力实验。
不适用:
- 知识库图片/视频自动描述;
- 标注截图、窗口截图、区域坐标解析;
- 未经授权的视频全量理解。
知识库 `purpose=knowledge_source``kind=image|video`VLM Tool 必须拒绝调用;检索只使用标题、标签和人工 `description`
输出示例应是结构化事实候选,并带 `confidence``uncertainFields`,由上层业务 Agent 决定是否可用,不能直接形成动作。
### 11.4 WeChat Action Orchestration Agent
职责:把已批准的业务决策转换为短期语义动作计划,不直接控制鼠标键盘。
输入:
- conversation fingerprint
- latest observation ID
- candidate reply
- 托管策略、quiet hours、联系人 allow/block 规则;
- `confirmBeforeSend`
- 当前错误计数。
输出仅允许:
- `focus_input`
- `replace_text`
- `request_send`
- `wait_and_reobserve`
- `abort`
安全规则:
- 默认不使用坐标动作;
- 发送前必须再次比对会话 fingerprint
- 回复为空、内容超长、联系人 block、quiet hours、窗口变化或 observation 过期时中止;
- `confirmBeforeSend=true` 时只填充输入框并等待确认;
- 连续错误达到阈值后暂停自动发送并发出 `engine.state.changed`
- 每个 plan 只能执行一次,重复回执幂等。
### 11.5 Chat Record Reader Agent
职责:管理聊天读取流程、消息归一化、跨页去重和增量游标;不直接读取标注文件。
分层:
1. Rust Native Collector 从当前微信窗口获得本地观察;
2. Rust 输出规范化 `conversation.observed`
3. Go Chat Reader 校验 schema、conversation fingerprint 和顺序;
4. 根据 message fingerprint、相邻消息上下文和时间窗口去重
5. 写入 `conversation_messages`
6. 发布 `conversation.updated` 供 Supervisor 使用。
消息 ID 不能只由 `sender+content` 决定,否则重复发送相同文本会被误去重。建议组合:会话 fingerprint、方向、规范化内容、页面邻接 fingerprint、可见时间和首次观察序号。
如果评审要求 Go 内 VLM 直接读取微信截图,就必须先修改第 14 节的本地隐私边界;按当前契约不可实施。
### 11.6 Employee Distillation Agent
职责:把已上传且解析完成的文本材料转成可版本化的员工能力包。
持久化状态机与 API stage 对齐:
1. `source_validation`:文件状态、数量、最小有效对话数;
2. `data_cleaning`:编码、空记录、重复、角色归一化;
3. `scene_clustering`:按业务场景聚类;
4. `strategy_extraction`:提取目标、触发条件、话术策略;
5. `boundary_induction`:提取禁止行为、优惠/承诺边界和转人工条件;
6. `counterexample_generation`:生成越界和歧义样本;
7. `evaluation`:固定评测集 + 新反例评测;
8. `completed`:生成不可变 EmployeeVersion 草稿。
蒸馏产物不能只有一段 prompt应包含
```json
{
"persona": {},
"scenePolicies": [],
"decisionRules": [],
"responsePatterns": [],
"prohibitedBehaviors": [],
"escalationRules": [],
"positiveExamples": [],
"counterExamples": [],
"sourceRefs": [],
"evaluation": {}
}
```
发布前要求:
- 所有 sourceRef 可追溯;
- overallScore 达到阈值;
- overreachRate 满足阈值;
- 评估使用的 job revision 等于当前 revision
- 发布事务同时生成 Employee、EmployeeVersion 和 bindings。
### 11.7 Knowledge Summary Agent
职责:只对文本知识生成辅助摘要、标题建议、主题和章节概览,降低检索上下文长度。
边界:
- 输入只来自解析后的 TXT 或操作者填写的媒体 description
- 不对知识图片或视频调用 VLM
- 摘要是派生数据,不能替换原文;
- 每条摘要保存 source chunk refs、模型版本和生成时间
- 知识版本变化后旧摘要失效并异步重建;
- 摘要失败不能阻止原始文档发布,但 UI 应显示派生状态。
### 11.8 Knowledge Entity Agent知识体 Agent
本文将“知识体 Agent”定义为版本化知识组织与检索 Agent不是第二个自由对话 Agent。
职责:
- 将 KnowledgeVersion 组装成稳定的 Knowledge Entity
- 管理文本 chunk、人工媒体描述、标签、摘要和来源引用
- 根据 Agent/Employee 的知识授权过滤候选;
- 使用 FTS5 BM25 召回并执行确定性重排;
- 返回带证据的 KnowledgeContext
- 检查知识启停状态和绑定版本,禁止命中已停用知识;
- 记录 retrieval trace用于详情页 hit metrics。
建议返回:
```json
{
"query": "退款期限",
"items": [
{
"knowledgeId": "kb_refund",
"version": "v1.8",
"chunkId": "chunk_01...",
"sourceFileId": "file_01...",
"score": 0.87,
"text": "……",
"sourceKind": "document_text"
}
]
}
```
`sourceKind` 可为 `document_text | manual_media_description`,不能出现 `generated_media_description`
### 11.9 Employee Runtime Agent
员工不是简单的 Agent ID 集合。运行时应加载不可变 EmployeeVersion
- 根据场景选择已授权能力 Agent
- 注入画像、边界和 escalation rules
- 限制知识库为 employee bindings 与 agent bindings 的交集;
- 汇总子 Agent 结果,生成候选回复;
- 记录采用、人工修改、拒绝和异常,形成 calls/metrics
- 不在线自我修改 prompt重新学习必须通过 redistill 和新版本发布。
## 12. 关键业务流程
### 12.1 Agent 测试流式回复
1. HTTP 创建 test session固定 agent release 或 draft revision 快照;
2. 前端上传附件并等待解析 ready
3. WS 发送 message command服务端以 `clientMessageId` 幂等受理;
4. 事务写 user message、assistant placeholder 和 run
5. 发送 accepted
6. Supervisor 执行知识检索、模型调用和校验;
7. delta 按 sequence 推送;
8. 完整消息、usage 和 test result 原子落库;
9. 发送 completed/failed
10. draft 修改后旧测试立即失效。
取消只取消当前 generation context不删除已有 user message。
### 12.2 知识发布
1. 创建/更新 draft
2. 文件上传完成;
3. 文档解析为 TXT媒体等待人工 description
4. preview 汇总阻塞错误;
5. publish 事务固定 file IDs、内容哈希和 baseVersion
6. 生成 KnowledgeVersion
7. 文本切块并更新 FTS5
8. 写 knowledge.changed outbox
9. 异步运行 Knowledge Summary Agent
10. 已绑定 Agent 若使用“跟随当前版本”,下次调用读取新版本;若绑定固定版本则不变。
### 12.3 微信自动回复
1. Rust 确认当前窗口和本地标注有效;
2. Native Collector 产生新的语义 observation
3. Chat Reader 去重并持久化;
4. Conversation Supervisor 读取最近消息、长期摘要和联系人策略;
5. Knowledge Entity Agent 检索授权知识;
6. Employee Runtime Agent 应用场景策略;
7. LLM 生成候选回复;
8. Policy Validator 检查敏感内容、越权、quiet hours 和发送权限;
9. WeChat Action Agent 生成短期计划;
10. Rust 重新检查会话,确认或自动执行;
11. Rust 返回逐动作结果;
12. Go 写 agent run、employee call 和结构化日志。
任一步不确定都应中止发送,而不是“尽力点击”。
### 12.4 员工蒸馏
1. 创建 draft、绑定解析完成文件
2. start 在事务内创建 job 和 stage rows
3. worker 分批清洗和聚类,并在 checkpoint 后更新 progress
4. 每阶段写结构化中间产物,不把全部上下文塞入单次 prompt
5. 评估失败可重跑 evaluation但不重复前面已完成阶段
6. cancel 设置 `cancelRequested`worker 在批次边界安全停止;
7. publish 固定 job revision 和评估结果,创建 EmployeeVersion。
## 13. 模型网关
### 13.1 Provider 抽象
统一能力:
- `Generate`
- `Stream`
- `SupportsVision`
- `SupportsJSONSchema`
- `CountOrEstimateTokens`
- `HealthCheck`
每个 profile 配置:
- provider、endpoint、modelName
- context window 和 max output
- request timeout
- max concurrency
- 每分钟请求/token 限制;
- 支持的输入类型和结构化输出方式。
### 13.2 重试
可重试连接重置、429、部分 5xx不可重试401、无效模型、输入超长、内容策略拒绝、schema 长期不合法。
生成回复不能无条件重试,因为第一次请求可能已在上游完成。使用 provider request ID 和本地 run step 幂等语义,最多有限次重试,并在日志中标明 attempt。
### 13.3 Prompt 管理
- 固定安全 prompt 编译进版本化资源;
- 用户 custom prompt 是独立字段;
- Agent release 保存 prompt hash 和 runtime version
- prompt 组合顺序固定:系统安全规则 -> Agent 角色 -> Employee policy -> KnowledgeContext -> ConversationContext -> 当前输入;
- 对外日志只保存 prompt hash、字符数和模板版本不保存完整系统 prompt。
## 14. 安全与权限
### 14.1 权限模型
工具权限使用明确 code
- `knowledge.query`
- `conversation.read_current`
- `conversation.read_history`
- `attachment.read`
- `model.llm.invoke`
- `model.vlm.invoke`
- `message.compose`
- `message.request_send`
- `employee.policy.read`
Agent release 固定权限快照。Supervisor 只能取交集,不能给子 Agent 增权。
### 14.2 文件安全
- 用户文件名只作展示,不参与存储路径;
- 拒绝路径穿越、NTFS alternate data stream 和非法设备名;
- Office ZIP 限制展开文件数、总大小和压缩比;
- 预览响应设置安全 Content-Type、Content-Disposition 和 `X-Content-Type-Options: nosniff`
- 不执行 Office 宏、嵌入对象或上传文件内脚本;
- 视频只支持 Range 读取,不自动启动转码或识别。
### 14.3 日志脱敏
记录requestId、resourceId、agentKind、stage、latency、token、errorCode。
禁止API Key、完整 prompt、完整聊天原文、附件正文、截图路径、绝对本机路径、窗口 title/handle。
模型上游错误体先通过 allowlist 提取 code/message不能原样写日志。
## 15. 可观测性与故障恢复
- 每个 HTTP 请求、WS command、job 和 agent run 共享 trace/request ID
- `/bootstrap` 返回 serverVersion 和 schema version
- 提供只监听 loopback 的 `/health/live``/health/ready`
- ready 检查 SQLite、迁移状态、文件目录和 job runner不强制检查外部模型
- 每次模型调用记录 usage 和耗时;
- outbox backlog、job queue depth、WS connection count 和连续错误数写结构化指标;
- Go sidecar 崩溃后running job 由 lease 恢复running agent generation 标记 interrupted由客户端重试不自动重复发送消息
- Rust 发现 Go 不可用时暂停托管和所有发送动作。
## 16. 测试策略
### 16.1 单元测试
重点覆盖:
- revision 冲突;
- idempotency key 同体/异体;
- cursor 稳定分页;
- 文件类型三重校验;
- Range 请求;
- chat message 去重;
- Agent 权限交集和 budget
- 微信动作计划过期、会话变更和重复执行;
- 知识媒体禁止 VLM、只索引人工描述
- distill 状态机的取消和恢复。
### 16.2 Repository 集成测试
每个测试使用独立临时 SQLite
- migrations 从空库可完成;
- foreign key 和 cascade/restrict 符合预期;
- 聚合更新与 outbox 在同一事务;
- FTS5 查询、停用过滤和版本绑定;
- job claim/lease/recovery
- 并发 revision 更新只有一个成功。
### 16.3 API 契约测试
从 OpenAPI 生成或维护 request/response fixtures覆盖
- 所有 `api-design.md` 页面入口;
- 错误 code
- 未知字段和 body size
- ticket 单次消费;
- WS 事件顺序和断线续传;
- 文件上传、分片、完成、取消和清理。
### 16.4 Agent 评测
Agent 不能只测“调用成功”。为每个 Agent 建固定 golden scenarios
- 意图和结构化抽取准确性;
- 知识引用是否真实存在;
- 无知识时是否拒绝编造;
- 员工边界和转人工规则;
- 自动发送是否在危险条件下阻断;
- VLM 不确定输出是否正确标注;
- 蒸馏重跑的一致性和 overreach rate。
模型评测记录 provider/model/prompt/runtime version避免模型升级后结果不可解释。
### 16.5 Windows 端到端测试
在真实 Tauri + Windows + 微信测试账号环境验证:
- sidecar 启停和 token 传递;
- 标注数据未进入 Go 日志、DB 和 Bridge
- observation/action fingerprint 防误会话;
- confirmBeforeSend
- quiet hours、block list 和异常暂停;
- 进程崩溃后不重复发送;
- DPI、窗口移动和窗口切换时动作中止。
## 17. 分阶段开发路线
### 阶段 0契约冻结
交付:
- 修正 annotationComplete/WS 事件边界;
- 增加 model profiles、agentKind/capabilities/toolPolicy
- 明确 VLM 可接受输入;
- 补 Agent Run 诊断接口;
- 生成并评审 OpenAPI 3.1
- 固定 Native Bridge 消息 schema。
验收前端、Rust 和 Go 对每个字段的所有权无冲突。
### 阶段 1服务基础层
交付:
- 新目录结构和依赖装配;
- loopback HTTP、session token、request ID、错误包络
- SQLite migrations、revision、idempotency
- settings、SecretStore、bootstrap
- WS ticket、hub、outbox、续传
- health、结构化日志和优雅关闭。
验收:基础契约测试通过,重启后状态和事件可恢复。
### 阶段 2文件中心与知识库
交付:
- 小文件、分片上传、Range 下载;
- TXT/PDF/DOCX/PPTX 解析;
- 媒体人工 description
- knowledge draft/version/publish/status/delete
- FTS5、引用关系和清理任务
- Knowledge Summary/Entity Agent。
验收:文档、图片、视频知识按契约工作;任何路径都不会自动生成媒体描述。
### 阶段 3模型网关与 Agent Runtime
交付:
- LLM/VLM model profiles
- provider adapter、streaming、限流、取消和 usage
- Agent Registry、Supervisor、Tool Registry、Policy Engine
- run/step/tool trace
- budget、schema validation 和权限交集。
验收:用 fake model 可完全重放流程;真实 provider 的错误分类和取消正确。
### 阶段 4Agent 管理与测试会话
交付:
- agent draft、release、knowledge binding、status/delete
- test session/messages
- WS accepted/delta/completed/failed
- 发布前 revision-matched test gate
- Conversation、LLM、VLM Agent。
验收:关闭并重新打开测试窗口可恢复消息;重复 command 不重复生成。
### 阶段 5蒸馏与员工
交付:
- distill draft/job/stages/checkpoint/cancel
- Employee Distillation Agent
- evaluation、report export、publish
- EmployeeVersion、bindings、calls、redistill、clone
- Employee Runtime Agent。
验收:长任务重启可恢复,取消有效,发布产物可追溯到来源和评估版本。
### 阶段 6微信生产运行链路
交付:
- Native Bridge
- Chat Record Reader Agent
- WeChat Action Orchestration Agent
- engine state、startup/stop/pause
- semantic observation、action receipt 和异常暂停;
- Tauri/Rust 人工确认和最终动作执行。
验收:窗口切换、会话变化、过期计划、重复回执和 sidecar 崩溃均不会误发消息。
### 阶段 7替换 demo 与发布加固
交付:
- 前端移除 mock/localStorage 业务状态;
- 删除已迁移的旧 `package main` demo 路径,不保留双实现;
- Windows sidecar 打包、迁移备份和回滚;
- 性能、资源和安全测试;
- 完整端到端发布检查。
验收:`api-design.md` 页面映射中的所有按钮和状态都来自真实接口或明确的 Tauri IPC。
## 18. 主要风险与决策
| 风险 | 影响 | 建议决策 |
|---|---|---|
| API 的 annotation 状态所有权冲突 | Go/Tauri 双事实源 | 阶段 0 先修契约,不带冲突开工 |
| 旧 `.ppt` 解析 | Go 生态弱、攻击面大 | 依赖受限 LibreOffice或首期移除 `.ppt` |
| 微信截图不能进入 Go但旧 demo 依赖截图 VLM | chat_sync 无法直接迁移 | Native Collector 输出语义消息;若要 Go 看截图,必须显式改隐私契约 |
| 多 Agent 自由协作 | 循环、成本失控、难审计 | Supervisor + DAG + budget不做自由自治群聊 |
| 自动发送误会话 | 高风险用户事故 | fingerprint + observation binding + expiry + Rust 二次校验 |
| SQLite 并发写 | busy/锁竞争 | 单写队列、短事务、WAL、worker 并发受控 |
| 大视频上传 | 磁盘占满、恢复困难 | quota、分片 TTL、预留空间检查、无自动处理 |
| 模型输出不稳定 | 流程失败或越权 | schema、有限 repair、policy validator、确定性工具层 |
| 蒸馏任务成本和上下文过大 | 超时、结果不可重复 | 分阶段 checkpoint、小批次、产物版本化 |
| API Key 泄露 | 严重安全问题 | Windows Credential Manager、日志 allowlist、禁止 argv/env/DB 明文 |
## 19. 评审时建议确认的决策
1. 是否接受 Tauri/Rust 是唯一桌面动作执行者Go 只输出语义动作计划?
2. 是否接受 Go 不读取任何标注/窗口截图Chat Reader 只接收 Native Collector 的结构化消息?
3. VLM 首期是否只用于用户授权的图片附件,而不用于知识库媒体和标注截图?
4. `.ppt` 是依赖 LibreOffice还是从首期格式中移除
5. 是否接受模块化单体和 SQLite durable jobs而不是首期引入微服务和外部队列
6. 自动发送首期是否强制 `confirmBeforeSend=true`,稳定后再开放联系人级别白名单?
7. “知识体 Agent”是否按本文定义为版本化知识组织/检索 Agent而不是可以自行修改知识的自治 Agent
8. 模型 profile 是否需要首期支持多个 provider还是先实现一个 provider、但保留多 profile 数据模型?
9. 员工蒸馏最低发布阈值、overreach 上限和人工复核规则由谁配置?
10. Agent run trace 在 UI 中展示到什么粒度,哪些字段只供本地诊断?
## 20. 最小可行落地范围
如果希望先验证架构而不是一次完成全部功能,最小闭环应包含:
1. HTTP/SQLite/WS 基础层;
2. settings + 模型密钥;
3. 文件上传和 TXT/PDF/DOCX/PPTX 文本解析;
4. 知识库发布 + FTS5 + Knowledge Entity Agent
5. 单 LLM profile + Agent Runtime
6. Agent draft/test/publish
7. Native Bridge 的一条 observation -> candidate reply -> confirm -> send 闭环;
8. 全链路 run/step 日志和误发送防护。
VLM、员工蒸馏、复杂视频、自动发送可在该闭环稳定后加入。这个切分没有改变最终架构也不会产生需要保留的临时双实现。