-
Notifications
You must be signed in to change notification settings - Fork 603
Description
我目前基于v0.5 做了【内置分块策略】、【“API 进程内直接执行对话流”重构为“异步任务执行 + SSE 增量拉取”】、【Skills 管理】几个功能。 @xerrors 麻烦看下这些功能描述,提供一些建议,是否采纳。
这几个功能代码 我已经提交到我 fork 的仓库了
https://github.com/1165506270/Yuxi-Know/tree/main
1) 内置分块策略(Built-in Chunking Presets)
为什么做
当前文档类型差异大(通用文档、问答文档、书籍章节、法规条款),单一切分方式会导致召回稳定性不足。
平台将分块能力产品化为“预设策略”,让用户在不理解底层算法细节的情况下,按文档类型选择合适切分方式并提升检索效果。
交互过程
用户在创建/编辑知识库时选择分块策略:general、qa、book、laws。
文件入库时默认继承知识库策略,也支持本次入库覆盖策略。
每个文件会记录本次实际使用的策略与参数快照(便于追溯与复现)。
切换知识库策略后,仅影响后续新入库文件,不自动重跑历史文件。
实现思路
参考 RAGFlow
在分块链路中引入统一调度器(ragflow-like dispatcher),按 chunk_preset_id 分发到对应解析流程。
策略映射对齐 RAGFlow:general -> naive,qa/book/laws 使用各自专用解析逻辑。
参数按固定优先级合并:请求参数 > 文件已有处理参数 > 知识库参数 > 预设默认参数。
不新增表:
知识库维度使用 knowledge_bases.additional_params 保存默认策略;
文件维度使用 knowledge_files.processing_params 保存实际执行快照(chunk_preset_id、chunk_parser_config、chunk_engine_version)。
2) 断线续流输出(Streaming Resume,Run + SSE)
为什么做
- 原先“HTTP 直连流”模式下,前端离开对话页面任务就会中断, 长任务场景下体验不友好。
- 目标是实现“前端可断开重连,但后台任务继续执行”,并支持从断点补流。
重构改动(核心架构变化)
- 将“API 进程内直接执行对话流”重构为“异步任务执行 + SSE 增量拉取”。
- 新增
worker容器,专门负责执行 run(LangGraph / LLM / tools)。 api容器不再承担长时执行,改为:- 创建 run
- 提供 run 状态查询
- 提供 SSE 增量事件流
- 接收 cancel 请求
- 运行基础设施职责划分:
- Redis:任务队列、取消信号、短期事件流(Redis Stream)
- Postgres:
agent_runs状态机、messages/tool_calls最终落库、checkpointer 持久化
交互过程
- 客户端调用
POST /api/chat/agent/{agent_id}/runs创建任务,拿到run_id。 - 客户端调用
GET /api/chat/runs/{run_id}/events?after_seq=...建立 SSE。 - worker 从队列消费
run_id,执行任务并持续写入增量事件。 - 前端实时消费事件并记录最新
seq。 - 若连接中断,前端自动重连并带上
after_seq=last_seq。 - 服务端按游标补发缺失事件,再继续实时推送。
- run 终态后发送
close,前端收尾并刷新历史消息/状态。
分块与续流策略(当前实现)
- worker 对增量文本做分块写入,flush 条件:
- 每
100ms,或 - 累计
512字符
- 每
- 分块事件以
loading形式输出(payload.items)。 - SSE 端按
after_seq从 Redis Stream 增量读取。 - 前端做
seq单调门禁:seq <= runLastSeq直接丢弃,避免重复渲染。 - 空闲连接发送 heartbeat;终态时补发剩余事件后发送
close。
用户侧效果
- 页面刷新/离开后,不需要重新提问。
- 回来后可从中断点继续显示输出。
- 任务本身不会因为前端离开而被动取消(仅显式 cancel 才中断)。
3)Skills 管理
Skills 管理模块用于集中维护可供 Agent 只读引用的技能包。
本期采用“文件系统存内容,数据库存索引”模式:
- 技能目录存储在
/app/saves/skills(本地save_dir/skills)。 - 技能元数据(slug/name/description/dir_path)存储在
skills表。 - Agent 配置通过
context.skills选择技能,运行时挂载到/skills且只读。
权限与入口
- 系统设置中新增
Skills 管理页签(仅superadmin可见)。 admin仅可调用列表接口(用于 Agent 配置选择 skills)。user无 skills 管理权限。
导入规范(ZIP)
- 单包单技能,且必须包含一个
SKILL.md。 SKILL.md必须包含 frontmatter,且name、description必填。name需满足 slug 规则:小写字母/数字/短横线。- 导入时执行路径安全校验,拒绝绝对路径与
..路径穿越。 - slug 冲突时自动追加
-v2/-v3...,并自动改写SKILL.md中name为最终 slug。 - 导入采用临时目录 + 原子替换,避免半成品落盘。
在线管理能力
- Skills 列表:来自数据库,避免全量目录扫描。
- 目录树:按原生目录结构展示。
- 文件级 CRUD:支持新建文件/目录、编辑文本文件、删除文件/目录。
- 文件编辑仅允许文本类型(如 md/py/js/ts/json/yaml/toml/txt 等)。
SKILL.md保存后会重新解析,并同步更新数据库中的name/description。- 支持导出单个 skill 为 ZIP。
- 删除 skill 时会同时删除目录与数据库记录(硬删除)。
Agent 运行时行为
context.skills用于配置技能 slug 列表。- 运行时按会话构建
SkillResolver快照(同一会话首次构建,后续复用)。 - 运行时仅暴露快照中的可见 skills 到
/skills/<slug>/...。 /skills路径只读,不允许写入、编辑、上传。- 同会话内若
context.skills变化会触发快照重建。 - 后台修改 skills 内容后,已有会话不会自动刷新,需新会话或调整
context.skills才生效。
依赖类型说明
每个 skill 支持三类依赖,均在 Skills 管理页维护:
tool_dependencies:该 skill 需要的内置工具名列表。mcp_dependencies:该 skill 需要的 MCP 服务器名列表。skill_dependencies:该 skill 依赖的其他 skill slug 列表。
约束与语义:
- 依赖在保存时做合法性校验,不允许引用不存在的工具/MCP/skill。
skill_dependencies不允许包含自身。skill_dependencies按递归闭包生效,自动去重、去环、保序。
渐进式加载流程
系统不会在会话开始时一次性加载全部依赖,而是按阶段渐进加载:
阶段 1:会话启动前(构建 skill 可见集)
- 读取
context.skills作为用户显式选择的 skills(selected)。 SkillResolver递归展开skill_dependencies,得到visible_skills(selected + 依赖闭包)。- 把快照写入
runtime.context.skill_session_snapshot。 - 基于
visible_skills构建 skills prompt 段,并在abefore_agent预拼接到system_prompt。 /skills只挂载visible_skills,所以被依赖 skill 从会话首轮起即可被读取。
结论:skill_dependencies 是“会话启动即生效”的。
阶段 2:技能激活时(按需激活)
- Agent 通过
read_file读取/skills/<slug>/SKILL.md时,视为激活该 skill。 - 仅当
<slug>在skill_session_snapshot.visible_skills内,激活才被接受。 - 激活结果写入
activated_skills(去重保序)。
结论:只有“真正被读取并使用”的 skill 才会进入后续依赖注入计算。
阶段 3:后续模型轮次(注入工具与 MCP 依赖)
- 在
awrap_model_call中,基于activated_skills计算依赖闭包。 - 聚合闭包内 skill 的
tool_dependencies与mcp_dependencies。 - 仅把这些依赖工具/MCP 合并进本轮可用工具集。
tool_dependencies与mcp_dependencies是“激活后按需加载”的,不会在会话首轮全量注入。