Crispy 后台 AI Agent 完整实现解析
Crispy 3 后台 AI Agent 是一套登录态 + Permission 鉴权 + OpenAI Function Calling + SSE 流式的内容运营助手。它与字段 AI、前台只读助手、MCP 并列,但职责与工具集完全独立。本文梳理当前完整实现,方便二次开发与排障。
一句话架构
Admin Cookie 用户在浮窗或 /admin/ai-agent 发消息 → SSE 进入 runAiAgentStream → OpenAI tools 循环(最多 16 轮)执行 AGENT_TOOLS → 每步 Permission assert + overrideAccess: false → 对话落入 ai-chat-sessions;资源边界由 resources.ts 白名单划定,权限真相来自 authz-cache,侧栏导航由 list_admin_menu 与可点击 Markdown 链接对齐真实 Admin。
入口:UI 与 API
Admin 全页
- Custom View:src/app/(payload)/admin/ai-agent/AiAgentView.tsx
- 路由:/admin/ai-agent(payload.config.ts → admin.components.views.aiAgent)
- 侧栏:运营组「AI 内容助手」,anyOf: [ai:use]
- 服务端先校验登录与 canUseAiAgent,无权限只提示文案
全局浮窗
- AdminAiAgentProvider 注册在 admin.components.providers
- 右侧轨道 + Drawer(AdminAiAgentWidget)
- 与全页共享 AdminAiAgentContext / useAiAgentChat
- Provider 会挂在登录页,因此会话列表必须等 useAuth().user 就绪后再拉取
API
- POST /api/ai/agent — SSE 对话主入口
- GET /api/ai/agent/sessions — 当前用户会话列表
- GET /api/ai/agent/sessions/:id — 会话详情
- DELETE /api/ai/agent/sessions/:id — 软删除会话
鉴权链:payload.auth({ headers }) → Cookie 用户 → canUseAiAgent(等价 ai:use)。客户端用 consumeAgentStream 解析 text/event-stream。
Streaming 与 Function Calling 循环
核心在 src/ai/agent/runAgentStream.ts 的 runAiAgentStream:
- resolveLlmClient({ purpose: 'agent' }) 解析 Catalog LLM
- 注入 system prompt(含当前用户 authz 权限块)
- 循环最多 MAX_TOOL_ITERATIONS = 16
- openAiChatCompletionWithToolsStream(OpenAI 兼容 /v1/chat/completions)
- 若有 tool_calls:executeAgentTool,把结果写回 conversation 继续
- 若仅有文本:yield done
SSE 事件
- text — 增量文本
- tool_start / tool_result — 工具开始与结果摘要
- session — API 路由推送,绑定持久化会话 ID
- done / error — 结束
Agent 统一走 OpenAI 兼容协议(src/ai/providers/openaiCompatible.ts),不单独 fork DeepSeek SDK;字段 AI 仍可走其它 provider 路径。
工具注册表 AGENT_TOOLS
定义与执行均在 src/ai/agent/tools.ts,当前约 24 个工具,按职责分组如下。
元信息与导航
- get_my_permissions — 当前用户角色与 Permission(authz-cache)
- list_admin_menu — 当前用户可见 Admin 侧栏(含 href/url,已按权限过滤)
- list_resources — Agent 可管 Collections / Globals 白名单
- describe_resource — 查看 collection/global 字段结构(写前应先调)
内容 CRUD
- semantic_search — 语义搜索 posts/pages/novels/novel-chapters(需 pgvector)
- find_documents / get_document — 列表与详情
- create_document / update_document — 新建与更新
- delete_document / restore_document — 软删除与恢复
运维与媒体
- get_site_stats / list_audit_logs — 统计与审计
- list_frontend_cache / purge_frontend_cache / get|update_cache_settings — 前台 HTML 缓存
- list_query_presets — 查询预设
- search_stock_images / import_stock_image(s) — Unsplash 检索与导入
- bulk_add_gallery_images — 批量加入图库
- get_global / update_global — 读写白名单 Globals
工具结果有 MAX_RESULT_CHARS = 128000 截断保护;读 ai-settings 时会附带密钥不在 Global 明文的说明。
Access 与 RBAC 双检
总闸:canUseAiAgent → canUseAi → can(user, 'ai:use')。工具层通过 assertAgentCollectionAccess / assertAgentGlobalAccess / assertAgentCacheAccess 等与 Admin Permission 对齐。
- posts:无 posts:update:any 时仅能管自己的文章
- media:禁止通过 Agent 删除
- form-submissions:禁止 create/update
- Catalog:按 catalog:* 拆分读写
双重校验:工具层先 assert*(Permission),再对 Payload Local API 一律 overrideAccess: false + user: req.user。即使 Permission 映射有疏漏,Collection/Global 自身 access 仍会挡住。
会话持久化
- Collection:ai-chat-sessions(title、user、lastMessageAt、messages JSON)
- Admin 列表 hidden,由聊天 API 写入
- sessionStore:create / append user|assistant / list / get / soft-delete
近期修复:Provider 在登录页也会 mount,未登录请求会 401;现用 userId 驱动 refreshSessions,并用 sessionsFetchedForUserRef 避免失败结果覆盖已成功拉取的侧栏。打开浮窗 / 展开历史时也会再刷一次列表。
资源白名单与禁区
白名单见 src/ai/agent/resources.ts(与 MCP 大致对齐)。可管 Collections 含 posts、pages、taxonomy、运营内容、小说、短链、Catalog、画布元数据、评论、表单、media 等;Globals 含 header/footer/site-settings/cache-settings/ai-settings 等。
明确不可管(勿假装可操作):users、roles、authz-cache、payload-mcp-api-keys、search、imports/exports、api-access-logs、文档版本还原。ai-canvases 只管元数据,不改 graph。
近期能力:list_admin_menu 与可点击链接
- listAdminMenu.ts 复用 getAccessResults / getVisibleEntities / getNavGroups,并 merge 自定义导航
- 把 authz-cache permissions 挂到 user,使 admin.hidden 与自定义 anyOf 与真实侧栏一致
- 返回 href(如 /admin/collections/links)与绝对 url;可按 group 过滤
- System prompt 要求 Markdown [label](href);ChatPanel 解析 Markdown / 裸 URL / /admin 路径为可点击链接
与前台助手、MCP 的差异
- Admin Agent:Cookie + ai:use,24 个 CRUD/运维工具,会话落库
- 前台助手:无需登录,仅公开只读检索,浏览器内存会话
- MCP:API Key,自动 Collection/Global 工具 + mcpCustomTools;复用部分 assert*,但范围与 Agent 不完全相同
配置
无 .env LLM 回退。Global ai-settings 管总开关与默认 Provider;Collection llm-providers 存 OpenAI 兼容端点与加密 API Key;prompt-templates 主要服务字段 AI / 画布,Agent 对话本身使用固定 systemPrompt.ts。
关键路径地图
1入口 UI2 src/app/(payload)/admin/ai-agent/3 src/components/AdminAiAgent/45API6 src/app/(payload)/api/ai/agent/78Agent 核心9 src/ai/agent/runAgentStream.ts10 src/ai/agent/tools.ts11 src/ai/agent/access.ts12 src/ai/agent/resources.ts13 src/ai/agent/systemPrompt.ts14 src/ai/agent/sessionStore.ts15 src/ai/agent/listAdminMenu.ts1617LLM18 src/ai/resolveLlmClient.ts19 src/ai/providers/openaiCompatible.ts
更完整的权限与工具对照表可在后台打开 /admin/dev-docs#ai-agent 与 #permissions 查看。
暂无评论,来抢沙发吧。