Compare commits

...

2 Commits

Author SHA1 Message Date
caoqianming 2e063e2ac0 fix(prompt): Word 渲染段命令行按 backend 换路径——host 不再注容器路径
_build_system_prompt 渲染段原硬编码 /sandbox/rendering/render.py,host 模式
(本地 dogfood)下该容器路径不存在,agent 照调必 FileNotFoundError。
按 is_docker 分支:docker 原样不变;host 换 venv 解释器 + 宿主真实路径。
skill 文档里的 /sandbox 写法是 docker 专属管线,不动。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 16:13:56 +08:00
caoqianming 6e455d37be fix(kb): 注入契约改主动查阅——相关即先读无需点名,去掉 document_search 路由
- _KB_CONTRACT 第一条换成主动性规矩:INDEX 条目与问题相关就先 read 正文再答,
  用户无需说"从我的知识库里查";此前契约只写"怎么用"没写"何时主动用",
  flash 容易把 INDEX 当背景略过
- 去掉契约里的 document_search 路由条(契约只管 .kb 自己怎么用,路由靠各自
  工具描述自然分流,少一层耦合)
- DESIGN §3.8 两处描述同步收窄

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 15:43:01 +08:00
3 changed files with 15 additions and 6 deletions

View File

@ -87,11 +87,11 @@ Session = 消息列表,ORM 直写 PG `messages`(append-only,jsonb 存 LiteLLM
### 3.8 个人知识库(`core/kb.py` + `core/kb_ingest.py`,✅ 2026-07-22)
用户自建资料(规范/报告/标准/内部文档)的长期查阅层,与 §3.7 记忆同范式:**纯文件 + prompt 注入契约,无向量无 DB**(判据同"真实文件为准":个人库几十~百余文件,agentic search 足够;索引若引入只能是可重建派生缓存)。**两层格局**:zcbot 内建 `.kb/` 私有小库(本节)+ 院检索服务共享大库(document_search,zcbot 只当客户端)——分工标准 = 文件数 × 查询频次,路由规则写进注入契约(学科文献→院库 / 自建资料→`.kb`)。
用户自建资料(规范/报告/标准/内部文档)的长期查阅层,与 §3.7 记忆同范式:**纯文件 + prompt 注入契约,无向量无 DB**(判据同"真实文件为准":个人库几十~百余文件,agentic search 足够;索引若引入只能是可重建派生缓存)。**两层格局**:zcbot 内建 `.kb/` 私有小库(本节)+ 院检索服务共享大库(document_search,zcbot 只当客户端)——分工标准 = 文件数 × 查询频次,路由靠各自工具/契约描述自然分流,不在 kb 契约里点名 document_search(2026-07-22 收窄:契约只管自己怎么用,少一层耦合)。
- **做成机制而非 skill**(判据:有独立于会话的持久状态需用户管理 → 机制):落盘 `user_root/.kb/<库名>/`(INDEX.md + docs/ 转换后 md + sources/ 原件)。**"已入库"判据 = INDEX.md 有条目**,sources 有而 INDEX 无 = 待入库 → 入库幂等、崩溃可恢复、零 migration。dotfile 命名同 `.memory` 双向防呆,GET /v1/files 天然隐藏。
- **入库管线**(`core/kb_ingest.py`,上传即触发 + 手动兜底):markitdown Python API 转 md → 扫描件 PDF(文本近零)走方舟文档理解 OCR 兜底(§8.13 同通道)→ deepseek flash 单次 chat 写 标题/摘要/关键词(失败降级文件名+正文开头,不阻塞)→ 追加 INDEX 行。编排照定时执行器:create_task + to_thread + per-(user,库) 内存锁去重;进度存内存供前端轮询,崩了靠 FS 判据续跑。
- **agent 侧零新工具**:`kb_block`(照 memory_block)把 INDEX 全文 + 契约(路由规则 / INDEX 行格式 / 答题标来源)注 prompt,**用户有库才注入**;fs 工具在 user_root 内可读写、docker 沙箱整 user_root bind → `.kb` 天然可达。INDEX 行格式是对话内手动入库与后台产出的同一契约。
- **agent 侧零新工具**:`kb_block`(照 memory_block)把 INDEX 全文 + 契约(主动查阅无需点名 / INDEX 行格式 / 答题标来源)注 prompt,**用户有库才注入**;fs 工具在 user_root 内可读写、docker 沙箱整 user_root bind → `.kb` 天然可达。INDEX 行格式是对话内手动入库与后台产出的同一契约。
- **API 薄壳**(`/v1/kb*` 8 端点):列/建/删库、详情(带入库进度)、上传即入库、手动 ingest、看/删单篇。**不设 HTTP 检索端点**——检索是 agent 的事。前端两栏 modal(kb.js)管上传/删除,查询全走对话。
- **记账**:`usage_events` kind="kb_ingest"(OCR 那笔走 kind="vision"),无 task 上下文 → 0022 放宽 task_id 可 NULL,溯源靠 units JSONB `{"kb", "source"}`

View File

@ -18,6 +18,7 @@ state.json 已删除(元数据全在 PG)。
from __future__ import annotations
import os
import sys
from datetime import datetime
from pathlib import Path
from typing import Any, Callable, Optional, Tuple
@ -379,6 +380,14 @@ def _build_system_prompt(
wd_path = "/workspace"
else:
wd_path = str(wd_abs)
# 渲染器调用命令按 backend 换:docker 是容器内 bind 的 /sandbox 路径 + 容器 python;
# host(本地 dogfood)按宿主真实路径 + 当前解释器(venv,依赖齐)—— 否则 agent 拿着
# 容器路径在宿主上调,必 FileNotFoundError。skill 文档里的 /sandbox 写法是 docker
# 专属管线,不受此影响。
if is_docker:
render_cmd = "python /sandbox/rendering/render.py"
else:
render_cmd = f'"{sys.executable}" "{ROOT / "rendering" / "render.py"}"'
today = datetime.now().strftime("%Y-%m-%d")
tname = task_name or "<未指定>"
short_id = task_id.hex[:8]
@ -414,7 +423,7 @@ def _build_system_prompt(
f"**优先**把正文写成 Markdown(`<task_dir>/sections/*.md`,纯文本、零转义 / 零语法风险),"
f"再调平台渲染器出 docx —— **别在 run_python 里手撸 python-docx 内联大段中文正文**"
f"(中文引号 / 全角标点混进源码极易 SyntaxError、反复返工烧 token):\n\n"
f" python /sandbox/rendering/render.py --profile report --format docx <task_dir>/sections/ -o <task_dir>/<报告名>.docx\n\n"
f" {render_cmd} --profile report --format docx <task_dir>/sections/ -o <task_dir>/<报告名>.docx\n\n"
f"渲染器自动管字体(正文宋体小四 / 标题黑体 / 1.5 倍行距)、目录(加 `--toc`)、"
f"表格、`![](path)` 居中插图 + 图题编号、mermaid 图。已加载 proposal / paper 等 skill 时"
f"按其 render 指引的 profile 走(更具体),通用报告用 `--profile report`。\n"

View File

@ -241,9 +241,9 @@ def save_source(workspace_dir: Path, user_id: UUID, name: str, filename: str, da
_KB_CONTRACT = """\
用法规矩:
- **路由**:**材料学科学术文献**优先 `document_search`(院内共享大库);**用户自建
资料**(个人上传的规范 / 报告 / 标准 / 内部文档)用下面的知识库 先看各库 INDEX
条目定位, `read` 对应 `docs/*.md` 正文,量大时 `grep` 先缩范围
- **主动查阅**:回答前先扫一眼下方各库条目,标题 / 摘要 / 关键词与用户问题相关就先
`read` 对应 `docs/*.md` 正文再作答(量大时 `grep` 先缩范围)**无需用户点名
"知识库"** 用户资料里可能已有的内容,宁可多查一次,不要凭空回答
- **答题标来源**:引用了哪个库哪篇就在回答里注明(标题或文件名)
- **对话内入库**:用户在对话里给了值得长期留的资料时,可直接写入:原件放
`sources/`(没有原件就跳过)正文转成 markdown `docs/<slug>.md`再往该库