-
- single ReAct entry for all free text: 7 fixed tools (useSkill + 6); flow knowledge lives in 5 skill files (resources/skills/*.md, first line = brief for prompt index; xly.skills.dir overrides for hot reload) - useSkill returns skill body and logs skill_active; projection pins the active skill full text on the flow card until confirm/cancel/new skill - system prompt from template prompts/system.txt (domain map + skill index); bench reads the same files to avoid replica drift - delete IntentService/Intent/SlotFillService/LlmJsonClient/StateService/ OkHttpUtil and route()/handleCreate/handleWrite/deriveWriteAction/ ground/withState; dimension-split regex migrated into FormCollectTool prefill assist (model provably fails dimension splitting) - anti-fabrication guards now unconditional (zero-tools+digits retry, WRITE_CLAIM check); invariant layer and button endpoints untouched - bench_ext: --arch new (same-source prompt/skills) and --fifty (bench50 cases judged on full trajectory for both arches)
-
- chat:ledger becomes the only conversation store: model messages land as user/tool_call(payload)/tool_result/ai events via EventLogChatMemory (per-event rightPush, no more whole-blob read-modify-write races) - EventProjectionService: one renderer for both frontend history and LLM context (system+flow card / deterministic digest of expired turns / ~6000-char verbatim recent turns, current turn payload-exact) - pinned active-flow card (form pending / proposal pending / skill_active full text) unpinned on executed/cancelled/skill_done - anti-fab retry nudges logged as internal user events (LLM-visible, hidden from history); grounded suffixes never duplicate user events - delete ProjectedChatMemory; RedisChatMemoryStore demoted to legacy read-only compat (old convs age out via 30d TTL); conv list lazy cleanup - tests: projection correctness + concurrent stream/confirm append safety
-
…ction, anti-fabrication guards - LedgerService: append-only chat
{conv} events incl. deterministic-path
form/clarify/proposal/confirm-outcome; history replays from ledger
- StateService: chat:state:{conv} slots (上轮意图/最近实体/在办单据) written by code,
fed to intent gate + write-slot extraction and appended to agent user text
- ProjectedChatMemory replaces MessageWindowChatMemory: full store + char-budget
projection, old tool results collapsed to one line, current turn kept intact
- RedisChatMemoryStore.appendTurn patches memory holes on deterministic paths;
op confirm/cancel outcomes recorded to ledger/state/memory
- anti-fabrication (tool_choice=required NOT enforced by Ollama 0.32.3, retested):
query turn zero-tools+digits → one forced retry then flag; write claim without
proposeWrite → corrective notice
-
- delete queryData (QueryTool, sqlChatModel bean, llm.sql-model, jsqlparser dep) - delete kgSearch (findForms stays), delete loadSkill (SkillTool/SkillService) - single system prompt (domain map + 业务常识) replaces 3 ToolScope versions; ToolScope removed - intent gate reduced to 查询/新增/操作已有单据/其他 with class definitions only; write action derived from utterance in router - dedup: shared locateRecord() in ProposeWriteTool; name-field/label lookups consolidated into FormResolverService
-
- Replace langchain4j-ollama with langchain4j-open-ai; AgentFactory/ QueryTool depend on ChatModel/StreamingChatModel interfaces - OllamaJsonClient -> LlmJsonClient: raw /v1/chat/completions with response_format json_schema; single OkHttpClient instance - Thinking off at all 3 call sites via reasoning_effort=none (the only switch that works on /v1; think:false and /no_think are ignored) - Drop client-side length params (num_ctx/num_predict/max_tokens) — server-side OLLAMA_CONTEXT_LENGTH=16384 on xlyllm covers them - Unified tracing: TracingChatModelListener.record() shared by listener callbacks and LlmJsonClient; per-request model name from ctx; sql model now has the listener too (was untraced and mislabeled) - Config keys langchain4j.ollama.* -> llm.{base-url,api-key,chat-model, sql-model}; both models = qwen3.6-27b-iq3:latest (tools+thinking+ vision, verified: streaming tool-calls / json_schema / reasoning off) Verified end-to-end on :8199: intent gate traced (340/28 tokens), agent tool loop, correct answers; warm 1-4s, cold load ~96s (KEEP_ALIVE=30s).
-
Add a deterministic §5 intent stage before ReAct: extract {intent, form, entities, missing slots} via constrained JSON, then expose only the 3-5 tools relevant to that intent instead of all 12. New: - agent/Intent, agent/ToolScope: intent + visible-tool-set model - service/IntentService: constrained-JSON intent/entity extraction - service/OllamaJsonClient: JSON-mode Ollama calls - service/SlotFillService: slot extraction/prefill of known values Wire through AgentFactory, SystemPromptService, QueryTool, ProposeWriteTool, ErpClient, AgentChatController, OpController, chat.html.
-
Root cause of the reported failure: - collectForm sourced fields from gdsconfigformslave -> quote master's form config only exposes 3 system/header fields (失效时间/制单人/单据日期); user filled 单据日期(tCreateDate,datetime)='12' -> ERP type mismatch. - proposeCreate never coerced by column type, never FK-resolved names, used addBusinessData (no billNo). Fixes: - FormResolverService: businessFields() curated authoritative label->{col,fk} for quoquotationmaster (客户名称/产品名称/数量/长/宽/高/单价 -> real writable cols sCustomerId/sProductId(FK)/dQty/dLength/dWidth/dHeight/dPrice), field-dict fallback for other tables; columnTypes/coerce/typeDefault/resolveFk/nextBillNo(BJD+YYYYMM+seq); isSystemColumn excludes reserve/money/rate/discount/person/date/bool/tenant/maker; resolveMasterForm excludes param/slave/control/config/color secondary tables. - collectForm: fields from businessFields (excludes system/header); gdsconfigformslave fallback. - proposeCreate: label->{col,fk} via businessFields; FK name->id; type-coerce; skip system cols; auto sId/sFormId + generated sBillNo; type-correct required defaults. - ErpClient.createForm: addUpdateDelBusinessData(handleType=add)+moduleId (was addBusinessData). - ProposeWriteTool.resolveForm unified to FormResolverService. Verified via agent end-to-end (real write): collectForm shows correct fields; created quoquotationmaster BJD202607082 = Little Antelope / 妇科三醇乳膏 / qty5000 / dims / price, tenant+maker+date auto-injected. -
…ormCollect + Skills + KgSearch - AgentIdentity + AgentFactory: build agent per request with token+form-allowlist carried in tool instances (per-call context; robust vs LC4j callback threading) - ErpClient: token-aware read/write/examine; user-token expiry does NOT silently re-login as dev-admin (no privilege escalation) - AuthzService: devIdentity()/userIdentity() resolve granted-form set (sAuthsId) - proposeExamine tool + OpController examine dispatch + forward user Authorization on confirm - InteractionTool.askUser (structured options), FormCollectTool.collectForm (real gdsconfigformslave schema) - SkillService + SkillTool.loadSkill + ai_skill digest in system prompt - KgQueryTool.kgSearch: L2 neighbors/flow + L3 field->table - tools ErpReadTool/ProposeWriteTool/QueryTool/FormCollectTool now per-request (not @Component)