Show / hide languages:
📋 Course plans · Week 5 / 6

🎧 Week 5 — Customer Support

Three separate Hermes agents — Responder, Adversarial Reviewer, Closer. Python orchestrates, not the LLM.

Hermes 3 ตัวแยกกัน — Responder, Adversarial Reviewer, Closer Python เป็นคนสั่ง ไม่ใช่ LLM

三个独立的 Hermes — 回复者、对抗审查者、关单者。由 Python 编排,不交给 LLM。

🤖×3 ReActAgents 🔍 LlamaIndex RAG 🛡️ presidio PII ⏱️ 90 min

🎯 Learning objectives

1

RAG over your policy PDF

LlamaIndex VectorStoreIndex + Ollama embeddings. Hermes answers from the doc.

LlamaIndex VectorStoreIndex + embedding ของ Ollama Hermes ตอบ จาก doc

LlamaIndex VectorStoreIndex + Ollama 嵌入。Hermes 从文档里答。

2

Three agents, not one

Separate build_agent() instances. Python passes the draft between them.

เรียก build_agent() 3 ครั้ง Python ส่งร่างต่อกัน

三次 build_agent(),由 Python 把草稿在它们之间传递。

3

HITL in code

The 1,000 THB threshold lives in Python — prompts cannot override it.

เกณฑ์ 1,000 บาทอยู่ใน Python — prompt บังคับไม่ได้

1,000 泰铢门槛写在 Python 里,提示词无权覆盖。

🛠️ Live: simulate the 3-agent pipeline

Click Run safe ticket to watch all three agents pass through. Click Run 1,500 THB refund to see the Reviewer halt the chain.

คลิก Run safe ticket ดู agent ทั้ง 3 ผ่านครบ คลิก Run 1,500 THB refund ดู Reviewer หยุดสาย

点击 Run safe ticket 看三代理依次通过;点击 Run 1,500 THB refund 看审查者中止流水线。

📝
Responder
idle
→
🕵️
Adversarial Reviewer
idle
→
📤
Closer
idle

📚 Key concepts

🇬🇧 English

RAG vs tool-calling — RAG = "read the policy PDF and quote it." Tool-calling = "actually do the action." Today we RAG only; sending uses the Week-2 draft tool.

Three Hermes agents — one big prompt with three roles drifts. Three separate build_agent() calls each with a tight system prompt stays sharp.

HITL in Python — the Closer's send tool checks the THB amount and refuses above the threshold. Prompts cannot override Python.

🇹🇭 ไทย

RAG vs tool-calling — RAG = อ่าน PDF แล้วยกอ้าง tool-calling = ทำจริง วันนี้ RAG เท่านั้น ส่งใช้ draft tool ของ Week 2

Hermes 3 ตัว — prompt ใหญ่ 3 บทบาทจะไหล แยก build_agent() 3 ครั้งทั้งสามมี system prompt แน่น

HITL ใน Python — เครื่องมือ send ของ Closer เช็คจำนวนเงิน เกินเกณฑ์ปฏิเสธ prompt บังคับไม่ได้

🇨🇳 中文

RAG 与工具调用 — RAG = 读策略 PDF 并引用;工具调用 = 真正执行操作。本周只用 RAG;发送沿用 Week 2 的草稿工具。

三个 Hermes — 一段大提示词管三个角色会漂移。分别 build_agent(),每个都有紧的系统提示,才稳。

Python 里的人工介入 — Closer 的发送工具检查金额,超阈值就拒绝。提示词无法绕过 Python。

🧪 Hands-on lab

1
2
3
4
1

Build the policy index

Drop your business policy PDF into ./policies/.

วาง PDF นโยบายธุรกิจไว้ใน ./policies/

把业务策略 PDF 放进 ./policies/。

pip install llama-index-embeddings-ollama llama-index-readers-file \ presidio-analyzer presidio-anonymizer ollama pull nomic-embed-text # the same embedder from the Mac/Windows stack
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings from llama_index.embeddings.ollama import OllamaEmbedding Settings.embed_model = OllamaEmbedding(model_name="nomic-embed-text") index = VectorStoreIndex.from_documents(SimpleDirectoryReader("./policies").load_data()) policy_engine = index.as_query_engine()
2

