ARTICLE DETAIL

资讯详情

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

AI自写文档的工程实践:Python打造自动化文档生成系统

AI自写文档的工程实践:Python打造自动化文档生成系统 最近在整理 AI 工程相关议题时很多人都在转 Ethan Mollick 的一个观点AI 实验室应该自己写文档。他是沃顿商学院的教授长期研究人工智能对工作方式、教育模式和创新的影响。在公开讨论中他一直呼吁 AI 实验室提高模型信息披露的透明度其中一句核心主张让我印象很深——AI 实验室不该只依赖外部用户、媒体或第三方研究人员来解读模型而应该让 AI 系统自己参与到自身文档的生成与维护中。这句话乍一看像是管理建议但落到开发者视角它其实是一个非常具体的工程问题模型迭代越来越快行为边界越来越复杂人工维护技术文档往往是整个交付链条里最滞后、最容易失真的一环。Mollick 强调的并不是让 AI 写几段 README 文案而是希望“文档化”本身被纳入工程闭环让文档在模型更新、接口变化、行为调整的过程中同步更新。这篇文章就从技术实现角度来拆解这个命题。我会用 Python 构建一个最小的“AI 自写文档”系统扫描代码仓库、提取函数与类结构、通过大模型生成 Markdown 文档、再用校验模块拦截明显的格式问题和幻觉内容。整个流程跑通之后再讨论如何接入 CI/CD让文档随着代码提交自动更新。如果你正在搭建自己的 AI 项目文档流程或者想找一个适合练手 AI Agent 开发的小案例这篇文章应该能给你一套直接可用的思路。1. 从 Ethan Mollick 的呼吁说起AI 实验室为什么需要自写文档1.1 Mollick 的核心观点Ethan Mollick 长期关注 AI 对组织、教育和创新的影响。他在相关研究中经常提到一个问题大模型是一个行为不完全确定的系统外部人员很难通过几次测试就真正理解模型的能力边界。于是 AI 实验室需要更主动地披露信息而且这种披露不能只是发布一份静态的报告。所以他的观点里带有一个工程主张AI 应该自己写文档。这句话的深层含义是文档不应该依赖人工在发布之后慢慢补充而应该由系统基于训练配置、代码、评估结果自动生成并随版本更新。对于实验室内部开发者来说这等于把“文档维护”从一项体力活升级成一条自动化流水线。不过在把这个主张变成现实之前我们得先理解一个更基本的问题为什么传统的文档维护方式在 AI 项目里行不通。1.2 为什么“文档追着模型跑”会失控传统软件项目里接口和类通常是确定的文档变化速度相对可控。但大模型应用不同模型发布的节奏非常快而且模型的输出行为会受到提示词、采样参数、上下文长度甚至部署环境的影响。同一个接口在不同模型版本下可能返回不同格式同一个功能在不同温度参数下表现也可能差异很大。如果把文档维护完全交给人工会出现几种典型情况发布新模型时团队先写 API 文档和技术报告文档描述的是“预期行为”。用户很快发现实际行为和文档对不上于是通过社区提问、Issue 和实验反馈慢慢拼出模型的真实边界。等人工把反馈整理进文档模型已经又迭代了一个版本前面的信息再次过时。这种循环的本质是“信息生产速度跟不上系统变化速度”。AI 大模型生成文档的价值就是在信息产生的那一刻同步生成可用的描述文本而不是等外部反馈倒逼文档更新。1.3 这其实是一个 AI Agent 问题我们还可以把“AI 自写文档”放到 AI Agent 的语境里看。一个 Agent 通常需要具备目标拆解、工具调用和结果修正三种能力。让 AI 写文档恰好满足这些特征目标根据代码生成并维护一篇技术文档。工具读取源码、调用大模型接口、读取配置、输出 Markdown。循环生成 → 校验 → 发现不一致 → 重新生成或人工介入。所以设计一个文档自动生成工具本质上就是在设计一个精简的 Agent。这个思路可以继续延伸比如自动生成单元测试、自动生成变更日志、自动分析安全告警等。2. AI 自写文档核心概念与技术链路2.1 什么是“AI 自写文档”“AI 自写文档”在不同场景下有不同含义。面向普通用户它可能意味着让聊天机器人帮你写一篇周报或方案面向软件工程它指的是让 AI 根据代码仓库、接口定义和配置文件生成并维护技术文档而面向 AI 实验室它更接近让模型根据训练配置、评估指标、部署记录等内部信息生成模型卡Model Card和技术说明。本文要讨论的是后两者的结合文档被当作结构化产物由程序驱动大模型生产、校验和更新。这个定义有两个关键点。第一文档不是一次性生成的它需要随着代码变更持续更新。第二文档的质量不能只看自然语言是否通顺还要看它与代码事实是否一致。这也是“AI 写文档”和“AI 聊天代笔”最大的区别。在一个典型的项目里文档资产至少包括这几类API 文档接口路径、请求参数、响应格式、错误码。函数与类文档方法签名、输入输出、异常行为。模型文档训练数据范围、评估指标、已知限制。部署文档环境要求、启动命令、配置项说明。这些信息本质上都存在于代码、配置和日志中只是缺少一个把它转成规范文本的自动化过程。大模型擅长信息重组和文本生成所以“自写文档”在工程上是完全可行的。2.2 文档生成链路中的五个关键环节完整的文档生成链路可以拆成五步数据读取扫描代码仓库、配置文件、测试报告等原始材料。结构抽取从原始材料中提取可文档化的实体例如函数名、参数、类关系。文本生成把实体信息组织成上下文交给大模型生成规范文档。质量校验检查文档格式、内容完整度并拦截幻觉或占位符。发布回写把生成的文档写入项目目录或提交到文档站点。很多人容易忽略第二步。一开始我也想过直接把整个仓库内容丢给模型让它一口气生成文档。但实际效果很差大模型上下文窗口有限面对超长代码会截断Token 成本高输出结果容易发散很难控制格式。更稳妥的方式是先用 AST 或正则解析器做“冷处理”把仓库压缩成结构化的 JSON再让大模型基于这个“瘦身后”的信息生成文档。这样做既节省 Token也更容易保证准确性因为模型看到的是经过筛选的结构化事实而不是整片原始代码。2.3 为什么需要校验模块AI 生成内容的通病是“读起来像真的但不一定是对的”。文档场景里这种问题会被放大一篇技术文档如果描述了一个不存在的函数、一个错误的参数名或是一段本不该公开的内部路径后果可能比“没有文档”更严重。因此校验不是可选项而是文档链路中的强制关卡。校验规则可以从简单到复杂逐步建设简单规则文档是否为空、是否包含标题、是否含有“TODO”占位符。一致性规则文档中出现的函数名、参数名是否在源码中存在。语义规则文档描述的行为是否与代码实现一致。本文示例先实现简单规则但会说明如何扩展成更严格的一致性校验。3. 环境准备与技术选型3.1 运行环境本文示例基于 Python 开发建议使用 Python 3.10 及以上版本。依赖尽量精简只有两个第三方库httpx用于调用大模型的 HTTP 接口。PyYAML用于读取配置文件。操作系统不限Windows、macOS、Linux 都可以运行。如果你在本地测试需要一个兼容 OpenAI 协议的大模型推理服务常见选择有本地部署Ollama、vLLM、FastChat 等推理服务。云端 API各家大模型厂商提供的 OpenAI 兼容接入点。不用纠结具体品牌关键是三个参数能够配置化接口地址、API Key、模型名称。示例代码会用config.yaml管理这些内容方便切换不同服务。3.2 示例项目结构我们准备构建一个小工具目录结构如下ai-docs-lab/ ├── config.yaml # 模型与输出配置 ├── requirements.txt # Python 依赖 ├── llm_client.py # 大模型接口调用封装 ├── code_scanner.py # 代码结构扫描器 ├── doc_generator.py # 文档生成器 ├── validator.py # 文档校验器 └── main.py # 主流程项目不大但每个文件职责清楚。下面逐个文件实现。4. 构建最小“AI 自写文档”系统4.1 项目初始化与依赖先创建项目目录并安装依赖。mkdir ai-docs-lab cd ai-docs-lab在requirements.txt中写入httpx0.27 pyyaml6.0执行安装pip install -r requirements.txt4.2 配置模型接口创建config.yamlllm: base_url: http://localhost:11434/v1 api_key: EMPTY model: qwen2.5:7b docs: output_dir: output language: zh-CN配置项说明base_url大模型服务地址末尾不带多余斜杠。api_key如果服务不需要鉴权可以填 EMPTY。model模型名称需要与部署的服务保持匹配。output_dir生成文档的输出目录。如果使用云端服务把 base_url 和 api_key 替换成你自己的值即可。注意不要在代码里写死凭据生产环境建议从环境变量读取。4.3 编写代码结构扫描器code_scanner.py使用 Python 自带的ast模块解析代码。它的作用是把一个 Python 项目中的函数、类、方法提取成结构化字典供后续生成文档使用。扫描 Python 工程抽取可文档化的代码结构。 import ast from pathlib import Path def _extract_function_info(func_node: ast.FunctionDef) - dict: args [arg.arg for arg in func_node.args.args] docstring ast.get_docstring(func_node) return { type: function, name: func_node.name, args: args, docstring: docstring, lineno: func_node.lineno, } def _extract_class_info(cls_node: ast.ClassDef, path: str) - dict: methods [] for node in cls_node.body: if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)): methods.append(_extract_function_info(node)) docstring ast.get_docstring(cls_node) return { type: class, name: cls_node.name, methods: methods, docstring: docstring, lineno: cls_node.lineno, path: path, } def scan_python_codebase(root: str) - list[dict]: 递归扫描目录下的所有 .py 文件返回结构摘要列表。 items [] base_path Path(root) for py_file in sorted(base_path.rglob(*.py)): if venv in str(py_file) or .git in str(py_file): continue try: tree ast.parse(py_file.read_text(encodingutf-8)) except SyntaxError: continue rel_path str(py_file.relative_to(base_path)) for node in tree.body: if isinstance(node, ast.FunctionDef): item _extract_function_info(node) item[path] rel_path items.append(item) elif isinstance(node, ast.ClassDef): items.append(_extract_class_info(node, rel_path)) return items几个关键点需要说明ast.get_docstring()专门用来提取函数和类开头的文档字符串如果源码没有写 docstring它会返回None。函数参数只取了位置参数名没有处理默认值和复杂类型注解。对于文档生成来说参数名已经足够如果后续想更精确可以继续扩展。跳过venv和.git目录避免把第三方依赖也当作业务代码。你可以在自己的工程上运行这个模块输出是一个列表每个元素是一个 JSON 风格字典结构类似[ { type: class, name: UserService, methods: [ {type: function, name: register, args: [self, username, email], docstring: None, lineno: 5} ], docstring: 用户服务模块。, lineno: 4, path: user_service.py } ]4.4 编写大模型客户端llm_client.py封装对 OpenAI 兼容接口的调用。之所以直接用httpx而不是某个厂商 SDK是为了让代码在不同服务之间可以平滑切换。兼容 OpenAI 格式的大模型客户端封装。 import httpx DEFAULT_TIMEOUT 30.0 def chat_completion( messages: list[dict], *, base_url: str, api_key: str,
返回列表