ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

仓颉Skill实战:用Python让AI自动整理本地文档

仓颉Skill实战:用Python让AI自动整理本地文档 把散落的资料文件交给 AI自动整理成你想要的格式这个场景听起来很诱人但真正落地时会遇到不少问题文件格式五花八门有 PDF、Word、TXT内容长短不一AI 怎么准确读取怎么让 AI 按照自己的业务要求输出而不是泛泛而谈本文从一个可运行的“仓颉 Skill”示例出发完整拆解把资料文件交给 AI 整理的实现思路包括文件解析、上下文构造、提示词模板设计、结构化输出和常见坑点全程配有可复制代码适合正在做 AI 应用开发、知识库整理和个人助理工具的同学参考。1. 什么是“仓颉 Skill”让 AI 读懂你的资料文件很多人在使用大模型时都有一个朴素的需求把自己手头的文档、报告、笔记、会议纪要交给 AI让它按照指定的模板整理成自己想要的样子。但直接粘贴文本往往受限于上下文长度而且不同文件的格式、版式、编码各不相同AI 拿到之后经常答非所问。“仓颉 Skill”本质上是一套面向文档整理场景的 AI 能力封装。仓颉是传说中创造文字的人物用这个名字来命名很形象地表达了“让机器理解和整理人类文字资料”的定位。具体来说它把下面几个环节串成一条完整链路文件接入读取本地资料文件支持 TXT、PDF、DOCX 等常见格式。内容清洗与切片去掉无效字符控制每次送入模型的文本长度。上下文组装把用户要求、文档内容和输出格式模板拼装成一次完整的模型请求。结构化输出让 AI 按照 JSON 或 Markdown 格式返回整理结果便于后续程序处理。复用与扩展把整套逻辑封装成 Skill下次遇到类似任务直接调用。从产品形态上看Skill 可以理解成一个“带输入输出规范的提示词模板 配套处理函数”。它比单纯写 prompt 更工程化也比直接调 API 更贴近业务场景。这个方案适合谁来用需要批量整理本地文档的个人用户。正在搭建企业知识库、资料归档系统的后端开发者。想给自己的 AI 助手增加“读文件”能力的应用开发者。对提示词工程感兴趣想了解如何让 AI 输出稳定格式的初学者。下面我们直接进入实战打造一个可以运行的仓颉 Skill 最小系统。2. 环境准备与版本说明本文示例以 Python 3.10 以上版本为例操作系统不限Windows、macOS、Linux 都可以。核心依赖如下依赖库用途openai调用大模型接口pypdf解析 PDF 文件python-docx解析 Word 文档tiktoken估算 Token 数量控制上下文长度安装命令pip install openai pypdf python-docx tiktoken版本需要根据你的项目实际情况调整本文重点演示配置思路。以 OpenAI 兼容接口为例你既可以使用官方 OpenAI API也可以使用各类国内大模型的 OpenAI 兼容端点。关键配置项如下import os os.environ[OPENAI_API_KEY] 你的 API Key os.environ[OPENAI_BASE_URL] https://api.example.com/v1如果你只是本地测试建议准备一份几百字到几千字的 TXT 文件先跑通流程再逐步换成 PDF 和 Word 文件测试。3. 核心原理拆解从文件到 AI 输出的完整链路在写代码之前我们先把核心原理讲清楚。很多人以为“把文件交给 AI”就是把文件内容直接用read()读出来然后传给模型实际上中间还有很多细节。3.1 文档读取为什么不能一刀切不同格式的文件读取方式完全不同TXT 文件直接用open()读取但要处理编码问题常见utf-8、gbk。PDF 文件内容可能包含文本层也可能是扫描图片pypdf 只能读取文本层内容。Word 文件后缀为.docx时可以用 python-docx 解析段落、表格后缀为.doc的旧格式则需要额外转格式。Markdown/HTML需要去掉标记符号只保留正文文本。读取文件的核心目标是把“视觉上能看到的内容”尽可能完整地转化为纯文本。表格、列表、标题层级如果能保留下语义信息AI 的整理效果会更好。3.2 为什么需要 Token 截断大模型输入长度是有限的。一个几千页的 PDF 不可能一次性全部塞给模型。因此必须对文本进行截断或切片。不同模型上下文长度差别很大比如常见的 8K、32K、128K 上下文模型。为了不写死模型参数我们引入tiktoken来估算 Token 数量import tiktoken def count_tokens(text: str, model: str gpt-4) - int: try: encoding tiktoken.encoding_for_model(model) except KeyError: encoding tiktoken.get_encoding(cl100k_base) return len(encoding.encode(text))这段代码会返回文本对应的 Token 数。如果文本超过我们设定的阈值就按比例截断或者分段多次调用模型。3.3 Skill 的核心提示词模板所谓“整理出你想要的”关键不在于读文件而在于让 AI 清楚知道“你想要什么”。仓颉 Skill 的做法是维护一套结构化提示词模板包括系统角色指令“你是一名专业的资料整理助手……”用户任务描述“请根据下面的文档内容整理出关键信息摘要。”输出格式要求“请使用 Markdown 格式输出包含核心观点、关键数据、待办事项。”提示词模板需要做到明确任务边界防止 AI 自由发挥。给出输出示例让格式稳定。如果原始文档太短要求 AI 做出判断而不是强行编造。3.4 结构化输出JSON 解析与容错如果后续程序需要处理 AI 的返回结果最好让 AI 输出 JSON。但大模型偶尔会在 JSON 前后添加解释性文字导致解析失败。所以解析时要加上容错逻辑import json import re def parse_json_response(text: str) - dict: # 去掉可能的代码块标记 text text.strip() if text.startswith(): text re.sub(r^(?:json)?, , text).strip() text text.rstrip().strip() try: return json.loads(text) except json.JSONDecodeError: # 尝试提取第一个 { 到最后一个 } start text.find({) end text.rfind(}) if start ! -1 and end ! -1: return json.loads(text[start:end 1]) raise ValueError(无法从模型输出中解析 JSON)这是个很实用的容错函数后面代码中会直接用到。4. 完整实战案例把资料文件交给 AI 整理现在我们把上面的原理组合成一个可以运行的项目。这个项目名称就叫cangjie_skill读取指定目录下的资料文件调用大模型整理并输出一份 Markdown 格式的整理报告。4.1 创建项目结构cangjie_skill/ ├── main.py # 主入口 ├── readers.py # 文件读取模块 ├── skill.py # 仓颉 Skill 核心逻辑 ├── output/ # 输出目录 └── docs/ # 存放待整理资料4.2 编写文件读取模块新建readers.py# 文件路径cangjie_skill/readers.py from pathlib import Path from typing import List def read_txt(path: Path) - str: 读取 TXT 文件自动处理常见编码 for encoding in [utf-8, gbk, utf-8-sig]: try: return path.read_text(encodingencoding) except UnicodeDecodeError: continue raise UnicodeDecodeError(f无法识别文件编码: {path}) def read_pdf(path: Path) - str: 读取 PDF 文件提取文本层内容 from pypdf import PdfReader reader PdfReader(str(path)) texts [] for page in reader.pages: page_text page.extract_text() if page_text: texts.append(page_text) return \n.join(texts) def read_docx(path: Path) - str: 读取 Word 文档提取段落和表格文本 from docx import Document doc Document(str(path)) parts [] for para in doc.paragraphs: if para.text.strip(): parts.append(para.text) for table in doc.tables: for row in table.rows: row_text | .join(cell.text.strip() for cell in row.cells) parts.append(row_text) return \n.join(parts) def load_document(file_path: str | Path) - str: 根据文件后缀分发到对应解析函数 path Path(file_path) suffix path.suffix.lower() if suffix .txt: return read_txt(path) elif suffix .pdf: return read_pdf(path) elif suffix .docx: return read_docx(path) else: raise ValueError(f暂不支持的文件格式: {suffix})这段代码的关键点TXT 读取时尝试多编码兼容 Windows 下常见的 GBK 文件。PDF 解析依赖文件本身存在文本层扫描版 PDF 需要使用 OCR 方案。Word 表格中用|拼接单元格AI 能更好理解表格结构。4.3 编写文件加载与切片工具一个文件可能很长我们需要把它拆成长度合适的片段。新建skill.py时加入切片逻辑# 文件路径cangjie_skill/skill.py import os from pathlib import Path from typing import List, Optional from readers import load_document import tiktoken class CangjieSkill: 仓颉 Skill读取资料文件并按照用户要求整理 def __init__( self, api_key: Optional[str] None, base_url: Optional[str] None, model: str gpt-4o-mini, max_tokens: int 12000, ): self.api_key api_key or os.environ.get(OPENAI_API_KEY) self.base_url base_url or os.environ.get(OPENAI_BASE_URL) self.model model self.max_tokens max_tokens self.client self._create_client() def _create_client(self): try: from openai import OpenAI return OpenAI(api_keyself.api_key, base_urlself.base_url) except ImportError: raise RuntimeError(请先安装 openai 库pip install openai) staticmethod def _count_tokens(text: str, model: str gpt-4o-mini) - int: try: encoding tiktoken.encoding_for_model(model) except KeyError: encoding tiktoken.get_encoding(cl100k_base) return len(encoding.encode(text))4.4 编写仓颉 Skill 核心处理函数在skill.py中继续添加核心方法。核心思路是先读取文件再把文件内容组装进用户消息让模型返回整理结果。def organize( self, file_path: str | Path, instruction: str, output_format: Optional[str] None, ) - str: 整理单个资料文件 :param file_path: 资料文件路径 :param instruction: 用户希望 AI 怎么整理例如“提取核心观点” :param output_format: 输出格式要求例如“Markdown 表格” :return: AI 返回的整理结果 path Path(file_path) if not path.exists(): raise FileNotFoundError(f文件不存在: {path}) # 1. 读取资料内容 content load_document(path) if not content.strip(): raise ValueError(f文件内容为空或无法提取文本: {path}) # 2. 控制上下文长度 content self._truncate_content(content) # 3. 组装提示词 system_prompt ( 你是一名专业的资料整理助手负责阅读用户提供的资料 并按照要求输出整理结果。你输出的内容需要忠实于原文 不要编造原文中没有的信息。 ) format_instruction output_format or 请使用清晰的 Markdown 结构输出。 user_prompt f请阅读以下资料文件内容并按照要求进行整理。 【用户整理要求】 {instruction} 【输出格式要求】 {format_instruction} 【资料文件名】 {path.name} 【资料内容开始】 {content} 【资料内容结束】 请根据用户要求输出整理结果。 # 4. 调用模型 response self.client.chat.completions.create( modelself.model, messages[ {role: system, content: system_prompt}, {role: user, content: user_prompt}, ], temperature0.3, ) return response.choices[0].message.content def _truncate_content(self, content: str) - str: 根据最大 Token 数截断文本保留开头和结尾 token_count self._count_tokens(content, self.model) if token_count self.max_tokens: return content # 简单按字符比例截断保留前 60% 和后 40% 的关键信息 char_ratio self.max_tokens / token_count keep_chars int(len(content) * char_ratio) head content[: int(keep_chars * 0.6)] tail content[-int(keep_chars * 0.4):] return head \n...[内容过长已截断]...\n tail这里有一个细节值得展开_truncate_content为什么保留开头和结尾而不是中间因为很多文档的摘要和结论往往出现在开头或结尾。开头通常是背景、目标、执行摘要结尾通常是结论、建议、下一步行动这两部分对整理任务价值最高。当然这种方式并不完美更严谨的做法是使用文本分割器按语义进行切片再分段调用模型但作为最小可用方案保留首尾已经能满足大多数场景。4.5 批量处理多个文件实际使用中我们大概率会有多份资料需要整理。在skill.py中继续添加批量方法def organize_many( self, file_paths: List[str | Path], instruction: str, output_format: Optional[str] None, ) - str: 批量整理多个文件合并生成一份总体报告 :param file_paths: 文件路径列表 :param instruction: 用户整理要求 :param output_format: 输出格式 :return: 合并后的整理报告 all_parts [] for path in file_paths: single_result self.organize(path, instruction, output_format) all_parts.append(f## 文件{Path(path).name}\n\n{single_result}) return \n\n---\n\n.join(all_parts)4.6 编写主入口文件新建main.py# 文件路径cangjie_skill/main.py import argparse from pathlib import Path from skill import CangjieSkill def main(): parser argparse.ArgumentParser(description把资料文件交给 AI 整理) parser.add_argument(--dir, typestr, defaultdocs, help资料目录) parser.add_argument(--instruction, typestr, default提取每份资料的核心观点、关键数据和待办事项并汇总成报告。) parser.add_argument(--format, typestr, default使用 Markdown 输出包含表格。) parser.add_argument(--model, typestr, defaultgpt-4o-mini) args parser.parse_args() # 获取目录下所有支持的文件 dir_path Path(args.dir) supported_suffixes [.txt, .pdf, .docx] file_paths [ p for p in dir_path.iterdir() if p.is_file() and p.suffix.lower() in supported_suffixes ] if not file_paths: print(f目录 {dir_path} 下没有找到支持的文件) return print(f共发现 {len(file_paths)} 个文件开始整理...) skill CangjieSkill(modelargs.model) report skill.organize_many(file_paths, args.instruction, args.format) # 输出结果 output_dir Path(output) output_dir.mkdir(exist_okTrue) output_path output_dir / 整理报告.md output_path.write_text(report, encodingutf-8) print(f整理完成报告已保存到: {output_path}) if __name__ __main__: main()4.7 运行与验证在docs目录下放几份测试资料然后运行python main.py --instruction 提取每份资料的核心观点、关键数据和待办事项并汇总成报告。预期输出共发现 3 个文件开始整理... 整理完成报告已保存到: output/整理报告.md打开output/整理报告.md你应该能看到类似下面的结构## 文件项目计划书.txt ### 核心观点 - 项目目标是在三个月内上线核心功能。 ### 关键数据 | 指标 | 数值 | | --- | --- | | 用户目标 | 10 万 | | 预算 | 200 万 | ### 待办事项 - [ ] 完成需求文档评审 - [ ] 搭建开发环境不同模型对 Markdown 的渲染风格可能略有差异但整体结构应该是一致的。5. 常见问题与排查思路跑通第一个版本后你大概率会遇到下面一些典型问题。问题现象常见原因解决思路PDF 文件读取后内容为空PDF 是扫描件没有文本层先做 OCR 识别或更换含文本层的 PDF中文乱码文件编码不是 UTF-8readers.py 中已尝试多编码读取若仍乱码手动指定 encoding 参数提示文件不存在路径使用相对路径但当前工作目录不对打印Path.resolve()确认实际路径模型返回“内容过长”文本截断后仍超过模型上下文调低max_tokens分段调用模型后合并结果JSON 解析失败模型输出了额外解释文字使用parse_json_response做容错解析接口调用报 401API Key 配置不正确检查环境变量是否生效base_url 是否与模型服务商匹配输出内容与原文不符temperature 设置过高将 temperature 降到 0.2 到 0.3提升事实忠实度5.1 PDF 提取不到文本怎么办扫描版 PDF 非常常见。pypdf 只能读取数字型 PDF 的文本内容对于扫描件需要使用 OCR 工具比如 Tesseract、PaddleOCR或者云厂商的文档识别接口。在整条链路中OCR 返回的是纯文本后续处理方式完全一样。5.2 长文档如何完整处理如果文档特别长简单的截断会遗失中间内容导致整理结果不完整。更可靠的方案是把文档拆成多个片段分别调用模型然后使用第二次汇总调用把各片段的关键信息合并成最终报告。这本质上是一个 Map-Reduce 结构Map 阶段对每个片段独立调用模型提取关键信息。Reduce 阶段把所有片段的提取结果合并调用模型生成最终报告。这种方案会增加 API 调用次数和成本但能保证信息覆盖度。5.3 如何让 AI 按固定 JSON Schema 输出如果整理结果需要直接对接业务系统建议在提示词中给出明确的 JSON Schema 示例请严格按以下 JSON 格式输出 { summary: 一段话总结, key_points: [要点1, 要点2], action_items: [待办1, 待办2] }注意不同模型对 JSON Schema 的理解能力有差异。如果稳定性要求很高可以使用支持 Function Calling 或 Structured Output 特性的模型接口这样模型会按照接口定义的输出结构返回而不是靠提示词约束。6. 最佳实践与工程建议从“能跑”到“好用”中间还差几步工程化打磨。下面几条建议来自实际落地经验。6.1 使用 Skill 配置化而不是硬编码仓颉 Skill 的价值在于复用。提示词不应该散落在代码里而是应该以配置形式存放例如使用 YAML 或 JSON 文件# 文件路径cangjie_skill/skills/report_skill.yaml name: report_skill description: 用于生成周报/月报的整理技能 system_prompt: 你是一名专业的业务分析师负责从多份资料中提取关键信息。 user_template: | 请根据以下资料整理周报 【资料内容】 {content} 【周报格式】 {format}代码中只需要读取模板替换变量就可以复用不同场景from string import Template template Template(skill_config[user_template]) prompt template.substitute(contentcontent, formatformat_instruction)这样做的好处是不懂代码的业务人员也能通过修改配置文件来调整 AI 行为而不是每次都改代码。6.2 记录 Token 消耗与调用日志在大模型应用中日志非常重要。建议每次调用模型前记录输入 Token 数调用后记录输出 Token 数和耗时import time start time.time() response self.client.chat.completions.create(...) elapsed time.time() - start print({ model: self.model, input_tokens: response.usage.prompt_tokens, output_tokens: response.usage.completion_tokens, elapsed_ms: round(elapsed * 1000, 2), })如果你用的是企业级应用建议把日志输出到独立的日志文件或日志中心方便后续进行成本核算和效果评估。6.3 文件解析失败不要直接崩溃批量整理资料时单个文件解析失败不应该拖垮整个流程。建议在主流程中加异常捕获把失败文件记录下来跳过继续处理failed_files [] success_reports [] for path in file_paths: try: report skill.organize(path, instruction, output_format) success_reports.append(f## 文件{path.name}\n\n{report}) except Exception as e: failed_files.append((str(path), str(e))) if failed_files: print(以下文件处理失败) for f, err in failed_files: print(f- {f}: {err})6.4 敏感信息与越权风险把资料文件交给 AI 之前一定要确认以下几点该文件是否包含个人隐私、商业机密、内部数据。是否允许将内容发送到第三方大模型服务。如果文件敏感优先使用私有化部署模型或本地模型。在企业环境中推荐把文件读取、AI 调用、结果存储三个环节都加上审计日志且遵循最小权限原则只给应用开放必要的文件目录读取权限。6.5 考虑缓存机制如果相同的文件被反复整理例如每周提交周报时都基于同一份项目文档建议对结果做缓存。缓存 key 可以使用“文件哈希 指令哈希 模型名称”避免重复调用 API降低成本和时延。import hashlib def generate_cache_key(file_path: str, instruction: str, model: str) - str: content_hash hashlib.md5(Path(file_path).read_bytes()).hexdigest() instruction_hash hashlib.md5(instruction.encode(utf-8)).hexdigest() return f{content_hash}_{instruction_hash}_{model}7. 总结与下一步学习路线这篇文章从“把资料文件交给 AI让他整理出你想要的”这个场景出发完整实现了一个可运行的仓颉 Skill。我们梳理了以下关键环节多种格式文件的读取与清洗Token 估算与上下文的截断策略提示词模板的设计与组装调用大模型完成整理任务结果输出与常见错误容错批量处理与工程化优化思路。如果你想继续深入可以从三个方向迭代文本分割优化引入真正的语义切片器例如按标题、段落边界切分文档而不是简单按字符比例截断。多轮对话式整理用户可以在第一次结果基础上追问细节而不是一次性提完所有要求。Agent 化改造让 Skill 支持自动决定读取哪些文件、调用哪些工具例如让 AI 自己列出目录中的文件并决定优先级这就从“单个整理技能”演进成了“资料整理 Agent”。实际项目中优先关注的是信息完整性和调用成本。建议先用小规模文档跑通流程记录不同模型和不同提示词下的输出效果再逐步扩展到批量处理。AI 整理文档的上限由模型能力决定下限则由你输入的提示词和上下文管理决定。把本文中的代码跑起来再结合自己的业务场景调整系统提示词和输出格式你很快就能得到一套属于自己的资料整理助手。
返回列表