1. 项目概述一个为ChatGPT“开刃”的代码库如果你深度使用过ChatGPT的API尤其是尝试过构建一些需要复杂逻辑或长期记忆的应用大概率会遇到一个头疼的问题模型本身很强大但让它严格按照你的指令去执行一个多步骤的任务或者记住对话中很早之前的某个关键细节并不是一件容易的事。模型可能会“跑偏”、遗忘或者输出格式不符合你的程序解析要求。这正是johniwasz/whetstone.chatgpt这个项目试图解决的问题。你可以把它理解为一个为ChatGPT API“开刃”的工具包通过一系列精心设计的“提示工程”模板和结构化输出控制让模型变得更锋利、更听话、更可靠。这个项目名字起得很形象“Whetstone”就是磨刀石。它不改变模型本身而是通过外部的方法论和工具将ChatGPT这把原本就锋利的“刀”打磨得更加趁手以适应更专业、更复杂的开发任务。它的核心价值在于将那些散落在各种博客、论坛和开发者个人笔记中的最佳实践封装成了可复用的代码和模式。对于想要快速构建基于大语言模型的智能应用但又不想从零开始摸索提示词工程和对话管理的开发者来说这无疑是一个高效的起点。2. 核心设计思路超越简单问答的对话管理2.1 从单轮对话到“状态机”式交互普通的ChatGPT API调用大多是基于当前一轮的提示词Prompt和对话历史Messages来生成回复。这就像是一次性的问答。但在真实应用中我们往往需要模型扮演一个具有明确目标和流程的“智能体”。例如一个客服机器人需要先问候、再询问问题类型、接着收集详细信息、最后提供解决方案。这个流程中的每一步模型都需要根据当前“状态”和用户输入决定下一步该做什么并输出结构化的信息供程序判断。whetstone.chatgpt的设计核心就是将对话视为一个可管理的状态机。它引入了“对话阶段”、“工具调用”、“记忆管理”等概念。开发者可以预先定义好对话的各个阶段Phase比如initial_greeting、collecting_info、providing_solution。在每个阶段项目提供的工具会帮助构建最有效的提示词引导模型输出符合该阶段预期的、结构化的内容比如一个JSON对象而不仅仅是自由文本。程序则根据这个结构化输出来更新内部状态并决定是否推进到下一个对话阶段。2.2 结构化输出让模型与程序无缝对接这是项目中一个至关重要的特性。让ChatGPT输出JSON、XML或其他格式化的数据虽然可以通过在提示词中要求来实现但稳定性往往不够。whetstone.chatgpt通过结合OpenAI的“函数调用”Function Calling后演进为Tools或更严格的输出格式控制库如Pydantic强制模型返回程序可直接解析的数据结构。例如在信息收集阶段你不再需要让模型说“请告诉我您的订单号”然后费力地从“我的订单号是123456”这样的自然语言中通过正则表达式提取数字。你可以直接定义一个Pydantic模型from pydantic import BaseModel, Field class OrderInfo(BaseModel): order_id: str Field(description用户提供的订单编号) issue_type: str Field(description问题分类如物流、退款、商品质量) description: str Field(description问题的详细描述)然后通过whetstone.chatgpt的封装将用户当前输入和这个模型定义一起发送给ChatGPT。模型会理解它需要填充这个结构并直接返回一个完整的OrderInfo对象。你的代码拿到这个对象后就可以直接访问order_info.order_id完全省去了文本解析的麻烦和不确定性。注意实现结构化输出的具体技术栈可能随OpenAI API的更新而变化。早期可能重度依赖函数调用而现在更推荐使用OpenAI的JSON Mode或response_format参数配合结构化定义。whetstone.chatgpt的价值在于它封装了这些最佳实践并提供了统一的接口即使底层API方式变化上层的应用代码也可能无需大改。2.3 记忆与上下文管理解决“金鱼脑”问题ChatGPT的上下文窗口有限如GPT-4 Turbo的128K且并非所有历史信息对当前回复都同等重要。一股脑地将整个对话历史塞进上下文不仅浪费Token还可能让模型注意力分散。whetstone.chatgpt通常会实现某种形式的记忆管理策略。一种常见策略是“摘要记忆”。当对话轮数变多时系统会自动生成一个对之前对话核心事实的摘要并用这个摘要替代冗长的原始历史记录作为新的上下文输入。另一种是“向量记忆”将对话中的关键实体如产品名、日期、用户偏好提取出来存入一个向量数据库。当用户提到相关概念时从数据库中检索最相关的记忆片段注入提示词而不是依赖模型自己去回忆。项目通过提供这些记忆管理模块的抽象接口和默认实现让开发者可以轻松地为自己的智能体添加长期记忆能力使其能够进行更连贯、更个性化的多轮对话。3. 关键技术组件与实操解析3.1 提示词模板引擎告别字符串拼接手动拼接提示词是提示工程中最繁琐且易错的部分。whetstone.chatgpt通常会内置一个模板引擎。它允许你将提示词写成模板文件如Jinja2格式其中包含变量占位符、条件判断和循环。例如一个用于代码审查的提示词模板code_review.j2可能如下你是一位资深的{{ language }}开发专家。请审查以下代码 {{ language }} {{ code_snippet }}请重点关注代码风格是否符合{{ style_guide }}规范是否存在潜在的性能瓶颈或安全漏洞是否有更优雅或更高效的实现方式请以JSON格式输出包含“score”1-10分、“issues”问题列表和“suggestions”改进建议列表三个字段。在你的Python代码中你可以这样使用 python from whetstone.chatgpt import PromptTemplate template PromptTemplate.from_file(code_review.j2) prompt template.render( languagePython, code_snippetuser_code, style_guidePEP 8 ) # 然后将prompt发送给模型这种方式将提示词逻辑与业务逻辑分离便于维护、版本控制和A/B测试。你可以为不同的任务准备不同的模板库像调用函数一样调用它们。3.2 工具/函数调用集成扩展模型能力边界虽然ChatGPT知识渊博但它无法直接执行动作比如查询数据库、调用外部API、执行计算。OpenAI的Tools工具调用功能就是为了解决这个问题。whetstone.chatgpt的核心功能之一就是简化工具的定义、注册和调用流程。在项目中你可能会这样定义一个获取天气的工具from whetstone.chatgpt import Tool class WeatherTool(Tool): name get_current_weather description 获取指定城市的当前天气情况 # 定义输入参数的JSON Schema parameters { type: object, properties: { location: {type: string, description: 城市名例如北京}, unit: {type: string, enum: [celsius, fahrenheit], default: celsius} }, required: [location] } async def execute(self, location: str, unit: str celsius) - str: # 这里实现调用真实天气API的逻辑 weather_data await call_weather_api(location, unit) return f{location}的当前天气是{weather_data[condition]}温度{weather_data[temp]}度。然后你将这个工具注册到你的对话管理器Agent中。当用户问“北京天气怎么样”时ChatGPT会识别出需要调用get_current_weather工具并自动提取参数{location: 北京}。你的程序接收到这个工具调用请求后执行WeatherTool.execute(北京)将执行结果真实天气信息作为上下文再次发给模型由模型组织成最终的自然语言回复给用户。这个过程完全自动化开发者只需要关心工具本身的实现。whetstone.chatgpt负责处理与模型之间的工具调用协议管理工具调用的状态和结果返回。3.3 对话会话与状态管理这是项目的骨架。一个典型的Agent或Session类会管理一次完整对话的生命周期。它会持有消息历史维护一个List[ChatMessage]包含用户输入、助手回复、工具调用结果等。当前阶段跟踪对话处于哪个预定义的阶段。记忆系统关联一个记忆存储实例用于保存和读取长期记忆。工具集注册了所有可用的工具。配置如使用的模型、温度参数、最大Token数等。其实操代码结构可能如下from whetstone.chatgpt import Agent, Phase # 1. 定义对话阶段 class MyPhases: GREETING Phase(greeting, initial_prompt你是助手A请友好地问候用户并询问来意。) COLLECTING Phase(collecting, prompt_templatecollect_info.j2) PROCESSING Phase(processing, prompt_templateprocess_request.j2) # ... 其他阶段 # 2. 创建Agent实例 agent Agent( modelgpt-4-turbo-preview, phasesMyPhases, tools[WeatherTool(), DBTool()], # 注册工具 memorySummaryMemory() # 配置记忆系统 ) # 3. 处理用户输入 async def handle_user_input(session_id: str, user_message: str): # 获取或创建特定会话 session await agent.get_or_create_session(session_id) # 添加用户消息并触发Agent处理流程 response await session.process(user_message) # response 包含助手的回复文本以及可能的状态变更信息 print(f助手回复: {response.text}) print(f当前阶段: {session.current_phase}) # 你可以根据session.state可能是一个字典来决定程序的下一步逻辑 if session.current_phase MyPhases.COLLECTING and session.state.get(info_complete): # 信息收集完毕可以触发后台处理流程 start_background_processing(session.state)这个Session对象封装了所有的复杂性让开发者可以专注于业务逻辑定义阶段、工具和模板而不必反复处理底层的API调用、消息列表管理和工具调用循环。4. 实战构建一个智能客服对话引擎让我们通过一个简化的智能客服场景将上述组件串联起来看看如何使用whetstone.chatgpt或其设计理念构建一个可用的系统。4.1 阶段与流程设计首先我们规划对话流程问候与分类问候用户并引导用户说出问题类型售后、咨询、投诉等。信息收集根据问题类型收集必要的信息如订单号、问题描述、联系方式。解决方案提供基于收集的信息提供解决方案或知识库文章。转人工判断如果问题复杂或用户不满意询问是否转接人工客服。4.2 定义数据结构与工具我们需要定义在信息收集阶段要用到的数据结构from pydantic import BaseModel, Field from typing import Literal class UserIssue(BaseModel): category: Literal[售后, 咨询, 投诉, 其他] Field(description用户问题分类) order_id: Optional[str] Field(defaultNone, description订单编号如果是售后/投诉) problem_detail: str Field(description问题的详细描述) contact_preference: Literal[电话, 邮箱, 站内信] Field(description用户偏好的联系方)定义一个查询知识库的工具class KnowledgeBaseTool(Tool): name query_knowledge_base description 根据问题描述从知识库中查找相关解决方案 parameters { type: object, properties: { query: {type: string, description: 用于检索的关键词或问题描述}, category: {type: string, description: 问题分类用于缩小检索范围} }, required: [query] } async def execute(self, query: str, category: str None) - str: # 模拟调用向量数据库或全文搜索引擎 results search_knowledge_base(query, category) return json.dumps(results, ensure_asciiFalse) # 返回结构化结果供模型总结4.3 配置Agent与模板创建各个阶段的提示词模板。例如collect_info.j2你正在帮助用户解决{{ session.state.category }}问题。请根据对话历史尝试填充以下信息。 如果用户已经提供了某项信息请直接使用如果尚未提供请用友好的方式询问用户。 需要收集的信息结构 {{ user_issue_schema }} 当前已收集到的信息 {{ current_info }} 用户最新消息{{ latest_message }} 请输出一个JSON对象严格符合上述结构只包含已确认的信息字段。对于未确认的信息字段值请设为null。 同时生成一句对用户的自然语言回复用于确认信息或继续询问。 输出格式 { collected_data: { ... }, // 填充好的UserIssue部分数据 response_to_user: ... // 你的回复 }在代码中初始化Agentagent Agent( modelgpt-4, phases[GreetingPhase, CollectInfoPhase, SolutionPhase, TransferPhase], tools[KnowledgeBaseTool()], system_prompt你是一个专业、耐心的智能客服助手。, output_parserJsonOutputParser(pydantic_modelUserIssue) # 配置输出解析器 )4.4 运行与迭代启动一个简单的服务如FastAPI来接收用户请求并路由给对应的Agent会话处理。在开发过程中最关键的是不断测试和迭代提示词模板。你需要收集测试用例涵盖各种用户表达清晰、模糊、带有情绪。分析失败对话是模板指令不明确还是模型误解了上下文或是工具返回结果格式不对调整模板和阶段逻辑可能需要增加一个“澄清”阶段来处理模糊输入或者调整工具的描述使其更易被模型理解。实操心得在定义工具时description字段至关重要。它不仅是给人看的更是模型决定是否调用该工具的主要依据。描述要精确、具体说明工具的用途、输入是什么、输出是什么。例如“查询知识库”就不如“根据用户描述的技术问题或错误信息从产品知识库中查找相关的故障排除步骤和解决方案文章”来得有效。5. 常见问题、调试技巧与性能优化5.1 模型不遵循指令或输出格式错误这是最常见的问题。排查步骤如下检查系统提示词确保系统提示词中明确要求了模型扮演的角色和需要遵守的规则。例如“你必须以指定的JSON格式输出”这样的指令需要放在显眼位置。验证结构化输出配置如果使用Pydantic确保你正确配置了OpenAI的response_format为{type: json_object}并且在提示词中再次强调了JSON格式。对于函数调用/Tools检查函数签名和描述是否清晰。简化与分步如果任务复杂模型容易出错。尝试将复杂任务拆分成多个简单的子步骤分多次API调用完成。whetstone.chatgpt的“阶段”设计正是为此而生。调整温度参数对于需要严格输出的任务将温度temperature设置为0或接近0如0.1以减少随机性。5.2 工具调用不准确或不被触发工具描述优化如前所述仔细打磨工具的name和description确保它们能精准匹配用户可能的问题表述。可以先用一些示例用户问题测试模型是否会选择正确的工具。提供少量示例在系统提示词或上下文历史中提供一两个工具调用成功的示例Few-shot Learning能显著提高模型使用工具的准确性。检查参数提取有时模型决定调用工具但提取的参数不对。确保参数description字段写清楚格式要求如“日期格式为YYYY-MM-DD”。5.3 上下文长度与Token消耗管理随着对话进行上下文会越来越长导致API调用成本增加、速度变慢甚至可能超过模型上下文窗口限制。启用摘要记忆这是最有效的策略。whetstone.chatgpt的记忆模块应能在对话历史达到一定长度时自动触发摘要生成并用摘要替换旧的历史消息。选择性上下文注入不是所有历史消息都同等重要。在调用API前可以程序化地筛选出与当前阶段最相关的历史消息例如只保留最近5轮对话和涉及关键实体的对话而非全部发送。设置最大历史轮数一个简单的策略是只保留最近N轮对话的原始内容更早的则仅保留摘要或直接丢弃。5.4 处理模型的不确定性与错误模型有时会“胡言乱语”或坚持一个错误的认知。实现验证层对于关键信息如订单号、邮箱不要完全信任模型的提取结果。在程序中使用正则表达式或校验库进行二次验证。如果验证失败可以要求模型重新提取或直接提示用户确认。设计重试与回退逻辑当模型输出无法解析或工具调用失败时你的Agent应该有能力重试当前步骤可能使用一个更明确的提示词或者在几次失败后优雅地回退到默认流程如“我将为您转接人工客服”。记录与监控记录所有对话的完整日志包括原始消息、模型响应、工具调用和内部状态。这是调试复杂问题和改进系统不可或缺的。5.5 性能与成本优化缓存对于常见、静态的查询如知识库中的标准问题解答可以将模型的回复结果缓存起来。当遇到相同或高度相似的问题时直接返回缓存结果避免重复调用API。模型分级并非所有任务都需要最强的GPT-4。对于简单的意图分类、信息提取可以尝试使用更便宜、更快的模型如GPT-3.5-Turbo。whetstone.chatgpt的架构应允许你为不同的“阶段”或“工具”配置不同的模型。异步处理确保你的整个对话处理流程是异步的使用asyncio避免在等待IO网络请求、数据库查询时阻塞这对于高并发应用至关重要。6. 进阶应用与扩展思路当你掌握了基础用法后可以考虑以下方向扩展你的智能应用多智能体协作whetstone.chatgpt的Agent可以不止一个。你可以设计一个“调度员”Agent根据用户问题类型将对话路由给不同的“专家”Agent如技术客服Agent、销售咨询Agent。这些Agent可以共享记忆或通过消息总线通信共同解决复杂问题。与工作流引擎集成将Agent的某个阶段如“信息收集完成”作为触发器连接到外部的工作流引擎如Airflow、Prefect。一旦Agent收集齐所有必要信息就自动创建一个工单、发起一个审批流程或调用一个后端服务实现AI与业务流程的深度集成。持续学习与反馈循环建立一个反馈机制将人工客服最终处理的成功案例以及用户对AI回复的满意度评价作为数据反哺给系统。这些数据可以用于微调提示词模板针对经常出错的场景优化对应阶段的提示词。优化工具选择分析模型在什么情况下错误地选择或未选择某个工具调整工具描述。甚至微调模型本身如果数据量足够可以考虑用这些高质量的对话数据对基础模型进行轻量级微调使其更贴合你的业务领域。可观测性与分析构建一个仪表盘监控Agent的各项指标不同阶段的耗时、工具调用频率与成功率、用户满意度、Token消耗等。这能帮助你发现瓶颈哪个阶段最慢、定位问题哪个工具经常失败和优化成本。johniwasz/whetstone.chatgpt这类项目提供的是一套方法论和基础工具链。它的最大价值在于将构建可靠AI应用的“最佳实践”产品化降低了开发门槛。但真正构建出一个优秀的、能处理复杂现实任务的智能体仍然需要开发者深入理解自己的业务场景并投入精力进行细致的设计、测试和调优。它是一块上好的磨刀石但最终刀的锋利程度取决于你用它的方式和耐心。
基于Whetstone.ChatGPT构建可控AI对话系统:提示工程与状态机实践
1. 项目概述一个为ChatGPT“开刃”的代码库如果你深度使用过ChatGPT的API尤其是尝试过构建一些需要复杂逻辑或长期记忆的应用大概率会遇到一个头疼的问题模型本身很强大但让它严格按照你的指令去执行一个多步骤的任务或者记住对话中很早之前的某个关键细节并不是一件容易的事。模型可能会“跑偏”、遗忘或者输出格式不符合你的程序解析要求。这正是johniwasz/whetstone.chatgpt这个项目试图解决的问题。你可以把它理解为一个为ChatGPT API“开刃”的工具包通过一系列精心设计的“提示工程”模板和结构化输出控制让模型变得更锋利、更听话、更可靠。这个项目名字起得很形象“Whetstone”就是磨刀石。它不改变模型本身而是通过外部的方法论和工具将ChatGPT这把原本就锋利的“刀”打磨得更加趁手以适应更专业、更复杂的开发任务。它的核心价值在于将那些散落在各种博客、论坛和开发者个人笔记中的最佳实践封装成了可复用的代码和模式。对于想要快速构建基于大语言模型的智能应用但又不想从零开始摸索提示词工程和对话管理的开发者来说这无疑是一个高效的起点。2. 核心设计思路超越简单问答的对话管理2.1 从单轮对话到“状态机”式交互普通的ChatGPT API调用大多是基于当前一轮的提示词Prompt和对话历史Messages来生成回复。这就像是一次性的问答。但在真实应用中我们往往需要模型扮演一个具有明确目标和流程的“智能体”。例如一个客服机器人需要先问候、再询问问题类型、接着收集详细信息、最后提供解决方案。这个流程中的每一步模型都需要根据当前“状态”和用户输入决定下一步该做什么并输出结构化的信息供程序判断。whetstone.chatgpt的设计核心就是将对话视为一个可管理的状态机。它引入了“对话阶段”、“工具调用”、“记忆管理”等概念。开发者可以预先定义好对话的各个阶段Phase比如initial_greeting、collecting_info、providing_solution。在每个阶段项目提供的工具会帮助构建最有效的提示词引导模型输出符合该阶段预期的、结构化的内容比如一个JSON对象而不仅仅是自由文本。程序则根据这个结构化输出来更新内部状态并决定是否推进到下一个对话阶段。2.2 结构化输出让模型与程序无缝对接这是项目中一个至关重要的特性。让ChatGPT输出JSON、XML或其他格式化的数据虽然可以通过在提示词中要求来实现但稳定性往往不够。whetstone.chatgpt通过结合OpenAI的“函数调用”Function Calling后演进为Tools或更严格的输出格式控制库如Pydantic强制模型返回程序可直接解析的数据结构。例如在信息收集阶段你不再需要让模型说“请告诉我您的订单号”然后费力地从“我的订单号是123456”这样的自然语言中通过正则表达式提取数字。你可以直接定义一个Pydantic模型from pydantic import BaseModel, Field class OrderInfo(BaseModel): order_id: str Field(description用户提供的订单编号) issue_type: str Field(description问题分类如物流、退款、商品质量) description: str Field(description问题的详细描述)然后通过whetstone.chatgpt的封装将用户当前输入和这个模型定义一起发送给ChatGPT。模型会理解它需要填充这个结构并直接返回一个完整的OrderInfo对象。你的代码拿到这个对象后就可以直接访问order_info.order_id完全省去了文本解析的麻烦和不确定性。注意实现结构化输出的具体技术栈可能随OpenAI API的更新而变化。早期可能重度依赖函数调用而现在更推荐使用OpenAI的JSON Mode或response_format参数配合结构化定义。whetstone.chatgpt的价值在于它封装了这些最佳实践并提供了统一的接口即使底层API方式变化上层的应用代码也可能无需大改。2.3 记忆与上下文管理解决“金鱼脑”问题ChatGPT的上下文窗口有限如GPT-4 Turbo的128K且并非所有历史信息对当前回复都同等重要。一股脑地将整个对话历史塞进上下文不仅浪费Token还可能让模型注意力分散。whetstone.chatgpt通常会实现某种形式的记忆管理策略。一种常见策略是“摘要记忆”。当对话轮数变多时系统会自动生成一个对之前对话核心事实的摘要并用这个摘要替代冗长的原始历史记录作为新的上下文输入。另一种是“向量记忆”将对话中的关键实体如产品名、日期、用户偏好提取出来存入一个向量数据库。当用户提到相关概念时从数据库中检索最相关的记忆片段注入提示词而不是依赖模型自己去回忆。项目通过提供这些记忆管理模块的抽象接口和默认实现让开发者可以轻松地为自己的智能体添加长期记忆能力使其能够进行更连贯、更个性化的多轮对话。3. 关键技术组件与实操解析3.1 提示词模板引擎告别字符串拼接手动拼接提示词是提示工程中最繁琐且易错的部分。whetstone.chatgpt通常会内置一个模板引擎。它允许你将提示词写成模板文件如Jinja2格式其中包含变量占位符、条件判断和循环。例如一个用于代码审查的提示词模板code_review.j2可能如下你是一位资深的{{ language }}开发专家。请审查以下代码 {{ language }} {{ code_snippet }}请重点关注代码风格是否符合{{ style_guide }}规范是否存在潜在的性能瓶颈或安全漏洞是否有更优雅或更高效的实现方式请以JSON格式输出包含“score”1-10分、“issues”问题列表和“suggestions”改进建议列表三个字段。在你的Python代码中你可以这样使用 python from whetstone.chatgpt import PromptTemplate template PromptTemplate.from_file(code_review.j2) prompt template.render( languagePython, code_snippetuser_code, style_guidePEP 8 ) # 然后将prompt发送给模型这种方式将提示词逻辑与业务逻辑分离便于维护、版本控制和A/B测试。你可以为不同的任务准备不同的模板库像调用函数一样调用它们。3.2 工具/函数调用集成扩展模型能力边界虽然ChatGPT知识渊博但它无法直接执行动作比如查询数据库、调用外部API、执行计算。OpenAI的Tools工具调用功能就是为了解决这个问题。whetstone.chatgpt的核心功能之一就是简化工具的定义、注册和调用流程。在项目中你可能会这样定义一个获取天气的工具from whetstone.chatgpt import Tool class WeatherTool(Tool): name get_current_weather description 获取指定城市的当前天气情况 # 定义输入参数的JSON Schema parameters { type: object, properties: { location: {type: string, description: 城市名例如北京}, unit: {type: string, enum: [celsius, fahrenheit], default: celsius} }, required: [location] } async def execute(self, location: str, unit: str celsius) - str: # 这里实现调用真实天气API的逻辑 weather_data await call_weather_api(location, unit) return f{location}的当前天气是{weather_data[condition]}温度{weather_data[temp]}度。然后你将这个工具注册到你的对话管理器Agent中。当用户问“北京天气怎么样”时ChatGPT会识别出需要调用get_current_weather工具并自动提取参数{location: 北京}。你的程序接收到这个工具调用请求后执行WeatherTool.execute(北京)将执行结果真实天气信息作为上下文再次发给模型由模型组织成最终的自然语言回复给用户。这个过程完全自动化开发者只需要关心工具本身的实现。whetstone.chatgpt负责处理与模型之间的工具调用协议管理工具调用的状态和结果返回。3.3 对话会话与状态管理这是项目的骨架。一个典型的Agent或Session类会管理一次完整对话的生命周期。它会持有消息历史维护一个List[ChatMessage]包含用户输入、助手回复、工具调用结果等。当前阶段跟踪对话处于哪个预定义的阶段。记忆系统关联一个记忆存储实例用于保存和读取长期记忆。工具集注册了所有可用的工具。配置如使用的模型、温度参数、最大Token数等。其实操代码结构可能如下from whetstone.chatgpt import Agent, Phase # 1. 定义对话阶段 class MyPhases: GREETING Phase(greeting, initial_prompt你是助手A请友好地问候用户并询问来意。) COLLECTING Phase(collecting, prompt_templatecollect_info.j2) PROCESSING Phase(processing, prompt_templateprocess_request.j2) # ... 其他阶段 # 2. 创建Agent实例 agent Agent( modelgpt-4-turbo-preview, phasesMyPhases, tools[WeatherTool(), DBTool()], # 注册工具 memorySummaryMemory() # 配置记忆系统 ) # 3. 处理用户输入 async def handle_user_input(session_id: str, user_message: str): # 获取或创建特定会话 session await agent.get_or_create_session(session_id) # 添加用户消息并触发Agent处理流程 response await session.process(user_message) # response 包含助手的回复文本以及可能的状态变更信息 print(f助手回复: {response.text}) print(f当前阶段: {session.current_phase}) # 你可以根据session.state可能是一个字典来决定程序的下一步逻辑 if session.current_phase MyPhases.COLLECTING and session.state.get(info_complete): # 信息收集完毕可以触发后台处理流程 start_background_processing(session.state)这个Session对象封装了所有的复杂性让开发者可以专注于业务逻辑定义阶段、工具和模板而不必反复处理底层的API调用、消息列表管理和工具调用循环。4. 实战构建一个智能客服对话引擎让我们通过一个简化的智能客服场景将上述组件串联起来看看如何使用whetstone.chatgpt或其设计理念构建一个可用的系统。4.1 阶段与流程设计首先我们规划对话流程问候与分类问候用户并引导用户说出问题类型售后、咨询、投诉等。信息收集根据问题类型收集必要的信息如订单号、问题描述、联系方式。解决方案提供基于收集的信息提供解决方案或知识库文章。转人工判断如果问题复杂或用户不满意询问是否转接人工客服。4.2 定义数据结构与工具我们需要定义在信息收集阶段要用到的数据结构from pydantic import BaseModel, Field from typing import Literal class UserIssue(BaseModel): category: Literal[售后, 咨询, 投诉, 其他] Field(description用户问题分类) order_id: Optional[str] Field(defaultNone, description订单编号如果是售后/投诉) problem_detail: str Field(description问题的详细描述) contact_preference: Literal[电话, 邮箱, 站内信] Field(description用户偏好的联系方)定义一个查询知识库的工具class KnowledgeBaseTool(Tool): name query_knowledge_base description 根据问题描述从知识库中查找相关解决方案 parameters { type: object, properties: { query: {type: string, description: 用于检索的关键词或问题描述}, category: {type: string, description: 问题分类用于缩小检索范围} }, required: [query] } async def execute(self, query: str, category: str None) - str: # 模拟调用向量数据库或全文搜索引擎 results search_knowledge_base(query, category) return json.dumps(results, ensure_asciiFalse) # 返回结构化结果供模型总结4.3 配置Agent与模板创建各个阶段的提示词模板。例如collect_info.j2你正在帮助用户解决{{ session.state.category }}问题。请根据对话历史尝试填充以下信息。 如果用户已经提供了某项信息请直接使用如果尚未提供请用友好的方式询问用户。 需要收集的信息结构 {{ user_issue_schema }} 当前已收集到的信息 {{ current_info }} 用户最新消息{{ latest_message }} 请输出一个JSON对象严格符合上述结构只包含已确认的信息字段。对于未确认的信息字段值请设为null。 同时生成一句对用户的自然语言回复用于确认信息或继续询问。 输出格式 { collected_data: { ... }, // 填充好的UserIssue部分数据 response_to_user: ... // 你的回复 }在代码中初始化Agentagent Agent( modelgpt-4, phases[GreetingPhase, CollectInfoPhase, SolutionPhase, TransferPhase], tools[KnowledgeBaseTool()], system_prompt你是一个专业、耐心的智能客服助手。, output_parserJsonOutputParser(pydantic_modelUserIssue) # 配置输出解析器 )4.4 运行与迭代启动一个简单的服务如FastAPI来接收用户请求并路由给对应的Agent会话处理。在开发过程中最关键的是不断测试和迭代提示词模板。你需要收集测试用例涵盖各种用户表达清晰、模糊、带有情绪。分析失败对话是模板指令不明确还是模型误解了上下文或是工具返回结果格式不对调整模板和阶段逻辑可能需要增加一个“澄清”阶段来处理模糊输入或者调整工具的描述使其更易被模型理解。实操心得在定义工具时description字段至关重要。它不仅是给人看的更是模型决定是否调用该工具的主要依据。描述要精确、具体说明工具的用途、输入是什么、输出是什么。例如“查询知识库”就不如“根据用户描述的技术问题或错误信息从产品知识库中查找相关的故障排除步骤和解决方案文章”来得有效。5. 常见问题、调试技巧与性能优化5.1 模型不遵循指令或输出格式错误这是最常见的问题。排查步骤如下检查系统提示词确保系统提示词中明确要求了模型扮演的角色和需要遵守的规则。例如“你必须以指定的JSON格式输出”这样的指令需要放在显眼位置。验证结构化输出配置如果使用Pydantic确保你正确配置了OpenAI的response_format为{type: json_object}并且在提示词中再次强调了JSON格式。对于函数调用/Tools检查函数签名和描述是否清晰。简化与分步如果任务复杂模型容易出错。尝试将复杂任务拆分成多个简单的子步骤分多次API调用完成。whetstone.chatgpt的“阶段”设计正是为此而生。调整温度参数对于需要严格输出的任务将温度temperature设置为0或接近0如0.1以减少随机性。5.2 工具调用不准确或不被触发工具描述优化如前所述仔细打磨工具的name和description确保它们能精准匹配用户可能的问题表述。可以先用一些示例用户问题测试模型是否会选择正确的工具。提供少量示例在系统提示词或上下文历史中提供一两个工具调用成功的示例Few-shot Learning能显著提高模型使用工具的准确性。检查参数提取有时模型决定调用工具但提取的参数不对。确保参数description字段写清楚格式要求如“日期格式为YYYY-MM-DD”。5.3 上下文长度与Token消耗管理随着对话进行上下文会越来越长导致API调用成本增加、速度变慢甚至可能超过模型上下文窗口限制。启用摘要记忆这是最有效的策略。whetstone.chatgpt的记忆模块应能在对话历史达到一定长度时自动触发摘要生成并用摘要替换旧的历史消息。选择性上下文注入不是所有历史消息都同等重要。在调用API前可以程序化地筛选出与当前阶段最相关的历史消息例如只保留最近5轮对话和涉及关键实体的对话而非全部发送。设置最大历史轮数一个简单的策略是只保留最近N轮对话的原始内容更早的则仅保留摘要或直接丢弃。5.4 处理模型的不确定性与错误模型有时会“胡言乱语”或坚持一个错误的认知。实现验证层对于关键信息如订单号、邮箱不要完全信任模型的提取结果。在程序中使用正则表达式或校验库进行二次验证。如果验证失败可以要求模型重新提取或直接提示用户确认。设计重试与回退逻辑当模型输出无法解析或工具调用失败时你的Agent应该有能力重试当前步骤可能使用一个更明确的提示词或者在几次失败后优雅地回退到默认流程如“我将为您转接人工客服”。记录与监控记录所有对话的完整日志包括原始消息、模型响应、工具调用和内部状态。这是调试复杂问题和改进系统不可或缺的。5.5 性能与成本优化缓存对于常见、静态的查询如知识库中的标准问题解答可以将模型的回复结果缓存起来。当遇到相同或高度相似的问题时直接返回缓存结果避免重复调用API。模型分级并非所有任务都需要最强的GPT-4。对于简单的意图分类、信息提取可以尝试使用更便宜、更快的模型如GPT-3.5-Turbo。whetstone.chatgpt的架构应允许你为不同的“阶段”或“工具”配置不同的模型。异步处理确保你的整个对话处理流程是异步的使用asyncio避免在等待IO网络请求、数据库查询时阻塞这对于高并发应用至关重要。6. 进阶应用与扩展思路当你掌握了基础用法后可以考虑以下方向扩展你的智能应用多智能体协作whetstone.chatgpt的Agent可以不止一个。你可以设计一个“调度员”Agent根据用户问题类型将对话路由给不同的“专家”Agent如技术客服Agent、销售咨询Agent。这些Agent可以共享记忆或通过消息总线通信共同解决复杂问题。与工作流引擎集成将Agent的某个阶段如“信息收集完成”作为触发器连接到外部的工作流引擎如Airflow、Prefect。一旦Agent收集齐所有必要信息就自动创建一个工单、发起一个审批流程或调用一个后端服务实现AI与业务流程的深度集成。持续学习与反馈循环建立一个反馈机制将人工客服最终处理的成功案例以及用户对AI回复的满意度评价作为数据反哺给系统。这些数据可以用于微调提示词模板针对经常出错的场景优化对应阶段的提示词。优化工具选择分析模型在什么情况下错误地选择或未选择某个工具调整工具描述。甚至微调模型本身如果数据量足够可以考虑用这些高质量的对话数据对基础模型进行轻量级微调使其更贴合你的业务领域。可观测性与分析构建一个仪表盘监控Agent的各项指标不同阶段的耗时、工具调用频率与成功率、用户满意度、Token消耗等。这能帮助你发现瓶颈哪个阶段最慢、定位问题哪个工具经常失败和优化成本。johniwasz/whetstone.chatgpt这类项目提供的是一套方法论和基础工具链。它的最大价值在于将构建可靠AI应用的“最佳实践”产品化降低了开发门槛。但真正构建出一个优秀的、能处理复杂现实任务的智能体仍然需要开发者深入理解自己的业务场景并投入精力进行细致的设计、测试和调优。它是一块上好的磨刀石但最终刀的锋利程度取决于你用它的方式和耐心。