You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

17 KiB

Agent 文档功能 — 交接文档

日期:2026-08-09 分支:feat/agent-independence Commits:b62a417 → 10688be(共 16 个 commit)

一、功能概述

Agent 文档功能让 agent 能够跨会话持久化信息,分为两种类型:

类型 用途 上下文行为
memory 内部记忆(用户偏好、身份信息等) 每次对话自动注入 system prompt
document 交付物(周报、需求文档、会议纪要等) 不自动注入,需主动调用工具读取

核心能力

  1. Agent 工具:LLM 可通过 document 工具 create/read/update/delete/list 文档
  2. 记忆注入:type=memory 的文档在每次对话时自动拼接到 system prompt,LLM 无需调工具即可使用
  3. 用户界面:右侧抽屉组件,在会话页面内查看/搜索/删除文档,不跳转页面
  4. REST API:5 个端点供前端直接操作文档
  5. 权限隔离:所有操作强制 WHERE userId = ?,用户级隔离
  6. 审批机制:delete 操作默认需用户审批

二、架构设计

┌─────────────────────────────────────────────────────────┐
│  前端                                                    │
│  ┌──────────────┐  ┌──────────────────────────────────┐ │
│  │ AgentToolbar │  │ AgentSidebar (desktop + mobile)  │ │
│  │  文档按钮     │  │  文档按钮                         │ │
│  └──────┬───────┘  └────────────┬─────────────────────┘ │
│         │  emit('showDocuments')│                        │
│         └──────────┬────────────┘                        │
│                    ▼                                     │
│  ┌──────────────────────────────────────────────────┐   │
│  │  AgentChatArea → emit('showDocuments')           │   │
│  └──────────────────────┬───────────────────────────┘   │
│                         ▼                               │
│  ┌──────────────────────────────────────────────────┐   │
│  │  chat/[agentSlug]/index.vue                      │   │
│  │  showDocumentDrawer = true                       │   │
│  │  ┌────────────────────────────────────────────┐  │   │
│  │  │ AgentDocumentDrawer.vue                    │  │   │
│  │  │  ┌──────────┐  ┌────────────────────────┐  │  │   │
│  │  │  │ 列表视图  │  │ 详情视图 (markdown)     │  │  │   │
│  │  │  │ 筛选+搜索 │  │ 删除按钮               │  │  │   │
│  │  │  │ 删除按钮  │  │ AgentMarkdown 渲染     │  │  │   │
│  │  │  └──────────┘  └────────────────────────┘  │  │   │
│  │  └────────────────────────────────────────────┘  │   │
│  └──────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────┐
│  后端                                                    │
│                                                          │
│  ┌─────────────┐   ┌──────────────┐   ┌───────────────┐ │
│  │ REST API    │   │ chat-engine  │   │ agent-tool    │ │
│  │ 5 endpoints │   │              │   │ registry      │ │
│  │             │   │ getMemory    │   │               │ │
│  │ GET    /api │   │ Context()    │   │ document      │ │
│  │ POST   /api │   │ → systemPrompt│  │ executor      │ │
│  │ GET    /:id │   │              │   │               │ │
│  │ PATCH  /:id │   └──────────────┘   └───────┬───────┘ │
│  │ DELETE /:id │                               │         │
│  └──────┬──────┘                               │         │
│         │                                      │         │
│         ▼                                      ▼         │
│  ┌──────────────────────────────────────────────────┐   │
│  │  agent-document service (CRUD + 权限隔离)        │   │
│  │  createDocument / getDocumentById / listDocuments│   │
│  │  updateDocument / deleteDocument                 │   │
│  │  getMemoryContext (查 memory 类型,拼接上下文)    │   │
│  └──────────────────────┬───────────────────────────┘   │
│                         ▼                               │
│  ┌──────────────────────────────────────────────────┐   │
│  │  SQLite: agent_documents 表                      │   │
│  │  id / userId / sessionId / type / title /         │   │
│  │  content / summary / tags / createdAt / updatedAt │   │
│  └──────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────┘

三、文件清单

数据层

文件 说明
packages/drizzle-pkg/lib/schema/agent-document.ts agentDocuments 表 schema,createdAt/updatedAt 用 mode: "timestamp_ms"
packages/drizzle-pkg/lib/schema/agent-tool.ts AgentToolTypes 新增 "document"
packages/drizzle-pkg/migrations/0002_noisy_ronan.sql 建表迁移
packages/drizzle-pkg/seed.ts document 工具种子数据(id=tool_document)

Service 层

