本规范以 Python 官方 PEP8、PEP20 等核心规范为基础,参考阿里巴巴 Java 开发手册的结构与约束逻辑,结合 Java 团队的使用习惯制定。规范覆盖大模型智能体开发全场景,按约束力分为【强制】(必须遵守,违反易引发故障 / 可读性灾难)、【推荐】(建议遵守,违反易降低代码质量)、【参考】(按需参考,适配个性化场景)三类;每个规约配套「说明」「正例」「反例」,降低 Java 团队转向 Python 的学习成本。
agent.coreutils.text | agent_coreos(内置模块名)、requests(第三方库名) | |||
model_loader.pyprompt_builder.py | ModelLoader.pyceshi.py(拼音)、test1.py(模糊) | |||
Abstract,异常类后缀Exception,接口类(ABC)前缀I | AbstractAgentModelCallException、IAgentAdapter | abstract_agentAgentError(异常类未加 Exception 后缀) | ||
load_model_configparse_user_query | LoadModelConfigdo_something(模糊)、handle_data(模糊) | |||
is_/has_/can_;常量全大写,下划线分隔 | user_query、max_token;布尔:is_initialized;常量:MAX_TOKEN_SIZE = 4096 | UserQuery(驼峰);布尔:initialized(无前缀);常量:maxTokenSize = 4096(小写 + 驼峰) | ||
def call_model(model_name: str, timeout: int) | def call_model(m: str, t: int) |
python<br>if is_valid:<br> for item in data_list:<br> process_item(item) | python<br>if is_valid:<br> for item in data_list:<br> for sub in item:<br> for val in sub:<br> print(val) | |||
python<br>response = model.call(<br> prompt=user_query,<br> max_token=MAX_TOKEN_SIZE,<br> timeout=30<br>) | python<br>response = model.call(prompt=user_query, max_token=MAX_TOKEN_SIZE, timeout=30) | |||
python<br>x = 1 + 2<br>func(1, 2)<br>def call_model(timeout=30): | python<br>x=1+2<br>func( 1, 2 )<br>def call_model(timeout = 30): | |||
python<br>import os<br>import sys<br><br>class AgentCore:<br> def __init__(self):<br> pass<br><br> def init(self):<br> pass | python<br>import os<br>import sys<br>class AgentCore:<br> def __init__(self):<br> pass<br> def init(self):<br> pass |
python<br>import os<br>import sys<br><br>import requests<br>import torch<br><br>from agent.core import AgentCore | python<br>from agent.core import AgentCore<br>import os<br>import requests | |||
from xxx import *通配符导入 | python<br>from utils.text import parse_query | python<br>from utils.text import * | ||
python<br># 同一包内<br>from .model_client import ModelClient<br># 跨包<br>from agent.data import VectorStore | python<br>from ....core import AgentCore |
python<br>from dataclasses import dataclass<br><br>@dataclass<br>class ModelParams:<br> name: str<br> timeout: int<br> max_token: int<br><br>def call_model(params: ModelParams):<br> # 仅执行模型调用逻辑(≤50行)<br> pass | python<br># 函数含参数校验+模型调用+结果存储(多职责,行数80)<br>def call_model(name, timeout, max_token, url, headers, proxy, retry):<br> # 复杂逻辑<br> pass | |||
python<br>def build_prompt(template, variables=None):<br> if variables is None:<br> variables = {}<br> return template.format(**variables) | python<br>def build_prompt(template, variables={}):<br> return template.format(**variables) | |||
python<br>def load_model(model_name: str):<br> if not model_name:<br> raise ValueError("model_name不能为空")<br> if not isinstance(model_name, str):<br> raise TypeError("model_name必须为字符串") | python<br>def load_model(model_name):<br> # 无参数校验,直接使用<br> pass | |||
python<br># 始终返回列表(空列表替代None)<br>def get_valid_data() -> list:<br> if not data:<br> return []<br> return [item for item in data if item.is_valid()] | python<br># 有时返回列表,有时返回None<br>def get_valid_data():<br> if not data:<br> return None<br> return [item for item in data if item.is_valid()] |
except:/except Exception: | python<br>try:<br> requests.get(url, timeout=10)<br>except requests.exceptions.Timeout:<br> logger.error("请求超时")<br>except requests.exceptions.ConnectionError:<br> logger.error("连接失败") | python<br>try:<br> requests.get(url, timeout=10)<br>except:<br> logger.error("请求异常") | ||
# TODO注释 | python<br>if condition:<br> # TODO: 待实现模型降级逻辑<br>else:<br> process_normal() | python<br>if condition:<br> pass<br>else:<br> process_normal() | ||
python<br># 字典映射替代多elif<br>handler_map = {<br> "gpt-4": handle_gpt4,<br> "claude": handle_claude,<br> "qwen": handle_qwen<br>}<br>handler = handler_map.get(model_name, handle_default)<br>handler(prompt) | python<br>if model_name == "gpt-4":<br> handle_gpt4(prompt)<br>elif model_name == "claude":<br> handle_claude(prompt)<br>elif model_name == "qwen":<br> handle_qwen(prompt)<br>elif model_name == "llama":<br> handle_llama(prompt)<br>elif model_name == "ernie":<br> handle_ernie(prompt)<br>else:<br> handle_default(prompt) | |||
python<br># 单break,退出条件清晰<br>for item in data_list:<br> if item.is_invalid():<br> break<br> process_item(item) | python<br># 多个break/continue,逻辑混乱<br>for item in data_list:<br> if item.skip:<br> continue<br> if item.is_invalid():<br> break<br> if item.need_retry:<br> continue<br> process_item(item) |
str.join(),格式化用 f-string,禁止 % 格式化 | python<br># 少量拼接<br>info = f"模型:{model_name},版本:{version}"<br># 大量拼接<br>parts = [str(i) for i in range(1000)]<br>result = "".join(parts) | python<br>info = "模型:%s,版本:%s" % (model_name, version)<br># 大量拼接用+,效率低<br>result = ""<br>for i in range(1000):<br> result += str(i) | ||
get()方法,避免 KeyError;遍历字典用items() | python<br>config = {"model_name": "gpt-4"}<br>name = config.get("model_name", "default")<br>for key, value in config.items():<br> print(f"{key}: {value}") | python<br>name = config["model_name"] # 无key时抛KeyError<br>for key in config:<br> value = config[key] # 冗余取值 | ||
python<br>from typing import List, Optional<br><br>def parse_queries(queries: List[str]) -> Optional[List[str]]:<br> pass | python<br>def parse_queries(queries):<br> pass |
结合 Python 官方 PEP 257(文档字符串规范)、PEP 8 注释要求,对齐 Java 团队 Javadoc 注释习惯,制定以下注释规范,仍按【强制】【推荐】【参考】分级,配套「说明」「正例」「反例」:
python<br>def load_model_config(model_name: str) -> dict:<br> """<br> 加载指定模型的配置文件<br> <br> Args:<br> model_name (str): 模型名称(如gpt-4、claude)<br> <br> Returns:<br> dict: 模型配置字典(含max_token、temperature等)<br> <br> Raises:<br> FileNotFoundError: 配置文件不存在时抛出<br> """<br> pass | python<br># 无Docstring,仅靠变量名猜测功能<br>def load_model_config(model_name):<br> pass | |||
#,与代码间保留 1 个空格;仅解释「为什么做」,不解释「做什么」 | #(类比 Java 的//);避免冗余注释(如注释 “x=1 # 赋值 x 为 1”),仅注释非直观逻辑 | python<br>time.sleep(1) # 延迟1秒,避免接口QPS限流触发 | python<br>time.sleep(1)#休眠1秒(无空格)<br>x = 1 + 2 # 计算x的值(冗余注释) | |
python<br># 过滤敏感词,防止Prompt Injection攻击 | python<br># Filter sensitive words to prevent 提示注入攻击(混杂中英文)<br># Check user query length(纯英文,不符合团队习惯) | |||
python<br># 调试完成后删除以下注释代码<br># temp_config = {"temperature": 0.8}<br># print(temp_config) | python<br># 临时调试代码,暂保留<br>temp_config = {"temperature": 0.8}<br># print(temp_config) | |||
python<br>class LLMClient(ABC):<br> """<br> 大模型客户端抽象类,定义模型调用的统一接口<br> <br> 属性:<br> model_name (str): 模型名称<br> max_retry (int): 最大重试次数,默认3次<br> <br> 核心方法:<br> generate: 抽象方法,子类需实现模型响应生成逻辑<br> """<br> @abstractmethod<br> def generate(self, prompt: str) -> str:<br> """<br> 生成模型响应<br> <br> Args:<br> prompt (str): 用户输入的提示词<br> <br> Returns:<br> str: 模型生成的响应文本<br> <br> Raises:<br> ModelCallException: 模型调用失败时抛出<br> <br> Examples:<br> >>> client = GPTClient("gpt-4")<br> >>> client.generate("你好")<br> "你好!有什么我能帮助你的吗?"<br> """<br> pass | python<br>class LLMClient(ABC):<br> """大模型客户端抽象类"""<br> @abstractmethod<br> def generate(self, prompt):<br> """生成响应"""<br> pass | |||
#逐行开头,禁止用三重引号(三重引号仅用于 Docstring) | python<br># 以下逻辑处理大模型响应脱敏<br># 1. 加载敏感词库(来自config/sensitive_words.txt)<br># 2. 替换响应中的手机号、邮箱等隐私信息<br># 3. 过滤违规敏感词,返回合规响应<br>def filter_response(response: str) -> str:<br> pass | python<br>"""<br>以下逻辑处理大模型响应脱敏<br>1. 加载敏感词库<br>2. 替换隐私信息<br>3. 过滤敏感词<br>"""<br>def filter_response(response: str) -> str:<br> pass | ||
# TODO: 责任人 截止时间 待办内容/# FIXME: 责任人 问题描述 | // TODO: 张三 2026-03-01 补充降级逻辑,便于团队协作和任务追踪 | python<br># TODO: 李四 2026-02-28 适配通义千问模型的参数格式<br># FIXME: 王五 2026-02-25 修复模型超时重试次数不生效问题 | python<br># 待适配通义千问模型(无统一格式)<br># 修复重试次数问题(无责任人/时间) | |
python<br>def _parse_response_raw(raw_response: str) -> dict:<br> """解析模型原始响应为字典(内部方法)"""<br> pass | python<br>def _parse_response_raw(raw_response: str) -> dict:<br> """<br> 解析模型原始响应为字典<br> <br> Args:<br> raw_response (str): 模型原始响应字符串<br> <br> Returns:<br> dict: 解析后的字典<br> """<br> pass | |||
python<br># 模型选择逻辑:<br># - 若用户指定模型,优先使用指定模型<br># - 若未指定,根据查询长度自动选择(短查询用gpt-3.5,长查询用gpt-4)<br># - 若模型不可用,降级到通义千问<br>if user_model:<br> client = get_client(user_model)<br>elif len(prompt) < 100:<br> client = get_client("gpt-3.5")<br>else:<br> client = get_client("gpt-4")<br>if not client.is_available():<br> client = get_client("qwen") | python<br># 选择模型<br>if user_model:<br> client = get_client(user_model)<br>elif len(prompt) < 100:<br> client = get_client("gpt-3.5")<br>else:<br> client = get_client("gpt-4")<br>if not client.is_available():<br> client = get_client("qwen") |
Exception,禁止继承BaseException;异常信息需包含具体原因 | python<br>class AgentInitException(Exception):<br> """智能体初始化异常"""<br> pass<br><br>raise AgentInitException(f"模型加载失败:{model_name},错误:{str(e)}") | python<br>class AgentInitException(BaseException):<br> pass<br><br>raise AgentInitException("模型加载失败") # 无具体原因 | ||
except Exception: pass | python<br>try:<br> load_model()<br>except AgentInitException as e:<br> logger.error(f"模型加载失败:{str(e)}", exc_info=True)<br> raise # 抛上层处理 | python<br>try:<br> load_model()<br>except Exception:<br> pass # 吞异常,无任何处理 | ||
with语句(上下文管理器),替代 try-finally | python<br>with open("config.json", "r") as f:<br> config = json.load(f) | python<br>f = open("config.json", "r")<br>try:<br> config = json.load(f)<br>finally:<br> f.close() | ||
raise NewExc() from e保留原始堆栈 | except*捕获多异常 | python<br>try:<br> requests.get(url)<br>except requests.exceptions.Timeout as e:<br> raise AgentCallException("接口超时") from e | python<br>try:<br> requests.get(url)<br>except requests.exceptions.Timeout:<br> raise AgentCallException("接口超时") |
print()替代日志 | print()无法统一管理,禁止使用 | python<br>import logging<br><br>logger = logging.getLogger(__name__)<br>logger.info("智能体初始化完成,模型:%s", model_name)<br>logger.error("模型调用失败", exc_info=True) | python<br>print("智能体初始化完成") # 用print替代日志<br>logger.debug("生产环境输出调试日志") # 生产环境输出DEBUG | |
python<br>logging.basicConfig(<br> format="%(asctime)s - %(levelname)s - %(module)s:%(funcName)s - %(message)s",<br> datefmt="%Y-%m-%d %H:%M:%S"<br>)<br>logger.info("用户登录,用户名:%s", mask_username(username)) | python<br>logging.basicConfig(format="%(message)s") # 格式缺失<br>logger.info("用户登录,token:%s", token) # 敏感信息未脱敏 | |||
python<br>from logging.handlers import TimedRotatingFileHandler<br><br>handler = TimedRotatingFileHandler("agent.log", when="D", backupCount=7)<br>logger.addHandler(handler) | python<br># 仅输出到控制台,生产环境无日志文件<br>logging.basicConfig(level=logging.INFO) |
test_+业务模块名.py;测试函数命名:test_+功能名 | test_model_loader.pytest_load_model_config | model_loader_test.pytest1 | ||
python<br>def test_load_model_config():<br> # 正常场景<br> config = load_model_config("gpt-4")<br> assert config["max_token"] == 4096<br> # 异常场景<br> with pytest.raises(ValueError):<br> load_model_config("") | python<br>def test_load_model_config():<br> config = load_model_config("gpt-4")<br> assert config["max_token"] == 4096 | |||
python<br># test_data.yaml<br>model_config:<br> gpt-4: {max_token: 4096}<br><br># 测试函数<br>def test_load_model_config():<br> with open("test_data.yaml") as f:<br> test_data = yaml.load(f)<br> config = load_model_config("gpt-4")<br> assert config["max_token"] == test_data["model_config"]["gpt-4"]["max_token"] | python<br>def test_load_model_config():<br> # 硬编码测试数据<br> config = load_model_config("gpt-4")<br> assert config["max_token"] == 4096 | |||
python<br>@mock.patch("agent.core.model_client.ModelClient.call")<br>def test_agent_call(mock_call):<br> mock_call.return_value = "测试响应"<br> agent = AgentCore()<br> response = agent.call("测试查询")<br> assert response == "测试响应" | python<br>def test_agent_call():<br> # 依赖真实模型接口,不稳定<br> agent = AgentCore()<br> response = agent.call("测试查询")<br> assert response is not None |
python<br>import os<br><br>API_KEY = os.getenv("LLM_API_KEY")<br>if not API_KEY:<br> raise ValueError("未配置LLM_API_KEY环境变量") | python<br>API_KEY = "sk-xxxxxx" # 硬编码密钥 | |||
python<br>def validate_query(query: str) -> str:<br> if len(query) > 1000:<br> raise ValueError("查询长度超过限制")<br> # 过滤特殊注入字符<br> return query.replace(";", "").replace("'", "") | python<br>def call_llm(query: str):<br> # 无输入校验,直接传入<br> return model.generate(query) | |||
>=/<=模糊版本;定期更新依赖(修复安全漏洞) | python<br># requirements.txt<br>requests==2.31.0<br>langchain==0.1.10 | python<br># requirements.txt<br>requests>=2.0.0<br>langchain | ||
python<br>def filter_response(response: str) -> str:<br> sensitive_words = ["敏感词1", "敏感词2"]<br> for word in sensitive_words:<br> response = response.replace(word, "***")<br> return response | python<br>def return_response(response: str):<br> # 无内容审核,直接返回<br> return response |
python<br>import pymysql<br><br>conn = pymysql.connect(host=os.getenv("DB_HOST"), user=os.getenv("DB_USER"))<br>with conn.cursor() as cur:<br> # 参数化查询<br> cur.execute("SELECT * FROM agent_log WHERE user_id = %s", (user_id,))<br> result = cur.fetchall() | python<br># 拼接SQL,易注入<br>cur.execute(f"SELECT * FROM agent_log WHERE user_id = {user_id}") | |||
python<br>from DBUtils.PooledDB import PooledDB<br><br>pool = PooledDB(<br> creator=pymysql,<br> maxconnections=10,<br> host=os.getenv("DB_HOST")<br>)<br>conn = pool.connection() | python<br># 每次查询创建连接,性能差<br>def query_data():<br> conn = pymysql.connect(host=os.getenv("DB_HOST"))<br> # 查询逻辑<br> conn.close() | |||
python<br>from sqlalchemy import Column, String, Integer<br>from sqlalchemy.ext.declarative import declarative_base<br><br>Base = declarative_base()<br><br>class AgentLog(Base):<br> __tablename__ = "agent_log"<br> id = Column(Integer, primary_key=True)<br> user_id = Column(String(64))<br> query = Column(String(1000)) | python<br># 所有操作均用原生SQL,可读性差<br>def add_log(user_id, query):<br> cur.execute("INSERT INTO agent_log (user_id, query) VALUES (%s, %s)", (user_id, query)) | |||
python<br>cur.execute("SELECT * FROM agent_log LIMIT %s OFFSET %s", (page_size, page_num * page_size)) | python<br>cur.execute("SELECT * FROM agent_log") # 全表查询,数据量大时溢出 |
<br>agent_project/<br>├── agent/ # 核心业务(类比src/main/java)<br>│ ├── core/ # 智能体核心逻辑<br>│ ├── data/ # 数据处理<br>│ ├── api/ # 对外接口<br>│ └── exception/ # 自定义异常<br>├── config/ # 配置文件(类比src/main/resources)<br>├── utils/ # 工具类(类比util包)<br>├── tests/ # 单元测试(类比src/test/java)<br>├── docs/ # 文档<br>├── requirements.txt # 依赖清单(类比pom.xml)<br>└── README.md<br> | <br>agent_project/<br>├── core.py # 无分层,文件散落<br>├── test.py<br>├── config.yaml<br>└── utils.py<br> | |||
__init__.py(即使为空) | agent/core/__init__.py | __init__.py,导入时提示「No module named agent.core」 | ||
<br># requirements.txt(生产)<br>requests==2.31.0<br>langchain==0.1.10<br><br># requirements-dev.txt(开发)<br>pytest==7.4.3<br>flake8==6.1.0<br> | <br># 所有依赖混在requirements.txt<br>requests==2.31.0<br>pytest==7.4.3<br> | |||
pyproject.toml管理项目构建(替代 setup.py),贴合 Python 现代工程规范 | toml<br># pyproject.toml<br>[project]<br>name = "agent-core"<br>version = "1.0.0"<br>dependencies = ["requests==2.31.0"]<br> |
.gitignore | <br># .gitignore<br>__pycache__/<br>*.pyc<br>.env<br>*.log<br>venv/<br> | |||
feature/model-loaderbugfix/agent-init | test/fix1 |
结合 Python 包设计原则(PEP 420)、Java 包分层思想(领域驱动 / 分层架构),针对大模型智能体开发场景制定包结构规范,延续【强制】【推荐】【参考】分级,配套「说明」「正例」「反例」,确保包结构「分层清晰、职责单一、依赖可控」:
<br># 按业务领域拆分(大模型智能体场景)<br>agent/<br>├── core/ # 智能体核心逻辑(状态管理、任务调度)<br>├── adapter/ # 模型适配层(GPT/Claude/通义千问适配)<br>├── prompt/ # 提示工程(模板管理、变量渲染)<br>├── memory/ # 智能体记忆(短期/长期记忆存储)<br>└── output/ # 输出处理(响应格式化、敏感信息过滤)<br> | <br># 按技术类型拆分(混乱)<br>agent/<br>├── utils/ # 混有提示处理、模型调用、记忆操作的工具函数<br>├── classes/ # 所有类都放这里(核心类、适配类、记忆类)<br>└── functions/ # 所有函数都放这里<br> | |||
from agent.core.adapter.model.gpt import GPTClient),类比 Java 包层级不超过 4 层的规范;3 层足以覆盖绝大多数大模型智能体场景 | <br># 3层示例(顶级包+业务包+子功能包)<br>agent/adapter/gpt/ # agent(1)→ adapter(2)→ gpt(3)<br> | <br># 4层嵌套(过深)<br>agent/core/model/adapter/gpt/ # 导入路径冗长,维护成本高<br> | ||
__init__.py必须包含「包职责说明 Docstring」,禁止空__init__.py(无任何注释 / 导出) | __init__.py | python<br># agent/adapter/__init__.py<br>"""<br>模型适配层:统一不同大模型的调用接口,屏蔽模型间的参数/响应格式差异<br>支持GPT、Claude、通义千问等主流大模型,新增模型需实现BaseAdapter接口<br>"""<br>from .base import BaseAdapter<br>from .gpt import GPTAdapter<br>from .claude import ClaudeAdapter<br> | python<br># agent/adapter/__init__.py<br># 空文件,无任何注释/导出 | |
<br># 单向依赖(正确)<br>adapter/ → core/ (adapter导入core的BaseModel类)<br>prompt/ → core/ (prompt导入core的Config类)<br> | <br># 循环导入(错误)<br>core/ 导入 adapter/的GPTAdapter<br>adapter/ 导入 core/的BaseModel<br> | |||
<br># 通用包拆分<br>common/<br>├── log/ # 日志配置(统一日志格式、轮转)<br>├── crypto/ # 加密解密(API密钥脱敏)<br>└── config/ # 配置读取(统一加载YAML/环境变量)<br> | <br># 重复实现通用逻辑(错误)<br>agent/adapter/utils.py # 实现HTTP请求<br>agent/prompt/utils.py # 又实现一套HTTP请求<br> | |||
<br>config/<br>├── dev/ # 开发环境配置<br>│ ├── model_config.yaml<br>│ └── db_config.yaml<br>├── test/ # 测试环境配置<br>└── prod/ # 生产环境配置(敏感信息通过环境变量注入)<br> | <br># 配置混放(错误)<br>config/<br>├── model_config_dev.yaml<br>├── model_config_test.yaml<br>└── model_config_prod.yaml<br> | |||
<br># 镜像对齐(正确)<br>agent/core/agent_core.py → tests/agent/core/test_agent_core.py<br>agent/adapter/gpt/gpt_adapter.py → tests/agent/adapter/gpt/test_gpt_adapter.py<br> | <br># 测试文件散乱(错误)<br>tests/<br>├── test_agent_core.py<br>├── test_gpt_adapter.py<br>└── test_claude_adapter.py<br> | |||
agent/单顶级包;多智能体 / 多模块项目拆分顶级包,降低单包复杂度 | <br># 大型项目(多模块)<br>agent_llm/ # LLM智能体核心<br>agent_vector/ # 向量库管理模块<br>agent_api/ # 对外API模块<br>agent_admin/ # 后台管理模块<br><br># 小型项目(单模块)<br>agent/ # 所有逻辑在一个顶级包内<br> | <br># 小型项目过度拆分(错误)<br>agent_core/<br>agent_prompt/<br>agent_memory/<br> | ||
__init__.py,外部仅通过包名导入(禁止直接导入子模块) | python<br># agent/adapter/__init__.py 导出公共接口<br>from .base import BaseAdapter<br>from .gpt import GPTAdapter<br>from .claude import ClaudeAdapter<br><br># 外部导入(简洁)<br>from agent.adapter import GPTAdapter<br> | python<br># 外部直接导入子模块(耦合内部结构)<br>from agent.adapter.gpt.gpt_adapter import GPTAdapter<br> | ||
<br>agent/<br>├── init/ # 初始化(模型加载、配置读取)<br>├── run/ # 运行(任务执行、模型调用)<br>├── monitor/ # 监控(性能统计、异常告警)<br>└── stop/ # 停止(资源释放、状态保存)<br> | <br># 无生命周期拆分(复杂场景混乱)<br>agent/<br>├── core.py # 混有初始化、运行、停止逻辑<br> |
结合 uv 工具(现代 Python 包管理 / 虚拟环境工具,替代 pip/venv/poetry)的核心特性,对齐 Java 团队 Maven/Gradle 的项目管理习惯(依赖锁定、环境隔离、构建发布),制定以下规范,延续【强制】【推荐】【参考】分级,确保团队使用 uv 统一项目管理流程,降低环境不一致、依赖冲突问题:
uv init初始化项目,统一用pyproject.toml管理项目配置(替代 requirements.txt/setup.py) | uv init生成标准pyproject.toml(类比 Java 的 pom.xml/gradle.build),统一项目元信息、依赖、构建配置,禁止混用老旧的 requirements.txt | bash<br># 初始化项目(指定Python版本,对齐团队环境)<br>uv init agent-project --python 3.11<br># pyproject.toml核心配置示例<br>[project]<br>name = "agent-project"<br>version = "1.0.0"<br>dependencies = [ "requests==2.31.0", "langchain==0.1.10" ]<br> | bash<br># 未用uv init,仍用requirements.txt管理依赖<br>echo "requests==2.31.0" > requirements.txt<br>pip install -r requirements.txt<br> | |
uv venv创建项目专属虚拟环境,禁止全局安装依赖;虚拟环境目录统一命名为.venv,加入.gitignore | .venv是 uv 默认虚拟环境目录,统一命名便于团队识别 | bash<br># 创建虚拟环境(默认生成.venv目录)<br>uv venv<br># 激活虚拟环境(Linux/Mac)<br>source .venv/bin/activate<br># 激活虚拟环境(Windows)<br>.venv\Scripts\activate<br># .gitignore添加<br>.venv/<br> | bash<br># 全局安装依赖,无环境隔离<br>uv install requests==2.31.0 # 未激活虚拟环境,安装到全局<br># 虚拟环境命名混乱<br>uv venv agent-venv # 不同项目命名不一致<br> | |
uv add添加依赖,uv lock生成uv.lock并提交到仓库;禁止手动修改uv.lock | uv addpyproject.toml,uv lock生成精准的依赖锁文件(类比 Java 的 pom.lock/gradle.lock),确保团队所有成员依赖版本完全一致;手动修改锁文件会导致依赖不一致 | bash<br># 添加生产依赖<br>uv add requests==2.31.0<br># 添加开发依赖(分组管理)<br>uv add --dev pytest==7.4.3<br># 生成锁文件<br>uv lock<br># 提交到仓库<br>git add pyproject.toml uv.lock<br>git commit -m "添加requests/pytest依赖,锁定版本"<br> | bash<br># 手动修改pyproject.toml添加依赖<br>vim pyproject.toml # 手动写入requests==2.31.0<br># 未生成/提交uv.lock<br>uv add requests==2.31.0<br>git add pyproject.toml # 仅提交配置文件,无锁文件<br> | |
uv sync同步依赖(基于 pyproject.toml+uv.lock) | uv sync类比 Java 的mvn clean install,一键同步锁文件中的依赖版本,确保环境一致 | bash<br># 新成员拉取代码后,同步依赖(自动读取lock文件)<br>uv sync<br># 仅更新单个依赖并重新锁定<br>uv add requests==2.32.0<br>uv lock<br> | bash<br># 混用pip安装依赖,破坏uv锁文件<br>uv sync<br>pip install requests==2.32.0 # 导致实际依赖与lock文件不一致<br> | |
uv run执行项目命令(如启动、测试、打包),禁止直接在激活的虚拟环境中执行 | uv run.venv中的命令(类比 Java 的mvn exec:java),统一命令执行方式,避免环境激活遗漏 | bash<br># 运行测试(无需激活虚拟环境)<br>uv run pytest tests/<br># 运行项目主程序<br>uv run python agent/main.py<br> | bash<br># 激活虚拟环境后执行,易遗漏激活步骤<br>source .venv/bin/activate<br>pytest tests/<br>python agent/main.py<br> | |
pyproject.toml中用[project.optional-dependencies]定义;开发依赖统一放入dev分组 | toml<br># pyproject.toml配置<br>[project]<br>name = "agent-project"<br>dependencies = [ "requests==2.31.0" ]<br><br>[project.optional-dependencies]<br>dev = [ "pytest==7.4.3", "flake8==6.1.0", "black==24.2.0" ]<br>bash<br># 安装生产依赖+开发依赖<br>uv sync --all-extras<br># 仅安装生产依赖(生产环境)<br>uv sync<br> | toml<br># 开发依赖混入生产依赖<br>[project]<br>dependencies = [ "requests==2.31.0", "pytest==7.4.3" ]<br> | ||
.uv.toml或环境变量设置,禁止各自修改源 | .uv.toml放入项目根目录,团队共享配置 | toml<br># .uv.toml 统一镜像源配置<br>[registry]<br>index = "https://mirrors.aliyun.com/pypi/simple/"<br>bash<br># 或临时环境变量(CI/CD中使用)<br>UV_REGISTRY_INDEX=https://mirrors.aliyun.com/pypi/simple/ uv sync<br> | bash<br># 各自修改源,导致依赖拉取不一致<br>uv config set registry.index https://pypi.tuna.tsinghua.edu.cn/simple/<br> | |
uv run -s),封装常用命令(启动 / 测试 / 打包),放入pyproject.toml的[tool.uv.scripts] | mvn test/mvn package),统一团队操作命令,避免记复杂指令;脚本化后新人可快速上手 | toml<br># pyproject.toml配置脚本<br>[tool.uv.scripts]<br>test = "pytest tests/ -v" # 运行测试<br>start = "python agent/main.py" # 启动项目<br>lint = "flake8 agent/ tests/" # 代码检查<br>bash<br># 执行脚本(统一命令)<br>uv run test<br>uv run start<br> | bash<br># 无统一脚本,各自执行不同命令<br>uv run pytest tests/ -v # 有人加-v,有人不加<br>uv run python agent/main.py --dev # 参数不统一<br> | |
uv build构建项目包(wheel/sdist),uv publish发布(需配置 PyPI 凭据);构建产物放入dist/,加入.gitignore | mvn package构建 jar 包,uv build生成标准 Python 包格式,便于部署 / 发布;dist/为默认构建目录,统一管理产物 | bash<br># 构建项目包<br>uv build<br># 发布到PyPI(需提前配置UV_PYPI_TOKEN)<br>uv publish<br># .gitignore添加<br>dist/<br>*.whl<br>*.tar.gz<br> | bash<br># 手动打包,格式不标准<br>python setup.py sdist bdist_wheel # 未用uv build,易生成不兼容产物<br> | |
uv workspace管理,在根目录pyproject.toml中定义 workspace,子模块独立配置 | toml<br># 根目录pyproject.toml<br>[workspace]<br>members = [ "agent-core", "agent-api", "agent-utils" ]<br>bash<br># 根目录同步所有子模块依赖<br>uv sync<br># 进入子模块执行命令<br>cd agent-core && uv run test<br> | bash<br># 多模块项目无workspace,各自管理依赖<br>cd agent-core && uv sync<br>cd agent-api && uv sync # 重复操作,依赖易冲突<br> | ||
ghcr.io/astral-sh/uv),统一 CI 环境;缓存uv cache目录提升构建速度 | yaml<br># GitHub Actions示例(CI/CD配置)<br>jobs:<br> test:<br> runs-on: ubuntu-latest<br> steps:<br> - uses: actions/checkout@v4<br> - uses: astral-sh/setup-uv@v2 # 安装uv<br> - name: Cache uv dependencies<br> uses: actions/cache@v3<br> with:<br> path: ~/.cache/uv<br> key: ${{ runner.os }}-uv-${{ hashFiles('uv.lock') }}<br> - run: uv sync # 同步依赖<br> - run: uv run test # 运行测试<br> | yaml<br># CI中未用uv,仍用pip<br>steps:<br> - run: pip install -r requirements.txt<br> - run: pytest tests/<br> |
python<br># 单一职责:仅处理模型加载<br>class ModelLoader:<br> def load_config(self, model_name):<br> pass<br> def load_model(self, config):<br> pass<br><br># 单一职责:仅处理提示构建<br>class PromptBuilder:<br> def build(self, template, variables):<br> pass | python<br># 多职责:模型加载+提示构建+响应处理<br>class AgentUtil:<br> def load_model(self):<br> pass<br> def build_prompt(self):<br> pass<br> def handle_response(self):<br> pass | |||
python<br>from abc import ABC, abstractmethod<br><br>class LLMClient(ABC):<br> @abstractmethod<br> def generate(self, prompt: str) -> str:<br> pass<br><br>class GPTClient(LLMClient):<br> def generate(self, prompt: str) -> str:<br> # GPT实现<br> pass<br><br>class ClaudeClient(LLMClient):<br> def generate(self, prompt: str) -> str:<br> # Claude实现<br> pass | python<br># 无抽象,直接写死GPT实现<br>def generate(prompt: str) -> str:<br> # GPT调用逻辑<br> pass<br># 新增Claude时,需修改generate函数,违反开闭原则 | |||
python<br># 工具函数:通用字符串脱敏<br>def mask_sensitive(text: str) -> str:<br> # 脱敏逻辑<br> pass<br><br># 基类:通用模型配置加载<br>class BaseModelConfig:<br> def load_config(self, model_name):<br> # 通用加载逻辑<br> pass |