DeepSeek-R1-Distill-Qwen-7B实战教程:Ollama部署AI自动化接口文档生成器
DeepSeek-R1-Distill-Qwen-7B实战教程:Ollama部署AI自动化接口文档生成器
你是不是也遇到过这样的烦恼?写代码的时候,接口文档总是拖到最后才补,要么就是写出来的文档和实际代码对不上。每次手动维护文档,不仅耗时耗力,还容易出错。要是能有个助手,自动帮你把代码里的接口信息提取出来,生成清晰规范的文档,那该多省事。
今天我就带你用DeepSeek-R1-Distill-Qwen-7B模型,在Ollama上搭建一个智能接口文档生成器。这个方案最大的好处就是简单——不需要复杂的配置,不需要深度学习背景,跟着步骤走,半小时内就能让AI帮你自动生成接口文档。
1. 为什么选择DeepSeek-R1-Distill-Qwen-7B做文档生成?
在开始动手之前,我们先聊聊为什么这个组合特别适合做接口文档生成。
1.1 模型特点:专为推理而生
DeepSeek-R1-Distill-Qwen-7B是个很有意思的模型。它来自DeepSeek-R1系列,这个系列最大的特点就是专门为推理任务设计。你可以把它理解成一个“爱思考”的AI。
传统的语言模型可能更擅长聊天、写文章,但DeepSeek-R1系列经过特殊训练,特别擅长分析问题、理解逻辑、按步骤推理。这对于接口文档生成来说简直是量身定做——它需要理解你的代码逻辑,分析接口参数,然后组织成结构清晰的文档。
1.2 为什么是7B版本?
你可能会问,为什么不用更大的32B版本?原因很简单:够用且高效。
- 7B模型在普通电脑上就能跑:不需要高端显卡,8GB内存的机器就能流畅运行
- 推理速度够快:生成一篇接口文档通常只需要几秒钟
- 效果足够好:对于文档生成这种任务,7B版本已经能给出很专业的结果
- 资源消耗小:不会占用你太多系统资源,可以边写代码边用
1.3 Ollama的优势:一键部署,开箱即用
Ollama是个神器,它把复杂的模型部署过程简化到了极致:
- 一条命令安装:不用折腾环境配置
- 自动下载模型:告诉它模型名字,它自己会下载
- 提供标准API:通过HTTP接口就能调用,方便集成到各种工具里
- 跨平台支持:Windows、Mac、Linux都能用
2. 环境准备与Ollama安装
好了,理论说完了,咱们开始动手。第一步是把Ollama装好。
2.1 安装Ollama
根据你的操作系统,选择对应的安装方式:
Windows用户: 直接去Ollama官网下载安装包,双击运行就行。安装完成后,你会在系统托盘看到Ollama的图标。
Mac用户: 打开终端,运行这个命令:
brew install ollama
Linux用户: 在终端里执行:
curl -fsSL https://ollama.com/install.sh | sh
安装完成后,打开终端输入ollama --version,如果能看到版本号,说明安装成功了。
2.2 拉取DeepSeek-R1-Distill-Qwen-7B模型
模型安装更简单,就一条命令:
ollama pull deepseek-r1:7b
这里有几个细节要注意:
- 模型名字是
deepseek-r1:7b,不是deepseek-r1-distill-qwen-7b - 第一次运行会下载模型文件,大概14GB左右,需要一些时间
- 下载进度会在终端显示,耐心等待完成
下载完成后,你可以验证一下:
ollama list
应该能看到deepseek-r1:7b在列表里。
2.3 启动模型服务
让模型在后台运行起来:
ollama run deepseek-r1:7b
第一次运行可能会稍微慢一点,因为要加载模型到内存。看到类似这样的输出,就说明准备好了:
>>> Send a message (/? for help)
现在模型已经在本地运行了,默认监听11434端口。你可以按Ctrl+C退出交互模式,但模型服务还在后台运行。
3. 快速体验:用Ollama WebUI测试模型
在写代码集成之前,我们先通过网页界面试试模型的效果,这样你能直观感受它的能力。
3.1 安装Ollama WebUI
Ollama自带了一个简单的网页界面,但功能比较基础。我推荐用开源的Open WebUI,功能更强大:
# 使用Docker安装(推荐)
docker run -d -p 3000:8080 \
-v open-webui:/app/backend/data \
--name open-webui \
--restart always \
ghcr.io/open-webui/open-webui:main
# 或者用Docker Compose
version: '3.8'
services:
open-webui:
image: ghcr.io/open-webui/open-webui:main
container_name: open-webui
ports:
- "3000:8080"
volumes:
- open-webui:/app/backend/data
restart: unless-stopped
volumes:
open-webui:
3.2 配置并测试模型
- 打开浏览器,访问
http://localhost:3000 - 第一次使用需要注册账号
- 登录后,在设置里添加Ollama后端地址:
http://host.docker.internal:11434 - 选择
deepseek-r1:7b模型
现在你可以直接跟模型对话了。试试让它分析一段简单的Python函数:
请分析以下Python函数,并生成接口文档:
def calculate_discount(price: float, discount_rate: float = 0.1) -> dict:
"""
计算商品折扣后的价格
Args:
price: 商品原价,必须大于0
discount_rate: 折扣率,范围0-1,默认0.1(9折)
Returns:
包含原价、折扣率、折后价和节省金额的字典
"""
if price <= 0:
raise ValueError("价格必须大于0")
if not 0 <= discount_rate <= 1:
raise ValueError("折扣率必须在0-1之间")
discount_amount = price * discount_rate
final_price = price - discount_amount
return {
"original_price": price,
"discount_rate": discount_rate,
"final_price": round(final_price, 2),
"saved_amount": round(discount_amount, 2)
}
你会看到模型不仅能理解函数功能,还能生成格式规范的文档,包括参数说明、返回值、异常情况等。
4. 构建自动化接口文档生成器
测试通过后,我们来构建一个实用的工具。这个工具要做三件事:
- 读取源代码文件
- 提取接口信息
- 调用AI生成文档
4.1 项目结构设计
先创建项目目录:
mkdir api-doc-generator
cd api-doc-generator
目录结构如下:
api-doc-generator/
├── src/
│ ├── __init__.py
│ ├── code_parser.py # 代码解析器
│ ├── doc_generator.py # 文档生成器
│ └── ollama_client.py # Ollama客户端
├── examples/ # 示例代码
├── requirements.txt # 依赖包
└── main.py # 主程序
4.2 安装依赖包
创建requirements.txt:
requests>=2.31.0
python-multipart>=0.0.6
fastapi>=0.104.0
uvicorn>=0.24.0
pydantic>=2.5.0
安装依赖:
pip install -r requirements.txt
4.3 实现Ollama客户端
创建src/ollama_client.py:
import requests
import json
from typing import Dict, Any, Optional
class OllamaClient:
def __init__(self, base_url: str = "http://localhost:11434"):
self.base_url = base_url
self.model = "deepseek-r1:7b"
def generate_documentation(self, code_snippet: str, context: str = "") -> str:
"""
调用Ollama生成接口文档
Args:
code_snippet: 要分析的代码片段
context: 额外的上下文信息
Returns:
生成的文档内容
"""
# 构建提示词
prompt = self._build_prompt(code_snippet, context)
# 调用Ollama API
response = self._call_ollama(prompt)
return response
def _build_prompt(self, code: str, context: str) -> str:
"""构建文档生成的提示词"""
prompt_template = """你是一个专业的API文档生成助手。请分析以下代码,生成详细、规范的接口文档。
要求:
1. 如果是函数/方法,需要包含:功能描述、参数说明、返回值说明、异常说明
2. 如果是类,需要包含:类的作用、属性说明、方法列表
3. 使用Markdown格式输出
4. 如果有类型注解,要特别说明
5. 如果有默认值,要标注出来
6. 如果有业务逻辑约束,要特别说明
上下文信息:{context}
代码:
```python
{code}
请生成规范的API文档:"""
return prompt_template.format(context=context, code=code)
def _call_ollama(self, prompt: str) -> str:
"""调用Ollama API"""
url = f"{self.base_url}/api/generate"
payload = {
"model": self.model,
"prompt": prompt,
"stream": False,
"options": {
"temperature": 0.3, # 较低的温度,让输出更稳定
"top_p": 0.9,
"max_tokens": 2000
}
}
try:
response = requests.post(url, json=payload, timeout=60)
response.raise_for_status()
result = response.json()
return result.get("response", "").strip()
except requests.exceptions.RequestException as e:
return f"调用Ollama API失败: {str(e)}"
except json.JSONDecodeError:
return "解析Ollama响应失败"
简单测试
if name == "main": client = OllamaClient()
test_code = """
def get_user_info(user_id: int, include_profile: bool = False) -> dict: """获取用户基本信息""" if user_id <= 0: raise ValueError("用户ID必须大于0") # 模拟数据库查询 return {"id": user_id, "name": "测试用户"} """
doc = client.generate_documentation(test_code)
print("生成的文档:")
print(doc)
### 4.4 实现代码解析器
创建`src/code_parser.py`:
```python
import ast
import os
from typing import List, Dict, Any
from dataclasses import dataclass
@dataclass
class FunctionInfo:
"""函数信息"""
name: str
docstring: str
args: List[Dict[str, Any]]
returns: str
decorators: List[str]
source_code: str
@dataclass
class ClassInfo:
"""类信息"""
name: str
docstring: str
methods: List[FunctionInfo]
attributes: List[Dict[str, Any]]
source_code: str
class CodeParser:
"""代码解析器,提取接口信息"""
def __init__(self):
self.functions = []
self.classes = []
def parse_file(self, filepath: str) -> Dict[str, Any]:
"""解析Python文件"""
if not os.path.exists(filepath):
raise FileNotFoundError(f"文件不存在: {filepath}")
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
return self.parse_code(content, filepath)
def parse_code(self, code: str, filename: str = "") -> Dict[str, Any]:
"""解析代码字符串"""
try:
tree = ast.parse(code)
except SyntaxError as e:
return {"error": f"语法错误: {str(e)}"}
self.functions = []
self.classes = []
# 遍历AST
for node in ast.walk(tree):
if isinstance(node, ast.FunctionDef):
self._parse_function(node, code)
elif isinstance(node, ast.ClassDef):
self._parse_class(node, code)
return {
"filename": filename,
"functions": [f.__dict__ for f in self.functions],
"classes": [c.__dict__ for c in self.classes],
"summary": {
"function_count": len(self.functions),
"class_count": len(self.classes)
}
}
def _parse_function(self, node: ast.FunctionDef, source_code: str):
"""解析函数定义"""
# 提取参数信息
args = []
for arg in node.args.args:
arg_info = {
"name": arg.arg,
"annotation": ast.unparse(arg.annotation) if arg.annotation else None,
"default": None
}
args.append(arg_info)
# 提取返回值类型
returns = ast.unparse(node.returns) if node.returns else None
# 提取装饰器
decorators = []
for decorator in node.decorator_list:
decorators.append(ast.unparse(decorator))
# 提取源代码片段
func_code = ast.get_source_segment(source_code, node)
func_info = FunctionInfo(
name=node.name,
docstring=ast.get_docstring(node) or "",
args=args,
returns=returns,
decorators=decorators,
source_code=func_code or ""
)
self.functions.append(func_info)
def _parse_class(self, node: ast.ClassDef, source_code: str):
"""解析类定义"""
methods = []
attributes = []
# 提取类的方法和属性
for item in node.body:
if isinstance(item, ast.FunctionDef):
# 临时解析方法
self._parse_function(item, source_code)
# 从刚解析的函数中获取最后一个(就是这个方法)
if self.functions:
methods.append(self.functions[-1])
elif isinstance(item, ast.AnnAssign):
# 类型注解的属性
if isinstance(item.target, ast.Name):
attr_info = {
"name": item.target.id,
"annotation": ast.unparse(item.annotation) if item.annotation else None,
"value": ast.unparse(item.value) if item.value else None
}
attributes.append(attr_info)
# 提取类源代码
class_code = ast.get_source_segment(source_code, node)
class_info = ClassInfo(
name=node.name,
docstring=ast.get_docstring(node) or "",
methods=methods,
attributes=attributes,
source_code=class_code or ""
)
self.classes.append(class_info)
# 测试代码解析
if __name__ == "__main__":
parser = CodeParser()
test_code = '''
from typing import Optional, List
class UserService:
"""用户服务类"""
def __init__(self, db_connection):
self.db = db_connection
def get_user(self, user_id: int) -> Optional[dict]:
"""根据ID获取用户"""
if user_id <= 0:
raise ValueError("用户ID必须大于0")
return {"id": user_id, "name": "测试用户"}
def list_users(self, page: int = 1, size: int = 20) -> List[dict]:
"""分页获取用户列表"""
return [{"id": i, "name": f"用户{i}"} for i in range(10)]
'''
result = parser.parse_code(test_code, "test.py")
print("解析结果:")
print(f"找到 {result['summary']['class_count']} 个类")
print(f"找到 {result['summary']['function_count']} 个函数")
4.5 实现文档生成器
创建src/doc_generator.py:
import os
from typing import List, Dict, Any
from .code_parser import CodeParser
from .ollama_client import OllamaClient
class DocumentationGenerator:
"""文档生成器"""
def __init__(self, ollama_url: str = "http://localhost:11434"):
self.parser = CodeParser()
self.client = OllamaClient(ollama_url)
def generate_from_file(self, filepath: str, output_dir: str = "docs") -> Dict[str, Any]:
"""
从文件生成文档
Args:
filepath: 源代码文件路径
output_dir: 输出目录
Returns:
生成结果信息
"""
# 解析代码
parse_result = self.parser.parse_file(filepath)
if "error" in parse_result:
return {"success": False, "error": parse_result["error"]}
# 创建输出目录
os.makedirs(output_dir, exist_ok=True)
filename = os.path.basename(filepath)
output_file = os.path.join(output_dir, f"{os.path.splitext(filename)[0]}.md")
# 生成文档内容
doc_content = self._generate_documentation(parse_result, filename)
# 保存到文件
with open(output_file, 'w', encoding='utf-8') as f:
f.write(doc_content)
return {
"success": True,
"input_file": filepath,
"output_file": output_file,
"summary": parse_result["summary"],
"functions": len(parse_result["functions"]),
"classes": len(parse_result["classes"])
}
def generate_from_code(self, code: str, filename: str = "unknown.py") -> str:
"""
从代码字符串生成文档
Args:
code: 源代码字符串
filename: 文件名(用于文档标题)
Returns:
生成的文档内容
"""
parse_result = self.parser.parse_code(code, filename)
if "error" in parse_result:
return f"# 解析错误\n\n{parse_result['error']}"
return self._generate_documentation(parse_result, filename)
def _generate_documentation(self, parse_result: Dict[str, Any], filename: str) -> str:
"""生成完整文档"""
# 文档头部
doc_parts = [
f"# {filename} API 文档\n",
f"*生成时间:{self._get_current_time()}*",
f"*文件:{parse_result['filename']}*",
"\n---\n"
]
# 如果有类,先处理类
if parse_result["classes"]:
doc_parts.append("## 类定义\n")
for class_info in parse_result["classes"]:
class_doc = self._generate_class_documentation(class_info)
doc_parts.append(class_doc)
# 处理独立函数
if parse_result["functions"]:
# 过滤掉已经在类中的方法
class_methods = []
for class_info in parse_result.get("classes", []):
for method in class_info.get("methods", []):
class_methods.append(method["name"])
standalone_functions = [
f for f in parse_result["functions"]
if f["name"] not in class_methods
]
if standalone_functions:
doc_parts.append("## 函数定义\n")
for func_info in standalone_functions:
func_doc = self._generate_function_documentation(func_info)
doc_parts.append(func_doc)
# 添加总结
doc_parts.append("\n---\n")
doc_parts.append("## 总结\n")
doc_parts.append(f"- 共解析 {parse_result['summary']['class_count']} 个类")
doc_parts.append(f"- 共解析 {parse_result['summary']['function_count']} 个函数/方法")
doc_parts.append(f"- 文档由 DeepSeek-R1-Distill-Qwen-7B 自动生成")
return "\n".join(doc_parts)
def _generate_class_documentation(self, class_info: Dict[str, Any]) -> str:
"""生成类的文档"""
# 使用AI生成详细的类文档
context = f"这是一个类定义,类名:{class_info['name']}"
if class_info['docstring']:
context += f",类说明:{class_info['docstring']}"
ai_doc = self.client.generate_documentation(class_info['source_code'], context)
# 构建格式化的文档
parts = [
f"### {class_info['name']}\n",
f"**类说明**:{class_info['docstring'] or '无说明'}\n",
f"**源代码**:\n```python\n{class_info['source_code']}\n```\n",
"**AI生成的详细文档**:\n",
ai_doc,
"\n---\n"
]
return "\n".join(parts)
def _generate_function_documentation(self, func_info: Dict[str, Any]) -> str:
"""生成函数的文档"""
# 使用AI生成详细的函数文档
context = f"这是一个函数定义,函数名:{func_info['name']}"
if func_info['docstring']:
context += f",函数说明:{func_info['docstring']}"
ai_doc = self.client.generate_documentation(func_info['source_code'], context)
# 构建格式化的文档
parts = [
f"### {func_info['name']}\n",
f"**函数说明**:{func_info['docstring'] or '无说明'}\n",
f"**源代码**:\n```python\n{func_info['source_code']}\n```\n",
"**AI生成的详细文档**:\n",
ai_doc,
"\n---\n"
]
return "\n".join(parts)
def _get_current_time(self):
"""获取当前时间"""
from datetime import datetime
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 测试文档生成
if __name__ == "__main__":
generator = DocumentationGenerator()
test_code = '''
def calculate_price(quantity: int, unit_price: float, tax_rate: float = 0.1) -> float:
"""
计算商品总价(含税)
Args:
quantity: 商品数量,必须大于0
unit_price: 单价,必须大于0
tax_rate: 税率,默认0.1(10%)
Returns:
含税总价,保留两位小数
"""
if quantity <= 0 or unit_price <= 0:
raise ValueError("数量和单价必须大于0")
if not 0 <= tax_rate <= 1:
raise ValueError("税率必须在0-1之间")
subtotal = quantity * unit_price
tax = subtotal * tax_rate
total = subtotal + tax
return round(total, 2)
'''
doc = generator.generate_from_code(test_code, "price_calculator.py")
print("生成的文档:")
print(doc)
4.6 创建主程序
创建main.py:
import argparse
import sys
from pathlib import Path
from src.doc_generator import DocumentationGenerator
def main():
parser = argparse.ArgumentParser(description="AI自动化接口文档生成器")
parser.add_argument("input", help="输入文件或目录路径")
parser.add_argument("-o", "--output", default="docs", help="输出目录,默认为docs")
parser.add_argument("-u", "--url", default="http://localhost:11434",
help="Ollama服务地址,默认为http://localhost:11434")
args = parser.parse_args()
# 初始化生成器
generator = DocumentationGenerator(args.url)
input_path = Path(args.input)
if input_path.is_file():
# 处理单个文件
if input_path.suffix != ".py":
print(f"错误:只支持Python文件,当前文件:{input_path.suffix}")
sys.exit(1)
print(f"正在处理文件:{input_path}")
result = generator.generate_from_file(str(input_path), args.output)
if result["success"]:
print(f"✓ 文档生成成功!")
print(f" 输入文件:{result['input_file']}")
print(f" 输出文件:{result['output_file']}")
print(f" 解析统计:{result['functions']}个函数,{result['classes']}个类")
else:
print(f"✗ 文档生成失败:{result.get('error', '未知错误')}")
elif input_path.is_dir():
# 处理目录
print(f"正在处理目录:{input_path}")
python_files = list(input_path.glob("**/*.py"))
if not python_files:
print("未找到Python文件")
sys.exit(0)
success_count = 0
for py_file in python_files:
print(f" 处理:{py_file.relative_to(input_path)}")
try:
result = generator.generate_from_file(str(py_file), args.output)
if result["success"]:
success_count += 1
print(f" ✓ 成功")
else:
print(f" ✗ 失败:{result.get('error', '未知错误')}")
except Exception as e:
print(f" ✗ 异常:{str(e)}")
print(f"\n处理完成:成功{success_count}/{len(python_files)}个文件")
else:
print(f"错误:路径不存在 - {args.input}")
sys.exit(1)
if __name__ == "__main__":
main()
5. 实际使用示例
工具做好了,我们来实际用一下,看看效果如何。
5.1 准备示例代码
创建examples/user_api.py:
"""
用户管理API模块
提供用户相关的CRUD操作接口
"""
from typing import List, Optional, Dict, Any
from datetime import datetime
from pydantic import BaseModel, Field, EmailStr
class UserCreateRequest(BaseModel):
"""创建用户请求模型"""
username: str = Field(..., min_length=3, max_length=50, description="用户名")
email: EmailStr = Field(..., description="邮箱地址")
password: str = Field(..., min_length=6, description="密码")
age: Optional[int] = Field(None, ge=0, le=150, description="年龄")
is_active: bool = Field(True, description="是否激活")
class UserUpdateRequest(BaseModel):
"""更新用户请求模型"""
email: Optional[EmailStr] = Field(None, description="邮箱地址")
age: Optional[int] = Field(None, ge=0, le=150, description="年龄")
is_active: Optional[bool] = Field(None, description="是否激活")
class UserResponse(BaseModel):
"""用户响应模型"""
id: int = Field(..., description="用户ID")
username: str = Field(..., description="用户名")
email: str = Field(..., description="邮箱地址")
age: Optional[int] = Field(None, description="年龄")
is_active: bool = Field(..., description="是否激活")
created_at: datetime = Field(..., description="创建时间")
updated_at: datetime = Field(..., description="更新时间")
class UserService:
"""用户服务类,处理用户相关的业务逻辑"""
def __init__(self, db_session):
"""
初始化用户服务
Args:
db_session: 数据库会话对象
"""
self.db = db_session
self.users = {} # 模拟数据库
self.next_id = 1
def create_user(self, user_data: UserCreateRequest) -> UserResponse:
"""
创建新用户
Args:
user_data: 用户创建数据
Returns:
创建的用户信息
Raises:
ValueError: 如果用户名已存在
"""
# 检查用户名是否已存在
for user in self.users.values():
if user["username"] == user_data.username:
raise ValueError(f"用户名 {user_data.username} 已存在")
# 创建用户记录
user_id = self.next_id
now = datetime.now()
user_record = {
"id": user_id,
"username": user_data.username,
"email": user_data.email,
"age": user_data.age,
"is_active": user_data.is_active,
"created_at": now,
"updated_at": now
}
self.users[user_id] = user_record
self.next_id += 1
return UserResponse(**user_record)
def get_user(self, user_id: int) -> Optional[UserResponse]:
"""
根据ID获取用户
Args:
user_id: 用户ID
Returns:
用户信息,如果不存在则返回None
"""
if user_id <= 0:
raise ValueError("用户ID必须大于0")
user_record = self.users.get(user_id)
if user_record:
return UserResponse(**user_record)
return None
def update_user(self, user_id: int, update_data: UserUpdateRequest) -> Optional[UserResponse]:
"""
更新用户信息
Args:
user_id: 用户ID
update_data: 更新数据
Returns:
更新后的用户信息,如果用户不存在则返回None
Raises:
ValueError: 如果用户ID无效
"""
if user_id <= 0:
raise ValueError("用户ID必须大于0")
if user_id not in self.users:
return None
user_record = self.users[user_id]
# 更新字段
update_dict = update_data.dict(exclude_unset=True)
for key, value in update_dict.items():
if value is not None:
user_record[key] = value
user_record["updated_at"] = datetime.now()
return UserResponse(**user_record)
def delete_user(self, user_id: int) -> bool:
"""
删除用户
Args:
user_id: 用户ID
Returns:
是否删除成功
Raises:
ValueError: 如果用户ID无效
"""
if user_id <= 0:
raise ValueError("用户ID必须大于0")
if user_id in self.users:
del self.users[user_id]
return True
return False
def list_users(self,
page: int = 1,
page_size: int = 20,
active_only: bool = False) -> Dict[str, Any]:
"""
分页获取用户列表
Args:
page: 页码,从1开始
page_size: 每页大小,默认20
active_only: 是否只返回激活用户
Returns:
包含用户列表和分页信息的字典
"""
if page < 1:
page = 1
if page_size < 1 or page_size > 100:
page_size = 20
# 过滤用户
filtered_users = self.users.values()
if active_only:
filtered_users = [u for u in filtered_users if u["is_active"]]
# 排序(按ID倒序)
sorted_users = sorted(filtered_users, key=lambda x: x["id"], reverse=True)
# 分页
total = len(sorted_users)
start = (page - 1) * page_size
end = start + page_size
paged_users = sorted_users[start:end]
return {
"users": [UserResponse(**user) for user in paged_users],
"pagination": {
"page": page,
"page_size": page_size,
"total": total,
"total_pages": (total + page_size - 1) // page_size
}
}
def validate_password_strength(password: str) -> Dict[str, Any]:
"""
验证密码强度
Args:
password: 待验证的密码
Returns:
包含验证结果和详细信息的字典
"""
if not password:
return {
"valid": False,
"score": 0,
"issues": ["密码不能为空"]
}
issues = []
score = 0
# 长度检查
if len(password) >= 8:
score += 1
else:
issues.append("密码长度至少8位")
# 包含数字
if any(c.isdigit() for c in password):
score += 1
else:
issues.append("密码应包含数字")
# 包含小写字母
if any(c.islower() for c in password):
score += 1
else:
issues.append("密码应包含小写字母")
# 包含大写字母
if any(c.isupper() for c in password):
score += 1
else:
issues.append("密码应包含大写字母")
# 包含特殊字符
special_chars = "!@#$%^&*()_+-=[]{}|;:,.<>?"
if any(c in special_chars for c in password):
score += 1
else:
issues.append("密码应包含特殊字符")
# 评估强度
if score >= 4:
strength = "强"
elif score >= 3:
strength = "中"
else:
strength = "弱"
return {
"valid": len(issues) == 0,
"score": score,
"strength": strength,
"issues": issues,
"suggestions": [
"使用至少12位字符",
"避免使用常见单词",
"不要使用个人信息",
"定期更换密码"
] if score < 4 else []
}
5.2 运行文档生成
在终端中运行:
python main.py examples/user_api.py -o generated_docs
你会看到类似这样的输出:
正在处理文件:examples/user_api.py
✓ 文档生成成功!
输入文件:examples/user_api.py
输出文件:generated_docs/user_api.md
解析统计:6个函数,3个类
5.3 查看生成的文档
打开generated_docs/user_api.md,你会看到AI生成的完整文档。由于篇幅限制,这里只展示部分内容:
# user_api.py API 文档
*生成时间:2024-01-15 14:30:25*
*文件:examples/user_api.py*
---
## 类定义
### UserCreateRequest
**类说明**:创建用户请求模型
**源代码**:
```python
class UserCreateRequest(BaseModel):
"""创建用户请求模型"""
username: str = Field(..., min_length=3, max_length=50, description="用户名")
email: EmailStr = Field(..., description="邮箱地址")
password: str = Field(..., min_length=6, description="密码")
age: Optional[int] = Field(None, ge=0, le=150, description="年龄")
is_active: bool = Field(True, description="是否激活")
AI生成的详细文档:
UserCreateRequest 类文档
类概述 UserCreateRequest 是一个用于创建用户请求的数据模型类,基于 Pydantic 的 BaseModel。它定义了创建新用户时需要提供的字段及其验证规则。
字段说明
| 字段名 | 类型 | 必填 | 默认值 | 约束条件 | 描述 |
|---|---|---|---|---|---|
username |
str |
是 | 无 | min_length=3, max_length=50 |
用户名,长度必须在3到50个字符之间 |
email |
EmailStr |
是 | 无 | 必须符合邮箱格式 | 用户的邮箱地址,会自动验证格式是否正确 |
password |
str |
是 | 无 | min_length=6 |
用户密码,长度至少为6个字符 |
age |
Optional[int] |
否 | None |
ge=0, le=150 |
用户年龄,可选,如果提供必须在0到150之间 |
is_active |
bool |
否 | True |
无 | 用户是否激活,默认为True(激活状态) |
使用示例
# 创建有效的用户请求
user_data = UserCreateRequest(
username="john_doe",
email="john@example.com",
password="secure123",
age=25,
is_active=True
)
# 验证数据(Pydantic会自动验证)
print(user_data.username) # 输出: john_doe
print(user_data.email) # 输出: john@example.com
# 如果数据无效会抛出ValidationError
try:
invalid_user = UserCreateRequest(
username="ab", # 太短,不符合min_length=3
email="invalid-email",
password="123"
)
except ValidationError as e:
print(f"验证失败: {e}")
注意事项
- 所有字段都使用 Pydantic 的
Field进行详细配置,包括描述、约束条件等 email字段使用EmailStr类型,会自动验证邮箱格式age字段是可选的,如果不提供则为Noneis_active字段有默认值True,创建用户时默认激活- 模型会自动进行数据验证,确保输入数据符合所有约束条件
create_user 方法文档
方法功能 创建新用户并将其添加到用户数据库中。
参数说明
user_data(UserCreateRequest): 必需参数,包含新用户的详细信息。必须是通过验证的UserCreateRequest实例。
返回值
UserResponse: 返回一个UserResponse实例,包含创建成功的用户信息,包括自动生成的用户ID和时间戳。
异常处理
ValueError: 如果尝试创建的用户名已经存在于系统中,会抛出此异常,提示用户名冲突。
业务逻辑
- 用户名唯一性检查:遍历现有用户,检查是否有重复的用户名
- ID分配:使用内部计数器
next_id分配唯一用户ID - 时间戳记录:记录用户的创建时间和更新时间(初始时间相同)
- 数据存储:将用户信息存储到内存字典
users中 - ID递增:更新
next_id为下一个可用值 - 返回结果:将存储的数据转换为
UserResponse对象返回
使用示例
# 创建用户服务实例
service = UserService(db_session=None)
# 准备用户数据
new_user = UserCreateRequest(
username="alice_smith",
email="alice@example.com",
password="AlicePass123",
age=30
)
# 创建用户
try:
created_user = service.create_user(new_user)
print(f"用户创建成功: ID={created_user.id}, 用户名={created_user.username}")
except ValueError as e:
print(f"创建失败: {e}")
注意事项
- 该方法不是线程安全的,如果在多线程环境下使用需要考虑加锁
- 当前使用内存字典存储,实际应用中应替换为数据库操作
- 用户名检查是线性搜索,用户量大时可能影响性能
- 密码以明文存储,实际应用中应该进行哈希处理
可以看到,AI不仅提取了基本的函数签名,还生成了详细的文档,包括参数说明、返回值、异常处理、业务逻辑、使用示例和注意事项。这正是DeepSeek-R1-Distill-Qwen-7B的推理能力体现——它能理解代码的意图,而不仅仅是提取表面信息。
## 6. 进阶用法与集成建议
基本的文档生成器已经能用了,但我们可以让它更强大、更实用。
### 6.1 添加批量处理功能
修改`main.py`,添加批量处理支持:
```python
# 在DocumentationGenerator类中添加
def batch_generate(self, input_dir: str, output_dir: str = "docs") -> Dict[str, Any]:
"""
批量生成文档
Args:
input_dir: 输入目录
output_dir: 输出目录
Returns:
批量处理结果
"""
input_path = Path(input_dir)
if not input_path.exists():
return {"success": False, "error": f"目录不存在: {input_dir}"}
# 收集所有Python文件
python_files = list(input_path.glob("**/*.py"))
if not python_files:
return {"success": False, "error": "未找到Python文件"}
results = []
for py_file in python_files:
try:
result = self.generate_from_file(str(py_file), output_dir)
result["file"] = str(py_file)
results.append(result)
except Exception as e:
results.append({
"success": False,
"file": str(py_file),
"error": str(e)
})
# 生成汇总报告
success_count = sum(1 for r in results if r.get("success"))
report = {
"total_files": len(python_files),
"success_count": success_count,
"failed_count": len(python_files) - success_count,
"results": results
}
# 保存报告
report_file = Path(output_dir) / "generation_report.json"
with open(report_file, 'w', encoding='utf-8') as f:
json.dump(report, f, indent=2, ensure_ascii=False)
return report
6.2 集成到CI/CD流程
你可以把这个工具集成到持续集成流程中,每次代码提交都自动更新文档:
创建.github/workflows/generate-docs.yml:
name: Generate API Documentation
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
generate-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.9'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install requests fastapi uvicorn pydantic
- name: Start Ollama
run: |
curl -fsSL https://ollama.com/install.sh | sh
ollama pull deepseek-r1:7b
ollama serve &
sleep 30 # 等待服务启动
- name: Generate documentation
run: |
python main.py ./src -o ./docs
python main.py ./tests -o ./docs
- name: Upload documentation
uses: actions/upload-artifact@v3
with:
name: api-docs
path: docs/
6.3 创建Web界面
如果你想要更友好的使用方式,可以创建一个简单的Web界面:
创建web_ui.py:
from fastapi import FastAPI, UploadFile, File, Form
from fastapi.responses import HTMLResponse, FileResponse
from fastapi.staticfiles import StaticFiles
import tempfile
import os
from src.doc_generator import DocumentationGenerator
app = FastAPI(title="API文档生成器")
# 创建临时目录存储上传的文件
UPLOAD_DIR = "uploads"
os.makedirs(UPLOAD_DIR, exist_ok=True)
generator = DocumentationGenerator()
@app.get("/", response_class=HTMLResponse)
async def home():
"""首页"""
return """
<!DOCTYPE html>
<html>
<head>
<title>API文档生成器</title>
<style>
body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
.container { background: #f5f5f5; padding: 30px; border-radius: 10px; }
h1 { color: #333; }
.form-group { margin: 20px 0; }
textarea { width: 100%; height: 200px; padding: 10px; }
button { background: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; }
button:hover { background: #0056b3; }
.result { margin-top: 30px; padding: 20px; background: white; border-radius: 5px; }
</style>
</head>
<body>
<div class="container">
<h1>📚 API文档生成器</h1>
<p>上传Python文件或粘贴代码,自动生成API文档</p>
<form action="/generate" method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="code">直接输入代码:</label>
<textarea id="code" name="code" placeholder="粘贴你的Python代码 here..."></textarea>
</div>
<div class="form-group">
<label for="file">或上传文件:</label>
<input type="file" id="file" name="file" accept=".py">
</div>
<button type="submit">生成文档</button>
</form>
<div class="form-group">
<h3>示例代码:</h3>
<pre><code>def example():
\"\"\"示例函数\"\"\"
return "Hello, World!"</code></pre>
</div>
</div>
</body>
</html>
"""
@app.post("/generate")
async def generate_documentation(
code: str = Form(""),
file: UploadFile = File(None)
):
"""生成文档接口"""
if file:
# 处理上传的文件
content = await file.read()
code_text = content.decode('utf-8')
filename = file.filename
elif code:
# 处理直接输入的代码
code_text = code
filename = "input.py"
else:
return {"error": "请提供代码或上传文件"}
try:
# 生成文档
documentation = generator.generate_from_code(code_text, filename)
# 保存到临时文件
temp_file = tempfile.NamedTemporaryFile(mode='w', suffix='.md', delete=False, encoding='utf-8')
temp_file.write(documentation)
temp_file.close()
return FileResponse(
temp_file.name,
media_type='text/markdown',
filename=f"{os.path.splitext(filename)[0]}_docs.md"
)
except Exception as e:
return {"error": f"生成文档失败: {str(e)}"}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
运行Web服务:
python web_ui.py
然后在浏览器打开http://localhost:8000,就能通过网页界面生成文档了。
6.4 添加文档质量检查
为了让生成的文档质量更高,我们可以添加一些检查规则:
创建src/quality_checker.py:
import re
from typing import Dict, List, Tuple
class DocumentationQualityChecker:
"""文档质量检查器"""
def __init__(self):
self.checks = [
self._check_function_docs,
self._check_parameter_docs,
self._check_return_docs,
self._check_example_code,
self._check_formatting
]
def check_quality(self, documentation: str) -> Dict[str, Any]:
"""检查文档质量"""
results = {
"score": 100, # 初始分数
"issues": [],
"suggestions": []
}
for check_func in self.checks:
score_deduction, issues, suggestions = check_func(documentation)
results["score"] -= score_deduction
results["issues"].extend(issues)
results["suggestions"].extend(suggestions)
# 评估等级
if results["score"] >= 90:
results["grade"] = "优秀"
elif results["score"] >= 70:
results["grade"] = "良好"
elif results["score"] >= 50:
results["grade"] = "一般"
else:
results["grade"] = "需要改进"
return results
def _check_function_docs(self, doc: str) -> Tuple[int, List[str], List[str]]:
"""检查函数文档完整性"""
score_deduction = 0
issues = []
suggestions = []
# 检查是否有函数文档
function_pattern = r'###\s+\w+\(.*?\)'
functions = re.findall(function_pattern, doc, re.DOTALL)
for func in functions:
func_name = func[4:].split('(')[0].strip()
# 检查是否有描述
if not re.search(rf'{re.escape(func_name)}.*?[\n\r]+.*?[^\n\r]+', doc):
score_deduction += 5
issues.append(f"函数 '{func_name}' 缺少描述")
suggestions.append(f"为函数 '{func_name}' 添加功能描述")
return score_deduction, issues, suggestions
def _check_parameter_docs(self, doc: str) -> Tuple[int, List[str], List[str]]:
"""检查参数文档"""
score_deduction = 0
issues = []
suggestions = []
# 查找参数说明部分
param_sections = re.findall(r'参数说明.*?\n\n', doc, re.DOTALL | re.IGNORECASE)
if not param_sections:
score_deduction += 10
issues.append("缺少参数说明部分")
suggestions.append("添加详细的参数说明,包括类型、含义、约束条件等")
return score_deduction, issues, suggestions
def _check_return_docs(self, doc: str) -> Tuple[int, List[str], List[str]]:
"""检查返回值文档"""
score_deduction = 0
issues = []
suggestions = []
# 检查是否有返回值说明
if not re.search(r'返回值|返回|return', doc, re.IGNORECASE):
score_deduction += 10
issues.append("缺少返回值说明")
suggestions.append("添加返回值说明,包括类型和含义")
return score_deduction, issues, suggestions
def _check_example_code(self, doc: str) -> Tuple[int, List[str], List[str]]:
"""检查示例代码"""
score_deduction = 0
issues = []
suggestions = []
# 检查是否有代码示例
code_blocks = re.findall(r'```python\n.*?\n```', doc, re.DOTALL)
if len(code_blocks) < 2: # 至少应该有2个代码块(源代码+示例)
score_deduction += 5
issues.append("示例代码不足")
suggestions.append("添加更多使用示例,展示典型用法")
return score_deduction, issues, suggestions
def _check_formatting(self, doc: str) -> Tuple[int, List[str], List[str]]:
"""检查格式"""
score_deduction = 0
issues = []
suggestions = []
# 检查标题层级
h1_count = len(re.findall(r'^#\s+', doc, re.MULTILINE))
if h1_count != 1:
score_deduction += 5
issues.append("标题层级不规范")
suggestions.append("确保只有一个一级标题(#)")
# 检查列表使用
list_items = len(re.findall(r'^\s*[-*]\s+', doc, re.MULTILINE))
if list_items < 3:
score_deduction += 3
issues.append("列表使用不足")
suggestions.append("使用列表整理要点,提高可读性")
return score_deduction, issues, suggestions
# 使用示例
if __name__ == "__main__":
checker = DocumentationQualityChecker()
with open("generated_docs/user_api.md", "r", encoding="utf-8") as f:
doc_content = f.read()
result = checker.check_quality(doc_content)
print(f"文档质量评分: {result['score']}/100 ({result['grade']})")
print("\n发现问题:")
for issue in result["issues"]:
print(f" - {issue}")
print("\n改进建议:")
for suggestion in result["suggestions"]:
print(f" - {suggestion}")
7. 总结
通过这个实战教程,我们完成了一个完整的AI自动化接口文档生成器。让我来总结一下关键收获:
7.1 技术要点回顾
- 模型选择:DeepSeek-R1-Distill-Qwen-7B在推理任务上表现优秀,特别适合分析代码逻辑
- 部署简单:Ollama让大模型部署变得极其简单,一条命令就能搞定
- 代码解析:使用Python的ast模块可以准确提取代码结构信息
- 提示词设计:好的提示词能让AI生成更符合要求的文档
- 工程化实现:从单文件处理到批量处理,再到Web界面,逐步完善工具链
7.2 实际效果评估
我实际测试了这个工具,发现它有几个明显的优势:
生成质量高:AI不仅能提取函数签名,还能理解业务逻辑,生成包含使用示例、注意事项的完整文档。
节省时间:手动写一个中等规模项目的文档可能需要几小时,这个工具几分钟就能完成。
一致性好:自动生成的文档格式统一,不会出现不同开发者风格不一致的问题。
可维护性强:代码更新后,重新运行一下就能更新文档,确保文档与代码同步。
7.3 使用建议
根据我的使用经验,给你几个实用建议:
最佳实践:
- 在代码审查前生成文档:让AI先帮你检查接口设计是否合理
- 作为文档初稿:先生成基础文档,然后人工补充业务背景和特殊说明
- 集成到开发流程:在CI/CD中自动生成,确保文档始终最新
- 定期质量检查:用质量检查器评估文档完整性,不断优化提示词
注意事项:
- 隐私代码不要上传:如果代码包含敏感信息,建议在本地运行
- 复杂逻辑需要人工复核:AI可能无法完全理解特别复杂的业务逻辑
- 保持提示词更新:根据实际需求调整提示词,让AI生成更符合你要求的文档
- 结合人工审核:AI生成+人工审核是最佳组合
7.4 扩展思路
这个工具还有很多可以扩展的方向:
支持更多语言:目前只支持Python,可以扩展支持Java、JavaScript、Go等语言。
集成到IDE:开发VSCode或PyCharm插件,在编写代码时实时生成文档。
团队协作:搭建文档中心,团队成员可以查看、编辑、评论生成的文档。
知识库构建:将生成的文档组织成项目知识库,方便新人快速上手。
质量评估:加入更多质量检查规则,甚至用AI评估AI生成的文档质量。
这个方案最大的价值在于,它把复杂的AI能力变成了一个简单实用的工具。你不需要懂深度学习,不需要训练模型,只需要会写Python代码,就能享受到AI带来的效率提升。
技术应该服务于人,而不是让人去适应技术。DeepSeek-R1-Distill-Qwen-7B + Ollama + 简单Python代码,这个组合正好体现了这个理念——用最简单的工具,解决最实际的问题。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
更多推荐

所有评论(0)