39 KiB
微信 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。
推荐修正:
annotationComplete由 Tauri 前端通过本地 IPC 合并展示,不由 Go 持久化。engine.annotation.changed改为 Tauri event,不进入 Go WebSocket。- Rust 在启动生产引擎前完成本地检查,仅向 Go 提交一次性
nativeReadinessToken或布尔能力证明;Go 不接收标注内容。 - 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. 总体架构
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/v1HTTP 和 WebSocket; - 管理设置、文件、知识库、Agent、蒸馏、员工、日志和导出;
- 运行模型网关和多智能体调度;
- 保存结构化运行记录和业务状态;
- 不直接调用 Windows 鼠标键盘 API,不读取标注文件。
4.2 Native Agent Bridge
生产自动化不建议复用公开 HTTP。使用 Tauri 启动 Go 时建立的匿名管道或当前用户受限的 Windows named pipe,传输长度前缀 JSON 消息。
Rust 到 Go 的最小语义消息:
{
"type": "conversation.observed",
"observationId": "obs_01...",
"conversationFingerprint": "sha256:...",
"messages": [
{
"messageFingerprint": "sha256:...",
"role": "other",
"content": "请问可以退款吗?",
"occurredAt": null
}
],
"observedAt": "2026-07-21T09:35:01Z"
}
Go 到 Rust 的语义动作计划:
{
"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 工程结构
推荐目录:
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 通用请求链
每个请求依次经过:
- loopback 来源检查;
- Bearer session token 鉴权;
- request ID 生成或透传;
- body 大小和 Content-Type 限制;
- JSON 严格解码,拒绝未知字段;
- handler DTO 校验;
- application command/query;
- SQLite 事务和 revision 校验;
- outbox 事件写入;
- 标准成功或错误包络。
错误必须使用稳定 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 必须使用:
UPDATE agents
SET enabled = ?, revision = revision + 1, updated_at = ?
WHERE id = ? AND revision = ?;
RowsAffected=0 后重新查询:不存在返回 404,存在则返回 REVISION_CONFLICT。
7.4 Cursor
cursor 使用 base64url 编码的服务端签名结构,例如:
{ "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 文件中心
存储布局建议:
app-data/
files/sha256/ab/cd/<full-sha256>
files/converted/<fileId>.txt
uploads/<uploadId>/<partNumber>.part
exports/<exportId>.<ext>
流程:
- 上传写入临时文件,同时流式计算 SHA-256,不把完整文件读入内存;
- 同时校验扩展名、MIME 和 magic bytes;
- fsync 后原子 rename 到内容寻址路径;
- 事务更新 FileAsset;
- 文档投递 parser job;媒体直接进入
parseStatus=not_required; - 分片完成时逐片复核哈希和总长度,再合并并校验整体哈希;
- Range 下载严格处理
206/416、Content-Range 和最大并发; - 清理任务删除过期 upload、无引用测试附件和孤立导出文件。
8.4 文档解析
首期可行实现:
- TXT:BOM 检测、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 限制;
- VLM:1,避免本机内存和上游限流;
- 蒸馏: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 接口示意
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)
}
模型调用应为单独接口:
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:
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
职责:管理聊天读取流程、消息归一化、跨页去重和增量游标;不直接读取标注文件。
分层:
- Rust Native Collector 从当前微信窗口获得本地观察;
- Rust 输出规范化
conversation.observed; - Go Chat Reader 校验 schema、conversation fingerprint 和顺序;
- 根据 message fingerprint、相邻消息上下文和时间窗口去重;
- 写入
conversation_messages; - 发布
conversation.updated供 Supervisor 使用。
消息 ID 不能只由 sender+content 决定,否则重复发送相同文本会被误去重。建议组合:会话 fingerprint、方向、规范化内容、页面邻接 fingerprint、可见时间和首次观察序号。
如果评审要求 Go 内 VLM 直接读取微信截图,就必须先修改第 14 节的本地隐私边界;按当前契约不可实施。
11.6 Employee Distillation Agent
职责:把已上传且解析完成的文本材料转成可版本化的员工能力包。
持久化状态机与 API stage 对齐:
source_validation:文件状态、数量、最小有效对话数;data_cleaning:编码、空记录、重复、角色归一化;scene_clustering:按业务场景聚类;strategy_extraction:提取目标、触发条件、话术策略;boundary_induction:提取禁止行为、优惠/承诺边界和转人工条件;counterexample_generation:生成越界和歧义样本;evaluation:固定评测集 + 新反例评测;completed:生成不可变 EmployeeVersion 草稿。
蒸馏产物不能只有一段 prompt,应包含:
{
"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。
建议返回:
{
"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 测试流式回复
- HTTP 创建 test session,固定 agent release 或 draft revision 快照;
- 前端上传附件并等待解析 ready;
- WS 发送 message command,服务端以
clientMessageId幂等受理; - 事务写 user message、assistant placeholder 和 run;
- 发送 accepted;
- Supervisor 执行知识检索、模型调用和校验;
- delta 按 sequence 推送;
- 完整消息、usage 和 test result 原子落库;
- 发送 completed/failed;
- draft 修改后旧测试立即失效。
取消只取消当前 generation context,不删除已有 user message。
12.2 知识发布
- 创建/更新 draft;
- 文件上传完成;
- 文档解析为 TXT,媒体等待人工 description;
- preview 汇总阻塞错误;
- publish 事务固定 file IDs、内容哈希和 baseVersion;
- 生成 KnowledgeVersion;
- 文本切块并更新 FTS5;
- 写 knowledge.changed outbox;
- 异步运行 Knowledge Summary Agent;
- 已绑定 Agent 若使用“跟随当前版本”,下次调用读取新版本;若绑定固定版本则不变。
12.3 微信自动回复
- Rust 确认当前窗口和本地标注有效;
- Native Collector 产生新的语义 observation;
- Chat Reader 去重并持久化;
- Conversation Supervisor 读取最近消息、长期摘要和联系人策略;
- Knowledge Entity Agent 检索授权知识;
- Employee Runtime Agent 应用场景策略;
- LLM 生成候选回复;
- Policy Validator 检查敏感内容、越权、quiet hours 和发送权限;
- WeChat Action Agent 生成短期计划;
- Rust 重新检查会话,确认或自动执行;
- Rust 返回逐动作结果;
- Go 写 agent run、employee call 和结构化日志。
任一步不确定都应中止发送,而不是“尽力点击”。
12.4 员工蒸馏
- 创建 draft、绑定解析完成文件;
- start 在事务内创建 job 和 stage rows;
- worker 分批清洗和聚类,并在 checkpoint 后更新 progress;
- 每阶段写结构化中间产物,不把全部上下文塞入单次 prompt;
- 评估失败可重跑 evaluation,但不重复前面已完成阶段;
- cancel 设置
cancelRequested,worker 在批次边界安全停止; - 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 的错误分类和取消正确。
阶段 4:Agent 管理与测试会话
交付:
- 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 maindemo 路径,不保留双实现; - 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. 评审时建议确认的决策
- 是否接受 Tauri/Rust 是唯一桌面动作执行者,Go 只输出语义动作计划?
- 是否接受 Go 不读取任何标注/窗口截图,Chat Reader 只接收 Native Collector 的结构化消息?
- VLM 首期是否只用于用户授权的图片附件,而不用于知识库媒体和标注截图?
.ppt是依赖 LibreOffice,还是从首期格式中移除?- 是否接受模块化单体和 SQLite durable jobs,而不是首期引入微服务和外部队列?
- 自动发送首期是否强制
confirmBeforeSend=true,稳定后再开放联系人级别白名单? - “知识体 Agent”是否按本文定义为版本化知识组织/检索 Agent,而不是可以自行修改知识的自治 Agent?
- 模型 profile 是否需要首期支持多个 provider,还是先实现一个 provider、但保留多 profile 数据模型?
- 员工蒸馏最低发布阈值、overreach 上限和人工复核规则由谁配置?
- Agent run trace 在 UI 中展示到什么粒度,哪些字段只供本地诊断?
20. 最小可行落地范围
如果希望先验证架构而不是一次完成全部功能,最小闭环应包含:
- HTTP/SQLite/WS 基础层;
- settings + 模型密钥;
- 文件上传和 TXT/PDF/DOCX/PPTX 文本解析;
- 知识库发布 + FTS5 + Knowledge Entity Agent;
- 单 LLM profile + Agent Runtime;
- Agent draft/test/publish;
- Native Bridge 的一条 observation -> candidate reply -> confirm -> send 闭环;
- 全链路 run/step 日志和误发送防护。
VLM、员工蒸馏、复杂视频、自动发送可在该闭环稳定后加入。这个切分没有改变最终架构,也不会产生需要保留的临时双实现。