客服
用你自己的文档回答客服问题
创建一个 LiveDoc,导入帮助中心和内部 runbook,检索能回答工单的段落,再让模型只根据这些证据回答。
复制 prompt
把方括号里的字段替换掉,然后粘贴到 Claude Code、Codex 或任何能访问终端的 AI。它会安装 Felo skill、在花额度前询问,并执行这套 workflow。
只用我们的文档回答这个支持问题:[客户问题]。 知识库:[帮助中心 URL 或 LiveDoc short_id]。升级路径:[负责人或队列]。 可用客户上下文:[套餐、地区、产品](不要索取密码或支付数据)。 输出: 1. 两到四句直接回答。 2. 支撑回答的文档段落,附资源标题。 3. 客户的下一步。 4. 内部备注:使用的资源和相关度分数。 规则: - 只根据检索到的段落回答。没有命中或相关度低时升级,绝不猜测。 - 不要编造政策、退款、定价或账户操作。 - 不要引入客户私密数据、凭证或支付信息。 - 在消耗额度做数据导入或检索前先询问。 - 不要把回答发送给客户;返回给我审阅。
复制的内容也包含安装步骤和安全规则。
你会得到什么
一次运行的示例输出,不是实时生成。
回答:你的方案在每月 1 日续费。银行卡扣款失败后会重试三天,然后席位暂停。
来源:“账单常见问题” - https://example.com/help/billing
如果这里没有覆盖:带上发票 ID 升级到账单队列。
实际调用
给开发者:同一套 workflow 的可复制代码,按执行顺序排列。
展开实际 API 调用
创建知识库
用 LiveDoc API 创建一个知识库,保存 short_id。
support.ts const BASE = "https://openapi.felo.ai"; const headers = { Authorization: `Bearer ${process.env.FELO_API_KEY}`, "Content-Type": "application/json", }; async function felo<T>(path: string, body?: unknown): Promise<T> { const res = await fetch(`${BASE}${path}`, { method: body ? "POST" : "GET", headers, body: body ? JSON.stringify(body) : undefined, }); if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`); return res.json() as Promise<T>; } type LiveDocData = { data: { short_id: string } }; const kb = await felo<LiveDocData>("/v2/livedocs", { name: "Support knowledge base", description: "Help center, policy pages, and internal runbooks", }); const kbId = kb.data.short_id; // save this in your config示例输出
{ "short_id": "PvyKouzJirXjFdst4uKRK3", "name": "Support knowledge base", "description": "Help center, policy pages, and internal runbooks" }导入公开帮助中心
把帮助中心 URL 作为资源加进 LiveDoc。
support.ts type UrlResult = { data: { url: string; status: string; fail_reason: string | null; resource_id: string | null; }[]; }; const added = await felo<UrlResult>( `/v2/livedocs/${kbId}/resources/urls`, { urls: [ "https://example.com/help/getting-started", { url: "https://example.com/help/billing", title: "Billing FAQ" }, ], }, ); const failed = added.data.filter((item) => item.status === "failed");示例输出
[ { "url": "https://example.com/help/getting-started", "status": "success", "resource_id": "res_003" }, { "url": "https://example.com/help/billing", "status": "existed", "resource_id": "res_004" } ]补充非公开文档
把内部 runbook 作为文档资源加进去。
support.ts type ResourceData = { data: { id: string } }; const runbook = `# Refund policy Refunds are available within 30 days of purchase. Requests after 30 days need a manual review by the billing team. `; const policy = await felo<ResourceData>( `/v2/livedocs/${kbId}/resources/doc`, { title: "Refund policy", content: runbook }, ); console.log(policy.data.id); // use this for updates检索问题相关证据
用语义检索拿到最相关的段落和分数。
support.ts type Hit = { id: string; title: string; content: string; score: number }; async function findEvidence(question: string) { const res = await felo<{ data: Hit[] }>( `/v2/livedocs/${kbId}/resources/retrieve`, { query: question }, ); return res.data.filter((hit) => hit.score >= 0.7).slice(0, 4); } const question = "Can I get a refund after 45 days?"; const hits = await findEvidence(question);示例输出
[ { "id": "res_005", "title": "Refund policy", "content": "Refunds are available within 30 days of purchase…", "score": 0.92 } ]只基于证据回答
让模型只使用检索到的段落,并在没有命中时升级。
support.ts type Completion = { choices: { message: { content: string | null } }[]; usage: { prompt_tokens: number; completion_tokens: number; total_tokens: number }; }; const context = hits .map((hit) => `### ${hit.title}\n${hit.content}`) .join("\n\n"); const completion = await felo<Completion>("/api/v1/chat/completions", { model: "anthropic/claude-haiku-5.5", messages: [ { role: "system", content: "Answer only from the context. If the context does not cover the question, say so and hand the ticket to a human.", }, { role: "user", content: `Context:\n${context}\n\nQuestion: ${question}`, }, ], }); console.log(completion.choices[0].message.content); console.log(completion.usage.total_tokens);示例输出
"No. The Refund policy says refunds are available within 30 days of purchase, so a request at 45 days needs a manual review by the billing team."
包含什么
- 由帮助中心和内部 runbook 构建的 LiveDoc
- 带段落和标题的语义检索
- 有依据、可引用的回答
- 文档不覆盖时明确的升级路径
不做什么
- 只从你的文档回答,不浏览开放网络
- 不执行账户操作、退款或改套餐
- 不能把私有客户数据或凭证放进知识库
- 文档过时会导致回答过时,需要定期刷新
- 它只起草回答,不直接发给客户
常见问题
回答从哪里来?
只来自你构建的 LiveDoc:帮助中心页面和 runbook。检索返回段落,agent 再基于段落写回答。
文档没有覆盖时怎么办?
升级。没有命中或相关度过低就视为未覆盖,而不是允许模型猜。
怎么保持知识库最新?
政策变化时重新添加或更新 URL 和文档资源;workflow 包含更新和审计命令。
可以接进工单队列吗?
可以,作为起草步骤。发送给客户之前保留人工审批。
能处理账户特定问题吗?
不能只靠文档。账户数据在你的系统里;只传 agent 需要且安全的信息,绝不要传凭证。
一次要花多少?
导入和检索按用量计费;当前费率在价格页面,prompt 会先请求确认。
相关 workflow
改成你的版本
同一套配方,按你实际的交付方式调整。
只导入一个产品线
把范围缩到一个产品,知识库更干净。
加入工单分类
在回答前先按问题类型分类,再检索对应文档。
定期审计
每月检查一次失效链接和旧政策。
继续深入
这套配方背后的参考页面,以及下一步可以看什么。