Files
yawan-workbench/docs/系统整体架构与功能检查文档.md

34 KiB
Raw Permalink Blame History

私域 Agent 内容生产工作台:系统整体架构与功能检查文档

文档用途:给产品、运营、测试和维护人员逐项核对当前系统。内容依据 /server/app、/web/src 和启动脚本整理,描述的是代码已经实现或明确配置的行为;“待确认”项需要在实际环境中验收。本文不包含管理员密码、API 密钥等敏感信息。

代码位置:server/app/main.py(FastAPI 路由)、server/app/models.py(SQLModel 数据模型)、server/app/agents(Agent Runtime)、server/app/rag(知识库检索)、web/src(React 前端)。

1. 系统边界和运行拓扑

系统是一个单组织、本地持久化、可通过公网隧道访问的内容生产工作台。浏览器只访问 React 单页应用;前端通过 /api 调用 FastAPI;FastAPI 使用 SQLite 保存业务状态,知识库源文件和产物保存在数据目录,向量索引由 RAG 子系统维护。微信 iLink 连接由独立 Node sidecar 持有账号凭据,主 API 只保存哈希和引用。

flowchart LR
  U[浏览器用户] -->|HTTPS / HashRouter| W[React 工作台]
  W -->|/api + 会话令牌| A[FastAPI main.py]
  A --> DB[(SQLite workspace.db)]
  A --> FS[(data/ kb artifacts ocr models)]
  A --> R[RAG pipeline]
  R --> V[(向量/全文索引)]
  A --> RT[Agent Runtime]
  RT --> LLM[Provider / 模型]
  A --> Q[持久任务队列]
  A --> I[进度 SSE / 轮询]
  I --> W
  S[wechat_ilink_sidecar.mjs] -->|本机 127.0.0.1:8765| A
  S --> WX[官方 iLink 微信协议]
  CF[cloudflared / ngrok] --> A

1.1 进程与端口

进程 作用 默认地址/端口 主要数据/日志
FastAPI + Uvicorn 认证、业务 API、任务调度和后台线程 开发 8011;生产 8010 /tmp/yawan-uvicorn.log;生产 server/data
React/Vite 开发预览;生产构建后的静态文件由现有部署方式提供 开发通常 5173 web/dist
微信 iLink sidecar 多账号扫码、收发微信消息、状态回调 127.0.0.1:8765 /tmp/yawan-wechat-sidecar.log;按账号隔离的 storage
cloudflared/ngrok 把生产 API/前端暴露到公网 隧道地址 /tmp/yawan-cloudflared.log、/tmp/yawan-ngrok.log

1.2 环境与存储

  • YAWAN_ENV=dev 使用 server/data-dev;默认或 prod 使用 server/data。
  • YAWAN_DATA_DIR 可指定绝对路径,把 workspace.db、kb/、artifacts/、ocr/、models/、chroma/ 等整体迁移到外接硬盘。
  • YAWAN_CORS_ORIGINS 控制允许的前端来源;生产默认包含 https://agent.pducv.cn。
  • DB_PATH、KB_DIR、ARTIFACTS_DIR、OCR_DIR、MODELS_DIR 在 server/app/config.py 根据环境动态创建。
  • 启动时 init_db() 建表、执行兼容迁移、恢复未完成的知识片段预留、对账物理文件与索引,并将空质检报告标记为需复检。

2. 用户端功能地图

侧栏由 web/src/shell.tsx 的 navFor() 根据权限生成;隐藏侧栏只是第一层保护,AppRouter.tsx 的 FeatureGate 和后端中间件还会再次校验。训练营导图已经作为内容任务入口的兼容路由保留;技能库和记忆库作为 Agent 与技能页签;标签作为知识库页签。

