refactor(api): TOML 配置 SSOT、统一错误契约、Auth/事务加固与可观测性 (#33)

配置 SSOT(TOML + .env)
统一错误契约
Auth 与事务边界
Redis / Celery 可靠性:业务 Redis(DB/0)与 Celery broker/backend(DB/1)显式拆分;连接池、sync client
可观测性(OpenTelemetry + LGTM)
This commit is contained in:
Sully
2026-05-22 13:44:50 +08:00
committed by GitHub
parent f09ae248f9
commit 53e0065e3e
298 changed files with 15247 additions and 4344 deletions

View File

@@ -15,6 +15,7 @@ from app.core.config import settings
from app.core.llm_call import LLMCallError, llm_json_call
from app.core.logging import get_logger
from app.features.conversation.models import Segment
from app.features.memoir.constants import memoir
logger = get_logger(__name__)
@@ -68,7 +69,7 @@ def run_batch_phase1_prep(
llm,
prompt,
BatchPhase1LLMOutput,
max_tokens=int(settings.memoir_phase1_batch_llm_max_tokens),
max_tokens=int(memoir.phase1_batch_llm_max_tokens),
agent="BatchPhase1Prep.run",
)
except LLMCallError as e:

View File

@@ -26,6 +26,7 @@ from app.core.config import settings
from app.core.json_utils import extract_json_payload
from app.core.llm_call import LLMCallError, llm_json_call
from app.core.logging import get_logger
from app.features.memoir.constants import memoir
logger = get_logger(__name__)
@@ -144,7 +145,7 @@ class ClassificationAgent:
llm,
prompt,
ClassificationOutput,
max_tokens=settings.memoir_classification_max_tokens,
max_tokens=memoir.classification_max_tokens,
agent="ClassificationAgent.classify",
)
category = _normalize_llm_category(out.category)

View File

@@ -14,6 +14,7 @@ from app.agents.stage_constants import normalize_chat_stage
from app.core.config import settings
from app.core.llm_call import LLMCallError, llm_json_call
from app.core.logging import get_logger
from app.features.memoir.constants import memoir
logger = get_logger(__name__)
@@ -64,7 +65,7 @@ class ExtractionAgent:
llm,
prompt,
StateExtractionOutput,
max_tokens=settings.memoir_extraction_max_tokens,
max_tokens=memoir.extraction_max_tokens,
agent="ExtractionAgent.extract",
)
raw_slots = parsed.slots or {}

View File

@@ -13,6 +13,7 @@ from app.agents.memoir.schemas import FidelityOutput
from app.core.config import settings
from app.core.llm_call import LLMCallError, llm_json_call
from app.core.logging import get_logger
from app.features.memoir.constants import memoir
logger = get_logger(__name__)
@@ -46,7 +47,7 @@ class FidelityCheckAgent:
existing_canonical_markdown: str | None = None,
is_append: bool = False,
) -> bool:
if not llm or not settings.memoir_fidelity_check_enabled:
if not llm or not memoir.fidelity_check_enabled:
return True
oral = (oral_text or "").strip()
gen = (narrative_json or "").strip()
@@ -108,7 +109,7 @@ class FidelityCheckAgent:
llm,
prompt,
FidelityOutput,
max_tokens=settings.memoir_fidelity_check_max_tokens,
max_tokens=memoir.fidelity_check_max_tokens,
agent="FidelityCheckAgent.passes",
)
ok = bool(out.pass_)
@@ -120,7 +121,7 @@ class FidelityCheckAgent:
return ok
except LLMCallError as e:
logger.warning("FidelityCheckAgent 解析失败: {}", e)
if is_append or settings.memoir_fidelity_fail_open_on_parse_error:
if is_append or memoir.fidelity_fail_open_on_parse_error:
logger.info("event=fidelity_parse_fail_open is_append={}", is_append)
return True
logger.warning("event=fidelity_parse_fail_closed")

View File