PII redaction (Python, before any agent reads)

from presidio_analyzer import AnalyzerEngine from presidio_anonymizer import AnonymizerEngine _an, _anon = AnalyzerEngine(), AnonymizerEngine() def redact_pii(text: str) -> str: r = _an.analyze(text=text, language="en") return _anon.anonymize(text=text, analyzer_results=r).text
3

Three Hermes agents

from llama_index.core.agent.workflow import ReActAgent from llama_index.llms.ollama import Ollama def hermes(system: str, tools=()): return ReActAgent(tools=list(tools), llm=Ollama(model="hermes3:8b"), system_prompt=system, verbose=False) responder = hermes( "You draft customer replies using ONLY query_policy. " "State the THB amount if a refund applies. Reply in the customer's language.", tools=[FunctionTool.from_defaults(lambda q: str(policy_engine.query(q)), name="query_policy")]) reviewer = hermes( "You are an adversarial reviewer. Critique the responder's draft. " "Return JSON: {confidence: 0-100, halt: bool, reasons: [...]}. " "HALT if refund/reschedule exceeds 1000 THB.") closer = hermes( "Given an approved draft, decide: use draft_gmail_reply (always Draft).")
4

Python orchestrates — not Hermes

import json def support_pipeline(ticket: str) -> str: safe = redact_pii(ticket) draft = responder.chat(f"Draft a reply: {safe}") review = reviewer.chat(f"Review draft:\n{draft}") j = json.loads(str(review)) if j["halt"] or j["confidence"] < 90: return draft_gmail_reply(message_id_of(ticket), str(draft)) # to Drafts only return closer.chat(f"Send appropriately: {draft}")

💡 Why JSON between agents?

Forcing the Reviewer to return strict JSON means Python can branch on the result deterministically. No regex on natural language.

บังคับ Reviewer คืน JSON ทำให้ Python ตัดสินใจได้แน่นอน ไม่ต้อง regex ภาษาธรรมชาติ

强制审查者输出严格 JSON,Python 就能确定地分支处理,不必再用正则分析自然语言。

⚠️ Top gotchas

1. Hallucinated exceptions

The responder must use ONLY query_policy. Without that constraint, a polite Hermes invents generous policies.

Responder ต้องใช้ query_policy เท่านั้น ไม่งั้น Hermes จะคิดนโยบายใจกว้างมาเอง

回复者只能用 query_policy,否则有礼貌的 Hermes 会自己编出宽松政策。

2. Language drift

The system prompt must say "reply in the customer's language" — or English will creep into Thai replies.

system prompt ต้องสั่ง "ตอบเป็นภาษาลูกค้า" — ไม่งั้นจะหลุดอังกฤษไปตอบไทย

系统提示必须写"用客户的语言回复" — 否则英文会渗进泰文回复。

3. PII leak into history

Redact before the responder sees the ticket. Otherwise PII permanently lives in the conversation context.

redact ก่อน responder อ่าน ticket ไม่งั้น PII จะติด context ตลอด

在回复者读到工单之前脱敏。否则 PII 会永远留在对话上下文。

📝 Assessment & homework

✅ Assessment

A 1,500 THB refund halted by the Reviewer; the draft lands in Drafts. Explain why the HITL threshold lives in Python, not in the prompt.

เคสคืนเงิน 1,500 บาท Reviewer หยุด ร่างไปอยู่ Drafts อธิบายทำไม HITL อยู่ใน Python ไม่ใช่ prompt

1,500 泰铢退款被审查者拦住,草稿落到 Drafts。说明为什么人工介入门槛写在 Python 而不是提示词。

🏠 Homework

Run 10 past tickets through the pipeline in Draft mode only. Bring the lowest-confidence one to Week 6 — we'll tune the index based on edge cases.

รัน 10 ticket เก่าใน Draft mode เอาตัว confidence ต่ำสุดไป Week 6 — จูน index ตาม edge cases

用 Draft 模式跑完 10 张历史工单,把置信度最低的一张带到 Week 6 — 据此微调索引。