Vendor CS Agent
A KakaoTalk chatbot that answers only tagged questions, never hands off, and rewrites any number or brand that does not match the evidence
Staff PCs collect the conversations and upload them to the server, and replies also go out from staff Macs. The server agent writes answers by searching per-counterpart records and the LightRAG knowledge hub (graph RAG over entities and relations, 13 workspaces). Since 2026-09-02 it no longer asks follow-up questions and answers only tagged questions, with no handoff. In exchange, it checks amounts, percentages, and brands against the evidence, and if they do not match it searches again and rewrites.
- A similar name does not decide the counterpart. The '(1234)' at the start of a room name is read as the ID. If the name part points better to a different vendor, at jamo similarity 0.80 or higher, it is treated as an ID typo and blocked. Without an ID, only a single name that is an exact match or a containment match is accepted. Sharing just a common suffix already scored 0.81–0.88, so I dropped fuzzy matching.
- One message came in 51 times. kakaocli resends the latest message of an unread room every 2 seconds. When I counted, it was 51 times for 1 message, 170–200 per minute. A (room, message, unread count, sent by me) key drops resends within 15 seconds. Because the unread count is in the key, the signal from closing and reopening a room still gets through.
- Numbers and brands are checked in code. Amounts and percentages in the draft are normalized ('3만원' is 30000원). Values not in the retrieved evidence, and words one character off from an evidence brand, are flagged as violations. If the LLM judgment fails or is ambiguous, it counts as no evidence. When a violation is found, it searches again with the reason attached and rewrites.
- 'Sent' is written only when it is true. If the send API was not called in that turn, completed-action sentences like '제안서 보내드렸습니다' ("I've sent the proposal") are removed. When a retry arrives with the same idempotency key, it checks the actual queue state. Items in progress or already sent are not re-queued; only failed ones are retried. If the state is unknown, it returns an error instead of success.
- Other counterparts' cases are masked. If a vendor name other than the current counterpart appears in search results, it is replaced with [다른 벤더], and the model is told that the replacement happened. All 11 Spark tools that query company-wide data are blocked in external rooms. The vendor name passed to the product recommendation lookup is set by the server, not the model.
- Delivery is counted from the KakaoTalk DB. A baseline count is taken before sending. After sending, it counts how many text messages and photos were added in the local DB and resends only what is missing. Photos get an extra 60 seconds. In a 70-person room, the same photo arriving twice is worse than one photo missing. Completion is reported to the server only after this check.
- The checkpoint moves only after 2xx. The uploader moves the offset only after receiving 2xx. 422 and 413 are skipped; on 5xx or 429 it stops without committing and uploads again on the next run.
- The processing path leaves its own liveness markers. It leaves one marker when a tagged message is accepted and one when it reaches a result. If no result marker appears past a business-hours threshold, the monitor catches it. The earlier approach, where the monitor guessed from outside that 'no draft means it stalled,' was removed in review. This path has 30 tests.
- 107 test files