@@ -18,6 +18,7 @@ from app.core.config import settings
from app.core.langchain_llm import invoke_json_object
from app.core.llm_call import llm_json_call
from app.core.logging import get_logger
from app.features.memoir.constants import memoir
logger = get_logger(__name__)
@@ -63,7 +64,7 @@ class NarrativeAgent:
llm,
prompt,
MemoirTitleOutput,
max_tokens=settings.memoir_title_max_tokens,
max_tokens=memoir.title_max_tokens,
agent="NarrativeAgent.generate_title",
fallback_factory=_title_fallback,
)
@@ -118,7 +119,7 @@ class NarrativeAgent:
occupation=occupation,
language=language,
)
max_tokens = int(settings.memoir_narrative_merge_max_tokens)
max_tokens = int(memoir.narrative_merge_max_tokens)
agent_name = "NarrativeAgent.generate_narrative_merge"
else:
prompt = get_narrative_json_prompt(
@@ -132,7 +133,7 @@ class NarrativeAgent:
occupation=occupation,
language=language,
)
max_tokens = int(settings.memoir_narrative_max_tokens)
max_tokens = int(memoir.narrative_max_tokens)
agent_name = "NarrativeAgent.generate_narrative"
return invoke_json_object(
llm,

View File

@@ -29,6 +29,7 @@ from app.core.agent_logging import agent_span, agent_summary_enabled, log_agent_
from app.core.config import settings
from app.core.logging import get_logger
from app.features.conversation.models import Segment
from app.features.memoir.constants import memoir
logger = get_logger(__name__)
@@ -90,7 +91,7 @@ class MemoirOrchestrator:
use_batch = (
bool(segments)
and classify_extract_llm is not None
and settings.memoir_phase1_batch_llm_enabled
and memoir.phase1_batch_llm_enabled
)
if use_batch:
try:
@@ -204,7 +205,7 @@ class MemoirOrchestrator:
segments,
state,
classify_extract_llm,
chunk_size=int(settings.memoir_phase1_batch_llm_chunk_size),
chunk_size=int(memoir.phase1_batch_llm_chunk_size),
on_chunk=on_phase1_chunk,
language=language,
)

View File

@@ -21,6 +21,8 @@ from app.core.config import settings
from app.core.llm_call import LLMCallError, llm_json_call
from app.core.logging import get_logger
from app.features.story.models import Story
from app.features.memoir.constants import memoir
from app.features.story.constants import story
logger = get_logger(__name__)
@@ -47,7 +49,7 @@ def default_append_target_story_id(
ordered = sort_stories_for_route(
candidate_stories,
meta,
summary_min_chars=int(settings.story_route_summary_min_chars),
summary_min_chars=int(story.route_summary_min_chars),
)
if not ordered:
return None
@@ -247,7 +249,7 @@ class StoryRouteAgent:
llm,
prompt,
StoryRouteDecision,
max_tokens=settings.memoir_story_route_max_tokens,
max_tokens=memoir.story_route_max_tokens,
agent="StoryRouteAgent.decide",
fallback_factory=_decide_fallback,
)
@@ -295,7 +297,7 @@ class StoryRouteAgent:
llm,
prompt,
StoryBatchPlan,
max_tokens=settings.memoir_story_batch_plan_max_tokens,
max_tokens=memoir.story_batch_plan_max_tokens,
agent="StoryRouteAgent.plan_batch",
)
except LLMCallError as e:

View File

@@ -15,6 +15,7 @@ if TYPE_CHECKING:
from app.core.config import Settings
from app.features.story.models import Story
from app.features.story.constants import story
_PLAIN_SNIPPET_NOISE = re.compile(r"[`*_#]+")
@@ -213,11 +214,11 @@ def build_route_candidate_rows(
) -> list[dict[str, Any]]:
"""排序 + 完整候选行(尚未做总预算降级)。"""
meta = story_meta or {}
summary_min = int(settings.story_route_summary_min_chars)
summary_min = int(story.route_summary_min_chars)
ordered = sort_stories_for_route(stories, meta, summary_min_chars=summary_min)
body_max = int(settings.story_route_candidate_body_max_chars)
head_c = int(settings.story_route_long_body_head_chars)
tail_c = int(settings.story_route_long_body_tail_chars)
body_max = int(story.route_candidate_body_max_chars)
head_c = int(story.route_long_body_head_chars)
tail_c = int(story.route_long_body_tail_chars)
rows: list[dict[str, Any]] = []
for s in ordered:
rows.append(
@@ -231,8 +232,8 @@ def build_route_candidate_rows(
)
)
by_id = {str(s.id): s for s in ordered}
total_max = int(settings.story_route_candidate_total_max_chars)
index_prev = int(settings.story_route_index_preview_chars)
total_max = int(story.route_candidate_total_max_chars)
index_prev = int(story.route_index_preview_chars)
return apply_total_budget_downgrade(
rows,
stories_by_id=by_id,