Skip to content

Latest commit

 

History

History
238 lines (197 loc) · 30.1 KB

File metadata and controls

238 lines (197 loc) · 30.1 KB

AI-Ink-Brain API(Python 后端)项目配置真值表(给总 Agent / 子 Agent)

最后校准:2026-05-14(P1-2CHATBI_PROMPT_GUARD_MODE — Unified JSON + SSE handle_unified_chat / handle_unified_chat_stream);此前 2026-05-13(P2CHATBI_V3_PLAN_PREVIEW_CONFIRM …)

目标:把本仓库的边界、入口、环境变量、目录地图、对外契约、安全注意事项整理成“可复制粘贴的真值表”。
说明:本文档只描述本仓库实际读取/依赖的内容;前端仓库的 PY_API_URL、Next BFF 等不在此展开(但会在边界里点名)。


A. 仓库身份与边界

真值 / 说明
仓库名(示例) ai-ink-brain-api-python
远程默认分支 main(以你本地 git branch / GitHub 默认分支为准)
技术栈摘要 FastAPI + Uvicorn;OpenAI SDK(指向 SiliconFlow 兼容接口);supabase-py;Supabase(Postgres + pgvector + FTS)
本仓负责的边界(Single Source of Truth) Embedding / Chunking / Retrieval / Hybrid Search / RAG 日志 的权威实现以本仓库代码为准;Cursor 规则载体.cursor/rules/*.mdc 为真值,根目录 .cursorrules 已移除(若外部引用仍以 .cursorrules 为准,须迁移至 .cursor/rules/*.mdc
本仓不负责的边界 博客页面渲染、内容编辑 UX、Next.js BFF 转发ai-ink-brain;本仓只提供 HTTP API
部署入口(概念) 本地:uvicorn main:app;Vercel:README 说明生产入口为 api/index.py(以 Vercel Python Runtime 配置为准)

B. Cursor / Agent 规则(本仓)

文件 作用 是否必须存在
.cursor/rules/*.mdc 分路径规则(图谱、RAG、错误处理等);当前人类/Agent 真值入口 建议必须(当前已存在多份 .mdc
.cursorrules 已移除;历史 .cursorrules 不再维护,若发现外部引用仍以该文件为准,须迁移至 .cursor/rules/*.mdc 不存在
AGENTS.md / CLAUDE.md 额外 Agent 指引 本仓 AGENTS.md 存在CLAUDE.md 可选)

.cursor/rules/*.mdc 要点(执行层摘要,以代码为准):

  • RAG 日志必须写入 rag_conversation_logs
  • pgvector 相似度使用 Cosine Distance(RPC match_documents
  • 每次请求必须处理 session_id,检索前读取最近 3-5 轮历史(当前实现为 5)
  • Legacy POST /api/py/chat 的助手输出为 StreamingResponse(text/plain)Unified 另提供 POST /api/py/unified/chat(JSON events[])与 /stream(SSE),见 §F
  • Hybrid:Vector + FTS,并融合排序

C. 环境变量(与代码读取点对齐)

读取规则:本仓库通过 api/rag_env.py 在 import 时加载仓库根目录 .env.local.envoverride=False)。
下表“谁读取”以实际 grep 命中为准。

名称 用途 必填/可选 谁读取(文件/模块) 典型值 / 留空行为 与 Supabase 维度一致性
NEXT_PUBLIC_SUPABASE_URL Supabase Project URL 必填(二选一) api/rag_env.py:pick_supabase_url()api/index.py 间接使用 形如 https://xxx.supabase.co 与项目无关
SUPABASE_URL Supabase URL 别名 可选(二选一) api/rag_env.py:pick_supabase_url() 留空则使用 NEXT_PUBLIC_SUPABASE_URL 与项目无关
SUPABASE_SERVICE_ROLE_KEY service_role key(服务端写库) 必填(二选一) api/rag_env.py:pick_supabase_service_key() 留空会导致无法创建 Supabase client 与项目无关
SUPABASE_SERVICE_KEY service key 别名 可选(二选一) api/rag_env.py:pick_supabase_service_key() 留空则使用 SUPABASE_SERVICE_ROLE_KEY 与项目无关
SUPABASE_HTTP_RETRIES PostgREST 请求(rag_conversation_logs 等 insert/select)遇 瞬时网络错误(如 Connection reset by peer / 超时)时的最大尝试次数 可选 api/rag_env.py:_supabase_http_retry_params()supabase_execute_with_retrysupabase_table_insert_with_retryapi/unified_chat.pyapi/agent_memory.pyapi/database_manager.py 默认 4;未设时可读别名 SUPABASE_INSERT_RETRIES;范围 clamp 112 与项目无关
SUPABASE_HTTP_RETRY_BASE_DELAY_S 上述重试的指数退避 初始间隔(秒) 可选 同上 默认 0.25;别名 SUPABASE_INSERT_RETRY_BASE_DELAY_S 与项目无关
SILICONFLOW_API_KEY SiliconFlow API Key 必填 api/index.py(chat);api/rag_env.py:must_siliconflow_api_key()(ingest) 留空:chat 直接 500;ingest 抛 RuntimeError 与项目无关
SILICONFLOW_BASE_URL OpenAI 兼容 Base URL 可选 api/index.pySILICONFLOW_BASE);api/rag_env.py:siliconflow_base() 默认 https://api.siliconflow.cn/v1 与项目无关
SILICONFLOW_EMBEDDING_MODEL Embedding 模型名 可选 api/index.pyapi/rag_env.py:siliconflow_embedding_model() 空字符串会被视为未设置:回退默认 Qwen/Qwen3-Embedding-0.6B(避免 CI/环境变量显式空值导致上游 400) 影响向量空间;需与入库一致
SILICONFLOW_EMBEDDING_DIMENSIONS Embedding 输出维度(Qwen3 需要) 可选 api/index.pyapi/rag_env.py:siliconflow_embedding_dimensions() 默认 1024;当模型名包含 Qwen3-Embedding 时传给 embeddings API 必须与 public.documents.embedding vector(N) 一致(默认 N=1024)
SILICONFLOW_CHAT_MODEL Chat 模型 可选 api/index.py 默认 deepseek-ai/DeepSeek-V4-Pro 与向量维度无关
SYNC_ADMIN_SECRET admin/sync Bearer secret(与前端 BFF 同值) 推荐 · portfolio 真值 api/rag_env.py:admin_secret()api/index.py:_require_auth() 留空且无废弃 fallback 时:鉴权接口 500 与项目无关
CHAT_API_SECRET Admin secret (已废弃 · 待删) 可选 fallback api/rag_env.py:admin_secret() 仅当未设 SYNC_ADMIN_SECRET 时读取 在新环境配置
NEXT_PUBLIC_ADMIN_SECRET Admin secret (已废弃 · 待删) 可选 fallback api/rag_env.py:admin_secret() 前端 不再使用;仅兼容旧 .env 在新环境配置
CHATBI_USE_AGENT Unified Chat 是否走 V2 Agent(ReAct)路径 可选 api/unified_chat.py 默认 false1/true/yes/on 开启 V2 与项目无关
CHATBI_SSE_INCREMENTAL Unified Agent 流式是否 边执行边 emit(vNext) 可选 api/unified_chat.py(规划) 默认 true(vNext 落地后);false强制 await run 后批量 replay,忽略 X-ChatBI-Sse-Contract: 2 的增量语义(仍须安全);组合真值见 SPEC-ChatBI-V2-Incremental-SSE-Timeline-vNext.md §9 与项目无关
CHATBI_SSE_EMIT_QUEUE_MAX G2 路径 emit → asyncio.Queuemaxsize(有界缓冲);队列满时先发 agent.llm.truncatedreason=backpressure)再阻塞入队(vNext §4.3) 可选 api/unified_chat.py 默认 512;合法范围 clamp 为 88192;单测可调低以验证背压 与项目无关
CHATBI_V2_DEBUG_LLM_PROMPTS V2 Unified:SSE/JSON 是否附带完整 LLM messages(agent.debug.llm_prompts 等) 可选 api/unified_chat.py:_debug_llm_prompts_enabled() 1/true/yes/on 开启;与请求体 debug_llm_prompts: true 任一满足即生效;含 system 指令,生产慎用 与项目无关
CHATBI_JSON_LOG V3 P0-2:是否输出 单行 JSON 结构化日志(chatbi.obstext2sql_phase_end / text2sql_tool_call_end;根字段含 request_id/run_id,与 SSE meta.run_id 对齐;text2sql_phases_msToolResult.data 同形) 可选 api/chatbi_json_log.pyapi/tools.py::text2sql_executeapi/agent.pyChatBIAgent 默认 关闭1/true/yes/on 开启;见 SPEC-ChatBI-V3-Logging-Trace.md 与项目无关
CHATBI_PROMPT_GUARD_MODE V3 P1-2:Unified JSONSSE/unified/chat/stream)路径上对用户 query 的 Prompt 注入 PoC 可选 api/chatbi_prompt_guard.pyapi/unified_chat.py::handle_unified_chathandle_unified_chat_stream 默认 offwarn 命中时写 prompt_guard_warn 并继续下游;block 命中时写 prompt_guard_deny不调用上游 LLM(JSON:eventserror;SSE:chainerror + done.ok=false);见 docs/tasks/active/task_chatbi_v3_prompt_injection_guard_poc_v1.md 与项目无关
CHATBI_RATE_LIMIT_ENABLED V3 P2-1b:是否对 POST /api/py/chatPOST /api/py/unified/chat/stream 启用按 客户端 IP 限流 可选 api/chatbi_rate_limit.py(middleware) 默认 开启0/false/no/off 关闭;CHATBI_RATE_LIMIT_MAX_REQUESTS=0 时等同关闭 与项目无关
CHATBI_RATE_LIMIT_MAX_REQUESTS 滑动窗口内允许的最大请求数(每 IP) 可选 api/chatbi_rate_limit.py 默认 60;非法值回退默认并 日志告警 与项目无关
CHATBI_RATE_LIMIT_WINDOW_SEC 滑动窗口长度(秒) 可选 api/chatbi_rate_limit.py 默认 60;非法值回退默认并 日志告警 与项目无关
CHATBI_CIRCUIT_BREAKER_ENABLED V3 P2-1c:是否对外呼(LLM / Supabase)启用熔断 可选 api/chatbi_circuit_breaker.py 默认 开启0/false 关闭 与项目无关
CHATBI_CB_FAILURE_THRESHOLD 连续失败次数阈值(达到后 open 可选 api/chatbi_circuit_breaker.py 默认 3 与项目无关
CHATBI_CB_RECOVERY_TIMEOUT_SEC open 状态恢复窗口(秒),超时后进入 half-open 探测 可选 api/chatbi_circuit_breaker.py 默认 30 与项目无关
CHATBI_CB_HALF_OPEN_SUCCESS_THRESHOLD half-open 连续成功次数(达到后回到 closed 可选 api/chatbi_circuit_breaker.py 默认 1 与项目无关
CHATBI_ACCESS_TOKEN_PEPPER 可选全局 pepper:参与 SHA256(pepper_bytes + 明文 token),须与运维本地脚本 tmp/diary/local_chatbi_access_token_gen.py(见 docs/diary/POINTER_local_chatbi_access_token_gen.md)及 Supabase 插入的 key_hash 一致 可选 api/chatbi_access_hash.pyapi/chatbi_principal.py;本地脚本 tmp/diary/local_chatbi_access_token_gen.py 留空则 pepper 为空字节串;把 pepper 提交进 Git 与项目无关
CHATBI_AGENT_DB_PERSIST_TIMEOUT_S V2 Agent 每轮结束写 rag_conversation_logs最大等待秒数(在发出 SSE done 之前 await 可选 api/unified_chat.py:_await_persist_chatbi_v2_agent_log() 默认 12;范围 clamp 为 1120;超时则 done.persist.ok=false 且先发 errorstage=agent_db 与项目无关
CHATBI_V2_INTENT_LLM V2 意图是否调用 SiliconFlow LLM 可选 api/intent_agent.pytests/test_intent_agent_accuracy.pytests/benchmark_intent_latency.py 默认 truefalse 为纯启发式/V1 超时降级,不创建上游 client(CI 零外呼) 与项目无关
INTENT_LLM_MODEL 意图识别所用 chat 模型名 可选 api/intent_agent.py 默认 deepseek-ai/DeepSeek-V4-Pro 与项目无关
CHATBI_V2_INTENT_EVAL 启用 60 条意图准确率 pytest(@pytest.mark.intent_eval 可选 tests/test_intent_agent_accuracy.py 不设为跳过;需密钥时配 CHATBI_V2_INTENT_LLM=true + SILICONFLOW_API_KEY 与项目无关
CHATBI_V2_INTENT_EVAL_OUT 评测结果 JSONL/同 stem CSV 输出路径 可选 tests/test_intent_agent_accuracy.py 默认 tests/_out/intent_accuracy.jsonl相对路径(推荐):以 ai-ink-brain-api-python 仓库根为锚写 tests/_out/foo.jsonl;或以 tests/ 为锚写 _out/foo.jsonl(与 pytest 启动目录无关) 与项目无关
CHATBI_V2_INTENT_EVAL_PROGRESS 60 条评测是否逐条打印开始/结束行 可选 tests/test_intent_agent_accuracy.py 默认 true;CI 内 test_stub_eval_end_to_end_writes_exports 强制 false 与项目无关
CHATBI_V2_INTENT_BENCH_N Intent 延迟基准采样次数 可选 tests/benchmark_intent_latency.py 默认 100 与项目无关
CHATBI_V2_INTENT_BENCH_COLD_WARM Intent 延迟脚本是否输出「冷缓存 vs 热缓存」两轮 P50/P95 可选 tests/benchmark_intent_latency.py 1/true/... 开启;需 PYTHONPATH=. 从仓库根运行脚本 与项目无关
DEBUG_INTENT_CACHE Intent 缓存诊断日志(仅 key_hash + latency_ms,不打印完整 query) 可选 api/intent_agent.py 1/true/... 开启 与项目无关
CHATBI_V2_INTENT_TIMEOUT_S Intent LLM 单次等待上限(秒),asyncio.wait_for 包住上游 chat.completions;超时后 raw_response.used=v1_fallback,走 V1 规则路由 可选 api/intent_agent.pydecide_intent_v2)、tests/benchmark_intent_latency.py 未设时沿用调用方默认 3.0;SiliconFlow 较慢时建议 153060 条 intent_eval 冻结验收docs/diary/2026-05-06-p1-intent-benchmark.md(复跑五使用 60 与项目无关
INTENT_MIN_CONFIDENCE V2 Agent 传入 decide_intent_v2 的最低置信度;低于则填 fallback(映射见 api/intent_agent.py:_fallback_tool_by_low_confidence 可选 api/agent.pyChatBIAgent 默认 0.6 与项目无关
INTENT_HINTS_ENABLED 是否加载 intent_hints.yaml 并注入 Intent LLM Prompt(Portfolio 站点上下文) 可选 api/intent_hints.py · api/intent_agent.py::_llm_decide_v2 默认 开启0/false/no/off 关闭 · 行为等同现行无注入 CHATBI_V2_INTENT_LLM 正交
INTENT_HINTS_PATH 覆盖 Intent 站点上下文 YAML 路径(绝对或相对仓库根) 可选 api/intent_hints.py::_resolve_hints_path() 留空 → docs/chatbi/v1/intent_hints.yaml 与项目无关
INTENT_HINTS_ARBITRATION Step2:配置命中 + LLM direct_answer 时强制 rag_search 可选 api/intent_hints.py::arbitration_enabled() · api/intent_agent.py::apply_hints_arbitration() 默认 开启0/false/no/off 关闭 · 行为等同 Step1 Prompt-only INTENT_HINTS_ENABLED 正交
CHATBI_V3_LOW_CONFIDENCE_CLARIFY P1-4 §4.3:Intent 候选为 text2sql_queryconfidence < INTENT_MIN_CONFIDENCEprefer=auto 时,先发 agent.clarify 并短路首轮 text2sql(JSON / SSE 全路径;SSE 增量路径见 api/agent.py emit) 可选 api/agent.py 默认 关闭1/true/yes/on 开启;与 SPEC-ChatBI-V2-Events.md §3.2.1 对齐 与项目无关
CHATBI_V3_CLARIFY_PROMPT_USE_REASONING 澄清帧 prompt_for_user 是否拼接 Intent LLM reasoning可能含表名/列名,生产慎用;默认关走泛化追问文案) 可选 api/agent.py 默认 关闭1/true/yes/on 开启 与 RBAC 展示策略相关
CHATBI_V3_PLAN_PREVIEW_CONFIRM 低置信澄清时是否生成 SQL 预览、签发 plan_execution_token,并在 prompt_for_user 中说明 TTL 与重试规则;用户下一轮同问句带令牌可跳过澄清短路(见 SPEC-ChatBI-V3-LowConfidence-Plan-Confirm.md 可选 api/agent.pyapi/chatbi_plan_token.pyapi/unified_chat.py 默认 开启(未设置或空视为开);0/false/no/off 关闭;依赖 CHATBI_V3_LOW_CONFIDENCE_CLARIFY=1 才会进入澄清分支 与 Text2SQL 权限 / 外显 SQL 策略相关
CHATBI_PLAN_TOKEN_TTL_S plan_execution_token 有效秒数(绑定 session + 问句指纹) 可选 api/chatbi_plan_token.py:plan_token_ttl_s() 默认 120;clamp 30~600 与项目无关
CHATBI_PLAN_EXEC_TOKEN_SECRET HMAC 密钥材料(留空则 SHA256 派生自 admin_secret(),再否则开发回退串) 可选 api/chatbi_plan_token.py:_token_secret() 生产建议显式设置 敏感

| CHATBI_V2_INTENT_BENCH_RUN | 是否执行 pytest 中 B1 延迟基准(intent_benchmark) | 可选 | tests/benchmark_intent_latency.py | 默认不跑;true 时依赖外网与 SILICONFLOW_API_KEY | 与项目无关 | | RAG_MATCH_THRESHOLD | match_documents 相似度阈值过滤 | 可选 | api/rag_shared.py:parse_match_threshold();由 api/index.py(Legacy chat)、api/unified_chat.pyapi/code_retrieval.py(注入)调用 | 默认 0.3none/null/off 关闭阈值过滤;非法值或 <0 回退默认;>1 视为关闭过滤(None) | 与项目无关 | | RAG_EMBEDDING_MISMATCH_MODE | 检索前校验 documents.metadata.embedding_model 与运行时 SILICONFLOW_EMBEDDING_MODEL 是否一致 | 可选 | api/rag_embedding_guard.pyapi/tools.pyapi/unified_chat.pyapi/index.py | 默认 block:不一致时返回 RAG_EMBEDDING_MODEL_MISMATCH(禁止 silent 空命中);warn 仅 stderr;off 关闭。换模型须三处 env 同改 + 全量 re-sync;运维脚本 python tools/rag_embedding_consistency_check.py | 须与入库 metadata.embedding_model 一致 | | DEBUG_RAG / RAG_DEBUG | RAG 调试日志开关 | 可选 | api/index.py | 1/true/yes/onNODE_ENV=development | 与项目无关 | | NODE_ENV | 影响 debug 判定 | 可选 | api/index.py | development 会打开部分 debug 行为 | 与项目无关 | | CONTENT_DEFAULT_YEAR | 解析 MM-DD 日期时的默认年份 | 可选 | api/index.py | 默认 2026 | 与项目无关 | | DEBUG_INGEST | ingest 调试输出 | 可选 | api/ingest_pipeline.py | 默认关闭 | 与项目无关 | | CONTENT_ROOT | Markdown 内容根目录(用于 ingest/sync) | 可选 | api/ingest_pipeline.py:get_all_markdown_chunks() | 留空:使用后端仓库内 REPO_ROOT/content;设置则扫描该目录(不存在则返回空) | 与项目无关 | | EMBEDDING_DIM | 期望向量维度(入库校验) | 可选 | api/rag_env.py:expected_embedding_dim() | 默认 1024 | 必须与 vector(N) 一致 | | SILICONFLOW_EMBEDDING_DIM | EMBEDDING_DIM 兼容别名 | 可选 | api/rag_env.py:expected_embedding_dim() | 留空则看 EMBEDDING_DIM | 必须与 vector(N) 一致 | | TEXT2SQL_VALUE_HINTS_PATH | Text2SQL 列值域 / 同义词 YAML 路径 | 可选 | api/text2sql_value_hints.py:_resolve_hints_path() | 留空则使用仓库内 docs/text2sql/v1/value_hints.yaml(存在则加载) | 与 Text2SQL 样例库枚举一致 | | TEXT2SQL_VALUE_HINTS_ENABLED | 是否注入值域块 | 可选 | api/text2sql_value_hints.py:_resolve_hints_path() | 0/false/no/off 关闭;未设时默认开启(仍受路径与文件是否存在约束) | 与项目无关 | | TEXT2SQL_DISTINCT_PROBE | 是否对 allowlist 列执行 DISTINCT 并与 YAML values 并集 | 可选 | api/text2sql_value_hints.py:_is_distinct_probe_enabled() | 1/true 开启;未设或 0/false 等为关闭 | 依赖 TEXT2SQL_DATABASE_URL;失败列降级为仅 YAML | | TEXT2SQL_DISTINCT_MAX | 每条 DISTINCT 的 LIMIT 上限 | 可选 | api/text2sql_value_hints.py:_distinct_row_limit() | 默认 64; clamp 至 1..500 | 与项目无关 | | TEXT2SQL_DISTINCT_COLUMNS | allowlist:schema.table.column,英文逗号分隔 | 可选 | api/text2sql_value_hints.py:parse_distinct_allowlist() | 例:public.agent_info.gender;仅 [A-Za-z0-9_] 段接受 | 与样例库表一致 | | TEXT2SQL_DISTINCT_MAX_PROBES | 单次请求最多执行的探针次数 | 可选 | api/text2sql_value_hints.py:_distinct_max_probes() | 默认 8; clamp 1..32 | 与项目无关 | | TEXT2SQL_DISTINCT_STMT_TIMEOUT_MS | 单条探针 SQL 的 statement_timeout(毫秒) | 可选 | api/text2sql_value_hints.py:_distinct_statement_timeout_ms() | 留空则不设置;有值时经 execute_select_sql(..., statement_timeout_ms=) 注入 SET LOCAL | 与项目无关 | | CHATBI_TEXT2SQL_LLM_TIMEOUT_S | Text2SQL 两段 LLM(生成 SQL / 总结)共用的 超时秒数兜底 | 可选 | api/tools.py::text2sql_executeasyncio.wait_for) | 未设时代码默认 120.0;当 CHATBI_TEXT2SQL_LLM_SQL_TIMEOUT_S / CHATBI_TEXT2SQL_LLM_SUMMARY_TIMEOUT_S 已分别设置时,本变量仅作二者缺省时的回退 | 与项目无关 | | CHATBI_TEXT2SQL_LLM_SQL_TIMEOUT_S | llm_generate_sql 阶段 timeout(秒) | 可选 | api/tools.py::text2sql_execute | 未设时回退 CHATBI_TEXT2SQL_LLM_TIMEOUT_S → 再未设则代码默认 120.0 | 与项目无关 | | CHATBI_TEXT2SQL_LLM_SUMMARY_TIMEOUT_S | llm_summarize 阶段 timeout(秒) | 可选 | api/tools.py::text2sql_execute | 未设时回退 CHATBI_TEXT2SQL_LLM_TIMEOUT_S → 再未设则代码默认 120.0 | 与项目无关 | | CHATBI_TEXT2SQL_SUMMARY_LLM_MODEL | Text2SQL 总结阶段 chat 模型名(可选加速 / 降级) | 可选 | api/tools.py::text2sql_execute | 未设置或仅空白时,与 Intent 默认一致(INTENT_LLM_MODEL 默认 deepseek-ai/DeepSeek-V4-Pro,与 api/intent_agent.py 对齐) | 与项目无关 | | TEXT2SQL_DIALOGUE_CONTEXT_MAX_LEN | 多轮 history_to_rewrite_block 注入 build_sql_prompt 前的 最大字符数(超出保留尾部) | 可选 | api/tools.py::text2sql_execute | 默认 8000<=0 表示不截断 | 与项目无关 | | TEXT2SQL_SCHEMA_PREFETCH | 写入/更新意图下是否在 LLM 生成前 只读预取 information_schema.columns | 可选 | api/text2sql_schema_prefetch.py::schema_prefetch_enabled() | 0/false/no/off 关闭;1/true 强制开启;未设时若已配置 TEXT2SQL_DATABASE_URL 则默认开启 | 依赖 TEXT2SQL_DATABASE_URL | | TEXT2SQL_SCHEMA_PREFETCH_TIMEOUT_MS | 预取查询 SET LOCAL statement_timeout(毫秒) | 可选 | api/text2sql_schema_prefetch.py::fetch_public_table_columns_sync() | 默认 8000;clamp 200..60000 | 与项目无关 | | TEXT2SQL_SCHEMA_PREFETCH_MAX_ROWS | 预取结果 LIMIT 上限 | 可选 | api/text2sql_schema_prefetch.py::fetch_public_table_columns_sync() | 默认 2000;clamp 10..20000 | 与项目无关 |

补充:.cursorrules 文本里提到 SUPABASE_URL / SUPABASE_SERVICE_ROLE_KEY,但代码实际优先读取 NEXT_PUBLIC_SUPABASE_URLSUPABASE_SERVICE_ROLE_KEY(并支持别名)。以代码为准

C.1 Portfolio 演示站(ingest / sync · PORTFOLIO-RAG-DEMO@2026-06-01

用途:投递前 portfolio 演示站 RAG 语料与前端 ai-ink-brain/content/ 同源入库。
操作 RUNBOOKdocs/harness/guides/RUNBOOK_portfolio_rag_five_questions_v1_zh.md
治理 SPECdocs/spec/governance/SPEC-Governance-Portfolio-RAG-Demo-v1_zh.md

真值 / 说明
CONTENT_ROOT 生产 / 预发必须显式设置,指向前端仓 content/ 根目录(含 methodology/resume/evidence/)。留空时代码回退 REPO_ROOT/content(后端仓内)——禁止作为 portfolio 生产真值。
本地示例 CONTENT_ROOT=/path/to/ai-ink-brain/content(与 .env.example 注释一致;路径随本机 checkout 而变)
category 规则 ingest 取相对路径 第一段metadata.categorymethodology / resume / evidence);见 api/ingest_pipeline.py::get_all_markdown_chunks()
入库接口 POST /api/py/admin/sync(异步 job);portfolio RUNBOOK 不含 admin/ingest
admin 鉴权 SYNC_ADMIN_SECRET(与前端同值)→ Bearer / x-admin-tokenCHAT_API_SECRET / NEXT_PUBLIC_ADMIN_SECRET 已废弃 · 待删(见前端 SPEC-portfolio_admin_sync_auth_v1_zh.md
Embedding SILICONFLOW_API_KEY + EMBEDDING_DIM(默认 1024)须与 Supabase documents.embedding vector(N) 一致
Supabase 写库 NEXT_PUBLIC_SUPABASE_URL + SUPABASE_SERVICE_ROLE_KEY
部署边界 演示 URL 沿用现有前端 Vercel 项目(NEXT_PUBLIC_SITE_MODE=portfolio);变更后端 API 域名或 Supabase 项目名(SPEC Q-3)
DEBUG_INGEST 本地排障可 1生产关闭
Secrets 禁止将 admin / Supabase / SiliconFlow 密钥提交 Git;平台 Secrets 或本地 .env

生产 mount 语义(概念):Python 服务进程须能 read 挂载后的 CONTENT_ROOT 目录树;Vercel/serverless redeploy 期间 job 可能丢失(404 → 重新 POST sync)。


D. 运行与脚本

真值 / 说明
Python 版本建议 3.11+(与前端 CI ingest workflow 对齐)
依赖安装 pip install -r requirements.txt
本地启动 python -m uvicorn main:app --host 127.0.0.1 --port 8000
本仓是否包含 Node (纯 Python)
包管理器 (不使用 pnpm/npm)

E. 目录地图(“去哪改”)

目录/文件 入口/职责
main.py 本地 uvicorn 入口:转发 api.index:app
api/index.py FastAPI 路由注册、Legacy POST /api/py/chat 流式外壳、管理端 ingest/sync、Unified 路由投递至 unified_chat
api/unified_chat.py Unified Chat:JSON / SSE 事件链、RAG + Text2SQL 路由;详见图谱 docs/_tech_graph/00_main.md
api/rag_shared.py Legacy 与 Unified 共用的无状态 RAG 小工具(如阈值解析、snippet 去前缀)
api/rag_env.py .env 加载、Supabase/SiliconFlow 选择器、Embedding 参数封装
api/database_manager.py Supabase 写入/读取 rag_conversation_logs
api/ingest_pipeline.py Markdown ingest/sync、批量 embedding、写 documents
supabase/sql/ 数据库初始化/迁移脚本(init.sqlhybrid_search.sql 等)
docs/tasks/ 后端任务规格(Task03/Task04 等)
docs/_tech_graph/ 技术图谱与 _manifest.json / _contract_manifest.json(CI:tech_graph_manifest_check / tech_graph_drift_check
.github/workflows/ 已存在tech-graph.yml(图谱/契约门禁)、tech-graph-contract.yml(契约相关校验);真值以 YAML 内 jobs 为准

F. 对外契约(易忘项)

契约 路径/说明
GET /api/py/live 进程存活探针(轻量 200;ok=true;不做重依赖外呼)
GET /api/py/ready 依赖就绪探针(检查 Supabase 配置与 SILICONFLOW_API_KEY;失败返回 503 + components[]
GET /api/py/health 兼容历史探针,当前与 /api/py/live 返回语义保持一致
POST /api/py/chat 流式 text/plain;检索 hybrid;失败降级策略见下;超限时 429 JSON(error_code=RATE_LIMIT_EXCEEDED,可选 retry_after
GET /api/py/chat/history session_id 拉取 rag_conversation_logs鉴权:Ink admin(_require_auth请求头 X-ChatBI-Access-Token(DB 明文,与 Next BFF 对齐;实现见 api/index.py::_require_rag_history_auth
GET /api/py/chatbi/access/verify ChatBI 明文 token 探活(JSON:ok / access_level / principal_kind / token_id);鉴权:与 Unified 相同, Authorization: Bearer <明文>require_chatbi_principal
POST /api/py/admin/ingest 同步扫描内容并写入 documents(重删再插策略)
POST /api/py/admin/sync + GET /api/py/admin/sync?jobId= 异步任务(内存队列,serverless 不保证持久)
POST /api/py/unified/chat Unified 非流式:events[] JSON;字段与锚点以 docs/_tech_graph/_contract_manifest.json 为准;鉴权:仅 Authorization: Bearer + public.chatbi_access_tokens(见 api/chatbi_principal.py),不再接受与 Legacy 相同的 API_KEY 明文并行校验
POST /api/py/unified/chat/stream Unified SSE:链式事件流;契约同上;鉴权同上;超限时 429 JSON(error_code=RATE_LIMIT_EXCEEDED,可选 retry_after

F.1 流式回答 + 证据链(Task04)

机制 说明
x-sources response header JSON(percent-encoded),前端优先解析
流末尾 marker ---RAG_SOURCES_JSON--- + JSON(兼容代理丢 header)

F.2 检索降级(Embedding 失败)

行为 说明
Embedding 失败 不再 502;跳过 vector,走 keyword_documents(FTS)
日志字段 metadata.match.hybrid.modehybrid / keyword_onlyembedding_error

G. 安全与密钥

规则
绝不能提交进 Git .env.env.local、任何 service role key、SiliconFlow key
GitHub Actions(若在本仓跑) 使用 Secrets 注入;不要写进 workflow 明文
最小权限原则 service role key 仅用于服务端;不要暴露给浏览器

H. 任务驱动流程(与本仓协作约定)

约定 说明
任务入口 前端仓库 content/tasks/*.md + 本仓库 docs/tasks/*.md(后端实现/验收)
子 Agent 交付物(建议) 本文件:docs/meta/PROJECT_CONFIG_AI_INK_BRAIN_API_PYTHON.md(持续更新)
变更回填 任务完成后应回填:涉及文件、关键 env、SQL 执行顺序、验收 SQL/接口

附:Supabase 必备对象清单(与本仓代码强绑定)

对象 说明
public.chatbi_access_tokens ChatBI V3:key_hash + access_level + subject_user_id(L2 必填);Unified Depends(require_chatbi_principal) 查询
public.chatbi_sql_table_policy Text2SQL 表级 min_*_level;NULL=该操作类型关闭
public.chatbi_user_portrait L2 肖像/长久 Prompt;写路径列白名单见任务单
public.documents 向量列默认 vector(1024)(见 supabase/sql/init.sql
public.match_documents(...) Vector Top-k + threshold
public.keyword_documents(...) FTS keyword 路(见 supabase/sql/hybrid_search.sql
public.refresh_documents_fts_tokens_for_paths(...) ingest 后刷新 fts_tokens(兜底)
public.rag_conversation_logs RAG 全链路日志表