FastGPT maintains full history server-side; LangGraph truncated the
injected history at a hardcoded 50 messages, so long conversations
behaved differently across backends.
- Config.AGENT_HISTORY_MESSAGES (env): max messages injected into the
model prompt (recent N, both roles counted); default 50 unchanged;
larger values support long conversations; 0 = no truncation, matching
FastGPT's full-history semantics. Only the injected window is
affected - dialogue stays fully persisted in the checkpoint.
- validate(): rejects negative values; 0 and positive accepted
- conversation_history reads the config (import-time class attribute,
monkeypatched in tests); explicit None-check keeps 0 falsy-safe
- .env.example documents the knob
Verified: 225 unit tests (6 new history-window tests)
Replaces the unequal SLA (LLM 30s/2 retries vs FastGPT client 60s/3)
that made the LangGraph backend look less stable under gray release.
- core/fastgpt_client: FASTGPT_TIMEOUT_SECONDS / FASTGPT_MAX_RETRIES
module constants (were inline literals in lifespan)
- agent/llm: OpenAILLMService defaults 60.0s / 3 retries
- core/config: named-profile fallback defaults 60/3 (prefixed and
JSON-dict forms)
- contract test test/backends/test_sla_alignment.py pins both sides to
the same constants so the SLA cannot drift apart again
- retry backoff intentionally differs (FastGPT fixed 1s vs LLM
exponential) and is documented; aligned parameters are per-call
timeout and max retry count
Verified: 215 unit tests (3 new SLA contract tests)
- Config.llm_profiles: LLM_PROVIDERS declares names, each group defined by
LLM_<NAME>_BASE_URL/_API_KEY/_MODEL (required) and optional _TIMEOUT_SECONDS/
_MAX_RETRIES/_TEMPERATURE/_EXTRA_BODY; JSON-dict form of LLM_PROVIDERS also
supported. LLM_PROVIDER selects the active group at runtime; empty/fake =
offline scripted model
- removed fixed openai/kimi groups (AGENT_LLM_PROVIDER, KIMI_LLM_*)
- validate(): incomplete groups and unknown LLM_PROVIDER fail fast with
the configured-name list
- OpenAILLMService: http client trust_env from LLM_HTTP_TRUST_ENV (default
False - local gateways must bypass the Windows system proxy)
- build_llm_service(provider): explicit name or LLM_PROVIDER default
- .env/.env.example: deepseek + kimi groups side by side, switch by
LLM_PROVIDER=kimi (thinking off via EXTRA_BODY reasoning_effort=none)
- eval probe scripts updated to the new config interface
Verified: 172 unit tests; live calls succeed on both providers
(deepseek 28s, kimi 6.6s, both emitting valid <state> prefixes)
- prompts/collection.md: versioned collection system prompt extracted
from workflow node yQaBxfrWjbRr with source/version/porting notes
- llm.py: LLMService protocol; FakeLLMService (scripted, records
calls); OpenAILLMService (async, wait_for timeout with cancellation,
retry only on timeout/429/connection, errors normalized)
- collect.py: run_collect reference impl - one LLM call produces
state prefix + body, controlled repair (max 1 retry) for missing
prefix or illegal stage proposal, whitelist guard, CollectReplyError
without raw model content; dialogue history + confirmed fields
injected into prompt so the model skips known info (作业4-5)
- fields.py / clock.py: three-state field candidates (unknown/
candidate/confirmed), per-type validation (count not inferred from
description, future time rejected), injectable Clock
- graph.py: welcome node - first message returns fixed 1001 greeting
without LLM (mirrors workflow is_first_message -> Assigned Reply#3),
route empty stage to welcome
- endpoints/delete_session: backend switch - langgraph clears graph
checkpoint, fastgpt path unchanged
- config: AGENT_LLM_PROVIDER fake|openai with validation
- untrack .env (secrets), move template to root .env.example
Verified:
- pytest 103 passed; smoke turns 1/2/1
- Real LLM e2e: POST /chat multi-turn context works
- Golden eval collection_skip_known_info: 12/12 cases pass
- Golden eval no_false: 8/10 cases pass; 4 confirm/photo cases fail
at final step - model routes on short reply '对' (prompt-adherence
gap, photo/confirm stages are assignment 5 scope); recorded in
evals/results/20261020-144856
Known limits: field extraction from model reply not wired (stub);
photo/confirm nodes still scaffold; clarify counting is approximate.