开发运行说明
当前阶段
当前实现范围为 P0+P1+P2,以及 P3 阶段附件离线高保真解析与离线 QA RAG 问答 Prompter:
- FastAPI Sidecar API。
- Memos webhook 接收。
- SQLite 任务表、工作区表和 memo 映射表。
- 后台 worker 轮询处理
process_memo任务。 - Memos API Client 基础封装。
- Memos 用户 webhook 自动配置探针。
- 标签树配置加载与本地整理草案生成。
- 候选标签持久化与后台审核接口。
- 审核通过的候选标签进入 Sidecar active 标签集合,后续整理会直接使用。
- 调试管理 Web 页面
/admin/ui,用于查看任务、重试任务和审核候选标签。 - 管理页面支持按标签生成整体总结 memo,把同一标签下的零散 memos 整理成可读展示。
- 管理页面支持下载 Sidecar 备份 ZIP,并从备份 ZIP 恢复 Sidecar SQLite 数据库。
- 用户原始 memo 没有业务标签时,LLM 从正文自动建议正式标签和候选标签;新标签仍需审核。
- AI 整理 memo 本地模板创建,并在 Sidecar 数据库记录来源关联。
- 待澄清 memo 评论追问,并把任务置为
waiting_user。 - OpenAI-compatible LLM provider 接入,默认使用 DeepSeek
deepseek-chat,并保留 OpenRouter、OpenAI 等 provider 模板。 #提醒时间识别、提醒持久化、到期 webhook 通知和管理接口。- P3 离线高保真解析:
.txt、.md附件下载并解析为 Markdown artifact;Word、Excel、PPT、PDF 附件通过 MinerU 在线服务转成 Markdown;特别原生支持.drawio(包括 .drawio.svg) 附件离线解压提取与Mind Elixir脑图 JSON 大纲递归生成,100% 离线。 - P3 离线 QA & Prompt 编译器: 控制台新增 QA 问答页面,支持多标签药丸胶囊选择、拼音中文模糊联想提示,后端执行标签精准与文本 contains 双路召回,一键编译与复制超级 Prompt。
向量索引、自动文档和 Memos 主库备份恢复属于后续阶段。
环境准备
本项目在 Linux 环境下开发和测试。所有常用开发命令通过 Nx 任务入口执行:
npx nx test sidecar
npx nx run sidecar:compile
npx nx build sidecar
不要直接运行 pip install;Python 包和虚拟环境统一由 uv 管理,并封装在 Nx target、容器构建或后续统一脚本中。开发阶段优先执行本地 Nx 测试,Docker 构建放到阶段末尾验收。
启动 API
npx nx run sidecar:up
默认 Compose 会启动 gateway、memos、sidecar 和 sidecar-worker。Caddy 网关只暴露一个宿主机入口:http://localhost:8080/ 进入 Memos,/admin/*、/health、/webhooks/* 进入 Sidecar。Memos 的 5230 和 Sidecar 容器内部 8080 默认不直接暴露;需要更换宿主机端口时使用 GATEWAY_PORT=8090 npx nx run sidecar:up。
Memos 页面:
http://localhost:8080/
健康检查:
curl http://localhost:8080/health
调试管理页面:
http://localhost:8080/admin/ui
页面通过现有管理 API 工作,需要输入 SIDECAR_ADMIN_TOKEN。token 只保存在浏览器 localStorage,不会写入 HTML、日志或仓库。页面也支持查看和保存 AI 调用配置;单条 memo 整理、标签总结和提醒抽取都可以单独选择模型 provider 并编辑提示词。
页面“大模型”区域支持直接切换默认 provider、修改模型名、base URL、响应格式、扩展 JSON 和 key。保存后 config/models.yaml 会记录非机密模型参数,真实 key 写入已忽略的 config/.env.local。API 和 worker 会在后续加载模型配置时读取该文件;备份包不会包含该密钥文件。
Memos 探针
执行 Memos API 探针:
npx nx run sidecar:probe-memos
首次本地联调可创建测试用户、登录并创建 memo:
npx nx run sidecar:probe-memos -- --bootstrap-username test --bootstrap-password testtest --create-memo "探针 memo #系统/原始记录"
创建 Memos Personal Access Token,供 Sidecar/worker 长期读取 Memos API:
npx nx run sidecar:probe-memos -- \
--bootstrap-username test \
--bootstrap-password testtest \
--create-pat \
--pat-output-env-file /tmp/memosima-pat.env
默认输出会隐藏 PAT 原文;/tmp/memosima-pat.env 仅供本机临时注入容器,不要提交到仓库。
本地部署默认使用 Sidecar 主动轮询 Memos,不需要公网 webhook。config/app.yaml 中 memos.ingestion_mode: poll 会让 worker 在空闲时读取最近 memo,发现未处理的原始 memo 后自动创建 process_memo 任务。
可选:配置 Memos 内置 webhook:
npx nx run sidecar:probe-memos -- \
--bootstrap-username test \
--bootstrap-password testtest \
--configure-webhook-url "https://your-public-sidecar.example.com/webhooks/memos"
也可以通过 .env 配置 MEMOS_WEBHOOK_URL,然后直接执行探针。Memos 0.28.0 会拒绝 webhook URL 解析到本机、Docker 内网或其他保留/私有 IP,例如 http://sidecar:8080/webhooks/memos、http://localhost:8080/webhooks/memos 和 http://172.x.x.x:8080/webhooks/memos。本地测试不需要绕过该限制,使用默认轮询模式即可;公网部署时把 webhook 指向 Caddy 网关公开入口的 /webhooks/memos。
配置 webhook、创建 memo 并轮询 Sidecar 任务状态:
npx nx run sidecar:probe-memos -- \
--bootstrap-username test \
--bootstrap-password testtest \
--configure-webhook-url "$MEMOS_WEBHOOK_URL" \
--create-memo "自动 webhook 探针 #系统/原始记录" \
--verify-sidecar-url "http://localhost:8080" \
--verify-sidecar-token "$SIDECAR_ADMIN_TOKEN"
启动 Worker
持续轮询由 Compose 中的 sidecar-worker 服务负责:
npx nx run sidecar:up
管理接口
调试页面:
http://localhost:8080/admin/ui
页面支持健康状态刷新、任务状态筛选、任务详情查看、失败或待澄清任务重试、候选标签详情查看、候选标签通过/拒绝、按标签生成整体总结、提醒管理、Sidecar 备份恢复,以及 AI 调用配置查看和保存。
worker 维护 #系统/Memosima 管理入口 memo 时,会使用 Memos 0.28 兼容的 content.contains("memosima:admin-entry") filter 表达式查找已有入口,避免把 HTML marker 原文作为 filter 导致 Memos 返回 400。
查询任务:
curl -H "Authorization: Bearer<空格>$SIDECAR_ADMIN_TOKEN" \
"http://localhost:8080/admin/jobs"
重试失败任务:
curl -X POST -H "Authorization: Bearer<空格>$SIDECAR_ADMIN_TOKEN" \
"http://localhost:8080/admin/jobs/1/retry"
读取和更新 AI 调用配置。请求体中的 provider 可填写 config/models.yaml 中的 provider 名称;为空时使用默认 provider:
curl -H "Authorization: Bearer<空格>$SIDECAR_ADMIN_TOKEN" \
"http://localhost:8080/admin/prompts"
curl -X PUT -H "Authorization: Bearer<空格>$SIDECAR_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"system":"系统提示 {active_tags}","user":"用户提示 {content}"}' \
"http://localhost:8080/admin/prompts/organize-memo"
临时覆盖某次重试使用的提示词。该覆盖只影响提示词,不会临时改变模型 provider:
curl -X POST -H "Authorization: Bearer<空格>$SIDECAR_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"prompt_override":{"system":"临时系统 {active_tags}","user":"临时用户 {content}"}}' \
"http://localhost:8080/admin/jobs/1/retry"
按标签生成整体总结:
curl -X POST -H "Authorization: Bearer<空格>$SIDECAR_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"tag":"#项目/个人AI知识库","limit":50}' \
"http://localhost:8080/admin/tag-summaries"
该接口会读取最近的 Memos 列表,在 Sidecar 本地按标签路径匹配,排除已有 #系统/AI整理 和 #系统/标签总结 memo,按 config/prompts.yaml 的 tag_summary.provider 选择模型生成 Markdown 总结,并在 Memos 中创建带有 #系统/标签总结 和目标标签的新 memo。标签匹配支持高层级路径:请求 #项目 会包含 #项目 和 #项目/... 子标签,但不会包含 #项目管理。如果匹配发生在 AI 整理 memo 上,Sidecar 会用本地 memos.source_memo_uid 反查原始 memo,把原始 memo 纳入总结而不是把 AI 整理 memo 作为来源。创建成功后,Sidecar 会把总结 memo 通过 Memos 原生 REFERENCE relation 引用到每条参与整理的普通来源 memo,便于在 Memos 界面点击回看来源。默认提示词使用 config/prompts.yaml 的 tag_summary,支持 {tag}、{memo_count} 和 {memos_markdown} 占位符。
查询和管理提醒:
curl -H "Authorization: Bearer<空格>$SIDECAR_ADMIN_TOKEN" \
"http://localhost:8080/admin/reminders"
curl -X POST -H "Authorization: Bearer<空格>$SIDECAR_ADMIN_TOKEN" \
"http://localhost:8080/admin/reminders/1/retry"
curl -X POST -H "Authorization: Bearer<空格>$SIDECAR_ADMIN_TOKEN" \
"http://localhost:8080/admin/reminders/1/cancel"
/admin/reminders 支持 ?status=pending、?status=failed、?status=sent 和 ?status=cancelled 过滤。retry 会把 failed 或 sent 的提醒重新置为 pending,下次 worker 扫描到期提醒时再次发送;cancel 只取消 pending 或 failed 的提醒。
下载和恢复 Sidecar 备份:
curl -H "Authorization: Bearer<空格>$SIDECAR_ADMIN_TOKEN" \
-o memosima-sidecar-backup.zip \
"http://localhost:8080/admin/backups/download"
curl -X POST -H "Authorization: Bearer<空格>$SIDECAR_ADMIN_TOKEN" \
-H "Content-Type: application/zip" \
--data-binary @memosima-sidecar-backup.zip \
"http://localhost:8080/admin/backups/restore"
备份 ZIP 包含 SQLite 快照、manifest 和非机密配置文件。恢复接口只替换 Sidecar SQLite 数据库,不自动覆盖配置文件,也不包含 Memos 主库或 Memos 附件。恢复前建议先下载当前状态备份。
测试
npx nx test sidecar
当前已通过自动化测试:
npx nx test sidecar
全部测试通过
P2 本地整理草案
worker 处理 memo 时会加载 config/taxonomy.yaml,在 job result.ai_plan 中写入本地整理草案:
system_tags:默认包含#系统/原始记录,必要时包含#系统/待澄清或#系统/标签待审核。active_tags:命中已审核业务标签或别名后的正式标签。candidate_tags:memo 中出现但不在已审核标签树中的业务标签。disabled_tags:命中禁用标签的条目。needs_clarification:内容过短时标记为需要澄清;问号、URL 参数等特殊字符不会单独触发待澄清。
该草案用于 P2 早期验证标签治理和任务结构。内容明确时,worker 会创建一条 Markdown AI 整理 memo,内容包含 #系统/AI整理、来源 memo、摘要、标签状态和原文摘录,并在 job result.ai_summary_memo_uid 返回新 memo uid。AI 整理 memo 不再写入业务 #tag,业务标签只在“标签”区域以普通文本展示,避免 AI 生成内容污染 Memos 原生标签筛选。
当所选 provider 对应的 key 存在时,worker 会按 config/models.yaml 调用 OpenAI-compatible /chat/completions,要求模型返回 JSON 对象,并把模型输出的摘要、要点和待办写入 AI 整理 memo。当前默认 provider 为 deepseek,默认模型为 deepseek-v4-flash,需要配置 DEEPSEEK_API_KEY。模型请求中的 base_url、default_model、temperature、max_tokens、response_format 和 extra_body 全部由配置文件控制;DeepSeek 模板在 extra_body.thinking.type 中显式配置 disabled,让摘要类任务使用非 thinking 输出。max_tokens 留空时不发送输出 token 限制,Sidecar 不主动截断输入正文。真实 key 只放在本地 .env、部署环境变量
P3 附件解析与 QA 问答
worker 处理 memo 时会读取 memo 中的 resources 或 attachments 字段。对于允许扩展名内的 .txt 和 .md 附件,会通过 Memos 资源接口下载并安全解码为 Markdown;对于 .doc、.docx、.xls、.xlsx、.ppt、.pptx 和 .pdf,会调用可插拔文档解析 provider(默认 MinerU 在线 API)。对于 .drawio(.drawio.svg)与 Mind Elixir .json 脑图,会启动本地 100% 离线的高保真解析器:
kind=attachment_drawio(本地离线解压 cell 文本)kind=attachment_mind_elixir(递归遍历 JSON 生成层级 Markdown 大纲)kind=attachment_text或kind=attachment_document
所有解析结果均写入 Sidecar SQLite 的 artifacts 表,字段包括 memo_uid、resource_uid 和 content_markdown 等。解析得到的 Markdown 会在调用 LLM 前拼接到原 memo 正文后面参与智能整理。
对于正文为空、只有附件的原 memo,worker 会在 LLM 分析完成后使用 PATCH /api/v1/memos/{memo_uid} 回写一级标题。标题来自 LLM draft 的 title 字段,并会去掉多余的 AI整理 前缀和 Markdown # 符号,避免覆盖已有正文。
解析结果会出现在 job result.attachments 中。若未配置 MINERU_API_TOKEN,Office/PDF 附件会记录为 document_parser_not_configured,而 Draw.io 与思维脑图不受影响,依然可以通过本地离线解析成功。
离线 RAG Prompt 编译器接口:在 API 中新增了 POST /admin/qa/generate-prompt,支持用户通过 active 标签和模糊关键词(通过 Memos API 的 content.contains 召回)获取相关的 Memo 正文及关联的 Artifacts 解析段,组装成系统提示词和用户 Query 合一的超级 Prompt 返给管理页面,便于离线环境一键复制粘贴。
business_tags 中的 active 标签时才直接使用;未知标签会降级为候选标签并写入 tag_candidates;禁用标签进入 disabled_tags;系统标签不会由 LLM 创建。业务标签的最后一级名称必须全局唯一,例如已有 #项目/数管 时,后台会把 #数管 归一到该正式标签,并阻止 #其他/数管 成为候选或审核通过。Sidecar 还会按 limits.max_ai_active_tags 和 limits.max_ai_candidate_tags 限制单条无标签 memo 的 LLM 自动补充数量,默认最多接收 5 个正式标签和 2 个候选标签。
所有 LLM 调用点的默认提示词和模型选择都从 config/prompts.yaml 加载。当前调用点为 organize_memo、tag_summary 和 reminder_extraction。organize_memo 支持 {active_tags}、{local_plan_json}、{content} 占位符;tag_summary 支持 {tag}、{memo_count}、{memos_markdown} 占位符;reminder_extraction 支持 {trigger_tag}、{now}、{timezone}、{content} 占位符。管理页面保存 AI 调用配置会写回该文件;任务重试时的临时提示词覆盖只写入任务 payload,不会改变默认配置或临时切换模型。
Sidecar 会在本地 memos 表记录两类 memo:
type=original:原始 Memos memo,同步状态为synced。type=ai_summary:AI 整理 memo,source_memo_uid指向原始 memo,状态为created。
worker 创建 AI 整理 memo 后,会同时写入 Memos 原生 relation:AI 整理 memo REFERENCE 到原始 memo。标签整体总结创建后,也会写入原生 relation:总结 memo REFERENCE 到参与整理的来源 memos。生成内容中只展示来源 UID,不再写入裸 memos/{uid} 文本,避免正文引用和原生 relation 叠加形成双向跳转。所有 relation 写入统一经过 MemosClient.upsert_memo_reference_relation,会跳过自引用、已有重复引用、反向引用,以及从目标 memo 沿 REFERENCE 链路可回到源 memo 的多跳循环引用。Sidecar 本地 memos.source_memo_uid 仍保留,作为本地查询和恢复时的冗余关联。
当 needs_clarification=true 时,worker 不会创建 AI 整理 memo,而是在原 memo 下创建澄清评论,并把任务状态置为 waiting_user。补充原始 memo 内容后,可以通过现有重试接口重新处理:
curl -X POST -H "Authorization: Bearer<空格>$SIDECAR_ADMIN_TOKEN" \
"http://localhost:8080/admin/jobs/1/retry"
候选标签管理接口:
curl -H "Authorization: Bearer<空格>$SIDECAR_ADMIN_TOKEN" \
"http://localhost:8080/admin/tag-candidates"
curl -X POST -H "Authorization: Bearer<空格>$SIDECAR_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"note":"纳入正式标签"}' \
"http://localhost:8080/admin/tag-candidates/1/approve"
curl -X POST -H "Authorization: Bearer<空格>$SIDECAR_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"note":"重复标签"}' \
"http://localhost:8080/admin/tag-candidates/1/reject"
审核通过会把候选标签写入 Sidecar SQLite 的 business_tags 表,状态为 active。worker 每次处理 memo 时会合并 config/taxonomy.yaml 中的 active 标签和数据库中审核通过的 active 标签,因此后续同类 memo 会直接使用该标签,不再重复创建候选。
当前不会自动改写 config/taxonomy.yaml;如果需要把运行期审核结果固化为配置文件,后续会提供导出或管理接口。
P3 附件解析
worker 处理 memo 时会读取 memo 中的 resources 或 attachments 字段。对于允许扩展名内的 .txt 和 .md 附件,会通过 Memos 资源接口下载并安全解码为 Markdown;对于 .doc、.docx、.xls、.xlsx、.ppt、.pptx 和 .pdf,会调用可插拔文档解析 provider,默认 provider 为 MinerU 在线 API。解析结果写入 Sidecar SQLite 的 artifacts 表:
kind=attachment_text或kind=attachment_documentmemo_uid:来源 memo uidresource_uid:Memos resource name,例如resources/...content_markdown:解析后的 Markdown 文本metadata_json:文件名、content type、大小、扩展名等元数据
Office/PDF 解析流程为:向 MinerU 申请上传 URL,PUT 上传文件,轮询批量解析结果,下载结果 zip 并读取其中的 Markdown。得到的 Markdown 会在调用 LLM 前拼接到原 memo 正文后面,后续 AI 整理、标签生成、候选标签审核和 AI 整理 memo 创建流程保持不变。
对于正文为空、只有附件的原 memo,worker 会在 LLM 分析完成后使用 PATCH /api/v1/memos/{memo_uid} 回写一级标题。标题来自 LLM draft 的 title 字段,并会去掉多余的 AI整理 前缀和 Markdown # 符号,避免把原 memo 变成标签或覆盖已有正文。
解析结果会出现在 job result.attachments 中,状态可能是 parsed、skipped 或 failed。如果未配置 MINERU_API_TOKEN,Office/PDF 附件会记录为 document_parser_not_configured,不会阻塞普通正文整理。
Docker 状态
仓库已提供可发布的 docker-compose.yml、Dockerfile 和 gateway/Caddyfile。
npx nx build sidecar 会执行 docker compose build,覆盖 Sidecar、worker 和网关发布栈。真实联调时需先确认 Compose 正在运行最新镜像和当前挂载配置,再从实际监听的 Caddy 网关端口访问 Memos、/admin/ui 和 /health。
Dockerfile 已将第三方依赖安装与项目源码拷贝分层,后续普通代码变更不会反复下载全部 Python 依赖。
Compose 中 Sidecar 和 worker 的 ./config:/app/config 挂载保持可写,便于管理页面保存 config/prompts.yaml。不要把真实密钥写入 config 文件;密钥仍只通过环境变量或部署密钥管理提供。