项目核心是创建一个由AI驱动的双角色(SWK 和 ADA)对话系统,目标是引导用户在一个预设的剧情框架下做出关键选择。其关键特性如下:
- 静态世界观:存在一个固定的“故事背景”,以及两个性格、目标、说话风格迥异的NPC:“SWK”和“ADA”。这些是整个对话系统的基础上下文。
- 动态引导:对话并非完全开放,而是有一个明确的“剧情设定”,即引导用户最终做出“追随SWK”或“追随ADA”的选择。NPC的对话内容需要服务于这个目标。
- 智能输入处理:系统需要具备两种智能校验能力:
- 相关性校验:判断用户的输入是否与当前对话主题相关。如果无关,则主动引导用户回来。
- 歧义校验:判断用户的输入是否模糊不清。如果存在歧义,则不直接回答,而是生成2-4个澄清选项,让用户选择,从而确保对话的准确性。
- 状态化对话:整个对话过程需要记录上下文(聊天记录),以便AI能做出连贯的回应。
整个流程可以看作一个由LangGraph构建的“智能对话图”:
第零步:服务启动与初始化
- 当后端服务启动时,从配置文件(如
config/story.json,config/characters.json)中加载故事背景、剧情设定以及SWK和ADA的详细角色设定(性格、目标、说话风格等)到内存中。
第一步:接收用户输入 (API Endpoint)
- 前端通过调用
POST /chat/sendAPI,将用户的输入内容和会话ID(session_id)发送到后端。
第二步:进入LangGraph工作流
- 后端根据
session_id找到或创建一个新的对话状态(State),其中包含聊天记录、角色设定等信息。 - 将用户的新输入添加到状态中,启动LangGraph工作流。
第三步:相关性判断节点 (Relevance Check Node)
- 这是图的第一个逻辑节点。
- 它会调用LLM,并提供一个简单的提示词,例如:
“背景:[故事背景]。当前对话:[最近几轮对话]。用户最新输入:‘{user_input}’。请判断此输入是否与当前对话主题相关。请只回答‘相关’或‘不相关’。”
- 此节点的结果将决定图的走向。这是一个条件路由 (Conditional Edge)。
第四步:路由选择
- 如果结果是“不相关”:
- 工作流转向引导节点 (Guidance Node)。
- 此节点生成一句提示性的话术,如“我们好像聊远了,还是继续刚才的话题吧。”或者“现在专注于解决眼前的问题更重要。”
- 将这句话作为AI的回应,工作流结束,返回给前端。
- 如果结果是“相关”:
- 工作流继续前进到下一步。
第五步:歧义判断节点 (Ambiguity Check Node)
- 这是图的第二个逻辑节点。
- 它会调用LLM,提示词会更复杂一些,例如:
“在以下对话情境中,分析用户输入‘{user_input}’是否存在多种可能的解释或歧义。如果存在,请生成2-4个最有可能的、简洁的澄清选项(例如‘你的意思是指A吗?’)。如果输入清晰明确,则返回一个空列表。请以JSON列表格式输出。”
- 此节点的输出同样会触发一个条件路由。
第六步:再次路由选择
- 如果返回的澄清选项列表不为空:
- 工作流结束。
- API直接将这个选项列表返回给前端。前端需要将这些选项展示给用户点击。用户的下一次请求将是
POST /chat/clarify,带着他选择的那个选项文本。
- 如果返回的列表为空:
- 用户的输入被认为是清晰的,工作流进入最终的核心对话生成环节。
第七步:核心对话生成节点 (Dialogue Generation Node)
- 这是最重要的节点,它聚合了所有上下文信息来调用LLM。
- 提示词将包含:
- 故事背景和核心剧情设定。
- SWK的角色设定(性格、目标、对用户的看法等)。
- ADA的角色设定。
- 完整的对话历史。
- 用户(已确认清晰的)输入。
- 核心指令:“请你同时扮演SWK和ADA,根据各自的角色设定和当前对话情境,对用户的输入做出回应。你们的对话需要潜移默化地引导用户思考并最终选择追随谁。请以JSON格式返回,包含SWK和ADA各自的回复。”
- LLM生成SWK和ADA的回应。
第八步:更新状态并返回
- 将用户的输入以及AI生成的回应追加到会话的聊天记录中。
- 将生成的对话内容通过API返回给前端。工作流本次执行完毕。
一个清晰的项目结构能让开发和维护更简单。
/your_project
|
├── main.py # FastAPI应用主入口,定义API接口
|
├── config/
| ├── story.json # 存放共同的故事背景和核心剧情设定
| └── characters.json # 存放SWK和ADA的详细角色设定(性格、MBTI、目标、风格等)
|
├── prompts/
| ├── relevance_check.txt # 相关性检查的提示词模板
| ├── ambiguity_check.txt # 歧义检查的提示词模板
| └── dialogue_gen.txt # 核心对话生成的提示词模板
|
├── services/
| └── chat_service.py # 核心业务逻辑,LangGraph图的定义和构建就在这里
|
└── models.py # Pydantic模型,定义API的请求体和响应体结构
main.py: 负责启动FastAPI服务,定义/chat/send等API端点,并调用chat_service中的功能。config/*.json: 将设定数据化,便于程序读取和修改,而不用硬编码在代码里。prompts/*.txt: 将复杂的提示词与业务逻辑代码分离,便于调试和优化Prompt。services/chat_service.py: 项目的大脑。这里会初始化LangGraph,定义图中所有的节点(函数)和边(路由逻辑)。models.py: 定义数据契约。例如,ChatRequest模型规定了前端发来的请求必须包含哪些字段,ChatResponse模型规定了后端返回的数据格式。
您至少需要以下两个API端点:
1. 发送对话 (Send Dialogue)
- Endpoint:
POST /chat/send - 作用: 用户输入新对话,启动主要的对话处理流程。
- 请求体 (Request Body):
{ "session_id": "a_unique_session_identifier_string", "text": "用户输入的对话内容" } - 成功响应 (Success Response - 200 OK):
- 情况A:正常对话回复
{ "type": "dialogue", "data": [ { "character": "SWK", "text": "孙悟空的回应..." }, { "character": "ADA", "text": "艾达的回应..." } ] } - 情况B:需要用户澄清
{ "type": "clarification", "data": [ "你的意思是指...吗?", "你是想问关于...的事情吗?", "或者你是想表达...?" ] } - 情况C:用户输入不相关
{ "type": "guidance", "data": { "text": "我们还是继续刚才的话题吧。" } }
- 情况A:正常对话回复
2. 选择澄清选项 (Select Clarification)
这个API是可选的,但能让逻辑更清晰。当用户点击了澄清选项后,前端调用此接口,后端将其视为用户“真正想说的话”来继续处理。
- Endpoint:
POST /chat/clarify - 作用: 用户从澄清选项中选择一个,作为他/她的明确输入。
- 请求体 (Request Body):
{ "session_id": "a_unique_session_identifier_string", "text": "用户选择的那个澄清选项的文本" } - 逻辑: 这个API的后端逻辑会跳过相关性和歧义检查,直接将
text内容送入核心对话生成节点,然后返回正常的对话回复。
这个方案为您提供了一个从概念到具体代码实现的完整蓝图,您可以基于此开始搭建您的AI后端了。