功能栏 页面/路由 主要能力 主要权限
总览 /admin/overview 状态、自检、快捷入口、通知 read
内容任务 /admin/tasks、/admin/tasks/:id 建任务、导图拆解、逐段生成、质检、组合和交付 feature:tasks、tasks:*
运行记录 /admin/runs 运行状态、事件、工具审批、失败恢复 feature:runs、runs:read
操作日志 /admin/audit-logs 用户动作审计 feature:audit、audit:read
Agent 与技能 /admin/agents,`?tab=skills memories` Agent、技能、记忆、模型工具、数字人身份配置
数字人 /admin/digital-humans 文档蒸馏、测试、反馈、版本、授权、微信 Bot feature:digital-humans、digital_humans:read
画布编排 /admin/flows 节点、边、波次、总监模式、授权 feature:flows、flows:read
知识库 /admin/knowledge 建库、上传、去重、分类、预览、检索、消费记录 feature:knowledge、kb:*
模型管理 /admin/settings/providers Provider、模型目录、默认模型、连接测试 feature:models、providers:*
用量分析 /admin/settings/usage 用量事件、余额、点数发放、配额 feature:usage、usage:read、billing:manage
系统日志 /admin/system-logs HTTP/应用/任务错误和 Trace feature:system-logs、system_logs:read
访问控制 /admin/settings/access 成员、角色、资源授权、全局发布、版本审核 feature:access、roles/users/audit:manage
功能开关 /admin/settings/flags 读取和修改应用功能开关 feature:flags、flags:read
运营看板 /admin/ops 指标、告警、备份、死信队列 feature:ops、ops:*
操作手册 /admin/manual 面向普通用户的使用说明 登录后可见

3. 认证、组织和权限模型

3.1 登录链路

  1. GET /api/auth/status 检查是否需要首次初始化。
  2. 首次使用 POST /api/auth/bootstrap 创建管理员;之后使用 POST /api/auth/login。
  3. 服务端生成不透明会话令牌,数据库只保存 SHA-256 哈希(AuthSession),默认有效期 12 小时。
  4. 浏览器把令牌放入 API 请求的 Authorization 头;退出调用 POST /api/auth/logout 撤销会话。
  5. GET /api/auth/me 返回当前用户、角色、组织和权限,前端据此渲染页面。

3.2 内置角色

  • 管理员 admin:* 全部权限,仍受组织边界约束。
  • 编辑 editor:内容任务、Agent/画布、知识库、数字人查看、运行和日志等日常生产权限。
  • 审查 reviewer:查看和审查任务、知识库、记忆,不含配置和生产写入权限。
  • 只读 viewer:只能查看被允许的知识库内容。

角色存储在 AppUser.role,可维护的角色集合存储在 RoleDefinition.permissions。权限目录按“内容生产、资产与知识、数据与洞察、系统管理”等抽屉分组,仅改变展示方式,不改变已保存 key。

3.3 访问判定顺序

  1. HTTP 中间件确认 /api 请求已认证;微信回调为特例,必须在接口内用账号密钥校验。
  2. required_permission() 校验方法和路径所需操作权限。
  3. feature_permissions() 校验功能栏权限。
  4. 资源访问函数(require_kb、require_skill、require_canvas、require_memory 等)校验组织、所有者、可见性和成员授权。
  5. 组织 ID:0 表示全局资源;正整数表示租户。数据库迁移会添加索引和触发器,阻止非法组织值落库。

3.4 可见性和授权

资源具有 private/shared/global 三种可见性。所有者可以管理自己的资源;共享资源通过 *Grant 表按 read/use/manage/export 授权;全局资源对普通用户只允许查看和使用,不能导出或修改全局本体。普通用户对全局资源的修改/删除写入 ResourceRevision,管理员审核后才合并。ResourceFork 记录个人副本与全局源的版本基线。

4. 数据模型和绑定关系

4.1 核心实体

实体 表 关键字段/职责
组织 Organization 租户名称、slug、启用状态
用户/角色/会话 AppUser、RoleDefinition、AuthSession 本地账号、PBKDF2 密码摘要、RBAC、可撤销登录
Agent Agent 角色类型、标签、知识库 ID/分类、融合 Agent、模型、工具、规则、数字人、发布快照
技能 AgentSkill、AgentSkillBinding、AgentSkillGrant 技能指令、版本、挂载 Agent、成员授权
数字人 DigitalHuman、DigitalHumanGrant 十一维人格档案、蒸馏元数据、版本、来源文件和授权
微信账号 WeChatBotAccount 所有者、组织、Agent、状态、二维码、凭据哈希/引用
画布 Canvas、CanvasGrant 节点 Agent、边、总监 Agent/模式、授权
知识库 KnowledgeBase 源目录、索引状态、文件/片段计数、分段策略、所有权
分类/文件 KnowledgeCategory、KnowledgeFile 无限层级分类、AI 推荐分类、文件哈希和 revision
消费记录 KnowledgeUsage Agent+知识库+片段唯一锁、引用、状态、禁用标记
任务/内容段 Campaign、Segment 导图原文、画布快照、段级 Agent、状态、锚点、引用、历史版本
质检/产物 QCReport、Artifact 结构/内容/风格/跨稿质检,组合成稿和下载预览
运行 CampaignRun、RunEvent、AgentSession、TaskQueueItem 可恢复执行、进度事件、工具调用会话、租约/重试/死信
AI 用量 LLMCall、UsageEvent、PointAccount、PointTransaction、UsageQuota 调用追踪、不可变计量、余额流水和配额
日志/通知/记忆 AuditLog、SystemLog、Notification、PendingMemory、Memory 用户动作、系统故障、待读提醒、Agent 长期记忆
版本提案 ResourceRevision、ResourceFork 全局资源个人修改、删除提案及冲突基线

