Files
meida_backend/.env.example
T
xsl d5f366fa4c chore(prep): shared groundwork for the Sprint-2 parallel batch
第二批(T6~T11)协调提交:
- 迁移 0005:kb 七表(entity/relation/rule/chunk vector1024+tsv 生成列/
  asset/color/gap),HNSW+GIN 索引,FK 级联
- ORM:七个 Kb* 模型(pgvector Vector/TSVECTOR/Computed)
- 配置:检索与 embedding、华为 JWKS、短信全参数组
- 错误码:40110/40111/42910/42911/61000
- 骨架路由:kb.py + auth_sms.py(已注册);依赖:tencentcloud-sdk-python-sms
  + spike extra(onnxruntime/opencv);gitignore:models/ 与 spike 输出
2026-08-14 17:01:43 +08:00

146 lines
8.7 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 复制为 .env 后填入真实值。.env 已在 .gitignore 中,不要提交。
# dev/staging/prod 由部署平台注入环境变量,不使用 .env(架构文档 §11.2)。
APP_ENV=local
APP_NAME=meida-backend
API_PREFIX=/api/v1
DEBUG=true
LOG_LEVEL=INFO
LOG_JSON=true
# 需要额外脱敏的字段名,逗号分隔;默认清单见 packages/shared/logging.py
LOG_EXTRA_REDACT_KEYS=
# ── 数据库 / Redis ─────────────────────────────────────────────────────────
# 端口刻意用 55432 / 56379,避免与本机已有的 PostgreSQL、Redis 抢端口
DATABASE_URL=postgresql+asyncpg://meida:meida@localhost:55432/meida
DB_POOL_SIZE=10
DB_MAX_OVERFLOW=20
DB_ECHO=false
REDIS_URL=redis://localhost:56379/0
CELERY_BROKER_URL=redis://localhost:56379/1
CELERY_RESULT_BACKEND=redis://localhost:56379/2
# ── 鉴权 ──────────────────────────────────────────────────────────────────
# 生成:openssl rand -hex 32 。staging/prod 若沿用占位值会启动失败
JWT_SECRET=change-me-local-only-do-not-use-outside-local
JWT_ALGORITHM=HS256
JWT_ACCESS_TTL_SECONDS=900
JWT_ISSUER=meida
# 免登录换 token 的调试入口,仅本地/联调可开
DEV_AUTH_ENABLED=true
# ── LLM 路由 ──────────────────────────────────────────────────────────────
LLM_PRIMARY_PROVIDER=deepseek
LLM_BACKUP_PROVIDER=zhipu
LLM_STRUCTURED_MAX_RETRIES=2
LLM_CIRCUIT_FAILURE_THRESHOLD=3
LLM_CIRCUIT_COOLDOWN_SECONDS=30
# 按场景覆盖模型与采样参数,如 {"agent_chat":{"temperature":0.5}}
LLM_SCENE_OVERRIDES_JSON={}
DEEPSEEK_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
DEEPSEEK_BASE_URL=https://api.deepseek.com/v1
DEEPSEEK_MODEL=deepseek-v4-flash
DEEPSEEK_TIMEOUT_SECONDS=30
ZHIPU_API_KEY=
ZHIPU_BASE_URL=https://open.bigmodel.cn/api/paas/v4
ZHIPU_MODEL=glm-4-flash
ZHIPU_TIMEOUT_SECONDS=30
# ── Prompt 缓存纪律 ───────────────────────────────────────────────────────
# strict:固定前缀里出现时间戳/随机值等易变 token 直接启动失败。
# 命中缓存的输入价格只有未命中的 1/30,前缀被污染会让输入成本翻数十倍。
LLM_CACHE_PREFIX_MODE=strict
PROMPTS_DIR=prompts
# ── 成本单价(单位:分 / 百万 token)──────────────────────────────────────
# 取自 DeepSeek 官方价目表。2026-08-17 00:00 起改为峰谷定价:
# 高峰(北京时间 09:00-12:00、14:00-18:00)单价是空闲时段的 2 倍。
# 因此这里要配两套,由 packages/llm/cost.py 按调用时刻选择。
# flash 空闲:缓存命中 ¥0.05 / 输入 ¥1.5 / 输出 ¥4.5 每百万 token
LLM_COST_RATES_JSON={"deepseek-v4-flash":{"input_cents_per_mtok":"150","cached_input_cents_per_mtok":"5","output_cents_per_mtok":"450"},"deepseek-v4-pro":{"input_cents_per_mtok":"450","cached_input_cents_per_mtok":"15","output_cents_per_mtok":"1350"},"glm-4-flash":{"input_cents_per_mtok":"10","cached_input_cents_per_mtok":"10","output_cents_per_mtok":"10"}}
# flash 高峰:缓存命中 ¥0.10 / 输入 ¥3 / 输出 ¥9 每百万 token
LLM_COST_RATES_PEAK_JSON={"deepseek-v4-flash":{"input_cents_per_mtok":"300","cached_input_cents_per_mtok":"10","output_cents_per_mtok":"900"},"deepseek-v4-pro":{"input_cents_per_mtok":"900","cached_input_cents_per_mtok":"30","output_cents_per_mtok":"2700"},"glm-4-flash":{"input_cents_per_mtok":"10","cached_input_cents_per_mtok":"10","output_cents_per_mtok":"10"}}
# 未登记的模型按这个价算。刻意取高档:宁可高估触发熔断,也不要低估成本形成盲区
LLM_DEFAULT_COST_RATE_JSON={"input_cents_per_mtok":"300","cached_input_cents_per_mtok":"10","output_cents_per_mtok":"900"}
LLM_PEAK_PRICING_ENABLED=true
# ── 全局日成本熔断(NFR-COST-02)─────────────────────────────────────────
# 按用户配额封不住总成本(总成本 = 用户数 × 人均,用户数无上限),
# 真正封顶的只有这个全局开关。
# 100000 分 = ¥1000/天,是按 8-17 之前旧单价推的占位,不是验收值。
# 峰谷生效后须用实测 token 分布重算(T-P1-25b),否则熔断会在错误位置触发。
LLM_DAILY_BUDGET_ENABLED=true
LLM_DAILY_BUDGET_CENTS=100000
LLM_BUDGET_TIMEZONE_OFFSET_HOURS=8
# ── 可观测性 ──────────────────────────────────────────────────────────────
OTEL_ENABLED=false
OTEL_SERVICE_NAME=meida-api
OTEL_EXPORTER_OTLP_ENDPOINT=
PROMETHEUS_ENABLED=true
# ── 四档分级降级(T-P1-25b,架构 §13.3)──────────────────────────────────
# JSON 为列表;blocked 支持 "*";allow 仅 block_all 档有意义(纯文本对话放行)。
# 留空则使用内置默认四档(与下面示例一致)。
LLM_BUDGET_TIERS_JSON=[{"threshold":0.6,"name":"warn","blocked":[]},{"threshold":0.8,"name":"degrade_secondary","blocked":["hd_export","report_regen"]},{"threshold":0.9,"name":"degrade_generation","blocked":["hairstyle","tryon"]},{"threshold":1.0,"name":"block_all","blocked":"*","allow":["agent_chat"]}]
# ── 会话(FR-ACC-05)───────────────────────────────────────────────────────
REFRESH_TOKEN_TTL_SECONDS=2592000
# ── 任务奖励(FR-BILL-03/04)───────────────────────────────────────────────
# amount 均为占位值 1:正式数值待产品在产品方案 §3.2 定稿后改此处,不改代码。
# claim_period 决定幂等粒度(同一任务同周期只能领一次)。
TASK_BONUS_RULES_JSON={"sign_in":{"quota_key":"agent_chat","amount":1,"claim_period":"day"},"profile_complete":{"quota_key":"agent_chat","amount":1,"claim_period":"lifetime"},"report_feedback":{"quota_key":"report_regen","amount":1,"claim_period":"day"},"share_report":{"quota_key":"tryon","amount":1,"claim_period":"day"},"invite_friend":{"quota_key":"tryon","amount":1,"claim_period":"day"}}
# ── 客户端埋点(FR-SYS-06)─────────────────────────────────────────────────
EVENTS_MAX_BATCH=50
EVENTS_PROPS_MAX_BYTES=8192
# ── 腾讯云 COS 直传(FR-SYS-03 / T-P1-27)──────────────────────────────────
# 密钥只在此文件对应的真实 .env 里出现;四桶按《前置开通清单》创建后填名称。
COS_REGION=ap-shanghai
COS_SECRET_ID=
COS_SECRET_KEY=
COS_BUCKET_TEMP=meida-temp
COS_BUCKET_USER=meida-user
COS_BUCKET_KB=meida-kb
COS_BUCKET_REPORT=meida-report
COS_PRESIGN_EXPIRE_SECONDS=600
UPLOAD_MAX_BYTES=20971520
UPLOAD_ALLOWED_TYPES=image/jpeg,image/png,image/webp
UPLOAD_SCENES_JSON={"report_photo":{"bucket":"temp"},"avatar":{"bucket":"temp"}}
# ── 知识库与检索(架构 §8.3,TD-08)────────────────────────────────────────
# 当前 embedding 为确定性假实现(dev/test);真实 BGE-M3 ONNX 接入时只换这里。
KB_VECTOR_DIMENSIONS=1024
KB_EMBEDDING_MODEL=deterministic-v1
KB_EMBEDDING_DEVICE=cpu
RETRIEVAL_TOP_K=50
RETRIEVAL_RERANK_WEIGHTS_JSON={"vector":0.45,"keyword":0.2,"rule":0.25,"freshness":0.1}
# ── 华为账号登录(FR-ACC-01;真实联调待 AGC 配置,见《前置开通清单》§3)────
HUAWEI_JWKS_URL=https://oauth-login.cloud.huawei.com/oauth2/v3/certs
HUAWEI_AUDIENCE=
HUAWEI_ISSUER=https://accounts.huawei.com
HUAWEI_JWKS_CACHE_SECONDS=86400
# ── 手机号验证码登录(FR-ACC-04/14,TD-32)─────────────────────────────────
# fake = 验证码打日志(dev);tencent = 真实发送(签名审核通过后切换并填下方凭证)
SMS_PROVIDER=fake
TENCENT_SMS_SECRET_ID=
TENCENT_SMS_SECRET_KEY=
TENCENT_SMS_SDK_APP_ID=
TENCENT_SMS_SIGN_NAME=
TENCENT_SMS_TEMPLATE_ID=
SMS_CODE_TTL_SECONDS=300
SMS_CODE_LENGTH=6
SMS_VERIFY_MAX_ATTEMPTS=5
SMS_RESEND_COOLDOWN_SECONDS=60
SMS_HOURLY_LIMIT=5
SMS_DAILY_LIMIT=10
SMS_IP_DAILY_LIMIT=20
SMS_DEVICE_DAILY_LIMIT=10