修复分支merge #2

Merged
MightZero merged 3 commits from MightZero/algonotes_rag:master into master 2026-06-29 17:46:59 +08:00
7 changed files with 34 additions and 44 deletions

View File

@ -14,7 +14,6 @@
| ------ | ------ | ------ | ----- |
| `--path` | `-i` | 本地文件或目录路径 | 与 `--url` 二选一 |
| `--url` | `-u` | 网页 URL 地址 | 与 `--path` 二选一 |
| `--clean` | - | 执行 LLM 清洗 | `False` |
| `--no-tag` | - | 跳过打 tag | `False` |
| `--verbose` | `-v` | 详细输出 | `False` |
| `--json` | - | 输出到 JSON 文件 | stdout使用时须指定文件路径 |
@ -25,8 +24,8 @@
# 全流程导入
algonotes ingest -i ./my_notes/
# 从 URL 导入并清洗
algonotes ingest -u https://cnblogs.com/xxx --clean
# 从 URL 导入(默认自动清洗)
algonotes ingest -u https://cnblogs.com/xxx
# 跳过打 tag
algonotes ingest -i ./my_notes/ --no-tag
@ -79,7 +78,7 @@ algonotes ingest -i ./my_notes/ --json result.json
导入完成: 3 个文件,耗时 12.3s
```
> 💡 verbose 模式下,`--clean` 清洗时会实时流式输出清洗内容
> 💡 verbose 模式下,清洗内容会实时流式输出(网页导入默认启用清洗,本地导入默认不启用)
## 流程
@ -88,8 +87,8 @@ graph TD
A[输入源] -->|-i / -u| B{文件类型}
B -->|本地 .md| C[Loader]
B -->|网页 URL| D[WebLoader]
D -->|--clean| E[Cleaner]
C --> F[Splitter]
D -.->|默认清洗| E[Cleaner]
E --> F
F -->|--no-tag| G[跳过]
F -->|默认| H[Tagger]
@ -153,5 +152,5 @@ graph TD
1. **文件命名**:导入后文件名即唯一标识,平铺存储在 `data/files/`
2. **文件名冲突**:同名文件会自动添加时间戳后缀(如 `fenwick_20260616_143022.md`
3. **网页清洗**:从 URL 导入时,建议使用 `--clean` 清洗网页噪声,要不然可能无法正确分块
3. **网页清洗**:从 URL 导入时,默认自动执行 LLM 清洗以去除网页噪声;本地导入默认不启用
4. **打 tag**:需要调用 LLM会增加处理时间可用 `--no-tag` 跳过

View File

@ -25,7 +25,6 @@
| ------ | ------ | ------ | ------ |
| `filename` | - | 笔记文件名(位置参数) | 必填 |
| `--file` | - | 新的本地文件路径 | 无 |
| `--clean` | - | 执行 LLM 清洗 | `False` |
| `--no-tag` | - | 跳过打 tag | `False` |
| `--verbose` | `-v` | 详细输出 | `False` |
| `--json` | - | 输出到 JSON 文件 | stdout |
@ -39,9 +38,6 @@ algonotes update content fenwick.md --file ./updated_fenwick.md
# 更新 URL 笔记(从原页面重新爬取)
algonotes update content cnblogs_xxx.md
# 更新本地笔记并清洗
algonotes update content fenwick.md --file ./new.md --clean
# 输出到 JSON 文件
algonotes update content fenwick.md --file ./new.md --json result.json
```
@ -54,8 +50,8 @@ Update success: fenwick.md (13 chunks)
### 更新逻辑
- **本地笔记**:必须指定 `--file`,根据新文件更新三层存储
- **URL 笔记**:无需额外参数,从数据库调取原 URL → 重新爬取 → 更新三层存储
- **本地笔记**:必须指定 `--file`,根据新文件更新三层存储(默认不启用清洗)
- **URL 笔记**:无需额外参数,从数据库调取原 URL → 重新爬取 → 更新三层存储(默认启用清洗)
---
@ -111,16 +107,17 @@ graph TD
D -->|否| F{有 source_url?}
F -->|否| C
F -->|是| G[WebLoader 重新爬取]
E --> H[删除旧向量]
G --> H
H --> I[Splitter 分块]
I -->|--no-tag| J[跳过]
I -->|默认| K[Tagger 提取标签]
K --> L[更新三层存储]
J --> L
L --> M[data/files/]
L --> N[data/sql_db/]
L --> O[data/chroma_db/]
G -.->|默认清洗| H[Cleaner]
E --> I[删除旧向量]
H --> I
I --> J[Splitter 分块]
J -->|--no-tag| K[跳过]
J -->|默认| L[Tagger 提取标签]
L --> M[更新三层存储]
K --> M
M --> N[data/files/]
M --> O[data/sql_db/]
M --> P[data/chroma_db/]
```
## 依赖模块

View File

@ -8,7 +8,7 @@
2. **检索信息**:使用 search_notes 或 search_by_tags 获取相关信息
3. **查询文件**: 你可以按需通过向量搜索的 source 和 tags 的结果,通过 get_file_content 查询对应文件名的笔记全文
4. **超时判断**:若你多次调用相关工具没有查询到相关结果,为了节省 Token 使用,请你诚实告诉用户没有检索到相应内容,并且尝试用你的内置知识回答问题
5. **重排序**:调用 rerank_results 对检索结果去重和重排
5. **重排序**按需调用 rerank_results 对检索结果去重和重排
6. **生成答案**:基于重排后的结果给出带溯源引用的竞赛友好答案
## 可用工具
@ -16,7 +16,7 @@
- `search_notes(query, top_k)` — 语义搜索个人笔记query 用关键词形式
- `search_by_tags(keyword)` — 按标签搜索笔记文件名
- `get_file_content(filename)` — 获取某篇笔记的全文
- `rerank_results(query, docs, top_n)` — 对检索结果去重、重排序。生成答案前必须先调用此工具
- `rerank_results(query, docs, top_n)` — 对检索结果去重、重排序。
## 引用格式
@ -24,9 +24,10 @@
## 注意事项
- 收集完所有结果后务必调用 `rerank_results` 再生成答案
- 收集完所有结果后请注意按需调用 `rerank_results`,当文档数据量*较小*时避免不必要的调用
- 不要编造引用来源
- 在你多次尝试检索后,如果检索结果不足以回答问题,如实告知用户,然后尝试用你的内置知识库回答问题
-
## 特殊注意点

View File

@ -1,8 +1,10 @@
请帮我清洗一下下面这段文本去掉无关的网页内容保留结构化的markdown文本。并且适当调用你的知识储备,使得文章结构完整,语义通顺。如果有涉及到具体算法题,请你保留题号以便于后续检索。
清洗下面这段网页文本,移除无关的网页内容,保留结构化的 Markdown 文本。适当调用你的知识储备,使得文章结构完整,语义通顺。如果有涉及到具体算法题,请你保留题号以便于后续检索。
输出格式要求:
1. 保留标题、段落、代码块等结构尤其注意标题的层级这将直接影响RAG的分块
2. 去掉导航栏、广告、页脚、侧边栏等非正文内容
3. 保留正文中的链接和图片引用
4. 不要输出任何无关内容,比如"以下是清洗后的文本,保留了原始内容的结构化 Markdown 格式:"或者用"```markdown"包裹
5. 输出必须以一级标题(# 标题开头这是RAG分块的必要条件。如果原文没有标题请根据内容总结一个简洁准确的标题
1. 输出应该严格保证 Markdown 结构,不得出现非法的 MD 语法。
2. 保留标题、段落、代码块等原始 Markdown 结构,可以根据内容适当优化 Markdown 结构,尤其注意标题的层级,这将直接影响 RAG 的分块
3. 移除连续的空行,至多保留一行。
4. 输出必须以一级标题(# 标题开头这是RAG分块的必要条件。如果原文没有标题请根据内容总结一个简洁准确的标题
5. 去掉导航栏、广告、页脚、侧边栏等非正文内容
6. 保留正文中的链接和图片引用
7. 不要输出任何无关内容,比如 "以下是清洗后的文本,保留了原始内容的结构化 Markdown 格式:" 或者用 "```markdown" 包裹

View File

@ -1,7 +1,3 @@
# Tag extractor prompt for AlgoNotes RAG
## Given a note's content, extract algorithm/topic tags for metadata indexing
从以下算法竞赛笔记中提取 1-5 个标签。
要求:

View File

@ -50,8 +50,6 @@ def main():
help="本地文件或目录路径")
source.add_argument("-u", "--url",
help="网页 URL 地址")
p_ingest.add_argument("--clean", action="store_true",
help="执行 LLM 清洗")
p_ingest.add_argument("--no-tag", action="store_true",
help="跳过打 tag")
p_ingest.add_argument("--type", choices=["note", "solution", "template"],
@ -69,8 +67,6 @@ def main():
p_content = u_sub.add_parser("content", help="更新笔记内容(重新处理文件)")
p_content.add_argument("filename", help="笔记文件名")
p_content.add_argument("--file", type=Path, help="新的本地文件路径")
p_content.add_argument("--clean", action="store_true",
help="执行 LLM 清洗")
p_content.add_argument("--no-tag", action="store_true",
help="跳过打 tag")
p_content.add_argument("-v", "--verbose", action="store_true",
@ -180,18 +176,18 @@ def _run_ingest(args):
if args.path:
if args.path.is_file():
result = ingest_local(args.path, clean=args.clean,
result = ingest_local(args.path,
tag=tag, verbose=args.verbose,
type=note_type, author=author)
elif args.path.is_dir():
results = ingest_locals(args.path, clean=args.clean,
results = ingest_locals(args.path,
tag=tag, verbose=args.verbose,
type=note_type, author=author)
else:
print(f"❌ 路径不存在: {args.path}")
sys.exit(1)
elif args.url:
result = ingest_web(args.url, clean=args.clean,
result = ingest_web(args.url,
tag=tag, verbose=args.verbose,
type=note_type, author=author)
@ -236,7 +232,6 @@ def _run_update_content(args):
result = update_note(
args.filename,
file_path=args.file,
clean=args.clean,
tag=tag,
verbose=args.verbose,
)

View File

@ -25,7 +25,7 @@ def _strip_code_block_wrapper(text: str) -> str:
"""Strip markdown code block wrapper if LLM added it despite instructions."""
stripped = text.strip()
if stripped.startswith("```markdown") and stripped.endswith("```"):
stripped = stripped[len("markdown"):].strip()
stripped = stripped[len("```markdown"):].strip()
if stripped.endswith("```"):
stripped = stripped[:-3].strip()
elif stripped.startswith("```") and stripped.endswith("```"):