Asisten AI Situs: Batas Kemampuan dan Solusi Teknis
Asisten AI situs saat ini adalah tanya-jawab otomatis berbasis aturan (basis pengetahuan bawaan, tanpa akses rekam medis dan tanpa LLM eksternal); berikut rencana solusi teknis untuk menjelaskan pendekatan desain dan implementasi referensi.
Arsitektur sistem keseluruhan
Tanggung jawab empat modul inti
Antarmuka percakapan (frontend)
Komponen React/Vue: daftar pesan, input, indikator mengetik, chip cepat, rendering streaming, pengalih bahasa, dan aksesibilitas (aria / keyboard).
Layanan pemrosesan pesan (backend)
Status sesi, routing intent, pagar kepatuhan, penyusunan konteks, pemanggilan API LLM, pemicuan eskalasi, dan audit log.
Integrasi antarmuka percakapan LLM (rencana)
API layanan LLM: System Prompt kepatuhan medis, RAG, Function Calling untuk KB/CRM, balasan streaming SSE.
Agen bantu R&D · generasi / perbaikan kode
Agen bantu R&D yang direncanakan: menghasilkan kode intent dan FAQ baru, memperbaiki bug, menghasilkan PR, digabung setelah review manual.
Rantai pemrosesan satu permintaan percakapan
- 1Pengguna mengirim
Frontend mengumpulkan pesan dan sessionId, lalu mengirimnya terenkripsi lewat WSS/HTTPS ke /api/chat.
- 2Routing intent
Backend mengenali intent (harga / mata / perjalanan / anggota / darurat) lewat kata kunci dan model klasifikasi, lalu menyusun konteks dan cuplikan basis pengetahuan.
- 3menghasilkan antarmuka percakapan LLM
Backend memanggil API LLM (dengan pagar kepatuhan dan RAG), mengembalikan respons streaming SSE; jika memenuhi syarat eskalasi, dialihkan ke agen manusia.
- 4Rendering frontend
Frontend merender balasan secara bertahap, mencatat log percakapan dan tingkat kepuasan untuk iterasi dan perbaikan mandiri berikutnya.
Jalur bantu R&D berjalan independen: pengembang mengajukan tiket (intent baru / Bug) → agen menghasilkan atau memperbaiki kode → menghasilkan Pull Request → direview dan digabung ke produksi.
Antarmuka kunci / kontrak data
POST /api/chat (SSE) request/response contract:
// Request
{
"sessionId": "sess_8f3a", // session id
"message": "How much is a dental implant?", // user text
"lang": "en" // language
}
// Response (text/event-stream, chunked)
data: {"delta": "The indicative USD range for a single implant is ..."}
data: {"delta": "Final pricing follows the hospital."}
data: [DONE]
Kontrak pemanggilan LLM (backend → layanan model):
POST https://api.openai.com/v1/chat/completions
{
"model": "gpt-4o-mini",
"stream": true,
"messages": [
{"role":"system","content":"compliance guardrails + KB snippets"},
{"role":"user","content":"[en] How much is a dental implant?"}
]
}
Kontrak tugas agen bantu R&D (backend → agen):
{
"task": "Tambahkan follow-up FAQ untuk intent harga: apakah sudah termasuk biaya penambahan tulang",
"file": "src/intents/price.js",
"failing_test": null,
"review": "required" // harus direview manual sebelum merge
}
Implementasi fungsi kunci (bisa langsung dijalankan)
Berikut contoh umum, hanya untuk menggambarkan pendekatan integrasi,bukan kode produksi situs ini, dan belum dideploy.
Layanan pemrosesan pesan + integrasi LLM (Node 18+, memerlukan express dan openai):
// server.js
import express from 'express';
import OpenAI from 'openai';
const app = express();
app.use(express.json());
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
// Medical compliance guardrails: no diagnosis / prescriptions / efficacy promises
const GUARDRAILS = [
'You are the AI assistant of a medical travel concierge site; provide objective process and credential information only.',
'Never diagnose, prescribe, promise outcomes, or rank doctors.',
'Actual treatment requires an in-person visit with a licensed physician; costs follow hospital pricing.',
'For emergencies, guide users to local emergency numbers (120 in China / 911 in the US).',
'When unsure, escalate to a human agent.'
].join(String.fromCharCode(10));
// Intent routing: keyword hit decides the class, otherwise general
const INTENTS = {
price: /价格|比价|费用|报价|usd|\$/i,
eye: /眼科|近视|激光|smile|lasik|icl|白内障/i,
travel: /行程|签证|机票|酒店|陪护/i,
member: /会员|登录|账号|保险/i,
emergency: /紧急|急救|意外|危险/i
};
function route(text){ for(const k in INTENTS) if(INTENTS[k].test(text)) return k; return 'general'; }
app.post('/api/chat', async (req, res) => {
const { sessionId, message, lang = 'zh-CN' } = req.body;
const intent = route(message);
const kb = await retrieveKB(intent, message); // vector retrieval placeholder
const stream = await openai.chat.completions.create({
model: 'gpt-4o-mini', stream: true,
messages: [
{ role:'system', content: GUARDRAILS + '\nKB snippets:\n' + kb },
{ role:'user', content: '[' + lang + '] ' + message }
]
});
res.setHeader('Content-Type','text/event-stream');
for await (const chunk of stream) {
const t = (chunk.choices[0] && chunk.choices[0].delta && chunk.choices[0].delta.content) || '';
if (t) res.write('data: ' + JSON.stringify({ delta: t }) + String.fromCharCode(10) + String.fromCharCode(10));
}
res.write('data: [DONE]' + String.fromCharCode(10) + String.fromCharCode(10));
res.end();
});
async function retrieveKB(intent, q){ return '(Example) public credential and price-range notes for this intent.'; }
app.listen(3000, () => console.log('AI chat service on :3000'));
Pemanggilan streaming frontend (browser):
// chat-client.js
export async function sendChat(sessionId, message, lang, onDelta) {
const res = await fetch('/api/chat', {
method:'POST', headers:{'Content-Type':'application/json'},
body: JSON.stringify({ sessionId, message, lang })
});
const reader = res.body.getReader();
const dec = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
for (const line of dec.decode(value).split(String.fromCharCode(10))) {
if (line.startsWith('data: ')) {
const payload = line.slice(6);
if (payload === '[DONE]') return;
onDelta(JSON.parse(payload).delta);
}
}
}
}
Modul pembuatan / perbaikan kode (asisten R&D, rencana) (Python, memerlukan openai, ganti model saat menghubungkan agen bantu R&D):
# codex_agent.py
import os, openai, sys
client = openai.OpenAI(api_key=os.environ['OPENAI_API_KEY'])
def generate_or_fix(task, file_path=None, failing_test=None):
ctx = ''
if file_path and os.path.exists(file_path):
ctx += '\n# Existing file ' + file_path + '\n' + open(file_path, encoding='utf-8').read()
if failing_test:
ctx += '\n# Failing test output\n' + failing_test
prompt = ('You are the code engineer for the customer-service system. Task: ' + task +
'\nOutput only a mergeable code diff or the complete file, with a brief explanation.\n' + ctx)
r = client.chat.completions.create(
model='gpt-4o', # replace model when wiring in the actual code model
messages=[{'role':'system','content':'You are a senior frontend / Node engineer familiar with this customer-service system.'},
{'role':'user','content':prompt}])
return r.choices[0].message.content
if __name__ == '__main__':
print(generate_or_fix(sys.argv[1], sys.argv[2] if len(sys.argv) > 2 else None))