4.2 绑定关系(当前代码语义)

erDiagram
  APP_USER ||--o{ AGENT : owns
  APP_USER ||--o{ KNOWLEDGE_BASE : owns
  APP_USER ||--o{ DIGITAL_HUMAN : owns
  AGENT }o--o{ AGENT_SKILL : mounts
  AGENT }o--o{ KNOWLEDGE_BASE : reads
  AGENT }o--o{ AGENT : fusion
  AGENT }o--|| DIGITAL_HUMAN : identity
  CANVAS }o--o{ AGENT : nodes
  CAMPAIGN }o--|| CANVAS : snapshot
  CAMPAIGN ||--o{ SEGMENT : contains
  SEGMENT }o--|| AGENT : assigned
  SEGMENT }o--o{ KNOWLEDGE_BASE : consumes
  AGENT ||--o{ MEMORY : accumulates
  CAMPAIGN_RUN ||--o{ RUN_EVENT : emits
  CAMPAIGN_RUN ||--o{ AGENT_SESSION : resumes
  LLM_CALL ||--o| USAGE_EVENT : measured
  • Agent→知识库:Agent.kb_ids 和 kb_category_ids 保存挂接及分类范围;任务创建时运行快照冻结,生成时不读取后来新增的未授权库。
  • Agent→技能:AgentSkillBinding 多对多;任务快照记录技能指令。
  • Agent→数字人:Agent.digital_human_id 绑定身份;运行时数字人人格优先于 Agent 的 persona_json。
  • Agent→记忆:Memory.agent_id 归属 Agent;记忆候选按用户、组织、画布范围过滤并冻结到运行快照。
  • 画布→Agent/知识/记忆:画布节点保存 Agent;画布授权只连带允许依赖资源的读/用,不放大编辑、删除、导出权限。
  • 内容任务→画布:Campaign.canvas_snapshot 是创建时快照,之后修改画布不会改变历史任务。
  • 知识库消费隔离:KnowledgeUsage 唯一约束为 (agent_id,kb_id,chunk_id),不同 Agent 的消费互不锁定;banned=true 的片段永久排除检索。
  • 微信账号→Agent:一个 WeChatBotAccount.agent_id 绑定一个 Agent;sidecar 收到消息时把账号 ID、Agent ID、会话 ID 一并回传,后端再次校验所有权和授权。

5. Agent 与技能工作区

5.1 Agent 配置

可创建、编辑、停用、发布和删除非内置 Agent。职责类型代码为 production、training_map、qc、service、coordinator、composer。生产 Agent 可配置内容标签和融合 Agent;知识库可以限定到分类;模型可跟随全局默认或指定 Provider/目录模型;allowed_tools 控制 Runtime 工具。

发布接口 POST /api/agents/{id}/publish 调用快照冻结逻辑,将规则、模型、技能、知识边界和记忆候选固化到 runtime_snapshot。任务创建又会把该快照复制到 Segment.runtime_snapshot,保证生成中途修改配置不会改变本次任务。

5.2 技能和记忆

技能支持 Markdown 导入(POST /api/skills/import)、版本和 Agent 多选挂载;技能自身可以按成员授权。记忆分为 L1 规则、L2 纠错、L3 偏好、L4 成功等层级,先进入 PendingMemory,审批后写入 Memory。Runtime 在模型真正调用前记录注入记忆的次数,避免恢复会话重复计量。

5.3 删除与绑定检查(现状和验收点)

当前删除接口会先检查引用关系:被画布节点、融合 Agent、历史任务或其他资源引用的 Agent/技能/知识库/记忆/数字人可能被拒绝删除,前端会提示先解绑。产品要求“弹出一键解绑所有后再删除”时,验收应确保:

  • 明确列出将解除的绑定(Agent、技能、画布节点、知识库分类、数字人、记忆、微信账号等)。
  • 一键操作在同一事务或可恢复事务中完成;失败不得留下半解绑状态。
  • 历史任务的快照、日志、质检和账单保留,不因删除配置而丢失。
  • 全局资源的普通用户操作仍只能建立个人 ResourceRevision,不能直接解绑全局本体。
  • 删除微信账号先停止 sidecar 实例、清理二维码和凭据引用,再删除数据库记录。

6.1 蒸馏流程

  1. POST /api/digital-humans/distill 上传或选择文档,服务端抽取代表性样本。
  2. _dh_distill() 生成 persona 与 persona_meta,记录来源文件、覆盖范围和不确定性,状态为 testing 或 distilling。
  3. POST /api/digital-humans/{id}/test-write 进行人工试写;/redistill 根据反馈提升版本号。
  4. 补充素材通过 /redistill 上传并生成待测试新版本;微信对话不会自动写入数字人人格。
  5. 创建数字人时自动生成同名默认 Agent 并绑定;后续可继续创建多个 Agent 绑定同一数字人,运行时把人格档案合并进系统提示。
  • 前端数字人页调用 POST /api/wechat/bot/accounts/connect,后端生成账号级密钥(只保存哈希)并转发到 YAWAN_WECHAT_ADAPTER_URL。
  • sidecar 使用 @wechatbot/wechatbot、Node 22 和每账号独立 storage 目录;登录回调把 pending_qr、connected、error、disconnected 和二维码状态回传 API。
  • 微信消息签名为 HMAC-SHA256,后端验证时间戳、账号密钥、账号状态、Agent 绑定、组织和所有者;会话按账号/用户/Agent 隔离。
  • 删除调用 DELETE /api/wechat/bot/accounts/{id},sidecar 停止对应 Bot 并回调断开。
  • 生产环境需要 .env.production 中的 YAWAN_WECHAT_ADAPTER_URL=http://127.0.0.1:8765,并由 守护隧道.sh 检查 8765 端口自动拉起。

7. 知识库、索引和检索

7.1 导入链路

支持 .doc/.docx/.srt/.md/.txt/.json/.jsonl/.pdf 以及音视频转写后索引。大文件走 uploads/init、分片上传、uploads/{id}/finish;目录导入走 import-folder。文件落盘后计算 content_hash,同内容文件跳过,重复片段在索引阶段去重。KnowledgeFile.revision 在同名内容变化时递增。

上传/分片 → 文件哈希和去重 → 文本解析或媒体转写 → 分段
→ Embedding → 向量/全文索引 → 后台预热 → ready

index_status:empty、indexing、ready、needs_reindex、error。启动对账会比较磁盘文件、文件表和向量计数;不会因为对账自动重建大库。

7.2 分类和预览

KnowledgeCategory 为无限层级树;文件同时保存人工分类 category_id 和 AI 建议 ai_category_id、置信度、理由。POST /api/kbs/{kid}/classify 批量推荐,.../classification/confirm 人工确认。知识库页签提供文件、分类、检索测试、消费记录和设置;文件查看走预览接口,管理员可查看全部消费记录,普通用户只返回自己有权看到的记录。

7.3 检索模式

  • full:选定知识库/分类的全部已索引资料分批阅读/检索,时间和用量较高。
  • quick:按查询相关性召回,适合快速生成。
  • reuse:复用已阅读缓存,减少重复解析和模型调用。

RAG 管道包含查询校验、Embedding、召回、去重、消费锁和后处理,并记录阶段耗时和缓存命中率;/api/kbs/{kid}/search 和 /api/kbs/search 提供检索测试。知识片段消费状态为 reserved、consumed、available,进程启动会归还中断留下的 reserved。

8. 内容任务和训练营导图

8.1 创建和拆解

POST /api/campaigns 创建任务并保存导图文本、所选画布快照、知识库范围和 Agent;POST /api/campaigns/{cid}/parse 调用 coordinator 将导图拆为 Segment。每段包含节点、标题、时间范围、标签、指定 Agent、知识分类限制和运行快照。拆解失败可由 POST /api/campaigns/{cid}/reparse 重新拆解。

训练营导图 API 位于 server/app/training_map.py,核心输入包括主题、至少一个知识库、可选分类、天数和 Agent。严格模型校验:天数连续、节点标题和叶子内容去重、每个叶子必须有证据来源;导图节点只保留框架短语,详细正文在内容任务生成。导图建议支持整套方案、单天、单日导图和全部导图修改,生成阶段支持进度事件。

全库评估采用分层摘要:原始片段按库分批阅读并递归归并;同一组织、用户、主题、知识库/分类范围及模型签名下,完全相同批次会写入 training-corpus/summary-cache.sqlite,后续草稿或重试可增量复用,缓存使用 WAL、忙等待和单批次文件锁避免并发重复调用。通用全文预读仍使用按知识库隔离的 training-knowledge 清单;两类缓存均不写入 KnowledgeUsage 消费账本。

8.2 连续生成和跳过

任务运行使用 CampaignRun、Segment.status 和锚点卡:上游段产出 anchor_card,下游只接收摘要和最后确认段结尾,避免重复全文。跳过段会被记录为 skipped,后续段不能假设用户已经学会该前置知识,需要补足最小前提。段状态包括 pending/running/qc/human_review/approved/rework/failed/skipped。

逐段操作接口:

  • POST /api/campaigns/{cid}/segments/{sid}:新增段。
  • PUT /api/campaigns/{cid}/segments/{sid}:修改 Agent、分类或正文。
  • DELETE /api/campaigns/{cid}/segments/{sid}:删除段。
  • POST /api/segments/{sid}/review:通过、打回或跳过。
  • POST /api/segments/{sid}/fix:提交修改意见并重新生成。
  • POST /api/campaigns/{cid}/run-step:运行下一步。
  • POST /api/campaigns/{cid}/run:启动完整流水线;支持暂停、取消、恢复。

8.3 质检、组合和交付

质检门包括 structure、content、style、cross;报告存放在 QCReport,空检查列表在启动迁移时自动标记 FAIL。全部段通过后 POST /api/campaigns/{cid}/compose 生成 Artifact,支持预览和下载。运行期间每次模型调用都关联 trace_id、Agent、段、Provider、模型和用量事件。

9. Agent Runtime、工具和 AI 调用

Runtime 的系统工具:knowledge_search、read_upstream_anchors、read_agent_memory、request_handoff;联网工具 web_search、web_collect 默认关闭,启用后需人工审批。每个 AgentSession 保存消息、工具状态、轮次、阶段和结果,可从检查点恢复;每个运行共享 240 轮模型预算,耗尽即停止并写入事件。

每次调用的记录路径:

AgentSession → RuntimeContext → LLMCall → UsageEvent → PointTransaction(如结算)
                               ↘ RunEvent / Trace / SystemLog

模型选择:Agent 可指定 model_provider_id/model_catalog_id/model_name,否则跟随 /api/settings/model-default。Provider 通过 /api/providers 管理,支持连接测试、发现模型、刷新目录和删除;密钥来自配置或本地密钥存储,错误响应经过脱敏处理。

10. 日志、追踪、通知和用量

10.1 日志

  • AuditLog 操作日志:记录用户、动作、资源、结果;不记录请求正文、令牌和密钥。典型动作包括登录、建库、上传、建 Agent、改权限、生成任务等。
  • SystemLog 系统日志:记录 HTTP 失败、应用错误、任务失败、RAG/队列异常和 Trace;错误处理中间件会把具体 detail 写入日志。级别支持 INFO/WARNING/ERROR,前端可按来源、状态和时间查看。
  • RunEvent/LLMCall:运行级工具调用、Agent、模型、重试、耗时和失败原因;用于运行记录和 Trace 详情。

接口:/api/audit-logs、/api/system-logs、/api/llm_calls、/api/traces、/api/traces/{trace_id}。

10.2 通知和进度

Notification 记录失败、待审查、记忆待确认等提醒;GET /api/notifications、POST /api/notifications/{id}/read、POST /api/notifications/read-all 支持单条和一键已读。生成进度由 /api/events/progress(SSE)和 /api/events/progress-poll(轮询)提供,前端 ProgressToast 显示 AI 工作阶段。

10.3 用量和点数

UsageEvent 是追加式计量账本,服务类型包括 llm/embedding/ocr/storage/export/rerank,具备幂等键、价格版本、输入输出数量和金额分。PointAccount 保存余额,PointTransaction 保存充值/扣费/调整流水,UsageQuota 保存每日/月度 token、金额、存储和并发限制。用户端 /api/me/usage、/api/points/me 只返回本人;管理员端 /api/admin/usage/* 和 /api/admin/points/* 可按用户/组织汇总和发放。

11. 任务队列、可靠性和恢复

TaskQueueItem 提供幂等 task_key、租约、重试退避和死信状态。CampaignRun 的 checkpoint、pause_requested、cancel_requested 支持服务重启后恢复。后台线程负责运行任务、索引、预热和告警;进程启动会回收未完成的知识消费预留和历史异常质检。

运营接口包括:

  • GET /api/ops/dashboard:健康指标。
  • POST /api/ops/alerts/sweep:扫描告警。
  • POST /api/ops/dead-letter/{task_id}/requeue:死信重放。
  • GET/POST /api/ops/backup、POST /api/ops/backup/drill:备份和恢复演练。
  • GET /api/system/status、GET /api/health:API、RAG、队列等状态检查。

12. 管理员资源发布和版本审核

管理员资源页按 Agent、技能、知识库、画布、数字人、记忆分别查看授权。对应接口提供成员 grant、撤销、发布全局和导出。普通用户编辑全局资源时,后端创建 ResourceRevision(operation=update/delete) 和必要的 ResourceFork;管理员通过 /api/admin/resource-revisions/{id}/approve 或 reject 审核。审核批准后才改变全局资源版本,个人删除只隐藏自己的视图,不影响其他用户。

13. API 分组速查

认证与管理

/auth/status、/auth/bootstrap、/auth/login、/auth/logout、/auth/me、/auth/users、/auth/roles;管理员资源授权集中在 /admin/{agents,skills,knowledge-bases,canvases,digital-humans,memories}。

Agent、技能、数字人和画布

/agents、/agents/{id}/publish、/agents/{id}/fork、/skills、/skills/import、/skills/{id}/agents、/digital-humans/*、/canvases、/canvases/{id}/fork。

知识库和上传

/kbs、/kbs/{id}、/kbs/{id}/categories、/kbs/{id}/files/*、/kbs/{id}/classify、/kbs/{id}/search、/kbs/search、/uploads/init、/uploads/{id}/chunk/{index}、/uploads/{id}/finish、/kbs/{id}/import、/kbs/{id}/rebuild。

任务与运行

/campaigns、/campaigns/{id}/parse、/campaigns/{id}/reparse、/campaigns/{id}/segments/*、/campaigns/{id}/run、/runs/{id}、/agent-sessions/{id}、/segments/{id}/review、/segments/{id}/fix、/campaigns/{id}/compose、/artifacts/{id}/preview。

微信

/wechat/bot/accounts(列表、连接、更新、绑定 Agent、删除)、/wechat/bot/accounts/{id}/callback(sidecar 状态回调)、/wechat/bot/reply(签名消息转发)。

14. 从用户角度的标准操作链

  1. 登录后在“模型管理”确认可用 Provider 和默认模型。
  2. 在“知识库”建库,上传文件/目录,等待索引状态为“就绪”;必要时执行去重、分类和预览。
  3. 在“Agent 与技能”创建 Agent,选择职责、挂接知识库/分类、技能、模型和数字人,保存并发布。
  4. 在“画布编排”用节点和连线编排 Agent;检查每个节点是否有唯一 Agent 和有效知识范围。
  5. 在“内容任务”粘贴训练营导图/框架,选择画布和知识范围,创建任务并拆解;若失败使用“重新拆解”。
  6. 查看每个内容段的 Agent、知识引用和锚点;可更换 Agent、修改分类、生成、质检、通过/打回/跳过。
  7. 全部段通过后组合成稿,在预览页面复核并下载交付。
  8. 需要微信服务时,在“数字人 → 微信 Bot 连接”选择已配置 Agent,生成二维码,扫码后确认状态为“已连接”。
  9. 在“运行记录、操作日志、系统日志、用量分析”核对执行、错误、模型调用和余额。

15. 逐项验收清单

账号与权限

  • 非管理员直接访问无权限路由显示明确中文提示,API 返回 403/404 且不泄露资源存在性。
  • 普通用户看不到未授权 Agent、知识库、技能、数字人、记忆和画布。
  • 全局资源个人修改/删除生成个人版本提案,不影响其他用户。
  • 账号删除是永久删除;停用只改变 enabled,两者按钮和审计动作不同。
  • 删除有关联资源时可查看依赖,并验证一键解绑事务、历史快照和日志保留。

知识库

  • 首次打开知识库不会显示旧库残留或短暂的“不存在”;详情加载有明确状态。
  • 同内容文件和完全重复片段被跳过,导入结果显示跳过数量。
  • 子分类有文件时父分类计数同步;分类树可展开/收起。
  • 普通用户消费记录只包含自己可用的 Agent/片段;管理员可按用户筛选。
  • 预览按钮返回正确文件标题和正文;大文件不阻塞列表首屏。
  • full/quick/reuse 三种检索模式显示估算耗时、进度和失败原因。

AI 生成与任务

  • 导图先输出框架文本,确认后才能进入内容任务;节点标题/叶子内容无重复。
  • 导图每天按前置关系递进;跳过内容段后,后续段能看到桥接提示。
  • 内容段显示当前 Agent、模型、知识分类和引用来源。
  • 拆解失败、生成失败、AI 修改、图片/OCR/预读均有进度条、重试入口和日志。
  • 质检四道门均产生可追踪报告;空报告自动判为需复检。
  • 运行暂停、取消、恢复后不会重复扣费或重复消费片段。
  • 选择 Agent 后二维码出现;扫码成功后二维码隐藏且列表显示“已连接”。
  • 已连接账号仍显示删除按钮;删除后 sidecar 实例停止、状态回调断开、刷新不复现。
  • 多账号使用不同 storage 目录和账号密钥;账号 A 无法调用账号 B 的 Agent/会话。
  • 绑定 Agent 变更实时同步 sidecar;失效/过期/错误状态能回传并允许重新扫码。

可靠性与部署

  • 生产只使用 data/(或明确的 YAWAN_DATA_DIR),开发只使用 data-dev/。
  • 后端、sidecar、隧道守护进程均可单独重启;502/1033 时日志能定位是 API、隧道还是 sidecar。
  • 启动后未完成运行、片段预留和索引状态能正确恢复或标记。
  • 生产构建通过 npm run build,前端动态模块版本与静态资源缓存一致。

16. 当前限制和风险边界

  • SQLite + NullPool 适合单机/中小规模;多实例横向扩展前需要共享数据库、对象存储和队列,不能直接把本地文件目录挂到多个实例。
  • iLink sidecar 依赖 Node.js 22 和 @wechatbot/wechatbot;官方适配器不可用时只会显示配置/连接错误,不能在浏览器端直接完成协议登录。
  • 本地向量和全文索引路径由 server/app/rag 管理;若切换 Qdrant 等外部服务,需要同步配置、迁移和故障回退策略,当前代码仍保留本地存储能力。
  • AI 输出受模型可用性、点数余额、Runtime 轮次预算和知识索引状态影响;任何“全库阅读”都可能显著增加时间和用量。
  • 日志会对密钥、令牌和请求正文脱敏;若需要排查具体模型错误,应使用 Trace ID、Provider 状态和服务端原始日志,而不是把密钥写入前端提示。

16.1 性能基线与运行维护

  • SQLite 连接统一启用 WAL、busy_timeout=30000、synchronous=NORMAL 和外键约束,并建立日志、知识库文件/分类/消费、授权、运行事件、队列等复合索引。
  • 知识片段消费预留、确认和释放使用批量查询/executemany,减少逐片段 SQL 往返和写锁竞争。
  • RAG 检索记录校验、Embedding、召回、后处理和总耗时,并保留缓存命中率;缓存键包含知识库版本、范围、模型和检索参数。
  • 管理员可调用 GET /api/ops/performance 查看最近 512 次 API 的 P50/P95/P99、慢接口、状态分布及 RAG 阶段指标。该指标为进程内基线,重启后重新采样。
  • 启动阶段只做必要初始化;知识库文件对账和全文索引预热由后台维护线程执行,避免大库扫描阻塞首屏和健康检查。
  • 生产守护脚本使用单实例锁,避免重复守护进程同时启动后端,降低内存争抢和 SQLite 写锁风险。
  • 普通 INFO/DEBUG/WARNING 系统日志与 AI 观测日志进入有界批量队列(最多 1000 条、每批 100 条、最长 1 秒刷盘);ERROR、关键审计、计量账本和任务状态仍同步写入。队列丢弃/失败计数可通过性能指标追踪,进程优雅退出会先刷盘。
  • 性能指标现在通过匿名指标信封从 RAG 子进程回传 API 进程,包含 SQL 次数、SQL 耗时、锁错误、RAG 各阶段耗时和错误样本,避免把查询正文、令牌或原始路径写入指标。
  • 当前任务队列仍是旁路记录,内容生成/导图/上传依赖进程内线程和内存进度总线;外部 Worker 尚未启用。直接启用会造成重复执行和 SSE 进度丢失,必须先完成原子租约认领、持久化进度游标及唯一执行模式切换。
  • 2026-09-13 基线(本机冷启动、37 段产品信息库):首次检索约 3.37 秒,其中 Embedding 约 2.93 秒、召回约 0.41 秒;相同查询命中缓存约 6 毫秒。该样本不能代表 9.8 万段以上大库,需在空闲、内容生成和索引运行中分别采样 P50/P95/P99。
  • Worker 审计结论:TaskQueueItem.lease_next 当前不是原子认领,且内容任务入队后仍由内存线程直接执行;上传、拆解、导图和 SSE 也依赖进程内状态。因此暂不启用内容生成外部 Worker,下一安全阶段仅考虑可幂等的 FTS 预热;迁移前需先完成原子租约、唯一执行模式、持久化进度游标和幂等验收。
  • 2026-09-13 Embedding 诊断已细分为模型加载、Tokenizer、Encode 推理、向量后处理/序列化、进程启动和 IPC 残差,并记录来源、数量、模型版本、维度、PID、缓存命中及 Worker 是否复用。管理员性能接口会聚合这些阶段的 P50/P95;embedding_count 可识别 quick 检索误做批量向量化。
  • 查询向量 LRU 与检索候选池缓存已分离:向量缓存只依赖规范化 query、模型/版本和策略(模型版本代表向量维度契约);候选池缓存包含知识库/分类文件范围、权限签名、索引版本、检索模式和 top-k。知识库版本变化只影响候选池,避免无关地清空查询向量。
  • 2026-09-13 热态未命中采样(单库产品信息,15 条不同 query):首条冷启动约 4.17 秒,其中模型加载约 3.06 秒;模型常驻后总耗时 P50 约 15.93ms、P95 约 25.84ms,Embedding P95 约 16.70ms,Encode P95 约 16.59ms,召回 P95 约 4.30ms,embedding_count=1 且 15 条均未命中查询缓存。六库联合采样(约 15 万段)首条冷启动约 7.48 秒,热态未命中约 0.66~0.78 秒,主要耗时在多库召回而非 Embedding。
  • 查询缓存复测确认:同 query、同 top-k 第二次命中候选池约 17ms;改变 top-k 后候选池重新计算约 45ms,但查询向量缓存命中、Embedding 耗时约 0ms。缓存键已修复首次维度从未知切换到 512 导致的伪未命中问题。
  • 2026-09-13 六库召回稳定性优化:召回线程池改为进程内固定 4 个 Worker,避免每次请求创建线程并限制高并发时的磁盘争用;只读 FTS 索引使用带 inode/版本校验的共享连接、页缓存和 mmap,索引原子替换后自动重连。新增 fts_connection_reused 指标,用于区分连接复用与索引自身耗时。
  • 2026-09-13 六库热态未命中复测(生产 6 库):Embedding 已常驻后约 14~129ms,召回约 0.64~0.91 秒;瓶颈集中在心法、情欲内容的大型 FTS 索引(约 461MB/862MB)和对应向量 I/O,模型加载不再是稳态瓶颈。后续优先做大库索引体积与查询词规模优化,暂不切换模型或向量数据库。
  • 2026-09-13 向量查询进一步优化:移除检索热路径上的 collection.count()。该调用在外置盘冷读时,108135 段库约 1.7 秒,而实际向量查询约 20ms;Chroma/Qdrant 对空集合均直接返回空结果,因此无需先 count。检索指标现在只记录 collection、filter、vector 三段真实 I/O。
  • 2026-09-13 空闲态 10 条不同 query 只读采样:P50 约 556ms,P95 约 1.25s;首条冷启动约 6.43s,后续 Embedding 约 6~345ms。4 路并发只读采样全部完成,未再出现 database is locked;高并发仍受单个常驻 RAG Worker 的队列容量限制,继续保持单 Worker 以控制内存峰值。
  • 2026-09-13 稳定性修复:Embedding 用量事件改为独立短事务提交,计量写入失败只记录告警,不再让知识库检索失败;避免内容任务并发时主业务事务与用量写入互相持有 SQLite 写锁。
  • 计量短事务设置 500ms 忙等待上限;数据库暂时繁忙时只丢弃本次非关键计量并保留检索结果,避免用户看到 30 秒级假性超时。

17. 检查记录模板

检查日期 环境(dev/prod) 页面/API 操作步骤 预期 实际 Trace/截图 结论

维护此文档时,应以代码中的模型字段、路由和权限 key 为准;新增功能同时补充“功能地图、数据模型、API、权限、验收清单”五个位置。