文件 说明
server/service/agent-document/index.ts CRUD + getMemoryContext() + deserializeTags
server/service/agent-document/index.test.ts 32 个单元测试

Executor 层

文件 说明
server/service/agent-tool/executors/document/config.ts document executor config(审批白名单、maxContentLength 等)
server/service/agent-tool/executors/document/document.ts executor 实现,5 种 action 分发,toISO() 序列化 Date
server/service/agent-tool/registry.ts ToolContext 扩展 approved?: boolean
server/service/agent-tool/index.ts document executor 注册(line 128-133)

API 层

文件 说明
server/api/agent-documents/index.get.ts GET 列表(分页 + 类型筛选 + 关键词搜索)
server/api/agent-documents/index.post.ts POST 创建
server/api/agent-documents/[id].get.ts GET 详情
server/api/agent-documents/[id].patch.ts PATCH 更新
server/api/agent-documents/[id].delete.ts DELETE 删除

前端

文件 说明
app/components/agent/AgentDocumentDrawer.vue 右侧抽屉(列表 + 详情 + 删除 + 筛选 + 搜索)
app/components/agent/AgentToolbar.vue 工具栏文档按钮 → emit showDocuments
app/components/agent/AgentSidebar.vue 侧边栏文档按钮(desktop + mobile)→ emit showDocuments
app/components/agent/AgentChatArea.vue 透传 showDocuments 事件
app/pages/chat/[agentSlug]/index.vue 接入 showDocumentDrawer 状态 + 渲染抽屉
app/pages/agent-documents/index.vue 独立列表页(保留,导航入口在 TopNav)
app/pages/agent-documents/[id].vue 独立详情页(保留)

Chat Engine

文件 说明
server/service/agent/chat-engine.ts 记忆注入 system prompt(line 250-260)+ buildModelMessages 修复

测试

文件 说明
e2e/specs/agent-documents.spec.ts 10 个 E2E 测试用例

文档

文件 说明
docs/superpowers/specs/2026-08-09-agent-document-tool-design.md 设计文档
docs/superpowers/plans/2026-08-09-agent-document-tool.md 实施计划
docs/handover/2026-08-09-agent-document-tool.md 本交接文档

四、关键实现细节

4.1 记忆注入上下文

// chat-engine.ts line 250-260
let systemPrompt = baseSystemPrompt;
if (user) {
  const memoryContext = await getMemoryContext(user.id);
  if (memoryContext) {
    const memoryInstruction =
      "\n\n# 持久记忆(已注入上下文)\n" +
      "以下 <memory> 标签内的信息是你的持久记忆,每次对话开始时自动加载,始终是最新的。\n" +
      "**禁止调用 document 工具的 read 或 list 操作来读取这些记忆** — 它们已经在你的上下文中了。\n" +
      "直接使用 <memory> 中的内容回答用户问题即可。\n" +
      "只有需要创建新记忆或修改已有记忆时,才使用 document 工具。";
    systemPrompt = systemPrompt
      ? `${systemPrompt}${memoryInstruction}\n${memoryContext}`
      : `${memoryInstruction}\n${memoryContext}`;
  }
}
  • 实时查询:每次 executeChat 调用时从数据库查 type=memory 的文档,文档更新后下一轮对话自动生效
  • 格式:每条记忆用 ## {title}\n{content} 格式,整体包裹在 <memory> 标签内
  • 防冗余调用:system prompt 中明确禁止 LLM 调用 document 工具读取已有记忆

4.2 getMemoryContext 实现

// agent-document/index.ts
export async function getMemoryContext(userId: number): Promise<string | null> {
  const rows = await dbGlobal
    .select({ title: agentDocuments.title, content: agentDocuments.content })
    .from(agentDocuments)
    .where(and(eq(agentDocuments.userId, userId), eq(agentDocuments.type, "memory")))
    .orderBy(desc(agentDocuments.updatedAt));

  if (rows.length === 0) return null;

  const parts = rows.map((r) => `## ${r.title}\n${r.content}`);
  return `<memory>\n${parts.join("\n\n")}\n</memory>`;
}

4.3 Date 序列化问题

drizzle timestamp_ms mode 返回 Date 对象,AI SDK Zod 校验拒绝 Date(期望 string)。executor 中用 toISO() helper 序列化:

function toISO(date: Date | null | undefined): string | null {
  return date ? date.toISOString() : null;
}

4.4 buildModelMessages 审批修复

approval-responded + hasResult=false 时只 push tool-approval-request,不 push 无 output 的 tool-call(AI SDK 校验失败)。

