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:
@@ -48,6 +48,9 @@ from app.core.config import settings
|
||||
from app.core.llm_gateway import LlmGateway, LlmUseCase
|
||||
from app.core.logging import get_logger
|
||||
from app.features.conversation.input_normalize import normalize_chat_input_for_agent
|
||||
from app.core.runtime_constants import agent_log_defaults
|
||||
from app.features.conversation.constants import chat
|
||||
from app.features.story.constants import story
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
@@ -171,8 +174,8 @@ class InterviewAgent:
|
||||
if normalized_user_message is not None:
|
||||
return (normalized_user_message or "").strip()
|
||||
llm_n = None
|
||||
if settings.chat_input_normalize_enabled and (
|
||||
(settings.chat_input_normalize_mode or "").strip().lower() == "llm"
|
||||
if chat.input_normalize_enabled and (
|
||||
(chat.input_normalize_mode or "").strip().lower() == "llm"
|
||||
):
|
||||
llm_n = self.llm
|
||||
return normalize_chat_input_for_agent(user_message or "", llm=llm_n)
|
||||
@@ -218,16 +221,16 @@ class InterviewAgent:
|
||||
du = self._detect_user_stage(text_for_model)
|
||||
hw = await get_history_with_window(
|
||||
conversation_id,
|
||||
max_pairs=settings.chat_history_max_pairs,
|
||||
max_chars=settings.chat_history_max_chars,
|
||||
max_pairs=chat.history_max_pairs,
|
||||
max_chars=chat.history_max_chars,
|
||||
)
|
||||
recent_questions = extract_recent_questions(hw.window)
|
||||
conversation_turn_total = hw.turn_total
|
||||
all_stages_coverage = narrative_state.all_stages_coverage()
|
||||
persona = normalize_interview_persona(settings.chat_interview_persona)
|
||||
max_segments = int(settings.chat_interview_max_segments)
|
||||
max_tokens = int(settings.chat_interview_max_tokens)
|
||||
max_chars = int(settings.chat_interview_max_chars_per_segment)
|
||||
persona = normalize_interview_persona(chat.interview_persona)
|
||||
max_segments = int(chat.interview_max_segments)
|
||||
max_tokens = int(chat.interview_max_tokens)
|
||||
max_chars = int(chat.interview_max_chars_per_segment)
|
||||
|
||||
turn_plan = plan_interview_turn(
|
||||
current_stage=memoir_state.current_stage,
|
||||
@@ -246,7 +249,7 @@ class InterviewAgent:
|
||||
reply_planner_raw = ""
|
||||
baseline_mode = turn_plan.mode
|
||||
baseline_primary_focus = turn_plan.primary_focus
|
||||
if settings.chat_reply_planner_llm_enabled:
|
||||
if chat.reply_planner_llm_enabled:
|
||||
rq_preview = (
|
||||
"\n".join(recent_questions[-4:])
|
||||
if recent_questions
|
||||
@@ -258,8 +261,8 @@ class InterviewAgent:
|
||||
text_for_model=text_for_model,
|
||||
memory_evidence_text=(memory_planner_text or memory_evidence_text)
|
||||
or "",
|
||||
max_tokens=int(settings.chat_reply_planner_max_tokens),
|
||||
temperature=float(settings.chat_reply_planner_temperature),
|
||||
max_tokens=int(chat.reply_planner_max_tokens),
|
||||
temperature=float(chat.reply_planner_temperature),
|
||||
scene_cues_for_planner=scene_cues_for_planner or [],
|
||||
recent_questions_preview=rq_preview,
|
||||
)
|
||||
@@ -310,12 +313,12 @@ class InterviewAgent:
|
||||
"InterviewAgent.generate_response.prompt",
|
||||
format_history_string(
|
||||
messages,
|
||||
omit_system_body=settings.agent_log_omit_system_message_body,
|
||||
omit_system_body=agent_log_defaults.omit_system_message_body,
|
||||
),
|
||||
)
|
||||
chat_llm = self.llm.bind(
|
||||
max_tokens=max_tokens,
|
||||
temperature=float(settings.chat_interview_temperature),
|
||||
temperature=float(chat.interview_temperature),
|
||||
)
|
||||
prompt_chars = _message_contents_char_count(messages)
|
||||
llm_t0 = time.perf_counter()
|
||||
@@ -377,7 +380,7 @@ class InterviewAgent:
|
||||
"InterviewAgent.generate_response.retry_prompt",
|
||||
format_history_string(
|
||||
retry_messages,
|
||||
omit_system_body=settings.agent_log_omit_system_message_body,
|
||||
omit_system_body=agent_log_defaults.omit_system_message_body,
|
||||
),
|
||||
)
|
||||
llm_t1 = time.perf_counter()
|
||||
@@ -445,7 +448,7 @@ class InterviewAgent:
|
||||
"duplicate_question_guard_llm_retry": retry_used,
|
||||
"autobiographical_boundary_guard_triggered": auto_bio,
|
||||
"reply_planner_llm_used": bool(
|
||||
settings.chat_reply_planner_llm_enabled
|
||||
chat.reply_planner_llm_enabled
|
||||
and (reply_planner_raw or "").strip()
|
||||
),
|
||||
"reply_planner_raw_preview": (reply_planner_raw or "")[:800],
|
||||
@@ -483,7 +486,7 @@ class InterviewAgent:
|
||||
)
|
||||
slot_table = SLOT_NAME_MAP_EN if language == "en" else SLOT_NAME_MAP
|
||||
empty_slots_readable = [slot_table.get(s, s) for s in empty_slots]
|
||||
persona = normalize_interview_persona(settings.chat_interview_persona)
|
||||
persona = normalize_interview_persona(chat.interview_persona)
|
||||
prompt = get_opening_prompt(
|
||||
current_stage=memoir_state.current_stage,
|
||||
empty_slots_readable=empty_slots_readable,
|
||||
@@ -497,8 +500,8 @@ class InterviewAgent:
|
||||
)
|
||||
hw = await get_history_with_window(
|
||||
conversation_id,
|
||||
max_pairs=settings.chat_history_max_pairs,
|
||||
max_chars=settings.chat_history_max_chars,
|
||||
max_pairs=chat.history_max_pairs,
|
||||
max_chars=chat.history_max_chars,
|
||||
)
|
||||
messages: List[Any] = [SystemMessage(content=prompt)]
|
||||
messages.extend(hw.window)
|
||||
@@ -520,12 +523,12 @@ class InterviewAgent:
|
||||
"InterviewAgent.opening.prompt",
|
||||
format_history_string(
|
||||
messages,
|
||||
omit_system_body=settings.agent_log_omit_system_message_body,
|
||||
omit_system_body=agent_log_defaults.omit_system_message_body,
|
||||
),
|
||||
)
|
||||
opening_llm = self.llm.bind(
|
||||
max_tokens=settings.chat_opening_max_tokens,
|
||||
temperature=float(settings.chat_interview_temperature),
|
||||
max_tokens=chat.opening_max_tokens,
|
||||
temperature=float(chat.interview_temperature),
|
||||
)
|
||||
prompt_chars = _message_contents_char_count(messages)
|
||||
llm_t0 = time.perf_counter()
|
||||
@@ -564,7 +567,7 @@ class InterviewAgent:
|
||||
raw_list = segments_from_llm_response(response_text, max_segments=2)
|
||||
if not raw_list:
|
||||
raw_list = [response_text.strip()]
|
||||
max_chars = int(settings.chat_interview_max_chars_per_segment)
|
||||
max_chars = int(chat.interview_max_chars_per_segment)
|
||||
out = truncate_chat_segments(
|
||||
raw_list,
|
||||
max_segments=2,
|
||||
@@ -612,7 +615,7 @@ class InterviewAgent:
|
||||
)
|
||||
slot_table = SLOT_NAME_MAP_EN if language == "en" else SLOT_NAME_MAP
|
||||
empty_slots_readable = [slot_table.get(s, s) for s in empty_slots]
|
||||
persona = normalize_interview_persona(settings.chat_interview_persona)
|
||||
persona = normalize_interview_persona(chat.interview_persona)
|
||||
prompt = get_re_greeting_prompt(
|
||||
current_stage=memoir_state.current_stage,
|
||||
empty_slots_readable=empty_slots_readable,
|
||||
@@ -627,8 +630,8 @@ class InterviewAgent:
|
||||
)
|
||||
hw = await get_history_with_window(
|
||||
conversation_id,
|
||||
max_pairs=settings.chat_history_max_pairs,
|
||||
max_chars=settings.chat_history_max_chars,
|
||||
max_pairs=chat.history_max_pairs,
|
||||
max_chars=chat.history_max_chars,
|
||||
)
|
||||
messages: List[Any] = [SystemMessage(content=prompt)]
|
||||
messages.extend(hw.window)
|
||||
@@ -647,12 +650,12 @@ class InterviewAgent:
|
||||
"InterviewAgent.re_greeting.prompt",
|
||||
format_history_string(
|
||||
messages,
|
||||
omit_system_body=settings.agent_log_omit_system_message_body,
|
||||
omit_system_body=agent_log_defaults.omit_system_message_body,
|
||||
),
|
||||
)
|
||||
re_greet_llm = self.llm.bind(
|
||||
max_tokens=settings.chat_opening_max_tokens,
|
||||
temperature=float(settings.chat_interview_temperature),
|
||||
max_tokens=chat.opening_max_tokens,
|
||||
temperature=float(chat.interview_temperature),
|
||||
)
|
||||
llm_t0 = time.perf_counter()
|
||||
with agent_span(
|
||||
@@ -691,7 +694,7 @@ class InterviewAgent:
|
||||
raw_list = segments_from_llm_response(response_text, max_segments=2)
|
||||
if not raw_list:
|
||||
raw_list = [response_text.strip()]
|
||||
max_chars = int(settings.chat_interview_max_chars_per_segment)
|
||||
max_chars = int(chat.interview_max_chars_per_segment)
|
||||
out = truncate_chat_segments(
|
||||
raw_list,
|
||||
max_segments=2,
|
||||
|
||||
Reference in New Issue
Block a user