
最近在做一个内部客服系统的升级项目核心目标是用更低的成本实现更快的响应和更准的答案。传统方案要么依赖人工坐席响应慢、成本高要么用规则引擎知识更新繁琐维护起来头大。我们最终选择了一条“捷径”用飞书云文档当知识库用大语言模型LLM当大脑搭建了一套智能客服系统。实践下来效果拔群开发效率也高。今天就来详细拆解一下从设计到优化的全过程希望能给有类似需求的同学一些参考。1. 为什么是飞书云文档 LLM先说说为什么选这两样。传统客服系统的知识库要么是自建数据库更新麻烦要么用Wiki但API可能不好用。飞书云文档有几个天然优势免运维的知识库产品、运营同学直接在飞书上编辑文档内容实时更新天然就是结构化的知识源。强大的开放能力飞书开放平台提供了完善的文档内容获取API、机器人消息推送API集成成本低。协同与权限文档的权限管理和版本历史与飞书组织架构打通安全又方便。而LLM的选择我们主要对比了GPT系列和Claude。考虑到成本、响应速度以及对中文的理解我们最终选择了国内一家云服务商提供的LLM API功能类似GPT-3.5。它的意图识别和文本生成能力足够应对大部分客服场景且API稳定价格也合适。2. 系统架构全景图整个系统的核心思想是将飞书文档作为“记忆”将LLM作为“思考与表达”的引擎。整个流程可以这样描述知识同步层一个后台服务定时或通过飞书事件订阅拉取指定知识库文件夹下的所有云文档内容进行清洗、分段、向量化然后存入向量数据库如Chroma、Milvus。问答处理层用户通过飞书机器人或Web界面提问。服务端接收到问题后首先将其向量化然后在向量数据库中进行相似度检索找出最相关的几条知识片段。智能回复层将用户问题和检索到的相关知识片段组合成一个精心设计的Prompt提交给LLM。LLM基于这些上下文信息生成一段准确、友好、符合客服话术的回复。返回与记录将LLM生成的回复返回给用户同时将本轮问答日志记录下来用于后续分析和模型优化。上图示意了数据从飞书文档经过处理最终通过LLM生成回答的流动过程3. 飞书API接入与内容同步这是系统的数据源头。飞书开放平台的文档权限管理比较细首先要创建一个“自建应用”并配置好“读取用户所拥有的文档”等权限。最容易踩坑的是“权限配置”和“安全设置”IP白名单、事件订阅URL校验。下面是一个简化的Python示例展示如何获取文档内容import requests import json class FeishuDocSync: def __init__(self, app_id, app_secret): self.app_id app_id self.app_secret app_secret self.tenant_access_token None self.base_url https://open.feishu.cn/open-apis def _get_tenant_access_token(self): 获取租户访问令牌 url f{self.base_url}/auth/v3/tenant_access_token/internal payload {app_id: self.app_id, app_secret: self.app_secret} resp requests.post(url, jsonpayload) resp.raise_for_status() self.tenant_access_token resp.json().get(tenant_access_token) def get_doc_content(self, doc_token): 根据文档token获取纯文本内容 if not self.tenant_access_token: self._get_tenant_access_token() url f{self.base_url}/docx/v1/documents/{doc_token}/raw_content headers { Authorization: fBearer {self.tenant_access_token}, Content-Type: application/json } # 这里指定返回纯文本格式也可以返回JSON结构化数据 params {document_format: TEXT} resp requests.get(url, headersheaders, paramsparams) resp.raise_for_status() # 实际返回结构较复杂需解析content字段中的文本 content_data resp.json() return self._extract_text(content_data) def _extract_text(self, content_data): 从API返回的复杂结构中提取纯文本简化示例 # 此处为示例真实情况需递归遍历 content 中的 blocks text_list [] for block in content_data.get(data, {}).get(document, {}).get(blocks, []): if block.get(type) paragraph: for elem in block.get(paragraph, {}).get(elements, []): if elem.get(type) textRun: text_list.append(elem.get(textRun, {}).get(content, )) return \n.join(text_list) # 使用示例 if __name__ __main__: sync FeishuDocSync(your_app_id, your_app_secret) content sync.get_doc_content(doxcnxxxxxxxxxxxx) print(content[:500]) # 打印前500字符同步服务可以设计为定时任务遍历知识库文件夹获取所有文档的最新版本然后调用上述方法拉取内容。4. LLM Prompt工程与对话处理这是系统的智能核心。直接让LLM回答它容易“胡说八道”或回答得过于笼统。我们的关键是将飞书文档中的相关知识作为上下文“喂”给它。一个有效的Prompt模板如下你是一个专业的客服助手请严格根据以下提供的“参考知识”来回答用户的问题。 如果参考知识中没有明确答案请回答“抱歉我暂时无法回答这个问题您可以联系人工客服进一步咨询。” 参考知识 {context} 用户问题{question} 请生成专业、友好、简洁的客服回复对应的核心处理逻辑代码import openai # 这里以OpenAI SDK为例其他LLM API类似 from vector_db import VectorDB # 假设的向量数据库客户端 class LLMChatProcessor: def __init__(self, llm_api_key, vector_db_client): self.llm_client openai.OpenAI(api_keyllm_api_key) self.vector_db vector_db_client def retrieve_context(self, query, top_k3): 从向量数据库检索相关上下文 query_vector self._get_embedding(query) # 将问题转换为向量 search_results self.vector_db.search(query_vector, top_ktop_k) # search_results 应包含文本片段和来源如文档标题 context \n---\n.join([res[text] for res in search_results]) return context def generate_reply(self, user_question): 生成回复的核心方法 # 1. 检索 context self.retrieve_context(user_question) # 2. 构建Prompt prompt self._build_prompt(context, user_question) # 3. 调用LLM try: response self.llm_client.chat.completions.create( modelgpt-3.5-turbo, # 或您选择的模型 messages[ {role: system, content: 你是一个专业的客服助手。}, {role: user, content: prompt} ], temperature0.2, # 温度参数调低使输出更确定 max_tokens500 ) reply response.choices[0].message.content.strip() except openai.APIError as e: # 记录日志并返回降级回复 print(fLLM API调用失败: {e}) reply 服务暂时繁忙请稍后再试。 return reply def _build_prompt(self, context, question): 构建Prompt字符串 prompt_template 你是一个专业的客服助手请严格根据以下提供的“参考知识”来回答用户的问题。 如果参考知识中没有明确答案请回答“抱歉我暂时无法回答这个问题您可以联系人工客服进一步咨询。” 参考知识 {context} 用户问题{question} 请生成专业、友好、简洁的客服回复 return prompt_template.format(contextcontext, questionquestion) # 使用示例 processor LLMChatProcessor(your_llm_key, vector_db_client) answer processor.generate_reply(请问产品A的退货政策是什么) print(answer)5. 性能优化与避坑指南系统上线后性能和稳定性是挑战。性能优化点并发与异步用户提问是并发的。可以使用asyncioaiohttp异步处理LLM API调用和向量检索。对于Web框架如FastAPI其本身支持异步能很好地处理并发请求。LLM响应延迟流式输出如果回复较长可以使用LLM的流式响应streaming让用户先看到部分答案体验更好。缓存对高频、通用问题如“上班时间”的问答结果进行缓存Redis可以极大减少LLM调用。模型选择在效果可接受的情况下选择更轻、更快的模型。飞书API频控飞书API有调用频率限制。同步服务要设计好拉取策略比如增量同步、错峰同步并做好重试机制和指数退避。避坑指南飞书API权限确保应用发布的版本和权限配置匹配。经常遇到“无权限访问文档”的问题检查三点应用是否已发布文档是否对应用所属的“机器人”可见权限配置中是否勾选了正确的“权限范围”LLM的Temperature参数这个参数控制输出的随机性。在客服场景下我们希望答案稳定可靠通常设置为较低的值如0.1-0.3。太高会导致回答波动大太低可能让回答过于死板。敏感信息过滤飞书文档中可能包含内部联系方式、未公开信息等。必须在两个环节过滤知识入库前在文档内容同步、向量化之前通过关键词或正则表达式进行初步过滤。LLM输出后对LLM生成的回复再做一次安全检查防止模型在上下文中“学到”并泄露敏感信息。6. 未来还能怎么玩这个基础框架的扩展性很好多轮对话目前是单轮问答。可以引入对话状态管理记录上下文让LLM能处理“上一个问题”、“修改订单”这类需要记忆的对话。多模态输入用户不仅可以发文字还可以发图片如产品故障图。可以结合视觉模型VLM先识别图片内容再结合文本问题一起检索和回答。人工接管与学习当LLM置信度低时自动转人工坐席。并将人工坐席的优秀回复沉淀下来作为新的高质量样本用于微调LLM模型形成闭环优化。数据分析看板收集所有问答日志分析高频问题、用户满意度、LLM回答的准确率等驱动知识库的优化和产品的迭代。写在最后通过这次实践我深刻感受到利用飞书这样的成熟协同工具作为数据底座结合LLM的强大生成能力能够快速搭建出体验不错的智能应用。它未必能100%替代人工但能解决80%的重复性咨询问题将人力解放出来处理更复杂的情况降本增效的目标非常明显。整个技术栈都是现成的云服务或开源组件重点在于如何巧妙地将它们串联起来并处理好细节。希望这篇笔记能为你提供一条清晰的实现路径。