4.5 抽屉组件

  • Teleport to="body" + Transition 实现滑入动画
  • 列表视图:类型筛选 tabs(全部/文档/记忆)+ 搜索框(400ms 防抖)+ 卡片列表
  • 详情视图:返回按钮 + 标题 + AgentMarkdown 渲染 + 删除按钮
  • 每次 show 变 true 都重新 fetch(不缓存)
  • 删除带 confirm() 确认,删除后自动从列表移除

4.6 agent-tool 关联

工具必须通过 agent_tool_associations 表关联到 agent 才能被 LLM 使用,仅 enabled=1 不够。已为 default agent(id=1)手动插入关联记录。

五、数据库表结构

CREATE TABLE agent_documents (
  id          INTEGER PRIMARY KEY AUTOINCREMENT,
  userId      INTEGER NOT NULL,
  sessionId   TEXT,
  type        TEXT NOT NULL DEFAULT 'document',  -- 'memory' | 'document'
  title       TEXT NOT NULL,
  content     TEXT NOT NULL,
  summary     TEXT,
  tags        TEXT,                               -- JSON array string
  createdAt   INTEGER NOT NULL,                   -- timestamp_ms
  updatedAt   INTEGER NOT NULL                    -- timestamp_ms
);

-- 索引
CREATE INDEX idx_agent_documents_userId ON agent_documents(userId);
CREATE INDEX idx_agent_documents_userId_type ON agent_documents(userId, type);
CREATE INDEX idx_agent_documents_userId_updatedAt ON agent_documents(userId, updatedAt);

六、API 接口

方法 路径 说明
GET /api/agent-documents?page=1&pageSize=20&type=memory&keyword=xxx 列表查询
POST /api/agent-documents 创建文档
GET /api/agent-documents/:id 获取详情
PATCH /api/agent-documents/:id 更新文档
DELETE /api/agent-documents/:id 删除文档

响应格式:{ code: 0, message: 'success', data: ... }

七、Agent 工具接口

LLM 可调用的 document 工具,通过 action 字段分发:

action 必填参数 可选参数 说明
create title, content type, tags 创建文档/记忆
read id fullContent 读取详情(默认仅返回 summary)
update id title, content, tags 更新文档
delete id — 删除文档(默认需审批)
list — type, keyword, page, pageSize 列表查询

八、已知问题与注意事项

  1. seed.ts 不是 upsert:admin 用户已存在时重跑 seed 会 UNIQUE 冲突;开发库需手动插入新工具记录
  2. guess-who 残留:packages/drizzle-pkg/seed.ts line 215-225 有 guess-who 种子数据,但 executor 不存在
  3. 前端无 agent 编辑页:无法通过 UI 管理 agent-tool 关联,需手动插库
  4. typecheck 预先存在错误:search、chat、favorite、ideas、llm 模块有 TS 错误,与本次改动无关
  5. 记忆无 token 上限:当前 getMemoryContext 拼接所有 memory 文档,如果记忆数量多可能撑爆上下文。后续可加 token 预算截断

九、Commit 历史

Commit 说明
b62a417 feat: add agent_documents table schema, migration, and seed data
2bd451a feat: add agent-document service layer with CRUD, permission isolation, and tests
b40bfa4 feat: add document tool executor with config, registration, and approved flag
e5d7e68 feat: add REST API endpoints for agent documents
d06a642 feat: add agent-documents frontend pages (list + detail) and nav entry
0c8d51a feat: add POST create endpoint and E2E tests for agent-documents
6b381d6 docs: add agent-documents E2E test entry to AGENTS.md
322accb fix: buildModelMessages approval-responded without result should not emit tool-call
0ae318a feat(agent): add document entry in sidebar footer and toolbar
50f0ca4 fix(agent-document): serialize Date fields to ISO strings in executor output
c5e9ae9 fix(agent-document): deserialize tags in listDocuments + null guard in template
72659af feat(agent-documents): replace page navigation with right-side drawer
bf88935 feat(agent-documents): add delete in drawer + inject memory into system prompt
c2bf347 fix(chat-engine): instruct LLM not to call document tool for existing memory
10688be fix(chat-engine): strengthen memory instruction to prevent redundant tool calls

十、后续可优化方向

  1. 记忆 token 预算:getMemoryContext 加 token 上限,超限时按优先级截断
  2. 向量检索:文档量大时用向量检索替代 SQL 模糊搜索
  3. agent 编辑页:前端 UI 管理 agent-tool 关联,避免手动插库
  4. 记忆分类:memory 细分为 preference/identity/fact 等,按类别注入
  5. 文档分享:document 类型支持生成分享链接
  6. 版本历史:文档更新时保留历史版本